diff --git a/.ci/ctest2ci.py b/.ci/ctest2ci.py
index 9a6ee626ef7a..4ccd9f94e1b6 100755
--- a/.ci/ctest2ci.py
+++ b/.ci/ctest2ci.py
@@ -1,5 +1,4 @@
#!/usr/bin/env python3
-# -*- coding: utf-8 -*-
"""
***************************************************************************
@@ -18,42 +17,47 @@
***************************************************************************
"""
-__author__ = 'Matthias Kuhn'
-__date__ = 'March 2017'
-__copyright__ = '(C) 2017, Matthias Kuhn'
+__author__ = "Matthias Kuhn"
+__date__ = "March 2017"
+__copyright__ = "(C) 2017, Matthias Kuhn"
# This script parses output from ctest and injects
#
# - Colors for failing unit tests and test cases
# - Group control sequences to hide uninteresting output by default
-import sys
import re
+import string
import subprocess
+import sys
+
from termcolor import colored
-import string
fold_stack = list()
printable = set(string.printable)
def start_fold(tag):
- sys.stdout.write('::group::{}\n'.format(tag))
+ sys.stdout.write(f"::group::{tag}\n")
fold_stack.append(tag)
def end_fold():
try:
tag = fold_stack.pop()
- sys.stdout.write('::endgroup::\n')
+ sys.stdout.write("::endgroup::\n")
except IndexError:
- updated_line = colored("======================", 'magenta')
- updated_line += colored("ctest2ci error when processing the following line:", 'magenta')
- updated_line += colored("----------------------", 'magenta')
- updated_line += colored(updated_line, 'magenta')
- updated_line += colored("----------------------", 'magenta')
- updated_line += colored("Tried to end fold, but fold was never started.", 'magenta')
- updated_line += colored("======================", 'magenta')
+ updated_line = colored("======================", "magenta")
+ updated_line += colored(
+ "ctest2ci error when processing the following line:", "magenta"
+ )
+ updated_line += colored("----------------------", "magenta")
+ updated_line += colored(updated_line, "magenta")
+ updated_line += colored("----------------------", "magenta")
+ updated_line += colored(
+ "Tried to end fold, but fold was never started.", "magenta"
+ )
+ updated_line += colored("======================", "magenta")
test_count = 0
@@ -61,8 +65,8 @@ def end_fold():
def start_test_fold():
global test_count
- sys.stdout.write('Running tests\n')
- start_fold('test.{}'.format(test_count))
+ sys.stdout.write("Running tests\n")
+ start_fold(f"test.{test_count}")
test_count += 1
@@ -72,55 +76,61 @@ def start_test_fold():
p = subprocess.Popen(sys.argv[1:], stdout=subprocess.PIPE)
for line in p.stdout:
- updated_line = line.decode('utf-8')
+ updated_line = line.decode("utf-8")
# remove non printable characters https://stackoverflow.com/a/8689826/1548052
filter(lambda x: x in printable, updated_line)
- if re.match('Run dashboard with model Experimental', updated_line):
- start_fold('Run tests')
- updated_line = '{title}\n{line}'.format(title=colored('Running tests...', 'yellow', attrs=['bold']),
- line=updated_line)
-
- elif re.match('Test project /home/runner/QGIS/QGIS/build', updated_line):
+ if re.match("Run dashboard with model Experimental", updated_line):
+ start_fold("Run tests")
+ updated_line = "{title}\n{line}".format(
+ title=colored("Running tests...", "yellow", attrs=["bold"]),
+ line=updated_line,
+ )
+
+ elif re.match("Test project /home/runner/QGIS/QGIS/build", updated_line):
end_fold() # tag=Run tests
start_test_fold()
- if re.search(r'\*\*\*Failed', updated_line) or re.search(r'\*\*\*Timeout', updated_line):
+ if re.search(r"\*\*\*Failed", updated_line) or re.search(
+ r"\*\*\*Timeout", updated_line
+ ):
end_fold()
- updated_line = colored(updated_line, 'red')
+ updated_line = colored(updated_line, "red")
in_failing_test = True
if in_failing_test:
- if re.match(' Start', updated_line):
+ if re.match(" Start", updated_line):
start_test_fold()
in_failing_test = False
elif in_failure:
- if re.match('PASS', updated_line) or re.match('Ran', updated_line):
+ if re.match("PASS", updated_line) or re.match("Ran", updated_line):
in_failure = False
else:
- updated_line = colored(updated_line, 'yellow')
- elif re.search(r'\*\*\* Segmentation fault', updated_line):
- start_fold('segfault')
- updated_line = colored(updated_line, 'magenta')
- elif re.match(' Test failed: Segmentation fault', updated_line):
+ updated_line = colored(updated_line, "yellow")
+ elif re.search(r"\*\*\* Segmentation fault", updated_line):
+ start_fold("segfault")
+ updated_line = colored(updated_line, "magenta")
+ elif re.match(" Test failed: Segmentation fault", updated_line):
end_fold()
else:
- if re.match(r'(FAIL|ERROR)[:\!].*', updated_line):
- updated_line = colored(updated_line, 'yellow')
+ if re.match(r"(FAIL|ERROR)[:\!].*", updated_line):
+ updated_line = colored(updated_line, "yellow")
in_failure = True
- if not in_failing_test and re.search('[0-9]+% tests passed, [0-9]+ tests failed out of', updated_line):
- tests_failing = re.match(r'.* ([0-9]+) tests failed', updated_line).group(1)
+ if not in_failing_test and re.search(
+ "[0-9]+% tests passed, [0-9]+ tests failed out of", updated_line
+ ):
+ tests_failing = re.match(r".* ([0-9]+) tests failed", updated_line).group(1)
# updated_line += '\n::set-output name=TESTS_FAILING::{}'.format(tests_failing)
end_fold()
- if re.search('100% tests passed', updated_line):
- updated_line = colored(updated_line, 'green')
+ if re.search("100% tests passed", updated_line):
+ updated_line = colored(updated_line, "green")
- if re.match('Submit files', updated_line):
- start_fold('submit')
- elif re.search('Test results submitted to', updated_line):
- cdash_url = re.match(r'.*(http.*)$', updated_line).group(1)
+ if re.match("Submit files", updated_line):
+ start_fold("submit")
+ elif re.search("Test results submitted to", updated_line):
+ cdash_url = re.match(r".*(http.*)$", updated_line).group(1)
# updated_line += '\n::set-output name=CDASH_URL::{}'.format(cdash_url)
end_fold()
diff --git a/.ci/pr_has_label.py b/.ci/pr_has_label.py
index c2475e8d2620..d2a8aca7a98f 100755
--- a/.ci/pr_has_label.py
+++ b/.ci/pr_has_label.py
@@ -1,34 +1,37 @@
#!/usr/bin/env python3
-import sys
+import argparse
import json
-from urllib.request import urlopen # using urllib since it is a standard module (vs. requests)
+import sys
+
from urllib.error import URLError
-import argparse
+from urllib.request import ( # using urllib since it is a standard module (vs. requests)
+ urlopen,
+)
-parser = argparse.ArgumentParser(description='Determines if a pull request has a defined label')
-parser.add_argument('pull_request', type=str,
- help='pull request id')
-parser.add_argument('label', type=int,
- help='label ID')
+parser = argparse.ArgumentParser(
+ description="Determines if a pull request has a defined label"
+)
+parser.add_argument("pull_request", type=str, help="pull request id")
+parser.add_argument("label", type=int, help="label ID")
args = parser.parse_args()
-if args.pull_request == 'false':
+if args.pull_request == "false":
print("false")
sys.exit(1)
-url = "https://api.github.com/repos/qgis/QGIS/pulls/{}".format(args.pull_request)
+url = f"https://api.github.com/repos/qgis/QGIS/pulls/{args.pull_request}"
try:
- data = urlopen(url).read().decode('utf-8')
+ data = urlopen(url).read().decode("utf-8")
except URLError as err:
- print("URLError: {}".format(err.reason))
+ print(f"URLError: {err.reason}")
sys.exit(1)
obj = json.loads(data)
-for label in obj['labels']:
+for label in obj["labels"]:
if label["id"] == args.label:
print("true")
sys.exit(0)
diff --git a/.docker/qgis_resources/test_runner/qgis_startup.py b/.docker/qgis_resources/test_runner/qgis_startup.py
index 94c07906f0e4..6475604e883a 100644
--- a/.docker/qgis_resources/test_runner/qgis_startup.py
+++ b/.docker/qgis_resources/test_runner/qgis_startup.py
@@ -6,16 +6,18 @@
~/.qgis3/python/startup.py
"""
-from qgis.core import Qgis
-from qgis import utils
+
import traceback
+from qgis import utils
+from qgis.core import Qgis
+
def _showException(type, value, tb, msg, messagebar=False, level=Qgis.Warning):
print(msg)
- logmessage = ''
+ logmessage = ""
for s in traceback.format_exception(type, value, tb):
- logmessage += s.decode('utf-8', 'replace') if hasattr(s, 'decode') else s
+ logmessage += s.decode("utf-8", "replace") if hasattr(s, "decode") else s
print(logmessage)
diff --git a/.docker/qgis_resources/test_runner/qgis_testrunner.py b/.docker/qgis_resources/test_runner/qgis_testrunner.py
index a04b9295ea35..7173a93c1da0 100755
--- a/.docker/qgis_resources/test_runner/qgis_testrunner.py
+++ b/.docker/qgis_resources/test_runner/qgis_testrunner.py
@@ -1,5 +1,4 @@
#!/usr/bin/env python
-# -*- coding: utf-8 -*-
"""
***************************************************************************
@@ -42,18 +41,19 @@
***************************************************************************
"""
-__author__ = 'Alessandro Pasotti'
-__date__ = 'May 2016'
+__author__ = "Alessandro Pasotti"
+__date__ = "May 2016"
+import importlib
import os
import re
+import signal
import sys
import traceback
-import signal
-import importlib
-from pexpect import run
-from pipes import quote
+from shlex import quote
+
+from pexpect import run
from qgis.utils import iface
@@ -68,14 +68,17 @@ def __get_test_function(test_module_name):
print("QGIS Test Runner - Trying to import %s" % test_module_name)
try:
test_module = importlib.import_module(test_module_name)
- function_name = 'run_all'
+ function_name = "run_all"
except ImportError as e:
# traceback.print_exc(file=sys.stdout)
# Strip latest name
- pos = test_module_name.rfind('.')
+ pos = test_module_name.rfind(".")
if pos <= 0:
raise e
- test_module_name, function_name = test_module_name[:pos], test_module_name[pos + 1:]
+ test_module_name, function_name = (
+ test_module_name[:pos],
+ test_module_name[pos + 1 :],
+ )
print("QGIS Test Runner - Trying to import %s" % test_module_name)
sys.stdout.flush()
try:
@@ -93,47 +96,55 @@ def __get_test_function(test_module_name):
sys.path.append(os.getcwd())
test_module_name = sys.argv[-1]
if __get_test_function(test_module_name) is None:
- print("QGIS Test Runner - [ERROR] cannot load test function from %s" % test_module_name)
+ print(
+ "QGIS Test Runner - [ERROR] cannot load test function from %s"
+ % test_module_name
+ )
sys.exit(1)
try:
me = __file__
except NameError:
me = sys.argv[0]
- os.environ['QGIS_DEBUG'] = '1'
+ os.environ["QGIS_DEBUG"] = "1"
args = [
- 'qgis',
- os.environ.get('QGIS_EXTRA_OPTIONS', ''),
- '--nologo',
- '--noversioncheck',
- '--code',
+ "qgis",
+ os.environ.get("QGIS_EXTRA_OPTIONS", ""),
+ "--nologo",
+ "--noversioncheck",
+ "--code",
me,
test_module_name, # Must be the last one!
]
- command_line = ' '.join(args)
+ command_line = " ".join(args)
print("QGIS Test Runner - launching QGIS as %s ..." % command_line)
out, returncode = run("sh -c " + quote(command_line), withexitstatus=1)
if isinstance(out, bytes):
out = out.decode("utf-8")
assert returncode is not None
print("QGIS Test Runner - QGIS exited.")
- ok = out.find('(failures=') < 0 and \
- len(re.findall(r'Ran \d+ tests in\s',
- out, re.MULTILINE)) > 0
- print('=' * 60)
+ ok = (
+ out.find("(failures=") < 0
+ and len(re.findall(r"Ran \d+ tests in\s", out, re.MULTILINE)) > 0
+ )
+ print("=" * 60)
if not ok:
print(out)
else:
eprint(out)
if len(out) == 0:
print("QGIS Test Runner - [WARNING] subprocess returned no output")
- print('=' * 60)
+ print("=" * 60)
- print("QGIS Test Runner - %s bytes returned and finished with exit code: %s" % (len(out), 0 if ok else 1))
+ print(
+ "QGIS Test Runner - {} bytes returned and finished with exit code: {}".format(
+ len(out), 0 if ok else 1
+ )
+ )
sys.exit(0 if ok else 1)
else: # We are inside QGIS!
# Start as soon as the initializationCompleted signal is fired
- from qgis.core import QgsApplication, QgsProjectBadLayerHandler, QgsProject
+ from qgis.core import QgsApplication, QgsProject, QgsProjectBadLayerHandler
from qgis.PyQt.QtCore import QDir
from qgis.utils import iface
diff --git a/.github/actions/vcpkg_update_report/vcpkg-diff.py b/.github/actions/vcpkg_update_report/vcpkg-diff.py
index bc895b038b6c..21ff42ef772f 100644
--- a/.github/actions/vcpkg_update_report/vcpkg-diff.py
+++ b/.github/actions/vcpkg_update_report/vcpkg-diff.py
@@ -89,7 +89,7 @@ def read_file(file_path):
"""
Read the content of a file.
"""
- with open(file_path, "r") as file:
+ with open(file_path) as file:
return file.read()
diff --git a/cmake/FindPyQt5.py b/cmake/FindPyQt5.py
index fe029af9faca..39d3b246c43d 100644
--- a/cmake/FindPyQt5.py
+++ b/cmake/FindPyQt5.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Copyright (c) 2007, Simon Edwards
# All rights reserved.
@@ -31,16 +30,19 @@
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
import os.path
+import sys
+
import PyQt5.QtCore
import sipconfig
-import sys
cfg = sipconfig.Configuration()
sip_dir = cfg.default_sip_dir
-for p in (os.path.join(sip_dir, "PyQt5"),
- os.path.join(sip_dir, "PyQt5-3"),
- sip_dir,
- os.path.join(cfg.default_mod_dir, "PyQt5", "bindings")):
+for p in (
+ os.path.join(sip_dir, "PyQt5"),
+ os.path.join(sip_dir, "PyQt5-3"),
+ sip_dir,
+ os.path.join(cfg.default_mod_dir, "PyQt5", "bindings"),
+):
if os.path.exists(os.path.join(p, "QtCore", "QtCoremod.sip")):
sip_dir = p
break
@@ -48,7 +50,7 @@
print("pyqt_version_str:%s" % PyQt5.QtCore.PYQT_VERSION_STR)
print("pyqt_mod_dir:%s" % os.path.join(cfg.default_mod_dir, "PyQt5"))
print("pyqt_sip_dir:%s" % sip_dir)
-print("pyqt_sip_flags:%s" % PyQt5.QtCore.PYQT_CONFIGURATION['sip_flags'])
+print("pyqt_sip_flags:%s" % PyQt5.QtCore.PYQT_CONFIGURATION["sip_flags"])
print("pyqt_bin_dir:%s" % cfg.default_bin_dir)
try:
diff --git a/cmake/FindPyQt6.py b/cmake/FindPyQt6.py
index de735d467a18..8a149f4f1aba 100644
--- a/cmake/FindPyQt6.py
+++ b/cmake/FindPyQt6.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Copyright (c) 2007, Simon Edwards
# All rights reserved.
@@ -31,16 +30,19 @@
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
import os.path
+import sys
+
import PyQt6.QtCore
import sipconfig
-import sys
cfg = sipconfig.Configuration()
sip_dir = cfg.default_sip_dir
-for p in (os.path.join(sip_dir, "PyQt6"),
- os.path.join(sip_dir, "PyQt6-3"),
- sip_dir,
- os.path.join(cfg.default_mod_dir, "PyQt6", "bindings")):
+for p in (
+ os.path.join(sip_dir, "PyQt6"),
+ os.path.join(sip_dir, "PyQt6-3"),
+ sip_dir,
+ os.path.join(cfg.default_mod_dir, "PyQt6", "bindings"),
+):
if os.path.exists(os.path.join(p, "QtCore", "QtCoremod.sip")):
sip_dir = p
break
diff --git a/cmake/FindQsci.py b/cmake/FindQsci.py
index f74f7c5201e9..de104ba5b105 100644
--- a/cmake/FindQsci.py
+++ b/cmake/FindQsci.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Copyright (c) 2012, Larry Shaffer
# All rights reserved.
@@ -30,9 +29,9 @@
.. note:: Redistribution and use is allowed according to the terms of the BSD
license. For details see the accompanying COPYING-CMAKE-SCRIPTS file.
"""
-__author__ = 'Larry Shaffer (larry@dakotacarto.com)'
-__date__ = '22/10/2012'
-__copyright__ = 'Copyright 2012, The QGIS Project'
+__author__ = "Larry Shaffer (larry@dakotacarto.com)"
+__date__ = "22/10/2012"
+__copyright__ = "Copyright 2012, The QGIS Project"
import sys
@@ -40,24 +39,30 @@
if len(sys.argv) > 0:
if sys.argv[1] == "4":
from PyQt4.Qsci import QSCINTILLA_VERSION_STR
+
VER = QSCINTILLA_VERSION_STR
if sys.argv[1] == "5":
from PyQt5.Qsci import QSCINTILLA_VERSION_STR
+
VER = QSCINTILLA_VERSION_STR
else:
from PyQt6.Qsci import QSCINTILLA_VERSION_STR
+
VER = QSCINTILLA_VERSION_STR
else:
try:
from PyQt4.Qsci import QSCINTILLA_VERSION_STR
+
VER = QSCINTILLA_VERSION_STR
except ImportError:
try:
from PyQt5.Qsci import QSCINTILLA_VERSION_STR
+
VER = QSCINTILLA_VERSION_STR
except ImportError:
try:
from PyQt6.Qsci import QSCINTILLA_VERSION_STR
+
VER = QSCINTILLA_VERSION_STR
except ImportError:
pass
diff --git a/cmake/FindSIP.py b/cmake/FindSIP.py
index 2e8eea04bb56..01ff1469528e 100644
--- a/cmake/FindSIP.py
+++ b/cmake/FindSIP.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Copyright (c) 2007, Simon Edwards
# All rights reserved.
@@ -38,6 +37,7 @@
print("sip_version_str:%s" % sipbuild.version.SIP_VERSION_STR)
import sysconfig
+
if "deb_system" in sysconfig.get_scheme_names():
python_modules_dir = sysconfig.get_path("purelib", "deb_system")
else:
diff --git a/cmake/PythonCompile.py b/cmake/PythonCompile.py
index 4117aa77065b..a20e9f7c187b 100644
--- a/cmake/PythonCompile.py
+++ b/cmake/PythonCompile.py
@@ -1,6 +1,5 @@
-# -*- coding: utf-8 -*-
-
# By Simon Edwards
# This file is in the public domain.
import py_compile
+
py_compile.main()
diff --git a/python/PyQt6/core/additions/edit.py b/python/PyQt6/core/additions/edit.py
index 92756d1e8953..b82f268ea0a9 100644
--- a/python/PyQt6/core/additions/edit.py
+++ b/python/PyQt6/core/additions/edit.py
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-
"""
***************************************************************************
edit.py
@@ -17,8 +15,6 @@
***************************************************************************
"""
-from builtins import object
-
class QgsEditError(Exception):
@@ -29,7 +25,7 @@ def __str__(self):
return repr(self.value)
-class edit(object):
+class edit:
def __init__(self, layer):
self.layer = layer
diff --git a/python/PyQt6/core/additions/fromfunction.py b/python/PyQt6/core/additions/fromfunction.py
index 92c3647449b5..7bbe1761a975 100644
--- a/python/PyQt6/core/additions/fromfunction.py
+++ b/python/PyQt6/core/additions/fromfunction.py
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-
"""
***************************************************************************
fromfunction.py
@@ -23,36 +21,38 @@
@staticmethod
-def _fromFunction(description: str,
- function: _typing.Callable,
- *args,
- on_finished: _typing.Optional[_typing.Callable] = None,
- flags=QgsTask.Flag.AllFlags,
- **kwargs) -> QgsTask:
+def _fromFunction(
+ description: str,
+ function: _typing.Callable,
+ *args,
+ on_finished: _typing.Optional[_typing.Callable] = None,
+ flags=QgsTask.Flag.AllFlags,
+ **kwargs
+) -> QgsTask:
"""
-Creates a new QgsTask task from a python function.
+ Creates a new QgsTask task from a python function.
-Example
--------
+ Example
+ -------
-.. code-block:: python
+ .. code-block:: python
- def calculate(task):
- # pretend this is some complex maths and stuff we want
- # to run in the background
- return 5*6
+ def calculate(task):
+ # pretend this is some complex maths and stuff we want
+ # to run in the background
+ return 5*6
- def calculation_finished(exception, value=None):
- if not exception:
- iface.messageBar().pushMessage(
- 'the magic number is {}'.format(value))
- else:
- iface.messageBar().pushMessage(
- str(exception))
+ def calculation_finished(exception, value=None):
+ if not exception:
+ iface.messageBar().pushMessage(
+ 'the magic number is {}'.format(value))
+ else:
+ iface.messageBar().pushMessage(
+ str(exception))
- task = QgsTask.fromFunction('my task', calculate,
- on_finished=calculation_finished)
- QgsApplication.taskManager().addTask(task)
+ task = QgsTask.fromFunction('my task', calculate,
+ on_finished=calculation_finished)
+ QgsApplication.taskManager().addTask(task)
"""
diff --git a/python/PyQt6/core/additions/metaenum.py b/python/PyQt6/core/additions/metaenum.py
index dac7b1b1c464..0d1fb6b39683 100644
--- a/python/PyQt6/core/additions/metaenum.py
+++ b/python/PyQt6/core/additions/metaenum.py
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-
"""
***************************************************************************
metaenum.py
@@ -61,7 +59,9 @@ def metaEnumFromType(enumClass, baseClass=None, raiseException=True):
return metaEnumFromType(enumClass, baseClass, raiseException)
except AttributeError:
if raiseException:
- raise ValueError("Enum type does not implement baseClass method. Provide the base class as argument.")
+ raise ValueError(
+ "Enum type does not implement baseClass method. Provide the base class as argument."
+ )
try:
meta_object = baseClass.staticMetaObject
@@ -71,7 +71,7 @@ def metaEnumFromType(enumClass, baseClass=None, raiseException=True):
META_ENUM_BY_ENUM_CLASS[enumClass] = meta_enum
except AttributeError:
if raiseException:
- raise TypeError("could not get the metaEnum for {}".format(enumClass.__name__))
+ raise TypeError(f"could not get the metaEnum for {enumClass.__name__}")
meta_enum = None
return meta_enum
diff --git a/python/PyQt6/core/additions/projectdirtyblocker.py b/python/PyQt6/core/additions/projectdirtyblocker.py
index 7f06bd0a8412..95cec0432a79 100644
--- a/python/PyQt6/core/additions/projectdirtyblocker.py
+++ b/python/PyQt6/core/additions/projectdirtyblocker.py
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-
"""
***************************************************************************
projectdirtyblocker.py
@@ -17,11 +15,10 @@
***************************************************************************
"""
-
from qgis._core import QgsProjectDirtyBlocker
-class ProjectDirtyBlocker():
+class ProjectDirtyBlocker:
"""
Context manager used to block project setDirty calls.
diff --git a/python/PyQt6/core/additions/providermetadata.py b/python/PyQt6/core/additions/providermetadata.py
index d188f6e26fde..b1a676c37386 100644
--- a/python/PyQt6/core/additions/providermetadata.py
+++ b/python/PyQt6/core/additions/providermetadata.py
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-
"""
***************************************************************************
providermetadata.py
@@ -21,12 +19,12 @@
class PyProviderMetadata(QgsProviderMetadata):
- """ wrapper around QgsProviderMetadata to keep the existing Python code running which registers
- data providers by passing a custom python createProvider() function to QgsProviderMetadata
- constructor. The proper new way of doing it is to subclass QgsProviderMetadata and implement
- its virtual functions.
+ """wrapper around QgsProviderMetadata to keep the existing Python code running which registers
+ data providers by passing a custom python createProvider() function to QgsProviderMetadata
+ constructor. The proper new way of doing it is to subclass QgsProviderMetadata and implement
+ its virtual functions.
- TODO: QGIS 4 - remove this wrapper (only subclassing of QgsProviderMetadata should be used)
+ TODO: QGIS 4 - remove this wrapper (only subclassing of QgsProviderMetadata should be used)
"""
# this is a workaround to keep references to metadata classes
diff --git a/python/PyQt6/core/additions/qgsfeature.py b/python/PyQt6/core/additions/qgsfeature.py
index 252a89fc010e..b3dcef297db1 100644
--- a/python/PyQt6/core/additions/qgsfeature.py
+++ b/python/PyQt6/core/additions/qgsfeature.py
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-
"""
***************************************************************************
qgsfeature.py
@@ -22,6 +20,8 @@ def _mapping_feature(feature):
geom = feature.geometry()
fields = [field.name() for field in feature.fields()]
properties = dict(list(zip(fields, feature.attributes())))
- return {'type': 'Feature',
- 'properties': properties,
- 'geometry': geom.__geo_interface__}
+ return {
+ "type": "Feature",
+ "properties": properties,
+ "geometry": geom.__geo_interface__,
+ }
diff --git a/python/PyQt6/core/additions/qgsfunction.py b/python/PyQt6/core/additions/qgsfunction.py
index e91e25a7fc0b..32a338dac291 100644
--- a/python/PyQt6/core/additions/qgsfunction.py
+++ b/python/PyQt6/core/additions/qgsfunction.py
@@ -15,13 +15,18 @@
***************************************************************************
"""
-
import inspect
import string
import traceback
from qgis.PyQt.QtCore import QCoreApplication
-from qgis._core import QgsExpressionFunction, QgsExpression, QgsMessageLog, QgsFeatureRequest, Qgis
+from qgis._core import (
+ QgsExpressionFunction,
+ QgsExpression,
+ QgsMessageLog,
+ QgsFeatureRequest,
+ Qgis,
+)
class QgsPyExpressionFunction(QgsExpressionFunction):
@@ -143,7 +148,8 @@ def register_function(
if not QgsExpression.unregisterFunction(name):
msgtitle = QCoreApplication.translate("UserExpressions", "User expressions")
msg = QCoreApplication.translate(
- "UserExpressions", "The user expression {0} already exists and could not be unregistered."
+ "UserExpressions",
+ "The user expression {0} already exists and could not be unregistered.",
).format(name)
QgsMessageLog.logMessage(msg + "\n", msgtitle, Qgis.MessageLevel.Warning)
return None
@@ -154,7 +160,14 @@ def register_function(
# Legacy: if args was not 'auto', parameters were passed as a list
params_as_list = params_as_list or args != "auto"
f = QgsPyExpressionFunction(
- function, name, group, helptext, usesgeometry, referenced_columns, handlesnull, params_as_list
+ function,
+ name,
+ group,
+ helptext,
+ usesgeometry,
+ referenced_columns,
+ handlesnull,
+ params_as_list,
)
if register:
diff --git a/python/PyQt6/core/additions/qgsgeometry.py b/python/PyQt6/core/additions/qgsgeometry.py
index 6d2babfe1f03..63dbdeb5ccd7 100644
--- a/python/PyQt6/core/additions/qgsgeometry.py
+++ b/python/PyQt6/core/additions/qgsgeometry.py
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-
"""
***************************************************************************
qgsgeometry.py
diff --git a/python/PyQt6/core/additions/qgssettings.py b/python/PyQt6/core/additions/qgssettings.py
index a8190a31c7c9..8140211df44c 100644
--- a/python/PyQt6/core/additions/qgssettings.py
+++ b/python/PyQt6/core/additions/qgssettings.py
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-
"""
***************************************************************************
qgssettings.py
@@ -22,7 +20,9 @@
import qgis # required to get base class of enums
-def _qgssettings_enum_value(self, key, enumDefaultValue, section=QgsSettings.Section.NoSection):
+def _qgssettings_enum_value(
+ self, key, enumDefaultValue, section=QgsSettings.Section.NoSection
+):
"""
Return the setting value for a setting based on an enum.
This forces the output to be a valid and existing entry of the enum.
@@ -41,8 +41,11 @@ def _qgssettings_enum_value(self, key, enumDefaultValue, section=QgsSettings.Sec
meta_enum = metaEnumFromValue(enumDefaultValue)
if meta_enum is None or not meta_enum.isValid():
# this should not happen
- raise ValueError("could not get the meta enum for given enum default value (type: {})"
- .format(enumDefaultValue.__class__))
+ raise ValueError(
+ "could not get the meta enum for given enum default value (type: {})".format(
+ enumDefaultValue.__class__
+ )
+ )
str_val = self.value(key, meta_enum.valueToKey(enumDefaultValue), str, section)
# need a new meta enum as QgsSettings.value is making a copy and leads to seg fault (probably a PyQt issue)
@@ -58,7 +61,9 @@ def _qgssettings_enum_value(self, key, enumDefaultValue, section=QgsSettings.Sec
return enu_val
-def _qgssettings_set_enum_value(self, key, enumValue, section=QgsSettings.Section.NoSection):
+def _qgssettings_set_enum_value(
+ self, key, enumValue, section=QgsSettings.Section.NoSection
+):
"""
Save the setting value for a setting based on an enum.
This forces the output to be a valid and existing entry of the enum.
@@ -76,12 +81,16 @@ def _qgssettings_set_enum_value(self, key, enumValue, section=QgsSettings.Sectio
meta_enum = metaEnumFromValue(enumValue)
if meta_enum is None or not meta_enum.isValid():
# this should not happen
- raise ValueError("could not get the meta enum for given enum default value (type: {})".format(type(enumValue)))
+ raise ValueError(
+ f"could not get the meta enum for given enum default value (type: {type(enumValue)})"
+ )
self.setValue(key, meta_enum.valueToKey(enumValue), section)
-def _qgssettings_flag_value(self, key, flagDefaultValue, section=QgsSettings.Section.NoSection):
+def _qgssettings_flag_value(
+ self, key, flagDefaultValue, section=QgsSettings.Section.NoSection
+):
"""
Return the setting value for a setting based on a flag.
This forces the output to be a valid and existing entry of the enum.
@@ -102,13 +111,19 @@ def _qgssettings_flag_value(self, key, flagDefaultValue, section=QgsSettings.Sec
# dirty hack to get the parent class
__import__(flagDefaultValue.__module__)
baseClass = None
- exec("baseClass={module}.{flag_class}".format(module=flagDefaultValue.__module__.replace('_', ''),
- flag_class=flagDefaultValue.__class__.__name__))
+ exec(
+ "baseClass={module}.{flag_class}".format(
+ module=flagDefaultValue.__module__.replace("_", ""),
+ flag_class=flagDefaultValue.__class__.__name__,
+ )
+ )
meta_enum = metaEnumFromValue(flagDefaultValue, baseClass)
if meta_enum is None or not meta_enum.isValid():
# this should not happen
- raise ValueError("could not get the meta enum for given enum default value (type: {})".format(type(flagDefaultValue)))
+ raise ValueError(
+ f"could not get the meta enum for given enum default value (type: {type(flagDefaultValue)})"
+ )
str_val = self.value(key, meta_enum.valueToKeys(flagDefaultValue), str, section)
# need a new meta enum as QgsSettings.value is making a copy and leads to seg fault (probably a PyQt issue)
diff --git a/python/PyQt6/core/additions/qgssettingsentry.py b/python/PyQt6/core/additions/qgssettingsentry.py
index ca55c90e4f66..d07797c0d55c 100644
--- a/python/PyQt6/core/additions/qgssettingsentry.py
+++ b/python/PyQt6/core/additions/qgssettingsentry.py
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-
"""
***************************************************************************
qgssettingsentry.py
@@ -18,7 +16,13 @@
"""
from .metaenum import metaEnumFromValue
-from qgis.core import QgsSettings, QgsSettingsTree, QgsSettingsEntryBase, QgsLogger, Qgis
+from qgis.core import (
+ QgsSettings,
+ QgsSettingsTree,
+ QgsSettingsEntryBase,
+ QgsLogger,
+ Qgis,
+)
import qgis # required to get base class of enums
@@ -29,7 +33,14 @@ class PyQgsSettingsEntryEnumFlag
since QGIS 3.20
"""
- def __init__(self, key, pluginName, defaultValue, description=str(), options=Qgis.SettingsOptions()):
+ def __init__(
+ self,
+ key,
+ pluginName,
+ defaultValue,
+ description="",
+ options=Qgis.SettingsOptions(),
+ ):
"""
Constructor for PyQgsSettingsEntryEnumFlag.
@@ -42,10 +53,12 @@ def __init__(self, key, pluginName, defaultValue, description=str(), options=Qgi
# TODO QGIS 4: rename pluginName arg to parent and key to name
self.options = options
- defaultValueStr = str()
+ defaultValueStr = ""
self.__metaEnum = metaEnumFromValue(defaultValue)
if self.__metaEnum is None or not self.__metaEnum.isValid():
- QgsLogger.debug("Invalid metaenum. Enum/Flag probably misses Q_ENUM/Q_FLAG declaration. Settings key: '{0}'".format(self.key()))
+ QgsLogger.debug(
+ f"Invalid metaenum. Enum/Flag probably misses Q_ENUM/Q_FLAG declaration. Settings key: '{self.key()}'"
+ )
else:
if self.__metaEnum.isFlag():
defaultValueStr = self.__metaEnum.valueToKeys(defaultValue)
@@ -75,9 +88,13 @@ def value(self, dynamicKeyPart=None):
:param dynamicKeyPart: argument specifies the dynamic part of the settings key.
"""
if self.__metaEnum.isFlag():
- return QgsSettings().flagValue(self.key(dynamicKeyPart), self.defaultValue())
+ return QgsSettings().flagValue(
+ self.key(dynamicKeyPart), self.defaultValue()
+ )
else:
- return QgsSettings().enumValue(self.key(dynamicKeyPart), self.defaultValue())
+ return QgsSettings().enumValue(
+ self.key(dynamicKeyPart), self.defaultValue()
+ )
def valueWithDefaultOverride(self, defaultValueOverride, dynamicKeyPart=None):
"""
@@ -87,9 +104,13 @@ def valueWithDefaultOverride(self, defaultValueOverride, dynamicKeyPart=None):
:param dynamicKeyPart: argument specifies the dynamic part of the settings key.
"""
if self.__metaEnum.isFlag():
- return QgsSettings().flagValue(self.key(dynamicKeyPart), defaultValueOverride)
+ return QgsSettings().flagValue(
+ self.key(dynamicKeyPart), defaultValueOverride
+ )
else:
- return QgsSettings().enumValue(self.key(dynamicKeyPart), defaultValueOverride)
+ return QgsSettings().enumValue(
+ self.key(dynamicKeyPart), defaultValueOverride
+ )
def defaultValue(self):
"""
@@ -97,7 +118,9 @@ def defaultValue(self):
"""
if self.__metaEnum is None or not self.__metaEnum.isValid():
- QgsLogger.debug("Invalid metaenum. Enum/Flag probably misses Q_ENUM/Q_FLAG declaration. Settings key: '{0}'".format(self.key()))
+ QgsLogger.debug(
+ f"Invalid metaenum. Enum/Flag probably misses Q_ENUM/Q_FLAG declaration. Settings key: '{self.key()}'"
+ )
return -1
defaultValueString = self.defaultValueAsVariant()
@@ -106,7 +129,9 @@ def defaultValue(self):
else:
(defaultValue, ok) = self.__metaEnum.keyToValue(defaultValueString)
if not ok:
- QgsLogger.debug("Invalid enum/flag key/s '{0}'.".format(self.defaultValueAsVariant()))
+ QgsLogger.debug(
+ f"Invalid enum/flag key/s '{self.defaultValueAsVariant()}'."
+ )
return -1
# cast to the enum class
@@ -122,7 +147,9 @@ def setValue(self, value, dynamicKeyPart: (list, str) = None):
"""
if self.__metaEnum is None or not self.__metaEnum.isValid():
- QgsLogger.debug("Invalid metaenum. Enum/Flag probably misses Q_ENUM/Q_FLAG declaration. Settings key: '{0}'".format(self.key()))
+ QgsLogger.debug(
+ f"Invalid metaenum. Enum/Flag probably misses Q_ENUM/Q_FLAG declaration. Settings key: '{self.key()}'"
+ )
return False
if self.options & Qgis.SettingsOption.SaveEnumFlagAsInt:
@@ -133,7 +160,7 @@ def setValue(self, value, dynamicKeyPart: (list, str) = None):
else:
enum_flag_key = self.__metaEnum.valueToKey(value)
if not enum_flag_key:
- QgsLogger.debug("Invalid enum/flag value '{0}'.".format(value))
+ QgsLogger.debug(f"Invalid enum/flag value '{value}'.")
return False
if type(dynamicKeyPart) is str:
diff --git a/python/PyQt6/core/additions/qgstaskwrapper.py b/python/PyQt6/core/additions/qgstaskwrapper.py
index 6c2b7560d812..a3a7d8c347bf 100644
--- a/python/PyQt6/core/additions/qgstaskwrapper.py
+++ b/python/PyQt6/core/additions/qgstaskwrapper.py
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-
"""
***************************************************************************
qgstaskwrapper.py
@@ -17,7 +15,6 @@
***************************************************************************
"""
-
from qgis._core import QgsTask
@@ -47,7 +44,7 @@ def finished(self, result):
return
if not result and self.exception is None:
- self.exception = Exception('Task canceled')
+ self.exception = Exception("Task canceled")
try:
if self.returned_values:
diff --git a/python/PyQt6/core/additions/readwritecontextentercategory.py b/python/PyQt6/core/additions/readwritecontextentercategory.py
index af9c509342cd..79a9c44e8bac 100644
--- a/python/PyQt6/core/additions/readwritecontextentercategory.py
+++ b/python/PyQt6/core/additions/readwritecontextentercategory.py
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-
"""
***************************************************************************
readwritecontextentercategory.py
@@ -18,7 +16,7 @@
"""
-class ReadWriteContextEnterCategory():
+class ReadWriteContextEnterCategory:
"""
Push a category to the stack
diff --git a/python/PyQt6/core/additions/runtimeprofiler.py b/python/PyQt6/core/additions/runtimeprofiler.py
index 2216f5609e9d..95758a1ce899 100644
--- a/python/PyQt6/core/additions/runtimeprofiler.py
+++ b/python/PyQt6/core/additions/runtimeprofiler.py
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-
"""
***************************************************************************
runtimeprofiler.py
@@ -17,11 +15,10 @@
***************************************************************************
"""
-
from qgis._core import QgsScopedRuntimeProfile
-class ScopedRuntimeProfileContextManager():
+class ScopedRuntimeProfileContextManager:
"""
Context manager used to profile blocks of code in the QgsApplication.profiler() registry.
diff --git a/python/PyQt6/core/additions/validitycheck.py b/python/PyQt6/core/additions/validitycheck.py
index 25fdd1586f09..37a32b9cf5e1 100644
--- a/python/PyQt6/core/additions/validitycheck.py
+++ b/python/PyQt6/core/additions/validitycheck.py
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-
"""
***************************************************************************
validitycheck.py
@@ -16,9 +14,8 @@
* *
***************************************************************************
"""
-from qgis._core import (
- QgsAbstractValidityCheck,
- QgsApplication)
+
+from qgis._core import QgsAbstractValidityCheck, QgsApplication
class CheckFactory:
diff --git a/python/PyQt6/core/contextmanagers.py b/python/PyQt6/core/contextmanagers.py
index 62e0c624659d..72be360097e6 100644
--- a/python/PyQt6/core/contextmanagers.py
+++ b/python/PyQt6/core/contextmanagers.py
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-
"""
***************************************************************************
contextmanagers.py
@@ -17,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Nathan Woodrow'
-__date__ = 'May 2014'
-__copyright__ = '(C) 2014, Nathan Woodrow'
+__author__ = "Nathan Woodrow"
+__date__ = "May 2014"
+__copyright__ = "(C) 2014, Nathan Woodrow"
import sys
from contextlib import contextmanager
diff --git a/python/PyQt6/gui/additions/qgssettingsenumflageditorwrapper.py b/python/PyQt6/gui/additions/qgssettingsenumflageditorwrapper.py
index 245b0470a35f..528adb8192a2 100644
--- a/python/PyQt6/gui/additions/qgssettingsenumflageditorwrapper.py
+++ b/python/PyQt6/gui/additions/qgssettingsenumflageditorwrapper.py
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-
"""
***************************************************************************
qgssettingsenumflageditorwrapper.py
@@ -28,7 +26,9 @@ class PyQgsSettingsEnumEditorWidgetWrapper(QgsSettingsEditorWidgetWrapper):
A settings editor widget wrapper for enum settings as PyQgsSettingsEntryEnumFlag
"""
- def __init__(self, parent=None, editor=None, setting=None, displayStrings: dict = None):
+ def __init__(
+ self, parent=None, editor=None, setting=None, displayStrings: dict = None
+ ):
self.setting = setting
self.editor = editor
self.displayStrings = {}
@@ -39,19 +39,23 @@ def __init__(self, parent=None, editor=None, setting=None, displayStrings: dict
self.configureEditor(editor, setting)
def id(self):
- return 'py-enum'
+ return "py-enum"
def createWrapper(self, parent=None):
return PyQgsSettingsEnumEditorWidgetWrapper(parent)
def setWidgetFromSetting(self):
if self.setting:
- return self.setWidgetFromVariant(self.setting.valueAsVariant(self.dynamicKeyPartList()))
+ return self.setWidgetFromVariant(
+ self.setting.valueAsVariant(self.dynamicKeyPartList())
+ )
return False
def setSettingFromWidget(self):
if self.editor:
- self.setting.setVariantValue(self.variantValueFromWidget(), self.dynamicKeyPartList())
+ self.setting.setVariantValue(
+ self.variantValueFromWidget(), self.dynamicKeyPartList()
+ )
return True
else:
return False
@@ -88,4 +92,7 @@ def configureEditorPrivate(self, editor: QComboBox, setting: QgsSettingsEntryBas
def enableAutomaticUpdatePrivate(self):
self.editor.currentIndexChanged.connect(
- lambda: self.setting.setValue(self.editor.currentData(), self.dynamicKeyPartList()))
+ lambda: self.setting.setValue(
+ self.editor.currentData(), self.dynamicKeyPartList()
+ )
+ )
diff --git a/python/__init__.py b/python/__init__.py
index bee060f91a58..35fdfd666538 100644
--- a/python/__init__.py
+++ b/python/__init__.py
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-
"""
***************************************************************************
__init__.py
@@ -17,11 +15,10 @@
***************************************************************************
"""
-__author__ = 'Martin Dobias'
-__date__ = 'January 2007'
-__copyright__ = '(C) 2007, Martin Dobias'
+__author__ = "Martin Dobias"
+__date__ = "January 2007"
+__copyright__ = "(C) 2007, Martin Dobias"
-from builtins import zip
import os
import sys
@@ -32,7 +29,7 @@ def setupenv():
OSGeo4W package format.
"""
# If the prefix path is already set then we don't do any more path setup.
- if os.getenv('QGIS_PREFIX_PATH'):
+ if os.getenv("QGIS_PREFIX_PATH"):
return
# Setup the paths based on the .vars file.
@@ -41,13 +38,13 @@ def setupenv():
path_split = PurePath(os.path.dirname(os.path.realpath(__file__))).parts
try:
- appname = os.environ['QGIS_ENVNAME']
+ appname = os.environ["QGIS_ENVNAME"]
except KeyError:
appname = path_split[-3]
envfile = list(path_split[:-4])
envfile.append("bin")
- envfile.append("{0}-bin.env".format(appname))
+ envfile.append(f"{appname}-bin.env")
envfile = os.path.join(*envfile)
if not os.path.exists(envfile):
@@ -65,12 +62,14 @@ def setupenv():
pass
-if os.name == 'nt':
+if os.name == "nt":
# On Windows we need to setup the paths before we can import
# any of the QGIS modules or else it will error.
setupenv()
- if sys.version_info[0] > 3 or (sys.version_info[0] == 3 and sys.version_info[1] >= 9):
+ if sys.version_info[0] > 3 or (
+ sys.version_info[0] == 3 and sys.version_info[1] >= 9
+ ):
for p in os.getenv("PATH").split(";"):
if os.path.exists(p):
os.add_dll_directory(p)
@@ -84,11 +83,12 @@ def setupenv():
# (thanks to uic/widget-plugins/qgis_customwidgets.py)
try:
import qgis.gui
+
widget_list = dir(qgis.gui)
# remove widgets that are not allowed as custom widgets (they need to be manually promoted)
- skip_list = ['QgsScrollArea']
+ skip_list = ["QgsScrollArea"]
for widget in widget_list:
- if widget.startswith('Qgs') and widget not in skip_list:
+ if widget.startswith("Qgs") and widget not in skip_list:
sys.modules[widget.lower()] = qgis.gui
except ImportError:
# gui might not be built
diff --git a/python/console/__init__.py b/python/console/__init__.py
index f9477a90b37f..e2f7bf4cd4ad 100644
--- a/python/console/__init__.py
+++ b/python/console/__init__.py
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-
"""
***************************************************************************
__init__.py
@@ -17,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Salvatore Larosa'
-__date__ = 'September 2012'
-__copyright__ = '(C) 2012, Salvatore Larosa'
+__author__ = "Salvatore Larosa"
+__date__ = "September 2012"
+__copyright__ = "(C) 2012, Salvatore Larosa"
from .console import show_console # NOQA
from .console import init_options_widget
diff --git a/python/console/console.py b/python/console/console.py
index 9da2f97273e7..ba15c4460f1a 100644
--- a/python/console/console.py
+++ b/python/console/console.py
@@ -17,34 +17,50 @@
***************************************************************************/
Some portions of code were taken from https://code.google.com/p/pydee/
"""
+
import os
import subprocess
-from qgis.PyQt.QtCore import Qt, QTimer, QCoreApplication, QSize, QByteArray, QFileInfo, QUrl, QDir
-from qgis.PyQt.QtWidgets import QToolBar, QToolButton, QWidget, QSplitter, QTreeWidget, QAction, QFileDialog, QCheckBox, QSizePolicy, QMenu, QGridLayout, QApplication, QShortcut
-from qgis.PyQt.QtGui import QDesktopServices, QKeySequence
+from qgis.PyQt.QtCore import (
+ Qt,
+ QTimer,
+ QCoreApplication,
+ QSize,
+ QByteArray,
+ QFileInfo,
+ QUrl,
+ QDir,
+)
from qgis.PyQt.QtWidgets import (
- QVBoxLayout,
- QMessageBox
+ QToolBar,
+ QToolButton,
+ QWidget,
+ QSplitter,
+ QTreeWidget,
+ QAction,
+ QFileDialog,
+ QCheckBox,
+ QSizePolicy,
+ QMenu,
+ QGridLayout,
+ QApplication,
+ QShortcut,
)
+from qgis.PyQt.QtGui import QDesktopServices, QKeySequence
+from qgis.PyQt.QtWidgets import QVBoxLayout, QMessageBox
from qgis.utils import iface
from .console_sci import ShellScintilla
from .console_output import ShellOutputScintilla
from .console_editor import EditorTabWidget
from .console_settings import ConsoleOptionsFactory
-from qgis.core import (
- Qgis,
- QgsApplication,
- QgsSettings,
- QgsFileUtils
-)
+from qgis.core import Qgis, QgsApplication, QgsSettings, QgsFileUtils
from qgis.gui import (
QgsFilterLineEdit,
QgsHelp,
QgsDockWidget,
QgsGui,
QgsApplicationExitBlockerInterface,
- QgsCodeEditorDockWidget
+ QgsCodeEditorDockWidget,
)
from functools import partial
@@ -56,13 +72,15 @@
def show_console():
- """ called from QGIS to open the console """
+ """called from QGIS to open the console"""
global _console
if _console is None:
parent = iface.mainWindow() if iface else None
_console = PythonConsole(parent)
if iface:
- _console.visibilityChanged.connect(iface.actionShowPythonDialog().setChecked)
+ _console.visibilityChanged.connect(
+ iface.actionShowPythonDialog().setChecked
+ )
_console.show() # force show even if it was restored as hidden
# set focus to the console so the user can start typing
@@ -89,7 +107,7 @@ def console_displayhook(obj):
def init_options_widget():
- """ called from QGIS to add the console options widget """
+ """called from QGIS to add the console options widget"""
global _options_factory
_options_factory.setTitle(QCoreApplication.translate("PythonConsole", "Python"))
iface.registerOptionsWidgetFactory(_options_factory)
@@ -143,13 +161,14 @@ class PythonConsoleWidget(QWidget):
def __init__(self, parent=None):
QWidget.__init__(self, parent)
- self.setWindowTitle(QCoreApplication.translate("PythonConsole", "Python Console"))
+ self.setWindowTitle(
+ QCoreApplication.translate("PythonConsole", "Python Console")
+ )
self.shell = ShellScintilla(console_widget=self)
self.setFocusProxy(self.shell)
self.shell_output = ShellOutputScintilla(
- console_widget=self,
- shell_editor=self.shell
+ console_widget=self, shell_editor=self.shell
)
self.tabEditorWidget = EditorTabWidget(console_widget=self)
@@ -181,7 +200,7 @@ def __init__(self, parent=None):
self.listClassMethod = QTreeWidget(self.splitterObj)
self.listClassMethod.setColumnCount(2)
objInspLabel = QCoreApplication.translate("PythonConsole", "Object Inspector")
- self.listClassMethod.setHeaderLabels([objInspLabel, ''])
+ self.listClassMethod.setHeaderLabels([objInspLabel, ""])
self.listClassMethod.setColumnHidden(1, True)
self.listClassMethod.setAlternatingRowColors(True)
@@ -205,17 +224,23 @@ def __init__(self, parent=None):
self.openFileButton = QAction(self)
self.openFileButton.setCheckable(False)
self.openFileButton.setEnabled(True)
- self.openFileButton.setIcon(QgsApplication.getThemeIcon("mActionScriptOpen.svg"))
+ self.openFileButton.setIcon(
+ QgsApplication.getThemeIcon("mActionScriptOpen.svg")
+ )
self.openFileButton.setMenuRole(QAction.MenuRole.PreferencesRole)
self.openFileButton.setIconVisibleInMenu(True)
self.openFileButton.setToolTip(openFileBt)
self.openFileButton.setText(openFileBt)
- openExtEditorBt = QCoreApplication.translate("PythonConsole", "Open in External Editor")
+ openExtEditorBt = QCoreApplication.translate(
+ "PythonConsole", "Open in External Editor"
+ )
self.openInEditorButton = QAction(self)
self.openInEditorButton.setCheckable(False)
self.openInEditorButton.setEnabled(True)
- self.openInEditorButton.setIcon(QgsApplication.getThemeIcon("console/iconShowEditorConsole.svg"))
+ self.openInEditorButton.setIcon(
+ QgsApplication.getThemeIcon("console/iconShowEditorConsole.svg")
+ )
self.openInEditorButton.setMenuRole(QAction.MenuRole.PreferencesRole)
self.openInEditorButton.setIconVisibleInMenu(True)
self.openInEditorButton.setToolTip(openExtEditorBt)
@@ -235,7 +260,9 @@ def __init__(self, parent=None):
self.saveAsFileButton = QAction(self)
self.saveAsFileButton.setCheckable(False)
self.saveAsFileButton.setEnabled(True)
- self.saveAsFileButton.setIcon(QgsApplication.getThemeIcon("mActionFileSaveAs.svg"))
+ self.saveAsFileButton.setIcon(
+ QgsApplication.getThemeIcon("mActionFileSaveAs.svg")
+ )
self.saveAsFileButton.setMenuRole(QAction.MenuRole.PreferencesRole)
self.saveAsFileButton.setIconVisibleInMenu(True)
self.saveAsFileButton.setToolTip(saveAsFileBt)
@@ -255,7 +282,9 @@ def __init__(self, parent=None):
self.copyEditorButton = QAction(self)
self.copyEditorButton.setCheckable(False)
self.copyEditorButton.setEnabled(True)
- self.copyEditorButton.setIcon(QgsApplication.getThemeIcon("mActionEditCopy.svg"))
+ self.copyEditorButton.setIcon(
+ QgsApplication.getThemeIcon("mActionEditCopy.svg")
+ )
self.copyEditorButton.setMenuRole(QAction.MenuRole.PreferencesRole)
self.copyEditorButton.setIconVisibleInMenu(True)
self.copyEditorButton.setToolTip(copyEditorBt)
@@ -265,7 +294,9 @@ def __init__(self, parent=None):
self.pasteEditorButton = QAction(self)
self.pasteEditorButton.setCheckable(False)
self.pasteEditorButton.setEnabled(True)
- self.pasteEditorButton.setIcon(QgsApplication.getThemeIcon("mActionEditPaste.svg"))
+ self.pasteEditorButton.setIcon(
+ QgsApplication.getThemeIcon("mActionEditPaste.svg")
+ )
self.pasteEditorButton.setMenuRole(QAction.MenuRole.PreferencesRole)
self.pasteEditorButton.setIconVisibleInMenu(True)
self.pasteEditorButton.setToolTip(pasteEditorBt)
@@ -275,7 +306,9 @@ def __init__(self, parent=None):
self.runScriptEditorButton = QAction(self)
self.runScriptEditorButton.setCheckable(False)
self.runScriptEditorButton.setEnabled(True)
- self.runScriptEditorButton.setIcon(QgsApplication.getThemeIcon("mActionStart.svg"))
+ self.runScriptEditorButton.setIcon(
+ QgsApplication.getThemeIcon("mActionStart.svg")
+ )
self.runScriptEditorButton.setMenuRole(QAction.MenuRole.PreferencesRole)
self.runScriptEditorButton.setIconVisibleInMenu(True)
self.runScriptEditorButton.setToolTip(runScriptEditorBt)
@@ -286,7 +319,9 @@ def __init__(self, parent=None):
self.toggleCommentEditorButton = QAction(self)
self.toggleCommentEditorButton.setCheckable(False)
self.toggleCommentEditorButton.setEnabled(True)
- self.toggleCommentEditorButton.setIcon(QgsApplication.getThemeIcon("console/iconCommentEditorConsole.svg"))
+ self.toggleCommentEditorButton.setIcon(
+ QgsApplication.getThemeIcon("console/iconCommentEditorConsole.svg")
+ )
self.toggleCommentEditorButton.setMenuRole(QAction.MenuRole.PreferencesRole)
self.toggleCommentEditorButton.setIconVisibleInMenu(True)
self.toggleCommentEditorButton.setToolTip(toggleText + " Ctrl+: ")
@@ -297,10 +332,14 @@ def __init__(self, parent=None):
self.reformatCodeEditorButton = QAction(self)
self.reformatCodeEditorButton.setCheckable(False)
self.reformatCodeEditorButton.setEnabled(True)
- self.reformatCodeEditorButton.setIcon(QgsApplication.getThemeIcon("console/iconFormatCode.svg"))
+ self.reformatCodeEditorButton.setIcon(
+ QgsApplication.getThemeIcon("console/iconFormatCode.svg")
+ )
self.reformatCodeEditorButton.setMenuRole(QAction.MenuRole.PreferencesRole)
self.reformatCodeEditorButton.setIconVisibleInMenu(True)
- self.reformatCodeEditorButton.setToolTip(reformatCodeText + " Ctrl+Alt+F ")
+ self.reformatCodeEditorButton.setToolTip(
+ reformatCodeText + " Ctrl+Alt+F "
+ )
self.reformatCodeEditorButton.setShortcut("Ctrl+Alt+F")
self.reformatCodeEditorButton.setText(reformatCodeText)
@@ -308,9 +347,12 @@ def __init__(self, parent=None):
objList = QCoreApplication.translate("PythonConsole", "Object Inspector…")
self.objectListButton = QAction(self)
self.objectListButton.setCheckable(True)
- self.objectListButton.setEnabled(QgsSettings().value("pythonConsole/enableObjectInsp",
- False, type=bool))
- self.objectListButton.setIcon(QgsApplication.getThemeIcon("console/iconClassBrowserConsole.svg"))
+ self.objectListButton.setEnabled(
+ QgsSettings().value("pythonConsole/enableObjectInsp", False, type=bool)
+ )
+ self.objectListButton.setIcon(
+ QgsApplication.getThemeIcon("console/iconClassBrowserConsole.svg")
+ )
self.objectListButton.setMenuRole(QAction.MenuRole.PreferencesRole)
self.objectListButton.setIconVisibleInMenu(True)
self.objectListButton.setToolTip(objList)
@@ -321,7 +363,9 @@ def __init__(self, parent=None):
self.find_text_action = QAction(self)
self.find_text_action.setCheckable(True)
self.find_text_action.setEnabled(True)
- self.find_text_action.setIcon(QgsApplication.getThemeIcon("console/iconSearchEditorConsole.svg"))
+ self.find_text_action.setIcon(
+ QgsApplication.getThemeIcon("console/iconSearchEditorConsole.svg")
+ )
self.find_text_action.setMenuRole(QAction.MenuRole.PreferencesRole)
self.find_text_action.setIconVisibleInMenu(True)
self.find_text_action.setToolTip(findText)
@@ -330,9 +374,7 @@ def __init__(self, parent=None):
self.tabEditorWidget.search_bar_toggled.connect(
self.find_text_action.setChecked
)
- self.find_text_action.toggled.connect(
- self.tabEditorWidget.toggle_search_bar
- )
+ self.find_text_action.toggled.connect(self.tabEditorWidget.toggle_search_bar)
# ----------------Toolbar Console-------------------------------------
@@ -341,7 +383,9 @@ def __init__(self, parent=None):
self.showEditorButton = QAction(self)
self.showEditorButton.setEnabled(True)
self.showEditorButton.setCheckable(True)
- self.showEditorButton.setIcon(QgsApplication.getThemeIcon("console/iconShowEditorConsole.svg"))
+ self.showEditorButton.setIcon(
+ QgsApplication.getThemeIcon("console/iconShowEditorConsole.svg")
+ )
self.showEditorButton.setMenuRole(QAction.MenuRole.PreferencesRole)
self.showEditorButton.setIconVisibleInMenu(True)
self.showEditorButton.setToolTip(showEditor)
@@ -351,7 +395,9 @@ def __init__(self, parent=None):
self.clearButton = QAction(self)
self.clearButton.setCheckable(False)
self.clearButton.setEnabled(True)
- self.clearButton.setIcon(QgsApplication.getThemeIcon("console/iconClearConsole.svg"))
+ self.clearButton.setIcon(
+ QgsApplication.getThemeIcon("console/iconClearConsole.svg")
+ )
self.clearButton.setMenuRole(QAction.MenuRole.PreferencesRole)
self.clearButton.setIconVisibleInMenu(True)
self.clearButton.setToolTip(clearBt)
@@ -361,7 +407,9 @@ def __init__(self, parent=None):
self.optionsButton = QAction(self)
self.optionsButton.setCheckable(False)
self.optionsButton.setEnabled(True)
- self.optionsButton.setIcon(QgsApplication.getThemeIcon("console/iconSettingsConsole.svg"))
+ self.optionsButton.setIcon(
+ QgsApplication.getThemeIcon("console/iconSettingsConsole.svg")
+ )
self.optionsButton.setMenuRole(QAction.MenuRole.PreferencesRole)
self.optionsButton.setIconVisibleInMenu(True)
self.optionsButton.setToolTip(optionsBt)
@@ -380,13 +428,19 @@ def __init__(self, parent=None):
# Help button
self.helpConsoleAction = QAction(self)
self.helpConsoleAction.setEnabled(True)
- self.helpConsoleAction.setText(QCoreApplication.translate("PythonConsole", "Python Console Help"))
+ self.helpConsoleAction.setText(
+ QCoreApplication.translate("PythonConsole", "Python Console Help")
+ )
self.helpAPIAction = QAction(self)
self.helpAPIAction.setEnabled(True)
- self.helpAPIAction.setText(QCoreApplication.translate("PythonConsole", "PyQGIS API Documentation"))
+ self.helpAPIAction.setText(
+ QCoreApplication.translate("PythonConsole", "PyQGIS API Documentation")
+ )
self.helpCookbookAction = QAction(self)
self.helpCookbookAction.setEnabled(True)
- self.helpCookbookAction.setText(QCoreApplication.translate("PythonConsole", "PyQGIS Cookbook"))
+ self.helpCookbookAction.setText(
+ QCoreApplication.translate("PythonConsole", "PyQGIS Cookbook")
+ )
self.helpMenu = QMenu(self)
self.helpMenu.addAction(self.helpConsoleAction)
@@ -397,7 +451,9 @@ def __init__(self, parent=None):
self.helpButton = QToolButton(self)
self.helpButton.setPopupMode(QToolButton.ToolButtonPopupMode.InstantPopup)
self.helpButton.setEnabled(True)
- self.helpButton.setIcon(QgsApplication.getThemeIcon("console/iconHelpConsole.svg"))
+ self.helpButton.setIcon(
+ QgsApplication.getThemeIcon("console/iconHelpConsole.svg")
+ )
self.helpButton.setToolTip(helpBt)
self.helpButton.setMenu(self.helpMenu)
@@ -457,16 +513,22 @@ def __init__(self, parent=None):
sizePolicy = QSizePolicy(QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Preferred)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
- sizePolicy.setHeightForWidth(self.widgetButtonEditor.sizePolicy().hasHeightForWidth())
+ sizePolicy.setHeightForWidth(
+ self.widgetButtonEditor.sizePolicy().hasHeightForWidth()
+ )
self.widgetButtonEditor.setSizePolicy(sizePolicy)
- sizePolicy = QSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding)
+ sizePolicy = QSizePolicy(
+ QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding
+ )
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.shell_output.sizePolicy().hasHeightForWidth())
self.shell_output.setSizePolicy(sizePolicy)
- self.shell_output.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAsNeeded)
+ self.shell_output.setVerticalScrollBarPolicy(
+ Qt.ScrollBarPolicy.ScrollBarAsNeeded
+ )
self.shell.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAsNeeded)
# ------------ Layout -------------------------------
@@ -523,9 +585,17 @@ def allowExit(self):
tab_index = tab_count - i - 1
tab_widget = self.tabEditorWidget.widget(tab_index)
if tab_widget.isModified():
- ret = QMessageBox.question(self, self.tr("Save {}").format(self.tabEditorWidget.tabText(tab_index)),
- self.tr("There are unsaved changes in this script. Do you want to keep those?"),
- QMessageBox.StandardButton.Save | QMessageBox.StandardButton.Cancel | QMessageBox.StandardButton.Discard, QMessageBox.StandardButton.Cancel)
+ ret = QMessageBox.question(
+ self,
+ self.tr("Save {}").format(self.tabEditorWidget.tabText(tab_index)),
+ self.tr(
+ "There are unsaved changes in this script. Do you want to keep those?"
+ ),
+ QMessageBox.StandardButton.Save
+ | QMessageBox.StandardButton.Cancel
+ | QMessageBox.StandardButton.Discard,
+ QMessageBox.StandardButton.Cancel,
+ )
if ret == QMessageBox.StandardButton.Save:
tab_widget.save()
if tab_widget.isModified():
@@ -545,14 +615,14 @@ def _toggleFind(self):
def onClickGoToLine(self, item, column):
tabEditor = self.tabEditorWidget.currentWidget()
- if item.text(1) == 'syntaxError':
+ if item.text(1) == "syntaxError":
check = tabEditor.syntaxCheck()
if check and not tabEditor.isReadOnly():
self.tabEditorWidget.currentWidget().save()
return
linenr = int(item.text(1))
itemName = str(item.text(0))
- charPos = itemName.find(' ')
+ charPos = itemName.find(" ")
if charPos != -1:
objName = itemName[0:charPos]
else:
@@ -595,7 +665,8 @@ def openScriptFile(self):
lastDirPath = settings.value("pythonConsole/lastDirPath", QDir.homePath())
openFileTr = QCoreApplication.translate("PythonConsole", "Open File")
fileList, selected_filter = QFileDialog.getOpenFileNames(
- self, openFileTr, lastDirPath, "Script file (*.py)")
+ self, openFileTr, lastDirPath, "Script file (*.py)"
+ )
if fileList:
for pyFile in fileList:
for i in range(self.tabEditorWidget.count()):
@@ -609,16 +680,16 @@ def openScriptFile(self):
lastDirPath = QFileInfo(pyFile).path()
settings.setValue("pythonConsole/lastDirPath", pyFile)
- self.updateTabListScript(pyFile, action='append')
+ self.updateTabListScript(pyFile, action="append")
def saveScriptFile(self):
tabWidget = self.tabEditorWidget.currentWidget()
try:
tabWidget.save()
- except (IOError, OSError) as error:
- msgText = QCoreApplication.translate('PythonConsole',
- 'The file {0} could not be saved. Error: {1}').format(tabWidget.file_path(),
- error.strerror)
+ except OSError as error:
+ msgText = QCoreApplication.translate(
+ "PythonConsole", "The file {0} could not be saved. Error: {1}"
+ ).format(tabWidget.file_path(), error.strerror)
self.callWidgetMessageBarEditor(msgText, Qgis.MessageLevel.Critical)
def saveAsScriptFile(self, index=None):
@@ -626,9 +697,8 @@ def saveAsScriptFile(self, index=None):
if not index:
index = self.tabEditorWidget.currentIndex()
if not tabWidget.file_path():
- fileName = self.tabEditorWidget.tabText(index).replace('*', '')
- fileName = QgsFileUtils.ensureFileNameHasExtension(fileName,
- ['py'])
+ fileName = self.tabEditorWidget.tabText(index).replace("*", "")
+ fileName = QgsFileUtils.ensureFileNameHasExtension(fileName, ["py"])
folder = QgsSettings().value("pythonConsole/lastDirPath", QDir.homePath())
pathFileName = os.path.join(folder, fileName)
fileNone = True
@@ -636,18 +706,19 @@ def saveAsScriptFile(self, index=None):
pathFileName = tabWidget.file_path()
fileNone = False
saveAsFileTr = QCoreApplication.translate("PythonConsole", "Save File As")
- filename, filter = QFileDialog.getSaveFileName(self,
- saveAsFileTr,
- pathFileName, "Script file (*.py)")
+ filename, filter = QFileDialog.getSaveFileName(
+ self, saveAsFileTr, pathFileName, "Script file (*.py)"
+ )
if filename:
- filename = QgsFileUtils.ensureFileNameHasExtension(filename, ['py'])
+ filename = QgsFileUtils.ensureFileNameHasExtension(filename, ["py"])
try:
tabWidget.save(filename)
- except (IOError, OSError) as error:
- msgText = QCoreApplication.translate('PythonConsole',
- 'The file {0} could not be saved. Error: {1}').format(tabWidget.file_path(),
- error.strerror)
+ except OSError as error:
+ msgText = QCoreApplication.translate(
+ "PythonConsole",
+ "The file {0} could not be saved. Error: {1}",
+ ).format(tabWidget.file_path(), error.strerror)
self.callWidgetMessageBarEditor(msgText, Qgis.MessageLevel.Critical)
if fileNone:
tabWidget.set_file_path(None)
@@ -656,23 +727,29 @@ def saveAsScriptFile(self, index=None):
return
if not fileNone:
- self.updateTabListScript(pathFileName, action='remove')
+ self.updateTabListScript(pathFileName, action="remove")
def openHelpConsole(self):
QgsHelp.openHelp("plugins/python_console.html")
def openHelpAPI(self):
- m = re.search(r'^([0-9]+)\.([0-9]+)\.', Qgis.QGIS_VERSION)
+ m = re.search(r"^([0-9]+)\.([0-9]+)\.", Qgis.QGIS_VERSION)
if m:
- QDesktopServices.openUrl(QUrl('https://qgis.org/pyqgis/{}.{}/'.format(m.group(1), m.group(2))))
+ QDesktopServices.openUrl(
+ QUrl(f"https://qgis.org/pyqgis/{m.group(1)}.{m.group(2)}/")
+ )
def openHelpCookbook(self):
- m = re.search(r'^([0-9]+)\.([0-9]+)\.', Qgis.QGIS_VERSION)
+ m = re.search(r"^([0-9]+)\.([0-9]+)\.", Qgis.QGIS_VERSION)
if m:
- QDesktopServices.openUrl(QUrl('https://docs.qgis.org/{}.{}/en/docs/pyqgis_developer_cookbook/index.html'.format(m.group(1), m.group(2))))
+ QDesktopServices.openUrl(
+ QUrl(
+ f"https://docs.qgis.org/{m.group(1)}.{m.group(2)}/en/docs/pyqgis_developer_cookbook/index.html"
+ )
+ )
def openSettings(self):
- iface.showOptionsDialog(iface.mainWindow(), currentPage='consoleOptions')
+ iface.showOptionsDialog(iface.mainWindow(), currentPage="consoleOptions")
def updateSettings(self):
self.shell.refreshSettingsShell()
@@ -686,23 +763,24 @@ def callWidgetMessageBarEditor(self, text, level):
self.tabEditorWidget.showMessage(text, level)
def updateTabListScript(self, script, action=None):
- if action == 'remove':
+ if action == "remove":
self.tabListScript.remove(script)
- elif action == 'append':
+ elif action == "append":
if not self.tabListScript:
self.tabListScript = []
if script not in self.tabListScript:
self.tabListScript.append(script)
else:
self.tabListScript = []
- QgsSettings().setValue("pythonConsole/tabScripts",
- self.tabListScript)
+ QgsSettings().setValue("pythonConsole/tabScripts", self.tabListScript)
def saveSettingsConsole(self):
settings = QgsSettings()
settings.setValue("pythonConsole/splitterConsole", self.splitter.saveState())
settings.setValue("pythonConsole/splitterObj", self.splitterObj.saveState())
- settings.setValue("pythonConsole/splitterEditor", self.splitterEditor.saveState())
+ settings.setValue(
+ "pythonConsole/splitterEditor", self.splitterEditor.saveState()
+ )
self.shell.writeHistoryFile()
@@ -710,12 +788,18 @@ def restoreSettingsConsole(self):
settings = QgsSettings()
storedTabScripts = settings.value("pythonConsole/tabScripts", [])
self.tabListScript = storedTabScripts
- self.splitter.restoreState(settings.value("pythonConsole/splitterConsole", QByteArray()))
- self.splitterEditor.restoreState(settings.value("pythonConsole/splitterEditor", QByteArray()))
- self.splitterObj.restoreState(settings.value("pythonConsole/splitterObj", QByteArray()))
+ self.splitter.restoreState(
+ settings.value("pythonConsole/splitterConsole", QByteArray())
+ )
+ self.splitterEditor.restoreState(
+ settings.value("pythonConsole/splitterEditor", QByteArray())
+ )
+ self.splitterObj.restoreState(
+ settings.value("pythonConsole/splitterObj", QByteArray())
+ )
-if __name__ == '__main__':
+if __name__ == "__main__":
a = QApplication(sys.argv)
console = PythonConsoleWidget()
console.show()
diff --git a/python/console/console_compile_apis.py b/python/console/console_compile_apis.py
index 9ea869646b34..3b112270b54c 100644
--- a/python/console/console_compile_apis.py
+++ b/python/console/console_compile_apis.py
@@ -27,7 +27,9 @@
from qgis.PyQt.QtWidgets import QDialog, QDialogButtonBox
from qgis.PyQt.QtCore import QCoreApplication
-Ui_APIsDialogPythonConsole, _ = uic.loadUiType(Path(__file__).parent / 'console_compile_apis.ui')
+Ui_APIsDialogPythonConsole, _ = uic.loadUiType(
+ Path(__file__).parent / "console_compile_apis.ui"
+)
class PrepareAPIDialog(QDialog):
@@ -61,21 +63,24 @@ def _preparationFinished(self):
self._clearLexer()
if os.path.exists(self._pap_file):
os.remove(self._pap_file)
- self.ui.label.setText(QCoreApplication.translate("PythonConsole", "Saving prepared file…"))
+ self.ui.label.setText(
+ QCoreApplication.translate("PythonConsole", "Saving prepared file…")
+ )
prepd = self._api.savePrepared(self._pap_file)
rslt = self.tr("Error")
if prepd:
rslt = QCoreApplication.translate("PythonConsole", "Saved")
- self.ui.label.setText('{0} {1}'.format(self.ui.label.text(), rslt))
+ self.ui.label.setText(f"{self.ui.label.text()} {rslt}")
self._api = None
self.ui.progressBar.setVisible(False)
self.ui.buttonBox.button(QDialogButtonBox.StandardButton.Cancel).setText(
- QCoreApplication.translate("PythonConsole", "Done"))
+ QCoreApplication.translate("PythonConsole", "Done")
+ )
self.adjustSize()
def prepareAPI(self):
# self.ui.textEdit_Qsci.setLexer(0)
- exec('self.qlexer = {0}(self.ui.textEdit_Qsci)'.format(self._api_lexer))
+ exec(f"self.qlexer = {self._api_lexer}(self.ui.textEdit_Qsci)")
# self.ui.textEdit_Qsci.setLexer(self.qlexer)
self._api = QsciAPIs(self.qlexer)
self._api.apiPreparationFinished.connect(self._preparationFinished)
@@ -86,9 +91,13 @@ def prepareAPI(self):
except Exception as err:
self._api = None
self._clearLexer()
- self.ui.label.setText(QCoreApplication.translate("PythonConsole", "Error preparing file…"))
+ self.ui.label.setText(
+ QCoreApplication.translate("PythonConsole", "Error preparing file…")
+ )
self.ui.progressBar.setVisible(False)
self.ui.plainTextEdit.setVisible(True)
self.ui.plainTextEdit.insertPlainText(err)
- self.ui.buttonBox.button(QDialogButtonBox.StandardButton.Cancel).setText(self.tr("Done"))
+ self.ui.buttonBox.button(QDialogButtonBox.StandardButton.Cancel).setText(
+ self.tr("Done")
+ )
self.adjustSize()
diff --git a/python/console/console_editor.py b/python/console/console_editor.py
index b1929e1478ed..c7e868372c52 100644
--- a/python/console/console_editor.py
+++ b/python/console/console_editor.py
@@ -17,6 +17,7 @@
***************************************************************************/
Some portions of code were taken from https://code.google.com/p/pydee/
"""
+
from __future__ import annotations
import codecs
@@ -26,20 +27,13 @@
import re
import sys
import tempfile
-from typing import (
- Optional,
- TYPE_CHECKING
-)
+from typing import Optional, TYPE_CHECKING
from functools import partial
from operator import itemgetter
from pathlib import Path
from qgis.core import Qgis, QgsApplication, QgsBlockingNetworkRequest, QgsSettings
-from qgis.gui import (
- QgsCodeEditorPython,
- QgsCodeEditorWidget,
- QgsMessageBar
-)
+from qgis.gui import QgsCodeEditorPython, QgsCodeEditorWidget, QgsMessageBar
from qgis.PyQt.Qsci import QsciScintilla
from qgis.PyQt.QtCore import (
@@ -52,7 +46,7 @@
QJsonDocument,
QSize,
Qt,
- QUrl
+ QUrl,
)
from qgis.PyQt.QtGui import QKeySequence
from qgis.PyQt.QtNetwork import QNetworkRequest
@@ -83,41 +77,57 @@ class Editor(QgsCodeEditorPython):
trigger_find = pyqtSignal()
- def __init__(self,
- editor_tab: EditorTab,
- console_widget: PythonConsoleWidget,
- tab_widget: EditorTabWidget):
+ def __init__(
+ self,
+ editor_tab: EditorTab,
+ console_widget: PythonConsoleWidget,
+ tab_widget: EditorTabWidget,
+ ):
super().__init__(editor_tab)
self.editor_tab: EditorTab = editor_tab
self.console_widget: PythonConsoleWidget = console_widget
self.tab_widget: EditorTabWidget = tab_widget
- self.code_editor_widget: Optional[QgsCodeEditorWidget] = None
+ self.code_editor_widget: QgsCodeEditorWidget | None = None
self.setMinimumHeight(120)
self.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAsNeeded)
# Disable default scintilla shortcuts
ctrl, shift = self.SCMOD_CTRL << 16, self.SCMOD_SHIFT << 16
- self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('T') + ctrl) # Switch current line with the next one
- self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('D') + ctrl) # Duplicate current line / selection
- self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('L') + ctrl) # Delete current line
- self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('L') + ctrl + shift)
+ self.SendScintilla(
+ QsciScintilla.SCI_CLEARCMDKEY, ord("T") + ctrl
+ ) # Switch current line with the next one
+ self.SendScintilla(
+ QsciScintilla.SCI_CLEARCMDKEY, ord("D") + ctrl
+ ) # Duplicate current line / selection
+ self.SendScintilla(
+ QsciScintilla.SCI_CLEARCMDKEY, ord("L") + ctrl
+ ) # Delete current line
+ self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord("L") + ctrl + shift)
# New QShortcut = ctrl+space/ctrl+alt+space for Autocomplete
- self.newShortcutCS = QShortcut(QKeySequence(Qt.Modifier.CTRL | Qt.Key.Key_Space), self)
+ self.newShortcutCS = QShortcut(
+ QKeySequence(Qt.Modifier.CTRL | Qt.Key.Key_Space), self
+ )
self.newShortcutCS.setContext(Qt.ShortcutContext.WidgetShortcut)
- self.redoScut = QShortcut(QKeySequence(Qt.Modifier.CTRL | Qt.Modifier.SHIFT | Qt.Key.Key_Z), self)
+ self.redoScut = QShortcut(
+ QKeySequence(Qt.Modifier.CTRL | Qt.Modifier.SHIFT | Qt.Key.Key_Z), self
+ )
self.redoScut.setContext(Qt.ShortcutContext.WidgetShortcut)
self.redoScut.activated.connect(self.redo)
self.newShortcutCS.activated.connect(self.autoComplete)
self.runScut = QShortcut(QKeySequence(Qt.Modifier.CTRL | Qt.Key.Key_E), self)
self.runScut.setContext(Qt.ShortcutContext.WidgetShortcut)
self.runScut.activated.connect(self.runSelectedCode) # spellok
- self.runScriptScut = QShortcut(QKeySequence(Qt.Modifier.SHIFT | Qt.Modifier.CTRL | Qt.Key.Key_E), self)
+ self.runScriptScut = QShortcut(
+ QKeySequence(Qt.Modifier.SHIFT | Qt.Modifier.CTRL | Qt.Key.Key_E), self
+ )
self.runScriptScut.setContext(Qt.ShortcutContext.WidgetShortcut)
self.runScriptScut.activated.connect(self.runScriptCode)
- self.syntaxCheckScut = QShortcut(QKeySequence(Qt.Modifier.CTRL | Qt.Key.Key_4), self)
+ self.syntaxCheckScut = QShortcut(
+ QKeySequence(Qt.Modifier.CTRL | Qt.Key.Key_4), self
+ )
self.syntaxCheckScut.setContext(Qt.ShortcutContext.WidgetShortcut)
self.syntaxCheckScut.activated.connect(self.syntaxCheck)
self.modificationChanged.connect(self.editor_tab.modified)
@@ -139,22 +149,26 @@ def settingsEditor(self):
def contextMenuEvent(self, e):
menu = QMenu(self)
menu.addAction(
- QCoreApplication.translate("PythonConsole", "Hide Editor"),
- self.hideEditor)
+ QCoreApplication.translate("PythonConsole", "Hide Editor"), self.hideEditor
+ )
menu.addSeparator()
- syntaxCheckAction = QAction(QgsApplication.getThemeIcon("console/iconSyntaxErrorConsole.svg"),
- QCoreApplication.translate("PythonConsole", "Check Syntax"),
- menu)
+ syntaxCheckAction = QAction(
+ QgsApplication.getThemeIcon("console/iconSyntaxErrorConsole.svg"),
+ QCoreApplication.translate("PythonConsole", "Check Syntax"),
+ menu,
+ )
syntaxCheckAction.triggered.connect(self.syntaxCheck)
- syntaxCheckAction.setShortcut('Ctrl+4')
+ syntaxCheckAction.setShortcut("Ctrl+4")
menu.addAction(syntaxCheckAction)
- runSelected = QAction(QgsApplication.getThemeIcon("console/mIconRunConsole.svg"), # spellok
- QCoreApplication.translate("PythonConsole", "Run Selected"),
- menu)
+ runSelected = QAction(
+ QgsApplication.getThemeIcon("console/mIconRunConsole.svg"), # spellok
+ QCoreApplication.translate("PythonConsole", "Run Selected"),
+ menu,
+ )
runSelected.triggered.connect(self.runSelectedCode) # spellok
- runSelected.setShortcut('Ctrl+E') # spellok
+ runSelected.setShortcut("Ctrl+E") # spellok
menu.addAction(runSelected) # spellok
word = self.selectedText() or self.wordAtPoint(e.pos())
@@ -162,66 +176,85 @@ def contextMenuEvent(self, e):
context_help_action = QAction(
QgsApplication.getThemeIcon("mActionHelpContents.svg"),
QCoreApplication.translate("PythonConsole", "Context Help"),
- menu)
- context_help_action.triggered.connect(partial(self.console_widget.shell.showApiDocumentation, word, force_search=True))
- context_help_action.setShortcut('F1')
+ menu,
+ )
+ context_help_action.triggered.connect(
+ partial(
+ self.console_widget.shell.showApiDocumentation,
+ word,
+ force_search=True,
+ )
+ )
+ context_help_action.setShortcut("F1")
menu.addAction(context_help_action)
- start_action = QAction(QgsApplication.getThemeIcon("mActionStart.svg"),
- QCoreApplication.translate("PythonConsole", "Run Script"),
- menu)
+ start_action = QAction(
+ QgsApplication.getThemeIcon("mActionStart.svg"),
+ QCoreApplication.translate("PythonConsole", "Run Script"),
+ menu,
+ )
start_action.triggered.connect(self.runScriptCode)
- start_action.setShortcut('Ctrl+Shift+E')
+ start_action.setShortcut("Ctrl+Shift+E")
menu.addAction(start_action)
menu.addSeparator()
- undoAction = QAction(QgsApplication.getThemeIcon("mActionUndo.svg"),
- QCoreApplication.translate("PythonConsole", "Undo"),
- menu)
+ undoAction = QAction(
+ QgsApplication.getThemeIcon("mActionUndo.svg"),
+ QCoreApplication.translate("PythonConsole", "Undo"),
+ menu,
+ )
undoAction.triggered.connect(self.undo)
undoAction.setShortcut(QKeySequence.StandardKey.Undo)
menu.addAction(undoAction)
- redoAction = QAction(QgsApplication.getThemeIcon("mActionRedo.svg"),
- QCoreApplication.translate("PythonConsole", "Redo"),
- menu)
+ redoAction = QAction(
+ QgsApplication.getThemeIcon("mActionRedo.svg"),
+ QCoreApplication.translate("PythonConsole", "Redo"),
+ menu,
+ )
redoAction.triggered.connect(self.redo)
- redoAction.setShortcut('Ctrl+Shift+Z')
+ redoAction.setShortcut("Ctrl+Shift+Z")
menu.addAction(redoAction)
menu.addSeparator()
find_action = QAction(
QgsApplication.getThemeIcon("console/iconSearchEditorConsole.svg"),
QCoreApplication.translate("PythonConsole", "Find Text"),
- menu)
+ menu,
+ )
find_action.triggered.connect(self.trigger_find)
menu.addAction(find_action)
cutAction = QAction(
QgsApplication.getThemeIcon("mActionEditCut.svg"),
QCoreApplication.translate("PythonConsole", "Cut"),
- menu)
+ menu,
+ )
cutAction.triggered.connect(self.cut)
cutAction.setShortcut(QKeySequence.StandardKey.Cut)
menu.addAction(cutAction)
- copyAction = QAction(QgsApplication.getThemeIcon("mActionEditCopy.svg"),
- QCoreApplication.translate("PythonConsole", "Copy"),
- menu)
+ copyAction = QAction(
+ QgsApplication.getThemeIcon("mActionEditCopy.svg"),
+ QCoreApplication.translate("PythonConsole", "Copy"),
+ menu,
+ )
copyAction.triggered.connect(self.copy)
copyAction.setShortcut(QKeySequence.StandardKey.Copy)
menu.addAction(copyAction)
- pasteAction = QAction(QgsApplication.getThemeIcon("mActionEditPaste.svg"),
- QCoreApplication.translate("PythonConsole", "Paste"),
- menu)
+ pasteAction = QAction(
+ QgsApplication.getThemeIcon("mActionEditPaste.svg"),
+ QCoreApplication.translate("PythonConsole", "Paste"),
+ menu,
+ )
pasteAction.triggered.connect(self.paste)
pasteAction.setShortcut(QKeySequence.StandardKey.Paste)
menu.addAction(pasteAction)
selectAllAction = QAction(
- QCoreApplication.translate("PythonConsole", "Select All"),
- menu)
+ QCoreApplication.translate("PythonConsole", "Select All"), menu
+ )
selectAllAction.triggered.connect(self.selectAll)
selectAllAction.setShortcut(QKeySequence.StandardKey.SelectAll)
menu.addAction(selectAllAction)
@@ -230,27 +263,38 @@ def contextMenuEvent(self, e):
toggle_comment_action = QAction(
QgsApplication.getThemeIcon("console/iconCommentEditorConsole.svg"),
QCoreApplication.translate("PythonConsole", "Toggle Comment"),
- menu)
+ menu,
+ )
toggle_comment_action.triggered.connect(self.toggleComment)
- toggle_comment_action.setShortcut('Ctrl+:')
+ toggle_comment_action.setShortcut("Ctrl+:")
menu.addAction(toggle_comment_action)
menu.addSeparator()
gist_menu = QMenu(self)
- gist_menu.setTitle(QCoreApplication.translate("PythonConsole", "Share on GitHub"))
+ gist_menu.setTitle(
+ QCoreApplication.translate("PythonConsole", "Share on GitHub")
+ )
gist_menu.setIcon(QgsApplication.getThemeIcon("console/iconCodepadConsole.svg"))
- gist_menu.addAction(QCoreApplication.translate("PythonConsole", "Secret Gist"),
- partial(self.shareOnGist, False))
- gist_menu.addAction(QCoreApplication.translate("PythonConsole", "Public Gist"),
- partial(self.shareOnGist, True))
+ gist_menu.addAction(
+ QCoreApplication.translate("PythonConsole", "Secret Gist"),
+ partial(self.shareOnGist, False),
+ )
+ gist_menu.addAction(
+ QCoreApplication.translate("PythonConsole", "Public Gist"),
+ partial(self.shareOnGist, True),
+ )
menu.addMenu(gist_menu)
- showCodeInspection = menu.addAction(QgsApplication.getThemeIcon("console/iconClassBrowserConsole.svg"),
- QCoreApplication.translate("PythonConsole", "Hide/Show Object Inspector"),
- self.objectListEditor)
+ showCodeInspection = menu.addAction(
+ QgsApplication.getThemeIcon("console/iconClassBrowserConsole.svg"),
+ QCoreApplication.translate("PythonConsole", "Hide/Show Object Inspector"),
+ self.objectListEditor,
+ )
menu.addSeparator()
- menu.addAction(QgsApplication.getThemeIcon("console/iconSettingsConsole.svg"),
- QCoreApplication.translate("PythonConsole", "Options…"),
- self.console_widget.openSettings)
+ menu.addAction(
+ QgsApplication.getThemeIcon("console/iconSettingsConsole.svg"),
+ QCoreApplication.translate("PythonConsole", "Options…"),
+ self.console_widget.openSettings,
+ )
syntaxCheckAction.setEnabled(False)
pasteAction.setEnabled(False)
cutAction.setEnabled(False)
@@ -264,7 +308,7 @@ def contextMenuEvent(self, e):
runSelected.setEnabled(True) # spellok
copyAction.setEnabled(True)
cutAction.setEnabled(True)
- if not self.text() == '':
+ if not self.text() == "":
selectAllAction.setEnabled(True)
syntaxCheckAction.setEnabled(True)
if self.isUndoAvailable():
@@ -273,8 +317,7 @@ def contextMenuEvent(self, e):
redoAction.setEnabled(True)
if QApplication.clipboard().text():
pasteAction.setEnabled(True)
- if QgsSettings().value("pythonConsole/enableObjectInsp",
- False, type=bool):
+ if QgsSettings().value("pythonConsole/enableObjectInsp", False, type=bool):
showCodeInspection.setEnabled(True)
menu.exec(self.mapToGlobal(e.pos()))
@@ -297,7 +340,7 @@ def hideEditor(self):
def createTempFile(self):
name = tempfile.NamedTemporaryFile(delete=False).name
# Need to use newline='' to avoid adding extra \r characters on Windows
- with open(name, 'w', encoding='utf-8', newline='') as f:
+ with open(name, "w", encoding="utf-8", newline="") as f:
f.write(self.text())
return name
@@ -305,8 +348,9 @@ def runScriptCode(self):
autoSave = QgsSettings().value("pythonConsole/autoSaveScript", False, type=bool)
filename = self.code_editor_widget.filePath()
filename_override = None
- msgEditorBlank = QCoreApplication.translate('PythonConsole',
- 'Hey, type something to run!')
+ msgEditorBlank = QCoreApplication.translate(
+ "PythonConsole", "Hey, type something to run!"
+ )
if filename is None:
if not self.isModified():
self.showMessage(msgEditorBlank)
@@ -319,8 +363,10 @@ def runScriptCode(self):
elif not filename or self.isModified():
# Create a new temp file if the file isn't already saved.
filename = self.createTempFile()
- filename_override = self.tab_widget.tabText(self.tab_widget.currentIndex())
- if filename_override.startswith('*'):
+ filename_override = self.tab_widget.tabText(
+ self.tab_widget.currentIndex()
+ )
+ if filename_override.startswith("*"):
filename_override = filename_override[1:]
deleteTempFile = True
@@ -342,10 +388,14 @@ def getTextFromEditor(self):
def goToLine(self, objName, linenr):
self.SendScintilla(QsciScintilla.SCI_GOTOLINE, linenr - 1)
- self.SendScintilla(QsciScintilla.SCI_SETTARGETSTART,
- self.SendScintilla(QsciScintilla.SCI_GETCURRENTPOS))
+ self.SendScintilla(
+ QsciScintilla.SCI_SETTARGETSTART,
+ self.SendScintilla(QsciScintilla.SCI_GETCURRENTPOS),
+ )
self.SendScintilla(QsciScintilla.SCI_SETTARGETEND, len(self.text()))
- pos = self.SendScintilla(QsciScintilla.SCI_SEARCHINTARGET, len(objName), objName)
+ pos = self.SendScintilla(
+ QsciScintilla.SCI_SEARCHINTARGET, len(objName), objName
+ )
index = pos - self.SendScintilla(QsciScintilla.SCI_GETCURRENTPOS)
# line, _ = self.getCursorPosition()
self.setSelection(linenr - 1, index, linenr - 1, index + len(objName))
@@ -373,11 +423,13 @@ def loaded_external_changes(self):
self.tab_widget.listObject(self.tab_widget.currentWidget())
def fileReadOnly(self):
- msgText = QCoreApplication.translate('PythonConsole',
- 'The file "{0}" is read only, please save to different file first.').format(self.code_editor_widget.filePath())
+ msgText = QCoreApplication.translate(
+ "PythonConsole",
+ 'The file "{0}" is read only, please save to different file first.',
+ ).format(self.code_editor_widget.filePath())
self.showMessage(msgText)
- def save(self, filename: Optional[str] = None):
+ def save(self, filename: str | None = None):
if self.isReadOnly():
return
@@ -386,13 +438,18 @@ def save(self, filename: Optional[str] = None):
index = self.tab_widget.indexOf(self.editor_tab)
if not filename and not self.code_editor_widget.filePath():
- saveTr = QCoreApplication.translate('PythonConsole',
- 'Python Console: Save file')
+ saveTr = QCoreApplication.translate(
+ "PythonConsole", "Python Console: Save file"
+ )
folder = QgsSettings().value("pythonConsole/lastDirPath", QDir.homePath())
- path, filter = QFileDialog().getSaveFileName(self,
- saveTr,
- os.path.join(folder, self.tab_widget.tabText(index).replace('*', '') + '.py'),
- "Script file (*.py)")
+ path, filter = QFileDialog().getSaveFileName(
+ self,
+ saveTr,
+ os.path.join(
+ folder, self.tab_widget.tabText(index).replace("*", "") + ".py"
+ ),
+ "Script file (*.py)",
+ )
# If the user didn't select a file, abort the save operation
if not path:
self.code_editor_widget.setFilePath(None)
@@ -401,29 +458,40 @@ def save(self, filename: Optional[str] = None):
self.code_editor_widget.save(filename)
- msgText = QCoreApplication.translate('PythonConsole',
- 'Script was correctly saved.')
+ msgText = QCoreApplication.translate(
+ "PythonConsole", "Script was correctly saved."
+ )
self.showMessage(msgText)
# Save the new contents
# Need to use newline='' to avoid adding extra \r characters on Windows
- with open(self.code_editor_widget.filePath(), 'w', encoding='utf-8', newline='') as f:
+ with open(
+ self.code_editor_widget.filePath(), "w", encoding="utf-8", newline=""
+ ) as f:
f.write(self.text())
- self.tab_widget.setTabTitle(index, Path(self.code_editor_widget.filePath()).name)
+ self.tab_widget.setTabTitle(
+ index, Path(self.code_editor_widget.filePath()).name
+ )
self.tab_widget.setTabToolTip(index, self.code_editor_widget.filePath())
self.setModified(False)
self.console_widget.saveFileButton.setEnabled(False)
- self.console_widget.updateTabListScript(self.code_editor_widget.filePath(), action='append')
+ self.console_widget.updateTabListScript(
+ self.code_editor_widget.filePath(), action="append"
+ )
self.tab_widget.listObject(self.editor_tab)
- QgsSettings().setValue("pythonConsole/lastDirPath",
- Path(self.code_editor_widget.filePath()).parent.as_posix())
+ QgsSettings().setValue(
+ "pythonConsole/lastDirPath",
+ Path(self.code_editor_widget.filePath()).parent.as_posix(),
+ )
def event(self, e):
- """ Used to override the Application shortcuts when the editor has focus """
+ """Used to override the Application shortcuts when the editor has focus"""
if e.type() == QEvent.Type.ShortcutOverride:
ctrl = e.modifiers() == Qt.KeyboardModifier.ControlModifier
- ctrl_shift = e.modifiers() == (Qt.KeyboardModifier.ControlModifier | Qt.KeyboardModifier.ShiftModifier)
+ ctrl_shift = e.modifiers() == (
+ Qt.KeyboardModifier.ControlModifier | Qt.KeyboardModifier.ShiftModifier
+ )
if (
(ctrl and e.key() == Qt.Key.Key_W)
or (ctrl_shift and e.key() == Qt.Key.Key_W)
@@ -439,7 +507,9 @@ def event(self, e):
def keyPressEvent(self, e):
ctrl = e.modifiers() == Qt.KeyboardModifier.ControlModifier
- ctrl_shift = e.modifiers() == (Qt.KeyboardModifier.ControlModifier | Qt.KeyboardModifier.ShiftModifier)
+ ctrl_shift = e.modifiers() == (
+ Qt.KeyboardModifier.ControlModifier | Qt.KeyboardModifier.ShiftModifier
+ )
# Ctrl+W: close current tab
if ctrl and e.key() == Qt.Key.Key_W:
@@ -463,10 +533,9 @@ def keyPressEvent(self, e):
super().keyPressEvent(e)
- def showMessage(self,
- text: str,
- title: Optional[str] = None,
- level=Qgis.MessageLevel.Info):
+ def showMessage(
+ self, text: str, title: str | None = None, level=Qgis.MessageLevel.Info
+ ):
self.editor_tab.showMessage(text, level, title=title)
@@ -474,29 +543,25 @@ class EditorTab(QWidget):
search_bar_toggled = pyqtSignal(bool)
- def __init__(self,
- tab_widget: EditorTabWidget,
- console_widget: PythonConsoleWidget,
- filename: Optional[str],
- read_only: bool):
+ def __init__(
+ self,
+ tab_widget: EditorTabWidget,
+ console_widget: PythonConsoleWidget,
+ filename: str | None,
+ read_only: bool,
+ ):
super().__init__(tab_widget)
self.tab_widget: EditorTabWidget = tab_widget
- self._editor = Editor(editor_tab=self,
- console_widget=console_widget,
- tab_widget=tab_widget)
-
- self._editor_code_widget = QgsCodeEditorWidget(
- self._editor
+ self._editor = Editor(
+ editor_tab=self, console_widget=console_widget, tab_widget=tab_widget
)
+
+ self._editor_code_widget = QgsCodeEditorWidget(self._editor)
self._editor.set_code_editor_widget(self._editor_code_widget)
- self._editor_code_widget.searchBarToggled.connect(
- self.search_bar_toggled
- )
+ self._editor_code_widget.searchBarToggled.connect(self.search_bar_toggled)
- self._editor.trigger_find.connect(
- self._editor_code_widget.triggerFind
- )
+ self._editor.trigger_find.connect(self._editor_code_widget.triggerFind)
if filename:
if QFileInfo(filename).exists():
@@ -511,7 +576,7 @@ def __init__(self,
def set_file_path(self, path: str):
self._editor_code_widget.setFilePath(path)
- def file_path(self) -> Optional[str]:
+ def file_path(self) -> str | None:
return self._editor_code_widget.filePath()
def open_in_external_editor(self):
@@ -542,14 +607,14 @@ def close(self):
self.tab_widget._removeTab(self, tab2index=True)
def __getattr__(self, name):
- """ Forward all missing attribute requests to the editor."""
+ """Forward all missing attribute requests to the editor."""
try:
return super().__getattr__(name)
except AttributeError:
return getattr(self._editor, name)
def __setattr__(self, name, value):
- """ Forward all missing attribute requests to the editor."""
+ """Forward all missing attribute requests to the editor."""
try:
return super().__setattr__(name, value)
except AttributeError:
@@ -571,38 +636,45 @@ def __init__(self, console_widget: PythonConsoleWidget):
# Layout for top frame (restore tabs)
self.layoutTopFrame = QGridLayout(self)
self.layoutTopFrame.setContentsMargins(0, 0, 0, 0)
- spacerItem = QSpacerItem(20, 40, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding)
+ spacerItem = QSpacerItem(
+ 20, 40, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding
+ )
self.layoutTopFrame.addItem(spacerItem, 1, 0, 1, 1)
self.topFrame = QFrame(self)
- self.topFrame.setStyleSheet('background-color: rgb(255, 255, 230);')
+ self.topFrame.setStyleSheet("background-color: rgb(255, 255, 230);")
self.topFrame.setFrameShape(QFrame.Shape.StyledPanel)
self.topFrame.setMinimumHeight(24)
self.layoutTopFrame2 = QGridLayout(self.topFrame)
self.layoutTopFrame2.setContentsMargins(0, 0, 0, 0)
- label = QCoreApplication.translate("PythonConsole",
- "Click on button to restore all tabs from last session.")
+ label = QCoreApplication.translate(
+ "PythonConsole", "Click on button to restore all tabs from last session."
+ )
self.label = QLabel(label)
self.restoreTabsButton = QToolButton()
- toolTipRestore = QCoreApplication.translate("PythonConsole",
- "Restore tabs")
+ toolTipRestore = QCoreApplication.translate("PythonConsole", "Restore tabs")
self.restoreTabsButton.setToolTip(toolTipRestore)
- self.restoreTabsButton.setIcon(QgsApplication.getThemeIcon("console/iconRestoreTabsConsole.svg"))
+ self.restoreTabsButton.setIcon(
+ QgsApplication.getThemeIcon("console/iconRestoreTabsConsole.svg")
+ )
self.restoreTabsButton.setIconSize(QSize(24, 24))
self.restoreTabsButton.setAutoRaise(True)
self.restoreTabsButton.setCursor(Qt.CursorShape.PointingHandCursor)
- self.restoreTabsButton.setStyleSheet('QToolButton:hover{border: none } \
- QToolButton:pressed{border: none}')
+ self.restoreTabsButton.setStyleSheet(
+ "QToolButton:hover{border: none } \
+ QToolButton:pressed{border: none}"
+ )
self.clButton = QToolButton()
- toolTipClose = QCoreApplication.translate("PythonConsole",
- "Close")
+ toolTipClose = QCoreApplication.translate("PythonConsole", "Close")
self.clButton.setToolTip(toolTipClose)
self.clButton.setIcon(QgsApplication.getThemeIcon("/mIconClose.svg"))
self.clButton.setIconSize(QSize(18, 18))
self.clButton.setCursor(Qt.CursorShape.PointingHandCursor)
- self.clButton.setStyleSheet('QToolButton:hover{border: none } \
- QToolButton:pressed{border: none}')
+ self.clButton.setStyleSheet(
+ "QToolButton:hover{border: none } \
+ QToolButton:pressed{border: none}"
+ )
self.clButton.setAutoRaise(True)
sizePolicy = QSizePolicy(QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Fixed)
@@ -617,7 +689,7 @@ def __init__(self, console_widget: PythonConsoleWidget):
self.clButton.clicked.connect(self.closeRestore)
# Fixes #7653
- if sys.platform != 'darwin':
+ if sys.platform != "darwin":
self.setDocumentMode(True)
self.setMovable(True)
@@ -629,10 +701,13 @@ def __init__(self, console_widget: PythonConsoleWidget):
self.fileTabMenu.aboutToShow.connect(self.showFileTabMenu)
self.fileTabMenu.triggered.connect(self.showFileTabMenuTriggered)
self.fileTabButton = QToolButton()
- txtToolTipMenuFile = QCoreApplication.translate("PythonConsole",
- "List all tabs")
+ txtToolTipMenuFile = QCoreApplication.translate(
+ "PythonConsole", "List all tabs"
+ )
self.fileTabButton.setToolTip(txtToolTipMenuFile)
- self.fileTabButton.setIcon(QgsApplication.getThemeIcon("console/iconFileTabsMenuConsole.svg"))
+ self.fileTabButton.setIcon(
+ QgsApplication.getThemeIcon("console/iconFileTabsMenuConsole.svg")
+ )
self.fileTabButton.setIconSize(QSize(24, 24))
self.fileTabButton.setAutoRaise(True)
self.fileTabButton.setPopupMode(QToolButton.ToolButtonPopupMode.InstantPopup)
@@ -643,26 +718,24 @@ def __init__(self, console_widget: PythonConsoleWidget):
# New Editor button
self.newTabButton = QToolButton()
- txtToolTipNewTab = QCoreApplication.translate("PythonConsole",
- "New Editor")
+ txtToolTipNewTab = QCoreApplication.translate("PythonConsole", "New Editor")
self.newTabButton.setToolTip(txtToolTipNewTab)
self.newTabButton.setAutoRaise(True)
- self.newTabButton.setIcon(QgsApplication.getThemeIcon("console/iconNewTabEditorConsole.svg"))
+ self.newTabButton.setIcon(
+ QgsApplication.getThemeIcon("console/iconNewTabEditorConsole.svg")
+ )
self.newTabButton.setIconSize(QSize(24, 24))
self.setCornerWidget(self.newTabButton, Qt.Corner.TopLeftCorner)
self.newTabButton.clicked.connect(self.newTabEditor)
def _currentWidgetChanged(self, tab):
- if QgsSettings().value("pythonConsole/enableObjectInsp",
- False, type=bool):
+ if QgsSettings().value("pythonConsole/enableObjectInsp", False, type=bool):
self.listObject(tab)
self.changeLastDirPath(tab)
self.enableSaveIfModified(tab)
if self.currentWidget():
- self.search_bar_toggled.emit(
- self.currentWidget().search_bar_visible()
- )
+ self.search_bar_toggled.emit(self.currentWidget().search_bar_visible())
def toggle_search_bar(self, visible: bool):
"""
@@ -682,24 +755,26 @@ def contextMenuEvent(self, e):
menu.addSeparator()
menu.addAction(
QCoreApplication.translate("PythonConsole", "New Editor"),
- self.newTabEditor)
+ self.newTabEditor,
+ )
menu.addSeparator()
closeTabAction = menu.addAction(
- QCoreApplication.translate("PythonConsole", "Close Tab"),
- cW.close)
+ QCoreApplication.translate("PythonConsole", "Close Tab"), cW.close
+ )
closeAllTabAction = menu.addAction(
- QCoreApplication.translate("PythonConsole", "Close All"),
- self.closeAll)
+ QCoreApplication.translate("PythonConsole", "Close All"), self.closeAll
+ )
closeOthersTabAction = menu.addAction(
QCoreApplication.translate("PythonConsole", "Close Others"),
- self.closeOthers)
+ self.closeOthers,
+ )
menu.addSeparator()
saveAction = menu.addAction(
- QCoreApplication.translate("PythonConsole", "Save"),
- cW.save)
+ QCoreApplication.translate("PythonConsole", "Save"), cW.save
+ )
menu.addAction(
- QCoreApplication.translate("PythonConsole", "Save As"),
- self.saveAs)
+ QCoreApplication.translate("PythonConsole", "Save As"), self.saveAs
+ )
closeTabAction.setEnabled(False)
closeAllTabAction.setEnabled(False)
closeOthersTabAction.setEnabled(False)
@@ -723,7 +798,9 @@ def closeAll(self):
for i in range(countTab - 1, 0, -1):
self._removeTab(i)
- self.newTabEditor(tabName=QCoreApplication.translate("PythonConsole", "Untitled-0"))
+ self.newTabEditor(
+ tabName=QCoreApplication.translate("PythonConsole", "Untitled-0")
+ )
self._removeTab(0)
def saveAs(self):
@@ -739,31 +816,35 @@ def enableToolBarEditor(self, enable):
enable = False
self.console_widget.toolBarEditor.setEnabled(enable)
- def newTabEditor(self, tabName=None, filename: Optional[str] = None):
+ def newTabEditor(self, tabName=None, filename: str | None = None):
read_only = False
if filename:
read_only = not QFileInfo(filename).isWritable()
try:
- fn = codecs.open(filename, "rb", encoding='utf-8')
+ fn = codecs.open(filename, "rb", encoding="utf-8")
fn.read()
fn.close()
- except IOError as error:
- IOErrorTr = QCoreApplication.translate('PythonConsole',
- 'The file {0} could not be opened. Error: {1}\n').format(filename,
- error.strerror)
- print('## Error: ')
+ except OSError as error:
+ IOErrorTr = QCoreApplication.translate(
+ "PythonConsole", "The file {0} could not be opened. Error: {1}\n"
+ ).format(filename, error.strerror)
+ print("## Error: ")
sys.stderr.write(IOErrorTr)
return
nr = self.count()
if not tabName:
- tabName = QCoreApplication.translate('PythonConsole', 'Untitled-{0}').format(nr)
- tab = EditorTab(tab_widget=self,
- console_widget=self.console_widget,
- filename=filename,
- read_only=read_only)
- self.iconTab = QgsApplication.getThemeIcon('console/iconTabEditorConsole.svg')
- self.addTab(tab, self.iconTab, tabName + ' (ro)' if read_only else tabName)
+ tabName = QCoreApplication.translate(
+ "PythonConsole", "Untitled-{0}"
+ ).format(nr)
+ tab = EditorTab(
+ tab_widget=self,
+ console_widget=self.console_widget,
+ filename=filename,
+ read_only=read_only,
+ )
+ self.iconTab = QgsApplication.getThemeIcon("console/iconTabEditorConsole.svg")
+ self.addTab(tab, self.iconTab, tabName + " (ro)" if read_only else tabName)
self.setCurrentWidget(tab)
if filename:
self.setTabToolTip(self.currentIndex(), filename)
@@ -781,7 +862,7 @@ def _tab_search_bar_toggled(self, visible: bool):
def tabModified(self, tab, modified):
index = self.indexOf(tab)
s = self.tabText(index)
- self.setTabTitle(index, '*{}'.format(s) if modified else re.sub(r'^(\*)', '', s))
+ self.setTabTitle(index, f"*{s}" if modified else re.sub(r"^(\*)", "", s))
self.console_widget.saveFileButton.setEnabled(modified)
def setTabTitle(self, tab, title):
@@ -792,25 +873,37 @@ def _removeTab(self, tab, tab2index=False):
tab = self.indexOf(tab)
editorTab = self.widget(tab)
if editorTab.isModified():
- txtSaveOnRemove = QCoreApplication.translate("PythonConsole",
- "Python Console: Save File")
- txtMsgSaveOnRemove = QCoreApplication.translate("PythonConsole",
- "The file '{0}' has been modified, save changes?").format(self.tabText(tab))
- res = QMessageBox.question(self, txtSaveOnRemove,
- txtMsgSaveOnRemove,
- QMessageBox.StandardButton.Save | QMessageBox.StandardButton.Discard | QMessageBox.StandardButton.Cancel)
+ txtSaveOnRemove = QCoreApplication.translate(
+ "PythonConsole", "Python Console: Save File"
+ )
+ txtMsgSaveOnRemove = QCoreApplication.translate(
+ "PythonConsole",
+ "The file '{0}' has been modified, save changes?",
+ ).format(self.tabText(tab))
+ res = QMessageBox.question(
+ self,
+ txtSaveOnRemove,
+ txtMsgSaveOnRemove,
+ QMessageBox.StandardButton.Save
+ | QMessageBox.StandardButton.Discard
+ | QMessageBox.StandardButton.Cancel,
+ )
if res == QMessageBox.StandardButton.Cancel:
return
if res == QMessageBox.StandardButton.Save:
editorTab.save()
if editorTab.code_editor_widget.filePath():
- self.console_widget.updateTabListScript(editorTab.code_editor_widget.filePath(), action='remove')
+ self.console_widget.updateTabListScript(
+ editorTab.code_editor_widget.filePath(), action="remove"
+ )
self.removeTab(tab)
if self.count() < 1:
self.newTabEditor()
else:
if editorTab.code_editor_widget.filePath():
- self.console_widget.updateTabListScript(editorTab.code_editor_widget.filePath(), action='remove')
+ self.console_widget.updateTabListScript(
+ editorTab.code_editor_widget.filePath(), action="remove"
+ )
if self.count() <= 1:
self.removeTab(tab)
self.newTabEditor()
@@ -837,15 +930,16 @@ def restoreTabs(self):
for script in self.restoreTabList:
pathFile = script
if QFileInfo(pathFile).exists():
- tabName = pathFile.split('/')[-1]
+ tabName = pathFile.split("/")[-1]
self.newTabEditor(tabName, pathFile)
else:
- errOnRestore = QCoreApplication.translate("PythonConsole",
- "Unable to restore the file: \n{0}\n").format(pathFile)
- print('## Error: ')
+ errOnRestore = QCoreApplication.translate(
+ "PythonConsole", "Unable to restore the file: \n{0}\n"
+ ).format(pathFile)
+ print("## Error: ")
s = errOnRestore
sys.stderr.write(s)
- self.console_widget.updateTabListScript(pathFile, action='remove')
+ self.console_widget.updateTabListScript(pathFile, action="remove")
if self.count() < 1:
self.newTabEditor(filename=None)
self.topFrame.close()
@@ -861,7 +955,9 @@ def closeRestore(self):
def showFileTabMenu(self):
self.fileTabMenu.clear()
for index in range(self.count()):
- action = self.fileTabMenu.addAction(self.tabIcon(index), self.tabText(index))
+ action = self.fileTabMenu.addAction(
+ self.tabIcon(index), self.tabText(index)
+ )
action.setData(index)
def showFileTabMenuTriggered(self, action):
@@ -888,11 +984,15 @@ def listObject(self, tab):
dictObject = {}
readModule = pyclbr.readmodule(module)
readModuleFunction = pyclbr.readmodule_ex(module)
- for name, class_data in sorted(list(readModule.items()), key=lambda x: x[1].lineno):
- if os.path.normpath(class_data.file) == os.path.normpath(tabWidget.file_path()):
+ for name, class_data in sorted(
+ list(readModule.items()), key=lambda x: x[1].lineno
+ ):
+ if os.path.normpath(class_data.file) == os.path.normpath(
+ tabWidget.file_path()
+ ):
superClassName = []
for superClass in class_data.super:
- if superClass == 'object':
+ if superClass == "object":
continue
if isinstance(superClass, str):
superClassName.append(superClass)
@@ -900,56 +1000,76 @@ def listObject(self, tab):
superClassName.append(superClass.name)
classItem = QTreeWidgetItem()
if superClassName:
- super = ', '.join([i for i in superClassName])
- classItem.setText(0, name + ' [' + super + ']')
- classItem.setToolTip(0, name + ' [' + super + ']')
+ super = ", ".join([i for i in superClassName])
+ classItem.setText(0, name + " [" + super + "]")
+ classItem.setToolTip(0, name + " [" + super + "]")
else:
classItem.setText(0, name)
classItem.setToolTip(0, name)
- if sys.platform.startswith('win'):
+ if sys.platform.startswith("win"):
classItem.setSizeHint(0, QSize(18, 18))
classItem.setText(1, str(class_data.lineno))
- iconClass = QgsApplication.getThemeIcon("console/iconClassTreeWidgetConsole.svg")
+ iconClass = QgsApplication.getThemeIcon(
+ "console/iconClassTreeWidgetConsole.svg"
+ )
classItem.setIcon(0, iconClass)
dictObject[name] = class_data.lineno
- for meth, lineno in sorted(list(class_data.methods.items()), key=itemgetter(1)):
+ for meth, lineno in sorted(
+ list(class_data.methods.items()), key=itemgetter(1)
+ ):
methodItem = QTreeWidgetItem()
- methodItem.setText(0, meth + ' ')
+ methodItem.setText(0, meth + " ")
methodItem.setText(1, str(lineno))
methodItem.setToolTip(0, meth)
- iconMeth = QgsApplication.getThemeIcon("console/iconMethodTreeWidgetConsole.svg")
+ iconMeth = QgsApplication.getThemeIcon(
+ "console/iconMethodTreeWidgetConsole.svg"
+ )
methodItem.setIcon(0, iconMeth)
- if sys.platform.startswith('win'):
+ if sys.platform.startswith("win"):
methodItem.setSizeHint(0, QSize(18, 18))
classItem.addChild(methodItem)
dictObject[meth] = lineno
- self.console_widget.listClassMethod.addTopLevelItem(classItem)
- for func_name, data in sorted(list(readModuleFunction.items()), key=lambda x: x[1].lineno):
- if isinstance(data, pyclbr.Function) and \
- os.path.normpath(data.file) == os.path.normpath(tabWidget.file_path()):
+ self.console_widget.listClassMethod.addTopLevelItem(
+ classItem
+ )
+ for func_name, data in sorted(
+ list(readModuleFunction.items()), key=lambda x: x[1].lineno
+ ):
+ if isinstance(data, pyclbr.Function) and os.path.normpath(
+ data.file
+ ) == os.path.normpath(tabWidget.file_path()):
funcItem = QTreeWidgetItem()
- funcItem.setText(0, func_name + ' ')
+ funcItem.setText(0, func_name + " ")
funcItem.setText(1, str(data.lineno))
funcItem.setToolTip(0, func_name)
- iconFunc = QgsApplication.getThemeIcon("console/iconFunctionTreeWidgetConsole.svg")
+ iconFunc = QgsApplication.getThemeIcon(
+ "console/iconFunctionTreeWidgetConsole.svg"
+ )
funcItem.setIcon(0, iconFunc)
- if sys.platform.startswith('win'):
+ if sys.platform.startswith("win"):
funcItem.setSizeHint(0, QSize(18, 18))
dictObject[func_name] = data.lineno
- self.console_widget.listClassMethod.addTopLevelItem(funcItem)
+ self.console_widget.listClassMethod.addTopLevelItem(
+ funcItem
+ )
if found:
sys.path.remove(pathFile)
except:
msgItem = QTreeWidgetItem()
- msgItem.setText(0, QCoreApplication.translate("PythonConsole", "Check Syntax"))
- msgItem.setText(1, 'syntaxError')
- iconWarning = QgsApplication.getThemeIcon("console/iconSyntaxErrorConsole.svg")
+ msgItem.setText(
+ 0, QCoreApplication.translate("PythonConsole", "Check Syntax")
+ )
+ msgItem.setText(1, "syntaxError")
+ iconWarning = QgsApplication.getThemeIcon(
+ "console/iconSyntaxErrorConsole.svg"
+ )
msgItem.setIcon(0, iconWarning)
self.console_widget.listClassMethod.addTopLevelItem(msgItem)
def refreshSettingsEditor(self):
- objInspectorEnabled = QgsSettings().value("pythonConsole/enableObjectInsp",
- False, type=bool)
+ objInspectorEnabled = QgsSettings().value(
+ "pythonConsole/enableObjectInsp", False, type=bool
+ )
listObj = self.console_widget.objectListButton
if self.console_widget.listClassMethod.isVisible():
listObj.setChecked(objInspectorEnabled)
@@ -963,8 +1083,10 @@ def refreshSettingsEditor(self):
def changeLastDirPath(self, tab):
tabWidget = self.widget(tab)
if tabWidget and tabWidget.file_path():
- QgsSettings().setValue("pythonConsole/lastDirPath",
- Path(tabWidget.file_path()).parent.as_posix())
+ QgsSettings().setValue(
+ "pythonConsole/lastDirPath",
+ Path(tabWidget.file_path()).parent.as_posix(),
+ )
def showMessage(self, text, level=Qgis.MessageLevel.Info, timeout=-1, title=""):
currWidget = self.currentWidget()
diff --git a/python/console/console_output.py b/python/console/console_output.py
index b1544c687e65..9fab7c043704 100644
--- a/python/console/console_output.py
+++ b/python/console/console_output.py
@@ -17,6 +17,7 @@
***************************************************************************/
Some portions of code were taken from https://code.google.com/p/pydee/
"""
+
from __future__ import annotations
import sys
@@ -24,9 +25,25 @@
from typing import TYPE_CHECKING
from qgis.PyQt import sip
-from qgis.PyQt.QtCore import Qt, QCoreApplication, QThread, QMetaObject, Q_ARG, QObject, pyqtSlot
+from qgis.PyQt.QtCore import (
+ Qt,
+ QCoreApplication,
+ QThread,
+ QMetaObject,
+ Q_ARG,
+ QObject,
+ pyqtSlot,
+)
from qgis.PyQt.QtGui import QColor, QKeySequence
-from qgis.PyQt.QtWidgets import QAction, QGridLayout, QSpacerItem, QSizePolicy, QShortcut, QMenu, QApplication
+from qgis.PyQt.QtWidgets import (
+ QAction,
+ QGridLayout,
+ QSpacerItem,
+ QSizePolicy,
+ QShortcut,
+ QMenu,
+ QApplication,
+)
from qgis.PyQt.Qsci import QsciScintilla
from qgis.core import Qgis, QgsApplication, QgsSettings
from qgis.gui import QgsMessageBar, QgsCodeEditorPython
@@ -58,19 +75,33 @@ def write(self, m):
# This manage the case when console is called from another thread
if QThread.currentThread() != QCoreApplication.instance().thread():
- QMetaObject.invokeMethod(self, "write", Qt.ConnectionType.QueuedConnection, Q_ARG(str, m))
+ QMetaObject.invokeMethod(
+ self, "write", Qt.ConnectionType.QueuedConnection, Q_ARG(str, m)
+ )
return
if self.style == "_traceback":
# Show errors in red
- stderrColor = QColor(QgsSettings().value("pythonConsole/stderrFontColor", QColor(self.ERROR_COLOR)))
- self.sO.SendScintilla(QsciScintilla.SCI_STYLESETFORE, self.ERROR_STYLE_INDEX, stderrColor)
- self.sO.SendScintilla(QsciScintilla.SCI_STYLESETITALIC, self.ERROR_STYLE_INDEX, True)
- self.sO.SendScintilla(QsciScintilla.SCI_STYLESETBOLD, self.ERROR_STYLE_INDEX, True)
+ stderrColor = QColor(
+ QgsSettings().value(
+ "pythonConsole/stderrFontColor", QColor(self.ERROR_COLOR)
+ )
+ )
+ self.sO.SendScintilla(
+ QsciScintilla.SCI_STYLESETFORE, self.ERROR_STYLE_INDEX, stderrColor
+ )
+ self.sO.SendScintilla(
+ QsciScintilla.SCI_STYLESETITALIC, self.ERROR_STYLE_INDEX, True
+ )
+ self.sO.SendScintilla(
+ QsciScintilla.SCI_STYLESETBOLD, self.ERROR_STYLE_INDEX, True
+ )
pos = self.sO.linearPosition()
self.sO.SendScintilla(QsciScintilla.SCI_STARTSTYLING, pos, 0)
self.sO.append(m)
- self.sO.SendScintilla(QsciScintilla.SCI_SETSTYLING, len(m), self.ERROR_STYLE_INDEX)
+ self.sO.SendScintilla(
+ QsciScintilla.SCI_SETSTYLING, len(m), self.ERROR_STYLE_INDEX
+ )
else:
self.sO.append(m)
@@ -94,7 +125,9 @@ def isatty(self):
return False
-FULL_HELP_TEXT = QCoreApplication.translate("PythonConsole", """QGIS Python Console
+FULL_HELP_TEXT = QCoreApplication.translate(
+ "PythonConsole",
+ """QGIS Python Console
======================================
The console is a Python interpreter that allows you to execute python commands.
@@ -122,14 +155,15 @@ def isatty(self):
!ping www.qgis.org: Ping the QGIS website
!pip install black: install black python formatter using pip (if available)
- ?: Show this help
-""")
+""",
+)
class ShellOutputScintilla(QgsCodeEditorPython):
- def __init__(self,
- console_widget: PythonConsoleWidget,
- shell_editor: ShellScintilla):
+ def __init__(
+ self, console_widget: PythonConsoleWidget, shell_editor: ShellScintilla
+ ):
super().__init__(console_widget)
self.console_widget: PythonConsoleWidget = console_widget
self.shell_editor: ShellScintilla = shell_editor
@@ -137,7 +171,9 @@ def __init__(self,
# Creates layout for message bar
self.layout = QGridLayout(self)
self.layout.setContentsMargins(0, 0, 0, 0)
- spacerItem = QSpacerItem(20, 40, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding)
+ spacerItem = QSpacerItem(
+ 20, 40, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding
+ )
self.layout.addItem(spacerItem, 1, 0, 1, 1)
# messageBar instance
self.infoBar = QgsMessageBar()
@@ -180,20 +216,22 @@ def on_app_exit(self):
sys.stderr = self._old_stderr
def insertInitText(self):
- txtInit = QCoreApplication.translate("PythonConsole",
- "Python Console\n"
- "Use iface to access QGIS API interface or type '?' for more info\n"
- "Security warning: typing commands from an untrusted source can harm your computer")
+ txtInit = QCoreApplication.translate(
+ "PythonConsole",
+ "Python Console\n"
+ "Use iface to access QGIS API interface or type '?' for more info\n"
+ "Security warning: typing commands from an untrusted source can harm your computer",
+ )
- txtInit = '\n'.join(['# ' + line for line in txtInit.split('\n')])
+ txtInit = "\n".join(["# " + line for line in txtInit.split("\n")])
# some translation string for the console header ends without '\n'
# and the first command in console will be appended at the header text.
# The following code add a '\n' at the end of the string if not present.
- if txtInit.endswith('\n'):
+ if txtInit.endswith("\n"):
self.setText(txtInit)
else:
- self.setText(txtInit + '\n')
+ self.setText(txtInit + "\n")
def insertHelp(self):
self.append(FULL_HELP_TEXT)
@@ -212,31 +250,38 @@ def refreshSettingsOutput(self):
self.setCaretWidth(0) # NO (blinking) caret in the output
def clearConsole(self):
- self.setText('')
+ self.setText("")
self.insertInitText()
self.shell_editor.setFocus()
def contextMenuEvent(self, e):
menu = QMenu(self)
- menu.addAction(QgsApplication.getThemeIcon("console/iconHideToolConsole.svg"),
- QCoreApplication.translate("PythonConsole", "Hide/Show Toolbar"),
- self.hideToolBar)
+ menu.addAction(
+ QgsApplication.getThemeIcon("console/iconHideToolConsole.svg"),
+ QCoreApplication.translate("PythonConsole", "Hide/Show Toolbar"),
+ self.hideToolBar,
+ )
menu.addSeparator()
showEditorAction = menu.addAction(
QgsApplication.getThemeIcon("console/iconShowEditorConsole.svg"),
QCoreApplication.translate("PythonConsole", "Show Editor"),
- self.showEditor)
+ self.showEditor,
+ )
menu.addSeparator()
- runAction = QAction(QgsApplication.getThemeIcon("console/mIconRunConsole.svg"),
- QCoreApplication.translate("PythonConsole", "Enter Selected"),
- menu)
+ runAction = QAction(
+ QgsApplication.getThemeIcon("console/mIconRunConsole.svg"),
+ QCoreApplication.translate("PythonConsole", "Enter Selected"),
+ menu,
+ )
runAction.triggered.connect(self.enteredSelected)
runAction.setShortcut(QKeySequence(Qt.Modifier.CTRL | Qt.Key.Key_E))
menu.addAction(runAction)
- clearAction = QAction(QgsApplication.getThemeIcon("console/iconClearConsole.svg"),
- QCoreApplication.translate("PythonConsole", "Clear Console"),
- menu)
+ clearAction = QAction(
+ QgsApplication.getThemeIcon("console/iconClearConsole.svg"),
+ QCoreApplication.translate("PythonConsole", "Clear Console"),
+ menu,
+ )
clearAction.triggered.connect(self.clearConsole)
menu.addAction(clearAction)
@@ -245,31 +290,37 @@ def contextMenuEvent(self, e):
context_help_action = QAction(
QgsApplication.getThemeIcon("mActionHelpContents.svg"),
QCoreApplication.translate("PythonConsole", "Context Help"),
- menu)
- context_help_action.triggered.connect(partial(self.shell_editor.showApiDocumentation, word, force_search=True))
- context_help_action.setShortcut('F1')
+ menu,
+ )
+ context_help_action.triggered.connect(
+ partial(self.shell_editor.showApiDocumentation, word, force_search=True)
+ )
+ context_help_action.setShortcut("F1")
menu.addAction(context_help_action)
menu.addSeparator()
copyAction = QAction(
QgsApplication.getThemeIcon("mActionEditCopy.svg"),
QCoreApplication.translate("PythonConsole", "Copy"),
- menu)
+ menu,
+ )
copyAction.triggered.connect(self.copy)
copyAction.setShortcut(QKeySequence.StandardKey.Copy)
menu.addAction(copyAction)
selectAllAction = QAction(
- QCoreApplication.translate("PythonConsole", "Select All"),
- menu)
+ QCoreApplication.translate("PythonConsole", "Select All"), menu
+ )
selectAllAction.triggered.connect(self.selectAll)
selectAllAction.setShortcut(QKeySequence.StandardKey.SelectAll)
menu.addAction(selectAllAction)
menu.addSeparator()
- settings_action = QAction(QgsApplication.getThemeIcon("console/iconSettingsConsole.svg"),
- QCoreApplication.translate("PythonConsole", "Options…"),
- menu)
+ settings_action = QAction(
+ QgsApplication.getThemeIcon("console/iconSettingsConsole.svg"),
+ QCoreApplication.translate("PythonConsole", "Options…"),
+ menu,
+ )
settings_action.triggered.connect(self.console_widget.openSettings)
menu.addAction(settings_action)
@@ -281,7 +332,7 @@ def contextMenuEvent(self, e):
if self.hasSelectedText():
runAction.setEnabled(True)
copyAction.setEnabled(True)
- if not self.text(3) == '':
+ if not self.text(3) == "":
selectAllAction.setEnabled(True)
clearAction.setEnabled(True)
if self.console_widget.tabEditorWidget.isVisible():
@@ -304,7 +355,9 @@ def copy(self):
"""Copy text to clipboard... or keyboard interrupt"""
if self.hasSelectedText():
text = self.selectedText()
- text = text.replace('>>> ', '').replace('... ', '').strip() # removing prompts
+ text = (
+ text.replace(">>> ", "").replace("... ", "").strip()
+ ) # removing prompts
QApplication.clipboard().setText(text)
else:
raise KeyboardInterrupt
diff --git a/python/console/console_sci.py b/python/console/console_sci.py
index 5b0d9d8d270b..2895e6c1db5c 100644
--- a/python/console/console_sci.py
+++ b/python/console/console_sci.py
@@ -17,6 +17,7 @@
***************************************************************************/
Some portions of code were taken from https://code.google.com/p/pydee/
"""
+
from __future__ import annotations
import code
@@ -25,10 +26,7 @@
import sys
import traceback
from functools import partial
-from typing import (
- Optional,
- TYPE_CHECKING
-)
+from typing import Optional, TYPE_CHECKING
from pathlib import Path
from tempfile import NamedTemporaryFile
@@ -42,13 +40,10 @@
QgsProcessingUtils,
QgsSettingsTree,
)
-from qgis.gui import (
- QgsCodeEditorPython,
- QgsCodeEditor,
- QgsCodeInterpreter
-)
+from qgis.gui import QgsCodeEditorPython, QgsCodeEditor, QgsCodeInterpreter
from .process_wrapper import ProcessWrapper
+
if TYPE_CHECKING:
from .console import PythonConsoleWidget
@@ -79,7 +74,6 @@
"from qgis.PyQt.QtWidgets import *",
"from qgis.PyQt.QtNetwork import *",
"from qgis.PyQt.QtXml import *",
-
r"""
def __parse_object(object=None):
if not object:
@@ -167,7 +161,7 @@ def _pyqgis(object=None):
If the object is not part of the QGIS API but is a Qt object the Qt documentation is opened.
'''
return _help(object, api=Qgis.DocumentationApi.PyQgis)
-"""
+""",
]
@@ -225,7 +219,9 @@ def execCommandImpl(self, cmd, show_input=True):
# Use a temporary file to communicate the result to the inner interpreter
tmp = Path(NamedTemporaryFile(delete=False).name)
tmp.write_text(res, encoding="utf-8")
- self.runsource(f'{varname} = Path("{tmp}").read_text(encoding="utf-8").split("\\n")')
+ self.runsource(
+ f'{varname} = Path("{tmp}").read_text(encoding="utf-8").split("\\n")'
+ )
tmp.unlink()
self.sub_process = None
return 0
@@ -244,19 +240,25 @@ def execCommandImpl(self, cmd, show_input=True):
res = 0
import webbrowser
- version = 'master' if 'master' in Qgis.QGIS_VERSION.lower() else \
- re.findall(r'^\d.[0-9]*', Qgis.QGIS_VERSION)[0]
+
+ version = (
+ "master"
+ if "master" in Qgis.QGIS_VERSION.lower()
+ else re.findall(r"^\d.[0-9]*", Qgis.QGIS_VERSION)[0]
+ )
if cmd == "?":
self.shell.console_widget.shell_output.insertHelp()
- elif cmd == '_pyqgis':
+ elif cmd == "_pyqgis":
self.shell.showApi(Qgis.DocumentationApi.PyQgis)
- elif cmd == '_api':
+ elif cmd == "_api":
self.shell.showApi(Qgis.DocumentationApi.CppQgis)
- elif cmd == '_cookbook':
+ elif cmd == "_cookbook":
webbrowser.open(
"https://docs.qgis.org/{}/en/docs/pyqgis_developer_cookbook/".format(
- 'testing' if version == 'master' else version))
+ "testing" if version == "master" else version
+ )
+ )
else:
self.buffer.append(cmd)
src = "\n".join(self.buffer)
@@ -270,20 +272,21 @@ def writeCMD(self, txt):
if sys.stdout:
sys.stdout.fire_keyboard_interrupt = False
if len(txt) > 0:
- sys.stdout.write(f'{self.promptForState()} {txt}\n')
+ sys.stdout.write(f"{self.promptForState()} {txt}\n")
- def runsource(self, source, filename=' ', symbol='single'):
+ def runsource(self, source, filename=" ", symbol="single"):
if sys.stdout:
sys.stdout.fire_keyboard_interrupt = False
hook = sys.excepthook
try:
+
def excepthook(etype, value, tb):
self.write("".join(traceback.format_exception(etype, value, tb)))
sys.excepthook = excepthook
- return super(PythonInterpreter, self).runsource(source, filename, symbol)
+ return super().runsource(source, filename, symbol)
finally:
sys.excepthook = hook
@@ -313,33 +316,45 @@ def __init__(self, console_widget: PythonConsoleWidget):
# We set the ImmediatelyUpdateHistory flag here, as users can easily
# crash QGIS by entering a Python command, and we don't want the
# history leading to the crash lost...
- super().__init__(console_widget, [], QgsCodeEditor.Mode.CommandInput,
- flags=QgsCodeEditor.Flags(QgsCodeEditor.Flag.CodeFolding | QgsCodeEditor.Flag.ImmediatelyUpdateHistory))
+ super().__init__(
+ console_widget,
+ [],
+ QgsCodeEditor.Mode.CommandInput,
+ flags=QgsCodeEditor.Flags(
+ QgsCodeEditor.Flag.CodeFolding
+ | QgsCodeEditor.Flag.ImmediatelyUpdateHistory
+ ),
+ )
self.console_widget: PythonConsoleWidget = console_widget
self._interpreter = PythonInterpreter(shell=self)
self.setInterpreter(self._interpreter)
- self.opening = ['(', '{', '[', "'", '"']
- self.closing = [')', '}', ']', "'", '"']
+ self.opening = ["(", "{", "[", "'", '"']
+ self.closing = [")", "}", "]", "'", '"']
self.setHistoryFilePath(
- os.path.join(QgsApplication.qgisSettingsDirPath(), "console_history.txt"))
+ os.path.join(QgsApplication.qgisSettingsDirPath(), "console_history.txt")
+ )
self.refreshSettingsShell()
# Disable command key
ctrl, shift = self.SCMOD_CTRL << 16, self.SCMOD_SHIFT << 16
- self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('L') + ctrl)
- self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('T') + ctrl)
- self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('D') + ctrl)
- self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('Z') + ctrl)
- self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('Y') + ctrl)
- self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('L') + ctrl + shift)
+ self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord("L") + ctrl)
+ self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord("T") + ctrl)
+ self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord("D") + ctrl)
+ self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord("Z") + ctrl)
+ self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord("Y") + ctrl)
+ self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord("L") + ctrl + shift)
# New QShortcut = ctrl+space/ctrl+alt+space for Autocomplete
- self.newShortcutCSS = QShortcut(QKeySequence(Qt.Modifier.CTRL | Qt.Modifier.SHIFT | Qt.Key.Key_Space), self)
- self.newShortcutCAS = QShortcut(QKeySequence(Qt.Modifier.CTRL | Qt.Modifier.ALT | Qt.Key.Key_Space), self)
+ self.newShortcutCSS = QShortcut(
+ QKeySequence(Qt.Modifier.CTRL | Qt.Modifier.SHIFT | Qt.Key.Key_Space), self
+ )
+ self.newShortcutCAS = QShortcut(
+ QKeySequence(Qt.Modifier.CTRL | Qt.Modifier.ALT | Qt.Key.Key_Space), self
+ )
self.newShortcutCSS.setContext(Qt.ShortcutContext.WidgetShortcut)
self.newShortcutCAS.setContext(Qt.ShortcutContext.WidgetShortcut)
self.newShortcutCAS.activated.connect(self.autoComplete)
@@ -362,18 +377,25 @@ def refreshSettingsShell(self):
self._setMinimumHeight()
def on_session_history_cleared(self):
- msgText = QCoreApplication.translate('PythonConsole',
- 'Session history cleared successfully.')
+ msgText = QCoreApplication.translate(
+ "PythonConsole", "Session history cleared successfully."
+ )
self.console_widget.callWidgetMessageBar(msgText)
def on_persistent_history_cleared(self):
- msgText = QCoreApplication.translate('PythonConsole',
- 'History cleared successfully.')
+ msgText = QCoreApplication.translate(
+ "PythonConsole", "History cleared successfully."
+ )
self.console_widget.callWidgetMessageBar(msgText)
def keyPressEvent(self, e):
- if e.modifiers() & (Qt.KeyboardModifier.ControlModifier | Qt.KeyboardModifier.MetaModifier) and e.key() == Qt.Key.Key_C and not self.hasSelectedText():
+ if (
+ e.modifiers()
+ & (Qt.KeyboardModifier.ControlModifier | Qt.KeyboardModifier.MetaModifier)
+ and e.key() == Qt.Key.Key_C
+ and not self.hasSelectedText()
+ ):
if self._interpreter.sub_process:
sys.stderr.write("Terminate child process\n")
self._interpreter.sub_process.kill()
@@ -462,43 +484,68 @@ def write(self, txt):
if sys.stderr:
sys.stderr.write(txt)
- def runFile(self, filename, override_file_name: Optional[str] = None):
+ def runFile(self, filename, override_file_name: str | None = None):
filename = filename.replace("\\", "/")
dirname = os.path.dirname(filename)
# Append the directory of the file to the path and set __file__ to the filename
- self._interpreter.execCommandImpl("sys.path.append({0})".format(
- QgsProcessingUtils.stringToPythonLiteral(dirname)), False)
- self._interpreter.execCommandImpl("__file__ = {0}".format(
- QgsProcessingUtils.stringToPythonLiteral(filename)), False)
+ self._interpreter.execCommandImpl(
+ "sys.path.append({})".format(
+ QgsProcessingUtils.stringToPythonLiteral(dirname)
+ ),
+ False,
+ )
+ self._interpreter.execCommandImpl(
+ f"__file__ = {QgsProcessingUtils.stringToPythonLiteral(filename)}",
+ False,
+ )
try:
# Run the file
- self.runCommand("exec(compile(Path({0}).read_text(), {1}, 'exec'))".format(
- QgsProcessingUtils.stringToPythonLiteral(filename),
- QgsProcessingUtils.stringToPythonLiteral(override_file_name or filename)),
- skipHistory=True)
+ self.runCommand(
+ "exec(compile(Path({}).read_text(), {}, 'exec'))".format(
+ QgsProcessingUtils.stringToPythonLiteral(filename),
+ QgsProcessingUtils.stringToPythonLiteral(
+ override_file_name or filename
+ ),
+ ),
+ skipHistory=True,
+ )
finally:
# Remove the directory from the path and delete the __file__ variable
self._interpreter.execCommandImpl("del __file__", False)
- self._interpreter.execCommandImpl("sys.path.remove({0})".format(
- QgsProcessingUtils.stringToPythonLiteral(dirname)), False)
+ self._interpreter.execCommandImpl(
+ "sys.path.remove({})".format(
+ QgsProcessingUtils.stringToPythonLiteral(dirname)
+ ),
+ False,
+ )
def showApiDocumentation(self, text, force_search=False):
- self._interpreter.execCommandImpl(f'_help({repr(text)}, api=Qgis.DocumentationApi.PyQgis, force_search={force_search})', show_input=False)
+ self._interpreter.execCommandImpl(
+ f"_help({repr(text)}, api=Qgis.DocumentationApi.PyQgis, force_search={force_search})",
+ show_input=False,
+ )
def showApi(self, api: Qgis.DocumentationApi):
- self._interpreter.execCommandImpl(f'_help(api=Qgis.DocumentationApi.{api.name})', show_input=False)
+ self._interpreter.execCommandImpl(
+ f"_help(api=Qgis.DocumentationApi.{api.name})", show_input=False
+ )
def populateContextMenu(self, menu):
- word = self.selectedText() or self.wordAtPoint(self.mapFromGlobal(QCursor.pos()))
+ word = self.selectedText() or self.wordAtPoint(
+ self.mapFromGlobal(QCursor.pos())
+ )
if word:
context_help_action = QAction(
QgsApplication.getThemeIcon("mActionHelpContents.svg"),
QCoreApplication.translate("PythonConsole", "Context Help"),
- menu)
- context_help_action.triggered.connect(partial(self.showApiDocumentation, word, force_search=True))
- context_help_action.setShortcut('F1')
+ menu,
+ )
+ context_help_action.triggered.connect(
+ partial(self.showApiDocumentation, word, force_search=True)
+ )
+ context_help_action.setShortcut("F1")
menu.addAction(context_help_action)
diff --git a/python/console/console_settings.py b/python/console/console_settings.py
index dafa29931eee..ef7c6d575d8c 100644
--- a/python/console/console_settings.py
+++ b/python/console/console_settings.py
@@ -22,7 +22,13 @@
from qgis.PyQt import uic
from qgis.PyQt.QtCore import QCoreApplication, QUrl
-from qgis.PyQt.QtWidgets import QWidget, QFileDialog, QMessageBox, QTableWidgetItem, QHBoxLayout
+from qgis.PyQt.QtWidgets import (
+ QWidget,
+ QFileDialog,
+ QMessageBox,
+ QTableWidgetItem,
+ QHBoxLayout,
+)
from qgis.PyQt.QtGui import QIcon, QDesktopServices
from qgis.core import QgsSettings, QgsApplication, QgsSettingsTree, Qgis
@@ -30,7 +36,9 @@
from .console_compile_apis import PrepareAPIDialog
-Ui_SettingsDialogPythonConsole, _ = uic.loadUiType(Path(__file__).parent / 'console_settings.ui')
+Ui_SettingsDialogPythonConsole, _ = uic.loadUiType(
+ Path(__file__).parent / "console_settings.ui"
+)
class ConsoleOptionsFactory(QgsOptionsWidgetFactory):
@@ -39,10 +47,10 @@ def __init__(self):
super(QgsOptionsWidgetFactory, self).__init__()
def icon(self):
- return QgsApplication.getThemeIcon('/console/mIconRunConsole.svg')
+ return QgsApplication.getThemeIcon("/console/mIconRunConsole.svg")
def path(self):
- return ['ide']
+ return ["ide"]
def createWidget(self, parent):
return ConsoleOptionsPage(parent)
@@ -51,34 +59,45 @@ def createWidget(self, parent):
class ConsoleOptionsPage(QgsOptionsPageWidget):
def __init__(self, parent):
- super(ConsoleOptionsPage, self).__init__(parent)
+ super().__init__(parent)
self.options_widget = ConsoleOptionsWidget(parent)
layout = QHBoxLayout()
layout.setContentsMargins(0, 0, 0, 0)
layout.setMargin(0)
self.setLayout(layout)
layout.addWidget(self.options_widget)
- self.setObjectName('consoleOptions')
+ self.setObjectName("consoleOptions")
def apply(self):
self.options_widget.accept()
def helpKey(self):
- return 'plugins/python_console.html'
+ return "plugins/python_console.html"
class ConsoleOptionsWidget(QWidget, Ui_SettingsDialogPythonConsole):
def __init__(self, parent):
super().__init__(parent)
- self.setWindowTitle(QCoreApplication.translate(
- "SettingsDialogPythonConsole", "Python Console Settings"))
+ self.setWindowTitle(
+ QCoreApplication.translate(
+ "SettingsDialogPythonConsole", "Python Console Settings"
+ )
+ )
self.parent = parent
self.setupUi(self)
# Populate the documentation Browser combobox
- self.contextHelpBrowser.addItem(QCoreApplication.translate("PythonConsole", "Embedded Webview (developer tools)"), Qgis.DocumentationBrowser.DeveloperToolsPanel)
- self.contextHelpBrowser.addItem(QCoreApplication.translate("PythonConsole", "Default System Web Browser"), Qgis.DocumentationBrowser.SystemWebBrowser)
+ self.contextHelpBrowser.addItem(
+ QCoreApplication.translate(
+ "PythonConsole", "Embedded Webview (developer tools)"
+ ),
+ Qgis.DocumentationBrowser.DeveloperToolsPanel,
+ )
+ self.contextHelpBrowser.addItem(
+ QCoreApplication.translate("PythonConsole", "Default System Web Browser"),
+ Qgis.DocumentationBrowser.SystemWebBrowser,
+ )
self.autopep8Level.setClearValue(1)
self.maxLineLength.setClearValue(80)
@@ -93,9 +112,13 @@ def __init__(self, parent):
self.initialCheck()
self.addAPIpath.setIcon(QIcon(":/images/themes/default/symbologyAdd.svg"))
- self.addAPIpath.setToolTip(QCoreApplication.translate("PythonConsole", "Add API path"))
+ self.addAPIpath.setToolTip(
+ QCoreApplication.translate("PythonConsole", "Add API path")
+ )
self.removeAPIpath.setIcon(QIcon(":/images/themes/default/symbologyRemove.svg"))
- self.removeAPIpath.setToolTip(QCoreApplication.translate("PythonConsole", "Remove API path"))
+ self.removeAPIpath.setToolTip(
+ QCoreApplication.translate("PythonConsole", "Remove API path")
+ )
self.preloadAPI.stateChanged.connect(self.initialCheck)
self.addAPIpath.clicked.connect(self.loadAPIFile)
@@ -121,7 +144,8 @@ def loadAPIFile(self):
settings = QgsSettings()
lastDirPath = settings.value("pythonConsole/lastDirAPIPath", "", type=str)
fileAPI, selected_filter = QFileDialog.getOpenFileName(
- self, "Open API File", lastDirPath, "API file (*.api)")
+ self, "Open API File", lastDirPath, "API file (*.api)"
+ )
if fileAPI:
self.addAPI(fileAPI)
settings.setValue("pythonConsole/lastDirAPIPath", fileAPI)
@@ -129,17 +153,17 @@ def loadAPIFile(self):
def _prepareAPI(self):
if self.tableWidget.rowCount() != 0:
pap_file, filter = QFileDialog().getSaveFileName(
- self,
- "",
- '*.pap',
- "Prepared APIs file (*.pap)")
+ self, "", "*.pap", "Prepared APIs file (*.pap)"
+ )
else:
QMessageBox.information(
- self, self.tr("Warning!"),
- self.tr('You need to add some APIs file in order to compile'))
+ self,
+ self.tr("Warning!"),
+ self.tr("You need to add some APIs file in order to compile"),
+ )
return
if pap_file:
- api_lexer = 'QsciLexerPython'
+ api_lexer = "QsciLexerPython"
api_files = []
count = self.tableWidget.rowCount()
for i in range(0, count):
@@ -152,18 +176,24 @@ def _prepareAPI(self):
self.lineEdit.setText(pap_file)
def accept(self):
- if not self.preloadAPI.isChecked() and \
- not self.groupBoxPreparedAPI.isChecked():
+ if not self.preloadAPI.isChecked() and not self.groupBoxPreparedAPI.isChecked():
if self.tableWidget.rowCount() == 0:
QMessageBox.information(
- self, self.tr("Warning!"),
- self.tr('Please specify API file or check "Use preloaded API files"'))
+ self,
+ self.tr("Warning!"),
+ self.tr(
+ 'Please specify API file or check "Use preloaded API files"'
+ ),
+ )
return
- if self.groupBoxPreparedAPI.isChecked() and \
- not self.lineEdit.text():
+ if self.groupBoxPreparedAPI.isChecked() and not self.lineEdit.text():
QMessageBox.information(
- self, self.tr("Warning!"),
- QCoreApplication.translate('optionsDialog', 'The APIs file was not compiled, click on "Compile APIs…"')
+ self,
+ self.tr("Warning!"),
+ QCoreApplication.translate(
+ "optionsDialog",
+ 'The APIs file was not compiled, click on "Compile APIs…"',
+ ),
)
return
self.saveSettings()
@@ -188,49 +218,83 @@ def removeAPI(self):
def saveSettings(self):
settings = QgsSettings()
settings.setValue("pythonConsole/preloadAPI", self.preloadAPI.isChecked())
- settings.setValue("pythonConsole/autoSaveScript", self.autoSaveScript.isChecked())
+ settings.setValue(
+ "pythonConsole/autoSaveScript", self.autoSaveScript.isChecked()
+ )
for i in range(0, self.tableWidget.rowCount()):
text = self.tableWidget.item(i, 1).text()
self.listPath.append(text)
settings.setValue("pythonConsole/userAPI", self.listPath)
- settings.setValue("pythonConsole/autoCompThreshold", self.autoCompThreshold.value())
- settings.setValue("pythonConsole/autoCompleteEnabled", self.groupBoxAutoCompletion.isChecked())
+ settings.setValue(
+ "pythonConsole/autoCompThreshold", self.autoCompThreshold.value()
+ )
+ settings.setValue(
+ "pythonConsole/autoCompleteEnabled", self.groupBoxAutoCompletion.isChecked()
+ )
- settings.setValue("pythonConsole/usePreparedAPIFile", self.groupBoxPreparedAPI.isChecked())
+ settings.setValue(
+ "pythonConsole/usePreparedAPIFile", self.groupBoxPreparedAPI.isChecked()
+ )
settings.setValue("pythonConsole/preparedAPIFile", self.lineEdit.text())
if self.autoCompFromAPI.isChecked():
- settings.setValue("pythonConsole/autoCompleteSource", 'fromAPI')
+ settings.setValue("pythonConsole/autoCompleteSource", "fromAPI")
elif self.autoCompFromDoc.isChecked():
- settings.setValue("pythonConsole/autoCompleteSource", 'fromDoc')
+ settings.setValue("pythonConsole/autoCompleteSource", "fromDoc")
elif self.autoCompFromDocAPI.isChecked():
- settings.setValue("pythonConsole/autoCompleteSource", 'fromDocAPI')
+ settings.setValue("pythonConsole/autoCompleteSource", "fromDocAPI")
- settings.setValue("pythonConsole/enableObjectInsp", self.enableObjectInspector.isChecked())
- settings.setValue("pythonConsole/autoCloseBracket", self.autoCloseBracket.isChecked())
+ settings.setValue(
+ "pythonConsole/enableObjectInsp", self.enableObjectInspector.isChecked()
+ )
+ settings.setValue(
+ "pythonConsole/autoCloseBracket", self.autoCloseBracket.isChecked()
+ )
settings.setValue("pythonConsole/autoSurround", self.autoSurround.isChecked())
- settings.setValue("pythonConsole/autoInsertImport", self.autoInsertImport.isChecked())
+ settings.setValue(
+ "pythonConsole/autoInsertImport", self.autoInsertImport.isChecked()
+ )
settings.setValue("pythonConsole/formatOnSave", self.formatOnSave.isChecked())
codeEditorTreeNode = QgsSettingsTree.node("gui").childNode("code-editor")
pythonSettingsTreeNode = codeEditorTreeNode.childNode("python")
- pythonSettingsTreeNode.childSetting("sort-imports").setValue(self.sortImports.isChecked())
- pythonSettingsTreeNode.childSetting("formatter").setValue(self.formatter.currentText())
- pythonSettingsTreeNode.childSetting("autopep8-level").setValue(self.autopep8Level.value())
- pythonSettingsTreeNode.childSetting("black-normalize-quotes").setValue(self.blackNormalizeQuotes.isChecked())
- pythonSettingsTreeNode.childSetting("max-line-length").setValue(self.maxLineLength.value())
- pythonSettingsTreeNode.childSetting('external-editor').setValue(self.externalEditor.text())
- pythonSettingsTreeNode.childSetting('context-help-browser').setVariantValue(self.contextHelpBrowser.currentData().name)
+ pythonSettingsTreeNode.childSetting("sort-imports").setValue(
+ self.sortImports.isChecked()
+ )
+ pythonSettingsTreeNode.childSetting("formatter").setValue(
+ self.formatter.currentText()
+ )
+ pythonSettingsTreeNode.childSetting("autopep8-level").setValue(
+ self.autopep8Level.value()
+ )
+ pythonSettingsTreeNode.childSetting("black-normalize-quotes").setValue(
+ self.blackNormalizeQuotes.isChecked()
+ )
+ pythonSettingsTreeNode.childSetting("max-line-length").setValue(
+ self.maxLineLength.value()
+ )
+ pythonSettingsTreeNode.childSetting("external-editor").setValue(
+ self.externalEditor.text()
+ )
+ pythonSettingsTreeNode.childSetting("context-help-browser").setVariantValue(
+ self.contextHelpBrowser.currentData().name
+ )
- codeEditorTreeNode.childSetting('context-help-hover').setValue(self.contextHelpHover.isChecked())
+ codeEditorTreeNode.childSetting("context-help-hover").setValue(
+ self.contextHelpHover.isChecked()
+ )
def restoreSettings(self):
settings = QgsSettings()
- self.preloadAPI.setChecked(settings.value("pythonConsole/preloadAPI", True, type=bool))
- self.lineEdit.setText(settings.value("pythonConsole/preparedAPIFile", "", type=str))
+ self.preloadAPI.setChecked(
+ settings.value("pythonConsole/preloadAPI", True, type=bool)
+ )
+ self.lineEdit.setText(
+ settings.value("pythonConsole/preparedAPIFile", "", type=str)
+ )
itemTable = settings.value("pythonConsole/userAPI", [])
if itemTable:
self.tableWidget.setRowCount(0)
@@ -241,49 +305,81 @@ def restoreSettings(self):
apiName = pathSplit[-1][0:-4]
self.tableWidget.setItem(i, 0, QTableWidgetItem(apiName))
self.tableWidget.setItem(i, 1, QTableWidgetItem(itemTable[i]))
- self.autoSaveScript.setChecked(settings.value("pythonConsole/autoSaveScript", False, type=bool))
+ self.autoSaveScript.setChecked(
+ settings.value("pythonConsole/autoSaveScript", False, type=bool)
+ )
- self.autoCompThreshold.setValue(settings.value("pythonConsole/autoCompThreshold", 2, type=int))
- self.groupBoxAutoCompletion.setChecked(settings.value("pythonConsole/autoCompleteEnabled", True, type=bool))
+ self.autoCompThreshold.setValue(
+ settings.value("pythonConsole/autoCompThreshold", 2, type=int)
+ )
+ self.groupBoxAutoCompletion.setChecked(
+ settings.value("pythonConsole/autoCompleteEnabled", True, type=bool)
+ )
- self.enableObjectInspector.setChecked(settings.value("pythonConsole/enableObjectInsp", False, type=bool))
- self.autoCloseBracket.setChecked(settings.value("pythonConsole/autoCloseBracket", True, type=bool))
- self.autoSurround.setChecked(settings.value("pythonConsole/autoSurround", True, type=bool))
- self.autoInsertImport.setChecked(settings.value("pythonConsole/autoInsertImport", False, type=bool))
+ self.enableObjectInspector.setChecked(
+ settings.value("pythonConsole/enableObjectInsp", False, type=bool)
+ )
+ self.autoCloseBracket.setChecked(
+ settings.value("pythonConsole/autoCloseBracket", True, type=bool)
+ )
+ self.autoSurround.setChecked(
+ settings.value("pythonConsole/autoSurround", True, type=bool)
+ )
+ self.autoInsertImport.setChecked(
+ settings.value("pythonConsole/autoInsertImport", False, type=bool)
+ )
codeEditorTreeNode = QgsSettingsTree.node("gui").childNode("code-editor")
pythonSettingsTreeNode = codeEditorTreeNode.childNode("python")
- self.formatOnSave.setChecked(settings.value("pythonConsole/formatOnSave", False, type=bool))
- self.sortImports.setChecked(pythonSettingsTreeNode.childSetting("sort-imports").value())
- self.formatter.setCurrentText(pythonSettingsTreeNode.childSetting("formatter").value())
- self.autopep8Level.setValue(pythonSettingsTreeNode.childSetting("autopep8-level").value())
- self.blackNormalizeQuotes.setChecked(pythonSettingsTreeNode.childSetting("black-normalize-quotes").value())
- self.maxLineLength.setValue(pythonSettingsTreeNode.childSetting("max-line-length").value())
+ self.formatOnSave.setChecked(
+ settings.value("pythonConsole/formatOnSave", False, type=bool)
+ )
+ self.sortImports.setChecked(
+ pythonSettingsTreeNode.childSetting("sort-imports").value()
+ )
+ self.formatter.setCurrentText(
+ pythonSettingsTreeNode.childSetting("formatter").value()
+ )
+ self.autopep8Level.setValue(
+ pythonSettingsTreeNode.childSetting("autopep8-level").value()
+ )
+ self.blackNormalizeQuotes.setChecked(
+ pythonSettingsTreeNode.childSetting("black-normalize-quotes").value()
+ )
+ self.maxLineLength.setValue(
+ pythonSettingsTreeNode.childSetting("max-line-length").value()
+ )
- browserName = pythonSettingsTreeNode.childSetting('context-help-browser').valueAsVariant()
+ browserName = pythonSettingsTreeNode.childSetting(
+ "context-help-browser"
+ ).valueAsVariant()
try:
browser = Qgis.DocumentationBrowser[browserName]
except KeyError:
browser = Qgis.DocumentationBrowser.DeveloperToolsPanel
- self.contextHelpBrowser.setCurrentIndex(self.contextHelpBrowser.findData(browser))
- self.contextHelpHover.setChecked(codeEditorTreeNode.childSetting('context-help-hover').value())
+ self.contextHelpBrowser.setCurrentIndex(
+ self.contextHelpBrowser.findData(browser)
+ )
+ self.contextHelpHover.setChecked(
+ codeEditorTreeNode.childSetting("context-help-hover").value()
+ )
- if settings.value("pythonConsole/autoCompleteSource") == 'fromDoc':
+ if settings.value("pythonConsole/autoCompleteSource") == "fromDoc":
self.autoCompFromDoc.setChecked(True)
- elif settings.value("pythonConsole/autoCompleteSource") == 'fromAPI':
+ elif settings.value("pythonConsole/autoCompleteSource") == "fromAPI":
self.autoCompFromAPI.setChecked(True)
- elif settings.value("pythonConsole/autoCompleteSource") == 'fromDocAPI':
+ elif settings.value("pythonConsole/autoCompleteSource") == "fromDocAPI":
self.autoCompFromDocAPI.setChecked(True)
self.externalEditor.setText(
- pythonSettingsTreeNode.childSetting('external-editor').value()
+ pythonSettingsTreeNode.childSetting("external-editor").value()
)
def onFormatterChanged(self):
- """ Toggle formatter-specific options visibility when the formatter is changed """
- if self.formatter.currentText() == 'autopep8':
+ """Toggle formatter-specific options visibility when the formatter is changed"""
+ if self.formatter.currentText() == "autopep8":
self.autopep8Level.setVisible(True)
self.autopep8LevelLabel.setVisible(True)
self.blackNormalizeQuotes.setVisible(False)
diff --git a/python/console/process_wrapper.py b/python/console/process_wrapper.py
index b59d8a6ead92..4d9acbd83606 100644
--- a/python/console/process_wrapper.py
+++ b/python/console/process_wrapper.py
@@ -15,7 +15,6 @@
***************************************************************************
"""
-
import locale
import os
import subprocess
@@ -43,7 +42,7 @@ def __init__(self, command, interactive=True, parent=None):
"stdout": subprocess.PIPE,
"stdin": subprocess.PIPE,
"stderr": subprocess.PIPE,
- "shell": True
+ "shell": True,
}
# On Unix, we can use os.setsid
@@ -64,12 +63,16 @@ def __init__(self, command, interactive=True, parent=None):
# Read process stdout and push to out queue
self.q_out = Queue()
- self.t_out = Thread(daemon=True, target=self.enqueue_output, args=[self.p.stdout, self.q_out])
+ self.t_out = Thread(
+ daemon=True, target=self.enqueue_output, args=[self.p.stdout, self.q_out]
+ )
self.t_out.start()
# Read process stderr and push to err queue
self.q_err = Queue()
- self.t_err = Thread(daemon=True, target=self.enqueue_output, args=[self.p.stderr, self.q_err])
+ self.t_err = Thread(
+ daemon=True, target=self.enqueue_output, args=[self.p.stderr, self.q_err]
+ )
self.t_err.start()
# Polls process and output both queues content to sys.stdout and sys.stderr
@@ -89,8 +92,10 @@ def enqueue_output(self, stream, queue):
stream.close()
def __repr__(self):
- """ Helpful representation of the maanaged process """
- status = "Running" if self.returncode is None else f"Completed ({self.returncode})"
+ """Helpful representation of the maanaged process"""
+ status = (
+ "Running" if self.returncode is None else f"Completed ({self.returncode})"
+ )
repr = f"ProcessWrapper object at {hex(id(self))}"
repr += f"\n - Status: {status}"
repr += f"\n - stdout: {self.stdout}"
@@ -111,7 +116,7 @@ def decode(self, bytes):
return text
def read_content(self, queue, stream, is_stderr):
- """ Write queue content to the standard stream and append it to the internal buffer """
+ """Write queue content to the standard stream and append it to the internal buffer"""
content = b""
while True:
try:
@@ -130,7 +135,7 @@ def read_content(self, queue, stream, is_stderr):
return
def dequeue_output(self):
- """ Check process every 0.1s and forward its outputs to stdout and stderr """
+ """Check process every 0.1s and forward its outputs to stdout and stderr"""
# Poll process and forward its outputs to stdout and stderr
while self.p.poll() is None:
@@ -151,11 +156,11 @@ def dequeue_output(self):
self.finished.emit(self.returncode)
def wait(self, timeout=1):
- """ Wait for the managed process to finish. If timeout=-1, waits indefinitely (and freeze the GUI) """
+ """Wait for the managed process to finish. If timeout=-1, waits indefinitely (and freeze the GUI)"""
self.p.wait(timeout)
def write(self, data):
- """ Send data to the managed process"""
+ """Send data to the managed process"""
try:
self.p.stdin.write((data + "\n").encode("utf8"))
self.p.stdin.flush()
@@ -165,7 +170,7 @@ def write(self, data):
self.finished.emit(self.p.poll())
def kill(self):
- """ Kill the managed process """
+ """Kill the managed process"""
# Process in run with shell=True, so calling self.p.kill() would only kill the shell
# (i.e a text editor launched with !gedit would not close) so we need to iterate
@@ -173,6 +178,7 @@ def kill(self):
try:
import psutil
+
if self.p.returncode is None:
process = psutil.Process(self.p.pid)
for child_process in process.children(recursive=True):
@@ -187,7 +193,7 @@ def kill(self):
self.p.kill()
def __del__(self):
- """ Ensure streams are closed when the process is destroyed """
+ """Ensure streams are closed when the process is destroyed"""
self.p.stdout.close()
self.p.stderr.close()
self.p.stdin.close()
diff --git a/python/core/additions/edit.py b/python/core/additions/edit.py
index 92756d1e8953..b82f268ea0a9 100644
--- a/python/core/additions/edit.py
+++ b/python/core/additions/edit.py
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-
"""
***************************************************************************
edit.py
@@ -17,8 +15,6 @@
***************************************************************************
"""
-from builtins import object
-
class QgsEditError(Exception):
@@ -29,7 +25,7 @@ def __str__(self):
return repr(self.value)
-class edit(object):
+class edit:
def __init__(self, layer):
self.layer = layer
diff --git a/python/core/additions/fromfunction.py b/python/core/additions/fromfunction.py
index 92c3647449b5..7bbe1761a975 100644
--- a/python/core/additions/fromfunction.py
+++ b/python/core/additions/fromfunction.py
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-
"""
***************************************************************************
fromfunction.py
@@ -23,36 +21,38 @@
@staticmethod
-def _fromFunction(description: str,
- function: _typing.Callable,
- *args,
- on_finished: _typing.Optional[_typing.Callable] = None,
- flags=QgsTask.Flag.AllFlags,
- **kwargs) -> QgsTask:
+def _fromFunction(
+ description: str,
+ function: _typing.Callable,
+ *args,
+ on_finished: _typing.Optional[_typing.Callable] = None,
+ flags=QgsTask.Flag.AllFlags,
+ **kwargs
+) -> QgsTask:
"""
-Creates a new QgsTask task from a python function.
+ Creates a new QgsTask task from a python function.
-Example
--------
+ Example
+ -------
-.. code-block:: python
+ .. code-block:: python
- def calculate(task):
- # pretend this is some complex maths and stuff we want
- # to run in the background
- return 5*6
+ def calculate(task):
+ # pretend this is some complex maths and stuff we want
+ # to run in the background
+ return 5*6
- def calculation_finished(exception, value=None):
- if not exception:
- iface.messageBar().pushMessage(
- 'the magic number is {}'.format(value))
- else:
- iface.messageBar().pushMessage(
- str(exception))
+ def calculation_finished(exception, value=None):
+ if not exception:
+ iface.messageBar().pushMessage(
+ 'the magic number is {}'.format(value))
+ else:
+ iface.messageBar().pushMessage(
+ str(exception))
- task = QgsTask.fromFunction('my task', calculate,
- on_finished=calculation_finished)
- QgsApplication.taskManager().addTask(task)
+ task = QgsTask.fromFunction('my task', calculate,
+ on_finished=calculation_finished)
+ QgsApplication.taskManager().addTask(task)
"""
diff --git a/python/core/additions/metaenum.py b/python/core/additions/metaenum.py
index dac7b1b1c464..0d1fb6b39683 100644
--- a/python/core/additions/metaenum.py
+++ b/python/core/additions/metaenum.py
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-
"""
***************************************************************************
metaenum.py
@@ -61,7 +59,9 @@ def metaEnumFromType(enumClass, baseClass=None, raiseException=True):
return metaEnumFromType(enumClass, baseClass, raiseException)
except AttributeError:
if raiseException:
- raise ValueError("Enum type does not implement baseClass method. Provide the base class as argument.")
+ raise ValueError(
+ "Enum type does not implement baseClass method. Provide the base class as argument."
+ )
try:
meta_object = baseClass.staticMetaObject
@@ -71,7 +71,7 @@ def metaEnumFromType(enumClass, baseClass=None, raiseException=True):
META_ENUM_BY_ENUM_CLASS[enumClass] = meta_enum
except AttributeError:
if raiseException:
- raise TypeError("could not get the metaEnum for {}".format(enumClass.__name__))
+ raise TypeError(f"could not get the metaEnum for {enumClass.__name__}")
meta_enum = None
return meta_enum
diff --git a/python/core/additions/projectdirtyblocker.py b/python/core/additions/projectdirtyblocker.py
index 7f06bd0a8412..95cec0432a79 100644
--- a/python/core/additions/projectdirtyblocker.py
+++ b/python/core/additions/projectdirtyblocker.py
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-
"""
***************************************************************************
projectdirtyblocker.py
@@ -17,11 +15,10 @@
***************************************************************************
"""
-
from qgis._core import QgsProjectDirtyBlocker
-class ProjectDirtyBlocker():
+class ProjectDirtyBlocker:
"""
Context manager used to block project setDirty calls.
diff --git a/python/core/additions/providermetadata.py b/python/core/additions/providermetadata.py
index d188f6e26fde..b1a676c37386 100644
--- a/python/core/additions/providermetadata.py
+++ b/python/core/additions/providermetadata.py
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-
"""
***************************************************************************
providermetadata.py
@@ -21,12 +19,12 @@
class PyProviderMetadata(QgsProviderMetadata):
- """ wrapper around QgsProviderMetadata to keep the existing Python code running which registers
- data providers by passing a custom python createProvider() function to QgsProviderMetadata
- constructor. The proper new way of doing it is to subclass QgsProviderMetadata and implement
- its virtual functions.
+ """wrapper around QgsProviderMetadata to keep the existing Python code running which registers
+ data providers by passing a custom python createProvider() function to QgsProviderMetadata
+ constructor. The proper new way of doing it is to subclass QgsProviderMetadata and implement
+ its virtual functions.
- TODO: QGIS 4 - remove this wrapper (only subclassing of QgsProviderMetadata should be used)
+ TODO: QGIS 4 - remove this wrapper (only subclassing of QgsProviderMetadata should be used)
"""
# this is a workaround to keep references to metadata classes
diff --git a/python/core/additions/qgsfeature.py b/python/core/additions/qgsfeature.py
index 4de498f766f8..0bd2a5a23695 100644
--- a/python/core/additions/qgsfeature.py
+++ b/python/core/additions/qgsfeature.py
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-
"""
***************************************************************************
qgsfeature.py
@@ -16,12 +14,18 @@
* *
***************************************************************************
"""
+
from PyQt5.QtCore import QVariant
def _mapping_feature(feature):
geom = feature.geometry()
- properties = {k: None if (v is None or (isinstance(v, QVariant) and v.isNull())) else v for k, v in feature.attributeMap().items()}
- return {'type': 'Feature',
- 'properties': properties,
- 'geometry': geom.__geo_interface__}
+ properties = {
+ k: None if (v is None or (isinstance(v, QVariant) and v.isNull())) else v
+ for k, v in feature.attributeMap().items()
+ }
+ return {
+ "type": "Feature",
+ "properties": properties,
+ "geometry": geom.__geo_interface__,
+ }
diff --git a/python/core/additions/qgsfunction.py b/python/core/additions/qgsfunction.py
index e91e25a7fc0b..32a338dac291 100644
--- a/python/core/additions/qgsfunction.py
+++ b/python/core/additions/qgsfunction.py
@@ -15,13 +15,18 @@
***************************************************************************
"""
-
import inspect
import string
import traceback
from qgis.PyQt.QtCore import QCoreApplication
-from qgis._core import QgsExpressionFunction, QgsExpression, QgsMessageLog, QgsFeatureRequest, Qgis
+from qgis._core import (
+ QgsExpressionFunction,
+ QgsExpression,
+ QgsMessageLog,
+ QgsFeatureRequest,
+ Qgis,
+)
class QgsPyExpressionFunction(QgsExpressionFunction):
@@ -143,7 +148,8 @@ def register_function(
if not QgsExpression.unregisterFunction(name):
msgtitle = QCoreApplication.translate("UserExpressions", "User expressions")
msg = QCoreApplication.translate(
- "UserExpressions", "The user expression {0} already exists and could not be unregistered."
+ "UserExpressions",
+ "The user expression {0} already exists and could not be unregistered.",
).format(name)
QgsMessageLog.logMessage(msg + "\n", msgtitle, Qgis.MessageLevel.Warning)
return None
@@ -154,7 +160,14 @@ def register_function(
# Legacy: if args was not 'auto', parameters were passed as a list
params_as_list = params_as_list or args != "auto"
f = QgsPyExpressionFunction(
- function, name, group, helptext, usesgeometry, referenced_columns, handlesnull, params_as_list
+ function,
+ name,
+ group,
+ helptext,
+ usesgeometry,
+ referenced_columns,
+ handlesnull,
+ params_as_list,
)
if register:
diff --git a/python/core/additions/qgsgeometry.py b/python/core/additions/qgsgeometry.py
index 6d2babfe1f03..63dbdeb5ccd7 100644
--- a/python/core/additions/qgsgeometry.py
+++ b/python/core/additions/qgsgeometry.py
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-
"""
***************************************************************************
qgsgeometry.py
diff --git a/python/core/additions/qgssettings.py b/python/core/additions/qgssettings.py
index a8190a31c7c9..8140211df44c 100644
--- a/python/core/additions/qgssettings.py
+++ b/python/core/additions/qgssettings.py
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-
"""
***************************************************************************
qgssettings.py
@@ -22,7 +20,9 @@
import qgis # required to get base class of enums
-def _qgssettings_enum_value(self, key, enumDefaultValue, section=QgsSettings.Section.NoSection):
+def _qgssettings_enum_value(
+ self, key, enumDefaultValue, section=QgsSettings.Section.NoSection
+):
"""
Return the setting value for a setting based on an enum.
This forces the output to be a valid and existing entry of the enum.
@@ -41,8 +41,11 @@ def _qgssettings_enum_value(self, key, enumDefaultValue, section=QgsSettings.Sec
meta_enum = metaEnumFromValue(enumDefaultValue)
if meta_enum is None or not meta_enum.isValid():
# this should not happen
- raise ValueError("could not get the meta enum for given enum default value (type: {})"
- .format(enumDefaultValue.__class__))
+ raise ValueError(
+ "could not get the meta enum for given enum default value (type: {})".format(
+ enumDefaultValue.__class__
+ )
+ )
str_val = self.value(key, meta_enum.valueToKey(enumDefaultValue), str, section)
# need a new meta enum as QgsSettings.value is making a copy and leads to seg fault (probably a PyQt issue)
@@ -58,7 +61,9 @@ def _qgssettings_enum_value(self, key, enumDefaultValue, section=QgsSettings.Sec
return enu_val
-def _qgssettings_set_enum_value(self, key, enumValue, section=QgsSettings.Section.NoSection):
+def _qgssettings_set_enum_value(
+ self, key, enumValue, section=QgsSettings.Section.NoSection
+):
"""
Save the setting value for a setting based on an enum.
This forces the output to be a valid and existing entry of the enum.
@@ -76,12 +81,16 @@ def _qgssettings_set_enum_value(self, key, enumValue, section=QgsSettings.Sectio
meta_enum = metaEnumFromValue(enumValue)
if meta_enum is None or not meta_enum.isValid():
# this should not happen
- raise ValueError("could not get the meta enum for given enum default value (type: {})".format(type(enumValue)))
+ raise ValueError(
+ f"could not get the meta enum for given enum default value (type: {type(enumValue)})"
+ )
self.setValue(key, meta_enum.valueToKey(enumValue), section)
-def _qgssettings_flag_value(self, key, flagDefaultValue, section=QgsSettings.Section.NoSection):
+def _qgssettings_flag_value(
+ self, key, flagDefaultValue, section=QgsSettings.Section.NoSection
+):
"""
Return the setting value for a setting based on a flag.
This forces the output to be a valid and existing entry of the enum.
@@ -102,13 +111,19 @@ def _qgssettings_flag_value(self, key, flagDefaultValue, section=QgsSettings.Sec
# dirty hack to get the parent class
__import__(flagDefaultValue.__module__)
baseClass = None
- exec("baseClass={module}.{flag_class}".format(module=flagDefaultValue.__module__.replace('_', ''),
- flag_class=flagDefaultValue.__class__.__name__))
+ exec(
+ "baseClass={module}.{flag_class}".format(
+ module=flagDefaultValue.__module__.replace("_", ""),
+ flag_class=flagDefaultValue.__class__.__name__,
+ )
+ )
meta_enum = metaEnumFromValue(flagDefaultValue, baseClass)
if meta_enum is None or not meta_enum.isValid():
# this should not happen
- raise ValueError("could not get the meta enum for given enum default value (type: {})".format(type(flagDefaultValue)))
+ raise ValueError(
+ f"could not get the meta enum for given enum default value (type: {type(flagDefaultValue)})"
+ )
str_val = self.value(key, meta_enum.valueToKeys(flagDefaultValue), str, section)
# need a new meta enum as QgsSettings.value is making a copy and leads to seg fault (probably a PyQt issue)
diff --git a/python/core/additions/qgssettingsentry.py b/python/core/additions/qgssettingsentry.py
index ca55c90e4f66..d07797c0d55c 100644
--- a/python/core/additions/qgssettingsentry.py
+++ b/python/core/additions/qgssettingsentry.py
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-
"""
***************************************************************************
qgssettingsentry.py
@@ -18,7 +16,13 @@
"""
from .metaenum import metaEnumFromValue
-from qgis.core import QgsSettings, QgsSettingsTree, QgsSettingsEntryBase, QgsLogger, Qgis
+from qgis.core import (
+ QgsSettings,
+ QgsSettingsTree,
+ QgsSettingsEntryBase,
+ QgsLogger,
+ Qgis,
+)
import qgis # required to get base class of enums
@@ -29,7 +33,14 @@ class PyQgsSettingsEntryEnumFlag
since QGIS 3.20
"""
- def __init__(self, key, pluginName, defaultValue, description=str(), options=Qgis.SettingsOptions()):
+ def __init__(
+ self,
+ key,
+ pluginName,
+ defaultValue,
+ description="",
+ options=Qgis.SettingsOptions(),
+ ):
"""
Constructor for PyQgsSettingsEntryEnumFlag.
@@ -42,10 +53,12 @@ def __init__(self, key, pluginName, defaultValue, description=str(), options=Qgi
# TODO QGIS 4: rename pluginName arg to parent and key to name
self.options = options
- defaultValueStr = str()
+ defaultValueStr = ""
self.__metaEnum = metaEnumFromValue(defaultValue)
if self.__metaEnum is None or not self.__metaEnum.isValid():
- QgsLogger.debug("Invalid metaenum. Enum/Flag probably misses Q_ENUM/Q_FLAG declaration. Settings key: '{0}'".format(self.key()))
+ QgsLogger.debug(
+ f"Invalid metaenum. Enum/Flag probably misses Q_ENUM/Q_FLAG declaration. Settings key: '{self.key()}'"
+ )
else:
if self.__metaEnum.isFlag():
defaultValueStr = self.__metaEnum.valueToKeys(defaultValue)
@@ -75,9 +88,13 @@ def value(self, dynamicKeyPart=None):
:param dynamicKeyPart: argument specifies the dynamic part of the settings key.
"""
if self.__metaEnum.isFlag():
- return QgsSettings().flagValue(self.key(dynamicKeyPart), self.defaultValue())
+ return QgsSettings().flagValue(
+ self.key(dynamicKeyPart), self.defaultValue()
+ )
else:
- return QgsSettings().enumValue(self.key(dynamicKeyPart), self.defaultValue())
+ return QgsSettings().enumValue(
+ self.key(dynamicKeyPart), self.defaultValue()
+ )
def valueWithDefaultOverride(self, defaultValueOverride, dynamicKeyPart=None):
"""
@@ -87,9 +104,13 @@ def valueWithDefaultOverride(self, defaultValueOverride, dynamicKeyPart=None):
:param dynamicKeyPart: argument specifies the dynamic part of the settings key.
"""
if self.__metaEnum.isFlag():
- return QgsSettings().flagValue(self.key(dynamicKeyPart), defaultValueOverride)
+ return QgsSettings().flagValue(
+ self.key(dynamicKeyPart), defaultValueOverride
+ )
else:
- return QgsSettings().enumValue(self.key(dynamicKeyPart), defaultValueOverride)
+ return QgsSettings().enumValue(
+ self.key(dynamicKeyPart), defaultValueOverride
+ )
def defaultValue(self):
"""
@@ -97,7 +118,9 @@ def defaultValue(self):
"""
if self.__metaEnum is None or not self.__metaEnum.isValid():
- QgsLogger.debug("Invalid metaenum. Enum/Flag probably misses Q_ENUM/Q_FLAG declaration. Settings key: '{0}'".format(self.key()))
+ QgsLogger.debug(
+ f"Invalid metaenum. Enum/Flag probably misses Q_ENUM/Q_FLAG declaration. Settings key: '{self.key()}'"
+ )
return -1
defaultValueString = self.defaultValueAsVariant()
@@ -106,7 +129,9 @@ def defaultValue(self):
else:
(defaultValue, ok) = self.__metaEnum.keyToValue(defaultValueString)
if not ok:
- QgsLogger.debug("Invalid enum/flag key/s '{0}'.".format(self.defaultValueAsVariant()))
+ QgsLogger.debug(
+ f"Invalid enum/flag key/s '{self.defaultValueAsVariant()}'."
+ )
return -1
# cast to the enum class
@@ -122,7 +147,9 @@ def setValue(self, value, dynamicKeyPart: (list, str) = None):
"""
if self.__metaEnum is None or not self.__metaEnum.isValid():
- QgsLogger.debug("Invalid metaenum. Enum/Flag probably misses Q_ENUM/Q_FLAG declaration. Settings key: '{0}'".format(self.key()))
+ QgsLogger.debug(
+ f"Invalid metaenum. Enum/Flag probably misses Q_ENUM/Q_FLAG declaration. Settings key: '{self.key()}'"
+ )
return False
if self.options & Qgis.SettingsOption.SaveEnumFlagAsInt:
@@ -133,7 +160,7 @@ def setValue(self, value, dynamicKeyPart: (list, str) = None):
else:
enum_flag_key = self.__metaEnum.valueToKey(value)
if not enum_flag_key:
- QgsLogger.debug("Invalid enum/flag value '{0}'.".format(value))
+ QgsLogger.debug(f"Invalid enum/flag value '{value}'.")
return False
if type(dynamicKeyPart) is str:
diff --git a/python/core/additions/qgstaskwrapper.py b/python/core/additions/qgstaskwrapper.py
index 6c2b7560d812..a3a7d8c347bf 100644
--- a/python/core/additions/qgstaskwrapper.py
+++ b/python/core/additions/qgstaskwrapper.py
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-
"""
***************************************************************************
qgstaskwrapper.py
@@ -17,7 +15,6 @@
***************************************************************************
"""
-
from qgis._core import QgsTask
@@ -47,7 +44,7 @@ def finished(self, result):
return
if not result and self.exception is None:
- self.exception = Exception('Task canceled')
+ self.exception = Exception("Task canceled")
try:
if self.returned_values:
diff --git a/python/core/additions/readwritecontextentercategory.py b/python/core/additions/readwritecontextentercategory.py
index af9c509342cd..79a9c44e8bac 100644
--- a/python/core/additions/readwritecontextentercategory.py
+++ b/python/core/additions/readwritecontextentercategory.py
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-
"""
***************************************************************************
readwritecontextentercategory.py
@@ -18,7 +16,7 @@
"""
-class ReadWriteContextEnterCategory():
+class ReadWriteContextEnterCategory:
"""
Push a category to the stack
diff --git a/python/core/additions/runtimeprofiler.py b/python/core/additions/runtimeprofiler.py
index 2216f5609e9d..95758a1ce899 100644
--- a/python/core/additions/runtimeprofiler.py
+++ b/python/core/additions/runtimeprofiler.py
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-
"""
***************************************************************************
runtimeprofiler.py
@@ -17,11 +15,10 @@
***************************************************************************
"""
-
from qgis._core import QgsScopedRuntimeProfile
-class ScopedRuntimeProfileContextManager():
+class ScopedRuntimeProfileContextManager:
"""
Context manager used to profile blocks of code in the QgsApplication.profiler() registry.
diff --git a/python/core/additions/validitycheck.py b/python/core/additions/validitycheck.py
index 25fdd1586f09..37a32b9cf5e1 100644
--- a/python/core/additions/validitycheck.py
+++ b/python/core/additions/validitycheck.py
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-
"""
***************************************************************************
validitycheck.py
@@ -16,9 +14,8 @@
* *
***************************************************************************
"""
-from qgis._core import (
- QgsAbstractValidityCheck,
- QgsApplication)
+
+from qgis._core import QgsAbstractValidityCheck, QgsApplication
class CheckFactory:
diff --git a/python/core/contextmanagers.py b/python/core/contextmanagers.py
index 62e0c624659d..72be360097e6 100644
--- a/python/core/contextmanagers.py
+++ b/python/core/contextmanagers.py
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-
"""
***************************************************************************
contextmanagers.py
@@ -17,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Nathan Woodrow'
-__date__ = 'May 2014'
-__copyright__ = '(C) 2014, Nathan Woodrow'
+__author__ = "Nathan Woodrow"
+__date__ = "May 2014"
+__copyright__ = "(C) 2014, Nathan Woodrow"
import sys
from contextlib import contextmanager
diff --git a/python/custom_widgets/qgis_customwidgets.py b/python/custom_widgets/qgis_customwidgets.py
index ade5d47bec89..90ca5579a479 100644
--- a/python/custom_widgets/qgis_customwidgets.py
+++ b/python/custom_widgets/qgis_customwidgets.py
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-
"""
***************************************************************************
customwidgets.py
@@ -50,8 +48,9 @@
def moduleInformation():
try:
import qgis.gui
+
widget_list = dir(qgis.gui)
- widget_list.remove('QgsScrollArea')
+ widget_list.remove("QgsScrollArea")
return "qgis.gui", widget_list
except ImportError:
return "", []
diff --git a/python/gui/additions/qgssettingsenumflageditorwrapper.py b/python/gui/additions/qgssettingsenumflageditorwrapper.py
index 245b0470a35f..528adb8192a2 100644
--- a/python/gui/additions/qgssettingsenumflageditorwrapper.py
+++ b/python/gui/additions/qgssettingsenumflageditorwrapper.py
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-
"""
***************************************************************************
qgssettingsenumflageditorwrapper.py
@@ -28,7 +26,9 @@ class PyQgsSettingsEnumEditorWidgetWrapper(QgsSettingsEditorWidgetWrapper):
A settings editor widget wrapper for enum settings as PyQgsSettingsEntryEnumFlag
"""
- def __init__(self, parent=None, editor=None, setting=None, displayStrings: dict = None):
+ def __init__(
+ self, parent=None, editor=None, setting=None, displayStrings: dict = None
+ ):
self.setting = setting
self.editor = editor
self.displayStrings = {}
@@ -39,19 +39,23 @@ def __init__(self, parent=None, editor=None, setting=None, displayStrings: dict
self.configureEditor(editor, setting)
def id(self):
- return 'py-enum'
+ return "py-enum"
def createWrapper(self, parent=None):
return PyQgsSettingsEnumEditorWidgetWrapper(parent)
def setWidgetFromSetting(self):
if self.setting:
- return self.setWidgetFromVariant(self.setting.valueAsVariant(self.dynamicKeyPartList()))
+ return self.setWidgetFromVariant(
+ self.setting.valueAsVariant(self.dynamicKeyPartList())
+ )
return False
def setSettingFromWidget(self):
if self.editor:
- self.setting.setVariantValue(self.variantValueFromWidget(), self.dynamicKeyPartList())
+ self.setting.setVariantValue(
+ self.variantValueFromWidget(), self.dynamicKeyPartList()
+ )
return True
else:
return False
@@ -88,4 +92,7 @@ def configureEditorPrivate(self, editor: QComboBox, setting: QgsSettingsEntryBas
def enableAutomaticUpdatePrivate(self):
self.editor.currentIndexChanged.connect(
- lambda: self.setting.setValue(self.editor.currentData(), self.dynamicKeyPartList()))
+ lambda: self.setting.setValue(
+ self.editor.currentData(), self.dynamicKeyPartList()
+ )
+ )
diff --git a/python/plugins/MetaSearch/__init__.py b/python/plugins/MetaSearch/__init__.py
index ae8a29158156..069a287012c2 100644
--- a/python/plugins/MetaSearch/__init__.py
+++ b/python/plugins/MetaSearch/__init__.py
@@ -26,4 +26,5 @@
def classFactory(iface):
"""invoke plugin"""
from MetaSearch.plugin import MetaSearchPlugin
+
return MetaSearchPlugin(iface)
diff --git a/python/plugins/MetaSearch/dialogs/apidialog.py b/python/plugins/MetaSearch/dialogs/apidialog.py
index 03edfe8af3ff..a774f8af899a 100644
--- a/python/plugins/MetaSearch/dialogs/apidialog.py
+++ b/python/plugins/MetaSearch/dialogs/apidialog.py
@@ -24,17 +24,11 @@
import json
-from qgis.PyQt.QtWidgets import (
- QDialog,
- QVBoxLayout
-)
-from qgis.gui import (
- QgsCodeEditorJson,
- QgsCodeEditorHTML
-)
+from qgis.PyQt.QtWidgets import QDialog, QVBoxLayout
+from qgis.gui import QgsCodeEditorJson, QgsCodeEditorHTML
from MetaSearch.util import get_ui_class, prettify_xml
-BASE_CLASS = get_ui_class('apidialog.ui')
+BASE_CLASS = get_ui_class("apidialog.ui")
class APIRequestResponseDialog(QDialog, BASE_CLASS):
@@ -46,7 +40,7 @@ def __init__(self, request, response, mime_type: str):
self.setupUi(self)
- if mime_type == 'json':
+ if mime_type == "json":
self.txtbrAPIRequest = QgsCodeEditorJson()
self.txtbrAPIResponse = QgsCodeEditorJson()
self.txtbrAPIRequest.setText(json.dumps(request, indent=4))
diff --git a/python/plugins/MetaSearch/dialogs/maindialog.py b/python/plugins/MetaSearch/dialogs/maindialog.py
index 96419750c4f3..36ece1f5c57b 100644
--- a/python/plugins/MetaSearch/dialogs/maindialog.py
+++ b/python/plugins/MetaSearch/dialogs/maindialog.py
@@ -31,15 +31,29 @@
from urllib.request import build_opener, install_opener, ProxyHandler
from qgis.PyQt.QtCore import Qt
-from qgis.PyQt.QtWidgets import (QDialog, QComboBox,
- QDialogButtonBox, QMessageBox,
- QTreeWidgetItem, QWidget)
+from qgis.PyQt.QtWidgets import (
+ QDialog,
+ QComboBox,
+ QDialogButtonBox,
+ QMessageBox,
+ QTreeWidgetItem,
+ QWidget,
+)
from qgis.PyQt.QtGui import QColor
-from qgis.core import (Qgis, QgsApplication, QgsCoordinateReferenceSystem,
- QgsCoordinateTransform, QgsGeometry, QgsPointXY,
- QgsProviderRegistry, QgsSettings, QgsProject,
- QgsRectangle, QgsSettingsTree)
+from qgis.core import (
+ Qgis,
+ QgsApplication,
+ QgsCoordinateReferenceSystem,
+ QgsCoordinateTransform,
+ QgsGeometry,
+ QgsPointXY,
+ QgsProviderRegistry,
+ QgsSettings,
+ QgsProject,
+ QgsRectangle,
+ QgsSettingsTree,
+)
from qgis.gui import QgsRubberBand, QgsGui
from qgis.utils import OverrideCursor
@@ -54,12 +68,19 @@
from MetaSearch.dialogs.recorddialog import RecordDialog
from MetaSearch.dialogs.apidialog import APIRequestResponseDialog
from MetaSearch.search_backend import get_catalog_service
-from MetaSearch.util import (clean_ows_url, get_connections_from_file,
- get_ui_class, get_help_url,
- normalize_text, open_url, render_template,
- serialize_string, StaticContext)
+from MetaSearch.util import (
+ clean_ows_url,
+ get_connections_from_file,
+ get_ui_class,
+ get_help_url,
+ normalize_text,
+ open_url,
+ render_template,
+ serialize_string,
+ StaticContext,
+)
-BASE_CLASS = get_ui_class('maindialog.ui')
+BASE_CLASS = get_ui_class("maindialog.ui")
class MetaSearchDialog(QDialog, BASE_CLASS):
@@ -82,9 +103,9 @@ def __init__(self, iface):
self.context = StaticContext()
self.leKeywords.setShowSearchIcon(True)
- self.leKeywords.setPlaceholderText(self.tr('Search keywords'))
+ self.leKeywords.setPlaceholderText(self.tr("Search keywords"))
- self.setWindowTitle(self.tr('MetaSearch'))
+ self.setWindowTitle(self.tr("MetaSearch"))
self.rubber_band = QgsRubberBand(self.map, Qgis.GeometryType.Polygon)
self.rubber_band.setColor(QColor(255, 0, 0, 75))
@@ -93,10 +114,11 @@ def __init__(self, iface):
# form inputs
self.startfrom = 1
self.constraints = []
- self.maxrecords = int(self.settings.value('/MetaSearch/returnRecords', 10))
- self.timeout = int(self.settings.value('/MetaSearch/timeout', 10))
+ self.maxrecords = int(self.settings.value("/MetaSearch/returnRecords", 10))
+ self.timeout = int(self.settings.value("/MetaSearch/timeout", 10))
self.disable_ssl_verification = self.settings.value(
- '/MetaSearch/disableSSL', False, bool)
+ "/MetaSearch/disableSSL", False, bool
+ )
# Services tab
self.cmbConnectionsServices.activated.connect(self.save_connection)
@@ -119,7 +141,9 @@ def __init__(self, iface):
self.btnSearch.clicked.connect(self.search)
self.leKeywords.returnPressed.connect(self.search)
# prevent dialog from closing upon pressing enter
- self.buttonBox.button(QDialogButtonBox.StandardButton.Close).setAutoDefault(False)
+ self.buttonBox.button(QDialogButtonBox.StandardButton.Close).setAutoDefault(
+ False
+ )
# launch help from button
self.buttonBox.helpRequested.connect(self.help)
self.btnCanvasBbox.setAutoDefault(False)
@@ -144,16 +168,17 @@ def __init__(self, iface):
def manageGui(self):
"""open window"""
+
def _on_timeout_change(value):
- self.settings.setValue('/MetaSearch/timeout', value)
+ self.settings.setValue("/MetaSearch/timeout", value)
self.timeout = value
def _on_records_change(value):
- self.settings.setValue('/MetaSearch/returnRecords', value)
+ self.settings.setValue("/MetaSearch/returnRecords", value)
self.maxrecords = value
def _on_ssl_state_change(state):
- self.settings.setValue('/MetaSearch/disableSSL', bool(state))
+ self.settings.setValue("/MetaSearch/disableSSL", bool(state))
self.disable_ssl_verification = bool(state)
self.tabWidget.setCurrentIndex(0)
@@ -168,11 +193,11 @@ def _on_ssl_state_change(state):
self.disableSSLVerification.setChecked(self.disable_ssl_verification)
self.disableSSLVerification.stateChanged.connect(_on_ssl_state_change)
- key = '/MetaSearch/%s' % self.cmbConnectionsSearch.currentText()
- self.catalog_url = self.settings.value('%s/url' % key)
- self.catalog_username = self.settings.value('%s/username' % key)
- self.catalog_password = self.settings.value('%s/password' % key)
- self.catalog_type = self.settings.value('%s/catalog-type' % key)
+ key = "/MetaSearch/%s" % self.cmbConnectionsSearch.currentText()
+ self.catalog_url = self.settings.value("%s/url" % key)
+ self.catalog_username = self.settings.value("%s/username" % key)
+ self.catalog_password = self.settings.value("%s/password" % key)
+ self.catalog_type = self.settings.value("%s/catalog-type" % key)
self.set_bbox_global()
@@ -186,7 +211,7 @@ def _on_ssl_state_change(state):
def populate_connection_list(self):
"""populate select box with connections"""
- self.settings.beginGroup('/MetaSearch/')
+ self.settings.beginGroup("/MetaSearch/")
self.cmbConnectionsServices.clear()
self.cmbConnectionsServices.addItems(self.settings.childGroups())
self.cmbConnectionsSearch.clear()
@@ -202,11 +227,13 @@ def populate_connection_list(self):
# and start with connection tab open
self.tabWidget.setCurrentIndex(1)
# tell the user to add services
- msg = self.tr('No services/connections defined. To get '
- 'started with MetaSearch, create a new '
- 'connection by clicking \'New\' or click '
- '\'Add default services\'.')
- self.textMetadata.setHtml('
%s
' % msg)
+ msg = self.tr(
+ "No services/connections defined. To get "
+ "started with MetaSearch, create a new "
+ "connection by clicking 'New' or click "
+ "'Add default services'."
+ )
+ self.textMetadata.setHtml("
%s " % msg)
else:
# connections - enable various buttons
state_disabled = True
@@ -217,7 +244,7 @@ def populate_connection_list(self):
def set_connection_list_position(self):
"""set the current index to the selected connection"""
- to_select = self.settings.value('/MetaSearch/selected')
+ to_select = self.settings.value("/MetaSearch/selected")
conn_count = self.cmbConnectionsServices.count()
if conn_count == 0:
@@ -256,21 +283,21 @@ def save_connection(self):
caller = self.sender().objectName()
- if caller == 'cmbConnectionsServices': # servers tab
+ if caller == "cmbConnectionsServices": # servers tab
current_text = self.cmbConnectionsServices.currentText()
- elif caller == 'cmbConnectionsSearch': # search tab
+ elif caller == "cmbConnectionsSearch": # search tab
current_text = self.cmbConnectionsSearch.currentText()
- self.settings.setValue('/MetaSearch/selected', current_text)
- key = '/MetaSearch/%s' % current_text
+ self.settings.setValue("/MetaSearch/selected", current_text)
+ key = "/MetaSearch/%s" % current_text
- if caller == 'cmbConnectionsSearch': # bind to service in search tab
- self.catalog_url = self.settings.value('%s/url' % key)
- self.catalog_username = self.settings.value('%s/username' % key)
- self.catalog_password = self.settings.value('%s/password' % key)
- self.catalog_type = self.settings.value('%s/catalog-type' % key)
+ if caller == "cmbConnectionsSearch": # bind to service in search tab
+ self.catalog_url = self.settings.value("%s/url" % key)
+ self.catalog_username = self.settings.value("%s/username" % key)
+ self.catalog_password = self.settings.value("%s/password" % key)
+ self.catalog_type = self.settings.value("%s/catalog-type" % key)
- if caller == 'cmbConnectionsServices': # clear server metadata
+ if caller == "cmbConnectionsServices": # clear server metadata
self.textMetadata.clear()
self.btnRawAPIResponse.setEnabled(False)
@@ -279,11 +306,11 @@ def connection_info(self):
"""show connection info"""
current_text = self.cmbConnectionsServices.currentText()
- key = '/MetaSearch/%s' % current_text
- self.catalog_url = self.settings.value('%s/url' % key)
- self.catalog_username = self.settings.value('%s/username' % key)
- self.catalog_password = self.settings.value('%s/password' % key)
- self.catalog_type = self.settings.value('%s/catalog-type' % key)
+ key = "/MetaSearch/%s" % current_text
+ self.catalog_url = self.settings.value("%s/url" % key)
+ self.catalog_username = self.settings.value("%s/username" % key)
+ self.catalog_password = self.settings.value("%s/password" % key)
+ self.catalog_type = self.settings.value("%s/catalog-type" % key)
# connect to the server
if not self._get_catalog():
@@ -291,9 +318,12 @@ def connection_info(self):
if self.catalog: # display service metadata
self.btnRawAPIResponse.setEnabled(True)
- metadata = render_template('en', self.context,
- self.catalog.conn,
- self.catalog.service_info_template)
+ metadata = render_template(
+ "en",
+ self.context,
+ self.catalog.conn,
+ self.catalog.service_info_template,
+ )
style = QgsApplication.reportStyleSheet()
self.textMetadata.clear()
self.textMetadata.document().setDefaultStyleSheet(style)
@@ -306,7 +336,7 @@ def add_connection(self):
"""add new service"""
conn_new = NewConnectionDialog()
- conn_new.setWindowTitle(self.tr('New Catalog Service'))
+ conn_new.setWindowTitle(self.tr("New Catalog Service"))
if conn_new.exec() == QDialog.DialogCode.Accepted: # add to service list
self.populate_connection_list()
self.textMetadata.clear()
@@ -316,19 +346,22 @@ def edit_connection(self):
current_text = self.cmbConnectionsServices.currentText()
- url = self.settings.value('/MetaSearch/%s/url' % current_text)
+ url = self.settings.value("/MetaSearch/%s/url" % current_text)
conn_edit = NewConnectionDialog(current_text)
- conn_edit.setWindowTitle(self.tr('Edit Catalog Service'))
+ conn_edit.setWindowTitle(self.tr("Edit Catalog Service"))
conn_edit.leName.setText(current_text)
conn_edit.leURL.setText(url)
conn_edit.leUsername.setText(
- self.settings.value('/MetaSearch/%s/username' % current_text))
+ self.settings.value("/MetaSearch/%s/username" % current_text)
+ )
conn_edit.lePassword.setText(
- self.settings.value('/MetaSearch/%s/password' % current_text))
+ self.settings.value("/MetaSearch/%s/password" % current_text)
+ )
conn_edit.cmbCatalogType.setCurrentText(
- self.settings.value('/MetaSearch/%s/catalog-type' % current_text))
+ self.settings.value("/MetaSearch/%s/catalog-type" % current_text)
+ )
if conn_edit.exec() == QDialog.DialogCode.Accepted: # update service list
self.populate_connection_list()
@@ -338,13 +371,17 @@ def delete_connection(self):
current_text = self.cmbConnectionsServices.currentText()
- key = '/MetaSearch/%s' % current_text
+ key = "/MetaSearch/%s" % current_text
- msg = self.tr('Remove service {0}?').format(current_text)
+ msg = self.tr("Remove service {0}?").format(current_text)
result = QMessageBox.question(
- self, self.tr('Delete Service'), msg,
- QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No, QMessageBox.StandardButton.No)
+ self,
+ self.tr("Delete Service"),
+ msg,
+ QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No,
+ QMessageBox.StandardButton.No,
+ )
if result == QMessageBox.StandardButton.Yes: # remove service from list
self.settings.remove(key)
index_to_delete = self.cmbConnectionsServices.currentIndex()
@@ -361,32 +398,39 @@ def load_connections(self):
def add_default_connections(self):
"""add default connections"""
- filename = os.path.join(self.context.ppath,
- 'resources', 'connections-default.xml')
+ filename = os.path.join(
+ self.context.ppath, "resources", "connections-default.xml"
+ )
doc = get_connections_from_file(self, filename)
if doc is None:
return
- self.settings.beginGroup('/MetaSearch/')
+ self.settings.beginGroup("/MetaSearch/")
keys = self.settings.childGroups()
self.settings.endGroup()
- for server in doc.findall('csw'):
- name = server.attrib.get('name')
+ for server in doc.findall("csw"):
+ name = server.attrib.get("name")
# check for duplicates
if name in keys:
- msg = self.tr('{0} exists. Overwrite?').format(name)
- res = QMessageBox.warning(self,
- self.tr('Loading connections'), msg,
- QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No)
+ msg = self.tr("{0} exists. Overwrite?").format(name)
+ res = QMessageBox.warning(
+ self,
+ self.tr("Loading connections"),
+ msg,
+ QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No,
+ )
if res != QMessageBox.StandardButton.Yes:
continue
# no dups detected or overwrite is allowed
- key = '/MetaSearch/%s' % name
- self.settings.setValue('%s/url' % key, server.attrib.get('url'))
- self.settings.setValue('%s/catalog-type' % key, server.attrib.get('catalog-type', 'OGC CSW 2.0.2'))
+ key = "/MetaSearch/%s" % name
+ self.settings.setValue("%s/url" % key, server.attrib.get("url"))
+ self.settings.setValue(
+ "%s/catalog-type" % key,
+ server.attrib.get("catalog-type", "OGC CSW 2.0.2"),
+ )
self.populate_connection_list()
@@ -395,17 +439,17 @@ def add_default_connections(self):
def set_ows_save_title_ask(self):
"""save ows save strategy as save ows title, ask if duplicate"""
- self.settings.setValue('/MetaSearch/ows_save_strategy', 'title_ask')
+ self.settings.setValue("/MetaSearch/ows_save_strategy", "title_ask")
def set_ows_save_title_no_ask(self):
"""save ows save strategy as save ows title, do NOT ask if duplicate"""
- self.settings.setValue('/MetaSearch/ows_save_strategy', 'title_no_ask')
+ self.settings.setValue("/MetaSearch/ows_save_strategy", "title_no_ask")
def set_ows_save_temp_name(self):
"""save ows save strategy as save with a temporary name"""
- self.settings.setValue('/MetaSearch/ows_save_strategy', 'temp_name')
+ self.settings.setValue("/MetaSearch/ows_save_strategy", "temp_name")
# Search tab
@@ -417,14 +461,12 @@ def set_bbox_from_map(self):
extent = self.map.extent()
- if crsid != 'EPSG:4326': # reproject to EPSG:4326
+ if crsid != "EPSG:4326": # reproject to EPSG:4326
src = QgsCoordinateReferenceSystem(crsid)
dest = QgsCoordinateReferenceSystem("EPSG:4326")
xform = QgsCoordinateTransform(src, dest, QgsProject.instance())
- minxy = xform.transform(QgsPointXY(extent.xMinimum(),
- extent.yMinimum()))
- maxxy = xform.transform(QgsPointXY(extent.xMaximum(),
- extent.yMaximum()))
+ minxy = xform.transform(QgsPointXY(extent.xMinimum(), extent.yMinimum()))
+ maxxy = xform.transform(QgsPointXY(extent.xMaximum(), extent.yMaximum()))
minx, miny = minxy
maxx, maxy = maxxy
else: # EPSG:4326
@@ -440,10 +482,10 @@ def set_bbox_from_map(self):
def set_bbox_global(self):
"""set global bounding box"""
- self.leNorth.setText('90')
- self.leSouth.setText('-90')
- self.leWest.setText('-180')
- self.leEast.setText('180')
+ self.leNorth.setText("90")
+ self.leSouth.setText("-90")
+ self.leWest.setText("-180")
+ self.leEast.setText("180")
def search(self):
"""execute search"""
@@ -456,11 +498,11 @@ def search(self):
# set current catalog
current_text = self.cmbConnectionsSearch.currentText()
- key = '/MetaSearch/%s' % current_text
- self.catalog_url = self.settings.value('%s/url' % key)
- self.catalog_username = self.settings.value('%s/username' % key)
- self.catalog_password = self.settings.value('%s/password' % key)
- self.catalog_type = self.settings.value('%s/catalog-type' % key)
+ key = "/MetaSearch/%s" % current_text
+ self.catalog_url = self.settings.value("%s/url" % key)
+ self.catalog_username = self.settings.value("%s/username" % key)
+ self.catalog_password = self.settings.value("%s/password" % key)
+ self.catalog_type = self.settings.value("%s/catalog-type" % key)
# start position and number of records to return
self.startfrom = 1
@@ -483,16 +525,18 @@ def search(self):
# to find ('service', 'dataset', etc.)
try:
with OverrideCursor(Qt.CursorShape.WaitCursor):
- self.catalog.query_records(bbox, keywords, self.maxrecords,
- self.startfrom)
+ self.catalog.query_records(
+ bbox, keywords, self.maxrecords, self.startfrom
+ )
except Exception as err:
- QMessageBox.warning(self, self.tr('Search error'),
- self.tr('Search error: {0}').format(err))
+ QMessageBox.warning(
+ self, self.tr("Search error"), self.tr("Search error: {0}").format(err)
+ )
return
if self.catalog.matches == 0:
- self.lblResults.setText(self.tr('0 results'))
+ self.lblResults.setText(self.tr("0 results"))
return
self.display_results()
@@ -504,21 +548,24 @@ def display_results(self):
position = self.catalog.returned + self.startfrom - 1
- msg = self.tr('Showing {0} - {1} of %n result(s)', 'number of results',
- self.catalog.matches).format(self.startfrom, position)
+ msg = self.tr(
+ "Showing {0} - {1} of %n result(s)",
+ "number of results",
+ self.catalog.matches,
+ ).format(self.startfrom, position)
self.lblResults.setText(msg)
for rec in self.catalog.records():
item = QTreeWidgetItem(self.treeRecords)
- if rec['type']:
- item.setText(0, normalize_text(rec['type']))
+ if rec["type"]:
+ item.setText(0, normalize_text(rec["type"]))
else:
- item.setText(0, 'unknown')
- if rec['title']:
- item.setText(1, normalize_text(rec['title']))
- if rec['identifier']:
- set_item_data(item, 'identifier', rec['identifier'])
+ item.setText(0, "unknown")
+ if rec["title"]:
+ item.setText(1, normalize_text(rec["title"]))
+ if rec["identifier"]:
+ set_item_data(item, "identifier", rec["identifier"])
self.btnViewRawAPIResponse.setEnabled(True)
@@ -555,36 +602,43 @@ def record_clicked(self):
if not item:
return
- identifier = get_item_data(item, 'identifier')
+ identifier = get_item_data(item, "identifier")
try:
- record = next(item for item in self.catalog.records()
- if item['identifier'] == identifier)
+ record = next(
+ item
+ for item in self.catalog.records()
+ if item["identifier"] == identifier
+ )
except KeyError:
- QMessageBox.warning(self,
- self.tr('Record parsing error'),
- 'Unable to locate record identifier')
+ QMessageBox.warning(
+ self,
+ self.tr("Record parsing error"),
+ "Unable to locate record identifier",
+ )
return
# if the record has a bbox, show a footprint on the map
- if record['bbox'] is not None:
- bx = record['bbox']
- rt = QgsRectangle(float(bx['minx']), float(bx['miny']),
- float(bx['maxx']), float(bx['maxy']))
+ if record["bbox"] is not None:
+ bx = record["bbox"]
+ rt = QgsRectangle(
+ float(bx["minx"]),
+ float(bx["miny"]),
+ float(bx["maxx"]),
+ float(bx["maxy"]),
+ )
geom = QgsGeometry.fromRect(rt)
if geom is not None:
src = QgsCoordinateReferenceSystem("EPSG:4326")
dst = self.map.mapSettings().destinationCrs()
if src.postgisSrid() != dst.postgisSrid():
- ctr = QgsCoordinateTransform(
- src, dst, QgsProject.instance())
+ ctr = QgsCoordinateTransform(src, dst, QgsProject.instance())
try:
geom.transform(ctr)
except Exception as err:
QMessageBox.warning(
- self,
- self.tr('Coordinate Transformation Error'),
- str(err))
+ self, self.tr("Coordinate Transformation Error"), str(err)
+ )
self.rubber_band.setToGeometry(geom, None)
# figure out if the data is interactive and can be operated on
@@ -594,73 +648,78 @@ def find_services(self, record, item):
"""scan record for WMS/WMTS|WFS|WCS endpoints"""
services = {}
- for link in record['links']:
+ for link in record["links"]:
link = self.catalog.parse_link(link)
- if 'scheme' in link:
- link_type = link['scheme']
- elif 'protocol' in link:
- link_type = link['protocol']
+ if "scheme" in link:
+ link_type = link["scheme"]
+ elif "protocol" in link:
+ link_type = link["protocol"]
else:
link_type = None
if link_type is not None:
link_type = link_type.upper()
- wmswmst_link_types = list(
- map(str.upper, link_types.WMSWMST_LINK_TYPES))
+ wmswmst_link_types = list(map(str.upper, link_types.WMSWMST_LINK_TYPES))
wfs_link_types = list(map(str.upper, link_types.WFS_LINK_TYPES))
wcs_link_types = list(map(str.upper, link_types.WCS_LINK_TYPES))
ams_link_types = list(map(str.upper, link_types.AMS_LINK_TYPES))
afs_link_types = list(map(str.upper, link_types.AFS_LINK_TYPES))
- gis_file_link_types = list(
- map(str.upper, link_types.GIS_FILE_LINK_TYPES))
+ gis_file_link_types = list(map(str.upper, link_types.GIS_FILE_LINK_TYPES))
# if the link type exists, and it is one of the acceptable
# interactive link types, then set
- all_link_types = (wmswmst_link_types + wfs_link_types +
- wcs_link_types + ams_link_types +
- afs_link_types + gis_file_link_types)
+ all_link_types = (
+ wmswmst_link_types
+ + wfs_link_types
+ + wcs_link_types
+ + ams_link_types
+ + afs_link_types
+ + gis_file_link_types
+ )
if all([link_type is not None, link_type in all_link_types]):
if link_type in wmswmst_link_types:
- services['wms'] = link['url']
+ services["wms"] = link["url"]
self.mActionAddWms.setEnabled(True)
if link_type in wfs_link_types:
- services['wfs'] = link['url']
+ services["wfs"] = link["url"]
self.mActionAddWfs.setEnabled(True)
if link_type in wcs_link_types:
- services['wcs'] = link['url']
+ services["wcs"] = link["url"]
self.mActionAddWcs.setEnabled(True)
if link_type in ams_link_types:
- services['ams'] = link['url']
+ services["ams"] = link["url"]
self.mActionAddAms.setEnabled(True)
if link_type in afs_link_types:
- services['afs'] = link['url']
+ services["afs"] = link["url"]
self.mActionAddAfs.setEnabled(True)
if link_type in gis_file_link_types:
- services['gis_file'] = link['url']
- services['title'] = record.get('title', '')
+ services["gis_file"] = link["url"]
+ services["title"] = record.get("title", "")
self.mActionAddGisFile.setEnabled(True)
self.tbAddData.setEnabled(True)
- set_item_data(item, 'link', json.dumps(services))
+ set_item_data(item, "link", json.dumps(services))
def navigate(self):
"""manage navigation / paging"""
caller = self.sender().objectName()
- if caller == 'btnFirst':
+ if caller == "btnFirst":
self.startfrom = 1
- elif caller == 'btnLast':
+ elif caller == "btnLast":
self.startfrom = self.catalog.matches - self.maxrecords + 1
- elif caller == 'btnNext':
+ elif caller == "btnNext":
if self.startfrom > self.catalog.matches - self.maxrecords:
- msg = self.tr('End of results. Go to start?')
- res = QMessageBox.information(self, self.tr('Navigation'),
- msg,
- (QMessageBox.StandardButton.Ok |
- QMessageBox.StandardButton.Cancel))
+ msg = self.tr("End of results. Go to start?")
+ res = QMessageBox.information(
+ self,
+ self.tr("Navigation"),
+ msg,
+ (QMessageBox.StandardButton.Ok | QMessageBox.StandardButton.Cancel),
+ )
if res == QMessageBox.StandardButton.Ok:
self.startfrom = 1
else:
@@ -669,14 +728,15 @@ def navigate(self):
self.startfrom += self.maxrecords
elif caller == "btnPrev":
if self.startfrom == 1:
- msg = self.tr('Start of results. Go to end?')
- res = QMessageBox.information(self, self.tr('Navigation'),
- msg,
- (QMessageBox.StandardButton.Ok |
- QMessageBox.StandardButton.Cancel))
+ msg = self.tr("Start of results. Go to end?")
+ res = QMessageBox.information(
+ self,
+ self.tr("Navigation"),
+ msg,
+ (QMessageBox.StandardButton.Ok | QMessageBox.StandardButton.Cancel),
+ )
if res == QMessageBox.StandardButton.Ok:
- self.startfrom = (self.catalog.matches -
- self.maxrecords + 1)
+ self.startfrom = self.catalog.matches - self.maxrecords + 1
else:
return
elif self.startfrom <= self.maxrecords:
@@ -696,12 +756,13 @@ def navigate(self):
try:
with OverrideCursor(Qt.CursorShape.WaitCursor):
- self.catalog.query_records(bbox, keywords,
- limit=self.maxrecords,
- offset=self.startfrom)
+ self.catalog.query_records(
+ bbox, keywords, limit=self.maxrecords, offset=self.startfrom
+ )
except Exception as err:
- QMessageBox.warning(self, self.tr('Search error'),
- self.tr('Search error: {0}').format(err))
+ QMessageBox.warning(
+ self, self.tr("Search error"), self.tr("Search error: {0}").format(err)
+ )
return
self.display_results()
@@ -716,42 +777,56 @@ def add_to_ows(self):
if not item:
return
- item_data = json.loads(get_item_data(item, 'link'))
+ item_data = json.loads(get_item_data(item, "link"))
caller = self.sender().objectName()
- if caller == 'mActionAddWms':
- service_type = 'OGC:WMS/OGC:WMTS'
- sname = 'WMS'
- dyn_param = ['wms']
- provider_name = 'wms'
- setting_node = QgsSettingsTree.node('connections').childNode('ows').childNode('connections')
- data_url = item_data['wms']
- elif caller == 'mActionAddWfs':
- service_type = 'OGC:WFS'
- sname = 'WFS'
- dyn_param = ['wfs']
- provider_name = 'WFS'
- setting_node = QgsSettingsTree.node('connections').childNode('ows').childNode('connections')
- data_url = item_data['wfs']
- elif caller == 'mActionAddWcs':
- service_type = 'OGC:WCS'
- sname = 'WCS'
- dyn_param = ['wcs']
- provider_name = 'wcs'
- setting_node = QgsSettingsTree.node('connections').childNode('ows').childNode('connections')
- data_url = item_data['wcs']
- elif caller == 'mActionAddAfs':
- service_type = 'ESRI:ArcGIS:FeatureServer'
- sname = 'AFS'
+ if caller == "mActionAddWms":
+ service_type = "OGC:WMS/OGC:WMTS"
+ sname = "WMS"
+ dyn_param = ["wms"]
+ provider_name = "wms"
+ setting_node = (
+ QgsSettingsTree.node("connections")
+ .childNode("ows")
+ .childNode("connections")
+ )
+ data_url = item_data["wms"]
+ elif caller == "mActionAddWfs":
+ service_type = "OGC:WFS"
+ sname = "WFS"
+ dyn_param = ["wfs"]
+ provider_name = "WFS"
+ setting_node = (
+ QgsSettingsTree.node("connections")
+ .childNode("ows")
+ .childNode("connections")
+ )
+ data_url = item_data["wfs"]
+ elif caller == "mActionAddWcs":
+ service_type = "OGC:WCS"
+ sname = "WCS"
+ dyn_param = ["wcs"]
+ provider_name = "wcs"
+ setting_node = (
+ QgsSettingsTree.node("connections")
+ .childNode("ows")
+ .childNode("connections")
+ )
+ data_url = item_data["wcs"]
+ elif caller == "mActionAddAfs":
+ service_type = "ESRI:ArcGIS:FeatureServer"
+ sname = "AFS"
dyn_param = []
- provider_name = 'arcgisfeatureserver'
- setting_node = QgsSettingsTree.node('connections').childNode('arcgisfeatureserver')
- data_url = (item_data['afs'].split('FeatureServer')[0] + 'FeatureServer')
+ provider_name = "arcgisfeatureserver"
+ setting_node = QgsSettingsTree.node("connections").childNode(
+ "arcgisfeatureserver"
+ )
+ data_url = item_data["afs"].split("FeatureServer")[0] + "FeatureServer"
keys = setting_node.items(dyn_param)
- sname = '%s from MetaSearch' % sname
+ sname = "%s from MetaSearch" % sname
for key in keys:
if key.startswith(sname):
conn_name_matches.append(key)
@@ -760,10 +835,15 @@ def add_to_ows(self):
# check for duplicates
if sname in keys: # duplicate found
- msg = self.tr('Connection {0} exists. Overwrite?').format(sname)
+ msg = self.tr("Connection {0} exists. Overwrite?").format(sname)
res = QMessageBox.warning(
- self, self.tr('Saving server'), msg,
- QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No | QMessageBox.StandardButton.Cancel)
+ self,
+ self.tr("Saving server"),
+ msg,
+ QMessageBox.StandardButton.Yes
+ | QMessageBox.StandardButton.No
+ | QMessageBox.StandardButton.Cancel,
+ )
if res == QMessageBox.StandardButton.No: # assign new name with serial
sname = serialize_string(sname)
elif res == QMessageBox.StandardButton.Cancel:
@@ -771,37 +851,41 @@ def add_to_ows(self):
# no dups detected or overwrite is allowed
dyn_param.append(sname)
- setting_node.childSetting('url').setValue(clean_ows_url(data_url), dyn_param)
+ setting_node.childSetting("url").setValue(clean_ows_url(data_url), dyn_param)
# open provider window
- ows_provider = QgsGui.sourceSelectProviderRegistry().\
- createSelectionWidget(
- provider_name, self, Qt.WindowType.Widget,
- QgsProviderRegistry.WidgetMode.Embedded)
+ ows_provider = QgsGui.sourceSelectProviderRegistry().createSelectionWidget(
+ provider_name,
+ self,
+ Qt.WindowType.Widget,
+ QgsProviderRegistry.WidgetMode.Embedded,
+ )
# connect dialog signals to iface slots
- if service_type == 'OGC:WMS/OGC:WMTS':
+ if service_type == "OGC:WMS/OGC:WMTS":
ows_provider.addRasterLayer.connect(self.iface.addRasterLayer)
- conn_cmb = ows_provider.findChild(QWidget, 'cmbConnections')
- connect = 'btnConnect_clicked'
- elif service_type == 'OGC:WFS':
+ conn_cmb = ows_provider.findChild(QWidget, "cmbConnections")
+ connect = "btnConnect_clicked"
+ elif service_type == "OGC:WFS":
+
def addVectorLayer(path, name):
- self.iface.addVectorLayer(path, name, 'WFS')
+ self.iface.addVectorLayer(path, name, "WFS")
ows_provider.addVectorLayer.connect(addVectorLayer)
- conn_cmb = ows_provider.findChild(QWidget, 'cmbConnections')
- connect = 'connectToServer'
- elif service_type == 'OGC:WCS':
+ conn_cmb = ows_provider.findChild(QWidget, "cmbConnections")
+ connect = "connectToServer"
+ elif service_type == "OGC:WCS":
ows_provider.addRasterLayer.connect(self.iface.addRasterLayer)
- conn_cmb = ows_provider.findChild(QWidget, 'mConnectionsComboBox')
- connect = 'mConnectButton_clicked'
- elif service_type == 'ESRI:ArcGIS:FeatureServer':
+ conn_cmb = ows_provider.findChild(QWidget, "mConnectionsComboBox")
+ connect = "mConnectButton_clicked"
+ elif service_type == "ESRI:ArcGIS:FeatureServer":
+
def addAfsLayer(path, name):
- self.iface.addVectorLayer(path, name, 'afs')
+ self.iface.addVectorLayer(path, name, "afs")
ows_provider.addVectorLayer.connect(addAfsLayer)
conn_cmb = ows_provider.findChild(QComboBox)
- connect = 'connectToServer'
+ connect = "connectToServer"
ows_provider.setModal(False)
ows_provider.show()
@@ -811,9 +895,9 @@ def addAfsLayer(path, name):
if index > -1:
conn_cmb.setCurrentIndex(index)
# only for wfs
- if service_type == 'OGC:WFS':
+ if service_type == "OGC:WFS":
ows_provider.cmbConnections_activated(index)
- elif service_type == 'ESRI:ArcGIS:FeatureServer':
+ elif service_type == "ESRI:ArcGIS:FeatureServer":
ows_provider.cmbConnections_activated(index)
getattr(ows_provider, connect)()
@@ -824,10 +908,10 @@ def add_gis_file(self):
if not item:
return
- item_data = json.loads(get_item_data(item, 'link'))
- gis_file = item_data['gis_file']
+ item_data = json.loads(get_item_data(item, "link"))
+ gis_file = item_data["gis_file"]
- title = item_data['title']
+ title = item_data["title"]
layer = self.iface.addVectorLayer(gis_file, title, "ogr")
if not layer:
@@ -843,7 +927,7 @@ def show_metadata(self):
if not item:
return
- identifier = get_item_data(item, 'identifier')
+ identifier = get_item_data(item, "identifier")
auth = None
@@ -855,32 +939,39 @@ def show_metadata(self):
try:
with OverrideCursor(Qt.CursorShape.WaitCursor):
- cat = get_catalog_service(self.catalog_url, # spellok
- catalog_type=self.catalog_type,
- timeout=self.timeout,
- username=self.catalog_username or None,
- password=self.catalog_password or None,
- auth=auth)
+ cat = get_catalog_service(
+ self.catalog_url, # spellok
+ catalog_type=self.catalog_type,
+ timeout=self.timeout,
+ username=self.catalog_username or None,
+ password=self.catalog_password or None,
+ auth=auth,
+ )
record = cat.get_record(identifier)
- if cat.type == 'OGC API - Records':
- record['url'] = cat.conn.request
- elif cat.type == 'OGC CSW 2.0.2':
+ if cat.type == "OGC API - Records":
+ record["url"] = cat.conn.request
+ elif cat.type == "OGC CSW 2.0.2":
record.url = cat.conn.request
except Exception as err:
QMessageBox.warning(
- self, self.tr('GetRecords error'),
- self.tr('Error getting response: {0}').format(err))
+ self,
+ self.tr("GetRecords error"),
+ self.tr("Error getting response: {0}").format(err),
+ )
return
except KeyError as err:
QMessageBox.warning(
- self, self.tr('Record parsing error'),
- self.tr('Unable to locate record identifier: {0}').format(err))
+ self,
+ self.tr("Record parsing error"),
+ self.tr("Unable to locate record identifier: {0}").format(err),
+ )
return
crd = RecordDialog()
- metadata = render_template('en', self.context,
- record, self.catalog.record_info_template)
+ metadata = render_template(
+ "en", self.context, record, self.catalog.record_info_template
+ )
style = QgsApplication.reportStyleSheet()
crd.textMetadata.document().setDefaultStyleSheet(style)
@@ -891,9 +982,7 @@ def show_api(self):
"""show API request / response"""
crd = APIRequestResponseDialog(
- self.catalog.request,
- self.catalog.response,
- self.catalog.format
+ self.catalog.request, self.catalog.response, self.catalog.format
)
crd.exec()
@@ -944,41 +1033,45 @@ def _get_catalog(self):
with OverrideCursor(Qt.CursorShape.WaitCursor):
try:
self.catalog = get_catalog_service(
- self.catalog_url, catalog_type=self.catalog_type,
- timeout=self.timeout, username=self.catalog_username or None,
- password=self.catalog_password or None, auth=auth)
+ self.catalog_url,
+ catalog_type=self.catalog_type,
+ timeout=self.timeout,
+ username=self.catalog_username or None,
+ password=self.catalog_password or None,
+ auth=auth,
+ )
return True
except Exception as err:
- msg = self.tr('Error connecting to service: {0}').format(err)
+ msg = self.tr("Error connecting to service: {0}").format(err)
- QMessageBox.warning(self, self.tr('CSW Connection error'), msg)
+ QMessageBox.warning(self, self.tr("CSW Connection error"), msg)
return False
def install_proxy(self):
"""set proxy if one is set in QGIS network settings"""
# initially support HTTP for now
- if self.settings.value('/proxy/proxyEnabled') == 'true':
- if self.settings.value('/proxy/proxyType') == 'HttpProxy':
- ptype = 'http'
+ if self.settings.value("/proxy/proxyEnabled") == "true":
+ if self.settings.value("/proxy/proxyType") == "HttpProxy":
+ ptype = "http"
else:
return
- user = self.settings.value('/proxy/proxyUser')
- password = self.settings.value('/proxy/proxyPassword')
- host = self.settings.value('/proxy/proxyHost')
- port = self.settings.value('/proxy/proxyPort')
+ user = self.settings.value("/proxy/proxyUser")
+ password = self.settings.value("/proxy/proxyPassword")
+ host = self.settings.value("/proxy/proxyHost")
+ port = self.settings.value("/proxy/proxyPort")
- proxy_up = ''
- proxy_port = ''
+ proxy_up = ""
+ proxy_port = ""
- if all([user != '', password != '']):
- proxy_up = f'{user}:{password}@'
+ if all([user != "", password != ""]):
+ proxy_up = f"{user}:{password}@"
- if port != '':
- proxy_port = ':%s' % port
+ if port != "":
+ proxy_port = ":%s" % port
- conn = f'{ptype}://{proxy_up}{host}{proxy_port}'
+ conn = f"{ptype}://{proxy_up}{host}{proxy_port}"
install_opener(build_opener(ProxyHandler({ptype: conn})))
@@ -1005,9 +1098,9 @@ def _get_field_value(field):
value = 0
- if field == 'identifier':
+ if field == "identifier":
value = 0
- if field == 'link':
+ if field == "link":
value = 1
return value
diff --git a/python/plugins/MetaSearch/dialogs/manageconnectionsdialog.py b/python/plugins/MetaSearch/dialogs/manageconnectionsdialog.py
index a34b8ba7a82f..22110dd51e26 100644
--- a/python/plugins/MetaSearch/dialogs/manageconnectionsdialog.py
+++ b/python/plugins/MetaSearch/dialogs/manageconnectionsdialog.py
@@ -29,12 +29,17 @@
import xml.etree.ElementTree as etree
from qgis.core import QgsSettings
-from qgis.PyQt.QtWidgets import QDialog, QDialogButtonBox, QFileDialog, QListWidgetItem, QMessageBox # noqa
+from qgis.PyQt.QtWidgets import (
+ QDialog,
+ QDialogButtonBox,
+ QFileDialog,
+ QListWidgetItem,
+ QMessageBox,
+) # noqa
-from MetaSearch.util import (get_connections_from_file, get_ui_class,
- prettify_xml)
+from MetaSearch.util import get_connections_from_file, get_ui_class, prettify_xml
-BASE_CLASS = get_ui_class('manageconnectionsdialog.ui')
+BASE_CLASS = get_ui_class("manageconnectionsdialog.ui")
class ManageConnectionsDialog(QDialog, BASE_CLASS):
@@ -55,11 +60,15 @@ def manage_gui(self):
"""manage interface"""
if self.mode == 1:
- self.label.setText(self.tr('Load from file'))
- self.buttonBox.button(QDialogButtonBox.StandardButton.Ok).setText(self.tr('Load'))
+ self.label.setText(self.tr("Load from file"))
+ self.buttonBox.button(QDialogButtonBox.StandardButton.Ok).setText(
+ self.tr("Load")
+ )
else:
- self.label.setText(self.tr('Save to file'))
- self.buttonBox.button(QDialogButtonBox.StandardButton.Ok).setText(self.tr('Save'))
+ self.label.setText(self.tr("Save to file"))
+ self.buttonBox.button(QDialogButtonBox.StandardButton.Ok).setText(
+ self.tr("Save")
+ )
self.populate()
self.buttonBox.button(QDialogButtonBox.StandardButton.Ok).setEnabled(False)
@@ -67,23 +76,25 @@ def manage_gui(self):
def select_file(self):
"""select file ops"""
- label = self.tr('eXtensible Markup Language (*.xml *.XML)')
+ label = self.tr("eXtensible Markup Language (*.xml *.XML)")
if self.mode == 0:
- slabel = self.tr('Save Connections')
- self.filename, filter = QFileDialog.getSaveFileName(self, slabel,
- '.', label)
+ slabel = self.tr("Save Connections")
+ self.filename, filter = QFileDialog.getSaveFileName(
+ self, slabel, ".", label
+ )
else:
- slabel = self.tr('Load Connections')
+ slabel = self.tr("Load Connections")
self.filename, selected_filter = QFileDialog.getOpenFileName(
- self, slabel, '.', label)
+ self, slabel, ".", label
+ )
if not self.filename:
return
# ensure the user never omitted the extension from the file name
- if not self.filename.lower().endswith('.xml'):
- self.filename = '%s.xml' % self.filename
+ if not self.filename.lower().endswith(".xml"):
+ self.filename = "%s.xml" % self.filename
self.leFileName.setText(self.filename)
@@ -96,7 +107,7 @@ def populate(self):
"""populate connections list from settings"""
if self.mode == 0:
- self.settings.beginGroup('/MetaSearch/')
+ self.settings.beginGroup("/MetaSearch/")
keys = self.settings.childGroups()
for key in keys:
item = QListWidgetItem(self.listConnections)
@@ -111,43 +122,46 @@ def populate(self):
self.listConnections.clear()
return
- for catalog in doc.findall('csw'):
+ for catalog in doc.findall("csw"):
item = QListWidgetItem(self.listConnections)
- item.setText(catalog.attrib.get('name'))
+ item.setText(catalog.attrib.get("name"))
def save(self, connections):
"""save connections ops"""
- doc = etree.Element('qgsCSWConnections')
- doc.attrib['version'] = '1.0'
+ doc = etree.Element("qgsCSWConnections")
+ doc.attrib["version"] = "1.0"
for conn in connections:
- url = self.settings.value('/MetaSearch/%s/url' % conn)
- type_ = self.settings.value('/MetaSearch/%s/catalog-type' % conn)
+ url = self.settings.value("/MetaSearch/%s/url" % conn)
+ type_ = self.settings.value("/MetaSearch/%s/catalog-type" % conn)
if url is not None:
- connection = etree.SubElement(doc, 'csw')
- connection.attrib['name'] = conn
- connection.attrib['type'] = type_ or 'OGC CSW 2.0.2'
- connection.attrib['url'] = url
+ connection = etree.SubElement(doc, "csw")
+ connection.attrib["name"] = conn
+ connection.attrib["type"] = type_ or "OGC CSW 2.0.2"
+ connection.attrib["url"] = url
# write to disk
- with open(self.filename, 'w') as fileobj:
+ with open(self.filename, "w") as fileobj:
fileobj.write(prettify_xml(etree.tostring(doc)))
- QMessageBox.information(self, self.tr('Save Connections'),
- self.tr('Saved to {0}.').format(self.filename))
+ QMessageBox.information(
+ self,
+ self.tr("Save Connections"),
+ self.tr("Saved to {0}.").format(self.filename),
+ )
self.reject()
def load(self, items):
"""load connections"""
- self.settings.beginGroup('/MetaSearch/')
+ self.settings.beginGroup("/MetaSearch/")
keys = self.settings.childGroups()
self.settings.endGroup()
exml = etree.parse(self.filename).getroot()
- for catalog in exml.findall('csw'):
- conn_name = catalog.attrib.get('name')
+ for catalog in exml.findall("csw"):
+ conn_name = catalog.attrib.get("name")
# process only selected connections
if conn_name not in items:
@@ -155,19 +169,23 @@ def load(self, items):
# check for duplicates
if conn_name in keys:
- label = self.tr('File {0} exists. Overwrite?').format(
- conn_name)
- res = QMessageBox.warning(self, self.tr('Loading Connections'),
- label,
- QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No)
+ label = self.tr("File {0} exists. Overwrite?").format(conn_name)
+ res = QMessageBox.warning(
+ self,
+ self.tr("Loading Connections"),
+ label,
+ QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No,
+ )
if res != QMessageBox.StandardButton.Yes:
continue
# no dups detected or overwrite is allowed
- url = '/MetaSearch/%s/url' % conn_name
- type_ = '/MetaSearch/%s/catalog-type' % conn_name
- self.settings.setValue(url, catalog.attrib.get('url'))
- self.settings.setValue(type_, catalog.attrib.get('catalog-type', 'OGC CSW 2.0.2'))
+ url = "/MetaSearch/%s/url" % conn_name
+ type_ = "/MetaSearch/%s/catalog-type" % conn_name
+ self.settings.setValue(url, catalog.attrib.get("url"))
+ self.settings.setValue(
+ type_, catalog.attrib.get("catalog-type", "OGC CSW 2.0.2")
+ )
def accept(self):
"""accept connections"""
diff --git a/python/plugins/MetaSearch/dialogs/newconnectiondialog.py b/python/plugins/MetaSearch/dialogs/newconnectiondialog.py
index fee10ccaeee4..f4eb8e5d90cd 100644
--- a/python/plugins/MetaSearch/dialogs/newconnectiondialog.py
+++ b/python/plugins/MetaSearch/dialogs/newconnectiondialog.py
@@ -32,7 +32,7 @@
from MetaSearch.util import get_ui_class
from MetaSearch.search_backend import CATALOG_TYPES
-BASE_CLASS = get_ui_class('newconnectiondialog.ui')
+BASE_CLASS = get_ui_class("newconnectiondialog.ui")
class NewConnectionDialog(QDialog, BASE_CLASS):
@@ -60,49 +60,53 @@ def accept(self):
conn_password = self.lePassword.text().strip()
conn_catalog_type = self.cmbCatalogType.currentText()
- if any([conn_name == '', conn_url == '']):
- QMessageBox.warning(self, self.tr('Save Connection'),
- self.tr('Both Name and URL must be provided.'))
+ if any([conn_name == "", conn_url == ""]):
+ QMessageBox.warning(
+ self,
+ self.tr("Save Connection"),
+ self.tr("Both Name and URL must be provided."),
+ )
return
- if '/' in conn_name:
- QMessageBox.warning(self, self.tr('Save Connection'),
- self.tr('Name cannot contain \'/\'.'))
+ if "/" in conn_name:
+ QMessageBox.warning(
+ self, self.tr("Save Connection"), self.tr("Name cannot contain '/'.")
+ )
return
if conn_name is not None:
- key = '/MetaSearch/%s' % conn_name
- keyurl = '%s/url' % key
- key_orig = '/MetaSearch/%s' % self.conn_name_orig
+ key = "/MetaSearch/%s" % conn_name
+ keyurl = "%s/url" % key
+ key_orig = "/MetaSearch/%s" % self.conn_name_orig
# warn if entry was renamed to an existing connection
- if all([self.conn_name_orig != conn_name,
- self.settings.contains(keyurl)]):
+ if all([self.conn_name_orig != conn_name, self.settings.contains(keyurl)]):
res = QMessageBox.warning(
- self, self.tr('Save Connection'),
- self.tr('Overwrite {0}?').format(conn_name),
- QMessageBox.StandardButton.Ok | QMessageBox.StandardButton.Cancel)
+ self,
+ self.tr("Save Connection"),
+ self.tr("Overwrite {0}?").format(conn_name),
+ QMessageBox.StandardButton.Ok | QMessageBox.StandardButton.Cancel,
+ )
if res == QMessageBox.StandardButton.Cancel:
return
# on rename delete original entry first
- if all([self.conn_name_orig is not None,
- self.conn_name_orig != conn_name]):
+ if all([self.conn_name_orig is not None, self.conn_name_orig != conn_name]):
self.settings.remove(key_orig)
self.settings.setValue(keyurl, conn_url)
- self.settings.setValue('/MetaSearch/selected', conn_name)
+ self.settings.setValue("/MetaSearch/selected", conn_name)
- if conn_username != '':
- self.settings.setValue('%s/username' % key, conn_username)
+ if conn_username != "":
+ self.settings.setValue("%s/username" % key, conn_username)
else:
- self.settings.remove('%s/username' % key)
- if conn_password != '':
- self.settings.setValue('%s/password' % key, conn_password)
+ self.settings.remove("%s/username" % key)
+ if conn_password != "":
+ self.settings.setValue("%s/password" % key, conn_password)
else:
- self.settings.remove('%s/password' % key)
+ self.settings.remove("%s/password" % key)
- self.settings.setValue('%s/catalog-type' % key, conn_catalog_type)
+ self.settings.setValue("%s/catalog-type" % key, conn_catalog_type)
QDialog.accept(self)
diff --git a/python/plugins/MetaSearch/dialogs/recorddialog.py b/python/plugins/MetaSearch/dialogs/recorddialog.py
index 9c9f9b9e00b5..89bfe9f00a7f 100644
--- a/python/plugins/MetaSearch/dialogs/recorddialog.py
+++ b/python/plugins/MetaSearch/dialogs/recorddialog.py
@@ -30,7 +30,7 @@
from MetaSearch.util import get_ui_class
-BASE_CLASS = get_ui_class('recorddialog.ui')
+BASE_CLASS = get_ui_class("recorddialog.ui")
class RecordDialog(QDialog, BASE_CLASS):
diff --git a/python/plugins/MetaSearch/link_types.py b/python/plugins/MetaSearch/link_types.py
index 66dce8d983ec..2a0647dc2ce6 100644
--- a/python/plugins/MetaSearch/link_types.py
+++ b/python/plugins/MetaSearch/link_types.py
@@ -21,46 +21,37 @@
###############################################################################
WMSWMST_LINK_TYPES = [
- 'WMS',
- 'WMTS',
- 'OGC:WMS',
- 'OGC:WMTS',
- 'OGC:WMS-1.1.1-http-get-map',
- 'OGC:WMS-1.1.1-http-get-capabilities',
- 'OGC:WMS-1.3.0-http-get-map',
- 'OGC:WMS-1.3.0-http-get-capabilities',
- 'urn:x-esri:specification:ServiceType:wms:url',
- 'urn:x-esri:specification:ServiceType:Gmd:URL.wms'
+ "WMS",
+ "WMTS",
+ "OGC:WMS",
+ "OGC:WMTS",
+ "OGC:WMS-1.1.1-http-get-map",
+ "OGC:WMS-1.1.1-http-get-capabilities",
+ "OGC:WMS-1.3.0-http-get-map",
+ "OGC:WMS-1.3.0-http-get-capabilities",
+ "urn:x-esri:specification:ServiceType:wms:url",
+ "urn:x-esri:specification:ServiceType:Gmd:URL.wms",
]
WFS_LINK_TYPES = [
- 'WFS',
- 'OGC:WFS',
- 'OGC:WFS-1.0.0-http-get-capabilities',
- 'OGC:WFS-1.1.0-http-get-capabilities',
- 'urn:x-esri:specification:ServiceType:wfs:url',
- 'urn:x-esri:specification:ServiceType:Gmd:URL.wfs'
+ "WFS",
+ "OGC:WFS",
+ "OGC:WFS-1.0.0-http-get-capabilities",
+ "OGC:WFS-1.1.0-http-get-capabilities",
+ "urn:x-esri:specification:ServiceType:wfs:url",
+ "urn:x-esri:specification:ServiceType:Gmd:URL.wfs",
]
WCS_LINK_TYPES = [
- 'WCS',
- 'OGC:WCS',
- 'OGC:WCS-1.1.0-http-get-capabilities',
- 'urn:x-esri:specification:ServiceType:wcs:url',
- 'urn:x-esri:specification:ServiceType:Gmd:URL.wcs'
+ "WCS",
+ "OGC:WCS",
+ "OGC:WCS-1.1.0-http-get-capabilities",
+ "urn:x-esri:specification:ServiceType:wcs:url",
+ "urn:x-esri:specification:ServiceType:Gmd:URL.wcs",
]
-AMS_LINK_TYPES = [
- 'ESRI:ArcGIS:MapServer',
- 'Esri REST: Map Service',
- 'ESRI REST'
-]
+AMS_LINK_TYPES = ["ESRI:ArcGIS:MapServer", "Esri REST: Map Service", "ESRI REST"]
-AFS_LINK_TYPES = [
- 'ESRI:ArcGIS:FeatureServer',
- 'Esri REST: Feature Service'
-]
+AFS_LINK_TYPES = ["ESRI:ArcGIS:FeatureServer", "Esri REST: Feature Service"]
-GIS_FILE_LINK_TYPES = [
- 'FILE:GEO'
-]
+GIS_FILE_LINK_TYPES = ["FILE:GEO"]
diff --git a/python/plugins/MetaSearch/pavement.py b/python/plugins/MetaSearch/pavement.py
index 2fc7476ceafb..6cfeed6f83b6 100644
--- a/python/plugins/MetaSearch/pavement.py
+++ b/python/plugins/MetaSearch/pavement.py
@@ -26,35 +26,30 @@
import xmlrpc.client
import zipfile
-from paver.easy import (call_task, cmdopts, error, info, options, path,
- sh, task, Bunch)
+from paver.easy import call_task, cmdopts, error, info, options, path, sh, task, Bunch
from owslib.csw import CatalogueServiceWeb # spellok
-PLUGIN_NAME = 'MetaSearch'
+PLUGIN_NAME = "MetaSearch"
BASEDIR = os.path.abspath(os.path.dirname(__file__))
-USERDIR = os.path.expanduser('~')
+USERDIR = os.path.expanduser("~")
-with open('metadata.txt') as mf:
+with open("metadata.txt") as mf:
cp = ConfigParser()
cp.readfp(mf)
- VERSION = cp.get('general', 'version')
+ VERSION = cp.get("general", "version")
options(
base=Bunch(
home=BASEDIR,
plugin=path(BASEDIR),
- ui=path(BASEDIR) / 'plugin' / PLUGIN_NAME / 'ui',
- install=path('%s/.qgis3/python/plugins/MetaSearch' % USERDIR),
- ext_libs=path('plugin/MetaSearch/ext-libs'),
- tmp=path(path('%s/MetaSearch-dist' % USERDIR)),
- version=VERSION
+ ui=path(BASEDIR) / "plugin" / PLUGIN_NAME / "ui",
+ install=path("%s/.qgis3/python/plugins/MetaSearch" % USERDIR),
+ ext_libs=path("plugin/MetaSearch/ext-libs"),
+ tmp=path(path("%s/MetaSearch-dist" % USERDIR)),
+ version=VERSION,
),
- upload=Bunch(
- host='plugins.qgis.org',
- port=80,
- endpoint='plugins/RPC2/'
- )
+ upload=Bunch(host="plugins.qgis.org", port=80, endpoint="plugins/RPC2/"),
)
@@ -72,17 +67,17 @@ def clean():
if os.path.exists(options.base.ext_libs):
shutil.rmtree(options.base.ext_libs)
for ui_file in os.listdir(options.base.ui):
- if ui_file.endswith('.py') and ui_file != '__init__.py':
- os.remove(options.base.plugin / 'ui' / ui_file)
- os.remove(path(options.base.home) / '%s.pro' % PLUGIN_NAME)
- sh('git clean -dxf')
+ if ui_file.endswith(".py") and ui_file != "__init__.py":
+ os.remove(options.base.plugin / "ui" / ui_file)
+ os.remove(path(options.base.home) / "%s.pro" % PLUGIN_NAME)
+ sh("git clean -dxf")
@task
def install():
"""install plugin into user QGIS environment"""
- plugins_dir = path(USERDIR) / '.qgis3/python/plugins'
+ plugins_dir = path(USERDIR) / ".qgis3/python/plugins"
if os.path.exists(options.base.install):
if os.path.islink(options.base.install):
@@ -91,8 +86,8 @@ def install():
shutil.rmtree(options.base.install)
if not os.path.exists(plugins_dir):
- raise OSError('The directory %s does not exist.' % plugins_dir)
- if not hasattr(os, 'symlink'):
+ raise OSError("The directory %s does not exist." % plugins_dir)
+ if not hasattr(os, "symlink"):
shutil.copytree(options.base.plugin, options.base.install)
elif not os.path.exists(options.base.install):
os.symlink(options.base.plugin, options.base.install)
@@ -103,11 +98,11 @@ def package():
"""create zip file of plugin"""
skip_files = [
- 'AUTHORS.txt',
- 'CMakeLists.txt',
- 'requirements.txt',
- 'requirements-dev.txt',
- 'pavement.txt'
+ "AUTHORS.txt",
+ "CMakeLists.txt",
+ "requirements.txt",
+ "requirements-dev.txt",
+ "pavement.txt",
]
package_file = get_package_filename()
@@ -116,10 +111,10 @@ def package():
options.base.tmp.mkdir()
if os.path.exists(package_file):
os.unlink(package_file)
- with zipfile.ZipFile(package_file, 'w', zipfile.ZIP_DEFLATED) as zipf:
+ with zipfile.ZipFile(package_file, "w", zipfile.ZIP_DEFLATED) as zipf:
for root, dirs, files in os.walk(options.base.plugin):
for file_add in files:
- if file_add.endswith('.pyc') or file_add in skip_files:
+ if file_add.endswith(".pyc") or file_add in skip_files:
continue
filepath = os.path.join(root, file_add)
relpath = os.path.join(PLUGIN_NAME, os.path.relpath(filepath))
@@ -128,81 +123,90 @@ def package():
@task
-@cmdopts([
- ('user=', 'u', 'OSGeo userid'),
-])
+@cmdopts(
+ [
+ ("user=", "u", "OSGeo userid"),
+ ]
+)
def upload():
"""upload package zipfile to server"""
- user = options.get('user', False)
+ user = options.get("user", False)
if not user:
- raise ValueError('OSGeo userid required')
+ raise ValueError("OSGeo userid required")
- password = getpass.getpass('Enter your password: ')
- if password.strip() == '':
- raise ValueError('password required')
+ password = getpass.getpass("Enter your password: ")
+ if password.strip() == "":
+ raise ValueError("password required")
- call_task('package')
+ call_task("package")
zipf = get_package_filename()
- url = 'http://%s:%s@%s:%d/%s' % (user, password, options.upload.host,
- options.upload.port,
- options.upload.endpoint)
+ url = "http://%s:%s@%s:%d/%s" % (
+ user,
+ password,
+ options.upload.host,
+ options.upload.port,
+ options.upload.endpoint,
+ )
- info('Uploading to http://{}/{}'.format(options.upload.host, options.upload.endpoint))
+ info(f"Uploading to http://{options.upload.host}/{options.upload.endpoint}")
server = xmlrpc.client.ServerProxy(url, verbose=False)
try:
with open(zipf) as zfile:
- plugin_id, version_id = \
- server.plugin.upload(xmlrpc.client.Binary(zfile.read()))
- info('Plugin ID: %s', plugin_id)
- info('Version ID: %s', version_id)
+ plugin_id, version_id = server.plugin.upload(
+ xmlrpc.client.Binary(zfile.read())
+ )
+ info("Plugin ID: %s", plugin_id)
+ info("Version ID: %s", version_id)
except xmlrpc.client.Fault as err:
- error('ERROR: fault error')
- error('Fault code: %d', err.faultCode)
- error('Fault string: %s', err.faultString)
+ error("ERROR: fault error")
+ error("Fault code: %d", err.faultCode)
+ error("Fault string: %s", err.faultString)
except xmlrpc.client.ProtocolError as err:
- error('Error: Protocol error')
+ error("Error: Protocol error")
error("%s : %s", err.errcode, err.errmsg)
if err.errcode == 403:
- error('Invalid name and password')
+ error("Invalid name and password")
@task
def test_default_csw_connections():
"""test that the default CSW connections work"""
- relpath = 'resources%sconnections-default.xml' % os.sep
+ relpath = "resources%sconnections-default.xml" % os.sep
csw_connections_xml = options.base.plugin / relpath
conns = etree.parse(csw_connections_xml)
- for conn in conns.findall('csw'):
+ for conn in conns.findall("csw"):
try:
- csw = CatalogueServiceWeb(conn.attrib.get('url')) # spellok
- info('Success: %s', csw.identification.title)
+ csw = CatalogueServiceWeb(conn.attrib.get("url")) # spellok
+ info("Success: %s", csw.identification.title)
csw.getrecords2()
except Exception as err:
- raise ValueError('ERROR: %s', err)
+ raise ValueError("ERROR: %s", err)
@task
-@cmdopts([
- ('filename=', 'f', 'Path to file of CSW URLs'),
-])
+@cmdopts(
+ [
+ ("filename=", "f", "Path to file of CSW URLs"),
+ ]
+)
def generate_csw_connections_file():
"""generate a CSW connections file from a flat file of CSW URLs"""
- filename = options.get('filename', False)
+ filename = options.get("filename", False)
if not filename:
- raise ValueError('path to file of CSW URLs required')
+ raise ValueError("path to file of CSW URLs required")
- conns = etree.Element('qgsCSWConnections')
- conns.attrib['version'] = '1.0'
+ conns = etree.Element("qgsCSWConnections")
+ conns.attrib["version"] = "1.0"
with open(filename) as connsfh:
for line in connsfh:
@@ -212,17 +216,17 @@ def generate_csw_connections_file():
try:
csw = CatalogueServiceWeb(url) # spellok
title = str(csw.identification.title)
- etree.SubElement(conns, 'csw', name=title, url=url)
+ etree.SubElement(conns, "csw", name=title, url=url)
except Exception as err:
- error('ERROR on CSW %s: %s', url, err)
+ error("ERROR on CSW %s: %s", url, err)
- with open('%s.xml' % filename, 'w') as connsxmlfh:
- connsxmlfh.write(etree.tostring(conns, encoding='utf-8'))
+ with open("%s.xml" % filename, "w") as connsxmlfh:
+ connsxmlfh.write(etree.tostring(conns, encoding="utf-8"))
def get_package_filename():
"""return filepath of plugin zipfile"""
- filename = f'{PLUGIN_NAME}-{options.base.version}.zip'
- package_file = f'{options.base.tmp}/{filename}'
+ filename = f"{PLUGIN_NAME}-{options.base.version}.zip"
+ package_file = f"{options.base.tmp}/{filename}"
return package_file
diff --git a/python/plugins/MetaSearch/plugin.py b/python/plugins/MetaSearch/plugin.py
index d131c4b7cc96..7e4c0c0db528 100644
--- a/python/plugins/MetaSearch/plugin.py
+++ b/python/plugins/MetaSearch/plugin.py
@@ -44,21 +44,22 @@ def __init__(self, iface):
self.action_run = None
self.action_help = None
self.dialog = None
- self.web_menu = '&MetaSearch'
+ self.web_menu = "&MetaSearch"
def initGui(self):
"""startup"""
# run
- log_message('Initializing plugin', Qgis.MessageLevel.Info)
+ log_message("Initializing plugin", Qgis.MessageLevel.Info)
- run_icon = QIcon('{}/{}'.format(self.context.ppath, 'images/MetaSearch.svg'))
- self.action_run = QAction(run_icon, 'MetaSearch',
- self.iface.mainWindow())
+ run_icon = QIcon("{}/{}".format(self.context.ppath, "images/MetaSearch.svg"))
+ self.action_run = QAction(run_icon, "MetaSearch", self.iface.mainWindow())
self.action_run.setWhatsThis(
- QCoreApplication.translate('MetaSearch', 'MetaSearch plugin'))
- self.action_run.setStatusTip(QCoreApplication.translate(
- 'MetaSearch', 'Search Metadata Catalogs'))
+ QCoreApplication.translate("MetaSearch", "MetaSearch plugin")
+ )
+ self.action_run.setStatusTip(
+ QCoreApplication.translate("MetaSearch", "Search Metadata Catalogs")
+ )
self.action_run.triggered.connect(self.run)
@@ -66,12 +67,14 @@ def initGui(self):
self.iface.addPluginToWebMenu(self.web_menu, self.action_run)
# help
- help_icon = QgsApplication.getThemeIcon('/mActionHelpContents.svg')
- self.action_help = QAction(help_icon, 'Help', self.iface.mainWindow())
+ help_icon = QgsApplication.getThemeIcon("/mActionHelpContents.svg")
+ self.action_help = QAction(help_icon, "Help", self.iface.mainWindow())
self.action_help.setWhatsThis(
- QCoreApplication.translate('MetaSearch', 'MetaSearch plugin help'))
- self.action_help.setStatusTip(QCoreApplication.translate(
- 'MetaSearch', 'Get Help on MetaSearch'))
+ QCoreApplication.translate("MetaSearch", "MetaSearch plugin help")
+ )
+ self.action_help.setStatusTip(
+ QCoreApplication.translate("MetaSearch", "Get Help on MetaSearch")
+ )
self.action_help.triggered.connect(self.help)
self.iface.addPluginToWebMenu(self.web_menu, self.action_help)
@@ -82,7 +85,7 @@ def initGui(self):
def unload(self):
"""teardown"""
- log_message('Unloading plugin', Qgis.MessageLevel.Info)
+ log_message("Unloading plugin", Qgis.MessageLevel.Info)
# remove the plugin menu item and icon
self.iface.removePluginWebMenu(self.web_menu, self.action_run)
@@ -92,7 +95,7 @@ def unload(self):
def run(self):
"""open MetaSearch"""
- log_message('Running plugin', Qgis.MessageLevel.Info)
+ log_message("Running plugin", Qgis.MessageLevel.Info)
self.dialog.exec()
diff --git a/python/plugins/MetaSearch/search_backend.py b/python/plugins/MetaSearch/search_backend.py
index 1b461fec19bb..99ba387e8307 100644
--- a/python/plugins/MetaSearch/search_backend.py
+++ b/python/plugins/MetaSearch/search_backend.py
@@ -36,15 +36,12 @@
from qgis.core import Qgis
-if owslib.__version__ < '0.25':
+if owslib.__version__ < "0.25":
OWSLIB_OAREC_SUPPORTED = False
else:
OWSLIB_OAREC_SUPPORTED = True
-CATALOG_TYPES = [
- 'OGC CSW 2.0.2',
- 'OGC API - Records'
-]
+CATALOG_TYPES = ["OGC CSW 2.0.2", "OGC API - Records"]
class SearchBase:
@@ -83,17 +80,19 @@ def __init__(self, url, timeout, username, password, auth):
super().__init__(url, timeout, username, password, auth)
self.type = CATALOG_TYPES[0]
- self.format = 'xml'
- self.service_info_template = 'csw_service_metadata.html'
- self.record_info_template = 'record_metadata_dc.html'
+ self.format = "xml"
+ self.service_info_template = "csw_service_metadata.html"
+ self.record_info_template = "record_metadata_dc.html"
self.constraints = []
- log_message(f'Connecting to CSW: {self.url}', Qgis.MessageLevel.Info)
- self.conn = CatalogueServiceWeb(self.url, # spellok
- timeout=self.timeout,
- username=self.username,
- password=self.password,
- auth=self.auth)
+ log_message(f"Connecting to CSW: {self.url}", Qgis.MessageLevel.Info)
+ self.conn = CatalogueServiceWeb(
+ self.url, # spellok
+ timeout=self.timeout,
+ username=self.username,
+ password=self.password,
+ auth=self.auth,
+ )
self.request = self.conn.request
self.response = self.conn.response
@@ -105,29 +104,36 @@ def query_records(self, bbox=[], keywords=None, limit=10, offset=1):
# only apply spatial filter if bbox is not global
# even for a global bbox, if a spatial filter is applied, then
# the CSW server will skip records without a bbox
- if bbox and bbox != ['-180', '-90', '180', '90']:
- log_message(f'Setting bbox filter ({bbox})', Qgis.MessageLevel.Info)
+ if bbox and bbox != ["-180", "-90", "180", "90"]:
+ log_message(f"Setting bbox filter ({bbox})", Qgis.MessageLevel.Info)
minx, miny, maxx, maxy = bbox
- self.constraints.append(BBox([miny, minx, maxy, maxx],
- crs='urn:ogc:def:crs:EPSG::4326'))
+ self.constraints.append(
+ BBox([miny, minx, maxy, maxx], crs="urn:ogc:def:crs:EPSG::4326")
+ )
# keywords
if keywords:
# TODO: handle multiple word searches
- log_message(f'Setting csw:AnyText filter {keywords}', Qgis.MessageLevel.Info)
- self.constraints.append(PropertyIsLike('csw:AnyText', keywords))
+ log_message(
+ f"Setting csw:AnyText filter {keywords}", Qgis.MessageLevel.Info
+ )
+ self.constraints.append(PropertyIsLike("csw:AnyText", keywords))
if len(self.constraints) > 1: # exclusive search (a && b)
self.constraints = [self.constraints]
- log_message('Searching CSW: {self.url}', Qgis.MessageLevel.Info)
- self.conn.getrecords2(constraints=self.constraints, maxrecords=limit,
- startposition=offset, esn='full')
+ log_message("Searching CSW: {self.url}", Qgis.MessageLevel.Info)
+ self.conn.getrecords2(
+ constraints=self.constraints,
+ maxrecords=limit,
+ startposition=offset,
+ esn="full",
+ )
- self.matches = self.conn.results['matches']
- self.returned = self.conn.results['returned']
- log_message(f'Matches: {self.matches}', Qgis.MessageLevel.Info)
- log_message(f'Returned: {self.returned}', Qgis.MessageLevel.Info)
+ self.matches = self.conn.results["matches"]
+ self.returned = self.conn.results["returned"]
+ log_message(f"Matches: {self.matches}", Qgis.MessageLevel.Info)
+ log_message(f"Returned: {self.returned}", Qgis.MessageLevel.Info)
self.request = self.conn.request
self.response = self.conn.response
@@ -136,32 +142,27 @@ def records(self):
recs = []
for record in self.conn.records:
- rec = {
- 'identifier': None,
- 'type': None,
- 'title': None,
- 'bbox': None
- }
+ rec = {"identifier": None, "type": None, "title": None, "bbox": None}
if self.conn.records[record].identifier:
- rec['identifier'] = self.conn.records[record].identifier
+ rec["identifier"] = self.conn.records[record].identifier
if self.conn.records[record].type:
- rec['type'] = self.conn.records[record].type
+ rec["type"] = self.conn.records[record].type
if self.conn.records[record].title:
- rec['title'] = self.conn.records[record].title
+ rec["title"] = self.conn.records[record].title
if self.conn.records[record].bbox:
- rec['bbox'] = bbox_list_to_dict(
- self.conn.records[record].bbox)
+ rec["bbox"] = bbox_list_to_dict(self.conn.records[record].bbox)
- rec['links'] = (self.conn.records[record].uris +
- self.conn.records[record].references)
+ rec["links"] = (
+ self.conn.records[record].uris + self.conn.records[record].references
+ )
recs.append(rec)
return recs
def get_record(self, identifier):
- log_message(f'Searching CSW for record: {identifier}', Qgis.MessageLevel.Info)
+ log_message(f"Searching CSW for record: {identifier}", Qgis.MessageLevel.Info)
self.conn.getrecordbyid([identifier])
return self.conn.records[identifier]
@@ -178,27 +179,28 @@ def __init__(self, url, timeout, auth):
super().__init__(url, timeout, auth)
self.type = CATALOG_TYPES[1]
- self.format = 'json'
- self.service_info_template = 'oarec_service_metadata.html'
- self.record_info_template = 'record_metadata_oarec.html'
+ self.format = "json"
+ self.service_info_template = "oarec_service_metadata.html"
+ self.record_info_template = "record_metadata_oarec.html"
self.base_url = None
self.record_collection = None
- if '/collections/' in self.url: # catalog is a collection
- log_message('OARec endpoint is a collection', Qgis.MessageLevel.Info)
- self.base_url, self.record_collection = self.url.split('/collections/') # noqa
- self.conn = Records(
- self.base_url, timeout=self.timeout, auth=self.auth)
+ if "/collections/" in self.url: # catalog is a collection
+ log_message("OARec endpoint is a collection", Qgis.MessageLevel.Info)
+ self.base_url, self.record_collection = self.url.split(
+ "/collections/"
+ ) # noqa
+ self.conn = Records(self.base_url, timeout=self.timeout, auth=self.auth)
c = self.conn.collection(self.record_collection)
try:
- self.conn.links = c['links']
- self.conn.title = c['title']
- self.conn.description = c['description']
+ self.conn.links = c["links"]
+ self.conn.title = c["title"]
+ self.conn.description = c["description"]
except KeyError:
pass
self.request = self.conn.request
else:
- log_message('OARec endpoint is not a collection', Qgis.MessageLevel.Info)
+ log_message("OARec endpoint is not a collection", Qgis.MessageLevel.Info)
self.conn = Records(self.url, timeout=self.timeout, auth=self.auth)
self.request = None
@@ -210,47 +212,49 @@ def query_records(self, bbox=[], keywords=None, limit=10, offset=1):
offset2 = offset - 1
params = {
- 'collection_id': self.record_collection,
- 'limit': limit,
- 'offset': offset2
+ "collection_id": self.record_collection,
+ "limit": limit,
+ "offset": offset2,
}
if keywords:
- log_message(f'Setting keyword search {keywords}', Qgis.MessageLevel.Info)
- params['q'] = keywords
- if bbox and bbox != ['-180', '-90', '180', '90']:
- log_message(f'Setting bbox search {bbox}', Qgis.MessageLevel.Info)
- params['bbox'] = bbox
+ log_message(f"Setting keyword search {keywords}", Qgis.MessageLevel.Info)
+ params["q"] = keywords
+ if bbox and bbox != ["-180", "-90", "180", "90"]:
+ log_message(f"Setting bbox search {bbox}", Qgis.MessageLevel.Info)
+ params["bbox"] = bbox
- log_message(f'Searching OARec: {self.url}', Qgis.MessageLevel.Info)
+ log_message(f"Searching OARec: {self.url}", Qgis.MessageLevel.Info)
self.response = self.conn.collection_items(**params)
- self.matches = self.response.get('numberMatched', 0)
- self.returned = self.response.get('numberReturned', 0)
+ self.matches = self.response.get("numberMatched", 0)
+ self.returned = self.response.get("numberReturned", 0)
self.request = self.conn.request
- log_message(f'Matches: {self.matches}', Qgis.MessageLevel.Info)
- log_message(f'Returned: {self.returned}', Qgis.MessageLevel.Info)
+ log_message(f"Matches: {self.matches}", Qgis.MessageLevel.Info)
+ log_message(f"Returned: {self.returned}", Qgis.MessageLevel.Info)
def records(self):
recs = []
- for rec in self.response['features']:
+ for rec in self.response["features"]:
rec1 = {
- 'identifier': rec['id'],
- 'type': rec['properties']['type'],
- 'bbox': None,
- 'title': rec['properties']['title'],
- 'links': rec.get('links', [])
+ "identifier": rec["id"],
+ "type": rec["properties"]["type"],
+ "bbox": None,
+ "title": rec["properties"]["title"],
+ "links": rec.get("links", []),
}
try:
- if rec.get('geometry') is not None:
- rec1['bbox'] = bbox_list_to_dict([
- rec['geometry']['coordinates'][0][0][0],
- rec['geometry']['coordinates'][0][0][1],
- rec['geometry']['coordinates'][0][2][0],
- rec['geometry']['coordinates'][0][2][1]
- ])
+ if rec.get("geometry") is not None:
+ rec1["bbox"] = bbox_list_to_dict(
+ [
+ rec["geometry"]["coordinates"][0][0][0],
+ rec["geometry"]["coordinates"][0][0][1],
+ rec["geometry"]["coordinates"][0][2][0],
+ rec["geometry"]["coordinates"][0][2][1],
+ ]
+ )
except KeyError:
pass
@@ -259,30 +263,30 @@ def records(self):
return recs
def get_record(self, identifier):
- log_message(f'Searching OARec endpoint for item {identifier}',
- Qgis.MessageLevel.Info)
+ log_message(
+ f"Searching OARec endpoint for item {identifier}", Qgis.MessageLevel.Info
+ )
return self.conn.collection_item(self.record_collection, identifier)
def parse_link(self, link):
link2 = {}
- if 'href' in link:
- link2['url'] = link['href']
- if 'type' in link:
- link2['protocol'] = link['type']
- if 'title' in link:
- link2['title'] = link['title']
- if 'id' in link:
- link2['name'] = link['id']
+ if "href" in link:
+ link2["url"] = link["href"]
+ if "type" in link:
+ link2["protocol"] = link["type"]
+ if "title" in link:
+ link2["title"] = link["title"]
+ if "id" in link:
+ link2["name"] = link["id"]
return link2
-def get_catalog_service(url, catalog_type, timeout, username, password,
- auth=None):
+def get_catalog_service(url, catalog_type, timeout, username, password, auth=None):
if catalog_type in [None, CATALOG_TYPES[0]]:
- log_message('CSW endpoint detected', Qgis.MessageLevel.Info)
+ log_message("CSW endpoint detected", Qgis.MessageLevel.Info)
return CSW202Search(url, timeout, username, password, auth)
elif catalog_type == CATALOG_TYPES[1]:
- log_message('OARec endpoint detected', Qgis.MessageLevel.Info)
+ log_message("OARec endpoint detected", Qgis.MessageLevel.Info)
if not OWSLIB_OAREC_SUPPORTED:
raise ValueError("OGC API - Records requires OWSLib 0.25 or above")
return OARecSearch(url, timeout, auth)
@@ -290,17 +294,12 @@ def get_catalog_service(url, catalog_type, timeout, username, password,
def bbox_list_to_dict(bbox):
if isinstance(bbox, list):
- dict_ = {
- 'minx': bbox[0],
- 'maxx': bbox[2],
- 'miny': bbox[1],
- 'maxy': bbox[3]
- }
+ dict_ = {"minx": bbox[0], "maxx": bbox[2], "miny": bbox[1], "maxy": bbox[3]}
else:
dict_ = {
- 'minx': bbox.minx,
- 'maxx': bbox.maxx,
- 'miny': bbox.miny,
- 'maxy': bbox.maxy
+ "minx": bbox.minx,
+ "maxx": bbox.maxx,
+ "miny": bbox.miny,
+ "maxy": bbox.maxy,
}
return dict_
diff --git a/python/plugins/MetaSearch/util.py b/python/plugins/MetaSearch/util.py
index 7f6345baf06a..a939604f5809 100644
--- a/python/plugins/MetaSearch/util.py
+++ b/python/plugins/MetaSearch/util.py
@@ -53,18 +53,21 @@ def __init__(self):
def get_ui_class(ui_file):
"""return class object of a uifile"""
- ui_file_full = '{}{}ui{}{}'.format(os.path.dirname(os.path.abspath(__file__)), os.sep, os.sep, ui_file)
+ ui_file_full = (
+ f"{os.path.dirname(os.path.abspath(__file__))}{os.sep}ui{os.sep}{ui_file}"
+ )
return loadUiType(ui_file_full)[0]
def render_template(language, context, data, template):
"""Renders HTML display of raw API request/response/content"""
- env = Environment(extensions=['jinja2.ext.i18n'],
- loader=FileSystemLoader(context.ppath))
+ env = Environment(
+ extensions=["jinja2.ext.i18n"], loader=FileSystemLoader(context.ppath)
+ )
env.install_gettext_callables(gettext, ngettext, newstyle=True)
- template_file = 'resources/templates/%s' % template
+ template_file = "resources/templates/%s" % template
template = env.get_template(template_file)
return template.render(language=language, obj=data)
@@ -75,18 +78,18 @@ def get_connections_from_file(parent, filename):
error = 0
try:
doc = etree.parse(filename).getroot()
- if doc.tag != 'qgsCSWConnections':
+ if doc.tag != "qgsCSWConnections":
error = 1
- msg = parent.tr('Invalid Catalog connections XML.')
+ msg = parent.tr("Invalid Catalog connections XML.")
except etree.ParseError as err:
error = 1
- msg = parent.tr('Cannot parse XML file: {0}').format(err)
+ msg = parent.tr("Cannot parse XML file: {0}").format(err)
except OSError as err:
error = 1
- msg = parent.tr('Cannot open file: {0}').format(err)
+ msg = parent.tr("Cannot open file: {0}").format(err)
if error == 1:
- QMessageBox.information(parent, parent.tr('Loading Connections'), msg)
+ QMessageBox.information(parent, parent.tr("Loading Connections"), msg)
return
return doc
@@ -95,13 +98,13 @@ def prettify_xml(xml):
"""convenience function to prettify XML"""
if isinstance(xml, bytes):
- xml = xml.decode('utf-8')
+ xml = xml.decode("utf-8")
- if xml.count('\n') > 20: # likely already pretty printed
+ if xml.count("\n") > 20: # likely already pretty printed
return xml
# check if it's a GET request
- if xml.startswith('http'):
+ if xml.startswith("http"):
return xml
else:
return parseString(xml).toprettyxml()
@@ -110,17 +113,17 @@ def prettify_xml(xml):
def get_help_url():
"""return QGIS MetaSearch help documentation link"""
- locale_name = QgsSettings().value('locale/userLocale')[0:2]
- major, minor = Qgis.QGIS_VERSION.split('.')[:2]
+ locale_name = QgsSettings().value("locale/userLocale")[0:2]
+ major, minor = Qgis.QGIS_VERSION.split(".")[:2]
- if minor == '99': # master
- version = 'testing'
+ if minor == "99": # master
+ version = "testing"
else:
- version = '.'.join([major, minor])
+ version = ".".join([major, minor])
- path = f'{version}/{locale_name}/docs/user_manual/plugins/core_plugins/plugins_metasearch.html' # noqa
+ path = f"{version}/{locale_name}/docs/user_manual/plugins/core_plugins/plugins_metasearch.html" # noqa
- return '/'.join(['https://docs.qgis.org', path])
+ return "/".join(["https://docs.qgis.org", path])
def open_url(url):
@@ -132,7 +135,7 @@ def open_url(url):
def normalize_text(text):
"""tidy up string"""
- return text.replace('\n', '')
+ return text.replace("\n", "")
def serialize_string(input_string):
@@ -141,12 +144,12 @@ def serialize_string(input_string):
s = input_string.strip().split()
last_token = s[-1]
- all_other_tokens_as_string = input_string.replace(last_token, '')
+ all_other_tokens_as_string = input_string.replace(last_token, "")
if last_token.isdigit():
- value = f'{all_other_tokens_as_string}{int(last_token) + 1}'
+ value = f"{all_other_tokens_as_string}{int(last_token) + 1}"
else:
- value = '%s 1' % input_string
+ value = "%s 1" % input_string
return value
@@ -159,10 +162,10 @@ def clean_ows_url(url):
if query_string:
query_string = QUrlQuery(query_string)
- query_string.removeQueryItem('service')
- query_string.removeQueryItem('SERVICE')
- query_string.removeQueryItem('request')
- query_string.removeQueryItem('REQUEST')
+ query_string.removeQueryItem("service")
+ query_string.removeQueryItem("SERVICE")
+ query_string.removeQueryItem("request")
+ query_string.removeQueryItem("REQUEST")
url.setQuery(query_string)
return url.toString()
@@ -171,4 +174,4 @@ def clean_ows_url(url):
def log_message(message, level=Qgis.MessageLevel.Info):
"""helper function to emit logging messages"""
- LOGGER.logMessage(message, 'MetaSearch', level)
+ LOGGER.logMessage(message, "MetaSearch", level)
diff --git a/python/plugins/db_manager/db_manager.py b/python/plugins/db_manager/db_manager.py
index 5562d023b8e0..cbae74596beb 100644
--- a/python/plugins/db_manager/db_manager.py
+++ b/python/plugins/db_manager/db_manager.py
@@ -23,16 +23,25 @@
import functools
from qgis.PyQt.QtCore import Qt, QByteArray, QSize
-from qgis.PyQt.QtWidgets import QAction, QMainWindow, QApplication, QMenu, QTabWidget, QGridLayout, QSpacerItem, QSizePolicy, QDockWidget, QStatusBar, QMenuBar, QToolBar, QTabBar
+from qgis.PyQt.QtWidgets import (
+ QAction,
+ QMainWindow,
+ QApplication,
+ QMenu,
+ QTabWidget,
+ QGridLayout,
+ QSpacerItem,
+ QSizePolicy,
+ QDockWidget,
+ QStatusBar,
+ QMenuBar,
+ QToolBar,
+ QTabBar,
+)
from qgis.PyQt.QtGui import QIcon, QKeySequence
from qgis.gui import QgsMessageBar
-from qgis.core import (
- Qgis,
- QgsApplication,
- QgsSettings,
- QgsMapLayerType
-)
+from qgis.core import Qgis, QgsApplication, QgsSettings, QgsMapLayerType
from qgis.utils import OverrideCursor
from .info_viewer import InfoViewer
@@ -56,8 +65,16 @@ def __init__(self, iface, parent=None):
# restore the window state
settings = QgsSettings()
- self.restoreGeometry(settings.value("/DB_Manager/mainWindow/geometry", QByteArray(), type=QByteArray))
- self.restoreState(settings.value("/DB_Manager/mainWindow/windowState", QByteArray(), type=QByteArray))
+ self.restoreGeometry(
+ settings.value(
+ "/DB_Manager/mainWindow/geometry", QByteArray(), type=QByteArray
+ )
+ )
+ self.restoreState(
+ settings.value(
+ "/DB_Manager/mainWindow/windowState", QByteArray(), type=QByteArray
+ )
+ )
self.toolBar.setIconSize(self.iface.iconSize())
self.toolBarOrientation()
@@ -102,7 +119,7 @@ def itemChanged(self, item):
def reloadButtons(self):
db = self.tree.currentDatabase()
- if not hasattr(self, '_lastDb'):
+ if not hasattr(self, "_lastDb"):
self._lastDb = db
elif db == self._lastDb:
@@ -131,8 +148,12 @@ def refreshTabs(self):
# enable/disable tabs
self.tabs.setTabEnabled(self.tabs.indexOf(self.table), table is not None)
- self.tabs.setTabEnabled(self.tabs.indexOf(self.preview), table is not None and table.type in [table.VectorType,
- table.RasterType] and table.geomColumn is not None)
+ self.tabs.setTabEnabled(
+ self.tabs.indexOf(self.preview),
+ table is not None
+ and table.type in [table.VectorType, table.RasterType]
+ and table.geomColumn is not None,
+ )
# show the info tab if the current tab is disabled
if not self.tabs.isTabEnabled(index):
self.tabs.setCurrentWidget(self.info)
@@ -154,8 +175,11 @@ def refreshActionSlot(self):
def importActionSlot(self):
db = self.tree.currentDatabase()
if db is None:
- self.infoBar.pushMessage(self.tr("No database selected or you are not connected to it."),
- Qgis.MessageLevel.Info, self.iface.messageTimeout())
+ self.infoBar.pushMessage(
+ self.tr("No database selected or you are not connected to it."),
+ Qgis.MessageLevel.Info,
+ self.iface.messageTimeout(),
+ )
return
outUri = db.uri()
@@ -171,15 +195,20 @@ def importActionSlot(self):
def exportActionSlot(self):
table = self.tree.currentTable()
if table is None:
- self.infoBar.pushMessage(self.tr("Select the table you want export to file."), Qgis.MessageLevel.Info,
- self.iface.messageTimeout())
+ self.infoBar.pushMessage(
+ self.tr("Select the table you want export to file."),
+ Qgis.MessageLevel.Info,
+ self.iface.messageTimeout(),
+ )
return
inLayer = table.toMapLayer()
if inLayer.type() != QgsMapLayerType.VectorLayer:
self.infoBar.pushMessage(
self.tr("Select a vector or a tabular layer you want export."),
- Qgis.MessageLevel.Warning, self.iface.messageTimeout())
+ Qgis.MessageLevel.Warning,
+ self.iface.messageTimeout(),
+ )
return
from .dlg_export_vector import DlgExportVector
@@ -192,8 +221,11 @@ def exportActionSlot(self):
def runSqlWindow(self):
db = self.tree.currentDatabase()
if db is None:
- self.infoBar.pushMessage(self.tr("No database selected or you are not connected to it."),
- Qgis.MessageLevel.Info, self.iface.messageTimeout())
+ self.infoBar.pushMessage(
+ self.tr("No database selected or you are not connected to it."),
+ Qgis.MessageLevel.Info,
+ self.iface.messageTimeout(),
+ )
# force displaying of the message, it appears on the first tab (i.e. Info)
self.tabs.setCurrentIndex(0)
return
@@ -206,10 +238,13 @@ def runSqlWindow(self):
index = self.tabs.addTab(query, tabname)
self.tabs.setTabIcon(index, db.connection().icon())
self.tabs.setCurrentIndex(index)
- query.nameChanged.connect(functools.partial(self.update_query_tab_name, index, dbname))
+ query.nameChanged.connect(
+ functools.partial(self.update_query_tab_name, index, dbname)
+ )
def runSqlLayerWindow(self, layer):
from .dlg_sql_layer_window import DlgSqlLayerWindow
+
query = DlgSqlLayerWindow(self.iface, layer, self)
lname = layer.name()
tabname = self.tr("Layer ({0})").format(lname)
@@ -220,18 +255,19 @@ def runSqlLayerWindow(self, layer):
def update_query_tab_name(self, index, dbname, queryname):
if not queryname:
queryname = self.tr("Query")
- tabname = "%s (%s)" % (queryname, dbname)
+ tabname = f"{queryname} ({dbname})"
self.tabs.setTabText(index, tabname)
def showSystemTables(self):
self.tree.showSystemTables(self.actionShowSystemTables.isChecked())
def registerAction(self, action, menuName, callback=None):
- """ register an action to the manager's main menu """
- if not hasattr(self, '_registeredDbActions'):
+ """register an action to the manager's main menu"""
+ if not hasattr(self, "_registeredDbActions"):
self._registeredDbActions = {}
if callback is not None:
+
def invoke_callback(x):
return self.invokeCallback(callback)
@@ -272,7 +308,9 @@ def invoke_callback(x):
# get the placeholder's position to insert before it
pos = 0
for pos in range(len(menuActions)):
- if menuActions[pos].isSeparator() and menuActions[pos].objectName().endswith("_placeholder"):
+ if menuActions[pos].isSeparator() and menuActions[
+ pos
+ ].objectName().endswith("_placeholder"):
menuActions[pos].setVisible(True)
break
@@ -294,12 +332,12 @@ def invoke_callback(x):
return True
def invokeCallback(self, callback, *params):
- """ Call a method passing the selected item in the database tree,
- the sender (usually a QAction), the plugin mainWindow and
- optionally additional parameters.
+ """Call a method passing the selected item in the database tree,
+ the sender (usually a QAction), the plugin mainWindow and
+ optionally additional parameters.
- This method takes care to override and restore the cursor,
- but also catches exceptions and displays the error dialog.
+ This method takes care to override and restore the cursor,
+ but also catches exceptions and displays the error dialog.
"""
with OverrideCursor(Qt.CursorShape.WaitCursor):
try:
@@ -309,7 +347,7 @@ def invokeCallback(self, callback, *params):
DlgDbError.showError(e, self)
def unregisterAction(self, action, menuName):
- if not hasattr(self, '_registeredDbActions'):
+ if not hasattr(self, "_registeredDbActions"):
return
if menuName is None or menuName == "":
@@ -340,7 +378,9 @@ def unregisterAction(self, action, menuName):
# hide the placeholder if there're no other registered actions
if len(self._registeredDbActions[menuName]) <= 0:
for i in range(len(menuActions)):
- if menuActions[i].isSeparator() and menuActions[i].objectName().endswith("_placeholder"):
+ if menuActions[i].isSeparator() and menuActions[
+ i
+ ].objectName().endswith("_placeholder"):
menuActions[i].setVisible(False)
break
@@ -350,7 +390,7 @@ def unregisterAction(self, action, menuName):
return False
def unregisterAllActions(self):
- if not hasattr(self, '_registeredDbActions'):
+ if not hasattr(self, "_registeredDbActions"):
return
for menuName in self._registeredDbActions:
@@ -400,14 +440,20 @@ def setupUi(self):
self.tabs.tabCloseRequested.connect(self.close_tab)
tabbar = self.tabs.tabBar()
for i in range(3):
- btn = tabbar.tabButton(i, QTabBar.ButtonPosition.RightSide) if tabbar.tabButton(i, QTabBar.ButtonPosition.RightSide) else tabbar.tabButton(i, QTabBar.ButtonPosition.LeftSide)
+ btn = (
+ tabbar.tabButton(i, QTabBar.ButtonPosition.RightSide)
+ if tabbar.tabButton(i, QTabBar.ButtonPosition.RightSide)
+ else tabbar.tabButton(i, QTabBar.ButtonPosition.LeftSide)
+ )
btn.resize(0, 0)
btn.hide()
# Creates layout for message bar
self.layout = QGridLayout(self.info)
self.layout.setContentsMargins(0, 0, 0, 0)
- spacerItem = QSpacerItem(20, 40, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding)
+ spacerItem = QSpacerItem(
+ 20, 40, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding
+ )
self.layout.addItem(spacerItem, 1, 0, 1, 1)
# init messageBar instance
self.infoBar = QgsMessageBar(self.info)
@@ -452,15 +498,18 @@ def setupUi(self):
sep.setObjectName("DB_Manager_DbMenu_placeholder")
sep.setVisible(False)
- self.actionRefresh = QAction(QgsApplication.getThemeIcon("/mActionRefresh.svg"), self.tr("&Refresh"),
- self.menuDb)
+ self.actionRefresh = QAction(
+ QgsApplication.getThemeIcon("/mActionRefresh.svg"),
+ self.tr("&Refresh"),
+ self.menuDb,
+ )
self.actionRefresh.triggered.connect(self.refreshActionSlot)
self.actionRefresh.setShortcut(QKeySequence("F5"))
self.menuDb.addAction(self.actionRefresh)
- self.actionSqlWindow = QAction(GuiUtils.get_icon('mActionSQLWindow'),
- self.tr("&SQL Window"),
- self.menuDb)
+ self.actionSqlWindow = QAction(
+ GuiUtils.get_icon("mActionSQLWindow"), self.tr("&SQL Window"), self.menuDb
+ )
self.actionSqlWindow.triggered.connect(self.runSqlWindow)
self.actionSqlWindow.setShortcut(QKeySequence("F2"))
self.menuDb.addAction(self.actionSqlWindow)
@@ -484,12 +533,16 @@ def setupUi(self):
sep.setObjectName("DB_Manager_TableMenu_placeholder")
sep.setVisible(False)
- self.actionImport = self.menuTable.addAction(GuiUtils.get_icon("mActionDBImport"),
- QApplication.translate("DBManager", "&Import Layer/File…"),
- self.importActionSlot)
- self.actionExport = self.menuTable.addAction(GuiUtils.get_icon("mActionDBExport"),
- QApplication.translate("DBManager", "&Export to File…"),
- self.exportActionSlot)
+ self.actionImport = self.menuTable.addAction(
+ GuiUtils.get_icon("mActionDBImport"),
+ QApplication.translate("DBManager", "&Import Layer/File…"),
+ self.importActionSlot,
+ )
+ self.actionExport = self.menuTable.addAction(
+ GuiUtils.get_icon("mActionDBExport"),
+ QApplication.translate("DBManager", "&Export to File…"),
+ self.exportActionSlot,
+ )
self.menuTable.addSeparator()
# self.actionShowSystemTables = self.menuTable.addAction(self.tr("Show system tables/views"), self.showSystemTables)
# self.actionShowSystemTables.setCheckable(True)
diff --git a/python/plugins/db_manager/db_manager_plugin.py b/python/plugins/db_manager/db_manager_plugin.py
index cd0ea9318e05..78d996c5a867 100644
--- a/python/plugins/db_manager/db_manager_plugin.py
+++ b/python/plugins/db_manager/db_manager_plugin.py
@@ -22,12 +22,7 @@
from qgis.PyQt.QtWidgets import QAction, QApplication
from qgis.PyQt.QtGui import QIcon
-from qgis.core import (
- QgsProject,
- QgsMapLayerType,
- QgsDataSourceUri,
- QgsApplication
-)
+from qgis.core import QgsProject, QgsMapLayerType, QgsDataSourceUri, QgsApplication
class DBManagerPlugin:
@@ -37,28 +32,37 @@ def __init__(self, iface):
self.dlg = None
def initGui(self):
- self.action = QAction(QgsApplication.getThemeIcon('dbmanager.svg'), QApplication.translate("DBManagerPlugin", "DB Manager…"),
- self.iface.mainWindow())
+ self.action = QAction(
+ QgsApplication.getThemeIcon("dbmanager.svg"),
+ QApplication.translate("DBManagerPlugin", "DB Manager…"),
+ self.iface.mainWindow(),
+ )
self.action.setObjectName("dbManager")
self.action.triggered.connect(self.run)
# Add toolbar button and menu item
- if hasattr(self.iface, 'addDatabaseToolBarIcon'):
+ if hasattr(self.iface, "addDatabaseToolBarIcon"):
self.iface.addDatabaseToolBarIcon(self.action)
else:
self.iface.addToolBarIcon(self.action)
- if hasattr(self.iface, 'addPluginToDatabaseMenu'):
- self.iface.addPluginToDatabaseMenu(QApplication.translate("DBManagerPlugin", None), self.action)
+ if hasattr(self.iface, "addPluginToDatabaseMenu"):
+ self.iface.addPluginToDatabaseMenu(
+ QApplication.translate("DBManagerPlugin", None), self.action
+ )
else:
- self.iface.addPluginToMenu(QApplication.translate("DBManagerPlugin", "DB Manager"), self.action)
+ self.iface.addPluginToMenu(
+ QApplication.translate("DBManagerPlugin", "DB Manager"), self.action
+ )
def unload(self):
# Remove the plugin menu item and icon
- if hasattr(self.iface, 'databaseMenu'):
+ if hasattr(self.iface, "databaseMenu"):
self.iface.databaseMenu().removeAction(self.action)
else:
- self.iface.removePluginMenu(QApplication.translate("DBManagerPlugin", "DB Manager"), self.action)
- if hasattr(self.iface, 'removeDatabaseToolBarIcon'):
+ self.iface.removePluginMenu(
+ QApplication.translate("DBManagerPlugin", "DB Manager"), self.action
+ )
+ if hasattr(self.iface, "removeDatabaseToolBarIcon"):
self.iface.removeDatabaseToolBarIcon(self.action)
else:
self.iface.removeToolBarIcon(self.action)
@@ -69,7 +73,7 @@ def unload(self):
def onUpdateSqlLayer(self):
# Be able to update every Db layer from Postgres, Spatialite and Oracle
l = self.iface.activeLayer()
- if l.dataProvider().name() in ['postgres', 'spatialite', 'oracle']:
+ if l.dataProvider().name() in ["postgres", "spatialite", "oracle"]:
self.run()
self.dlg.runSqlLayerWindow(l)
# virtual has QUrl source
@@ -87,7 +91,9 @@ def run(self):
self.dlg.destroyed.connect(self.onDestroyed)
self.dlg.show()
self.dlg.raise_()
- self.dlg.setWindowState(self.dlg.windowState() & ~Qt.WindowState.WindowMinimized)
+ self.dlg.setWindowState(
+ self.dlg.windowState() & ~Qt.WindowState.WindowMinimized
+ )
self.dlg.activateWindow()
def onDestroyed(self, obj):
diff --git a/python/plugins/db_manager/db_model.py b/python/plugins/db_manager/db_model.py
index 14d30472bfd3..191aaed1e40d 100644
--- a/python/plugins/db_manager/db_model.py
+++ b/python/plugins/db_manager/db_model.py
@@ -19,7 +19,19 @@
"""
from functools import partial
-from qgis.PyQt.QtCore import Qt, QObject, qDebug, QByteArray, QMimeData, QDataStream, QIODevice, QFileInfo, QAbstractItemModel, QModelIndex, pyqtSignal
+from qgis.PyQt.QtCore import (
+ Qt,
+ QObject,
+ qDebug,
+ QByteArray,
+ QMimeData,
+ QDataStream,
+ QIODevice,
+ QFileInfo,
+ QAbstractItemModel,
+ QModelIndex,
+ pyqtSignal,
+)
from qgis.PyQt.QtWidgets import QApplication, QMessageBox
from qgis.PyQt.QtGui import QIcon
@@ -156,7 +168,7 @@ def __init__(self, connection, parent=None):
connection.deleted.connect(self.itemDeleted)
# load (shared) icon with first instance of table item
- if not hasattr(ConnectionItem, 'connectedIcon'):
+ if not hasattr(ConnectionItem, "connectedIcon"):
ConnectionItem.connectedIcon = GuiUtils.get_icon("plugged")
ConnectionItem.disconnectedIcon = GuiUtils.get_icon("unplugged")
@@ -214,7 +226,7 @@ def __init__(self, schema, parent):
schema.deleted.connect(self.itemDeleted)
# load (shared) icon with first instance of schema item
- if not hasattr(SchemaItem, 'schemaIcon'):
+ if not hasattr(SchemaItem, "schemaIcon"):
SchemaItem.schemaIcon = GuiUtils.get_icon("namespace")
def data(self, column):
@@ -245,14 +257,20 @@ def __init__(self, table, parent):
self.populate()
# load (shared) icon with first instance of table item
- if not hasattr(TableItem, 'tableIcon'):
+ if not hasattr(TableItem, "tableIcon"):
TableItem.tableIcon = QgsApplication.getThemeIcon("/mIconTableLayer.svg")
TableItem.viewIcon = GuiUtils.get_icon("view")
TableItem.viewMaterializedIcon = GuiUtils.get_icon("view_materialized")
- TableItem.layerPointIcon = QgsApplication.getThemeIcon("/mIconPointLayer.svg")
+ TableItem.layerPointIcon = QgsApplication.getThemeIcon(
+ "/mIconPointLayer.svg"
+ )
TableItem.layerLineIcon = QgsApplication.getThemeIcon("/mIconLineLayer.svg")
- TableItem.layerPolygonIcon = QgsApplication.getThemeIcon("/mIconPolygonLayer.svg")
- TableItem.layerRasterIcon = QgsApplication.getThemeIcon("/mIconRasterLayer.svg")
+ TableItem.layerPolygonIcon = QgsApplication.getThemeIcon(
+ "/mIconPolygonLayer.svg"
+ )
+ TableItem.layerRasterIcon = QgsApplication.getThemeIcon(
+ "/mIconRasterLayer.svg"
+ )
TableItem.layerUnknownIcon = GuiUtils.get_icon("layer_unknown")
def data(self, column):
@@ -267,11 +285,15 @@ def icon(self):
if self.getItemData().type == Table.VectorType:
geom_type = self.getItemData().geomType
if geom_type is not None:
- if geom_type.find('POINT') != -1:
+ if geom_type.find("POINT") != -1:
return self.layerPointIcon
- elif geom_type.find('LINESTRING') != -1 or geom_type in ('CIRCULARSTRING', 'COMPOUNDCURVE', 'MULTICURVE'):
+ elif geom_type.find("LINESTRING") != -1 or geom_type in (
+ "CIRCULARSTRING",
+ "COMPOUNDCURVE",
+ "MULTICURVE",
+ ):
return self.layerLineIcon
- elif geom_type.find('POLYGON') != -1 or geom_type == 'MULTISURFACE':
+ elif geom_type.find("POLYGON") != -1 or geom_type == "MULTISURFACE":
return self.layerPolygonIcon
return self.layerUnknownIcon
@@ -279,7 +301,10 @@ def icon(self):
return self.layerRasterIcon
if self.getItemData().isView:
- if hasattr(self.getItemData(), '_relationType') and self.getItemData()._relationType == 'm':
+ if (
+ hasattr(self.getItemData(), "_relationType")
+ and self.getItemData()._relationType == "m"
+ ):
return self.viewMaterializedIcon
else:
return self.viewIcon
@@ -291,7 +316,7 @@ def path(self):
pathList.extend(self.parent().path())
if self.getItemData().type == Table.VectorType:
- pathList.append("%s::%s" % (self.data(0), self.getItemData().geomColumn))
+ pathList.append(f"{self.data(0)}::{self.getItemData().geomColumn}")
else:
pathList.append(self.data(0))
@@ -307,7 +332,7 @@ def __init__(self, parent=None):
QAbstractItemModel.__init__(self, parent)
self.treeView = parent
- self.header = [self.tr('Databases')]
+ self.header = [self.tr("Databases")]
if isImportVectorAvail:
self.importVector.connect(self.vectorImport)
@@ -400,10 +425,14 @@ def flags(self, index):
if index.column() == 0:
item = index.internalPointer()
- if isinstance(item, SchemaItem) \
- or (isinstance(item, TableItem)
- and not (self.hasGPKGSupport and item.getItemData().type == Table.RasterType
- and int(gdal.VersionInfo()) < 3100000)):
+ if isinstance(item, SchemaItem) or (
+ isinstance(item, TableItem)
+ and not (
+ self.hasGPKGSupport
+ and item.getItemData().type == Table.RasterType
+ and int(gdal.VersionInfo()) < 3100000
+ )
+ ):
flags |= Qt.ItemFlag.ItemIsEditable
if isinstance(item, TableItem):
@@ -424,7 +453,11 @@ def flags(self, index):
return flags
def headerData(self, section, orientation, role):
- if orientation == Qt.Orientation.Horizontal and role == Qt.ItemDataRole.DisplayRole and section < len(self.header):
+ if (
+ orientation == Qt.Orientation.Horizontal
+ and role == Qt.ItemDataRole.DisplayRole
+ and section < len(self.header)
+ ):
return self.header[section]
return None
@@ -546,9 +579,17 @@ def dropMimeData(self, data, action, row, column, parent):
return True
# vectors/tables to be imported must be dropped on connected db, schema or table
- canImportLayer = isImportVectorAvail and parent.isValid() and \
- (isinstance(parent.internalPointer(), (SchemaItem, TableItem)) or
- (isinstance(parent.internalPointer(), ConnectionItem) and parent.internalPointer().populated))
+ canImportLayer = (
+ isImportVectorAvail
+ and parent.isValid()
+ and (
+ isinstance(parent.internalPointer(), (SchemaItem, TableItem))
+ or (
+ isinstance(parent.internalPointer(), ConnectionItem)
+ and parent.internalPointer().populated
+ )
+ )
+ )
added = 0
@@ -578,20 +619,24 @@ def dropMimeData(self, data, action, row, column, parent):
if canImportLayer:
if QgsRasterLayer.isValidRasterFileName(filename):
- layerType = 'raster'
- providerKey = 'gdal'
+ layerType = "raster"
+ providerKey = "gdal"
else:
- layerType = 'vector'
- providerKey = 'ogr'
+ layerType = "vector"
+ providerKey = "ogr"
layerName = QFileInfo(filename).completeBaseName()
- if self.importLayer(layerType, providerKey, layerName, filename, parent):
+ if self.importLayer(
+ layerType, providerKey, layerName, filename, parent
+ ):
added += 1
if data.hasFormat(self.QGIS_URI_MIME):
for uri in QgsMimeDataUtils.decodeUriList(data):
if canImportLayer:
- if self.importLayer(uri.layerType, uri.providerKey, uri.name, uri.uri, parent):
+ if self.importLayer(
+ uri.layerType, uri.providerKey, uri.name, uri.uri, parent
+ ):
added += 1
return added > 0
@@ -602,7 +647,7 @@ def importLayer(self, layerType, providerKey, layerName, uriString, parent):
if not isImportVectorAvail:
return False
- if layerType == 'raster':
+ if layerType == "raster":
return False # not implemented yet
inLayer = QgsRasterLayer(uriString, layerName, providerKey)
else:
@@ -610,7 +655,11 @@ def importLayer(self, layerType, providerKey, layerName, uriString, parent):
if not inLayer.isValid():
# invalid layer
- QMessageBox.warning(None, self.tr("Invalid layer"), self.tr("Unable to load the layer {0}").format(inLayer.name()))
+ QMessageBox.warning(
+ None,
+ self.tr("Invalid layer"),
+ self.tr("Unable to load the layer {0}").format(inLayer.name()),
+ )
return False
# retrieve information about the new table's db and schema
@@ -630,11 +679,15 @@ def importLayer(self, layerType, providerKey, layerName, uriString, parent):
if inLayer.type() == inLayer.VectorLayer:
# create the output uri
- schema = outSchema.name if outDb.schemas() is not None and outSchema is not None else ""
+ schema = (
+ outSchema.name
+ if outDb.schemas() is not None and outSchema is not None
+ else ""
+ )
pkCol = geomCol = ""
# default pk and geom field name value
- if providerKey in ['postgres', 'spatialite']:
+ if providerKey in ["postgres", "spatialite"]:
inUri = QgsDataSourceUri(inLayer.source())
pkCol = inUri.keyColumn()
geomCol = inUri.geometryColumn()
diff --git a/python/plugins/db_manager/db_plugins/__init__.py b/python/plugins/db_manager/db_plugins/__init__.py
index 41f61c7bb5c9..e35b113dcf9c 100644
--- a/python/plugins/db_manager/db_plugins/__init__.py
+++ b/python/plugins/db_manager/db_plugins/__init__.py
@@ -23,11 +23,14 @@ class NotSupportedDbType(Exception):
def __init__(self, dbtype):
from qgis.PyQt.QtWidgets import QApplication
- self.msg = QApplication.translate("DBManagerPlugin", "{0} is not supported yet").format(dbtype)
+
+ self.msg = QApplication.translate(
+ "DBManagerPlugin", "{0} is not supported yet"
+ ).format(dbtype)
Exception(self, self.msg)
def __str__(self):
- return self.msg.encode('utf-8')
+ return self.msg.encode("utf-8")
def initDbPluginList():
@@ -35,7 +38,7 @@ def initDbPluginList():
current_dir = os.path.dirname(__file__)
for name in os.listdir(current_dir):
- if name == '__pycache__':
+ if name == "__pycache__":
continue
if not os.path.isdir(os.path.join(current_dir, name)):
continue
@@ -43,7 +46,7 @@ def initDbPluginList():
try:
exec("from .%s import plugin as mod" % name, globals())
except ImportError as e:
- DBPLUGIN_ERRORS.append("%s: %s" % (name, str(e)))
+ DBPLUGIN_ERRORS.append(f"{name}: {str(e)}")
continue
pluginclass = mod.classFactory() # NOQA
diff --git a/python/plugins/db_manager/db_plugins/connector.py b/python/plugins/db_manager/db_plugins/connector.py
index 4cda39e1992b..49ec950e57ba 100644
--- a/python/plugins/db_manager/db_plugins/connector.py
+++ b/python/plugins/db_manager/db_plugins/connector.py
@@ -26,8 +26,7 @@
class DBConnector:
def __init__(self, uri):
- """Creates a new DB connector
- """
+ """Creates a new DB connector"""
self.connection = None
self._uri = uri
@@ -95,17 +94,22 @@ def _execute(self, cursor, sql):
return cursor
def _execute_and_commit(self, sql):
- """ tries to execute and commit some action, on error it rolls back the change """
+ """tries to execute and commit some action, on error it rolls back the change"""
self._execute(None, sql)
self._commit()
def _get_cursor(self, name=None):
try:
if name is not None:
- name = str(name).encode('ascii', 'replace').replace('?', "_")
- self._last_cursor_named_id = 0 if not hasattr(self,
- '_last_cursor_named_id') else self._last_cursor_named_id + 1
- return self.connection.cursor("%s_%d" % (name, self._last_cursor_named_id))
+ name = str(name).encode("ascii", "replace").replace("?", "_")
+ self._last_cursor_named_id = (
+ 0
+ if not hasattr(self, "_last_cursor_named_id")
+ else self._last_cursor_named_id + 1
+ )
+ return self.connection.cursor(
+ "%s_%d" % (name, self._last_cursor_named_id)
+ )
return self.connection.cursor()
@@ -183,36 +187,33 @@ def _get_cursor_columns(self, c):
@classmethod
def quoteId(self, identifier):
- if hasattr(identifier, '__iter__') and not isinstance(identifier, str):
- return '.'.join(
- self.quoteId(i)
- for i in identifier
- if i is not None and i != ""
+ if hasattr(identifier, "__iter__") and not isinstance(identifier, str):
+ return ".".join(
+ self.quoteId(i) for i in identifier if i is not None and i != ""
)
- identifier = str(
- identifier) if identifier is not None else '' # make sure it's python unicode string
+ identifier = (
+ str(identifier) if identifier is not None else ""
+ ) # make sure it's python unicode string
return '"%s"' % identifier.replace('"', '""')
@classmethod
def quoteString(self, txt):
- """ make the string safe - replace ' with '' """
- if hasattr(txt, '__iter__') and not isinstance(txt, str):
- return '.'.join(
- self.quoteString(i)
- for i in txt
- if i is not None
- )
+ """make the string safe - replace ' with ''"""
+ if hasattr(txt, "__iter__") and not isinstance(txt, str):
+ return ".".join(self.quoteString(i) for i in txt if i is not None)
- txt = str(txt) if txt is not None else '' # make sure it's python unicode string
+ txt = (
+ str(txt) if txt is not None else ""
+ ) # make sure it's python unicode string
return "'%s'" % txt.replace("'", "''")
@classmethod
def getSchemaTableName(self, table):
- if not hasattr(table, '__iter__') and not isinstance(table, str):
+ if not hasattr(table, "__iter__") and not isinstance(table, str):
return (None, table)
if isinstance(table, str):
- table = table.split('.')
+ table = table.split(".")
if len(table) < 2:
return (None, table[0])
else:
@@ -220,7 +221,7 @@ def getSchemaTableName(self, table):
@classmethod
def getSqlDictionary(self):
- """ return a generic SQL dictionary """
+ """return a generic SQL dictionary"""
try:
from ..sql_dictionary import getSqlDictionary
@@ -230,7 +231,7 @@ def getSqlDictionary(self):
def getComment(self, tablename, field):
"""Returns the comment for a field"""
- return ''
+ return ""
def commentTable(self, schema, tablename, comment=None):
"""Comment the table"""
diff --git a/python/plugins/db_manager/db_plugins/data_model.py b/python/plugins/db_manager/db_plugins/data_model.py
index 1087035fe8ba..a8e9b9ae918f 100644
--- a/python/plugins/db_manager/db_plugins/data_model.py
+++ b/python/plugins/db_manager/db_plugins/data_model.py
@@ -18,15 +18,15 @@
***************************************************************************/
"""
-from qgis.PyQt.QtCore import (Qt,
- QElapsedTimer,
- QRegularExpression,
- QAbstractTableModel,
- pyqtSignal,
- QObject)
-from qgis.PyQt.QtGui import (QFont,
- QStandardItemModel,
- QStandardItem)
+from qgis.PyQt.QtCore import (
+ Qt,
+ QElapsedTimer,
+ QRegularExpression,
+ QAbstractTableModel,
+ pyqtSignal,
+ QObject,
+)
+from qgis.PyQt.QtGui import QFont, QStandardItemModel, QStandardItem
from qgis.PyQt.QtWidgets import QApplication
from qgis.core import QgsTask
@@ -47,8 +47,7 @@ def headerToString(self, sep="\t"):
def rowToString(self, row, sep="\t"):
return sep.join(
- str(self.getData(row, col))
- for col in range(self.columnCount())
+ str(self.getData(row, col)) for col in range(self.columnCount())
)
def getData(self, row, col):
@@ -64,9 +63,11 @@ def columnCount(self, parent=None):
return len(self._header)
def data(self, index, role):
- if role not in [Qt.ItemDataRole.DisplayRole,
- Qt.ItemDataRole.EditRole,
- Qt.ItemDataRole.FontRole]:
+ if role not in [
+ Qt.ItemDataRole.DisplayRole,
+ Qt.ItemDataRole.EditRole,
+ Qt.ItemDataRole.FontRole,
+ ]:
return None
val = self.getData(index.row(), index.column())
@@ -92,7 +93,9 @@ def data(self, index, role):
try:
return str(val) # convert to Unicode
except UnicodeDecodeError:
- return str(val, 'utf-8', 'replace') # convert from utf8 and replace errors (if any)
+ return str(
+ val, "utf-8", "replace"
+ ) # convert from utf8 and replace errors (if any)
def headerData(self, section, orientation, role):
if role != Qt.ItemDataRole.DisplayRole:
@@ -121,16 +124,22 @@ def __init__(self, table, parent=None):
self.fields.append(self._sanitizeTableField(fld))
self.fetchedCount = 201
- self.fetchedFrom = -self.fetchedCount - 1 # so the first call to getData will exec fetchMoreData(0)
+ self.fetchedFrom = (
+ -self.fetchedCount - 1
+ ) # so the first call to getData will exec fetchMoreData(0)
def _sanitizeTableField(self, field):
- """ quote column names to avoid some problems (e.g. columns with upper case) """
+ """quote column names to avoid some problems (e.g. columns with upper case)"""
return self.db.quoteId(field)
def getData(self, row, col):
if row < self.fetchedFrom or row >= self.fetchedFrom + self.fetchedCount:
margin = self.fetchedCount / 2
- start = int(self.rowCount() - margin if row + margin >= self.rowCount() else row - margin)
+ start = int(
+ self.rowCount() - margin
+ if row + margin >= self.rowCount()
+ else row - margin
+ )
if start < 0:
start = 0
self.fetchMoreData(start)
@@ -141,7 +150,11 @@ def fetchMoreData(self, row_start):
def rowCount(self, index=None):
# case for tables with no columns ... any reason to use them? :-)
- return self.table.rowCount if self.table.rowCount is not None and self.columnCount(index) > 0 else 0
+ return (
+ self.table.rowCount
+ if self.table.rowCount is not None and self.columnCount(index) > 0
+ else 0
+ )
class SqlResultModelAsync(QObject):
@@ -149,7 +162,7 @@ class SqlResultModelAsync(QObject):
def __init__(self):
super().__init__()
- self.error = BaseError('')
+ self.error = BaseError("")
self.status = None
self.model = None
self.task = None
@@ -172,11 +185,13 @@ def modelDone(self):
class SqlResultModelTask(QgsTask):
def __init__(self, db, sql, parent):
- super().__init__(description=QApplication.translate("DBManagerPlugin", "Executing SQL"))
+ super().__init__(
+ description=QApplication.translate("DBManagerPlugin", "Executing SQL")
+ )
self.db = db
self.sql = sql
self.parent = parent
- self.error = BaseError('')
+ self.error = BaseError("")
self.model = None
@@ -231,12 +246,19 @@ def rowFromData(self, data):
row = []
for c in data:
item = QStandardItem(str(c))
- item.setFlags((item.flags() | Qt.ItemFlag.ItemIsEditable) if self.editable else (item.flags() & ~Qt.ItemFlag.ItemIsEditable))
+ item.setFlags(
+ (item.flags() | Qt.ItemFlag.ItemIsEditable)
+ if self.editable
+ else (item.flags() & ~Qt.ItemFlag.ItemIsEditable)
+ )
row.append(item)
return row
def headerData(self, section, orientation, role):
- if orientation == Qt.Orientation.Horizontal and role == Qt.ItemDataRole.DisplayRole:
+ if (
+ orientation == Qt.Orientation.Horizontal
+ and role == Qt.ItemDataRole.DisplayRole
+ ):
return self.header[section]
return None
@@ -254,27 +276,46 @@ def getObjectIter(self):
class TableFieldsModel(SimpleTableModel):
def __init__(self, parent, editable=False):
- SimpleTableModel.__init__(self, ['Name', 'Type', 'Null', 'Default', 'Comment'], editable, parent)
+ SimpleTableModel.__init__(
+ self, ["Name", "Type", "Null", "Default", "Comment"], editable, parent
+ )
def headerData(self, section, orientation, role):
- if orientation == Qt.Orientation.Vertical and role == Qt.ItemDataRole.DisplayRole:
+ if (
+ orientation == Qt.Orientation.Vertical
+ and role == Qt.ItemDataRole.DisplayRole
+ ):
return section + 1
return SimpleTableModel.headerData(self, section, orientation, role)
def flags(self, index):
flags = SimpleTableModel.flags(self, index)
- if index.column() == 2 and flags & Qt.ItemFlag.ItemIsEditable: # set Null column as checkable instead of editable
- flags = flags & ~Qt.ItemFlag.ItemIsEditable | Qt.ItemFlag.ItemIsUserCheckable
+ if (
+ index.column() == 2 and flags & Qt.ItemFlag.ItemIsEditable
+ ): # set Null column as checkable instead of editable
+ flags = (
+ flags & ~Qt.ItemFlag.ItemIsEditable | Qt.ItemFlag.ItemIsUserCheckable
+ )
return flags
def append(self, fld):
- data = [fld.name, fld.type2String(), not fld.notNull, fld.default2String(), fld.getComment()]
+ data = [
+ fld.name,
+ fld.type2String(),
+ not fld.notNull,
+ fld.default2String(),
+ fld.getComment(),
+ ]
self.appendRow(self.rowFromData(data))
row = self.rowCount() - 1
self.setData(self.index(row, 0), fld, Qt.ItemDataRole.UserRole)
self.setData(self.index(row, 1), fld.primaryKey, Qt.ItemDataRole.UserRole)
self.setData(self.index(row, 2), None, Qt.ItemDataRole.DisplayRole)
- self.setData(self.index(row, 2), Qt.CheckState.Unchecked if fld.notNull else Qt.CheckState.Checked, Qt.ItemDataRole.CheckStateRole)
+ self.setData(
+ self.index(row, 2),
+ Qt.CheckState.Unchecked if fld.notNull else Qt.CheckState.Checked,
+ Qt.ItemDataRole.CheckStateRole,
+ )
def _getNewObject(self):
from .plugin import TableField
@@ -295,24 +336,31 @@ def getObject(self, row):
fld.modifier = None
fld.dataType = typestr
- fld.notNull = self.data(self.index(row, 2), Qt.ItemDataRole.CheckStateRole) == Qt.CheckState.Unchecked
+ fld.notNull = (
+ self.data(self.index(row, 2), Qt.ItemDataRole.CheckStateRole)
+ == Qt.CheckState.Unchecked
+ )
fld.primaryKey = self.data(self.index(row, 1), Qt.ItemDataRole.UserRole)
fld.comment = self.data(self.index(row, 4))
return fld
def getFields(self):
- return [
- fld
- for fld in self.getObjectIter()
- ]
+ return [fld for fld in self.getObjectIter()]
class TableConstraintsModel(SimpleTableModel):
def __init__(self, parent, editable=False):
- SimpleTableModel.__init__(self, [QApplication.translate("DBManagerPlugin", 'Name'),
- QApplication.translate("DBManagerPlugin", 'Type'),
- QApplication.translate("DBManagerPlugin", 'Column(s)')], editable, parent)
+ SimpleTableModel.__init__(
+ self,
+ [
+ QApplication.translate("DBManagerPlugin", "Name"),
+ QApplication.translate("DBManagerPlugin", "Type"),
+ QApplication.translate("DBManagerPlugin", "Column(s)"),
+ ],
+ editable,
+ parent,
+ )
def append(self, constr):
field_names = [str(k_v[1].name) for k_v in iter(list(constr.fields().items()))]
@@ -338,17 +386,21 @@ def getObject(self, row):
return constr
def getConstraints(self):
- return [
- constr
- for constr in self.getObjectIter()
- ]
+ return [constr for constr in self.getObjectIter()]
class TableIndexesModel(SimpleTableModel):
def __init__(self, parent, editable=False):
- SimpleTableModel.__init__(self, [QApplication.translate("DBManagerPlugin", 'Name'),
- QApplication.translate("DBManagerPlugin", 'Column(s)')], editable, parent)
+ SimpleTableModel.__init__(
+ self,
+ [
+ QApplication.translate("DBManagerPlugin", "Name"),
+ QApplication.translate("DBManagerPlugin", "Column(s)"),
+ ],
+ editable,
+ parent,
+ )
def append(self, idx):
field_names = [str(k_v1[1].name) for k_v1 in iter(list(idx.fields().items()))]
@@ -372,7 +424,4 @@ def getObject(self, row):
return idx
def getIndexes(self):
- return [
- idx
- for idx in self.getObjectIter()
- ]
+ return [idx for idx in self.getObjectIter()]
diff --git a/python/plugins/db_manager/db_plugins/gpkg/connector.py b/python/plugins/db_manager/db_plugins/gpkg/connector.py
index 77de9a3f7606..a7091a0f6ed7 100644
--- a/python/plugins/db_manager/db_plugins/gpkg/connector.py
+++ b/python/plugins/db_manager/db_plugins/gpkg/connector.py
@@ -39,6 +39,7 @@
import sqlite3
from osgeo import gdal, ogr, osr
+
gdal.UseExceptions()
ogr.UseExceptions()
@@ -83,10 +84,24 @@ def _opendb(self):
try:
self.gdal_ds = gdal.OpenEx(self.dbname)
except Exception:
- raise ConnectionError(QApplication.translate("DBManagerPlugin", '"{0}" not found').format(self.dbname))
- if self.gdal_ds.GetDriver().ShortName != 'GPKG':
- raise ConnectionError(QApplication.translate("DBManagerPlugin", '"{dbname}" not recognized as GPKG ({shortname} reported instead.)').format(dbname=self.dbname, shortname=self.gdal_ds.GetDriver().ShortName))
- self.has_raster = self.gdal_ds.RasterCount != 0 or self.gdal_ds.GetMetadata('SUBDATASETS') is not None
+ raise ConnectionError(
+ QApplication.translate("DBManagerPlugin", '"{0}" not found').format(
+ self.dbname
+ )
+ )
+ if self.gdal_ds.GetDriver().ShortName != "GPKG":
+ raise ConnectionError(
+ QApplication.translate(
+ "DBManagerPlugin",
+ '"{dbname}" not recognized as GPKG ({shortname} reported instead.)',
+ ).format(
+ dbname=self.dbname, shortname=self.gdal_ds.GetDriver().ShortName
+ )
+ )
+ self.has_raster = (
+ self.gdal_ds.RasterCount != 0
+ or self.gdal_ds.GetMetadata("SUBDATASETS") is not None
+ )
self.connection = None
self._current_thread = None
@@ -97,7 +112,9 @@ def connection(self):
invalidates it and create a new one.
"""
- if self._connection is None or self._current_thread != int(QThread.currentThreadId()):
+ if self._connection is None or self._current_thread != int(
+ QThread.currentThreadId()
+ ):
self._current_thread = int(QThread.currentThreadId())
try:
self._connection = spatialite_connect(str(self.dbname))
@@ -110,9 +127,13 @@ def connection(self, conn):
self._connection = conn
def unquoteId(self, quotedId):
- if len(quotedId) <= 2 or quotedId[0] != '"' or quotedId[len(quotedId) - 1] != '"':
+ if (
+ len(quotedId) <= 2
+ or quotedId[0] != '"'
+ or quotedId[len(quotedId) - 1] != '"'
+ ):
return quotedId
- unquoted = ''
+ unquoted = ""
i = 1
while i < len(quotedId) - 1:
if quotedId[i] == '"' and quotedId[i + 1] == '"':
@@ -194,7 +215,7 @@ def isValidDatabase(cls, path):
ds = gdal.OpenEx(path)
except Exception:
return False
- return ds.GetDriver().ShortName == 'GPKG'
+ return ds.GetDriver().ShortName == "GPKG"
def getInfo(self):
return None
@@ -217,10 +238,9 @@ def canAddGeometryColumn(self, table):
def canAddSpatialIndex(self, table):
_, tablename = self.getSchemaTableName(table)
lyr = self.gdal_ds.GetLayerByName(tablename)
- if lyr is None or lyr.GetGeometryColumn() == '':
+ if lyr is None or lyr.GetGeometryColumn() == "":
return False
- return not self.hasSpatialIndex(table,
- lyr.GetGeometryColumn())
+ return not self.hasSpatialIndex(table, lyr.GetGeometryColumn())
def hasRasterSupport(self):
return self.has_raster
@@ -243,8 +263,7 @@ def fieldTypes(self):
"TINYINT",
"SMALLINT",
"DOUBLE",
- "FLOAT"
- "DATE",
+ "FLOAT" "DATE",
"DATETIME",
"BOOLEAN",
]
@@ -253,7 +272,7 @@ def getSchemas(self):
return None
def getTables(self, schema=None, add_sys_tables=False):
- """ get list of tables """
+ """get list of tables"""
items = []
try:
@@ -276,62 +295,73 @@ def getTables(self, schema=None, add_sys_tables=False):
return sorted(items, key=cmp_to_key(lambda x, y: (x[1] > y[1]) - (x[1] < y[1])))
def getVectorTables(self, schema=None):
- """Returns a list of vector table information
- """
+ """Returns a list of vector table information"""
items = []
- for table in self.core_connection.tables(schema, QgsAbstractDatabaseProviderConnection.TableFlag.Vector | QgsAbstractDatabaseProviderConnection.TableFlag.Aspatial):
- if not (table.flags() & QgsAbstractDatabaseProviderConnection.TableFlag.Aspatial):
+ for table in self.core_connection.tables(
+ schema,
+ QgsAbstractDatabaseProviderConnection.TableFlag.Vector
+ | QgsAbstractDatabaseProviderConnection.TableFlag.Aspatial,
+ ):
+ if not (
+ table.flags() & QgsAbstractDatabaseProviderConnection.TableFlag.Aspatial
+ ):
geom_type = table.geometryColumnTypes()[0]
# Use integer PG code for SRID
srid = geom_type.crs.postgisSrid()
geomtype_flatten = QgsWkbTypes.flatType(geom_type.wkbType)
- geomname = 'GEOMETRY'
+ geomname = "GEOMETRY"
if geomtype_flatten == QgsWkbTypes.Type.Point:
- geomname = 'POINT'
+ geomname = "POINT"
elif geomtype_flatten == QgsWkbTypes.Type.LineString:
- geomname = 'LINESTRING'
+ geomname = "LINESTRING"
elif geomtype_flatten == QgsWkbTypes.Type.Polygon:
- geomname = 'POLYGON'
+ geomname = "POLYGON"
elif geomtype_flatten == QgsWkbTypes.Type.MultiPoint:
- geomname = 'MULTIPOINT'
+ geomname = "MULTIPOINT"
elif geomtype_flatten == QgsWkbTypes.Type.MultiLineString:
- geomname = 'MULTILINESTRING'
+ geomname = "MULTILINESTRING"
elif geomtype_flatten == QgsWkbTypes.Type.MultiPolygon:
- geomname = 'MULTIPOLYGON'
+ geomname = "MULTIPOLYGON"
elif geomtype_flatten == QgsWkbTypes.Type.GeometryCollection:
- geomname = 'GEOMETRYCOLLECTION'
+ geomname = "GEOMETRYCOLLECTION"
elif geomtype_flatten == QgsWkbTypes.Type.CircularString:
- geomname = 'CIRCULARSTRING'
+ geomname = "CIRCULARSTRING"
elif geomtype_flatten == QgsWkbTypes.Type.CompoundCurve:
- geomname = 'COMPOUNDCURVE'
+ geomname = "COMPOUNDCURVE"
elif geomtype_flatten == QgsWkbTypes.Type.CurvePolygon:
- geomname = 'CURVEPOLYGON'
+ geomname = "CURVEPOLYGON"
elif geomtype_flatten == QgsWkbTypes.Type.MultiCurve:
- geomname = 'MULTICURVE'
+ geomname = "MULTICURVE"
elif geomtype_flatten == QgsWkbTypes.Type.MultiSurface:
- geomname = 'MULTISURFACE'
- geomdim = 'XY'
+ geomname = "MULTISURFACE"
+ geomdim = "XY"
if QgsWkbTypes.hasZ(geom_type.wkbType):
- geomdim += 'Z'
+ geomdim += "Z"
if QgsWkbTypes.hasM(geom_type.wkbType):
- geomdim += 'M'
+ geomdim += "M"
item = [
Table.VectorType,
table.tableName(),
- bool(table.flags() & QgsAbstractDatabaseProviderConnection.TableFlag.View), # is_view
+ bool(
+ table.flags()
+ & QgsAbstractDatabaseProviderConnection.TableFlag.View
+ ), # is_view
table.tableName(),
table.geometryColumn(),
geomname,
geomdim,
- srid
+ srid,
]
self.mapSridToName[srid] = geom_type.crs.description()
else:
item = [
Table.TableType,
table.tableName(),
- bool(table.flags() & QgsAbstractDatabaseProviderConnection.TableFlag.View),
+ bool(
+ table.flags()
+ & QgsAbstractDatabaseProviderConnection.TableFlag.View
+ ),
]
items.append(item)
@@ -339,25 +369,29 @@ def getVectorTables(self, schema=None):
return items
def getRasterTables(self, schema=None):
- """ get list of table with a geometry column
- it returns:
- name (table name)
- type = 'view' (is a view?)
- geometry_column:
- r.table_name (the prefix table name, use this to load the layer)
- r.geometry_column
- srid
+ """get list of table with a geometry column
+ it returns:
+ name (table name)
+ type = 'view' (is a view?)
+ geometry_column:
+ r.table_name (the prefix table name, use this to load the layer)
+ r.geometry_column
+ srid
"""
items = []
- for table in self.core_connection.tables(schema, QgsAbstractDatabaseProviderConnection.TableFlag.Raster):
+ for table in self.core_connection.tables(
+ schema, QgsAbstractDatabaseProviderConnection.TableFlag.Raster
+ ):
geom_type = table.geometryColumnTypes()[0]
# Use integer PG code for SRID
srid = geom_type.crs.postgisSrid()
item = [
Table.RasterType,
table.tableName(),
- bool(table.flags() & QgsAbstractDatabaseProviderConnection.TableFlag.View),
+ bool(
+ table.flags() & QgsAbstractDatabaseProviderConnection.TableFlag.View
+ ),
table.tableName(),
table.geometryColumn(),
srid,
@@ -372,7 +406,7 @@ def getTableRowCount(self, table):
return lyr.GetFeatureCount() if lyr is not None else None
def getTableFields(self, table):
- """ return list of columns in table """
+ """return list of columns in table"""
sql = "PRAGMA table_info(%s)" % (self.quoteId(table))
ret = self._fetchAll(sql)
if ret is None:
@@ -380,7 +414,7 @@ def getTableFields(self, table):
return ret
def getTableIndexes(self, table):
- """ get info about table's indexes """
+ """get info about table's indexes"""
sql = "PRAGMA index_list(%s)" % (self.quoteId(table))
indexes = self._fetchAll(sql)
if indexes is None:
@@ -398,10 +432,7 @@ def getTableIndexes(self, table):
sql = "PRAGMA index_info(%s)" % (self.quoteId(name))
idx = [num, name, unique]
- cols = [
- cid
- for seq, cid, cname in self._fetchAll(sql)
- ]
+ cols = [cid for seq, cid, cname in self._fetchAll(sql)]
idx.append(cols)
indexes[i] = idx
@@ -414,7 +445,10 @@ def getTableTriggers(self, table):
_, tablename = self.getSchemaTableName(table)
# Do not list rtree related triggers as we don't want them to be dropped
- sql = "SELECT name, sql FROM sqlite_master WHERE tbl_name = %s AND type = 'trigger'" % (self.quoteString(tablename))
+ sql = (
+ "SELECT name, sql FROM sqlite_master WHERE tbl_name = %s AND type = 'trigger'"
+ % (self.quoteString(tablename))
+ )
if self.isVectorTable(table):
sql += " AND name NOT LIKE 'rtree_%%'"
elif self.isRasterTable(table):
@@ -427,21 +461,23 @@ def getTableTriggers(self, table):
return self._fetchAll(sql)
def deleteTableTrigger(self, trigger, table=None):
- """Deletes trigger """
+ """Deletes trigger"""
sql = "DROP TRIGGER %s" % self.quoteId(trigger)
self._execute_and_commit(sql)
def getTableExtent(self, table, geom, force=False):
- """ find out table extent """
+ """find out table extent"""
_, tablename = self.getSchemaTableName(table)
if self.isRasterTable(table):
- md = self.gdal_ds.GetMetadata('SUBDATASETS')
+ md = self.gdal_ds.GetMetadata("SUBDATASETS")
if md is None or len(md) == 0:
ds = self.gdal_ds
else:
- subdataset_name = 'GPKG:%s:%s' % (self.gdal_ds.GetDescription(), tablename)
+ subdataset_name = "GPKG:{}:{}".format(
+ self.gdal_ds.GetDescription(), tablename
+ )
try:
ds = gdal.Open(subdataset_name)
except Exception:
@@ -466,14 +502,17 @@ def getTableExtent(self, table, geom, force=False):
return (minx, miny, maxx, maxy)
def getViewDefinition(self, view):
- """ returns definition of the view """
+ """returns definition of the view"""
return None
def getSpatialRefInfo(self, srid):
if srid in self.mapSridToName:
return self.mapSridToName[srid]
- sql = "SELECT srs_name FROM gpkg_spatial_ref_sys WHERE srs_id = %s" % self.quoteString(srid)
+ sql = (
+ "SELECT srs_name FROM gpkg_spatial_ref_sys WHERE srs_id = %s"
+ % self.quoteString(srid)
+ )
res = self._fetchOne(sql)
if res is not None and len(res) > 0:
res = res[0]
@@ -488,13 +527,18 @@ def isVectorTable(self, table):
def isRasterTable(self, table):
if self.has_raster and not self.isVectorTable(table):
_, tablename = self.getSchemaTableName(table)
- md = self.gdal_ds.GetMetadata('SUBDATASETS')
+ md = self.gdal_ds.GetMetadata("SUBDATASETS")
if md is None or len(md) == 0:
- sql = "SELECT COUNT(*) FROM gpkg_contents WHERE data_type = 'tiles' AND table_name = %s" % self.quoteString(tablename)
+ sql = (
+ "SELECT COUNT(*) FROM gpkg_contents WHERE data_type = 'tiles' AND table_name = %s"
+ % self.quoteString(tablename)
+ )
ret = self._fetchOne(sql)
return ret != [] and ret[0][0] == 1
else:
- subdataset_name = 'GPKG:%s:%s' % (self.gdal_ds.GetDescription(), tablename)
+ subdataset_name = "GPKG:{}:{}".format(
+ self.gdal_ds.GetDescription(), tablename
+ )
for key in md:
if md[key] == subdataset_name:
return True
@@ -505,37 +549,41 @@ def getOGRFieldTypeFromSQL(self, sql_type):
ogr_type = ogr.OFTString
ogr_subtype = ogr.OFSTNone
width = 0
- if not sql_type.startswith('TEXT ('):
- pos = sql_type.find(' (')
+ if not sql_type.startswith("TEXT ("):
+ pos = sql_type.find(" (")
if pos >= 0:
sql_type = sql_type[0:pos]
- if sql_type == 'BOOLEAN':
+ if sql_type == "BOOLEAN":
ogr_type = ogr.OFTInteger
ogr_subtype = ogr.OFSTBoolean
- elif sql_type in ('TINYINT', 'SMALLINT', 'MEDIUMINT'):
+ elif sql_type in ("TINYINT", "SMALLINT", "MEDIUMINT"):
ogr_type = ogr.OFTInteger
- elif sql_type == 'INTEGER':
+ elif sql_type == "INTEGER":
ogr_type = ogr.OFTInteger64
- elif sql_type == 'FLOAT':
+ elif sql_type == "FLOAT":
ogr_type = ogr.OFTReal
ogr_subtype = ogr.OFSTFloat32
- elif sql_type == 'DOUBLE':
+ elif sql_type == "DOUBLE":
ogr_type = ogr.OFTReal
- elif sql_type == 'DATE':
+ elif sql_type == "DATE":
ogr_type = ogr.OFTDate
- elif sql_type == 'DATETIME':
+ elif sql_type == "DATETIME":
ogr_type = ogr.OFTDateTime
- elif sql_type.startswith('TEXT (') and sql_type.endswith(')'):
- width = int(sql_type[len('TEXT ('):-1])
+ elif sql_type.startswith("TEXT (") and sql_type.endswith(")"):
+ width = int(sql_type[len("TEXT (") : -1])
return (ogr_type, ogr_subtype, width)
def createOGRFieldDefnFromSQL(self, sql_fielddef):
- f_split = sql_fielddef.split(' ')
+ f_split = sql_fielddef.split(" ")
quoted_name = f_split[0]
name = self.unquoteId(quoted_name)
sql_type = f_split[1].upper()
- if len(f_split) >= 3 and f_split[2].startswith('(') and f_split[2].endswith(')'):
- sql_type += ' ' + f_split[2]
+ if (
+ len(f_split) >= 3
+ and f_split[2].startswith("(")
+ and f_split[2].endswith(")")
+ ):
+ sql_type += " " + f_split[2]
f_split = [f for f in f_split[3:]]
else:
f_split = [f for f in f_split[2:]]
@@ -543,16 +591,16 @@ def createOGRFieldDefnFromSQL(self, sql_fielddef):
fld_defn = ogr.FieldDefn(name, ogr_type)
fld_defn.SetSubType(ogr_subtype)
fld_defn.SetWidth(width)
- if len(f_split) >= 2 and f_split[0] == 'NOT' and f_split[1] == 'NULL':
+ if len(f_split) >= 2 and f_split[0] == "NOT" and f_split[1] == "NULL":
fld_defn.SetNullable(False)
f_split = [f for f in f_split[2:]]
elif len(f_split) >= 1:
f_split = [f for f in f_split[1:]]
- if len(f_split) >= 2 and f_split[0] == 'DEFAULT':
+ if len(f_split) >= 2 and f_split[0] == "DEFAULT":
new_default = f_split[1]
- if new_default == '':
+ if new_default == "":
fld_defn.SetDefault(None)
- elif new_default == 'NULL' or ogr_type in (ogr.OFTInteger, ogr.OFTReal):
+ elif new_default == "NULL" or ogr_type in (ogr.OFTInteger, ogr.OFTReal):
fld_defn.SetDefault(new_default)
elif new_default.startswith("'") and new_default.endswith("'"):
fld_defn.SetDefault(new_default)
@@ -562,17 +610,19 @@ def createOGRFieldDefnFromSQL(self, sql_fielddef):
def createTable(self, table, field_defs, pkey):
"""Creates ordinary table
- 'fields' is array containing field definitions
- 'pkey' is the primary key name
+ 'fields' is array containing field definitions
+ 'pkey' is the primary key name
"""
if len(field_defs) == 0:
return False
options = []
if pkey is not None and pkey != "":
- options += ['FID=' + pkey]
+ options += ["FID=" + pkey]
_, tablename = self.getSchemaTableName(table)
- lyr = self.gdal_ds.CreateLayer(tablename, geom_type=ogr.wkbNone, options=options)
+ lyr = self.gdal_ds.CreateLayer(
+ tablename, geom_type=ogr.wkbNone, options=options
+ )
if lyr is None:
return False
for field_def in field_defs:
@@ -585,9 +635,9 @@ def createTable(self, table, field_defs, pkey):
return True
def deleteTable(self, table):
- """Deletes table from the database """
+ """Deletes table from the database"""
if self.isRasterTable(table):
- sql = "DROP TABLE {}".format(self.quoteId(table))
+ sql = f"DROP TABLE {self.quoteId(table)}"
self._execute_and_commit(sql)
return True
@@ -598,7 +648,7 @@ def deleteTable(self, table):
return False
def emptyTable(self, table):
- """Deletes all rows from table """
+ """Deletes all rows from table"""
if self.isRasterTable(table):
return False
@@ -617,11 +667,16 @@ def renameTable(self, table, new_table):
"""
try:
name = table[1] # 0 is schema
- vector_table_names = [t.tableName() for t in self.core_connection.tables('', QgsAbstractDatabaseProviderConnection.TableFlag.Vector)]
+ vector_table_names = [
+ t.tableName()
+ for t in self.core_connection.tables(
+ "", QgsAbstractDatabaseProviderConnection.TableFlag.Vector
+ )
+ ]
if name in vector_table_names:
- self.core_connection.renameVectorTable('', name, new_table)
+ self.core_connection.renameVectorTable("", name, new_table)
else:
- self.core_connection.renameRasterTable('', name, new_table)
+ self.core_connection.renameRasterTable("", name, new_table)
return True
except QgsProviderConnectionException:
return False
@@ -630,11 +685,11 @@ def moveTable(self, table, new_table, new_schema=None):
return self.renameTable(table, new_table)
def runVacuum(self):
- """ run vacuum on the db """
+ """run vacuum on the db"""
self._execute_and_commit("VACUUM")
def addTableColumn(self, table, field_def):
- """Adds a column to table """
+ """Adds a column to table"""
_, tablename = self.getSchemaTableName(table)
lyr = self.gdal_ds.GetLayerByName(tablename)
@@ -644,7 +699,7 @@ def addTableColumn(self, table, field_def):
return lyr.CreateField(fld_defn) == 0
def deleteTableColumn(self, table, column):
- """Deletes column from a table """
+ """Deletes column from a table"""
if self.isGeometryColumn(table, column):
return False
@@ -657,7 +712,16 @@ def deleteTableColumn(self, table, column):
return lyr.DeleteField(idx) == 0
return False
- def updateTableColumn(self, table, column, new_name, new_data_type=None, new_not_null=None, new_default=None, comment=None):
+ def updateTableColumn(
+ self,
+ table,
+ column,
+ new_name,
+ new_data_type=None,
+ new_not_null=None,
+ new_default=None,
+ comment=None,
+ ):
if self.isGeometryColumn(table, column):
return False
@@ -682,15 +746,17 @@ def updateTableColumn(self, table, column, new_name, new_data_type=None, new_not
else:
flag |= ogr.ALTER_TYPE_FLAG
flag |= ogr.ALTER_WIDTH_PRECISION_FLAG
- ogr_type, ogr_subtype, width = self.getOGRFieldTypeFromSQL(new_data_type)
+ ogr_type, ogr_subtype, width = self.getOGRFieldTypeFromSQL(
+ new_data_type
+ )
new_fielddefn = ogr.FieldDefn(new_name, ogr_type)
new_fielddefn.SetSubType(ogr_subtype)
new_fielddefn.SetWidth(width)
if new_default is not None:
flag |= ogr.ALTER_DEFAULT_FLAG
- if new_default == '':
+ if new_default == "":
new_fielddefn.SetDefault(None)
- elif new_default == 'NULL' or ogr_type in (ogr.OFTInteger, ogr.OFTReal):
+ elif new_default == "NULL" or ogr_type in (ogr.OFTInteger, ogr.OFTReal):
new_fielddefn.SetDefault(str(new_default))
elif new_default.startswith("'") and new_default.endswith("'"):
new_fielddefn.SetDefault(str(new_default))
@@ -715,36 +781,38 @@ def isGeometryColumn(self, table, column):
return False
return column == lyr.GetGeometryColumn()
- def addGeometryColumn(self, table, geom_column='geometry', geom_type='POINT', srid=-1, dim=2):
+ def addGeometryColumn(
+ self, table, geom_column="geometry", geom_type="POINT", srid=-1, dim=2
+ ):
_, tablename = self.getSchemaTableName(table)
lyr = self.gdal_ds.GetLayerByName(tablename)
if lyr is None:
return False
ogr_type = ogr.wkbUnknown
- if geom_type == 'POINT':
+ if geom_type == "POINT":
ogr_type = ogr.wkbPoint
- elif geom_type == 'LINESTRING':
+ elif geom_type == "LINESTRING":
ogr_type = ogr.wkbLineString
- elif geom_type == 'POLYGON':
+ elif geom_type == "POLYGON":
ogr_type = ogr.wkbPolygon
- elif geom_type == 'MULTIPOINT':
+ elif geom_type == "MULTIPOINT":
ogr_type = ogr.wkbMultiPoint
- elif geom_type == 'MULTILINESTRING':
+ elif geom_type == "MULTILINESTRING":
ogr_type = ogr.wkbMultiLineString
- elif geom_type == 'MULTIPOLYGON':
+ elif geom_type == "MULTIPOLYGON":
ogr_type = ogr.wkbMultiPolygon
- elif geom_type == 'GEOMETRYCOLLECTION':
+ elif geom_type == "GEOMETRYCOLLECTION":
ogr_type = ogr.wkbGeometryCollection
if dim == 3:
ogr_type = ogr_type | ogr.wkb25DBit
elif dim == 4:
- if hasattr(ogr, 'GT_HasZ'):
+ if hasattr(ogr, "GT_HasZ"):
ogr_type = ogr.GT_SetZ(ogr_type)
else:
ogr_type = ogr_type | ogr.wkb25DBit
- if hasattr(ogr, 'GT_HasM'):
+ if hasattr(ogr, "GT_HasM"):
ogr_type = ogr.GT_SetM(ogr_type)
geom_field_defn = ogr.GeomFieldDefn(self.unquoteId(geom_column), ogr_type)
@@ -762,23 +830,26 @@ def deleteGeometryColumn(self, table, geom_column):
return False # not supported
def addTableUniqueConstraint(self, table, column):
- """Adds a unique constraint to a table """
+ """Adds a unique constraint to a table"""
return False # constraints not supported
def deleteTableConstraint(self, table, constraint):
- """Deletes constraint in a table """
+ """Deletes constraint in a table"""
return False # constraints not supported
def addTablePrimaryKey(self, table, column):
- """Adds a primery key (with one column) to a table """
- sql = "ALTER TABLE %s ADD PRIMARY KEY (%s)" % (self.quoteId(table), self.quoteId(column))
+ """Adds a primery key (with one column) to a table"""
+ sql = "ALTER TABLE {} ADD PRIMARY KEY ({})".format(
+ self.quoteId(table), self.quoteId(column)
+ )
self._execute_and_commit(sql)
def createTableIndex(self, table, name, column, unique=False):
- """Creates index on one column using default options """
+ """Creates index on one column using default options"""
unique_str = "UNIQUE" if unique else ""
- sql = "CREATE %s INDEX %s ON %s (%s)" % (
- unique_str, self.quoteId(name), self.quoteId(table), self.quoteId(column))
+ sql = "CREATE {} INDEX {} ON {} ({})".format(
+ unique_str, self.quoteId(name), self.quoteId(table), self.quoteId(column)
+ )
self._execute_and_commit(sql)
def deleteTableIndex(self, table, name):
@@ -790,8 +861,9 @@ def createSpatialIndex(self, table, geom_column):
if self.isRasterTable(table):
return False
_, tablename = self.getSchemaTableName(table)
- sql = "SELECT CreateSpatialIndex(%s, %s)" % (
- self.quoteId(tablename), self.quoteId(geom_column))
+ sql = "SELECT CreateSpatialIndex({}, {})".format(
+ self.quoteId(tablename), self.quoteId(geom_column)
+ )
try:
res = self._fetchOne(sql)
except QgsProviderConnectionException:
@@ -802,8 +874,9 @@ def deleteSpatialIndex(self, table, geom_column):
if self.isRasterTable(table):
return False
_, tablename = self.getSchemaTableName(table)
- sql = "SELECT DisableSpatialIndex(%s, %s)" % (
- self.quoteId(tablename), self.quoteId(geom_column))
+ sql = "SELECT DisableSpatialIndex({}, {})".format(
+ self.quoteId(tablename), self.quoteId(geom_column)
+ )
res = self._fetchOne(sql)
return len(res) > 0 and len(res[0]) > 0 and res[0][0] == 1
@@ -813,14 +886,19 @@ def hasSpatialIndex(self, table, geom_column):
_, tablename = self.getSchemaTableName(table)
# (only available in >= 2.1.2)
- sql = "SELECT HasSpatialIndex(%s, %s)" % (self.quoteString(tablename), self.quoteString(geom_column))
+ sql = "SELECT HasSpatialIndex({}, {})".format(
+ self.quoteString(tablename), self.quoteString(geom_column)
+ )
gdal.PushErrorHandler()
ret = self._fetchOne(sql)
gdal.PopErrorHandler()
if len(ret) == 0:
# might be the case for GDAL < 2.1.2
- sql = "SELECT COUNT(*) FROM sqlite_master WHERE type = 'table' AND name LIKE %s" % self.quoteString("%%rtree_" + tablename + "_%%")
+ sql = (
+ "SELECT COUNT(*) FROM sqlite_master WHERE type = 'table' AND name LIKE %s"
+ % self.quoteString("%%rtree_" + tablename + "_%%")
+ )
ret = self._fetchOne(sql)
if len(ret) == 0:
return False
diff --git a/python/plugins/db_manager/db_plugins/gpkg/data_model.py b/python/plugins/db_manager/db_plugins/gpkg/data_model.py
index dd692703e927..a1a79a11ec1b 100644
--- a/python/plugins/db_manager/db_plugins/gpkg/data_model.py
+++ b/python/plugins/db_manager/db_plugins/gpkg/data_model.py
@@ -20,10 +20,12 @@
from qgis.core import QgsMessageLog
-from ..data_model import (TableDataModel,
- SqlResultModel,
- SqlResultModelAsync,
- SqlResultModelTask)
+from ..data_model import (
+ TableDataModel,
+ SqlResultModel,
+ SqlResultModelAsync,
+ SqlResultModelTask,
+)
from ..plugin import BaseError
diff --git a/python/plugins/db_manager/db_plugins/gpkg/info_model.py b/python/plugins/db_manager/db_plugins/gpkg/info_model.py
index cd346e5f8237..d0f2c31dca9b 100644
--- a/python/plugins/db_manager/db_plugins/gpkg/info_model.py
+++ b/python/plugins/db_manager/db_plugins/gpkg/info_model.py
@@ -31,7 +31,10 @@ def __init__(self, db):
def connectionDetails(self):
tbl = [
- (QApplication.translate("DBManagerPlugin", "Filename:"), self.db.connector.dbname)
+ (
+ QApplication.translate("DBManagerPlugin", "Filename:"),
+ self.db.connector.dbname,
+ )
]
return HtmlTable(tbl)
diff --git a/python/plugins/db_manager/db_plugins/gpkg/plugin.py b/python/plugins/db_manager/db_plugins/gpkg/plugin.py
index d6f63e8b3579..7fd5ee9ad904 100644
--- a/python/plugins/db_manager/db_plugins/gpkg/plugin.py
+++ b/python/plugins/db_manager/db_plugins/gpkg/plugin.py
@@ -33,8 +33,17 @@
)
from qgis.gui import QgsMessageBar
-from ..plugin import DBPlugin, Database, Table, VectorTable, RasterTable, TableField, TableIndex, TableTrigger, \
- InvalidDataException
+from ..plugin import (
+ DBPlugin,
+ Database,
+ Table,
+ VectorTable,
+ RasterTable,
+ TableField,
+ TableIndex,
+ TableTrigger,
+ InvalidDataException,
+)
def classFactory():
@@ -49,19 +58,19 @@ def icon(self):
@classmethod
def typeName(self):
- return 'gpkg'
+ return "gpkg"
@classmethod
def typeNameString(self):
- return QCoreApplication.translate('db_manager', 'GeoPackage')
+ return QCoreApplication.translate("db_manager", "GeoPackage")
@classmethod
def providerName(self):
- return 'ogr'
+ return "ogr"
@classmethod
def connectionSettingsKey(self):
- return 'providers/ogr/GPKG/connections'
+ return "providers/ogr/GPKG/connections"
def databasesFactory(self, connection, uri):
return GPKGDatabase(connection, uri)
@@ -73,7 +82,11 @@ def connect(self, parent=None):
conn = md.findConnection(conn_name)
if conn is None: # non-existent entry?
- raise InvalidDataException(self.tr('There is no defined database connection "{0}".').format(conn_name))
+ raise InvalidDataException(
+ self.tr('There is no defined database connection "{0}".').format(
+ conn_name
+ )
+ )
uri = QgsDataSourceUri()
uri.setDatabase(conn.uri())
@@ -90,8 +103,9 @@ def addConnection(self, conn_name, uri):
def addConnectionActionSlot(self, item, action, parent, index):
QApplication.restoreOverrideCursor()
try:
- filename, selected_filter = QFileDialog.getOpenFileName(parent,
- parent.tr("Choose GeoPackage file"), None, "GeoPackage (*.gpkg)")
+ filename, selected_filter = QFileDialog.getOpenFileName(
+ parent, parent.tr("Choose GeoPackage file"), None, "GeoPackage (*.gpkg)"
+ )
if not filename:
return
finally:
@@ -138,7 +152,9 @@ def sqlResultModelAsync(self, sql, parent):
def registerDatabaseActions(self, mainWindow):
action = QAction(self.tr("Run &Vacuum"), self)
- mainWindow.registerAction(action, self.tr("&Database"), self.runVacuumActionSlot)
+ mainWindow.registerAction(
+ action, self.tr("&Database"), self.runVacuumActionSlot
+ )
Database.registerDatabaseActions(self, mainWindow)
@@ -146,8 +162,11 @@ def runVacuumActionSlot(self, item, action, parent):
QApplication.restoreOverrideCursor()
try:
if not isinstance(item, (DBPlugin, Table)) or item.database() is None:
- parent.infoBar.pushMessage(self.tr("No database selected or you are not connected to it."),
- Qgis.MessageLevel.Info, parent.iface.messageTimeout())
+ parent.infoBar.pushMessage(
+ self.tr("No database selected or you are not connected to it."),
+ Qgis.MessageLevel.Info,
+ parent.iface.messageTimeout(),
+ )
return
finally:
QApplication.setOverrideCursor(Qt.CursorShape.WaitCursor)
@@ -172,10 +191,19 @@ def runAction(self, action):
def uniqueIdFunction(self):
return None
- def toSqlLayer(self, sql, geomCol, uniqueCol, layerName="QueryLayer", layerType=None, avoidSelectById=False, filter=""):
+ def toSqlLayer(
+ self,
+ sql,
+ geomCol,
+ uniqueCol,
+ layerName="QueryLayer",
+ layerType=None,
+ avoidSelectById=False,
+ filter="",
+ ):
from qgis.core import QgsVectorLayer
- vl = QgsVectorLayer(self.uri().database() + '|subset=' + sql, layerName, 'ogr')
+ vl = QgsVectorLayer(self.uri().database() + "|subset=" + sql, layerName, "ogr")
return vl
def supportsComment(self):
@@ -199,12 +227,12 @@ def __init__(self, row, db, schema=None):
self.name, self.isView, self.isSysTable = row
def ogrUri(self):
- ogrUri = "%s|layername=%s" % (self.uri().database(), self.name)
+ ogrUri = f"{self.uri().database()}|layername={self.name}"
return ogrUri
def mimeUri(self):
# QGIS has no provider to load Geopackage vectors, let's use OGR
- return "vector:ogr:%s:%s" % (self.name, self.ogrUri())
+ return f"vector:ogr:{self.name}:{self.ogrUri()}"
def toMapLayer(self, geometryType=None, crs=None):
from qgis.core import QgsVectorLayer
@@ -214,12 +242,12 @@ def toMapLayer(self, geometryType=None, crs=None):
if geometryType:
geom_mapping = {
- 'POINT': 'Point',
- 'LINESTRING': 'LineString',
- 'POLYGON': 'Polygon',
+ "POINT": "Point",
+ "LINESTRING": "LineString",
+ "POLYGON": "Polygon",
}
geometryType = geom_mapping[geometryType]
- uri = "{}|geometrytype={}".format(uri, geometryType)
+ uri = f"{uri}|geometrytype={geometryType}"
return QgsVectorLayer(uri, self.name, provider)
@@ -246,17 +274,23 @@ def __init__(self, row, db, schema=None):
# GPKG does case-insensitive checks for table names, but the
# GPKG provider didn't do the same in QGIS < 1.9, so self.geomTableName
# stores the table name like stored in the geometry_columns table
- self.geomTableName, self.geomColumn, self.geomType, self.geomDim, self.srid = row[-5:]
- self.extent = self.database().connector.getTableExtent((self.schemaName(), self.name), self.geomColumn, force=False)
+ self.geomTableName, self.geomColumn, self.geomType, self.geomDim, self.srid = (
+ row[-5:]
+ )
+ self.extent = self.database().connector.getTableExtent(
+ (self.schemaName(), self.name), self.geomColumn, force=False
+ )
def uri(self):
uri = self.database().uri()
- uri.setDataSource('', self.geomTableName, self.geomColumn)
+ uri.setDataSource("", self.geomTableName, self.geomColumn)
return uri
def hasSpatialIndex(self, geom_column=None):
geom_column = geom_column if geom_column is not None else self.geomColumn
- return self.database().connector.hasSpatialIndex((self.schemaName(), self.name), geom_column)
+ return self.database().connector.hasSpatialIndex(
+ (self.schemaName(), self.name), geom_column
+ )
def createSpatialIndex(self, geom_column=None):
self.aboutToChange.emit()
@@ -277,7 +311,9 @@ def refreshTableEstimatedExtent(self):
def refreshTableExtent(self):
prevExtent = self.extent
- self.extent = self.database().connector.getTableExtent((self.schemaName(), self.name), self.geomColumn, force=True)
+ self.extent = self.database().connector.getTableExtent(
+ (self.schemaName(), self.name), self.geomColumn, force=True
+ )
if self.extent != prevExtent:
self.refresh()
@@ -293,16 +329,18 @@ def __init__(self, row, db, schema=None):
GPKGTable.__init__(self, row[:-3], db, schema)
RasterTable.__init__(self, db, schema)
self.prefixName, self.geomColumn, self.srid = row[-3:]
- self.geomType = 'RASTER'
- self.extent = self.database().connector.getTableExtent((self.schemaName(), self.name), self.geomColumn)
+ self.geomType = "RASTER"
+ self.extent = self.database().connector.getTableExtent(
+ (self.schemaName(), self.name), self.geomColumn
+ )
def gpkgGdalUri(self):
- gdalUri = 'GPKG:%s:%s' % (self.uri().database(), self.prefixName)
+ gdalUri = f"GPKG:{self.uri().database()}:{self.prefixName}"
return gdalUri
def mimeUri(self):
# QGIS has no provider to load rasters, let's use GDAL
- uri = "raster:gdal:%s:%s" % (self.name, self.uri().database())
+ uri = f"raster:gdal:{self.name}:{self.uri().database()}"
return uri
def toMapLayer(self, geometryType=None, crs=None):
@@ -312,7 +350,9 @@ def toMapLayer(self, geometryType=None, crs=None):
uri = self.gpkgGdalUri()
rl = QgsRasterLayer(uri, self.name)
if rl.isValid():
- rl.setContrastEnhancement(QgsContrastEnhancement.ContrastEnhancementAlgorithm.StretchToMinimumMaximum)
+ rl.setContrastEnhancement(
+ QgsContrastEnhancement.ContrastEnhancementAlgorithm.StretchToMinimumMaximum
+ )
return rl
@@ -320,7 +360,14 @@ class GPKGTableField(TableField):
def __init__(self, row, table):
TableField.__init__(self, table)
- self.num, self.name, self.dataType, self.notNull, self.default, self.primaryKey = row
+ (
+ self.num,
+ self.name,
+ self.dataType,
+ self.notNull,
+ self.default,
+ self.primaryKey,
+ ) = row
self.hasDefault = self.default
diff --git a/python/plugins/db_manager/db_plugins/gpkg/sql_dictionary.py b/python/plugins/db_manager/db_plugins/gpkg/sql_dictionary.py
index 514c804bb494..439a4645f1ed 100644
--- a/python/plugins/db_manager/db_plugins/gpkg/sql_dictionary.py
+++ b/python/plugins/db_manager/db_plugins/gpkg/sql_dictionary.py
@@ -18,9 +18,11 @@
def getSqlDictionary(spatial=True):
from ..spatialite.sql_dictionary import getSqlDictionary
+
return getSqlDictionary(spatial)
def getQueryBuilderDictionary():
from ..spatialite.sql_dictionary import getQueryBuilderDictionary
+
return getQueryBuilderDictionary()
diff --git a/python/plugins/db_manager/db_plugins/html_elems.py b/python/plugins/db_manager/db_plugins/html_elems.py
index 96b47f4c301e..69ab9fc6c91b 100644
--- a/python/plugins/db_manager/db_plugins/html_elems.py
+++ b/python/plugins/db_manager/db_plugins/html_elems.py
@@ -26,12 +26,12 @@ def __init__(self, data):
def toHtml(self):
if isinstance(self.data, list) or isinstance(self.data, tuple):
- html = ''
+ html = ""
for item in self.data:
html += HtmlContent(item).toHtml()
return html
- if hasattr(self.data, 'toHtml'):
+ if hasattr(self.data, "toHtml"):
return self.data.toHtml()
html = str(self.data).replace("\n", " ")
@@ -46,7 +46,7 @@ def hasContents(self):
break
return not empty
- if hasattr(self.data, 'hasContents'):
+ if hasattr(self.data, "hasContents"):
return self.data.hasContents()
return len(self.data) > 0
@@ -58,9 +58,9 @@ def __init__(self, tag, data, attrs=None):
self.tag = tag
self.data = data if isinstance(data, HtmlContent) else HtmlContent(data)
self.attrs = attrs if attrs is not None else dict()
- if 'tag' in self.attrs:
- self.setTag(self.attrs['tag'])
- del self.attrs['tag']
+ if "tag" in self.attrs:
+ self.setTag(self.attrs["tag"])
+ del self.attrs["tag"]
def setTag(self, tag):
self.tag = tag
@@ -72,19 +72,21 @@ def setAttr(self, name, value):
self.attrs[name] = value
def getAttrsHtml(self):
- html = ''
+ html = ""
for k, v in self.attrs.items():
- html += ' %s="%s"' % (k, v)
+ html += f' {k}="{v}"'
return html
def openTagHtml(self):
- return "<%s%s>" % (self.tag, self.getAttrsHtml())
+ return f"<{self.tag}{self.getAttrsHtml()}>"
def closeTagHtml(self):
return "%s>" % self.tag
def toHtml(self):
- return "%s%s%s" % (self.openTagHtml(), self.data.toHtml(), self.closeTagHtml())
+ return "{}{}{}".format(
+ self.openTagHtml(), self.data.toHtml(), self.closeTagHtml()
+ )
def hasContents(self):
return self.data.toHtml() != ""
@@ -93,13 +95,13 @@ def hasContents(self):
class HtmlParagraph(HtmlElem):
def __init__(self, data, attrs=None):
- HtmlElem.__init__(self, 'p', data, attrs)
+ HtmlElem.__init__(self, "p", data, attrs)
class HtmlListItem(HtmlElem):
def __init__(self, data, attrs=None):
- HtmlElem.__init__(self, 'li', data, attrs)
+ HtmlElem.__init__(self, "li", data, attrs)
class HtmlList(HtmlElem):
@@ -110,13 +112,13 @@ def __init__(self, items, attrs=None):
for i, item in enumerate(items):
if not isinstance(item, HtmlListItem):
items[i] = HtmlListItem(item)
- HtmlElem.__init__(self, 'ul', items, attrs)
+ HtmlElem.__init__(self, "ul", items, attrs)
class HtmlTableCol(HtmlElem):
def __init__(self, data, attrs=None):
- HtmlElem.__init__(self, 'td', data, attrs)
+ HtmlElem.__init__(self, "td", data, attrs)
def closeTagHtml(self):
# FIX INVALID BEHAVIOR: an empty cell as last table's cell break margins
@@ -131,7 +133,7 @@ def __init__(self, cols, attrs=None):
for i, c in enumerate(cols):
if not isinstance(c, HtmlTableCol):
cols[i] = HtmlTableCol(c)
- HtmlElem.__init__(self, 'tr', cols, attrs)
+ HtmlElem.__init__(self, "tr", cols, attrs)
class HtmlTableHeader(HtmlTableRow):
@@ -139,7 +141,7 @@ class HtmlTableHeader(HtmlTableRow):
def __init__(self, cols, attrs=None):
HtmlTableRow.__init__(self, cols, attrs)
for c in self.getOriginalData():
- c.setTag('th')
+ c.setTag("th")
class HtmlTable(HtmlElem):
@@ -150,14 +152,14 @@ def __init__(self, rows, attrs=None):
for i, r in enumerate(rows):
if not isinstance(r, HtmlTableRow):
rows[i] = HtmlTableRow(r)
- HtmlElem.__init__(self, 'table', rows, attrs)
+ HtmlElem.__init__(self, "table", rows, attrs)
class HtmlSection(HtmlContent):
def __init__(self, title, content=None):
- data = ['', title, ' ']
+ data = ['
', title, " "]
if content is not None:
- data.extend(['
', content, '
'])
- data.append('
')
+ data.extend(["
", content, "
"])
+ data.append("
")
HtmlContent.__init__(self, data)
diff --git a/python/plugins/db_manager/db_plugins/info_model.py b/python/plugins/db_manager/db_plugins/info_model.py
index c27d77b521b3..cf3af0c1753a 100644
--- a/python/plugins/db_manager/db_plugins/info_model.py
+++ b/python/plugins/db_manager/db_plugins/info_model.py
@@ -20,7 +20,15 @@
from qgis.PyQt.QtWidgets import QApplication
-from .html_elems import HtmlContent, HtmlSection, HtmlParagraph, HtmlList, HtmlTable, HtmlTableHeader, HtmlTableCol
+from .html_elems import (
+ HtmlContent,
+ HtmlSection,
+ HtmlParagraph,
+ HtmlList,
+ HtmlTable,
+ HtmlTableHeader,
+ HtmlTableCol,
+)
class DatabaseInfo:
@@ -33,15 +41,19 @@ def __del__(self):
def generalInfo(self):
info = self.db.connector.getInfo()
- tbl = [
- (QApplication.translate("DBManagerPlugin", "Server version: "), info[0])
- ]
+ tbl = [(QApplication.translate("DBManagerPlugin", "Server version: "), info[0])]
return HtmlTable(tbl)
def connectionDetails(self):
tbl = [
- (QApplication.translate("DBManagerPlugin", "Host:"), self.db.connector.host),
- (QApplication.translate("DBManagerPlugin", "User:"), self.db.connector.user)
+ (
+ QApplication.translate("DBManagerPlugin", "Host:"),
+ self.db.connector.host,
+ ),
+ (
+ QApplication.translate("DBManagerPlugin", "User:"),
+ self.db.connector.user,
+ ),
]
return HtmlTable(tbl)
@@ -55,14 +67,20 @@ def spatialInfo(self):
tbl = [
(QApplication.translate("DBManagerPlugin", "Library:"), info[0]),
("GEOS:", info[1]),
- ("Proj:", info[2])
+ ("Proj:", info[2]),
]
ret.append(HtmlTable(tbl))
if not self.db.connector.has_geometry_columns:
- ret.append(HtmlParagraph(
- QApplication.translate("DBManagerPlugin", " geometry_columns table doesn't exist!\n"
- "This table is essential for many GIS applications for enumeration of tables.")))
+ ret.append(
+ HtmlParagraph(
+ QApplication.translate(
+ "DBManagerPlugin",
+ " geometry_columns table doesn't exist!\n"
+ "This table is essential for many GIS applications for enumeration of tables.",
+ )
+ )
+ )
return ret
@@ -72,12 +90,16 @@ def privilegesDetails(self):
if details[0]:
lst.append(QApplication.translate("DBManagerPlugin", "create new schemas"))
if details[1]:
- lst.append(QApplication.translate("DBManagerPlugin", "create temporary tables"))
+ lst.append(
+ QApplication.translate("DBManagerPlugin", "create temporary tables")
+ )
return HtmlList(lst)
def toHtml(self):
if self.db is None:
- return HtmlSection(QApplication.translate("DBManagerPlugin", ' Not connected')).toHtml()
+ return HtmlSection(
+ QApplication.translate("DBManagerPlugin", " Not connected")
+ ).toHtml()
ret = []
@@ -86,14 +108,24 @@ def toHtml(self):
if conn_details is None:
pass
else:
- ret.append(HtmlSection(QApplication.translate("DBManagerPlugin", 'Connection details'), conn_details))
+ ret.append(
+ HtmlSection(
+ QApplication.translate("DBManagerPlugin", "Connection details"),
+ conn_details,
+ )
+ )
# database information
general_info = self.generalInfo()
if general_info is None:
pass
else:
- ret.append(HtmlSection(QApplication.translate("DBManagerPlugin", 'General info'), general_info))
+ ret.append(
+ HtmlSection(
+ QApplication.translate("DBManagerPlugin", "General info"),
+ general_info,
+ )
+ )
# has spatial enabled?
spatial_info = self.spatialInfo()
@@ -103,7 +135,9 @@ def toHtml(self):
typename = self.db.connection().typeNameString()
spatial_info = HtmlContent(spatial_info)
if not spatial_info.hasContents():
- spatial_info = QApplication.translate("DBManagerPlugin", ' {0} support not enabled!').format(typename)
+ spatial_info = QApplication.translate(
+ "DBManagerPlugin", " {0} support not enabled!"
+ ).format(typename)
ret.append(HtmlSection(typename, spatial_info))
# privileges
@@ -113,10 +147,20 @@ def toHtml(self):
else:
priv_details = HtmlContent(priv_details)
if not priv_details.hasContents():
- priv_details = QApplication.translate("DBManagerPlugin", ' This user has no privileges!')
+ priv_details = QApplication.translate(
+ "DBManagerPlugin", " This user has no privileges!"
+ )
else:
- priv_details = [QApplication.translate("DBManagerPlugin", "User has privileges:"), priv_details]
- ret.append(HtmlSection(QApplication.translate("DBManagerPlugin", 'Privileges'), priv_details))
+ priv_details = [
+ QApplication.translate("DBManagerPlugin", "User has privileges:"),
+ priv_details,
+ ]
+ ret.append(
+ HtmlSection(
+ QApplication.translate("DBManagerPlugin", "Privileges"),
+ priv_details,
+ )
+ )
return HtmlContent(ret).toHtml()
@@ -134,9 +178,16 @@ def generalInfo(self):
# ("Tables:", self.schema.tableCount)
]
if self.schema.owner:
- tbl.append((QApplication.translate("DBManagerPlugin", "Owner:"), self.schema.owner))
+ tbl.append(
+ (QApplication.translate("DBManagerPlugin", "Owner:"), self.schema.owner)
+ )
if self.schema.comment:
- tbl.append((QApplication.translate("DBManagerPlugin", "Comment:"), self.schema.comment))
+ tbl.append(
+ (
+ QApplication.translate("DBManagerPlugin", "Comment:"),
+ self.schema.comment,
+ )
+ )
return HtmlTable(tbl)
def privilegesDetails(self):
@@ -155,7 +206,12 @@ def toHtml(self):
if general_info is None:
pass
else:
- ret.append(HtmlSection(QApplication.translate("DBManagerPlugin", 'Schema details'), general_info))
+ ret.append(
+ HtmlSection(
+ QApplication.translate("DBManagerPlugin", "Schema details"),
+ general_info,
+ )
+ )
priv_details = self.privilegesDetails()
if priv_details is None:
@@ -163,11 +219,21 @@ def toHtml(self):
else:
priv_details = HtmlContent(priv_details)
if not priv_details.hasContents():
- priv_details = QApplication.translate("DBManagerPlugin",
- ' This user has no privileges to access this schema!')
+ priv_details = QApplication.translate(
+ "DBManagerPlugin",
+ " This user has no privileges to access this schema!",
+ )
else:
- priv_details = [QApplication.translate("DBManagerPlugin", "User has privileges:"), priv_details]
- ret.append(HtmlSection(QApplication.translate("DBManagerPlugin", 'Privileges'), priv_details))
+ priv_details = [
+ QApplication.translate("DBManagerPlugin", "User has privileges:"),
+ priv_details,
+ ]
+ ret.append(
+ HtmlSection(
+ QApplication.translate("DBManagerPlugin", "Privileges"),
+ priv_details,
+ )
+ )
return HtmlContent(ret).toHtml()
@@ -189,15 +255,33 @@ def generalInfo(self):
self.table.blockSignals(False)
tbl = [
- (QApplication.translate("DBManagerPlugin", "Relation type:"),
- QApplication.translate("DBManagerPlugin", "View") if self.table.isView else QApplication.translate(
- "DBManagerPlugin", "Table")),
- (QApplication.translate("DBManagerPlugin", "Rows:"),
- self.table.rowCount if self.table.rowCount is not None else QApplication.translate("DBManagerPlugin",
- 'Unknown (find out )'))
+ (
+ QApplication.translate("DBManagerPlugin", "Relation type:"),
+ (
+ QApplication.translate("DBManagerPlugin", "View")
+ if self.table.isView
+ else QApplication.translate("DBManagerPlugin", "Table")
+ ),
+ ),
+ (
+ QApplication.translate("DBManagerPlugin", "Rows:"),
+ (
+ self.table.rowCount
+ if self.table.rowCount is not None
+ else QApplication.translate(
+ "DBManagerPlugin",
+ 'Unknown (find out )',
+ )
+ ),
+ ),
]
if self.table.comment:
- tbl.append((QApplication.translate("DBManagerPlugin", "Comment:"), self.table.comment))
+ tbl.append(
+ (
+ QApplication.translate("DBManagerPlugin", "Comment:"),
+ self.table.comment,
+ )
+ )
return HtmlTable(tbl)
@@ -209,8 +293,12 @@ def fieldsDetails(self):
# define the table header
header = (
- "#", QApplication.translate("DBManagerPlugin", "Name"), QApplication.translate("DBManagerPlugin", "Type"),
- QApplication.translate("DBManagerPlugin", "Null"), QApplication.translate("DBManagerPlugin", "Default"))
+ "#",
+ QApplication.translate("DBManagerPlugin", "Name"),
+ QApplication.translate("DBManagerPlugin", "Type"),
+ QApplication.translate("DBManagerPlugin", "Null"),
+ QApplication.translate("DBManagerPlugin", "Default"),
+ )
tbl.append(HtmlTableHeader(header))
# add table contents
@@ -221,7 +309,9 @@ def fieldsDetails(self):
attrs = {"class": "underline"} if fld.primaryKey else None
name = HtmlTableCol(fld.name, attrs)
- tbl.append((fld.num, name, fld.type2String(), is_null_txt, fld.default2String()))
+ tbl.append(
+ (fld.num, name, fld.type2String(), is_null_txt, fld.default2String())
+ )
return HtmlTable(tbl, {"class": "header"})
@@ -232,15 +322,21 @@ def constraintsDetails(self):
tbl = []
# define the table header
- header = (QApplication.translate("DBManagerPlugin", "Name"), QApplication.translate("DBManagerPlugin", "Type"),
- QApplication.translate("DBManagerPlugin", "Column(s)"))
+ header = (
+ QApplication.translate("DBManagerPlugin", "Name"),
+ QApplication.translate("DBManagerPlugin", "Type"),
+ QApplication.translate("DBManagerPlugin", "Column(s)"),
+ )
tbl.append(HtmlTableHeader(header))
# add table contents
for con in self.table.constraints():
# get the fields the constraint is defined on
- cols = [p[1].name if p[1] is not None else "??? (#%d)" % p[0] for p in iter(list(con.fields().items()))]
- tbl.append((con.name, con.type2String(), '\n'.join(cols)))
+ cols = [
+ p[1].name if p[1] is not None else "??? (#%d)" % p[0]
+ for p in iter(list(con.fields().items()))
+ ]
+ tbl.append((con.name, con.type2String(), "\n".join(cols)))
return HtmlTable(tbl, {"class": "header"})
@@ -252,14 +348,19 @@ def indexesDetails(self):
# define the table header
header = (
- QApplication.translate("DBManagerPlugin", "Name"), QApplication.translate("DBManagerPlugin", "Column(s)"))
+ QApplication.translate("DBManagerPlugin", "Name"),
+ QApplication.translate("DBManagerPlugin", "Column(s)"),
+ )
tbl.append(HtmlTableHeader(header))
# add table contents
for idx in self.table.indexes():
# get the fields the index is defined on
- cols = [p[1].name if p[1] is not None else "??? (#%d)" % p[0] for p in iter(list(idx.fields().items()))]
- tbl.append((idx.name, '\n'.join(cols)))
+ cols = [
+ p[1].name if p[1] is not None else "??? (#%d)" % p[0]
+ for p in iter(list(idx.fields().items()))
+ ]
+ tbl.append((idx.name, "\n".join(cols)))
return HtmlTable(tbl, {"class": "header"})
@@ -271,21 +372,28 @@ def triggersDetails(self):
# define the table header
header = (
- QApplication.translate("DBManagerPlugin", "Name"), QApplication.translate("DBManagerPlugin", "Function"))
+ QApplication.translate("DBManagerPlugin", "Name"),
+ QApplication.translate("DBManagerPlugin", "Function"),
+ )
tbl.append(HtmlTableHeader(header))
# add table contents
for trig in self.table.triggers():
- name = '%(name)s (%(action)s )' % {"name": trig.name,
- "action": "delete"}
- tbl.append((name, trig.function.replace('<', '<')))
+ name = (
+ '{name} ({action} )'.format(
+ name=trig.name, action="delete"
+ )
+ )
+ tbl.append((name, trig.function.replace("<", "<")))
return HtmlTable(tbl, {"class": "header"})
def getViewDefinition(self):
if not self.table.isView:
return None
- return self.table.database().connector.getViewDefinition((self.table.schemaName(), self.table.name))
+ return self.table.database().connector.getViewDefinition(
+ (self.table.schemaName(), self.table.name)
+ )
def getTableInfo(self):
ret = []
@@ -294,7 +402,12 @@ def getTableInfo(self):
if general_info is None:
pass
else:
- ret.append(HtmlSection(QApplication.translate("DBManagerPlugin", 'General info'), general_info))
+ ret.append(
+ HtmlSection(
+ QApplication.translate("DBManagerPlugin", "General info"),
+ general_info,
+ )
+ )
# spatial info
spatial_info = self.spatialInfo()
@@ -303,36 +416,61 @@ def getTableInfo(self):
else:
spatial_info = HtmlContent(spatial_info)
if not spatial_info.hasContents():
- spatial_info = QApplication.translate("DBManagerPlugin", ' This is not a spatial table.')
- ret.append(HtmlSection(self.table.database().connection().typeNameString(), spatial_info))
+ spatial_info = QApplication.translate(
+ "DBManagerPlugin", " This is not a spatial table."
+ )
+ ret.append(
+ HtmlSection(
+ self.table.database().connection().typeNameString(), spatial_info
+ )
+ )
# fields
fields_details = self.fieldsDetails()
if fields_details is None:
pass
else:
- ret.append(HtmlSection(QApplication.translate("DBManagerPlugin", 'Fields'), fields_details))
+ ret.append(
+ HtmlSection(
+ QApplication.translate("DBManagerPlugin", "Fields"), fields_details
+ )
+ )
# constraints
constraints_details = self.constraintsDetails()
if constraints_details is None:
pass
else:
- ret.append(HtmlSection(QApplication.translate("DBManagerPlugin", 'Constraints'), constraints_details))
+ ret.append(
+ HtmlSection(
+ QApplication.translate("DBManagerPlugin", "Constraints"),
+ constraints_details,
+ )
+ )
# indexes
indexes_details = self.indexesDetails()
if indexes_details is None:
pass
else:
- ret.append(HtmlSection(QApplication.translate("DBManagerPlugin", 'Indexes'), indexes_details))
+ ret.append(
+ HtmlSection(
+ QApplication.translate("DBManagerPlugin", "Indexes"),
+ indexes_details,
+ )
+ )
# triggers
triggers_details = self.triggersDetails()
if triggers_details is None:
pass
else:
- ret.append(HtmlSection(QApplication.translate("DBManagerPlugin", 'Triggers'), triggers_details))
+ ret.append(
+ HtmlSection(
+ QApplication.translate("DBManagerPlugin", "Triggers"),
+ triggers_details,
+ )
+ )
return ret
@@ -347,7 +485,12 @@ def getViewInfo(self):
if view_def is None:
pass
else:
- ret.append(HtmlSection(QApplication.translate("DBManagerPlugin", 'View definition'), view_def))
+ ret.append(
+ HtmlSection(
+ QApplication.translate("DBManagerPlugin", "View definition"),
+ view_def,
+ )
+ )
return ret
@@ -370,19 +513,38 @@ def spatialInfo(self):
return ret
tbl = [
- (QApplication.translate("DBManagerPlugin", "Column:"), self.table.geomColumn),
- (QApplication.translate("DBManagerPlugin", "Geometry:"), self.table.geomType)
+ (
+ QApplication.translate("DBManagerPlugin", "Column:"),
+ self.table.geomColumn,
+ ),
+ (
+ QApplication.translate("DBManagerPlugin", "Geometry:"),
+ self.table.geomType,
+ ),
]
# only if we have info from geometry_columns
if self.table.geomDim:
- tbl.append((QApplication.translate("DBManagerPlugin", "Dimension:"), self.table.geomDim))
+ tbl.append(
+ (
+ QApplication.translate("DBManagerPlugin", "Dimension:"),
+ self.table.geomDim,
+ )
+ )
srid = self.table.srid if self.table.srid not in (None, 0) else -1
- sr_info = self.table.database().connector.getSpatialRefInfo(srid) if srid != -1 else QApplication.translate(
- "DBManagerPlugin", "Undefined")
+ sr_info = (
+ self.table.database().connector.getSpatialRefInfo(srid)
+ if srid != -1
+ else QApplication.translate("DBManagerPlugin", "Undefined")
+ )
if sr_info:
- tbl.append((QApplication.translate("DBManagerPlugin", "Spatial ref:"), "%s (%d)" % (sr_info, srid)))
+ tbl.append(
+ (
+ QApplication.translate("DBManagerPlugin", "Spatial ref:"),
+ "%s (%d)" % (sr_info, srid),
+ )
+ )
# estimated extent
if not self.table.isView:
@@ -393,36 +555,62 @@ def spatialInfo(self):
self.table.refreshTableEstimatedExtent()
self.table.blockSignals(False)
- if self.table.estimatedExtent is not None and self.table.estimatedExtent[0] is not None:
+ if (
+ self.table.estimatedExtent is not None
+ and self.table.estimatedExtent[0] is not None
+ ):
if isinstance(self.table.estimatedExtent, list):
- estimated_extent_str = ', '.join('%.5f' % e for e in self.table.estimatedExtent)
+ estimated_extent_str = ", ".join(
+ "%.5f" % e for e in self.table.estimatedExtent
+ )
else:
- estimated_extent_str = '%.5f, %.5f - %.5f, %.5f' % self.table.estimatedExtent
- tbl.append((QApplication.translate("DBManagerPlugin", "Estimated extent:"), estimated_extent_str))
+ estimated_extent_str = (
+ "%.5f, %.5f - %.5f, %.5f" % self.table.estimatedExtent
+ )
+ tbl.append(
+ (
+ QApplication.translate("DBManagerPlugin", "Estimated extent:"),
+ estimated_extent_str,
+ )
+ )
# extent
if self.table.extent is not None and self.table.extent[0] is not None:
if isinstance(self.table.extent, list):
- extent_str = ', '.join('%.5f' % e for e in self.table.extent)
+ extent_str = ", ".join("%.5f" % e for e in self.table.extent)
else:
- extent_str = '%.5f, %.5f - %.5f, %.5f' % self.table.extent
+ extent_str = "%.5f, %.5f - %.5f, %.5f" % self.table.extent
else:
- extent_str = QApplication.translate("DBManagerPlugin",
- '(unknown) (find out )')
+ extent_str = QApplication.translate(
+ "DBManagerPlugin",
+ '(unknown) (find out )',
+ )
tbl.append((QApplication.translate("DBManagerPlugin", "Extent:"), extent_str))
ret.append(HtmlTable(tbl))
# is there an entry in geometry_columns?
- if self.table.geomType.lower() == 'geometry':
- ret.append(HtmlParagraph(
- QApplication.translate("DBManagerPlugin", " There is no entry in geometry_columns!")))
+ if self.table.geomType.lower() == "geometry":
+ ret.append(
+ HtmlParagraph(
+ QApplication.translate(
+ "DBManagerPlugin",
+ " There is no entry in geometry_columns!",
+ )
+ )
+ )
# find out whether the geometry column has spatial index on it
if not self.table.isView:
if not self.table.hasSpatialIndex():
- ret.append(HtmlParagraph(QApplication.translate("DBManagerPlugin",
- ' No spatial index defined (create it )')))
+ ret.append(
+ HtmlParagraph(
+ QApplication.translate(
+ "DBManagerPlugin",
+ ' No spatial index defined (create it )',
+ )
+ )
+ )
return ret
@@ -438,23 +626,39 @@ def spatialInfo(self):
return ret
tbl = [
- (QApplication.translate("DBManagerPlugin", "Column:"), self.table.geomColumn),
- (QApplication.translate("DBManagerPlugin", "Geometry:"), self.table.geomType)
+ (
+ QApplication.translate("DBManagerPlugin", "Column:"),
+ self.table.geomColumn,
+ ),
+ (
+ QApplication.translate("DBManagerPlugin", "Geometry:"),
+ self.table.geomType,
+ ),
]
# only if we have info from geometry_columns
srid = self.table.srid if self.table.srid is not None else -1
- sr_info = self.table.database().connector.getSpatialRefInfo(srid) if srid != -1 else QApplication.translate(
- "DBManagerPlugin", "Undefined")
+ sr_info = (
+ self.table.database().connector.getSpatialRefInfo(srid)
+ if srid != -1
+ else QApplication.translate("DBManagerPlugin", "Undefined")
+ )
if sr_info:
- tbl.append((QApplication.translate("DBManagerPlugin", "Spatial ref:"), "%s (%d)" % (sr_info, srid)))
+ tbl.append(
+ (
+ QApplication.translate("DBManagerPlugin", "Spatial ref:"),
+ "%s (%d)" % (sr_info, srid),
+ )
+ )
# extent
if self.table.extent is not None and self.table.extent[0] is not None:
- extent_str = '%.5f, %.5f - %.5f, %.5f' % self.table.extent
+ extent_str = "%.5f, %.5f - %.5f, %.5f" % self.table.extent
else:
- extent_str = QApplication.translate("DBManagerPlugin",
- '(unknown) (find out )')
+ extent_str = QApplication.translate(
+ "DBManagerPlugin",
+ '(unknown) (find out )',
+ )
tbl.append((QApplication.translate("DBManagerPlugin", "Extent:"), extent_str))
ret.append(HtmlTable(tbl))
diff --git a/python/plugins/db_manager/db_plugins/oracle/QtSqlDB.py b/python/plugins/db_manager/db_plugins/oracle/QtSqlDB.py
index 9e37ce98946c..0f96119e3751 100644
--- a/python/plugins/db_manager/db_plugins/oracle/QtSqlDB.py
+++ b/python/plugins/db_manager/db_plugins/oracle/QtSqlDB.py
@@ -112,15 +112,17 @@ def execute(self, operation, parameters=[]):
else:
continue
- self.description.append([
- f.name(), # name
- t, # type_code
- f.length(), # display_size
- f.length(), # internal_size
- f.precision(), # precision
- None, # scale
- f.requiredStatus() != QSqlField.RequiredStatus.Required # null_ok
- ])
+ self.description.append(
+ [
+ f.name(), # name
+ t, # type_code
+ f.length(), # display_size
+ f.length(), # internal_size
+ f.precision(), # precision
+ None, # scale
+ f.requiredStatus() != QSqlField.RequiredStatus.Required, # null_ok
+ ]
+ )
def executemany(self, operation, seq_of_parameters):
if len(seq_of_parameters) == 0:
@@ -146,9 +148,11 @@ def fetchone(self):
row = []
for i in range(len(self.description)):
value = self.qry.value(i)
- if (isinstance(value, QDate) or
- isinstance(value, QTime) or
- isinstance(value, QDateTime)):
+ if (
+ isinstance(value, QDate)
+ or isinstance(value, QTime)
+ or isinstance(value, QDateTime)
+ ):
value = value.toString()
elif isinstance(value, QByteArray):
value = "GEOMETRY"
@@ -190,7 +194,8 @@ class QtSqlDBConnection:
def __init__(self, driver, dbname, user, passwd):
self.conn = QSqlDatabase.addDatabase(
- driver, "qtsql_%d" % QtSqlDBConnection.connections)
+ driver, "qtsql_%d" % QtSqlDBConnection.connections
+ )
QtSqlDBConnection.connections += 1
self.conn.setDatabaseName(dbname)
self.conn.setUserName(user)
diff --git a/python/plugins/db_manager/db_plugins/oracle/connector.py b/python/plugins/db_manager/db_plugins/oracle/connector.py
index 0055fac61ef5..ba2c61e31176 100644
--- a/python/plugins/db_manager/db_plugins/oracle/connector.py
+++ b/python/plugins/db_manager/db_plugins/oracle/connector.py
@@ -54,14 +54,14 @@ class OracleDBConnector(DBConnector):
3003: QgsWkbTypes.Type.Polygon25D,
3005: QgsWkbTypes.Type.MultiPoint25D,
3006: QgsWkbTypes.Type.MultiLineString25D,
- 3007: QgsWkbTypes.Type.MultiPolygon25D
+ 3007: QgsWkbTypes.Type.MultiPolygon25D,
}
def __init__(self, uri, connName):
DBConnector.__init__(self, uri)
self.connName = connName
- self.user = uri.username() or os.environ.get('USER')
+ self.user = uri.username() or os.environ.get("USER")
self.passwd = uri.password()
self.host = uri.host()
@@ -76,29 +76,29 @@ def __init__(self, uri, connName):
# Connection options
self.useEstimatedMetadata = uri.useEstimatedMetadata()
- self.userTablesOnly = uri.param('userTablesOnly').lower() == "true"
- self.geometryColumnsOnly = uri.param(
- 'geometryColumnsOnly').lower() == "true"
- self.allowGeometrylessTables = uri.param(
- 'allowGeometrylessTables').lower() == "true"
- self.onlyExistingTypes = uri.param(
- 'onlyExistingTypes').lower() == "true"
- self.includeGeoAttributes = uri.param(
- 'includeGeoAttributes').lower() == "true"
+ self.userTablesOnly = uri.param("userTablesOnly").lower() == "true"
+ self.geometryColumnsOnly = uri.param("geometryColumnsOnly").lower() == "true"
+ self.allowGeometrylessTables = (
+ uri.param("allowGeometrylessTables").lower() == "true"
+ )
+ self.onlyExistingTypes = uri.param("onlyExistingTypes").lower() == "true"
+ self.includeGeoAttributes = uri.param("includeGeoAttributes").lower() == "true"
# For refreshing
self.populated = False
try:
self.connection = QtSqlDB.connect(
- "QOCISPATIAL", self.dbname, self.user, self.passwd)
+ "QOCISPATIAL", self.dbname, self.user, self.passwd
+ )
except self.connection_error_types() as e:
raise ConnectionError(e)
# Find if we can connect to data_sources_cache.db
sqlite_cache_file = os.path.join(
- QgsApplication.qgisSettingsDirPath(), "data_sources_cache.db")
- if (os.path.isfile(sqlite_cache_file)):
+ QgsApplication.qgisSettingsDirPath(), "data_sources_cache.db"
+ )
+ if os.path.isfile(sqlite_cache_file):
try:
self.cache_connection = sqlite3.connect(sqlite_cache_file)
except sqlite3.Error:
@@ -110,8 +110,9 @@ def __init__(self, uri, connName):
if self.cache_connection:
try:
cache_c = self.cache_connection.cursor()
- query = ("SELECT COUNT(*) FROM meta_oracle WHERE"
- " conn = '{}'".format(self.connName))
+ query = "SELECT COUNT(*) FROM meta_oracle WHERE" " conn = '{}'".format(
+ self.connName
+ )
cache_c.execute(query)
has_cached = cache_c.fetchone()[0]
cache_c.close()
@@ -129,8 +130,10 @@ def _connectionInfo(self):
def _checkSpatial(self):
"""Check whether Oracle Spatial is present in catalog."""
- query = ("SELECT count(*) FROM v$option WHERE parameter = "
- " 'Spatial' AND value = 'TRUE'")
+ query = (
+ "SELECT count(*) FROM v$option WHERE parameter = "
+ " 'Spatial' AND value = 'TRUE'"
+ )
c = self._execute(None, query)
self.has_spatial = self._fetchone(c)[0] > 0
c.close()
@@ -140,12 +143,12 @@ def _checkSpatial(self):
def _checkGeometryColumnsTable(self):
"""Check if user can read *_SDO_GEOM_METADATA view."""
# First check if user can read ALL_SDO_GEOM_METADATA
- privs = self.getRawTablePrivileges('ALL_SDO_GEOM_METADATA',
- 'MDSYS', 'PUBLIC')
+ privs = self.getRawTablePrivileges("ALL_SDO_GEOM_METADATA", "MDSYS", "PUBLIC")
# Otherwise, try with USER_SDO_GEOM_METADATA
if not privs[0]:
- privs = self.getRawTablePrivileges('USER_SDO_GEOM_METADATA',
- 'MDSYS', 'PUBLIC')
+ privs = self.getRawTablePrivileges(
+ "USER_SDO_GEOM_METADATA", "MDSYS", "PUBLIC"
+ )
if privs[0]:
self.has_geometry_columns = True
@@ -211,12 +214,18 @@ def fieldTypes(self):
http://docs.oracle.com/cd/B28359_01/server.111/b28318/datatype.htm#CNCPT1828
"""
return [
- "number", "number(9)", # integers
- "number(9,2)", "number(*,4)", "binary_float",
+ "number",
+ "number(9)", # integers
+ "number(9,2)",
+ "number(*,4)",
+ "binary_float",
"binary_double", # floats
- "varchar2(255)", "char(20)", "nvarchar2(255)",
+ "varchar2(255)",
+ "char(20)",
+ "nvarchar2(255)",
"nchar(20)", # strings
- "date", "timestamp" # date/time
+ "date",
+ "timestamp", # date/time
]
def getSchemaPrivileges(self, schema):
@@ -248,10 +257,12 @@ def getRawTablePrivileges(self, table, owner, grantee):
AND TABLE_NAME = {}
AND OWNER = {}
AND GRANTEE IN ({}, {})
- """.format(self.quoteString(table),
- self.quoteString(owner),
- self.quoteString(grantee),
- self.quoteString(grantee.upper()))
+ """.format(
+ self.quoteString(table),
+ self.quoteString(owner),
+ self.quoteString(grantee),
+ self.quoteString(grantee.upper()),
+ )
c = self._execute(None, sql)
res = self._fetchall(c)
@@ -284,7 +295,9 @@ def getSchemasCache(self):
SELECT DISTINCT ownername
FROM "oracle_{}"
ORDER BY ownername
- """.format(self.connName)
+ """.format(
+ self.connName
+ )
c = self.cache_connection.cursor()
c.execute(sql)
res = c.fetchall()
@@ -303,13 +316,11 @@ def getSchemas(self):
return self.getSchemasCache()
# Use cache if available:
- metatable = ("all_objects WHERE object_type IN "
- "('TABLE','VIEW','SYNONYM')")
+ metatable = "all_objects WHERE object_type IN " "('TABLE','VIEW','SYNONYM')"
if self.geometryColumnsOnly:
metatable = "all_sdo_geom_metadata"
- sql = """SELECT DISTINCT owner FROM {} ORDER BY owner""".format(
- metatable)
+ sql = f"""SELECT DISTINCT owner FROM {metatable} ORDER BY owner"""
c = self._execute(None, sql)
res = self._fetchall(c)
@@ -343,8 +354,7 @@ def getTables(self, schema=None, add_sys_tables=False):
prefix = "USER"
owner = "user As OWNER"
if schema and not self.userTablesOnly:
- where = "AND o.owner = {} ".format(
- self.quoteString(schema))
+ where = f"AND o.owner = {self.quoteString(schema)} "
sql = """
SELECT o.OBJECT_NAME, {},
@@ -355,9 +365,12 @@ def getTables(self, schema=None, add_sys_tables=False):
WHERE o.object_type IN ('TABLE','VIEW','SYNONYM')
{} {}
ORDER BY o.OBJECT_NAME
- """.format(owner, prefix, where,
- "" if add_sys_tables
- else "AND o.OBJECT_NAME NOT LIKE 'MDRT_%'")
+ """.format(
+ owner,
+ prefix,
+ where,
+ "" if add_sys_tables else "AND o.OBJECT_NAME NOT LIKE 'MDRT_%'",
+ )
c = self._execute(None, sql)
for tbl in self._fetchall(c):
@@ -370,7 +383,9 @@ def getTables(self, schema=None, add_sys_tables=False):
self.populated = True
- listTables = sorted(items, key=cmp_to_key(lambda x, y: (x[1] > y[1]) - (x[1] < y[1])))
+ listTables = sorted(
+ items, key=cmp_to_key(lambda x, y: (x[1] > y[1]) - (x[1] < y[1]))
+ )
if self.hasCache():
self.updateCache(listTables, schema)
@@ -393,23 +408,25 @@ def getTablesCache(self, schema=None):
pass
if not self.allowGeometrylessTables:
- return sorted(items, key=cmp_to_key(lambda x, y: (x[1] > y[1]) - (x[1] < y[1])))
+ return sorted(
+ items, key=cmp_to_key(lambda x, y: (x[1] > y[1]) - (x[1] < y[1]))
+ )
# get all non geographic tables and views
schema_where = ""
if self.userTablesOnly:
- schema_where = "AND ownername = '{}'".format(
- self.user)
+ schema_where = f"AND ownername = '{self.user}'"
if schema and not self.userTablesOnly:
- schema_where = "AND ownername = '{}'".format(
- schema)
+ schema_where = f"AND ownername = '{schema}'"
sql = """
SELECT tablename, ownername, isview
FROM "oracle_{}"
WHERE geometrycolname IS '' {}
ORDER BY tablename
- """.format(self.connName, schema_where)
+ """.format(
+ self.connName, schema_where
+ )
c = self.cache_connection.cursor()
c.execute(sql)
@@ -435,18 +452,28 @@ def updateCache(self, tableList, schema=None):
pkCols = self.pkCols((schema, table[1]))
# Deals with non-geographic tables
if table[0] == Table.TableType:
- line = (table[1], table[2], int(table[3]),
- "",
- ",".join(pkCols) if pkCols else "",
- 100, 0, "")
+ line = (
+ table[1],
+ table[2],
+ int(table[3]),
+ "",
+ ",".join(pkCols) if pkCols else "",
+ 100,
+ 0,
+ "",
+ )
# Deals with vector tables
elif table[0] == Table.VectorType:
- line = (table[1], table[2], int(table[3]),
- table[4],
- ",".join(pkCols) if pkCols else "",
- table[9],
- table[8] if table[10] == "-1" else table[10],
- "")
+ line = (
+ table[1],
+ table[2],
+ int(table[3]),
+ table[4],
+ ",".join(pkCols) if pkCols else "",
+ table[9],
+ table[8] if table[10] == "-1" else table[10],
+ "",
+ )
else:
continue
data.append(line)
@@ -454,8 +481,9 @@ def updateCache(self, tableList, schema=None):
# Then, empty the cache list
sql = """
DELETE FROM "oracle_{}" {}
- """.format(self.connName,
- "WHERE ownername = '{}'".format(schema) if schema else "")
+ """.format(
+ self.connName, f"WHERE ownername = '{schema}'" if schema else ""
+ )
self.cache_connection.execute(sql)
self.cache_connection.commit()
@@ -464,7 +492,9 @@ def updateCache(self, tableList, schema=None):
INSERT INTO "oracle_{}"(tablename, ownername, isview,
geometrycolname, pkcols, geomtypes, geomsrids, sql)
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
- """.format(self.connName)
+ """.format(
+ self.connName
+ )
c = self.cache_connection.cursor()
c.executemany(sql, data)
c.close()
@@ -472,16 +502,22 @@ def updateCache(self, tableList, schema=None):
def singleGeomTypes(self, geomtypes, srids):
"""Intelligent wkbtype grouping (multi with non multi)"""
- if (QgsWkbTypes.Type.Polygon in geomtypes
- and QgsWkbTypes.Type.MultiPolygon in geomtypes):
+ if (
+ QgsWkbTypes.Type.Polygon in geomtypes
+ and QgsWkbTypes.Type.MultiPolygon in geomtypes
+ ):
srids.pop(geomtypes.index(QgsWkbTypes.Type.Polygon))
geomtypes.pop(geomtypes.index(QgsWkbTypes.Type.Polygon))
- if (QgsWkbTypes.Type.Point in geomtypes
- and QgsWkbTypes.Type.MultiPoint in geomtypes):
+ if (
+ QgsWkbTypes.Type.Point in geomtypes
+ and QgsWkbTypes.Type.MultiPoint in geomtypes
+ ):
srids.pop(geomtypes.index(QgsWkbTypes.Type.Point))
geomtypes.pop(geomtypes.index(QgsWkbTypes.Type.Point))
- if (QgsWkbTypes.Type.LineString in geomtypes
- and QgsWkbTypes.Type.MultiLineString in geomtypes):
+ if (
+ QgsWkbTypes.Type.LineString in geomtypes
+ and QgsWkbTypes.Type.MultiLineString in geomtypes
+ ):
srids.pop(geomtypes.index(QgsWkbTypes.Type.LineString))
geomtypes.pop(geomtypes.index(QgsWkbTypes.Type.LineString))
if QgsWkbTypes.Type.Unknown in geomtypes and len(geomtypes) > 1:
@@ -502,11 +538,9 @@ def getVectorTablesCache(self, schema=None):
"""
schema_where = ""
if self.userTablesOnly:
- schema_where = "AND ownername = '{}'".format(
- self.user)
+ schema_where = f"AND ownername = '{self.user}'"
if schema and not self.userTablesOnly:
- schema_where = "AND ownername = '{}'".format(
- schema)
+ schema_where = f"AND ownername = '{schema}'"
sql = """
SELECT tablename, ownername, isview,
@@ -515,7 +549,9 @@ def getVectorTablesCache(self, schema=None):
FROM "oracle_{}"
WHERE geometrycolname IS NOT '' {}
ORDER BY tablename
- """.format(self.connName, schema_where)
+ """.format(
+ self.connName, schema_where
+ )
items = []
@@ -538,7 +574,9 @@ def getVectorTablesCache(self, schema=None):
buf = list(item)
geomtype = geomtypes[j]
srid = srids[j]
- datatype = QgsWkbTypes.displayString(QgsWkbTypes.flatType(QgsWkbTypes.singleType(geomtype)))
+ datatype = QgsWkbTypes.displayString(
+ QgsWkbTypes.flatType(QgsWkbTypes.singleType(geomtype))
+ )
geo = datatype.upper()
buf.append(geo)
buf.append(geomtype)
@@ -571,8 +609,8 @@ def getVectorTables(self, schema=None):
where = "WHERE c.data_type = 'SDO_GEOMETRY'"
if schema and not self.userTablesOnly:
where = "{} c.owner = {}".format(
- "{} AND".format(where) if where else "WHERE",
- self.quoteString(schema))
+ f"{where} AND" if where else "WHERE", self.quoteString(schema)
+ )
if self.userTablesOnly:
prefix = "user"
@@ -591,15 +629,14 @@ def getVectorTables(self, schema=None):
JOIN {2}_objects o ON c.table_name = o.object_name
AND o.object_type IN ('TABLE','VIEW','SYNONYM') {4} {5}
ORDER BY TABLE_NAME
- """.format(owner,
- "c.srid" if self.geometryColumnsOnly
- else "NULL as srid",
- prefix,
- "sdo_geom_metadata" if self.geometryColumnsOnly
- else "tab_columns",
- "" if self.userTablesOnly
- else "AND c.owner = o.owner",
- where)
+ """.format(
+ owner,
+ "c.srid" if self.geometryColumnsOnly else "NULL as srid",
+ prefix,
+ "sdo_geom_metadata" if self.geometryColumnsOnly else "tab_columns",
+ "" if self.userTablesOnly else "AND c.owner = o.owner",
+ where,
+ )
# For each table, get all of the details
items = []
@@ -617,12 +654,11 @@ def getVectorTables(self, schema=None):
detectedSrid = int(detectedSrid)
if schema:
- table_name = "{}.{}".format(self.quoteId(schema), self.quoteId(item[0]))
+ table_name = f"{self.quoteId(schema)}.{self.quoteId(item[0])}"
else:
table_name = self.quoteId(item[0])
geocol = self.quoteId(item[3])
- geomMultiTypes, multiSrids = self.getTableGeomTypes(
- table_name, geocol)
+ geomMultiTypes, multiSrids = self.getTableGeomTypes(table_name, geocol)
geomtypes = list(geomMultiTypes)
srids = list(multiSrids)
item.insert(0, Table.VectorType)
@@ -632,7 +668,9 @@ def getVectorTables(self, schema=None):
for j in range(len(geomtypes)):
buf = list(item)
geomtype = geomtypes[j]
- datatype = QgsWkbTypes.displayString(QgsWkbTypes.flatType(QgsWkbTypes.singleType(geomtype)))
+ datatype = QgsWkbTypes.displayString(
+ QgsWkbTypes.flatType(QgsWkbTypes.singleType(geomtype))
+ )
geo = datatype.upper()
buf.append(geo) # Geometry type as String
buf.append(geomtype) # Qgis.WkbType
@@ -641,8 +679,7 @@ def getVectorTables(self, schema=None):
if not self.onlyExistingTypes:
geomMultiTypes.append(0)
multiSrids.append(multiSrids[0])
- buf.append(",".join([str(x) for x in
- geomMultiTypes]))
+ buf.append(",".join([str(x) for x in geomMultiTypes]))
buf.append(",".join([str(x) for x in multiSrids]))
items.append(buf)
@@ -662,8 +699,7 @@ def getTableComment(self, table, objectType):
schema, tablename = self.getSchemaTableName(table)
data_prefix = "ALL" if schema else "USER"
- where = "AND OWNER = {}".format(
- self.quoteString(schema)) if schema else ""
+ where = f"AND OWNER = {self.quoteString(schema)}" if schema else ""
if objectType in ["TABLE", "VIEW"]:
data_table = "{}_TAB_COMMENTS"
table = "TABLE"
@@ -677,9 +713,9 @@ def getTableComment(self, table, objectType):
sql = """
SELECT COMMENTS FROM {} WHERE {}_NAME = {}
{}
- """.format(data_table, table,
- self.quoteString(tablename),
- where)
+ """.format(
+ data_table, table, self.quoteString(tablename), where
+ )
c = self._execute(None, sql)
res = self._fetchone(c)
@@ -702,14 +738,13 @@ def getTableType(self, table):
SELECT OBJECT_TYPE FROM {0} WHERE OBJECT_NAME = {1} {2}
"""
if schema:
- sql = sql.format("ALL_OBJECTS",
- self.quoteString(tablename),
- "AND OWNER = {}".format(
- self.quoteString(schema)))
+ sql = sql.format(
+ "ALL_OBJECTS",
+ self.quoteString(tablename),
+ f"AND OWNER = {self.quoteString(schema)}",
+ )
else:
- sql = sql.format("USER_OBJECTS",
- self.quoteString(tablename),
- "")
+ sql = sql.format("USER_OBJECTS", self.quoteString(tablename), "")
c = self._execute(None, sql)
res = self._fetchall(c)
@@ -736,8 +771,10 @@ def pkCols(self, table):
WHERE owner={}
AND table_name={}
ORDER BY column_id
- """.format(self.quoteString(schema) if schema else self.user,
- self.quoteString(tablename))
+ """.format(
+ self.quoteString(schema) if schema else self.user,
+ self.quoteString(tablename),
+ )
c = self._execute(None, sql)
res = self._fetchall(c)
c.close()
@@ -760,7 +797,9 @@ def getTableGeomTypes(self, table, geomCol):
FROM {1} a
WHERE a.{0} IS NOT NULL {2}
ORDER BY a.{0}.SDO_GTYPE
- """.format(geomCol, table, estimated)
+ """.format(
+ geomCol, table, estimated
+ )
try:
c = self._execute(None, query)
@@ -799,12 +838,20 @@ def getTableMainGeomType(self, table, geomCol):
# Make the decision:
wkbType = QgsWkbTypes.Type.Unknown
srid = -1
- order = [QgsWkbTypes.Type.MultiPolygon25D, QgsWkbTypes.Type.Polygon25D,
- QgsWkbTypes.Type.MultiPolygon, QgsWkbTypes.Type.Polygon,
- QgsWkbTypes.Type.MultiLineString25D, QgsWkbTypes.Type.LineString25D,
- QgsWkbTypes.Type.MultiLineString, QgsWkbTypes.Type.LineString,
- QgsWkbTypes.Type.MultiPoint25D, QgsWkbTypes.Type.Point25D,
- QgsWkbTypes.Type.MultiPoint, QgsWkbTypes.Type.Point]
+ order = [
+ QgsWkbTypes.Type.MultiPolygon25D,
+ QgsWkbTypes.Type.Polygon25D,
+ QgsWkbTypes.Type.MultiPolygon,
+ QgsWkbTypes.Type.Polygon,
+ QgsWkbTypes.Type.MultiLineString25D,
+ QgsWkbTypes.Type.LineString25D,
+ QgsWkbTypes.Type.MultiLineString,
+ QgsWkbTypes.Type.LineString,
+ QgsWkbTypes.Type.MultiPoint25D,
+ QgsWkbTypes.Type.Point25D,
+ QgsWkbTypes.Type.MultiPoint,
+ QgsWkbTypes.Type.Point,
+ ]
for geomType in order:
if geomType in geomTypes:
wkbType = geomType
@@ -814,17 +861,18 @@ def getTableMainGeomType(self, table, geomCol):
return wkbType, srid
def getTableRowEstimation(self, table):
- """ Find the estimated number of rows of a table. """
+ """Find the estimated number of rows of a table."""
schema, tablename = self.getSchemaTableName(table)
prefix = "ALL" if schema else "USER"
- where = "AND OWNER = {}".format(
- self.quoteString(schema)) if schema else ""
+ where = f"AND OWNER = {self.quoteString(schema)}" if schema else ""
sql = """
SELECT NUM_ROWS FROM {}_ALL_TABLES
WHERE TABLE_NAME = {}
{}
- """.format(prefix, self.quoteString(tablename), where)
+ """.format(
+ prefix, self.quoteString(tablename), where
+ )
c = self._execute(None, sql)
res = self._fetchone(c)
@@ -836,17 +884,18 @@ def getTableRowEstimation(self, table):
return int(res[0])
def getTableDates(self, table):
- """ Returns the modification/creation dates of an object"""
+ """Returns the modification/creation dates of an object"""
schema, tablename = self.getSchemaTableName(table)
prefix = "ALL" if schema else "USER"
- where = "AND OWNER = {}".format(
- self.quoteString(schema)) if schema else ""
+ where = f"AND OWNER = {self.quoteString(schema)}" if schema else ""
sql = """
SELECT CREATED, LAST_DDL_TIME FROM {}_OBJECTS
WHERE OBJECT_NAME = {}
{}
- """.format(prefix, self.quoteString(tablename), where)
+ """.format(
+ prefix, self.quoteString(tablename), where
+ )
c = self._execute(None, sql)
res = self._fetchone(c)
@@ -859,8 +908,7 @@ def getTableDates(self, table):
def getTableRowCount(self, table):
"""Returns the number of rows of the table."""
- c = self._execute(
- None, "SELECT COUNT(*) FROM {}".format(self.quoteId(table)))
+ c = self._execute(None, f"SELECT COUNT(*) FROM {self.quoteId(table)}")
res = self._fetchone(c)[0]
c.close()
@@ -871,7 +919,8 @@ def getTableFields(self, table):
schema, tablename = self.getSchemaTableName(table)
schema_where = " AND a.OWNER={}".format(
- self.quoteString(schema) if schema else "")
+ self.quoteString(schema) if schema else ""
+ )
sql = """
SELECT a.COLUMN_ID As ordinal_position,
a.COLUMN_NAME As column_name,
@@ -892,7 +941,9 @@ def getTableFields(self, table):
AND a.OWNER = c.OWNER
WHERE a.TABLE_NAME = {} {}
ORDER BY a.COLUMN_ID
- """.format(self.quoteString(tablename), schema_where)
+ """.format(
+ self.quoteString(tablename), schema_where
+ )
c = self._execute(None, sql)
res = self._fetchall(c)
@@ -913,7 +964,8 @@ def getTableIndexes(self, table):
"""Get info about table's indexes."""
schema, tablename = self.getSchemaTableName(table)
schema_where = " AND i.OWNER = {} ".format(
- self.quoteString(schema) if schema else "")
+ self.quoteString(schema) if schema else ""
+ )
sql = """
SELECT i.INDEX_NAME, c.COLUMN_NAME, i.ITYP_NAME,
@@ -922,7 +974,9 @@ def getTableIndexes(self, table):
FROM ALL_INDEXES i
INNER JOIN ALL_IND_COLUMNS c ON i.index_name = c.index_name
WHERE i.table_name = {} {}
- """.format(self.quoteString(tablename), schema_where)
+ """.format(
+ self.quoteString(tablename), schema_where
+ )
c = self._execute(None, sql)
res = self._fetchall(c)
@@ -933,8 +987,7 @@ def getTableIndexes(self, table):
def getMViewInfo(self, table):
"""Find some information about materialized views"""
schema, tablename = self.getSchemaTableName(table)
- where = " AND a.OWNER = {} ".format(
- self.quoteString(schema)) if schema else ""
+ where = f" AND a.OWNER = {self.quoteString(schema)} " if schema else ""
prefix = "ALL" if schema else "USER"
sql = """
SELECT a.REFRESH_MODE,
@@ -944,7 +997,9 @@ def getMViewInfo(self, table):
FROM {}_MVIEWS a
WHERE MVIEW_NAME = {}
{}
- """.format(prefix, self.quoteString(tablename), where)
+ """.format(
+ prefix, self.quoteString(tablename), where
+ )
c = self._execute(None, sql)
res = self._fetchone(c)
@@ -955,8 +1010,7 @@ def getMViewInfo(self, table):
def getTableConstraints(self, table):
"""Find all the constraints for a table."""
schema, tablename = self.getSchemaTableName(table)
- schema_where = " AND c.OWNER={} ".format(
- self.quoteString(schema)) if schema else ""
+ schema_where = f" AND c.OWNER={self.quoteString(schema)} " if schema else ""
sql = """
SELECT a.CONSTRAINT_NAME, a.CONSTRAINT_TYPE,
@@ -973,7 +1027,9 @@ def getTableConstraints(self, table):
AND a.R_OWNER = b.OWNER
AND b.POSITION = c.POSITION
WHERE c.TABLE_NAME = {} {}
- """.format(self.quoteString(tablename), schema_where)
+ """.format(
+ self.quoteString(tablename), schema_where
+ )
c = self._execute(None, sql)
res = self._fetchall(c)
@@ -990,7 +1046,9 @@ def getTableTriggers(self, table):
FROM ALL_TRIGGERS
WHERE TABLE_OWNER = {}
AND TABLE_NAME = {}
- """.format(self.quoteString(schema), self.quoteString(tablename))
+ """.format(
+ self.quoteString(schema), self.quoteString(tablename)
+ )
c = self._execute(None, sql)
res = self._fetchall(c)
@@ -1015,7 +1073,7 @@ def deleteTableTrigger(self, trigger, table):
"""Deletes the trigger on a table."""
schema, tablename = self.getSchemaTableName(table)
trigger = ".".join([self.quoteId(schema), self.quoteId(trigger)])
- sql = "DROP TRIGGER {}".format(trigger)
+ sql = f"DROP TRIGGER {trigger}"
self._execute_and_commit(sql)
def canUpdateMetadata(self, table):
@@ -1025,12 +1083,13 @@ def canUpdateMetadata(self, table):
schema, tablename = self.getSchemaTableName(table)
metadata = False
# User can only update in USER_SDO_GEOM_METADATA
- if self.getRawTablePrivileges('USER_SDO_GEOM_METADATA', 'MDSYS',
- 'PUBLIC')[2]:
+ if self.getRawTablePrivileges("USER_SDO_GEOM_METADATA", "MDSYS", "PUBLIC")[2]:
tbQuery = """
SELECT COUNT(*) FROM USER_SDO_GEOM_METADATA
WHERE TABLE_NAME = {}
- """.format(self.quoteString(tablename))
+ """.format(
+ self.quoteString(tablename)
+ )
c = self._execute(None, tbQuery)
res = self._fetchone(c)
c.close()
@@ -1044,17 +1103,18 @@ def canUpdateMetadata(self, table):
def getTableExtent(self, table, geom):
"""Calculate the real table extent."""
schema, tablename = self.getSchemaTableName(table)
- tableQuote = "'{}.{}'".format(schema, tablename)
+ tableQuote = f"'{schema}.{tablename}'"
# Extent calculation without spatial index
- extentFunction = """SDO_AGGR_MBR("{}")""".format(geom)
- fromTable = '"{}"."{}"'.format(schema, tablename)
+ extentFunction = f"""SDO_AGGR_MBR("{geom}")"""
+ fromTable = f'"{schema}"."{tablename}"'
# if table as spatial index:
indexes = self.getTableIndexes(table)
if indexes:
if "SPATIAL_INDEX" in [f[2] for f in indexes]:
extentFunction = "SDO_TUNE.EXTENT_OF({}, {})".format(
- tableQuote, self.quoteString(geom))
+ tableQuote, self.quoteString(geom)
+ )
fromTable = "DUAL"
sql = """
@@ -1064,7 +1124,9 @@ def getTableExtent(self, table, geom):
SDO_GEOM.SDO_MAX_MBR_ORDINATE({0}, 1),
SDO_GEOM.SDO_MAX_MBR_ORDINATE({0}, 2)
FROM {1}
- """.format(extentFunction, fromTable)
+ """.format(
+ extentFunction, fromTable
+ )
try:
c = self._execute(None, sql)
@@ -1086,11 +1148,11 @@ def getTableEstimatedExtent(self, table, geom):
where = """
WHERE TABLE_NAME = {}
AND COLUMN_NAME = {}
- """.format(self.quoteString(tablename),
- self.quoteString(geom))
+ """.format(
+ self.quoteString(tablename), self.quoteString(geom)
+ )
if schema:
- where = "{} AND OWNER = {}".format(
- where, self.quoteString(schema))
+ where = f"{where} AND OWNER = {self.quoteString(schema)}"
request = """
SELECT SDO_LB, SDO_UB
@@ -1124,18 +1186,21 @@ def getDefinition(self, view, objectType):
schema, tablename = self.getSchemaTableName(view)
where = ""
if schema:
- where = " AND OWNER={} ".format(
- self.quoteString(schema))
+ where = f" AND OWNER={self.quoteString(schema)} "
# Query to grab a view definition
if objectType == "VIEW":
sql = """
SELECT TEXT FROM ALL_VIEWS WHERE VIEW_NAME = {} {}
- """.format(self.quoteString(tablename), where)
+ """.format(
+ self.quoteString(tablename), where
+ )
elif objectType == "MATERIALIZED VIEW":
sql = """
SELECT QUERY FROM ALL_MVIEWS WHERE MVIEW_NAME = {} {}
- """.format(self.quoteString(tablename), where)
+ """.format(
+ self.quoteString(tablename), where
+ )
else:
return None
@@ -1155,8 +1220,8 @@ def getSpatialRefInfo(self, srid):
try:
c = self._execute(
None,
- ("SELECT CS_NAME FROM MDSYS.CS_SRS WHERE"
- " SRID = {}".format(srid)))
+ ("SELECT CS_NAME FROM MDSYS.CS_SRS WHERE" " SRID = {}".format(srid)),
+ )
except DbError:
return
sr = self._fetchone(c)
@@ -1170,16 +1235,16 @@ def isVectorTable(self, table):
"""
if self.has_geometry_columns and self.has_geometry_columns_access:
schema, tablename = self.getSchemaTableName(table)
- where = "WHERE TABLE_NAME = {}".format(
- self.quoteString(tablename))
+ where = f"WHERE TABLE_NAME = {self.quoteString(tablename)}"
if schema:
- where = "{} AND OWNER = {}".format(where,
- self.quoteString(schema))
+ where = f"{where} AND OWNER = {self.quoteString(schema)}"
sql = """
SELECT COUNT(*)
FROM ALL_SDO_GEOM_METADATA
{}
- """.format(where)
+ """.format(
+ where
+ )
c = self._execute(None, sql)
res = self._fetchone(c)
@@ -1196,10 +1261,10 @@ def createTable(self, table, field_defs, pkey):
if len(field_defs) == 0:
return False
- sql = "CREATE TABLE {} (".format(self.quoteId(table))
+ sql = f"CREATE TABLE {self.quoteId(table)} ("
sql += ", ".join(field_defs)
if pkey:
- sql += ", PRIMARY KEY ({})".format(self.quoteId(pkey))
+ sql += f", PRIMARY KEY ({self.quoteId(pkey)})"
sql += ")"
self._execute_and_commit(sql)
@@ -1213,13 +1278,13 @@ def deleteTable(self, table):
if self.isVectorTable(table):
self.deleteMetadata(table)
- sql = "DROP TABLE {}".format(self.quoteId(table))
+ sql = f"DROP TABLE {self.quoteId(table)}"
self._execute_and_commit(sql)
def emptyTable(self, table):
"""Deletes all the rows of a table."""
- sql = "TRUNCATE TABLE {}".format(self.quoteId(table))
+ sql = f"TRUNCATE TABLE {self.quoteId(table)}"
self._execute_and_commit(sql)
def renameTable(self, table, new_table):
@@ -1234,15 +1299,14 @@ def renameTable(self, table, new_table):
if self.isVectorTable(table):
self.updateMetadata(table, None, new_table=new_table)
- sql = "RENAME {} TO {}".format(
- self.quoteId(tablename), self.quoteId(new_table))
+ sql = f"RENAME {self.quoteId(tablename)} TO {self.quoteId(new_table)}"
self._execute(c, sql)
self._commit()
def createView(self, view, query):
"""Creates a view as defined."""
- sql = "CREATE VIEW {} AS {}".format(self.quoteId(view), query)
+ sql = f"CREATE VIEW {self.quoteId(view)} AS {query}"
self._execute_and_commit(sql)
def createSpatialView(self, view, query):
@@ -1281,19 +1345,18 @@ def deleteView(self, view):
if self.isVectorTable(view):
self.deleteMetadata(view)
- sql = "DROP VIEW {}".format(self.quoteId(view))
+ sql = f"DROP VIEW {self.quoteId(view)}"
self._execute_and_commit(sql)
def createSchema(self, schema):
"""Creates a new empty schema in database."""
# Not tested
- sql = "CREATE SCHEMA AUTHORIZATION {}".format(
- self.quoteId(schema))
+ sql = f"CREATE SCHEMA AUTHORIZATION {self.quoteId(schema)}"
self._execute_and_commit(sql)
def deleteSchema(self, schema):
"""Drops (empty) schema from database."""
- sql = "DROP USER {} CASCADE".format(self.quoteId(schema))
+ sql = f"DROP USER {self.quoteId(schema)} CASCADE"
self._execute_and_commit(sql)
def renameSchema(self, schema, new_schema):
@@ -1303,14 +1366,13 @@ def renameSchema(self, schema, new_schema):
def addTableColumn(self, table, field_def):
"""Adds a column to a table."""
- sql = "ALTER TABLE {} ADD {}".format(self.quoteId(table), field_def)
+ sql = f"ALTER TABLE {self.quoteId(table)} ADD {field_def}"
self._execute_and_commit(sql)
def deleteTableColumn(self, table, column):
"""Deletes column from a table."""
# Delete all the constraints for this column
- constraints = [f[0] for f in self.getTableConstraints(table)
- if f[2] == column]
+ constraints = [f[0] for f in self.getTableConstraints(table) if f[2] == column]
for constraint in constraints:
self.deleteTableConstraint(table, constraint)
@@ -1324,12 +1386,20 @@ def deleteTableColumn(self, table, column):
self.deleteMetadata(table, column)
sql = "ALTER TABLE {} DROP COLUMN {}".format(
- self.quoteId(table), self.quoteId(column))
+ self.quoteId(table), self.quoteId(column)
+ )
self._execute_and_commit(sql)
- def updateTableColumn(self, table, column, new_name=None,
- data_type=None, not_null=None,
- default=None, comment=None):
+ def updateTableColumn(
+ self,
+ table,
+ column,
+ new_name=None,
+ data_type=None,
+ not_null=None,
+ default=None,
+ comment=None,
+ ):
"""Updates properties of a column in a table."""
schema, tablename = self.getSchemaTableName(table)
@@ -1339,9 +1409,9 @@ def updateTableColumn(self, table, column, new_name=None,
# update column definition
col_actions = []
if data_type:
- col_actions.append("{}".format(data_type))
+ col_actions.append(f"{data_type}")
if default:
- col_actions.append("DEFAULT {}".format(default))
+ col_actions.append(f"DEFAULT {default}")
else:
col_actions.append("DEFAULT NULL")
@@ -1352,16 +1422,16 @@ def updateTableColumn(self, table, column, new_name=None,
if col_actions:
sql = "ALTER TABLE {} MODIFY ( {} {} )".format(
- self.quoteId(table), self.quoteId(column),
- " ".join(col_actions))
+ self.quoteId(table), self.quoteId(column), " ".join(col_actions)
+ )
self._execute(c, sql)
# rename the column
if new_name and new_name != column:
isGeo = self.isGeometryColumn(table, column)
sql = "ALTER TABLE {} RENAME COLUMN {} TO {}".format(
- self.quoteId(table), self.quoteId(column),
- self.quoteId(new_name))
+ self.quoteId(table), self.quoteId(column), self.quoteId(new_name)
+ )
self._execute(c, sql)
# update geometry_columns if Spatial is enabled
@@ -1392,16 +1462,16 @@ def isGeometryColumn(self, table, column):
"""Find if a column is geometric."""
schema, tablename = self.getSchemaTableName(table)
prefix = "ALL" if schema else "USER"
- where = "AND owner = {} ".format(
- self.quoteString(schema)) if schema else ""
+ where = f"AND owner = {self.quoteString(schema)} " if schema else ""
sql = """
SELECT COUNT(*)
FROM {}_SDO_GEOM_METADATA
WHERE TABLE_NAME = {}
AND COLUMN_NAME = {} {}
- """.format(prefix, self.quoteString(tablename),
- self.quoteString(column.upper()), where)
+ """.format(
+ prefix, self.quoteString(tablename), self.quoteString(column.upper()), where
+ )
c = self._execute(None, sql)
res = self._fetchone(c)[0] > 0
@@ -1412,92 +1482,100 @@ def isGeometryColumn(self, table, column):
def refreshMView(self, table):
"""Refreshes an MVIEW"""
schema, tablename = self.getSchemaTableName(table)
- mview = "{}.{}".format(schema, tablename) if schema else tablename
+ mview = f"{schema}.{tablename}" if schema else tablename
sql = """
BEGIN
DBMS_MVIEW.REFRESH({},'?');
END;
- """.format(self.quoteString(mview))
+ """.format(
+ self.quoteString(mview)
+ )
self._execute_and_commit(sql)
def deleteMetadata(self, table, geom_column=None):
"""Deletes the metadata entry for a table"""
schema, tablename = self.getSchemaTableName(table)
- if not (self.getRawTablePrivileges('USER_SDO_GEOM_METADATA',
- 'MDSYS',
- 'PUBLIC')[3] and
- schema == self.user):
+ if not (
+ self.getRawTablePrivileges("USER_SDO_GEOM_METADATA", "MDSYS", "PUBLIC")[3]
+ and schema == self.user
+ ):
return False
- where = "WHERE TABLE_NAME = {}".format(self.quoteString(tablename))
+ where = f"WHERE TABLE_NAME = {self.quoteString(tablename)}"
if geom_column:
- where = ("{} AND COLUMN_NAME = "
- "{}".format(where,
- self.quoteString(geom_column)))
- sql = "DELETE FROM USER_SDO_GEOM_METADATA {}".format(where)
+ where = "{} AND COLUMN_NAME = " "{}".format(
+ where, self.quoteString(geom_column)
+ )
+ sql = f"DELETE FROM USER_SDO_GEOM_METADATA {where}"
self._execute_and_commit(sql)
- def updateMetadata(self, table, geom_column, new_geom_column=None,
- new_table=None, extent=None, srid=None):
+ def updateMetadata(
+ self,
+ table,
+ geom_column,
+ new_geom_column=None,
+ new_table=None,
+ extent=None,
+ srid=None,
+ ):
"""Updates the metadata table with the new information"""
schema, tablename = self.getSchemaTableName(table)
- if not (self.getRawTablePrivileges('USER_SDO_GEOM_METADATA',
- 'MDSYS',
- 'PUBLIC')[2] and
- schema == self.user):
+ if not (
+ self.getRawTablePrivileges("USER_SDO_GEOM_METADATA", "MDSYS", "PUBLIC")[2]
+ and schema == self.user
+ ):
return False
- where = "WHERE TABLE_NAME = {}".format(self.quoteString(tablename))
+ where = f"WHERE TABLE_NAME = {self.quoteString(tablename)}"
if geom_column:
# in Metadata view, geographic column is always in uppercase
- where = ("{} AND COLUMN_NAME = "
- "{}".format(where,
- self.quoteString(geom_column.upper())))
+ where = "{} AND COLUMN_NAME = " "{}".format(
+ where, self.quoteString(geom_column.upper())
+ )
update = "SET"
if srid == 0:
srid = -1
if srid:
- update = "{} SRID = {}".format(update, srid)
+ update = f"{update} SRID = {srid}"
if extent:
if len(extent) == 4:
if update != "SET":
- update = "{},".format(update)
+ update = f"{update},"
update = """{4} DIMINFO = MDSYS.SDO_DIM_ARRAY(
MDSYS.SDO_DIM_ELEMENT('X', {0:.9f}, {1:.9f}, 0.005),
MDSYS.SDO_DIM_ELEMENT('Y', {2:.9f}, {3:.9f}, 0.005))
- """.format(extent[0], extent[2], extent[1],
- extent[3], update)
+ """.format(
+ extent[0], extent[2], extent[1], extent[3], update
+ )
if new_geom_column:
if update != "SET":
- update = "{},".format(update)
+ update = f"{update},"
# in Metadata view, geographic column is always in uppercase
- update = ("{} COLUMN_NAME = "
- "{}".format(update,
- self.quoteString(new_geom_column.upper())))
+ update = "{} COLUMN_NAME = " "{}".format(
+ update, self.quoteString(new_geom_column.upper())
+ )
if new_table:
if update != "SET":
- update = "{},".format(update)
- update = ("{} TABLE_NAME = "
- "{}".format(update,
- self.quoteString(new_table)))
+ update = f"{update},"
+ update = "{} TABLE_NAME = " "{}".format(update, self.quoteString(new_table))
- sql = "UPDATE USER_SDO_GEOM_METADATA {} {}".format(update, where)
+ sql = f"UPDATE USER_SDO_GEOM_METADATA {update} {where}"
self._execute_and_commit(sql)
def insertMetadata(self, table, geom_column, extent, srid, dim=2):
"""Inserts a line for the table in Oracle Metadata table."""
schema, tablename = self.getSchemaTableName(table)
- if not (self.getRawTablePrivileges('USER_SDO_GEOM_METADATA',
- 'MDSYS',
- 'PUBLIC')[1] and
- schema == self.user):
+ if not (
+ self.getRawTablePrivileges("USER_SDO_GEOM_METADATA", "MDSYS", "PUBLIC")[1]
+ and schema == self.user
+ ):
return False
# in Metadata view, geographic column is always in uppercase
@@ -1507,16 +1585,21 @@ def insertMetadata(self, table, geom_column, extent, srid, dim=2):
if len(extent) != 4:
return False
- dims = ['X', 'Y', 'Z', 'T']
+ dims = ["X", "Y", "Z", "T"]
extentParts = []
for i in range(dim):
extentParts.append(
"""MDSYS.SDO_DIM_ELEMENT(
- '{}', {:.9f}, {:.9f}, 0.005)""".format(dims[i], extent[i], extent[i + 1]))
+ '{}', {:.9f}, {:.9f}, 0.005)""".format(
+ dims[i], extent[i], extent[i + 1]
+ )
+ )
extentParts = ",".join(extentParts)
sqlExtent = """MDSYS.SDO_DIM_ARRAY(
{})
- """.format(extentParts)
+ """.format(
+ extentParts
+ )
sql = """
INSERT INTO USER_SDO_GEOM_METADATA (TABLE_NAME,
@@ -1525,14 +1608,18 @@ def insertMetadata(self, table, geom_column, extent, srid, dim=2):
VALUES({}, {},
{},
{})
- """.format(self.quoteString(tablename),
- self.quoteString(geom_column),
- sqlExtent, str(srid))
+ """.format(
+ self.quoteString(tablename),
+ self.quoteString(geom_column),
+ sqlExtent,
+ str(srid),
+ )
self._execute_and_commit(sql)
- def addGeometryColumn(self, table, geom_column='GEOM',
- geom_type=None, srid=-1, dim=2):
+ def addGeometryColumn(
+ self, table, geom_column="GEOM", geom_type=None, srid=-1, dim=2
+ ):
"""Adds a geometry column and update Oracle Spatial
metadata.
"""
@@ -1543,7 +1630,8 @@ def addGeometryColumn(self, table, geom_column='GEOM',
# Add the column to the table
sql = "ALTER TABLE {} ADD {} SDO_GEOMETRY".format(
- self.quoteId(table), self.quoteId(geom_column))
+ self.quoteId(table), self.quoteId(geom_column)
+ )
self._execute_and_commit(sql)
@@ -1551,9 +1639,9 @@ def addGeometryColumn(self, table, geom_column='GEOM',
extent = []
for i in range(dim):
extent.extend([-100000, 10000])
- self.insertMetadata(table, geom_column,
- [-100000, 100000, -10000, 10000],
- srid, dim)
+ self.insertMetadata(
+ table, geom_column, [-100000, 100000, -10000, 10000], srid, dim
+ )
def deleteGeometryColumn(self, table, geom_column):
"""Deletes a geometric column."""
@@ -1562,57 +1650,61 @@ def deleteGeometryColumn(self, table, geom_column):
def addTableUniqueConstraint(self, table, column):
"""Adds a unique constraint to a table."""
sql = "ALTER TABLE {} ADD UNIQUE ({})".format(
- self.quoteId(table), self.quoteId(column))
+ self.quoteId(table), self.quoteId(column)
+ )
self._execute_and_commit(sql)
def deleteTableConstraint(self, table, constraint):
"""Deletes constraint in a table."""
sql = "ALTER TABLE {} DROP CONSTRAINT {}".format(
- self.quoteId(table), self.quoteId(constraint))
+ self.quoteId(table), self.quoteId(constraint)
+ )
self._execute_and_commit(sql)
def addTablePrimaryKey(self, table, column):
"""Adds a primary key (with one column) to a table."""
sql = "ALTER TABLE {} ADD PRIMARY KEY ({})".format(
- self.quoteId(table), self.quoteId(column))
+ self.quoteId(table), self.quoteId(column)
+ )
self._execute_and_commit(sql)
def createTableIndex(self, table, name, column):
"""Creates index on one column using default options."""
sql = "CREATE INDEX {} ON {} ({})".format(
- self.quoteId(name), self.quoteId(table),
- self.quoteId(column))
+ self.quoteId(name), self.quoteId(table), self.quoteId(column)
+ )
self._execute_and_commit(sql)
def rebuildTableIndex(self, table, name):
"""Rebuilds a table index"""
schema, tablename = self.getSchemaTableName(table)
- sql = "ALTER INDEX {} REBUILD".format(self.quoteId((schema, name)))
+ sql = f"ALTER INDEX {self.quoteId((schema, name))} REBUILD"
self._execute_and_commit(sql)
def deleteTableIndex(self, table, name):
"""Deletes an index on a table."""
schema, tablename = self.getSchemaTableName(table)
- sql = "DROP INDEX {}".format(self.quoteId((schema, name)))
+ sql = f"DROP INDEX {self.quoteId((schema, name))}"
self._execute_and_commit(sql)
- def createSpatialIndex(self, table, geom_column='GEOM'):
+ def createSpatialIndex(self, table, geom_column="GEOM"):
"""Creates a spatial index on a geometric column."""
geom_column = geom_column.upper()
schema, tablename = self.getSchemaTableName(table)
- idx_name = self.quoteId("sidx_{}_{}".format(tablename, geom_column))
+ idx_name = self.quoteId(f"sidx_{tablename}_{geom_column}")
sql = """
CREATE INDEX {}
ON {}({})
INDEXTYPE IS MDSYS.SPATIAL_INDEX
- """.format(idx_name, self.quoteId(table),
- self.quoteId(geom_column))
+ """.format(
+ idx_name, self.quoteId(table), self.quoteId(geom_column)
+ )
self._execute_and_commit(sql)
- def deleteSpatialIndex(self, table, geom_column='GEOM'):
+ def deleteSpatialIndex(self, table, geom_column="GEOM"):
"""Deletes a spatial index of a geometric column."""
schema, tablename = self.getSchemaTableName(table)
- idx_name = self.quoteId("sidx_{}_{}".format(tablename, geom_column))
+ idx_name = self.quoteId(f"sidx_{tablename}_{geom_column}")
return self.deleteTableIndex(table, idx_name)
def execution_error_types(self):
@@ -1672,6 +1764,7 @@ def _close_cursor(self, c):
def getSqlDictionary(self):
"""Returns the dictionary for SQL dialog."""
from .sql_dictionary import getSqlDictionary
+
sql_dict = getSqlDictionary()
# get schemas, tables and field names
@@ -1683,7 +1776,9 @@ def getSqlDictionary(self):
SELECT DISTINCT tablename FROM "oracle_{0}"
UNION
SELECT DISTINCT ownername FROM "oracle_{0}"
- """.format(self.connName)
+ """.format(
+ self.connName
+ )
if self.userTablesOnly:
sql = """
SELECT DISTINCT tablename
@@ -1691,7 +1786,9 @@ def getSqlDictionary(self):
UNION
SELECT DISTINCT ownername
FROM "oracle_{conn}" WHERE ownername = '{user}'
- """.format(conn=self.connName, user=self.user)
+ """.format(
+ conn=self.connName, user=self.user
+ )
c = self.cache_connection.cursor()
c.execute(sql)
@@ -1702,8 +1799,9 @@ def getSqlDictionary(self):
if self.hasCache():
sql = """
SELECT DISTINCT COLUMN_NAME FROM {}_TAB_COLUMNS
- """.format("USER" if self.userTablesOnly else
- "ALL")
+ """.format(
+ "USER" if self.userTablesOnly else "ALL"
+ )
elif self.userTablesOnly:
sql = """
SELECT DISTINCT TABLE_NAME FROM USER_ALL_TABLES
@@ -1731,6 +1829,7 @@ def getSqlDictionary(self):
def getQueryBuilderDictionary(self):
from .sql_dictionary import getQueryBuilderDictionary
+
return getQueryBuilderDictionary()
def cancel(self):
diff --git a/python/plugins/db_manager/db_plugins/oracle/data_model.py b/python/plugins/db_manager/db_plugins/oracle/data_model.py
index 0fc8f6512932..f86336c2154a 100644
--- a/python/plugins/db_manager/db_plugins/oracle/data_model.py
+++ b/python/plugins/db_manager/db_plugins/oracle/data_model.py
@@ -23,11 +23,13 @@
from qgis.PyQt.QtCore import QElapsedTimer
from qgis.core import QgsMessageLog
-from ..data_model import (TableDataModel,
- SqlResultModel,
- SqlResultModelAsync,
- SqlResultModelTask,
- BaseTableModel)
+from ..data_model import (
+ TableDataModel,
+ SqlResultModel,
+ SqlResultModelAsync,
+ SqlResultModelTask,
+ BaseTableModel,
+)
from ..plugin import DbError
from ..plugin import BaseError
@@ -46,39 +48,38 @@ def __init__(self, table, parent=None):
def _createCursor(self):
fields_txt = ", ".join(self.fields)
- table_txt = self.db.quoteId(
- (self.table.schemaName(), self.table.name))
+ table_txt = self.db.quoteId((self.table.schemaName(), self.table.name))
self.cursor = self.db._get_cursor()
- sql = "SELECT {} FROM {}".format(fields_txt, table_txt)
+ sql = f"SELECT {fields_txt} FROM {table_txt}"
self.db._execute(self.cursor, sql)
def _sanitizeTableField(self, field):
# get fields, ignore geometry columns
if field.dataType.upper() == "SDO_GEOMETRY":
- return ("CASE WHEN {0} IS NULL THEN NULL ELSE 'GEOMETRY'"
- "END AS {0}".format(
- self.db.quoteId(field.name)))
+ return (
+ "CASE WHEN {0} IS NULL THEN NULL ELSE 'GEOMETRY'"
+ "END AS {0}".format(self.db.quoteId(field.name))
+ )
if field.dataType.upper() == "DATE":
- return "CAST({} AS VARCHAR2(8))".format(
- self.db.quoteId(field.name))
+ return f"CAST({self.db.quoteId(field.name)} AS VARCHAR2(8))"
if "TIMESTAMP" in field.dataType.upper():
return "TO_CHAR({}, 'YYYY-MM-DD HH:MI:SS.FF')".format(
- self.db.quoteId(field.name))
+ self.db.quoteId(field.name)
+ )
if field.dataType.upper() == "NUMBER":
if not field.charMaxLen:
- return "CAST({} AS VARCHAR2(135))".format(
- self.db.quoteId(field.name))
+ return f"CAST({self.db.quoteId(field.name)} AS VARCHAR2(135))"
elif field.modifier:
- nbChars = 2 + int(field.charMaxLen) + \
- int(field.modifier)
+ nbChars = 2 + int(field.charMaxLen) + int(field.modifier)
return "CAST({} AS VARCHAR2({}))".format(
- self.db.quoteId(field.name),
- str(nbChars))
+ self.db.quoteId(field.name), str(nbChars)
+ )
return "CAST({} As VARCHAR2({}))".format(
- self.db.quoteId(field.name), field.charMaxLen)
+ self.db.quoteId(field.name), field.charMaxLen
+ )
def _deleteCursor(self):
self.db._close_cursor(self.cursor)
@@ -89,8 +90,7 @@ def __del__(self):
self._deleteCursor()
def getData(self, row, col):
- if (row < self.fetchedFrom or
- row >= self.fetchedFrom + self.fetchedCount):
+ if row < self.fetchedFrom or row >= self.fetchedFrom + self.fetchedCount:
margin = self.fetchedCount / 2
if row + margin >= self.rowCount():
start = int(self.rowCount() - margin)
diff --git a/python/plugins/db_manager/db_plugins/oracle/info_model.py b/python/plugins/db_manager/db_plugins/oracle/info_model.py
index c8d531ab06eb..08805225e07a 100644
--- a/python/plugins/db_manager/db_plugins/oracle/info_model.py
+++ b/python/plugins/db_manager/db_plugins/oracle/info_model.py
@@ -25,8 +25,14 @@
from qgis.core import QgsWkbTypes
from ..info_model import TableInfo, VectorTableInfo, DatabaseInfo
-from ..html_elems import HtmlContent, HtmlSection, HtmlParagraph, \
- HtmlTable, HtmlTableHeader, HtmlTableCol
+from ..html_elems import (
+ HtmlContent,
+ HtmlSection,
+ HtmlParagraph,
+ HtmlTable,
+ HtmlTableHeader,
+ HtmlTableCol,
+)
# Syntax Highlight for VIEWS/MVIEWS
from pygments import highlight
@@ -43,16 +49,27 @@ def connectionDetails(self):
tbl = []
if self.db.connector.host != "":
- tbl.append((QApplication.translate("DBManagerPlugin", "Host:"),
- self.db.connector.host))
- tbl.append((QApplication.translate("DBManagerPlugin", "Database:"),
- self.db.connector.dbname))
- tbl.append((QApplication.translate("DBManagerPlugin", "User:"),
- self.db.connector.user))
- tbl.append((QApplication.translate("DBManagerPlugin",
- "SQLite list tables cache:"),
- "Enabled" if self.db.connector.hasCache else
- "Unavailable"))
+ tbl.append(
+ (
+ QApplication.translate("DBManagerPlugin", "Host:"),
+ self.db.connector.host,
+ )
+ )
+ tbl.append(
+ (
+ QApplication.translate("DBManagerPlugin", "Database:"),
+ self.db.connector.dbname,
+ )
+ )
+ tbl.append(
+ (QApplication.translate("DBManagerPlugin", "User:"), self.db.connector.user)
+ )
+ tbl.append(
+ (
+ QApplication.translate("DBManagerPlugin", "SQLite list tables cache:"),
+ "Enabled" if self.db.connector.hasCache else "Unavailable",
+ )
+ )
return HtmlTable(tbl)
@@ -63,10 +80,7 @@ def spatialInfo(self):
if not info:
return
- tbl = [
- (QApplication.translate("DBManagerPlugin", "Oracle Spatial:"),
- info[0])
- ]
+ tbl = [(QApplication.translate("DBManagerPlugin", "Oracle Spatial:"), info[0])]
ret.append(HtmlTable(tbl))
if not self.db.connector.has_geometry_columns:
@@ -77,12 +91,15 @@ def spatialInfo(self):
" ALL_SDO_GEOM_METADATA"
" view doesn't exist!\n"
"This view is essential for many"
- " GIS applications for enumeration of tables.")))
+ " GIS applications for enumeration of tables.",
+ )
+ )
+ )
return ret
def privilegesDetails(self):
- """ find if user can create schemas (CREATE ANY TABLE or something)"""
+ """find if user can create schemas (CREATE ANY TABLE or something)"""
# TODO
return None
@@ -105,9 +122,11 @@ def generalInfo(self):
# if the estimation is less than 100 rows, try to count them - it
# shouldn't take long time
- if (not self.table.isView and
- not self.table.rowCount and
- self.table.estimatedRowCount < 100):
+ if (
+ not self.table.isView
+ and not self.table.rowCount
+ and self.table.estimatedRowCount < 100
+ ):
# row count information is not displayed yet, so just block
# table signals to avoid double refreshing
# (infoViewer->refreshRowCount->tableChanged->infoViewer)
@@ -115,70 +134,92 @@ def generalInfo(self):
self.table.refreshRowCount()
self.table.blockSignals(False)
- relation_type = QApplication.translate(
- "DBManagerPlugin", self.table.objectType) if isinstance(self.table.objectType, str) else QApplication.translate("DBManagerPlugin", "Unknown")
+ relation_type = (
+ QApplication.translate("DBManagerPlugin", self.table.objectType)
+ if isinstance(self.table.objectType, str)
+ else QApplication.translate("DBManagerPlugin", "Unknown")
+ )
tbl = [
- (QApplication.translate("DBManagerPlugin", "Object type:"),
- relation_type),
- (QApplication.translate("DBManagerPlugin", "Owner:"),
- self.table.owner)
+ (QApplication.translate("DBManagerPlugin", "Object type:"), relation_type),
+ (QApplication.translate("DBManagerPlugin", "Owner:"), self.table.owner),
]
if self.table.comment:
tbl.append(
- (QApplication.translate(
- "DBManagerPlugin",
- "Comment:"),
- self.table.comment))
+ (
+ QApplication.translate("DBManagerPlugin", "Comment:"),
+ self.table.comment,
+ )
+ )
# Estimated rows
if not self.table.isView:
tbl.append(
- (QApplication.translate(
- "DBManagerPlugin", "Rows (estimation):"),
- self.table.estimatedRowCount)
+ (
+ QApplication.translate("DBManagerPlugin", "Rows (estimation):"),
+ self.table.estimatedRowCount,
+ )
)
if self.table.rowCount is not None and self.table.rowCount >= 0:
# Add a real count of rows
tbl.append(
- (QApplication.translate("DBManagerPlugin", "Rows (counted):"),
- self.table.rowCount)
+ (
+ QApplication.translate("DBManagerPlugin", "Rows (counted):"),
+ self.table.rowCount,
+ )
)
else:
tbl.append(
- (QApplication.translate("DBManagerPlugin", "Rows (counted):"),
- 'Unknown (find out )')
+ (
+ QApplication.translate("DBManagerPlugin", "Rows (counted):"),
+ 'Unknown (find out )',
+ )
)
# Add creation and modification dates
if self.table.creationDate:
tbl.append(
- (QApplication.translate("DBManagerPlugin", "Creation Date:"),
- self.table.creationDate))
+ (
+ QApplication.translate("DBManagerPlugin", "Creation Date:"),
+ self.table.creationDate,
+ )
+ )
if self.table.modificationDate:
tbl.append(
- (QApplication.translate(
- "DBManagerPlugin", "Last Modification Date:"),
- self.table.modificationDate))
+ (
+ QApplication.translate(
+ "DBManagerPlugin", "Last Modification Date:"
+ ),
+ self.table.modificationDate,
+ )
+ )
# privileges
# has the user access to this schema?
- schema_priv = self.table.database().connector.getSchemaPrivileges(
- self.table.schemaName()) if self.table.schema() else None
+ schema_priv = (
+ self.table.database().connector.getSchemaPrivileges(self.table.schemaName())
+ if self.table.schema()
+ else None
+ )
if not schema_priv:
pass
elif schema_priv[1] is False: # no usage privileges on the schema
- tbl.append((QApplication.translate(
- "DBManagerPlugin", "Privileges:"),
- QApplication.translate(
- "DBManagerPlugin",
- " This user doesn't have usage privileges"
- " for this schema!")))
+ tbl.append(
+ (
+ QApplication.translate("DBManagerPlugin", "Privileges:"),
+ QApplication.translate(
+ "DBManagerPlugin",
+ " This user doesn't have usage privileges"
+ " for this schema!",
+ ),
+ )
+ )
else:
table_priv = self.table.database().connector.getTablePrivileges(
- (self.table.schemaName(), self.table.name))
+ (self.table.schemaName(), self.table.name)
+ )
privileges = []
if table_priv[0]:
privileges.append("select")
@@ -193,35 +234,43 @@ def generalInfo(self):
priv_string = ", ".join(privileges)
else:
priv_string = QApplication.translate(
- "DBManagerPlugin",
- ' This user has no privileges!')
+ "DBManagerPlugin", " This user has no privileges!"
+ )
tbl.append(
- (QApplication.translate(
- "DBManagerPlugin", "Privileges:"),
- priv_string))
+ (QApplication.translate("DBManagerPlugin", "Privileges:"), priv_string)
+ )
ret.append(HtmlTable(tbl))
if schema_priv and schema_priv[1]:
- if (table_priv[0] and
- not table_priv[1] and
- not table_priv[2] and
- not table_priv[3]):
+ if (
+ table_priv[0]
+ and not table_priv[1]
+ and not table_priv[2]
+ and not table_priv[3]
+ ):
ret.append(
- HtmlParagraph(QApplication.translate(
- "DBManagerPlugin",
- " This user has read-only privileges.")))
+ HtmlParagraph(
+ QApplication.translate(
+ "DBManagerPlugin",
+ " This user has read-only privileges.",
+ )
+ )
+ )
# primary key defined?
- if (not self.table.isView and
- self.table.objectType != "MATERIALIZED VIEW"):
+ if not self.table.isView and self.table.objectType != "MATERIALIZED VIEW":
pk = [fld for fld in self.table.fields() if fld.primaryKey]
if len(pk) <= 0:
ret.append(
- HtmlParagraph(QApplication.translate(
- "DBManagerPlugin",
- " No primary key defined for this table!")))
+ HtmlParagraph(
+ QApplication.translate(
+ "DBManagerPlugin",
+ " No primary key defined for this table!",
+ )
+ )
+ )
return ret
@@ -232,19 +281,20 @@ def getSpatialInfo(self):
if not info:
return
- tbl = [
- (QApplication.translate(
- "DBManagerPlugin", "Library:"), info[0]) # ,
- ]
+ tbl = [(QApplication.translate("DBManagerPlugin", "Library:"), info[0])] # ,
ret.append(HtmlTable(tbl))
if not self.db.connector.has_geometry_columns:
- ret.append(HtmlParagraph(
- QApplication.translate(
- "DBManagerPlugin",
- " ALL_SDO_GEOM_METADATA table doesn't exist!\n"
- "This table is essential for many GIS"
- " applications for enumeration of tables.")))
+ ret.append(
+ HtmlParagraph(
+ QApplication.translate(
+ "DBManagerPlugin",
+ " ALL_SDO_GEOM_METADATA table doesn't exist!\n"
+ "This table is essential for many GIS"
+ " applications for enumeration of tables.",
+ )
+ )
+ )
return ret
@@ -259,14 +309,15 @@ def fieldsDetails(self):
QApplication.translate("DBManagerPlugin", "Length"),
QApplication.translate("DBManagerPlugin", "Null"),
QApplication.translate("DBManagerPlugin", "Default"),
- QApplication.translate("DBManagerPlugin", "Comment"))
+ QApplication.translate("DBManagerPlugin", "Comment"),
+ )
tbl.append(HtmlTableHeader(header))
# add table contents
for fld in self.table.fields():
char_max_len = fld.charMaxLen if fld.charMaxLen else ""
if fld.modifier:
- char_max_len = "{},{}".format(char_max_len, fld.modifier)
+ char_max_len = f"{char_max_len},{fld.modifier}"
is_null_txt = "N" if fld.notNull else "Y"
# make primary key field underlined
@@ -274,8 +325,16 @@ def fieldsDetails(self):
name = HtmlTableCol(fld.name, attrs)
tbl.append(
- (fld.num, name, fld.type2String(), char_max_len,
- is_null_txt, fld.default2String(), fld.comment))
+ (
+ fld.num,
+ name,
+ fld.type2String(),
+ char_max_len,
+ is_null_txt,
+ fld.default2String(),
+ fld.comment,
+ )
+ )
return HtmlTable(tbl, {"class": "header"})
@@ -286,24 +345,36 @@ def constraintsDetails(self):
tbl = []
# define the table header
- header = (QApplication.translate("DBManagerPlugin", "Name"),
- QApplication.translate("DBManagerPlugin", "Type"),
- QApplication.translate("DBManagerPlugin", "Column"),
- QApplication.translate("DBManagerPlugin", "Status"),
- QApplication.translate("DBManagerPlugin", "Validated"),
- QApplication.translate("DBManagerPlugin", "Generated"),
- QApplication.translate("DBManagerPlugin", "Check condition"),
- QApplication.translate("DBManagerPlugin", "Foreign Table"),
- QApplication.translate("DBManagerPlugin", "Foreign column"),
- QApplication.translate("DBManagerPlugin", "On Delete"))
+ header = (
+ QApplication.translate("DBManagerPlugin", "Name"),
+ QApplication.translate("DBManagerPlugin", "Type"),
+ QApplication.translate("DBManagerPlugin", "Column"),
+ QApplication.translate("DBManagerPlugin", "Status"),
+ QApplication.translate("DBManagerPlugin", "Validated"),
+ QApplication.translate("DBManagerPlugin", "Generated"),
+ QApplication.translate("DBManagerPlugin", "Check condition"),
+ QApplication.translate("DBManagerPlugin", "Foreign Table"),
+ QApplication.translate("DBManagerPlugin", "Foreign column"),
+ QApplication.translate("DBManagerPlugin", "On Delete"),
+ )
tbl.append(HtmlTableHeader(header))
# add table contents
for con in self.table.constraints():
- tbl.append((con.name, con.type2String(), con.column,
- con.status, con.validated, con.generated,
- con.checkSource, con.foreignTable,
- con.foreignKey, con.foreignOnDelete))
+ tbl.append(
+ (
+ con.name,
+ con.type2String(),
+ con.column,
+ con.status,
+ con.validated,
+ con.generated,
+ con.checkSource,
+ con.foreignTable,
+ con.foreignKey,
+ con.foreignOnDelete,
+ )
+ )
return HtmlTable(tbl, {"class": "header"})
@@ -314,24 +385,36 @@ def indexesDetails(self):
tbl = []
# define the table header
- header = (QApplication.translate("DBManagerPlugin", "Name"),
- QApplication.translate("DBManagerPlugin", "Column(s)"),
- QApplication.translate("DBManagerPlugin", "Index Type"),
- QApplication.translate("DBManagerPlugin", "Status"),
- QApplication.translate("DBManagerPlugin", "Last analyzed"),
- QApplication.translate("DBManagerPlugin", "Compression"),
- QApplication.translate("DBManagerPlugin", "Uniqueness"),
- QApplication.translate("DBManagerPlugin", "Action"))
+ header = (
+ QApplication.translate("DBManagerPlugin", "Name"),
+ QApplication.translate("DBManagerPlugin", "Column(s)"),
+ QApplication.translate("DBManagerPlugin", "Index Type"),
+ QApplication.translate("DBManagerPlugin", "Status"),
+ QApplication.translate("DBManagerPlugin", "Last analyzed"),
+ QApplication.translate("DBManagerPlugin", "Compression"),
+ QApplication.translate("DBManagerPlugin", "Uniqueness"),
+ QApplication.translate("DBManagerPlugin", "Action"),
+ )
tbl.append(HtmlTableHeader(header))
# add table contents
for idx in self.table.indexes():
# get the fields the index is defined on
- tbl.append((idx.name, idx.column, idx.indexType,
- idx.status, idx.analyzed, idx.compression,
- idx.isUnique,
- ('Rebuild'
- """ """.format(idx.name))))
+ tbl.append(
+ (
+ idx.name,
+ idx.column,
+ idx.indexType,
+ idx.status,
+ idx.analyzed,
+ idx.compression,
+ idx.isUnique,
+ (
+ 'Rebuild'
+ """ """.format(idx.name)
+ ),
+ )
+ )
return HtmlTable(tbl, {"class": "header"})
@@ -347,26 +430,31 @@ def triggersDetails(self):
QApplication.translate("DBManagerPlugin", "Name"),
QApplication.translate("DBManagerPlugin", "Event"),
QApplication.translate("DBManagerPlugin", "Type"),
- QApplication.translate("DBManagerPlugin", "Enabled"))
+ QApplication.translate("DBManagerPlugin", "Enabled"),
+ )
tbl.append(HtmlTableHeader(header))
# add table contents
for trig in self.table.triggers():
- name = ("""{0} ({1} )""".format(trig.name, "delete"))
+ name = """{0} ({1} )""".format(
+ trig.name, "delete"
+ )
if trig.enabled == "ENABLED":
enabled, action = (
QApplication.translate("DBManagerPlugin", "Yes"),
- "disable")
+ "disable",
+ )
else:
enabled, action = (
QApplication.translate("DBManagerPlugin", "No"),
- "enable")
+ "enable",
+ )
- txt_enabled = ("""{0} ({2} )""".format(
- enabled, trig.name, action))
+ txt_enabled = (
+ """{0} ({2} )""".format(enabled, trig.name, action)
+ )
tbl.append((name, trig.event, trig.type, txt_enabled))
@@ -377,9 +465,12 @@ def triggersDetails(self):
QApplication.translate(
"DBManagerPlugin",
''
- 'Enable all triggers / '
+ "Enable all triggers / "
''
- 'Disable all triggers ')))
+ "Disable all triggers",
+ )
+ )
+ )
return ret
@@ -392,9 +483,10 @@ def getTableInfo(self):
else:
ret.append(
HtmlSection(
- QApplication.translate(
- "DBManagerPlugin", 'General info'),
- general_info))
+ QApplication.translate("DBManagerPlugin", "General info"),
+ general_info,
+ )
+ )
# spatial info
spatial_info = self.spatialInfo()
@@ -404,12 +496,13 @@ def getTableInfo(self):
spatial_info = HtmlContent(spatial_info)
if not spatial_info.hasContents():
spatial_info = QApplication.translate(
- "DBManagerPlugin",
- ' This is not a spatial table.')
+ "DBManagerPlugin", " This is not a spatial table."
+ )
ret.append(
HtmlSection(
- self.table.database().connection().typeNameString(),
- spatial_info))
+ self.table.database().connection().typeNameString(), spatial_info
+ )
+ )
# fields
fields_details = self.fieldsDetails()
@@ -418,10 +511,9 @@ def getTableInfo(self):
else:
ret.append(
HtmlSection(
- QApplication.translate(
- "DBManagerPlugin",
- 'Fields'),
- fields_details))
+ QApplication.translate("DBManagerPlugin", "Fields"), fields_details
+ )
+ )
# constraints
constraints_details = self.constraintsDetails()
@@ -430,10 +522,10 @@ def getTableInfo(self):
else:
ret.append(
HtmlSection(
- QApplication.translate(
- "DBManagerPlugin",
- 'Constraints'),
- constraints_details))
+ QApplication.translate("DBManagerPlugin", "Constraints"),
+ constraints_details,
+ )
+ )
# indexes
indexes_details = self.indexesDetails()
@@ -442,10 +534,10 @@ def getTableInfo(self):
else:
ret.append(
HtmlSection(
- QApplication.translate(
- "DBManagerPlugin",
- 'Indexes'),
- indexes_details))
+ QApplication.translate("DBManagerPlugin", "Indexes"),
+ indexes_details,
+ )
+ )
# triggers
triggers_details = self.triggersDetails()
@@ -454,19 +546,21 @@ def getTableInfo(self):
else:
ret.append(
HtmlSection(
- QApplication.translate(
- "DBManagerPlugin",
- 'Triggers'),
- triggers_details))
+ QApplication.translate("DBManagerPlugin", "Triggers"),
+ triggers_details,
+ )
+ )
if self.table.objectType == "MATERIALIZED VIEW":
mview_info = self.getMViewInfo()
ret.append(
HtmlSection(
QApplication.translate(
- "DBManagerPlugin",
- 'Materialized View information'),
- mview_info))
+ "DBManagerPlugin", "Materialized View information"
+ ),
+ mview_info,
+ )
+ )
return ret
@@ -477,39 +571,44 @@ def getMViewInfo(self):
ret = []
tbl = []
values = self.table.getMViewInfo()
- tbl.append((QApplication.translate("DBManagerPlugin",
- "Refresh Mode:"),
- values[0]))
- tbl.append((QApplication.translate("DBManagerPlugin",
- "Refresh Method:"),
- values[1]))
- tbl.append((QApplication.translate("DBManagerPlugin",
- "Build Mode:"),
- values[2]))
- tbl.append((QApplication.translate("DBManagerPlugin",
- "Last Refresh Date:"),
- values[5]))
- tbl.append((QApplication.translate("DBManagerPlugin",
- "Last Refresh Type:"),
- values[4]))
- tbl.append((QApplication.translate("DBManagerPlugin",
- "Fast Refreshable:"),
- values[3]))
- tbl.append((QApplication.translate("DBManagerPlugin",
- "Staleness:"),
- values[6]))
- tbl.append((QApplication.translate("DBManagerPlugin",
- "Stale since:"),
- values[7]))
- tbl.append((QApplication.translate("DBManagerPlugin",
- "Compile State:"),
- values[8]))
- tbl.append((QApplication.translate("DBManagerPlugin",
- "Use no index:"),
- values[9]))
- tbl.append(('{} '.format(
- QApplication.translate("DBManagerPlugin", "Refresh the materialized view")),
- ""))
+ tbl.append(
+ (QApplication.translate("DBManagerPlugin", "Refresh Mode:"), values[0])
+ )
+ tbl.append(
+ (QApplication.translate("DBManagerPlugin", "Refresh Method:"), values[1])
+ )
+ tbl.append(
+ (QApplication.translate("DBManagerPlugin", "Build Mode:"), values[2])
+ )
+ tbl.append(
+ (QApplication.translate("DBManagerPlugin", "Last Refresh Date:"), values[5])
+ )
+ tbl.append(
+ (QApplication.translate("DBManagerPlugin", "Last Refresh Type:"), values[4])
+ )
+ tbl.append(
+ (QApplication.translate("DBManagerPlugin", "Fast Refreshable:"), values[3])
+ )
+ tbl.append((QApplication.translate("DBManagerPlugin", "Staleness:"), values[6]))
+ tbl.append(
+ (QApplication.translate("DBManagerPlugin", "Stale since:"), values[7])
+ )
+ tbl.append(
+ (QApplication.translate("DBManagerPlugin", "Compile State:"), values[8])
+ )
+ tbl.append(
+ (QApplication.translate("DBManagerPlugin", "Use no index:"), values[9])
+ )
+ tbl.append(
+ (
+ '{} '.format(
+ QApplication.translate(
+ "DBManagerPlugin", "Refresh the materialized view"
+ )
+ ),
+ "",
+ )
+ )
ret.append(HtmlTable(tbl))
return ret
@@ -529,8 +628,7 @@ def getViewInfo(self):
# Syntax highlight
lexer = get_lexer_by_name("sql")
- formatter = HtmlFormatter(
- linenos=True, cssclass="source", noclasses=True)
+ formatter = HtmlFormatter(linenos=True, cssclass="source", noclasses=True)
result = highlight(view_def, lexer, formatter)
if view_def:
@@ -539,9 +637,8 @@ def getViewInfo(self):
else:
title = "Materialized View Definition"
ret.append(
- HtmlSection(
- QApplication.translate("DBManagerPlugin", title),
- result))
+ HtmlSection(QApplication.translate("DBManagerPlugin", title), result)
+ )
return ret
@@ -565,35 +662,41 @@ def spatialInfo(self):
return ret
tbl = [
- (QApplication.translate("DBManagerPlugin", "Column:"),
- self.table.geomColumn),
- (QApplication.translate("DBManagerPlugin", "Geometry:"),
- self.table.geomType),
- (QApplication.translate("DBManagerPlugin",
- "QGIS Geometry type:"),
- QgsWkbTypes.displayString(self.table.wkbType))
+ (
+ QApplication.translate("DBManagerPlugin", "Column:"),
+ self.table.geomColumn,
+ ),
+ (
+ QApplication.translate("DBManagerPlugin", "Geometry:"),
+ self.table.geomType,
+ ),
+ (
+ QApplication.translate("DBManagerPlugin", "QGIS Geometry type:"),
+ QgsWkbTypes.displayString(self.table.wkbType),
+ ),
]
# only if we have info from geometry_columns
if self.table.geomDim:
tbl.append(
- (QApplication.translate(
- "DBManagerPlugin",
- "Dimension:"),
- self.table.geomDim))
+ (
+ QApplication.translate("DBManagerPlugin", "Dimension:"),
+ self.table.geomDim,
+ )
+ )
srid = self.table.srid if self.table.srid else -1
if srid != -1:
- sr_info = (
- self.table.database().connector.getSpatialRefInfo(srid))
+ sr_info = self.table.database().connector.getSpatialRefInfo(srid)
else:
- sr_info = QApplication.translate("DBManagerPlugin",
- "Undefined")
+ sr_info = QApplication.translate("DBManagerPlugin", "Undefined")
if sr_info:
tbl.append(
- (QApplication.translate(
- "DBManagerPlugin", "Spatial ref:"),
- "{} ({})".format(sr_info, srid)))
+ (
+ QApplication.translate("DBManagerPlugin", "Spatial ref:"),
+ f"{sr_info} ({srid})",
+ )
+ )
# estimated extent
if not self.table.estimatedExtent:
@@ -605,53 +708,65 @@ def spatialInfo(self):
self.table.blockSignals(False)
if self.table.estimatedExtent:
- estimated_extent_str = ("{:.9f}, {:.9f} - {:.9f}, "
- "{:.9f}".format(
- *self.table.estimatedExtent))
+ estimated_extent_str = "{:.9f}, {:.9f} - {:.9f}, " "{:.9f}".format(
+ *self.table.estimatedExtent
+ )
tbl.append(
- (QApplication.translate(
- "DBManagerPlugin", "Estimated extent:"),
- estimated_extent_str))
+ (
+ QApplication.translate("DBManagerPlugin", "Estimated extent:"),
+ estimated_extent_str,
+ )
+ )
# extent
extent_str = None
if self.table.extent and len(self.table.extent) == 4:
- extent_str = ("{:.9f}, {:.9f} - {:.9f}, "
- "{:.9f}".format(*self.table.extent))
- elif (self.table.rowCount is not None and self.table.rowCount > 0) or (self.table.estimatedRowCount is not None and self.table.estimatedRowCount > 0):
+ extent_str = "{:.9f}, {:.9f} - {:.9f}, " "{:.9f}".format(*self.table.extent)
+ elif (self.table.rowCount is not None and self.table.rowCount > 0) or (
+ self.table.estimatedRowCount is not None
+ and self.table.estimatedRowCount > 0
+ ):
# Can't calculate an extent on empty layer
extent_str = QApplication.translate(
"DBManagerPlugin",
- '(unknown) (find out )')
+ '(unknown) (find out )',
+ )
if extent_str:
tbl.append(
- (QApplication.translate(
- "DBManagerPlugin", "Extent:"),
- extent_str))
+ (QApplication.translate("DBManagerPlugin", "Extent:"), extent_str)
+ )
ret.append(HtmlTable(tbl))
# Handle extent update metadata
- if (self.table.extent and
- self.table.extent != self.table.estimatedExtent and
- self.table.canUpdateMetadata()):
+ if (
+ self.table.extent
+ and self.table.extent != self.table.estimatedExtent
+ and self.table.canUpdateMetadata()
+ ):
ret.append(
HtmlParagraph(
QApplication.translate(
"DBManagerPlugin",
- ' Metadata extent is different from'
+ " Metadata extent is different from"
' real extent. You should update it !')))
+ '/update">update it!',
+ )
+ )
+ )
# is there an entry in geometry_columns?
- if self.table.geomType.lower() == 'geometry':
+ if self.table.geomType.lower() == "geometry":
ret.append(
HtmlParagraph(
QApplication.translate(
"DBManagerPlugin",
- " There is no entry in geometry_columns!")))
+ " There is no entry in geometry_columns!",
+ )
+ )
+ )
# find out whether the geometry column has spatial index on it
if not self.table.isView:
@@ -660,8 +775,11 @@ def spatialInfo(self):
HtmlParagraph(
QApplication.translate(
"DBManagerPlugin",
- ' No spatial index defined ('
- 'create it ).')))
+ "create it).",
+ )
+ )
+ )
return ret
diff --git a/python/plugins/db_manager/db_plugins/oracle/plugin.py b/python/plugins/db_manager/db_plugins/oracle/plugin.py
index 2c19063065ca..d3de0e4c70fe 100644
--- a/python/plugins/db_manager/db_plugins/oracle/plugin.py
+++ b/python/plugins/db_manager/db_plugins/oracle/plugin.py
@@ -22,10 +22,7 @@
"""
# this will disable the dbplugin if the connector raise an ImportError
-from typing import (
- Optional,
- Union
-)
+from typing import Optional, Union
from .connector import OracleDBConnector
@@ -35,9 +32,19 @@
from qgis.core import QgsApplication, QgsVectorLayer, NULL, QgsSettings
-from ..plugin import ConnectionError, InvalidDataException, DBPlugin, \
- Database, Schema, Table, VectorTable, TableField, TableConstraint, \
- TableIndex, TableTrigger
+from ..plugin import (
+ ConnectionError,
+ InvalidDataException,
+ DBPlugin,
+ Database,
+ Schema,
+ Table,
+ VectorTable,
+ TableField,
+ TableConstraint,
+ TableIndex,
+ TableTrigger,
+)
from qgis.core import QgsCredentials
@@ -54,19 +61,19 @@ def icon(self):
@classmethod
def typeName(self):
- return 'oracle'
+ return "oracle"
@classmethod
def typeNameString(self):
- return QCoreApplication.translate('db_manager', 'Oracle Spatial')
+ return QCoreApplication.translate("db_manager", "Oracle Spatial")
@classmethod
def providerName(self):
- return 'oracle'
+ return "oracle"
@classmethod
def connectionSettingsKey(self):
- return '/Oracle/connections'
+ return "/Oracle/connections"
def connectToUri(self, uri):
self.db = self.databasesFactory(self, uri)
@@ -80,35 +87,44 @@ def databasesFactory(self, connection, uri):
def connect(self, parent=None):
conn_name = self.connectionName()
settings = QgsSettings()
- settings.beginGroup("/{}/{}".format(
- self.connectionSettingsKey(), conn_name))
+ settings.beginGroup(f"/{self.connectionSettingsKey()}/{conn_name}")
if not settings.contains("database"): # non-existent entry?
raise InvalidDataException(
- self.tr('There is no defined database connection "{}".'.format(
- conn_name)))
+ self.tr(f'There is no defined database connection "{conn_name}".')
+ )
from qgis.core import QgsDataSourceUri
+
uri = QgsDataSourceUri()
settingsList = ["host", "port", "database", "username", "password"]
host, port, database, username, password = (
- settings.value(x, "", type=str) for x in settingsList)
+ settings.value(x, "", type=str) for x in settingsList
+ )
# get all of the connection options
- useEstimatedMetadata = settings.value(
- "estimatedMetadata", False, type=bool)
- uri.setParam('userTablesOnly', str(
- settings.value("userTablesOnly", False, type=bool)))
- uri.setParam('geometryColumnsOnly', str(
- settings.value("geometryColumnsOnly", False, type=bool)))
- uri.setParam('allowGeometrylessTables', str(
- settings.value("allowGeometrylessTables", False, type=bool)))
- uri.setParam('onlyExistingTypes', str(
- settings.value("onlyExistingTypes", False, type=bool)))
- uri.setParam('includeGeoAttributes', str(
- settings.value("includeGeoAttributes", False, type=bool)))
+ useEstimatedMetadata = settings.value("estimatedMetadata", False, type=bool)
+ uri.setParam(
+ "userTablesOnly", str(settings.value("userTablesOnly", False, type=bool))
+ )
+ uri.setParam(
+ "geometryColumnsOnly",
+ str(settings.value("geometryColumnsOnly", False, type=bool)),
+ )
+ uri.setParam(
+ "allowGeometrylessTables",
+ str(settings.value("allowGeometrylessTables", False, type=bool)),
+ )
+ uri.setParam(
+ "onlyExistingTypes",
+ str(settings.value("onlyExistingTypes", False, type=bool)),
+ )
+ uri.setParam(
+ "includeGeoAttributes",
+ str(settings.value("includeGeoAttributes", False, type=bool)),
+ )
settings.endGroup()
@@ -126,7 +142,8 @@ def connect(self, parent=None):
max_attempts = 3
for i in range(max_attempts):
(ok, username, password) = QgsCredentials.instance().get(
- uri.connectionInfo(False), username, password, err)
+ uri.connectionInfo(False), username, password, err
+ )
if not ok:
return False
@@ -141,8 +158,7 @@ def connect(self, parent=None):
err = str(e)
continue
- QgsCredentials.instance().put(
- uri.connectionInfo(False), username, password)
+ QgsCredentials.instance().put(uri.connectionInfo(False), username, password)
return True
@@ -166,6 +182,7 @@ def vectorTablesFactory(self, row, db, schema=None):
def info(self):
from .info_model import ORDatabaseInfo
+
return ORDatabaseInfo(self)
def schemasFactory(self, row, db):
@@ -174,7 +191,7 @@ def schemasFactory(self, row, db):
def columnUniqueValuesModel(self, col, table, limit=10):
l = ""
if limit:
- l = "WHERE ROWNUM < {:d}".format(limit)
+ l = f"WHERE ROWNUM < {limit:d}"
con = self.database().connector
# Prevent geometry column show
tableName = table.replace('"', "").split(".")
@@ -185,11 +202,12 @@ def columnUniqueValuesModel(self, col, table, limit=10):
if con.isGeometryColumn(tableName, colName):
return None
- query = "SELECT DISTINCT {} FROM {} {}".format(col, table, l)
+ query = f"SELECT DISTINCT {col} FROM {table} {l}"
return self.sqlResultModel(query, self)
def sqlResultModel(self, sql, parent):
from .data_model import ORSqlResultModel
+
return ORSqlResultModel(self, sql, parent)
def sqlResultModelAsync(self, sql, parent):
@@ -197,9 +215,16 @@ def sqlResultModelAsync(self, sql, parent):
return ORSqlResultModelAsync(self, sql, parent)
- def toSqlLayer(self, sql, geomCol, uniqueCol,
- layerName="QueryLayer", layerType=None,
- avoidSelectById=False, filter=""):
+ def toSqlLayer(
+ self,
+ sql,
+ geomCol,
+ uniqueCol,
+ layerName="QueryLayer",
+ layerType=None,
+ avoidSelectById=False,
+ filter="",
+ ):
uri = self.uri()
con = self.database().connector
@@ -207,8 +232,7 @@ def toSqlLayer(self, sql, geomCol, uniqueCol,
if uniqueCol is not None:
uniqueCol = uniqueCol.strip('"').replace('""', '"')
- uri.setDataSource("", "({}\n)".format(
- sql), geomCol, filter, uniqueCol)
+ uri.setDataSource("", f"({sql}\n)", geomCol, filter, uniqueCol)
if avoidSelectById:
uri.disableSelectAtId(True)
@@ -218,8 +242,7 @@ def toSqlLayer(self, sql, geomCol, uniqueCol,
# handling undetermined geometry type
if not vlayer.isValid():
- wkbType, srid = con.getTableMainGeomType(
- "({}\n)".format(sql), geomCol)
+ wkbType, srid = con.getTableMainGeomType(f"({sql}\n)", geomCol)
uri.setWkbType(wkbType)
if srid:
uri.setSrid(str(srid))
@@ -228,45 +251,76 @@ def toSqlLayer(self, sql, geomCol, uniqueCol,
return vlayer
def registerDatabaseActions(self, mainWindow):
- action = QAction(QApplication.translate(
- "DBManagerPlugin", "&Re-connect"), self)
- mainWindow.registerAction(action, QApplication.translate(
- "DBManagerPlugin", "&Database"), self.reconnectActionSlot)
+ action = QAction(QApplication.translate("DBManagerPlugin", "&Re-connect"), self)
+ mainWindow.registerAction(
+ action,
+ QApplication.translate("DBManagerPlugin", "&Database"),
+ self.reconnectActionSlot,
+ )
if self.schemas():
- action = QAction(QApplication.translate(
- "DBManagerPlugin", "&Create Schema…"), self)
- mainWindow.registerAction(action, QApplication.translate(
- "DBManagerPlugin", "&Schema"), self.createSchemaActionSlot)
- action = QAction(QApplication.translate(
- "DBManagerPlugin", "&Delete (Empty) Schema…"), self)
- mainWindow.registerAction(action, QApplication.translate(
- "DBManagerPlugin", "&Schema"), self.deleteSchemaActionSlot)
-
- action = QAction(QApplication.translate(
- "DBManagerPlugin", "Delete Selected Item"), self)
+ action = QAction(
+ QApplication.translate("DBManagerPlugin", "&Create Schema…"), self
+ )
+ mainWindow.registerAction(
+ action,
+ QApplication.translate("DBManagerPlugin", "&Schema"),
+ self.createSchemaActionSlot,
+ )
+ action = QAction(
+ QApplication.translate("DBManagerPlugin", "&Delete (Empty) Schema…"),
+ self,
+ )
+ mainWindow.registerAction(
+ action,
+ QApplication.translate("DBManagerPlugin", "&Schema"),
+ self.deleteSchemaActionSlot,
+ )
+
+ action = QAction(
+ QApplication.translate("DBManagerPlugin", "Delete Selected Item"), self
+ )
mainWindow.registerAction(action, None, self.deleteActionSlot)
action.setShortcuts(QKeySequence.StandardKey.Delete)
- action = QAction(QgsApplication.getThemeIcon("/mActionCreateTable.svg"),
- QApplication.translate(
- "DBManagerPlugin", "&Create Table…"), self)
- mainWindow.registerAction(action, QApplication.translate(
- "DBManagerPlugin", "&Table"), self.createTableActionSlot)
- action = QAction(QgsApplication.getThemeIcon("/mActionEditTable.svg"),
- QApplication.translate(
- "DBManagerPlugin", "&Edit Table…"), self)
- mainWindow.registerAction(action, QApplication.translate(
- "DBManagerPlugin", "&Table"), self.editTableActionSlot)
- action = QAction(QgsApplication.getThemeIcon("/mActionDeleteTable.svg"),
- QApplication.translate(
- "DBManagerPlugin", "&Delete Table/View…"), self)
- mainWindow.registerAction(action, QApplication.translate(
- "DBManagerPlugin", "&Table"), self.deleteTableActionSlot)
- action = QAction(QApplication.translate(
- "DBManagerPlugin", "&Empty Table…"), self)
- mainWindow.registerAction(action, QApplication.translate(
- "DBManagerPlugin", "&Table"), self.emptyTableActionSlot)
+ action = QAction(
+ QgsApplication.getThemeIcon("/mActionCreateTable.svg"),
+ QApplication.translate("DBManagerPlugin", "&Create Table…"),
+ self,
+ )
+ mainWindow.registerAction(
+ action,
+ QApplication.translate("DBManagerPlugin", "&Table"),
+ self.createTableActionSlot,
+ )
+ action = QAction(
+ QgsApplication.getThemeIcon("/mActionEditTable.svg"),
+ QApplication.translate("DBManagerPlugin", "&Edit Table…"),
+ self,
+ )
+ mainWindow.registerAction(
+ action,
+ QApplication.translate("DBManagerPlugin", "&Table"),
+ self.editTableActionSlot,
+ )
+ action = QAction(
+ QgsApplication.getThemeIcon("/mActionDeleteTable.svg"),
+ QApplication.translate("DBManagerPlugin", "&Delete Table/View…"),
+ self,
+ )
+ mainWindow.registerAction(
+ action,
+ QApplication.translate("DBManagerPlugin", "&Table"),
+ self.deleteTableActionSlot,
+ )
+ action = QAction(
+ QApplication.translate("DBManagerPlugin", "&Empty Table…"), self
+ )
+ mainWindow.registerAction(
+ action,
+ QApplication.translate("DBManagerPlugin", "&Table"),
+ self.emptyTableActionSlot,
+ )
def supportsComment(self):
return False
@@ -298,36 +352,40 @@ def __init__(self, row, db, schema=None):
def getDates(self):
"""Grab the creation/modification dates of the table"""
self.creationDate, self.modificationDate = (
- self.database().connector.getTableDates((self.schemaName(),
- self.name)))
+ self.database().connector.getTableDates((self.schemaName(), self.name))
+ )
def refreshRowEstimation(self):
"""Use ALL_ALL_TABLE to get an estimation of rows"""
if self.isView:
self.estimatedRowCount = 0
- self.estimatedRowCount = (
- self.database().connector.getTableRowEstimation(
- (self.schemaName(), self.name)))
+ self.estimatedRowCount = self.database().connector.getTableRowEstimation(
+ (self.schemaName(), self.name)
+ )
def getType(self):
"""Grab the type of object for the table"""
self.objectType = self.database().connector.getTableType(
- (self.schemaName(), self.name))
+ (self.schemaName(), self.name)
+ )
def getComment(self):
"""Grab the general comment of the table/view"""
self.comment = self.database().connector.getTableComment(
- (self.schemaName(), self.name), self.objectType)
+ (self.schemaName(), self.name), self.objectType
+ )
def getDefinition(self):
return self.database().connector.getDefinition(
- (self.schemaName(), self.name), self.objectType)
+ (self.schemaName(), self.name), self.objectType
+ )
def getMViewInfo(self):
if self.objectType == "MATERIALIZED VIEW":
return self.database().connector.getMViewInfo(
- (self.schemaName(), self.name))
+ (self.schemaName(), self.name)
+ )
else:
return None
@@ -339,22 +397,25 @@ def runAction(self, action):
self.refreshRowCount()
return True
elif action.startswith("index/"):
- parts = action.split('/')
+ parts = action.split("/")
index_name = parts[1]
index_action = parts[2]
msg = QApplication.translate(
"DBManagerPlugin",
- "Do you want to {} index {}?".format(
- index_action, index_name))
+ f"Do you want to {index_action} index {index_name}?",
+ )
QApplication.restoreOverrideCursor()
try:
- if QMessageBox.question(
+ if (
+ QMessageBox.question(
None,
- QApplication.translate(
- "DBManagerPlugin", "Table Index"),
+ QApplication.translate("DBManagerPlugin", "Table Index"),
msg,
- QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No) == QMessageBox.StandardButton.No:
+ QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No,
+ )
+ == QMessageBox.StandardButton.No
+ ):
return False
finally:
QApplication.setOverrideCursor(Qt.CursorShape.WaitCursor)
@@ -362,14 +423,14 @@ def runAction(self, action):
if index_action == "rebuild":
self.aboutToChange.emit()
self.database().connector.rebuildTableIndex(
- (self.schemaName(), self.name), index_name)
+ (self.schemaName(), self.name), index_name
+ )
self.refreshIndexes()
return True
elif action.startswith("mview/"):
if action == "mview/refresh":
self.aboutToChange.emit()
- self.database().connector.refreshMView(
- (self.schemaName(), self.name))
+ self.database().connector.refreshMView((self.schemaName(), self.name))
return True
return Table.runAction(self, action)
@@ -388,14 +449,16 @@ def tableTriggersFactory(self, row, table):
def info(self):
from .info_model import ORTableInfo
+
return ORTableInfo(self)
def tableDataModel(self, parent):
from .data_model import ORTableDataModel
+
return ORTableDataModel(self, parent)
def getValidQgisUniqueFields(self, onlyOne=False):
- """ list of fields valid to load the table as layer in QGIS canvas.
+ """list of fields valid to load the table as layer in QGIS canvas.
QGIS automatically search for a valid unique field, so it's
needed only for queries and views.
"""
@@ -413,12 +476,22 @@ def getValidQgisUniqueFields(self, onlyOne=False):
for idx in indexes:
if idx.isUnique and len(idx.columns) == 1:
fld = idx.fields()[idx.columns[0]]
- if (fld.dataType == "NUMBER" and not fld.modifier and fld.notNull and fld not in ret):
+ if (
+ fld.dataType == "NUMBER"
+ and not fld.modifier
+ and fld.notNull
+ and fld not in ret
+ ):
ret.append(fld)
# and finally append the other suitable fields
for fld in self.fields():
- if (fld.dataType == "NUMBER" and not fld.modifier and fld.notNull and fld not in ret):
+ if (
+ fld.dataType == "NUMBER"
+ and not fld.modifier
+ and fld.notNull
+ and fld not in ret
+ ):
ret.append(fld)
if onlyOne:
@@ -427,13 +500,18 @@ def getValidQgisUniqueFields(self, onlyOne=False):
def uri(self):
uri = self.database().uri()
- schema = self.schemaName() if self.schemaName() else ''
- geomCol = self.geomColumn if self.type in [
- Table.VectorType, Table.RasterType] else ""
- uniqueCol = self.getValidQgisUniqueFields(
- True) if self.isView else None
- uri.setDataSource(schema, self.name, geomCol if geomCol else None,
- None, uniqueCol.name if uniqueCol else "")
+ schema = self.schemaName() if self.schemaName() else ""
+ geomCol = (
+ self.geomColumn if self.type in [Table.VectorType, Table.RasterType] else ""
+ )
+ uniqueCol = self.getValidQgisUniqueFields(True) if self.isView else None
+ uri.setDataSource(
+ schema,
+ self.name,
+ geomCol if geomCol else None,
+ None,
+ uniqueCol.name if uniqueCol else "",
+ )
# Handle geographic table
if geomCol:
@@ -448,11 +526,13 @@ class ORVectorTable(ORTable, VectorTable):
def __init__(self, row, db, schema=None):
ORTable.__init__(self, row[0:3], db, schema)
VectorTable.__init__(self, db, schema)
- self.geomColumn, self.geomType, self.wkbType, self.geomDim, \
- self.srid = row[-7:-2]
+ self.geomColumn, self.geomType, self.wkbType, self.geomDim, self.srid = row[
+ -7:-2
+ ]
def info(self):
from .info_model import ORVectorTableInfo
+
return ORVectorTableInfo(self)
def runAction(self, action):
@@ -468,13 +548,14 @@ def runAction(self, action):
return VectorTable.runAction(self, action)
def canUpdateMetadata(self):
- return self.database().connector.canUpdateMetadata((self.schemaName(),
- self.name))
+ return self.database().connector.canUpdateMetadata(
+ (self.schemaName(), self.name)
+ )
def updateExtent(self):
self.database().connector.updateMetadata(
- (self.schemaName(), self.name),
- self.geomColumn, extent=self.extent)
+ (self.schemaName(), self.name), self.geomColumn, extent=self.extent
+ )
self.refreshTableEstimatedExtent()
self.refresh()
@@ -490,11 +571,20 @@ def hasSpatialIndex(self, geom_column=None):
class ORTableField(TableField):
def __init__(self, row, table):
- """ build fields information from query and find primary key """
+ """build fields information from query and find primary key"""
TableField.__init__(self, table)
- self.num, self.name, self.dataType, self.charMaxLen, \
- self.modifier, self.notNull, self.hasDefault, \
- self.default, typeStr, self.comment = row
+ (
+ self.num,
+ self.name,
+ self.dataType,
+ self.charMaxLen,
+ self.modifier,
+ self.notNull,
+ self.hasDefault,
+ self.default,
+ typeStr,
+ self.comment,
+ ) = row
self.primaryKey = False
self.num = int(self.num)
@@ -523,18 +613,23 @@ def __init__(self, row, table):
break
def type2String(self):
- if ("TIMESTAMP" in self.dataType or self.dataType in ["DATE", "SDO_GEOMETRY", "BINARY_FLOAT", "BINARY_DOUBLE"]):
- return "{}".format(self.dataType)
+ if "TIMESTAMP" in self.dataType or self.dataType in [
+ "DATE",
+ "SDO_GEOMETRY",
+ "BINARY_FLOAT",
+ "BINARY_DOUBLE",
+ ]:
+ return f"{self.dataType}"
if self.charMaxLen in [None, -1]:
- return "{}".format(self.dataType)
+ return f"{self.dataType}"
elif self.modifier in [None, -1, 0]:
- return "{}({})".format(self.dataType, self.charMaxLen)
+ return f"{self.dataType}({self.charMaxLen})"
- return "{}({},{})".format(self.dataType, self.charMaxLen,
- self.modifier)
+ return f"{self.dataType}({self.charMaxLen},{self.modifier})"
- def update(self, new_name, new_type_str=None, new_not_null=None,
- new_default_str=None):
+ def update(
+ self, new_name, new_type_str=None, new_not_null=None, new_default_str=None
+ ):
self.table().aboutToChange.emit()
if self.name == new_name:
new_name = None
@@ -545,10 +640,18 @@ def update(self, new_name, new_type_str=None, new_not_null=None,
if self.default2String() == new_default_str:
new_default_str = None
- ret = self.table().database().connector.updateTableColumn(
- (self.table().schemaName(), self.table().name),
- self.name, new_name, new_type_str,
- new_not_null, new_default_str)
+ ret = (
+ self.table()
+ .database()
+ .connector.updateTableColumn(
+ (self.table().schemaName(), self.table().name),
+ self.name,
+ new_name,
+ new_type_str,
+ new_not_null,
+ new_default_str,
+ )
+ )
# When changing a field, refresh also constraints and
# indexes.
@@ -560,17 +663,21 @@ def update(self, new_name, new_type_str=None, new_not_null=None,
class ORTableConstraint(TableConstraint):
- TypeCheck, TypeForeignKey, TypePrimaryKey, \
- TypeUnique, TypeUnknown = list(range(5))
+ TypeCheck, TypeForeignKey, TypePrimaryKey, TypeUnique, TypeUnknown = list(range(5))
- types = {"c": TypeCheck, "r": TypeForeignKey,
- "p": TypePrimaryKey, "u": TypeUnique}
+ types = {"c": TypeCheck, "r": TypeForeignKey, "p": TypePrimaryKey, "u": TypeUnique}
def __init__(self, row, table):
- """ build constraints info from query """
+ """build constraints info from query"""
TableConstraint.__init__(self, table)
- self.name, constr_type_str, self.column, self.validated, \
- self.generated, self.status = row[0:6]
+ (
+ self.name,
+ constr_type_str,
+ self.column,
+ self.validated,
+ self.generated,
+ self.status,
+ ) = row[0:6]
constr_type_str = constr_type_str.lower()
if constr_type_str in ORTableConstraint.types:
@@ -608,10 +715,10 @@ def type2String(self):
if self.type == ORTableConstraint.TypeUnique:
return QApplication.translate("DBManagerPlugin", "Unique")
- return QApplication.translate("DBManagerPlugin", 'Unknown')
+ return QApplication.translate("DBManagerPlugin", "Unknown")
def fields(self):
- """ Hack to make edit dialog box work """
+ """Hack to make edit dialog box work"""
fields = self.table().fields()
field = None
for fld in fields:
@@ -627,11 +734,18 @@ class ORTableIndex(TableIndex):
def __init__(self, row, table):
TableIndex.__init__(self, table)
- self.name, self.column, self.indexType, self.status, \
- self.analyzed, self.compression, self.isUnique = row
+ (
+ self.name,
+ self.column,
+ self.indexType,
+ self.status,
+ self.analyzed,
+ self.compression,
+ self.isUnique,
+ ) = row
def fields(self):
- """ Hack to make edit dialog box work """
+ """Hack to make edit dialog box work"""
self.table().refreshFields()
fields = self.table().fields()
diff --git a/python/plugins/db_manager/db_plugins/oracle/sql_dictionary.py b/python/plugins/db_manager/db_plugins/oracle/sql_dictionary.py
index 46e7e4211d37..4632abe69378 100644
--- a/python/plugins/db_manager/db_plugins/oracle/sql_dictionary.py
+++ b/python/plugins/db_manager/db_plugins/oracle/sql_dictionary.py
@@ -21,91 +21,481 @@
***************************************************************************/
"""
-__author__ = 'Médéric RIBREUX'
-__date__ = 'August 2014'
-__copyright__ = '(C) 2014, Médéric RIBREUX'
+__author__ = "Médéric RIBREUX"
+__date__ = "August 2014"
+__copyright__ = "(C) 2014, Médéric RIBREUX"
# keywords
keywords = [
# From:
# http://docs.oracle.com/cd/B19306_01/server.102/b14200/ap_keywd.htm
- "ACCESS", "ADD", "ALL", "ALTER", "AND", "ANY", "AS", "ASC",
- "AUDIT", "BETWEEN", "BY", "CHAR", "CHECK", "CLUSTER", "COLUMN",
- "COMMENT", "COMPRESS", "CONNECT", "CREATE", "CURRENT", "DATE",
- "DECIMAL", "DEFAULT", "DELETE", "DESC", "DISTINCT", "DROP",
- "ELSE", "EXCLUSIVE", "EXISTS", "FILE", "FLOAT", "FOR", "FROM",
- "GRANT", "GROUP", "HAVING", "IDENTIFIED", "IMMEDIATE", "IN",
- "INCREMENT", "INDEX", "INITIAL", "INSERT", "INTEGER", "INTERSECT",
- "INTO", "IS", "LEVEL", "LIKE", "LOCK", "LONG", "MAXEXTENTS",
- "MINUS", "MLSLABEL", "MODE", "MODIFY", "NOAUDIT", "NOCOMPRESS",
- "NOT", "NOWAIT", "NULL", "NUMBER", "OF", "OFFLINE", "ON",
- "ONLINE", "OPTION", "OR", "ORDER", "PCTFREE", "PRIOR",
- "PRIVILEGES", "PUBLIC", "RAW", "RENAME", "RESOURCE", "REVOKE",
- "ROW", "ROWID", "ROWNUM", "ROWS", "SELECT", "SESSION", "SET",
- "SHARE", "SIZE", "SMALLINT", "START", "SUCCESSFUL", "SYNONYM",
- "SYSDATE", "TABLE", "THEN", "TO", "TRIGGER", "UID", "UNION",
- "UNIQUE", "UPDATE", "USER", "VALIDATE", "VALUES", "VARCHAR",
- "VARCHAR2", "VIEW", "WHENEVER", "WHERE", "WITH",
+ "ACCESS",
+ "ADD",
+ "ALL",
+ "ALTER",
+ "AND",
+ "ANY",
+ "AS",
+ "ASC",
+ "AUDIT",
+ "BETWEEN",
+ "BY",
+ "CHAR",
+ "CHECK",
+ "CLUSTER",
+ "COLUMN",
+ "COMMENT",
+ "COMPRESS",
+ "CONNECT",
+ "CREATE",
+ "CURRENT",
+ "DATE",
+ "DECIMAL",
+ "DEFAULT",
+ "DELETE",
+ "DESC",
+ "DISTINCT",
+ "DROP",
+ "ELSE",
+ "EXCLUSIVE",
+ "EXISTS",
+ "FILE",
+ "FLOAT",
+ "FOR",
+ "FROM",
+ "GRANT",
+ "GROUP",
+ "HAVING",
+ "IDENTIFIED",
+ "IMMEDIATE",
+ "IN",
+ "INCREMENT",
+ "INDEX",
+ "INITIAL",
+ "INSERT",
+ "INTEGER",
+ "INTERSECT",
+ "INTO",
+ "IS",
+ "LEVEL",
+ "LIKE",
+ "LOCK",
+ "LONG",
+ "MAXEXTENTS",
+ "MINUS",
+ "MLSLABEL",
+ "MODE",
+ "MODIFY",
+ "NOAUDIT",
+ "NOCOMPRESS",
+ "NOT",
+ "NOWAIT",
+ "NULL",
+ "NUMBER",
+ "OF",
+ "OFFLINE",
+ "ON",
+ "ONLINE",
+ "OPTION",
+ "OR",
+ "ORDER",
+ "PCTFREE",
+ "PRIOR",
+ "PRIVILEGES",
+ "PUBLIC",
+ "RAW",
+ "RENAME",
+ "RESOURCE",
+ "REVOKE",
+ "ROW",
+ "ROWID",
+ "ROWNUM",
+ "ROWS",
+ "SELECT",
+ "SESSION",
+ "SET",
+ "SHARE",
+ "SIZE",
+ "SMALLINT",
+ "START",
+ "SUCCESSFUL",
+ "SYNONYM",
+ "SYSDATE",
+ "TABLE",
+ "THEN",
+ "TO",
+ "TRIGGER",
+ "UID",
+ "UNION",
+ "UNIQUE",
+ "UPDATE",
+ "USER",
+ "VALIDATE",
+ "VALUES",
+ "VARCHAR",
+ "VARCHAR2",
+ "VIEW",
+ "WHENEVER",
+ "WHERE",
+ "WITH",
# From http://docs.oracle.com/cd/B13789_01/appdev.101/a42525/apb.htm
- "ADMIN", "CURSOR", "FOUND", "MOUNT", "AFTER", "CYCLE", "FUNCTION",
- "NEXT", "ALLOCATE", "DATABASE", "GO", "NEW", "ANALYZE",
- "DATAFILE", "GOTO", "NOARCHIVELOG", "ARCHIVE", "DBA", "GROUPS",
- "NOCACHE", "ARCHIVELOG", "DEC", "INCLUDING", "NOCYCLE",
- "AUTHORIZATION", "DECLARE", "INDICATOR", "NOMAXVALUE", "AVG",
- "DISABLE", "INITRANS", "NOMINVALUE", "BACKUP", "DISMOUNT",
- "INSTANCE", "NONE", "BEGIN", "DOUBLE", "INT", "NOORDER", "BECOME",
- "DUMP", "KEY", "NORESETLOGS", "BEFORE", "EACH", "LANGUAGE",
- "NORMAL", "BLOCK", "ENABLE", "LAYER", "NOSORT", "BODY", "END",
- "LINK", "NUMERIC", "CACHE", "ESCAPE", "LISTS", "OFF", "CANCEL",
- "EVENTS", "LOGFILE", "OLD", "CASCADE", "EXCEPT", "MANAGE", "ONLY",
- "CHANGE", "EXCEPTIONS", "MANUAL", "OPEN", "CHARACTER", "EXEC",
- "MAX", "OPTIMAL", "CHECKPOINT", "EXPLAIN", "MAXDATAFILES", "OWN",
- "CLOSE", "EXECUTE", "MAXINSTANCES", "PACKAGE", "COBOL", "EXTENT",
- "MAXLOGFILES", "PARALLEL", "COMMIT", "EXTERNALLY",
- "MAXLOGHISTORY", "PCTINCREASE", "COMPILE", "FETCH",
- "MAXLOGMEMBERS", "PCTUSED", "CONSTRAINT", "FLUSH", "MAXTRANS",
- "PLAN", "CONSTRAINTS", "FREELIST", "MAXVALUE", "PLI", "CONTENTS",
- "FREELISTS", "MIN", "PRECISION", "CONTINUE", "FORCE",
- "MINEXTENTS", "PRIMARY", "CONTROLFILE", "FOREIGN", "MINVALUE",
- "PRIVATE", "COUNT", "FORTRAN", "MODULE", "PROCEDURE", "PROFILE",
- "SAVEPOINT", "SQLSTATE", "TRACING", "QUOTA", "SCHEMA",
- "STATEMENT_ID", "TRANSACTION", "READ", "SCN", "STATISTICS",
- "TRIGGERS", "REAL", "SECTION", "STOP", "TRUNCATE", "RECOVER",
- "SEGMENT", "STORAGE", "UNDER", "REFERENCES", "SEQUENCE", "SUM",
- "UNLIMITED", "REFERENCING", "SHARED", "SWITCH", "UNTIL",
- "RESETLOGS", "SNAPSHOT", "SYSTEM", "USE", "RESTRICTED", "SOME",
- "TABLES", "USING", "REUSE", "SORT", "TABLESPACE", "WHEN", "ROLE",
- "SQL", "TEMPORARY", "WRITE", "ROLES", "SQLCODE", "THREAD", "WORK",
- "ROLLBACK", "SQLERROR", "TIME", "ABORT", "BETWEEN", "CRASH",
- "DIGITS", "ACCEPT", "BINARY_INTEGER", "CREATE", "DISPOSE",
- "ACCESS", "BODY", "CURRENT", "DISTINCT", "ADD", "BOOLEAN",
- "CURRVAL", "DO", "ALL", "BY", "CURSOR", "DROP", "ALTER", "CASE",
- "DATABASE", "ELSE", "AND", "CHAR", "DATA_BASE", "ELSIF", "ANY",
- "CHAR_BASE", "DATE", "END", "ARRAY", "CHECK", "DBA", "ENTRY",
- "ARRAYLEN", "CLOSE", "DEBUGOFF", "EXCEPTION", "AS", "CLUSTER",
- "DEBUGON", "EXCEPTION_INIT", "ASC", "CLUSTERS", "DECLARE",
- "EXISTS", "ASSERT", "COLAUTH", "DECIMAL", "EXIT", "ASSIGN",
- "COLUMNS", "DEFAULT", "FALSE", "AT", "COMMIT", "DEFINITION",
- "FETCH", "AUTHORIZATION", "COMPRESS", "DELAY", "FLOAT", "AVG",
- "CONNECT", "DELETE", "FOR", "BASE_TABLE", "CONSTANT", "DELTA",
- "FORM", "BEGIN", "COUNT", "DESC", "FROM", "FUNCTION", "NEW",
- "RELEASE", "SUM", "GENERIC", "NEXTVAL", "REMR", "TABAUTH", "GOTO",
- "NOCOMPRESS", "RENAME", "TABLE", "GRANT", "NOT", "RESOURCE",
- "TABLES", "GROUP", "NULL", "RETURN", "TASK", "HAVING", "NUMBER",
- "REVERSE", "TERMINATE", "IDENTIFIED", "NUMBER_BASE", "REVOKE",
- "THEN", "IF", "OF", "ROLLBACK", "TO", "IN", "ON", "ROWID", "TRUE",
- "INDEX", "OPEN", "ROWLABEL", "TYPE", "INDEXES", "OPTION",
- "ROWNUM", "UNION", "INDICATOR", "OR", "ROWTYPE", "UNIQUE",
- "INSERT", "ORDER", "RUN", "UPDATE", "INTEGER", "OTHERS",
- "SAVEPOINT", "USE", "INTERSECT", "OUT", "SCHEMA", "VALUES",
- "INTO", "PACKAGE", "SELECT", "VARCHAR", "IS", "PARTITION",
- "SEPARATE", "VARCHAR2", "LEVEL", "PCTFREE", "SET", "VARIANCE",
- "LIKE", "POSITIVE", "SIZE", "VIEW", "LIMITED", "PRAGMA",
- "SMALLINT", "VIEWS", "LOOP", "PRIOR", "SPACE", "WHEN", "MAX",
- "PRIVATE", "SQL", "WHERE", "MIN", "PROCEDURE", "SQLCODE", "WHILE",
- "MINUS", "PUBLIC", "SQLERRM", "WITH", "MLSLABEL", "RAISE",
- "START", "WORK", "MOD", "RANGE", "STATEMENT", "XOR", "MODE",
- "REAL", "STDDEV", "NATURAL", "RECORD", "SUBTYPE"
+ "ADMIN",
+ "CURSOR",
+ "FOUND",
+ "MOUNT",
+ "AFTER",
+ "CYCLE",
+ "FUNCTION",
+ "NEXT",
+ "ALLOCATE",
+ "DATABASE",
+ "GO",
+ "NEW",
+ "ANALYZE",
+ "DATAFILE",
+ "GOTO",
+ "NOARCHIVELOG",
+ "ARCHIVE",
+ "DBA",
+ "GROUPS",
+ "NOCACHE",
+ "ARCHIVELOG",
+ "DEC",
+ "INCLUDING",
+ "NOCYCLE",
+ "AUTHORIZATION",
+ "DECLARE",
+ "INDICATOR",
+ "NOMAXVALUE",
+ "AVG",
+ "DISABLE",
+ "INITRANS",
+ "NOMINVALUE",
+ "BACKUP",
+ "DISMOUNT",
+ "INSTANCE",
+ "NONE",
+ "BEGIN",
+ "DOUBLE",
+ "INT",
+ "NOORDER",
+ "BECOME",
+ "DUMP",
+ "KEY",
+ "NORESETLOGS",
+ "BEFORE",
+ "EACH",
+ "LANGUAGE",
+ "NORMAL",
+ "BLOCK",
+ "ENABLE",
+ "LAYER",
+ "NOSORT",
+ "BODY",
+ "END",
+ "LINK",
+ "NUMERIC",
+ "CACHE",
+ "ESCAPE",
+ "LISTS",
+ "OFF",
+ "CANCEL",
+ "EVENTS",
+ "LOGFILE",
+ "OLD",
+ "CASCADE",
+ "EXCEPT",
+ "MANAGE",
+ "ONLY",
+ "CHANGE",
+ "EXCEPTIONS",
+ "MANUAL",
+ "OPEN",
+ "CHARACTER",
+ "EXEC",
+ "MAX",
+ "OPTIMAL",
+ "CHECKPOINT",
+ "EXPLAIN",
+ "MAXDATAFILES",
+ "OWN",
+ "CLOSE",
+ "EXECUTE",
+ "MAXINSTANCES",
+ "PACKAGE",
+ "COBOL",
+ "EXTENT",
+ "MAXLOGFILES",
+ "PARALLEL",
+ "COMMIT",
+ "EXTERNALLY",
+ "MAXLOGHISTORY",
+ "PCTINCREASE",
+ "COMPILE",
+ "FETCH",
+ "MAXLOGMEMBERS",
+ "PCTUSED",
+ "CONSTRAINT",
+ "FLUSH",
+ "MAXTRANS",
+ "PLAN",
+ "CONSTRAINTS",
+ "FREELIST",
+ "MAXVALUE",
+ "PLI",
+ "CONTENTS",
+ "FREELISTS",
+ "MIN",
+ "PRECISION",
+ "CONTINUE",
+ "FORCE",
+ "MINEXTENTS",
+ "PRIMARY",
+ "CONTROLFILE",
+ "FOREIGN",
+ "MINVALUE",
+ "PRIVATE",
+ "COUNT",
+ "FORTRAN",
+ "MODULE",
+ "PROCEDURE",
+ "PROFILE",
+ "SAVEPOINT",
+ "SQLSTATE",
+ "TRACING",
+ "QUOTA",
+ "SCHEMA",
+ "STATEMENT_ID",
+ "TRANSACTION",
+ "READ",
+ "SCN",
+ "STATISTICS",
+ "TRIGGERS",
+ "REAL",
+ "SECTION",
+ "STOP",
+ "TRUNCATE",
+ "RECOVER",
+ "SEGMENT",
+ "STORAGE",
+ "UNDER",
+ "REFERENCES",
+ "SEQUENCE",
+ "SUM",
+ "UNLIMITED",
+ "REFERENCING",
+ "SHARED",
+ "SWITCH",
+ "UNTIL",
+ "RESETLOGS",
+ "SNAPSHOT",
+ "SYSTEM",
+ "USE",
+ "RESTRICTED",
+ "SOME",
+ "TABLES",
+ "USING",
+ "REUSE",
+ "SORT",
+ "TABLESPACE",
+ "WHEN",
+ "ROLE",
+ "SQL",
+ "TEMPORARY",
+ "WRITE",
+ "ROLES",
+ "SQLCODE",
+ "THREAD",
+ "WORK",
+ "ROLLBACK",
+ "SQLERROR",
+ "TIME",
+ "ABORT",
+ "BETWEEN",
+ "CRASH",
+ "DIGITS",
+ "ACCEPT",
+ "BINARY_INTEGER",
+ "CREATE",
+ "DISPOSE",
+ "ACCESS",
+ "BODY",
+ "CURRENT",
+ "DISTINCT",
+ "ADD",
+ "BOOLEAN",
+ "CURRVAL",
+ "DO",
+ "ALL",
+ "BY",
+ "CURSOR",
+ "DROP",
+ "ALTER",
+ "CASE",
+ "DATABASE",
+ "ELSE",
+ "AND",
+ "CHAR",
+ "DATA_BASE",
+ "ELSIF",
+ "ANY",
+ "CHAR_BASE",
+ "DATE",
+ "END",
+ "ARRAY",
+ "CHECK",
+ "DBA",
+ "ENTRY",
+ "ARRAYLEN",
+ "CLOSE",
+ "DEBUGOFF",
+ "EXCEPTION",
+ "AS",
+ "CLUSTER",
+ "DEBUGON",
+ "EXCEPTION_INIT",
+ "ASC",
+ "CLUSTERS",
+ "DECLARE",
+ "EXISTS",
+ "ASSERT",
+ "COLAUTH",
+ "DECIMAL",
+ "EXIT",
+ "ASSIGN",
+ "COLUMNS",
+ "DEFAULT",
+ "FALSE",
+ "AT",
+ "COMMIT",
+ "DEFINITION",
+ "FETCH",
+ "AUTHORIZATION",
+ "COMPRESS",
+ "DELAY",
+ "FLOAT",
+ "AVG",
+ "CONNECT",
+ "DELETE",
+ "FOR",
+ "BASE_TABLE",
+ "CONSTANT",
+ "DELTA",
+ "FORM",
+ "BEGIN",
+ "COUNT",
+ "DESC",
+ "FROM",
+ "FUNCTION",
+ "NEW",
+ "RELEASE",
+ "SUM",
+ "GENERIC",
+ "NEXTVAL",
+ "REMR",
+ "TABAUTH",
+ "GOTO",
+ "NOCOMPRESS",
+ "RENAME",
+ "TABLE",
+ "GRANT",
+ "NOT",
+ "RESOURCE",
+ "TABLES",
+ "GROUP",
+ "NULL",
+ "RETURN",
+ "TASK",
+ "HAVING",
+ "NUMBER",
+ "REVERSE",
+ "TERMINATE",
+ "IDENTIFIED",
+ "NUMBER_BASE",
+ "REVOKE",
+ "THEN",
+ "IF",
+ "OF",
+ "ROLLBACK",
+ "TO",
+ "IN",
+ "ON",
+ "ROWID",
+ "TRUE",
+ "INDEX",
+ "OPEN",
+ "ROWLABEL",
+ "TYPE",
+ "INDEXES",
+ "OPTION",
+ "ROWNUM",
+ "UNION",
+ "INDICATOR",
+ "OR",
+ "ROWTYPE",
+ "UNIQUE",
+ "INSERT",
+ "ORDER",
+ "RUN",
+ "UPDATE",
+ "INTEGER",
+ "OTHERS",
+ "SAVEPOINT",
+ "USE",
+ "INTERSECT",
+ "OUT",
+ "SCHEMA",
+ "VALUES",
+ "INTO",
+ "PACKAGE",
+ "SELECT",
+ "VARCHAR",
+ "IS",
+ "PARTITION",
+ "SEPARATE",
+ "VARCHAR2",
+ "LEVEL",
+ "PCTFREE",
+ "SET",
+ "VARIANCE",
+ "LIKE",
+ "POSITIVE",
+ "SIZE",
+ "VIEW",
+ "LIMITED",
+ "PRAGMA",
+ "SMALLINT",
+ "VIEWS",
+ "LOOP",
+ "PRIOR",
+ "SPACE",
+ "WHEN",
+ "MAX",
+ "PRIVATE",
+ "SQL",
+ "WHERE",
+ "MIN",
+ "PROCEDURE",
+ "SQLCODE",
+ "WHILE",
+ "MINUS",
+ "PUBLIC",
+ "SQLERRM",
+ "WITH",
+ "MLSLABEL",
+ "RAISE",
+ "START",
+ "WORK",
+ "MOD",
+ "RANGE",
+ "STATEMENT",
+ "XOR",
+ "MODE",
+ "REAL",
+ "STDDEV",
+ "NATURAL",
+ "RECORD",
+ "SUBTYPE",
]
oracle_spatial_keywords = []
@@ -115,154 +505,332 @@
functions = [
# FROM
# https://docs.oracle.com/cd/B19306_01/server.102/b14200/functions001.htm
- "CAST", "COALESCE", "DECODE", "GREATEST", "LEAST", "LNNVL",
- "NULLIF", "NVL", "NVL2", "SET", "UID", "USER", "USERENV"
+ "CAST",
+ "COALESCE",
+ "DECODE",
+ "GREATEST",
+ "LEAST",
+ "LNNVL",
+ "NULLIF",
+ "NVL",
+ "NVL2",
+ "SET",
+ "UID",
+ "USER",
+ "USERENV",
]
# SQL math functions
math_functions = [
- 'ABS', 'ACOS', 'ASIN', 'ATAN', 'ATAN2', 'BITAND', 'CEIL', 'COS',
- 'COSH', 'EXP', 'FLOOR', 'LN', 'LOG', 'MOD', 'NANVL', 'POWER',
- 'REMAINDER', 'ROUND', 'SIGN', 'SIN', 'SINH', 'SQRT', 'TAN',
- 'TANH', 'TRUNC', 'WIDTH_BUCKET'
+ "ABS",
+ "ACOS",
+ "ASIN",
+ "ATAN",
+ "ATAN2",
+ "BITAND",
+ "CEIL",
+ "COS",
+ "COSH",
+ "EXP",
+ "FLOOR",
+ "LN",
+ "LOG",
+ "MOD",
+ "NANVL",
+ "POWER",
+ "REMAINDER",
+ "ROUND",
+ "SIGN",
+ "SIN",
+ "SINH",
+ "SQRT",
+ "TAN",
+ "TANH",
+ "TRUNC",
+ "WIDTH_BUCKET",
]
# Strings functions
string_functions = [
- 'CHR', 'CONCAT', 'INITCAP', 'LOWER', 'LPAD', 'LTRIM', 'NLS_INITCAP',
- 'NLS_LOWER', 'NLSSORT', 'NLS_UPPER', 'REGEXP_REPLACE', 'REGEXP_SUBSTR',
- 'REPLACE', 'RPAD', 'RTRIM', 'SOUNDEX', 'SUBSTR', 'TRANSLATE', 'TREAT',
- 'TRIM', 'UPPER', 'ASCII', 'INSTR', 'LENGTH', 'REGEXP_INSTR'
+ "CHR",
+ "CONCAT",
+ "INITCAP",
+ "LOWER",
+ "LPAD",
+ "LTRIM",
+ "NLS_INITCAP",
+ "NLS_LOWER",
+ "NLSSORT",
+ "NLS_UPPER",
+ "REGEXP_REPLACE",
+ "REGEXP_SUBSTR",
+ "REPLACE",
+ "RPAD",
+ "RTRIM",
+ "SOUNDEX",
+ "SUBSTR",
+ "TRANSLATE",
+ "TREAT",
+ "TRIM",
+ "UPPER",
+ "ASCII",
+ "INSTR",
+ "LENGTH",
+ "REGEXP_INSTR",
]
# Aggregate functions
aggregate_functions = [
- 'AVG', 'COLLECT', 'CORR', 'COUNT', 'COVAR_POP', 'COVAR_SAMP', 'CUME_DIST',
- 'DENSE_RANK', 'FIRST', 'GROUP_ID', 'GROUPING', 'GROUPING_ID',
- 'LAST', 'MAX', 'MEDIAN', 'MIN', 'PERCENTILE_CONT',
- 'PERCENTILE_DISC', 'PERCENT_RANK', 'RANK',
- 'STATS_BINOMIAL_TEST', 'STATS_CROSSTAB', 'STATS_F_TEST',
- 'STATS_KS_TEST', 'STATS_MODE', 'STATS_MW_TEST',
- 'STATS_ONE_WAY_ANOVA', 'STATS_WSR_TEST', 'STDDEV',
- 'STDDEV_POP', 'STDDEV_SAMP', 'SUM', 'SYS_XMLAGG', 'VAR_POP',
- 'VAR_SAMP', 'VARIANCE', 'XMLAGG'
+ "AVG",
+ "COLLECT",
+ "CORR",
+ "COUNT",
+ "COVAR_POP",
+ "COVAR_SAMP",
+ "CUME_DIST",
+ "DENSE_RANK",
+ "FIRST",
+ "GROUP_ID",
+ "GROUPING",
+ "GROUPING_ID",
+ "LAST",
+ "MAX",
+ "MEDIAN",
+ "MIN",
+ "PERCENTILE_CONT",
+ "PERCENTILE_DISC",
+ "PERCENT_RANK",
+ "RANK",
+ "STATS_BINOMIAL_TEST",
+ "STATS_CROSSTAB",
+ "STATS_F_TEST",
+ "STATS_KS_TEST",
+ "STATS_MODE",
+ "STATS_MW_TEST",
+ "STATS_ONE_WAY_ANOVA",
+ "STATS_WSR_TEST",
+ "STDDEV",
+ "STDDEV_POP",
+ "STDDEV_SAMP",
+ "SUM",
+ "SYS_XMLAGG",
+ "VAR_POP",
+ "VAR_SAMP",
+ "VARIANCE",
+ "XMLAGG",
]
oracle_spatial_functions = [
# From http://docs.oracle.com/cd/B19306_01/appdev.102/b14255/toc.htm
# Spatial operators
- "SDO_ANYINTERACT", "SDO_CONTAINS", "SDO_COVEREDBY", "SDO_COVERS",
- "SDO_EQUAL", "SDO_FILTER", "SDO_INSIDE", "SDO_JOIN", "SDO_NN",
- "SDO_NN_DISTANCE", "SDO_ON", "SDO_OVERLAPBDYDISJOINT",
- "SDO_OVERLAPBDYINTERSECT", "SDO_OVERLAPS", "SDO_RELATE",
- "SDO_TOUCH", "SDO_WITHIN_DISTANCE",
+ "SDO_ANYINTERACT",
+ "SDO_CONTAINS",
+ "SDO_COVEREDBY",
+ "SDO_COVERS",
+ "SDO_EQUAL",
+ "SDO_FILTER",
+ "SDO_INSIDE",
+ "SDO_JOIN",
+ "SDO_NN",
+ "SDO_NN_DISTANCE",
+ "SDO_ON",
+ "SDO_OVERLAPBDYDISJOINT",
+ "SDO_OVERLAPBDYINTERSECT",
+ "SDO_OVERLAPS",
+ "SDO_RELATE",
+ "SDO_TOUCH",
+ "SDO_WITHIN_DISTANCE",
# SPATIAL AGGREGATE FUNCTIONS
- "SDO_AGGR_CENTROID", "SDO_AGGR_CONCAT_LINES",
- "SDO_AGGR_CONVEXHULL", "SDO_AGGR_LRS_CONCAT", "SDO_AGGR_MBR",
+ "SDO_AGGR_CENTROID",
+ "SDO_AGGR_CONCAT_LINES",
+ "SDO_AGGR_CONVEXHULL",
+ "SDO_AGGR_LRS_CONCAT",
+ "SDO_AGGR_MBR",
"SDO_AGGR_UNION",
# COORDINATE SYSTEM TRANSFORMATION (SDO_CS)
- "SDO_CS.ADD_PREFERENCE_FOR_OP", "SDO_CS.CONVERT_NADCON_TO_XML",
- "SDO_CS.CONVERT_NTV2_TO_XML", "SDO_CS.CONVERT_XML_TO_NADCON",
- "SDO_CS.CONVERT_XML_TO_NTV2", "SDO_CS.CREATE_CONCATENATED_OP",
+ "SDO_CS.ADD_PREFERENCE_FOR_OP",
+ "SDO_CS.CONVERT_NADCON_TO_XML",
+ "SDO_CS.CONVERT_NTV2_TO_XML",
+ "SDO_CS.CONVERT_XML_TO_NADCON",
+ "SDO_CS.CONVERT_XML_TO_NTV2",
+ "SDO_CS.CREATE_CONCATENATED_OP",
"SDO_CS.CREATE_OBVIOUS_EPSG_RULES",
"SDO_CS.CREATE_PREF_CONCATENATED_OP",
- "SDO_CS.DELETE_ALL_EPSG_RULES", "SDO_CS.DELETE_OP",
- "SDO_CS.DETERMINE_CHAIN", "SDO_CS.DETERMINE_DEFAULT_CHAIN",
- "SDO_CS.FIND_GEOG_CRS", "SDO_CS.FIND_PROJ_CRS",
- "SDO_CS.FROM_OGC_SIMPLEFEATURE_SRS", "SDO_CS.FROM_USNG",
+ "SDO_CS.DELETE_ALL_EPSG_RULES",
+ "SDO_CS.DELETE_OP",
+ "SDO_CS.DETERMINE_CHAIN",
+ "SDO_CS.DETERMINE_DEFAULT_CHAIN",
+ "SDO_CS.FIND_GEOG_CRS",
+ "SDO_CS.FIND_PROJ_CRS",
+ "SDO_CS.FROM_OGC_SIMPLEFEATURE_SRS",
+ "SDO_CS.FROM_USNG",
"SDO_CS.MAP_EPSG_SRID_TO_ORACLE",
"SDO_CS.MAP_ORACLE_SRID_TO_EPSG",
"SDO_CS.REVOKE_PREFERENCE_FOR_OP",
- "SDO_CS.TO_OGC_SIMPLEFEATURE_SRS", "SDO_CS.TO_USNG",
- "SDO_CS.TRANSFORM", "SDO_CS.TRANSFORM_LAYER",
+ "SDO_CS.TO_OGC_SIMPLEFEATURE_SRS",
+ "SDO_CS.TO_USNG",
+ "SDO_CS.TRANSFORM",
+ "SDO_CS.TRANSFORM_LAYER",
"SDO_CS.UPDATE_WKTS_FOR_ALL_EPSG_CRS",
"SDO_CS.UPDATE_WKTS_FOR_EPSG_CRS",
"SDO_CS.UPDATE_WKTS_FOR_EPSG_DATUM",
"SDO_CS.UPDATE_WKTS_FOR_EPSG_ELLIPS",
"SDO_CS.UPDATE_WKTS_FOR_EPSG_OP",
"SDO_CS.UPDATE_WKTS_FOR_EPSG_PARAM",
- "SDO_CS.UPDATE_WKTS_FOR_EPSG_PM", "SDO_CS.VALIDATE_WKT",
+ "SDO_CS.UPDATE_WKTS_FOR_EPSG_PM",
+ "SDO_CS.VALIDATE_WKT",
"SDO_CS.VIEWPORT_TRANSFORM",
# GEOCODING (SDO_GCDR)
- "SDO_GCDR.GEOCODE", "SDO_GCDR.GEOCODE_ADDR",
- "SDO_GCDR.GEOCODE_ADDR_ALL", "SDO_GCDR.GEOCODE_ALL",
- "SDO_GCDR.GEOCODE_AS_GEOMETRY", "SDO_GCDR.REVERSE_GEOCODE",
+ "SDO_GCDR.GEOCODE",
+ "SDO_GCDR.GEOCODE_ADDR",
+ "SDO_GCDR.GEOCODE_ADDR_ALL",
+ "SDO_GCDR.GEOCODE_ALL",
+ "SDO_GCDR.GEOCODE_AS_GEOMETRY",
+ "SDO_GCDR.REVERSE_GEOCODE",
# GEOMETRY (SDO_GEOM)
- "SDO_GEOM.RELATE", "SDO_GEOM.SDO_ARC_DENSIFY",
- "SDO_GEOM.SDO_AREA", "SDO_GEOM.SDO_BUFFER",
- "SDO_GEOM.SDO_CENTROID", "SDO_GEOM.SDO_CONVEXHULL",
- "SDO_GEOM.SDO_DIFFERENCE", "SDO_GEOM.SDO_DISTANCE",
- "SDO_GEOM.SDO_INTERSECTION", "SDO_GEOM.SDO_LENGTH",
- "SDO_GEOM.SDO_MAX_MBR_ORDINATE", "SDO_GEOM.SDO_MBR",
- "SDO_GEOM.SDO_MIN_MBR_ORDINATE", "SDO_GEOM.SDO_POINTONSURFACE",
- "SDO_GEOM.SDO_UNION", "SDO_GEOM.SDO_XOR",
+ "SDO_GEOM.RELATE",
+ "SDO_GEOM.SDO_ARC_DENSIFY",
+ "SDO_GEOM.SDO_AREA",
+ "SDO_GEOM.SDO_BUFFER",
+ "SDO_GEOM.SDO_CENTROID",
+ "SDO_GEOM.SDO_CONVEXHULL",
+ "SDO_GEOM.SDO_DIFFERENCE",
+ "SDO_GEOM.SDO_DISTANCE",
+ "SDO_GEOM.SDO_INTERSECTION",
+ "SDO_GEOM.SDO_LENGTH",
+ "SDO_GEOM.SDO_MAX_MBR_ORDINATE",
+ "SDO_GEOM.SDO_MBR",
+ "SDO_GEOM.SDO_MIN_MBR_ORDINATE",
+ "SDO_GEOM.SDO_POINTONSURFACE",
+ "SDO_GEOM.SDO_UNION",
+ "SDO_GEOM.SDO_XOR",
"SDO_GEOM.VALIDATE_GEOMETRY_WITH_CONTEXT",
"SDO_GEOM.VALIDATE_LAYER_WITH_CONTEXT",
"SDO_GEOM.WITHIN_DISTANCE",
# LINEAR REFERENCING SYSTEM (SDO_LRS)
- "SDO_LRS.CLIP_GEOM_SEGMENT", "SDO_LRS.CONCATENATE_GEOM_SEGMENTS",
+ "SDO_LRS.CLIP_GEOM_SEGMENT",
+ "SDO_LRS.CONCATENATE_GEOM_SEGMENTS",
"SDO_LRS.CONNECTED_GEOM_SEGMENTS",
- "SDO_LRS.CONVERT_TO_LRS_DIM_ARRAY", "SDO_LRS.CONVERT_TO_LRS_GEOM",
+ "SDO_LRS.CONVERT_TO_LRS_DIM_ARRAY",
+ "SDO_LRS.CONVERT_TO_LRS_GEOM",
"SDO_LRS.CONVERT_TO_LRS_LAYER",
- "SDO_LRS.CONVERT_TO_STD_DIM_ARRAY", "SDO_LRS.CONVERT_TO_STD_GEOM",
- "SDO_LRS.CONVERT_TO_STD_LAYER", "SDO_LRS.DEFINE_GEOM_SEGMENT",
- "SDO_LRS.DYNAMIC_SEGMENT", "SDO_LRS.FIND_LRS_DIM_POS",
- "SDO_LRS.FIND_MEASURE", "SDO_LRS.FIND_OFFSET",
- "SDO_LRS.GEOM_SEGMENT_END_MEASURE", "SDO_LRS.GEOM_SEGMENT_END_PT",
+ "SDO_LRS.CONVERT_TO_STD_DIM_ARRAY",
+ "SDO_LRS.CONVERT_TO_STD_GEOM",
+ "SDO_LRS.CONVERT_TO_STD_LAYER",
+ "SDO_LRS.DEFINE_GEOM_SEGMENT",
+ "SDO_LRS.DYNAMIC_SEGMENT",
+ "SDO_LRS.FIND_LRS_DIM_POS",
+ "SDO_LRS.FIND_MEASURE",
+ "SDO_LRS.FIND_OFFSET",
+ "SDO_LRS.GEOM_SEGMENT_END_MEASURE",
+ "SDO_LRS.GEOM_SEGMENT_END_PT",
"SDO_LRS.GEOM_SEGMENT_LENGTH",
"SDO_LRS.GEOM_SEGMENT_START_MEASURE",
- "SDO_LRS.GEOM_SEGMENT_START_PT", "SDO_LRS.GET_MEASURE",
- "SDO_LRS.GET_NEXT_SHAPE_PT", "SDO_LRS.GET_NEXT_SHAPE_PT_MEASURE",
- "SDO_LRS.GET_PREV_SHAPE_PT", "SDO_LRS.GET_PREV_SHAPE_PT_MEASURE",
+ "SDO_LRS.GEOM_SEGMENT_START_PT",
+ "SDO_LRS.GET_MEASURE",
+ "SDO_LRS.GET_NEXT_SHAPE_PT",
+ "SDO_LRS.GET_NEXT_SHAPE_PT_MEASURE",
+ "SDO_LRS.GET_PREV_SHAPE_PT",
+ "SDO_LRS.GET_PREV_SHAPE_PT_MEASURE",
"SDO_LRS.IS_GEOM_SEGMENT_DEFINED",
- "SDO_LRS.IS_MEASURE_DECREASING", "SDO_LRS.IS_MEASURE_INCREASING",
- "SDO_LRS.IS_SHAPE_PT_MEASURE", "SDO_LRS.LOCATE_PT",
- "SDO_LRS.LRS_INTERSECTION", "SDO_LRS.MEASURE_RANGE",
- "SDO_LRS.MEASURE_TO_PERCENTAGE", "SDO_LRS.OFFSET_GEOM_SEGMENT",
- "SDO_LRS.PERCENTAGE_TO_MEASURE", "SDO_LRS.PROJECT_PT",
- "SDO_LRS.REDEFINE_GEOM_SEGMENT", "SDO_LRS.RESET_MEASURE",
- "SDO_LRS.REVERSE_GEOMETRY", "SDO_LRS.REVERSE_MEASURE",
- "SDO_LRS.SET_PT_MEASURE", "SDO_LRS.SPLIT_GEOM_SEGMENT",
- "SDO_LRS.TRANSLATE_MEASURE", "SDO_LRS.VALID_GEOM_SEGMENT",
- "SDO_LRS.VALID_LRS_PT", "SDO_LRS.VALID_MEASURE",
+ "SDO_LRS.IS_MEASURE_DECREASING",
+ "SDO_LRS.IS_MEASURE_INCREASING",
+ "SDO_LRS.IS_SHAPE_PT_MEASURE",
+ "SDO_LRS.LOCATE_PT",
+ "SDO_LRS.LRS_INTERSECTION",
+ "SDO_LRS.MEASURE_RANGE",
+ "SDO_LRS.MEASURE_TO_PERCENTAGE",
+ "SDO_LRS.OFFSET_GEOM_SEGMENT",
+ "SDO_LRS.PERCENTAGE_TO_MEASURE",
+ "SDO_LRS.PROJECT_PT",
+ "SDO_LRS.REDEFINE_GEOM_SEGMENT",
+ "SDO_LRS.RESET_MEASURE",
+ "SDO_LRS.REVERSE_GEOMETRY",
+ "SDO_LRS.REVERSE_MEASURE",
+ "SDO_LRS.SET_PT_MEASURE",
+ "SDO_LRS.SPLIT_GEOM_SEGMENT",
+ "SDO_LRS.TRANSLATE_MEASURE",
+ "SDO_LRS.VALID_GEOM_SEGMENT",
+ "SDO_LRS.VALID_LRS_PT",
+ "SDO_LRS.VALID_MEASURE",
"SDO_LRS.VALIDATE_LRS_GEOMETRY",
# SDO_MIGRATE
"SDO_MIGRATE.TO_CURRENT",
# SPATIAL ANALYSIS AND MINING (SDO_SAM)
- "SDO_SAM.AGGREGATES_FOR_GEOMETRY", "SDO_SAM.AGGREGATES_FOR_LAYER",
- "SDO_SAM.BIN_GEOMETRY", "SDO_SAM.BIN_LAYER",
+ "SDO_SAM.AGGREGATES_FOR_GEOMETRY",
+ "SDO_SAM.AGGREGATES_FOR_LAYER",
+ "SDO_SAM.BIN_GEOMETRY",
+ "SDO_SAM.BIN_LAYER",
"SDO_SAM.COLOCATED_REFERENCE_FEATURES",
- "SDO_SAM.SIMPLIFY_GEOMETRY", "SDO_SAM.SIMPLIFY_LAYER",
- "SDO_SAM.SPATIAL_CLUSTERS", "SDO_SAM.TILED_AGGREGATES",
+ "SDO_SAM.SIMPLIFY_GEOMETRY",
+ "SDO_SAM.SIMPLIFY_LAYER",
+ "SDO_SAM.SPATIAL_CLUSTERS",
+ "SDO_SAM.TILED_AGGREGATES",
"SDO_SAM.TILED_BINS",
# TUNING (SDO_TUNE)
- "SDO_TUNE.AVERAGE_MBR", "SDO_TUNE.ESTIMATE_RTREE_INDEX_SIZE",
- "SDO_TUNE.EXTENT_OF", "SDO_TUNE.MIX_INFO",
+ "SDO_TUNE.AVERAGE_MBR",
+ "SDO_TUNE.ESTIMATE_RTREE_INDEX_SIZE",
+ "SDO_TUNE.EXTENT_OF",
+ "SDO_TUNE.MIX_INFO",
"SDO_TUNE.QUALITY_DEGRADATION",
# UTILITY (SDO_UTIL)
- "SDO_UTIL.APPEND", "SDO_UTIL.CIRCLE_POLYGON",
- "SDO_UTIL.CONCAT_LINES", "SDO_UTIL.CONVERT_UNIT",
- "SDO_UTIL.ELLIPSE_POLYGON", "SDO_UTIL.EXTRACT",
- "SDO_UTIL.FROM_WKBGEOMETRY", "SDO_UTIL.FROM_WKTGEOMETRY",
- "SDO_UTIL.GETNUMELEM", "SDO_UTIL.GETNUMVERTICES",
- "SDO_UTIL.GETVERTICES", "SDO_UTIL.INITIALIZE_INDEXES_FOR_TTS",
- "SDO_UTIL.POINT_AT_BEARING", "SDO_UTIL.POLYGONTOLINE",
- "SDO_UTIL.PREPARE_FOR_TTS", "SDO_UTIL.RECTIFY_GEOMETRY",
+ "SDO_UTIL.APPEND",
+ "SDO_UTIL.CIRCLE_POLYGON",
+ "SDO_UTIL.CONCAT_LINES",
+ "SDO_UTIL.CONVERT_UNIT",
+ "SDO_UTIL.ELLIPSE_POLYGON",
+ "SDO_UTIL.EXTRACT",
+ "SDO_UTIL.FROM_WKBGEOMETRY",
+ "SDO_UTIL.FROM_WKTGEOMETRY",
+ "SDO_UTIL.GETNUMELEM",
+ "SDO_UTIL.GETNUMVERTICES",
+ "SDO_UTIL.GETVERTICES",
+ "SDO_UTIL.INITIALIZE_INDEXES_FOR_TTS",
+ "SDO_UTIL.POINT_AT_BEARING",
+ "SDO_UTIL.POLYGONTOLINE",
+ "SDO_UTIL.PREPARE_FOR_TTS",
+ "SDO_UTIL.RECTIFY_GEOMETRY",
"SDO_UTIL.REMOVE_DUPLICATE_VERTICES",
- "SDO_UTIL.REVERSE_LINESTRING", "SDO_UTIL.SIMPLIFY",
- "SDO_UTIL.TO_GMLGEOMETRY", "SDO_UTIL.TO_WKBGEOMETRY",
- "SDO_UTIL.TO_WKTGEOMETRY", "SDO_UTIL.VALIDATE_WKBGEOMETRY",
- "SDO_UTIL.VALIDATE_WKTGEOMETRY"
+ "SDO_UTIL.REVERSE_LINESTRING",
+ "SDO_UTIL.SIMPLIFY",
+ "SDO_UTIL.TO_GMLGEOMETRY",
+ "SDO_UTIL.TO_WKBGEOMETRY",
+ "SDO_UTIL.TO_WKTGEOMETRY",
+ "SDO_UTIL.VALIDATE_WKBGEOMETRY",
+ "SDO_UTIL.VALIDATE_WKTGEOMETRY",
]
# Oracle Operators
operators = [
- ' AND ', ' OR ', '||', ' < ', ' <= ', ' > ', ' >= ', ' = ',
- ' <> ', '!=', '^=', ' IS ', ' IS NOT ', ' IN ', ' ANY ', ' SOME ',
- ' NOT IN ', ' LIKE ', ' GLOB ', ' MATCH ', ' REGEXP ',
- ' BETWEEN x AND y ', ' NOT BETWEEN x AND y ', ' EXISTS ',
- ' IS NULL ', ' IS NOT NULL', ' ALL ', ' NOT ',
- ' CASE {column} WHEN {value} THEN {value} '
+ " AND ",
+ " OR ",
+ "||",
+ " < ",
+ " <= ",
+ " > ",
+ " >= ",
+ " = ",
+ " <> ",
+ "!=",
+ "^=",
+ " IS ",
+ " IS NOT ",
+ " IN ",
+ " ANY ",
+ " SOME ",
+ " NOT IN ",
+ " LIKE ",
+ " GLOB ",
+ " MATCH ",
+ " REGEXP ",
+ " BETWEEN x AND y ",
+ " NOT BETWEEN x AND y ",
+ " EXISTS ",
+ " IS NULL ",
+ " IS NOT NULL",
+ " ALL ",
+ " NOT ",
+ " CASE {column} WHEN {value} THEN {value} ",
]
# constants
@@ -278,26 +846,22 @@ def getSqlDictionary(spatial=True):
f += oracle_spatial_functions
c += oracle_spatial_constants
- return {'keyword': k, 'constant': c, 'function': f}
+ return {"keyword": k, "constant": c, "function": f}
def getQueryBuilderDictionary():
# concat functions
def ff(l):
- return [s for s in l if s[0] != '*']
+ return [s for s in l if s[0] != "*"]
def add_paren(l):
return [s + "(" for s in l]
foo = sorted(
- add_paren(
- ff(
- list(
- set.union(set(functions),
- set(oracle_spatial_functions))))))
+ add_paren(ff(list(set.union(set(functions), set(oracle_spatial_functions)))))
+ )
m = sorted(add_paren(ff(math_functions)))
agg = sorted(add_paren(ff(aggregate_functions)))
op = ff(operators)
s = sorted(add_paren(ff(string_functions)))
- return {'function': foo, 'math': m, 'aggregate': agg,
- 'operator': op, 'string': s}
+ return {"function": foo, "math": m, "aggregate": agg, "operator": op, "string": s}
diff --git a/python/plugins/db_manager/db_plugins/plugin.py b/python/plugins/db_manager/db_plugins/plugin.py
index 00d31a23119c..e5f39cd8bd3f 100644
--- a/python/plugins/db_manager/db_plugins/plugin.py
+++ b/python/plugins/db_manager/db_plugins/plugin.py
@@ -33,7 +33,7 @@
QInputDialog,
QMessageBox,
QDialog,
- QWidget
+ QWidget,
)
from qgis.PyQt.QtGui import QKeySequence
@@ -50,13 +50,10 @@
QgsRasterLayer,
QgsProject,
QgsMessageLog,
- QgsCoordinateReferenceSystem
+ QgsCoordinateReferenceSystem,
)
-from qgis.gui import (
- QgsMessageBarItem,
- QgsProjectionSelectionWidget
-)
+from qgis.gui import QgsMessageBarItem, QgsProjectionSelectionWidget
from ..db_plugins import createDbPlugin
@@ -66,12 +63,14 @@ class BaseError(Exception):
def __init__(self, e):
if isinstance(e, Exception):
- msg = e.args[0] if len(e.args) > 0 else ''
+ msg = e.args[0] if len(e.args) > 0 else ""
else:
msg = e
if not isinstance(msg, str):
- msg = str(msg, 'utf-8', 'replace') # convert from utf8 and replace errors (if any)
+ msg = str(
+ msg, "utf-8", "replace"
+ ) # convert from utf8 and replace errors (if any)
self.msg = msg
Exception.__init__(self, msg)
@@ -98,9 +97,13 @@ def __unicode__(self):
if self.query is None:
return BaseError.__unicode__(self)
- msg = QApplication.translate("DBManagerPlugin", "Error:\n{0}").format(BaseError.__unicode__(self))
+ msg = QApplication.translate("DBManagerPlugin", "Error:\n{0}").format(
+ BaseError.__unicode__(self)
+ )
if self.query:
- msg += QApplication.translate("DBManagerPlugin", "\n\nQuery:\n{0}").format(self.query)
+ msg += QApplication.translate("DBManagerPlugin", "\n\nQuery:\n{0}").format(
+ self.query
+ )
return msg
@@ -132,7 +135,7 @@ def info(self):
return DatabaseInfo(None)
def connect(self, parent=None):
- raise NotImplementedError('Needs to be implemented by subclasses')
+ raise NotImplementedError("Needs to be implemented by subclasses")
def connectToUri(self, uri):
self.db = self.databasesFactory(self, uri)
@@ -156,7 +159,9 @@ def remove(self):
md.deleteConnection(self.connectionName())
except (AttributeError, QgsProviderConnectionException):
settings = QgsSettings()
- settings.beginGroup("/%s/%s" % (self.connectionSettingsKey(), self.connectionName()))
+ settings.beginGroup(
+ f"/{self.connectionSettingsKey()}/{self.connectionName()}"
+ )
settings.remove("")
self.deleted.emit()
@@ -164,7 +169,7 @@ def remove(self):
@classmethod
def addConnection(self, conn_name, uri):
- raise NotImplementedError('Needs to be implemented by subclasses')
+ raise NotImplementedError("Needs to be implemented by subclasses")
@classmethod
def icon(self):
@@ -215,15 +220,19 @@ def databasesFactory(self, connection, uri):
@classmethod
def addConnectionActionSlot(self, item, action, parent):
- raise NotImplementedError('Needs to be implemented by subclasses')
+ raise NotImplementedError("Needs to be implemented by subclasses")
def removeActionSlot(self, item, action, parent):
QApplication.restoreOverrideCursor()
try:
- res = QMessageBox.question(parent, QApplication.translate("DBManagerPlugin", "DB Manager"),
- QApplication.translate("DBManagerPlugin",
- "Really remove connection to {0}?").format(item.connectionName()),
- QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No)
+ res = QMessageBox.question(
+ parent,
+ QApplication.translate("DBManagerPlugin", "DB Manager"),
+ QApplication.translate(
+ "DBManagerPlugin", "Really remove connection to {0}?"
+ ).format(item.connectionName()),
+ QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No,
+ )
if res != QMessageBox.StandardButton.Yes:
return
finally:
@@ -310,22 +319,35 @@ def columnUniqueValuesModel(self, col, table, limit=10):
l = ""
if limit is not None:
l = "LIMIT %d" % limit
- return self.sqlResultModel("SELECT DISTINCT %s FROM %s %s" % (col, table, l), self)
+ return self.sqlResultModel(f"SELECT DISTINCT {col} FROM {table} {l}", self)
def uniqueIdFunction(self):
"""Return a SQL function used to generate a unique id for rows of a query"""
# may be overloaded by derived classes
return "row_number() over ()"
- def toSqlLayer(self, sql, geomCol, uniqueCol, layerName="QueryLayer", layerType=None, avoidSelectById=False, filter=""):
+ def toSqlLayer(
+ self,
+ sql,
+ geomCol,
+ uniqueCol,
+ layerName="QueryLayer",
+ layerType=None,
+ avoidSelectById=False,
+ filter="",
+ ):
if uniqueCol is None:
- if hasattr(self, 'uniqueIdFunction'):
+ if hasattr(self, "uniqueIdFunction"):
uniqueFct = self.uniqueIdFunction()
if uniqueFct is not None:
q = 1
while "_subq_%d_" % q in sql:
q += 1
- sql = "SELECT %s AS _uid_,* FROM (%s\n) AS _subq_%d_" % (uniqueFct, sql, q)
+ sql = "SELECT %s AS _uid_,* FROM (%s\n) AS _subq_%d_" % (
+ uniqueFct,
+ sql,
+ q,
+ )
uniqueCol = "_uid_"
uri = self.uri()
@@ -352,45 +374,91 @@ def registerSubPluginActions(self, mainWindow):
def registerDatabaseActions(self, mainWindow):
action = QAction(QApplication.translate("DBManagerPlugin", "&Re-connect"), self)
- mainWindow.registerAction(action, QApplication.translate("DBManagerPlugin", "&Database"),
- self.reconnectActionSlot)
+ mainWindow.registerAction(
+ action,
+ QApplication.translate("DBManagerPlugin", "&Database"),
+ self.reconnectActionSlot,
+ )
if self.schemas() is not None:
- action = QAction(QApplication.translate("DBManagerPlugin", "&Create Schema…"), self)
- mainWindow.registerAction(action, QApplication.translate("DBManagerPlugin", "&Schema"),
- self.createSchemaActionSlot)
- action = QAction(QApplication.translate("DBManagerPlugin", "&Delete (Empty) Schema"), self)
- mainWindow.registerAction(action, QApplication.translate("DBManagerPlugin", "&Schema"),
- self.deleteSchemaActionSlot)
-
- action = QAction(QApplication.translate("DBManagerPlugin", "Delete Selected Item"), self)
+ action = QAction(
+ QApplication.translate("DBManagerPlugin", "&Create Schema…"), self
+ )
+ mainWindow.registerAction(
+ action,
+ QApplication.translate("DBManagerPlugin", "&Schema"),
+ self.createSchemaActionSlot,
+ )
+ action = QAction(
+ QApplication.translate("DBManagerPlugin", "&Delete (Empty) Schema"),
+ self,
+ )
+ mainWindow.registerAction(
+ action,
+ QApplication.translate("DBManagerPlugin", "&Schema"),
+ self.deleteSchemaActionSlot,
+ )
+
+ action = QAction(
+ QApplication.translate("DBManagerPlugin", "Delete Selected Item"), self
+ )
mainWindow.registerAction(action, None, self.deleteActionSlot)
action.setShortcuts(QKeySequence.StandardKey.Delete)
- action = QAction(QgsApplication.getThemeIcon("/mActionCreateTable.svg"),
- QApplication.translate("DBManagerPlugin", "&Create Table…"), self)
- mainWindow.registerAction(action, QApplication.translate("DBManagerPlugin", "&Table"),
- self.createTableActionSlot)
- action = QAction(QgsApplication.getThemeIcon("/mActionEditTable.svg"),
- QApplication.translate("DBManagerPlugin", "&Edit Table…"), self)
- mainWindow.registerAction(action, QApplication.translate("DBManagerPlugin", "&Table"), self.editTableActionSlot)
- action = QAction(QgsApplication.getThemeIcon("/mActionDeleteTable.svg"),
- QApplication.translate("DBManagerPlugin", "&Delete Table/View…"), self)
- mainWindow.registerAction(action, QApplication.translate("DBManagerPlugin", "&Table"),
- self.deleteTableActionSlot)
- action = QAction(QApplication.translate("DBManagerPlugin", "&Empty Table…"), self)
- mainWindow.registerAction(action, QApplication.translate("DBManagerPlugin", "&Table"),
- self.emptyTableActionSlot)
+ action = QAction(
+ QgsApplication.getThemeIcon("/mActionCreateTable.svg"),
+ QApplication.translate("DBManagerPlugin", "&Create Table…"),
+ self,
+ )
+ mainWindow.registerAction(
+ action,
+ QApplication.translate("DBManagerPlugin", "&Table"),
+ self.createTableActionSlot,
+ )
+ action = QAction(
+ QgsApplication.getThemeIcon("/mActionEditTable.svg"),
+ QApplication.translate("DBManagerPlugin", "&Edit Table…"),
+ self,
+ )
+ mainWindow.registerAction(
+ action,
+ QApplication.translate("DBManagerPlugin", "&Table"),
+ self.editTableActionSlot,
+ )
+ action = QAction(
+ QgsApplication.getThemeIcon("/mActionDeleteTable.svg"),
+ QApplication.translate("DBManagerPlugin", "&Delete Table/View…"),
+ self,
+ )
+ mainWindow.registerAction(
+ action,
+ QApplication.translate("DBManagerPlugin", "&Table"),
+ self.deleteTableActionSlot,
+ )
+ action = QAction(
+ QApplication.translate("DBManagerPlugin", "&Empty Table…"), self
+ )
+ mainWindow.registerAction(
+ action,
+ QApplication.translate("DBManagerPlugin", "&Table"),
+ self.emptyTableActionSlot,
+ )
if self.schemas() is not None:
- action = QAction(QApplication.translate("DBManagerPlugin", "&Move to Schema"), self)
+ action = QAction(
+ QApplication.translate("DBManagerPlugin", "&Move to Schema"), self
+ )
action.setMenu(QMenu(mainWindow))
def invoke_callback():
- return mainWindow.invokeCallback(self.prepareMenuMoveTableToSchemaActionSlot)
+ return mainWindow.invokeCallback(
+ self.prepareMenuMoveTableToSchemaActionSlot
+ )
action.menu().aboutToShow.connect(invoke_callback)
- mainWindow.registerAction(action, QApplication.translate("DBManagerPlugin", "&Table"))
+ mainWindow.registerAction(
+ action, QApplication.translate("DBManagerPlugin", "&Table")
+ )
def reconnectActionSlot(self, item, action, parent):
db = item.database()
@@ -404,20 +472,36 @@ def deleteActionSlot(self, item, action, parent):
self.deleteTableActionSlot(item, action, parent)
else:
QApplication.restoreOverrideCursor()
- parent.infoBar.pushMessage(QApplication.translate("DBManagerPlugin", "Cannot delete the selected item."),
- Qgis.MessageLevel.Info, parent.iface.messageTimeout())
+ parent.infoBar.pushMessage(
+ QApplication.translate(
+ "DBManagerPlugin", "Cannot delete the selected item."
+ ),
+ Qgis.MessageLevel.Info,
+ parent.iface.messageTimeout(),
+ )
QApplication.setOverrideCursor(Qt.CursorShape.WaitCursor)
def createSchemaActionSlot(self, item, action, parent):
QApplication.restoreOverrideCursor()
try:
- if not isinstance(item, (DBPlugin, Schema, Table)) or item.database() is None:
+ if (
+ not isinstance(item, (DBPlugin, Schema, Table))
+ or item.database() is None
+ ):
parent.infoBar.pushMessage(
- QApplication.translate("DBManagerPlugin", "No database selected or you are not connected to it."),
- Qgis.MessageLevel.Info, parent.iface.messageTimeout())
+ QApplication.translate(
+ "DBManagerPlugin",
+ "No database selected or you are not connected to it.",
+ ),
+ Qgis.MessageLevel.Info,
+ parent.iface.messageTimeout(),
+ )
return
- (schema, ok) = QInputDialog.getText(parent, QApplication.translate("DBManagerPlugin", "New schema"),
- QApplication.translate("DBManagerPlugin", "Enter new schema name"))
+ (schema, ok) = QInputDialog.getText(
+ parent,
+ QApplication.translate("DBManagerPlugin", "New schema"),
+ QApplication.translate("DBManagerPlugin", "Enter new schema name"),
+ )
if not ok:
return
finally:
@@ -430,13 +514,21 @@ def deleteSchemaActionSlot(self, item, action, parent):
try:
if not isinstance(item, Schema):
parent.infoBar.pushMessage(
- QApplication.translate("DBManagerPlugin", "Select an empty schema for deletion."),
- Qgis.MessageLevel.Info, parent.iface.messageTimeout())
+ QApplication.translate(
+ "DBManagerPlugin", "Select an empty schema for deletion."
+ ),
+ Qgis.MessageLevel.Info,
+ parent.iface.messageTimeout(),
+ )
return
- res = QMessageBox.question(parent, QApplication.translate("DBManagerPlugin", "DB Manager"),
- QApplication.translate("DBManagerPlugin",
- "Really delete schema {0}?").format(item.name),
- QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No)
+ res = QMessageBox.question(
+ parent,
+ QApplication.translate("DBManagerPlugin", "DB Manager"),
+ QApplication.translate(
+ "DBManagerPlugin", "Really delete schema {0}?"
+ ).format(item.name),
+ QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No,
+ )
if res != QMessageBox.StandardButton.Yes:
return
finally:
@@ -459,10 +551,15 @@ def createSchema(self, name):
def createTableActionSlot(self, item, action, parent):
QApplication.restoreOverrideCursor()
- if not hasattr(item, 'database') or item.database() is None:
+ if not hasattr(item, "database") or item.database() is None:
parent.infoBar.pushMessage(
- QApplication.translate("DBManagerPlugin", "No database selected or you are not connected to it."),
- Qgis.MessageLevel.Info, parent.iface.messageTimeout())
+ QApplication.translate(
+ "DBManagerPlugin",
+ "No database selected or you are not connected to it.",
+ ),
+ Qgis.MessageLevel.Info,
+ parent.iface.messageTimeout(),
+ )
return
from ..dlg_create_table import DlgCreateTable
@@ -473,13 +570,23 @@ def editTableActionSlot(self, item, action, parent):
QApplication.restoreOverrideCursor()
try:
if not isinstance(item, Table) or item.isView:
- parent.infoBar.pushMessage(QApplication.translate("DBManagerPlugin", "Select a table to edit."),
- Qgis.MessageLevel.Info, parent.iface.messageTimeout())
+ parent.infoBar.pushMessage(
+ QApplication.translate(
+ "DBManagerPlugin", "Select a table to edit."
+ ),
+ Qgis.MessageLevel.Info,
+ parent.iface.messageTimeout(),
+ )
return
if isinstance(item, RasterTable):
- parent.infoBar.pushMessage(QApplication.translate("DBManagerPlugin", "Editing of raster tables is not supported."),
- Qgis.MessageLevel.Info, parent.iface.messageTimeout())
+ parent.infoBar.pushMessage(
+ QApplication.translate(
+ "DBManagerPlugin", "Editing of raster tables is not supported."
+ ),
+ Qgis.MessageLevel.Info,
+ parent.iface.messageTimeout(),
+ )
return
from ..dlg_table_properties import DlgTableProperties
@@ -493,13 +600,21 @@ def deleteTableActionSlot(self, item, action, parent):
try:
if not isinstance(item, Table):
parent.infoBar.pushMessage(
- QApplication.translate("DBManagerPlugin", "Select a table/view for deletion."),
- Qgis.MessageLevel.Info, parent.iface.messageTimeout())
+ QApplication.translate(
+ "DBManagerPlugin", "Select a table/view for deletion."
+ ),
+ Qgis.MessageLevel.Info,
+ parent.iface.messageTimeout(),
+ )
return
- res = QMessageBox.question(parent, QApplication.translate("DBManagerPlugin", "DB Manager"),
- QApplication.translate("DBManagerPlugin",
- "Really delete table/view {0}?").format(item.name),
- QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No)
+ res = QMessageBox.question(
+ parent,
+ QApplication.translate("DBManagerPlugin", "DB Manager"),
+ QApplication.translate(
+ "DBManagerPlugin", "Really delete table/view {0}?"
+ ).format(item.name),
+ QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No,
+ )
if res != QMessageBox.StandardButton.Yes:
return
finally:
@@ -511,13 +626,22 @@ def emptyTableActionSlot(self, item, action, parent):
QApplication.restoreOverrideCursor()
try:
if not isinstance(item, Table) or item.isView:
- parent.infoBar.pushMessage(QApplication.translate("DBManagerPlugin", "Select a table to empty it."),
- Qgis.MessageLevel.Info, parent.iface.messageTimeout())
+ parent.infoBar.pushMessage(
+ QApplication.translate(
+ "DBManagerPlugin", "Select a table to empty it."
+ ),
+ Qgis.MessageLevel.Info,
+ parent.iface.messageTimeout(),
+ )
return
- res = QMessageBox.question(parent, QApplication.translate("DBManagerPlugin", "DB Manager"),
- QApplication.translate("DBManagerPlugin",
- "Really delete all items from table {0}?").format(item.name),
- QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No)
+ res = QMessageBox.question(
+ parent,
+ QApplication.translate("DBManagerPlugin", "DB Manager"),
+ QApplication.translate(
+ "DBManagerPlugin", "Really delete all items from table {0}?"
+ ).format(item.name),
+ QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No,
+ )
if res != QMessageBox.StandardButton.Yes:
return
finally:
@@ -526,10 +650,12 @@ def emptyTableActionSlot(self, item, action, parent):
item.empty()
def prepareMenuMoveTableToSchemaActionSlot(self, item, menu, mainWindow):
- """ populate menu with schemas """
+ """populate menu with schemas"""
def slot(x):
- return lambda: mainWindow.invokeCallback(self.moveTableToSchemaActionSlot, x)
+ return lambda: mainWindow.invokeCallback(
+ self.moveTableToSchemaActionSlot, x
+ )
menu.clear()
for schema in self.schemas():
@@ -539,8 +665,11 @@ def moveTableToSchemaActionSlot(self, item, action, parent, new_schema):
QApplication.restoreOverrideCursor()
try:
if not isinstance(item, Table):
- parent.infoBar.pushMessage(QApplication.translate("DBManagerPlugin", "Select a table/view."),
- Qgis.MessageLevel.Info, parent.iface.messageTimeout())
+ parent.infoBar.pushMessage(
+ QApplication.translate("DBManagerPlugin", "Select a table/view."),
+ Qgis.MessageLevel.Info,
+ parent.iface.messageTimeout(),
+ )
return
finally:
QApplication.setOverrideCursor(Qt.CursorShape.WaitCursor)
@@ -567,10 +696,7 @@ def rasterTablesFactory(self, row, db, schema=None):
def tables(self, schema=None, sys_tables=False):
tables = self.connector.getTables(schema.name if schema else None, sys_tables)
if tables is not None:
- ret = [
- self.tablesFactory(t, self, schema)
- for t in tables
- ]
+ ret = [self.tablesFactory(t, self, schema) for t in tables]
return ret
def createTable(self, table, fields, schema=None):
@@ -601,7 +727,9 @@ def createVectorTable(self, table, fields, geom, schema=None):
geomCol, geomType, geomSrid, geomDim = geom[:4]
createSpatialIndex = geom[4] if len(geom) > 4 else False
- self.connector.addGeometryColumn((schema, table), geomCol, geomType, geomSrid, geomDim)
+ self.connector.addGeometryColumn(
+ (schema, table), geomCol, geomType, geomSrid, geomDim
+ )
if createSpatialIndex:
# commit data definition changes, otherwise index can't be built
@@ -670,7 +798,7 @@ class Table(DbItemObject):
def __init__(self, db, schema=None, parent=None):
DbItemObject.__init__(self, db)
self._schema = schema
- if hasattr(self, 'type'):
+ if hasattr(self, "type"):
return
self.type = Table.TableType
@@ -678,7 +806,9 @@ def __init__(self, db, schema=None, parent=None):
self.comment = None
self.rowCount = None
- self._fields = self._indexes = self._constraints = self._triggers = self._rules = None
+ self._fields = self._indexes = self._constraints = self._triggers = (
+ self._rules
+ ) = None
def __del__(self):
pass # print "Table.__del__", self
@@ -710,7 +840,9 @@ def delete(self):
def rename(self, new_name):
self.aboutToChange.emit()
- ret = self.database().connector.renameTable((self.schemaName(), self.name), new_name)
+ ret = self.database().connector.renameTable(
+ (self.schemaName(), self.name), new_name
+ )
if ret is not False:
self.name = new_name
self._triggers = None
@@ -730,7 +862,9 @@ def moveToSchema(self, schema):
self.aboutToChange.emit()
if self.schema() == schema:
return True
- ret = self.database().connector.moveTableToSchema((self.schemaName(), self.name), schema.name)
+ ret = self.database().connector.moveTableToSchema(
+ (self.schemaName(), self.name), schema.name
+ )
if ret is not False:
self.schema().refresh()
schema.refresh()
@@ -743,10 +877,18 @@ def info(self):
def uri(self):
uri = self.database().uri()
- schema = self.schemaName() if self.schemaName() else ''
- geomCol = self.geomColumn if self.type in [Table.VectorType, Table.RasterType] else ""
+ schema = self.schemaName() if self.schemaName() else ""
+ geomCol = (
+ self.geomColumn if self.type in [Table.VectorType, Table.RasterType] else ""
+ )
uniqueCol = self.getValidQgisUniqueFields(True) if self.isView else None
- uri.setDataSource(schema, self.name, geomCol if geomCol else None, None, uniqueCol.name if uniqueCol else "")
+ uri.setDataSource(
+ schema,
+ self.name,
+ geomCol if geomCol else None,
+ None,
+ uniqueCol.name if uniqueCol else "",
+ )
return uri
def crs(self):
@@ -756,7 +898,12 @@ def crs(self):
def mimeUri(self):
layerType = "raster" if self.type == Table.RasterType else "vector"
- return "%s:%s:%s:%s" % (layerType, self.database().dbplugin().providerName(), self.name, self.uri().uri(False))
+ return "{}:{}:{}:{}".format(
+ layerType,
+ self.database().dbplugin().providerName(),
+ self.name,
+ self.uri().uri(False),
+ )
def toMapLayer(self, geometryType=None, crs=None):
provider = self.database().dbplugin().providerName()
@@ -776,9 +923,9 @@ def geometryType(self):
pass
def getValidQgisUniqueFields(self, onlyOne=False):
- """ list of fields valid to load the table as layer in QGIS canvas.
- QGIS automatically search for a valid unique field, so it's
- needed only for queries and views """
+ """list of fields valid to load the table as layer in QGIS canvas.
+ QGIS automatically search for a valid unique field, so it's
+ needed only for queries and views"""
ret = []
@@ -793,7 +940,10 @@ def getValidQgisUniqueFields(self, onlyOne=False):
for idx in indexes:
if idx.isUnique and len(idx.columns) == 1:
fld = idx.fields()[idx.columns[0]]
- if fld.dataType in ["oid", "serial", "int4", "int8"] and fld not in ret:
+ if (
+ fld.dataType in ["oid", "serial", "int4", "int8"]
+ and fld not in ret
+ ):
ret.append(fld)
# and finally append the other suitable fields
@@ -809,11 +959,13 @@ def tableDataModel(self, parent):
pass
def tableFieldsFactory(self, row, table):
- raise NotImplementedError('Needs to be implemented by subclasses')
+ raise NotImplementedError("Needs to be implemented by subclasses")
def fields(self):
if self._fields is None:
- fields = self.database().connector.getTableFields((self.schemaName(), self.name))
+ fields = self.database().connector.getTableFields(
+ (self.schemaName(), self.name)
+ )
if fields is not None:
self._fields = [self.tableFieldsFactory(x, self) for x in fields]
return self._fields
@@ -824,14 +976,18 @@ def refreshFields(self):
def addField(self, fld):
self.aboutToChange.emit()
- ret = self.database().connector.addTableColumn((self.schemaName(), self.name), fld.definition())
+ ret = self.database().connector.addTableColumn(
+ (self.schemaName(), self.name), fld.definition()
+ )
if ret is not False:
self.refreshFields()
return ret
def deleteField(self, fld):
self.aboutToChange.emit()
- ret = self.database().connector.deleteTableColumn((self.schemaName(), self.name), fld.name)
+ ret = self.database().connector.deleteTableColumn(
+ (self.schemaName(), self.name), fld.name
+ )
if ret is not False:
self.refreshFields()
self.refreshConstraints()
@@ -840,7 +996,9 @@ def deleteField(self, fld):
def addGeometryColumn(self, geomCol, geomType, srid, dim, createSpatialIndex=False):
self.aboutToChange.emit()
- ret = self.database().connector.addGeometryColumn((self.schemaName(), self.name), geomCol, geomType, srid, dim)
+ ret = self.database().connector.addGeometryColumn(
+ (self.schemaName(), self.name), geomCol, geomType, srid, dim
+ )
if not ret:
return False
@@ -848,10 +1006,14 @@ def addGeometryColumn(self, geomCol, geomType, srid, dim, createSpatialIndex=Fal
if createSpatialIndex:
# commit data definition changes, otherwise index can't be built
self.database().connector._commit()
- self.database().connector.createSpatialIndex((self.schemaName(), self.name), geomCol)
+ self.database().connector.createSpatialIndex(
+ (self.schemaName(), self.name), geomCol
+ )
finally:
- self.schema().refresh() if self.schema() else self.database().refresh() # another table was added
+ (
+ self.schema().refresh() if self.schema() else self.database().refresh()
+ ) # another table was added
return True
def tableConstraintsFactory(self):
@@ -859,9 +1021,13 @@ def tableConstraintsFactory(self):
def constraints(self):
if self._constraints is None:
- constraints = self.database().connector.getTableConstraints((self.schemaName(), self.name))
+ constraints = self.database().connector.getTableConstraints(
+ (self.schemaName(), self.name)
+ )
if constraints is not None:
- self._constraints = [self.tableConstraintsFactory(x, self) for x in constraints]
+ self._constraints = [
+ self.tableConstraintsFactory(x, self) for x in constraints
+ ]
return self._constraints
def refreshConstraints(self):
@@ -871,11 +1037,13 @@ def refreshConstraints(self):
def addConstraint(self, constr):
self.aboutToChange.emit()
if constr.type == TableConstraint.TypePrimaryKey:
- ret = self.database().connector.addTablePrimaryKey((self.schemaName(), self.name),
- constr.fields()[constr.columns[0]].name)
+ ret = self.database().connector.addTablePrimaryKey(
+ (self.schemaName(), self.name), constr.fields()[constr.columns[0]].name
+ )
elif constr.type == TableConstraint.TypeUnique:
- ret = self.database().connector.addTableUniqueConstraint((self.schemaName(), self.name),
- constr.fields()[constr.columns[0]].name)
+ ret = self.database().connector.addTableUniqueConstraint(
+ (self.schemaName(), self.name), constr.fields()[constr.columns[0]].name
+ )
else:
return False
if ret is not False:
@@ -884,7 +1052,9 @@ def addConstraint(self, constr):
def deleteConstraint(self, constr):
self.aboutToChange.emit()
- ret = self.database().connector.deleteTableConstraint((self.schemaName(), self.name), constr.name)
+ ret = self.database().connector.deleteTableConstraint(
+ (self.schemaName(), self.name), constr.name
+ )
if ret is not False:
self.refreshConstraints()
return ret
@@ -894,7 +1064,9 @@ def tableIndexesFactory(self):
def indexes(self):
if self._indexes is None:
- indexes = self.database().connector.getTableIndexes((self.schemaName(), self.name))
+ indexes = self.database().connector.getTableIndexes(
+ (self.schemaName(), self.name)
+ )
if indexes is not None:
self._indexes = [self.tableIndexesFactory(x, self) for x in indexes]
return self._indexes
@@ -905,15 +1077,18 @@ def refreshIndexes(self):
def addIndex(self, idx):
self.aboutToChange.emit()
- ret = self.database().connector.createTableIndex((self.schemaName(), self.name), idx.name,
- idx.fields()[idx.columns[0]].name)
+ ret = self.database().connector.createTableIndex(
+ (self.schemaName(), self.name), idx.name, idx.fields()[idx.columns[0]].name
+ )
if ret is not False:
self.refreshIndexes()
return ret
def deleteIndex(self, idx):
self.aboutToChange.emit()
- ret = self.database().connector.deleteTableIndex((self.schemaName(), self.name), idx.name)
+ ret = self.database().connector.deleteTableIndex(
+ (self.schemaName(), self.name), idx.name
+ )
if ret is not False:
self.refreshIndexes()
return ret
@@ -923,7 +1098,9 @@ def tableTriggersFactory(self, row, table):
def triggers(self):
if self._triggers is None:
- triggers = self.database().connector.getTableTriggers((self.schemaName(), self.name))
+ triggers = self.database().connector.getTableTriggers(
+ (self.schemaName(), self.name)
+ )
if triggers is not None:
self._triggers = [self.tableTriggersFactory(x, self) for x in triggers]
return self._triggers
@@ -937,7 +1114,9 @@ def tableRulesFactory(self, row, table):
def rules(self):
if self._rules is None:
- rules = self.database().connector.getTableRules((self.schemaName(), self.name))
+ rules = self.database().connector.getTableRules(
+ (self.schemaName(), self.name)
+ )
if rules is not None:
self._rules = [self.tableRulesFactory(x, self) for x in rules]
return self._rules
@@ -950,7 +1129,9 @@ def refreshRowCount(self):
self.aboutToChange.emit()
prevRowCount = self.rowCount
try:
- self.rowCount = self.database().connector.getTableRowCount((self.schemaName(), self.name))
+ self.rowCount = self.database().connector.getTableRowCount(
+ (self.schemaName(), self.name)
+ )
self.rowCount = int(self.rowCount) if self.rowCount is not None else None
except DbError:
self.rowCount = None
@@ -966,14 +1147,23 @@ def runAction(self, action):
return True
elif action.startswith("triggers/"):
- parts = action.split('/')
+ parts = action.split("/")
trigger_action = parts[1]
- msg = QApplication.translate("DBManagerPlugin", "Do you want to {0} all triggers?").format(trigger_action)
+ msg = QApplication.translate(
+ "DBManagerPlugin", "Do you want to {0} all triggers?"
+ ).format(trigger_action)
QApplication.restoreOverrideCursor()
try:
- if QMessageBox.question(None, QApplication.translate("DBManagerPlugin", "Table triggers"), msg,
- QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No) == QMessageBox.StandardButton.No:
+ if (
+ QMessageBox.question(
+ None,
+ QApplication.translate("DBManagerPlugin", "Table triggers"),
+ msg,
+ QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No,
+ )
+ == QMessageBox.StandardButton.No
+ ):
return False
finally:
QApplication.setOverrideCursor(Qt.CursorShape.WaitCursor)
@@ -981,35 +1171,49 @@ def runAction(self, action):
if trigger_action == "enable" or trigger_action == "disable":
enable = trigger_action == "enable"
self.aboutToChange.emit()
- self.database().connector.enableAllTableTriggers(enable, (self.schemaName(), self.name))
+ self.database().connector.enableAllTableTriggers(
+ enable, (self.schemaName(), self.name)
+ )
self.refreshTriggers()
return True
elif action.startswith("trigger/"):
- parts = action.split('/')
+ parts = action.split("/")
trigger_name = parts[1]
trigger_action = parts[2]
- msg = QApplication.translate("DBManagerPlugin", "Do you want to {0} trigger {1}?").format(
- trigger_action, trigger_name)
+ msg = QApplication.translate(
+ "DBManagerPlugin", "Do you want to {0} trigger {1}?"
+ ).format(trigger_action, trigger_name)
QApplication.restoreOverrideCursor()
try:
- if QMessageBox.question(None, QApplication.translate("DBManagerPlugin", "Table trigger"), msg,
- QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No) == QMessageBox.StandardButton.No:
+ if (
+ QMessageBox.question(
+ None,
+ QApplication.translate("DBManagerPlugin", "Table trigger"),
+ msg,
+ QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No,
+ )
+ == QMessageBox.StandardButton.No
+ ):
return False
finally:
QApplication.setOverrideCursor(Qt.CursorShape.WaitCursor)
if trigger_action == "delete":
self.aboutToChange.emit()
- self.database().connector.deleteTableTrigger(trigger_name, (self.schemaName(), self.name))
+ self.database().connector.deleteTableTrigger(
+ trigger_name, (self.schemaName(), self.name)
+ )
self.refreshTriggers()
return True
elif trigger_action == "enable" or trigger_action == "disable":
enable = trigger_action == "enable"
self.aboutToChange.emit()
- self.database().connector.enableTableTrigger(trigger_name, enable, (self.schemaName(), self.name))
+ self.database().connector.enableTableTrigger(
+ trigger_name, enable, (self.schemaName(), self.name)
+ )
self.refreshTriggers()
return True
@@ -1023,7 +1227,9 @@ def addExtraContextMenuEntries(self, menu):
class VectorTable(Table):
def __init__(self, db, schema=None, parent=None):
- if not hasattr(self, 'type'): # check if the superclass constructor was called yet!
+ if not hasattr(
+ self, "type"
+ ): # check if the superclass constructor was called yet!
Table.__init__(self, db, schema, parent)
self.type = Table.VectorType
self.geomColumn = self.geomType = self.geomDim = self.srid = None
@@ -1060,7 +1266,9 @@ def hasSpatialIndex(self, geom_column=None):
def createSpatialIndex(self, geom_column=None):
self.aboutToChange.emit()
geom_column = geom_column if geom_column is not None else self.geomColumn
- ret = self.database().connector.createSpatialIndex((self.schemaName(), self.name), geom_column)
+ ret = self.database().connector.createSpatialIndex(
+ (self.schemaName(), self.name), geom_column
+ )
if ret is not False:
self.refreshIndexes()
return ret
@@ -1068,7 +1276,9 @@ def createSpatialIndex(self, geom_column=None):
def deleteSpatialIndex(self, geom_column=None):
self.aboutToChange.emit()
geom_column = geom_column if geom_column is not None else self.geomColumn
- ret = self.database().connector.deleteSpatialIndex((self.schemaName(), self.name), geom_column)
+ ret = self.database().connector.deleteSpatialIndex(
+ (self.schemaName(), self.name), geom_column
+ )
if ret is not False:
self.refreshIndexes()
return ret
@@ -1076,7 +1286,9 @@ def deleteSpatialIndex(self, geom_column=None):
def refreshTableExtent(self):
prevExtent = self.extent
try:
- self.extent = self.database().connector.getTableExtent((self.schemaName(), self.name), self.geomColumn)
+ self.extent = self.database().connector.getTableExtent(
+ (self.schemaName(), self.name), self.geomColumn
+ )
except DbError:
self.extent = None
if self.extent != prevExtent:
@@ -1085,8 +1297,9 @@ def refreshTableExtent(self):
def refreshTableEstimatedExtent(self):
prevEstimatedExtent = self.estimatedExtent
try:
- self.estimatedExtent = self.database().connector.getTableEstimatedExtent((self.schemaName(), self.name),
- self.geomColumn)
+ self.estimatedExtent = self.database().connector.getTableEstimatedExtent(
+ (self.schemaName(), self.name), self.geomColumn
+ )
except DbError:
self.estimatedExtent = None
if self.estimatedExtent != prevEstimatedExtent:
@@ -1096,15 +1309,23 @@ def runAction(self, action):
action = str(action)
if action.startswith("spatialindex/"):
- parts = action.split('/')
+ parts = action.split("/")
spatialIndex_action = parts[1]
- msg = QApplication.translate("DBManagerPlugin", "Do you want to {0} spatial index for field {1}?").format(
- spatialIndex_action, self.geomColumn)
+ msg = QApplication.translate(
+ "DBManagerPlugin", "Do you want to {0} spatial index for field {1}?"
+ ).format(spatialIndex_action, self.geomColumn)
QApplication.restoreOverrideCursor()
try:
- if QMessageBox.question(None, QApplication.translate("DBManagerPlugin", "Spatial Index"), msg,
- QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No) == QMessageBox.StandardButton.No:
+ if (
+ QMessageBox.question(
+ None,
+ QApplication.translate("DBManagerPlugin", "Spatial Index"),
+ msg,
+ QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No,
+ )
+ == QMessageBox.StandardButton.No
+ ):
return False
finally:
QApplication.setOverrideCursor(Qt.CursorShape.WaitCursor)
@@ -1131,48 +1352,67 @@ def addLayer(self, geometryType=None, crs=None):
layer = self.toMapLayer(geometryType, crs)
layers = QgsProject.instance().addMapLayers([layer])
if len(layers) != 1:
- QgsMessageLog.logMessage(self.tr("{layer} is an invalid layer - not loaded").format(layer=layer.publicSource()))
- msgLabel = QLabel(self.tr("{layer} is an invalid layer and cannot be loaded. Please check the message log for further info.").format(layer=layer.publicSource()), self.mainWindow.infoBar)
+ QgsMessageLog.logMessage(
+ self.tr("{layer} is an invalid layer - not loaded").format(
+ layer=layer.publicSource()
+ )
+ )
+ msgLabel = QLabel(
+ self.tr(
+ '{layer} is an invalid layer and cannot be loaded. Please check the message log for further info.'
+ ).format(layer=layer.publicSource()),
+ self.mainWindow.infoBar,
+ )
msgLabel.setWordWrap(True)
- msgLabel.linkActivated.connect(self.mainWindow.iface.mainWindow().findChild(QWidget, "MessageLog").show)
+ msgLabel.linkActivated.connect(
+ self.mainWindow.iface.mainWindow().findChild(QWidget, "MessageLog").show
+ )
msgLabel.linkActivated.connect(self.mainWindow.iface.mainWindow().raise_)
- self.mainWindow.infoBar.pushItem(QgsMessageBarItem(msgLabel, Qgis.MessageLevel.Warning))
+ self.mainWindow.infoBar.pushItem(
+ QgsMessageBarItem(msgLabel, Qgis.MessageLevel.Warning)
+ )
def showAdvancedVectorDialog(self):
dlg = QDialog()
- dlg.setObjectName('dbManagerAdvancedVectorDialog')
+ dlg.setObjectName("dbManagerAdvancedVectorDialog")
settings = QgsSettings()
- dlg.restoreGeometry(settings.value("/DB_Manager/advancedAddDialog/geometry", QByteArray(), type=QByteArray))
+ dlg.restoreGeometry(
+ settings.value(
+ "/DB_Manager/advancedAddDialog/geometry", QByteArray(), type=QByteArray
+ )
+ )
layout = QFormLayout()
dlg.setLayout(layout)
- dlg.setWindowTitle(self.tr('Add Layer {}').format(self.name))
+ dlg.setWindowTitle(self.tr("Add Layer {}").format(self.name))
geometryTypeComboBox = QComboBox()
- geometryTypeComboBox.addItem(self.tr('Point'), 'POINT')
- geometryTypeComboBox.addItem(self.tr('Line'), 'LINESTRING')
- geometryTypeComboBox.addItem(self.tr('Polygon'), 'POLYGON')
- layout.addRow(self.tr('Geometry Type'), geometryTypeComboBox)
- zCheckBox = QCheckBox(self.tr('With Z'))
- mCheckBox = QCheckBox(self.tr('With M'))
+ geometryTypeComboBox.addItem(self.tr("Point"), "POINT")
+ geometryTypeComboBox.addItem(self.tr("Line"), "LINESTRING")
+ geometryTypeComboBox.addItem(self.tr("Polygon"), "POLYGON")
+ layout.addRow(self.tr("Geometry Type"), geometryTypeComboBox)
+ zCheckBox = QCheckBox(self.tr("With Z"))
+ mCheckBox = QCheckBox(self.tr("With M"))
layout.addRow(zCheckBox)
layout.addRow(mCheckBox)
crsSelector = QgsProjectionSelectionWidget()
crsSelector.setCrs(self.crs())
- layout.addRow(self.tr('CRS'), crsSelector)
+ layout.addRow(self.tr("CRS"), crsSelector)
def selectedGeometryType():
geomType = geometryTypeComboBox.currentData()
if zCheckBox.isChecked():
- geomType += 'Z'
+ geomType += "Z"
if mCheckBox.isChecked():
- geomType += 'M'
+ geomType += "M"
return geomType
def selectedCrs():
return crsSelector.crs()
- addButton = QPushButton(self.tr('Load Layer'))
- addButton.clicked.connect(lambda: self.addLayer(selectedGeometryType(), selectedCrs()))
+ addButton = QPushButton(self.tr("Load Layer"))
+ addButton.clicked.connect(
+ lambda: self.addLayer(selectedGeometryType(), selectedCrs())
+ )
btns = QDialogButtonBox(QDialogButtonBox.StandardButton.Cancel)
btns.addButton(addButton, QDialogButtonBox.ButtonRole.ActionRole)
@@ -1190,17 +1430,24 @@ def selectedCrs():
def addExtraContextMenuEntries(self, menu):
"""Called whenever a context menu is shown for this table. Can be used to add additional actions to the menu."""
- if self.geomType == 'GEOMETRY':
- menu.addAction(QApplication.translate("DBManagerPlugin", "Add Layer (Advanced)…"), self.showAdvancedVectorDialog)
+ if self.geomType == "GEOMETRY":
+ menu.addAction(
+ QApplication.translate("DBManagerPlugin", "Add Layer (Advanced)…"),
+ self.showAdvancedVectorDialog,
+ )
class RasterTable(Table):
def __init__(self, db, schema=None, parent=None):
- if not hasattr(self, 'type'): # check if the superclass constructor was called yet!
+ if not hasattr(
+ self, "type"
+ ): # check if the superclass constructor was called yet!
Table.__init__(self, db, schema, parent)
self.type = Table.RasterType
- self.geomColumn = self.geomType = self.pixelSizeX = self.pixelSizeY = self.pixelType = self.isExternal = self.srid = None
+ self.geomColumn = self.geomType = self.pixelSizeX = self.pixelSizeY = (
+ self.pixelType
+ ) = self.isExternal = self.srid = None
self.extent = None
def info(self):
@@ -1225,35 +1472,41 @@ class TableField(TableSubItemObject):
def __init__(self, table):
TableSubItemObject.__init__(self, table)
- self.num = self.name = self.dataType = self.modifier = self.notNull = self.default = self.hasDefault = self.primaryKey = None
+ self.num = self.name = self.dataType = self.modifier = self.notNull = (
+ self.default
+ ) = self.hasDefault = self.primaryKey = None
self.comment = None
def type2String(self):
if self.modifier is None or self.modifier == -1:
return "%s" % self.dataType
- return "%s (%s)" % (self.dataType, self.modifier)
+ return f"{self.dataType} ({self.modifier})"
def default2String(self):
if not self.hasDefault:
- return ''
+ return ""
return self.default if self.default is not None else "NULL"
def definition(self):
from .connector import DBConnector
- quoteIdFunc = self.database().connector.quoteId if self.database() else DBConnector.quoteId
+ quoteIdFunc = (
+ self.database().connector.quoteId
+ if self.database()
+ else DBConnector.quoteId
+ )
name = quoteIdFunc(self.name)
not_null = "NOT NULL" if self.notNull else ""
- txt = "%s %s %s" % (name, self.type2String(), not_null)
+ txt = f"{name} {self.type2String()} {not_null}"
if self.hasDefault:
txt += " DEFAULT %s" % self.default2String()
return txt
def getComment(self):
"""Returns the comment for a field"""
- return ''
+ return ""
def delete(self):
return self.table().deleteField(self)
@@ -1261,7 +1514,14 @@ def delete(self):
def rename(self, new_name):
return self.update(new_name)
- def update(self, new_name, new_type_str=None, new_not_null=None, new_default_str=None, new_comment=None):
+ def update(
+ self,
+ new_name,
+ new_type_str=None,
+ new_not_null=None,
+ new_default_str=None,
+ new_comment=None,
+ ):
self.table().aboutToChange.emit()
if self.name == new_name:
new_name = None
@@ -1273,21 +1533,50 @@ def update(self, new_name, new_type_str=None, new_not_null=None, new_default_str
new_default_str = None
if self.comment == new_comment:
new_comment = None
- ret = self.table().database().connector.updateTableColumn((self.table().schemaName(), self.table().name),
- self.name, new_name, new_type_str,
- new_not_null, new_default_str, new_comment)
+ ret = (
+ self.table()
+ .database()
+ .connector.updateTableColumn(
+ (self.table().schemaName(), self.table().name),
+ self.name,
+ new_name,
+ new_type_str,
+ new_not_null,
+ new_default_str,
+ new_comment,
+ )
+ )
if ret is not False:
self.table().refreshFields()
return ret
class TableConstraint(TableSubItemObject):
- """ class that represents a constraint of a table (relation) """
-
- TypeCheck, TypeForeignKey, TypePrimaryKey, TypeUnique, TypeExclusion, TypeUnknown = list(range(6))
- types = {"c": TypeCheck, "f": TypeForeignKey, "p": TypePrimaryKey, "u": TypeUnique, "x": TypeExclusion}
-
- onAction = {"a": "NO ACTION", "r": "RESTRICT", "c": "CASCADE", "n": "SET NULL", "d": "SET DEFAULT"}
+ """class that represents a constraint of a table (relation)"""
+
+ (
+ TypeCheck,
+ TypeForeignKey,
+ TypePrimaryKey,
+ TypeUnique,
+ TypeExclusion,
+ TypeUnknown,
+ ) = list(range(6))
+ types = {
+ "c": TypeCheck,
+ "f": TypeForeignKey,
+ "p": TypePrimaryKey,
+ "u": TypeUnique,
+ "x": TypeExclusion,
+ }
+
+ onAction = {
+ "a": "NO ACTION",
+ "r": "RESTRICT",
+ "c": "CASCADE",
+ "n": "SET NULL",
+ "d": "SET DEFAULT",
+ }
matchTypes = {"u": "UNSPECIFIED", "f": "FULL", "p": "PARTIAL", "s": "SIMPLE"}
def __init__(self, table):
@@ -1305,11 +1594,11 @@ def type2String(self):
return QApplication.translate("DBManagerPlugin", "Unique")
if self.type == TableConstraint.TypeExclusion:
return QApplication.translate("DBManagerPlugin", "Exclusion")
- return QApplication.translate("DBManagerPlugin", 'Unknown')
+ return QApplication.translate("DBManagerPlugin", "Unknown")
def fields(self):
def fieldFromNum(num, fields):
- """ return field specified by its number or None if doesn't exist """
+ """return field specified by its number or None if doesn't exist"""
for fld in fields:
if fld.num == num:
return fld
@@ -1333,7 +1622,7 @@ def __init__(self, table):
def fields(self):
def fieldFromNum(num, fields):
- """ return field specified by its number or None if doesn't exist """
+ """return field specified by its number or None if doesn't exist"""
for fld in fields:
if fld.num == num:
return fld
@@ -1350,23 +1639,23 @@ def delete(self):
class TableTrigger(TableSubItemObject):
- """ class that represents a trigger """
+ """class that represents a trigger"""
# Bits within tgtype (pg_trigger.h)
- TypeRow = (1 << 0) # row or statement
- TypeBefore = (1 << 1) # before or after
+ TypeRow = 1 << 0 # row or statement
+ TypeBefore = 1 << 1 # before or after
# events: one or more
- TypeInsert = (1 << 2)
- TypeDelete = (1 << 3)
- TypeUpdate = (1 << 4)
- TypeTruncate = (1 << 5)
+ TypeInsert = 1 << 2
+ TypeDelete = 1 << 3
+ TypeUpdate = 1 << 4
+ TypeTruncate = 1 << 5
def __init__(self, table):
TableSubItemObject.__init__(self, table)
self.name = self.function = None
def type2String(self):
- trig_type = ''
+ trig_type = ""
trig_type += "Before " if self.type & TableTrigger.TypeBefore else "After "
if self.type & TableTrigger.TypeInsert:
trig_type += "INSERT "
diff --git a/python/plugins/db_manager/db_plugins/postgis/connector.py b/python/plugins/db_manager/db_plugins/postgis/connector.py
index afe4ae3fc3f6..af63f10dff09 100644
--- a/python/plugins/db_manager/db_plugins/postgis/connector.py
+++ b/python/plugins/db_manager/db_plugins/postgis/connector.py
@@ -52,7 +52,7 @@ def classFactory():
return PostGisDBConnector
-class CursorAdapter():
+class CursorAdapter:
def _debug(self, msg):
pass
@@ -66,7 +66,7 @@ def __init__(self, connection, sql=None, feedback=None):
self.cursor = 0
self.feedback = feedback
self.closed = False
- if (self.sql is not None):
+ if self.sql is not None:
self._execute()
def _toStrResultSet(self, res):
@@ -75,11 +75,15 @@ def _toStrResultSet(self, res):
newrec = []
for col in rec:
if type(col) == type(QVariant(None)): # noqa
- if (str(col) == 'NULL'):
+ if str(col) == "NULL":
col = None
else:
col = str(col) # force to string
- if isinstance(col, QDateTime) or isinstance(col, QDate) or isinstance(col, QTime):
+ if (
+ isinstance(col, QDateTime)
+ or isinstance(col, QDate)
+ or isinstance(col, QTime)
+ ):
col = col.toString(Qt.DateFormat.ISODate)
newrec.append(col)
newres.append(newrec)
@@ -88,9 +92,9 @@ def _toStrResultSet(self, res):
def _execute(self, sql=None):
if (sql is None or self.sql == sql) and self.result is not None:
return
- if (sql is not None):
+ if sql is not None:
self.sql = sql
- if (self.sql is None):
+ if self.sql is None:
return
self._debug("execute called with sql " + self.sql)
try:
@@ -98,15 +102,17 @@ def _execute(self, sql=None):
self._description = [] # reset description
self.result = self._toStrResultSet(result.rows())
for c in result.columns():
- self._description.append([
- c, # name
- '', # type_code
- -1, # display_size
- -1, # internal_size
- -1, # precision
- None, # scale
- True # null_ok
- ])
+ self._description.append(
+ [
+ c, # name
+ "", # type_code
+ -1, # display_size
+ -1, # internal_size
+ -1, # precision
+ None, # scale
+ True, # null_ok
+ ]
+ )
except QgsProviderConnectionException as e:
self._description = None
@@ -122,48 +128,62 @@ def description(self):
self._description = []
- if re.match('^SHOW', self.sql.strip().upper()):
+ if re.match("^SHOW", self.sql.strip().upper()):
try:
count = len(self.connection.executeSql(self.sql)[0])
except QgsProviderConnectionException:
count = 1
for i in range(count):
- self._description.append([
- '', # name
- '', # type_code
- -1, # display_size
- -1, # internal_size
- -1, # precision
- None, # scale
- True # null_ok
- ])
+ self._description.append(
+ [
+ "", # name
+ "", # type_code
+ -1, # display_size
+ -1, # internal_size
+ -1, # precision
+ None, # scale
+ True, # null_ok
+ ]
+ )
else:
uri = QgsDataSourceUri(self.connection.uri())
# TODO: make this part provider-agnostic
- sql = self.sql if self.sql.upper().find(' LIMIT ') >= 0 else self.sql + ' LIMIT 1 '
- uri.setTable('(SELECT row_number() OVER () AS __rid__, * FROM (' + sql + ') as foo)')
- uri.setKeyColumn('__rid__')
- uri.setParam('checkPrimaryKeyUnicity', '0')
+ sql = (
+ self.sql
+ if self.sql.upper().find(" LIMIT ") >= 0
+ else self.sql + " LIMIT 1 "
+ )
+ uri.setTable(
+ "(SELECT row_number() OVER () AS __rid__, * FROM ("
+ + sql
+ + ") as foo)"
+ )
+ uri.setKeyColumn("__rid__")
+ uri.setParam("checkPrimaryKeyUnicity", "0")
# TODO: fetch provider name from connection (QgsAbstractConnectionProvider)
# TODO: re-use the VectorLayer for fetching rows in batch mode
- vl = QgsVectorLayer(uri.uri(False), 'dbmanager_cursor', 'postgres')
+ vl = QgsVectorLayer(uri.uri(False), "dbmanager_cursor", "postgres")
fields = vl.fields()
for i in range(1, len(fields)): # skip first field (__rid__)
f = fields[i]
- self._description.append([
- f.name(), # name
- f.type(), # type_code
- f.length(), # display_size
- f.length(), # internal_size
- f.precision(), # precision
- None, # scale
- True # null_ok
- ])
-
- self._debug("get_description returned " + str(len(self._description)) + " cols")
+ self._description.append(
+ [
+ f.name(), # name
+ f.type(), # type_code
+ f.length(), # display_size
+ f.length(), # internal_size
+ f.precision(), # precision
+ None, # scale
+ True, # null_ok
+ ]
+ )
+
+ self._debug(
+ "get_description returned " + str(len(self._description)) + " cols"
+ )
return self._description
@@ -178,33 +198,49 @@ def fetchone(self):
def fetchmany(self, size):
self._execute()
if self.result is None:
- self._debug("fetchmany: none result after _execute (self.sql is " + str(self.sql) + ", returning []")
+ self._debug(
+ "fetchmany: none result after _execute (self.sql is "
+ + str(self.sql)
+ + ", returning []"
+ )
return []
leftover = len(self.result) - self.cursor
- self._debug("fetchmany: cursor: " + str(self.cursor) + " leftover: " + str(leftover) + " requested: " + str(size))
+ self._debug(
+ "fetchmany: cursor: "
+ + str(self.cursor)
+ + " leftover: "
+ + str(leftover)
+ + " requested: "
+ + str(size)
+ )
if leftover < 1:
return []
if size > leftover:
size = leftover
stop = self.cursor + size
- res = self.result[self.cursor:stop]
+ res = self.result[self.cursor : stop]
self.cursor = stop
- self._debug("fetchmany: new cursor: " + str(self.cursor) + " reslen: " + str(len(self.result)))
+ self._debug(
+ "fetchmany: new cursor: "
+ + str(self.cursor)
+ + " reslen: "
+ + str(len(self.result))
+ )
return res
def fetchall(self):
self._execute()
- res = self.result[self.cursor:]
+ res = self.result[self.cursor :]
self.cursor = len(self.result)
return res
- def scroll(self, pos, mode='relative'):
+ def scroll(self, pos, mode="relative"):
self._execute()
if pos < 0:
self._debug("scroll pos is negative: " + str(pos))
- if mode == 'relative':
+ if mode == "relative":
self.cursor = self.cursor + pos
- elif mode == 'absolute':
+ elif mode == "absolute":
self.cursor = pos
def close(self):
@@ -224,13 +260,13 @@ def __init__(self, uri, connection):
"""
DBConnector.__init__(self, uri)
- username = uri.username() or os.environ.get('PGUSER')
+ username = uri.username() or os.environ.get("PGUSER")
# Do not get db and user names from the env if service is used
if not uri.service():
if username is None:
- username = os.environ.get('USER')
- self.dbname = uri.database() or os.environ.get('PGDATABASE') or username
+ username = os.environ.get("USER")
+ self.dbname = uri.database() or os.environ.get("PGDATABASE") or username
uri.setDatabase(self.dbname)
# self.connName = connName
@@ -269,9 +305,13 @@ def removeCert(certFile):
# On linux and Mac if file is set with QFile::>ReadUser
# does not create problem removing certs
if not file.setPermissions(QFile.Permission.WriteOwner):
- raise Exception('Cannot change permissions on {}: error code: {}'.format(file.fileName(), file.error()))
+ raise Exception(
+ f"Cannot change permissions on {file.fileName()}: error code: {file.error()}"
+ )
if not file.remove():
- raise Exception('Cannot remove {}: error code: {}'.format(file.fileName(), file.error()))
+ raise Exception(
+ f"Cannot remove {file.fileName()}: error code: {file.error()}"
+ )
sslCertFile = expandedUri.param("sslcert")
if sslCertFile:
@@ -286,48 +326,59 @@ def removeCert(certFile):
removeCert(sslCAFile)
def _checkSpatial(self):
- """ check whether postgis_version is present in catalog """
- c = self._execute(None, "SELECT COUNT(*) FROM pg_proc WHERE proname = 'postgis_version'")
+ """check whether postgis_version is present in catalog"""
+ c = self._execute(
+ None, "SELECT COUNT(*) FROM pg_proc WHERE proname = 'postgis_version'"
+ )
self.has_spatial = self._fetchone(c)[0] > 0
self._close_cursor(c)
return self.has_spatial
def _checkRaster(self):
- """ check whether postgis_version is present in catalog """
- c = self._execute(None, "SELECT COUNT(*) FROM pg_proc WHERE proname = 'postgis_raster_lib_version'")
+ """check whether postgis_version is present in catalog"""
+ c = self._execute(
+ None,
+ "SELECT COUNT(*) FROM pg_proc WHERE proname = 'postgis_raster_lib_version'",
+ )
self.has_raster = self._fetchone(c)[0] > 0
self._close_cursor(c)
return self.has_raster
def _checkGeometryColumnsTable(self):
- c = self._execute(None,
- "SELECT relkind = 'v' OR relkind = 'm' FROM pg_class WHERE relname = 'geometry_columns' AND relkind IN ('v', 'r', 'm', 'p')")
+ c = self._execute(
+ None,
+ "SELECT relkind = 'v' OR relkind = 'm' FROM pg_class WHERE relname = 'geometry_columns' AND relkind IN ('v', 'r', 'm', 'p')",
+ )
res = self._fetchone(c)
self._close_cursor(c)
- self.has_geometry_columns = (res is not None and len(res) != 0)
+ self.has_geometry_columns = res is not None and len(res) != 0
if not self.has_geometry_columns:
self.has_geometry_columns_access = self.is_geometry_columns_view = False
else:
self.is_geometry_columns_view = res[0]
# find out whether has privileges to access geometry_columns table
- priv = self.getTablePrivileges('geometry_columns')
+ priv = self.getTablePrivileges("geometry_columns")
self.has_geometry_columns_access = priv[0]
return self.has_geometry_columns
def _checkRasterColumnsTable(self):
- c = self._execute(None,
- "SELECT relkind = 'v' OR relkind = 'm' FROM pg_class WHERE relname = 'raster_columns' AND relkind IN ('v', 'r', 'm', 'p')")
+ c = self._execute(
+ None,
+ "SELECT relkind = 'v' OR relkind = 'm' FROM pg_class WHERE relname = 'raster_columns' AND relkind IN ('v', 'r', 'm', 'p')",
+ )
res = self._fetchone(c)
self._close_cursor(c)
- self.has_raster_columns = (res is not None and len(res) != 0)
+ self.has_raster_columns = res is not None and len(res) != 0
if not self.has_raster_columns:
self.has_raster_columns_access = self.is_raster_columns_view = False
else:
self.is_raster_columns_view = res[0]
# find out whether has privileges to access geometry_columns table
- self.has_raster_columns_access = self.getTablePrivileges('raster_columns')[0]
+ self.has_raster_columns_access = self.getTablePrivileges("raster_columns")[
+ 0
+ ]
return self.has_raster_columns
def cancel(self):
@@ -350,19 +401,21 @@ def getPsqlVersion(self):
raise DbError(f"Unknown PostgreSQL version: {self.getInfo()[0]}")
def getSpatialInfo(self):
- """ returns tuple about PostGIS support:
- - lib version
- - geos version
- - proj version
- - installed scripts version
- - released scripts version
+ """returns tuple about PostGIS support:
+ - lib version
+ - geos version
+ - proj version
+ - installed scripts version
+ - released scripts version
"""
if not self.has_spatial:
return
try:
- c = self._execute(None,
- "SELECT postgis_lib_version(), postgis_geos_version(), postgis_proj_version(), postgis_scripts_installed(), postgis_scripts_released()")
+ c = self._execute(
+ None,
+ "SELECT postgis_lib_version(), postgis_geos_version(), postgis_proj_version(), postgis_scripts_installed(), postgis_scripts_released()",
+ )
except DbError:
return
res = self._fetchone(c)
@@ -386,16 +439,26 @@ def hasCreateSpatialViewSupport(self):
def fieldTypes(self):
return [
- "integer", "bigint", "smallint", # integers
- "serial", "bigserial", # auto-incrementing ints
- "real", "double precision", "numeric", # floats
- "varchar", "varchar(255)", "char(20)", "text", # strings
- "date", "time", "timestamp", # date/time
- "boolean" # bool
+ "integer",
+ "bigint",
+ "smallint", # integers
+ "serial",
+ "bigserial", # auto-incrementing ints
+ "real",
+ "double precision",
+ "numeric", # floats
+ "varchar",
+ "varchar(255)",
+ "char(20)",
+ "text", # strings
+ "date",
+ "time",
+ "timestamp", # date/time
+ "boolean", # bool
]
def getDatabasePrivileges(self):
- """ db privileges: (can create schemas, can create temp. tables) """
+ """db privileges: (can create schemas, can create temp. tables)"""
sql = "SELECT has_database_privilege(current_database(), 'CREATE'), has_database_privilege(current_database(), 'TEMP')"
c = self._execute(None, sql)
res = self._fetchone(c)
@@ -403,16 +466,18 @@ def getDatabasePrivileges(self):
return res
def getSchemaPrivileges(self, schema):
- """ schema privileges: (can create new objects, can access objects in schema) """
- schema = 'current_schema()' if schema is None else self.quoteString(schema)
- sql = "SELECT has_schema_privilege(%(s)s, 'CREATE'), has_schema_privilege(%(s)s, 'USAGE')" % {'s': schema}
+ """schema privileges: (can create new objects, can access objects in schema)"""
+ schema = "current_schema()" if schema is None else self.quoteString(schema)
+ sql = "SELECT has_schema_privilege({s}, 'CREATE'), has_schema_privilege({s}, 'USAGE')".format(
+ s=schema
+ )
c = self._execute(None, sql)
res = self._fetchone(c)
self._close_cursor(c)
return res
def getTablePrivileges(self, table):
- """ table privileges: (select, insert, update, delete) """
+ """table privileges: (select, insert, update, delete)"""
schema, tablename = self.getSchemaTableName(table)
schema_priv = self.getSchemaPrivileges(schema)
@@ -420,16 +485,17 @@ def getTablePrivileges(self, table):
return
t = self.quoteId(table)
- sql = """SELECT has_table_privilege(%(t)s, 'SELECT'), has_table_privilege(%(t)s, 'INSERT'),
- has_table_privilege(%(t)s, 'UPDATE'), has_table_privilege(%(t)s, 'DELETE')""" % {
- 't': self.quoteString(t)}
+ sql = """SELECT has_table_privilege({t}, 'SELECT'), has_table_privilege({t}, 'INSERT'),
+ has_table_privilege({t}, 'UPDATE'), has_table_privilege({t}, 'DELETE')""".format(
+ t=self.quoteString(t)
+ )
c = self._execute(None, sql)
res = self._fetchone(c)
self._close_cursor(c)
return res
def getSchemas(self):
- """ get list of schemas in tuples: (oid, name, owner, perms) """
+ """get list of schemas in tuples: (oid, name, owner, perms)"""
sql = "SELECT oid, nspname, pg_get_userbyid(nspowner), nspacl, pg_catalog.obj_description(oid) FROM pg_namespace WHERE nspname !~ '^pg_' AND nspname != 'information_schema' ORDER BY nspname"
c = self._execute(None, sql)
@@ -438,17 +504,26 @@ def getSchemas(self):
return res
def getTables(self, schema=None, add_sys_tables=False):
- """ get list of tables """
+ """get list of tables"""
tablenames = []
items = []
- sys_tables = ["spatial_ref_sys", "geography_columns", "geometry_columns",
- "raster_columns", "raster_overviews"]
+ sys_tables = [
+ "spatial_ref_sys",
+ "geography_columns",
+ "geometry_columns",
+ "raster_columns",
+ "raster_overviews",
+ ]
try:
vectors = self.getVectorTables(schema)
for tbl in vectors:
- if not add_sys_tables and tbl[1] in sys_tables and tbl[2] in ['', 'public']:
+ if (
+ not add_sys_tables
+ and tbl[1] in sys_tables
+ and tbl[2] in ["", "public"]
+ ):
continue
tablenames.append((tbl[2], tbl[1]))
items.append(tbl)
@@ -458,30 +533,45 @@ def getTables(self, schema=None, add_sys_tables=False):
try:
rasters = self.getRasterTables(schema)
for tbl in rasters:
- if not add_sys_tables and tbl[1] in sys_tables and tbl[2] in ['', 'public']:
+ if (
+ not add_sys_tables
+ and tbl[1] in sys_tables
+ and tbl[2] in ["", "public"]
+ ):
continue
tablenames.append((tbl[2], tbl[1]))
items.append(tbl)
except DbError:
pass
- sys_tables = ["spatial_ref_sys", "geography_columns", "geometry_columns",
- "raster_columns", "raster_overviews"]
+ sys_tables = [
+ "spatial_ref_sys",
+ "geography_columns",
+ "geometry_columns",
+ "raster_columns",
+ "raster_overviews",
+ ]
if schema:
schema_where = " AND nspname = %s " % self.quoteString(schema)
else:
- schema_where = " AND (nspname != 'information_schema' AND nspname !~ 'pg_') "
+ schema_where = (
+ " AND (nspname != 'information_schema' AND nspname !~ 'pg_') "
+ )
# get all tables and views
- sql = """SELECT
+ sql = (
+ """SELECT
cla.relname, nsp.nspname, cla.relkind,
pg_get_userbyid(relowner), reltuples, relpages,
pg_catalog.obj_description(cla.oid)
FROM pg_class AS cla
JOIN pg_namespace AS nsp ON nsp.oid = cla.relnamespace
- WHERE cla.relkind IN ('v', 'r', 'm', 'p') """ + schema_where + """
+ WHERE cla.relkind IN ('v', 'r', 'm', 'p') """
+ + schema_where
+ + """
ORDER BY nsp.nspname, cla.relname"""
+ )
c = self._execute(None, sql)
for tbl in self._fetchall(c):
@@ -494,19 +584,19 @@ def getTables(self, schema=None, add_sys_tables=False):
return sorted(items, key=cmp_to_key(lambda x, y: (x[1] > y[1]) - (x[1] < y[1])))
def getVectorTables(self, schema=None):
- """ get list of table with a geometry column
- it returns:
- name (table name)
- namespace (schema)
- type = 'view' (is a view?)
- owner
- tuples
- pages
- geometry_column:
- f_geometry_column (or pg_attribute.attname, the geometry column name)
- type (or pg_attribute.atttypid::regtype, the geometry column type name)
- coord_dimension
- srid
+ """get list of table with a geometry column
+ it returns:
+ name (table name)
+ namespace (schema)
+ type = 'view' (is a view?)
+ owner
+ tuples
+ pages
+ geometry_column:
+ f_geometry_column (or pg_attribute.attname, the geometry column name)
+ type (or pg_attribute.atttypid::regtype, the geometry column type name)
+ coord_dimension
+ srid
"""
if not self.has_spatial:
@@ -515,7 +605,9 @@ def getVectorTables(self, schema=None):
if schema:
schema_where = " AND nspname = %s " % self.quoteString(schema)
else:
- schema_where = " AND (nspname != 'information_schema' AND nspname !~ 'pg_') "
+ schema_where = (
+ " AND (nspname != 'information_schema' AND nspname !~ 'pg_') "
+ )
geometry_column_from = ""
geometry_fields_select = """att.attname,
@@ -530,11 +622,14 @@ def getVectorTables(self, schema=None):
geo.coord_dimension, geo.srid"""
# discovery of all tables and whether they contain a geometry column
- sql = """SELECT
+ sql = (
+ """SELECT
cla.relname, nsp.nspname, cla.relkind,
pg_get_userbyid(relowner), cla.reltuples, cla.relpages,
pg_catalog.obj_description(cla.oid),
- """ + geometry_fields_select + """
+ """
+ + geometry_fields_select
+ + """
FROM pg_class AS cla
JOIN pg_namespace AS nsp ON
@@ -545,10 +640,15 @@ def getVectorTables(self, schema=None):
att.atttypid = 'geometry'::regtype OR
att.atttypid IN (SELECT oid FROM pg_type WHERE typbasetype='geometry'::regtype )
- """ + geometry_column_from + """
+ """
+ + geometry_column_from
+ + """
- WHERE cla.relkind IN ('v', 'r', 'm', 'p') """ + schema_where + """
+ WHERE cla.relkind IN ('v', 'r', 'm', 'p') """
+ + schema_where
+ + """
ORDER BY nsp.nspname, cla.relname, att.attname"""
+ )
items = []
@@ -562,20 +662,20 @@ def getVectorTables(self, schema=None):
return items
def getRasterTables(self, schema=None):
- """ get list of table with a raster column
- it returns:
- name (table name)
- namespace (schema)
- type = 'view' (is a view?)
- owner
- tuples
- pages
- raster_column:
- r_raster_column (or pg_attribute.attname, the raster column name)
- pixel type
- block size
- internal or external
- srid
+ """get list of table with a raster column
+ it returns:
+ name (table name)
+ namespace (schema)
+ type = 'view' (is a view?)
+ owner
+ tuples
+ pages
+ raster_column:
+ r_raster_column (or pg_attribute.attname, the raster column name)
+ pixel type
+ block size
+ internal or external
+ srid
"""
if not self.has_spatial:
@@ -586,7 +686,9 @@ def getRasterTables(self, schema=None):
if schema:
schema_where = " AND nspname = %s " % self.quoteString(schema)
else:
- schema_where = " AND (nspname != 'information_schema' AND nspname !~ 'pg_') "
+ schema_where = (
+ " AND (nspname != 'information_schema' AND nspname !~ 'pg_') "
+ )
raster_column_from = ""
raster_fields_select = """att.attname, NULL, NULL, NULL, NULL, NULL"""
@@ -602,11 +704,14 @@ def getRasterTables(self, schema=None):
rast.srid"""
# discovery of all tables and whether they contain a raster column
- sql = """SELECT
+ sql = (
+ """SELECT
cla.relname, nsp.nspname, cla.relkind,
pg_get_userbyid(relowner), cla.reltuples, cla.relpages,
pg_catalog.obj_description(cla.oid),
- """ + raster_fields_select + """
+ """
+ + raster_fields_select
+ + """
FROM pg_class AS cla
JOIN pg_namespace AS nsp ON
@@ -617,10 +722,15 @@ def getRasterTables(self, schema=None):
att.atttypid = 'raster'::regtype OR
att.atttypid IN (SELECT oid FROM pg_type WHERE typbasetype='raster'::regtype )
- """ + raster_column_from + """
+ """
+ + raster_column_from
+ + """
- WHERE cla.relkind IN ('v', 'r', 'm', 'p') """ + schema_where + """
+ WHERE cla.relkind IN ('v', 'r', 'm', 'p') """
+ + schema_where
+ + """
ORDER BY nsp.nspname, cla.relname, att.attname"""
+ )
items = []
@@ -640,13 +750,15 @@ def getTableRowCount(self, table):
return res
def getTableFields(self, table):
- """ return list of columns in table """
+ """return list of columns in table"""
schema, tablename = self.getSchemaTableName(table)
- schema_where = " AND nspname=%s " % self.quoteString(schema) if schema is not None else ""
+ schema_where = (
+ " AND nspname=%s " % self.quoteString(schema) if schema is not None else ""
+ )
version_number = self.getPsqlVersion()
- ad_col_name = 'adsrc' if version_number < 12 else 'adbin'
+ ad_col_name = "adsrc" if version_number < 12 else "adbin"
sql = """SELECT a.attnum AS ordinal_position,
a.attname AS column_name,
@@ -655,7 +767,7 @@ def getTableFields(self, table):
a.atttypmod AS modifier,
a.attnotnull AS notnull,
a.atthasdef AS hasdefault,
- adef.%s AS default_value,
+ adef.{} AS default_value,
pg_catalog.format_type(a.atttypid,a.atttypmod) AS formatted_type
FROM pg_class c
JOIN pg_attribute a ON a.attrelid = c.oid
@@ -663,8 +775,10 @@ def getTableFields(self, table):
JOIN pg_namespace nsp ON c.relnamespace = nsp.oid
LEFT JOIN pg_attrdef adef ON adef.adrelid = a.attrelid AND adef.adnum = a.attnum
WHERE
- a.attnum > 0 AND c.relname=%s %s
- ORDER BY a.attnum""" % (ad_col_name, self.quoteString(tablename), schema_where)
+ a.attnum > 0 AND c.relname={} {}
+ ORDER BY a.attnum""".format(
+ ad_col_name, self.quoteString(tablename), schema_where
+ )
c = self._execute(None, sql)
res = self._fetchall(c)
@@ -672,17 +786,20 @@ def getTableFields(self, table):
return res
def getTableIndexes(self, table):
- """ get info about table's indexes. ignore primary key constraint index, they get listed in constraints """
+ """get info about table's indexes. ignore primary key constraint index, they get listed in constraints"""
schema, tablename = self.getSchemaTableName(table)
- schema_where = " AND nspname=%s " % self.quoteString(schema) if schema is not None else ""
+ schema_where = (
+ " AND nspname=%s " % self.quoteString(schema) if schema is not None else ""
+ )
sql = """SELECT idxcls.relname, indkey, indisunique = 't'
FROM pg_index JOIN pg_class ON pg_index.indrelid=pg_class.oid
JOIN pg_class AS idxcls ON pg_index.indexrelid=idxcls.oid
JOIN pg_namespace nsp ON pg_class.relnamespace = nsp.oid
- WHERE pg_class.relname=%s %s
- AND indisprimary != 't' """ % (
- self.quoteString(tablename), schema_where)
+ WHERE pg_class.relname={} {}
+ AND indisprimary != 't' """.format(
+ self.quoteString(tablename), schema_where
+ )
c = self._execute(None, sql)
res = self._fetchall(c)
self._close_cursor(c)
@@ -691,20 +808,24 @@ def getTableIndexes(self, table):
def getTableConstraints(self, table):
schema, tablename = self.getSchemaTableName(table)
- schema_where = " AND nspname=%s " % self.quoteString(schema) if schema is not None else ""
+ schema_where = (
+ " AND nspname=%s " % self.quoteString(schema) if schema is not None else ""
+ )
version_number = self.getPsqlVersion()
- con_col_name = 'consrc' if version_number < 12 else 'conbin'
+ con_col_name = "consrc" if version_number < 12 else "conbin"
# In the query below, we exclude rows where pg_constraint.contype whose values are equal to 't'
# because 't' describes a CONSTRAINT TRIGGER, which is not really a constraint in the traditional
# sense, but a special type of trigger, and an extension to the SQL standard.
- sql = """SELECT c.conname, c.contype, c.condeferrable, c.condeferred, array_to_string(c.conkey, ' '), c.%s,
+ sql = """SELECT c.conname, c.contype, c.condeferrable, c.condeferred, array_to_string(c.conkey, ' '), c.{},
t2.relname, c.confupdtype, c.confdeltype, c.confmatchtype, array_to_string(c.confkey, ' ') FROM pg_constraint c
LEFT JOIN pg_class t ON c.conrelid = t.oid
LEFT JOIN pg_class t2 ON c.confrelid = t2.oid
JOIN pg_namespace nsp ON t.relnamespace = nsp.oid
- WHERE c.contype <> 't' AND t.relname = %s %s """ % (con_col_name, self.quoteString(tablename), schema_where)
+ WHERE c.contype <> 't' AND t.relname = {} {} """.format(
+ con_col_name, self.quoteString(tablename), schema_where
+ )
c = self._execute(None, sql)
res = self._fetchall(c)
@@ -714,14 +835,17 @@ def getTableConstraints(self, table):
def getTableTriggers(self, table):
schema, tablename = self.getSchemaTableName(table)
- schema_where = " AND nspname=%s " % self.quoteString(schema) if schema is not None else ""
+ schema_where = (
+ " AND nspname=%s " % self.quoteString(schema) if schema is not None else ""
+ )
sql = """SELECT tgname, proname, tgtype, tgenabled NOT IN ('f', 'D') FROM pg_trigger trig
LEFT JOIN pg_class t ON trig.tgrelid = t.oid
LEFT JOIN pg_proc p ON trig.tgfoid = p.oid
JOIN pg_namespace nsp ON t.relnamespace = nsp.oid
- WHERE t.relname = %s %s """ % (
- self.quoteString(tablename), schema_where)
+ WHERE t.relname = {} {} """.format(
+ self.quoteString(tablename), schema_where
+ )
c = self._execute(None, sql)
res = self._fetchall(c)
@@ -729,27 +853,35 @@ def getTableTriggers(self, table):
return res
def enableAllTableTriggers(self, enable, table):
- """ enable or disable all triggers on table """
+ """enable or disable all triggers on table"""
self.enableTableTrigger(None, enable, table)
def enableTableTrigger(self, trigger, enable, table):
- """ enable or disable one trigger on table """
+ """enable or disable one trigger on table"""
trigger = self.quoteId(trigger) if trigger is not None else "ALL"
- sql = "ALTER TABLE %s %s TRIGGER %s" % (self.quoteId(table), "ENABLE" if enable else "DISABLE", trigger)
+ sql = "ALTER TABLE {} {} TRIGGER {}".format(
+ self.quoteId(table), "ENABLE" if enable else "DISABLE", trigger
+ )
self._execute_and_commit(sql)
def deleteTableTrigger(self, trigger, table):
- """Deletes trigger on table """
- sql = "DROP TRIGGER %s ON %s" % (self.quoteId(trigger), self.quoteId(table))
+ """Deletes trigger on table"""
+ sql = f"DROP TRIGGER {self.quoteId(trigger)} ON {self.quoteId(table)}"
self._execute_and_commit(sql)
def getTableRules(self, table):
schema, tablename = self.getSchemaTableName(table)
- schema_where = " AND schemaname=%s " % self.quoteString(schema) if schema is not None else ""
+ schema_where = (
+ " AND schemaname=%s " % self.quoteString(schema)
+ if schema is not None
+ else ""
+ )
sql = """SELECT rulename, definition FROM pg_rules
- WHERE tablename=%s %s """ % (self.quoteString(tablename), schema_where)
+ WHERE tablename={} {} """.format(
+ self.quoteString(tablename), schema_where
+ )
c = self._execute(None, sql)
res = self._fetchall(c)
@@ -757,14 +889,19 @@ def getTableRules(self, table):
return res
def deleteTableRule(self, rule, table):
- """Deletes rule on table """
- sql = "DROP RULE %s ON %s" % (self.quoteId(rule), self.quoteId(table))
+ """Deletes rule on table"""
+ sql = f"DROP RULE {self.quoteId(rule)} ON {self.quoteId(table)}"
self._execute_and_commit(sql)
def getTableExtent(self, table, geom):
- """ find out table extent """
- subquery = "SELECT st_extent(%s) AS extent FROM %s" % (self.quoteId(geom), self.quoteId(table))
- sql = "SELECT st_xmin(extent), st_ymin(extent), st_xmax(extent), st_ymax(extent) FROM (%s) AS subquery" % subquery
+ """find out table extent"""
+ subquery = "SELECT st_extent({}) AS extent FROM {}".format(
+ self.quoteId(geom), self.quoteId(table)
+ )
+ sql = (
+ "SELECT st_xmin(extent), st_ymin(extent), st_xmax(extent), st_ymax(extent) FROM (%s) AS subquery"
+ % subquery
+ )
c = self._execute(None, sql)
res = self._fetchone(c)
@@ -772,14 +909,14 @@ def getTableExtent(self, table, geom):
return res
def getTableEstimatedExtent(self, table, geom):
- """ find out estimated extent (from the statistics) """
+ """find out estimated extent (from the statistics)"""
if self.isRasterTable(table):
return
schema, tablename = self.getSchemaTableName(table)
schema_part = "%s," % self.quoteString(schema) if schema is not None else ""
- pgis_versions = self.getSpatialInfo()[0].split('.')
+ pgis_versions = self.getSpatialInfo()[0].split(".")
pgis_major_version = int(pgis_versions[0])
pgis_minor_version = int(pgis_versions[1])
pgis_old = False
@@ -787,10 +924,16 @@ def getTableEstimatedExtent(self, table, geom):
pgis_old = True
elif pgis_major_version == 2 and pgis_minor_version < 1:
pgis_old = True
- subquery = "SELECT %s(%s%s,%s) AS extent" % (
- 'st_estimated_extent' if pgis_old else 'st_estimatedextent',
- schema_part, self.quoteString(tablename), self.quoteString(geom))
- sql = """SELECT st_xmin(extent), st_ymin(extent), st_xmax(extent), st_ymax(extent) FROM (%s) AS subquery """ % subquery
+ subquery = "SELECT {}({}{},{}) AS extent".format(
+ "st_estimated_extent" if pgis_old else "st_estimatedextent",
+ schema_part,
+ self.quoteString(tablename),
+ self.quoteString(geom),
+ )
+ sql = (
+ """SELECT st_xmin(extent), st_ymin(extent), st_xmax(extent), st_ymax(extent) FROM (%s) AS subquery """
+ % subquery
+ )
try:
c = self._execute(None, sql)
@@ -801,15 +944,18 @@ def getTableEstimatedExtent(self, table, geom):
return res
def getViewDefinition(self, view):
- """ returns definition of the view """
+ """returns definition of the view"""
schema, tablename = self.getSchemaTableName(view)
- schema_where = " AND nspname=%s " % self.quoteString(schema) if schema is not None else ""
+ schema_where = (
+ " AND nspname=%s " % self.quoteString(schema) if schema is not None else ""
+ )
sql = """SELECT pg_get_viewdef(c.oid) FROM pg_class c
JOIN pg_namespace nsp ON c.relnamespace = nsp.oid
- WHERE relname=%s %s AND (relkind='v' OR relkind='m') """ % (
- self.quoteString(tablename), schema_where)
+ WHERE relname={} {} AND (relkind='v' OR relkind='m') """.format(
+ self.quoteString(tablename), schema_where
+ )
c = self._execute(None, sql)
res = self._fetchone(c)
@@ -821,7 +967,9 @@ def getCrs(self, srid):
return QgsCoordinateReferenceSystem()
try:
- c = self._execute(None, "SELECT proj4text FROM spatial_ref_sys WHERE srid = '%d'" % srid)
+ c = self._execute(
+ None, "SELECT proj4text FROM spatial_ref_sys WHERE srid = '%d'" % srid
+ )
except DbError:
return QgsCoordinateReferenceSystem()
res = self._fetchone(c)
@@ -838,7 +986,9 @@ def getSpatialRefInfo(self, srid):
return
try:
- c = self._execute(None, "SELECT srtext FROM spatial_ref_sys WHERE srid = '%d'" % srid)
+ c = self._execute(
+ None, "SELECT srtext FROM spatial_ref_sys WHERE srid = '%d'" % srid
+ )
except DbError:
return
sr = self._fetchone(c)
@@ -857,8 +1007,9 @@ def getSpatialRefInfo(self, srid):
def isVectorTable(self, table):
if self.has_geometry_columns and self.has_geometry_columns_access:
schema, tablename = self.getSchemaTableName(table)
- sql = "SELECT count(*) FROM geometry_columns WHERE f_table_schema = %s AND f_table_name = %s" % (
- self.quoteString(schema), self.quoteString(tablename))
+ sql = "SELECT count(*) FROM geometry_columns WHERE f_table_schema = {} AND f_table_name = {}".format(
+ self.quoteString(schema), self.quoteString(tablename)
+ )
c = self._execute(None, sql)
res = self._fetchone(c)
@@ -870,8 +1021,9 @@ def isVectorTable(self, table):
def isRasterTable(self, table):
if self.has_raster_columns and self.has_raster_columns_access:
schema, tablename = self.getSchemaTableName(table)
- sql = "SELECT count(*) FROM raster_columns WHERE r_table_schema = %s AND r_table_name = %s" % (
- self.quoteString(schema), self.quoteString(tablename))
+ sql = "SELECT count(*) FROM raster_columns WHERE r_table_schema = {} AND r_table_name = {}".format(
+ self.quoteString(schema), self.quoteString(tablename)
+ )
c = self._execute(None, sql)
res = self._fetchone(c)
@@ -882,8 +1034,8 @@ def isRasterTable(self, table):
def createTable(self, table, field_defs, pkey):
"""Creates ordinary table
- 'fields' is array containing field definitions
- 'pkey' is the primary key name
+ 'fields' is array containing field definitions
+ 'pkey' is the primary key name
"""
if len(field_defs) == 0:
return False
@@ -898,11 +1050,13 @@ def createTable(self, table, field_defs, pkey):
return True
def deleteTable(self, table):
- """Deletes table and its reference in either geometry_columns or raster_columns """
+ """Deletes table and its reference in either geometry_columns or raster_columns"""
schema, tablename = self.getSchemaTableName(table)
schema_part = "%s, " % self.quoteString(schema) if schema is not None else ""
if self.isVectorTable(table):
- sql = "SELECT DropGeometryTable(%s%s)" % (schema_part, self.quoteString(tablename))
+ sql = "SELECT DropGeometryTable({}{})".format(
+ schema_part, self.quoteString(tablename)
+ )
elif self.isRasterTable(table):
# Fix #8521: delete raster table and references from raster_columns table
sql = "DROP TABLE %s" % self.quoteId(table)
@@ -911,24 +1065,31 @@ def deleteTable(self, table):
self._execute_and_commit(sql)
def emptyTable(self, table):
- """Deletes all rows from table """
+ """Deletes all rows from table"""
sql = "TRUNCATE %s" % self.quoteId(table)
self._execute_and_commit(sql)
def renameTable(self, table, new_table):
- """Renames a table in database """
+ """Renames a table in database"""
schema, tablename = self.getSchemaTableName(table)
if new_table == tablename:
return
- sql = "ALTER TABLE %s RENAME TO %s" % (self.quoteId(table), self.quoteId(new_table))
+ sql = "ALTER TABLE {} RENAME TO {}".format(
+ self.quoteId(table), self.quoteId(new_table)
+ )
self._executeSql(sql)
# update geometry_columns if PostGIS is enabled
if self.has_geometry_columns and not self.is_geometry_columns_view:
- schema_where = " AND f_table_schema=%s " % self.quoteString(schema) if schema is not None else ""
- sql = "UPDATE geometry_columns SET f_table_name=%s WHERE f_table_name=%s %s" % (
- self.quoteString(new_table), self.quoteString(tablename), schema_where)
+ schema_where = (
+ " AND f_table_schema=%s " % self.quoteString(schema)
+ if schema is not None
+ else ""
+ )
+ sql = "UPDATE geometry_columns SET f_table_name={} WHERE f_table_name={} {}".format(
+ self.quoteString(new_table), self.quoteString(tablename), schema_where
+ )
self._executeSql(sql)
def renameSchema(self, schema, new_schema):
@@ -940,16 +1101,23 @@ def renameSchema(self, schema, new_schema):
def commentTable(self, schema, tablename, comment=None):
if comment is None:
- self._execute(None, 'COMMENT ON TABLE "{}"."{}" IS NULL;'.format(schema, tablename))
+ self._execute(None, f'COMMENT ON TABLE "{schema}"."{tablename}" IS NULL;')
else:
- self._execute(None, 'COMMENT ON TABLE "{}"."{}" IS $escape${}$escape$;'.format(schema, tablename, comment))
+ self._execute(
+ None,
+ f'COMMENT ON TABLE "{schema}"."{tablename}" IS $escape${comment}$escape$;',
+ )
def getComment(self, tablename, field):
"""Returns the comment for a field"""
# SQL Query checking if a comment exists for the field
- sql_cpt = "Select count(*) from pg_description pd, pg_class pc, pg_attribute pa where relname = '%s' and attname = '%s' and pa.attrelid = pc.oid and pd.objoid = pc.oid and pd.objsubid = pa.attnum" % (tablename, field)
+ sql_cpt = "Select count(*) from pg_description pd, pg_class pc, pg_attribute pa where relname = '{}' and attname = '{}' and pa.attrelid = pc.oid and pd.objoid = pc.oid and pd.objsubid = pa.attnum".format(
+ tablename, field
+ )
# SQL Query that return the comment of the field
- sql = "Select pd.description from pg_description pd, pg_class pc, pg_attribute pa where relname = '%s' and attname = '%s' and pa.attrelid = pc.oid and pd.objoid = pc.oid and pd.objsubid = pa.attnum" % (tablename, field)
+ sql = "Select pd.description from pg_description pd, pg_class pc, pg_attribute pa where relname = '{}' and attname = '{}' and pa.attrelid = pc.oid and pd.objoid = pc.oid and pd.objsubid = pa.attnum".format(
+ tablename, field
+ )
c = self._execute(None, sql_cpt) # Execute Check query
res = self._fetchone(c)[0] # Store result
if res == 1:
@@ -959,7 +1127,7 @@ def getComment(self, tablename, field):
self._close_cursor(c) # Close cursor
return res # Return comment
else:
- return ''
+ return ""
def moveTableToSchema(self, table, new_schema):
schema, tablename = self.getSchemaTableName(table)
@@ -968,15 +1136,22 @@ def moveTableToSchema(self, table, new_schema):
c = self._get_cursor()
- sql = "ALTER TABLE %s SET SCHEMA %s" % (self.quoteId(table), self.quoteId(new_schema))
+ sql = "ALTER TABLE {} SET SCHEMA {}".format(
+ self.quoteId(table), self.quoteId(new_schema)
+ )
self._execute(c, sql)
# update geometry_columns if PostGIS is enabled
if self.has_geometry_columns and not self.is_geometry_columns_view:
schema, tablename = self.getSchemaTableName(table)
- schema_where = " AND f_table_schema=%s " % self.quoteString(schema) if schema is not None else ""
- sql = "UPDATE geometry_columns SET f_table_schema=%s WHERE f_table_name=%s %s" % (
- self.quoteString(new_schema), self.quoteString(tablename), schema_where)
+ schema_where = (
+ " AND f_table_schema=%s " % self.quoteString(schema)
+ if schema is not None
+ else ""
+ )
+ sql = "UPDATE geometry_columns SET f_table_schema={} WHERE f_table_name={} {}".format(
+ self.quoteString(new_schema), self.quoteString(tablename), schema_where
+ )
self._execute(c, sql)
self._commit()
@@ -993,100 +1168,145 @@ def moveTable(self, table, new_table, new_schema=None):
c = self._get_cursor()
t = "__new_table__"
- sql = "ALTER TABLE %s RENAME TO %s" % (self.quoteId(table), self.quoteId(t))
+ sql = "ALTER TABLE {} RENAME TO {}".format(
+ self.quoteId(table), self.quoteId(t)
+ )
self._execute(c, sql)
- sql = "ALTER TABLE %s SET SCHEMA %s" % (self.quoteId((schema, t)), self.quoteId(new_schema))
+ sql = "ALTER TABLE {} SET SCHEMA {}".format(
+ self.quoteId((schema, t)), self.quoteId(new_schema)
+ )
self._execute(c, sql)
- sql = "ALTER TABLE %s RENAME TO %s" % (self.quoteId((new_schema, t)), self.quoteId(table))
+ sql = "ALTER TABLE {} RENAME TO {}".format(
+ self.quoteId((new_schema, t)), self.quoteId(table)
+ )
self._execute(c, sql)
# update geometry_columns if PostGIS is enabled
if self.has_geometry_columns and not self.is_geometry_columns_view:
schema, tablename = self.getSchemaTableName(table)
- schema_where = " f_table_schema=%s AND " % self.quoteString(schema) if schema is not None else ""
- schema_part = " f_table_schema=%s, " % self.quoteString(new_schema) if schema is not None else ""
- sql = "UPDATE geometry_columns SET %s f_table_name=%s WHERE %s f_table_name=%s" % (
- schema_part, self.quoteString(new_table), schema_where, self.quoteString(tablename))
+ schema_where = (
+ " f_table_schema=%s AND " % self.quoteString(schema)
+ if schema is not None
+ else ""
+ )
+ schema_part = (
+ " f_table_schema=%s, " % self.quoteString(new_schema)
+ if schema is not None
+ else ""
+ )
+ sql = "UPDATE geometry_columns SET {} f_table_name={} WHERE {} f_table_name={}".format(
+ schema_part,
+ self.quoteString(new_table),
+ schema_where,
+ self.quoteString(tablename),
+ )
self._execute(c, sql)
self._commit()
def createView(self, view, query):
- view_name_parts = view.split('.')
+ view_name_parts = view.split(".")
if len(view_name_parts) > 2:
# Raise an error when more than one period is used.
- raise DbError("Invalid view name: Please use the format 'schema.viewname', or enter only the viewname for the public schema.")
+ raise DbError(
+ "Invalid view name: Please use the format 'schema.viewname', or enter only the viewname for the public schema."
+ )
elif len(view_name_parts) == 2: # To allow view creation into specified schema
schema, view_name = view_name_parts
- sql = "CREATE VIEW %s AS %s" % (self.quoteId([schema, view_name]), query)
+ sql = "CREATE VIEW {} AS {}".format(
+ self.quoteId([schema, view_name]), query
+ )
else: # No specific schema specified
- sql = "CREATE VIEW %s AS %s" % (self.quoteId(view), query)
+ sql = f"CREATE VIEW {self.quoteId(view)} AS {query}"
self._execute_and_commit(sql)
def createSpatialView(self, view, query):
self.createView(view, query)
def deleteView(self, view, isMaterialized=False):
- sql = "DROP %s VIEW %s" % ('MATERIALIZED' if isMaterialized else '', self.quoteId(view))
+ sql = "DROP {} VIEW {}".format(
+ "MATERIALIZED" if isMaterialized else "", self.quoteId(view)
+ )
self._execute_and_commit(sql)
def renameView(self, view, new_name):
- """Renames view in database """
+ """Renames view in database"""
self.renameTable(view, new_name)
def createSchema(self, schema):
- """Creates a new empty schema in database """
+ """Creates a new empty schema in database"""
sql = "CREATE SCHEMA %s" % self.quoteId(schema)
self._execute_and_commit(sql)
def deleteSchema(self, schema):
- """Drops (empty) schema from database """
+ """Drops (empty) schema from database"""
sql = "DROP SCHEMA %s" % self.quoteId(schema)
self._execute_and_commit(sql)
def renamesSchema(self, schema, new_schema):
- """Renames a schema in database """
- sql = "ALTER SCHEMA %s RENAME TO %s" % (self.quoteId(schema), self.quoteId(new_schema))
+ """Renames a schema in database"""
+ sql = "ALTER SCHEMA {} RENAME TO {}".format(
+ self.quoteId(schema), self.quoteId(new_schema)
+ )
self._execute_and_commit(sql)
def runVacuum(self):
- """Runs vacuum on the db """
+ """Runs vacuum on the db"""
self._execute_and_commit("VACUUM")
def runVacuumAnalyze(self, table):
- """Runs vacuum analyze on a table """
+ """Runs vacuum analyze on a table"""
sql = "VACUUM ANALYZE %s" % self.quoteId(table)
self._execute(None, sql)
self._commit()
def runRefreshMaterializedView(self, table):
- """Runs refresh materialized view on a table """
+ """Runs refresh materialized view on a table"""
sql = "REFRESH MATERIALIZED VIEW %s" % self.quoteId(table)
self._execute(None, sql)
self._commit()
def addTableColumn(self, table, field_def):
- """Adds a column to table """
- sql = "ALTER TABLE %s ADD %s" % (self.quoteId(table), field_def)
+ """Adds a column to table"""
+ sql = f"ALTER TABLE {self.quoteId(table)} ADD {field_def}"
self._execute_and_commit(sql)
def deleteTableColumn(self, table, column):
- """Deletes column from a table """
+ """Deletes column from a table"""
if self.isGeometryColumn(table, column):
# use PostGIS function to delete geometry column correctly
schema, tablename = self.getSchemaTableName(table)
schema_part = "%s, " % self.quoteString(schema) if schema else ""
- sql = "SELECT DropGeometryColumn(%s%s, %s)" % (
- schema_part, self.quoteString(tablename), self.quoteString(column))
+ sql = "SELECT DropGeometryColumn({}{}, {})".format(
+ schema_part, self.quoteString(tablename), self.quoteString(column)
+ )
else:
- sql = "ALTER TABLE %s DROP %s" % (self.quoteId(table), self.quoteId(column))
+ sql = "ALTER TABLE {} DROP {}".format(
+ self.quoteId(table), self.quoteId(column)
+ )
self._execute_and_commit(sql)
- def updateTableColumn(self, table, column, new_name=None, data_type=None, not_null=None, default=None, comment=None, test=None):
- if new_name is None and data_type is None and not_null is None and default is None and comment is None:
+ def updateTableColumn(
+ self,
+ table,
+ column,
+ new_name=None,
+ data_type=None,
+ not_null=None,
+ default=None,
+ comment=None,
+ test=None,
+ ):
+ if (
+ new_name is None
+ and data_type is None
+ and not_null is None
+ and default is None
+ and comment is None
+ ):
return
c = self._get_cursor()
@@ -1098,7 +1318,7 @@ def updateTableColumn(self, table, column, new_name=None, data_type=None, not_nu
if not_null is not None:
col_actions.append("SET NOT NULL" if not_null else "DROP NOT NULL")
if default is not None:
- if default and default != '':
+ if default and default != "":
col_actions.append("SET DEFAULT %s" % default)
else:
col_actions.append("DROP DEFAULT")
@@ -1106,91 +1326,125 @@ def updateTableColumn(self, table, column, new_name=None, data_type=None, not_nu
sql = "ALTER TABLE %s" % self.quoteId(table)
alter_col_str = "ALTER %s" % self.quoteId(column)
for a in col_actions:
- sql += " %s %s," % (alter_col_str, a)
+ sql += f" {alter_col_str} {a},"
self._execute(c, sql[:-1])
# Renames the column
if new_name is not None and new_name != column:
- sql = "ALTER TABLE %s RENAME %s TO %s" % (
- self.quoteId(table), self.quoteId(column), self.quoteId(new_name))
+ sql = "ALTER TABLE {} RENAME {} TO {}".format(
+ self.quoteId(table), self.quoteId(column), self.quoteId(new_name)
+ )
self._execute(c, sql)
# update geometry_columns if PostGIS is enabled
if self.has_geometry_columns and not self.is_geometry_columns_view:
schema, tablename = self.getSchemaTableName(table)
- schema_where = " f_table_schema=%s AND " % self.quoteString(schema) if schema is not None else ""
- sql = "UPDATE geometry_columns SET f_geometry_column=%s WHERE %s f_table_name=%s AND f_geometry_column=%s" % (
- self.quoteString(new_name), schema_where, self.quoteString(tablename), self.quoteString(column))
+ schema_where = (
+ " f_table_schema=%s AND " % self.quoteString(schema)
+ if schema is not None
+ else ""
+ )
+ sql = "UPDATE geometry_columns SET f_geometry_column={} WHERE {} f_table_name={} AND f_geometry_column={}".format(
+ self.quoteString(new_name),
+ schema_where,
+ self.quoteString(tablename),
+ self.quoteString(column),
+ )
self._execute(c, sql)
# comment the column
if comment is not None:
schema, tablename = self.getSchemaTableName(table)
- column_name = new_name if new_name is not None and new_name != column else column
- sql = "COMMENT ON COLUMN %s.%s.%s IS '%s'" % (schema, tablename, column_name, comment)
+ column_name = (
+ new_name if new_name is not None and new_name != column else column
+ )
+ sql = "COMMENT ON COLUMN {}.{}.{} IS '{}'".format(
+ schema, tablename, column_name, comment
+ )
self._execute(c, sql)
self._commit()
def renamesTableColumn(self, table, column, new_name):
- """Renames column in a table """
+ """Renames column in a table"""
return self.updateTableColumn(table, column, new_name)
def setTableColumnType(self, table, column, data_type):
- """Changes column type """
+ """Changes column type"""
return self.updateTableColumn(table, column, None, data_type)
def setTableColumnNull(self, table, column, is_null):
- """Changes whether column can contain null values """
+ """Changes whether column can contain null values"""
return self.updateTableColumn(table, column, None, None, not is_null)
def setTableColumnDefault(self, table, column, default):
"""Changes column's default value.
- If default=None or an empty string drop default value """
+ If default=None or an empty string drop default value"""
return self.updateTableColumn(table, column, None, None, None, default)
def isGeometryColumn(self, table, column):
schema, tablename = self.getSchemaTableName(table)
- schema_where = " f_table_schema=%s AND " % self.quoteString(schema) if schema is not None else ""
+ schema_where = (
+ " f_table_schema=%s AND " % self.quoteString(schema)
+ if schema is not None
+ else ""
+ )
- sql = "SELECT count(*) > 0 FROM geometry_columns WHERE %s f_table_name=%s AND f_geometry_column=%s" % (
- schema_where, self.quoteString(tablename), self.quoteString(column))
+ sql = "SELECT count(*) > 0 FROM geometry_columns WHERE {} f_table_name={} AND f_geometry_column={}".format(
+ schema_where, self.quoteString(tablename), self.quoteString(column)
+ )
c = self._execute(None, sql)
- res = self._fetchone(c)[0] == 't'
+ res = self._fetchone(c)[0] == "t"
self._close_cursor(c)
return res
- def addGeometryColumn(self, table, geom_column='geom', geom_type='POINT', srid=-1, dim=2):
+ def addGeometryColumn(
+ self, table, geom_column="geom", geom_type="POINT", srid=-1, dim=2
+ ):
schema, tablename = self.getSchemaTableName(table)
schema_part = "%s, " % self.quoteString(schema) if schema else ""
sql = "SELECT AddGeometryColumn(%s%s, %s, %d, %s, %d)" % (
- schema_part, self.quoteString(tablename), self.quoteString(geom_column), srid, self.quoteString(geom_type), dim)
+ schema_part,
+ self.quoteString(tablename),
+ self.quoteString(geom_column),
+ srid,
+ self.quoteString(geom_type),
+ dim,
+ )
self._execute_and_commit(sql)
def deleteGeometryColumn(self, table, geom_column):
return self.deleteTableColumn(table, geom_column)
def addTableUniqueConstraint(self, table, column):
- """Adds a unique constraint to a table """
- sql = "ALTER TABLE %s ADD UNIQUE (%s)" % (self.quoteId(table), self.quoteId(column))
+ """Adds a unique constraint to a table"""
+ sql = "ALTER TABLE {} ADD UNIQUE ({})".format(
+ self.quoteId(table), self.quoteId(column)
+ )
self._execute_and_commit(sql)
def deleteTableConstraint(self, table, constraint):
- """Deletes constraint in a table """
- sql = "ALTER TABLE %s DROP CONSTRAINT %s" % (self.quoteId(table), self.quoteId(constraint))
+ """Deletes constraint in a table"""
+ sql = "ALTER TABLE {} DROP CONSTRAINT {}".format(
+ self.quoteId(table), self.quoteId(constraint)
+ )
self._execute_and_commit(sql)
def addTablePrimaryKey(self, table, column):
- """Adds a primery key (with one column) to a table """
- sql = "ALTER TABLE %s ADD PRIMARY KEY (%s)" % (self.quoteId(table), self.quoteId(column))
+ """Adds a primery key (with one column) to a table"""
+ sql = "ALTER TABLE {} ADD PRIMARY KEY ({})".format(
+ self.quoteId(table), self.quoteId(column)
+ )
self._execute_and_commit(sql)
def createTableIndex(self, table, name, column):
- """Creates index on one column using default options """
- sql = "CREATE INDEX %s ON %s (%s)" % (self.quoteId(name), self.quoteId(table), self.quoteId(column))
+ """Creates index on one column using default options"""
+ sql = "CREATE INDEX {} ON {} ({})".format(
+ self.quoteId(name), self.quoteId(table), self.quoteId(column)
+ )
self._execute_and_commit(sql)
def deleteTableIndex(self, table, name):
@@ -1198,15 +1452,17 @@ def deleteTableIndex(self, table, name):
sql = "DROP INDEX %s" % self.quoteId((schema, name))
self._execute_and_commit(sql)
- def createSpatialIndex(self, table, geom_column='geom'):
+ def createSpatialIndex(self, table, geom_column="geom"):
schema, tablename = self.getSchemaTableName(table)
- idx_name = self.quoteId("sidx_%s_%s" % (tablename, geom_column))
- sql = "CREATE INDEX %s ON %s USING GIST(%s)" % (idx_name, self.quoteId(table), self.quoteId(geom_column))
+ idx_name = self.quoteId(f"sidx_{tablename}_{geom_column}")
+ sql = "CREATE INDEX {} ON {} USING GIST({})".format(
+ idx_name, self.quoteId(table), self.quoteId(geom_column)
+ )
self._execute_and_commit(sql)
- def deleteSpatialIndex(self, table, geom_column='geom'):
+ def deleteSpatialIndex(self, table, geom_column="geom"):
schema, tablename = self.getSchemaTableName(table)
- idx_name = self.quoteId("sidx_%s_%s" % (tablename, geom_column))
+ idx_name = self.quoteId(f"sidx_{tablename}_{geom_column}")
return self.deleteTableIndex(table, idx_name)
def _execute(self, cursor, sql):
@@ -1245,10 +1501,7 @@ def getSqlDictionary(self):
UNION SELECT relname FROM pg_class WHERE relkind IN ('v', 'r', 'm', 'p')
UNION SELECT attname FROM pg_attribute WHERE attnum > 0"""
c = self._execute(None, sql)
- items = [
- row[0]
- for row in self._fetchall(c)
- ]
+ items = [row[0] for row in self._fetchall(c)]
self._close_cursor(c)
sql_dict["identifier"] = items
diff --git a/python/plugins/db_manager/db_plugins/postgis/connector_test.py b/python/plugins/db_manager/db_plugins/postgis/connector_test.py
index b8be72f5a3f3..e943fe8929a5 100644
--- a/python/plugins/db_manager/db_plugins/postgis/connector_test.py
+++ b/python/plugins/db_manager/db_plugins/postgis/connector_test.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Sandro Santilli'
-__date__ = 'May 2017'
-__copyright__ = '(C) 2017, Sandro Santilli'
+__author__ = "Sandro Santilli"
+__date__ = "May 2017"
+__copyright__ = "(C) 2017, Sandro Santilli"
import os
import unittest
@@ -51,8 +51,8 @@ def _getDatabase(self, connector):
# and https://github.com/qgis/QGIS/issues/19005
def test_dbnameLessURI(self):
obj = QObject() # needs to be kept alive
- obj.connectionName = lambda: 'fake'
- obj.providerName = lambda: 'postgres'
+ obj.connectionName = lambda: "fake"
+ obj.providerName = lambda: "postgres"
c = PostGisDBConnector(QgsDataSourceUri(), obj)
self.assertIsInstance(c, PostGisDBConnector)
@@ -60,18 +60,18 @@ def test_dbnameLessURI(self):
# No username was passed, so we expect it to be taken
# from PGUSER or USER environment variables
- expected_user = os.environ.get('PGUSER') or os.environ.get('USER')
+ expected_user = os.environ.get("PGUSER") or os.environ.get("USER")
actual_user = self._getUser(c)
self.assertEqual(actual_user, expected_user)
# No database was passed, so we expect it to be taken
# from PGDATABASE or expected user
- expected_db = os.environ.get('PGDATABASE') or expected_user
+ expected_db = os.environ.get("PGDATABASE") or expected_user
actual_db = self._getDatabase(c)
self.assertEqual(actual_db, expected_db)
# TODO: add service-only test (requires a ~/.pg_service.conf file)
-if __name__ == '__main__':
+if __name__ == "__main__":
unittest.main()
diff --git a/python/plugins/db_manager/db_plugins/postgis/data_model.py b/python/plugins/db_manager/db_plugins/postgis/data_model.py
index be3f7b00667d..269e9713b5f6 100644
--- a/python/plugins/db_manager/db_plugins/postgis/data_model.py
+++ b/python/plugins/db_manager/db_plugins/postgis/data_model.py
@@ -20,10 +20,12 @@
from qgis.core import QgsMessageLog
from ..plugin import BaseError
-from ..data_model import (TableDataModel,
- SqlResultModel,
- SqlResultModelAsync,
- SqlResultModelTask)
+from ..data_model import (
+ TableDataModel,
+ SqlResultModel,
+ SqlResultModelAsync,
+ SqlResultModelTask,
+)
class PGTableDataModel(TableDataModel):
@@ -45,17 +47,21 @@ def _createCursor(self):
table_txt = self.db.quoteId((self.table.schemaName(), self.table.name))
self.cursor = self.db._get_cursor()
- sql = "SELECT %s FROM %s" % (fields_txt, table_txt)
+ sql = f"SELECT {fields_txt} FROM {table_txt}"
self.db._execute(self.cursor, sql)
def _sanitizeTableField(self, field):
# get fields, ignore geometry columns
if field.dataType.lower() == "geometry":
- return "CASE WHEN %(fld)s IS NULL THEN NULL ELSE GeometryType(%(fld)s) END AS %(fld)s" % {
- 'fld': self.db.quoteId(field.name)}
+ return "CASE WHEN {fld} IS NULL THEN NULL ELSE GeometryType({fld}) END AS {fld}".format(
+ fld=self.db.quoteId(field.name)
+ )
elif field.dataType.lower() == "raster":
- return "CASE WHEN %(fld)s IS NULL THEN NULL ELSE 'RASTER' END AS %(fld)s" % {
- 'fld': self.db.quoteId(field.name)}
+ return (
+ "CASE WHEN {fld} IS NULL THEN NULL ELSE 'RASTER' END AS {fld}".format(
+ fld=self.db.quoteId(field.name)
+ )
+ )
return "%s::text" % self.db.quoteId(field.name)
def _deleteCursor(self):
@@ -72,7 +78,7 @@ def fetchMoreData(self, row_start):
self._createCursor()
try:
- self.cursor.scroll(row_start, mode='absolute')
+ self.cursor.scroll(row_start, mode="absolute")
except self.db.error_types():
self._deleteCursor()
return self.fetchMoreData(row_start)
diff --git a/python/plugins/db_manager/db_plugins/postgis/info_model.py b/python/plugins/db_manager/db_plugins/postgis/info_model.py
index fa9dc3abb2e2..c5dda0b3e2fc 100644
--- a/python/plugins/db_manager/db_plugins/postgis/info_model.py
+++ b/python/plugins/db_manager/db_plugins/postgis/info_model.py
@@ -21,16 +21,31 @@
from qgis.PyQt.QtWidgets import QApplication
from ..info_model import TableInfo, VectorTableInfo, RasterTableInfo, DatabaseInfo
-from ..html_elems import HtmlSection, HtmlParagraph, HtmlTable, HtmlTableHeader, HtmlTableCol
+from ..html_elems import (
+ HtmlSection,
+ HtmlParagraph,
+ HtmlTable,
+ HtmlTableHeader,
+ HtmlTableCol,
+)
class PGDatabaseInfo(DatabaseInfo):
def connectionDetails(self):
tbl = [
- (QApplication.translate("DBManagerPlugin", "Host:"), self.db.connector.host),
- (QApplication.translate("DBManagerPlugin", "User:"), self.db.connector.user),
- (QApplication.translate("DBManagerPlugin", "Database:"), self.db.connector.dbname)
+ (
+ QApplication.translate("DBManagerPlugin", "Host:"),
+ self.db.connector.host,
+ ),
+ (
+ QApplication.translate("DBManagerPlugin", "User:"),
+ self.db.connector.user,
+ ),
+ (
+ QApplication.translate("DBManagerPlugin", "Database:"),
+ self.db.connector.dbname,
+ ),
]
return HtmlTable(tbl)
@@ -53,40 +68,81 @@ def generalInfo(self):
self.table.blockSignals(False)
tbl = [
- (QApplication.translate("DBManagerPlugin", "Relation type:"),
- QApplication.translate("DBManagerPlugin", "View") if self.table._relationType == 'v' else
- QApplication.translate("DBManagerPlugin", "Materialized view") if self.table._relationType == 'm' else
- QApplication.translate("DBManagerPlugin", "Table")),
- (QApplication.translate("DBManagerPlugin", "Owner:"), self.table.owner)
+ (
+ QApplication.translate("DBManagerPlugin", "Relation type:"),
+ (
+ QApplication.translate("DBManagerPlugin", "View")
+ if self.table._relationType == "v"
+ else (
+ QApplication.translate("DBManagerPlugin", "Materialized view")
+ if self.table._relationType == "m"
+ else QApplication.translate("DBManagerPlugin", "Table")
+ )
+ ),
+ ),
+ (QApplication.translate("DBManagerPlugin", "Owner:"), self.table.owner),
]
if self.table.comment:
- tbl.append((QApplication.translate("DBManagerPlugin", "Comment:"), self.table.comment))
-
- tbl.extend([
- (QApplication.translate("DBManagerPlugin", "Pages:"), self.table.pages),
- (QApplication.translate("DBManagerPlugin", "Rows (estimation):"), self.table.estimatedRowCount)
- ])
+ tbl.append(
+ (
+ QApplication.translate("DBManagerPlugin", "Comment:"),
+ self.table.comment,
+ )
+ )
+
+ tbl.extend(
+ [
+ (QApplication.translate("DBManagerPlugin", "Pages:"), self.table.pages),
+ (
+ QApplication.translate("DBManagerPlugin", "Rows (estimation):"),
+ self.table.estimatedRowCount,
+ ),
+ ]
+ )
# privileges
# has the user access to this schema?
- schema_priv = self.table.database().connector.getSchemaPrivileges(
- self.table.schemaName()) if self.table.schema() else None
+ schema_priv = (
+ self.table.database().connector.getSchemaPrivileges(self.table.schemaName())
+ if self.table.schema()
+ else None
+ )
if schema_priv is None:
pass
elif not schema_priv[1]: # no usage privileges on the schema
- tbl.append((QApplication.translate("DBManagerPlugin", "Privileges:"),
- QApplication.translate("DBManagerPlugin",
- " This user doesn't have usage privileges for this schema!")))
+ tbl.append(
+ (
+ QApplication.translate("DBManagerPlugin", "Privileges:"),
+ QApplication.translate(
+ "DBManagerPlugin",
+ " This user doesn't have usage privileges for this schema!",
+ ),
+ )
+ )
else:
- table_priv = self.table.database().connector.getTablePrivileges((self.table.schemaName(), self.table.name))
+ table_priv = self.table.database().connector.getTablePrivileges(
+ (self.table.schemaName(), self.table.name)
+ )
privileges = []
if table_priv[0]:
privileges.append("select")
if self.table.rowCount is not None and self.table.rowCount >= 0:
- tbl.append((QApplication.translate("DBManagerPlugin", "Rows (counted):"),
- self.table.rowCount if self.table.rowCount is not None else QApplication.translate(
- "DBManagerPlugin", 'Unknown (find out )')))
+ tbl.append(
+ (
+ QApplication.translate(
+ "DBManagerPlugin", "Rows (counted):"
+ ),
+ (
+ self.table.rowCount
+ if self.table.rowCount is not None
+ else QApplication.translate(
+ "DBManagerPlugin",
+ 'Unknown (find out )',
+ )
+ ),
+ )
+ )
if table_priv[1]:
privileges.append("insert")
@@ -94,31 +150,62 @@ def generalInfo(self):
privileges.append("update")
if table_priv[3]:
privileges.append("delete")
- priv_string = ", ".join(privileges) if len(privileges) > 0 else QApplication.translate("DBManagerPlugin",
- ' This user has no privileges!')
- tbl.append((QApplication.translate("DBManagerPlugin", "Privileges:"), priv_string))
+ priv_string = (
+ ", ".join(privileges)
+ if len(privileges) > 0
+ else QApplication.translate(
+ "DBManagerPlugin", " This user has no privileges!"
+ )
+ )
+ tbl.append(
+ (QApplication.translate("DBManagerPlugin", "Privileges:"), priv_string)
+ )
ret.append(HtmlTable(tbl))
if schema_priv is not None and schema_priv[1]:
- if table_priv[0] and not table_priv[1] and not table_priv[2] and not table_priv[3]:
- ret.append(HtmlParagraph(
- QApplication.translate("DBManagerPlugin", " This user has read-only privileges.")))
+ if (
+ table_priv[0]
+ and not table_priv[1]
+ and not table_priv[2]
+ and not table_priv[3]
+ ):
+ ret.append(
+ HtmlParagraph(
+ QApplication.translate(
+ "DBManagerPlugin",
+ " This user has read-only privileges.",
+ )
+ )
+ )
if not self.table.isView:
if self.table.rowCount is not None:
- if abs(self.table.estimatedRowCount - self.table.rowCount) > 1 and \
- (self.table.estimatedRowCount > 2 * self.table.rowCount
- or self.table.rowCount > 2 * self.table.estimatedRowCount):
- ret.append(HtmlParagraph(QApplication.translate("DBManagerPlugin",
- " There's a significant difference between estimated and real row count. "
- 'Consider running VACUUM ANALYZE .')))
+ if abs(self.table.estimatedRowCount - self.table.rowCount) > 1 and (
+ self.table.estimatedRowCount > 2 * self.table.rowCount
+ or self.table.rowCount > 2 * self.table.estimatedRowCount
+ ):
+ ret.append(
+ HtmlParagraph(
+ QApplication.translate(
+ "DBManagerPlugin",
+ " There's a significant difference between estimated and real row count. "
+ 'Consider running VACUUM ANALYZE .',
+ )
+ )
+ )
# primary key defined?
if not self.table.isView:
if len([fld for fld in self.table.fields() if fld.primaryKey]) <= 0:
- ret.append(HtmlParagraph(
- QApplication.translate("DBManagerPlugin", " No primary key defined for this table!")))
+ ret.append(
+ HtmlParagraph(
+ QApplication.translate(
+ "DBManagerPlugin",
+ " No primary key defined for this table!",
+ )
+ )
+ )
return ret
@@ -133,23 +220,41 @@ def getSpatialInfo(self):
(QApplication.translate("DBManagerPlugin", "Library:"), info[0]),
(QApplication.translate("DBManagerPlugin", "Scripts:"), info[3]),
("GEOS:", info[1]),
- ("Proj:", info[2])
+ ("Proj:", info[2]),
]
ret.append(HtmlTable(tbl))
if info[1] is not None and info[1] != info[2]:
- ret.append(HtmlParagraph(QApplication.translate("DBManagerPlugin",
- " Version of installed scripts doesn't match version of released scripts!\n"
- "This is probably a result of incorrect PostGIS upgrade.")))
+ ret.append(
+ HtmlParagraph(
+ QApplication.translate(
+ "DBManagerPlugin",
+ " Version of installed scripts doesn't match version of released scripts!\n"
+ "This is probably a result of incorrect PostGIS upgrade.",
+ )
+ )
+ )
if not self.db.connector.has_geometry_columns:
- ret.append(HtmlParagraph(
- QApplication.translate("DBManagerPlugin", " geometry_columns table doesn't exist!\n"
- "This table is essential for many GIS applications for enumeration of tables.")))
+ ret.append(
+ HtmlParagraph(
+ QApplication.translate(
+ "DBManagerPlugin",
+ " geometry_columns table doesn't exist!\n"
+ "This table is essential for many GIS applications for enumeration of tables.",
+ )
+ )
+ )
elif not self.db.connector.has_geometry_columns_access:
- ret.append(HtmlParagraph(QApplication.translate("DBManagerPlugin",
- " This user doesn't have privileges to read contents of geometry_columns table!\n"
- "This table is essential for many GIS applications for enumeration of tables.")))
+ ret.append(
+ HtmlParagraph(
+ QApplication.translate(
+ "DBManagerPlugin",
+ " This user doesn't have privileges to read contents of geometry_columns table!\n"
+ "This table is essential for many GIS applications for enumeration of tables.",
+ )
+ )
+ )
return ret
@@ -158,21 +263,40 @@ def fieldsDetails(self):
# define the table header
header = (
- "#", QApplication.translate("DBManagerPlugin", "Name"), QApplication.translate("DBManagerPlugin", "Type"),
- QApplication.translate("DBManagerPlugin", "Length"), QApplication.translate("DBManagerPlugin", "Null"),
- QApplication.translate("DBManagerPlugin", "Default"), QApplication.translate("DBManagerPlugin", "Comment"))
+ "#",
+ QApplication.translate("DBManagerPlugin", "Name"),
+ QApplication.translate("DBManagerPlugin", "Type"),
+ QApplication.translate("DBManagerPlugin", "Length"),
+ QApplication.translate("DBManagerPlugin", "Null"),
+ QApplication.translate("DBManagerPlugin", "Default"),
+ QApplication.translate("DBManagerPlugin", "Comment"),
+ )
tbl.append(HtmlTableHeader(header))
# add table contents
for fld in self.table.fields():
- char_max_len = fld.charMaxLen if fld.charMaxLen is not None and fld.charMaxLen != -1 else ""
+ char_max_len = (
+ fld.charMaxLen
+ if fld.charMaxLen is not None and fld.charMaxLen != -1
+ else ""
+ )
is_null_txt = "N" if fld.notNull else "Y"
# make primary key field underlined
attrs = {"class": "underline"} if fld.primaryKey else None
name = HtmlTableCol(fld.name, attrs)
- tbl.append((fld.num, name, fld.type2String(), char_max_len, is_null_txt, fld.default2String(), fld.getComment()))
+ tbl.append(
+ (
+ fld.num,
+ name,
+ fld.type2String(),
+ char_max_len,
+ is_null_txt,
+ fld.default2String(),
+ fld.getComment(),
+ )
+ )
return HtmlTable(tbl, {"class": "header"})
@@ -185,26 +309,42 @@ def triggersDetails(self):
tbl = []
# define the table header
header = (
- QApplication.translate("DBManagerPlugin", "Name"), QApplication.translate("DBManagerPlugin", "Function"),
- QApplication.translate("DBManagerPlugin", "Type"), QApplication.translate("DBManagerPlugin", "Enabled"))
+ QApplication.translate("DBManagerPlugin", "Name"),
+ QApplication.translate("DBManagerPlugin", "Function"),
+ QApplication.translate("DBManagerPlugin", "Type"),
+ QApplication.translate("DBManagerPlugin", "Enabled"),
+ )
tbl.append(HtmlTableHeader(header))
# add table contents
for trig in self.table.triggers():
- name = '%(name)s (%(action)s )' % {"name": trig.name,
- "action": "delete"}
-
- (enabled, action) = (QApplication.translate("DBManagerPlugin", "Yes"), "disable") if trig.enabled else (
- QApplication.translate("DBManagerPlugin", "No"), "enable")
- txt_enabled = '%(enabled)s (%(action)s )' % {
- "name": trig.name, "action": action, "enabled": enabled}
+ name = (
+ '{name} ({action} )'.format(
+ name=trig.name, action="delete"
+ )
+ )
+
+ (enabled, action) = (
+ (QApplication.translate("DBManagerPlugin", "Yes"), "disable")
+ if trig.enabled
+ else (QApplication.translate("DBManagerPlugin", "No"), "enable")
+ )
+ txt_enabled = '{enabled} ({action} )'.format(
+ name=trig.name, action=action, enabled=enabled
+ )
tbl.append((name, trig.function, trig.type2String(), txt_enabled))
ret.append(HtmlTable(tbl, {"class": "header"}))
- ret.append(HtmlParagraph(QApplication.translate("DBManagerPlugin",
- 'Enable all triggers / Disable all triggers ')))
+ ret.append(
+ HtmlParagraph(
+ QApplication.translate(
+ "DBManagerPlugin",
+ 'Enable all triggers / Disable all triggers ',
+ )
+ )
+ )
return ret
def rulesDetails(self):
@@ -214,13 +354,16 @@ def rulesDetails(self):
tbl = []
# define the table header
header = (
- QApplication.translate("DBManagerPlugin", "Name"), QApplication.translate("DBManagerPlugin", "Definition"))
+ QApplication.translate("DBManagerPlugin", "Name"),
+ QApplication.translate("DBManagerPlugin", "Definition"),
+ )
tbl.append(HtmlTableHeader(header))
# add table contents
for rule in self.table.rules():
- name = '%(name)s (%(action)s )' % {"name": rule.name,
- "action": "delete"}
+ name = '{name} ({action} )'.format(
+ name=rule.name, action="delete"
+ )
tbl.append((name, rule.definition))
return HtmlTable(tbl, {"class": "header"})
@@ -233,7 +376,11 @@ def getTableInfo(self):
if rules_details is None:
pass
else:
- ret.append(HtmlSection(QApplication.translate("DBManagerPlugin", 'Rules'), rules_details))
+ ret.append(
+ HtmlSection(
+ QApplication.translate("DBManagerPlugin", "Rules"), rules_details
+ )
+ )
return ret
diff --git a/python/plugins/db_manager/db_plugins/postgis/plugin.py b/python/plugins/db_manager/db_plugins/postgis/plugin.py
index 7e276251bacd..f294c7d579bd 100644
--- a/python/plugins/db_manager/db_plugins/postgis/plugin.py
+++ b/python/plugins/db_manager/db_plugins/postgis/plugin.py
@@ -21,18 +21,27 @@
# this will disable the dbplugin if the connector raise an ImportError
from .connector import PostGisDBConnector
-from qgis.PyQt.QtCore import (
- Qt,
- QRegularExpression,
- QCoreApplication
-)
+from qgis.PyQt.QtCore import Qt, QRegularExpression, QCoreApplication
from qgis.PyQt.QtGui import QIcon
from qgis.PyQt.QtWidgets import QAction, QApplication, QMessageBox
from qgis.core import Qgis, QgsApplication, QgsSettings
from qgis.gui import QgsMessageBar
-from ..plugin import ConnectionError, InvalidDataException, DBPlugin, Database, Schema, Table, VectorTable, RasterTable, \
- TableField, TableConstraint, TableIndex, TableTrigger, TableRule
+from ..plugin import (
+ ConnectionError,
+ InvalidDataException,
+ DBPlugin,
+ Database,
+ Schema,
+ Table,
+ VectorTable,
+ RasterTable,
+ TableField,
+ TableConstraint,
+ TableIndex,
+ TableTrigger,
+ TableRule,
+)
import re
@@ -49,19 +58,19 @@ def icon(self):
@classmethod
def typeName(self):
- return 'postgis'
+ return "postgis"
@classmethod
def typeNameString(self):
- return QCoreApplication.translate('db_manager', 'PostGIS')
+ return QCoreApplication.translate("db_manager", "PostGIS")
@classmethod
def providerName(self):
- return 'postgres'
+ return "postgres"
@classmethod
def connectionSettingsKey(self):
- return '/PostgreSQL/connections'
+ return "/PostgreSQL/connections"
def databasesFactory(self, connection, uri):
return PGDatabase(connection, uri)
@@ -69,17 +78,31 @@ def databasesFactory(self, connection, uri):
def connect(self, parent=None):
conn_name = self.connectionName()
settings = QgsSettings()
- settings.beginGroup("/%s/%s" % (self.connectionSettingsKey(), conn_name))
+ settings.beginGroup(f"/{self.connectionSettingsKey()}/{conn_name}")
if not settings.contains("database"): # non-existent entry?
- raise InvalidDataException(self.tr('There is no defined database connection "{0}".').format(conn_name))
+ raise InvalidDataException(
+ self.tr('There is no defined database connection "{0}".').format(
+ conn_name
+ )
+ )
from qgis.core import QgsDataSourceUri
uri = QgsDataSourceUri()
- settingsList = ["service", "host", "port", "database", "username", "password", "authcfg"]
- service, host, port, database, username, password, authcfg = (settings.value(x, "", type=str) for x in settingsList)
+ settingsList = [
+ "service",
+ "host",
+ "port",
+ "database",
+ "username",
+ "password",
+ "authcfg",
+ ]
+ service, host, port, database, username, password, authcfg = (
+ settings.value(x, "", type=str) for x in settingsList
+ )
useEstimatedMetadata = settings.value("estimatedMetadata", False, type=bool)
try:
@@ -89,13 +112,15 @@ def connect(self, parent=None):
settings.endGroup()
- if hasattr(authcfg, 'isNull') and authcfg.isNull():
- authcfg = ''
+ if hasattr(authcfg, "isNull") and authcfg.isNull():
+ authcfg = ""
if service:
uri.setConnection(service, database, username, password, sslmode, authcfg)
else:
- uri.setConnection(host, port, database, username, password, sslmode, authcfg)
+ uri.setConnection(
+ host, port, database, username, password, sslmode, authcfg
+ )
uri.setUseEstimatedMetadata(useEstimatedMetadata)
@@ -118,6 +143,7 @@ def dataTablesFactory(self, row, db, schema=None):
def info(self):
from .info_model import PGDatabaseInfo
+
return PGDatabaseInfo(self)
def vectorTablesFactory(self, row, db, schema=None):
@@ -148,17 +174,24 @@ def registerDatabaseActions(self, mainWindow):
mainWindow.registerAction(separator, self.tr("&Table"))
action = QAction(self.tr("Run &Vacuum Analyze"), self)
- mainWindow.registerAction(action, self.tr("&Table"), self.runVacuumAnalyzeActionSlot)
+ mainWindow.registerAction(
+ action, self.tr("&Table"), self.runVacuumAnalyzeActionSlot
+ )
action = QAction(self.tr("Run &Refresh Materialized View"), self)
- mainWindow.registerAction(action, self.tr("&Table"), self.runRefreshMaterializedViewSlot)
+ mainWindow.registerAction(
+ action, self.tr("&Table"), self.runRefreshMaterializedViewSlot
+ )
def runVacuumAnalyzeActionSlot(self, item, action, parent):
QApplication.restoreOverrideCursor()
try:
if not isinstance(item, Table) or item.isView:
- parent.infoBar.pushMessage(self.tr("Select a table for vacuum analyze."), Qgis.MessageLevel.Info,
- parent.iface.messageTimeout())
+ parent.infoBar.pushMessage(
+ self.tr("Select a table for vacuum analyze."),
+ Qgis.MessageLevel.Info,
+ parent.iface.messageTimeout(),
+ )
return
finally:
QApplication.setOverrideCursor(Qt.CursorShape.WaitCursor)
@@ -168,9 +201,12 @@ def runVacuumAnalyzeActionSlot(self, item, action, parent):
def runRefreshMaterializedViewSlot(self, item, action, parent):
QApplication.restoreOverrideCursor()
try:
- if not isinstance(item, PGTable) or item._relationType != 'm':
- parent.infoBar.pushMessage(self.tr("Select a materialized view for refresh."), Qgis.MessageLevel.Info,
- parent.iface.messageTimeout())
+ if not isinstance(item, PGTable) or item._relationType != "m":
+ parent.infoBar.pushMessage(
+ self.tr("Select a materialized view for refresh."),
+ Qgis.MessageLevel.Info,
+ parent.iface.messageTimeout(),
+ )
return
finally:
QApplication.setOverrideCursor(Qt.CursorShape.WaitCursor)
@@ -198,8 +234,16 @@ class PGTable(Table):
def __init__(self, row, db, schema=None):
Table.__init__(self, db, schema)
- self.name, schema_name, self._relationType, self.owner, self.estimatedRowCount, self.pages, self.comment = row
- self.isView = self._relationType in {'v', 'm'}
+ (
+ self.name,
+ schema_name,
+ self._relationType,
+ self.owner,
+ self.estimatedRowCount,
+ self.pages,
+ self.comment,
+ ) = row
+ self.isView = self._relationType in {"v", "m"}
self.estimatedRowCount = int(self.estimatedRowCount)
def runVacuumAnalyze(self):
@@ -210,7 +254,9 @@ def runVacuumAnalyze(self):
def runRefreshMaterializedView(self):
self.aboutToChange.emit()
- self.database().connector.runRefreshMaterializedView((self.schemaName(), self.name))
+ self.database().connector.runRefreshMaterializedView(
+ (self.schemaName(), self.name)
+ )
# TODO: change only this item, not re-create all the tables in the schema/database
self.schema().refresh() if self.schema() else self.database().refresh()
@@ -223,7 +269,7 @@ def runAction(self, action):
return True
elif action.startswith("rule/"):
- parts = action.split('/')
+ parts = action.split("/")
rule_name = parts[1]
rule_action = parts[2]
@@ -232,15 +278,24 @@ def runAction(self, action):
QApplication.restoreOverrideCursor()
try:
- if QMessageBox.question(None, self.tr("Table rule"), msg,
- QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No) == QMessageBox.StandardButton.No:
+ if (
+ QMessageBox.question(
+ None,
+ self.tr("Table rule"),
+ msg,
+ QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No,
+ )
+ == QMessageBox.StandardButton.No
+ ):
return False
finally:
QApplication.setOverrideCursor(Qt.CursorShape.WaitCursor)
if rule_action == "delete":
self.aboutToChange.emit()
- self.database().connector.deleteTableRule(rule_name, (self.schemaName(), self.name))
+ self.database().connector.deleteTableRule(
+ rule_name, (self.schemaName(), self.name)
+ )
self.refreshRules()
return True
@@ -282,7 +337,9 @@ def tableDataModel(self, parent):
def delete(self):
self.aboutToChange.emit()
if self.isView:
- ret = self.database().connector.deleteView((self.schemaName(), self.name), self._relationType == 'm')
+ ret = self.database().connector.deleteView(
+ (self.schemaName(), self.name), self._relationType == "m"
+ )
else:
ret = self.database().connector.deleteTable((self.schemaName(), self.name))
if not ret:
@@ -308,7 +365,7 @@ def runAction(self, action):
return VectorTable.runAction(self, action)
def geometryType(self):
- """ Returns the proper WKT type.
+ """Returns the proper WKT type.
PostGIS records type like this:
| WKT Type | geomType | geomDim |
|--------------|-------------|---------|
@@ -331,8 +388,15 @@ class PGRasterTable(PGTable, RasterTable):
def __init__(self, row, db, schema=None):
PGTable.__init__(self, row[:-6], db, schema)
RasterTable.__init__(self, db, schema)
- self.geomColumn, self.pixelType, self.pixelSizeX, self.pixelSizeY, self.isExternal, self.srid = row[-6:]
- self.geomType = 'RASTER'
+ (
+ self.geomColumn,
+ self.pixelType,
+ self.pixelSizeX,
+ self.pixelSizeY,
+ self.isExternal,
+ self.srid,
+ ) = row[-6:]
+ self.geomType = "RASTER"
def info(self):
from .info_model import PGRasterTableInfo
@@ -344,41 +408,56 @@ def uri(self, uri=None):
if not uri:
uri = self.database().uri()
- service = ('service=\'%s\'' % uri.service()) if uri.service() else ''
- dbname = ('dbname=\'%s\'' % uri.database()) if uri.database() else ''
- host = ('host=%s' % uri.host()) if uri.host() else ''
- user = ('user=%s' % uri.username()) if uri.username() else ''
- passw = ('password=%s' % uri.password()) if uri.password() else ''
- port = ('port=%s' % uri.port()) if uri.port() else ''
+ service = ("service='%s'" % uri.service()) if uri.service() else ""
+ dbname = ("dbname='%s'" % uri.database()) if uri.database() else ""
+ host = ("host=%s" % uri.host()) if uri.host() else ""
+ user = ("user=%s" % uri.username()) if uri.username() else ""
+ passw = ("password=%s" % uri.password()) if uri.password() else ""
+ port = ("port=%s" % uri.port()) if uri.port() else ""
- schema = self.schemaName() if self.schemaName() else 'public'
- table = '"%s"."%s"' % (schema, self.name)
+ schema = self.schemaName() if self.schemaName() else "public"
+ table = f'"{schema}"."{self.name}"'
if not dbname:
# postgresraster provider *requires* a dbname
connector = self.database().connector
r = connector._execute(None, "SELECT current_database()")
- dbname = ('dbname=\'%s\'' % connector._fetchone(r)[0])
+ dbname = "dbname='%s'" % connector._fetchone(r)[0]
connector._close_cursor(r)
# Find first raster field
- col = ''
+ col = ""
for fld in self.fields():
if fld.dataType == "raster":
- col = 'column=\'%s\'' % fld.name
+ col = "column='%s'" % fld.name
break
- uri = '%s %s %s %s %s %s %s table=%s' % \
- (service, dbname, host, user, passw, port, col, table)
+ uri = "{} {} {} {} {} {} {} table={}".format(
+ service,
+ dbname,
+ host,
+ user,
+ passw,
+ port,
+ col,
+ table,
+ )
return uri
def mimeUri(self):
- uri = "raster:postgresraster:{}:{}".format(self.name, re.sub(":", r"\:", self.uri()))
+ uri = "raster:postgresraster:{}:{}".format(
+ self.name, re.sub(":", r"\:", self.uri())
+ )
return uri
def toMapLayer(self, geometryType=None, crs=None):
- from qgis.core import QgsRasterLayer, QgsContrastEnhancement, QgsDataSourceUri, QgsCredentials
+ from qgis.core import (
+ QgsRasterLayer,
+ QgsContrastEnhancement,
+ QgsDataSourceUri,
+ QgsCredentials,
+ )
rl = QgsRasterLayer(self.uri(), self.name, "postgresraster")
if not rl.isValid():
@@ -389,7 +468,9 @@ def toMapLayer(self, geometryType=None, crs=None):
password = uri.password()
for i in range(3):
- (ok, username, password) = QgsCredentials.instance().get(conninfo, username, password, err)
+ (ok, username, password) = QgsCredentials.instance().get(
+ conninfo, username, password, err
+ )
if ok:
uri.setUsername(username)
uri.setPassword(password)
@@ -398,7 +479,9 @@ def toMapLayer(self, geometryType=None, crs=None):
break
if rl.isValid():
- rl.setContrastEnhancement(QgsContrastEnhancement.ContrastEnhancementAlgorithm.StretchToMinimumMaximum)
+ rl.setContrastEnhancement(
+ QgsContrastEnhancement.ContrastEnhancementAlgorithm.StretchToMinimumMaximum
+ )
return rl
@@ -406,7 +489,17 @@ class PGTableField(TableField):
def __init__(self, row, table):
TableField.__init__(self, table)
- self.num, self.name, self.dataType, self.charMaxLen, self.modifier, self.notNull, self.hasDefault, self.default, typeStr = row
+ (
+ self.num,
+ self.name,
+ self.dataType,
+ self.charMaxLen,
+ self.modifier,
+ self.notNull,
+ self.hasDefault,
+ self.default,
+ typeStr,
+ ) = row
self.primaryKey = False
# get modifier (e.g. "precision,scale") from formatted type string
@@ -428,9 +521,13 @@ def getComment(self):
"""Returns the comment for a field"""
tab = self.table()
# SQL Query checking if a comment exists for the field
- sql_cpt = "Select count(*) from pg_description pd, pg_class pc, pg_attribute pa where relname = '%s' and attname = '%s' and pa.attrelid = pc.oid and pd.objoid = pc.oid and pd.objsubid = pa.attnum" % (tab.name, self.name)
+ sql_cpt = "Select count(*) from pg_description pd, pg_class pc, pg_attribute pa where relname = '{}' and attname = '{}' and pa.attrelid = pc.oid and pd.objoid = pc.oid and pd.objsubid = pa.attnum".format(
+ tab.name, self.name
+ )
# SQL Query that return the comment of the field
- sql = "Select pd.description from pg_description pd, pg_class pc, pg_attribute pa where relname = '%s' and attname = '%s' and pa.attrelid = pc.oid and pd.objoid = pc.oid and pd.objsubid = pa.attnum" % (tab.name, self.name)
+ sql = "Select pd.description from pg_description pd, pg_class pc, pg_attribute pa where relname = '{}' and attname = '{}' and pa.attrelid = pc.oid and pd.objoid = pc.oid and pd.objsubid = pa.attnum".format(
+ tab.name, self.name
+ )
c = tab.database().connector._execute(None, sql_cpt) # Execute Check query
res = tab.database().connector._fetchone(c)[0] # Store result
if res == 1:
@@ -440,15 +537,17 @@ def getComment(self):
tab.database().connector._close_cursor(c) # Close cursor
return res # Return comment
else:
- return ''
+ return ""
class PGTableConstraint(TableConstraint):
def __init__(self, row, table):
TableConstraint.__init__(self, table)
- self.name, constr_type_str, self.isDefferable, self.isDeffered, columns = row[:5]
- self.columns = list(map(int, columns.split(' ')))
+ self.name, constr_type_str, self.isDefferable, self.isDeffered, columns = row[
+ :5
+ ]
+ self.columns = list(map(int, columns.split(" ")))
if constr_type_str in TableConstraint.types:
self.type = TableConstraint.types[constr_type_str]
@@ -470,7 +569,7 @@ class PGTableIndex(TableIndex):
def __init__(self, row, table):
TableIndex.__init__(self, table)
self.name, columns, self.isUnique = row
- self.columns = list(map(int, columns.split(' ')))
+ self.columns = list(map(int, columns.split(" ")))
class PGTableTrigger(TableTrigger):
diff --git a/python/plugins/db_manager/db_plugins/postgis/plugin_test.py b/python/plugins/db_manager/db_plugins/postgis/plugin_test.py
index 9f57ff047080..f202b1354af2 100644
--- a/python/plugins/db_manager/db_plugins/postgis/plugin_test.py
+++ b/python/plugins/db_manager/db_plugins/postgis/plugin_test.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Sandro Santilli'
-__date__ = 'May 2017'
-__copyright__ = '(C) 2017, Sandro Santilli'
+__author__ = "Sandro Santilli"
+__date__ = "May 2017"
+__copyright__ = "(C) 2017, Sandro Santilli"
import os
import re
@@ -40,23 +40,23 @@ class TestDBManagerPostgisPlugin(QgisTestCase):
@classmethod
def setUpClass(self):
- self.old_pgdatabase_env = os.environ.get('PGDATABASE')
+ self.old_pgdatabase_env = os.environ.get("PGDATABASE")
# QGIS_PGTEST_DB contains the full connection string and not only the DB name!
- QGIS_PGTEST_DB = os.environ.get('QGIS_PGTEST_DB')
+ QGIS_PGTEST_DB = os.environ.get("QGIS_PGTEST_DB")
if QGIS_PGTEST_DB is not None:
test_uri = QgsDataSourceUri(QGIS_PGTEST_DB)
self.testdb = test_uri.database()
else:
- self.testdb = 'qgis_test'
- os.environ['PGDATABASE'] = self.testdb
+ self.testdb = "qgis_test"
+ os.environ["PGDATABASE"] = self.testdb
# Create temporary service file
- self.old_pgservicefile_env = os.environ.get('PGSERVICEFILE')
- self.tmpservicefile = '/tmp/qgis-test-{}-pg_service.conf'.format(os.getpid())
- os.environ['PGSERVICEFILE'] = self.tmpservicefile
+ self.old_pgservicefile_env = os.environ.get("PGSERVICEFILE")
+ self.tmpservicefile = f"/tmp/qgis-test-{os.getpid()}-pg_service.conf"
+ os.environ["PGSERVICEFILE"] = self.tmpservicefile
f = open(self.tmpservicefile, "w")
- f.write("[dbmanager]\ndbname={}\n".format(self.testdb))
+ f.write(f"[dbmanager]\ndbname={self.testdb}\n")
# TODO: add more things if PGSERVICEFILE was already set ?
f.close()
@@ -64,9 +64,9 @@ def setUpClass(self):
def tearDownClass(self):
# Restore previous env variables if needed
if self.old_pgdatabase_env:
- os.environ['PGDATABASE'] = self.old_pgdatabase_env
+ os.environ["PGDATABASE"] = self.old_pgdatabase_env
if self.old_pgservicefile_env:
- os.environ['PGSERVICEFILE'] = self.old_pgservicefile_env
+ os.environ["PGSERVICEFILE"] = self.old_pgservicefile_env
# Remove temporary service file
os.unlink(self.tmpservicefile)
@@ -81,7 +81,7 @@ def check_rasterTableURI(expected_dbname):
if tab.type == Table.RasterType:
raster_tables_count += 1
uri = tab.uri()
- m = re.search(' dbname=\'([^ ]*)\' ', uri)
+ m = re.search(" dbname='([^ ]*)' ", uri)
self.assertTrue(m)
actual_dbname = m.group(1)
self.assertEqual(actual_dbname, expected_dbname)
@@ -94,48 +94,48 @@ def check_rasterTableURI(expected_dbname):
self.assertGreaterEqual(raster_tables_count, 1)
obj = QObject() # needs to be kept alive
- obj.connectionName = lambda: 'fake'
- obj.providerName = lambda: 'postgres'
+ obj.connectionName = lambda: "fake"
+ obj.providerName = lambda: "postgres"
# Test for empty URI
# See https://github.com/qgis/QGIS/issues/24525
# and https://github.com/qgis/QGIS/issues/19005
expected_dbname = self.testdb
- os.environ['PGDATABASE'] = expected_dbname
+ os.environ["PGDATABASE"] = expected_dbname
database = PGDatabase(obj, QgsDataSourceUri())
self.assertIsInstance(database, PGDatabase)
uri = database.uri()
- self.assertEqual(uri.host(), '')
- self.assertEqual(uri.username(), '')
+ self.assertEqual(uri.host(), "")
+ self.assertEqual(uri.username(), "")
self.assertEqual(uri.database(), expected_dbname)
- self.assertEqual(uri.service(), '')
+ self.assertEqual(uri.service(), "")
check_rasterTableURI(expected_dbname)
# Test for service-only URI
# See https://github.com/qgis/QGIS/issues/24526
- os.environ['PGDATABASE'] = 'fake'
- database = PGDatabase(obj, QgsDataSourceUri('service=dbmanager'))
+ os.environ["PGDATABASE"] = "fake"
+ database = PGDatabase(obj, QgsDataSourceUri("service=dbmanager"))
self.assertIsInstance(database, PGDatabase)
uri = database.uri()
- self.assertEqual(uri.host(), '')
- self.assertEqual(uri.username(), '')
- self.assertEqual(uri.database(), '')
- self.assertEqual(uri.service(), 'dbmanager')
+ self.assertEqual(uri.host(), "")
+ self.assertEqual(uri.username(), "")
+ self.assertEqual(uri.database(), "")
+ self.assertEqual(uri.service(), "dbmanager")
check_rasterTableURI(expected_dbname)
# See https://github.com/qgis/QGIS/issues/24732
def test_unicodeInQuery(self):
- os.environ['PGDATABASE'] = self.testdb
+ os.environ["PGDATABASE"] = self.testdb
obj = QObject() # needs to be kept alive
- obj.connectionName = lambda: 'fake'
- obj.providerName = lambda: 'postgres'
+ obj.connectionName = lambda: "fake"
+ obj.providerName = lambda: "postgres"
database = PGDatabase(obj, QgsDataSourceUri())
self.assertIsInstance(database, PGDatabase)
# SQL as string literal
@@ -150,5 +150,5 @@ def test_unicodeInQuery(self):
self.assertEqual(dat, "é")
-if __name__ == '__main__':
+if __name__ == "__main__":
unittest.main()
diff --git a/python/plugins/db_manager/db_plugins/postgis/plugins/__init__.py b/python/plugins/db_manager/db_plugins/postgis/plugins/__init__.py
index aa526e4a9fcb..a881b28d1a71 100644
--- a/python/plugins/db_manager/db_plugins/postgis/plugins/__init__.py
+++ b/python/plugins/db_manager/db_plugins/postgis/plugins/__init__.py
@@ -28,10 +28,10 @@ def load(db, mainwindow):
for name in os.listdir(current_dir):
if not os.path.isdir(os.path.join(current_dir, name)):
continue
- if name in ('__pycache__'):
+ if name in ("__pycache__"):
continue
try:
- plugin_module = import_module('.'.join((__package__, name)))
+ plugin_module = import_module(".".join((__package__, name)))
except ImportError:
continue
plugin_module.load(db, mainwindow)
diff --git a/python/plugins/db_manager/db_plugins/postgis/plugins/qgis_topoview/__init__.py b/python/plugins/db_manager/db_plugins/postgis/plugins/qgis_topoview/__init__.py
index 80c038df01b0..3b66aa9716e8 100644
--- a/python/plugins/db_manager/db_plugins/postgis/plugins/qgis_topoview/__init__.py
+++ b/python/plugins/db_manager/db_plugins/postgis/plugins/qgis_topoview/__init__.py
@@ -68,32 +68,47 @@ def run(item, action, mainwindow):
# check if the selected item is a topology schema
isTopoSchema = False
- if not hasattr(item, 'schema'):
- mainwindow.infoBar.pushMessage("Invalid topology", 'Select a topology schema to continue.', Qgis.MessageLevel.Info,
- mainwindow.iface.messageTimeout())
+ if not hasattr(item, "schema"):
+ mainwindow.infoBar.pushMessage(
+ "Invalid topology",
+ "Select a topology schema to continue.",
+ Qgis.MessageLevel.Info,
+ mainwindow.iface.messageTimeout(),
+ )
return False
if item.schema() is not None:
- sql = "SELECT srid FROM topology.topology WHERE name = %s" % quoteStr(item.schema().name)
+ sql = "SELECT srid FROM topology.topology WHERE name = %s" % quoteStr(
+ item.schema().name
+ )
res = db.executeSql(sql)
isTopoSchema = len(res) > 0
if not isTopoSchema:
- mainwindow.infoBar.pushMessage("Invalid topology",
- 'Schema "{}" is not registered in topology.topology.'.format(
- item.schema().name), Qgis.MessageLevel.Warning,
- mainwindow.iface.messageTimeout())
+ mainwindow.infoBar.pushMessage(
+ "Invalid topology",
+ 'Schema "{}" is not registered in topology.topology.'.format(
+ item.schema().name
+ ),
+ Qgis.MessageLevel.Warning,
+ mainwindow.iface.messageTimeout(),
+ )
return False
- if (res[0][0] < 0):
- mainwindow.infoBar.pushMessage("WARNING", 'Topology "{}" is registered as having a srid of {} in topology.topology, we will assume 0 (for unknown)'.format(item.schema().name, res[0]), Qgis.MessageLevel.Warning, mainwindow.iface.messageTimeout())
- toposrid = '0'
+ if res[0][0] < 0:
+ mainwindow.infoBar.pushMessage(
+ "WARNING",
+ f'Topology "{item.schema().name}" is registered as having a srid of {res[0]} in topology.topology, we will assume 0 (for unknown)',
+ Qgis.MessageLevel.Warning,
+ mainwindow.iface.messageTimeout(),
+ )
+ toposrid = "0"
else:
toposrid = str(res[0][0])
# load layers into the current project
toponame = item.schema().name
- template_dir = os.path.join(current_path, 'templates')
+ template_dir = os.path.join(current_path, "templates")
# do not refresh the canvas until all the layers are added
wasFrozen = iface.mapCanvas().isFrozen()
@@ -108,134 +123,164 @@ def run(item, action, mainwindow):
# FACES
# face mbr
- uri.setDataSource(toponame, 'face', 'mbr', '', 'face_id')
+ uri.setDataSource(toponame, "face", "mbr", "", "face_id")
uri.setSrid(toposrid)
uri.setWkbType(QgsWkbTypes.Type.Polygon)
- layerFaceMbr = QgsVectorLayer(uri.uri(False), '%s.face_mbr' % toponame, provider)
- layerFaceMbr.loadNamedStyle(os.path.join(template_dir, 'face_mbr.qml'))
+ layerFaceMbr = QgsVectorLayer(
+ uri.uri(False), "%s.face_mbr" % toponame, provider
+ )
+ layerFaceMbr.loadNamedStyle(os.path.join(template_dir, "face_mbr.qml"))
face_extent = layerFaceMbr.extent()
# face geometry
- sql = 'SELECT face_id, mbr, topology.ST_GetFaceGeometry(%s,' \
- 'face_id)::geometry(polygon, %s) as geom ' \
- 'FROM %s.face WHERE face_id > 0' % \
- (quoteStr(toponame), toposrid, quoteId(toponame))
- uri.setDataSource('', '(%s\n)' % sql, 'geom', '', 'face_id')
- uri.setParam('bbox', 'mbr')
- uri.setParam('checkPrimaryKeyUnicity', '0')
+ sql = (
+ "SELECT face_id, mbr, topology.ST_GetFaceGeometry(%s,"
+ "face_id)::geometry(polygon, %s) as geom "
+ "FROM %s.face WHERE face_id > 0"
+ % (quoteStr(toponame), toposrid, quoteId(toponame))
+ )
+ uri.setDataSource("", "(%s\n)" % sql, "geom", "", "face_id")
+ uri.setParam("bbox", "mbr")
+ uri.setParam("checkPrimaryKeyUnicity", "0")
uri.setSrid(toposrid)
uri.setWkbType(QgsWkbTypes.Type.Polygon)
- layerFaceGeom = QgsVectorLayer(uri.uri(False), '%s.face' % toponame, provider)
+ layerFaceGeom = QgsVectorLayer(uri.uri(False), "%s.face" % toponame, provider)
layerFaceGeom.setExtent(face_extent)
- layerFaceGeom.loadNamedStyle(os.path.join(template_dir, 'face.qml'))
+ layerFaceGeom.loadNamedStyle(os.path.join(template_dir, "face.qml"))
# face_seed
- sql = 'SELECT face_id, mbr, ST_PointOnSurface(' \
- 'topology.ST_GetFaceGeometry(%s,' \
- 'face_id))::geometry(point, %s) as geom ' \
- 'FROM %s.face WHERE face_id > 0' % \
- (quoteStr(toponame), toposrid, quoteId(toponame))
- uri.setDataSource('', '(%s)' % sql, 'geom', '', 'face_id')
- uri.setParam('bbox', 'mbr')
- uri.setParam('checkPrimaryKeyUnicity', '0')
+ sql = (
+ "SELECT face_id, mbr, ST_PointOnSurface("
+ "topology.ST_GetFaceGeometry(%s,"
+ "face_id))::geometry(point, %s) as geom "
+ "FROM %s.face WHERE face_id > 0"
+ % (quoteStr(toponame), toposrid, quoteId(toponame))
+ )
+ uri.setDataSource("", "(%s)" % sql, "geom", "", "face_id")
+ uri.setParam("bbox", "mbr")
+ uri.setParam("checkPrimaryKeyUnicity", "0")
uri.setSrid(toposrid)
uri.setWkbType(QgsWkbTypes.Type.Point)
- layerFaceSeed = QgsVectorLayer(uri.uri(False), '%s.face_seed' % toponame, provider)
+ layerFaceSeed = QgsVectorLayer(
+ uri.uri(False), "%s.face_seed" % toponame, provider
+ )
layerFaceSeed.setExtent(face_extent)
- layerFaceSeed.loadNamedStyle(os.path.join(template_dir, 'face_seed.qml'))
+ layerFaceSeed.loadNamedStyle(os.path.join(template_dir, "face_seed.qml"))
# TODO: add polygon0, polygon1 and polygon2 ?
# NODES
# node
- uri.setDataSource(toponame, 'node', 'geom', '', 'node_id')
- uri.removeParam('bbox')
+ uri.setDataSource(toponame, "node", "geom", "", "node_id")
+ uri.removeParam("bbox")
uri.setSrid(toposrid)
uri.setWkbType(QgsWkbTypes.Type.Point)
- layerNode = QgsVectorLayer(uri.uri(False), '%s.node' % toponame, provider)
- layerNode.loadNamedStyle(os.path.join(template_dir, 'node.qml'))
+ layerNode = QgsVectorLayer(uri.uri(False), "%s.node" % toponame, provider)
+ layerNode.loadNamedStyle(os.path.join(template_dir, "node.qml"))
node_extent = layerNode.extent()
# node labels
- uri.setDataSource(toponame, 'node', 'geom', '', 'node_id')
+ uri.setDataSource(toponame, "node", "geom", "", "node_id")
uri.setSrid(toposrid)
uri.setWkbType(QgsWkbTypes.Type.Point)
- uri.removeParam('bbox')
- layerNodeLabel = QgsVectorLayer(uri.uri(False), '%s.node_id' % toponame, provider)
+ uri.removeParam("bbox")
+ layerNodeLabel = QgsVectorLayer(
+ uri.uri(False), "%s.node_id" % toponame, provider
+ )
layerNodeLabel.setExtent(node_extent)
- layerNodeLabel.loadNamedStyle(os.path.join(template_dir, 'node_label.qml'))
+ layerNodeLabel.loadNamedStyle(os.path.join(template_dir, "node_label.qml"))
# EDGES
# edge
- uri.setDataSource(toponame, 'edge_data', 'geom', '', 'edge_id')
+ uri.setDataSource(toponame, "edge_data", "geom", "", "edge_id")
uri.setSrid(toposrid)
uri.setWkbType(QgsWkbTypes.Type.LineString)
- uri.removeParam('bbox')
- layerEdge = QgsVectorLayer(uri.uri(False), '%s.edge' % toponame, provider)
+ uri.removeParam("bbox")
+ layerEdge = QgsVectorLayer(uri.uri(False), "%s.edge" % toponame, provider)
edge_extent = layerEdge.extent()
# directed edge
- uri.setDataSource(toponame, 'edge_data', 'geom', '', 'edge_id')
+ uri.setDataSource(toponame, "edge_data", "geom", "", "edge_id")
uri.setSrid(toposrid)
uri.setWkbType(QgsWkbTypes.Type.LineString)
- uri.removeParam('bbox')
- layerDirectedEdge = QgsVectorLayer(uri.uri(False), '%s.directed_edge' % toponame, provider)
+ uri.removeParam("bbox")
+ layerDirectedEdge = QgsVectorLayer(
+ uri.uri(False), "%s.directed_edge" % toponame, provider
+ )
layerDirectedEdge.setExtent(edge_extent)
- layerDirectedEdge.loadNamedStyle(os.path.join(template_dir, 'edge.qml'))
+ layerDirectedEdge.loadNamedStyle(os.path.join(template_dir, "edge.qml"))
# edge labels
- uri.setDataSource(toponame, 'edge_data', 'geom', '', 'edge_id')
+ uri.setDataSource(toponame, "edge_data", "geom", "", "edge_id")
uri.setSrid(toposrid)
uri.setWkbType(QgsWkbTypes.Type.LineString)
- uri.removeParam('bbox')
- layerEdgeLabel = QgsVectorLayer(uri.uri(False), '%s.edge_id' % toponame, provider)
+ uri.removeParam("bbox")
+ layerEdgeLabel = QgsVectorLayer(
+ uri.uri(False), "%s.edge_id" % toponame, provider
+ )
layerEdgeLabel.setExtent(edge_extent)
- layerEdgeLabel.loadNamedStyle(os.path.join(template_dir, 'edge_label.qml'))
+ layerEdgeLabel.loadNamedStyle(os.path.join(template_dir, "edge_label.qml"))
# face_left
- uri.setDataSource(toponame, 'edge_data', 'geom', '', 'edge_id')
+ uri.setDataSource(toponame, "edge_data", "geom", "", "edge_id")
uri.setSrid(toposrid)
uri.setWkbType(QgsWkbTypes.Type.LineString)
- uri.removeParam('bbox')
- layerFaceLeft = QgsVectorLayer(uri.uri(False), '%s.face_left' % toponame, provider)
+ uri.removeParam("bbox")
+ layerFaceLeft = QgsVectorLayer(
+ uri.uri(False), "%s.face_left" % toponame, provider
+ )
layerFaceLeft.setExtent(edge_extent)
- layerFaceLeft.loadNamedStyle(os.path.join(template_dir, 'face_left.qml'))
+ layerFaceLeft.loadNamedStyle(os.path.join(template_dir, "face_left.qml"))
# face_right
- uri.setDataSource(toponame, 'edge_data', 'geom', '', 'edge_id')
+ uri.setDataSource(toponame, "edge_data", "geom", "", "edge_id")
uri.setSrid(toposrid)
uri.setWkbType(QgsWkbTypes.Type.LineString)
- uri.removeParam('bbox')
- layerFaceRight = QgsVectorLayer(uri.uri(False), '%s.face_right' % toponame, provider)
+ uri.removeParam("bbox")
+ layerFaceRight = QgsVectorLayer(
+ uri.uri(False), "%s.face_right" % toponame, provider
+ )
layerFaceRight.setExtent(edge_extent)
- layerFaceRight.loadNamedStyle(os.path.join(template_dir, 'face_right.qml'))
+ layerFaceRight.loadNamedStyle(os.path.join(template_dir, "face_right.qml"))
# next_left
- uri.setDataSource(toponame, 'edge_data', 'geom', '', 'edge_id')
+ uri.setDataSource(toponame, "edge_data", "geom", "", "edge_id")
uri.setSrid(toposrid)
uri.setWkbType(QgsWkbTypes.Type.LineString)
- uri.removeParam('bbox')
- layerNextLeft = QgsVectorLayer(uri.uri(False), '%s.next_left' % toponame, provider)
+ uri.removeParam("bbox")
+ layerNextLeft = QgsVectorLayer(
+ uri.uri(False), "%s.next_left" % toponame, provider
+ )
layerNextLeft.setExtent(edge_extent)
- layerNextLeft.loadNamedStyle(os.path.join(template_dir, 'next_left.qml'))
+ layerNextLeft.loadNamedStyle(os.path.join(template_dir, "next_left.qml"))
# next_right
- uri.setDataSource(toponame, 'edge_data', 'geom', '', 'edge_id')
+ uri.setDataSource(toponame, "edge_data", "geom", "", "edge_id")
uri.setSrid(toposrid)
uri.setWkbType(QgsWkbTypes.Type.LineString)
- uri.removeParam('bbox')
- layerNextRight = QgsVectorLayer(uri.uri(False), '%s.next_right' % toponame, provider)
+ uri.removeParam("bbox")
+ layerNextRight = QgsVectorLayer(
+ uri.uri(False), "%s.next_right" % toponame, provider
+ )
layerNextRight.setExtent(edge_extent)
- layerNextRight.loadNamedStyle(os.path.join(template_dir, 'next_right.qml'))
+ layerNextRight.loadNamedStyle(os.path.join(template_dir, "next_right.qml"))
# Add layers to the layer tree
faceLayers = [layerFaceMbr, layerFaceGeom, layerFaceSeed]
nodeLayers = [layerNode, layerNodeLabel]
- edgeLayers = [layerEdge, layerDirectedEdge, layerEdgeLabel, layerFaceLeft, layerFaceRight, layerNextLeft, layerNextRight]
+ edgeLayers = [
+ layerEdge,
+ layerDirectedEdge,
+ layerEdgeLabel,
+ layerFaceLeft,
+ layerFaceRight,
+ layerNextLeft,
+ layerNextRight,
+ ]
QgsProject.instance().addMapLayers(faceLayers, False)
QgsProject.instance().addMapLayers(nodeLayers, False)
@@ -243,19 +288,19 @@ def run(item, action, mainwindow):
# Organize layers in groups
- groupFaces = QgsLayerTreeGroup('Faces')
+ groupFaces = QgsLayerTreeGroup("Faces")
for layer in faceLayers:
nodeLayer = groupFaces.addLayer(layer)
nodeLayer.setItemVisibilityChecked(False)
nodeLayer.setExpanded(False)
- groupNodes = QgsLayerTreeGroup('Nodes')
+ groupNodes = QgsLayerTreeGroup("Nodes")
for layer in nodeLayers:
nodeLayer = groupNodes.addLayer(layer)
nodeLayer.setItemVisibilityChecked(False)
nodeLayer.setExpanded(False)
- groupEdges = QgsLayerTreeGroup('Edges')
+ groupEdges = QgsLayerTreeGroup("Edges")
for layer in edgeLayers:
nodeLayer = groupEdges.addLayer(layer)
nodeLayer.setItemVisibilityChecked(False)
@@ -295,7 +340,7 @@ def run(item, action, mainwindow):
# Set canvas extent to topology extent, if not yet initialized
canvas = iface.mapCanvas()
- if (canvas.fullExtent().isNull()):
+ if canvas.fullExtent().isNull():
ext = node_extent
ext.combineExtentWith(edge_extent)
# Grow by 1/20 of largest side
diff --git a/python/plugins/db_manager/db_plugins/postgis/plugins/versioning/__init__.py b/python/plugins/db_manager/db_plugins/postgis/plugins/versioning/__init__.py
index 4320453779b4..556ce859bcdc 100644
--- a/python/plugins/db_manager/db_plugins/postgis/plugins/versioning/__init__.py
+++ b/python/plugins/db_manager/db_plugins/postgis/plugins/versioning/__init__.py
@@ -30,8 +30,12 @@
def load(db, mainwindow):
# add the action to the DBManager menu
- action = QAction(QIcon(), QApplication.translate("DBManagerPlugin", "&Change Logging…"), db)
- mainwindow.registerAction(action, QApplication.translate("DBManagerPlugin", "&Table"), run)
+ action = QAction(
+ QIcon(), QApplication.translate("DBManagerPlugin", "&Change Logging…"), db
+ )
+ mainwindow.registerAction(
+ action, QApplication.translate("DBManagerPlugin", "&Table"), run
+ )
# The run function is called once the user clicks on the action TopoViewer
diff --git a/python/plugins/db_manager/db_plugins/postgis/plugins/versioning/dlg_versioning.py b/python/plugins/db_manager/db_plugins/postgis/plugins/versioning/dlg_versioning.py
index 41813bcb35a1..068ba08503b9 100644
--- a/python/plugins/db_manager/db_plugins/postgis/plugins/versioning/dlg_versioning.py
+++ b/python/plugins/db_manager/db_plugins/postgis/plugins/versioning/dlg_versioning.py
@@ -28,7 +28,7 @@
from .....dlg_db_error import DlgDbError
from ....plugin import BaseError, Table
-Ui_DlgVersioning, _ = uic.loadUiType(Path(__file__).parent / 'DlgVersioining.ui')
+Ui_DlgVersioning, _ = uic.loadUiType(Path(__file__).parent / "DlgVersioining.ui")
class DlgVersioning(QDialog, Ui_DlgVersioning):
@@ -75,7 +75,7 @@ def populateSchemas(self):
index = -1
for schema in self.schemas:
self.cboSchema.addItem(schema.name)
- if hasattr(self.item, 'schema') and schema.name == self.item.schema().name:
+ if hasattr(self.item, "schema") and schema.name == self.item.schema().name:
index = self.cboSchema.count() - 1
self.cboSchema.setCurrentIndex(index)
@@ -100,12 +100,15 @@ def populateTables(self):
self.cboTable.addItem(table.name)
def get_escaped_name(self, schema, table, suffix):
- name = self.db.connector.quoteId("%s%s" % (table, suffix))
+ name = self.db.connector.quoteId(f"{table}{suffix}")
schema_name = self.db.connector.quoteId(schema) if schema else None
- return "%s.%s" % (schema_name, name) if schema_name else name
+ return f"{schema_name}.{name}" if schema_name else name
def updateSql(self):
- if self.cboTable.currentIndex() < 0 or len(self.tables) < self.cboTable.currentIndex():
+ if (
+ self.cboTable.currentIndex() < 0
+ or len(self.tables) < self.cboTable.currentIndex()
+ ):
return
self.table = self.tables[self.cboTable.currentIndex()]
@@ -124,7 +127,10 @@ def updateSql(self):
for constr in self.table.constraints():
if constr.type == constr.TypePrimaryKey:
self.origPkeyName = self.db.connector.quoteId(constr.name)
- self.colOrigPkey = [self.db.connector.quoteId(x_y[1].name) for x_y in iter(list(constr.fields().items()))]
+ self.colOrigPkey = [
+ self.db.connector.quoteId(x_y[1].name)
+ for x_y in iter(list(constr.fields().items()))
+ ]
break
if self.colOrigPkey is None:
@@ -140,11 +146,19 @@ def updateSql(self):
self.colOrigPkey = self.colOrigPkey[0]
# define view, function, rule and trigger names
- self.view = self.get_escaped_name(self.table.schemaName(), self.table.name, "_current")
-
- self.func_at_time = self.get_escaped_name(self.table.schemaName(), self.table.name, "_at_time")
- self.func_update = self.get_escaped_name(self.table.schemaName(), self.table.name, "_update")
- self.func_insert = self.get_escaped_name(self.table.schemaName(), self.table.name, "_insert")
+ self.view = self.get_escaped_name(
+ self.table.schemaName(), self.table.name, "_current"
+ )
+
+ self.func_at_time = self.get_escaped_name(
+ self.table.schemaName(), self.table.name, "_at_time"
+ )
+ self.func_update = self.get_escaped_name(
+ self.table.schemaName(), self.table.name, "_update"
+ )
+ self.func_insert = self.get_escaped_name(
+ self.table.schemaName(), self.table.name, "_insert"
+ )
self.rule_del = self.get_escaped_name(None, self.table.name, "_del")
self.trigger_update = self.get_escaped_name(None, self.table.name, "_update")
@@ -166,7 +180,7 @@ def updateSql(self):
# if self.current:
sql.append(self.sql_updatesView())
- self.txtSql.setPlainText('\n\n'.join(sql))
+ self.txtSql.setPlainText("\n\n".join(sql))
self.buttonBox.button(QDialogButtonBox.StandardButton.Ok).setEnabled(True)
return sql
@@ -176,18 +190,27 @@ def showHelp(self):
QMessageBox.information(self, "Help", helpText)
def sql_alterTable(self):
- return "ALTER TABLE %s ADD %s serial, ADD %s timestamp default '-infinity', ADD %s timestamp, ADD %s varchar;" % (
- self.schematable, self.colPkey, self.colStart, self.colEnd, self.colUser)
+ return "ALTER TABLE {} ADD {} serial, ADD {} timestamp default '-infinity', ADD {} timestamp, ADD {} varchar;".format(
+ self.schematable, self.colPkey, self.colStart, self.colEnd, self.colUser
+ )
def sql_setPkey(self):
- return "ALTER TABLE %s DROP CONSTRAINT %s, ADD PRIMARY KEY (%s);" % (
- self.schematable, self.origPkeyName, self.colPkey)
+ return "ALTER TABLE {} DROP CONSTRAINT {}, ADD PRIMARY KEY ({});".format(
+ self.schematable, self.origPkeyName, self.colPkey
+ )
def sql_currentView(self):
cols = self.colPkey + "," + ",".join(self.columns)
- return "CREATE VIEW %(view)s AS SELECT %(cols)s FROM %(schematable)s WHERE %(end)s IS NULL;" % \
- {'view': self.view, 'cols': cols, 'schematable': self.schematable, 'end': self.colEnd}
+ return (
+ "CREATE VIEW %(view)s AS SELECT %(cols)s FROM %(schematable)s WHERE %(end)s IS NULL;"
+ % {
+ "view": self.view,
+ "cols": cols,
+ "schematable": self.schematable,
+ "end": self.colEnd,
+ }
+ )
def sql_functions(self):
cols = ",".join(self.columns)
@@ -195,80 +218,99 @@ def sql_functions(self):
old_cols = ",".join("OLD." + x for x in self.columns)
sql = """
-CREATE OR REPLACE FUNCTION %(func_at_time)s(timestamp)
-RETURNS SETOF %(view)s AS
+CREATE OR REPLACE FUNCTION {func_at_time}(timestamp)
+RETURNS SETOF {view} AS
$$
-SELECT %(all_cols)s FROM %(schematable)s WHERE
- ( SELECT CASE WHEN %(end)s IS NULL THEN (%(start)s <= $1) ELSE (%(start)s <= $1 AND %(end)s > $1) END );
+SELECT {all_cols} FROM {schematable} WHERE
+ ( SELECT CASE WHEN {end} IS NULL THEN ({start} <= $1) ELSE ({start} <= $1 AND {end} > $1) END );
$$
LANGUAGE 'sql';
-CREATE OR REPLACE FUNCTION %(func_update)s()
+CREATE OR REPLACE FUNCTION {func_update}()
RETURNS TRIGGER AS
$$
BEGIN
- IF OLD.%(end)s IS NOT NULL THEN
+ IF OLD.{end} IS NOT NULL THEN
RETURN NULL;
END IF;
- IF NEW.%(end)s IS NULL THEN
- INSERT INTO %(schematable)s (%(cols)s, %(start)s, %(end)s) VALUES (%(oldcols)s, OLD.%(start)s, current_timestamp);
- NEW.%(start)s = current_timestamp;
- NEW.%(user)s = current_user;
+ IF NEW.{end} IS NULL THEN
+ INSERT INTO {schematable} ({cols}, {start}, {end}) VALUES ({oldcols}, OLD.{start}, current_timestamp);
+ NEW.{start} = current_timestamp;
+ NEW.{user} = current_user;
END IF;
RETURN NEW;
END;
$$
LANGUAGE 'plpgsql';
-CREATE OR REPLACE FUNCTION %(func_insert)s()
+CREATE OR REPLACE FUNCTION {func_insert}()
RETURNS trigger AS
$$
BEGIN
- if NEW.%(start)s IS NULL then
- NEW.%(start)s = now();
- NEW.%(end)s = null;
- NEW.%(user)s = current_user;
+ if NEW.{start} IS NULL then
+ NEW.{start} = now();
+ NEW.{end} = null;
+ NEW.{user} = current_user;
end if;
RETURN NEW;
END;
$$
-LANGUAGE 'plpgsql';""" % {'view': self.view, 'schematable': self.schematable, 'cols': cols, 'oldcols': old_cols,
- 'start': self.colStart, 'end': self.colEnd, 'user': self.colUser, 'func_at_time': self.func_at_time,
- 'all_cols': all_cols, 'func_update': self.func_update, 'func_insert': self.func_insert}
+LANGUAGE 'plpgsql';""".format(
+ view=self.view,
+ schematable=self.schematable,
+ cols=cols,
+ oldcols=old_cols,
+ start=self.colStart,
+ end=self.colEnd,
+ user=self.colUser,
+ func_at_time=self.func_at_time,
+ all_cols=all_cols,
+ func_update=self.func_update,
+ func_insert=self.func_insert,
+ )
return sql
def sql_triggers(self):
return """
-CREATE RULE %(rule_del)s AS ON DELETE TO %(schematable)s
-DO INSTEAD UPDATE %(schematable)s SET %(end)s = current_timestamp WHERE %(pkey)s = OLD.%(pkey)s AND %(end)s IS NULL;
-
-CREATE TRIGGER %(trigger_update)s BEFORE UPDATE ON %(schematable)s
-FOR EACH ROW EXECUTE PROCEDURE %(func_update)s();
-
-CREATE TRIGGER %(trigger_insert)s BEFORE INSERT ON %(schematable)s
-FOR EACH ROW EXECUTE PROCEDURE %(func_insert)s();""" % \
- {'rule_del': self.rule_del, 'trigger_update': self.trigger_update, 'trigger_insert': self.trigger_insert,
- 'func_update': self.func_update, 'func_insert': self.func_insert, 'schematable': self.schematable,
- 'pkey': self.colPkey, 'end': self.colEnd}
+CREATE RULE {rule_del} AS ON DELETE TO {schematable}
+DO INSTEAD UPDATE {schematable} SET {end} = current_timestamp WHERE {pkey} = OLD.{pkey} AND {end} IS NULL;
+
+CREATE TRIGGER {trigger_update} BEFORE UPDATE ON {schematable}
+FOR EACH ROW EXECUTE PROCEDURE {func_update}();
+
+CREATE TRIGGER {trigger_insert} BEFORE INSERT ON {schematable}
+FOR EACH ROW EXECUTE PROCEDURE {func_insert}();""".format(
+ rule_del=self.rule_del,
+ trigger_update=self.trigger_update,
+ trigger_insert=self.trigger_insert,
+ func_update=self.func_update,
+ func_insert=self.func_insert,
+ schematable=self.schematable,
+ pkey=self.colPkey,
+ end=self.colEnd,
+ )
def sql_updatesView(self):
cols = ",".join(self.columns)
return_cols = self.colPkey + "," + ",".join(self.columns)
new_cols = ",".join("NEW." + x for x in self.columns)
- assign_cols = ",".join("%s = NEW.%s" % (x, x) for x in self.columns)
+ assign_cols = ",".join(f"{x} = NEW.{x}" for x in self.columns)
return """
-CREATE OR REPLACE RULE "_DELETE" AS ON DELETE TO %(view)s DO INSTEAD
- DELETE FROM %(schematable)s WHERE %(origpkey)s = old.%(origpkey)s;
-CREATE OR REPLACE RULE "_INSERT" AS ON INSERT TO %(view)s DO INSTEAD
- INSERT INTO %(schematable)s (%(cols)s) VALUES (%(newcols)s) RETURNING %(return_cols)s;
-CREATE OR REPLACE RULE "_UPDATE" AS ON UPDATE TO %(view)s DO INSTEAD
- UPDATE %(schematable)s SET %(assign)s WHERE %(origpkey)s = NEW.%(origpkey)s;""" % {'view': self.view,
- 'schematable': self.schematable,
- 'cols': cols, 'newcols': new_cols,
- 'return_cols': return_cols,
- 'assign': assign_cols,
- 'origpkey': self.colOrigPkey}
+CREATE OR REPLACE RULE "_DELETE" AS ON DELETE TO {view} DO INSTEAD
+ DELETE FROM {schematable} WHERE {origpkey} = old.{origpkey};
+CREATE OR REPLACE RULE "_INSERT" AS ON INSERT TO {view} DO INSTEAD
+ INSERT INTO {schematable} ({cols}) VALUES ({newcols}) RETURNING {return_cols};
+CREATE OR REPLACE RULE "_UPDATE" AS ON UPDATE TO {view} DO INSTEAD
+ UPDATE {schematable} SET {assign} WHERE {origpkey} = NEW.{origpkey};""".format(
+ view=self.view,
+ schematable=self.schematable,
+ cols=cols,
+ newcols=new_cols,
+ return_cols=return_cols,
+ assign=assign_cols,
+ origpkey=self.colOrigPkey,
+ )
def onOK(self):
# execute and commit the code
@@ -284,5 +326,7 @@ def onOK(self):
finally:
QApplication.restoreOverrideCursor()
- QMessageBox.information(self, "DB Manager", "Versioning was successfully created.")
+ QMessageBox.information(
+ self, "DB Manager", "Versioning was successfully created."
+ )
self.accept()
diff --git a/python/plugins/db_manager/db_plugins/postgis/sql_dictionary.py b/python/plugins/db_manager/db_plugins/postgis/sql_dictionary.py
index ea7c6de97a11..9b8f1f19a485 100644
--- a/python/plugins/db_manager/db_plugins/postgis/sql_dictionary.py
+++ b/python/plugins/db_manager/db_plugins/postgis/sql_dictionary.py
@@ -15,185 +15,855 @@
***************************************************************************
"""
-__author__ = 'Giuseppe Sucameli'
-__date__ = 'April 2012'
-__copyright__ = '(C) 2012, Giuseppe Sucameli'
+__author__ = "Giuseppe Sucameli"
+__date__ = "April 2012"
+__copyright__ = "(C) 2012, Giuseppe Sucameli"
# keywords
keywords = [
# TODO get them from a reference page
- "action", "add", "after", "all", "alter", "analyze", "and", "as", "asc",
- "before", "begin", "between", "by", "cascade", "case", "cast", "check",
- "collate", "column", "commit", "constraint", "create", "cross", "current_date",
- "current_time", "current_timestamp", "default", "deferrable", "deferred",
- "delete", "desc", "distinct", "drop", "each", "else", "end", "escape",
- "except", "exists", "for", "foreign", "from", "full", "group", "having",
- "ignore", "immediate", "in", "initially", "inner", "insert", "intersect",
- "into", "is", "isnull", "join", "key", "left", "like", "limit", "match",
- "natural", "no", "not", "notnull", "null", "of", "offset", "on", "or", "order",
- "outer", "primary", "references", "release", "restrict", "right", "rollback",
- "row", "savepoint", "select", "set", "table", "temporary", "then", "to",
- "transaction", "trigger", "union", "unique", "update", "using", "values",
- "view", "when", "where",
-
- "absolute", "admin", "aggregate", "alias", "allocate", "analyse", "any", "are",
- "array", "asensitive", "assertion", "asymmetric", "at", "atomic",
- "authorization", "avg", "bigint", "binary", "bit", "bit_length", "blob",
- "boolean", "both", "breadth", "call", "called", "cardinality", "cascaded",
- "catalog", "ceil", "ceiling", "char", "character", "character_length",
- "char_length", "class", "clob", "close", "coalesce", "collation", "collect",
- "completion", "condition", "connect", "connection", "constraints",
- "constructor", "continue", "convert", "corr", "corresponding", "count",
- "covar_pop", "covar_samp", "cube", "cume_dist", "current",
- "current_default_transform_group", "current_path", "current_role",
- "current_transform_group_for_type", "current_user", "cursor", "cycle", "data",
- "date", "day", "deallocate", "dec", "decimal", "declare", "dense_rank",
- "depth", "deref", "describe", "descriptor", "destroy", "destructor",
- "deterministic", "diagnostics", "dictionary", "disconnect", "do", "domain",
- "double", "dynamic", "element", "end-exec", "equals", "every", "exception",
- "exec", "execute", "exp", "external", "extract", "false", "fetch", "filter",
- "first", "float", "floor", "found", "free", "freeze", "function", "fusion",
- "general", "get", "global", "go", "goto", "grant", "grouping", "hold", "host",
- "hour", "identity", "ilike", "indicator", "initialize", "inout", "input",
- "insensitive", "int", "integer", "intersection", "interval", "isolation",
- "iterate", "language", "large", "last", "lateral", "leading", "less", "level",
- "ln", "local", "localtime", "localtimestamp", "locator", "lower", "map", "max",
- "member", "merge", "method", "min", "minute", "mod", "modifies", "modify",
- "module", "month", "multiset", "names", "national", "nchar", "nclob", "new",
- "next", "none", "normalize", "nullif", "numeric", "object", "octet_length",
- "off", "old", "only", "open", "operation", "option", "ordinality", "out",
- "output", "over", "overlaps", "overlay", "pad", "parameter", "parameters",
- "partial", "partition", "path", "percentile_cont", "percentile_disc",
- "percent_rank", "placing", "position", "postfix", "power", "precision",
- "prefix", "preorder", "prepare", "preserve", "prior", "privileges",
- "procedure", "public", "range", "rank", "read", "reads", "real", "recursive",
- "ref", "referencing", "regr_avgx", "regr_avgy", "regr_count", "regr_intercept",
- "regr_r2", "regr_slope", "regr_sxx", "regr_sxy", "regr_syy", "relative",
- "result", "return", "returning", "returns", "revoke", "role", "rollup",
- "routine", "rows", "row_number", "schema", "scope", "scroll", "search",
- "second", "section", "sensitive", "sequence", "session", "session_user",
- "sets", "similar", "size", "smallint", "some", "space", "specific",
- "specifictype", "sql", "sqlcode", "sqlerror", "sqlexception", "sqlstate",
- "sqlwarning", "sqrt", "start", "state", "statement", "static", "stddev_pop",
- "stddev_samp", "structure", "submultiset", "substring", "sum", "symmetric",
- "system", "system_user", "tablesample", "terminate", "than", "time",
- "timestamp", "timezone_hour", "timezone_minute", "trailing", "translate",
- "translation", "treat", "trim", "true", "uescape", "under", "unknown",
- "unnest", "upper", "usage", "user", "value", "varchar", "variable", "varying",
- "var_pop", "var_samp", "verbose", "whenever", "width_bucket", "window", "with",
- "within", "without", "work", "write", "xml", "xmlagg", "xmlattributes",
- "xmlbinary", "xmlcomment", "xmlconcat", "xmlelement", "xmlforest",
- "xmlnamespaces", "xmlparse", "xmlpi", "xmlroot", "xmlserialize", "year", "zone"
+ "action",
+ "add",
+ "after",
+ "all",
+ "alter",
+ "analyze",
+ "and",
+ "as",
+ "asc",
+ "before",
+ "begin",
+ "between",
+ "by",
+ "cascade",
+ "case",
+ "cast",
+ "check",
+ "collate",
+ "column",
+ "commit",
+ "constraint",
+ "create",
+ "cross",
+ "current_date",
+ "current_time",
+ "current_timestamp",
+ "default",
+ "deferrable",
+ "deferred",
+ "delete",
+ "desc",
+ "distinct",
+ "drop",
+ "each",
+ "else",
+ "end",
+ "escape",
+ "except",
+ "exists",
+ "for",
+ "foreign",
+ "from",
+ "full",
+ "group",
+ "having",
+ "ignore",
+ "immediate",
+ "in",
+ "initially",
+ "inner",
+ "insert",
+ "intersect",
+ "into",
+ "is",
+ "isnull",
+ "join",
+ "key",
+ "left",
+ "like",
+ "limit",
+ "match",
+ "natural",
+ "no",
+ "not",
+ "notnull",
+ "null",
+ "of",
+ "offset",
+ "on",
+ "or",
+ "order",
+ "outer",
+ "primary",
+ "references",
+ "release",
+ "restrict",
+ "right",
+ "rollback",
+ "row",
+ "savepoint",
+ "select",
+ "set",
+ "table",
+ "temporary",
+ "then",
+ "to",
+ "transaction",
+ "trigger",
+ "union",
+ "unique",
+ "update",
+ "using",
+ "values",
+ "view",
+ "when",
+ "where",
+ "absolute",
+ "admin",
+ "aggregate",
+ "alias",
+ "allocate",
+ "analyse",
+ "any",
+ "are",
+ "array",
+ "asensitive",
+ "assertion",
+ "asymmetric",
+ "at",
+ "atomic",
+ "authorization",
+ "avg",
+ "bigint",
+ "binary",
+ "bit",
+ "bit_length",
+ "blob",
+ "boolean",
+ "both",
+ "breadth",
+ "call",
+ "called",
+ "cardinality",
+ "cascaded",
+ "catalog",
+ "ceil",
+ "ceiling",
+ "char",
+ "character",
+ "character_length",
+ "char_length",
+ "class",
+ "clob",
+ "close",
+ "coalesce",
+ "collation",
+ "collect",
+ "completion",
+ "condition",
+ "connect",
+ "connection",
+ "constraints",
+ "constructor",
+ "continue",
+ "convert",
+ "corr",
+ "corresponding",
+ "count",
+ "covar_pop",
+ "covar_samp",
+ "cube",
+ "cume_dist",
+ "current",
+ "current_default_transform_group",
+ "current_path",
+ "current_role",
+ "current_transform_group_for_type",
+ "current_user",
+ "cursor",
+ "cycle",
+ "data",
+ "date",
+ "day",
+ "deallocate",
+ "dec",
+ "decimal",
+ "declare",
+ "dense_rank",
+ "depth",
+ "deref",
+ "describe",
+ "descriptor",
+ "destroy",
+ "destructor",
+ "deterministic",
+ "diagnostics",
+ "dictionary",
+ "disconnect",
+ "do",
+ "domain",
+ "double",
+ "dynamic",
+ "element",
+ "end-exec",
+ "equals",
+ "every",
+ "exception",
+ "exec",
+ "execute",
+ "exp",
+ "external",
+ "extract",
+ "false",
+ "fetch",
+ "filter",
+ "first",
+ "float",
+ "floor",
+ "found",
+ "free",
+ "freeze",
+ "function",
+ "fusion",
+ "general",
+ "get",
+ "global",
+ "go",
+ "goto",
+ "grant",
+ "grouping",
+ "hold",
+ "host",
+ "hour",
+ "identity",
+ "ilike",
+ "indicator",
+ "initialize",
+ "inout",
+ "input",
+ "insensitive",
+ "int",
+ "integer",
+ "intersection",
+ "interval",
+ "isolation",
+ "iterate",
+ "language",
+ "large",
+ "last",
+ "lateral",
+ "leading",
+ "less",
+ "level",
+ "ln",
+ "local",
+ "localtime",
+ "localtimestamp",
+ "locator",
+ "lower",
+ "map",
+ "max",
+ "member",
+ "merge",
+ "method",
+ "min",
+ "minute",
+ "mod",
+ "modifies",
+ "modify",
+ "module",
+ "month",
+ "multiset",
+ "names",
+ "national",
+ "nchar",
+ "nclob",
+ "new",
+ "next",
+ "none",
+ "normalize",
+ "nullif",
+ "numeric",
+ "object",
+ "octet_length",
+ "off",
+ "old",
+ "only",
+ "open",
+ "operation",
+ "option",
+ "ordinality",
+ "out",
+ "output",
+ "over",
+ "overlaps",
+ "overlay",
+ "pad",
+ "parameter",
+ "parameters",
+ "partial",
+ "partition",
+ "path",
+ "percentile_cont",
+ "percentile_disc",
+ "percent_rank",
+ "placing",
+ "position",
+ "postfix",
+ "power",
+ "precision",
+ "prefix",
+ "preorder",
+ "prepare",
+ "preserve",
+ "prior",
+ "privileges",
+ "procedure",
+ "public",
+ "range",
+ "rank",
+ "read",
+ "reads",
+ "real",
+ "recursive",
+ "ref",
+ "referencing",
+ "regr_avgx",
+ "regr_avgy",
+ "regr_count",
+ "regr_intercept",
+ "regr_r2",
+ "regr_slope",
+ "regr_sxx",
+ "regr_sxy",
+ "regr_syy",
+ "relative",
+ "result",
+ "return",
+ "returning",
+ "returns",
+ "revoke",
+ "role",
+ "rollup",
+ "routine",
+ "rows",
+ "row_number",
+ "schema",
+ "scope",
+ "scroll",
+ "search",
+ "second",
+ "section",
+ "sensitive",
+ "sequence",
+ "session",
+ "session_user",
+ "sets",
+ "similar",
+ "size",
+ "smallint",
+ "some",
+ "space",
+ "specific",
+ "specifictype",
+ "sql",
+ "sqlcode",
+ "sqlerror",
+ "sqlexception",
+ "sqlstate",
+ "sqlwarning",
+ "sqrt",
+ "start",
+ "state",
+ "statement",
+ "static",
+ "stddev_pop",
+ "stddev_samp",
+ "structure",
+ "submultiset",
+ "substring",
+ "sum",
+ "symmetric",
+ "system",
+ "system_user",
+ "tablesample",
+ "terminate",
+ "than",
+ "time",
+ "timestamp",
+ "timezone_hour",
+ "timezone_minute",
+ "trailing",
+ "translate",
+ "translation",
+ "treat",
+ "trim",
+ "true",
+ "uescape",
+ "under",
+ "unknown",
+ "unnest",
+ "upper",
+ "usage",
+ "user",
+ "value",
+ "varchar",
+ "variable",
+ "varying",
+ "var_pop",
+ "var_samp",
+ "verbose",
+ "whenever",
+ "width_bucket",
+ "window",
+ "with",
+ "within",
+ "without",
+ "work",
+ "write",
+ "xml",
+ "xmlagg",
+ "xmlattributes",
+ "xmlbinary",
+ "xmlcomment",
+ "xmlconcat",
+ "xmlelement",
+ "xmlforest",
+ "xmlnamespaces",
+ "xmlparse",
+ "xmlpi",
+ "xmlroot",
+ "xmlserialize",
+ "year",
+ "zone",
]
postgis_keywords = []
# functions
-functions = [
- "coalesce",
- "nullif", "quote", "random",
- "replace", "soundex"
-]
+functions = ["coalesce", "nullif", "quote", "random", "replace", "soundex"]
operators = [
- ' AND ', ' OR ', '||', ' < ', ' <= ', ' > ', ' >= ', ' = ', ' <> ', ' IS ', ' IS NOT ', ' IN ', ' LIKE ', ' GLOB ', ' MATCH ', ' REGEXP '
+ " AND ",
+ " OR ",
+ "||",
+ " < ",
+ " <= ",
+ " > ",
+ " >= ",
+ " = ",
+ " <> ",
+ " IS ",
+ " IS NOT ",
+ " IN ",
+ " LIKE ",
+ " GLOB ",
+ " MATCH ",
+ " REGEXP ",
]
math_functions = [
# SQL math functions
- "Abs", "ACos", "ASin", "ATan", "Cos", "Cot", "Degrees", "Exp", "Floor", "Log", "Log2",
- "Log10", "Pi", "Radians", "Round", "Sign", "Sin", "Sqrt", "StdDev_Pop", "StdDev_Samp", "Tan",
- "Var_Pop", "Var_Samp"]
+ "Abs",
+ "ACos",
+ "ASin",
+ "ATan",
+ "Cos",
+ "Cot",
+ "Degrees",
+ "Exp",
+ "Floor",
+ "Log",
+ "Log2",
+ "Log10",
+ "Pi",
+ "Radians",
+ "Round",
+ "Sign",
+ "Sin",
+ "Sqrt",
+ "StdDev_Pop",
+ "StdDev_Samp",
+ "Tan",
+ "Var_Pop",
+ "Var_Samp",
+]
-string_functions = ["Length", "Lower", "Upper", "Like", "Trim", "LTrim", "RTrim", "Replace", "Substr"]
+string_functions = [
+ "Length",
+ "Lower",
+ "Upper",
+ "Like",
+ "Trim",
+ "LTrim",
+ "RTrim",
+ "Replace",
+ "Substr",
+]
aggregate_functions = [
- "Max", "Min", "Avg", "Count", "Sum", "Group_Concat", "Total", "Var_Pop", "Var_Samp", "StdDev_Pop", "StdDev_Samp"
+ "Max",
+ "Min",
+ "Avg",
+ "Count",
+ "Sum",
+ "Group_Concat",
+ "Total",
+ "Var_Pop",
+ "Var_Samp",
+ "StdDev_Pop",
+ "StdDev_Samp",
]
postgis_functions = [ # from http://www.postgis.org/docs/reference.html
- # 7.1. PostgreSQL PostGIS Types
- "*box2d", "*box3d", "*box3d_extent", "*geometry", "*geometry_dump", "*geography",
- # 7.2. Management Functions
- "*addgeometrycolumn", "*dropgeometrycolumn", "*dropgeometrytable", "*postgis_full_version",
- "*postgis_geos_version", "*postgis_libxml_version", "*postgis_lib_build_date",
- "*postgis_lib_version", "*postgis_proj_version", "*postgis_scripts_build_date",
- "*postgis_scripts_installed", "*postgis_scripts_released", "*postgis_uses_stats", "*postgis_version",
- "*populate_geometry_columns", "*probe_geometry_columns", "*updategeometrysrid",
- # 7.3. Geometry Constructors
- "*ST_bdpolyfromtext", "*ST_bdmpolyfromtext", "*ST_geogfromtext", "*ST_geographyfromtext",
- "*ST_geogfromwkb", "*ST_geomcollfromtext", "*ST_geomfromewkb", "*ST_geomfromewkt",
- "*ST_geometryfromtext", "*ST_geomfromgml", "*ST_geomfromkml", "*ST_gmltosql", "*ST_geomfromtext",
- "*ST_geomfromwkb", "*ST_linefrommultipoint", "*ST_linefromtext", "*ST_linefromwkb",
- "*ST_linestringfromwkb", "*ST_makebox2d", "*ST_makebox3d", "ST_MakeLine", "*ST_makeenvelope",
- "ST_MakePolygon", "ST_MakePoint", "ST_MakePointM", "*ST_MLinefromtext", "*ST_mpointfromtext",
- "*ST_mpolyfromtext", "ST_Point", "*ST_pointfromtext", "*ST_pointfromwkb", "ST_Polygon",
- "*ST_polygonfromtext", "*ST_wkbtosql", "*ST_wkttosql",
- # 7.4. Geometry Accessors
- "GeometryType", "ST_Boundary", "*ST_coorddim", "ST_Dimension", "ST_EndPoint", "ST_Envelope",
- "ST_ExteriorRing", "ST_GeometryN", "ST_GeometryType", "ST_InteriorRingN", "ST_isClosed",
- "ST_isEmpty", "ST_isRing", "ST_isSimple", "ST_isValid", "ST_isValidReason", "ST_M", "ST_NDims",
- "ST_NPoints", "ST_NRings", "ST_NumGeometries", "ST_NumInteriorrings", "ST_NumInteriorring",
- "ST_NumPoints", "ST_PointN", "ST_Srid", "ST_StartPoint", "ST_Summary", "ST_X", "ST_Y", "ST_Z",
- "*ST_zmflag",
- # 7.5. Geometry Editors
- "ST_AddPoint", "ST_Affine", "ST_Force2D", "*ST_Force3D", "*ST_Force3dZ", "*ST_Force3DM",
- "*ST_Force_4d", "*ST_force_collection", "*ST_forcerhr", "*ST_linemerge", "*ST_collectionextract",
- "ST_Multi", "*ST_removepoint", "*ST_reverse", "*ST_rotate", "*ST_rotatex", "*ST_rotatey",
- "*ST_rotatez", "*ST_scale", "*ST_segmentize", "*ST_setpoint", "ST_SetSrid", "ST_SnapToGrid",
- "ST_Transform", "ST_Translate", "*ST_transscale",
- # 7.6. Geometry Outputs
- "*ST_asbinary", "*ST_asewkb", "*ST_asewkt", "*ST_asgeojson", "*ST_asgml", "*ST_ashexewkb", "*ST_askml",
- "*ST_assvg", "*ST_geohash", "ST_Astext",
- # 7.7. Operators
- # 7.8. Spatial Relationships and Measurements
- "ST_Area", "ST_Azimuth", "ST_Centroid", "ST_ClosestPoint", "ST_Contains", "ST_ContainsProperly",
- "ST_Covers", "ST_CoveredBy", "ST_Crosses", "*ST_linecrossingdirection", "ST_Cisjoint",
- "ST_Distance", "*ST_hausdorffdistance", "*ST_maxdistance", "ST_Distance_Sphere",
- "ST_Distance_Spheroid", "*ST_DFullyWithin", "ST_DWithin", "ST_Equals", "*ST_hasarc",
- "ST_Intersects", "ST_Length", "*ST_Length2d", "*ST_length3d", "ST_Length_Spheroid",
- "*ST_length2d_spheroid", "*ST_length3d_spheroid", "*ST_longestline", "*ST_orderingequals",
- "ST_Overlaps", "*ST_perimeter", "*ST_perimeter2d", "*ST_perimeter3d", "ST_PointOnSurface",
- "ST_Relate", "ST_ShortestLine", "ST_Touches", "ST_Within",
- # 7.9. Geometry Processing Functions
- "ST_Buffer", "ST_BuildArea", "ST_Collect", "ST_ConvexHull", "*ST_curvetoline", "ST_Difference",
- "ST_Dump", "*ST_dumppoints", "*ST_dumprings", "ST_Intersection", "*ST_linetocurve", "*ST_memunion",
- "*ST_minimumboundingcircle", "*ST_polygonize", "*ST_shift_longitude", "ST_Simplify",
- "ST_SimplifyPreserveTopology", "ST_SymDifference", "ST_Union",
- # 7.10. Linear Referencing
- "ST_Line_Interpolate_Point", "ST_Line_Locate_Point", "ST_Line_Substring",
- "*ST_locate_along_measure", "*ST_locate_between_measures", "*ST_locatebetweenelevations",
- "*ST_addmeasure",
- # 7.11. Long Transactions Support
- "*addauth", "*checkauth", "*disablelongtransactions", "*enablelongtransactions", "*lockrow",
- "*unlockrows",
- # 7.12. Miscellaneous Functions
- "*ST_accum", "*box2d", "*box3d", "*ST_estimated_extent", "*ST_expand", "ST_Extent", "*ST_extent3d",
- "*find_srid", "*ST_mem_size", "*ST_point_inside_circle", "ST_XMax", "ST_XMin", "ST_YMax", "ST_YMin",
- "ST_ZMax", "ST_ZMin",
- # 7.13. Exceptional Functions
- "*postgis_addbbox", "*postgis_dropbbox", "*postgis_hasbbox",
- # Raster functions
- "AddRasterConstraints", "DropRasterConstraints", "AddOverviewConstraints", "DropOverviewConstraints",
- "PostGIS_GDAL_Version", "PostGIS_Raster_Lib_Build_Date", "PostGIS_Raster_Lib_Version", "ST_GDALDrivers",
- "UpdateRasterSRID", "ST_CreateOverview", "ST_AddBand", "ST_AsRaster", "ST_Band", "ST_MakeEmptyCoverage",
- "ST_MakeEmptyRaster", "ST_Tile", "ST_Retile", "ST_FromGDALRaster", "ST_GeoReference", "ST_Height",
- "ST_IsEmpty", "ST_MemSize", "ST_MetaData", "ST_NumBands", "ST_PixelHeight", "ST_PixelWidth", "ST_ScaleX",
- "ST_ScaleY", "ST_RasterToWorldCoord", "ST_RasterToWorldCoordX", "ST_RasterToWorldCoordY", "ST_Rotation",
- "ST_SkewX", "ST_SkewY", "ST_SRID", "ST_Summary", "ST_UpperLeftX", "ST_UpperLeftY", "ST_Width",
- "ST_WorldToRasterCoord", "ST_WorldToRasterCoordX", "ST_WorldToRasterCoordY", "ST_BandMetaData",
- "ST_BandNoDataValue", "ST_BandIsNoData", "ST_BandPath", "ST_BandFileSize", "ST_BandFileTimestamp",
- "ST_BandPixelType", "ST_MinPossibleValue", "ST_HasNoBand", "ST_PixelAsPolygon", "ST_PixelAsPolygons",
- "ST_PixelAsPoint", "ST_PixelAsPoints", "ST_PixelAsCentroid", "ST_PixelAsCentroids", "ST_Value",
- "ST_NearestValue", "ST_Neighborhood", "ST_SetValue", "ST_SetValues", "ST_DumpValues", "ST_PixelOfValue",
- "ST_SetGeoReference", "ST_SetRotation", "ST_SetScale", "ST_SetSkew", "ST_SetSRID", "ST_SetUpperLeft",
- "ST_Resample", "ST_Rescale", "ST_Reskew", "ST_SnapToGrid", "ST_Resize", "ST_Transform",
- "ST_SetBandNoDataValue", "ST_SetBandIsNoData", "ST_SetBandPath", "ST_SetBandIndex", "ST_Count",
- "ST_CountAgg", "ST_Histogram", "ST_Quantile", "ST_SummaryStats", "ST_SummaryStatsAgg", "ST_ValueCount",
- "ST_RastFromWKB", "ST_RastFromHexWKB", "ST_AsBinary", "ST_AsWKB", "ST_AsHexWKB", "ST_AsGDALRaster",
- "ST_AsJPEG", "ST_AsPNG", "ST_AsTIFF", "ST_Clip", "ST_ColorMap", "ST_Grayscale", "ST_Intersection",
- "ST_MapAlgebra", "ST_MapAlgebraExpr", "ST_MapAlgebraFct", "ST_MapAlgebraFctNgb", "ST_Reclass", "ST_Union",
- "ST_Distinct4ma", "ST_InvDistWeight4ma", "ST_Max4ma", "ST_Mean4ma", "ST_Min4ma", "ST_MinDist4ma",
- "ST_Range4ma", "ST_StdDev4ma", "ST_Sum4ma", "ST_Aspect", "ST_HillShade", "ST_Roughness", "ST_Slope",
- "ST_TPI", "ST_TRI",
+ # 7.1. PostgreSQL PostGIS Types
+ "*box2d",
+ "*box3d",
+ "*box3d_extent",
+ "*geometry",
+ "*geometry_dump",
+ "*geography",
+ # 7.2. Management Functions
+ "*addgeometrycolumn",
+ "*dropgeometrycolumn",
+ "*dropgeometrytable",
+ "*postgis_full_version",
+ "*postgis_geos_version",
+ "*postgis_libxml_version",
+ "*postgis_lib_build_date",
+ "*postgis_lib_version",
+ "*postgis_proj_version",
+ "*postgis_scripts_build_date",
+ "*postgis_scripts_installed",
+ "*postgis_scripts_released",
+ "*postgis_uses_stats",
+ "*postgis_version",
+ "*populate_geometry_columns",
+ "*probe_geometry_columns",
+ "*updategeometrysrid",
+ # 7.3. Geometry Constructors
+ "*ST_bdpolyfromtext",
+ "*ST_bdmpolyfromtext",
+ "*ST_geogfromtext",
+ "*ST_geographyfromtext",
+ "*ST_geogfromwkb",
+ "*ST_geomcollfromtext",
+ "*ST_geomfromewkb",
+ "*ST_geomfromewkt",
+ "*ST_geometryfromtext",
+ "*ST_geomfromgml",
+ "*ST_geomfromkml",
+ "*ST_gmltosql",
+ "*ST_geomfromtext",
+ "*ST_geomfromwkb",
+ "*ST_linefrommultipoint",
+ "*ST_linefromtext",
+ "*ST_linefromwkb",
+ "*ST_linestringfromwkb",
+ "*ST_makebox2d",
+ "*ST_makebox3d",
+ "ST_MakeLine",
+ "*ST_makeenvelope",
+ "ST_MakePolygon",
+ "ST_MakePoint",
+ "ST_MakePointM",
+ "*ST_MLinefromtext",
+ "*ST_mpointfromtext",
+ "*ST_mpolyfromtext",
+ "ST_Point",
+ "*ST_pointfromtext",
+ "*ST_pointfromwkb",
+ "ST_Polygon",
+ "*ST_polygonfromtext",
+ "*ST_wkbtosql",
+ "*ST_wkttosql",
+ # 7.4. Geometry Accessors
+ "GeometryType",
+ "ST_Boundary",
+ "*ST_coorddim",
+ "ST_Dimension",
+ "ST_EndPoint",
+ "ST_Envelope",
+ "ST_ExteriorRing",
+ "ST_GeometryN",
+ "ST_GeometryType",
+ "ST_InteriorRingN",
+ "ST_isClosed",
+ "ST_isEmpty",
+ "ST_isRing",
+ "ST_isSimple",
+ "ST_isValid",
+ "ST_isValidReason",
+ "ST_M",
+ "ST_NDims",
+ "ST_NPoints",
+ "ST_NRings",
+ "ST_NumGeometries",
+ "ST_NumInteriorrings",
+ "ST_NumInteriorring",
+ "ST_NumPoints",
+ "ST_PointN",
+ "ST_Srid",
+ "ST_StartPoint",
+ "ST_Summary",
+ "ST_X",
+ "ST_Y",
+ "ST_Z",
+ "*ST_zmflag",
+ # 7.5. Geometry Editors
+ "ST_AddPoint",
+ "ST_Affine",
+ "ST_Force2D",
+ "*ST_Force3D",
+ "*ST_Force3dZ",
+ "*ST_Force3DM",
+ "*ST_Force_4d",
+ "*ST_force_collection",
+ "*ST_forcerhr",
+ "*ST_linemerge",
+ "*ST_collectionextract",
+ "ST_Multi",
+ "*ST_removepoint",
+ "*ST_reverse",
+ "*ST_rotate",
+ "*ST_rotatex",
+ "*ST_rotatey",
+ "*ST_rotatez",
+ "*ST_scale",
+ "*ST_segmentize",
+ "*ST_setpoint",
+ "ST_SetSrid",
+ "ST_SnapToGrid",
+ "ST_Transform",
+ "ST_Translate",
+ "*ST_transscale",
+ # 7.6. Geometry Outputs
+ "*ST_asbinary",
+ "*ST_asewkb",
+ "*ST_asewkt",
+ "*ST_asgeojson",
+ "*ST_asgml",
+ "*ST_ashexewkb",
+ "*ST_askml",
+ "*ST_assvg",
+ "*ST_geohash",
+ "ST_Astext",
+ # 7.7. Operators
+ # 7.8. Spatial Relationships and Measurements
+ "ST_Area",
+ "ST_Azimuth",
+ "ST_Centroid",
+ "ST_ClosestPoint",
+ "ST_Contains",
+ "ST_ContainsProperly",
+ "ST_Covers",
+ "ST_CoveredBy",
+ "ST_Crosses",
+ "*ST_linecrossingdirection",
+ "ST_Cisjoint",
+ "ST_Distance",
+ "*ST_hausdorffdistance",
+ "*ST_maxdistance",
+ "ST_Distance_Sphere",
+ "ST_Distance_Spheroid",
+ "*ST_DFullyWithin",
+ "ST_DWithin",
+ "ST_Equals",
+ "*ST_hasarc",
+ "ST_Intersects",
+ "ST_Length",
+ "*ST_Length2d",
+ "*ST_length3d",
+ "ST_Length_Spheroid",
+ "*ST_length2d_spheroid",
+ "*ST_length3d_spheroid",
+ "*ST_longestline",
+ "*ST_orderingequals",
+ "ST_Overlaps",
+ "*ST_perimeter",
+ "*ST_perimeter2d",
+ "*ST_perimeter3d",
+ "ST_PointOnSurface",
+ "ST_Relate",
+ "ST_ShortestLine",
+ "ST_Touches",
+ "ST_Within",
+ # 7.9. Geometry Processing Functions
+ "ST_Buffer",
+ "ST_BuildArea",
+ "ST_Collect",
+ "ST_ConvexHull",
+ "*ST_curvetoline",
+ "ST_Difference",
+ "ST_Dump",
+ "*ST_dumppoints",
+ "*ST_dumprings",
+ "ST_Intersection",
+ "*ST_linetocurve",
+ "*ST_memunion",
+ "*ST_minimumboundingcircle",
+ "*ST_polygonize",
+ "*ST_shift_longitude",
+ "ST_Simplify",
+ "ST_SimplifyPreserveTopology",
+ "ST_SymDifference",
+ "ST_Union",
+ # 7.10. Linear Referencing
+ "ST_Line_Interpolate_Point",
+ "ST_Line_Locate_Point",
+ "ST_Line_Substring",
+ "*ST_locate_along_measure",
+ "*ST_locate_between_measures",
+ "*ST_locatebetweenelevations",
+ "*ST_addmeasure",
+ # 7.11. Long Transactions Support
+ "*addauth",
+ "*checkauth",
+ "*disablelongtransactions",
+ "*enablelongtransactions",
+ "*lockrow",
+ "*unlockrows",
+ # 7.12. Miscellaneous Functions
+ "*ST_accum",
+ "*box2d",
+ "*box3d",
+ "*ST_estimated_extent",
+ "*ST_expand",
+ "ST_Extent",
+ "*ST_extent3d",
+ "*find_srid",
+ "*ST_mem_size",
+ "*ST_point_inside_circle",
+ "ST_XMax",
+ "ST_XMin",
+ "ST_YMax",
+ "ST_YMin",
+ "ST_ZMax",
+ "ST_ZMin",
+ # 7.13. Exceptional Functions
+ "*postgis_addbbox",
+ "*postgis_dropbbox",
+ "*postgis_hasbbox",
+ # Raster functions
+ "AddRasterConstraints",
+ "DropRasterConstraints",
+ "AddOverviewConstraints",
+ "DropOverviewConstraints",
+ "PostGIS_GDAL_Version",
+ "PostGIS_Raster_Lib_Build_Date",
+ "PostGIS_Raster_Lib_Version",
+ "ST_GDALDrivers",
+ "UpdateRasterSRID",
+ "ST_CreateOverview",
+ "ST_AddBand",
+ "ST_AsRaster",
+ "ST_Band",
+ "ST_MakeEmptyCoverage",
+ "ST_MakeEmptyRaster",
+ "ST_Tile",
+ "ST_Retile",
+ "ST_FromGDALRaster",
+ "ST_GeoReference",
+ "ST_Height",
+ "ST_IsEmpty",
+ "ST_MemSize",
+ "ST_MetaData",
+ "ST_NumBands",
+ "ST_PixelHeight",
+ "ST_PixelWidth",
+ "ST_ScaleX",
+ "ST_ScaleY",
+ "ST_RasterToWorldCoord",
+ "ST_RasterToWorldCoordX",
+ "ST_RasterToWorldCoordY",
+ "ST_Rotation",
+ "ST_SkewX",
+ "ST_SkewY",
+ "ST_SRID",
+ "ST_Summary",
+ "ST_UpperLeftX",
+ "ST_UpperLeftY",
+ "ST_Width",
+ "ST_WorldToRasterCoord",
+ "ST_WorldToRasterCoordX",
+ "ST_WorldToRasterCoordY",
+ "ST_BandMetaData",
+ "ST_BandNoDataValue",
+ "ST_BandIsNoData",
+ "ST_BandPath",
+ "ST_BandFileSize",
+ "ST_BandFileTimestamp",
+ "ST_BandPixelType",
+ "ST_MinPossibleValue",
+ "ST_HasNoBand",
+ "ST_PixelAsPolygon",
+ "ST_PixelAsPolygons",
+ "ST_PixelAsPoint",
+ "ST_PixelAsPoints",
+ "ST_PixelAsCentroid",
+ "ST_PixelAsCentroids",
+ "ST_Value",
+ "ST_NearestValue",
+ "ST_Neighborhood",
+ "ST_SetValue",
+ "ST_SetValues",
+ "ST_DumpValues",
+ "ST_PixelOfValue",
+ "ST_SetGeoReference",
+ "ST_SetRotation",
+ "ST_SetScale",
+ "ST_SetSkew",
+ "ST_SetSRID",
+ "ST_SetUpperLeft",
+ "ST_Resample",
+ "ST_Rescale",
+ "ST_Reskew",
+ "ST_SnapToGrid",
+ "ST_Resize",
+ "ST_Transform",
+ "ST_SetBandNoDataValue",
+ "ST_SetBandIsNoData",
+ "ST_SetBandPath",
+ "ST_SetBandIndex",
+ "ST_Count",
+ "ST_CountAgg",
+ "ST_Histogram",
+ "ST_Quantile",
+ "ST_SummaryStats",
+ "ST_SummaryStatsAgg",
+ "ST_ValueCount",
+ "ST_RastFromWKB",
+ "ST_RastFromHexWKB",
+ "ST_AsBinary",
+ "ST_AsWKB",
+ "ST_AsHexWKB",
+ "ST_AsGDALRaster",
+ "ST_AsJPEG",
+ "ST_AsPNG",
+ "ST_AsTIFF",
+ "ST_Clip",
+ "ST_ColorMap",
+ "ST_Grayscale",
+ "ST_Intersection",
+ "ST_MapAlgebra",
+ "ST_MapAlgebraExpr",
+ "ST_MapAlgebraFct",
+ "ST_MapAlgebraFctNgb",
+ "ST_Reclass",
+ "ST_Union",
+ "ST_Distinct4ma",
+ "ST_InvDistWeight4ma",
+ "ST_Max4ma",
+ "ST_Mean4ma",
+ "ST_Min4ma",
+ "ST_MinDist4ma",
+ "ST_Range4ma",
+ "ST_StdDev4ma",
+ "ST_Sum4ma",
+ "ST_Aspect",
+ "ST_HillShade",
+ "ST_Roughness",
+ "ST_Slope",
+ "ST_TPI",
+ "ST_TRI",
]
# constants
@@ -203,7 +873,7 @@
def getSqlDictionary(spatial=True):
def strip_star(s):
- if s[0] == '*':
+ if s[0] == "*":
return s.lower()[1:]
else:
return s.lower()
@@ -215,13 +885,17 @@ def strip_star(s):
f += postgis_functions
c += postgis_constants
- return {'keyword': list(map(strip_star, k)), 'constant': list(map(strip_star, c)), 'function': list(map(strip_star, f))}
+ return {
+ "keyword": list(map(strip_star, k)),
+ "constant": list(map(strip_star, c)),
+ "function": list(map(strip_star, f)),
+ }
def getQueryBuilderDictionary():
# concat functions
def ff(l):
- return [s for s in l if s[0] != '*']
+ return [s for s in l if s[0] != "*"]
def add_paren(l):
return [s + "(" for s in l]
@@ -231,4 +905,4 @@ def add_paren(l):
agg = sorted(add_paren(ff(aggregate_functions)))
op = ff(operators)
s = sorted(add_paren(ff(string_functions)))
- return {'function': foo, 'math': m, 'aggregate': agg, 'operator': op, 'string': s}
+ return {"function": foo, "math": m, "aggregate": agg, "operator": op, "string": s}
diff --git a/python/plugins/db_manager/db_plugins/spatialite/connector.py b/python/plugins/db_manager/db_plugins/spatialite/connector.py
index 3956f52e8015..ca1b9732fe48 100644
--- a/python/plugins/db_manager/db_plugins/spatialite/connector.py
+++ b/python/plugins/db_manager/db_plugins/spatialite/connector.py
@@ -42,7 +42,11 @@ def __init__(self, uri):
self.dbname = uri.database()
if not QFile.exists(self.dbname):
- raise ConnectionError(QApplication.translate("DBManagerPlugin", '"{0}" not found').format(self.dbname))
+ raise ConnectionError(
+ QApplication.translate("DBManagerPlugin", '"{0}" not found').format(
+ self.dbname
+ )
+ )
try:
self.connection = spatialite_connect(self._connectionInfo())
@@ -85,12 +89,12 @@ def isValidDatabase(self, path):
return isValid
def _checkSpatial(self):
- """ check if it's a valid SpatiaLite db """
+ """check if it's a valid SpatiaLite db"""
self.has_spatial = self._checkGeometryColumnsTable()
return self.has_spatial
def _checkRaster(self):
- """ check if it's a rasterite db """
+ """check if it's a rasterite db"""
self.has_raster = self._checkRasterTables()
return self.has_raster
@@ -121,17 +125,19 @@ def getInfo(self):
return c.fetchone()
def getSpatialInfo(self):
- """ returns tuple about SpatiaLite support:
- - lib version
- - geos version
- - proj version
+ """returns tuple about SpatiaLite support:
+ - lib version
+ - geos version
+ - proj version
"""
if not self.has_spatial:
return
c = self._get_cursor()
try:
- self._execute(c, "SELECT spatialite_version(), geos_version(), proj4_version()")
+ self._execute(
+ c, "SELECT spatialite_version(), geos_version(), proj4_version()"
+ )
except DbError:
return
@@ -154,17 +160,26 @@ def hasCreateSpatialViewSupport(self):
def fieldTypes(self):
return [
- "integer", "bigint", "smallint", # integers
- "real", "double", "float", "numeric", # floats
- "varchar", "varchar(255)", "character(20)", "text", # strings
- "date", "datetime" # date/time
+ "integer",
+ "bigint",
+ "smallint", # integers
+ "real",
+ "double",
+ "float",
+ "numeric", # floats
+ "varchar",
+ "varchar(255)",
+ "character(20)",
+ "text", # strings
+ "date",
+ "datetime", # date/time
]
def getSchemas(self):
return None
def getTables(self, schema=None, add_sys_tables=False):
- """ get list of tables """
+ """get list of tables"""
tablenames = []
items = []
@@ -197,16 +212,16 @@ def getTables(self, schema=None, add_sys_tables=False):
sql = "SELECT f_table_name, f_geometry_column FROM geometry_columns WHERE spatial_index_enabled = 1"
self._execute(c, sql)
for idx_item in c.fetchall():
- sys_tables.append('idx_%s_%s' % idx_item)
- sys_tables.append('idx_%s_%s_node' % idx_item)
- sys_tables.append('idx_%s_%s_parent' % idx_item)
- sys_tables.append('idx_%s_%s_rowid' % idx_item)
+ sys_tables.append("idx_%s_%s" % idx_item)
+ sys_tables.append("idx_%s_%s_node" % idx_item)
+ sys_tables.append("idx_%s_%s_parent" % idx_item)
+ sys_tables.append("idx_%s_%s_rowid" % idx_item)
sql = "SELECT name, type = 'view' FROM sqlite_master WHERE type IN ('table', 'view')"
self._execute(c, sql)
for tbl in c.fetchall():
- if tablenames.count(tbl[0]) <= 0 and not tbl[0].startswith('idx_'):
+ if tablenames.count(tbl[0]) <= 0 and not tbl[0].startswith("idx_"):
if not add_sys_tables and tbl[0] in sys_tables:
continue
item = list(tbl)
@@ -219,16 +234,16 @@ def getTables(self, schema=None, add_sys_tables=False):
return sorted(items, key=cmp_to_key(lambda x, y: (x[1] > y[1]) - (x[1] < y[1])))
def getVectorTables(self, schema=None):
- """ get list of table with a geometry column
- it returns:
- name (table name)
- type = 'view' (is a view?)
- geometry_column:
- f_table_name (the table name in geometry_columns may be in a wrong case, use this to load the layer)
- f_geometry_column
- type
- coord_dimension
- srid
+ """get list of table with a geometry column
+ it returns:
+ name (table name)
+ type = 'view' (is a view?)
+ geometry_column:
+ f_table_name (the table name in geometry_columns may be in a wrong case, use this to load the layer)
+ f_geometry_column
+ type
+ coord_dimension
+ srid
"""
if self.has_geometry_columns:
@@ -253,10 +268,13 @@ def getVectorTables(self, schema=None):
cols = "g.type,g.coord_dimension"
# get geometry info from geometry_columns if exists
- sql = """SELECT m.name, m.type = 'view', g.f_table_name, g.f_geometry_column, %s, g.srid
+ sql = (
+ """SELECT m.name, m.type = 'view', g.f_table_name, g.f_geometry_column, %s, g.srid
FROM sqlite_master AS m JOIN geometry_columns AS g ON upper(m.name) = upper(g.f_table_name)
WHERE m.type in ('table', 'view')
- ORDER BY m.name, g.f_geometry_column""" % cols
+ ORDER BY m.name, g.f_geometry_column"""
+ % cols
+ )
else:
return []
@@ -273,14 +291,14 @@ def getVectorTables(self, schema=None):
return items
def getRasterTables(self, schema=None):
- """ get list of table with a geometry column
- it returns:
- name (table name)
- type = 'view' (is a view?)
- geometry_column:
- r.table_name (the prefix table name, use this to load the layer)
- r.geometry_column
- srid
+ """get list of table with a geometry column
+ it returns:
+ name (table name)
+ type = 'view' (is a view?)
+ geometry_column:
+ r.table_name (the prefix table name, use this to load the layer)
+ r.geometry_column
+ srid
"""
if not self.has_geometry_columns:
@@ -314,14 +332,14 @@ def getTableRowCount(self, table):
return ret[0] if ret is not None else None
def getTableFields(self, table):
- """ return list of columns in table """
+ """return list of columns in table"""
c = self._get_cursor()
sql = "PRAGMA table_info(%s)" % (self.quoteId(table))
self._execute(c, sql)
return c.fetchall()
def getTableIndexes(self, table):
- """ get info about table's indexes """
+ """get info about table's indexes"""
c = self._get_cursor()
sql = "PRAGMA index_list(%s)" % (self.quoteId(table))
self._execute(c, sql)
@@ -340,10 +358,7 @@ def getTableIndexes(self, table):
self._execute(c, sql)
idx = [num, name, unique]
- cols = [
- cid
- for seq, cid, cname in c.fetchall()
- ]
+ cols = [cid for seq, cid, cname in c.fetchall()]
idx.append(cols)
indexes[i] = idx
@@ -355,41 +370,50 @@ def getTableConstraints(self, table):
def getTableTriggers(self, table):
c = self._get_cursor()
schema, tablename = self.getSchemaTableName(table)
- sql = "SELECT name, sql FROM sqlite_master WHERE tbl_name = %s AND type = 'trigger'" % (
- self.quoteString(tablename))
+ sql = (
+ "SELECT name, sql FROM sqlite_master WHERE tbl_name = %s AND type = 'trigger'"
+ % (self.quoteString(tablename))
+ )
self._execute(c, sql)
return c.fetchall()
def deleteTableTrigger(self, trigger, table=None):
- """Deletes trigger """
+ """Deletes trigger"""
sql = "DROP TRIGGER %s" % self.quoteId(trigger)
self._execute_and_commit(sql)
def getTableExtent(self, table, geom):
- """ find out table extent """
+ """find out table extent"""
schema, tablename = self.getSchemaTableName(table)
c = self._get_cursor()
if self.isRasterTable(table):
- tablename = tablename.replace('_rasters', '_metadata')
- geom = 'geometry'
+ tablename = tablename.replace("_rasters", "_metadata")
+ geom = "geometry"
- sql = """SELECT Min(MbrMinX(%(geom)s)), Min(MbrMinY(%(geom)s)), Max(MbrMaxX(%(geom)s)), Max(MbrMaxY(%(geom)s))
- FROM %(table)s """ % {'geom': self.quoteId(geom),
- 'table': self.quoteId(tablename)}
+ sql = """SELECT Min(MbrMinX({geom})), Min(MbrMinY({geom})), Max(MbrMaxX({geom})), Max(MbrMaxY({geom}))
+ FROM {table} """.format(
+ geom=self.quoteId(geom), table=self.quoteId(tablename)
+ )
self._execute(c, sql)
return c.fetchone()
def getViewDefinition(self, view):
- """ returns definition of the view """
+ """returns definition of the view"""
schema, tablename = self.getSchemaTableName(view)
- sql = "SELECT sql FROM sqlite_master WHERE type = 'view' AND name = %s" % self.quoteString(tablename)
+ sql = (
+ "SELECT sql FROM sqlite_master WHERE type = 'view' AND name = %s"
+ % self.quoteString(tablename)
+ )
c = self._execute(None, sql)
ret = c.fetchone()
return ret[0] if ret is not None else None
def getSpatialRefInfo(self, srid):
- sql = "SELECT ref_sys_name FROM spatial_ref_sys WHERE srid = %s" % self.quoteString(srid)
+ sql = (
+ "SELECT ref_sys_name FROM spatial_ref_sys WHERE srid = %s"
+ % self.quoteString(srid)
+ )
c = self._execute(None, sql)
ret = c.fetchone()
return ret[0] if ret is not None else None
@@ -397,8 +421,10 @@ def getSpatialRefInfo(self, srid):
def isVectorTable(self, table):
if self.has_geometry_columns:
schema, tablename = self.getSchemaTableName(table)
- sql = "SELECT count(*) FROM geometry_columns WHERE upper(f_table_name) = upper(%s)" % self.quoteString(
- tablename)
+ sql = (
+ "SELECT count(*) FROM geometry_columns WHERE upper(f_table_name) = upper(%s)"
+ % self.quoteString(tablename)
+ )
c = self._execute(None, sql)
ret = c.fetchone()
return ret is not None and ret[0] > 0
@@ -414,7 +440,8 @@ def isRasterTable(self, table):
FROM layer_params AS r JOIN geometry_columns AS g
ON upper(r.table_name||'_metadata') = upper(g.f_table_name)
WHERE upper(r.table_name) = upper(REPLACE(%s, '_rasters', ''))""" % self.quoteString(
- tablename)
+ tablename
+ )
c = self._execute(None, sql)
ret = c.fetchone()
return ret is not None and ret[0] > 0
@@ -423,8 +450,8 @@ def isRasterTable(self, table):
def createTable(self, table, field_defs, pkey):
"""Creates ordinary table
- 'fields' is array containing field definitions
- 'pkey' is the primary key name
+ 'fields' is array containing field definitions
+ 'pkey' is the primary key name
"""
if len(field_defs) == 0:
return False
@@ -439,7 +466,7 @@ def createTable(self, table, field_defs, pkey):
return True
def deleteTable(self, table):
- """Deletes table from the database """
+ """Deletes table from the database"""
if self.isRasterTable(table):
return False
@@ -447,14 +474,17 @@ def deleteTable(self, table):
sql = "DROP TABLE %s" % self.quoteId(table)
self._execute(c, sql)
schema, tablename = self.getSchemaTableName(table)
- sql = "DELETE FROM geometry_columns WHERE upper(f_table_name) = upper(%s)" % self.quoteString(tablename)
+ sql = (
+ "DELETE FROM geometry_columns WHERE upper(f_table_name) = upper(%s)"
+ % self.quoteString(tablename)
+ )
self._execute(c, sql)
self._commit()
return True
def emptyTable(self, table):
- """Deletes all rows from table """
+ """Deletes all rows from table"""
if self.isRasterTable(table):
return False
@@ -462,7 +492,7 @@ def emptyTable(self, table):
self._execute_and_commit(sql)
def renameTable(self, table, new_table):
- """ rename a table """
+ """rename a table"""
schema, tablename = self.getSchemaTableName(table)
if new_table == tablename:
return
@@ -472,13 +502,16 @@ def renameTable(self, table, new_table):
c = self._get_cursor()
- sql = "ALTER TABLE %s RENAME TO %s" % (self.quoteId(table), self.quoteId(new_table))
+ sql = "ALTER TABLE {} RENAME TO {}".format(
+ self.quoteId(table), self.quoteId(new_table)
+ )
self._execute(c, sql)
# update geometry_columns
if self.has_geometry_columns:
- sql = "UPDATE geometry_columns SET f_table_name = %s WHERE upper(f_table_name) = upper(%s)" % (
- self.quoteString(new_table), self.quoteString(tablename))
+ sql = "UPDATE geometry_columns SET f_table_name = {} WHERE upper(f_table_name) = upper({})".format(
+ self.quoteString(new_table), self.quoteString(tablename)
+ )
self._execute(c, sql)
self._commit()
@@ -488,7 +521,7 @@ def moveTable(self, table, new_table, new_schema=None):
return self.renameTable(table, new_table)
def createView(self, view, query):
- sql = "CREATE VIEW %s AS %s" % (self.quoteId(view), query)
+ sql = f"CREATE VIEW {self.quoteId(view)} AS {query}"
self._execute_and_commit(sql)
def deleteView(self, view):
@@ -499,13 +532,16 @@ def deleteView(self, view):
# update geometry_columns
if self.has_geometry_columns:
- sql = "DELETE FROM geometry_columns WHERE f_table_name = %s" % self.quoteString(view)
+ sql = (
+ "DELETE FROM geometry_columns WHERE f_table_name = %s"
+ % self.quoteString(view)
+ )
self._execute(c, sql)
self._commit()
def renameView(self, view, new_name):
- """ rename view """
+ """rename view"""
return self.renameTable(view, new_name)
def createSpatialView(self, view, query):
@@ -516,50 +552,67 @@ def createSpatialView(self, view, query):
c = self._execute(None, sql)
geom_col = None
for r in c.fetchall():
- if r[2].upper() in ('POINT', 'LINESTRING', 'POLYGON',
- 'MULTIPOINT', 'MULTILINESTRING', 'MULTIPOLYGON'):
+ if r[2].upper() in (
+ "POINT",
+ "LINESTRING",
+ "POLYGON",
+ "MULTIPOINT",
+ "MULTILINESTRING",
+ "MULTIPOLYGON",
+ ):
geom_col = r[1]
break
if geom_col is None:
return
# get geometry type and srid
- sql = "SELECT geometrytype(%s), srid(%s) FROM %s LIMIT 1" % (self.quoteId(geom_col), self.quoteId(geom_col), self.quoteId(view))
+ sql = "SELECT geometrytype({}), srid({}) FROM {} LIMIT 1".format(
+ self.quoteId(geom_col), self.quoteId(geom_col), self.quoteId(view)
+ )
c = self._execute(None, sql)
r = c.fetchone()
if r is None:
return
gtype, gsrid = r
- gdim = 'XY'
- if ' ' in gtype:
- zm = gtype.split(' ')[1]
- gtype = gtype.split(' ')[0]
+ gdim = "XY"
+ if " " in gtype:
+ zm = gtype.split(" ")[1]
+ gtype = gtype.split(" ")[0]
gdim += zm
try:
- wkbType = ('POINT', 'LINESTRING', 'POLYGON', 'MULTIPOINT', 'MULTILINESTRING', 'MULTIPOLYGON').index(gtype) + 1
+ wkbType = (
+ "POINT",
+ "LINESTRING",
+ "POLYGON",
+ "MULTIPOINT",
+ "MULTILINESTRING",
+ "MULTIPOLYGON",
+ ).index(gtype) + 1
except:
wkbType = 0
- if 'Z' in gdim:
+ if "Z" in gdim:
wkbType += 1000
- if 'M' in gdim:
+ if "M" in gdim:
wkbType += 2000
sql = """INSERT INTO geometry_columns (f_table_name, f_geometry_column, geometry_type, coord_dimension, srid, spatial_index_enabled)
- VALUES (%s, %s, %s, %s, %s, 0)""" % (self.quoteId(view), self.quoteId(geom_col), wkbType, len(gdim), gsrid)
+ VALUES ({}, {}, {}, {}, {}, 0)""".format(
+ self.quoteId(view), self.quoteId(geom_col), wkbType, len(gdim), gsrid
+ )
self._execute_and_commit(sql)
def runVacuum(self):
- """ run vacuum on the db """
+ """run vacuum on the db"""
# Workaround http://bugs.python.org/issue28518
self.connection.isolation_level = None
c = self._get_cursor()
- c.execute('VACUUM')
- self.connection.isolation_level = '' # reset to default isolation
+ c.execute("VACUUM")
+ self.connection.isolation_level = "" # reset to default isolation
def addTableColumn(self, table, field_def):
- """Adds a column to table """
- sql = "ALTER TABLE %s ADD %s" % (self.quoteId(table), field_def)
+ """Adds a column to table"""
+ sql = f"ALTER TABLE {self.quoteId(table)} ADD {field_def}"
self._execute(None, sql)
sql = "SELECT InvalidateLayerStatistics(%s)" % (self.quoteId(table))
@@ -572,71 +625,93 @@ def addTableColumn(self, table, field_def):
return True
def deleteTableColumn(self, table, column):
- """Deletes column from a table """
+ """Deletes column from a table"""
if not self.isGeometryColumn(table, column):
return False # column editing not supported
# delete geometry column correctly
schema, tablename = self.getSchemaTableName(table)
- sql = "SELECT DiscardGeometryColumn(%s, %s)" % (self.quoteString(tablename), self.quoteString(column))
+ sql = "SELECT DiscardGeometryColumn({}, {})".format(
+ self.quoteString(tablename), self.quoteString(column)
+ )
self._execute_and_commit(sql)
- def updateTableColumn(self, table, column, new_name, new_data_type=None, new_not_null=None, new_default=None, comment=None):
+ def updateTableColumn(
+ self,
+ table,
+ column,
+ new_name,
+ new_data_type=None,
+ new_not_null=None,
+ new_default=None,
+ comment=None,
+ ):
return False # column editing not supported
def renameTableColumn(self, table, column, new_name):
- """ rename column in a table """
+ """rename column in a table"""
return False # column editing not supported
def setColumnType(self, table, column, data_type):
- """Changes column type """
+ """Changes column type"""
return False # column editing not supported
def setColumnDefault(self, table, column, default):
- """Changes column's default value. If default=None drop default value """
+ """Changes column's default value. If default=None drop default value"""
return False # column editing not supported
def setColumnNull(self, table, column, is_null):
- """Changes whether column can contain null values """
+ """Changes whether column can contain null values"""
return False # column editing not supported
def isGeometryColumn(self, table, column):
c = self._get_cursor()
schema, tablename = self.getSchemaTableName(table)
- sql = "SELECT count(*) > 0 FROM geometry_columns WHERE upper(f_table_name) = upper(%s) AND upper(f_geometry_column) = upper(%s)" % (
- self.quoteString(tablename), self.quoteString(column))
+ sql = "SELECT count(*) > 0 FROM geometry_columns WHERE upper(f_table_name) = upper({}) AND upper(f_geometry_column) = upper({})".format(
+ self.quoteString(tablename), self.quoteString(column)
+ )
self._execute(c, sql)
- return c.fetchone()[0] == 't'
+ return c.fetchone()[0] == "t"
- def addGeometryColumn(self, table, geom_column='geometry', geom_type='POINT', srid=-1, dim=2):
+ def addGeometryColumn(
+ self, table, geom_column="geometry", geom_type="POINT", srid=-1, dim=2
+ ):
schema, tablename = self.getSchemaTableName(table)
sql = "SELECT AddGeometryColumn(%s, %s, %d, %s, %s)" % (
- self.quoteString(tablename), self.quoteString(geom_column), srid, self.quoteString(geom_type), dim)
+ self.quoteString(tablename),
+ self.quoteString(geom_column),
+ srid,
+ self.quoteString(geom_type),
+ dim,
+ )
self._execute_and_commit(sql)
def deleteGeometryColumn(self, table, geom_column):
return self.deleteTableColumn(table, geom_column)
def addTableUniqueConstraint(self, table, column):
- """Adds a unique constraint to a table """
+ """Adds a unique constraint to a table"""
return False # constraints not supported
def deleteTableConstraint(self, table, constraint):
- """Deletes constraint in a table """
+ """Deletes constraint in a table"""
return False # constraints not supported
def addTablePrimaryKey(self, table, column):
- """Adds a primery key (with one column) to a table """
- sql = "ALTER TABLE %s ADD PRIMARY KEY (%s)" % (self.quoteId(table), self.quoteId(column))
+ """Adds a primery key (with one column) to a table"""
+ sql = "ALTER TABLE {} ADD PRIMARY KEY ({})".format(
+ self.quoteId(table), self.quoteId(column)
+ )
self._execute_and_commit(sql)
def createTableIndex(self, table, name, column, unique=False):
- """Creates index on one column using default options """
+ """Creates index on one column using default options"""
unique_str = "UNIQUE" if unique else ""
- sql = "CREATE %s INDEX %s ON %s (%s)" % (
- unique_str, self.quoteId(name), self.quoteId(table), self.quoteId(column))
+ sql = "CREATE {} INDEX {} ON {} ({})".format(
+ unique_str, self.quoteId(name), self.quoteId(table), self.quoteId(column)
+ )
self._execute_and_commit(sql)
def deleteTableIndex(self, table, name):
@@ -644,36 +719,43 @@ def deleteTableIndex(self, table, name):
sql = "DROP INDEX %s" % self.quoteId((schema, name))
self._execute_and_commit(sql)
- def createSpatialIndex(self, table, geom_column='geometry'):
+ def createSpatialIndex(self, table, geom_column="geometry"):
if self.isRasterTable(table):
return False
schema, tablename = self.getSchemaTableName(table)
- sql = "SELECT CreateSpatialIndex(%s, %s)" % (self.quoteString(tablename), self.quoteString(geom_column))
+ sql = "SELECT CreateSpatialIndex({}, {})".format(
+ self.quoteString(tablename), self.quoteString(geom_column)
+ )
self._execute_and_commit(sql)
- def deleteSpatialIndex(self, table, geom_column='geometry'):
+ def deleteSpatialIndex(self, table, geom_column="geometry"):
if self.isRasterTable(table):
return False
schema, tablename = self.getSchemaTableName(table)
try:
- sql = "SELECT DiscardSpatialIndex(%s, %s)" % (self.quoteString(tablename), self.quoteString(geom_column))
+ sql = "SELECT DiscardSpatialIndex({}, {})".format(
+ self.quoteString(tablename), self.quoteString(geom_column)
+ )
self._execute_and_commit(sql)
except DbError:
- sql = "SELECT DeleteSpatialIndex(%s, %s)" % (self.quoteString(tablename), self.quoteString(geom_column))
+ sql = "SELECT DeleteSpatialIndex({}, {})".format(
+ self.quoteString(tablename), self.quoteString(geom_column)
+ )
self._execute_and_commit(sql)
# delete the index table
- idx_table_name = "idx_%s_%s" % (tablename, geom_column)
+ idx_table_name = f"idx_{tablename}_{geom_column}"
self.deleteTable(idx_table_name)
- def hasSpatialIndex(self, table, geom_column='geometry'):
+ def hasSpatialIndex(self, table, geom_column="geometry"):
if not self.has_geometry_columns or self.isRasterTable(table):
return False
c = self._get_cursor()
schema, tablename = self.getSchemaTableName(table)
- sql = "SELECT spatial_index_enabled FROM geometry_columns WHERE upper(f_table_name) = upper(%s) AND upper(f_geometry_column) = upper(%s)" % (
- self.quoteString(tablename), self.quoteString(geom_column))
+ sql = "SELECT spatial_index_enabled FROM geometry_columns WHERE upper(f_table_name) = upper({}) AND upper(f_geometry_column) = upper({})".format(
+ self.quoteString(tablename), self.quoteString(geom_column)
+ )
self._execute(c, sql)
row = c.fetchone()
return row is not None and row[0] == 1
diff --git a/python/plugins/db_manager/db_plugins/spatialite/data_model.py b/python/plugins/db_manager/db_plugins/spatialite/data_model.py
index ceaf0b2b8a14..4eb7b519ceab 100644
--- a/python/plugins/db_manager/db_plugins/spatialite/data_model.py
+++ b/python/plugins/db_manager/db_plugins/spatialite/data_model.py
@@ -20,10 +20,12 @@
from qgis.core import QgsMessageLog
from ..plugin import BaseError
-from ..data_model import (TableDataModel,
- SqlResultModel,
- SqlResultModelAsync,
- SqlResultModelTask)
+from ..data_model import (
+ TableDataModel,
+ SqlResultModel,
+ SqlResultModelAsync,
+ SqlResultModelTask,
+)
from .plugin import SLDatabase
@@ -36,7 +38,7 @@ def __init__(self, table, parent=None):
table_txt = self.db.quoteId((self.table.schemaName(), self.table.name))
# run query and get results
- sql = "SELECT %s FROM %s" % (fields_txt, table_txt)
+ sql = f"SELECT {fields_txt} FROM {table_txt}"
c = self.db._get_cursor()
self.db._execute(c, sql)
@@ -57,7 +59,7 @@ def _sanitizeTableField(self, field):
if dataType[-10:] == "COLLECTION":
dataType = dataType[:-10]
if dataType in ["POINT", "LINESTRING", "POLYGON", "GEOMETRY"]:
- return 'GeometryType(%s)' % self.db.quoteId(field.name)
+ return "GeometryType(%s)" % self.db.quoteId(field.name)
return self.db.quoteId(field.name)
def rowCount(self, index=None):
diff --git a/python/plugins/db_manager/db_plugins/spatialite/info_model.py b/python/plugins/db_manager/db_plugins/spatialite/info_model.py
index c33314a5a053..4e326af51737 100644
--- a/python/plugins/db_manager/db_plugins/spatialite/info_model.py
+++ b/python/plugins/db_manager/db_plugins/spatialite/info_model.py
@@ -31,15 +31,16 @@ def __init__(self, db):
def connectionDetails(self):
tbl = [
- (QApplication.translate("DBManagerPlugin", "Filename:"), self.db.connector.dbname)
+ (
+ QApplication.translate("DBManagerPlugin", "Filename:"),
+ self.db.connector.dbname,
+ )
]
return HtmlTable(tbl)
def generalInfo(self):
info = self.db.connector.getInfo()
- tbl = [
- (QApplication.translate("DBManagerPlugin", "SQLite version:"), info[0])
- ]
+ tbl = [(QApplication.translate("DBManagerPlugin", "SQLite version:"), info[0])]
return HtmlTable(tbl)
def spatialInfo(self):
@@ -52,14 +53,20 @@ def spatialInfo(self):
tbl = [
(QApplication.translate("DBManagerPlugin", "Library:"), info[0]),
("GEOS:", info[1]),
- ("Proj:", info[2])
+ ("Proj:", info[2]),
]
ret.append(HtmlTable(tbl))
if not self.db.connector.has_geometry_columns:
- ret.append(HtmlParagraph(
- QApplication.translate("DBManagerPlugin", " geometry_columns table doesn't exist!\n"
- "This table is essential for many GIS applications for enumeration of tables.")))
+ ret.append(
+ HtmlParagraph(
+ QApplication.translate(
+ "DBManagerPlugin",
+ " geometry_columns table doesn't exist!\n"
+ "This table is essential for many GIS applications for enumeration of tables.",
+ )
+ )
+ )
return ret
diff --git a/python/plugins/db_manager/db_plugins/spatialite/plugin.py b/python/plugins/db_manager/db_plugins/spatialite/plugin.py
index f4a203755973..4cf7d90daf7d 100644
--- a/python/plugins/db_manager/db_plugins/spatialite/plugin.py
+++ b/python/plugins/db_manager/db_plugins/spatialite/plugin.py
@@ -27,8 +27,17 @@
from qgis.core import Qgis, QgsApplication, QgsDataSourceUri, QgsSettings
from qgis.gui import QgsMessageBar
-from ..plugin import DBPlugin, Database, Table, VectorTable, RasterTable, TableField, TableIndex, TableTrigger, \
- InvalidDataException
+from ..plugin import (
+ DBPlugin,
+ Database,
+ Table,
+ VectorTable,
+ RasterTable,
+ TableField,
+ TableIndex,
+ TableTrigger,
+ InvalidDataException,
+)
def classFactory():
@@ -43,19 +52,19 @@ def icon(self):
@classmethod
def typeName(self):
- return 'spatialite'
+ return "spatialite"
@classmethod
def typeNameString(self):
- return QCoreApplication.translate('db_manager', 'SpatiaLite')
+ return QCoreApplication.translate("db_manager", "SpatiaLite")
@classmethod
def providerName(self):
- return 'spatialite'
+ return "spatialite"
@classmethod
def connectionSettingsKey(self):
- return '/SpatiaLite/connections'
+ return "/SpatiaLite/connections"
def databasesFactory(self, connection, uri):
return SLDatabase(connection, uri)
@@ -63,10 +72,14 @@ def databasesFactory(self, connection, uri):
def connect(self, parent=None):
conn_name = self.connectionName()
settings = QgsSettings()
- settings.beginGroup("/%s/%s" % (self.connectionSettingsKey(), conn_name))
+ settings.beginGroup(f"/{self.connectionSettingsKey()}/{conn_name}")
if not settings.contains("sqlitepath"): # non-existent entry?
- raise InvalidDataException(self.tr('There is no defined database connection "{0}".').format(conn_name))
+ raise InvalidDataException(
+ self.tr('There is no defined database connection "{0}".').format(
+ conn_name
+ )
+ )
database = settings.value("sqlitepath")
@@ -77,7 +90,7 @@ def connect(self, parent=None):
@classmethod
def addConnection(self, conn_name, uri):
settings = QgsSettings()
- settings.beginGroup("/%s/%s" % (self.connectionSettingsKey(), conn_name))
+ settings.beginGroup(f"/{self.connectionSettingsKey()}/{conn_name}")
settings.setValue("sqlitepath", uri.database())
return True
@@ -85,7 +98,9 @@ def addConnection(self, conn_name, uri):
def addConnectionActionSlot(self, item, action, parent, index):
QApplication.restoreOverrideCursor()
try:
- filename, selected_filter = QFileDialog.getOpenFileName(parent, "Choose SQLite/SpatiaLite file")
+ filename, selected_filter = QFileDialog.getOpenFileName(
+ parent, "Choose SQLite/SpatiaLite file"
+ )
if not filename:
return
finally:
@@ -132,7 +147,9 @@ def sqlResultModelAsync(self, sql, parent):
def registerDatabaseActions(self, mainWindow):
action = QAction(self.tr("Run &Vacuum"), self)
- mainWindow.registerAction(action, self.tr("&Database"), self.runVacuumActionSlot)
+ mainWindow.registerAction(
+ action, self.tr("&Database"), self.runVacuumActionSlot
+ )
Database.registerDatabaseActions(self, mainWindow)
@@ -140,8 +157,11 @@ def runVacuumActionSlot(self, item, action, parent):
QApplication.restoreOverrideCursor()
try:
if not isinstance(item, (DBPlugin, Table)) or item.database() is None:
- parent.infoBar.pushMessage(self.tr("No database selected or you are not connected to it."),
- Qgis.MessageLevel.Info, parent.iface.messageTimeout())
+ parent.infoBar.pushMessage(
+ self.tr("No database selected or you are not connected to it."),
+ Qgis.MessageLevel.Info,
+ parent.iface.messageTimeout(),
+ )
return
finally:
QApplication.setOverrideCursor(Qt.CursorShape.WaitCursor)
@@ -170,7 +190,9 @@ def explicitSpatialIndex(self):
return True
def spatialIndexClause(self, src_table, src_column, dest_table, dest_column):
- return """ "%s".ROWID IN (\nSELECT ROWID FROM SpatialIndex WHERE f_table_name='%s' AND search_frame="%s"."%s") """ % (src_table, src_table, dest_table, dest_column)
+ return """ "{}".ROWID IN (\nSELECT ROWID FROM SpatialIndex WHERE f_table_name='{}' AND search_frame="{}"."{}") """.format(
+ src_table, src_table, dest_table, dest_column
+ )
def supportsComment(self):
return False
@@ -183,7 +205,7 @@ def __init__(self, row, db, schema=None):
self.name, self.isView, self.isSysTable = row
def ogrUri(self):
- ogrUri = "%s|layername=%s" % (self.uri().database(), self.name)
+ ogrUri = f"{self.uri().database()}|layername={self.name}"
return ogrUri
def mimeUri(self):
@@ -220,16 +242,20 @@ def __init__(self, row, db, schema=None):
# SpatiaLite does case-insensitive checks for table names, but the
# SL provider didn't do the same in QGIS < 1.9, so self.geomTableName
# stores the table name like stored in the geometry_columns table
- self.geomTableName, self.geomColumn, self.geomType, self.geomDim, self.srid = row[-5:]
+ self.geomTableName, self.geomColumn, self.geomType, self.geomDim, self.srid = (
+ row[-5:]
+ )
def uri(self):
uri = self.database().uri()
- uri.setDataSource('', self.geomTableName, self.geomColumn)
+ uri.setDataSource("", self.geomTableName, self.geomColumn)
return uri
def hasSpatialIndex(self, geom_column=None):
geom_column = geom_column if geom_column is not None else self.geomColumn
- return self.database().connector.hasSpatialIndex((self.schemaName(), self.name), geom_column)
+ return self.database().connector.hasSpatialIndex(
+ (self.schemaName(), self.name), geom_column
+ )
def createSpatialIndex(self, geom_column=None):
self.aboutToChange.emit()
@@ -260,19 +286,21 @@ def __init__(self, row, db, schema=None):
SLTable.__init__(self, row[:-3], db, schema)
RasterTable.__init__(self, db, schema)
self.prefixName, self.geomColumn, self.srid = row[-3:]
- self.geomType = 'RASTER'
+ self.geomType = "RASTER"
# def info(self):
# from .info_model import SLRasterTableInfo
# return SLRasterTableInfo(self)
def rasterliteGdalUri(self):
- gdalUri = 'RASTERLITE:%s,table=%s' % (self.uri().database(), self.prefixName)
+ gdalUri = "RASTERLITE:{},table={}".format(
+ self.uri().database(), self.prefixName
+ )
return gdalUri
def mimeUri(self):
# QGIS has no provider to load rasters, let's use GDAL
- uri = "raster:gdal:%s:%s" % (self.name, self.uri().database())
+ uri = f"raster:gdal:{self.name}:{self.uri().database()}"
return uri
def toMapLayer(self, geometryType=None, crs=None):
@@ -283,7 +311,9 @@ def toMapLayer(self, geometryType=None, crs=None):
rl = QgsRasterLayer(uri, self.name)
if rl.isValid():
- rl.setContrastEnhancement(QgsContrastEnhancement.ContrastEnhancementAlgorithm.StretchToMinimumMaximum)
+ rl.setContrastEnhancement(
+ QgsContrastEnhancement.ContrastEnhancementAlgorithm.StretchToMinimumMaximum
+ )
return rl
@@ -291,7 +321,14 @@ class SLTableField(TableField):
def __init__(self, row, table):
TableField.__init__(self, table)
- self.num, self.name, self.dataType, self.notNull, self.default, self.primaryKey = row
+ (
+ self.num,
+ self.name,
+ self.dataType,
+ self.notNull,
+ self.default,
+ self.primaryKey,
+ ) = row
self.hasDefault = self.default
diff --git a/python/plugins/db_manager/db_plugins/spatialite/sql_dictionary.py b/python/plugins/db_manager/db_plugins/spatialite/sql_dictionary.py
index 9fb8b253d109..8b2feb51feec 100644
--- a/python/plugins/db_manager/db_plugins/spatialite/sql_dictionary.py
+++ b/python/plugins/db_manager/db_plugins/spatialite/sql_dictionary.py
@@ -15,107 +15,347 @@
***************************************************************************
"""
-__author__ = 'Giuseppe Sucameli'
-__date__ = 'April 2012'
-__copyright__ = '(C) 2012, Giuseppe Sucameli'
+__author__ = "Giuseppe Sucameli"
+__date__ = "April 2012"
+__copyright__ = "(C) 2012, Giuseppe Sucameli"
# keywords
keywords = [
# TODO get them from a reference page
- "action", "add", "after", "all", "alter", "analyze", "and", "as", "asc",
- "before", "begin", "between", "by", "cascade", "case", "cast", "check",
- "collate", "column", "commit", "constraint", "create", "cross", "current_date",
- "current_time", "current_timestamp", "default", "deferrable", "deferred",
- "delete", "desc", "distinct", "drop", "each", "else", "end", "escape",
- "except", "exists", "for", "foreign", "from", "full", "group", "having",
- "ignore", "immediate", "in", "initially", "inner", "insert", "intersect",
- "into", "is", "isnull", "join", "key", "left", "like", "limit", "match",
- "natural", "no", "not", "notnull", "null", "of", "offset", "on", "or", "order",
- "outer", "primary", "references", "release", "restrict", "right", "rollback",
- "row", "savepoint", "select", "set", "table", "temporary", "then", "to",
- "transaction", "trigger", "union", "unique", "update", "using", "values",
- "view", "when", "where",
-
- "abort", "attach", "autoincrement", "conflict", "database", "detach",
- "exclusive", "explain", "fail", "glob", "if", "index", "indexed", "instead",
- "plan", "pragma", "query", "raise", "regexp", "reindex", "rename", "replace",
- "temp", "vacuum", "virtual"
+ "action",
+ "add",
+ "after",
+ "all",
+ "alter",
+ "analyze",
+ "and",
+ "as",
+ "asc",
+ "before",
+ "begin",
+ "between",
+ "by",
+ "cascade",
+ "case",
+ "cast",
+ "check",
+ "collate",
+ "column",
+ "commit",
+ "constraint",
+ "create",
+ "cross",
+ "current_date",
+ "current_time",
+ "current_timestamp",
+ "default",
+ "deferrable",
+ "deferred",
+ "delete",
+ "desc",
+ "distinct",
+ "drop",
+ "each",
+ "else",
+ "end",
+ "escape",
+ "except",
+ "exists",
+ "for",
+ "foreign",
+ "from",
+ "full",
+ "group",
+ "having",
+ "ignore",
+ "immediate",
+ "in",
+ "initially",
+ "inner",
+ "insert",
+ "intersect",
+ "into",
+ "is",
+ "isnull",
+ "join",
+ "key",
+ "left",
+ "like",
+ "limit",
+ "match",
+ "natural",
+ "no",
+ "not",
+ "notnull",
+ "null",
+ "of",
+ "offset",
+ "on",
+ "or",
+ "order",
+ "outer",
+ "primary",
+ "references",
+ "release",
+ "restrict",
+ "right",
+ "rollback",
+ "row",
+ "savepoint",
+ "select",
+ "set",
+ "table",
+ "temporary",
+ "then",
+ "to",
+ "transaction",
+ "trigger",
+ "union",
+ "unique",
+ "update",
+ "using",
+ "values",
+ "view",
+ "when",
+ "where",
+ "abort",
+ "attach",
+ "autoincrement",
+ "conflict",
+ "database",
+ "detach",
+ "exclusive",
+ "explain",
+ "fail",
+ "glob",
+ "if",
+ "index",
+ "indexed",
+ "instead",
+ "plan",
+ "pragma",
+ "query",
+ "raise",
+ "regexp",
+ "reindex",
+ "rename",
+ "replace",
+ "temp",
+ "vacuum",
+ "virtual",
]
spatialite_keywords = []
# functions
functions = [
# TODO get them from a reference page
- "changes", "coalesce", "glob", "ifnull", "hex", "last_insert_rowid",
- "nullif", "quote", "random",
- "randomblob", "replace", "round", "soundex", "total_change",
- "typeof", "zeroblob", "date", "datetime", "julianday", "strftime"
+ "changes",
+ "coalesce",
+ "glob",
+ "ifnull",
+ "hex",
+ "last_insert_rowid",
+ "nullif",
+ "quote",
+ "random",
+ "randomblob",
+ "replace",
+ "round",
+ "soundex",
+ "total_change",
+ "typeof",
+ "zeroblob",
+ "date",
+ "datetime",
+ "julianday",
+ "strftime",
]
operators = [
- ' AND ', ' OR ', '||', ' < ', ' <= ', ' > ', ' >= ', ' = ', ' <> ', ' IS ', ' IS NOT ', ' IN ', ' LIKE ', ' GLOB ', ' MATCH ', ' REGEXP '
+ " AND ",
+ " OR ",
+ "||",
+ " < ",
+ " <= ",
+ " > ",
+ " >= ",
+ " = ",
+ " <> ",
+ " IS ",
+ " IS NOT ",
+ " IN ",
+ " LIKE ",
+ " GLOB ",
+ " MATCH ",
+ " REGEXP ",
]
math_functions = [
# SQL math functions
- "Abs", "ACos", "ASin", "ATan", "Cos", "Cot", "Degrees", "Exp", "Floor", "Log", "Log2",
- "Log10", "Pi", "Radians", "Round", "Sign", "Sin", "Sqrt", "StdDev_Pop", "StdDev_Samp", "Tan",
- "Var_Pop", "Var_Samp"]
+ "Abs",
+ "ACos",
+ "ASin",
+ "ATan",
+ "Cos",
+ "Cot",
+ "Degrees",
+ "Exp",
+ "Floor",
+ "Log",
+ "Log2",
+ "Log10",
+ "Pi",
+ "Radians",
+ "Round",
+ "Sign",
+ "Sin",
+ "Sqrt",
+ "StdDev_Pop",
+ "StdDev_Samp",
+ "Tan",
+ "Var_Pop",
+ "Var_Samp",
+]
-string_functions = ["Length", "Lower", "Upper", "Like", "Trim", "LTrim", "RTrim", "Replace", "Substr"]
+string_functions = [
+ "Length",
+ "Lower",
+ "Upper",
+ "Like",
+ "Trim",
+ "LTrim",
+ "RTrim",
+ "Replace",
+ "Substr",
+]
aggregate_functions = [
- "Max", "Min", "Avg", "Count", "Sum", "Group_Concat", "Total", "Var_Pop", "Var_Samp", "StdDev_Pop", "StdDev_Samp"
+ "Max",
+ "Min",
+ "Avg",
+ "Count",
+ "Sum",
+ "Group_Concat",
+ "Total",
+ "Var_Pop",
+ "Var_Samp",
+ "StdDev_Pop",
+ "StdDev_Samp",
]
spatialite_functions = [ # from www.gaia-gis.it/spatialite-2.3.0/spatialite-sql-2.3.0.html
- # SQL utility functions for BLOB objects
- "*iszipblob", "*ispdfblob", "*isgifblob", "*ispngblob", "*isjpegblob", "*isexifblob",
- "*isexifgpsblob", "*geomfromexifgpsblob", "MakePoint", "BuildMbr", "*buildcirclembr", "ST_MinX",
- "ST_MinY", "ST_MaxX", "ST_MaxY",
- # SQL functions for constructing a geometric object given its Well-known Text Representation
- "ST_GeomFromText", "*pointfromtext",
- # SQL functions for constructing a geometric object given its Well-known Binary Representation
- "*geomfromwkb", "*pointfromwkb",
- # SQL functions for obtaining the Well-known Text / Well-known Binary Representation of a geometric object
- "ST_AsText", "ST_AsBinary",
- # SQL functions supporting exotic geometric formats
- "*assvg", "*asfgf", "*geomfromfgf",
- # SQL functions on type Geometry
- "ST_Dimension", "ST_GeometryType", "ST_Srid", "ST_SetSrid", "ST_isEmpty", "ST_isSimple", "ST_isValid", "ST_Boundary",
- "ST_Envelope",
- # SQL functions on type Point
- "ST_X", "ST_Y",
- # SQL functions on type Curve [Linestring or Ring]
- "ST_StartPoint", "ST_EndPoint", "ST_Length", "ST_isClosed", "ST_isRing", "ST_Simplify",
- "*simplifypreservetopology",
- # SQL functions on type LineString
- "ST_NumPoints", "ST_PointN",
- # SQL functions on type Surface [Polygon or Ring]
- "ST_Centroid", "ST_PointOnSurface", "ST_Area",
- # SQL functions on type Polygon
- "ST_ExteriorRing", "ST_InteriorRingN",
- # SQL functions on type GeomCollection
- "ST_NumGeometries", "ST_GeometryN",
- # SQL functions that test approximative spatial relationships via MBRs
- "MbrEqual", "MbrDisjoint", "MbrTouches", "MbrWithin", "MbrOverlaps", "MbrIntersects",
- "MbrContains",
- # SQL functions that test spatial relationships
- "ST_Equals", "ST_Disjoint", "ST_Touches", "ST_Within", "ST_Overlaps", "ST_Crosses", "ST_Intersects", "ST_Contains",
- "ST_Relate",
- # SQL functions for distance relationships
- "ST_Distance",
- # SQL functions that implement spatial operators
- "ST_Intersection", "ST_Difference", "ST_Union", "ST_SymDifference", "ST_Buffer", "ST_ConvexHull",
- # SQL functions for coordinate transformations
- "ST_Transform",
- # SQL functions for Spatial-MetaData and Spatial-Index handling
- "*initspatialmetadata", "*addgeometrycolumn", "*recovergeometrycolumn", "*discardgeometrycolumn",
- "*createspatialindex", "*creatembrcache", "*disablespatialindex",
- # SQL functions implementing FDO/OGR compatibility
- "*checkspatialmetadata", "*autofdostart", "*autofdostop", "*initfdospatialmetadata",
- "*addfdogeometrycolumn", "*recoverfdogeometrycolumn", "*discardfdogeometrycolumn",
- # SQL functions for MbrCache-based queries
- "*filtermbrwithin", "*filtermbrcontains", "*filtermbrintersects", "*buildmbrfilter"
+ # SQL utility functions for BLOB objects
+ "*iszipblob",
+ "*ispdfblob",
+ "*isgifblob",
+ "*ispngblob",
+ "*isjpegblob",
+ "*isexifblob",
+ "*isexifgpsblob",
+ "*geomfromexifgpsblob",
+ "MakePoint",
+ "BuildMbr",
+ "*buildcirclembr",
+ "ST_MinX",
+ "ST_MinY",
+ "ST_MaxX",
+ "ST_MaxY",
+ # SQL functions for constructing a geometric object given its Well-known Text Representation
+ "ST_GeomFromText",
+ "*pointfromtext",
+ # SQL functions for constructing a geometric object given its Well-known Binary Representation
+ "*geomfromwkb",
+ "*pointfromwkb",
+ # SQL functions for obtaining the Well-known Text / Well-known Binary Representation of a geometric object
+ "ST_AsText",
+ "ST_AsBinary",
+ # SQL functions supporting exotic geometric formats
+ "*assvg",
+ "*asfgf",
+ "*geomfromfgf",
+ # SQL functions on type Geometry
+ "ST_Dimension",
+ "ST_GeometryType",
+ "ST_Srid",
+ "ST_SetSrid",
+ "ST_isEmpty",
+ "ST_isSimple",
+ "ST_isValid",
+ "ST_Boundary",
+ "ST_Envelope",
+ # SQL functions on type Point
+ "ST_X",
+ "ST_Y",
+ # SQL functions on type Curve [Linestring or Ring]
+ "ST_StartPoint",
+ "ST_EndPoint",
+ "ST_Length",
+ "ST_isClosed",
+ "ST_isRing",
+ "ST_Simplify",
+ "*simplifypreservetopology",
+ # SQL functions on type LineString
+ "ST_NumPoints",
+ "ST_PointN",
+ # SQL functions on type Surface [Polygon or Ring]
+ "ST_Centroid",
+ "ST_PointOnSurface",
+ "ST_Area",
+ # SQL functions on type Polygon
+ "ST_ExteriorRing",
+ "ST_InteriorRingN",
+ # SQL functions on type GeomCollection
+ "ST_NumGeometries",
+ "ST_GeometryN",
+ # SQL functions that test approximative spatial relationships via MBRs
+ "MbrEqual",
+ "MbrDisjoint",
+ "MbrTouches",
+ "MbrWithin",
+ "MbrOverlaps",
+ "MbrIntersects",
+ "MbrContains",
+ # SQL functions that test spatial relationships
+ "ST_Equals",
+ "ST_Disjoint",
+ "ST_Touches",
+ "ST_Within",
+ "ST_Overlaps",
+ "ST_Crosses",
+ "ST_Intersects",
+ "ST_Contains",
+ "ST_Relate",
+ # SQL functions for distance relationships
+ "ST_Distance",
+ # SQL functions that implement spatial operators
+ "ST_Intersection",
+ "ST_Difference",
+ "ST_Union",
+ "ST_SymDifference",
+ "ST_Buffer",
+ "ST_ConvexHull",
+ # SQL functions for coordinate transformations
+ "ST_Transform",
+ # SQL functions for Spatial-MetaData and Spatial-Index handling
+ "*initspatialmetadata",
+ "*addgeometrycolumn",
+ "*recovergeometrycolumn",
+ "*discardgeometrycolumn",
+ "*createspatialindex",
+ "*creatembrcache",
+ "*disablespatialindex",
+ # SQL functions implementing FDO/OGR compatibility
+ "*checkspatialmetadata",
+ "*autofdostart",
+ "*autofdostop",
+ "*initfdospatialmetadata",
+ "*addfdogeometrycolumn",
+ "*recoverfdogeometrycolumn",
+ "*discardfdogeometrycolumn",
+ # SQL functions for MbrCache-based queries
+ "*filtermbrwithin",
+ "*filtermbrcontains",
+ "*filtermbrintersects",
+ "*buildmbrfilter",
]
# constants
@@ -125,7 +365,7 @@
def getSqlDictionary(spatial=True):
def strip_star(s):
- if s[0] == '*':
+ if s[0] == "*":
return s.lower()[1:]
else:
return s.lower()
@@ -137,20 +377,26 @@ def strip_star(s):
f += spatialite_functions
c += spatialite_constants
- return {'keyword': list(map(strip_star, k)), 'constant': list(map(strip_star, c)), 'function': list(map(strip_star, f))}
+ return {
+ "keyword": list(map(strip_star, k)),
+ "constant": list(map(strip_star, c)),
+ "function": list(map(strip_star, f)),
+ }
def getQueryBuilderDictionary():
# concat functions
def ff(l):
- return [s for s in l if s[0] != '*']
+ return [s for s in l if s[0] != "*"]
def add_paren(l):
return [s + "(" for s in l]
- foo = sorted(add_paren(ff(list(set.union(set(functions), set(spatialite_functions))))))
+ foo = sorted(
+ add_paren(ff(list(set.union(set(functions), set(spatialite_functions)))))
+ )
m = sorted(add_paren(ff(math_functions)))
agg = sorted(add_paren(ff(aggregate_functions)))
op = ff(operators)
s = sorted(add_paren(ff(string_functions)))
- return {'function': foo, 'math': m, 'aggregate': agg, 'operator': op, 'string': s}
+ return {"function": foo, "math": m, "aggregate": agg, "operator": op, "string": s}
diff --git a/python/plugins/db_manager/db_plugins/vlayers/connector.py b/python/plugins/db_manager/db_plugins/vlayers/connector.py
index 13bc9c505ce7..29e117c04fde 100644
--- a/python/plugins/db_manager/db_plugins/vlayers/connector.py
+++ b/python/plugins/db_manager/db_plugins/vlayers/connector.py
@@ -29,7 +29,7 @@
QgsMapLayerType,
QgsVectorLayer,
QgsCoordinateReferenceSystem,
- QgsWkbTypes
+ QgsWkbTypes,
)
import sqlite3
@@ -172,31 +172,40 @@ def hasTableColumnEditingSupport(self):
def fieldTypes(self):
return [
- "integer", "bigint", "smallint", # integers
- "real", "double", "float", "numeric", # floats
- "varchar", "varchar(255)", "character(20)", "text", # strings
- "date", "datetime" # date/time
+ "integer",
+ "bigint",
+ "smallint", # integers
+ "real",
+ "double",
+ "float",
+ "numeric", # floats
+ "varchar",
+ "varchar(255)",
+ "character(20)",
+ "text", # strings
+ "date",
+ "datetime", # date/time
]
def getSchemas(self):
return None
def getTables(self, schema=None, add_sys_tables=False):
- """ get list of tables """
+ """get list of tables"""
return self.getVectorTables()
def getVectorTables(self, schema=None):
- """ get list of table with a geometry column
- it returns:
- name (table name)
- is_system_table
- type = 'view' (is a view?)
- geometry_column:
- f_table_name (the table name in geometry_columns may be in a wrong case, use this to load the layer)
- f_geometry_column
- type
- coord_dimension
- srid
+ """get list of table with a geometry column
+ it returns:
+ name (table name)
+ is_system_table
+ type = 'view' (is a view?)
+ geometry_column:
+ f_table_name (the table name in geometry_columns may be in a wrong case, use this to load the layer)
+ f_geometry_column
+ type
+ coord_dimension
+ srid
"""
reg = VLayerRegistry.instance()
VLayerRegistry.instance().reset()
@@ -218,16 +227,27 @@ def getVectorTables(self, schema=None):
g_flat = QgsWkbTypes.flatType(g)
geomType = QgsWkbTypes.displayString(g_flat).upper()
if geomType:
- dim = 'XY'
+ dim = "XY"
if QgsWkbTypes.hasZ(g):
- dim += 'Z'
+ dim += "Z"
if QgsWkbTypes.hasM(g):
- dim += 'M'
+ dim += "M"
srid = l.crs().postgisSrid()
if srid not in self.mapSridToName:
self.mapSridToName[srid] = l.crs().description()
lst.append(
- (Table.VectorType, lname, False, False, l.id(), 'geometry', geomType, dim, srid))
+ (
+ Table.VectorType,
+ lname,
+ False,
+ False,
+ l.id(),
+ "geometry",
+ geomType,
+ dim,
+ srid,
+ )
+ )
else:
lst.append((Table.TableType, lname, False, False))
return lst
@@ -243,15 +263,17 @@ def getTableRowCount(self, table):
return l.featureCount()
def getTableFields(self, table):
- """ return list of columns in table """
+ """return list of columns in table"""
t = table[1]
l = VLayerRegistry.instance().getLayer(t)
if not l or not l.isValid():
return []
# id, name, type, nonnull, default, pk
n = l.dataProvider().fields().size()
- f = [(i, f.name(), f.typeName(), False, None, False)
- for i, f in enumerate(l.dataProvider().fields())]
+ f = [
+ (i, f.name(), f.typeName(), False, None, False)
+ for i, f in enumerate(l.dataProvider().fields())
+ ]
if l.isSpatial():
f += [(n, "geometry", "geometry", False, None, False)]
return f
@@ -335,7 +357,16 @@ def addTableColumn(self, table, field_def):
def deleteTableColumn(self, table, column):
print("**unimplemented** deleteTableColumn")
- def updateTableColumn(self, table, column, new_name, new_data_type=None, new_not_null=None, new_default=None, comment=None):
+ def updateTableColumn(
+ self,
+ table,
+ column,
+ new_name,
+ new_data_type=None,
+ new_not_null=None,
+ new_default=None,
+ comment=None,
+ ):
print("**unimplemented** updateTableColumn")
def renameTableColumn(self, table, column, new_name):
@@ -358,7 +389,9 @@ def isGeometryColumn(self, table, column):
print("**unimplemented** isGeometryColumn")
return False
- def addGeometryColumn(self, table, geom_column='geometry', geom_type='POINT', srid=-1, dim=2):
+ def addGeometryColumn(
+ self, table, geom_column="geometry", geom_type="POINT", srid=-1, dim=2
+ ):
print("**unimplemented** addGeometryColumn")
return False
@@ -386,15 +419,15 @@ def deleteTableIndex(self, table, name):
print("**unimplemented** deleteTableIndex")
return False
- def createSpatialIndex(self, table, geom_column='geometry'):
+ def createSpatialIndex(self, table, geom_column="geometry"):
print("**unimplemented** createSpatialIndex")
return False
- def deleteSpatialIndex(self, table, geom_column='geometry'):
+ def deleteSpatialIndex(self, table, geom_column="geometry"):
print("**unimplemented** deleteSpatialIndex")
return False
- def hasSpatialIndex(self, table, geom_column='geometry'):
+ def hasSpatialIndex(self, table, geom_column="geometry"):
print("**unimplemented** hasSpatialIndex")
return False
@@ -408,6 +441,7 @@ def connection_error_types(self):
def getSqlDictionary(self):
from .sql_dictionary import getSqlDictionary
+
sql_dict = getSqlDictionary()
items = []
diff --git a/python/plugins/db_manager/db_plugins/vlayers/data_model.py b/python/plugins/db_manager/db_plugins/vlayers/data_model.py
index 22b28d1686ff..4195f69778c9 100644
--- a/python/plugins/db_manager/db_plugins/vlayers/data_model.py
+++ b/python/plugins/db_manager/db_plugins/vlayers/data_model.py
@@ -17,21 +17,25 @@
***************************************************************************/
"""
-from ..data_model import (TableDataModel,
- BaseTableModel,
- SqlResultModelAsync,
- SqlResultModelTask)
+from ..data_model import (
+ TableDataModel,
+ BaseTableModel,
+ SqlResultModelAsync,
+ SqlResultModelTask,
+)
from .connector import VLayerRegistry, getQueryGeometryName
from .plugin import LVectorTable
from ..plugin import DbError, BaseError
from qgis.PyQt.QtCore import QElapsedTimer, QTemporaryFile
-from qgis.core import (QgsVectorLayer,
- QgsWkbTypes,
- QgsVirtualLayerDefinition,
- QgsVirtualLayerTask,
- QgsTask)
+from qgis.core import (
+ QgsVectorLayer,
+ QgsWkbTypes,
+ QgsVirtualLayerDefinition,
+ QgsVirtualLayerTask,
+ QgsTask,
+)
class LTableDataModel(TableDataModel):
@@ -56,7 +60,7 @@ def __init__(self, table, parent=None):
if f.hasGeometry():
a.append(QgsWkbTypes.displayString(f.geometry().wkbType()))
else:
- a.append('None')
+ a.append("None")
self.resdata.append(a)
self.fetchedFrom = 0
@@ -83,7 +87,9 @@ def __init__(self, db, sql, parent):
df.setQuery(sql)
self.subtask = QgsVirtualLayerTask(df)
- self.addSubTask(self.subtask, [], QgsTask.SubTaskDependency.ParentDependsOnSubTask)
+ self.addSubTask(
+ self.subtask, [], QgsTask.SubTaskDependency.ParentDependsOnSubTask
+ )
def run(self):
try:
diff --git a/python/plugins/db_manager/db_plugins/vlayers/info_model.py b/python/plugins/db_manager/db_plugins/vlayers/info_model.py
index 473caab0cff1..e5e4346c741f 100644
--- a/python/plugins/db_manager/db_plugins/vlayers/info_model.py
+++ b/python/plugins/db_manager/db_plugins/vlayers/info_model.py
@@ -29,15 +29,12 @@ def __init__(self, db):
self.db = db
def connectionDetails(self):
- tbl = [
- ]
+ tbl = []
return HtmlTable(tbl)
def generalInfo(self):
self.db.connector.getInfo()
- tbl = [
- (QApplication.translate("DBManagerPlugin", "SQLite version:"), "3")
- ]
+ tbl = [(QApplication.translate("DBManagerPlugin", "SQLite version:"), "3")]
return HtmlTable(tbl)
def privilegesDetails(self):
diff --git a/python/plugins/db_manager/db_plugins/vlayers/plugin.py b/python/plugins/db_manager/db_plugins/vlayers/plugin.py
index 19ba23fdd1d8..f9109008f1d4 100644
--- a/python/plugins/db_manager/db_plugins/vlayers/plugin.py
+++ b/python/plugins/db_manager/db_plugins/vlayers/plugin.py
@@ -22,7 +22,12 @@
from qgis.PyQt.QtCore import QCoreApplication
from qgis.PyQt.QtGui import QIcon
-from qgis.core import QgsApplication, QgsVectorLayer, QgsProject, QgsVirtualLayerDefinition
+from qgis.core import (
+ QgsApplication,
+ QgsVectorLayer,
+ QgsProject,
+ QgsVirtualLayerDefinition,
+)
from ..plugin import DBPlugin, Database, Table, VectorTable, TableField
@@ -42,23 +47,25 @@ def connectionIcon(self):
@classmethod
def typeName(self):
- return 'vlayers'
+ return "vlayers"
@classmethod
def typeNameString(self):
- return QCoreApplication.translate('db_manager', 'Virtual Layers')
+ return QCoreApplication.translate("db_manager", "Virtual Layers")
@classmethod
def providerName(self):
- return 'virtual'
+ return "virtual"
@classmethod
def connectionSettingsKey(self):
- return 'vlayers'
+ return "vlayers"
@classmethod
def connections(self):
- return [VLayerDBPlugin(QCoreApplication.translate('db_manager', 'Project layers'))]
+ return [
+ VLayerDBPlugin(QCoreApplication.translate("db_manager", "Project layers"))
+ ]
def databasesFactory(self, connection, uri):
return FakeDatabase(connection, uri)
@@ -92,17 +99,29 @@ def rasterTablesFactory(self, row, db, schema=None):
def info(self):
from .info_model import LDatabaseInfo
+
return LDatabaseInfo(self)
def sqlResultModel(self, sql, parent):
from .data_model import LSqlResultModel
+
return LSqlResultModel(self, sql, parent)
def sqlResultModelAsync(self, sql, parent):
from .data_model import LSqlResultModelAsync
+
return LSqlResultModelAsync(self, sql, parent)
- def toSqlLayer(self, sql, geomCol, uniqueCol, layerName="QueryLayer", layerType=None, avoidSelectById=False, _filter=""):
+ def toSqlLayer(
+ self,
+ sql,
+ geomCol,
+ uniqueCol,
+ layerName="QueryLayer",
+ layerType=None,
+ avoidSelectById=False,
+ _filter="",
+ ):
df = QgsVirtualLayerDefinition()
df.setQuery(sql)
if uniqueCol is not None:
@@ -128,7 +147,9 @@ def explicitSpatialIndex(self):
return True
def spatialIndexClause(self, src_table, src_column, dest_table, dest_column):
- return '"%s"._search_frame_ = "%s"."%s"' % (src_table, dest_table, dest_column)
+ return '"{}"._search_frame_ = "{}"."{}"'.format(
+ src_table, dest_table, dest_column
+ )
def supportsComment(self):
return False
@@ -145,6 +166,7 @@ def tableFieldsFactory(self, row, table):
def tableDataModel(self, parent):
from .data_model import LTableDataModel
+
return LTableDataModel(self, parent)
def canBeAddedToCanvas(self):
@@ -159,12 +181,13 @@ def __init__(self, row, db, schema=None):
# SpatiaLite does case-insensitive checks for table names, but the
# SL provider didn't do the same in QGIS < 1.9, so self.geomTableName
# stores the table name like stored in the geometry_columns table
- self.geomTableName, self.geomColumn, self.geomType, self.geomDim, self.srid = row[
- -5:]
+ self.geomTableName, self.geomColumn, self.geomType, self.geomDim, self.srid = (
+ row[-5:]
+ )
def uri(self):
uri = self.database().uri()
- uri.setDataSource('', self.geomTableName, self.geomColumn)
+ uri.setDataSource("", self.geomTableName, self.geomColumn)
return uri
def hasSpatialIndex(self, geom_column=None):
@@ -178,7 +201,8 @@ def deleteSpatialIndex(self, geom_column=None):
def refreshTableEstimatedExtent(self):
self.extent = self.database().connector.getTableExtent(
- ("id", self.geomTableName), None)
+ ("id", self.geomTableName), None
+ )
def runAction(self, action):
return
@@ -191,5 +215,12 @@ class LTableField(TableField):
def __init__(self, row, table):
TableField.__init__(self, table)
- self.num, self.name, self.dataType, self.notNull, self.default, self.primaryKey = row
+ (
+ self.num,
+ self.name,
+ self.dataType,
+ self.notNull,
+ self.default,
+ self.primaryKey,
+ ) = row
self.hasDefault = self.default
diff --git a/python/plugins/db_manager/db_plugins/vlayers/sql_dictionary.py b/python/plugins/db_manager/db_plugins/vlayers/sql_dictionary.py
index 0b177b52ce9e..6103273f9945 100644
--- a/python/plugins/db_manager/db_plugins/vlayers/sql_dictionary.py
+++ b/python/plugins/db_manager/db_plugins/vlayers/sql_dictionary.py
@@ -15,122 +15,472 @@
***************************************************************************
"""
-__author__ = 'Hugo Mercier'
-__date__ = 'December 2015'
-__copyright__ = '(C) 2015, Hugo Mercier'
+__author__ = "Hugo Mercier"
+__date__ = "December 2015"
+__copyright__ = "(C) 2015, Hugo Mercier"
# keywords
keywords = [
# TODO get them from a reference page
- "action", "add", "after", "all", "alter", "analyze", "and", "as", "asc",
- "before", "begin", "between", "by", "cascade", "case", "cast", "check",
- "collate", "column", "commit", "constraint", "create", "cross", "current_date",
- "current_time", "current_timestamp", "default", "deferrable", "deferred",
- "delete", "desc", "distinct", "drop", "each", "else", "end", "escape",
- "except", "exists", "for", "foreign", "from", "full", "group", "having",
- "ignore", "immediate", "in", "initially", "inner", "insert", "intersect",
- "into", "is", "isnull", "join", "key", "left", "like", "limit", "match",
- "natural", "no", "not", "notnull", "null", "of", "offset", "on", "or", "order",
- "outer", "primary", "references", "release", "restrict", "right", "rollback",
- "row", "savepoint", "select", "set", "table", "temporary", "then", "to",
- "transaction", "trigger", "union", "unique", "update", "using", "values",
- "view", "when", "where",
-
- "abort", "attach", "autoincrement", "conflict", "database", "detach",
- "exclusive", "explain", "fail", "glob", "if", "index", "indexed", "instead",
- "plan", "pragma", "query", "raise", "regexp", "reindex", "rename", "replace",
- "temp", "vacuum", "virtual"
+ "action",
+ "add",
+ "after",
+ "all",
+ "alter",
+ "analyze",
+ "and",
+ "as",
+ "asc",
+ "before",
+ "begin",
+ "between",
+ "by",
+ "cascade",
+ "case",
+ "cast",
+ "check",
+ "collate",
+ "column",
+ "commit",
+ "constraint",
+ "create",
+ "cross",
+ "current_date",
+ "current_time",
+ "current_timestamp",
+ "default",
+ "deferrable",
+ "deferred",
+ "delete",
+ "desc",
+ "distinct",
+ "drop",
+ "each",
+ "else",
+ "end",
+ "escape",
+ "except",
+ "exists",
+ "for",
+ "foreign",
+ "from",
+ "full",
+ "group",
+ "having",
+ "ignore",
+ "immediate",
+ "in",
+ "initially",
+ "inner",
+ "insert",
+ "intersect",
+ "into",
+ "is",
+ "isnull",
+ "join",
+ "key",
+ "left",
+ "like",
+ "limit",
+ "match",
+ "natural",
+ "no",
+ "not",
+ "notnull",
+ "null",
+ "of",
+ "offset",
+ "on",
+ "or",
+ "order",
+ "outer",
+ "primary",
+ "references",
+ "release",
+ "restrict",
+ "right",
+ "rollback",
+ "row",
+ "savepoint",
+ "select",
+ "set",
+ "table",
+ "temporary",
+ "then",
+ "to",
+ "transaction",
+ "trigger",
+ "union",
+ "unique",
+ "update",
+ "using",
+ "values",
+ "view",
+ "when",
+ "where",
+ "abort",
+ "attach",
+ "autoincrement",
+ "conflict",
+ "database",
+ "detach",
+ "exclusive",
+ "explain",
+ "fail",
+ "glob",
+ "if",
+ "index",
+ "indexed",
+ "instead",
+ "plan",
+ "pragma",
+ "query",
+ "raise",
+ "regexp",
+ "reindex",
+ "rename",
+ "replace",
+ "temp",
+ "vacuum",
+ "virtual",
]
spatialite_keywords = []
# functions
functions = [
# TODO get them from a reference page
- "changes", "coalesce", "glob", "ifnull", "hex", "last_insert_rowid",
- "nullif", "quote", "random",
- "randomblob", "replace", "round", "soundex", "total_change",
- "typeof", "zeroblob", "date", "datetime", "julianday", "strftime"
+ "changes",
+ "coalesce",
+ "glob",
+ "ifnull",
+ "hex",
+ "last_insert_rowid",
+ "nullif",
+ "quote",
+ "random",
+ "randomblob",
+ "replace",
+ "round",
+ "soundex",
+ "total_change",
+ "typeof",
+ "zeroblob",
+ "date",
+ "datetime",
+ "julianday",
+ "strftime",
]
operators = [
- ' AND ', ' OR ', '||', ' < ', ' <= ', ' > ', ' >= ', ' = ', ' <> ', ' IS ', ' IS NOT ', ' IN ', ' LIKE ', ' GLOB ', ' MATCH ', ' REGEXP '
+ " AND ",
+ " OR ",
+ "||",
+ " < ",
+ " <= ",
+ " > ",
+ " >= ",
+ " = ",
+ " <> ",
+ " IS ",
+ " IS NOT ",
+ " IN ",
+ " LIKE ",
+ " GLOB ",
+ " MATCH ",
+ " REGEXP ",
]
math_functions = [
# SQL math functions
- "Abs", "ACos", "ASin", "ATan", "Cos", "Cot", "Degrees", "Exp", "Floor", "Log", "Log2",
- "Log10", "Pi", "Radians", "Round", "Sign", "Sin", "Sqrt", "StdDev_Pop", "StdDev_Samp", "Tan",
- "Var_Pop", "Var_Samp"]
+ "Abs",
+ "ACos",
+ "ASin",
+ "ATan",
+ "Cos",
+ "Cot",
+ "Degrees",
+ "Exp",
+ "Floor",
+ "Log",
+ "Log2",
+ "Log10",
+ "Pi",
+ "Radians",
+ "Round",
+ "Sign",
+ "Sin",
+ "Sqrt",
+ "StdDev_Pop",
+ "StdDev_Samp",
+ "Tan",
+ "Var_Pop",
+ "Var_Samp",
+]
-string_functions = ["Length", "Lower", "Upper", "Like", "Trim", "LTrim", "RTrim", "Replace", "Substr"]
+string_functions = [
+ "Length",
+ "Lower",
+ "Upper",
+ "Like",
+ "Trim",
+ "LTrim",
+ "RTrim",
+ "Replace",
+ "Substr",
+]
aggregate_functions = [
- "Max", "Min", "Avg", "Count", "Sum", "Group_Concat", "Total", "Var_Pop", "Var_Samp", "StdDev_Pop", "StdDev_Samp"
+ "Max",
+ "Min",
+ "Avg",
+ "Count",
+ "Sum",
+ "Group_Concat",
+ "Total",
+ "Var_Pop",
+ "Var_Samp",
+ "StdDev_Pop",
+ "StdDev_Samp",
]
spatialite_functions = [ # from www.gaia-gis.it/spatialite-2.3.0/spatialite-sql-2.3.0.html
- # SQL utility functions for BLOB objects
- "*iszipblob", "*ispdfblob", "*isgifblob", "*ispngblob", "*isjpegblob", "*isexifblob",
- "*isexifgpsblob", "*geomfromexifgpsblob", "MakePoint", "BuildMbr", "*buildcirclembr", "ST_MinX",
- "ST_MinY", "ST_MaxX", "ST_MaxY",
- # SQL functions for constructing a geometric object given its Well-known Text Representation
- "ST_GeomFromText", "*pointfromtext",
- # SQL functions for constructing a geometric object given its Well-known Binary Representation
- "*geomfromwkb", "*pointfromwkb",
- # SQL functions for obtaining the Well-known Text / Well-known Binary Representation of a geometric object
- "ST_AsText", "ST_AsBinary",
- # SQL functions supporting exotic geometric formats
- "*assvg", "*asfgf", "*geomfromfgf",
- # SQL functions on type Geometry
- "ST_Dimension", "ST_GeometryType", "ST_Srid", "ST_SetSrid", "ST_isEmpty", "ST_isSimple", "ST_isValid", "ST_Boundary",
- "ST_Envelope",
- # SQL functions on type Point
- "ST_X", "ST_Y",
- # SQL functions on type Curve [Linestring or Ring]
- "ST_StartPoint", "ST_EndPoint", "ST_Length", "ST_isClosed", "ST_isRing", "ST_Simplify",
- "*simplifypreservetopology",
- # SQL functions on type LineString
- "ST_NumPoints", "ST_PointN",
- # SQL functions on type Surface [Polygon or Ring]
- "ST_Centroid", "ST_PointOnSurface", "ST_Area",
- # SQL functions on type Polygon
- "ST_ExteriorRing", "ST_InteriorRingN",
- # SQL functions on type GeomCollection
- "ST_NumGeometries", "ST_GeometryN",
- # SQL functions that test approximative spatial relationships via MBRs
- "MbrEqual", "MbrDisjoint", "MbrTouches", "MbrWithin", "MbrOverlaps", "MbrIntersects",
- "MbrContains",
- # SQL functions that test spatial relationships
- "ST_Equals", "ST_Disjoint", "ST_Touches", "ST_Within", "ST_Overlaps", "ST_Crosses", "ST_Intersects", "ST_Contains",
- "ST_Relate",
- # SQL functions for distance relationships
- "ST_Distance",
- # SQL functions that implement spatial operators
- "ST_Intersection", "ST_Difference", "ST_Union", "ST_SymDifference", "ST_Buffer", "ST_ConvexHull",
- # SQL functions for coordinate transformations
- "ST_Transform",
- # SQL functions for Spatial-MetaData and Spatial-Index handling
- "*initspatialmetadata", "*addgeometrycolumn", "*recovergeometrycolumn", "*discardgeometrycolumn",
- "*createspatialindex", "*creatembrcache", "*disablespatialindex",
- # SQL functions implementing FDO/OGR compatibility
- "*checkspatialmetadata", "*autofdostart", "*autofdostop", "*initfdospatialmetadata",
- "*addfdogeometrycolumn", "*recoverfdogeometrycolumn", "*discardfdogeometrycolumn",
- # SQL functions for MbrCache-based queries
- "*filtermbrwithin", "*filtermbrcontains", "*filtermbrintersects", "*buildmbrfilter"
+ # SQL utility functions for BLOB objects
+ "*iszipblob",
+ "*ispdfblob",
+ "*isgifblob",
+ "*ispngblob",
+ "*isjpegblob",
+ "*isexifblob",
+ "*isexifgpsblob",
+ "*geomfromexifgpsblob",
+ "MakePoint",
+ "BuildMbr",
+ "*buildcirclembr",
+ "ST_MinX",
+ "ST_MinY",
+ "ST_MaxX",
+ "ST_MaxY",
+ # SQL functions for constructing a geometric object given its Well-known Text Representation
+ "ST_GeomFromText",
+ "*pointfromtext",
+ # SQL functions for constructing a geometric object given its Well-known Binary Representation
+ "*geomfromwkb",
+ "*pointfromwkb",
+ # SQL functions for obtaining the Well-known Text / Well-known Binary Representation of a geometric object
+ "ST_AsText",
+ "ST_AsBinary",
+ # SQL functions supporting exotic geometric formats
+ "*assvg",
+ "*asfgf",
+ "*geomfromfgf",
+ # SQL functions on type Geometry
+ "ST_Dimension",
+ "ST_GeometryType",
+ "ST_Srid",
+ "ST_SetSrid",
+ "ST_isEmpty",
+ "ST_isSimple",
+ "ST_isValid",
+ "ST_Boundary",
+ "ST_Envelope",
+ # SQL functions on type Point
+ "ST_X",
+ "ST_Y",
+ # SQL functions on type Curve [Linestring or Ring]
+ "ST_StartPoint",
+ "ST_EndPoint",
+ "ST_Length",
+ "ST_isClosed",
+ "ST_isRing",
+ "ST_Simplify",
+ "*simplifypreservetopology",
+ # SQL functions on type LineString
+ "ST_NumPoints",
+ "ST_PointN",
+ # SQL functions on type Surface [Polygon or Ring]
+ "ST_Centroid",
+ "ST_PointOnSurface",
+ "ST_Area",
+ # SQL functions on type Polygon
+ "ST_ExteriorRing",
+ "ST_InteriorRingN",
+ # SQL functions on type GeomCollection
+ "ST_NumGeometries",
+ "ST_GeometryN",
+ # SQL functions that test approximative spatial relationships via MBRs
+ "MbrEqual",
+ "MbrDisjoint",
+ "MbrTouches",
+ "MbrWithin",
+ "MbrOverlaps",
+ "MbrIntersects",
+ "MbrContains",
+ # SQL functions that test spatial relationships
+ "ST_Equals",
+ "ST_Disjoint",
+ "ST_Touches",
+ "ST_Within",
+ "ST_Overlaps",
+ "ST_Crosses",
+ "ST_Intersects",
+ "ST_Contains",
+ "ST_Relate",
+ # SQL functions for distance relationships
+ "ST_Distance",
+ # SQL functions that implement spatial operators
+ "ST_Intersection",
+ "ST_Difference",
+ "ST_Union",
+ "ST_SymDifference",
+ "ST_Buffer",
+ "ST_ConvexHull",
+ # SQL functions for coordinate transformations
+ "ST_Transform",
+ # SQL functions for Spatial-MetaData and Spatial-Index handling
+ "*initspatialmetadata",
+ "*addgeometrycolumn",
+ "*recovergeometrycolumn",
+ "*discardgeometrycolumn",
+ "*createspatialindex",
+ "*creatembrcache",
+ "*disablespatialindex",
+ # SQL functions implementing FDO/OGR compatibility
+ "*checkspatialmetadata",
+ "*autofdostart",
+ "*autofdostop",
+ "*initfdospatialmetadata",
+ "*addfdogeometrycolumn",
+ "*recoverfdogeometrycolumn",
+ "*discardfdogeometrycolumn",
+ # SQL functions for MbrCache-based queries
+ "*filtermbrwithin",
+ "*filtermbrcontains",
+ "*filtermbrintersects",
+ "*buildmbrfilter",
]
qgis_functions = [
- "atan2", "round", "rand", "randf", "clamp", "scale_linear", "scale_polynomial", "scale_exponential", "_pi", "to_int", "toint", "to_real", "toreal",
- "to_string", "tostring", "to_datetime", "todatetime", "to_date", "todate", "to_time", "totime", "to_interval", "tointerval",
- "regexp_match", "now", "_now", "age", "year", "month", "week", "day", "hour", "minute", "second", "day_of_week", "title",
- "levenshtein", "longest_common_substring", "hamming_distance", "wordwrap", "regexp_replace", "regexp_substr", "concat",
- "strpos", "_left", "_right", "rpad", "lpad", "format", "format_number", "format_date", "color_rgb", "color_rgba", "color_rgbf", "ramp_color", "ramp_color_object",
- "color_hsl", "color_hsla", "color_hslf", "color_hsv", "color_hsva", "color_hsvf", "color_cmyk", "color_cmyka", "color_cmykf", "color_part", "darker", "lighter",
- "set_color_part", "point_n", "start_point", "end_point", "nodes_to_points", "segments_to_lines", "make_point",
- "make_point_m", "make_line", "make_polygon", "x_min", "xmin", "x_max", "xmax", "y_min", "ymin", "y_max", "ymax", "geom_from_wkt",
- "geomFromWKT", "geom_from_gml", "relate", "intersects_bbox", "bbox", "translate", "buffer", "point_on_surface", "reverse",
- "exterior_ring", "interior_ring_n", "geometry_n", "bounds", "num_points", "num_interior_rings", "num_rings", "num_geometries",
- "bounds_width", "bounds_height", "is_closed", "convex_hull", "sym_difference", "combine", "_union", "geom_to_wkt", "geomToWKT",
- "transform", "uuid", "_uuid", "layer_property", "var", "_specialcol_", "project_color", "project_color_object"]
+ "atan2",
+ "round",
+ "rand",
+ "randf",
+ "clamp",
+ "scale_linear",
+ "scale_polynomial",
+ "scale_exponential",
+ "_pi",
+ "to_int",
+ "toint",
+ "to_real",
+ "toreal",
+ "to_string",
+ "tostring",
+ "to_datetime",
+ "todatetime",
+ "to_date",
+ "todate",
+ "to_time",
+ "totime",
+ "to_interval",
+ "tointerval",
+ "regexp_match",
+ "now",
+ "_now",
+ "age",
+ "year",
+ "month",
+ "week",
+ "day",
+ "hour",
+ "minute",
+ "second",
+ "day_of_week",
+ "title",
+ "levenshtein",
+ "longest_common_substring",
+ "hamming_distance",
+ "wordwrap",
+ "regexp_replace",
+ "regexp_substr",
+ "concat",
+ "strpos",
+ "_left",
+ "_right",
+ "rpad",
+ "lpad",
+ "format",
+ "format_number",
+ "format_date",
+ "color_rgb",
+ "color_rgba",
+ "color_rgbf",
+ "ramp_color",
+ "ramp_color_object",
+ "color_hsl",
+ "color_hsla",
+ "color_hslf",
+ "color_hsv",
+ "color_hsva",
+ "color_hsvf",
+ "color_cmyk",
+ "color_cmyka",
+ "color_cmykf",
+ "color_part",
+ "darker",
+ "lighter",
+ "set_color_part",
+ "point_n",
+ "start_point",
+ "end_point",
+ "nodes_to_points",
+ "segments_to_lines",
+ "make_point",
+ "make_point_m",
+ "make_line",
+ "make_polygon",
+ "x_min",
+ "xmin",
+ "x_max",
+ "xmax",
+ "y_min",
+ "ymin",
+ "y_max",
+ "ymax",
+ "geom_from_wkt",
+ "geomFromWKT",
+ "geom_from_gml",
+ "relate",
+ "intersects_bbox",
+ "bbox",
+ "translate",
+ "buffer",
+ "point_on_surface",
+ "reverse",
+ "exterior_ring",
+ "interior_ring_n",
+ "geometry_n",
+ "bounds",
+ "num_points",
+ "num_interior_rings",
+ "num_rings",
+ "num_geometries",
+ "bounds_width",
+ "bounds_height",
+ "is_closed",
+ "convex_hull",
+ "sym_difference",
+ "combine",
+ "_union",
+ "geom_to_wkt",
+ "geomToWKT",
+ "transform",
+ "uuid",
+ "_uuid",
+ "layer_property",
+ "var",
+ "_specialcol_",
+ "project_color",
+ "project_color_object",
+]
# constants
@@ -140,7 +490,7 @@
def getSqlDictionary(spatial=True):
def strip_star(s):
- if s[0] == '*':
+ if s[0] == "*":
return s.lower()[1:]
else:
return s.lower()
@@ -153,20 +503,34 @@ def strip_star(s):
f += qgis_functions
c += spatialite_constants
- return {'keyword': list(map(strip_star, k)), 'constant': list(map(strip_star, c)), 'function': list(map(strip_star, f))}
+ return {
+ "keyword": list(map(strip_star, k)),
+ "constant": list(map(strip_star, c)),
+ "function": list(map(strip_star, f)),
+ }
def getQueryBuilderDictionary():
# concat functions
def ff(l):
- return [s for s in l if s[0] != '*']
+ return [s for s in l if s[0] != "*"]
def add_paren(l):
return [s + "(" for s in l]
- foo = sorted(add_paren(ff(list(set.union(set(functions), set(spatialite_functions), set(qgis_functions))))))
+ foo = sorted(
+ add_paren(
+ ff(
+ list(
+ set.union(
+ set(functions), set(spatialite_functions), set(qgis_functions)
+ )
+ )
+ )
+ )
+ )
m = sorted(add_paren(ff(math_functions)))
agg = sorted(add_paren(ff(aggregate_functions)))
op = ff(operators)
s = sorted(add_paren(ff(string_functions)))
- return {'function': foo, 'math': m, 'aggregate': agg, 'operator': op, 'string': s}
+ return {"function": foo, "math": m, "aggregate": agg, "operator": op, "string": s}
diff --git a/python/plugins/db_manager/db_tree.py b/python/plugins/db_manager/db_tree.py
index c40d2f42f2bf..2a080cbdaecd 100644
--- a/python/plugins/db_manager/db_tree.py
+++ b/python/plugins/db_manager/db_tree.py
@@ -41,7 +41,9 @@ def __init__(self, mainWindow):
self.setModel(DBModel(self))
self.setHeaderHidden(True)
- self.setEditTriggers(QTreeView.EditTrigger.EditKeyPressed | QTreeView.EditTrigger.SelectedClicked)
+ self.setEditTriggers(
+ QTreeView.EditTrigger.EditKeyPressed | QTreeView.EditTrigger.SelectedClicked
+ )
self.setDragEnabled(True)
self.setAcceptDrops(True)
@@ -125,8 +127,12 @@ def contextMenuEvent(self, ev):
menu = QMenu(self)
if isinstance(item, (Table, Schema)) and not isinstance(item, LTable):
- if not (isinstance(item, GPKGRasterTable) and int(gdal.VersionInfo()) < 3100000):
- menu.addAction(QCoreApplication.translate("DBTree", "Rename…"), self.rename)
+ if not (
+ isinstance(item, GPKGRasterTable) and int(gdal.VersionInfo()) < 3100000
+ ):
+ menu.addAction(
+ QCoreApplication.translate("DBTree", "Rename…"), self.rename
+ )
menu.addAction(QCoreApplication.translate("DBTree", "Delete…"), self.delete)
if isinstance(item, Table) and item.canBeAddedToCanvas():
@@ -140,7 +146,10 @@ def contextMenuEvent(self, ev):
menu.addAction(self.tr("Remove"), self.delete)
elif not index.parent().isValid() and item.typeName() in ("spatialite", "gpkg"):
- menu.addAction(QCoreApplication.translate("DBTree", "New Connection…"), self.newConnection)
+ menu.addAction(
+ QCoreApplication.translate("DBTree", "New Connection…"),
+ self.newConnection,
+ )
if not menu.isEmpty():
menu.exec(ev.globalPos())
@@ -166,14 +175,28 @@ def addLayer(self):
layers = QgsProject.instance().addMapLayers([layer])
if len(layers) != 1:
QgsMessageLog.logMessage(
- self.tr("%1 is an invalid layer - not loaded").replace("%1", layer.publicSource()))
- msgLabel = QLabel(self.tr(
- "%1 is an invalid layer and cannot be loaded. Please check the message log for further info.").replace(
- "%1", layer.publicSource()), self.mainWindow.infoBar)
+ self.tr("%1 is an invalid layer - not loaded").replace(
+ "%1", layer.publicSource()
+ )
+ )
+ msgLabel = QLabel(
+ self.tr(
+ '%1 is an invalid layer and cannot be loaded. Please check the message log for further info.'
+ ).replace("%1", layer.publicSource()),
+ self.mainWindow.infoBar,
+ )
msgLabel.setWordWrap(True)
- msgLabel.linkActivated.connect(self.mainWindow.iface.mainWindow().findChild(QWidget, "MessageLog").show)
- msgLabel.linkActivated.connect(self.mainWindow.iface.mainWindow().raise_)
- self.mainWindow.infoBar.pushItem(QgsMessageBarItem(msgLabel, Qgis.MessageLevel.Warning))
+ msgLabel.linkActivated.connect(
+ self.mainWindow.iface.mainWindow()
+ .findChild(QWidget, "MessageLog")
+ .show
+ )
+ msgLabel.linkActivated.connect(
+ self.mainWindow.iface.mainWindow().raise_
+ )
+ self.mainWindow.infoBar.pushItem(
+ QgsMessageBarItem(msgLabel, Qgis.MessageLevel.Warning)
+ )
def reconnect(self):
db = self.currentDatabase()
diff --git a/python/plugins/db_manager/dlg_add_geometry_column.py b/python/plugins/db_manager/dlg_add_geometry_column.py
index 559fae0ca76d..3a22e86a16d8 100644
--- a/python/plugins/db_manager/dlg_add_geometry_column.py
+++ b/python/plugins/db_manager/dlg_add_geometry_column.py
@@ -29,12 +29,19 @@
from .dlg_db_error import DlgDbError
from .gui_utils import GuiUtils
-Ui_Dialog, _ = uic.loadUiType(GuiUtils.get_ui_file_path('DlgAddGeometryColumn.ui'))
+Ui_Dialog, _ = uic.loadUiType(GuiUtils.get_ui_file_path("DlgAddGeometryColumn.ui"))
class DlgAddGeometryColumn(QDialog, Ui_Dialog):
- GEOM_TYPES = ["POINT", "LINESTRING", "POLYGON", "MULTIPOINT", "MULTILINESTRING", "MULTIPOLYGON",
- "GEOMETRYCOLLECTION"]
+ GEOM_TYPES = [
+ "POINT",
+ "LINESTRING",
+ "POLYGON",
+ "MULTIPOINT",
+ "MULTILINESTRING",
+ "MULTIPOLYGON",
+ "GEOMETRYCOLLECTION",
+ ]
def __init__(self, parent=None, table=None, db=None):
QDialog.__init__(self, parent)
@@ -45,9 +52,11 @@ def __init__(self, parent=None, table=None, db=None):
self.buttonBox.accepted.connect(self.createGeomColumn)
def createGeomColumn(self):
- """ first check whether everything's fine """
+ """first check whether everything's fine"""
if self.editName.text() == "":
- QMessageBox.critical(self, self.tr("DB Manager"), self.tr("Field name must not be empty."))
+ QMessageBox.critical(
+ self, self.tr("DB Manager"), self.tr("Field name must not be empty.")
+ )
return
name = self.editName.text()
@@ -62,7 +71,9 @@ def createGeomColumn(self):
# now create the geometry column
with OverrideCursor(Qt.CursorShape.WaitCursor):
try:
- self.table.addGeometryColumn(name, geom_type, srid, dim, createSpatialIndex)
+ self.table.addGeometryColumn(
+ name, geom_type, srid, dim, createSpatialIndex
+ )
except DbError as e:
DlgDbError.showError(e, self)
return
diff --git a/python/plugins/db_manager/dlg_create_constraint.py b/python/plugins/db_manager/dlg_create_constraint.py
index b2c571494fec..aeb0e62e163e 100644
--- a/python/plugins/db_manager/dlg_create_constraint.py
+++ b/python/plugins/db_manager/dlg_create_constraint.py
@@ -30,7 +30,7 @@
from .db_plugins.plugin import TableConstraint
from .gui_utils import GuiUtils
-Ui_Dialog, _ = uic.loadUiType(GuiUtils.get_ui_file_path('DlgCreateConstraint.ui'))
+Ui_Dialog, _ = uic.loadUiType(GuiUtils.get_ui_file_path("DlgCreateConstraint.ui"))
class DlgCreateConstraint(QDialog, Ui_Dialog):
@@ -65,7 +65,11 @@ def createConstraint(self):
def getConstraint(self):
constr = TableConstraint(self.table)
constr.name = ""
- constr.type = TableConstraint.TypePrimaryKey if self.radPrimaryKey.isChecked() else TableConstraint.TypeUnique
+ constr.type = (
+ TableConstraint.TypePrimaryKey
+ if self.radPrimaryKey.isChecked()
+ else TableConstraint.TypeUnique
+ )
constr.columns = []
column = self.cboColumn.currentText()
for fld in self.table.fields():
diff --git a/python/plugins/db_manager/dlg_create_index.py b/python/plugins/db_manager/dlg_create_index.py
index 40e3b4c1611a..2a6452edeee2 100644
--- a/python/plugins/db_manager/dlg_create_index.py
+++ b/python/plugins/db_manager/dlg_create_index.py
@@ -30,7 +30,7 @@
from .db_plugins.plugin import TableIndex
from .gui_utils import GuiUtils
-Ui_Dialog, _ = uic.loadUiType(GuiUtils.get_ui_file_path('DlgCreateIndex.ui'))
+Ui_Dialog, _ = uic.loadUiType(GuiUtils.get_ui_file_path("DlgCreateIndex.ui"))
class DlgCreateIndex(QDialog, Ui_Dialog):
@@ -52,12 +52,14 @@ def populateColumns(self):
self.cboColumn.addItem(fld.name)
def columnChanged(self):
- self.editName.setText("idx_%s_%s" % (self.table.name, self.cboColumn.currentText()))
+ self.editName.setText(f"idx_{self.table.name}_{self.cboColumn.currentText()}")
def createIndex(self):
idx = self.getIndex()
if idx.name == "":
- QMessageBox.critical(self, self.tr("Error"), self.tr("Please enter a name for the index."))
+ QMessageBox.critical(
+ self, self.tr("Error"), self.tr("Please enter a name for the index.")
+ )
return
# now create the index
diff --git a/python/plugins/db_manager/dlg_create_table.py b/python/plugins/db_manager/dlg_create_table.py
index c7b36d6e6d4d..7e617a8a3707 100644
--- a/python/plugins/db_manager/dlg_create_table.py
+++ b/python/plugins/db_manager/dlg_create_table.py
@@ -22,7 +22,15 @@
from qgis.PyQt import uic
from qgis.PyQt.QtCore import Qt, QModelIndex
-from qgis.PyQt.QtWidgets import QItemDelegate, QComboBox, QDialog, QPushButton, QDialogButtonBox, QMessageBox, QApplication
+from qgis.PyQt.QtWidgets import (
+ QItemDelegate,
+ QComboBox,
+ QDialog,
+ QPushButton,
+ QDialogButtonBox,
+ QMessageBox,
+ QApplication,
+)
from qgis.PyQt.QtCore import QItemSelectionModel, pyqtSignal
from qgis.utils import OverrideCursor
@@ -32,11 +40,11 @@
from .dlg_db_error import DlgDbError
from .gui_utils import GuiUtils
-Ui_Dialog, _ = uic.loadUiType(GuiUtils.get_ui_file_path('DlgCreateTable.ui'))
+Ui_Dialog, _ = uic.loadUiType(GuiUtils.get_ui_file_path("DlgCreateTable.ui"))
class TableFieldsDelegate(QItemDelegate):
- """ delegate with some special item editors """
+ """delegate with some special item editors"""
columnNameChanged = pyqtSignal()
@@ -56,7 +64,7 @@ def createEditor(self, parent, option, index):
return QItemDelegate.createEditor(self, parent, option, index)
def setEditorData(self, editor, index):
- """ load data from model to editor """
+ """load data from model to editor"""
m = index.model()
if index.column() == 1:
txt = m.data(index, Qt.ItemDataRole.DisplayRole)
@@ -66,7 +74,7 @@ def setEditorData(self, editor, index):
QItemDelegate.setEditorData(self, editor, index)
def setModelData(self, editor, model, index):
- """ save data from editor back to model """
+ """save data from editor back to model"""
if index.column() == 1:
model.setData(index, editor.currentText())
else:
@@ -77,8 +85,15 @@ def setModelData(self, editor, model, index):
class DlgCreateTable(QDialog, Ui_Dialog):
- GEOM_TYPES = ["POINT", "LINESTRING", "POLYGON", "MULTIPOINT", "MULTILINESTRING", "MULTIPOLYGON",
- "GEOMETRYCOLLECTION"]
+ GEOM_TYPES = [
+ "POINT",
+ "LINESTRING",
+ "POLYGON",
+ "MULTIPOINT",
+ "MULTILINESTRING",
+ "MULTIPOLYGON",
+ "GEOMETRYCOLLECTION",
+ ]
def __init__(self, item, parent=None):
QDialog.__init__(self, parent)
@@ -128,7 +143,7 @@ def populateSchemas(self):
index = -1
for schema in self.schemas:
self.cboSchema.addItem(schema.name)
- if hasattr(self.item, 'schema') and schema.name == self.item.schema().name:
+ if hasattr(self.item, "schema") and schema.name == self.item.schema().name:
index = self.cboSchema.count() - 1
self.cboSchema.setCurrentIndex(index)
@@ -146,8 +161,8 @@ def updateUi(self):
def updateUiFields(self):
fld = self.selectedField()
if fld is not None:
- up_enabled = (fld != 0)
- down_enabled = (fld != self.fields.model().rowCount() - 1)
+ up_enabled = fld != 0
+ down_enabled = fld != self.fields.model().rowCount() - 1
del_enabled = True
else:
up_enabled, down_enabled, del_enabled = False, False, False
@@ -156,7 +171,7 @@ def updateUiFields(self):
self.btnDeleteField.setEnabled(del_enabled)
def updatePkeyCombo(self, selRow=None):
- """ called when list of columns changes. if 'sel' is None, it keeps current index """
+ """called when list of columns changes. if 'sel' is None, it keeps current index"""
if selRow is None:
selRow = self.cboPrimaryKey.currentIndex()
@@ -171,7 +186,7 @@ def updatePkeyCombo(self, selRow=None):
self.cboPrimaryKey.setCurrentIndex(selRow)
def addField(self):
- """Adds new field to the end of field table """
+ """Adds new field to the end of field table"""
m = self.fields.model()
newRow = m.rowCount()
m.insertRows(newRow, 1)
@@ -192,7 +207,11 @@ def addField(self):
# selects the new row
sel = self.fields.selectionModel()
- sel.select(indexName, QItemSelectionModel.SelectionFlag.Rows | QItemSelectionModel.SelectionFlag.ClearAndSelect)
+ sel.select(
+ indexName,
+ QItemSelectionModel.SelectionFlag.Rows
+ | QItemSelectionModel.SelectionFlag.ClearAndSelect,
+ )
# starts editing
self.fields.edit(indexName)
@@ -206,23 +225,29 @@ def selectedField(self):
return sel[0].row()
def deleteField(self):
- """Deletes selected field """
+ """Deletes selected field"""
row = self.selectedField()
if row is None:
- QMessageBox.information(self, self.tr("DB Manager"), self.tr("No field selected."))
+ QMessageBox.information(
+ self, self.tr("DB Manager"), self.tr("No field selected.")
+ )
else:
self.fields.model().removeRows(row, 1)
self.updatePkeyCombo()
def fieldUp(self):
- """ move selected field up """
+ """move selected field up"""
row = self.selectedField()
if row is None:
- QMessageBox.information(self, self.tr("DB Manager"), self.tr("No field selected."))
+ QMessageBox.information(
+ self, self.tr("DB Manager"), self.tr("No field selected.")
+ )
return
if row == 0:
- QMessageBox.information(self, self.tr("DB Manager"), self.tr("Field is already at the top."))
+ QMessageBox.information(
+ self, self.tr("DB Manager"), self.tr("Field is already at the top.")
+ )
return
# take row and reinsert it
@@ -231,18 +256,26 @@ def fieldUp(self):
# set selection again
index = self.fields.model().index(row - 1, 0, QModelIndex())
- self.fields.selectionModel().select(index, QItemSelectionModel.SelectionFlag.Rows | QItemSelectionModel.SelectionFlag.ClearAndSelect)
+ self.fields.selectionModel().select(
+ index,
+ QItemSelectionModel.SelectionFlag.Rows
+ | QItemSelectionModel.SelectionFlag.ClearAndSelect,
+ )
self.updatePkeyCombo()
def fieldDown(self):
- """ move selected field down """
+ """move selected field down"""
row = self.selectedField()
if row is None:
- QMessageBox.information(self, self.tr("DB Manager"), self.tr("No field selected."))
+ QMessageBox.information(
+ self, self.tr("DB Manager"), self.tr("No field selected.")
+ )
return
if row == self.fields.model().rowCount() - 1:
- QMessageBox.information(self, self.tr("DB Manager"), self.tr("Field is already at the bottom."))
+ QMessageBox.information(
+ self, self.tr("DB Manager"), self.tr("Field is already at the bottom.")
+ )
return
# take row and reinsert it
@@ -251,35 +284,51 @@ def fieldDown(self):
# set selection again
index = self.fields.model().index(row + 1, 0, QModelIndex())
- self.fields.selectionModel().select(index, QItemSelectionModel.SelectionFlag.Rows | QItemSelectionModel.SelectionFlag.ClearAndSelect)
+ self.fields.selectionModel().select(
+ index,
+ QItemSelectionModel.SelectionFlag.Rows
+ | QItemSelectionModel.SelectionFlag.ClearAndSelect,
+ )
self.updatePkeyCombo()
def createTable(self):
- """Creates table with chosen fields, optionally add a geometry column """
+ """Creates table with chosen fields, optionally add a geometry column"""
if not self.hasSchemas:
schema = None
else:
schema = str(self.cboSchema.currentText())
if len(schema) == 0:
- QMessageBox.information(self, self.tr("DB Manager"), self.tr("A valid schema must be selected first."))
+ QMessageBox.information(
+ self,
+ self.tr("DB Manager"),
+ self.tr("A valid schema must be selected first."),
+ )
return
table = str(self.editName.text())
if len(table) == 0:
- QMessageBox.information(self, self.tr("DB Manager"), self.tr("A valid table name is required."))
+ QMessageBox.information(
+ self, self.tr("DB Manager"), self.tr("A valid table name is required.")
+ )
return
m = self.fields.model()
if m.rowCount() == 0:
- QMessageBox.information(self, self.tr("DB Manager"), self.tr("At least one field is required."))
+ QMessageBox.information(
+ self, self.tr("DB Manager"), self.tr("At least one field is required.")
+ )
return
useGeomColumn = self.chkGeomColumn.isChecked()
if useGeomColumn:
geomColumn = str(self.editGeomColumn.text())
if len(geomColumn) == 0:
- QMessageBox.information(self, self.tr("DB Manager"), self.tr("A name is required for the geometry column."))
+ QMessageBox.information(
+ self,
+ self.tr("DB Manager"),
+ self.tr("A name is required for the geometry column."),
+ )
return
geomType = self.GEOM_TYPES[self.cboGeomType.currentIndex()]
@@ -321,4 +370,6 @@ def createTable(self):
self.editGeomSrid.setEnabled(False)
self.chkSpatialIndex.setEnabled(False)
- QMessageBox.information(self, self.tr("DB Manager"), self.tr("Table created successfully."))
+ QMessageBox.information(
+ self, self.tr("DB Manager"), self.tr("Table created successfully.")
+ )
diff --git a/python/plugins/db_manager/dlg_db_error.py b/python/plugins/db_manager/dlg_db_error.py
index 3da3daa55cda..87cef96f0012 100644
--- a/python/plugins/db_manager/dlg_db_error.py
+++ b/python/plugins/db_manager/dlg_db_error.py
@@ -26,7 +26,7 @@
from .gui_utils import GuiUtils
from .db_plugins.plugin import DbError
-Ui_Dialog, _ = uic.loadUiType(GuiUtils.get_ui_file_path('DlgDbError.ui'))
+Ui_Dialog, _ = uic.loadUiType(GuiUtils.get_ui_file_path("DlgDbError.ui"))
class DlgDbError(QDialog, Ui_Dialog):
@@ -36,7 +36,7 @@ def __init__(self, e, parent=None):
self.setupUi(self)
def sanitize(txt):
- return "" if txt is None else "" + txt.replace('<', '<') + " "
+ return "" if txt is None else "" + txt.replace("<", "<") + " "
if isinstance(e, DbError):
self.setQueryMessage(sanitize(e.msg), sanitize(e.query))
diff --git a/python/plugins/db_manager/dlg_export_vector.py b/python/plugins/db_manager/dlg_export_vector.py
index 232b821e3d0d..26282c364134 100644
--- a/python/plugins/db_manager/dlg_export_vector.py
+++ b/python/plugins/db_manager/dlg_export_vector.py
@@ -25,16 +25,18 @@
from qgis.PyQt.QtWidgets import QDialog, QFileDialog, QMessageBox, QApplication
from qgis.PyQt.QtGui import QCursor
-from qgis.core import (QgsVectorFileWriter,
- QgsVectorDataProvider,
- QgsCoordinateReferenceSystem,
- QgsVectorLayerExporter,
- QgsSettings)
+from qgis.core import (
+ QgsVectorFileWriter,
+ QgsVectorDataProvider,
+ QgsCoordinateReferenceSystem,
+ QgsVectorLayerExporter,
+ QgsSettings,
+)
from qgis.utils import OverrideCursor
from .gui_utils import GuiUtils
-Ui_Dialog, _ = uic.loadUiType(GuiUtils.get_ui_file_path('DlgExportVector.ui'))
+Ui_Dialog, _ = uic.loadUiType(GuiUtils.get_ui_file_path("DlgExportVector.ui"))
class DlgExportVector(QDialog, Ui_Dialog):
@@ -46,8 +48,8 @@ def __init__(self, inLayer, inDb, parent=None):
self.setupUi(self)
vectorFilterName = "lastVectorFileFilter" # "lastRasterFileFilter"
- self.lastUsedVectorFilterSettingsKey = "/UI/{}".format(vectorFilterName)
- self.lastUsedVectorDirSettingsKey = "/UI/{}Dir".format(vectorFilterName)
+ self.lastUsedVectorFilterSettingsKey = f"/UI/{vectorFilterName}"
+ self.lastUsedVectorDirSettingsKey = f"/UI/{vectorFilterName}Dir"
# update UI
self.setupWorkingMode()
@@ -65,7 +67,7 @@ def setupWorkingMode(self):
self.checkSupports()
def checkSupports(self):
- """ update options available for the current input layer """
+ """update options available for the current input layer"""
allowSpatial = self.db.connector.hasSpatialSupport()
hasGeomType = self.inLayer and self.inLayer.isSpatial()
self.chkSourceSrid.setEnabled(allowSpatial and hasGeomType)
@@ -82,19 +84,22 @@ def chooseOutputFile(self):
selected_filter = QgsVectorFileWriter.filterForDriver(selected_driver)
# ask for a filename
- filename, filter = QFileDialog.getSaveFileName(self, self.tr("Choose where to save the file"), lastUsedDir,
- selected_filter)
+ filename, filter = QFileDialog.getSaveFileName(
+ self, self.tr("Choose where to save the file"), lastUsedDir, selected_filter
+ )
if filename == "":
return
- ext = selected_filter[selected_filter.find('.'):]
- ext = ext[:ext.find(' ')]
+ ext = selected_filter[selected_filter.find(".") :]
+ ext = ext[: ext.find(" ")]
if not filename.lower().endswith(ext):
filename += ext
# store the last used dir
- settings.setValue(self.lastUsedVectorDirSettingsKey, QFileInfo(filename).filePath())
+ settings.setValue(
+ self.lastUsedVectorDirSettingsKey, QFileInfo(filename).filePath()
+ )
self.editOutputFile.setText(filename)
@@ -127,23 +132,31 @@ def populateFileFilters(self):
def accept(self):
# sanity checks
if self.editOutputFile.text() == "":
- QMessageBox.information(self, self.tr("Export to file"), self.tr("Output file name is required"))
+ QMessageBox.information(
+ self, self.tr("Export to file"), self.tr("Output file name is required")
+ )
return
if self.chkSourceSrid.isEnabled() and self.chkSourceSrid.isChecked():
try:
sourceSrid = int(self.editSourceSrid.text())
except ValueError:
- QMessageBox.information(self, self.tr("Export to file"),
- self.tr("Invalid source srid: must be an integer"))
+ QMessageBox.information(
+ self,
+ self.tr("Export to file"),
+ self.tr("Invalid source srid: must be an integer"),
+ )
return
if self.chkTargetSrid.isEnabled() and self.chkTargetSrid.isChecked():
try:
targetSrid = int(self.editTargetSrid.text())
except ValueError:
- QMessageBox.information(self, self.tr("Export to file"),
- self.tr("Invalid target srid: must be an integer"))
+ QMessageBox.information(
+ self,
+ self.tr("Export to file"),
+ self.tr("Invalid target srid: must be an integer"),
+ )
return
with OverrideCursor(Qt.CursorShape.WaitCursor):
@@ -157,15 +170,15 @@ def accept(self):
# set the OGR driver will be used
driverName = self.cboFileFormat.currentData()
- options['driverName'] = driverName
+ options["driverName"] = driverName
# set the output file encoding
if self.chkEncoding.isEnabled() and self.chkEncoding.isChecked():
enc = self.cboEncoding.currentText()
- options['fileEncoding'] = enc
+ options["fileEncoding"] = enc
if self.chkDropTable.isChecked():
- options['overwrite'] = True
+ options["overwrite"] = True
outCrs = QgsCoordinateReferenceSystem()
if self.chkTargetSrid.isEnabled() and self.chkTargetSrid.isChecked():
@@ -179,8 +192,9 @@ def accept(self):
self.inLayer.setCrs(inCrs)
# do the export!
- ret, errMsg = QgsVectorLayerExporter.exportLayer(self.inLayer, uri, providerName, outCrs,
- False, options)
+ ret, errMsg = QgsVectorLayerExporter.exportLayer(
+ self.inLayer, uri, providerName, outCrs, False, options
+ )
except Exception as e:
ret = -1
errMsg = str(e)
@@ -190,12 +204,18 @@ def accept(self):
self.inLayer.setCrs(prevInCrs)
if ret != 0:
- QMessageBox.warning(self, self.tr("Export to file"), self.tr("Error {0}\n{1}").format(ret, errMsg))
+ QMessageBox.warning(
+ self,
+ self.tr("Export to file"),
+ self.tr("Error {0}\n{1}").format(ret, errMsg),
+ )
return
# create spatial index
# if self.chkSpatialIndex.isEnabled() and self.chkSpatialIndex.isChecked():
# self.db.connector.createSpatialIndex( (schema, table), geom )
- QMessageBox.information(self, self.tr("Export to file"), self.tr("Export finished."))
+ QMessageBox.information(
+ self, self.tr("Export to file"), self.tr("Export finished.")
+ )
return QDialog.accept(self)
diff --git a/python/plugins/db_manager/dlg_field_properties.py b/python/plugins/db_manager/dlg_field_properties.py
index c4fb29b5c356..1548569605e9 100644
--- a/python/plugins/db_manager/dlg_field_properties.py
+++ b/python/plugins/db_manager/dlg_field_properties.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Giuseppe Sucameli'
-__date__ = 'April 2012'
-__copyright__ = '(C) 2012, Giuseppe Sucameli'
+__author__ = "Giuseppe Sucameli"
+__date__ = "April 2012"
+__copyright__ = "(C) 2012, Giuseppe Sucameli"
from qgis.PyQt import uic
from qgis.PyQt.QtWidgets import QDialog, QMessageBox
@@ -25,7 +25,7 @@
from .db_plugins.plugin import TableField
from .gui_utils import GuiUtils
-Ui_Dialog, _ = uic.loadUiType(GuiUtils.get_ui_file_path('DlgFieldProperties.ui'))
+Ui_Dialog, _ = uic.loadUiType(GuiUtils.get_ui_file_path("DlgFieldProperties.ui"))
class DlgFieldProperties(QDialog, Ui_Dialog):
@@ -81,13 +81,17 @@ def getField(self, newCopy=False):
return fld
def onOK(self):
- """ first check whether everything's fine """
+ """first check whether everything's fine"""
fld = self.getField(True) # don't change the original copy
if fld.name == "":
- QMessageBox.critical(self, self.tr("DB Manager"), self.tr("Field name must not be empty."))
+ QMessageBox.critical(
+ self, self.tr("DB Manager"), self.tr("Field name must not be empty.")
+ )
return
if fld.dataType == "":
- QMessageBox.critical(self, self.tr("DB Manager"), self.tr("Field type must not be empty."))
+ QMessageBox.critical(
+ self, self.tr("DB Manager"), self.tr("Field type must not be empty.")
+ )
return
self.accept()
diff --git a/python/plugins/db_manager/dlg_import_vector.py b/python/plugins/db_manager/dlg_import_vector.py
index ebc2140a468c..d0cdbf0552f6 100644
--- a/python/plugins/db_manager/dlg_import_vector.py
+++ b/python/plugins/db_manager/dlg_import_vector.py
@@ -24,21 +24,23 @@
from qgis.PyQt.QtCore import Qt, QFileInfo
from qgis.PyQt.QtWidgets import QDialog, QFileDialog, QMessageBox
-from qgis.core import (QgsDataSourceUri,
- QgsVectorDataProvider,
- QgsVectorLayer,
- QgsMapLayerType,
- QgsProviderRegistry,
- QgsCoordinateReferenceSystem,
- QgsVectorLayerExporter,
- QgsProject,
- QgsSettings)
+from qgis.core import (
+ QgsDataSourceUri,
+ QgsVectorDataProvider,
+ QgsVectorLayer,
+ QgsMapLayerType,
+ QgsProviderRegistry,
+ QgsCoordinateReferenceSystem,
+ QgsVectorLayerExporter,
+ QgsProject,
+ QgsSettings,
+)
from qgis.gui import QgsMessageViewer
from qgis.utils import OverrideCursor, iface
from .gui_utils import GuiUtils
-Ui_Dialog, _ = uic.loadUiType(GuiUtils.get_ui_file_path('DlgImportVector.ui'))
+Ui_Dialog, _ = uic.loadUiType(GuiUtils.get_ui_file_path("DlgImportVector.ui"))
class DlgImportVector(QDialog, Ui_Dialog):
@@ -59,7 +61,9 @@ def __init__(self, inLayer, outDb, outUri, parent=None):
self.default_pk = "id"
self.default_geom = "geom"
- self.mode = self.ASK_FOR_INPUT_MODE if self.inLayer is None else self.HAS_INPUT_MODE
+ self.mode = (
+ self.ASK_FOR_INPUT_MODE if self.inLayer is None else self.HAS_INPUT_MODE
+ )
# used to delete the inlayer whether created inside this dialog
self.inLayerMustBeDestroyed = False
@@ -77,7 +81,7 @@ def __init__(self, inLayer, outDb, outUri, parent=None):
self.updateInputLayer()
def setupWorkingMode(self, mode):
- """ hide the widget to select a layer/file if the input layer is already set """
+ """hide the widget to select a layer/file if the input layer is already set"""
self.wdgInput.setVisible(mode == self.ASK_FOR_INPUT_MODE)
self.resize(450, 350)
@@ -90,7 +94,9 @@ def setupWorkingMode(self, mode):
self.editPrimaryKey.setText(self.default_pk)
self.editGeomColumn.setText(self.default_geom)
- self.chkLowercaseFieldNames.setEnabled(self.db.hasLowercaseFieldNamesOption())
+ self.chkLowercaseFieldNames.setEnabled(
+ self.db.hasLowercaseFieldNamesOption()
+ )
if not self.chkLowercaseFieldNames.isEnabled():
self.chkLowercaseFieldNames.setChecked(False)
else:
@@ -99,10 +105,14 @@ def setupWorkingMode(self, mode):
self.updateInputLayer()
def checkSupports(self):
- """ update options available for the current input layer """
+ """update options available for the current input layer"""
allowSpatial = self.db.connector.hasSpatialSupport()
hasGeomType = self.inLayer and self.inLayer.isSpatial()
- isShapefile = self.inLayer and self.inLayer.providerType() == "ogr" and self.inLayer.storageType() == "ESRI Shapefile"
+ isShapefile = (
+ self.inLayer
+ and self.inLayer.providerType() == "ogr"
+ and self.inLayer.storageType() == "ESRI Shapefile"
+ )
self.chkGeomColumn.setEnabled(allowSpatial and hasGeomType)
if not self.chkGeomColumn.isEnabled():
@@ -142,7 +152,7 @@ def populateLayers(self):
self.cboInputLayer.setCurrentIndex(index)
def deleteInputLayer(self):
- """ unset the input layer, then destroy it but only if it was created from this dialog """
+ """unset the input layer, then destroy it but only if it was created from this dialog"""
if self.mode == self.ASK_FOR_INPUT_MODE and self.inLayer:
if self.inLayerMustBeDestroyed:
self.inLayer.deleteLater()
@@ -158,8 +168,13 @@ def chooseInputFile(self):
lastDir = settings.value("/db_manager/lastUsedDir", "")
lastVectorFormat = settings.value("/UI/lastVectorFileFilter", "")
# ask for a filename
- filename, lastVectorFormat = QFileDialog.getOpenFileName(self, self.tr("Choose the file to import"),
- lastDir, vectorFormats, lastVectorFormat)
+ filename, lastVectorFormat = QFileDialog.getOpenFileName(
+ self,
+ self.tr("Choose the file to import"),
+ lastDir,
+ vectorFormats,
+ lastVectorFormat,
+ )
if filename == "":
return
# store the last used dir and format
@@ -170,7 +185,7 @@ def chooseInputFile(self):
self.cboInputLayer.setEditText(filename)
def reloadInputLayer(self):
- """Creates the input layer and update available options """
+ """Creates the input layer and update available options"""
if self.mode != self.ASK_FOR_INPUT_MODE:
return True
@@ -264,7 +279,7 @@ def populateEncodings(self):
# populate the combo with supported encodings
self.cboEncoding.addItems(QgsVectorDataProvider.availableEncodings())
- self.cboEncoding.insertItem(0, self.tr('Automatic'), "")
+ self.cboEncoding.insertItem(0, self.tr("Automatic"), "")
self.cboEncoding.setCurrentIndex(0)
def accept(self):
@@ -275,23 +290,37 @@ def accept(self):
# sanity checks
if self.inLayer is None:
- QMessageBox.critical(self, self.tr("Import to Database"), self.tr("Input layer missing or not valid."))
+ QMessageBox.critical(
+ self,
+ self.tr("Import to Database"),
+ self.tr("Input layer missing or not valid."),
+ )
return
if self.cboTable.currentText() == "":
- QMessageBox.critical(self, self.tr("Import to Database"), self.tr("Output table name is required."))
+ QMessageBox.critical(
+ self,
+ self.tr("Import to Database"),
+ self.tr("Output table name is required."),
+ )
return
if self.chkSourceSrid.isEnabled() and self.chkSourceSrid.isChecked():
if not self.widgetSourceSrid.crs().isValid():
- QMessageBox.critical(self, self.tr("Import to Database"),
- self.tr("Invalid source srid: must be a valid crs."))
+ QMessageBox.critical(
+ self,
+ self.tr("Import to Database"),
+ self.tr("Invalid source srid: must be a valid crs."),
+ )
return
if self.chkTargetSrid.isEnabled() and self.chkTargetSrid.isChecked():
if not self.widgetTargetSrid.crs().isValid():
- QMessageBox.critical(self, self.tr("Import to Database"),
- self.tr("Invalid target srid: must be a valid crs."))
+ QMessageBox.critical(
+ self,
+ self.tr("Import to Database"),
+ self.tr("Invalid target srid: must be a valid crs."),
+ )
return
with OverrideCursor(Qt.CursorShape.WaitCursor):
@@ -300,48 +329,63 @@ def accept(self):
prevInEncoding = self.inLayer.dataProvider().encoding()
try:
- schema = self.outUri.schema() if not self.cboSchema.isEnabled() else self.cboSchema.currentText()
+ schema = (
+ self.outUri.schema()
+ if not self.cboSchema.isEnabled()
+ else self.cboSchema.currentText()
+ )
table = self.cboTable.currentText()
# get pk and geom field names from the source layer or use the
# ones defined by the user
srcUri = QgsDataSourceUri(self.inLayer.source())
- pk = srcUri.keyColumn() if not self.chkPrimaryKey.isChecked() else self.editPrimaryKey.text()
+ pk = (
+ srcUri.keyColumn()
+ if not self.chkPrimaryKey.isChecked()
+ else self.editPrimaryKey.text()
+ )
if not pk:
pk = self.default_pk
if self.inLayer.isSpatial() and self.chkGeomColumn.isEnabled():
- geom = srcUri.geometryColumn() if not self.chkGeomColumn.isChecked() else self.editGeomColumn.text()
+ geom = (
+ srcUri.geometryColumn()
+ if not self.chkGeomColumn.isChecked()
+ else self.editGeomColumn.text()
+ )
if not geom:
geom = self.default_geom
else:
geom = None
options = {}
- if self.chkLowercaseFieldNames.isEnabled() and self.chkLowercaseFieldNames.isChecked():
+ if (
+ self.chkLowercaseFieldNames.isEnabled()
+ and self.chkLowercaseFieldNames.isChecked()
+ ):
pk = pk.lower()
if geom:
geom = geom.lower()
- options['lowercaseFieldNames'] = True
+ options["lowercaseFieldNames"] = True
# get output params, update output URI
self.outUri.setDataSource(schema, table, geom, "", pk)
typeName = self.db.dbplugin().typeName()
providerName = self.db.dbplugin().providerName()
- if typeName == 'gpkg':
+ if typeName == "gpkg":
uri = self.outUri.database()
- options['update'] = True
- options['driverName'] = 'GPKG'
- options['layerName'] = table
+ options["update"] = True
+ options["driverName"] = "GPKG"
+ options["layerName"] = table
else:
uri = self.outUri.uri(False)
if self.chkDropTable.isChecked():
- options['overwrite'] = True
+ options["overwrite"] = True
if self.chkSinglePart.isEnabled() and self.chkSinglePart.isChecked():
- options['forceSinglePartGeometryType'] = True
+ options["forceSinglePartGeometryType"] = True
outCrs = QgsCoordinateReferenceSystem()
if self.chkTargetSrid.isEnabled() and self.chkTargetSrid.isChecked():
@@ -352,14 +396,20 @@ def accept(self):
inCrs = self.widgetSourceSrid.crs()
self.inLayer.setCrs(inCrs)
- if self.chkEncoding.isEnabled() and self.chkEncoding.isChecked() and self.cboEncoding.currentData() is None:
+ if (
+ self.chkEncoding.isEnabled()
+ and self.chkEncoding.isChecked()
+ and self.cboEncoding.currentData() is None
+ ):
enc = self.cboEncoding.currentText()
self.inLayer.setProviderEncoding(enc)
onlySelected = self.chkSelectedFeatures.isChecked()
# do the import!
- ret, errMsg = QgsVectorLayerExporter.exportLayer(self.inLayer, uri, providerName, outCrs, onlySelected, options)
+ ret, errMsg = QgsVectorLayerExporter.exportLayer(
+ self.inLayer, uri, providerName, outCrs, onlySelected, options
+ )
except Exception as e:
ret = -1
errMsg = str(e)
@@ -389,7 +439,9 @@ def accept(self):
self.db.connection().reconnect()
self.db.refresh()
- QMessageBox.information(self, self.tr("Import to Database"), self.tr("Import was successful."))
+ QMessageBox.information(
+ self, self.tr("Import to Database"), self.tr("Import was successful.")
+ )
return QDialog.accept(self)
def closeEvent(self, event):
diff --git a/python/plugins/db_manager/dlg_query_builder.py b/python/plugins/db_manager/dlg_query_builder.py
index 33998530d23b..fb893cf3ac21 100644
--- a/python/plugins/db_manager/dlg_query_builder.py
+++ b/python/plugins/db_manager/dlg_query_builder.py
@@ -26,14 +26,14 @@
from .db_plugins.plugin import VectorTable
from .gui_utils import GuiUtils
-Ui_Dialog, _ = uic.loadUiType(GuiUtils.get_ui_file_path('DlgQueryBuilder.ui'))
+Ui_Dialog, _ = uic.loadUiType(GuiUtils.get_ui_file_path("DlgQueryBuilder.ui"))
class FocusEventFilter(QObject):
def __init__(self, parent):
QObject.__init__(self, parent)
- self.focus = ''
+ self.focus = ""
def eventFilter(self, obj, event):
if event.type() == QEvent.Type.FocusIn:
@@ -63,7 +63,7 @@ def __init__(self, iface, db, parent=None, reset=False):
QDialog.__init__(self, parent)
self.iface = iface
self.db = db
- self.query = ''
+ self.query = ""
self.ui = Ui_Dialog()
self.ui.setupUi(self)
self.ui.group.setMaximumHeight(self.ui.tab.sizeHint().height())
@@ -83,11 +83,11 @@ def __init__(self, iface, db, parent=None, reset=False):
self.coltables = []
self.ui.extract.setChecked(True)
# ComboBox default values
- self.ui.functions.insertItems(1, d['function'])
- self.ui.math.insertItems(1, d['math'])
- self.ui.aggregates.insertItems(1, d['aggregate'])
- self.ui.operators.insertItems(1, d['operator'])
- self.ui.stringfct.insertItems(1, d['string'])
+ self.ui.functions.insertItems(1, d["function"])
+ self.ui.math.insertItems(1, d["math"])
+ self.ui.aggregates.insertItems(1, d["aggregate"])
+ self.ui.operators.insertItems(1, d["operator"])
+ self.ui.stringfct.insertItems(1, d["string"])
# self.ui.Rtree.insertItems(1,rtreecommand)
# restore last query if needed
@@ -116,11 +116,19 @@ def __init__(self, iface, db, parent=None, reset=False):
self.ui.checkBox.stateChanged.connect(self.show_tables)
if self.db.explicitSpatialIndex():
- self.tablesGeo = [table for table in self.tables if isinstance(table, VectorTable)]
- tablesGeo = ['"%s"."%s"' % (table.name, table.geomColumn) for table in self.tablesGeo]
+ self.tablesGeo = [
+ table for table in self.tables if isinstance(table, VectorTable)
+ ]
+ tablesGeo = [
+ f'"{table.name}"."{table.geomColumn}"' for table in self.tablesGeo
+ ]
self.ui.table_target.insertItems(1, tablesGeo)
- self.idxTables = [table for table in self.tablesGeo if table.hasSpatialIndex()]
- idxTables = ['"%s"."%s"' % (table.name, table.geomColumn) for table in self.idxTables]
+ self.idxTables = [
+ table for table in self.tablesGeo if table.hasSpatialIndex()
+ ]
+ idxTables = [
+ f'"{table.name}"."{table.geomColumn}"' for table in self.idxTables
+ ]
self.ui.table_idx.insertItems(1, idxTables)
self.ui.usertree.clicked.connect(self.use_rtree)
@@ -199,16 +207,21 @@ def add_tables(self):
if len(tableObj) != 1:
return # No object with this name
self.table = tableObj[0]
- if (ag in self.coltables): # table already use
- response = QMessageBox.question(self, "Table already used", "Do you want to add table %s again?" % ag, QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No)
+ if ag in self.coltables: # table already use
+ response = QMessageBox.question(
+ self,
+ "Table already used",
+ "Do you want to add table %s again?" % ag,
+ QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No,
+ )
if response == QMessageBox.StandardButton.No:
return
ag = self.table.quotedName()
txt = self.ui.tab.text()
if (txt is None) or (txt in ("", " ")):
- self.ui.tab.setText('%s' % ag)
+ self.ui.tab.setText("%s" % ag)
else:
- self.ui.tab.setText('%s, %s' % (txt, ag))
+ self.ui.tab.setText(f"{txt}, {ag}")
self.ui.tables.setCurrentIndex(0)
def add_columns(self):
@@ -217,7 +230,12 @@ def add_columns(self):
ag = self.ui.columns.currentText()
if self.evt.focus == "where": # in where section
if ag in self.col_where: # column already called in where section
- response = QMessageBox.question(self, "Column already used in WHERE clause", "Do you want to add column %s again?" % ag, QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No)
+ response = QMessageBox.question(
+ self,
+ "Column already used in WHERE clause",
+ "Do you want to add column %s again?" % ag,
+ QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No,
+ )
if response == QMessageBox.StandardButton.No:
self.ui.columns.setCurrentIndex(0)
return
@@ -225,7 +243,12 @@ def add_columns(self):
self.col_where.append(ag)
elif self.evt.focus == "col":
if ag in self.col_col: # column already called in col section
- response = QMessageBox.question(self, "Column already used in COLUMNS section", "Do you want to add column %s again?" % ag, QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No)
+ response = QMessageBox.question(
+ self,
+ "Column already used in COLUMNS section",
+ "Do you want to add column %s again?" % ag,
+ QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No,
+ )
if response == QMessageBox.StandardButton.No:
self.ui.columns.setCurrentIndex(0)
return
@@ -249,12 +272,12 @@ def add_columns(self):
def list_cols(self):
table = self.table
- if (table is None):
+ if table is None:
return
- if (table.name in self.coltables):
+ if table.name in self.coltables:
return
- columns = ['"%s"."%s"' % (table.name, col.name) for col in table.fields()]
+ columns = [f'"{table.name}"."{col.name}"' for col in table.fields()]
# add special '*' column:
columns = ['"%s".*' % table.name] + columns
self.coltables.append(table.name) # table columns have been listed
@@ -273,11 +296,13 @@ def list_values(self):
# recover column and table:
column = item.split(".") # "table".'column'
table = column[0]
- if column[1] == '*':
+ if column[1] == "*":
return
table = table[1:-1]
- qtable = [t for t in self.tables if t.name.lower() == table.lower()][0].quotedName()
+ qtable = [t for t in self.tables if t.name.lower() == table.lower()][
+ 0
+ ].quotedName()
if self.ui.extract.isChecked():
limit = 10
@@ -290,14 +315,14 @@ def query_item(self, index):
value = index.data(Qt.ItemDataRole.EditRole)
if value is None:
- queryWord = 'NULL'
+ queryWord = "NULL"
elif isinstance(value, (int, float)):
queryWord = str(value)
else:
queryWord = self.db.connector.quoteString(value)
- if queryWord.strip() != '':
- self.ui.where.insertPlainText(' ' + queryWord)
+ if queryWord.strip() != "":
+ self.ui.where.insertPlainText(" " + queryWord)
self.ui.where.setFocus()
def use_rtree(self):
@@ -308,12 +333,17 @@ def use_rtree(self):
tab_idx = idx.split(".")[0][1:-1] # remove "
col_idx = idx.split(".")[1][1:-1] # remove '
except:
- QMessageBox.warning(self, "Use R-Tree", "All fields are necessary", QMessageBox.StandardButton.Cancel)
+ QMessageBox.warning(
+ self,
+ "Use R-Tree",
+ "All fields are necessary",
+ QMessageBox.StandardButton.Cancel,
+ )
tgt = self.ui.table_target.currentText()
if tgt in (None, "", " ", "Table (Target)"):
return
- tgt_tab = tgt.split('.')[0][1:-1]
- tgt_col = tgt.split('.')[1][1:-1]
+ tgt_tab = tgt.split(".")[0][1:-1]
+ tgt_col = tgt.split(".")[1][1:-1]
sql = ""
if self.ui.where.toPlainText() not in (None, "", " "):
sql += "\nAND"
@@ -337,15 +367,15 @@ def validate(self):
query_group = str(self.ui.group.toPlainText())
query_order = str(self.ui.order.toPlainText())
query = ""
- if query_col.strip() != '':
- query += "SELECT %s \nFROM %s" % (query_col, query_table)
- if query_where.strip() != '':
+ if query_col.strip() != "":
+ query += f"SELECT {query_col} \nFROM {query_table}"
+ if query_where.strip() != "":
query += "\nWHERE %s" % query_where
- if query_group.strip() != '':
+ if query_group.strip() != "":
query += "\nGROUP BY %s" % query_group
- if query_order.strip() != '':
+ if query_order.strip() != "":
query += "\nORDER BY %s" % query_order
- if query == '':
+ if query == "":
return
self.query = query
@@ -377,11 +407,15 @@ def restoreLastQuery(self):
# list previous colist:
for tablename in self.coltables:
# Retrieve table object from table name:
- table = [table for table in self.tables if table.name.upper() == tablename.upper()]
+ table = [
+ table
+ for table in self.tables
+ if table.name.upper() == tablename.upper()
+ ]
if len(table) != 1:
break
table = table[0]
- columns = ['"%s"."%s"' % (table.name, col.name) for col in table.fields()]
+ columns = [f'"{table.name}"."{col.name}"' for col in table.fields()]
# first and second col combobox
end = self.ui.columns.count()
self.ui.columns.insertItems(end, columns)
diff --git a/python/plugins/db_manager/dlg_sql_layer_window.py b/python/plugins/db_manager/dlg_sql_layer_window.py
index 25bd49a1b204..6d3b6fb07b36 100644
--- a/python/plugins/db_manager/dlg_sql_layer_window.py
+++ b/python/plugins/db_manager/dlg_sql_layer_window.py
@@ -19,33 +19,31 @@
* *
***************************************************************************/
"""
+
from hashlib import md5
from qgis.PyQt import uic
from qgis.PyQt.QtCore import Qt, pyqtSignal
-from qgis.PyQt.QtWidgets import (QDialog,
- QWidget,
- QAction,
- QApplication,
- QStyledItemDelegate,
- QMessageBox
- )
-from qgis.PyQt.QtGui import (QKeySequence,
- QCursor,
- QClipboard,
- QIcon,
- QStandardItemModel,
- QStandardItem
- )
+from qgis.PyQt.QtWidgets import (
+ QDialog,
+ QWidget,
+ QAction,
+ QApplication,
+ QStyledItemDelegate,
+ QMessageBox,
+)
+from qgis.PyQt.QtGui import (
+ QKeySequence,
+ QCursor,
+ QClipboard,
+ QIcon,
+ QStandardItemModel,
+ QStandardItem,
+)
from qgis.PyQt.Qsci import QsciAPIs
from qgis.PyQt.QtXml import QDomDocument
-from qgis.core import (
- QgsProject,
- QgsDataSourceUri,
- QgsReadWriteContext,
- QgsMapLayerType
-)
+from qgis.core import QgsProject, QgsDataSourceUri, QgsReadWriteContext, QgsMapLayerType
from qgis.utils import OverrideCursor
from .db_plugins import createDbPlugin
@@ -63,7 +61,7 @@
gui.QgsCodeEditorSQL = SqlEdit
-Ui_Dialog, _ = uic.loadUiType(GuiUtils.get_ui_file_path('DlgSqlLayerWindow.ui'))
+Ui_Dialog, _ = uic.loadUiType(GuiUtils.get_ui_file_path("DlgSqlLayerWindow.ui"))
import re
@@ -80,16 +78,16 @@ def __init__(self, iface, layer, parent=None):
uri = QgsDataSourceUri(layer.source())
dbplugin = None
db = None
- if layer.dataProvider().name() == 'postgres':
- dbplugin = createDbPlugin('postgis', 'postgres')
- elif layer.dataProvider().name() == 'spatialite':
- dbplugin = createDbPlugin('spatialite', 'spatialite')
- elif layer.dataProvider().name() == 'oracle':
- dbplugin = createDbPlugin('oracle', 'oracle')
- elif layer.dataProvider().name() == 'virtual':
- dbplugin = createDbPlugin('vlayers', 'virtual')
- elif layer.dataProvider().name() == 'ogr':
- dbplugin = createDbPlugin('gpkg', 'gpkg')
+ if layer.dataProvider().name() == "postgres":
+ dbplugin = createDbPlugin("postgis", "postgres")
+ elif layer.dataProvider().name() == "spatialite":
+ dbplugin = createDbPlugin("spatialite", "spatialite")
+ elif layer.dataProvider().name() == "oracle":
+ dbplugin = createDbPlugin("oracle", "oracle")
+ elif layer.dataProvider().name() == "virtual":
+ dbplugin = createDbPlugin("vlayers", "virtual")
+ elif layer.dataProvider().name() == "ogr":
+ dbplugin = createDbPlugin("gpkg", "gpkg")
if dbplugin:
dbplugin.connectToUri(uri)
db = dbplugin.db
@@ -97,13 +95,22 @@ def __init__(self, iface, layer, parent=None):
self.dbplugin = dbplugin
self.db = db
self.filter = ""
- self.allowMultiColumnPk = isinstance(db, PGDatabase) # at the moment only PostgreSQL allows a primary key to span multiple columns, SpatiaLite doesn't
- self.aliasSubQuery = isinstance(db, PGDatabase) # only PostgreSQL requires subqueries to be aliases
+ self.allowMultiColumnPk = isinstance(
+ db, PGDatabase
+ ) # at the moment only PostgreSQL allows a primary key to span multiple columns, SpatiaLite doesn't
+ self.aliasSubQuery = isinstance(
+ db, PGDatabase
+ ) # only PostgreSQL requires subqueries to be aliases
self.setupUi(self)
self.setWindowTitle(
- "%s - %s [%s]" % (self.windowTitle(), db.connection().connectionName(), db.connection().typeNameString()))
+ "{} - {} [{}]".format(
+ self.windowTitle(),
+ db.connection().connectionName(),
+ db.connection().typeNameString(),
+ )
+ )
- self.defaultLayerName = self.tr('QueryLayer')
+ self.defaultLayerName = self.tr("QueryLayer")
if self.allowMultiColumnPk:
self.uniqueColumnCheck.setText(self.tr("Column(s) with unique values"))
@@ -147,9 +154,12 @@ def __init__(self, iface, layer, parent=None):
self.uniqueCombo.setModel(self.uniqueModel)
if self.allowMultiColumnPk:
self.uniqueCombo.setItemDelegate(QStyledItemDelegate())
- self.uniqueModel.itemChanged.connect(self.uniqueChanged) # react to the (un)checking of an item
+ self.uniqueModel.itemChanged.connect(
+ self.uniqueChanged
+ ) # react to the (un)checking of an item
self.uniqueCombo.lineEdit().textChanged.connect(
- self.uniqueTextChanged) # there are other events that change the displayed text and some of them can not be caught directly
+ self.uniqueTextChanged
+ ) # there are other events that change the displayed text and some of them can not be caught directly
self.layerTypeWidget.hide() # show if load as raster is supported
# self.loadLayerBtn.clicked.connect(self.loadSqlLayer)
@@ -164,28 +174,36 @@ def __init__(self, iface, layer, parent=None):
# Update from layer
# First the SQL from QgsDataSourceUri table
- sql = uri.table().replace('\n', ' ').strip()
- if uri.keyColumn() == '_uid_':
- match = re.search(r'^\(SELECT .+ AS _uid_,\* FROM \((.*)\) AS _subq_.+_\s*\)$', sql, re.S | re.X | re.IGNORECASE)
+ sql = uri.table().replace("\n", " ").strip()
+ if uri.keyColumn() == "_uid_":
+ match = re.search(
+ r"^\(SELECT .+ AS _uid_,\* FROM \((.*)\) AS _subq_.+_\s*\)$",
+ sql,
+ re.S | re.X | re.IGNORECASE,
+ )
if match:
sql = match.group(1)
else:
- match = re.search(r'^\((SELECT .+ FROM .+)\)$', sql, re.S | re.X | re.IGNORECASE)
+ match = re.search(
+ r"^\((SELECT .+ FROM .+)\)$", sql, re.S | re.X | re.IGNORECASE
+ )
if match:
sql = match.group(1)
# Need to check on table() since the parentheses were removed by the regexp
- if not uri.table().startswith('(') and not uri.table().endswith(')'):
+ if not uri.table().startswith("(") and not uri.table().endswith(")"):
schema = uri.schema()
- if schema and schema.upper() != 'PUBLIC':
- sql = 'SELECT * FROM {}.{}'.format(self.db.connector.quoteId(schema), self.db.connector.quoteId(sql))
+ if schema and schema.upper() != "PUBLIC":
+ sql = f"SELECT * FROM {self.db.connector.quoteId(schema)}.{self.db.connector.quoteId(sql)}"
else:
- sql = 'SELECT * FROM {}'.format(self.db.connector.quoteId(sql))
+ sql = f"SELECT * FROM {self.db.connector.quoteId(sql)}"
self.editSql.setText(sql)
self.executeSql()
# Then the columns
- self.geomCombo.setCurrentIndex(self.geomCombo.findText(uri.geometryColumn(), Qt.MatchFlag.MatchExactly))
- if uri.keyColumn() != '_uid_':
+ self.geomCombo.setCurrentIndex(
+ self.geomCombo.findText(uri.geometryColumn(), Qt.MatchFlag.MatchExactly)
+ )
+ if uri.keyColumn() != "_uid_":
self.uniqueColumnCheck.setCheckState(Qt.CheckState.Checked)
if self.allowMultiColumnPk:
# Unchecked default values
@@ -193,7 +211,7 @@ def __init__(self, iface, layer, parent=None):
if item.checkState() == Qt.CheckState.Checked:
item.setCheckState(Qt.CheckState.Unchecked)
# Get key columns
- itemsData = uri.keyColumn().split(',')
+ itemsData = uri.keyColumn().split(",")
# Checked key columns
for keyColumn in itemsData:
for item in self.uniqueModel.findItems(keyColumn):
@@ -201,7 +219,9 @@ def __init__(self, iface, layer, parent=None):
else:
keyColumn = uri.keyColumn()
if self.uniqueModel.findItems(keyColumn):
- self.uniqueCombo.setCurrentIndex(self.uniqueCombo.findText(keyColumn, Qt.MatchFlag.MatchExactly))
+ self.uniqueCombo.setCurrentIndex(
+ self.uniqueCombo.findText(keyColumn, Qt.MatchFlag.MatchExactly)
+ )
# Finally layer name, filter and selectAtId
self.layerNameEdit.setText(layer.name())
@@ -210,21 +230,25 @@ def __init__(self, iface, layer, parent=None):
self.avoidSelectById.setCheckState(Qt.CheckState.Checked)
def getQueryHash(self, name):
- return 'q%s' % md5(name.encode('utf8')).hexdigest()
+ return "q%s" % md5(name.encode("utf8")).hexdigest()
def updatePresetButtonsState(self, *args):
"""Slot called when the combo box or the sql or the query name have changed:
- sets store button state"""
- self.presetStore.setEnabled(bool(self._getSqlQuery() and self.presetName.text()))
+ sets store button state"""
+ self.presetStore.setEnabled(
+ bool(self._getSqlQuery() and self.presetName.text())
+ )
self.presetDelete.setEnabled(bool(self.presetCombo.currentIndex() != -1))
def updatePresetsCombobox(self):
self.presetCombo.clear()
names = []
- entries = QgsProject.instance().subkeyList('DBManager', 'savedQueries')
+ entries = QgsProject.instance().subkeyList("DBManager", "savedQueries")
for entry in entries:
- name = QgsProject.instance().readEntry('DBManager', 'savedQueries/' + entry + '/name')[0]
+ name = QgsProject.instance().readEntry(
+ "DBManager", "savedQueries/" + entry + "/name"
+ )[0]
names.append(name)
for name in sorted(names):
@@ -236,8 +260,12 @@ def storePreset(self):
if query == "":
return
name = self.presetName.text()
- QgsProject.instance().writeEntry('DBManager', 'savedQueries/' + self.getQueryHash(name) + '/name', name)
- QgsProject.instance().writeEntry('DBManager', 'savedQueries/' + self.getQueryHash(name) + '/query', query)
+ QgsProject.instance().writeEntry(
+ "DBManager", "savedQueries/" + self.getQueryHash(name) + "/name", name
+ )
+ QgsProject.instance().writeEntry(
+ "DBManager", "savedQueries/" + self.getQueryHash(name) + "/query", query
+ )
index = self.presetCombo.findText(name)
if index == -1:
self.presetCombo.addItem(name)
@@ -247,12 +275,16 @@ def storePreset(self):
def deletePreset(self):
name = self.presetCombo.currentText()
- QgsProject.instance().removeEntry('DBManager', 'savedQueries/q' + self.getQueryHash(name))
+ QgsProject.instance().removeEntry(
+ "DBManager", "savedQueries/q" + self.getQueryHash(name)
+ )
self.presetCombo.removeItem(self.presetCombo.findText(name))
self.presetCombo.setCurrentIndex(-1)
def loadPreset(self, name):
- query = QgsProject.instance().readEntry('DBManager', 'savedQueries/' + self.getQueryHash(name) + '/query')[0]
+ query = QgsProject.instance().readEntry(
+ "DBManager", "savedQueries/" + self.getQueryHash(name) + "/query"
+ )[0]
self.editSql.setText(query)
def clearSql(self):
@@ -280,7 +312,11 @@ def executeSql(self):
# set the new model
model = self.db.sqlResultModel(sql, self)
self.viewResult.setModel(model)
- self.lblResult.setText(self.tr("{0} rows, {1:.3f} seconds").format(model.affectedRows(), model.secs()))
+ self.lblResult.setText(
+ self.tr("{0} rows, {1:.3f} seconds").format(
+ model.affectedRows(), model.secs()
+ )
+ )
cols = self.viewResult.model().columnNames()
for col in cols:
quotedCols.append(self.db.connector.quoteId(col))
@@ -310,7 +346,9 @@ def _getSqlLayer(self, _filter):
and not self.allowMultiColumnPk
and self.uniqueCombo.currentIndex() >= 0
):
- uniqueFieldName = self.uniqueModel.item(self.uniqueCombo.currentIndex()).data()
+ uniqueFieldName = self.uniqueModel.item(
+ self.uniqueCombo.currentIndex()
+ ).data()
else:
uniqueFieldName = None
hasGeomCol = self.hasGeometryCol.checkState() == Qt.CheckState.Checked
@@ -324,10 +362,14 @@ def _getSqlLayer(self, _filter):
return None
# remove a trailing ';' from query if present
- if query.strip().endswith(';'):
+ if query.strip().endswith(";"):
query = query.strip()[:-1]
- layerType = QgsMapLayerType.VectorLayer if self.vectorRadio.isChecked() else QgsMapLayerType.RasterLayer
+ layerType = (
+ QgsMapLayerType.VectorLayer
+ if self.vectorRadio.isChecked()
+ else QgsMapLayerType.RasterLayer
+ )
# get a new layer name
names = []
@@ -344,8 +386,15 @@ def _getSqlLayer(self, _filter):
newLayerName = "%s_%d" % (layerName, index)
# create the layer
- layer = self.db.toSqlLayer(query, geomFieldName, uniqueFieldName, newLayerName, layerType,
- self.avoidSelectById.isChecked(), _filter)
+ layer = self.db.toSqlLayer(
+ query,
+ geomFieldName,
+ uniqueFieldName,
+ newLayerName,
+ layerType,
+ self.avoidSelectById.isChecked(),
+ _filter,
+ )
if layer.isValid():
return layer
else:
@@ -371,7 +420,9 @@ def updateSqlLayer(self):
XMLMapLayers = XMLDocument.createElement("maplayers")
XMLMapLayer = XMLDocument.createElement("maplayer")
self.layer.writeLayerXml(XMLMapLayer, XMLDocument, QgsReadWriteContext())
- XMLMapLayer.firstChildElement("datasource").firstChild().setNodeValue(layer.source())
+ XMLMapLayer.firstChildElement("datasource").firstChild().setNodeValue(
+ layer.source()
+ )
XMLMapLayers.appendChild(XMLMapLayer)
XMLDocument.appendChild(XMLMapLayers)
self.layer.readLayerXml(XMLMapLayer, QgsReadWriteContext())
@@ -386,7 +437,7 @@ def fillColumnCombos(self):
with OverrideCursor(Qt.CursorShape.WaitCursor):
# remove a trailing ';' from query if present
- if query.strip().endswith(';'):
+ if query.strip().endswith(";"):
query = query.strip()[:-1]
# get all the columns
@@ -397,12 +448,14 @@ def fillColumnCombos(self):
aliasIndex = 0
while True:
alias = "_subQuery__%d" % aliasIndex
- escaped = re.compile('\\b("?)' + re.escape(alias) + '\\1\\b')
+ escaped = re.compile('\\b("?)' + re.escape(alias) + "\\1\\b")
if not escaped.search(query):
break
aliasIndex += 1
- sql = "SELECT * FROM (%s\n) AS %s LIMIT 0" % (str(query), connector.quoteId(alias))
+ sql = "SELECT * FROM ({}\n) AS {} LIMIT 0".format(
+ str(query), connector.quoteId(alias)
+ )
else:
sql = "SELECT * FROM (%s\n) WHERE 1=0" % str(query)
@@ -429,18 +482,20 @@ def fillColumnCombos(self):
def setColumnCombos(self, cols, quotedCols):
# get sensible default columns. do this before sorting in case there's hints in the column order (e.g., id is more likely to be first)
try:
- defaultGeomCol = next(col for col in cols if col in ['geom', 'geometry', 'the_geom', 'way'])
+ defaultGeomCol = next(
+ col for col in cols if col in ["geom", "geometry", "the_geom", "way"]
+ )
except:
defaultGeomCol = None
try:
- defaultUniqueCol = [col for col in cols if 'id' in col][0]
+ defaultUniqueCol = [col for col in cols if "id" in col][0]
except:
defaultUniqueCol = None
colNames = sorted(zip(cols, quotedCols))
newItems = []
uniqueIsFilled = False
- for (col, quotedCol) in colNames:
+ for col, quotedCol in colNames:
item = QStandardItem(col)
item.setData(quotedCol)
item.setEnabled(True)
@@ -450,7 +505,10 @@ def setColumnCombos(self, cols, quotedCols):
matchingItems = self.uniqueModel.findItems(col)
if matchingItems:
item.setCheckState(matchingItems[0].checkState())
- uniqueIsFilled = uniqueIsFilled or matchingItems[0].checkState() == Qt.CheckState.Checked
+ uniqueIsFilled = (
+ uniqueIsFilled
+ or matchingItems[0].checkState() == Qt.CheckState.Checked
+ )
else:
item.setCheckState(Qt.CheckState.Unchecked)
newItems.append(item)
@@ -469,7 +527,9 @@ def setColumnCombos(self, cols, quotedCols):
oldGeometryColumn = self.geomCombo.currentText()
self.geomCombo.clear()
self.geomCombo.addItems(cols)
- self.geomCombo.setCurrentIndex(self.geomCombo.findText(oldGeometryColumn, Qt.MatchFlag.MatchExactly))
+ self.geomCombo.setCurrentIndex(
+ self.geomCombo.findText(oldGeometryColumn, Qt.MatchFlag.MatchExactly)
+ )
# set sensible default columns if the columns are not already set
try:
@@ -550,6 +610,7 @@ def uniqueTextChanged(self, text):
def setFilter(self):
from qgis.gui import QgsQueryBuilder
+
layer = self._getSqlLayer("")
if not layer:
return
@@ -566,9 +627,14 @@ def setHasChanged(self, hasChanged):
def close(self):
if self.hasChanged:
ret = QMessageBox.question(
- self, self.tr('Unsaved Changes?'),
- self.tr('There are unsaved changes. Do you want to keep them?'),
- QMessageBox.StandardButton.Save | QMessageBox.StandardButton.Cancel | QMessageBox.StandardButton.Discard, QMessageBox.StandardButton.Cancel)
+ self,
+ self.tr("Unsaved Changes?"),
+ self.tr("There are unsaved changes. Do you want to keep them?"),
+ QMessageBox.StandardButton.Save
+ | QMessageBox.StandardButton.Cancel
+ | QMessageBox.StandardButton.Discard,
+ QMessageBox.StandardButton.Cancel,
+ )
if ret == QMessageBox.StandardButton.Save:
self.saveAsFilePreset()
diff --git a/python/plugins/db_manager/dlg_sql_window.py b/python/plugins/db_manager/dlg_sql_window.py
index 8109fa731ce3..fbf0f4c9fcb1 100644
--- a/python/plugins/db_manager/dlg_sql_window.py
+++ b/python/plugins/db_manager/dlg_sql_window.py
@@ -19,38 +19,35 @@
* *
***************************************************************************/
"""
+
from hashlib import md5
import os
from qgis.PyQt import uic
from qgis.PyQt.QtCore import Qt, pyqtSignal, QDir, QCoreApplication
-from qgis.PyQt.QtWidgets import (QDialog,
- QWidget,
- QAction,
- QApplication,
- QInputDialog,
- QStyledItemDelegate,
- QTableWidgetItem,
- QFileDialog,
- QMessageBox
- )
-from qgis.PyQt.QtGui import (QKeySequence,
- QCursor,
- QClipboard,
- QIcon,
- QStandardItemModel,
- QStandardItem
- )
+from qgis.PyQt.QtWidgets import (
+ QDialog,
+ QWidget,
+ QAction,
+ QApplication,
+ QInputDialog,
+ QStyledItemDelegate,
+ QTableWidgetItem,
+ QFileDialog,
+ QMessageBox,
+)
+from qgis.PyQt.QtGui import (
+ QKeySequence,
+ QCursor,
+ QClipboard,
+ QIcon,
+ QStandardItemModel,
+ QStandardItem,
+)
from qgis.PyQt.Qsci import QsciAPIs, QsciScintilla
-from qgis.core import (
- QgsProject,
- QgsApplication,
- QgsTask,
- QgsSettings,
- QgsMapLayerType
-)
+from qgis.core import QgsProject, QgsApplication, QgsTask, QgsSettings, QgsMapLayerType
from qgis.utils import OverrideCursor
from .db_plugins.plugin import BaseError
@@ -67,7 +64,7 @@
gui.QgsCodeEditorSQL = SqlEdit
-Ui_Dialog, _ = uic.loadUiType(GuiUtils.get_ui_file_path('DlgSqlWindow.ui'))
+Ui_Dialog, _ = uic.loadUiType(GuiUtils.get_ui_file_path("DlgSqlWindow.ui"))
import re
@@ -76,13 +73,10 @@
def check_comments_in_sql(raw_sql_input):
lines = []
for line in raw_sql_input.splitlines():
- if not line.strip().startswith('--'):
- if '--' in line:
- comments = re.finditer(r'--', line)
- comment_positions = [
- match.start()
- for match in comments
- ]
+ if not line.strip().startswith("--"):
+ if "--" in line:
+ comments = re.finditer(r"--", line)
+ comment_positions = [match.start() for match in comments]
identifiers = re.finditer(r'"(?:[^"]|"")*"', line)
quotes = re.finditer(r"'(?:[^']|'')*'", line)
quote_positions = []
@@ -96,12 +90,12 @@ def check_comments_in_sql(raw_sql_input):
if comment >= quote_position[0] and comment < quote_position[1]:
unquoted_comments.remove(comment)
if len(unquoted_comments) > 0:
- lines.append(line[:unquoted_comments[0]])
+ lines.append(line[: unquoted_comments[0]])
else:
lines.append(line)
else:
lines.append(line)
- sql = ' '.join(lines)
+ sql = " ".join(lines)
return sql.strip()
@@ -119,14 +113,20 @@ def __init__(self, iface, db, parent=None):
self.connectionName = db.connection().connectionName()
self.filter = ""
self.modelAsync = None
- self.allowMultiColumnPk = isinstance(db,
- PGDatabase) # at the moment only PostgreSQL allows a primary key to span multiple columns, SpatiaLite doesn't
- self.aliasSubQuery = isinstance(db, PGDatabase) # only PostgreSQL requires subqueries to be aliases
+ self.allowMultiColumnPk = isinstance(
+ db, PGDatabase
+ ) # at the moment only PostgreSQL allows a primary key to span multiple columns, SpatiaLite doesn't
+ self.aliasSubQuery = isinstance(
+ db, PGDatabase
+ ) # only PostgreSQL requires subqueries to be aliases
self.setupUi(self)
self.setWindowTitle(
- self.tr("{0} - {1} [{2}]").format(self.windowTitle(), self.connectionName, self.dbType))
+ self.tr("{0} - {1} [{2}]").format(
+ self.windowTitle(), self.connectionName, self.dbType
+ )
+ )
- self.defaultLayerName = self.tr('QueryLayer')
+ self.defaultLayerName = self.tr("QueryLayer")
if self.allowMultiColumnPk:
self.uniqueColumnCheck.setText(self.tr("Column(s) with unique values"))
@@ -140,7 +140,9 @@ def __init__(self, iface, db, parent=None):
self.editSql.textChanged.connect(lambda: self.setHasChanged(True))
settings = QgsSettings()
- self.history = settings.value('DB_Manager/queryHistory/' + self.dbType, {self.connectionName: []})
+ self.history = settings.value(
+ "DB_Manager/queryHistory/" + self.dbType, {self.connectionName: []}
+ )
if self.connectionName not in self.history:
self.history[self.connectionName] = []
@@ -188,9 +190,12 @@ def __init__(self, iface, db, parent=None):
self.uniqueCombo.setModel(self.uniqueModel)
if self.allowMultiColumnPk:
self.uniqueCombo.setItemDelegate(QStyledItemDelegate())
- self.uniqueModel.itemChanged.connect(self.uniqueChanged) # react to the (un)checking of an item
+ self.uniqueModel.itemChanged.connect(
+ self.uniqueChanged
+ ) # react to the (un)checking of an item
self.uniqueCombo.lineEdit().textChanged.connect(
- self.uniqueTextChanged) # there are other events that change the displayed text and some of them can not be caught directly
+ self.uniqueTextChanged
+ ) # there are other events that change the displayed text and some of them can not be caught directly
# hide the load query as layer if feature is not supported
self._loadAsLayerAvailable = self.db.connector.hasCustomQuerySupport()
@@ -230,9 +235,9 @@ def populateQueryHistory(self):
for i in range(len(dictlist)):
self.queryHistoryTableWidget.insertRow(0)
- queryItem = QTableWidgetItem(dictlist[i]['query'])
- rowsItem = QTableWidgetItem(str(dictlist[i]['rows']))
- durationItem = QTableWidgetItem(str(dictlist[i]['secs']))
+ queryItem = QTableWidgetItem(dictlist[i]["query"])
+ rowsItem = QTableWidgetItem(str(dictlist[i]["rows"]))
+ durationItem = QTableWidgetItem(str(dictlist[i]["secs"]))
self.queryHistoryTableWidget.setItem(0, 0, queryItem)
self.queryHistoryTableWidget.setItem(0, 1, rowsItem)
self.queryHistoryTableWidget.setItem(0, 2, durationItem)
@@ -245,23 +250,25 @@ def writeQueryHistory(self, sql, affectedRows, secs):
self.history[self.connectionName].pop(0)
settings = QgsSettings()
- self.history[self.connectionName].append({'query': sql,
- 'rows': affectedRows,
- 'secs': secs})
- settings.setValue('DB_Manager/queryHistory/' + self.dbType, self.history)
+ self.history[self.connectionName].append(
+ {"query": sql, "rows": affectedRows, "secs": secs}
+ )
+ settings.setValue("DB_Manager/queryHistory/" + self.dbType, self.history)
self.populateQueryHistory()
def getQueryHash(self, name):
- return 'q%s' % md5(name.encode('utf8')).hexdigest()
+ return "q%s" % md5(name.encode("utf8")).hexdigest()
def updatePresetsCombobox(self):
self.presetCombo.clear()
names = []
- entries = QgsProject.instance().subkeyList('DBManager', 'savedQueries')
+ entries = QgsProject.instance().subkeyList("DBManager", "savedQueries")
for entry in entries:
- name = QgsProject.instance().readEntry('DBManager', 'savedQueries/' + entry + '/name')[0]
+ name = QgsProject.instance().readEntry(
+ "DBManager", "savedQueries/" + entry + "/name"
+ )[0]
names.append(name)
for name in sorted(names):
@@ -273,8 +280,12 @@ def storePreset(self):
if query == "":
return
name = str(self.presetName.text())
- QgsProject.instance().writeEntry('DBManager', 'savedQueries/' + self.getQueryHash(name) + '/name', name)
- QgsProject.instance().writeEntry('DBManager', 'savedQueries/' + self.getQueryHash(name) + '/query', query)
+ QgsProject.instance().writeEntry(
+ "DBManager", "savedQueries/" + self.getQueryHash(name) + "/name", name
+ )
+ QgsProject.instance().writeEntry(
+ "DBManager", "savedQueries/" + self.getQueryHash(name) + "/query", query
+ )
index = self.presetCombo.findText(name)
if index == -1:
self.presetCombo.addItem(name)
@@ -284,36 +295,35 @@ def storePreset(self):
def saveAsFilePreset(self):
settings = QgsSettings()
- lastDir = settings.value('DB_Manager/lastDirSQLFIle', "")
+ lastDir = settings.value("DB_Manager/lastDirSQLFIle", "")
query = self.editSql.text()
if query == "":
return
filename, _ = QFileDialog.getSaveFileName(
- self,
- self.tr('Save SQL Query'),
- lastDir,
- self.tr("SQL File (*.sql *.SQL)"))
+ self, self.tr("Save SQL Query"), lastDir, self.tr("SQL File (*.sql *.SQL)")
+ )
if filename:
- if not filename.lower().endswith('.sql'):
+ if not filename.lower().endswith(".sql"):
filename += ".sql"
- with open(filename, 'w') as f:
+ with open(filename, "w") as f:
f.write(query)
lastDir = os.path.dirname(filename)
- settings.setValue('DB_Manager/lastDirSQLFile', lastDir)
+ settings.setValue("DB_Manager/lastDirSQLFile", lastDir)
def loadFilePreset(self):
settings = QgsSettings()
- lastDir = settings.value('DB_Manager/lastDirSQLFIle', "")
+ lastDir = settings.value("DB_Manager/lastDirSQLFIle", "")
filename, _ = QFileDialog.getOpenFileName(
self,
self.tr("Load SQL Query"),
lastDir,
- self.tr("SQL File (*.sql *.SQL);;All Files (*)"))
+ self.tr("SQL File (*.sql *.SQL);;All Files (*)"),
+ )
if filename:
with open(filename) as f:
@@ -321,16 +331,20 @@ def loadFilePreset(self):
for line in f:
self.editSql.insertText(line)
lastDir = os.path.dirname(filename)
- settings.setValue('DB_Manager/lastDirSQLFile', lastDir)
+ settings.setValue("DB_Manager/lastDirSQLFile", lastDir)
def deletePreset(self):
name = self.presetCombo.currentText()
- QgsProject.instance().removeEntry('DBManager', 'savedQueries/' + self.getQueryHash(name))
+ QgsProject.instance().removeEntry(
+ "DBManager", "savedQueries/" + self.getQueryHash(name)
+ )
self.presetCombo.removeItem(self.presetCombo.findText(name))
self.presetCombo.setCurrentIndex(-1)
def loadPreset(self, name):
- query = QgsProject.instance().readEntry('DBManager', 'savedQueries/' + self.getQueryHash(name) + '/query')[0]
+ query = QgsProject.instance().readEntry(
+ "DBManager", "savedQueries/" + self.getQueryHash(name) + "/query"
+ )[0]
self.editSql.setText(query)
def loadAsLayerToggled(self, checked):
@@ -391,16 +405,19 @@ def executeSqlCompleted(self):
model = self.modelAsync.model
self.showError(None)
self.viewResult.setModel(model)
- self.lblResult.setText(self.tr("{0} rows, {1:.3f} seconds").format(model.affectedRows(), model.secs()))
+ self.lblResult.setText(
+ self.tr("{0} rows, {1:.3f} seconds").format(
+ model.affectedRows(), model.secs()
+ )
+ )
cols = self.viewResult.model().columnNames()
- quotedCols = [
- self.db.connector.quoteId(col)
- for col in cols
- ]
+ quotedCols = [self.db.connector.quoteId(col) for col in cols]
self.setColumnCombos(cols, quotedCols)
- self.writeQueryHistory(self.modelAsync.task.sql, model.affectedRows(), model.secs())
+ self.writeQueryHistory(
+ self.modelAsync.task.sql, model.affectedRows(), model.secs()
+ )
self.update()
elif not self.modelAsync.canceled:
self.showError(self.modelAsync.error)
@@ -433,7 +450,7 @@ def executeSql(self):
return
def showError(self, error):
- '''Shows the error or hides it if error is None'''
+ """Shows the error or hides it if error is None"""
if error:
self.viewResult.setVisible(False)
self.errorText.setVisible(True)
@@ -456,7 +473,9 @@ def _getSqlLayer(self, _filter):
and not self.allowMultiColumnPk
and self.uniqueCombo.currentIndex() >= 0
):
- uniqueFieldName = self.uniqueModel.item(self.uniqueCombo.currentIndex()).data()
+ uniqueFieldName = self.uniqueModel.item(
+ self.uniqueCombo.currentIndex()
+ ).data()
else:
uniqueFieldName = None
hasGeomCol = self.hasGeometryCol.checkState() == Qt.CheckState.Checked
@@ -470,10 +489,14 @@ def _getSqlLayer(self, _filter):
return None
# remove a trailing ';' from query if present
- if query.strip().endswith(';'):
+ if query.strip().endswith(";"):
query = query.strip()[:-1]
- layerType = QgsMapLayerType.VectorLayer if self.vectorRadio.isChecked() else QgsMapLayerType.RasterLayer
+ layerType = (
+ QgsMapLayerType.VectorLayer
+ if self.vectorRadio.isChecked()
+ else QgsMapLayerType.RasterLayer
+ )
# get a new layer name
names = []
@@ -490,12 +513,23 @@ def _getSqlLayer(self, _filter):
newLayerName = "%s_%d" % (layerName, index)
# create the layer
- layer = self.db.toSqlLayer(query, geomFieldName, uniqueFieldName, newLayerName, layerType,
- self.avoidSelectById.isChecked(), _filter)
+ layer = self.db.toSqlLayer(
+ query,
+ geomFieldName,
+ uniqueFieldName,
+ newLayerName,
+ layerType,
+ self.avoidSelectById.isChecked(),
+ _filter,
+ )
if layer.isValid():
return layer
else:
- e = BaseError(self.tr("There was an error creating the SQL layer, please check the logs for further information."))
+ e = BaseError(
+ self.tr(
+ "There was an error creating the SQL layer, please check the logs for further information."
+ )
+ )
DlgDbError.showError(e, self)
return None
@@ -514,7 +548,7 @@ def fillColumnCombos(self):
with OverrideCursor(Qt.CursorShape.WaitCursor):
# remove a trailing ';' from query if present
- if query.strip().endswith(';'):
+ if query.strip().endswith(";"):
query = query.strip()[:-1]
# get all the columns
@@ -525,12 +559,14 @@ def fillColumnCombos(self):
aliasIndex = 0
while True:
alias = "_subQuery__%d" % aliasIndex
- escaped = re.compile('\\b("?)' + re.escape(alias) + '\\1\\b')
+ escaped = re.compile('\\b("?)' + re.escape(alias) + "\\1\\b")
if not escaped.search(query):
break
aliasIndex += 1
- sql = "SELECT * FROM (%s\n) AS %s LIMIT 0" % (str(query), connector.quoteId(alias))
+ sql = "SELECT * FROM ({}\n) AS {} LIMIT 0".format(
+ str(query), connector.quoteId(alias)
+ )
else:
sql = "SELECT * FROM (%s\n) WHERE 1=0" % str(query)
@@ -557,18 +593,20 @@ def fillColumnCombos(self):
def setColumnCombos(self, cols, quotedCols):
# get sensible default columns. do this before sorting in case there's hints in the column order (e.g., id is more likely to be first)
try:
- defaultGeomCol = next(col for col in cols if col in ['geom', 'geometry', 'the_geom', 'way'])
+ defaultGeomCol = next(
+ col for col in cols if col in ["geom", "geometry", "the_geom", "way"]
+ )
except:
defaultGeomCol = None
try:
- defaultUniqueCol = [col for col in cols if 'id' in col][0]
+ defaultUniqueCol = [col for col in cols if "id" in col][0]
except:
defaultUniqueCol = None
colNames = sorted(zip(cols, quotedCols))
newItems = []
uniqueIsFilled = False
- for (col, quotedCol) in colNames:
+ for col, quotedCol in colNames:
item = QStandardItem(col)
item.setData(quotedCol)
item.setEnabled(True)
@@ -578,7 +616,10 @@ def setColumnCombos(self, cols, quotedCols):
matchingItems = self.uniqueModel.findItems(col)
if matchingItems:
item.setCheckState(matchingItems[0].checkState())
- uniqueIsFilled = uniqueIsFilled or matchingItems[0].checkState() == Qt.CheckState.Checked
+ uniqueIsFilled = (
+ uniqueIsFilled
+ or matchingItems[0].checkState() == Qt.CheckState.Checked
+ )
else:
item.setCheckState(Qt.CheckState.Unchecked)
newItems.append(item)
@@ -597,7 +638,9 @@ def setColumnCombos(self, cols, quotedCols):
oldGeometryColumn = self.geomCombo.currentText()
self.geomCombo.clear()
self.geomCombo.addItems(cols)
- self.geomCombo.setCurrentIndex(self.geomCombo.findText(oldGeometryColumn, Qt.MatchFlag.MatchExactly))
+ self.geomCombo.setCurrentIndex(
+ self.geomCombo.findText(oldGeometryColumn, Qt.MatchFlag.MatchExactly)
+ )
# set sensible default columns if the columns are not already set
try:
@@ -655,7 +698,9 @@ def displayQueryBuilder(self):
self.editSql.setText(dlg.query)
def createView(self):
- name, ok = QInputDialog.getText(None, self.tr("View Name"), self.tr("View name"))
+ name, ok = QInputDialog.getText(
+ None, self.tr("View Name"), self.tr("View name")
+ )
if ok:
try:
self.db.connector.createSpatialView(name, self._getExecutableSqlQuery())
@@ -672,7 +717,7 @@ def _getExecutableSqlQuery(self):
sql = self._getSqlQuery().strip()
uncommented_sql = check_comments_in_sql(sql)
- uncommented_sql = uncommented_sql.rstrip(';')
+ uncommented_sql = uncommented_sql.rstrip(";")
return uncommented_sql
def uniqueChanged(self):
@@ -691,6 +736,7 @@ def uniqueTextChanged(self, text):
def setFilter(self):
from qgis.gui import QgsQueryBuilder
+
layer = self._getSqlLayer("")
if not layer:
return
@@ -707,9 +753,14 @@ def setHasChanged(self, hasChanged):
def close(self):
if self.hasChanged:
ret = QMessageBox.question(
- self, self.tr('Unsaved Changes?'),
- self.tr('There are unsaved changes. Do you want to keep them?'),
- QMessageBox.StandardButton.Save | QMessageBox.StandardButton.Cancel | QMessageBox.StandardButton.Discard, QMessageBox.StandardButton.Cancel)
+ self,
+ self.tr("Unsaved Changes?"),
+ self.tr("There are unsaved changes. Do you want to keep them?"),
+ QMessageBox.StandardButton.Save
+ | QMessageBox.StandardButton.Cancel
+ | QMessageBox.StandardButton.Discard,
+ QMessageBox.StandardButton.Cancel,
+ )
if ret == QMessageBox.StandardButton.Save:
self.saveAsFilePreset()
diff --git a/python/plugins/db_manager/dlg_table_properties.py b/python/plugins/db_manager/dlg_table_properties.py
index 36b9d7357162..879d712ac99e 100644
--- a/python/plugins/db_manager/dlg_table_properties.py
+++ b/python/plugins/db_manager/dlg_table_properties.py
@@ -26,7 +26,11 @@
from qgis.utils import OverrideCursor
-from .db_plugins.data_model import TableFieldsModel, TableConstraintsModel, TableIndexesModel
+from .db_plugins.data_model import (
+ TableFieldsModel,
+ TableConstraintsModel,
+ TableIndexesModel,
+)
from .db_plugins.plugin import BaseError, DbError
from .dlg_db_error import DlgDbError
@@ -37,7 +41,7 @@
from .gui_utils import GuiUtils
-Ui_Dialog, _ = uic.loadUiType(GuiUtils.get_ui_file_path('DlgTableProperties.ui'))
+Ui_Dialog, _ = uic.loadUiType(GuiUtils.get_ui_file_path("DlgTableProperties.ui"))
class DlgTableProperties(QDialog, Ui_Dialog):
@@ -95,8 +99,16 @@ def checkSupports(self):
self.btnEditColumn.setEnabled(allowEditColumns)
self.btnDeleteColumn.setEnabled(allowEditColumns)
- self.btnAddGeometryColumn.setEnabled(self.db.connector.canAddGeometryColumn((self.table.schemaName(), self.table.name)))
- self.btnAddSpatialIndex.setEnabled(self.db.connector.canAddSpatialIndex((self.table.schemaName(), self.table.name)))
+ self.btnAddGeometryColumn.setEnabled(
+ self.db.connector.canAddGeometryColumn(
+ (self.table.schemaName(), self.table.name)
+ )
+ )
+ self.btnAddSpatialIndex.setEnabled(
+ self.db.connector.canAddSpatialIndex(
+ (self.table.schemaName(), self.table.name)
+ )
+ )
def populateViews(self):
self.populateFields()
@@ -104,7 +116,7 @@ def populateViews(self):
self.populateIndexes()
def populateFields(self):
- """ load field information from database """
+ """load field information from database"""
m = self.viewFields.model()
m.clear()
@@ -115,16 +127,18 @@ def populateFields(self):
self.viewFields.resizeColumnToContents(col)
def currentColumn(self):
- """ returns row index of selected column """
+ """returns row index of selected column"""
sel = self.viewFields.selectionModel()
indexes = sel.selectedRows()
if len(indexes) == 0:
- QMessageBox.information(self, self.tr("DB Manager"), self.tr("No columns were selected."))
+ QMessageBox.information(
+ self, self.tr("DB Manager"), self.tr("No columns were selected.")
+ )
return -1
return indexes[0].row()
def addColumn(self):
- """ open dialog to set column info and add column to table """
+ """open dialog to set column info and add column to table"""
dlg = DlgFieldProperties(self, None, self.table)
if not dlg.exec():
return
@@ -140,14 +154,14 @@ def addColumn(self):
DlgDbError.showError(e, self)
def addGeometryColumn(self):
- """ open dialog to add geometry column """
+ """open dialog to add geometry column"""
dlg = DlgAddGeometryColumn(self, self.table)
if not dlg.exec():
return
self.refresh()
def editColumn(self):
- """ open dialog to change column info and alter table appropriately """
+ """open dialog to change column info and alter table appropriately"""
index = self.currentColumn()
if index == -1:
return
@@ -165,13 +179,19 @@ def editColumn(self):
with OverrideCursor(Qt.CursorShape.WaitCursor):
self.aboutToChangeTable.emit()
try:
- fld.update(new_fld.name, new_fld.type2String(), new_fld.notNull, new_fld.default2String(), new_fld.comment)
+ fld.update(
+ new_fld.name,
+ new_fld.type2String(),
+ new_fld.notNull,
+ new_fld.default2String(),
+ new_fld.comment,
+ )
self.refresh()
except BaseError as e:
DlgDbError.showError(e, self)
def deleteColumn(self):
- """Deletes currently selected column """
+ """Deletes currently selected column"""
index = self.currentColumn()
if index == -1:
return
@@ -179,9 +199,12 @@ def deleteColumn(self):
m = self.viewFields.model()
fld = m.getObject(index)
- res = QMessageBox.question(self, self.tr("Delete Column"),
- self.tr("Are you sure you want to delete column '{0}'?").format(fld.name),
- QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No)
+ res = QMessageBox.question(
+ self,
+ self.tr("Delete Column"),
+ self.tr("Are you sure you want to delete column '{0}'?").format(fld.name),
+ QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No,
+ )
if res != QMessageBox.StandardButton.Yes:
return
@@ -214,7 +237,7 @@ def hideConstraints(self):
self.tabs.setTabEnabled(index, False)
def addConstraint(self):
- """Adds primary key or unique constraint """
+ """Adds primary key or unique constraint"""
dlg = DlgCreateConstraint(self, self.table)
if not dlg.exec():
@@ -222,7 +245,7 @@ def addConstraint(self):
self.refresh()
def deleteConstraint(self):
- """Deletes a constraint """
+ """Deletes a constraint"""
index = self.currentConstraint()
if index == -1:
@@ -231,9 +254,14 @@ def deleteConstraint(self):
m = self.viewConstraints.model()
constr = m.getObject(index)
- res = QMessageBox.question(self, self.tr("Delete Constraint"),
- self.tr("Are you sure you want to delete constraint '{0}'?").format(constr.name),
- QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No)
+ res = QMessageBox.question(
+ self,
+ self.tr("Delete Constraint"),
+ self.tr("Are you sure you want to delete constraint '{0}'?").format(
+ constr.name
+ ),
+ QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No,
+ )
if res != QMessageBox.StandardButton.Yes:
return
@@ -246,11 +274,13 @@ def deleteConstraint(self):
DlgDbError.showError(e, self)
def currentConstraint(self):
- """ returns row index of selected index """
+ """returns row index of selected index"""
sel = self.viewConstraints.selectionModel()
indexes = sel.selectedRows()
if len(indexes) == 0:
- QMessageBox.information(self, self.tr("DB Manager"), self.tr("No constraints were selected."))
+ QMessageBox.information(
+ self, self.tr("DB Manager"), self.tr("No constraints were selected.")
+ )
return -1
return indexes[0].row()
@@ -275,21 +305,30 @@ def hideIndexes(self):
self.tabs.setTabEnabled(index, False)
def createIndex(self):
- """Creates an index """
+ """Creates an index"""
dlg = DlgCreateIndex(self, self.table)
if not dlg.exec():
return
self.refresh()
def createSpatialIndex(self):
- """Creates spatial index for the geometry column """
+ """Creates spatial index for the geometry column"""
if self.table.type != self.table.VectorType:
- QMessageBox.information(self, self.tr("DB Manager"), self.tr("The selected table has no geometry."))
+ QMessageBox.information(
+ self,
+ self.tr("DB Manager"),
+ self.tr("The selected table has no geometry."),
+ )
return
- res = QMessageBox.question(self, self.tr("Create Spatial Index"),
- self.tr("Create spatial index for field {0}?").format(self.table.geomColumn),
- QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No)
+ res = QMessageBox.question(
+ self,
+ self.tr("Create Spatial Index"),
+ self.tr("Create spatial index for field {0}?").format(
+ self.table.geomColumn
+ ),
+ QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No,
+ )
if res != QMessageBox.StandardButton.Yes:
return
@@ -304,16 +343,18 @@ def createSpatialIndex(self):
DlgDbError.showError(e, self)
def currentIndex(self):
- """ returns row index of selected index """
+ """returns row index of selected index"""
sel = self.viewIndexes.selectionModel()
indexes = sel.selectedRows()
if len(indexes) == 0:
- QMessageBox.information(self, self.tr("DB Manager"), self.tr("No indices were selected."))
+ QMessageBox.information(
+ self, self.tr("DB Manager"), self.tr("No indices were selected.")
+ )
return -1
return indexes[0].row()
def deleteIndex(self):
- """Deletes currently selected index """
+ """Deletes currently selected index"""
index = self.currentIndex()
if index == -1:
return
@@ -321,9 +362,12 @@ def deleteIndex(self):
m = self.viewIndexes.model()
idx = m.getObject(index)
- res = QMessageBox.question(self, self.tr("Delete Index"),
- self.tr("Are you sure you want to delete index '{0}'?").format(idx.name),
- QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No)
+ res = QMessageBox.question(
+ self,
+ self.tr("Delete Index"),
+ self.tr("Are you sure you want to delete index '{0}'?").format(idx.name),
+ QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No,
+ )
if res != QMessageBox.StandardButton.Yes:
return
@@ -347,7 +391,9 @@ def createComment(self):
return
self.refresh()
# Display successful message
- QMessageBox.information(self, self.tr("Add comment"), self.tr("Table successfully commented"))
+ QMessageBox.information(
+ self, self.tr("Add comment"), self.tr("Table successfully commented")
+ )
def deleteComment(self):
"""Drops the comment on the selected table"""
@@ -360,6 +406,8 @@ def deleteComment(self):
return
self.refresh()
# Refresh line edit, put a void comment
- self.viewComment.setText('')
+ self.viewComment.setText("")
# Display successful message
- QMessageBox.information(self, self.tr("Delete comment"), self.tr("Comment deleted"))
+ QMessageBox.information(
+ self, self.tr("Delete comment"), self.tr("Comment deleted")
+ )
diff --git a/python/plugins/db_manager/gui_utils.py b/python/plugins/db_manager/gui_utils.py
index 2d9994538568..b0b169f4a0a4 100644
--- a/python/plugins/db_manager/gui_utils.py
+++ b/python/plugins/db_manager/gui_utils.py
@@ -14,11 +14,7 @@
import os
from typing import Optional, Dict
-from qgis.PyQt.QtGui import (
- QIcon,
- QImage,
- QPixmap
-)
+from qgis.PyQt.QtGui import QIcon, QImage, QPixmap
class GuiUtils:
@@ -26,7 +22,7 @@ class GuiUtils:
Utilities for GUI plugin components
"""
- ICON_CACHE: Dict[str, QIcon] = {}
+ ICON_CACHE: dict[str, QIcon] = {}
@staticmethod
def get_icon(icon: str) -> QIcon:
@@ -62,12 +58,9 @@ def get_icon_svg(icon: str) -> str:
:param icon: icon name (base part of file name)
:return: icon svg path
"""
- path = os.path.join(
- os.path.dirname(__file__),
- 'icons',
- icon + '.svg')
+ path = os.path.join(os.path.dirname(__file__), "icons", icon + ".svg")
if not os.path.exists(path):
- return ''
+ return ""
return path
@@ -76,11 +69,8 @@ def get_pixmap_path(icon: str) -> Optional[str]:
"""
Returns the path to a pixmap icon
"""
- for suffix in ('.png', '.gif', '.xpm'):
- path = os.path.join(
- os.path.dirname(__file__),
- 'icons',
- icon + suffix)
+ for suffix in (".png", ".gif", ".xpm"):
+ path = os.path.join(os.path.dirname(__file__), "icons", icon + suffix)
if os.path.exists(path):
return path
@@ -107,11 +97,8 @@ def get_ui_file_path(file: str) -> str:
:param file: file name (uifile name)
:return: ui file path
"""
- path = os.path.join(
- os.path.dirname(__file__),
- 'ui',
- file)
+ path = os.path.join(os.path.dirname(__file__), "ui", file)
if not os.path.exists(path):
- return ''
+ return ""
return path
diff --git a/python/plugins/db_manager/info_viewer.py b/python/plugins/db_manager/info_viewer.py
index 67d0c6730974..567c959a9b2c 100644
--- a/python/plugins/db_manager/info_viewer.py
+++ b/python/plugins/db_manager/info_viewer.py
@@ -95,14 +95,21 @@ def _clear(self):
def _showPluginInfo(self):
from .db_plugins import getDbPluginErrors
- html = '
' + self.tr("DB Manager") + ' '
+ html = (
+ '
'
+ + self.tr("DB Manager")
+ + " "
+ )
html += ''
for msg in getDbPluginErrors():
html += "
%s" % msg
self.setHtml(html)
def _showDatabaseInfo(self, connection):
- html = '
%s ' % connection.connectionName()
+ html = (
+ '
%s '
+ % connection.connectionName()
+ )
html += '
'
try:
if connection.database() is None:
@@ -110,38 +117,47 @@ def _showDatabaseInfo(self, connection):
else:
html += connection.database().info().toHtml()
except DbError as e:
- html += '
%s
' % str(e).replace('\n', '
')
- html += '
'
+ html += '
%s
' % str(e).replace("\n", "
")
+ html += "
"
self.setHtml(html)
def _showSchemaInfo(self, schema):
- html = '
%s ' % schema.name
+ html = (
+ '
%s '
+ % schema.name
+ )
html += ''
try:
html += schema.info().toHtml()
except DbError as e:
- html += '
%s
' % str(e).replace('\n', '
')
+ html += '
%s
' % str(e).replace("\n", "
")
html += "
"
self.setHtml(html)
def _showTableInfo(self, table):
- html = '
%s ' % table.name
+ html = (
+ '
%s '
+ % table.name
+ )
html += ''
try:
html += table.info().toHtml()
except DbError as e:
- html += '
%s
' % str(e).replace('\n', '
')
- html += '
'
+ html += '%s
' % str(e).replace("\n", " ")
+ html += ""
self.setHtml(html)
return True
def setHtml(self, html):
# convert special tags
- warning_icon_path = GuiUtils.get_pixmap_path('warning-20px')
- html = str(html).replace('', f' ')
+ warning_icon_path = GuiUtils.get_pixmap_path("warning-20px")
+ html = str(html).replace(
+ "", f' '
+ )
# add default style
- html = """
+ html = (
+ """
@@ -158,7 +174,9 @@ def setHtml(self, html):
%s
-""" % html
+"""
+ % html
+ )
# print(">>>>>\n", html, "\n<<<<<<")
return QTextBrowser.setHtml(self, html)
diff --git a/python/plugins/db_manager/layer_preview.py b/python/plugins/db_manager/layer_preview.py
index 04ddcff975d9..02afb303331b 100644
--- a/python/plugins/db_manager/layer_preview.py
+++ b/python/plugins/db_manager/layer_preview.py
@@ -42,7 +42,9 @@ def __init__(self, parent=None):
# reuse settings from QGIS
settings = QgsSettings()
- self.enableAntiAliasing(settings.value("/qgis/enable_anti_aliasing", False, type=bool))
+ self.enableAntiAliasing(
+ settings.value("/qgis/enable_anti_aliasing", False, type=bool)
+ )
zoomFactor = settings.value("/qgis/zoom_factor", 2, type=float)
self.setWheelFactor(zoomFactor)
@@ -59,7 +61,10 @@ def loadPreview(self, item):
self._clear()
- if isinstance(item, Table) and item.type in [Table.VectorType, Table.RasterType]:
+ if isinstance(item, Table) and item.type in [
+ Table.VectorType,
+ Table.RasterType,
+ ]:
# update the preview, but first let the manager chance to show the canvas
def runPrev():
return self._loadTablePreview(item)
@@ -75,7 +80,7 @@ def setDirty(self, val=True):
self.dirty = val
def _clear(self):
- """ remove any layers from preview canvas """
+ """remove any layers from preview canvas"""
if self.item is not None:
# skip exception on RuntimeError fixes #6892
try:
@@ -88,7 +93,7 @@ def _clear(self):
self._loadTablePreview(None)
def _loadTablePreview(self, table, limit=False):
- """ if has geometry column load to map canvas """
+ """if has geometry column load to map canvas"""
with OverrideCursor(Qt.CursorShape.WaitCursor):
self.freeze()
vl = None
@@ -100,13 +105,22 @@ def _loadTablePreview(self, table, limit=False):
if uniqueField is None:
self.parent.tabs.setCurrentWidget(self.parent.info)
self.parent.infoBar.pushMessage(
- QApplication.translate("DBManagerPlugin", "Unable to find a valid unique field"),
- Qgis.MessageLevel.Warning, self.parent.iface.messageTimeout())
+ QApplication.translate(
+ "DBManagerPlugin", "Unable to find a valid unique field"
+ ),
+ Qgis.MessageLevel.Warning,
+ self.parent.iface.messageTimeout(),
+ )
return
uri = table.database().uri()
- uri.setDataSource("", "(SELECT * FROM %s LIMIT 1000)" % table.quotedName(), table.geomColumn, "",
- uniqueField.name)
+ uri.setDataSource(
+ "",
+ "(SELECT * FROM %s LIMIT 1000)" % table.quotedName(),
+ table.geomColumn,
+ "",
+ uniqueField.name,
+ )
provider = table.database().dbplugin().providerName()
vl = QgsVectorLayer(uri.uri(False), table.name, provider)
else:
diff --git a/python/plugins/db_manager/sql_dictionary.py b/python/plugins/db_manager/sql_dictionary.py
index e22449dffa21..3bdf96e93b9c 100644
--- a/python/plugins/db_manager/sql_dictionary.py
+++ b/python/plugins/db_manager/sql_dictionary.py
@@ -15,36 +15,149 @@
***************************************************************************
"""
-__author__ = 'Giuseppe Sucameli'
-__date__ = 'April 2012'
-__copyright__ = '(C) 2012, Giuseppe Sucameli'
+__author__ = "Giuseppe Sucameli"
+__date__ = "April 2012"
+__copyright__ = "(C) 2012, Giuseppe Sucameli"
# GENERIC SQL DICTIONARY
# keywords
keywords = [
- "action", "add", "after", "all", "alter", "analyze", "and", "as", "asc",
- "before", "begin", "between", "by", "cascade", "case", "cast", "check",
- "collate", "column", "commit", "constraint", "create", "cross", "current_date",
- "current_time", "current_timestamp", "default", "deferrable", "deferred",
- "delete", "desc", "distinct", "drop", "each", "else", "end", "escape",
- "except", "exists", "for", "foreign", "from", "full", "group", "having",
- "ignore", "immediate", "in", "initially", "inner", "insert", "intersect",
- "into", "is", "isnull", "join", "key", "left", "like", "limit", "match",
- "natural", "no", "not", "notnull", "null", "of", "offset", "on", "or", "order",
- "outer", "primary", "references", "release", "restrict", "right", "rollback",
- "row", "savepoint", "select", "set", "table", "temporary", "then", "to",
- "transaction", "trigger", "union", "unique", "update", "using", "values",
- "view", "when", "where"
+ "action",
+ "add",
+ "after",
+ "all",
+ "alter",
+ "analyze",
+ "and",
+ "as",
+ "asc",
+ "before",
+ "begin",
+ "between",
+ "by",
+ "cascade",
+ "case",
+ "cast",
+ "check",
+ "collate",
+ "column",
+ "commit",
+ "constraint",
+ "create",
+ "cross",
+ "current_date",
+ "current_time",
+ "current_timestamp",
+ "default",
+ "deferrable",
+ "deferred",
+ "delete",
+ "desc",
+ "distinct",
+ "drop",
+ "each",
+ "else",
+ "end",
+ "escape",
+ "except",
+ "exists",
+ "for",
+ "foreign",
+ "from",
+ "full",
+ "group",
+ "having",
+ "ignore",
+ "immediate",
+ "in",
+ "initially",
+ "inner",
+ "insert",
+ "intersect",
+ "into",
+ "is",
+ "isnull",
+ "join",
+ "key",
+ "left",
+ "like",
+ "limit",
+ "match",
+ "natural",
+ "no",
+ "not",
+ "notnull",
+ "null",
+ "of",
+ "offset",
+ "on",
+ "or",
+ "order",
+ "outer",
+ "primary",
+ "references",
+ "release",
+ "restrict",
+ "right",
+ "rollback",
+ "row",
+ "savepoint",
+ "select",
+ "set",
+ "table",
+ "temporary",
+ "then",
+ "to",
+ "transaction",
+ "trigger",
+ "union",
+ "unique",
+ "update",
+ "using",
+ "values",
+ "view",
+ "when",
+ "where",
]
# functions
functions = [
- "abs", "changes", "coalesce", "glob", "ifnull", "hex", "last_insert_rowid",
- "length", "like", "lower", "ltrim", "max", "min", "nullif", "quote", "random",
- "randomblob", "replace", "round", "rtrim", "soundex", "total_change", "trim",
- "typeof", "upper", "zeroblob", "date", "datetime", "julianday", "strftime",
- "avg", "count", "group_concat", "sum", "total"
+ "abs",
+ "changes",
+ "coalesce",
+ "glob",
+ "ifnull",
+ "hex",
+ "last_insert_rowid",
+ "length",
+ "like",
+ "lower",
+ "ltrim",
+ "max",
+ "min",
+ "nullif",
+ "quote",
+ "random",
+ "randomblob",
+ "replace",
+ "round",
+ "rtrim",
+ "soundex",
+ "total_change",
+ "trim",
+ "typeof",
+ "upper",
+ "zeroblob",
+ "date",
+ "datetime",
+ "julianday",
+ "strftime",
+ "avg",
+ "count",
+ "group_concat",
+ "sum",
+ "total",
]
# constants
@@ -52,4 +165,8 @@
def getSqlDictionary():
- return {'keyword': list(keywords), 'constant': list(constants), 'function': list(functions)}
+ return {
+ "keyword": list(keywords),
+ "constant": list(constants),
+ "function": list(functions),
+ }
diff --git a/python/plugins/db_manager/sqledit.py b/python/plugins/db_manager/sqledit.py
index 9b9067d6e4c1..deb78274ff77 100644
--- a/python/plugins/db_manager/sqledit.py
+++ b/python/plugins/db_manager/sqledit.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Alexander Bruy'
-__date__ = 'February 2014'
-__copyright__ = '(C) 2014, Alexander Bruy'
+__author__ = "Alexander Bruy"
+__date__ = "February 2014"
+__copyright__ = "(C) 2014, Alexander Bruy"
from qgis.PyQt.QtCore import Qt
from qgis.PyQt.QtGui import QColor, QFont, QKeySequence
@@ -45,7 +45,7 @@ def setCommonOptions(self):
# Default font
font = QFont()
- font.setFamily('Courier')
+ font.setFamily("Courier")
font.setFixedPitch(True)
font.setPointSize(10)
self.setFont(font)
@@ -54,30 +54,33 @@ def setCommonOptions(self):
self.setBraceMatching(QsciScintilla.BraceMatch.SloppyBraceMatch)
self.setWrapMode(QsciScintilla.WrapMode.WrapWord)
- self.setWrapVisualFlags(QsciScintilla.WrapVisualFlag.WrapFlagByText,
- QsciScintilla.WrapVisualFlag.WrapFlagNone, 4)
+ self.setWrapVisualFlags(
+ QsciScintilla.WrapVisualFlag.WrapFlagByText,
+ QsciScintilla.WrapVisualFlag.WrapFlagNone,
+ 4,
+ )
- self.setSelectionForegroundColor(QColor('#2e3436'))
- self.setSelectionBackgroundColor(QColor('#babdb6'))
+ self.setSelectionForegroundColor(QColor("#2e3436"))
+ self.setSelectionBackgroundColor(QColor("#babdb6"))
# Show line numbers
- self.setMarginWidth(1, '000')
+ self.setMarginWidth(1, "000")
self.setMarginLineNumbers(1, True)
- self.setMarginsForegroundColor(QColor('#2e3436'))
- self.setMarginsBackgroundColor(QColor('#babdb6'))
+ self.setMarginsForegroundColor(QColor("#2e3436"))
+ self.setMarginsBackgroundColor(QColor("#babdb6"))
# Highlight current line
self.setCaretLineVisible(True)
- self.setCaretLineBackgroundColor(QColor('#d3d7cf'))
+ self.setCaretLineBackgroundColor(QColor("#d3d7cf"))
# Folding
self.setFolding(QsciScintilla.FoldStyle.BoxedTreeFoldStyle)
- self.setFoldMarginColors(QColor('#d3d7cf'), QColor('#d3d7cf'))
+ self.setFoldMarginColors(QColor("#d3d7cf"), QColor("#d3d7cf"))
# Mark column 80 with vertical line
self.setEdgeMode(QsciScintilla.EdgeMode.EdgeLine)
self.setEdgeColumn(80)
- self.setEdgeColor(QColor('#eeeeec'))
+ self.setEdgeColor(QColor("#eeeeec"))
# Indentation
self.setAutoIndent(True)
@@ -94,8 +97,8 @@ def setCommonOptions(self):
# Load font from Python console settings
settings = QgsSettings()
- fontName = settings.value('pythonConsole/fontfamilytext', 'Monospace')
- fontSize = int(settings.value('pythonConsole/fontsize', 10))
+ fontName = settings.value("pythonConsole/fontfamilytext", "Monospace")
+ fontSize = int(settings.value("pythonConsole/fontsize", 10))
self.defaultFont = QFont(fontName)
self.defaultFont.setFixedPitch(True)
@@ -118,18 +121,18 @@ def initShortcuts(self):
(ctrl, shift) = (self.SCMOD_CTRL << 16, self.SCMOD_SHIFT << 16)
# Disable some shortcuts
- self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('D') + ctrl)
- self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('L') + ctrl)
- self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('L') + ctrl +
- shift)
- self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('T') + ctrl)
+ self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord("D") + ctrl)
+ self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord("L") + ctrl)
+ self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord("L") + ctrl + shift)
+ self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord("T") + ctrl)
# self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord("Z") + ctrl)
# self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord("Y") + ctrl)
# Use Ctrl+Space for autocompletion
- self.shortcutAutocomplete = QShortcut(QKeySequence(Qt.Modifier.CTRL +
- Qt.Key.Key_Space), self)
+ self.shortcutAutocomplete = QShortcut(
+ QKeySequence(Qt.Modifier.CTRL + Qt.Key.Key_Space), self
+ )
self.shortcutAutocomplete.setContext(Qt.ShortcutContext.WidgetShortcut)
self.shortcutAutocomplete.activated.connect(self.autoComplete)
@@ -139,13 +142,13 @@ def autoComplete(self):
def initLexer(self):
self.mylexer = QsciLexerSQL()
- colorDefault = QColor('#2e3436')
- colorComment = QColor('#c00')
- colorCommentBlock = QColor('#3465a4')
- colorNumber = QColor('#4e9a06')
- colorType = QColor('#4e9a06')
- colorKeyword = QColor('#204a87')
- colorString = QColor('#ce5c00')
+ colorDefault = QColor("#2e3436")
+ colorComment = QColor("#c00")
+ colorCommentBlock = QColor("#3465a4")
+ colorNumber = QColor("#4e9a06")
+ colorType = QColor("#4e9a06")
+ colorKeyword = QColor("#204a87")
+ colorString = QColor("#ce5c00")
self.mylexer.setDefaultFont(self.defaultFont)
self.mylexer.setDefaultColor(colorDefault)
diff --git a/python/plugins/grassprovider/__init__.py b/python/plugins/grassprovider/__init__.py
index 9af45507fb6d..42e27a6b6e70 100644
--- a/python/plugins/grassprovider/__init__.py
+++ b/python/plugins/grassprovider/__init__.py
@@ -15,11 +15,12 @@
***************************************************************************
"""
-__author__ = 'Alexander Bruy'
-__date__ = 'June 2021'
-__copyright__ = '(C) 2021, Alexander Bruy'
+__author__ = "Alexander Bruy"
+__date__ = "June 2021"
+__copyright__ = "(C) 2021, Alexander Bruy"
def classFactory(iface):
from grassprovider.grass_plugin import GrassProviderPlugin
+
return GrassProviderPlugin()
diff --git a/python/plugins/grassprovider/description_to_json.py b/python/plugins/grassprovider/description_to_json.py
index 08038d600c62..d90067f0b0d6 100644
--- a/python/plugins/grassprovider/description_to_json.py
+++ b/python/plugins/grassprovider/description_to_json.py
@@ -19,32 +19,34 @@
def main(description_folder: str, output_file: str):
- from .parsed_description import (
- ParsedDescription
- )
+ from .parsed_description import ParsedDescription
algorithms = []
folder = Path(description_folder)
- for description_file in folder.glob('*.txt'):
+ for description_file in folder.glob("*.txt"):
description = ParsedDescription.parse_description_file(
- description_file, translate=False)
+ description_file, translate=False
+ )
ext_path = description_file.parents[1].joinpath(
- 'ext', description.name.replace('.', '_') + '.py')
+ "ext", description.name.replace(".", "_") + ".py"
+ )
if ext_path.exists():
- description.ext_path = description.name.replace('.', '_')
+ description.ext_path = description.name.replace(".", "_")
algorithms.append(description.as_dict())
Path(output_file).parent.mkdir(parents=True, exist_ok=True)
- with open(output_file, 'wt', encoding='utf8') as f_out:
+ with open(output_file, "w", encoding="utf8") as f_out:
f_out.write(json.dumps(algorithms, indent=2))
-parser = argparse.ArgumentParser(description="Parses GRASS .txt algorithm "
- "description files and builds "
- "aggregated .json description")
+parser = argparse.ArgumentParser(
+ description="Parses GRASS .txt algorithm "
+ "description files and builds "
+ "aggregated .json description"
+)
parser.add_argument("input", help="Path to the description directory")
parser.add_argument("output", help="Path to the output algorithms.json file")
diff --git a/python/plugins/grassprovider/ext/g_extension_list.py b/python/plugins/grassprovider/ext/g_extension_list.py
index 263a173d9b47..9024e98c4d88 100644
--- a/python/plugins/grassprovider/ext/g_extension_list.py
+++ b/python/plugins/grassprovider/ext/g_extension_list.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Alister Hood'
-__date__ = 'May 2023'
-__copyright__ = '(C) 2023, Alister Hood'
+__author__ = "Alister Hood"
+__date__ = "May 2023"
+__copyright__ = "(C) 2023, Alister Hood"
from qgis.core import QgsProcessingParameterBoolean
@@ -25,26 +25,26 @@
def processInputs(alg, parameters, context, feedback):
# get the option we want to run
# we would need to update the if statements below if the order in the description file is changed
- selectedOption = alg.parameterAsInt(parameters, 'list', context)
+ selectedOption = alg.parameterAsInt(parameters, "list", context)
# Locally installed extensions
if selectedOption == 0:
- optionString = '-a'
+ optionString = "-a"
# Extensions available in the official GRASS GIS Addons repository
elif selectedOption == 1:
- optionString = '-l'
+ optionString = "-l"
# Extensions available in the official GRASS GIS Addons repository including module description
else:
- optionString = '-c'
- param = QgsProcessingParameterBoolean(optionString, '', True)
+ optionString = "-c"
+ param = QgsProcessingParameterBoolean(optionString, "", True)
alg.addParameter(param)
# Don't forget to remove the old input parameter
- alg.removeParameter('list')
+ alg.removeParameter("list")
def convertToHtml(alg, fileName, outputs):
# don't copy this for something that will have lots of data like r.stats
# it will be very slow
- with open(fileName, 'r') as f:
- outputs['GRASS_ADDONS'] = f.read()
+ with open(fileName) as f:
+ outputs["GRASS_ADDONS"] = f.read()
# this will read the file a second time, but calling it saves us duplicating the code here
alg.convertToHtml(fileName)
diff --git a/python/plugins/grassprovider/ext/g_extension_manage.py b/python/plugins/grassprovider/ext/g_extension_manage.py
index 51893b1de21d..d69cd49d7dfe 100644
--- a/python/plugins/grassprovider/ext/g_extension_manage.py
+++ b/python/plugins/grassprovider/ext/g_extension_manage.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Alister Hood'
-__date__ = 'May 2023'
-__copyright__ = '(C) 2023, Alister Hood'
+__author__ = "Alister Hood"
+__date__ = "May 2023"
+__copyright__ = "(C) 2023, Alister Hood"
def processInputs(alg, parameters, context, feedback):
diff --git a/python/plugins/grassprovider/ext/g_version.py b/python/plugins/grassprovider/ext/g_version.py
index 6fbd09ffc1f2..3d44d5102e04 100644
--- a/python/plugins/grassprovider/ext/g_version.py
+++ b/python/plugins/grassprovider/ext/g_version.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Alister Hood'
-__date__ = 'May 2023'
-__copyright__ = '(C) 2023, Alister Hood'
+__author__ = "Alister Hood"
+__date__ = "May 2023"
+__copyright__ = "(C) 2023, Alister Hood"
def processInputs(alg, parameters, context, feedback):
@@ -27,7 +27,7 @@ def processInputs(alg, parameters, context, feedback):
def convertToHtml(alg, fileName, outputs):
# don't copy this for something that will have lots of data like r.stats
# it will be very slow
- with open(fileName, 'r') as f:
- outputs['GRASS_VERSIONINFO'] = f.read()
+ with open(fileName) as f:
+ outputs["GRASS_VERSIONINFO"] = f.read()
# this will read the file a second time, but calling it saves us duplicating the code here
alg.convertToHtml(fileName)
diff --git a/python/plugins/grassprovider/ext/i.py b/python/plugins/grassprovider/ext/i.py
index 226eda04fc1d..51225470445f 100644
--- a/python/plugins/grassprovider/ext/i.py
+++ b/python/plugins/grassprovider/ext/i.py
@@ -15,12 +15,12 @@
***************************************************************************
"""
-__author__ = 'Médéric Ribreux'
-__date__ = 'April 2016'
-__copyright__ = '(C) 2016, Médéric Ribreux'
+__author__ = "Médéric Ribreux"
+__date__ = "April 2016"
+__copyright__ = "(C) 2016, Médéric Ribreux"
import os
-from processing.tools.system import (isWindows, getTempFilename)
+from processing.tools.system import isWindows, getTempFilename
from grassprovider.grass_utils import GrassUtils
from qgis.PyQt.QtCore import QDir
from qgis.core import QgsProcessingParameterString
@@ -36,10 +36,11 @@ def orderedInput(alg, parameters, context, src, tgt, numSeq=None):
:param tgt: Name of a new input parameter.
:param numSeq: List of a sequence for naming layers.
"""
- rootFilename = 'rast_{}.'.format(os.path.basename(getTempFilename(context=context)))
+ rootFilename = f"rast_{os.path.basename(getTempFilename(context=context))}."
# parameters[tgt] = rootFilename
- param = QgsProcessingParameterString(tgt, 'virtual input',
- rootFilename, False, False)
+ param = QgsProcessingParameterString(
+ tgt, "virtual input", rootFilename, False, False
+ )
alg.addParameter(param)
rasters = alg.parameterAsLayerList(parameters, src, context)
@@ -48,7 +49,7 @@ def orderedInput(alg, parameters, context, src, tgt, numSeq=None):
numSeq = list(range(1, len(rasters) + 1))
for idx, raster in enumerate(rasters):
- rasterName = '{}{}'.format(rootFilename, numSeq[idx])
+ rasterName = f"{rootFilename}{numSeq[idx]}"
alg.loadRasterLayer(rasterName, raster, context, False, None, rasterName)
# Don't forget to remove the old input parameter
@@ -69,32 +70,35 @@ def regroupRasters(alg, parameters, context, src, group, subgroup=None, extFile=
:param extFile: dict : parameterName:directory name
"""
# Create a group parameter
- groupName = 'group_{}'.format(os.path.basename(getTempFilename(context=context)))
- param = QgsProcessingParameterString(group, 'virtual group',
- groupName, False, False)
+ groupName = f"group_{os.path.basename(getTempFilename(context=context))}"
+ param = QgsProcessingParameterString(
+ group, "virtual group", groupName, False, False
+ )
alg.addParameter(param)
# Create a subgroup
subgroupName = None
if subgroup:
- subgroupName = 'subgroup_{}'.format(os.path.basename(getTempFilename(context=context)))
- param = QgsProcessingParameterString(subgroup, 'virtual subgroup',
- subgroupName, False, False)
+ subgroupName = f"subgroup_{os.path.basename(getTempFilename(context=context))}"
+ param = QgsProcessingParameterString(
+ subgroup, "virtual subgroup", subgroupName, False, False
+ )
alg.addParameter(param)
# Compute raster names
rasters = alg.parameterAsLayerList(parameters, src, context)
rasterNames = []
for idx, raster in enumerate(rasters):
- name = '{}_{}'.format(src, idx)
+ name = f"{src}_{idx}"
if name in alg.exportedLayers:
rasterNames.append(alg.exportedLayers[name])
# Insert a i.group command
- command = 'i.group group={}{} input={}'.format(
+ command = "i.group group={}{} input={}".format(
groupName,
- ' subgroup={}'.format(subgroupName) if subgroup else '',
- ','.join(rasterNames))
+ f" subgroup={subgroupName}" if subgroup else "",
+ ",".join(rasterNames),
+ )
alg.commands.append(command)
# Handle external files
@@ -115,35 +119,54 @@ def regroupRasters(alg, parameters, context, src, group, subgroup=None, extFile=
return groupName, subgroupName
-def importSigFile(alg, group, subgroup, src, sigDir='sig'):
+def importSigFile(alg, group, subgroup, src, sigDir="sig"):
"""
Import a signature file into an
internal GRASSDB folder
"""
shortSigFile = os.path.basename(src)
- interSig = os.path.join(GrassUtils.grassMapsetFolder(),
- 'PERMANENT', 'group', group, 'subgroup',
- subgroup, sigDir, shortSigFile)
+ interSig = os.path.join(
+ GrassUtils.grassMapsetFolder(),
+ "PERMANENT",
+ "group",
+ group,
+ "subgroup",
+ subgroup,
+ sigDir,
+ shortSigFile,
+ )
copyFile(alg, src, interSig)
return shortSigFile
-def exportSigFile(alg, group, subgroup, dest, sigDir='sig'):
+def exportSigFile(alg, group, subgroup, dest, sigDir="sig"):
"""
Export a signature file from internal GRASSDB
to final destination
"""
shortSigFile = os.path.basename(dest)
- grass_version = int(GrassUtils.installedVersion().split('.')[0])
+ grass_version = int(GrassUtils.installedVersion().split(".")[0])
if grass_version >= 8:
- interSig = os.path.join(GrassUtils.grassMapsetFolder(),
- 'PERMANENT', 'signatures',
- sigDir, shortSigFile, 'sig')
+ interSig = os.path.join(
+ GrassUtils.grassMapsetFolder(),
+ "PERMANENT",
+ "signatures",
+ sigDir,
+ shortSigFile,
+ "sig",
+ )
else:
- interSig = os.path.join(GrassUtils.grassMapsetFolder(),
- 'PERMANENT', 'group', group, 'subgroup',
- subgroup, sigDir, shortSigFile)
+ interSig = os.path.join(
+ GrassUtils.grassMapsetFolder(),
+ "PERMANENT",
+ "group",
+ group,
+ "subgroup",
+ subgroup,
+ sigDir,
+ shortSigFile,
+ )
moveFile(alg, interSig, dest)
return interSig
@@ -160,7 +183,8 @@ def exportInputRasters(alg, parameters, context, rasterDic):
# Get inputs and outputs
for inputName, outputName in rasterDic.items():
fileName = os.path.normpath(
- alg.parameterAsOutputLayer(parameters, outputName, context))
+ alg.parameterAsOutputLayer(parameters, outputName, context)
+ )
grassName = alg.exportedLayers[inputName]
outFormat = GrassUtils.getRasterFormatFromFilename(fileName)
alg.exportRasterLayer(grassName, fileName, True, outFormat, createOpt, metaOpt)
@@ -170,9 +194,15 @@ def verifyRasterNum(alg, parameters, context, rasters, mini, maxi=None):
"""Verify that we have at least n rasters in multipleInput"""
num = len(alg.parameterAsLayerList(parameters, rasters, context))
if num < mini:
- return False, 'You need to set at least {} input rasters for this algorithm!'.format(mini)
+ return (
+ False,
+ f"You need to set at least {mini} input rasters for this algorithm!",
+ )
if maxi and num > maxi:
- return False, 'You need to set a maximum of {} input rasters for this algorithm!'.format(maxi)
+ return (
+ False,
+ f"You need to set a maximum of {maxi} input rasters for this algorithm!",
+ )
return True, None
@@ -191,31 +221,32 @@ def verifyRasterNum(alg, parameters, context, rasters, mini, maxi=None):
def createDestDir(alg, toFile):
- """ Generates an mkdir command for GRASS script """
+ """Generates an mkdir command for GRASS script"""
# Creates the destination directory
- command = "{} \"{}\"".format(
+ command = '{} "{}"'.format(
"MD" if isWindows() else "mkdir -p",
- QDir.toNativeSeparators(os.path.dirname(toFile))
+ QDir.toNativeSeparators(os.path.dirname(toFile)),
)
alg.commands.append(command)
def moveFile(alg, fromFile, toFile):
- """ Generates a move command for GRASS script """
+ """Generates a move command for GRASS script"""
createDestDir(alg, toFile)
- command = "{} \"{}\" \"{}\"".format(
+ command = '{} "{}" "{}"'.format(
"MOVE /Y" if isWindows() else "mv -f",
QDir.toNativeSeparators(fromFile),
- QDir.toNativeSeparators(toFile)
+ QDir.toNativeSeparators(toFile),
)
alg.commands.append(command)
def copyFile(alg, fromFile, toFile):
- """ Generates a copy command for GRASS script """
+ """Generates a copy command for GRASS script"""
createDestDir(alg, toFile)
- command = "{} \"{}\" \"{}\"".format(
+ command = '{} "{}" "{}"'.format(
"COPY /Y" if isWindows() else "cp -f",
QDir.toNativeSeparators(fromFile),
- QDir.toNativeSeparators(toFile))
+ QDir.toNativeSeparators(toFile),
+ )
alg.commands.append(command)
diff --git a/python/plugins/grassprovider/ext/i_albedo.py b/python/plugins/grassprovider/ext/i_albedo.py
index ab418d15a01f..2dda8d334e5c 100644
--- a/python/plugins/grassprovider/ext/i_albedo.py
+++ b/python/plugins/grassprovider/ext/i_albedo.py
@@ -15,19 +15,20 @@
***************************************************************************
"""
-__author__ = 'Médéric Ribreux'
-__date__ = 'March 2016'
-__copyright__ = '(C) 2016, Médéric Ribreux'
+__author__ = "Médéric Ribreux"
+__date__ = "March 2016"
+__copyright__ = "(C) 2016, Médéric Ribreux"
from .i import verifyRasterNum
def checkParameterValuesBeforeExecuting(alg, parameters, context):
- if alg.parameterAsBoolean(parameters, '-m', context):
- return verifyRasterNum(alg, parameters, context, 'input', 7)
- elif alg.parameterAsBoolean(parameters, '-n', context):
- return verifyRasterNum(alg, parameters, context, 'input', 2)
- elif (alg.parameterAsBoolean(parameters, '-l', context)
- or alg.parameterAsBoolean(parameters, '-a', context)):
- return verifyRasterNum(alg, parameters, context, 'input', 6)
+ if alg.parameterAsBoolean(parameters, "-m", context):
+ return verifyRasterNum(alg, parameters, context, "input", 7)
+ elif alg.parameterAsBoolean(parameters, "-n", context):
+ return verifyRasterNum(alg, parameters, context, "input", 2)
+ elif alg.parameterAsBoolean(parameters, "-l", context) or alg.parameterAsBoolean(
+ parameters, "-a", context
+ ):
+ return verifyRasterNum(alg, parameters, context, "input", 6)
return True, None
diff --git a/python/plugins/grassprovider/ext/i_cca.py b/python/plugins/grassprovider/ext/i_cca.py
index 97e3acd99f31..61afff682146 100644
--- a/python/plugins/grassprovider/ext/i_cca.py
+++ b/python/plugins/grassprovider/ext/i_cca.py
@@ -15,25 +15,26 @@
***************************************************************************
"""
-__author__ = 'Médéric Ribreux'
-__date__ = 'March 2016'
-__copyright__ = '(C) 2016, Médéric Ribreux'
+__author__ = "Médéric Ribreux"
+__date__ = "March 2016"
+__copyright__ = "(C) 2016, Médéric Ribreux"
from .i import verifyRasterNum, regroupRasters, importSigFile
def checkParameterValuesBeforeExecuting(alg, parameters, context):
- return verifyRasterNum(alg, parameters, context, 'input', 2, 8)
+ return verifyRasterNum(alg, parameters, context, "input", 2, 8)
def processCommand(alg, parameters, context, feedback):
# Regroup rasters
- group, subgroup = regroupRasters(alg, parameters, context,
- 'input', 'group', 'subgroup')
+ group, subgroup = regroupRasters(
+ alg, parameters, context, "input", "group", "subgroup"
+ )
- signatureFile = alg.parameterAsString(parameters, 'signature', context)
+ signatureFile = alg.parameterAsString(parameters, "signature", context)
shortSigFile = importSigFile(alg, group, subgroup, signatureFile)
- parameters['signature'] = shortSigFile
+ parameters["signature"] = shortSigFile
# Handle other parameters
alg.processCommand(parameters, context, feedback)
diff --git a/python/plugins/grassprovider/ext/i_cluster.py b/python/plugins/grassprovider/ext/i_cluster.py
index ac7e1cbdb7e3..950e14d3e7f7 100644
--- a/python/plugins/grassprovider/ext/i_cluster.py
+++ b/python/plugins/grassprovider/ext/i_cluster.py
@@ -15,31 +15,33 @@
***************************************************************************
"""
-__author__ = 'Médéric Ribreux'
-__date__ = 'March 2016'
-__copyright__ = '(C) 2016, Médéric Ribreux'
+__author__ = "Médéric Ribreux"
+__date__ = "March 2016"
+__copyright__ = "(C) 2016, Médéric Ribreux"
import os
from .i import regroupRasters, verifyRasterNum, exportSigFile
def checkParameterValuesBeforeExecuting(alg, parameters, context):
- return verifyRasterNum(alg, parameters, context, 'input', 2)
+ return verifyRasterNum(alg, parameters, context, "input", 2)
def processCommand(alg, parameters, context, feedback):
# We need to extract the basename of the signature file
- signatureFile = alg.parameterAsString(parameters, 'signaturefile', context)
+ signatureFile = alg.parameterAsString(parameters, "signaturefile", context)
shortSigFile = os.path.basename(signatureFile)
- parameters['signaturefile'] = shortSigFile
+ parameters["signaturefile"] = shortSigFile
# Regroup rasters
- group, subgroup = regroupRasters(alg, parameters, context, 'input', 'group', 'subgroup')
+ group, subgroup = regroupRasters(
+ alg, parameters, context, "input", "group", "subgroup"
+ )
alg.processCommand(parameters, context, feedback)
# Re-add signature files
- parameters['signaturefile'] = signatureFile
- alg.fileOutputs['signaturefile'] = signatureFile
+ parameters["signaturefile"] = signatureFile
+ alg.fileOutputs["signaturefile"] = signatureFile
# Export signature file
exportSigFile(alg, group, subgroup, signatureFile)
diff --git a/python/plugins/grassprovider/ext/i_colors_enhance.py b/python/plugins/grassprovider/ext/i_colors_enhance.py
index 9fd9df1beedf..15c3d7a3ec57 100644
--- a/python/plugins/grassprovider/ext/i_colors_enhance.py
+++ b/python/plugins/grassprovider/ext/i_colors_enhance.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Médéric Ribreux'
-__date__ = 'March 2016'
-__copyright__ = '(C) 2016, Médéric Ribreux'
+__author__ = "Médéric Ribreux"
+__date__ = "March 2016"
+__copyright__ = "(C) 2016, Médéric Ribreux"
from .i import exportInputRasters
@@ -29,5 +29,5 @@ def processCommand(alg, parameters, context, feedback):
def processOutputs(alg, parameters, context, feedback):
# Input rasters are output rasters
- rasterDic = {'red': 'redoutput', 'green': 'greenoutput', 'blue': 'blueoutput'}
+ rasterDic = {"red": "redoutput", "green": "greenoutput", "blue": "blueoutput"}
exportInputRasters(alg, parameters, context, rasterDic)
diff --git a/python/plugins/grassprovider/ext/i_evapo_mh.py b/python/plugins/grassprovider/ext/i_evapo_mh.py
index 101f796d0047..761eebcae038 100644
--- a/python/plugins/grassprovider/ext/i_evapo_mh.py
+++ b/python/plugins/grassprovider/ext/i_evapo_mh.py
@@ -15,16 +15,22 @@
***************************************************************************
"""
-__author__ = 'Médéric Ribreux'
-__date__ = 'March 2016'
-__copyright__ = '(C) 2016, Médéric Ribreux'
+__author__ = "Médéric Ribreux"
+__date__ = "March 2016"
+__copyright__ = "(C) 2016, Médéric Ribreux"
def checkParameterValuesBeforeExecuting(alg, parameters, context):
- if (alg.parameterAsBoolean(parameters, '-h', context)
- and alg.parameterAsLayer(parameters, 'precipitation', context)):
- return False, alg.tr('You can\'t use original Hargreaves flag and precipitation parameter together!')
- if (not alg.parameterAsBoolean(parameters, '-h', context)
- and not alg.parameterAsLayer(parameters, 'precipitation', context)):
- return False, alg.tr('If you don\'t use original Hargreaves flag, you must set the precipitation raster parameter!')
+ if alg.parameterAsBoolean(parameters, "-h", context) and alg.parameterAsLayer(
+ parameters, "precipitation", context
+ ):
+ return False, alg.tr(
+ "You can't use original Hargreaves flag and precipitation parameter together!"
+ )
+ if not alg.parameterAsBoolean(
+ parameters, "-h", context
+ ) and not alg.parameterAsLayer(parameters, "precipitation", context):
+ return False, alg.tr(
+ "If you don't use original Hargreaves flag, you must set the precipitation raster parameter!"
+ )
return True, None
diff --git a/python/plugins/grassprovider/ext/i_gensig.py b/python/plugins/grassprovider/ext/i_gensig.py
index db67d2da4781..02ab5d6b5cba 100644
--- a/python/plugins/grassprovider/ext/i_gensig.py
+++ b/python/plugins/grassprovider/ext/i_gensig.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Médéric Ribreux'
-__date__ = 'March 2016'
-__copyright__ = '(C) 2016, Médéric Ribreux'
+__author__ = "Médéric Ribreux"
+__date__ = "March 2016"
+__copyright__ = "(C) 2016, Médéric Ribreux"
import os
from .i import regroupRasters, exportSigFile
@@ -25,17 +25,19 @@
def processCommand(alg, parameters, context, feedback):
# We need to extract the basename of the signature file
- signatureFile = alg.parameterAsString(parameters, 'signaturefile', context)
+ signatureFile = alg.parameterAsString(parameters, "signaturefile", context)
shortSigFile = os.path.basename(signatureFile)
- parameters['signaturefile'] = shortSigFile
+ parameters["signaturefile"] = shortSigFile
# Regroup rasters
- group, subgroup = regroupRasters(alg, parameters, context, 'input', 'group', 'subgroup')
+ group, subgroup = regroupRasters(
+ alg, parameters, context, "input", "group", "subgroup"
+ )
alg.processCommand(parameters, context, feedback)
# Re-add signature files
- parameters['signaturefile'] = signatureFile
- alg.fileOutputs['signaturefile'] = signatureFile
+ parameters["signaturefile"] = signatureFile
+ alg.fileOutputs["signaturefile"] = signatureFile
# Export signature file
exportSigFile(alg, group, subgroup, signatureFile)
diff --git a/python/plugins/grassprovider/ext/i_gensigset.py b/python/plugins/grassprovider/ext/i_gensigset.py
index c378f3550d2b..e233d30484cd 100644
--- a/python/plugins/grassprovider/ext/i_gensigset.py
+++ b/python/plugins/grassprovider/ext/i_gensigset.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Médéric Ribreux'
-__date__ = 'March 2016'
-__copyright__ = '(C) 2016, Médéric Ribreux'
+__author__ = "Médéric Ribreux"
+__date__ = "March 2016"
+__copyright__ = "(C) 2016, Médéric Ribreux"
import os
from .i import regroupRasters, exportSigFile
@@ -25,17 +25,19 @@
def processCommand(alg, parameters, context, feedback):
# We need to extract the basename of the signature file
- signatureFile = alg.parameterAsString(parameters, 'signaturefile', context)
+ signatureFile = alg.parameterAsString(parameters, "signaturefile", context)
shortSigFile = os.path.basename(signatureFile)
- parameters['signaturefile'] = shortSigFile
+ parameters["signaturefile"] = shortSigFile
# Regroup rasters
- group, subgroup = regroupRasters(alg, parameters, context, 'input', 'group', 'subgroup')
+ group, subgroup = regroupRasters(
+ alg, parameters, context, "input", "group", "subgroup"
+ )
alg.processCommand(parameters, context, feedback)
# Re-add signature files
- parameters['signaturefile'] = signatureFile
- alg.fileOutputs['signaturefile'] = signatureFile
+ parameters["signaturefile"] = signatureFile
+ alg.fileOutputs["signaturefile"] = signatureFile
# Export signature file
- exportSigFile(alg, group, subgroup, signatureFile, 'sigset')
+ exportSigFile(alg, group, subgroup, signatureFile, "sigset")
diff --git a/python/plugins/grassprovider/ext/i_group.py b/python/plugins/grassprovider/ext/i_group.py
index ff52ac71aebf..325039ed80e3 100644
--- a/python/plugins/grassprovider/ext/i_group.py
+++ b/python/plugins/grassprovider/ext/i_group.py
@@ -15,12 +15,12 @@
***************************************************************************
"""
-__author__ = 'Médéric Ribreux'
-__date__ = 'March 2016'
-__copyright__ = '(C) 2016, Médéric Ribreux'
+__author__ = "Médéric Ribreux"
+__date__ = "March 2016"
+__copyright__ = "(C) 2016, Médéric Ribreux"
from .i import verifyRasterNum
def checkParameterValuesBeforeExecuting(alg, parameters, context):
- return verifyRasterNum(alg, parameters, context, 'input', 2)
+ return verifyRasterNum(alg, parameters, context, "input", 2)
diff --git a/python/plugins/grassprovider/ext/i_in_spotvgt.py b/python/plugins/grassprovider/ext/i_in_spotvgt.py
index 0c6accf7f414..32b028e1271f 100644
--- a/python/plugins/grassprovider/ext/i_in_spotvgt.py
+++ b/python/plugins/grassprovider/ext/i_in_spotvgt.py
@@ -15,13 +15,13 @@
***************************************************************************
"""
-__author__ = 'Médéric Ribreux'
-__date__ = 'April 2016'
-__copyright__ = '(C) 2016, Médéric Ribreux'
+__author__ = "Médéric Ribreux"
+__date__ = "April 2016"
+__copyright__ = "(C) 2016, Médéric Ribreux"
def processInputs(alg, parameters, context, feedback):
# Here, we apply directly the algorithm
# So we just need to get the projection of the layer !
- layer = alg.parameterAsRasterLayer(parameters, 'input', context)
+ layer = alg.parameterAsRasterLayer(parameters, "input", context)
alg.setSessionProjectionFromLayer(layer, context)
diff --git a/python/plugins/grassprovider/ext/i_landsat_acca.py b/python/plugins/grassprovider/ext/i_landsat_acca.py
index 1b1729e07e9f..da74d16f7495 100644
--- a/python/plugins/grassprovider/ext/i_landsat_acca.py
+++ b/python/plugins/grassprovider/ext/i_landsat_acca.py
@@ -15,20 +15,19 @@
***************************************************************************
"""
-__author__ = 'Médéric Ribreux'
-__date__ = 'March 2016'
-__copyright__ = '(C) 2016, Médéric Ribreux'
+__author__ = "Médéric Ribreux"
+__date__ = "March 2016"
+__copyright__ = "(C) 2016, Médéric Ribreux"
from .i import verifyRasterNum, orderedInput
def checkParameterValuesBeforeExecuting(alg, parameters, context):
- return verifyRasterNum(alg, parameters, context, 'rasters', 5, 5)
+ return verifyRasterNum(alg, parameters, context, "rasters", 5, 5)
def processInputs(alg, parameters, context, feedback):
- orderedInput(alg, parameters, context, 'rasters', 'input',
- [2, 3, 4, 5, 61])
+ orderedInput(alg, parameters, context, "rasters", "input", [2, 3, 4, 5, 61])
def processCommand(alg, parameters, context, feedback):
diff --git a/python/plugins/grassprovider/ext/i_landsat_toar.py b/python/plugins/grassprovider/ext/i_landsat_toar.py
index d4b1509dc9f1..9b231091761a 100644
--- a/python/plugins/grassprovider/ext/i_landsat_toar.py
+++ b/python/plugins/grassprovider/ext/i_landsat_toar.py
@@ -15,20 +15,21 @@
***************************************************************************
"""
-__author__ = 'Médéric Ribreux'
-__date__ = 'March 2016'
-__copyright__ = '(C) 2016, Médéric Ribreux'
+__author__ = "Médéric Ribreux"
+__date__ = "March 2016"
+__copyright__ = "(C) 2016, Médéric Ribreux"
from .i import verifyRasterNum, orderedInput
def checkParameterValuesBeforeExecuting(alg, parameters, context):
- return verifyRasterNum(alg, parameters, context, 'rasters', 5, 12)
+ return verifyRasterNum(alg, parameters, context, "rasters", 5, 12)
def processInputs(alg, parameters, context, feedback):
- orderedInput(alg, parameters, context, 'rasters', 'input',
- [1, 2, 3, 4, 5, 61, 62, 7, 8])
+ orderedInput(
+ alg, parameters, context, "rasters", "input", [1, 2, 3, 4, 5, 61, 62, 7, 8]
+ )
def processCommand(alg, parameters, context, feedback):
diff --git a/python/plugins/grassprovider/ext/i_maxlik.py b/python/plugins/grassprovider/ext/i_maxlik.py
index 9e134d5f85c8..a2043eafa183 100644
--- a/python/plugins/grassprovider/ext/i_maxlik.py
+++ b/python/plugins/grassprovider/ext/i_maxlik.py
@@ -15,21 +15,22 @@
***************************************************************************
"""
-__author__ = 'Médéric Ribreux'
-__date__ = 'March 2016'
-__copyright__ = '(C) 2016, Médéric Ribreux'
+__author__ = "Médéric Ribreux"
+__date__ = "March 2016"
+__copyright__ = "(C) 2016, Médéric Ribreux"
from .i import regroupRasters, importSigFile
def processCommand(alg, parameters, context, feedback):
- group, subgroup = regroupRasters(alg, parameters, context,
- 'input', 'group', 'subgroup')
+ group, subgroup = regroupRasters(
+ alg, parameters, context, "input", "group", "subgroup"
+ )
# import signature
- signatureFile = alg.parameterAsString(parameters, 'signaturefile', context)
+ signatureFile = alg.parameterAsString(parameters, "signaturefile", context)
shortSigFile = importSigFile(alg, group, subgroup, signatureFile)
- parameters['signaturefile'] = shortSigFile
+ parameters["signaturefile"] = shortSigFile
# Handle other parameters
alg.processCommand(parameters, context, feedback)
diff --git a/python/plugins/grassprovider/ext/i_oif.py b/python/plugins/grassprovider/ext/i_oif.py
index 6249a931e1bc..e99925ef513d 100644
--- a/python/plugins/grassprovider/ext/i_oif.py
+++ b/python/plugins/grassprovider/ext/i_oif.py
@@ -15,12 +15,12 @@
***************************************************************************
"""
-__author__ = 'Médéric Ribreux'
-__date__ = 'March 2016'
-__copyright__ = '(C) 2016, Médéric Ribreux'
+__author__ = "Médéric Ribreux"
+__date__ = "March 2016"
+__copyright__ = "(C) 2016, Médéric Ribreux"
from .i import verifyRasterNum
def checkParameterValuesBeforeExecuting(alg, parameters, context):
- return verifyRasterNum(alg, parameters, context, 'input', 4)
+ return verifyRasterNum(alg, parameters, context, "input", 4)
diff --git a/python/plugins/grassprovider/ext/i_pansharpen.py b/python/plugins/grassprovider/ext/i_pansharpen.py
index 056d3e32361f..05e436e2805b 100644
--- a/python/plugins/grassprovider/ext/i_pansharpen.py
+++ b/python/plugins/grassprovider/ext/i_pansharpen.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Médéric Ribreux'
-__date__ = 'March 2016'
-__copyright__ = '(C) 2016, Médéric Ribreux'
+__author__ = "Médéric Ribreux"
+__date__ = "March 2016"
+__copyright__ = "(C) 2016, Médéric Ribreux"
import os
from qgis.core import QgsProcessingParameterString
@@ -27,19 +27,20 @@
def processCommand(alg, parameters, context, feedback):
# Temporary remove outputs and add a virtual output parameter
- outputName = 'output_{}'.format(os.path.basename(getTempFilename(context=context)))
- param = QgsProcessingParameterString('output', 'virtual output',
- outputName, False, False)
+ outputName = f"output_{os.path.basename(getTempFilename(context=context))}"
+ param = QgsProcessingParameterString(
+ "output", "virtual output", outputName, False, False
+ )
alg.addParameter(param)
alg.processCommand(parameters, context, feedback, True)
def processOutputs(alg, parameters, context, feedback):
- outputName = alg.parameterAsString(parameters, 'output', context)
+ outputName = alg.parameterAsString(parameters, "output", context)
createOpt = alg.parameterAsString(parameters, alg.GRASS_RASTER_FORMAT_OPT, context)
metaOpt = alg.parameterAsString(parameters, alg.GRASS_RASTER_FORMAT_META, context)
- for channel in ['red', 'green', 'blue']:
- fileName = alg.parameterAsOutputLayer(parameters, '{}output'.format(channel), context)
- grassName = '{}_{}'.format(outputName, channel)
+ for channel in ["red", "green", "blue"]:
+ fileName = alg.parameterAsOutputLayer(parameters, f"{channel}output", context)
+ grassName = f"{outputName}_{channel}"
outFormat = GrassUtils.getRasterFormatFromFilename(fileName)
alg.exportRasterLayer(grassName, fileName, True, outFormat, createOpt, metaOpt)
diff --git a/python/plugins/grassprovider/ext/i_pca.py b/python/plugins/grassprovider/ext/i_pca.py
index 89af12f8a34f..6a4b55586f2b 100644
--- a/python/plugins/grassprovider/ext/i_pca.py
+++ b/python/plugins/grassprovider/ext/i_pca.py
@@ -15,12 +15,12 @@
***************************************************************************
"""
-__author__ = 'Médéric Ribreux'
-__date__ = 'March 2016'
-__copyright__ = '(C) 2016, Médéric Ribreux'
+__author__ = "Médéric Ribreux"
+__date__ = "March 2016"
+__copyright__ = "(C) 2016, Médéric Ribreux"
from .i import verifyRasterNum
def checkParameterValuesBeforeExecuting(alg, parameters, context):
- return verifyRasterNum(alg, parameters, context, 'input', 2)
+ return verifyRasterNum(alg, parameters, context, "input", 2)
diff --git a/python/plugins/grassprovider/ext/i_segment.py b/python/plugins/grassprovider/ext/i_segment.py
index 19f676ee236a..c19c6cf9f358 100644
--- a/python/plugins/grassprovider/ext/i_segment.py
+++ b/python/plugins/grassprovider/ext/i_segment.py
@@ -15,14 +15,14 @@
***************************************************************************
"""
-__author__ = 'Médéric Ribreux'
-__date__ = 'March 2016'
-__copyright__ = '(C) 2016, Médéric Ribreux'
+__author__ = "Médéric Ribreux"
+__date__ = "March 2016"
+__copyright__ = "(C) 2016, Médéric Ribreux"
from .i import regroupRasters
def processCommand(alg, parameters, context, feedback):
# Regroup rasters
- regroupRasters(alg, parameters, context, 'input', 'group')
+ regroupRasters(alg, parameters, context, "input", "group")
alg.processCommand(parameters, context, feedback)
diff --git a/python/plugins/grassprovider/ext/i_smap.py b/python/plugins/grassprovider/ext/i_smap.py
index 310d234d66a0..e14535e411c3 100644
--- a/python/plugins/grassprovider/ext/i_smap.py
+++ b/python/plugins/grassprovider/ext/i_smap.py
@@ -15,21 +15,23 @@
***************************************************************************
"""
-__author__ = 'Médéric Ribreux'
-__date__ = 'March 2016'
-__copyright__ = '(C) 2016, Médéric Ribreux'
+__author__ = "Médéric Ribreux"
+__date__ = "March 2016"
+__copyright__ = "(C) 2016, Médéric Ribreux"
from .i import regroupRasters, importSigFile
def processCommand(alg, parameters, context, feedback):
# Regroup rasters
- group, subgroup = regroupRasters(alg, parameters, context, 'input', 'group', 'subgroup')
+ group, subgroup = regroupRasters(
+ alg, parameters, context, "input", "group", "subgroup"
+ )
# import signature
- signatureFile = alg.parameterAsString(parameters, 'signaturefile', context)
- shortSigFile = importSigFile(alg, group, subgroup, signatureFile, 'sigset')
- parameters['signaturefile'] = shortSigFile
+ signatureFile = alg.parameterAsString(parameters, "signaturefile", context)
+ shortSigFile = importSigFile(alg, group, subgroup, signatureFile, "sigset")
+ parameters["signaturefile"] = shortSigFile
# Handle other parameters
alg.processCommand(parameters, context, feedback)
diff --git a/python/plugins/grassprovider/ext/i_tasscap.py b/python/plugins/grassprovider/ext/i_tasscap.py
index eda544125acf..831fd959396f 100644
--- a/python/plugins/grassprovider/ext/i_tasscap.py
+++ b/python/plugins/grassprovider/ext/i_tasscap.py
@@ -15,12 +15,12 @@
***************************************************************************
"""
-__author__ = 'Médéric Ribreux'
-__date__ = 'March 2016'
-__copyright__ = '(C) 2016, Médéric Ribreux'
+__author__ = "Médéric Ribreux"
+__date__ = "March 2016"
+__copyright__ = "(C) 2016, Médéric Ribreux"
from .i import verifyRasterNum
def checkParameterValuesBeforeExecuting(alg, parameters, context):
- return verifyRasterNum(alg, parameters, context, 'input', 6, 8)
+ return verifyRasterNum(alg, parameters, context, "input", 6, 8)
diff --git a/python/plugins/grassprovider/ext/r_blend_combine.py b/python/plugins/grassprovider/ext/r_blend_combine.py
index 4608a8360594..5d7628256bb7 100644
--- a/python/plugins/grassprovider/ext/r_blend_combine.py
+++ b/python/plugins/grassprovider/ext/r_blend_combine.py
@@ -15,21 +15,21 @@
***************************************************************************
"""
-__author__ = 'Médéric Ribreux'
-__date__ = 'February 2016'
-__copyright__ = '(C) 2016, Médéric Ribreux'
+__author__ = "Médéric Ribreux"
+__date__ = "February 2016"
+__copyright__ = "(C) 2016, Médéric Ribreux"
def processInputs(alg, parameters, context, feedback):
- if 'first' and 'second' in alg.exportedLayers:
+ if "first" and "second" in alg.exportedLayers:
return
# Use v.in.ogr
- for name in ['first', 'second']:
+ for name in ["first", "second"]:
alg.loadRasterLayerFromParameter(name, parameters, context, False, None)
alg.postInputs(context)
def processOutputs(alg, parameters, context, feedback):
# Keep color table
- alg.exportRasterLayerFromParameter('output', parameters, context)
+ alg.exportRasterLayerFromParameter("output", parameters, context)
diff --git a/python/plugins/grassprovider/ext/r_blend_rgb.py b/python/plugins/grassprovider/ext/r_blend_rgb.py
index 2e763d5412c1..9cfe11ce7f5b 100644
--- a/python/plugins/grassprovider/ext/r_blend_rgb.py
+++ b/python/plugins/grassprovider/ext/r_blend_rgb.py
@@ -15,20 +15,20 @@
***************************************************************************
"""
-__author__ = 'Médéric Ribreux'
-__date__ = 'February 2016'
-__copyright__ = '(C) 2016, Médéric Ribreux'
+__author__ = "Médéric Ribreux"
+__date__ = "February 2016"
+__copyright__ = "(C) 2016, Médéric Ribreux"
import os
from grassprovider.grass_utils import GrassUtils
def processInputs(alg, parameters, context, feedback):
- if 'first' and 'second' in alg.exportedLayers:
+ if "first" and "second" in alg.exportedLayers:
return
# Use v.in.ogr
- for name in ['first', 'second']:
+ for name in ["first", "second"]:
alg.loadRasterLayerFromParameter(name, parameters, context, False, None)
alg.postInputs(context)
@@ -43,10 +43,12 @@ def processOutputs(alg, parameters, context, feedback):
metaOpt = alg.parameterAsString(parameters, alg.GRASS_RASTER_FORMAT_META, context)
# Export each color raster
- colors = ['red', 'green', 'blue']
+ colors = ["red", "green", "blue"]
for color in colors:
fileName = os.path.normpath(
- alg.parameterAsOutputLayer(parameters, 'output_{}'.format(color), context))
+ alg.parameterAsOutputLayer(parameters, f"output_{color}", context)
+ )
outFormat = GrassUtils.getRasterFormatFromFilename(fileName)
- alg.exportRasterLayer('blended.{}'.format(color[0]),
- fileName, True, outFormat, createOpt, metaOpt)
+ alg.exportRasterLayer(
+ f"blended.{color[0]}", fileName, True, outFormat, createOpt, metaOpt
+ )
diff --git a/python/plugins/grassprovider/ext/r_category.py b/python/plugins/grassprovider/ext/r_category.py
index 1f9e0476468e..06c35e68be90 100644
--- a/python/plugins/grassprovider/ext/r_category.py
+++ b/python/plugins/grassprovider/ext/r_category.py
@@ -15,24 +15,28 @@
***************************************************************************
"""
-__author__ = 'Médéric Ribreux'
-__date__ = 'February 2016'
-__copyright__ = '(C) 2016, Médéric Ribreux'
+__author__ = "Médéric Ribreux"
+__date__ = "February 2016"
+__copyright__ = "(C) 2016, Médéric Ribreux"
from processing.tools.system import getTempFilename
from grassprovider.grass_utils import GrassUtils
def checkParameterValuesBeforeExecuting(alg, parameters, context):
- """ Verify if we have the right parameters """
- rules = alg.parameterAsString(parameters, 'rules', context)
- txtrules = alg.parameterAsString(parameters, 'txtrules', context)
- raster = alg.parameterAsString(parameters, 'raster', context)
+ """Verify if we have the right parameters"""
+ rules = alg.parameterAsString(parameters, "rules", context)
+ txtrules = alg.parameterAsString(parameters, "txtrules", context)
+ raster = alg.parameterAsString(parameters, "raster", context)
if rules and txtrules:
- return False, alg.tr("You need to set either a rules file or write directly the rules!")
+ return False, alg.tr(
+ "You need to set either a rules file or write directly the rules!"
+ )
elif (rules and raster) or (txtrules and raster):
- return False, alg.tr("You need to set either rules or a raster from which to copy categories!")
+ return False, alg.tr(
+ "You need to set either rules or a raster from which to copy categories!"
+ )
return True, None
@@ -40,18 +44,16 @@ def checkParameterValuesBeforeExecuting(alg, parameters, context):
def processInputs(alg, parameters, context, feedback):
# If there is another raster to copy categories from
# we need to import it with r.in.gdal rather than r.external
- raster = alg.parameterAsString(parameters, 'raster', context)
+ raster = alg.parameterAsString(parameters, "raster", context)
if raster:
- alg.loadRasterLayerFromParameter('raster',
- parameters, context,
- False, None)
- alg.loadRasterLayerFromParameter('map', parameters, context)
+ alg.loadRasterLayerFromParameter("raster", parameters, context, False, None)
+ alg.loadRasterLayerFromParameter("map", parameters, context)
alg.postInputs(context)
def processCommand(alg, parameters, context, feedback):
# Handle inline rules
- txtRules = alg.parameterAsString(parameters, 'txtrules', context)
+ txtRules = alg.parameterAsString(parameters, "txtrules", context)
if txtRules:
# Creates a temporary txt file
tempRulesName = getTempFilename(context=context)
@@ -59,8 +61,8 @@ def processCommand(alg, parameters, context, feedback):
# Inject rules into temporary txt file
with open(tempRulesName, "w") as tempRules:
tempRules.write(txtRules)
- alg.removeParameter('txtrules')
- parameters['rules'] = tempRulesName
+ alg.removeParameter("txtrules")
+ parameters["rules"] = tempRulesName
alg.processCommand(parameters, context, feedback, True)
@@ -71,8 +73,7 @@ def processOutputs(alg, parameters, context, feedback):
metaOpt = alg.parameterAsString(parameters, alg.GRASS_RASTER_FORMAT_META, context)
# We need to export the raster with all its bands and its color table
- fileName = alg.parameterAsOutputLayer(parameters, 'output', context)
+ fileName = alg.parameterAsOutputLayer(parameters, "output", context)
outFormat = GrassUtils.getRasterFormatFromFilename(fileName)
- grassName = alg.exportedLayers['map']
- alg.exportRasterLayer(grassName, fileName, True,
- outFormat, createOpt, metaOpt)
+ grassName = alg.exportedLayers["map"]
+ alg.exportRasterLayer(grassName, fileName, True, outFormat, createOpt, metaOpt)
diff --git a/python/plugins/grassprovider/ext/r_colors.py b/python/plugins/grassprovider/ext/r_colors.py
index 3ec6f0ea9abc..3df349d6b99c 100644
--- a/python/plugins/grassprovider/ext/r_colors.py
+++ b/python/plugins/grassprovider/ext/r_colors.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Médéric Ribreux'
-__date__ = 'February 2016'
-__copyright__ = '(C) 2016, Médéric Ribreux'
+__author__ = "Médéric Ribreux"
+__date__ = "February 2016"
+__copyright__ = "(C) 2016, Médéric Ribreux"
import os
from grassprovider.grass_utils import GrassUtils
@@ -25,17 +25,19 @@
def checkParameterValuesBeforeExecuting(alg, parameters, context):
- """ Verify if we have the right parameters """
- txtRules = alg.parameterAsString(parameters, 'rules_txt', context)
- rules = alg.parameterAsString(parameters, 'rules', context)
+ """Verify if we have the right parameters"""
+ txtRules = alg.parameterAsString(parameters, "rules_txt", context)
+ rules = alg.parameterAsString(parameters, "rules", context)
if txtRules and rules:
return False, alg.tr("You need to set either inline rules or a rules file!")
rules_or_txtRules = bool(txtRules or rules)
- color = bool(alg.parameterAsEnum(parameters, 'color', context))
- raster = bool(alg.parameterAsString(parameters, 'raster', context))
+ color = bool(alg.parameterAsEnum(parameters, "color", context))
+ raster = bool(alg.parameterAsString(parameters, "raster", context))
if not sum([rules_or_txtRules, color, raster]) == 1:
- return False, alg.tr("The color table, color rules and raster map parameters are mutually exclusive. You need to set one and only one of them!")
+ return False, alg.tr(
+ "The color table, color rules and raster map parameters are mutually exclusive. You need to set one and only one of them!"
+ )
return True, None
@@ -43,23 +45,23 @@ def checkParameterValuesBeforeExecuting(alg, parameters, context):
def processInputs(alg, parameters, context, feedback):
# import all rasters with their color tables (and their bands)
# We need to import all the bands and color tables of the input rasters
- rasters = alg.parameterAsLayerList(parameters, 'map', context)
+ rasters = alg.parameterAsLayerList(parameters, "map", context)
for idx, layer in enumerate(rasters):
- layerName = 'map_{}'.format(idx)
+ layerName = f"map_{idx}"
# Add a raster layer
alg.loadRasterLayer(layerName, layer, context, False, None)
# Optional raster layer to copy from
- raster = alg.parameterAsString(parameters, 'raster', context)
+ raster = alg.parameterAsString(parameters, "raster", context)
if raster:
- alg.loadRasterLayerFromParameter('raster', parameters, context, False, None)
+ alg.loadRasterLayerFromParameter("raster", parameters, context, False, None)
alg.postInputs(context)
def processCommand(alg, parameters, context, feedback):
# Handle inline rules
- txtRules = alg.parameterAsString(parameters, 'txtrules', context)
+ txtRules = alg.parameterAsString(parameters, "txtrules", context)
if txtRules:
# Creates a temporary txt file
tempRulesName = getTempFilename(context=context)
@@ -67,11 +69,11 @@ def processCommand(alg, parameters, context, feedback):
# Inject rules into temporary txt file
with open(tempRulesName, "w") as tempRules:
tempRules.write(txtRules)
- alg.removeParameter('txtrules')
- parameters['rules'] = tempRulesName
+ alg.removeParameter("txtrules")
+ parameters["rules"] = tempRulesName
- if alg.parameterAsEnum(parameters, 'color', context) == 0:
- alg.removeParameter('color')
+ if alg.parameterAsEnum(parameters, "color", context) == 0:
+ alg.removeParameter("color")
alg.processCommand(parameters, context, feedback, True)
@@ -81,11 +83,17 @@ def processOutputs(alg, parameters, context, feedback):
metaOpt = alg.parameterAsString(parameters, alg.GRASS_RASTER_FORMAT_META, context)
# Export all rasters with their color tables (and their bands)
- rasters = alg.parameterAsLayerList(parameters, 'map', context)
- outputDir = alg.parameterAsString(parameters, 'output_dir', context)
+ rasters = alg.parameterAsLayerList(parameters, "map", context)
+ outputDir = alg.parameterAsString(parameters, "output_dir", context)
for idx, raster in enumerate(rasters):
- rasterName = 'map_{}'.format(idx)
+ rasterName = f"map_{idx}"
fileName = os.path.join(outputDir, rasterName)
outFormat = GrassUtils.getRasterFormatFromFilename(fileName)
- alg.exportRasterLayer(alg.exportedLayers[rasterName], fileName, True,
- outFormat, createOpt, metaOpt)
+ alg.exportRasterLayer(
+ alg.exportedLayers[rasterName],
+ fileName,
+ True,
+ outFormat,
+ createOpt,
+ metaOpt,
+ )
diff --git a/python/plugins/grassprovider/ext/r_colors_stddev.py b/python/plugins/grassprovider/ext/r_colors_stddev.py
index fd3602af5397..e65e8f36e807 100644
--- a/python/plugins/grassprovider/ext/r_colors_stddev.py
+++ b/python/plugins/grassprovider/ext/r_colors_stddev.py
@@ -15,20 +15,20 @@
***************************************************************************
"""
-__author__ = 'Médéric Ribreux'
-__date__ = 'February 2016'
-__copyright__ = '(C) 2016, Médéric Ribreux'
+__author__ = "Médéric Ribreux"
+__date__ = "February 2016"
+__copyright__ = "(C) 2016, Médéric Ribreux"
from grassprovider.grass_utils import GrassUtils
def processInputs(alg, parameters, context, feedback):
# We need to import all the bands and to preserve color table
- if 'map' in alg.exportedLayers:
+ if "map" in alg.exportedLayers:
return
# We need to import all the bands and color tables of the input raster
- alg.loadRasterLayerFromParameter('map', parameters, context, False, None)
+ alg.loadRasterLayerFromParameter("map", parameters, context, False, None)
alg.postInputs(context)
@@ -42,8 +42,7 @@ def processOutputs(alg, parameters, context, feedback):
metaOpt = alg.parameterAsString(parameters, alg.GRASS_RASTER_FORMAT_META, context)
# We need to export the raster with all its bands and its color table
- fileName = alg.parameterAsOutputLayer(parameters, 'output', context)
+ fileName = alg.parameterAsOutputLayer(parameters, "output", context)
outFormat = GrassUtils.getRasterFormatFromFilename(fileName)
- grassName = alg.exportedLayers['map']
- alg.exportRasterLayer(grassName, fileName, True,
- outFormat, createOpt, metaOpt)
+ grassName = alg.exportedLayers["map"]
+ alg.exportRasterLayer(grassName, fileName, True, outFormat, createOpt, metaOpt)
diff --git a/python/plugins/grassprovider/ext/r_drain.py b/python/plugins/grassprovider/ext/r_drain.py
index 383ce86b82f5..6a2ee0b65636 100644
--- a/python/plugins/grassprovider/ext/r_drain.py
+++ b/python/plugins/grassprovider/ext/r_drain.py
@@ -15,25 +15,32 @@
***************************************************************************
"""
-__author__ = 'Médéric Ribreux'
-__date__ = 'February 2016'
-__copyright__ = '(C) 2016, Médéric Ribreux'
+__author__ = "Médéric Ribreux"
+__date__ = "February 2016"
+__copyright__ = "(C) 2016, Médéric Ribreux"
def checkParameterValuesBeforeExecuting(alg, parameters, context):
- """ Verify if we have the right parameters """
+ """Verify if we have the right parameters"""
# start_coordinates and start_points are mutually exclusives
- if (alg.parameterAsString(parameters, 'start_coordinates', context)
- and alg.parameterAsVectorLayer(parameters, 'start_points', context)):
- return False, alg.tr("You need to set either start coordinates OR a start points vector layer!")
+ if alg.parameterAsString(
+ parameters, "start_coordinates", context
+ ) and alg.parameterAsVectorLayer(parameters, "start_points", context):
+ return False, alg.tr(
+ "You need to set either start coordinates OR a start points vector layer!"
+ )
# You need to set at least one parameter
- if (not alg.parameterAsString(parameters, 'start_coordinates', context)
- and not alg.parameterAsVectorLayer(parameters, 'start_points', context)):
- return False, alg.tr("You need to set either start coordinates OR a start points vector layer!")
+ if not alg.parameterAsString(
+ parameters, "start_coordinates", context
+ ) and not alg.parameterAsVectorLayer(parameters, "start_points", context):
+ return False, alg.tr(
+ "You need to set either start coordinates OR a start points vector layer!"
+ )
- paramscore = [f for f in ['-c', '-a', '-n']
- if alg.parameterAsBoolean(parameters, f, context)]
+ paramscore = [
+ f for f in ["-c", "-a", "-n"] if alg.parameterAsBoolean(parameters, f, context)
+ ]
if len(paramscore) > 1:
return False, alg.tr("-c, -a, -n parameters are mutually exclusive!")
return True, None
diff --git a/python/plugins/grassprovider/ext/r_horizon.py b/python/plugins/grassprovider/ext/r_horizon.py
index b287352c8c82..36a4b024d646 100644
--- a/python/plugins/grassprovider/ext/r_horizon.py
+++ b/python/plugins/grassprovider/ext/r_horizon.py
@@ -15,19 +15,19 @@
***************************************************************************
"""
-__author__ = 'Médéric Ribreux'
-__date__ = 'September 2017'
-__copyright__ = '(C) 2017, Médéric Ribreux'
+__author__ = "Médéric Ribreux"
+__date__ = "September 2017"
+__copyright__ = "(C) 2017, Médéric Ribreux"
import os
import math
def checkParameterValuesBeforeExecuting(alg, parameters, context):
- """ Verify if we have the right parameters """
- start = alg.parameterAsDouble(parameters, 'start', context)
- end = alg.parameterAsDouble(parameters, 'end', context)
- step = alg.parameterAsDouble(parameters, 'step', context)
+ """Verify if we have the right parameters"""
+ start = alg.parameterAsDouble(parameters, "start", context)
+ end = alg.parameterAsDouble(parameters, "end", context)
+ step = alg.parameterAsDouble(parameters, "step", context)
if start >= end:
return False, alg.tr("The start position must be inferior to the end position!")
@@ -39,7 +39,7 @@ def checkParameterValuesBeforeExecuting(alg, parameters, context):
def processOutputs(alg, parameters, context, feedback):
# Inspired from GRASS implementation
def getNumberDecimals(number):
- """ Return the number of decimals of a number (int or float) """
+ """Return the number of decimals of a number (int or float)"""
if int(number) == number:
return 0
return len(str(number).split(".")[-1])
@@ -52,28 +52,28 @@ def doubleToBaseName(number, nDecimals):
number += 0.0001
# adapted from GRASS https://github.com/OSGeo/grass/blob/6253da1bd6ce48d23419e99e8b503edf46178490/lib/gis/basename.c#L97-L101
if nDecimals == 0:
- return f'{int(number):03}'
+ return f"{int(number):03}"
int_part = int(number)
dec_part = int((number - int_part) * pow(10, nDecimals))
return f'{int_part:03}_{str(dec_part).rjust(nDecimals, "0")}'
# There will be as many outputs as the difference between start and end divided by steps
- start = alg.parameterAsDouble(parameters, 'start', context)
- end = alg.parameterAsDouble(parameters, 'end', context)
- step = alg.parameterAsDouble(parameters, 'step', context)
- direction = alg.parameterAsDouble(parameters, 'direction', context)
+ start = alg.parameterAsDouble(parameters, "start", context)
+ end = alg.parameterAsDouble(parameters, "end", context)
+ step = alg.parameterAsDouble(parameters, "step", context)
+ direction = alg.parameterAsDouble(parameters, "direction", context)
first_rad = math.radians(start + direction)
nDecimals = getNumberDecimals(step)
dfr_rad = math.radians(step)
arrayNumInt = int((end - start) / abs(step))
- directory = alg.parameterAsString(parameters, 'output', context)
+ directory = alg.parameterAsString(parameters, "output", context)
# Needed if output to a temporary directory
os.makedirs(directory, exist_ok=True)
for k in range(arrayNumInt):
angle_deg = math.degrees(first_rad + dfr_rad * k)
baseName = doubleToBaseName(angle_deg, nDecimals)
- grassName = f'output{alg.uniqueSuffix}_{baseName}'
- fileName = f'{os.path.join(directory, baseName)}.tif'
+ grassName = f"output{alg.uniqueSuffix}_{baseName}"
+ fileName = f"{os.path.join(directory, baseName)}.tif"
alg.exportRasterLayer(grassName, fileName)
diff --git a/python/plugins/grassprovider/ext/r_li.py b/python/plugins/grassprovider/ext/r_li.py
index 351414bc7c5d..4d8fad728606 100644
--- a/python/plugins/grassprovider/ext/r_li.py
+++ b/python/plugins/grassprovider/ext/r_li.py
@@ -15,68 +15,75 @@
***************************************************************************
"""
-__author__ = 'Médéric Ribreux'
-__date__ = 'February 2016'
-__copyright__ = '(C) 2016, Médéric Ribreux'
+__author__ = "Médéric Ribreux"
+__date__ = "February 2016"
+__copyright__ = "(C) 2016, Médéric Ribreux"
import shutil
from qgis.core import QgsProcessingParameterString
-from processing.tools.system import (isWindows, mkdir,
- getTempFilename)
+from processing.tools.system import isWindows, mkdir, getTempFilename
from grassprovider.grass_utils import GrassUtils
import os
# for MS-Windows users who have MBCS chars in their name:
-if os.name == 'nt':
+if os.name == "nt":
import win32api
def rliPath():
"""Return r.li GRASS user dir"""
- grass_version = GrassUtils.installedVersion().split('.')[0]
+ grass_version = GrassUtils.installedVersion().split(".")[0]
if isWindows():
- homeDir = win32api.GetShortPathName(os.path.expanduser('~'))
- return os.path.join(homeDir, 'AppData', 'Roaming', f'GRASS{grass_version}', 'r.li')
+ homeDir = win32api.GetShortPathName(os.path.expanduser("~"))
+ return os.path.join(
+ homeDir, "AppData", "Roaming", f"GRASS{grass_version}", "r.li"
+ )
else:
- return os.path.join(os.path.expanduser("~"), f'.grass{grass_version}', 'r.li')
+ return os.path.join(os.path.expanduser("~"), f".grass{grass_version}", "r.li")
def removeConfigFile(alg, parameters, context):
- """ Remove the r.li user dir config file """
- configPath = alg.parameterAsString(parameters, 'config', context)
+ """Remove the r.li user dir config file"""
+ configPath = alg.parameterAsString(parameters, "config", context)
if isWindows():
- command = "DEL {}".format(os.path.join(rliPath(), configPath))
+ command = f"DEL {os.path.join(rliPath(), configPath)}"
else:
- command = "rm {}".format(os.path.join(rliPath(), configPath))
+ command = f"rm {os.path.join(rliPath(), configPath)}"
alg.commands.append(command)
def checkMovingWindow(alg, parameters, context, outputTxt=False):
- """ Verify if we have the right parameters """
- configTxt = alg.parameterAsString(parameters, 'config_txt', context)
- config = alg.parameterAsString(parameters, 'config', context)
+ """Verify if we have the right parameters"""
+ configTxt = alg.parameterAsString(parameters, "config_txt", context)
+ config = alg.parameterAsString(parameters, "config", context)
if configTxt and config:
- return False, alg.tr("You need to set either inline configuration or a configuration file!")
+ return False, alg.tr(
+ "You need to set either inline configuration or a configuration file!"
+ )
# Verify that configuration is in moving window
movingWindow = False
if configTxt:
- if 'MOVINGWINDOW' in configTxt:
+ if "MOVINGWINDOW" in configTxt:
movingWindow = True
# Read config file:
if config:
with open(config) as f:
for line in f:
- if 'MOVINGWINDOW' in line:
+ if "MOVINGWINDOW" in line:
movingWindow = True
if not movingWindow and not outputTxt:
- return False, alg.tr('Your configuration needs to be a "moving window" configuration!')
+ return False, alg.tr(
+ 'Your configuration needs to be a "moving window" configuration!'
+ )
if movingWindow and outputTxt:
- return False, alg.tr('Your configuration needs to be a non "moving window" configuration!')
+ return False, alg.tr(
+ 'Your configuration needs to be a non "moving window" configuration!'
+ )
return True, None
@@ -89,37 +96,40 @@ def configFile(alg, parameters, context, feedback, outputTxt=False):
user_grass_path = rliPath()
if not os.path.isdir(user_grass_path):
mkdir(user_grass_path)
- if not os.path.isdir(os.path.join(user_grass_path, 'output')):
- mkdir(os.path.join(user_grass_path, 'output'))
+ if not os.path.isdir(os.path.join(user_grass_path, "output")):
+ mkdir(os.path.join(user_grass_path, "output"))
# If we have a configuration file, we need to copy it into user dir
- if parameters['config']:
- fileName = alg.parameterAsString(parameters, 'config', context)
+ if parameters["config"]:
+ fileName = alg.parameterAsString(parameters, "config", context)
configFilePath = os.path.join(user_grass_path, os.path.basename(fileName))
# Copy the file
- shutil.copy(parameters['config'], configFilePath)
+ shutil.copy(parameters["config"], configFilePath)
# Change the parameter value
- parameters['config'] = os.path.basename(configFilePath)
+ parameters["config"] = os.path.basename(configFilePath)
# Handle inline configuration
- elif parameters['config_txt']:
+ elif parameters["config_txt"]:
# Creates a temporary txt file in user r.li directory
tempConfig = os.path.basename(getTempFilename(context=context))
configFilePath = os.path.join(user_grass_path, tempConfig)
# Inject rules into temporary txt file
with open(configFilePath, "w") as f:
- f.write(alg.parameterAsString(parameters, 'config_txt', context))
+ f.write(alg.parameterAsString(parameters, "config_txt", context))
f.write("\n")
# Use temporary file as rules file
- parameters['config'] = os.path.basename(configFilePath)
- alg.removeParameter('config_txt')
+ parameters["config"] = os.path.basename(configFilePath)
+ alg.removeParameter("config_txt")
# For ascii output, we need a virtual output
if outputTxt:
param = QgsProcessingParameterString(
- 'output', 'virtual output',
- 'a' + os.path.basename(getTempFilename(context=context)),
- False, False)
+ "output",
+ "virtual output",
+ "a" + os.path.basename(getTempFilename(context=context)),
+ False,
+ False,
+ )
alg.addParameter(param)
alg.processCommand(parameters, context, feedback, outputTxt)
@@ -130,14 +140,15 @@ def configFile(alg, parameters, context, feedback, outputTxt=False):
def moveOutputTxtFile(alg, parameters, context):
# Find output file name:
- txtPath = alg.parameterAsString(parameters, 'output_txt', context)
+ txtPath = alg.parameterAsString(parameters, "output_txt", context)
user_grass_path = rliPath()
- output = os.path.join(user_grass_path, 'output',
- alg.parameterAsString(parameters, 'output', context))
+ output = os.path.join(
+ user_grass_path, "output", alg.parameterAsString(parameters, "output", context)
+ )
# move the file
if isWindows():
- command = "MOVE /Y {} {}".format(output, txtPath)
+ command = f"MOVE /Y {output} {txtPath}"
else:
- command = "mv -f {} {}".format(output, txtPath)
+ command = f"mv -f {output} {txtPath}"
alg.commands.append(command)
diff --git a/python/plugins/grassprovider/ext/r_li_cwed.py b/python/plugins/grassprovider/ext/r_li_cwed.py
index 50e80c989b81..185746668b3d 100644
--- a/python/plugins/grassprovider/ext/r_li_cwed.py
+++ b/python/plugins/grassprovider/ext/r_li_cwed.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Médéric Ribreux'
-__date__ = 'February 2016'
-__copyright__ = '(C) 2016, Médéric Ribreux'
+__author__ = "Médéric Ribreux"
+__date__ = "February 2016"
+__copyright__ = "(C) 2016, Médéric Ribreux"
from .r_li import checkMovingWindow, configFile
diff --git a/python/plugins/grassprovider/ext/r_li_cwed_ascii.py b/python/plugins/grassprovider/ext/r_li_cwed_ascii.py
index 497a882d4245..8052ce48e699 100644
--- a/python/plugins/grassprovider/ext/r_li_cwed_ascii.py
+++ b/python/plugins/grassprovider/ext/r_li_cwed_ascii.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Médéric Ribreux'
-__date__ = 'February 2016'
-__copyright__ = '(C) 2016, Médéric Ribreux'
+__author__ = "Médéric Ribreux"
+__date__ = "February 2016"
+__copyright__ = "(C) 2016, Médéric Ribreux"
from .r_li import checkMovingWindow, configFile, moveOutputTxtFile
diff --git a/python/plugins/grassprovider/ext/r_li_dominance.py b/python/plugins/grassprovider/ext/r_li_dominance.py
index 6e3a0a3eefd9..c869f3efc300 100644
--- a/python/plugins/grassprovider/ext/r_li_dominance.py
+++ b/python/plugins/grassprovider/ext/r_li_dominance.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Médéric Ribreux'
-__date__ = 'February 2016'
-__copyright__ = '(C) 2016, Médéric Ribreux'
+__author__ = "Médéric Ribreux"
+__date__ = "February 2016"
+__copyright__ = "(C) 2016, Médéric Ribreux"
from .r_li import checkMovingWindow, configFile
diff --git a/python/plugins/grassprovider/ext/r_li_dominance_ascii.py b/python/plugins/grassprovider/ext/r_li_dominance_ascii.py
index eb6b77f96340..a8aed9fa2ca2 100644
--- a/python/plugins/grassprovider/ext/r_li_dominance_ascii.py
+++ b/python/plugins/grassprovider/ext/r_li_dominance_ascii.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Médéric Ribreux'
-__date__ = 'February 2016'
-__copyright__ = '(C) 2016, Médéric Ribreux'
+__author__ = "Médéric Ribreux"
+__date__ = "February 2016"
+__copyright__ = "(C) 2016, Médéric Ribreux"
from .r_li import checkMovingWindow, configFile, moveOutputTxtFile
diff --git a/python/plugins/grassprovider/ext/r_li_edgedensity.py b/python/plugins/grassprovider/ext/r_li_edgedensity.py
index 5beac0885069..165c6f4030ca 100644
--- a/python/plugins/grassprovider/ext/r_li_edgedensity.py
+++ b/python/plugins/grassprovider/ext/r_li_edgedensity.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Médéric Ribreux'
-__date__ = 'February 2016'
-__copyright__ = '(C) 2016, Médéric Ribreux'
+__author__ = "Médéric Ribreux"
+__date__ = "February 2016"
+__copyright__ = "(C) 2016, Médéric Ribreux"
from .r_li import checkMovingWindow, configFile
diff --git a/python/plugins/grassprovider/ext/r_li_edgedensity_ascii.py b/python/plugins/grassprovider/ext/r_li_edgedensity_ascii.py
index a416d6ed68d4..2c4c4ed3c48f 100644
--- a/python/plugins/grassprovider/ext/r_li_edgedensity_ascii.py
+++ b/python/plugins/grassprovider/ext/r_li_edgedensity_ascii.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Médéric Ribreux'
-__date__ = 'February 2016'
-__copyright__ = '(C) 2016, Médéric Ribreux'
+__author__ = "Médéric Ribreux"
+__date__ = "February 2016"
+__copyright__ = "(C) 2016, Médéric Ribreux"
from .r_li import checkMovingWindow, configFile, moveOutputTxtFile
diff --git a/python/plugins/grassprovider/ext/r_li_mpa.py b/python/plugins/grassprovider/ext/r_li_mpa.py
index 1fd13334eccd..e2a481a8cc06 100644
--- a/python/plugins/grassprovider/ext/r_li_mpa.py
+++ b/python/plugins/grassprovider/ext/r_li_mpa.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Médéric Ribreux'
-__date__ = 'February 2016'
-__copyright__ = '(C) 2016, Médéric Ribreux'
+__author__ = "Médéric Ribreux"
+__date__ = "February 2016"
+__copyright__ = "(C) 2016, Médéric Ribreux"
from .r_li import checkMovingWindow, configFile
diff --git a/python/plugins/grassprovider/ext/r_li_mpa_ascii.py b/python/plugins/grassprovider/ext/r_li_mpa_ascii.py
index 90597643824f..22504a71c849 100644
--- a/python/plugins/grassprovider/ext/r_li_mpa_ascii.py
+++ b/python/plugins/grassprovider/ext/r_li_mpa_ascii.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Médéric Ribreux'
-__date__ = 'February 2016'
-__copyright__ = '(C) 2016, Médéric Ribreux'
+__author__ = "Médéric Ribreux"
+__date__ = "February 2016"
+__copyright__ = "(C) 2016, Médéric Ribreux"
from .r_li import checkMovingWindow, configFile, moveOutputTxtFile
diff --git a/python/plugins/grassprovider/ext/r_li_mps.py b/python/plugins/grassprovider/ext/r_li_mps.py
index f7de0f61977d..cdeed825ea57 100644
--- a/python/plugins/grassprovider/ext/r_li_mps.py
+++ b/python/plugins/grassprovider/ext/r_li_mps.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Médéric Ribreux'
-__date__ = 'February 2016'
-__copyright__ = '(C) 2016, Médéric Ribreux'
+__author__ = "Médéric Ribreux"
+__date__ = "February 2016"
+__copyright__ = "(C) 2016, Médéric Ribreux"
from .r_li import checkMovingWindow, configFile
diff --git a/python/plugins/grassprovider/ext/r_li_mps_ascii.py b/python/plugins/grassprovider/ext/r_li_mps_ascii.py
index eac3c41b64b8..b36396ac788b 100644
--- a/python/plugins/grassprovider/ext/r_li_mps_ascii.py
+++ b/python/plugins/grassprovider/ext/r_li_mps_ascii.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Médéric Ribreux'
-__date__ = 'February 2016'
-__copyright__ = '(C) 2016, Médéric Ribreux'
+__author__ = "Médéric Ribreux"
+__date__ = "February 2016"
+__copyright__ = "(C) 2016, Médéric Ribreux"
from .r_li import checkMovingWindow, configFile, moveOutputTxtFile
diff --git a/python/plugins/grassprovider/ext/r_li_padcv.py b/python/plugins/grassprovider/ext/r_li_padcv.py
index cfb4310e8b5c..1f90af63f38d 100644
--- a/python/plugins/grassprovider/ext/r_li_padcv.py
+++ b/python/plugins/grassprovider/ext/r_li_padcv.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Médéric Ribreux'
-__date__ = 'February 2016'
-__copyright__ = '(C) 2016, Médéric Ribreux'
+__author__ = "Médéric Ribreux"
+__date__ = "February 2016"
+__copyright__ = "(C) 2016, Médéric Ribreux"
from .r_li import checkMovingWindow, configFile
diff --git a/python/plugins/grassprovider/ext/r_li_padcv_ascii.py b/python/plugins/grassprovider/ext/r_li_padcv_ascii.py
index 0e045ec1471d..63d2cca7151f 100644
--- a/python/plugins/grassprovider/ext/r_li_padcv_ascii.py
+++ b/python/plugins/grassprovider/ext/r_li_padcv_ascii.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Médéric Ribreux'
-__date__ = 'February 2016'
-__copyright__ = '(C) 2016, Médéric Ribreux'
+__author__ = "Médéric Ribreux"
+__date__ = "February 2016"
+__copyright__ = "(C) 2016, Médéric Ribreux"
from .r_li import checkMovingWindow, configFile, moveOutputTxtFile
diff --git a/python/plugins/grassprovider/ext/r_li_padrange.py b/python/plugins/grassprovider/ext/r_li_padrange.py
index 24db8ae167d1..f520a0de8b97 100644
--- a/python/plugins/grassprovider/ext/r_li_padrange.py
+++ b/python/plugins/grassprovider/ext/r_li_padrange.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Médéric Ribreux'
-__date__ = 'February 2016'
-__copyright__ = '(C) 2016, Médéric Ribreux'
+__author__ = "Médéric Ribreux"
+__date__ = "February 2016"
+__copyright__ = "(C) 2016, Médéric Ribreux"
from .r_li import checkMovingWindow, configFile
diff --git a/python/plugins/grassprovider/ext/r_li_padrange_ascii.py b/python/plugins/grassprovider/ext/r_li_padrange_ascii.py
index 0d7d61f1a87c..57856b40ae49 100644
--- a/python/plugins/grassprovider/ext/r_li_padrange_ascii.py
+++ b/python/plugins/grassprovider/ext/r_li_padrange_ascii.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Médéric Ribreux'
-__date__ = 'February 2016'
-__copyright__ = '(C) 2016, Médéric Ribreux'
+__author__ = "Médéric Ribreux"
+__date__ = "February 2016"
+__copyright__ = "(C) 2016, Médéric Ribreux"
from .r_li import checkMovingWindow, configFile, moveOutputTxtFile
diff --git a/python/plugins/grassprovider/ext/r_li_padsd.py b/python/plugins/grassprovider/ext/r_li_padsd.py
index 17b29fc05885..f6bce09eb436 100644
--- a/python/plugins/grassprovider/ext/r_li_padsd.py
+++ b/python/plugins/grassprovider/ext/r_li_padsd.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Médéric Ribreux'
-__date__ = 'February 2016'
-__copyright__ = '(C) 2016, Médéric Ribreux'
+__author__ = "Médéric Ribreux"
+__date__ = "February 2016"
+__copyright__ = "(C) 2016, Médéric Ribreux"
from .r_li import checkMovingWindow, configFile
diff --git a/python/plugins/grassprovider/ext/r_li_padsd_ascii.py b/python/plugins/grassprovider/ext/r_li_padsd_ascii.py
index 8c7e7c22c5ee..c5a700daa7d1 100644
--- a/python/plugins/grassprovider/ext/r_li_padsd_ascii.py
+++ b/python/plugins/grassprovider/ext/r_li_padsd_ascii.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Médéric Ribreux'
-__date__ = 'February 2016'
-__copyright__ = '(C) 2016, Médéric Ribreux'
+__author__ = "Médéric Ribreux"
+__date__ = "February 2016"
+__copyright__ = "(C) 2016, Médéric Ribreux"
from .r_li import checkMovingWindow, configFile, moveOutputTxtFile
diff --git a/python/plugins/grassprovider/ext/r_li_patchdensity.py b/python/plugins/grassprovider/ext/r_li_patchdensity.py
index acc305aa828d..d658f4a3145c 100644
--- a/python/plugins/grassprovider/ext/r_li_patchdensity.py
+++ b/python/plugins/grassprovider/ext/r_li_patchdensity.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Médéric Ribreux'
-__date__ = 'February 2016'
-__copyright__ = '(C) 2016, Médéric Ribreux'
+__author__ = "Médéric Ribreux"
+__date__ = "February 2016"
+__copyright__ = "(C) 2016, Médéric Ribreux"
from .r_li import checkMovingWindow, configFile
diff --git a/python/plugins/grassprovider/ext/r_li_patchdensity_ascii.py b/python/plugins/grassprovider/ext/r_li_patchdensity_ascii.py
index 111efcbb18d7..620c33db1649 100644
--- a/python/plugins/grassprovider/ext/r_li_patchdensity_ascii.py
+++ b/python/plugins/grassprovider/ext/r_li_patchdensity_ascii.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Médéric Ribreux'
-__date__ = 'February 2016'
-__copyright__ = '(C) 2016, Médéric Ribreux'
+__author__ = "Médéric Ribreux"
+__date__ = "February 2016"
+__copyright__ = "(C) 2016, Médéric Ribreux"
from .r_li import checkMovingWindow, configFile, moveOutputTxtFile
diff --git a/python/plugins/grassprovider/ext/r_li_patchnum.py b/python/plugins/grassprovider/ext/r_li_patchnum.py
index 90f4ad460913..925b50620102 100644
--- a/python/plugins/grassprovider/ext/r_li_patchnum.py
+++ b/python/plugins/grassprovider/ext/r_li_patchnum.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Médéric Ribreux'
-__date__ = 'February 2016'
-__copyright__ = '(C) 2016, Médéric Ribreux'
+__author__ = "Médéric Ribreux"
+__date__ = "February 2016"
+__copyright__ = "(C) 2016, Médéric Ribreux"
from .r_li import checkMovingWindow, configFile
diff --git a/python/plugins/grassprovider/ext/r_li_patchnum_ascii.py b/python/plugins/grassprovider/ext/r_li_patchnum_ascii.py
index ec2da01d8cf1..0ba1cd84e424 100644
--- a/python/plugins/grassprovider/ext/r_li_patchnum_ascii.py
+++ b/python/plugins/grassprovider/ext/r_li_patchnum_ascii.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Médéric Ribreux'
-__date__ = 'February 2016'
-__copyright__ = '(C) 2016, Médéric Ribreux'
+__author__ = "Médéric Ribreux"
+__date__ = "February 2016"
+__copyright__ = "(C) 2016, Médéric Ribreux"
from .r_li import checkMovingWindow, configFile, moveOutputTxtFile
diff --git a/python/plugins/grassprovider/ext/r_li_pielou.py b/python/plugins/grassprovider/ext/r_li_pielou.py
index f1a636527ad4..52af65e5efc4 100644
--- a/python/plugins/grassprovider/ext/r_li_pielou.py
+++ b/python/plugins/grassprovider/ext/r_li_pielou.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Médéric Ribreux'
-__date__ = 'February 2016'
-__copyright__ = '(C) 2016, Médéric Ribreux'
+__author__ = "Médéric Ribreux"
+__date__ = "February 2016"
+__copyright__ = "(C) 2016, Médéric Ribreux"
from .r_li import checkMovingWindow, configFile
diff --git a/python/plugins/grassprovider/ext/r_li_pielou_ascii.py b/python/plugins/grassprovider/ext/r_li_pielou_ascii.py
index 4ce58b91c42a..87162f84723e 100644
--- a/python/plugins/grassprovider/ext/r_li_pielou_ascii.py
+++ b/python/plugins/grassprovider/ext/r_li_pielou_ascii.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Médéric Ribreux'
-__date__ = 'February 2016'
-__copyright__ = '(C) 2016, Médéric Ribreux'
+__author__ = "Médéric Ribreux"
+__date__ = "February 2016"
+__copyright__ = "(C) 2016, Médéric Ribreux"
from .r_li import checkMovingWindow, configFile, moveOutputTxtFile
diff --git a/python/plugins/grassprovider/ext/r_li_renyi.py b/python/plugins/grassprovider/ext/r_li_renyi.py
index 5e34cad1df1c..8bacea15cf8c 100644
--- a/python/plugins/grassprovider/ext/r_li_renyi.py
+++ b/python/plugins/grassprovider/ext/r_li_renyi.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Médéric Ribreux'
-__date__ = 'February 2016'
-__copyright__ = '(C) 2016, Médéric Ribreux'
+__author__ = "Médéric Ribreux"
+__date__ = "February 2016"
+__copyright__ = "(C) 2016, Médéric Ribreux"
from .r_li import checkMovingWindow, configFile
diff --git a/python/plugins/grassprovider/ext/r_li_renyi_ascii.py b/python/plugins/grassprovider/ext/r_li_renyi_ascii.py
index 0d9925d9326d..2daea6fd3251 100644
--- a/python/plugins/grassprovider/ext/r_li_renyi_ascii.py
+++ b/python/plugins/grassprovider/ext/r_li_renyi_ascii.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Médéric Ribreux'
-__date__ = 'February 2016'
-__copyright__ = '(C) 2016, Médéric Ribreux'
+__author__ = "Médéric Ribreux"
+__date__ = "February 2016"
+__copyright__ = "(C) 2016, Médéric Ribreux"
from .r_li import checkMovingWindow, configFile, moveOutputTxtFile
diff --git a/python/plugins/grassprovider/ext/r_li_richness.py b/python/plugins/grassprovider/ext/r_li_richness.py
index fcfdcb2ad357..dc1c3c00908f 100644
--- a/python/plugins/grassprovider/ext/r_li_richness.py
+++ b/python/plugins/grassprovider/ext/r_li_richness.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Médéric Ribreux'
-__date__ = 'February 2016'
-__copyright__ = '(C) 2016, Médéric Ribreux'
+__author__ = "Médéric Ribreux"
+__date__ = "February 2016"
+__copyright__ = "(C) 2016, Médéric Ribreux"
from .r_li import checkMovingWindow, configFile
diff --git a/python/plugins/grassprovider/ext/r_li_richness_ascii.py b/python/plugins/grassprovider/ext/r_li_richness_ascii.py
index 2061d7a31be8..0eb2e6f85d76 100644
--- a/python/plugins/grassprovider/ext/r_li_richness_ascii.py
+++ b/python/plugins/grassprovider/ext/r_li_richness_ascii.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Médéric Ribreux'
-__date__ = 'February 2016'
-__copyright__ = '(C) 2016, Médéric Ribreux'
+__author__ = "Médéric Ribreux"
+__date__ = "February 2016"
+__copyright__ = "(C) 2016, Médéric Ribreux"
from .r_li import checkMovingWindow, configFile, moveOutputTxtFile
diff --git a/python/plugins/grassprovider/ext/r_li_shannon.py b/python/plugins/grassprovider/ext/r_li_shannon.py
index cb9d29700299..4d1ac79ab3de 100644
--- a/python/plugins/grassprovider/ext/r_li_shannon.py
+++ b/python/plugins/grassprovider/ext/r_li_shannon.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Médéric Ribreux'
-__date__ = 'February 2016'
-__copyright__ = '(C) 2016, Médéric Ribreux'
+__author__ = "Médéric Ribreux"
+__date__ = "February 2016"
+__copyright__ = "(C) 2016, Médéric Ribreux"
from .r_li import checkMovingWindow, configFile
diff --git a/python/plugins/grassprovider/ext/r_li_shannon_ascii.py b/python/plugins/grassprovider/ext/r_li_shannon_ascii.py
index 5614f5b92390..694cd1b3acaa 100644
--- a/python/plugins/grassprovider/ext/r_li_shannon_ascii.py
+++ b/python/plugins/grassprovider/ext/r_li_shannon_ascii.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Médéric Ribreux'
-__date__ = 'February 2016'
-__copyright__ = '(C) 2016, Médéric Ribreux'
+__author__ = "Médéric Ribreux"
+__date__ = "February 2016"
+__copyright__ = "(C) 2016, Médéric Ribreux"
from .r_li import checkMovingWindow, configFile, moveOutputTxtFile
diff --git a/python/plugins/grassprovider/ext/r_li_shape.py b/python/plugins/grassprovider/ext/r_li_shape.py
index 2c2a47a6e7c7..5f389425145e 100644
--- a/python/plugins/grassprovider/ext/r_li_shape.py
+++ b/python/plugins/grassprovider/ext/r_li_shape.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Médéric Ribreux'
-__date__ = 'February 2016'
-__copyright__ = '(C) 2016, Médéric Ribreux'
+__author__ = "Médéric Ribreux"
+__date__ = "February 2016"
+__copyright__ = "(C) 2016, Médéric Ribreux"
from .r_li import checkMovingWindow, configFile
diff --git a/python/plugins/grassprovider/ext/r_li_shape_ascii.py b/python/plugins/grassprovider/ext/r_li_shape_ascii.py
index fc6a99a00005..681426c94186 100644
--- a/python/plugins/grassprovider/ext/r_li_shape_ascii.py
+++ b/python/plugins/grassprovider/ext/r_li_shape_ascii.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Médéric Ribreux'
-__date__ = 'February 2016'
-__copyright__ = '(C) 2016, Médéric Ribreux'
+__author__ = "Médéric Ribreux"
+__date__ = "February 2016"
+__copyright__ = "(C) 2016, Médéric Ribreux"
from .r_li import checkMovingWindow, configFile, moveOutputTxtFile
diff --git a/python/plugins/grassprovider/ext/r_li_simpson.py b/python/plugins/grassprovider/ext/r_li_simpson.py
index b6486085d4df..6d54abfd0d2d 100644
--- a/python/plugins/grassprovider/ext/r_li_simpson.py
+++ b/python/plugins/grassprovider/ext/r_li_simpson.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Médéric Ribreux'
-__date__ = 'February 2016'
-__copyright__ = '(C) 2016, Médéric Ribreux'
+__author__ = "Médéric Ribreux"
+__date__ = "February 2016"
+__copyright__ = "(C) 2016, Médéric Ribreux"
from .r_li import checkMovingWindow, configFile
diff --git a/python/plugins/grassprovider/ext/r_li_simpson_ascii.py b/python/plugins/grassprovider/ext/r_li_simpson_ascii.py
index 8baf6755b15c..9d92f8c46a6c 100644
--- a/python/plugins/grassprovider/ext/r_li_simpson_ascii.py
+++ b/python/plugins/grassprovider/ext/r_li_simpson_ascii.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Médéric Ribreux'
-__date__ = 'February 2016'
-__copyright__ = '(C) 2016, Médéric Ribreux'
+__author__ = "Médéric Ribreux"
+__date__ = "February 2016"
+__copyright__ = "(C) 2016, Médéric Ribreux"
from .r_li import checkMovingWindow, configFile, moveOutputTxtFile
diff --git a/python/plugins/grassprovider/ext/r_mask_rast.py b/python/plugins/grassprovider/ext/r_mask_rast.py
index 6d36a2eede9e..6adc80915266 100644
--- a/python/plugins/grassprovider/ext/r_mask_rast.py
+++ b/python/plugins/grassprovider/ext/r_mask_rast.py
@@ -15,16 +15,16 @@
***************************************************************************
"""
-__author__ = 'Médéric Ribreux'
-__date__ = 'February 2016'
-__copyright__ = '(C) 2016, Médéric Ribreux'
+__author__ = "Médéric Ribreux"
+__date__ = "February 2016"
+__copyright__ = "(C) 2016, Médéric Ribreux"
from grassprovider.grass_utils import GrassUtils
def processCommand(alg, parameters, context, feedback):
# Remove input
- alg.removeParameter('input')
+ alg.removeParameter("input")
alg.processCommand(parameters, context, feedback, True)
@@ -33,8 +33,7 @@ def processOutputs(alg, parameters, context, feedback):
metaOpt = alg.parameterAsString(parameters, alg.GRASS_RASTER_FORMAT_META, context)
# We need to export the raster with all its bands and its color table
- fileName = alg.parameterAsOutputLayer(parameters, 'output', context)
+ fileName = alg.parameterAsOutputLayer(parameters, "output", context)
outFormat = GrassUtils.getRasterFormatFromFilename(fileName)
- grassName = alg.exportedLayers['input']
- alg.exportRasterLayer(grassName, fileName, True,
- outFormat, createOpt, metaOpt)
+ grassName = alg.exportedLayers["input"]
+ alg.exportRasterLayer(grassName, fileName, True, outFormat, createOpt, metaOpt)
diff --git a/python/plugins/grassprovider/ext/r_mask_vect.py b/python/plugins/grassprovider/ext/r_mask_vect.py
index 40e5fb2c3f73..f0a768fcb3b9 100644
--- a/python/plugins/grassprovider/ext/r_mask_vect.py
+++ b/python/plugins/grassprovider/ext/r_mask_vect.py
@@ -15,16 +15,16 @@
***************************************************************************
"""
-__author__ = 'Médéric Ribreux'
-__date__ = 'February 2016'
-__copyright__ = '(C) 2016, Médéric Ribreux'
+__author__ = "Médéric Ribreux"
+__date__ = "February 2016"
+__copyright__ = "(C) 2016, Médéric Ribreux"
from grassprovider.grass_utils import GrassUtils
def processCommand(alg, parameters, context, feedback):
# Remove input
- alg.removeParameter('input')
+ alg.removeParameter("input")
alg.processCommand(parameters, context, feedback, True)
@@ -33,8 +33,7 @@ def processOutputs(alg, parameters, context, feedback):
metaOpt = alg.parameterAsString(parameters, alg.GRASS_RASTER_FORMAT_META, context)
# We need to export the raster with all its bands and its color table
- fileName = alg.parameterAsOutputLayer(parameters, 'output', context)
+ fileName = alg.parameterAsOutputLayer(parameters, "output", context)
outFormat = GrassUtils.getRasterFormatFromFilename(fileName)
- grassName = alg.exportedLayers['input']
- alg.exportRasterLayer(grassName, fileName, True,
- outFormat, createOpt, metaOpt)
+ grassName = alg.exportedLayers["input"]
+ alg.exportRasterLayer(grassName, fileName, True, outFormat, createOpt, metaOpt)
diff --git a/python/plugins/grassprovider/ext/r_neighbors.py b/python/plugins/grassprovider/ext/r_neighbors.py
index 256b0313912c..d01f3c45a2dc 100644
--- a/python/plugins/grassprovider/ext/r_neighbors.py
+++ b/python/plugins/grassprovider/ext/r_neighbors.py
@@ -15,15 +15,15 @@
***************************************************************************
"""
-__author__ = 'Nicolas Godet'
-__date__ = 'June 2021'
-__copyright__ = '(C) 2021, Nicolas Godet'
+__author__ = "Nicolas Godet"
+__date__ = "June 2021"
+__copyright__ = "(C) 2021, Nicolas Godet"
def checkParameterValuesBeforeExecuting(alg, parameters, context):
- """ Verify if we have the right parameters """
+ """Verify if we have the right parameters"""
# Verifiy that neighborhood size is odd
- if (alg.parameterAsInt(parameters, 'size', context) % 2) == 0:
+ if (alg.parameterAsInt(parameters, "size", context) % 2) == 0:
return False, alg.tr("The neighborhood size must be odd!")
return True, None
diff --git a/python/plugins/grassprovider/ext/r_null.py b/python/plugins/grassprovider/ext/r_null.py
index a3a1d0e82e71..1df7db79d716 100644
--- a/python/plugins/grassprovider/ext/r_null.py
+++ b/python/plugins/grassprovider/ext/r_null.py
@@ -15,27 +15,30 @@
***************************************************************************
"""
-__author__ = 'Médéric Ribreux'
-__date__ = 'February 2016'
-__copyright__ = '(C) 2016, Médéric Ribreux'
+__author__ = "Médéric Ribreux"
+__date__ = "February 2016"
+__copyright__ = "(C) 2016, Médéric Ribreux"
def checkParameterValuesBeforeExecuting(alg, parameters, context):
- """ Verify if we have the right parameters """
- if (alg.parameterAsString(parameters, 'setnull', context)
- or alg.parameterAsString(parameters, 'null', context)):
+ """Verify if we have the right parameters"""
+ if alg.parameterAsString(parameters, "setnull", context) or alg.parameterAsString(
+ parameters, "null", context
+ ):
return True, None
- return False, alg.tr("You need to set at least 'setnull' or 'null' parameters for this algorithm!")
+ return False, alg.tr(
+ "You need to set at least 'setnull' or 'null' parameters for this algorithm!"
+ )
def processInputs(alg, parameters, context, feedback):
"""Prepare the GRASS import commands"""
- if 'map' in alg.exportedLayers:
+ if "map" in alg.exportedLayers:
return
# We need to import without r.external
- alg.loadRasterLayerFromParameter('map', parameters, context, False)
+ alg.loadRasterLayerFromParameter("map", parameters, context, False)
alg.postInputs(context)
@@ -45,6 +48,6 @@ def processCommand(alg, parameters, context, feedback):
def processOutputs(alg, parameters, context, feedback):
- fileName = alg.parameterAsOutputLayer(parameters, 'output', context)
- grassName = alg.exportedLayers['map']
+ fileName = alg.parameterAsOutputLayer(parameters, "output", context)
+ grassName = alg.exportedLayers["map"]
alg.exportRasterLayer(grassName, fileName, False)
diff --git a/python/plugins/grassprovider/ext/r_proj.py b/python/plugins/grassprovider/ext/r_proj.py
index 46d0f7549308..5899948ed329 100644
--- a/python/plugins/grassprovider/ext/r_proj.py
+++ b/python/plugins/grassprovider/ext/r_proj.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Médéric Ribreux'
-__date__ = 'October 2017'
-__copyright__ = '(C) 2017, Médéric Ribreux'
+__author__ = "Médéric Ribreux"
+__date__ = "October 2017"
+__copyright__ = "(C) 2017, Médéric Ribreux"
from qgis.core import QgsProcessingParameterString
from processing.tools.system import isWindows
@@ -26,50 +26,51 @@
def processInputs(alg, parameters, context, feedback):
# Grab the projection from the input vector layer
- layer = alg.parameterAsLayer(parameters, 'input', context)
+ layer = alg.parameterAsLayer(parameters, "input", context)
# Creates a new location with this Crs
wkt_file_name = GrassUtils.exportCrsWktToFile(layer.crs(), context)
- newLocation = 'newProj{}'.format(alg.uniqueSuffix)
- alg.commands.append('g.proj wkt="{}" location={}'.format(
- wkt_file_name, newLocation))
+ newLocation = f"newProj{alg.uniqueSuffix}"
+ alg.commands.append(f'g.proj wkt="{wkt_file_name}" location={newLocation}')
# Go to the newly created location
- alg.commands.append('g.mapset mapset=PERMANENT location={}'.format(
- newLocation))
+ alg.commands.append(f"g.mapset mapset=PERMANENT location={newLocation}")
# Import the layer
- alg.loadRasterLayerFromParameter(
- 'input', parameters, context, False)
+ alg.loadRasterLayerFromParameter("input", parameters, context, False)
# Go back to default location
- alg.commands.append('g.mapset mapset=PERMANENT location=temp_location')
+ alg.commands.append("g.mapset mapset=PERMANENT location=temp_location")
# Grab the projected Crs
- crs = alg.parameterAsCrs(parameters, 'crs', context)
+ crs = alg.parameterAsCrs(parameters, "crs", context)
wkt_file_name = GrassUtils.exportCrsWktToFile(crs, context)
- alg.commands.append('g.proj -c wkt="{}"'.format(wkt_file_name))
+ alg.commands.append(f'g.proj -c wkt="{wkt_file_name}"')
# Remove crs parameter
- alg.removeParameter('crs')
+ alg.removeParameter("crs")
# Add the location parameter with proper value
location = QgsProcessingParameterString(
- 'location',
- 'new location',
- 'newProj{}'.format(alg.uniqueSuffix)
+ "location", "new location", f"newProj{alg.uniqueSuffix}"
)
alg.addParameter(location)
# And set the region
- grassName = alg.exportedLayers['input']
+ grassName = alg.exportedLayers["input"]
# We use the shell to capture the results from r.proj -g
if isWindows():
# TODO: make some tests under a non POSIX shell
- alg.commands.append('set regVar=')
- alg.commands.append('for /f "delims=" %%a in (\'r.proj -g input^="{}" location^="{}"\') do @set regVar=%%a'.format(
- grassName, newLocation))
- alg.commands.append('g.region -a %regVar%')
+ alg.commands.append("set regVar=")
+ alg.commands.append(
+ 'for /f "delims=" %%a in (\'r.proj -g input^="{}" location^="{}"\') do @set regVar=%%a'.format(
+ grassName, newLocation
+ )
+ )
+ alg.commands.append("g.region -a %regVar%")
else:
- alg.commands.append('g.region -a $(r.proj -g input="{}" location="{}")'.format(
- grassName, newLocation))
+ alg.commands.append(
+ 'g.region -a $(r.proj -g input="{}" location="{}")'.format(
+ grassName, newLocation
+ )
+ )
diff --git a/python/plugins/grassprovider/ext/r_reclass.py b/python/plugins/grassprovider/ext/r_reclass.py
index f29bf528b127..13cfb74f5793 100644
--- a/python/plugins/grassprovider/ext/r_reclass.py
+++ b/python/plugins/grassprovider/ext/r_reclass.py
@@ -15,25 +15,28 @@
***************************************************************************
"""
-__author__ = 'Médéric Ribreux'
-__date__ = 'February 2016'
-__copyright__ = '(C) 2016, Médéric Ribreux'
+__author__ = "Médéric Ribreux"
+__date__ = "February 2016"
+__copyright__ = "(C) 2016, Médéric Ribreux"
from processing.tools.system import getTempFilename
def checkParameterValuesBeforeExecuting(alg, parameters, context):
- """ Verify if we have the right parameters """
- if (alg.parameterAsString(parameters, 'rules', context)
- and alg.parameterAsString(parameters, 'txtrules', context)):
- return False, alg.tr("You need to set either a rules file or write directly the rules!")
+ """Verify if we have the right parameters"""
+ if alg.parameterAsString(parameters, "rules", context) and alg.parameterAsString(
+ parameters, "txtrules", context
+ ):
+ return False, alg.tr(
+ "You need to set either a rules file or write directly the rules!"
+ )
return True, None
def processCommand(alg, parameters, context, feedback):
- """ Handle inline rules """
- txtRules = alg.parameterAsString(parameters, 'txtrules', context)
+ """Handle inline rules"""
+ txtRules = alg.parameterAsString(parameters, "txtrules", context)
if txtRules:
# Creates a temporary txt file
tempRulesName = getTempFilename(context=context)
@@ -41,7 +44,7 @@ def processCommand(alg, parameters, context, feedback):
# Inject rules into temporary txt file
with open(tempRulesName, "w") as tempRules:
tempRules.write(txtRules)
- alg.removeParameter('txtrules')
- parameters['rules'] = tempRulesName
+ alg.removeParameter("txtrules")
+ parameters["rules"] = tempRulesName
alg.processCommand(parameters, context, feedback)
diff --git a/python/plugins/grassprovider/ext/r_resamp_filter.py b/python/plugins/grassprovider/ext/r_resamp_filter.py
index df57b247b771..7b0453c9bb38 100644
--- a/python/plugins/grassprovider/ext/r_resamp_filter.py
+++ b/python/plugins/grassprovider/ext/r_resamp_filter.py
@@ -15,18 +15,20 @@
***************************************************************************
"""
-__author__ = 'Médéric Ribreux'
-__date__ = 'February 2016'
-__copyright__ = '(C) 2016, Médéric Ribreux'
+__author__ = "Médéric Ribreux"
+__date__ = "February 2016"
+__copyright__ = "(C) 2016, Médéric Ribreux"
def checkParameterValuesBeforeExecuting(alg, parameters, context):
- """ Verify if we have the right parameters """
- radius = alg.parameterAsString(parameters, 'radius', context)
- x_radius = alg.parameterAsString(parameters, 'x_radius', context)
- y_radius = alg.parameterAsString(parameters, 'y_radius', context)
+ """Verify if we have the right parameters"""
+ radius = alg.parameterAsString(parameters, "radius", context)
+ x_radius = alg.parameterAsString(parameters, "x_radius", context)
+ y_radius = alg.parameterAsString(parameters, "y_radius", context)
- if (not radius and not x_radius and not y_radius) or (radius and (x_radius or y_radius)):
+ if (not radius and not x_radius and not y_radius) or (
+ radius and (x_radius or y_radius)
+ ):
return False, alg.tr("You need to set either radius or x_radius and y_radius!")
elif (x_radius and not y_radius) or (y_radius and not x_radius):
return False, alg.tr("You need to set x_radius and y_radius!")
diff --git a/python/plugins/grassprovider/ext/r_rgb.py b/python/plugins/grassprovider/ext/r_rgb.py
index bc8d3e7b3daf..257912a7539a 100644
--- a/python/plugins/grassprovider/ext/r_rgb.py
+++ b/python/plugins/grassprovider/ext/r_rgb.py
@@ -15,45 +15,47 @@
***************************************************************************
"""
-__author__ = 'Médéric Ribreux'
-__date__ = 'February 2016'
-__copyright__ = '(C) 2016, Médéric Ribreux'
+__author__ = "Médéric Ribreux"
+__date__ = "February 2016"
+__copyright__ = "(C) 2016, Médéric Ribreux"
def processInputs(alg, parameters, context, feedback):
- if 'input' in alg.exportedLayers:
+ if "input" in alg.exportedLayers:
return
# We need to import all the bands and color tables of the input raster
- alg.loadRasterLayerFromParameter('input', parameters, context, False, None)
+ alg.loadRasterLayerFromParameter("input", parameters, context, False, None)
alg.postInputs(context)
def processCommand(alg, parameters, context, feedback):
# if the input raster is multiband: export each component directly
- rasterInput = alg.exportedLayers['input']
- raster = alg.parameterAsRasterLayer(parameters, 'input', context)
- for color in ['red', 'green', 'blue']:
+ rasterInput = alg.exportedLayers["input"]
+ raster = alg.parameterAsRasterLayer(parameters, "input", context)
+ for color in ["red", "green", "blue"]:
alg.exportedLayers[color] = color + alg.uniqueSuffix
# If the raster is not multiband, really do r.rgb
if raster.bandCount() == 1:
- alg.commands.append(" r.rgb input={} red={} green={} blue={} --overwrite".format(
- rasterInput,
- alg.exportedLayers['red'],
- alg.exportedLayers['green'],
- alg.exportedLayers['blue']
- ))
+ alg.commands.append(
+ " r.rgb input={} red={} green={} blue={} --overwrite".format(
+ rasterInput,
+ alg.exportedLayers["red"],
+ alg.exportedLayers["green"],
+ alg.exportedLayers["blue"],
+ )
+ )
def processOutputs(alg, parameters, context, feedback):
- raster = alg.parameterAsRasterLayer(parameters, 'input', context)
+ raster = alg.parameterAsRasterLayer(parameters, "input", context)
# if the raster was monoband, export from r.rgb
- for color in ['red', 'green', 'blue']:
+ for color in ["red", "green", "blue"]:
fileName = alg.parameterAsOutputLayer(parameters, color, context)
if raster.bandCount() == 1:
- grassName = '{}{}'.format(color, alg.uniqueSuffix)
+ grassName = f"{color}{alg.uniqueSuffix}"
else:
- grassName = '{}.{}'.format(alg.exportedLayers['input'], color)
+ grassName = "{}.{}".format(alg.exportedLayers["input"], color)
alg.exportRasterLayer(grassName, fileName, True)
diff --git a/python/plugins/grassprovider/ext/r_series_interp.py b/python/plugins/grassprovider/ext/r_series_interp.py
index 0135c46d3f5b..4a4cd6462d50 100644
--- a/python/plugins/grassprovider/ext/r_series_interp.py
+++ b/python/plugins/grassprovider/ext/r_series_interp.py
@@ -15,27 +15,33 @@
***************************************************************************
"""
-__author__ = 'Médéric Ribreux'
-__date__ = 'February 2016'
-__copyright__ = '(C) 2016, Médéric Ribreux'
+__author__ = "Médéric Ribreux"
+__date__ = "February 2016"
+__copyright__ = "(C) 2016, Médéric Ribreux"
import os
from grassprovider.grass_utils import GrassUtils
def checkParameterValuesBeforeExecuting(alg, parameters, context):
- """ Verify if we have the right parameters """
- datapos = alg.parameterAsDouble(parameters, 'datapos', context)
- infile = alg.parameterAsString(parameters, 'infile', context)
- output = alg.parameterAsString(parameters, 'output', context)
- outfile = alg.parameterAsString(parameters, 'outfile', context)
+ """Verify if we have the right parameters"""
+ datapos = alg.parameterAsDouble(parameters, "datapos", context)
+ infile = alg.parameterAsString(parameters, "infile", context)
+ output = alg.parameterAsString(parameters, "output", context)
+ outfile = alg.parameterAsString(parameters, "outfile", context)
if datapos and infile:
- return False, alg.tr("You need to set either inline data positions or an input data positions file!")
+ return False, alg.tr(
+ "You need to set either inline data positions or an input data positions file!"
+ )
if output and outfile:
- return False, alg.tr("You need to set either sampling data positions or an output sampling data positions file!")
+ return False, alg.tr(
+ "You need to set either sampling data positions or an output sampling data positions file!"
+ )
if not (datapos or infile or output or outfile):
- return False, alg.tr("You need to set input and output data positions parameters!")
+ return False, alg.tr(
+ "You need to set input and output data positions parameters!"
+ )
return True, None
@@ -46,18 +52,18 @@ def processCommand(alg, parameters, context, feedback):
def processOutputs(alg, parameters, context, feedback):
# We take all the outputs and we export them to the output directory
- outputDir = alg.parameterAsString(parameters, 'output_dir', context)
- output = alg.parameterAsString(parameters, 'output', context)
- outfile = alg.parameterAsString(parameters, 'outfile', context)
+ outputDir = alg.parameterAsString(parameters, "output_dir", context)
+ output = alg.parameterAsString(parameters, "output", context)
+ outfile = alg.parameterAsString(parameters, "outfile", context)
outs = []
if output:
- outs = output.split(',')
+ outs = output.split(",")
elif outfile:
# Handle file manually to find the name of the layers
with open(outfile) as f:
for line in f:
- if '|' in line:
- outs.append(line.split('|')[0])
+ if "|" in line:
+ outs.append(line.split("|")[0])
createOpt = alg.parameterAsString(parameters, alg.GRASS_RASTER_FORMAT_OPT, context)
metaOpt = alg.parameterAsString(parameters, alg.GRASS_RASTER_FORMAT_META, context)
@@ -66,5 +72,4 @@ def processOutputs(alg, parameters, context, feedback):
# We need to export the raster with all its bands and its color table
fileName = os.path.join(outputDir, out)
outFormat = GrassUtils.getRasterFormatFromFilename(fileName)
- alg.exportRasterLayer(out, fileName, True,
- outFormat, createOpt, metaOpt)
+ alg.exportRasterLayer(out, fileName, True, outFormat, createOpt, metaOpt)
diff --git a/python/plugins/grassprovider/ext/r_shade.py b/python/plugins/grassprovider/ext/r_shade.py
index bcd6d7aa5a20..2e5588a56733 100644
--- a/python/plugins/grassprovider/ext/r_shade.py
+++ b/python/plugins/grassprovider/ext/r_shade.py
@@ -15,19 +15,17 @@
***************************************************************************
"""
-__author__ = 'Médéric Ribreux'
-__date__ = 'February 2016'
-__copyright__ = '(C) 2016, Médéric Ribreux'
+__author__ = "Médéric Ribreux"
+__date__ = "February 2016"
+__copyright__ = "(C) 2016, Médéric Ribreux"
def processInputs(alg, parameters, context, feedback):
# We need to import all the bands and color tables of the input rasters
- alg.loadRasterLayerFromParameter('shade', parameters, context,
- False, None)
- alg.loadRasterLayerFromParameter('color', parameters, context,
- False, None)
+ alg.loadRasterLayerFromParameter("shade", parameters, context, False, None)
+ alg.loadRasterLayerFromParameter("color", parameters, context, False, None)
def processOutputs(alg, parameters, context, feedback):
# Keep color table
- alg.exportRasterLayerFromParameter('output', parameters, context, True)
+ alg.exportRasterLayerFromParameter("output", parameters, context, True)
diff --git a/python/plugins/grassprovider/ext/r_statistics.py b/python/plugins/grassprovider/ext/r_statistics.py
index 11f403c70782..b822eaa3bc62 100644
--- a/python/plugins/grassprovider/ext/r_statistics.py
+++ b/python/plugins/grassprovider/ext/r_statistics.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Médéric Ribreux'
-__date__ = 'September 2017'
-__copyright__ = '(C) 2017, Médéric Ribreux'
+__author__ = "Médéric Ribreux"
+__date__ = "September 2017"
+__copyright__ = "(C) 2017, Médéric Ribreux"
from qgis.core import QgsProcessingParameterString
from grassprovider.grass_utils import GrassUtils
@@ -25,17 +25,16 @@
def processCommand(alg, parameters, context, feedback):
# We had a new "output" parameter
- out = 'output{}'.format(alg.uniqueSuffix)
- p = QgsProcessingParameterString('~output', None, out, False, False)
+ out = f"output{alg.uniqueSuffix}"
+ p = QgsProcessingParameterString("~output", None, out, False, False)
alg.addParameter(p)
# We need to remove all outputs
alg.processCommand(parameters, context, feedback, True)
# Then we add a new command for treating results
- calcExpression = 'correctedoutput{}=@{}'.format(
- alg.uniqueSuffix, out)
- command = 'r.mapcalc expression="{}"'.format(calcExpression)
+ calcExpression = f"correctedoutput{alg.uniqueSuffix}=@{out}"
+ command = f'r.mapcalc expression="{calcExpression}"'
alg.commands.append(command)
@@ -44,9 +43,7 @@ def processOutputs(alg, parameters, context, feedback):
metaOpt = alg.parameterAsString(parameters, alg.GRASS_RASTER_FORMAT_META, context)
# Export the results from correctedoutput
- grassName = 'correctedoutput{}'.format(alg.uniqueSuffix)
- fileName = alg.parameterAsOutputLayer(
- parameters, 'routput', context)
+ grassName = f"correctedoutput{alg.uniqueSuffix}"
+ fileName = alg.parameterAsOutputLayer(parameters, "routput", context)
outFormat = GrassUtils.getRasterFormatFromFilename(fileName)
- alg.exportRasterLayer(grassName, fileName, True,
- outFormat, createOpt, metaOpt)
+ alg.exportRasterLayer(grassName, fileName, True, outFormat, createOpt, metaOpt)
diff --git a/python/plugins/grassprovider/ext/r_stats_quantile_rast.py b/python/plugins/grassprovider/ext/r_stats_quantile_rast.py
index ccd8e4ca6316..d66490ba1350 100644
--- a/python/plugins/grassprovider/ext/r_stats_quantile_rast.py
+++ b/python/plugins/grassprovider/ext/r_stats_quantile_rast.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Médéric Ribreux'
-__date__ = 'February 2016'
-__copyright__ = '(C) 2016, Médéric Ribreux'
+__author__ = "Médéric Ribreux"
+__date__ = "February 2016"
+__copyright__ = "(C) 2016, Médéric Ribreux"
import os
from qgis.core import QgsProcessingParameterString
@@ -26,13 +26,13 @@
def processCommand(alg, parameters, context, feedback):
# We create the output sequence according to percentiles number
- quantiles = alg.parameterAsInt(parameters, 'quantiles', context) - 1
+ quantiles = alg.parameterAsInt(parameters, "quantiles", context) - 1
outputs = []
for i in range(0, int(quantiles)):
- outputs.append('output_{}'.format(i))
+ outputs.append(f"output_{i}")
param = QgsProcessingParameterString(
- 'output', 'virtual output',
- ','.join(outputs), False, False)
+ "output", "virtual output", ",".join(outputs), False, False
+ )
alg.addParameter(param)
# Removes outputs
@@ -42,13 +42,12 @@ def processCommand(alg, parameters, context, feedback):
def processOutputs(alg, parameters, context, feedback):
createOpt = alg.parameterAsString(parameters, alg.GRASS_RASTER_FORMAT_OPT, context)
metaOpt = alg.parameterAsString(parameters, alg.GRASS_RASTER_FORMAT_META, context)
- outputDir = alg.parameterAsString(parameters, 'output_dir', context)
- outputParam = alg.parameterAsString(parameters, 'output', context)
- outputs = outputParam.split(',')
+ outputDir = alg.parameterAsString(parameters, "output_dir", context)
+ outputParam = alg.parameterAsString(parameters, "output", context)
+ outputs = outputParam.split(",")
# We need to export each of the output
for output in outputs:
fileName = os.path.join(outputDir, output)
outFormat = GrassUtils.getRasterFormatFromFilename(fileName)
- alg.exportRasterLayer(output, fileName, True,
- outFormat, createOpt, metaOpt)
+ alg.exportRasterLayer(output, fileName, True, outFormat, createOpt, metaOpt)
diff --git a/python/plugins/grassprovider/ext/r_tileset.py b/python/plugins/grassprovider/ext/r_tileset.py
index 15d8c8deb904..54de52025936 100644
--- a/python/plugins/grassprovider/ext/r_tileset.py
+++ b/python/plugins/grassprovider/ext/r_tileset.py
@@ -15,15 +15,15 @@
***************************************************************************
"""
-__author__ = 'Médéric Ribreux'
-__date__ = 'October 2017'
-__copyright__ = '(C) 2017, Médéric Ribreux'
+__author__ = "Médéric Ribreux"
+__date__ = "October 2017"
+__copyright__ = "(C) 2017, Médéric Ribreux"
from grassprovider.grass_utils import GrassUtils
def processOutputs(alg, parameters, context, feedback):
- crs = alg.parameterAsCrs(parameters, 'sourceproj', context)
+ crs = alg.parameterAsCrs(parameters, "sourceproj", context)
wkt_file_name = GrassUtils.exportCrsWktToFile(crs, context)
- alg.commands.insert(0, 'g.proj -c wkt="{}"'.format(wkt_file_name))
+ alg.commands.insert(0, f'g.proj -c wkt="{wkt_file_name}"')
diff --git a/python/plugins/grassprovider/ext/r_what_color.py b/python/plugins/grassprovider/ext/r_what_color.py
index 9995e55922e4..ecf352a7935f 100644
--- a/python/plugins/grassprovider/ext/r_what_color.py
+++ b/python/plugins/grassprovider/ext/r_what_color.py
@@ -15,11 +15,11 @@
***************************************************************************
"""
-__author__ = 'Médéric Ribreux'
-__date__ = 'February 2016'
-__copyright__ = '(C) 2016, Médéric Ribreux'
+__author__ = "Médéric Ribreux"
+__date__ = "February 2016"
+__copyright__ = "(C) 2016, Médéric Ribreux"
def processInputs(alg, parameters, context, feedback):
# We need to import all the bands and color tables of the input rasters
- alg.loadRasterLayerFromParameter('input', parameters, context, False, None)
+ alg.loadRasterLayerFromParameter("input", parameters, context, False, None)
diff --git a/python/plugins/grassprovider/ext/v_distance.py b/python/plugins/grassprovider/ext/v_distance.py
index 7f1768d299cf..bf4ba6bf4d19 100644
--- a/python/plugins/grassprovider/ext/v_distance.py
+++ b/python/plugins/grassprovider/ext/v_distance.py
@@ -15,36 +15,42 @@
***************************************************************************
"""
-__author__ = 'Médéric Ribreux'
-__date__ = 'February 2016'
-__copyright__ = '(C) 2016, Médéric Ribreux'
+__author__ = "Médéric Ribreux"
+__date__ = "February 2016"
+__copyright__ = "(C) 2016, Médéric Ribreux"
from qgis.core import QgsProcessingParameterDefinition
def checkParameterValuesBeforeExecuting(alg, parameters, context):
- """ Verify if we have the right parameters """
+ """Verify if we have the right parameters"""
# Verifiy that we have the good number of columns
- uploads = alg.parameterAsEnums(parameters, 'upload', context)
- columns = alg.parameterAsFields(parameters, 'column', context)
+ uploads = alg.parameterAsEnums(parameters, "upload", context)
+ columns = alg.parameterAsFields(parameters, "column", context)
if len(columns) != len(uploads):
- return False, alg.tr("The number of columns and the number of upload parameters should be equal!")
+ return False, alg.tr(
+ "The number of columns and the number of upload parameters should be equal!"
+ )
return True, None
def processCommand(alg, parameters, context, feedback):
# We need to disable only from_output parameter
- fromOutput = alg.parameterDefinition('from_output')
- fromOutput.setFlags(fromOutput.flags() | QgsProcessingParameterDefinition.Flag.FlagHidden)
+ fromOutput = alg.parameterDefinition("from_output")
+ fromOutput.setFlags(
+ fromOutput.flags() | QgsProcessingParameterDefinition.Flag.FlagHidden
+ )
alg.processCommand(parameters, context, feedback, False)
- fromOutput.setFlags(fromOutput.flags() | QgsProcessingParameterDefinition.Flag.FlagHidden)
+ fromOutput.setFlags(
+ fromOutput.flags() | QgsProcessingParameterDefinition.Flag.FlagHidden
+ )
def processOutputs(alg, parameters, context, feedback):
alg.vectorOutputType(parameters, context)
- alg.exportVectorLayerFromParameter('output', parameters, context)
+ alg.exportVectorLayerFromParameter("output", parameters, context)
# for from_output, we export the initial layer
- fileName = alg.parameterAsOutputLayer(parameters, 'from_output', context)
- grassName = alg.exportedLayers['from']
+ fileName = alg.parameterAsOutputLayer(parameters, "from_output", context)
+ grassName = alg.exportedLayers["from"]
alg.exportVectorLayer(grassName, fileName)
diff --git a/python/plugins/grassprovider/ext/v_edit.py b/python/plugins/grassprovider/ext/v_edit.py
index 3091044ebd21..222741e13954 100644
--- a/python/plugins/grassprovider/ext/v_edit.py
+++ b/python/plugins/grassprovider/ext/v_edit.py
@@ -15,26 +15,29 @@
***************************************************************************
"""
-__author__ = 'Médéric Ribreux'
-__date__ = 'March 2016'
-__copyright__ = '(C) 2016, Médéric Ribreux'
+__author__ = "Médéric Ribreux"
+__date__ = "March 2016"
+__copyright__ = "(C) 2016, Médéric Ribreux"
import os
from processing.tools.system import getTempFilename
def checkParameterValuesBeforeExecuting(alg, parameters, context):
- """ Verify if we have the right parameters """
- if (alg.parameterAsString(parameters, 'input_txt', context)
- and alg.parameterAsString(parameters, 'input', context)):
- return False, alg.tr("You need to set either an input ASCII file or inline data!")
+ """Verify if we have the right parameters"""
+ if alg.parameterAsString(
+ parameters, "input_txt", context
+ ) and alg.parameterAsString(parameters, "input", context):
+ return False, alg.tr(
+ "You need to set either an input ASCII file or inline data!"
+ )
return True, None
def processCommand(alg, parameters, context, feedback):
# Handle inline rules
- txtRules = alg.parameterAsString(parameters, 'input_txt', context)
+ txtRules = alg.parameterAsString(parameters, "input_txt", context)
if txtRules:
# Creates a temporary txt file
tempRulesName = getTempFilename(context=context)
@@ -42,15 +45,15 @@ def processCommand(alg, parameters, context, feedback):
# Inject rules into temporary txt file
with open(tempRulesName, "w") as tempRules:
tempRules.write(txtRules)
- alg.removeParameter('input_txt')
- parameters['input'] = tempRulesName
+ alg.removeParameter("input_txt")
+ parameters["input"] = tempRulesName
alg.processCommand(parameters, context, feedback, True)
def processOutputs(alg, parameters, context, feedback):
# We need to add the from layer to outputs:
- fileName = alg.parameterAsOutputLayer(parameters, 'output', context)
- grassName = alg.exportedLayers['map']
- dataType = 'auto'
+ fileName = alg.parameterAsOutputLayer(parameters, "output", context)
+ grassName = alg.exportedLayers["map"]
+ dataType = "auto"
alg.exportVectorLayer(grassName, fileName, dataType=dataType)
diff --git a/python/plugins/grassprovider/ext/v_extrude.py b/python/plugins/grassprovider/ext/v_extrude.py
index 487eb451769f..8ceb33b50293 100644
--- a/python/plugins/grassprovider/ext/v_extrude.py
+++ b/python/plugins/grassprovider/ext/v_extrude.py
@@ -15,16 +15,18 @@
***************************************************************************
"""
-__author__ = 'Médéric Ribreux'
-__date__ = 'March 2016'
-__copyright__ = '(C) 2016, Médéric Ribreux'
+__author__ = "Médéric Ribreux"
+__date__ = "March 2016"
+__copyright__ = "(C) 2016, Médéric Ribreux"
def checkParameterValuesBeforeExecuting(alg, parameters, context):
- """ Verify if we have the right parameters """
- height = alg.parameterAsDouble(parameters, 'height', context)
- height_column = alg.parameterAsString(parameters, 'height_column', context)
+ """Verify if we have the right parameters"""
+ height = alg.parameterAsDouble(parameters, "height", context)
+ height_column = alg.parameterAsString(parameters, "height_column", context)
if (height and height_column) or (not height and not height_column):
- return False, alg.tr("You need to set either a fixed height value or the height column!")
+ return False, alg.tr(
+ "You need to set either a fixed height value or the height column!"
+ )
return True, None
diff --git a/python/plugins/grassprovider/ext/v_in_geonames.py b/python/plugins/grassprovider/ext/v_in_geonames.py
index 569628f9b5e9..bd7ab4d38413 100644
--- a/python/plugins/grassprovider/ext/v_in_geonames.py
+++ b/python/plugins/grassprovider/ext/v_in_geonames.py
@@ -15,14 +15,14 @@
***************************************************************************
"""
-__author__ = 'Médéric Ribreux'
-__date__ = 'March 2016'
-__copyright__ = '(C) 2016, Médéric Ribreux'
+__author__ = "Médéric Ribreux"
+__date__ = "March 2016"
+__copyright__ = "(C) 2016, Médéric Ribreux"
def processCommand(alg, parameters, context, feedback):
# v.in.geonames needs to use WGS84 projection
- alg.commands.append('g.proj -c epsg=4326')
+ alg.commands.append("g.proj -c epsg=4326")
# Launch the algorithm
alg.processCommand(parameters, context, feedback)
diff --git a/python/plugins/grassprovider/ext/v_net.py b/python/plugins/grassprovider/ext/v_net.py
index 35d056a7dd2b..db4ac2513c4a 100644
--- a/python/plugins/grassprovider/ext/v_net.py
+++ b/python/plugins/grassprovider/ext/v_net.py
@@ -19,16 +19,23 @@
the network vector map.
"""
-__author__ = 'Médéric Ribreux'
-__date__ = 'December 2015'
-__copyright__ = '(C) 2015, Médéric Ribreux'
+__author__ = "Médéric Ribreux"
+__date__ = "December 2015"
+__copyright__ = "(C) 2015, Médéric Ribreux"
import os
from qgis.core import QgsProcessingException
from processing.tools.system import getTempFilename
-def incorporatePoints(alg, parameters, context, feedback, pointLayerName='points', networkLayerName='input'):
+def incorporatePoints(
+ alg,
+ parameters,
+ context,
+ feedback,
+ pointLayerName="points",
+ networkLayerName="input",
+):
"""
incorporate points with lines to form a GRASS network
"""
@@ -37,7 +44,7 @@ def incorporatePoints(alg, parameters, context, feedback, pointLayerName='points
pointLayer = alg.parameterAsVectorLayer(parameters, pointLayerName, context)
if pointLayer:
# Create an intermediate GRASS layer which is the combination of network + centers
- intLayer = 'net' + os.path.basename(getTempFilename(context=context))
+ intLayer = "net" + os.path.basename(getTempFilename(context=context))
pointLayer = alg.exportedLayers[pointLayerName]
@@ -47,17 +54,19 @@ def incorporatePoints(alg, parameters, context, feedback, pointLayerName='points
lineLayer = alg.exportedLayers[networkLayerName]
else:
raise QgsProcessingException(
- alg.tr('GRASS GIS v.net requires a lines layer!'))
+ alg.tr("GRASS GIS v.net requires a lines layer!")
+ )
- threshold = alg.parameterAsDouble(parameters, 'threshold', context)
+ threshold = alg.parameterAsDouble(parameters, "threshold", context)
# Create the v.net connect command for point layer integration
- command = 'v.net -s input={} points={} output={} operation=connect threshold={}'.format(
- lineLayer, pointLayer, intLayer, threshold)
+ command = "v.net -s input={} points={} output={} operation=connect threshold={}".format(
+ lineLayer, pointLayer, intLayer, threshold
+ )
alg.commands.append(command)
# Connect the point layer database to the layer 2 of the network
- command = 'v.db.connect -o map={} table={} layer=2'.format(intLayer, pointLayer)
+ command = f"v.db.connect -o map={intLayer} table={pointLayer} layer=2"
alg.commands.append(command)
# remove undesired parameters
@@ -67,14 +76,14 @@ def incorporatePoints(alg, parameters, context, feedback, pointLayerName='points
alg.exportedLayers[networkLayerName] = intLayer
# Process the command
- if 'threshold' in parameters:
- alg.removeParameter('threshold')
+ if "threshold" in parameters:
+ alg.removeParameter("threshold")
alg.processCommand(parameters, context, feedback)
def variableOutput(alg, layers, parameters, context, nocats=True):
- """ Handle variable data output for v.net modules:
+ """Handle variable data output for v.net modules:
:param layers:
layers is a dict of outputs:
{ 'outputName': ['srcLayer', 'output_type', output_layer_number, nocats],
@@ -101,23 +110,25 @@ def variableOutput(alg, layers, parameters, context, nocats=True):
output_layer_number = typeList[2]
no_cats = typeList[3]
- grass_name = '{}{}'.format(src_layer, alg.uniqueSuffix)
- alg.exportVectorLayer(grassName=grass_name,
- fileName=file_name,
- layer=output_layer_number,
- exportnocat=no_cats,
- dataType=output_type)
+ grass_name = f"{src_layer}{alg.uniqueSuffix}"
+ alg.exportVectorLayer(
+ grassName=grass_name,
+ fileName=file_name,
+ layer=output_layer_number,
+ exportnocat=no_cats,
+ dataType=output_type,
+ )
def processOutputs(alg, parameters, context, feedback):
- idx = alg.parameterAsInt(parameters, 'operation', context)
- operations = alg.parameterDefinition('operation').options()
+ idx = alg.parameterAsInt(parameters, "operation", context)
+ operations = alg.parameterDefinition("operation").options()
operation = operations[idx]
- if operation == 'nodes':
- outputParameter = {'output': ['output', 'point', 2, True]}
- elif operation == 'connect':
- outputParameter = {'output': ['output', 'line', 1, False]}
- elif operation == 'arcs':
- outputParameter = {'output': ['output', 'line', 1, True]}
+ if operation == "nodes":
+ outputParameter = {"output": ["output", "point", 2, True]}
+ elif operation == "connect":
+ outputParameter = {"output": ["output", "line", 1, False]}
+ elif operation == "arcs":
+ outputParameter = {"output": ["output", "line", 1, True]}
variableOutput(alg, outputParameter, parameters, context)
diff --git a/python/plugins/grassprovider/ext/v_net_alloc.py b/python/plugins/grassprovider/ext/v_net_alloc.py
index 10f0844a8767..0b4d6aa13ed4 100644
--- a/python/plugins/grassprovider/ext/v_net_alloc.py
+++ b/python/plugins/grassprovider/ext/v_net_alloc.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Médéric Ribreux'
-__date__ = 'December 2015'
-__copyright__ = '(C) 2015, Médéric Ribreux'
+__author__ = "Médéric Ribreux"
+__date__ = "December 2015"
+__copyright__ = "(C) 2015, Médéric Ribreux"
from .v_net import incorporatePoints, variableOutput
@@ -27,5 +27,5 @@ def processCommand(alg, parameters, context, feedback):
def processOutputs(alg, parameters, context, feedback):
- outputParameter = {'output': ['output', 'line', 1, False]}
+ outputParameter = {"output": ["output", "line", 1, False]}
variableOutput(alg, outputParameter, parameters, context)
diff --git a/python/plugins/grassprovider/ext/v_net_allpairs.py b/python/plugins/grassprovider/ext/v_net_allpairs.py
index 43d23a668321..9823f7103442 100644
--- a/python/plugins/grassprovider/ext/v_net_allpairs.py
+++ b/python/plugins/grassprovider/ext/v_net_allpairs.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Médéric Ribreux'
-__date__ = 'December 2015'
-__copyright__ = '(C) 2015, Médéric Ribreux'
+__author__ = "Médéric Ribreux"
+__date__ = "December 2015"
+__copyright__ = "(C) 2015, Médéric Ribreux"
from .v_net import incorporatePoints, variableOutput
@@ -27,5 +27,5 @@ def processCommand(alg, parameters, context, feedback):
def processOutputs(alg, parameters, context, feedback):
- outputParameter = {'output': ['output', 'line', 1, True]}
+ outputParameter = {"output": ["output", "line", 1, True]}
variableOutput(alg, outputParameter, parameters, context)
diff --git a/python/plugins/grassprovider/ext/v_net_bridge.py b/python/plugins/grassprovider/ext/v_net_bridge.py
index 6a8ac8f35114..4a418d8d0ba3 100644
--- a/python/plugins/grassprovider/ext/v_net_bridge.py
+++ b/python/plugins/grassprovider/ext/v_net_bridge.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Médéric Ribreux'
-__date__ = 'December 2015'
-__copyright__ = '(C) 2015, Médéric Ribreux'
+__author__ = "Médéric Ribreux"
+__date__ = "December 2015"
+__copyright__ = "(C) 2015, Médéric Ribreux"
from .v_net import incorporatePoints, variableOutput
@@ -27,12 +27,12 @@ def processCommand(alg, parameters, context, feedback):
def processOutputs(alg, parameters, context, feedback):
- idx = alg.parameterAsInt(parameters, 'method', context)
- operations = alg.parameterDefinition('method').options()
+ idx = alg.parameterAsInt(parameters, "method", context)
+ operations = alg.parameterDefinition("method").options()
operation = operations[idx]
- if operation == 'articulation':
- outputParameter = {'output': ['output', 'point', 2, True]}
- elif operation == 'bridge':
- outputParameter = {'output': ['output', 'line', 1, False]}
+ if operation == "articulation":
+ outputParameter = {"output": ["output", "point", 2, True]}
+ elif operation == "bridge":
+ outputParameter = {"output": ["output", "line", 1, False]}
variableOutput(alg, outputParameter, parameters, context)
diff --git a/python/plugins/grassprovider/ext/v_net_centrality.py b/python/plugins/grassprovider/ext/v_net_centrality.py
index c3dfd92287ed..8f74e96e2c0b 100644
--- a/python/plugins/grassprovider/ext/v_net_centrality.py
+++ b/python/plugins/grassprovider/ext/v_net_centrality.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Médéric Ribreux'
-__date__ = 'December 2017'
-__copyright__ = '(C) 2017, Médéric Ribreux'
+__author__ = "Médéric Ribreux"
+__date__ = "December 2017"
+__copyright__ = "(C) 2017, Médéric Ribreux"
from .v_net import incorporatePoints, variableOutput
@@ -27,5 +27,5 @@ def processCommand(alg, parameters, context, feedback):
def processOutputs(alg, parameters, context, feedback):
- outputParameter = {'output': ['output', 'point', 1, False]}
+ outputParameter = {"output": ["output", "point", 1, False]}
variableOutput(alg, outputParameter, parameters, context)
diff --git a/python/plugins/grassprovider/ext/v_net_components.py b/python/plugins/grassprovider/ext/v_net_components.py
index a6c28f712cb2..d3580f4bc4b0 100644
--- a/python/plugins/grassprovider/ext/v_net_components.py
+++ b/python/plugins/grassprovider/ext/v_net_components.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Médéric Ribreux'
-__date__ = 'December 2015'
-__copyright__ = '(C) 2015, Médéric Ribreux'
+__author__ = "Médéric Ribreux"
+__date__ = "December 2015"
+__copyright__ = "(C) 2015, Médéric Ribreux"
from .v_net import incorporatePoints, variableOutput
from qgis.core import QgsProcessingParameterDefinition
@@ -25,13 +25,19 @@
def processCommand(alg, parameters, context, feedback):
# We need to disable only output_point parameter
- outPoint = alg.parameterDefinition('output_point')
- outPoint.setFlags(outPoint.flags() | QgsProcessingParameterDefinition.Flag.FlagHidden)
+ outPoint = alg.parameterDefinition("output_point")
+ outPoint.setFlags(
+ outPoint.flags() | QgsProcessingParameterDefinition.Flag.FlagHidden
+ )
incorporatePoints(alg, parameters, context, feedback)
- outPoint.setFlags(outPoint.flags() | QgsProcessingParameterDefinition.Flag.FlagHidden)
+ outPoint.setFlags(
+ outPoint.flags() | QgsProcessingParameterDefinition.Flag.FlagHidden
+ )
def processOutputs(alg, parameters, context, feedback):
- outputParameter = {'output': ['output', 'line', 1, True],
- 'output_point': ['output', 'point', 2, True]}
+ outputParameter = {
+ "output": ["output", "line", 1, True],
+ "output_point": ["output", "point", 2, True],
+ }
variableOutput(alg, outputParameter, parameters, context)
diff --git a/python/plugins/grassprovider/ext/v_net_connectivity.py b/python/plugins/grassprovider/ext/v_net_connectivity.py
index 72e6d7494681..cf66bce732da 100644
--- a/python/plugins/grassprovider/ext/v_net_connectivity.py
+++ b/python/plugins/grassprovider/ext/v_net_connectivity.py
@@ -15,31 +15,27 @@
***************************************************************************
"""
-__author__ = 'Médéric Ribreux'
-__date__ = 'December 2015'
-__copyright__ = '(C) 2015, Médéric Ribreux'
+__author__ = "Médéric Ribreux"
+__date__ = "December 2015"
+__copyright__ = "(C) 2015, Médéric Ribreux"
from .v_net import incorporatePoints, variableOutput
def checkParameterValuesBeforeExecuting(alg, parameters, context):
- """ Verify if we have the right parameters """
- params = ['where', 'cats']
+ """Verify if we have the right parameters"""
+ params = ["where", "cats"]
values = []
for param in params:
for i in range(1, 3):
- values.append(
- alg.parameterAsString(
- parameters,
- 'set{}_{}'.format(i, param),
- context
- )
- )
+ values.append(alg.parameterAsString(parameters, f"set{i}_{param}", context))
if (values[0] or values[2]) and (values[1] or values[3]):
return True, None
- return False, alg.tr('You need to set at least setX_where or setX_cats parameters for each set!')
+ return False, alg.tr(
+ "You need to set at least setX_where or setX_cats parameters for each set!"
+ )
def processCommand(alg, parameters, context, feedback):
@@ -47,5 +43,5 @@ def processCommand(alg, parameters, context, feedback):
def processOutputs(alg, parameters, context, feedback):
- outputParameter = {'output': ['output', 'point', 2, True]}
+ outputParameter = {"output": ["output", "point", 2, True]}
variableOutput(alg, outputParameter, parameters, context)
diff --git a/python/plugins/grassprovider/ext/v_net_distance.py b/python/plugins/grassprovider/ext/v_net_distance.py
index 574365fdab09..2ec7be3cacc6 100644
--- a/python/plugins/grassprovider/ext/v_net_distance.py
+++ b/python/plugins/grassprovider/ext/v_net_distance.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Médéric Ribreux'
-__date__ = 'December 2015'
-__copyright__ = '(C) 2015, Médéric Ribreux'
+__author__ = "Médéric Ribreux"
+__date__ = "December 2015"
+__copyright__ = "(C) 2015, Médéric Ribreux"
import os
from .v_net import variableOutput
@@ -26,51 +26,53 @@
def processCommand(alg, parameters, context, feedback):
- """ Handle data preparation for v.net.distance:
+ """Handle data preparation for v.net.distance:
* Integrate point layers into network vector map.
* Make v.net.distance use those layers.
* Delete the threshold parameter.
* If where statement, connect to the db
"""
# Grab the point layer and delete this parameter
- lineLayer = alg.exportedLayers['input']
- fromLayer = alg.exportedLayers['flayer']
- toLayer = alg.exportedLayers['tlayer']
- intLayer = 'bufnet' + os.path.basename(getTempFilename(context=context))
- netLayer = 'net' + os.path.basename(getTempFilename(context=context))
- threshold = alg.parameterAsDouble(parameters, 'threshold', context)
+ lineLayer = alg.exportedLayers["input"]
+ fromLayer = alg.exportedLayers["flayer"]
+ toLayer = alg.exportedLayers["tlayer"]
+ intLayer = "bufnet" + os.path.basename(getTempFilename(context=context))
+ netLayer = "net" + os.path.basename(getTempFilename(context=context))
+ threshold = alg.parameterAsDouble(parameters, "threshold", context)
# Create the v.net connect command for from_layer integration
- command = 'v.net -s input={} points={} output={} operation=connect threshold={} arc_layer=1 node_layer=2'.format(
- lineLayer, fromLayer, intLayer, threshold)
+ command = "v.net -s input={} points={} output={} operation=connect threshold={} arc_layer=1 node_layer=2".format(
+ lineLayer, fromLayer, intLayer, threshold
+ )
alg.commands.append(command)
# Do it again with to_layer
- command = 'v.net -s input={} points={} output={} operation=connect threshold={} arc_layer=1 node_layer=3'.format(
- intLayer, toLayer, netLayer, threshold)
+ command = "v.net -s input={} points={} output={} operation=connect threshold={} arc_layer=1 node_layer=3".format(
+ intLayer, toLayer, netLayer, threshold
+ )
alg.commands.append(command)
# Connect the point layer database to the layer 2 of the network
- command = 'v.db.connect -o map={} table={} layer=2'.format(netLayer, fromLayer)
+ command = f"v.db.connect -o map={netLayer} table={fromLayer} layer=2"
alg.commands.append(command)
- command = 'v.db.connect -o map={} table={} layer=3'.format(netLayer, toLayer)
+ command = f"v.db.connect -o map={netLayer} table={toLayer} layer=3"
alg.commands.append(command)
# remove undesired parameters
- alg.removeParameter('flayer')
- alg.removeParameter('tlayer')
- alg.removeParameter('threshold')
- alg.exportedLayers['input'] = netLayer
+ alg.removeParameter("flayer")
+ alg.removeParameter("tlayer")
+ alg.removeParameter("threshold")
+ alg.exportedLayers["input"] = netLayer
# Add the two new parameters
- fLayer = QgsProcessingParameterString('from_layer', None, 2, False, False)
+ fLayer = QgsProcessingParameterString("from_layer", None, 2, False, False)
alg.addParameter(fLayer)
- tLayer = QgsProcessingParameterString('to_layer', None, 3, False, False)
+ tLayer = QgsProcessingParameterString("to_layer", None, 3, False, False)
alg.addParameter(tLayer)
alg.processCommand(parameters, context, feedback)
def processOutputs(alg, parameters, context, feedback):
- outputParameter = {'output': ['output', 'line', 1, True]}
+ outputParameter = {"output": ["output", "line", 1, True]}
variableOutput(alg, outputParameter, parameters, context)
diff --git a/python/plugins/grassprovider/ext/v_net_flow.py b/python/plugins/grassprovider/ext/v_net_flow.py
index a0ada0fba081..efdf95f9374d 100644
--- a/python/plugins/grassprovider/ext/v_net_flow.py
+++ b/python/plugins/grassprovider/ext/v_net_flow.py
@@ -15,31 +15,27 @@
***************************************************************************
"""
-__author__ = 'Médéric Ribreux'
-__date__ = 'December 2015'
-__copyright__ = '(C) 2015, Médéric Ribreux'
+__author__ = "Médéric Ribreux"
+__date__ = "December 2015"
+__copyright__ = "(C) 2015, Médéric Ribreux"
from .v_net import incorporatePoints, variableOutput
def checkParameterValuesBeforeExecuting(alg, parameters, context):
- """ Verify if we have the right parameters """
- params = ['where', 'cats']
+ """Verify if we have the right parameters"""
+ params = ["where", "cats"]
values = []
for param in params:
- for i in ['source', 'sink']:
- values.append(
- alg.parameterAsString(
- parameters,
- '{}_{}'.format(i, param),
- context
- )
- )
+ for i in ["source", "sink"]:
+ values.append(alg.parameterAsString(parameters, f"{i}_{param}", context))
if (values[0] or values[2]) and (values[1] or values[3]):
return True, None
- return False, alg.tr('You need to set at least source/sink_where or source/sink_cats parameters for each set!')
+ return False, alg.tr(
+ "You need to set at least source/sink_where or source/sink_cats parameters for each set!"
+ )
def processCommand(alg, parameters, context, feedback):
@@ -47,6 +43,8 @@ def processCommand(alg, parameters, context, feedback):
def processOutputs(alg, parameters, context, feedback):
- outputParameter = {'output': ['output', 'line', 1, True],
- 'cut': ['cut', 'line', 1, True]}
+ outputParameter = {
+ "output": ["output", "line", 1, True],
+ "cut": ["cut", "line", 1, True],
+ }
variableOutput(alg, outputParameter, parameters, context)
diff --git a/python/plugins/grassprovider/ext/v_net_iso.py b/python/plugins/grassprovider/ext/v_net_iso.py
index 3cc81b80a63a..1bb2277334b5 100644
--- a/python/plugins/grassprovider/ext/v_net_iso.py
+++ b/python/plugins/grassprovider/ext/v_net_iso.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Médéric Ribreux'
-__date__ = 'December 2015'
-__copyright__ = '(C) 2015, Médéric Ribreux'
+__author__ = "Médéric Ribreux"
+__date__ = "December 2015"
+__copyright__ = "(C) 2015, Médéric Ribreux"
from .v_net import incorporatePoints, variableOutput
@@ -27,5 +27,5 @@ def processCommand(alg, parameters, context, feedback):
def processOutputs(alg, parameters, context, feedback):
- outputParameter = {'output': ['output', 'line', 1, True]}
+ outputParameter = {"output": ["output", "line", 1, True]}
variableOutput(alg, outputParameter, parameters, context)
diff --git a/python/plugins/grassprovider/ext/v_net_path.py b/python/plugins/grassprovider/ext/v_net_path.py
index eee13dae330f..6f9f3f19def2 100644
--- a/python/plugins/grassprovider/ext/v_net_path.py
+++ b/python/plugins/grassprovider/ext/v_net_path.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Médéric Ribreux'
-__date__ = 'December 2015'
-__copyright__ = '(C) 2015, Médéric Ribreux'
+__author__ = "Médéric Ribreux"
+__date__ = "December 2015"
+__copyright__ = "(C) 2015, Médéric Ribreux"
from .v_net import incorporatePoints, variableOutput
@@ -27,5 +27,5 @@ def processCommand(alg, parameters, context, feedback):
def processOutputs(alg, parameters, context, feedback):
- outputParameter = {'output': ['output', 'line', 1, False]}
+ outputParameter = {"output": ["output", "line", 1, False]}
variableOutput(alg, outputParameter, parameters, context)
diff --git a/python/plugins/grassprovider/ext/v_net_salesman.py b/python/plugins/grassprovider/ext/v_net_salesman.py
index 9f802eb4b292..a774ccef4ec5 100644
--- a/python/plugins/grassprovider/ext/v_net_salesman.py
+++ b/python/plugins/grassprovider/ext/v_net_salesman.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Médéric Ribreux'
-__date__ = 'December 2015'
-__copyright__ = '(C) 2015, Médéric Ribreux'
+__author__ = "Médéric Ribreux"
+__date__ = "December 2015"
+__copyright__ = "(C) 2015, Médéric Ribreux"
from .v_net import incorporatePoints, variableOutput
from qgis.core import QgsProcessingParameterDefinition
@@ -28,5 +28,5 @@ def processCommand(alg, parameters, context, feedback):
def processOutputs(alg, parameters, context, feedback):
- outputParameter = {'output': ['output', 'line', 1, True]}
+ outputParameter = {"output": ["output", "line", 1, True]}
variableOutput(alg, outputParameter, parameters, context)
diff --git a/python/plugins/grassprovider/ext/v_net_spanningtree.py b/python/plugins/grassprovider/ext/v_net_spanningtree.py
index 20cd537dca95..2e9bee20ad42 100644
--- a/python/plugins/grassprovider/ext/v_net_spanningtree.py
+++ b/python/plugins/grassprovider/ext/v_net_spanningtree.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Médéric Ribreux'
-__date__ = 'December 2017'
-__copyright__ = '(C) 2017, Médéric Ribreux'
+__author__ = "Médéric Ribreux"
+__date__ = "December 2017"
+__copyright__ = "(C) 2017, Médéric Ribreux"
from .v_net import incorporatePoints, variableOutput
@@ -27,5 +27,5 @@ def processCommand(alg, parameters, context, feedback):
def processOutputs(alg, parameters, context, feedback):
- outputParameter = {'output': ['output', 'line', 1, True]}
+ outputParameter = {"output": ["output", "line", 1, True]}
variableOutput(alg, outputParameter, parameters, context)
diff --git a/python/plugins/grassprovider/ext/v_net_steiner.py b/python/plugins/grassprovider/ext/v_net_steiner.py
index bcf524200831..1dab232b8417 100644
--- a/python/plugins/grassprovider/ext/v_net_steiner.py
+++ b/python/plugins/grassprovider/ext/v_net_steiner.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Médéric Ribreux'
-__date__ = 'December 2015'
-__copyright__ = '(C) 2015, Médéric Ribreux'
+__author__ = "Médéric Ribreux"
+__date__ = "December 2015"
+__copyright__ = "(C) 2015, Médéric Ribreux"
from .v_net import incorporatePoints, variableOutput
@@ -27,5 +27,5 @@ def processCommand(alg, parameters, context, feedback):
def processOutputs(alg, parameters, context, feedback):
- outputParameter = {'output': ['output', 'line', 1, False]}
+ outputParameter = {"output": ["output", "line", 1, False]}
variableOutput(alg, outputParameter, parameters, context)
diff --git a/python/plugins/grassprovider/ext/v_net_visibility.py b/python/plugins/grassprovider/ext/v_net_visibility.py
index 93eeb4836261..bb278002c480 100644
--- a/python/plugins/grassprovider/ext/v_net_visibility.py
+++ b/python/plugins/grassprovider/ext/v_net_visibility.py
@@ -15,13 +15,13 @@
***************************************************************************
"""
-__author__ = 'Médéric Ribreux'
-__date__ = 'December 2015'
-__copyright__ = '(C) 2015, Médéric Ribreux'
+__author__ = "Médéric Ribreux"
+__date__ = "December 2015"
+__copyright__ = "(C) 2015, Médéric Ribreux"
from .v_net import variableOutput
def processOutputs(alg, parameters, context, feedback):
- outputParameter = {'output': ['output', 'line', 1, True]}
+ outputParameter = {"output": ["output", "line", 1, True]}
variableOutput(alg, outputParameter, parameters, context)
diff --git a/python/plugins/grassprovider/ext/v_proj.py b/python/plugins/grassprovider/ext/v_proj.py
index deb72bd93352..ce9b20134d1e 100644
--- a/python/plugins/grassprovider/ext/v_proj.py
+++ b/python/plugins/grassprovider/ext/v_proj.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Médéric Ribreux'
-__date__ = 'November 2017'
-__copyright__ = '(C) 2017, Médéric Ribreux'
+__author__ = "Médéric Ribreux"
+__date__ = "November 2017"
+__copyright__ = "(C) 2017, Médéric Ribreux"
from qgis.core import QgsProcessingParameterString
from grassprovider.grass_utils import GrassUtils
@@ -25,39 +25,34 @@
def processInputs(alg, parameters, context, feedback):
# Grab the projection from the input vector layer
- layer = alg.parameterAsLayer(parameters, 'input', context)
+ layer = alg.parameterAsLayer(parameters, "input", context)
alg.setSessionProjectionFromLayer(layer, context)
layerCrs = layer.crs().toProj()
# Creates a new location with this Crs
wkt_file_name = GrassUtils.exportCrsWktToFile(layer.crs(), context)
- newLocation = 'newProj{}'.format(alg.uniqueSuffix)
- alg.commands.append('g.proj wkt="{}" location={}'.format(
- wkt_file_name, newLocation))
+ newLocation = f"newProj{alg.uniqueSuffix}"
+ alg.commands.append(f'g.proj wkt="{wkt_file_name}" location={newLocation}')
# Go to the newly created location
- alg.commands.append('g.mapset mapset=PERMANENT location={}'.format(
- newLocation))
+ alg.commands.append(f"g.mapset mapset=PERMANENT location={newLocation}")
# Import the layer
- alg.loadVectorLayerFromParameter(
- 'input', parameters, context, feedback, False)
+ alg.loadVectorLayerFromParameter("input", parameters, context, feedback, False)
# Go back to default location
- alg.commands.append('g.mapset mapset=PERMANENT location=temp_location')
+ alg.commands.append("g.mapset mapset=PERMANENT location=temp_location")
# Grab the projected Crs
- crs = alg.parameterAsCrs(parameters, 'crs', context)
+ crs = alg.parameterAsCrs(parameters, "crs", context)
wkt_file_name = GrassUtils.exportCrsWktToFile(crs, context)
- alg.commands.append('g.proj -c wkt="{}"'.format(wkt_file_name))
+ alg.commands.append(f'g.proj -c wkt="{wkt_file_name}"')
# Remove crs parameter
- alg.removeParameter('crs')
+ alg.removeParameter("crs")
# Add the location parameter with proper value
location = QgsProcessingParameterString(
- 'location',
- 'new location',
- 'newProj{}'.format(alg.uniqueSuffix)
+ "location", "new location", f"newProj{alg.uniqueSuffix}"
)
alg.addParameter(location)
diff --git a/python/plugins/grassprovider/ext/v_rast_stats.py b/python/plugins/grassprovider/ext/v_rast_stats.py
index 2f55a8f1e50a..f495979f4f57 100644
--- a/python/plugins/grassprovider/ext/v_rast_stats.py
+++ b/python/plugins/grassprovider/ext/v_rast_stats.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Médéric Ribreux'
-__date__ = 'March 2016'
-__copyright__ = '(C) 2016, Médéric Ribreux'
+__author__ = "Médéric Ribreux"
+__date__ = "March 2016"
+__copyright__ = "(C) 2016, Médéric Ribreux"
def processCommand(alg, parameters, context, feedback):
@@ -27,7 +27,7 @@ def processCommand(alg, parameters, context, feedback):
def processOutputs(alg, parameters, context, feedback):
# We need to add the initial vector layer to outputs:
- fileName = alg.parameterAsOutputLayer(parameters, 'output', context)
- grassName = alg.exportedLayers['map']
- dataType = 'auto'
+ fileName = alg.parameterAsOutputLayer(parameters, "output", context)
+ grassName = alg.exportedLayers["map"]
+ dataType = "auto"
alg.exportVectorLayer(grassName, fileName, dataType=dataType)
diff --git a/python/plugins/grassprovider/ext/v_reclass.py b/python/plugins/grassprovider/ext/v_reclass.py
index 80bda61e43b1..f7d6996ca0a6 100644
--- a/python/plugins/grassprovider/ext/v_reclass.py
+++ b/python/plugins/grassprovider/ext/v_reclass.py
@@ -15,16 +15,16 @@
***************************************************************************
"""
-__author__ = 'Andrea Giudiceandrea'
-__date__ = 'June 2023'
-__copyright__ = '(C) 2023, Andrea Giudiceandrea'
+__author__ = "Andrea Giudiceandrea"
+__date__ = "June 2023"
+__copyright__ = "(C) 2023, Andrea Giudiceandrea"
def checkParameterValuesBeforeExecuting(alg, parameters, context):
- """ Verify if we have the right parameters """
+ """Verify if we have the right parameters"""
# rules and column parameters are mutually exclusive
- rules = alg.parameterAsString(parameters, 'rules', context)
- column = alg.parameterAsString(parameters, 'column', context)
+ rules = alg.parameterAsString(parameters, "rules", context)
+ column = alg.parameterAsString(parameters, "column", context)
if (rules and column) or (not rules and not column):
return False, alg.tr("You need to set either a rules file or a column!")
diff --git a/python/plugins/grassprovider/ext/v_rectify.py b/python/plugins/grassprovider/ext/v_rectify.py
index ada7bbf1bcf1..fcaac2242856 100644
--- a/python/plugins/grassprovider/ext/v_rectify.py
+++ b/python/plugins/grassprovider/ext/v_rectify.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Médéric Ribreux'
-__date__ = 'March 2016'
-__copyright__ = '(C) 2016, Médéric Ribreux'
+__author__ = "Médéric Ribreux"
+__date__ = "March 2016"
+__copyright__ = "(C) 2016, Médéric Ribreux"
import os
from grassprovider.grass_utils import GrassUtils
@@ -25,17 +25,20 @@
def checkParameterValuesBeforeExecuting(alg, parameters, context):
- """ Verify if we have the right parameters """
- if (alg.parameterAsString(parameters, 'inline_points', context)
- and alg.parameterAsString(parameters, 'points', context)):
- return False, alg.tr("You need to set either an input control point file or inline control points!")
+ """Verify if we have the right parameters"""
+ if alg.parameterAsString(
+ parameters, "inline_points", context
+ ) and alg.parameterAsString(parameters, "points", context):
+ return False, alg.tr(
+ "You need to set either an input control point file or inline control points!"
+ )
return True, None
def processCommand(alg, parameters, context, feedback):
# handle inline points
- inlinePoints = alg.parameterAsString(parameters, 'inline_points', context)
+ inlinePoints = alg.parameterAsString(parameters, "inline_points", context)
if inlinePoints:
# Creates a temporary txt file
pointsName = getTempFilename(context=context)
@@ -43,7 +46,7 @@ def processCommand(alg, parameters, context, feedback):
# Inject rules into temporary txt file
with open(pointsName, "w") as tempPoints:
tempPoints.write(inlinePoints)
- alg.removeParameter('inline_points')
- parameters['points'] = pointsName
+ alg.removeParameter("inline_points")
+ parameters["points"] = pointsName
alg.processCommand(parameters, context, feedback)
diff --git a/python/plugins/grassprovider/ext/v_sample.py b/python/plugins/grassprovider/ext/v_sample.py
index dfa5f98fdf06..69758c784318 100644
--- a/python/plugins/grassprovider/ext/v_sample.py
+++ b/python/plugins/grassprovider/ext/v_sample.py
@@ -15,17 +15,17 @@
***************************************************************************
"""
-__author__ = 'Médéric Ribreux'
-__date__ = 'February 2016'
-__copyright__ = '(C) 2016, Médéric Ribreux'
+__author__ = "Médéric Ribreux"
+__date__ = "February 2016"
+__copyright__ = "(C) 2016, Médéric Ribreux"
def processInputs(alg, parameters, context, feedback):
- if 'input' in alg.exportedLayers:
+ if "input" in alg.exportedLayers:
return
# We need to import the vector with v.in.ogr
# and we can use r.external for the raster
- alg.loadVectorLayerFromParameter('input', parameters, context, feedback, False)
- alg.loadRasterLayerFromParameter('raster', parameters, context, True)
+ alg.loadVectorLayerFromParameter("input", parameters, context, feedback, False)
+ alg.loadRasterLayerFromParameter("raster", parameters, context, True)
alg.postInputs(context)
diff --git a/python/plugins/grassprovider/ext/v_to_3d.py b/python/plugins/grassprovider/ext/v_to_3d.py
index fd13399993a6..fd8c4727e55f 100644
--- a/python/plugins/grassprovider/ext/v_to_3d.py
+++ b/python/plugins/grassprovider/ext/v_to_3d.py
@@ -15,25 +15,27 @@
***************************************************************************
"""
-__author__ = 'Médéric Ribreux'
-__date__ = 'March 2016'
-__copyright__ = '(C) 2016, Médéric Ribreux'
+__author__ = "Médéric Ribreux"
+__date__ = "March 2016"
+__copyright__ = "(C) 2016, Médéric Ribreux"
def checkParameterValuesBeforeExecuting(alg, parameters, context):
- """ Verify if we have the right parameters """
- height = alg.parameterAsDouble(parameters, 'height', context)
- column = alg.parameterAsString(parameters, 'column', context)
+ """Verify if we have the right parameters"""
+ height = alg.parameterAsDouble(parameters, "height", context)
+ column = alg.parameterAsString(parameters, "column", context)
if (height and column) or (not height and not column):
- return False, alg.tr("You need to set either a fixed height value or the height column!")
+ return False, alg.tr(
+ "You need to set either a fixed height value or the height column!"
+ )
return True, None
def processInputs(alg, parameters, context, feedback):
- if 'input' in alg.exportedLayers:
+ if "input" in alg.exportedLayers:
return
# We need to import the vector layer with v.in.ogr
- alg.loadVectorLayerFromParameter('input', parameters, context, feedback, False)
+ alg.loadVectorLayerFromParameter("input", parameters, context, feedback, False)
alg.postInputs(context)
diff --git a/python/plugins/grassprovider/ext/v_transform.py b/python/plugins/grassprovider/ext/v_transform.py
index e24b78e56407..f6287f73a12e 100644
--- a/python/plugins/grassprovider/ext/v_transform.py
+++ b/python/plugins/grassprovider/ext/v_transform.py
@@ -15,18 +15,20 @@
***************************************************************************
"""
-__author__ = 'Andrea Giudiceandrea'
-__date__ = 'February 2024'
-__copyright__ = '(C) 2024, Andrea Giudiceandrea'
+__author__ = "Andrea Giudiceandrea"
+__date__ = "February 2024"
+__copyright__ = "(C) 2024, Andrea Giudiceandrea"
def checkParameterValuesBeforeExecuting(alg, parameters, context):
- """ Verify if we have the right parameters """
+ """Verify if we have the right parameters"""
# -w, -x and -y parameters are mutually exclusive
- w = alg.parameterAsBoolean(parameters, '-w', context)
- x = alg.parameterAsBoolean(parameters, '-x', context)
- y = alg.parameterAsBoolean(parameters, '-y', context)
+ w = alg.parameterAsBoolean(parameters, "-w", context)
+ x = alg.parameterAsBoolean(parameters, "-x", context)
+ y = alg.parameterAsBoolean(parameters, "-y", context)
if sum([w, x, y]) > 1:
- return False, alg.tr("The 'Swap coordinates' parameters -w, -x and -y are mutually exclusive. You need to set either none or only one of them!")
+ return False, alg.tr(
+ "The 'Swap coordinates' parameters -w, -x and -y are mutually exclusive. You need to set either none or only one of them!"
+ )
return True, None
diff --git a/python/plugins/grassprovider/ext/v_vect_stats.py b/python/plugins/grassprovider/ext/v_vect_stats.py
index bc73f5bc80a5..2d3476849289 100644
--- a/python/plugins/grassprovider/ext/v_vect_stats.py
+++ b/python/plugins/grassprovider/ext/v_vect_stats.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Médéric Ribreux'
-__date__ = 'March 2016'
-__copyright__ = '(C) 2016, Médéric Ribreux'
+__author__ = "Médéric Ribreux"
+__date__ = "March 2016"
+__copyright__ = "(C) 2016, Médéric Ribreux"
def processCommand(alg, parameters, context, feedback):
@@ -27,7 +27,7 @@ def processCommand(alg, parameters, context, feedback):
def processOutputs(alg, parameters, context, feedback):
# We need to add the initial vector layer to outputs:
- fileName = alg.parameterAsOutputLayer(parameters, 'output', context)
- grassName = alg.exportedLayers['areas']
- dataType = 'auto'
+ fileName = alg.parameterAsOutputLayer(parameters, "output", context)
+ grassName = alg.exportedLayers["areas"]
+ dataType = "auto"
alg.exportVectorLayer(grassName, fileName, dataType=dataType)
diff --git a/python/plugins/grassprovider/ext/v_voronoi.py b/python/plugins/grassprovider/ext/v_voronoi.py
index c57bea145744..8b0ac2ea60e3 100644
--- a/python/plugins/grassprovider/ext/v_voronoi.py
+++ b/python/plugins/grassprovider/ext/v_voronoi.py
@@ -15,26 +15,26 @@
***************************************************************************
"""
-__author__ = 'Médéric Ribreux'
-__date__ = 'February 2016'
-__copyright__ = '(C) 2016, Médéric Ribreux'
+__author__ = "Médéric Ribreux"
+__date__ = "February 2016"
+__copyright__ = "(C) 2016, Médéric Ribreux"
def processInputs(alg, parameters, context, feedback):
- if 'input' in alg.exportedLayers:
+ if "input" in alg.exportedLayers:
return
# We need to use v.in.ogr instead of v.external
- alg.loadVectorLayerFromParameter('input', parameters, context, feedback, False)
+ alg.loadVectorLayerFromParameter("input", parameters, context, feedback, False)
alg.processInputs(parameters, context, feedback)
def processOutputs(alg, parameters, context, feedback):
- fileName = alg.parameterAsOutputLayer(parameters, 'output', context)
- grassName = '{}{}'.format('output', alg.uniqueSuffix)
- dataType = 'auto'
+ fileName = alg.parameterAsOutputLayer(parameters, "output", context)
+ grassName = "{}{}".format("output", alg.uniqueSuffix)
+ dataType = "auto"
# if we export a graph, output type will be a line
- if alg.parameterAsBoolean(parameters, '-l', context):
- dataType = 'line'
+ if alg.parameterAsBoolean(parameters, "-l", context):
+ dataType = "line"
alg.exportVectorLayer(grassName, fileName, dataType=dataType)
diff --git a/python/plugins/grassprovider/ext/v_what_rast.py b/python/plugins/grassprovider/ext/v_what_rast.py
index 170f7341adc1..d898bd556906 100644
--- a/python/plugins/grassprovider/ext/v_what_rast.py
+++ b/python/plugins/grassprovider/ext/v_what_rast.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Médéric Ribreux'
-__date__ = 'December 2017'
-__copyright__ = '(C) 2017, Médéric Ribreux'
+__author__ = "Médéric Ribreux"
+__date__ = "December 2017"
+__copyright__ = "(C) 2017, Médéric Ribreux"
def processCommand(alg, parameters, context, feedback):
@@ -27,7 +27,7 @@ def processCommand(alg, parameters, context, feedback):
def processOutputs(alg, parameters, context, feedback):
# We need to add the initial vector layer to outputs:
- fileName = alg.parameterAsOutputLayer(parameters, 'output', context)
- grassName = alg.exportedLayers['map']
- dataType = 'auto'
+ fileName = alg.parameterAsOutputLayer(parameters, "output", context)
+ grassName = alg.exportedLayers["map"]
+ dataType = "auto"
alg.exportVectorLayer(grassName, fileName, dataType=dataType)
diff --git a/python/plugins/grassprovider/ext/v_what_vect.py b/python/plugins/grassprovider/ext/v_what_vect.py
index 242ae9844639..18ca0224d420 100644
--- a/python/plugins/grassprovider/ext/v_what_vect.py
+++ b/python/plugins/grassprovider/ext/v_what_vect.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Médéric Ribreux'
-__date__ = 'March 2016'
-__copyright__ = '(C) 2016, Médéric Ribreux'
+__author__ = "Médéric Ribreux"
+__date__ = "March 2016"
+__copyright__ = "(C) 2016, Médéric Ribreux"
def processCommand(alg, parameters, context, feedback):
@@ -27,6 +27,6 @@ def processCommand(alg, parameters, context, feedback):
def processOutputs(alg, parameters, context, feedback):
# We need to add the initial vector layer to outputs:
- fileName = alg.parameterAsOutputLayer(parameters, 'output', context)
- grassName = alg.exportedLayers['map']
+ fileName = alg.parameterAsOutputLayer(parameters, "output", context)
+ grassName = alg.exportedLayers["map"]
alg.exportVectorLayer(grassName, fileName)
diff --git a/python/plugins/grassprovider/grass_algorithm.py b/python/plugins/grassprovider/grass_algorithm.py
index 0556335b05e2..1f2eb3aec09d 100644
--- a/python/plugins/grassprovider/grass_algorithm.py
+++ b/python/plugins/grassprovider/grass_algorithm.py
@@ -15,14 +15,11 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'February 2015'
-__copyright__ = '(C) 2012-2015, Victor Olaya'
+__author__ = "Victor Olaya"
+__date__ = "February 2015"
+__copyright__ = "(C) 2012-2015, Victor Olaya"
-from typing import (
- Dict,
- Optional
-)
+from typing import Dict, Optional
import sys
import os
import uuid
@@ -32,41 +29,43 @@
from qgis.PyQt.QtCore import QCoreApplication, QUrl
-from qgis.core import (Qgis,
- QgsMapLayer,
- QgsRasterLayer,
- QgsApplication,
- QgsMapLayerType,
- QgsCoordinateReferenceSystem,
- QgsProcessingUtils,
- QgsProcessing,
- QgsMessageLog,
- QgsVectorFileWriter,
- QgsProcessingContext,
- QgsProcessingAlgorithm,
- QgsProcessingParameterDefinition,
- QgsProcessingException,
- QgsProcessingParameterCrs,
- QgsProcessingParameterExtent,
- QgsProcessingParameterEnum,
- QgsProcessingParameterNumber,
- QgsProcessingParameterString,
- QgsProcessingParameterField,
- QgsProcessingParameterPoint,
- QgsProcessingParameterBoolean,
- QgsProcessingParameterRange,
- QgsProcessingParameterFeatureSource,
- QgsProcessingParameterVectorLayer,
- QgsProcessingParameterRasterLayer,
- QgsProcessingParameterMultipleLayers,
- QgsProcessingParameterVectorDestination,
- QgsProcessingParameterRasterDestination,
- QgsProcessingParameterFileDestination,
- QgsProcessingParameterFile,
- QgsProcessingParameterFolderDestination,
- QgsProcessingOutputHtml,
- QgsVectorLayer,
- QgsProviderRegistry)
+from qgis.core import (
+ Qgis,
+ QgsMapLayer,
+ QgsRasterLayer,
+ QgsApplication,
+ QgsMapLayerType,
+ QgsCoordinateReferenceSystem,
+ QgsProcessingUtils,
+ QgsProcessing,
+ QgsMessageLog,
+ QgsVectorFileWriter,
+ QgsProcessingContext,
+ QgsProcessingAlgorithm,
+ QgsProcessingParameterDefinition,
+ QgsProcessingException,
+ QgsProcessingParameterCrs,
+ QgsProcessingParameterExtent,
+ QgsProcessingParameterEnum,
+ QgsProcessingParameterNumber,
+ QgsProcessingParameterString,
+ QgsProcessingParameterField,
+ QgsProcessingParameterPoint,
+ QgsProcessingParameterBoolean,
+ QgsProcessingParameterRange,
+ QgsProcessingParameterFeatureSource,
+ QgsProcessingParameterVectorLayer,
+ QgsProcessingParameterRasterLayer,
+ QgsProcessingParameterMultipleLayers,
+ QgsProcessingParameterVectorDestination,
+ QgsProcessingParameterRasterDestination,
+ QgsProcessingParameterFileDestination,
+ QgsProcessingParameterFile,
+ QgsProcessingParameterFolderDestination,
+ QgsProcessingOutputHtml,
+ QgsVectorLayer,
+ QgsProviderRegistry,
+)
from qgis.utils import iface
import warnings
@@ -83,41 +82,45 @@
from processing.tools.system import isWindows, getTempFilename
-pluginPath = os.path.normpath(os.path.join(
- os.path.split(os.path.dirname(__file__))[0], os.pardir))
+pluginPath = os.path.normpath(
+ os.path.join(os.path.split(os.path.dirname(__file__))[0], os.pardir)
+)
class GrassAlgorithm(QgsProcessingAlgorithm):
- GRASS_OUTPUT_TYPE_PARAMETER = 'GRASS_OUTPUT_TYPE_PARAMETER'
- GRASS_MIN_AREA_PARAMETER = 'GRASS_MIN_AREA_PARAMETER'
- GRASS_SNAP_TOLERANCE_PARAMETER = 'GRASS_SNAP_TOLERANCE_PARAMETER'
- GRASS_REGION_EXTENT_PARAMETER = 'GRASS_REGION_PARAMETER'
- GRASS_REGION_CELLSIZE_PARAMETER = 'GRASS_REGION_CELLSIZE_PARAMETER'
- GRASS_REGION_ALIGN_TO_RESOLUTION = 'GRASS_REGION_ALIGN_TO_RESOLUTION'
- GRASS_RASTER_FORMAT_OPT = 'GRASS_RASTER_FORMAT_OPT'
- GRASS_RASTER_FORMAT_META = 'GRASS_RASTER_FORMAT_META'
- GRASS_VECTOR_DSCO = 'GRASS_VECTOR_DSCO'
- GRASS_VECTOR_LCO = 'GRASS_VECTOR_LCO'
- GRASS_VECTOR_EXPORT_NOCAT = 'GRASS_VECTOR_EXPORT_NOCAT'
-
- OUTPUT_TYPES = ['auto', 'point', 'line', 'area']
- QGIS_OUTPUT_TYPES = {QgsProcessing.SourceType.TypeVectorAnyGeometry: 'auto',
- QgsProcessing.SourceType.TypeVectorPoint: 'point',
- QgsProcessing.SourceType.TypeVectorLine: 'line',
- QgsProcessing.SourceType.TypeVectorPolygon: 'area'}
-
- def __init__(self,
- description_file: Optional[Path] = None,
- json_definition: Optional[Dict] = None,
- description_folder: Optional[Path] = None
- ):
+ GRASS_OUTPUT_TYPE_PARAMETER = "GRASS_OUTPUT_TYPE_PARAMETER"
+ GRASS_MIN_AREA_PARAMETER = "GRASS_MIN_AREA_PARAMETER"
+ GRASS_SNAP_TOLERANCE_PARAMETER = "GRASS_SNAP_TOLERANCE_PARAMETER"
+ GRASS_REGION_EXTENT_PARAMETER = "GRASS_REGION_PARAMETER"
+ GRASS_REGION_CELLSIZE_PARAMETER = "GRASS_REGION_CELLSIZE_PARAMETER"
+ GRASS_REGION_ALIGN_TO_RESOLUTION = "GRASS_REGION_ALIGN_TO_RESOLUTION"
+ GRASS_RASTER_FORMAT_OPT = "GRASS_RASTER_FORMAT_OPT"
+ GRASS_RASTER_FORMAT_META = "GRASS_RASTER_FORMAT_META"
+ GRASS_VECTOR_DSCO = "GRASS_VECTOR_DSCO"
+ GRASS_VECTOR_LCO = "GRASS_VECTOR_LCO"
+ GRASS_VECTOR_EXPORT_NOCAT = "GRASS_VECTOR_EXPORT_NOCAT"
+
+ OUTPUT_TYPES = ["auto", "point", "line", "area"]
+ QGIS_OUTPUT_TYPES = {
+ QgsProcessing.SourceType.TypeVectorAnyGeometry: "auto",
+ QgsProcessing.SourceType.TypeVectorPoint: "point",
+ QgsProcessing.SourceType.TypeVectorLine: "line",
+ QgsProcessing.SourceType.TypeVectorPolygon: "area",
+ }
+
+ def __init__(
+ self,
+ description_file: Optional[Path] = None,
+ json_definition: Optional[dict] = None,
+ description_folder: Optional[Path] = None,
+ ):
super().__init__()
- self._name = ''
- self._display_name = ''
- self._short_description = ''
- self._group = ''
- self._groupId = ''
- self.grass_name = ''
+ self._name = ""
+ self._display_name = ""
+ self._short_description = ""
+ self._group = ""
+ self._groupId = ""
+ self.grass_name = ""
self.params = []
self.hardcodedStrings = []
self.inputLayers = []
@@ -126,7 +129,7 @@ def __init__(self,
self.exportedLayers = {}
self.fileOutputs = {}
self._description_file: Optional[Path] = description_file
- self._json_definition: Optional[Dict] = json_definition
+ self._json_definition: Optional[dict] = json_definition
self._description_folder: Optional[Path] = description_folder
# Default GRASS parameters
@@ -148,7 +151,7 @@ def __init__(self,
self.numExportedLayers = 0
# Do we need this anymore?
- self.uniqueSuffix = str(uuid.uuid4()).replace('-', '')
+ self.uniqueSuffix = str(uuid.uuid4()).replace("-", "")
# Use the ext mechanism
self.module = None
@@ -156,29 +159,38 @@ def __init__(self,
extpath = None
ext_name = None
if self._description_file:
- ext_name = self.name().replace('.', '_')
- extpath = self._description_file.parents[1].joinpath('ext', ext_name + '.py')
- elif self._json_definition.get('ext_path'):
- ext_name = self._json_definition['ext_path']
+ ext_name = self.name().replace(".", "_")
+ extpath = self._description_file.parents[1].joinpath(
+ "ext", ext_name + ".py"
+ )
+ elif self._json_definition.get("ext_path"):
+ ext_name = self._json_definition["ext_path"]
extpath = self._description_folder.parents[0].joinpath(
- 'ext', ext_name + '.py')
+ "ext", ext_name + ".py"
+ )
# this check makes it a bit faster
if extpath and extpath.exists():
spec = importlib.util.spec_from_file_location(
- 'grassprovider.ext.' + ext_name, extpath)
+ "grassprovider.ext." + ext_name, extpath
+ )
self.module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(self.module)
except Exception as e:
- QgsMessageLog.logMessage(self.tr('Failed to load: {0}\n{1}').format(extpath, e), 'Processing', Qgis.MessageLevel.Critical)
+ QgsMessageLog.logMessage(
+ self.tr("Failed to load: {0}\n{1}").format(extpath, e),
+ "Processing",
+ Qgis.MessageLevel.Critical,
+ )
pass
def createInstance(self):
return self.__class__(
description_file=self._description_file,
json_definition=self._json_definition,
- description_folder=self._description_folder)
+ description_folder=self._description_folder,
+ )
def name(self):
return self._name
@@ -203,22 +215,28 @@ def svgIconPath(self):
def flags(self):
# TODO - maybe it's safe to background thread this?
- return super().flags() | QgsProcessingAlgorithm.Flag.FlagNoThreading | QgsProcessingAlgorithm.Flag.FlagDisplayNameIsLiteral
+ return (
+ super().flags()
+ | QgsProcessingAlgorithm.Flag.FlagNoThreading
+ | QgsProcessingAlgorithm.Flag.FlagDisplayNameIsLiteral
+ )
- def tr(self, string, context=''):
- if context == '':
+ def tr(self, string, context=""):
+ if context == "":
context = self.__class__.__name__
return QCoreApplication.translate(context, string)
def helpUrl(self):
helpPath = GrassUtils.grassHelpPath()
- if helpPath == '':
+ if helpPath == "":
return None
if os.path.exists(helpPath):
- return QUrl.fromLocalFile(os.path.join(helpPath, '{}.html'.format(self.grass_name))).toString()
+ return QUrl.fromLocalFile(
+ os.path.join(helpPath, f"{self.grass_name}.html")
+ ).toString()
else:
- return helpPath + '{}.html'.format(self.grass_name)
+ return helpPath + f"{self.grass_name}.html"
def initAlgorithm(self, config=None):
"""
@@ -232,25 +250,19 @@ def _define_characteristics_from_file(self):
"""
Create algorithm parameters and outputs from a text file.
"""
- results = ParsedDescription.parse_description_file(
- self._description_file)
- self._define_characteristics_from_parsed_description(
- results
- )
+ results = ParsedDescription.parse_description_file(self._description_file)
+ self._define_characteristics_from_parsed_description(results)
def _define_characteristics_from_json(self):
"""
Create algorithm parameters and outputs from JSON definition.
"""
- results = ParsedDescription.from_dict(
- self._json_definition)
- self._define_characteristics_from_parsed_description(
- results
- )
+ results = ParsedDescription.from_dict(self._json_definition)
+ self._define_characteristics_from_parsed_description(results)
def _define_characteristics_from_parsed_description(
- self,
- description: ParsedDescription):
+ self, description: ParsedDescription
+ ):
"""
Create algorithm parameters and outputs from parsed description
"""
@@ -275,128 +287,164 @@ def _define_characteristics_from_parsed_description(
parameter = getParameterFromString(param_string, "GrassAlgorithm")
except Exception as e:
QgsMessageLog.logMessage(
- QCoreApplication.translate("GrassAlgorithm",
- 'Could not open GRASS GIS algorithm: {0}').format(
- self._name),
- QCoreApplication.translate("GrassAlgorithm",
- 'Processing'),
- Qgis.MessageLevel.Critical)
+ QCoreApplication.translate(
+ "GrassAlgorithm", "Could not open GRASS GIS algorithm: {0}"
+ ).format(self._name),
+ QCoreApplication.translate("GrassAlgorithm", "Processing"),
+ Qgis.MessageLevel.Critical,
+ )
raise e
if parameter is None:
continue
self.params.append(parameter)
- if isinstance(parameter, (
+ if isinstance(
+ parameter,
+ (
QgsProcessingParameterVectorLayer,
- QgsProcessingParameterFeatureSource)):
+ QgsProcessingParameterFeatureSource,
+ ),
+ ):
has_vector_input = True
- elif isinstance(parameter,
- QgsProcessingParameterRasterLayer):
+ elif isinstance(parameter, QgsProcessingParameterRasterLayer):
has_raster_input = True
- elif isinstance(parameter,
- QgsProcessingParameterMultipleLayers):
+ elif isinstance(parameter, QgsProcessingParameterMultipleLayers):
if parameter.layerType() < 3 or parameter.layerType() == 5:
has_vector_input = True
elif parameter.layerType() == 3:
has_raster_input = True
- elif isinstance(parameter,
- QgsProcessingParameterVectorDestination):
+ elif isinstance(parameter, QgsProcessingParameterVectorDestination):
has_vector_outputs = True
- elif isinstance(parameter,
- QgsProcessingParameterRasterDestination):
+ elif isinstance(parameter, QgsProcessingParameterRasterDestination):
has_raster_output = True
param = QgsProcessingParameterExtent(
self.GRASS_REGION_EXTENT_PARAMETER,
- self.tr('GRASS GIS region extent'),
- optional=True
+ self.tr("GRASS GIS region extent"),
+ optional=True,
+ )
+ param.setFlags(
+ param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
)
- param.setFlags(param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
self.params.append(param)
if has_raster_output or has_raster_input:
# Add a cellsize parameter
param = QgsProcessingParameterNumber(
self.GRASS_REGION_CELLSIZE_PARAMETER,
- self.tr('GRASS GIS region cellsize (leave 0 for default)'),
+ self.tr("GRASS GIS region cellsize (leave 0 for default)"),
type=QgsProcessingParameterNumber.Type.Double,
- minValue=0.0, maxValue=sys.float_info.max + 1, defaultValue=0.0
+ minValue=0.0,
+ maxValue=sys.float_info.max + 1,
+ defaultValue=0.0,
+ )
+ param.setFlags(
+ param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
)
- param.setFlags(param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
self.params.append(param)
if has_raster_output:
# Add a createopt parameter for format export
param = QgsProcessingParameterString(
self.GRASS_RASTER_FORMAT_OPT,
- self.tr('Output Rasters format options (createopt)'),
- multiLine=True, optional=True
+ self.tr("Output Rasters format options (createopt)"),
+ multiLine=True,
+ optional=True,
+ )
+ param.setFlags(
+ param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
)
- param.setFlags(param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
- param.setHelp(self.tr('Creation options should be comma separated'))
+ param.setHelp(self.tr("Creation options should be comma separated"))
self.params.append(param)
# Add a metadata parameter for format export
param = QgsProcessingParameterString(
self.GRASS_RASTER_FORMAT_META,
- self.tr('Output Rasters format metadata options (metaopt)'),
- multiLine=True, optional=True
+ self.tr("Output Rasters format metadata options (metaopt)"),
+ multiLine=True,
+ optional=True,
)
- param.setFlags(param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
- param.setHelp(self.tr('Metadata options should be comma separated'))
+ param.setFlags(
+ param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
+ param.setHelp(self.tr("Metadata options should be comma separated"))
self.params.append(param)
if has_vector_input:
- param = QgsProcessingParameterNumber(self.GRASS_SNAP_TOLERANCE_PARAMETER,
- self.tr('v.in.ogr snap tolerance (-1 = no snap)'),
- type=QgsProcessingParameterNumber.Type.Double,
- minValue=-1.0, maxValue=sys.float_info.max + 1,
- defaultValue=-1.0)
- param.setFlags(param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
+ param = QgsProcessingParameterNumber(
+ self.GRASS_SNAP_TOLERANCE_PARAMETER,
+ self.tr("v.in.ogr snap tolerance (-1 = no snap)"),
+ type=QgsProcessingParameterNumber.Type.Double,
+ minValue=-1.0,
+ maxValue=sys.float_info.max + 1,
+ defaultValue=-1.0,
+ )
+ param.setFlags(
+ param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
self.params.append(param)
- param = QgsProcessingParameterNumber(self.GRASS_MIN_AREA_PARAMETER,
- self.tr('v.in.ogr min area'),
- type=QgsProcessingParameterNumber.Type.Double,
- minValue=0.0, maxValue=sys.float_info.max + 1,
- defaultValue=0.0001)
- param.setFlags(param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
+ param = QgsProcessingParameterNumber(
+ self.GRASS_MIN_AREA_PARAMETER,
+ self.tr("v.in.ogr min area"),
+ type=QgsProcessingParameterNumber.Type.Double,
+ minValue=0.0,
+ maxValue=sys.float_info.max + 1,
+ defaultValue=0.0001,
+ )
+ param.setFlags(
+ param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
self.params.append(param)
if has_vector_outputs:
# Add an optional output type
- param = QgsProcessingParameterEnum(self.GRASS_OUTPUT_TYPE_PARAMETER,
- self.tr('v.out.ogr output type'),
- self.OUTPUT_TYPES,
- defaultValue=0)
- param.setFlags(param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
+ param = QgsProcessingParameterEnum(
+ self.GRASS_OUTPUT_TYPE_PARAMETER,
+ self.tr("v.out.ogr output type"),
+ self.OUTPUT_TYPES,
+ defaultValue=0,
+ )
+ param.setFlags(
+ param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
self.params.append(param)
# Add a DSCO parameter for format export
param = QgsProcessingParameterString(
self.GRASS_VECTOR_DSCO,
- self.tr('v.out.ogr output data source options (dsco)'),
- multiLine=True, optional=True
+ self.tr("v.out.ogr output data source options (dsco)"),
+ multiLine=True,
+ optional=True,
+ )
+ param.setFlags(
+ param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
)
- param.setFlags(param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
self.params.append(param)
# Add a LCO parameter for format export
param = QgsProcessingParameterString(
self.GRASS_VECTOR_LCO,
- self.tr('v.out.ogr output layer options (lco)'),
- multiLine=True, optional=True
+ self.tr("v.out.ogr output layer options (lco)"),
+ multiLine=True,
+ optional=True,
+ )
+ param.setFlags(
+ param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
)
- param.setFlags(param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
self.params.append(param)
# Add a -c flag for export
param = QgsProcessingParameterBoolean(
self.GRASS_VECTOR_EXPORT_NOCAT,
- self.tr('Also export features without category (not labeled). Otherwise only features with category are exported'),
- False
+ self.tr(
+ "Also export features without category (not labeled). Otherwise only features with category are exported"
+ ),
+ False,
+ )
+ param.setFlags(
+ param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
)
- param.setFlags(param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
self.params.append(param)
def getDefaultCellSize(self):
@@ -420,38 +468,41 @@ def grabDefaultGrassParameters(self, parameters, context):
object attributes for faster retrieving.
"""
# GRASS region extent
- self.region = self.parameterAsExtent(parameters,
- self.GRASS_REGION_EXTENT_PARAMETER,
- context)
+ self.region = self.parameterAsExtent(
+ parameters, self.GRASS_REGION_EXTENT_PARAMETER, context
+ )
# GRASS cell size
if self.parameterDefinition(self.GRASS_REGION_CELLSIZE_PARAMETER):
- self.cellSize = self.parameterAsDouble(parameters,
- self.GRASS_REGION_CELLSIZE_PARAMETER,
- context)
+ self.cellSize = self.parameterAsDouble(
+ parameters, self.GRASS_REGION_CELLSIZE_PARAMETER, context
+ )
# GRASS snap tolerance
- self.snapTolerance = self.parameterAsDouble(parameters,
- self.GRASS_SNAP_TOLERANCE_PARAMETER,
- context)
+ self.snapTolerance = self.parameterAsDouble(
+ parameters, self.GRASS_SNAP_TOLERANCE_PARAMETER, context
+ )
# GRASS min area
- self.minArea = self.parameterAsDouble(parameters,
- self.GRASS_MIN_AREA_PARAMETER,
- context)
+ self.minArea = self.parameterAsDouble(
+ parameters, self.GRASS_MIN_AREA_PARAMETER, context
+ )
# GRASS output type
- self.outputType = self.parameterAsString(parameters,
- self.GRASS_OUTPUT_TYPE_PARAMETER,
- context)
+ self.outputType = self.parameterAsString(
+ parameters, self.GRASS_OUTPUT_TYPE_PARAMETER, context
+ )
# GRASS align to resolution
- self.alignToResolution = self.parameterAsBoolean(parameters,
- self.GRASS_REGION_ALIGN_TO_RESOLUTION,
- context)
+ self.alignToResolution = self.parameterAsBoolean(
+ parameters, self.GRASS_REGION_ALIGN_TO_RESOLUTION, context
+ )
def processAlgorithm(self, original_parameters, context, feedback):
if isWindows():
path = GrassUtils.grassPath()
- if path == '':
+ if path == "":
raise QgsProcessingException(
- self.tr('GRASS GIS folder is not configured. Please '
- 'configure it before running GRASS GIS algorithms.'))
+ self.tr(
+ "GRASS GIS folder is not configured. Please "
+ "configure it before running GRASS GIS algorithms."
+ )
+ )
# make a copy of the original parameters dictionary - it gets modified by grass algorithms
parameters = {k: v for k, v in original_parameters.items()}
@@ -475,20 +526,22 @@ def processAlgorithm(self, original_parameters, context, feedback):
self.grabDefaultGrassParameters(parameters, context)
# Handle ext functions for inputs/command/outputs
- for fName in ['Inputs', 'Command', 'Outputs']:
- fullName = 'process{}'.format(fName)
+ for fName in ["Inputs", "Command", "Outputs"]:
+ fullName = f"process{fName}"
if self.module and hasattr(self.module, fullName):
getattr(self.module, fullName)(self, parameters, context, feedback)
else:
getattr(self, fullName)(parameters, context, feedback)
# Run GRASS
- loglines = [self.tr('GRASS GIS execution commands')]
+ loglines = [self.tr("GRASS GIS execution commands")]
for line in self.commands:
feedback.pushCommandInfo(line)
loglines.append(line)
if ProcessingConfig.getSetting(GrassUtils.GRASS_LOG_COMMANDS):
- QgsMessageLog.logMessage("\n".join(loglines), self.tr('Processing'), Qgis.MessageLevel.Info)
+ QgsMessageLog.logMessage(
+ "\n".join(loglines), self.tr("Processing"), Qgis.MessageLevel.Info
+ )
GrassUtils.executeGrass(self.commands, feedback, self.outputCommands)
@@ -509,8 +562,8 @@ def processAlgorithm(self, original_parameters, context, feedback):
else:
outputs[outName] = parameters[outName]
if isinstance(out, QgsProcessingOutputHtml):
- if self.module and hasattr(self.module, 'convertToHtml'):
- func = getattr(self.module, 'convertToHtml')
+ if self.module and hasattr(self.module, "convertToHtml"):
+ func = getattr(self.module, "convertToHtml")
func(self, self.fileOutputs[outName], outputs)
else:
self.convertToHtml(self.fileOutputs[outName])
@@ -518,11 +571,19 @@ def processAlgorithm(self, original_parameters, context, feedback):
def processInputs(self, parameters, context, feedback):
"""Prepare the GRASS import commands"""
- inputs = [p for p in self.parameterDefinitions()
- if isinstance(p, (QgsProcessingParameterVectorLayer,
- QgsProcessingParameterFeatureSource,
- QgsProcessingParameterRasterLayer,
- QgsProcessingParameterMultipleLayers))]
+ inputs = [
+ p
+ for p in self.parameterDefinitions()
+ if isinstance(
+ p,
+ (
+ QgsProcessingParameterVectorLayer,
+ QgsProcessingParameterFeatureSource,
+ QgsProcessingParameterRasterLayer,
+ QgsProcessingParameterMultipleLayers,
+ ),
+ )
+ ]
for param in inputs:
paramName = param.name()
if paramName not in parameters:
@@ -530,35 +591,51 @@ def processInputs(self, parameters, context, feedback):
# Handle Null parameter
if parameters[paramName] is None:
continue
- elif isinstance(parameters[paramName], str) and len(parameters[paramName]) == 0:
+ elif (
+ isinstance(parameters[paramName], str)
+ and len(parameters[paramName]) == 0
+ ):
continue
# Raster inputs needs to be imported into temp GRASS DB
if isinstance(param, QgsProcessingParameterRasterLayer):
if paramName not in self.exportedLayers:
- self.loadRasterLayerFromParameter(
- paramName, parameters, context)
+ self.loadRasterLayerFromParameter(paramName, parameters, context)
# Vector inputs needs to be imported into temp GRASS DB
- elif isinstance(param, (QgsProcessingParameterFeatureSource, QgsProcessingParameterVectorLayer)):
+ elif isinstance(
+ param,
+ (
+ QgsProcessingParameterFeatureSource,
+ QgsProcessingParameterVectorLayer,
+ ),
+ ):
if paramName not in self.exportedLayers:
# Attribute tables are also vector inputs
if QgsProcessing.SourceType.TypeFile in param.dataTypes():
self.loadAttributeTableFromParameter(
- paramName, parameters, context)
+ paramName, parameters, context
+ )
else:
self.loadVectorLayerFromParameter(
- paramName, parameters, context, external=None, feedback=feedback)
+ paramName,
+ parameters,
+ context,
+ external=None,
+ feedback=feedback,
+ )
# For multiple inputs, process each layer
elif isinstance(param, QgsProcessingParameterMultipleLayers):
layers = self.parameterAsLayerList(parameters, paramName, context)
for idx, layer in enumerate(layers):
- layerName = '{}_{}'.format(paramName, idx)
+ layerName = f"{paramName}_{idx}"
# Add a raster layer
if layer.type() == QgsMapLayerType.RasterLayer:
self.loadRasterLayer(layerName, layer, context)
# Add a vector layer
elif layer.type() == QgsMapLayerType.VectorLayer:
- self.loadVectorLayer(layerName, layer, context, external=None, feedback=feedback)
+ self.loadVectorLayer(
+ layerName, layer, context, external=None, feedback=feedback
+ )
self.postInputs(context)
@@ -571,10 +648,14 @@ def postInputs(self, context: QgsProcessingContext):
# Build GRASS region
if self.region.isEmpty():
- self.region = QgsProcessingUtils.combineLayerExtents(self.inputLayers, self.destination_crs, context)
- command = 'g.region n={} s={} e={} w={}'.format(
- self.region.yMaximum(), self.region.yMinimum(),
- self.region.xMaximum(), self.region.xMinimum()
+ self.region = QgsProcessingUtils.combineLayerExtents(
+ self.inputLayers, self.destination_crs, context
+ )
+ command = "g.region n={} s={} e={} w={}".format(
+ self.region.yMaximum(),
+ self.region.yMinimum(),
+ self.region.xMaximum(),
+ self.region.xMinimum(),
)
# Handle cell size
if self.parameterDefinition(self.GRASS_REGION_CELLSIZE_PARAMETER):
@@ -582,16 +663,20 @@ def postInputs(self, context: QgsProcessingContext):
cellSize = self.cellSize
else:
cellSize = self.getDefaultCellSize()
- command += ' res={}'.format(cellSize)
+ command += f" res={cellSize}"
# Handle align to resolution
if self.alignToResolution:
- command += ' -a'
+ command += " -a"
# Add the default parameters commands
self.commands.append(command)
- QgsMessageLog.logMessage(self.tr('processInputs end. Commands: {}').format(self.commands), 'Grass', Qgis.MessageLevel.Info)
+ QgsMessageLog.logMessage(
+ self.tr("processInputs end. Commands: {}").format(self.commands),
+ "Grass",
+ Qgis.MessageLevel.Info,
+ )
def processCommand(self, parameters, context, feedback, delOutputs=False):
"""
@@ -600,9 +685,13 @@ def processCommand(self, parameters, context, feedback, delOutputs=False):
:param context:
:param delOutputs: do not add outputs to commands.
"""
- noOutputs = [o for o in self.parameterDefinitions() if o not in self.destinationParameterDefinitions()]
- command = '{} '.format(self.grass_name)
- command += '{}'.join(self.hardcodedStrings)
+ noOutputs = [
+ o
+ for o in self.parameterDefinitions()
+ if o not in self.destinationParameterDefinitions()
+ ]
+ command = f"{self.grass_name} "
+ command += "{}".join(self.hardcodedStrings)
# Add algorithm command
for param in noOutputs:
@@ -610,42 +699,51 @@ def processCommand(self, parameters, context, feedback, delOutputs=False):
value = None
# Exclude default GRASS parameters
- if paramName in [self.GRASS_REGION_CELLSIZE_PARAMETER,
- self.GRASS_REGION_EXTENT_PARAMETER,
- self.GRASS_MIN_AREA_PARAMETER,
- self.GRASS_SNAP_TOLERANCE_PARAMETER,
- self.GRASS_OUTPUT_TYPE_PARAMETER,
- self.GRASS_REGION_ALIGN_TO_RESOLUTION,
- self.GRASS_RASTER_FORMAT_OPT,
- self.GRASS_RASTER_FORMAT_META,
- self.GRASS_VECTOR_DSCO,
- self.GRASS_VECTOR_LCO,
- self.GRASS_VECTOR_EXPORT_NOCAT]:
+ if paramName in [
+ self.GRASS_REGION_CELLSIZE_PARAMETER,
+ self.GRASS_REGION_EXTENT_PARAMETER,
+ self.GRASS_MIN_AREA_PARAMETER,
+ self.GRASS_SNAP_TOLERANCE_PARAMETER,
+ self.GRASS_OUTPUT_TYPE_PARAMETER,
+ self.GRASS_REGION_ALIGN_TO_RESOLUTION,
+ self.GRASS_RASTER_FORMAT_OPT,
+ self.GRASS_RASTER_FORMAT_META,
+ self.GRASS_VECTOR_DSCO,
+ self.GRASS_VECTOR_LCO,
+ self.GRASS_VECTOR_EXPORT_NOCAT,
+ ]:
continue
# Raster and vector layers
- if isinstance(param, (QgsProcessingParameterRasterLayer,
- QgsProcessingParameterVectorLayer,
- QgsProcessingParameterFeatureSource)):
+ if isinstance(
+ param,
+ (
+ QgsProcessingParameterRasterLayer,
+ QgsProcessingParameterVectorLayer,
+ QgsProcessingParameterFeatureSource,
+ ),
+ ):
if paramName in self.exportedLayers:
value = self.exportedLayers[paramName]
else:
value = self.parameterAsCompatibleSourceLayerPath(
- parameters, paramName, context,
- QgsVectorFileWriter.supportedFormatExtensions()
+ parameters,
+ paramName,
+ context,
+ QgsVectorFileWriter.supportedFormatExtensions(),
)
# MultipleLayers
elif isinstance(param, QgsProcessingParameterMultipleLayers):
layers = self.parameterAsLayerList(parameters, paramName, context)
values = []
for idx in range(len(layers)):
- layerName = '{}_{}'.format(paramName, idx)
+ layerName = f"{paramName}_{idx}"
values.append(self.exportedLayers[layerName])
- value = ','.join(values)
+ value = ",".join(values)
# For booleans, we just add the parameter name
elif isinstance(param, QgsProcessingParameterBoolean):
if self.parameterAsBoolean(parameters, paramName, context):
- command += ' {}'.format(paramName)
+ command += f" {paramName}"
# For Extents, remove if the value is null
elif isinstance(param, QgsProcessingParameterExtent):
if self.parameterAsExtent(parameters, paramName, context):
@@ -658,7 +756,9 @@ def processCommand(self, parameters, context, feedback, delOutputs=False):
else:
indexes = [self.parameterAsEnum(parameters, paramName, context)]
if indexes:
- value = '"{}"'.format(','.join([param.options()[i] for i in indexes]))
+ value = '"{}"'.format(
+ ",".join([param.options()[i] for i in indexes])
+ )
# For strings, we just translate as string
elif isinstance(param, QgsProcessingParameterString):
data = self.parameterAsString(parameters, paramName, context)
@@ -669,9 +769,7 @@ def processCommand(self, parameters, context, feedback, delOutputs=False):
)
# For fields, we just translate as string
elif isinstance(param, QgsProcessingParameterField):
- value = ','.join(
- self.parameterAsFields(parameters, paramName, context)
- )
+ value = ",".join(self.parameterAsFields(parameters, paramName, context))
elif isinstance(param, QgsProcessingParameterFile):
if self.parameterAsString(parameters, paramName, context):
value = '"{}"'.format(
@@ -682,29 +780,32 @@ def processCommand(self, parameters, context, feedback, delOutputs=False):
# parameter specified, evaluate as point
# TODO - handle CRS transform
point = self.parameterAsPoint(parameters, paramName, context)
- value = '{},{}'.format(point.x(), point.y())
+ value = f"{point.x()},{point.y()}"
# For numbers, we translate as a string
- elif isinstance(param, (QgsProcessingParameterNumber,
- QgsProcessingParameterPoint)):
+ elif isinstance(
+ param, (QgsProcessingParameterNumber, QgsProcessingParameterPoint)
+ ):
value = self.parameterAsString(parameters, paramName, context)
elif isinstance(param, QgsProcessingParameterRange):
v = self.parameterAsRange(parameters, paramName, context)
- if (param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional) and (math.isnan(v[0]) or math.isnan(v[1])):
+ if (
+ param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional
+ ) and (math.isnan(v[0]) or math.isnan(v[1])):
continue
else:
- value = '{},{}'.format(v[0], v[1])
+ value = f"{v[0]},{v[1]}"
elif isinstance(param, QgsProcessingParameterCrs):
if self.parameterAsCrs(parameters, paramName, context):
# TODO: ideally we should be exporting to WKT here, but it seems not all grass algorithms
# will accept a wkt string for a crs value (e.g. r.tileset)
- value = '"{}"'.format(self.parameterAsCrs(parameters, paramName, context).toProj())
+ value = f'"{self.parameterAsCrs(parameters, paramName, context).toProj()}"'
# For everything else, we assume that it is a string
else:
value = '"{}"'.format(
self.parameterAsString(parameters, paramName, context)
)
if value:
- command += ' {}={}'.format(paramName.replace('~', ''), value)
+ command += " {}={}".format(paramName.replace("~", ""), value)
# Handle outputs
if not delOutputs:
@@ -716,47 +817,52 @@ def processCommand(self, parameters, context, feedback, delOutputs=False):
# For File destination
if isinstance(out, QgsProcessingParameterFileDestination):
if outName in parameters and parameters[outName] is not None:
- outPath = self.parameterAsFileOutput(parameters, outName, context)
+ outPath = self.parameterAsFileOutput(
+ parameters, outName, context
+ )
self.fileOutputs[outName] = outPath
# for HTML reports, we need to redirect stdout
- if out.defaultFileExtension().lower() == 'html':
- if outName == 'html':
+ if out.defaultFileExtension().lower() == "html":
+ if outName == "html":
# for "fake" outputs redirect command stdout
- command += ' > "{}"'.format(outPath)
+ command += f' > "{outPath}"'
else:
# for real outputs only output itself should be redirected
- command += ' {}=- > "{}"'.format(outName, outPath)
+ command += f' {outName}=- > "{outPath}"'
else:
- command += ' {}="{}"'.format(outName, outPath)
+ command += f' {outName}="{outPath}"'
# For folders destination
elif isinstance(out, QgsProcessingParameterFolderDestination):
# We need to add a unique temporary basename
uniqueBasename = outName + self.uniqueSuffix
- command += ' {}={}'.format(outName, uniqueBasename)
+ command += f" {outName}={uniqueBasename}"
else:
if outName in parameters and parameters[outName] is not None:
# We add an output name to make sure it is unique if the session
# uses this algorithm several times.
uniqueOutputName = outName + self.uniqueSuffix
- command += ' {}={}'.format(outName, uniqueOutputName)
+ command += f" {outName}={uniqueOutputName}"
# Add output file to exported layers, to indicate that
# they are present in GRASS
self.exportedLayers[outName] = uniqueOutputName
- command += ' --overwrite'
+ command += " --overwrite"
self.commands.append(command)
- QgsMessageLog.logMessage(self.tr('processCommands end. Commands: {}').format(self.commands), 'Grass', Qgis.MessageLevel.Info)
+ QgsMessageLog.logMessage(
+ self.tr("processCommands end. Commands: {}").format(self.commands),
+ "Grass",
+ Qgis.MessageLevel.Info,
+ )
def vectorOutputType(self, parameters, context):
"""Determine vector output types for outputs"""
- self.outType = 'auto'
+ self.outType = "auto"
if self.parameterDefinition(self.GRASS_OUTPUT_TYPE_PARAMETER):
- typeidx = self.parameterAsEnum(parameters,
- self.GRASS_OUTPUT_TYPE_PARAMETER,
- context)
- self.outType = ('auto' if typeidx
- is None else self.OUTPUT_TYPES[typeidx])
+ typeidx = self.parameterAsEnum(
+ parameters, self.GRASS_OUTPUT_TYPE_PARAMETER, context
+ )
+ self.outType = "auto" if typeidx is None else self.OUTPUT_TYPES[typeidx]
def processOutputs(self, parameters, context, feedback):
"""Prepare the GRASS v.out.ogr commands"""
@@ -776,9 +882,9 @@ def processOutputs(self, parameters, context, feedback):
elif isinstance(out, QgsProcessingParameterFolderDestination):
self.exportRasterLayersIntoDirectory(outName, parameters, context)
- def loadRasterLayerFromParameter(self, name, parameters,
- context: QgsProcessingContext,
- external=None, band=1):
+ def loadRasterLayerFromParameter(
+ self, name, parameters, context: QgsProcessingContext, external=None, band=1
+ ):
"""
Creates a dedicated command to load a raster into
the temporary GRASS DB.
@@ -791,8 +897,15 @@ def loadRasterLayerFromParameter(self, name, parameters,
layer = self.parameterAsRasterLayer(parameters, name, context)
self.loadRasterLayer(name, layer, context, external, band)
- def loadRasterLayer(self, name, layer, context: QgsProcessingContext,
- external=None, band=1, destName=None):
+ def loadRasterLayer(
+ self,
+ name,
+ layer,
+ context: QgsProcessingContext,
+ external=None,
+ band=1,
+ destName=None,
+ ):
"""
Creates a dedicated command to load a raster into
the temporary GRASS DB.
@@ -808,16 +921,19 @@ def loadRasterLayer(self, name, layer, context: QgsProcessingContext,
self.inputLayers.append(layer)
self.setSessionProjectionFromLayer(layer, context)
if not destName:
- destName = 'rast_{}'.format(os.path.basename(getTempFilename(context=context)))
+ destName = f"rast_{os.path.basename(getTempFilename(context=context))}"
self.exportedLayers[name] = destName
command = '{} input="{}" {}output="{}" --overwrite -o'.format(
- 'r.external' if external else 'r.in.gdal',
+ "r.external" if external else "r.in.gdal",
os.path.normpath(layer.source()),
- 'band={} '.format(band) if band else '',
- destName)
+ f"band={band} " if band else "",
+ destName,
+ )
self.commands.append(command)
- def exportRasterLayerFromParameter(self, name, parameters, context, colorTable=True):
+ def exportRasterLayerFromParameter(
+ self, name, parameters, context, colorTable=True
+ ):
"""
Creates a dedicated command to export a raster from
temporary GRASS DB into a file via gdal.
@@ -831,18 +947,29 @@ def exportRasterLayerFromParameter(self, name, parameters, context, colorTable=T
return
fileName = os.path.normpath(fileName)
- grassName = '{}{}'.format(name, self.uniqueSuffix)
+ grassName = f"{name}{self.uniqueSuffix}"
outFormat = GrassUtils.getRasterFormatFromFilename(fileName)
- createOpt = self.parameterAsString(parameters, self.GRASS_RASTER_FORMAT_OPT, context)
- metaOpt = self.parameterAsString(parameters, self.GRASS_RASTER_FORMAT_META, context)
- self.exportRasterLayer(grassName, fileName, colorTable, outFormat, createOpt, metaOpt)
+ createOpt = self.parameterAsString(
+ parameters, self.GRASS_RASTER_FORMAT_OPT, context
+ )
+ metaOpt = self.parameterAsString(
+ parameters, self.GRASS_RASTER_FORMAT_META, context
+ )
+ self.exportRasterLayer(
+ grassName, fileName, colorTable, outFormat, createOpt, metaOpt
+ )
self.fileOutputs[name] = fileName
- def exportRasterLayer(self, grassName, fileName,
- colorTable=True, outFormat='GTiff',
- createOpt=None,
- metaOpt=None):
+ def exportRasterLayer(
+ self,
+ grassName,
+ fileName,
+ colorTable=True,
+ outFormat="GTiff",
+ createOpt=None,
+ metaOpt=None,
+ ):
"""
Creates a dedicated command to export a raster from
temporary GRASS DB into a file via gdal.
@@ -853,22 +980,27 @@ def exportRasterLayer(self, grassName, fileName,
:param createOpt: creation options for format.
:param metaOpt: metadata options for export.
"""
- createOpt = createOpt or GrassUtils.GRASS_RASTER_FORMATS_CREATEOPTS.get(outFormat)
+ createOpt = createOpt or GrassUtils.GRASS_RASTER_FORMATS_CREATEOPTS.get(
+ outFormat
+ )
for cmd in [self.commands, self.outputCommands]:
# Adjust region to layer before exporting
- cmd.append('g.region raster={}'.format(grassName))
+ cmd.append(f"g.region raster={grassName}")
cmd.append(
'r.out.gdal -t -m{} input="{}" output="{}" format="{}" {}{} --overwrite'.format(
- '' if colorTable else ' -c',
- grassName, fileName,
+ "" if colorTable else " -c",
+ grassName,
+ fileName,
outFormat,
- ' createopt="{}"'.format(createOpt) if createOpt else '',
- ' metaopt="{}"'.format(metaOpt) if metaOpt else ''
+ f' createopt="{createOpt}"' if createOpt else "",
+ f' metaopt="{metaOpt}"' if metaOpt else "",
)
)
- def exportRasterLayersIntoDirectory(self, name, parameters, context, colorTable=True, wholeDB=False):
+ def exportRasterLayersIntoDirectory(
+ self, name, parameters, context, colorTable=True, wholeDB=False
+ ):
"""
Creates a dedicated loop command to export rasters from
temporary GRASS DB into a directory via gdal.
@@ -879,9 +1011,8 @@ def exportRasterLayersIntoDirectory(self, name, parameters, context, colorTable=
:param wholeDB: export every raster layer from the GRASSDB
"""
# Grab directory name and temporary basename
- outDir = os.path.normpath(
- self.parameterAsString(parameters, name, context))
- basename = ''
+ outDir = os.path.normpath(self.parameterAsString(parameters, name, context))
+ basename = ""
if not wholeDB:
basename = name + self.uniqueSuffix
@@ -890,21 +1021,28 @@ def exportRasterLayersIntoDirectory(self, name, parameters, context, colorTable=
# TODO Format/options support
if isWindows():
cmd.append("if not exist {0} mkdir {0}".format(outDir))
- cmd.append("for /F %%r IN ('g.list type^=rast pattern^=\"{}*\"') do r.out.gdal -m{} input=%%r output={}/%%r.tif {}".format(
- basename,
- ' -t' if colorTable else '',
- outDir,
- '--overwrite -c createopt="TFW=YES,COMPRESS=LZW"'
- ))
+ cmd.append(
+ "for /F %%r IN ('g.list type^=rast pattern^=\"{}*\"') do r.out.gdal -m{} input=%%r output={}/%%r.tif {}".format(
+ basename,
+ " -t" if colorTable else "",
+ outDir,
+ '--overwrite -c createopt="TFW=YES,COMPRESS=LZW"',
+ )
+ )
else:
- cmd.append("for r in $(g.list type=rast pattern='{}*'); do".format(basename))
- cmd.append(" r.out.gdal -m{0} input=${{r}} output={1}/${{r}}.tif {2}".format(
- ' -t' if colorTable else '', outDir,
- '--overwrite -c createopt="TFW=YES,COMPRESS=LZW"'
- ))
+ cmd.append(f"for r in $(g.list type=rast pattern='{basename}*'); do")
+ cmd.append(
+ " r.out.gdal -m{0} input=${{r}} output={1}/${{r}}.tif {2}".format(
+ " -t" if colorTable else "",
+ outDir,
+ '--overwrite -c createopt="TFW=YES,COMPRESS=LZW"',
+ )
+ )
cmd.append("done")
- def loadVectorLayerFromParameter(self, name, parameters, context, feedback, external=False):
+ def loadVectorLayerFromParameter(
+ self, name, parameters, context, feedback, external=False
+ ):
"""
Creates a dedicated command to load a vector into
the temporary GRASS DB.
@@ -915,31 +1053,43 @@ def loadVectorLayerFromParameter(self, name, parameters, context, feedback, exte
"""
layer = self.parameterAsVectorLayer(parameters, name, context)
- is_ogr_disk_based_layer = layer is not None and layer.dataProvider().name() == 'ogr'
+ is_ogr_disk_based_layer = (
+ layer is not None and layer.dataProvider().name() == "ogr"
+ )
if is_ogr_disk_based_layer:
# we only support direct reading of disk based ogr layers -- not ogr postgres layers, etc
- source_parts = QgsProviderRegistry.instance().decodeUri('ogr', layer.source())
- if not source_parts.get('path'):
+ source_parts = QgsProviderRegistry.instance().decodeUri(
+ "ogr", layer.source()
+ )
+ if not source_parts.get("path"):
is_ogr_disk_based_layer = False
- elif source_parts.get('layerId'):
+ elif source_parts.get("layerId"):
# no support for directly reading layers by id in grass
is_ogr_disk_based_layer = False
if not is_ogr_disk_based_layer:
# parameter is not a vector layer or not an OGR layer - try to convert to a source compatible with
# grass OGR inputs and extract selection if required
- path = self.parameterAsCompatibleSourceLayerPath(parameters, name, context,
- QgsVectorFileWriter.supportedFormatExtensions(),
- feedback=feedback)
- ogr_layer = QgsVectorLayer(path, '', 'ogr')
- self.loadVectorLayer(name, ogr_layer, context, external=external, feedback=feedback)
+ path = self.parameterAsCompatibleSourceLayerPath(
+ parameters,
+ name,
+ context,
+ QgsVectorFileWriter.supportedFormatExtensions(),
+ feedback=feedback,
+ )
+ ogr_layer = QgsVectorLayer(path, "", "ogr")
+ self.loadVectorLayer(
+ name, ogr_layer, context, external=external, feedback=feedback
+ )
else:
# already an ogr disk based layer source
- self.loadVectorLayer(name, layer, context, external=external, feedback=feedback)
+ self.loadVectorLayer(
+ name, layer, context, external=external, feedback=feedback
+ )
- def loadVectorLayer(self, name, layer,
- context: QgsProcessingContext,
- external=False, feedback=None):
+ def loadVectorLayer(
+ self, name, layer, context: QgsProcessingContext, external=False, feedback=None
+ ):
"""
Creates a dedicated command to load a vector into
temporary GRASS DB.
@@ -951,47 +1101,57 @@ def loadVectorLayer(self, name, layer,
"""
# TODO: support multiple input formats
if external is None:
- external = ProcessingConfig.getSetting(
- GrassUtils.GRASS_USE_VEXTERNAL)
+ external = ProcessingConfig.getSetting(GrassUtils.GRASS_USE_VEXTERNAL)
- source_parts = QgsProviderRegistry.instance().decodeUri('ogr', layer.source())
- file_path = source_parts.get('path')
- layer_name = source_parts.get('layerName')
+ source_parts = QgsProviderRegistry.instance().decodeUri("ogr", layer.source())
+ file_path = source_parts.get("path")
+ layer_name = source_parts.get("layerName")
# safety check: we can only use external for ogr layers which support random read
if external:
if feedback is not None:
- feedback.pushInfo(self.tr('Attempting to use v.external for direct layer read'))
+ feedback.pushInfo(
+ self.tr("Attempting to use v.external for direct layer read")
+ )
ds = ogr.Open(file_path)
if ds is not None:
ogr_layer = ds.GetLayer()
if ogr_layer is None or not ogr_layer.TestCapability(ogr.OLCRandomRead):
if feedback is not None:
- feedback.reportError(self.tr('Cannot use v.external: layer does not support random read'))
+ feedback.reportError(
+ self.tr(
+ "Cannot use v.external: layer does not support random read"
+ )
+ )
external = False
else:
if feedback is not None:
- feedback.reportError(self.tr('Cannot use v.external: error reading layer'))
+ feedback.reportError(
+ self.tr("Cannot use v.external: error reading layer")
+ )
external = False
self.inputLayers.append(layer)
self.setSessionProjectionFromLayer(layer, context)
- destFilename = 'vector_{}'.format(os.path.basename(getTempFilename(context=context)))
+ destFilename = f"vector_{os.path.basename(getTempFilename(context=context))}"
self.exportedLayers[name] = destFilename
command = '{}{}{} input="{}"{} output="{}" --overwrite -o'.format(
- 'v.external' if external else 'v.in.ogr',
- ' min_area={}'.format(self.minArea) if not external else '',
- ' snap={}'.format(self.snapTolerance) if not external else '',
+ "v.external" if external else "v.in.ogr",
+ f" min_area={self.minArea}" if not external else "",
+ f" snap={self.snapTolerance}" if not external else "",
os.path.normpath(file_path),
- ' layer="{}"'.format(layer_name) if layer_name else '',
- destFilename)
+ f' layer="{layer_name}"' if layer_name else "",
+ destFilename,
+ )
if layer.subsetString():
escaped_subset = layer.subsetString().replace('"', '\\"')
command += f' where="{escaped_subset}"'
self.commands.append(command)
- def exportVectorLayerFromParameter(self, name, parameters, context, layer=None, nocats=False):
+ def exportVectorLayerFromParameter(
+ self, name, parameters, context, layer=None, nocats=False
+ ):
"""
Creates a dedicated command to export a vector from
a QgsProcessingParameter.
@@ -1001,28 +1161,53 @@ def exportVectorLayerFromParameter(self, name, parameters, context, layer=None,
:param nocats: do not export GRASS categories.
"""
fileName = os.path.normpath(
- self.parameterAsOutputLayer(parameters, name, context))
- grassName = '{}{}'.format(name, self.uniqueSuffix)
+ self.parameterAsOutputLayer(parameters, name, context)
+ )
+ grassName = f"{name}{self.uniqueSuffix}"
# Find if there is a dataType
dataType = self.outType
- if self.outType == 'auto':
+ if self.outType == "auto":
parameter = self.parameterDefinition(name)
if parameter:
layerType = parameter.dataType()
if layerType in self.QGIS_OUTPUT_TYPES:
dataType = self.QGIS_OUTPUT_TYPES[layerType]
- outFormat = QgsVectorFileWriter.driverForExtension(os.path.splitext(fileName)[1]).replace(' ', '_')
+ outFormat = QgsVectorFileWriter.driverForExtension(
+ os.path.splitext(fileName)[1]
+ ).replace(" ", "_")
dsco = self.parameterAsString(parameters, self.GRASS_VECTOR_DSCO, context)
lco = self.parameterAsString(parameters, self.GRASS_VECTOR_LCO, context)
- exportnocat = self.parameterAsBoolean(parameters, self.GRASS_VECTOR_EXPORT_NOCAT, context)
- self.exportVectorLayer(grassName, fileName, layer, nocats, dataType, outFormat, dsco, lco, exportnocat)
+ exportnocat = self.parameterAsBoolean(
+ parameters, self.GRASS_VECTOR_EXPORT_NOCAT, context
+ )
+ self.exportVectorLayer(
+ grassName,
+ fileName,
+ layer,
+ nocats,
+ dataType,
+ outFormat,
+ dsco,
+ lco,
+ exportnocat,
+ )
self.fileOutputs[name] = fileName
- def exportVectorLayer(self, grassName, fileName, layer=None, nocats=False, dataType='auto',
- outFormat=None, dsco=None, lco=None, exportnocat=False):
+ def exportVectorLayer(
+ self,
+ grassName,
+ fileName,
+ layer=None,
+ nocats=False,
+ dataType="auto",
+ outFormat=None,
+ dsco=None,
+ lco=None,
+ exportnocat=False,
+ ):
"""
Creates a dedicated command to export a vector from
temporary GRASS DB into a file via OGR.
@@ -1037,18 +1222,22 @@ def exportVectorLayer(self, grassName, fileName, layer=None, nocats=False, dataT
:param exportnocat: do not export features without categories.
"""
if outFormat is None:
- outFormat = QgsVectorFileWriter.driverForExtension(os.path.splitext(fileName)[1]).replace(' ', '_')
+ outFormat = QgsVectorFileWriter.driverForExtension(
+ os.path.splitext(fileName)[1]
+ ).replace(" ", "_")
for cmd in [self.commands, self.outputCommands]:
cmd.append(
'v.out.ogr{} type="{}" input="{}" output="{}" format="{}" {}{}{}{} --overwrite'.format(
- '' if nocats else '',
- dataType, grassName, fileName,
+ "" if nocats else "",
+ dataType,
+ grassName,
+ fileName,
outFormat,
- 'layer={}'.format(layer) if layer else '',
- ' dsco="{}"'.format(dsco) if dsco else '',
- ' lco="{}"'.format(lco) if lco else '',
- ' -c' if exportnocat else ''
+ f"layer={layer}" if layer else "",
+ f' dsco="{dsco}"' if dsco else "",
+ f' lco="{lco}"' if lco else "",
+ " -c" if exportnocat else "",
)
)
@@ -1063,8 +1252,9 @@ def loadAttributeTableFromParameter(self, name, parameters, context):
table = self.parameterAsVectorLayer(parameters, name, context)
self.loadAttributeTable(name, table, context)
- def loadAttributeTable(self, name, layer, context: QgsProcessingContext,
- destName=None):
+ def loadAttributeTable(
+ self, name, layer, context: QgsProcessingContext, destName=None
+ ):
"""
Creates a dedicated command to load an attribute table
into the temporary GRASS DB.
@@ -1075,13 +1265,14 @@ def loadAttributeTable(self, name, layer, context: QgsProcessingContext,
"""
self.inputLayers.append(layer)
if not destName:
- destName = 'table_{}'.format(os.path.basename(getTempFilename(context=context)))
+ destName = f"table_{os.path.basename(getTempFilename(context=context))}"
self.exportedLayers[name] = destName
command = 'db.in.ogr --overwrite input="{}" output="{}"'.format(
- os.path.normpath(layer.source()), destName)
+ os.path.normpath(layer.source()), destName
+ )
self.commands.append(command)
- def exportAttributeTable(self, grassName, fileName, outFormat='CSV', layer=1):
+ def exportAttributeTable(self, grassName, fileName, outFormat="CSV", layer=1):
"""
Creates a dedicated command to export an attribute
table from the temporary GRASS DB into a file via ogr.
@@ -1104,11 +1295,12 @@ def setSessionProjectionFromProject(self, context: QgsProcessingContext):
"""
if not GrassUtils.projectionSet and iface:
self.setSessionProjection(
- iface.mapCanvas().mapSettings().destinationCrs(),
- context
+ iface.mapCanvas().mapSettings().destinationCrs(), context
)
- def setSessionProjectionFromLayer(self, layer: QgsMapLayer, context: QgsProcessingContext):
+ def setSessionProjectionFromLayer(
+ self, layer: QgsMapLayer, context: QgsProcessingContext
+ ):
"""
Set the projection from a QgsVectorLayer.
We create a WKT definition which is transmitted to Grass
@@ -1122,25 +1314,27 @@ def setSessionProjection(self, crs, context: QgsProcessingContext):
"""
self.destination_crs = crs
file_name = GrassUtils.exportCrsWktToFile(crs, context)
- command = 'g.proj -c wkt="{}"'.format(file_name)
+ command = f'g.proj -c wkt="{file_name}"'
self.commands.append(command)
GrassUtils.projectionSet = True
def convertToHtml(self, fileName):
# Read HTML contents
lines = []
- with open(fileName, encoding='utf-8') as f:
+ with open(fileName, encoding="utf-8") as f:
lines = f.readlines()
- if len(lines) > 1 and '' not in lines[0]:
+ if len(lines) > 1 and "" not in lines[0]:
# Then write into the HTML file
- with open(fileName, 'w', encoding='utf-8') as f:
- f.write('')
- f.write(' ')
- f.write('')
+ with open(fileName, "w", encoding="utf-8") as f:
+ f.write("
")
+ f.write(
+ ' '
+ )
+ f.write("")
for line in lines:
- f.write('{}'.format(line))
- f.write('
')
+ f.write(f"{line}")
+ f.write("")
def canExecute(self):
message = GrassUtils.checkGrassIsInstalled()
@@ -1149,7 +1343,7 @@ def canExecute(self):
def checkParameterValues(self, parameters, context):
grass_parameters = {k: v for k, v in parameters.items()}
if self.module:
- if hasattr(self.module, 'checkParameterValuesBeforeExecuting'):
- func = getattr(self.module, 'checkParameterValuesBeforeExecuting')
+ if hasattr(self.module, "checkParameterValuesBeforeExecuting"):
+ func = getattr(self.module, "checkParameterValuesBeforeExecuting")
return func(self, grass_parameters, context)
return super().checkParameterValues(grass_parameters, context)
diff --git a/python/plugins/grassprovider/grass_plugin.py b/python/plugins/grassprovider/grass_plugin.py
index 1f82de63e7f9..7bf0c99f75b7 100644
--- a/python/plugins/grassprovider/grass_plugin.py
+++ b/python/plugins/grassprovider/grass_plugin.py
@@ -15,14 +15,14 @@
***************************************************************************
"""
-__author__ = 'Alexander Bruy'
-__date__ = 'June 2021'
-__copyright__ = '(C) 2021, Alexander Bruy'
+__author__ = "Alexander Bruy"
+__date__ = "June 2021"
+__copyright__ = "(C) 2021, Alexander Bruy"
from qgis.core import QgsApplication, QgsRuntimeProfiler
-with QgsRuntimeProfiler.profile('Import GRASS Provider'):
+with QgsRuntimeProfiler.profile("Import GRASS Provider"):
from grassprovider.grass_provider import GrassProvider
diff --git a/python/plugins/grassprovider/grass_provider.py b/python/plugins/grassprovider/grass_provider.py
index a71769397659..19022c0d08cc 100644
--- a/python/plugins/grassprovider/grass_provider.py
+++ b/python/plugins/grassprovider/grass_provider.py
@@ -15,21 +15,23 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'April 2014'
-__copyright__ = '(C) 2014, Victor Olaya'
+__author__ = "Victor Olaya"
+__date__ = "April 2014"
+__copyright__ = "(C) 2014, Victor Olaya"
import json
from typing import List
from qgis.PyQt.QtCore import QCoreApplication
-from qgis.core import (Qgis,
- QgsApplication,
- QgsProcessingAlgorithm,
- QgsProcessingProvider,
- QgsVectorFileWriter,
- QgsMessageLog,
- QgsRuntimeProfiler)
-from processing.core.ProcessingConfig import (ProcessingConfig, Setting)
+from qgis.core import (
+ Qgis,
+ QgsApplication,
+ QgsProcessingAlgorithm,
+ QgsProcessingProvider,
+ QgsVectorFileWriter,
+ QgsMessageLog,
+ QgsRuntimeProfiler,
+)
+from processing.core.ProcessingConfig import ProcessingConfig, Setting
from grassprovider.grass_utils import GrassUtils
from grassprovider.grass_algorithm import GrassAlgorithm
@@ -40,35 +42,57 @@ def __init__(self):
super().__init__()
def load(self):
- with QgsRuntimeProfiler.profile('Grass Provider'):
+ with QgsRuntimeProfiler.profile("Grass Provider"):
ProcessingConfig.settingIcons[self.name()] = self.icon()
- ProcessingConfig.addSetting(Setting(
- self.name(),
- GrassUtils.GRASS_LOG_COMMANDS,
- self.tr('Log execution commands'), False))
- ProcessingConfig.addSetting(Setting(
- self.name(),
- GrassUtils.GRASS_LOG_CONSOLE,
- self.tr('Log console output'), False))
- ProcessingConfig.addSetting(Setting(
- self.name(),
- GrassUtils.GRASS_HELP_URL,
- self.tr('Location of GRASS docs'), ''))
+ ProcessingConfig.addSetting(
+ Setting(
+ self.name(),
+ GrassUtils.GRASS_LOG_COMMANDS,
+ self.tr("Log execution commands"),
+ False,
+ )
+ )
+ ProcessingConfig.addSetting(
+ Setting(
+ self.name(),
+ GrassUtils.GRASS_LOG_CONSOLE,
+ self.tr("Log console output"),
+ False,
+ )
+ )
+ ProcessingConfig.addSetting(
+ Setting(
+ self.name(),
+ GrassUtils.GRASS_HELP_URL,
+ self.tr("Location of GRASS docs"),
+ "",
+ )
+ )
# Add settings for using r.external/v.external instead of r.in.gdal/v.in.ogr
# but set them to False by default because the {r,v}.external implementations
# have some bugs on windows + there are algorithms that can't be used with
# external data (need a solid r.in.gdal/v.in.ogr).
# For more info have a look at e.g. https://trac.osgeo.org/grass/ticket/3927
- ProcessingConfig.addSetting(Setting(
- self.name(),
- GrassUtils.GRASS_USE_REXTERNAL,
- self.tr('For raster layers, use r.external (faster) instead of r.in.gdal'),
- False))
- ProcessingConfig.addSetting(Setting(
- self.name(),
- GrassUtils.GRASS_USE_VEXTERNAL,
- self.tr('For vector layers, use v.external (faster) instead of v.in.ogr'),
- False))
+ ProcessingConfig.addSetting(
+ Setting(
+ self.name(),
+ GrassUtils.GRASS_USE_REXTERNAL,
+ self.tr(
+ "For raster layers, use r.external (faster) instead of r.in.gdal"
+ ),
+ False,
+ )
+ )
+ ProcessingConfig.addSetting(
+ Setting(
+ self.name(),
+ GrassUtils.GRASS_USE_VEXTERNAL,
+ self.tr(
+ "For vector layers, use v.external (faster) instead of v.in.ogr"
+ ),
+ False,
+ )
+ )
ProcessingConfig.readSettings()
self.refreshAlgorithms()
@@ -81,68 +105,94 @@ def unload(self):
ProcessingConfig.removeSetting(GrassUtils.GRASS_USE_REXTERNAL)
ProcessingConfig.removeSetting(GrassUtils.GRASS_USE_VEXTERNAL)
- def parse_algorithms(self) -> List[QgsProcessingAlgorithm]:
+ def parse_algorithms(self) -> list[QgsProcessingAlgorithm]:
"""
Parses all algorithm sources and returns a list of all GRASS
algorithms.
"""
algs = []
for folder in GrassUtils.grassDescriptionFolders():
- if (folder / 'algorithms.json').exists():
+ if (folder / "algorithms.json").exists():
# fast approach -- use aggregated JSON summary of algorithms
- with open(folder / 'algorithms.json', 'rt', encoding='utf8') as f_in:
+ with open(folder / "algorithms.json", encoding="utf8") as f_in:
algorithm_strings = f_in.read()
algorithms_json = json.loads(algorithm_strings)
for algorithm_json in algorithms_json:
try:
alg = GrassAlgorithm(
- json_definition=algorithm_json,
- description_folder=folder)
- if alg.name().strip() != '':
+ json_definition=algorithm_json, description_folder=folder
+ )
+ if alg.name().strip() != "":
algs.append(alg)
else:
- QgsMessageLog.logMessage(self.tr('Could not open GRASS GIS algorithm: {0}').format(algorithm_json.get('name')), self.tr('Processing'), Qgis.MessageLevel.Critical)
+ QgsMessageLog.logMessage(
+ self.tr(
+ "Could not open GRASS GIS algorithm: {0}"
+ ).format(algorithm_json.get("name")),
+ self.tr("Processing"),
+ Qgis.MessageLevel.Critical,
+ )
except Exception as e:
QgsMessageLog.logMessage(
- self.tr('Could not open GRASS GIS algorithm: {0}\n{1}').format(algorithm_json.get('name'), e), self.tr('Processing'), Qgis.MessageLevel.Critical)
+ self.tr(
+ "Could not open GRASS GIS algorithm: {0}\n{1}"
+ ).format(algorithm_json.get("name"), e),
+ self.tr("Processing"),
+ Qgis.MessageLevel.Critical,
+ )
else:
# slow approach - pass txt files one by one
- for descriptionFile in folder.glob('*.txt'):
+ for descriptionFile in folder.glob("*.txt"):
try:
- alg = GrassAlgorithm(
- description_file=descriptionFile)
- if alg.name().strip() != '':
+ alg = GrassAlgorithm(description_file=descriptionFile)
+ if alg.name().strip() != "":
algs.append(alg)
else:
- QgsMessageLog.logMessage(self.tr('Could not open GRASS GIS algorithm: {0}').format(descriptionFile), self.tr('Processing'), Qgis.MessageLevel.Critical)
+ QgsMessageLog.logMessage(
+ self.tr(
+ "Could not open GRASS GIS algorithm: {0}"
+ ).format(descriptionFile),
+ self.tr("Processing"),
+ Qgis.MessageLevel.Critical,
+ )
except Exception as e:
QgsMessageLog.logMessage(
- self.tr('Could not open GRASS GIS algorithm: {0}\n{1}').format(descriptionFile, e), self.tr('Processing'), Qgis.MessageLevel.Critical)
+ self.tr(
+ "Could not open GRASS GIS algorithm: {0}\n{1}"
+ ).format(descriptionFile, e),
+ self.tr("Processing"),
+ Qgis.MessageLevel.Critical,
+ )
return algs
def loadAlgorithms(self):
version = GrassUtils.installedVersion(True)
if version is None:
- QgsMessageLog.logMessage(self.tr('Problem with GRASS installation: GRASS was not found or is not correctly installed'),
- self.tr('Processing'), Qgis.MessageLevel.Critical)
+ QgsMessageLog.logMessage(
+ self.tr(
+ "Problem with GRASS installation: GRASS was not found or is not correctly installed"
+ ),
+ self.tr("Processing"),
+ Qgis.MessageLevel.Critical,
+ )
return
for a in self.parse_algorithms():
self.addAlgorithm(a)
def name(self):
- return 'GRASS'
+ return "GRASS"
def longName(self):
version = GrassUtils.installedVersion()
- return 'GRASS GIS ({})'.format(version) if version is not None else "GRASS GIS"
+ return f"GRASS GIS ({version})" if version is not None else "GRASS GIS"
def id(self):
- return 'grass'
+ return "grass"
def helpId(self):
- return 'grass7'
+ return "grass7"
def icon(self):
return QgsApplication.getThemeIcon("/providerGrass.svg")
@@ -172,7 +222,7 @@ def supportedOutputRasterLayerExtensions(self):
def canBeActivated(self):
return not bool(GrassUtils.checkGrassIsInstalled())
- def tr(self, string, context=''):
- if context == '':
- context = 'Grass7AlgorithmProvider'
+ def tr(self, string, context=""):
+ if context == "":
+ context = "Grass7AlgorithmProvider"
return QCoreApplication.translate(context, string)
diff --git a/python/plugins/grassprovider/grass_utils.py b/python/plugins/grassprovider/grass_utils.py
index 37c784c09d7d..0818efed030d 100644
--- a/python/plugins/grassprovider/grass_utils.py
+++ b/python/plugins/grassprovider/grass_utils.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'February 2015'
-__copyright__ = '(C) 2014-2015, Victor Olaya'
+__author__ = "Victor Olaya"
+__date__ = "February 2015"
+__copyright__ = "(C) 2014-2015, Victor Olaya"
import os
import re
@@ -25,16 +25,9 @@
import stat
import subprocess
import sys
-from dataclasses import (
- dataclass,
- field
-)
+from dataclasses import dataclass, field
from pathlib import Path
-from typing import (
- Optional,
- List,
- Dict
-)
+from typing import Optional, List, Dict
from qgis.PyQt.QtCore import QCoreApplication
from qgis.core import (
@@ -52,22 +45,22 @@
class GrassUtils:
- GRASS_REGION_XMIN = 'GRASS7_REGION_XMIN'
- GRASS_REGION_YMIN = 'GRASS7_REGION_YMIN'
- GRASS_REGION_XMAX = 'GRASS7_REGION_XMAX'
- GRASS_REGION_YMAX = 'GRASS7_REGION_YMAX'
- GRASS_REGION_CELLSIZE = 'GRASS7_REGION_CELLSIZE'
- GRASS_LOG_COMMANDS = 'GRASS7_LOG_COMMANDS'
- GRASS_LOG_CONSOLE = 'GRASS7_LOG_CONSOLE'
- GRASS_HELP_URL = 'GRASS_HELP_URL'
- GRASS_USE_REXTERNAL = 'GRASS_USE_REXTERNAL'
- GRASS_USE_VEXTERNAL = 'GRASS_USE_VEXTERNAL'
+ GRASS_REGION_XMIN = "GRASS7_REGION_XMIN"
+ GRASS_REGION_YMIN = "GRASS7_REGION_YMIN"
+ GRASS_REGION_XMAX = "GRASS7_REGION_XMAX"
+ GRASS_REGION_YMAX = "GRASS7_REGION_YMAX"
+ GRASS_REGION_CELLSIZE = "GRASS7_REGION_CELLSIZE"
+ GRASS_LOG_COMMANDS = "GRASS7_LOG_COMMANDS"
+ GRASS_LOG_CONSOLE = "GRASS7_LOG_CONSOLE"
+ GRASS_HELP_URL = "GRASS_HELP_URL"
+ GRASS_USE_REXTERNAL = "GRASS_USE_REXTERNAL"
+ GRASS_USE_VEXTERNAL = "GRASS_USE_VEXTERNAL"
# TODO Review all default options formats
GRASS_RASTER_FORMATS_CREATEOPTS = {
- 'GTiff': 'TFW=YES,COMPRESS=LZW',
- 'PNG': 'ZLEVEL=9',
- 'WEBP': 'QUALITY=85'
+ "GTiff": "TFW=YES,COMPRESS=LZW",
+ "PNG": "ZLEVEL=9",
+ "WEBP": "QUALITY=85",
}
sessionRunning = False
@@ -89,9 +82,9 @@ def grassBatchJobFilename():
"""
gisdbase = GrassUtils.grassDataFolder()
if isWindows():
- batchFile = os.path.join(gisdbase, 'grass_batch_job.cmd')
+ batchFile = os.path.join(gisdbase, "grass_batch_job.cmd")
else:
- batchFile = os.path.join(gisdbase, 'grass_batch_job.sh')
+ batchFile = os.path.join(gisdbase, "grass_batch_job.sh")
return batchFile
@staticmethod
@@ -101,8 +94,8 @@ def exportCrsWktToFile(crs, context: QgsProcessingContext):
to this file
"""
wkt = crs.toWkt(QgsCoordinateReferenceSystem.WktVariant.WKT_PREFERRED)
- wkt_file = QgsProcessingUtils.generateTempFilename('crs.prj', context)
- with open(wkt_file, 'w', encoding='utf-8') as f:
+ wkt_file = QgsProcessingUtils.generateTempFilename("crs.prj", context)
+ with open(wkt_file, "w", encoding="utf-8") as f:
f.write(wkt)
return wkt_file
@@ -125,13 +118,13 @@ def installedVersion(run=False):
si.dwFlags |= subprocess.STARTF_USESHOWWINDOW
si.wShowWindow = subprocess.SW_HIDE
with subprocess.Popen(
- [GrassUtils.command, '-v'],
+ [GrassUtils.command, "-v"],
shell=False,
stdout=subprocess.PIPE,
stdin=subprocess.DEVNULL,
stderr=subprocess.STDOUT,
universal_newlines=True,
- startupinfo=si if isWindows() else None
+ startupinfo=si if isWindows() else None,
) as proc:
try:
lines = proc.stdout.readlines()
@@ -174,31 +167,39 @@ def searchFolder(folder):
vn = os.path.join(path, "etc", "VERSIONNUMBER")
if os.path.isfile(vn):
with open(vn) as f:
- major, minor, patch = f.readlines()[0].split(' ')[0].split('.')
- if patch != 'svn':
- patch = ''
+ major, minor, patch = f.readlines()[0].split(" ")[0].split(".")
+ if patch != "svn":
+ patch = ""
cmdList = [
- "grass{}{}{}".format(major, minor, patch),
+ f"grass{major}{minor}{patch}",
"grass",
- "grass{}{}{}.{}".format(major, minor, patch,
- "bat" if isWindows() else "sh"),
- "grass.{}".format("bat" if isWindows() else "sh")
+ "grass{}{}{}.{}".format(
+ major, minor, patch, "bat" if isWindows() else "sh"
+ ),
+ "grass.{}".format("bat" if isWindows() else "sh"),
]
else:
- cmdList = ["grass80", "grass78", "grass76", "grass74", "grass72",
- "grass70", "grass"]
+ cmdList = [
+ "grass80",
+ "grass78",
+ "grass76",
+ "grass74",
+ "grass72",
+ "grass70",
+ "grass",
+ ]
cmdList.extend(
- ["{}.{}".format(b, "bat" if isWindows() else "sh") for b in
- cmdList])
+ ["{}.{}".format(b, "bat" if isWindows() else "sh") for b in cmdList]
+ )
# For MS-Windows there is a difference between GRASS Path and GRASS binary
if isWindows():
# If nothing found, use OSGEO4W or QgsPrefix:
if "OSGEO4W_ROOT" in os.environ:
- testFolder = str(os.environ['OSGEO4W_ROOT'])
+ testFolder = str(os.environ["OSGEO4W_ROOT"])
else:
testFolder = str(QgsApplication.prefixPath())
- testFolder = os.path.join(testFolder, 'bin')
+ testFolder = os.path.join(testFolder, "bin")
command = searchFolder(testFolder)
elif isMac():
# Search in grassPath
@@ -214,7 +215,7 @@ def searchFolder(folder):
if command:
GrassUtils.command = command
- if path == '':
+ if path == "":
GrassUtils.path = os.path.dirname(command)
return command
@@ -229,7 +230,7 @@ def grassPath():
return GrassUtils.path
if not isWindows() and not isMac():
- return ''
+ return ""
folder = None
# Under MS-Windows, we use GISBASE or QGIS Path for folder
@@ -238,16 +239,21 @@ def grassPath():
folder = os.environ["GISBASE"]
else:
testfolder = os.path.join(
- os.path.dirname(QgsApplication.prefixPath()), 'grass')
+ os.path.dirname(QgsApplication.prefixPath()), "grass"
+ )
if os.path.isdir(testfolder):
- grassfolders = sorted([f for f in os.listdir(testfolder) if
- f.startswith(
- "grass-7.") and os.path.isdir(
- os.path.join(testfolder, f))],
- reverse=True,
- key=lambda x: [int(v) for v in x[
- len("grass-"):].split(
- '.') if v != 'svn'])
+ grassfolders = sorted(
+ [
+ f
+ for f in os.listdir(testfolder)
+ if f.startswith("grass-7.")
+ and os.path.isdir(os.path.join(testfolder, f))
+ ],
+ reverse=True,
+ key=lambda x: [
+ int(v) for v in x[len("grass-") :].split(".") if v != "svn"
+ ],
+ )
if grassfolders:
folder = os.path.join(testfolder, grassfolders[0])
elif isMac():
@@ -256,18 +262,21 @@ def grassPath():
folder = os.environ["GISBASE"]
else:
# Find grass folder if it exists inside QGIS bundle
- for version in ['', '8', '7', '80', '78', '76', '74', '72',
- '71', '70']:
- testfolder = os.path.join(str(QgsApplication.prefixPath()),
- 'grass{}'.format(version))
+ for version in ["", "8", "7", "80", "78", "76", "74", "72", "71", "70"]:
+ testfolder = os.path.join(
+ str(QgsApplication.prefixPath()), f"grass{version}"
+ )
if os.path.isdir(testfolder):
folder = testfolder
break
# If nothing found, try standalone GRASS installation
if folder is None:
- for version in ['8', '6', '4', '2', '1', '0']:
- testfolder = '/Applications/GRASS-7.{}.app/Contents/MacOS'.format(
- version)
+ for version in ["8", "6", "4", "2", "1", "0"]:
+ testfolder = (
+ "/Applications/GRASS-7.{}.app/Contents/MacOS".format(
+ version
+ )
+ )
if os.path.isdir(testfolder):
folder = testfolder
break
@@ -275,7 +284,7 @@ def grassPath():
if folder is not None:
GrassUtils.path = folder
- return folder or ''
+ return folder or ""
@staticmethod
def userDescriptionFolder():
@@ -283,7 +292,7 @@ def userDescriptionFolder():
Creates and returns a directory for users to create additional algorithm descriptions.
Or modified versions of stock algorithm descriptions shipped with QGIS.
"""
- folder = Path(userFolder(), 'grassaddons', 'description')
+ folder = Path(userFolder(), "grassaddons", "description")
folder.mkdir(parents=True, exist_ok=True)
return folder
@@ -294,8 +303,10 @@ def grassDescriptionFolders():
Note that the provider will load from these in sequence, so we put the userDescriptionFolder first
to allow users to create modified versions of stock algorithms shipped with QGIS.
"""
- return [GrassUtils.userDescriptionFolder(),
- Path(__file__).parent.joinpath('description')]
+ return [
+ GrassUtils.userDescriptionFolder(),
+ Path(__file__).parent.joinpath("description"),
+ ]
@staticmethod
def getWindowsCodePage():
@@ -304,26 +315,26 @@ def getWindowsCodePage():
Used into GRASS exec script under MS-Windows.
"""
from ctypes import cdll
+
return str(cdll.kernel32.GetACP())
@staticmethod
def createGrassBatchJobFileFromGrassCommands(commands):
- with open(GrassUtils.grassBatchJobFilename(), 'w') as fout:
+ with open(GrassUtils.grassBatchJobFilename(), "w") as fout:
if not isWindows():
- fout.write('#!/bin/sh\n')
+ fout.write("#!/bin/sh\n")
else:
- fout.write(
- 'chcp {}>NUL\n'.format(GrassUtils.getWindowsCodePage()))
+ fout.write(f"chcp {GrassUtils.getWindowsCodePage()}>NUL\n")
for command in commands:
GrassUtils.writeCommand(fout, command)
- fout.write('exit')
+ fout.write("exit")
@staticmethod
def grassMapsetFolder():
"""
Creates and returns the GRASS temporary DB LOCATION directory.
"""
- folder = os.path.join(GrassUtils.grassDataFolder(), 'temp_location')
+ folder = os.path.join(GrassUtils.grassDataFolder(), "temp_location")
mkdir(folder)
return folder
@@ -333,7 +344,8 @@ def grassDataFolder():
Creates and returns the GRASS temporary DB directory.
"""
tempfolder = os.path.normpath(
- os.path.join(QgsProcessingUtils.tempFolder(), 'grassdata'))
+ os.path.join(QgsProcessingUtils.tempFolder(), "grassdata")
+ )
mkdir(tempfolder)
return tempfolder
@@ -348,45 +360,46 @@ def createTempMapset():
input image or vector
"""
folder = GrassUtils.grassMapsetFolder()
- mkdir(os.path.join(folder, 'PERMANENT'))
- mkdir(os.path.join(folder, 'PERMANENT', '.tmp'))
- GrassUtils.writeGrassWindow(
- os.path.join(folder, 'PERMANENT', 'DEFAULT_WIND'))
- with open(os.path.join(folder, 'PERMANENT', 'MYNAME'), 'w') as outfile:
+ mkdir(os.path.join(folder, "PERMANENT"))
+ mkdir(os.path.join(folder, "PERMANENT", ".tmp"))
+ GrassUtils.writeGrassWindow(os.path.join(folder, "PERMANENT", "DEFAULT_WIND"))
+ with open(os.path.join(folder, "PERMANENT", "MYNAME"), "w") as outfile:
outfile.write(
- 'QGIS GRASS GIS interface: temporary data processing location.\n')
+ "QGIS GRASS GIS interface: temporary data processing location.\n"
+ )
- GrassUtils.writeGrassWindow(os.path.join(folder, 'PERMANENT', 'WIND'))
- mkdir(os.path.join(folder, 'PERMANENT', 'sqlite'))
- with open(os.path.join(folder, 'PERMANENT', 'VAR'), 'w') as outfile:
- outfile.write('DB_DRIVER: sqlite\n')
+ GrassUtils.writeGrassWindow(os.path.join(folder, "PERMANENT", "WIND"))
+ mkdir(os.path.join(folder, "PERMANENT", "sqlite"))
+ with open(os.path.join(folder, "PERMANENT", "VAR"), "w") as outfile:
+ outfile.write("DB_DRIVER: sqlite\n")
outfile.write(
- 'DB_DATABASE: $GISDBASE/$LOCATION_NAME/$MAPSET/sqlite/sqlite.db\n')
+ "DB_DATABASE: $GISDBASE/$LOCATION_NAME/$MAPSET/sqlite/sqlite.db\n"
+ )
@staticmethod
def writeGrassWindow(filename):
"""
Creates the GRASS Window file
"""
- with open(filename, 'w') as out:
- out.write('proj: 0\n')
- out.write('zone: 0\n')
- out.write('north: 1\n')
- out.write('south: 0\n')
- out.write('east: 1\n')
- out.write('west: 0\n')
- out.write('cols: 1\n')
- out.write('rows: 1\n')
- out.write('e-w resol: 1\n')
- out.write('n-s resol: 1\n')
- out.write('top: 1\n')
- out.write('bottom: 0\n')
- out.write('cols3: 1\n')
- out.write('rows3: 1\n')
- out.write('depths: 1\n')
- out.write('e-w resol3: 1\n')
- out.write('n-s resol3: 1\n')
- out.write('t-b resol: 1\n')
+ with open(filename, "w") as out:
+ out.write("proj: 0\n")
+ out.write("zone: 0\n")
+ out.write("north: 1\n")
+ out.write("south: 0\n")
+ out.write("east: 1\n")
+ out.write("west: 0\n")
+ out.write("cols: 1\n")
+ out.write("rows: 1\n")
+ out.write("e-w resol: 1\n")
+ out.write("n-s resol: 1\n")
+ out.write("top: 1\n")
+ out.write("bottom: 0\n")
+ out.write("cols3: 1\n")
+ out.write("rows3: 1\n")
+ out.write("depths: 1\n")
+ out.write("e-w resol3: 1\n")
+ out.write("n-s resol3: 1\n")
+ out.write("t-b resol: 1\n")
@staticmethod
def prepareGrassExecution(commands):
@@ -398,21 +411,26 @@ def prepareGrassExecution(commands):
GrassUtils.grassBin()
env = os.environ.copy()
- env['GRASS_MESSAGE_FORMAT'] = 'plain'
- if 'GISBASE' in env:
- del env['GISBASE']
+ env["GRASS_MESSAGE_FORMAT"] = "plain"
+ if "GISBASE" in env:
+ del env["GISBASE"]
GrassUtils.createGrassBatchJobFileFromGrassCommands(commands)
- os.chmod(GrassUtils.grassBatchJobFilename(),
- stat.S_IEXEC | stat.S_IREAD | stat.S_IWRITE)
- command = [GrassUtils.command,
- os.path.join(GrassUtils.grassMapsetFolder(), 'PERMANENT'),
- '--exec', GrassUtils.grassBatchJobFilename()]
+ os.chmod(
+ GrassUtils.grassBatchJobFilename(),
+ stat.S_IEXEC | stat.S_IREAD | stat.S_IWRITE,
+ )
+ command = [
+ GrassUtils.command,
+ os.path.join(GrassUtils.grassMapsetFolder(), "PERMANENT"),
+ "--exec",
+ GrassUtils.grassBatchJobFilename(),
+ ]
return command, env
@staticmethod
def executeGrass(commands, feedback, outputCommands=None):
- loglines = [GrassUtils.tr('GRASS GIS execution console output')]
+ loglines = [GrassUtils.tr("GRASS GIS execution console output")]
grassOutDone = False
command, grassenv = GrassUtils.prepareGrassExecution(commands)
# QgsMessageLog.logMessage('exec: {}'.format(command), 'DEBUG', Qgis.Info)
@@ -423,10 +441,8 @@ def executeGrass(commands, feedback, outputCommands=None):
si = subprocess.STARTUPINFO()
si.dwFlags |= subprocess.STARTF_USESHOWWINDOW
si.wShowWindow = subprocess.SW_HIDE
- kw['startupinfo'] = si
- if sys.version_info >= (3, 6):
- kw['encoding'] = "cp{}".format(
- GrassUtils.getWindowsCodePage())
+ kw["startupinfo"] = si
+ kw["encoding"] = f"cp{GrassUtils.getWindowsCodePage()}"
def readline_with_recover(stdout):
"""A method wrapping stdout.readline() with try-except recovering.
@@ -440,7 +456,7 @@ def readline_with_recover(stdout):
try:
return stdout.readline()
except UnicodeDecodeError:
- return '' # replaced-text
+ return "" # replaced-text
with subprocess.Popen(
command,
@@ -450,35 +466,45 @@ def readline_with_recover(stdout):
stderr=subprocess.STDOUT,
universal_newlines=True,
env=grassenv,
- **kw
+ **kw,
) as proc:
- for line in iter(lambda: readline_with_recover(proc.stdout), ''):
- if 'GRASS_INFO_PERCENT' in line:
+ for line in iter(lambda: readline_with_recover(proc.stdout), ""):
+ if "GRASS_INFO_PERCENT" in line:
try:
- feedback.setProgress(
- int(line[len('GRASS_INFO_PERCENT') + 2:]))
+ feedback.setProgress(int(line[len("GRASS_INFO_PERCENT") + 2 :]))
except Exception:
pass
else:
- if 'r.out' in line or 'v.out' in line:
+ if "r.out" in line or "v.out" in line:
grassOutDone = True
loglines.append(line)
- if any([l in line for l in ['WARNING', GrassUtils.tr('WARNING')]]):
+ if any([l in line for l in ["WARNING", GrassUtils.tr("WARNING")]]):
feedback.pushWarning(line.strip())
- elif any([l in line for l in ['ERROR', GrassUtils.tr('ERROR')]]):
+ elif any([l in line for l in ["ERROR", GrassUtils.tr("ERROR")]]):
feedback.reportError(line.strip())
- elif 'Segmentation fault' in line:
+ elif "Segmentation fault" in line:
feedback.reportError(line.strip())
- feedback.reportError('\n' + GrassUtils.tr(
- 'GRASS command crashed :( Try a different set of input parameters and consult the GRASS algorithm manual for more information.') + '\n')
- if ProcessingConfig.getSetting(
- GrassUtils.GRASS_USE_REXTERNAL):
- feedback.reportError(GrassUtils.tr(
- 'Suggest disabling the experimental "use r.external" option from the Processing GRASS Provider options.') + '\n')
- if ProcessingConfig.getSetting(
- GrassUtils.GRASS_USE_VEXTERNAL):
- feedback.reportError(GrassUtils.tr(
- 'Suggest disabling the experimental "use v.external" option from the Processing GRASS Provider options.') + '\n')
+ feedback.reportError(
+ "\n"
+ + GrassUtils.tr(
+ "GRASS command crashed :( Try a different set of input parameters and consult the GRASS algorithm manual for more information."
+ )
+ + "\n"
+ )
+ if ProcessingConfig.getSetting(GrassUtils.GRASS_USE_REXTERNAL):
+ feedback.reportError(
+ GrassUtils.tr(
+ 'Suggest disabling the experimental "use r.external" option from the Processing GRASS Provider options.'
+ )
+ + "\n"
+ )
+ if ProcessingConfig.getSetting(GrassUtils.GRASS_USE_VEXTERNAL):
+ feedback.reportError(
+ GrassUtils.tr(
+ 'Suggest disabling the experimental "use v.external" option from the Processing GRASS Provider options.'
+ )
+ + "\n"
+ )
elif line.strip():
feedback.pushConsoleInfo(line.strip())
@@ -488,18 +514,15 @@ def readline_with_recover(stdout):
# are usually the output ones. If that is the case runs the output
# commands again.
if not grassOutDone and outputCommands:
- command, grassenv = GrassUtils.prepareGrassExecution(
- outputCommands)
+ command, grassenv = GrassUtils.prepareGrassExecution(outputCommands)
# For MS-Windows, we need to hide the console window.
kw = {}
if isWindows():
si = subprocess.STARTUPINFO()
si.dwFlags |= subprocess.STARTF_USESHOWWINDOW
si.wShowWindow = subprocess.SW_HIDE
- kw['startupinfo'] = si
- if sys.version_info >= (3, 6):
- kw['encoding'] = "cp{}".format(
- GrassUtils.getWindowsCodePage())
+ kw["startupinfo"] = si
+ kw["encoding"] = f"cp{GrassUtils.getWindowsCodePage()}"
with subprocess.Popen(
command,
shell=False,
@@ -508,17 +531,17 @@ def readline_with_recover(stdout):
stderr=subprocess.STDOUT,
universal_newlines=True,
env=grassenv,
- **kw
+ **kw,
) as proc:
- for line in iter(lambda: readline_with_recover(proc.stdout),
- ''):
- if 'GRASS_INFO_PERCENT' in line:
+ for line in iter(lambda: readline_with_recover(proc.stdout), ""):
+ if "GRASS_INFO_PERCENT" in line:
try:
- feedback.setProgress(int(
- line[len('GRASS_INFO_PERCENT') + 2:]))
+ feedback.setProgress(
+ int(line[len("GRASS_INFO_PERCENT") + 2 :])
+ )
except Exception:
pass
- if any(l in line for l in ['WARNING', 'ERROR']):
+ if any(l in line for l in ["WARNING", "ERROR"]):
loglines.append(line.strip())
feedback.reportError(line.strip())
elif line.strip():
@@ -526,8 +549,9 @@ def readline_with_recover(stdout):
feedback.pushConsoleInfo(line.strip())
if ProcessingConfig.getSetting(GrassUtils.GRASS_LOG_CONSOLE):
- QgsMessageLog.logMessage('\n'.join(loglines), 'Processing',
- Qgis.MessageLevel.Info)
+ QgsMessageLog.logMessage(
+ "\n".join(loglines), "Processing", Qgis.MessageLevel.Info
+ )
# GRASS session is used to hold the layers already exported or
# produced in GRASS between multiple calls to GRASS algorithms.
@@ -557,8 +581,8 @@ def getSessionLayers():
@staticmethod
def addSessionLayers(exportedLayers):
GrassUtils.sessionLayers = dict(
- list(GrassUtils.sessionLayers.items()) +
- list(exportedLayers.items()))
+ list(GrassUtils.sessionLayers.items()) + list(exportedLayers.items())
+ )
@staticmethod
def checkGrassIsInstalled(ignorePreviousState=False):
@@ -570,14 +594,15 @@ def checkGrassIsInstalled(ignorePreviousState=False):
if GrassUtils.installedVersion() is not None:
# For Ms-Windows, we check GRASS binaries
if isWindows():
- cmdpath = os.path.join(GrassUtils.path, 'bin',
- 'r.out.gdal.exe')
+ cmdpath = os.path.join(GrassUtils.path, "bin", "r.out.gdal.exe")
if not os.path.exists(cmdpath):
return GrassUtils.tr(
'The GRASS GIS folder "{}" does not contain a valid set '
- 'of GRASS modules.\nPlease, check that GRASS is correctly '
- 'installed and available on your system.'.format(
- os.path.join(GrassUtils.path, 'bin')))
+ "of GRASS modules.\nPlease, check that GRASS is correctly "
+ "installed and available on your system.".format(
+ os.path.join(GrassUtils.path, "bin")
+ )
+ )
GrassUtils.isGrassInstalled = True
return
# Return error messages
@@ -586,35 +611,39 @@ def checkGrassIsInstalled(ignorePreviousState=False):
if isWindows() or isMac():
if GrassUtils.path is None:
return GrassUtils.tr(
- 'Could not locate GRASS GIS folder. Please make '
- 'sure that GRASS GIS is correctly installed before '
- 'running GRASS algorithms.')
+ "Could not locate GRASS GIS folder. Please make "
+ "sure that GRASS GIS is correctly installed before "
+ "running GRASS algorithms."
+ )
if GrassUtils.command is None:
return GrassUtils.tr(
- 'GRASS GIS binary {} can\'t be found on this system from a shell. '
- 'Please install it or configure your PATH {} environment variable.'.format(
- '(grass.bat)' if isWindows() else '(grass.sh)',
- 'or OSGEO4W_ROOT' if isWindows() else ''))
+ "GRASS GIS binary {} can't be found on this system from a shell. "
+ "Please install it or configure your PATH {} environment variable.".format(
+ "(grass.bat)" if isWindows() else "(grass.sh)",
+ "or OSGEO4W_ROOT" if isWindows() else "",
+ )
+ )
# GNU/Linux
else:
return GrassUtils.tr(
- 'GRASS can\'t be found on this system from a shell. '
- 'Please install it or configure your PATH environment variable.')
+ "GRASS can't be found on this system from a shell. "
+ "Please install it or configure your PATH environment variable."
+ )
@staticmethod
- def tr(string, context=''):
- if context == '':
- context = 'Grass7Utils'
+ def tr(string, context=""):
+ if context == "":
+ context = "Grass7Utils"
return QCoreApplication.translate(context, string)
@staticmethod
def writeCommand(output, command):
try:
# Python 2
- output.write(command.encode('utf8') + '\n')
+ output.write(command.encode("utf8") + "\n")
except TypeError:
# Python 3
- output.write(command + '\n')
+ output.write(command + "\n")
@staticmethod
def grassHelpPath():
@@ -623,13 +652,15 @@ def grassHelpPath():
if not helpPath:
if isWindows() or isMac():
if GrassUtils.path is not None:
- localPath = os.path.join(GrassUtils.path, 'docs/html')
+ localPath = os.path.join(GrassUtils.path, "docs/html")
if os.path.exists(localPath):
helpPath = os.path.abspath(localPath)
else:
- searchPaths = ['/usr/share/doc/grass-doc/html',
- '/opt/grass/docs/html',
- '/usr/share/doc/grass/docs/html']
+ searchPaths = [
+ "/usr/share/doc/grass-doc/html",
+ "/opt/grass/docs/html",
+ "/usr/share/doc/grass/docs/html",
+ ]
for path in searchPaths:
if os.path.exists(path):
helpPath = os.path.abspath(path)
@@ -638,11 +669,11 @@ def grassHelpPath():
if helpPath:
return helpPath
elif GrassUtils.version:
- version = GrassUtils.version.replace('.', '')[:2]
- return 'https://grass.osgeo.org/grass{}/manuals/'.format(version)
+ version = GrassUtils.version.replace(".", "")[:2]
+ return f"https://grass.osgeo.org/grass{version}/manuals/"
else:
# GRASS not available!
- return 'https://grass.osgeo.org/grass-stable/manuals/'
+ return "https://grass.osgeo.org/grass-stable/manuals/"
@staticmethod
def getSupportedOutputRasterExtensions():
@@ -660,11 +691,11 @@ def getRasterFormatFromFilename(filename):
:return: The Gdal short format name for extension.
"""
ext = os.path.splitext(filename)[1].lower()
- ext = ext.lstrip('.')
+ ext = ext.lstrip(".")
if ext:
supported = GdalUtils.getSupportedRasters()
for name in list(supported.keys()):
exts = supported[name]
if ext in exts:
return name
- return 'GTiff'
+ return "GTiff"
diff --git a/python/plugins/grassprovider/parsed_description.py b/python/plugins/grassprovider/parsed_description.py
index 0b031936317e..675860eb0178 100644
--- a/python/plugins/grassprovider/parsed_description.py
+++ b/python/plugins/grassprovider/parsed_description.py
@@ -10,16 +10,9 @@
"""
import re
-from dataclasses import (
- dataclass,
- field
-)
+from dataclasses import dataclass, field
from pathlib import Path
-from typing import (
- Optional,
- List,
- Dict
-)
+from typing import Optional, List, Dict
@dataclass
@@ -28,7 +21,7 @@ class ParsedDescription:
Results of parsing a description file
"""
- GROUP_ID_REGEX = re.compile(r'^[^\s(]+')
+ GROUP_ID_REGEX = re.compile(r"^[^\s(]+")
grass_command: Optional[str] = None
short_description: Optional[str] = None
@@ -39,28 +32,28 @@ class ParsedDescription:
ext_path: Optional[str] = None
- hardcoded_strings: List[str] = field(default_factory=list)
- param_strings: List[str] = field(default_factory=list)
+ hardcoded_strings: list[str] = field(default_factory=list)
+ param_strings: list[str] = field(default_factory=list)
- def as_dict(self) -> Dict:
+ def as_dict(self) -> dict:
"""
Returns a JSON serializable dictionary representing the parsed
description
"""
return {
- 'name': self.name,
- 'display_name': self.display_name,
- 'command': self.grass_command,
- 'short_description': self.short_description,
- 'group': self.group,
- 'group_id': self.group_id,
- 'ext_path': self.ext_path,
- 'hardcoded_strings': self.hardcoded_strings,
- 'parameters': self.param_strings
+ "name": self.name,
+ "display_name": self.display_name,
+ "command": self.grass_command,
+ "short_description": self.short_description,
+ "group": self.group,
+ "group_id": self.group_id,
+ "ext_path": self.ext_path,
+ "hardcoded_strings": self.hardcoded_strings,
+ "parameters": self.param_strings,
}
@staticmethod
- def from_dict(description: Dict) -> 'ParsedDescription':
+ def from_dict(description: dict) -> "ParsedDescription":
"""
Parses a dictionary as a description and returns the result
"""
@@ -68,26 +61,26 @@ def from_dict(description: Dict) -> 'ParsedDescription':
from qgis.PyQt.QtCore import QCoreApplication
result = ParsedDescription()
- result.name = description.get('name')
- result.display_name = description.get('display_name')
- result.grass_command = description.get('command')
+ result.name = description.get("name")
+ result.display_name = description.get("display_name")
+ result.grass_command = description.get("command")
result.short_description = QCoreApplication.translate(
- "GrassAlgorithm",
- description.get('short_description')
+ "GrassAlgorithm", description.get("short_description")
)
- result.group = QCoreApplication.translate("GrassAlgorithm",
- description.get('group'))
- result.group_id = description.get('group_id')
- result.ext_path = description.get('ext_path')
- result.hardcoded_strings = description.get('hardcoded_strings', [])
- result.param_strings = description.get('parameters', [])
+ result.group = QCoreApplication.translate(
+ "GrassAlgorithm", description.get("group")
+ )
+ result.group_id = description.get("group_id")
+ result.ext_path = description.get("ext_path")
+ result.hardcoded_strings = description.get("hardcoded_strings", [])
+ result.param_strings = description.get("parameters", [])
return result
@staticmethod
def parse_description_file(
- description_file: Path,
- translate: bool = True) -> 'ParsedDescription':
+ description_file: Path, translate: bool = True
+ ) -> "ParsedDescription":
"""
Parses a description file and returns the result
"""
@@ -96,42 +89,44 @@ def parse_description_file(
with description_file.open() as lines:
# First line of the file is the Grass algorithm name
- line = lines.readline().strip('\n').strip()
+ line = lines.readline().strip("\n").strip()
result.grass_command = line
# Second line if the algorithm name in Processing
- line = lines.readline().strip('\n').strip()
+ line = lines.readline().strip("\n").strip()
result.short_description = line
if " - " not in line:
result.name = result.grass_command
else:
- result.name = line[:line.find(' ')].lower()
+ result.name = line[: line.find(" ")].lower()
if translate:
from qgis.PyQt.QtCore import QCoreApplication
+
result.short_description = QCoreApplication.translate(
- "GrassAlgorithm", line)
+ "GrassAlgorithm", line
+ )
else:
result.short_description = line
result.display_name = result.name
# Read the grass group
- line = lines.readline().strip('\n').strip()
+ line = lines.readline().strip("\n").strip()
if translate:
from qgis.PyQt.QtCore import QCoreApplication
- result.group = QCoreApplication.translate("GrassAlgorithm",
- line)
+
+ result.group = QCoreApplication.translate("GrassAlgorithm", line)
else:
result.group = line
- result.group_id = ParsedDescription.GROUP_ID_REGEX.search(
- line).group(0).lower()
+ result.group_id = (
+ ParsedDescription.GROUP_ID_REGEX.search(line).group(0).lower()
+ )
# Then you have parameters/output definition
- line = lines.readline().strip('\n').strip()
- while line != '':
- line = line.strip('\n').strip()
- if line.startswith('Hardcoded'):
- result.hardcoded_strings.append(
- line[len('Hardcoded|'):])
+ line = lines.readline().strip("\n").strip()
+ while line != "":
+ line = line.strip("\n").strip()
+ if line.startswith("Hardcoded"):
+ result.hardcoded_strings.append(line[len("Hardcoded|") :])
result.param_strings.append(line)
- line = lines.readline().strip('\n').strip()
+ line = lines.readline().strip("\n").strip()
return result
diff --git a/python/plugins/grassprovider/tests/AlgorithmsTestBase.py b/python/plugins/grassprovider/tests/AlgorithmsTestBase.py
index 9076368fedf2..353b44384623 100644
--- a/python/plugins/grassprovider/tests/AlgorithmsTestBase.py
+++ b/python/plugins/grassprovider/tests/AlgorithmsTestBase.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Matthias Kuhn'
-__date__ = 'January 2016'
-__copyright__ = '(C) 2016, Matthias Kuhn'
+__author__ = "Matthias Kuhn"
+__date__ = "January 2016"
+__copyright__ = "(C) 2016, Matthias Kuhn"
import os
@@ -34,20 +34,20 @@
from numpy import nan_to_num
from copy import deepcopy
-from qgis.core import (QgsVectorLayer,
- QgsRasterLayer,
- QgsCoordinateReferenceSystem,
- QgsFeatureRequest,
- QgsMapLayer,
- QgsProject,
- QgsApplication,
- QgsProcessingContext,
- QgsProcessingUtils,
- QgsProcessingFeedback)
-from qgis.analysis import (QgsNativeAlgorithms)
-from qgis.testing import (_UnexpectedSuccess,
- QgisTestCase,
- start_app)
+from qgis.core import (
+ QgsVectorLayer,
+ QgsRasterLayer,
+ QgsCoordinateReferenceSystem,
+ QgsFeatureRequest,
+ QgsMapLayer,
+ QgsProject,
+ QgsApplication,
+ QgsProcessingContext,
+ QgsProcessingUtils,
+ QgsProcessingFeedback,
+)
+from qgis.analysis import QgsNativeAlgorithms
+from qgis.testing import _UnexpectedSuccess, QgisTestCase, start_app
from utilities import unitTestDataPath
@@ -57,7 +57,7 @@
def processingTestDataPath():
- return os.path.join(os.path.dirname(__file__), 'testdata')
+ return os.path.join(os.path.dirname(__file__), "testdata")
class AlgorithmsTest:
@@ -66,13 +66,19 @@ def test_algorithms(self):
"""
This is the main test function. All others will be executed based on the definitions in testdata/algorithm_tests.yaml
"""
- with open(os.path.join(processingTestDataPath(), self.definition_file())) as stream:
+ with open(
+ os.path.join(processingTestDataPath(), self.definition_file())
+ ) as stream:
algorithm_tests = yaml.load(stream, Loader=yaml.SafeLoader)
- if 'tests' in algorithm_tests and algorithm_tests['tests'] is not None:
- for idx, algtest in enumerate(algorithm_tests['tests']):
- print('About to start {} of {}: "{}"'.format(idx, len(algorithm_tests['tests']), algtest['name']))
- yield self.check_algorithm, algtest['name'], algtest
+ if "tests" in algorithm_tests and algorithm_tests["tests"] is not None:
+ for idx, algtest in enumerate(algorithm_tests["tests"]):
+ print(
+ 'About to start {} of {}: "{}"'.format(
+ idx, len(algorithm_tests["tests"]), algtest["name"]
+ )
+ )
+ yield self.check_algorithm, algtest["name"], algtest
def check_algorithm(self, name, defs):
"""
@@ -83,25 +89,29 @@ def check_algorithm(self, name, defs):
self.vector_layer_params = {}
QgsProject.instance().clear()
- if 'project' in defs:
- full_project_path = os.path.join(processingTestDataPath(), defs['project'])
+ if "project" in defs:
+ full_project_path = os.path.join(processingTestDataPath(), defs["project"])
project_read_success = QgsProject.instance().read(full_project_path)
- self.assertTrue(project_read_success, 'Failed to load project file: ' + defs['project'])
-
- if 'project_crs' in defs:
- QgsProject.instance().setCrs(QgsCoordinateReferenceSystem(defs['project_crs']))
+ self.assertTrue(
+ project_read_success, "Failed to load project file: " + defs["project"]
+ )
+
+ if "project_crs" in defs:
+ QgsProject.instance().setCrs(
+ QgsCoordinateReferenceSystem(defs["project_crs"])
+ )
else:
QgsProject.instance().setCrs(QgsCoordinateReferenceSystem())
- if 'ellipsoid' in defs:
- QgsProject.instance().setEllipsoid(defs['ellipsoid'])
+ if "ellipsoid" in defs:
+ QgsProject.instance().setEllipsoid(defs["ellipsoid"])
else:
- QgsProject.instance().setEllipsoid('')
+ QgsProject.instance().setEllipsoid("")
- params = self.load_params(defs['params'])
+ params = self.load_params(defs["params"])
- print('Running alg: "{}"'.format(defs['algorithm']))
- alg = QgsApplication.processingRegistry().createAlgorithmById(defs['algorithm'])
+ print('Running alg: "{}"'.format(defs["algorithm"]))
+ alg = QgsApplication.processingRegistry().createAlgorithmById(defs["algorithm"])
parameters = {}
if isinstance(params, list):
@@ -111,45 +121,47 @@ def check_algorithm(self, name, defs):
for k, p in params.items():
parameters[k] = p
- for r, p in list(defs['results'].items()):
- if 'in_place_result' not in p or not p['in_place_result']:
+ for r, p in list(defs["results"].items()):
+ if "in_place_result" not in p or not p["in_place_result"]:
parameters[r] = self.load_result_param(p)
expectFailure = False
- if 'expectedFailure' in defs:
- exec(('\n'.join(defs['expectedFailure'][:-1])), globals(), locals())
- expectFailure = eval(defs['expectedFailure'][-1])
+ if "expectedFailure" in defs:
+ exec(("\n".join(defs["expectedFailure"][:-1])), globals(), locals())
+ expectFailure = eval(defs["expectedFailure"][-1])
- if 'expectedException' in defs:
+ if "expectedException" in defs:
expectFailure = True
# ignore user setting for invalid geometry handling
context = QgsProcessingContext()
context.setProject(QgsProject.instance())
- if 'skipInvalid' in defs and defs['skipInvalid']:
- context.setInvalidGeometryCheck(QgsFeatureRequest.InvalidGeometryCheck.GeometrySkipInvalid)
+ if "skipInvalid" in defs and defs["skipInvalid"]:
+ context.setInvalidGeometryCheck(
+ QgsFeatureRequest.InvalidGeometryCheck.GeometrySkipInvalid
+ )
feedback = QgsProcessingFeedback()
- print('Algorithm parameters are {}'.format(parameters))
+ print(f"Algorithm parameters are {parameters}")
# first check that algorithm accepts the parameters we pass...
ok, msg = alg.checkParameterValues(parameters, context)
- self.assertTrue(ok, 'Algorithm failed checkParameterValues with result {}'.format(msg))
+ self.assertTrue(ok, f"Algorithm failed checkParameterValues with result {msg}")
if expectFailure:
try:
results, ok = alg.run(parameters, context, feedback)
- self.check_results(results, context, parameters, defs['results'])
+ self.check_results(results, context, parameters, defs["results"])
if ok:
raise _UnexpectedSuccess
except Exception:
pass
else:
results, ok = alg.run(parameters, context, feedback)
- self.assertTrue(ok, 'params: {}, results: {}'.format(parameters, results))
- self.check_results(results, context, parameters, defs['results'])
+ self.assertTrue(ok, f"params: {parameters}, results: {results}")
+ self.check_results(results, context, parameters, defs["results"])
def load_params(self, params):
"""
@@ -168,68 +180,75 @@ def load_param(self, param, id=None):
parameter based on its key `type` and return the appropriate parameter to pass to the algorithm.
"""
try:
- if param['type'] in ('vector', 'raster', 'table'):
+ if param["type"] in ("vector", "raster", "table"):
return self.load_layer(id, param).id()
- elif param['type'] == 'vrtlayers':
+ elif param["type"] == "vrtlayers":
vals = []
- for p in param['params']:
- p['layer'] = self.load_layer(None, {'type': 'vector', 'name': p['layer']})
+ for p in param["params"]:
+ p["layer"] = self.load_layer(
+ None, {"type": "vector", "name": p["layer"]}
+ )
vals.append(p)
return vals
- elif param['type'] == 'multi':
- return [self.load_param(p) for p in param['params']]
- elif param['type'] == 'file':
+ elif param["type"] == "multi":
+ return [self.load_param(p) for p in param["params"]]
+ elif param["type"] == "file":
return self.filepath_from_param(param)
- elif param['type'] == 'interpolation':
+ elif param["type"] == "interpolation":
prefix = processingTestDataPath()
- tmp = ''
- for r in param['name'].split('::|::'):
- v = r.split('::~::')
- tmp += '{}::~::{}::~::{}::~::{};'.format(os.path.join(prefix, v[0]),
- v[1], v[2], v[3])
+ tmp = ""
+ for r in param["name"].split("::|::"):
+ v = r.split("::~::")
+ tmp += "{}::~::{}::~::{}::~::{};".format(
+ os.path.join(prefix, v[0]), v[1], v[2], v[3]
+ )
return tmp[:-1]
except TypeError:
# No type specified, use whatever is there
return param
- raise KeyError("Unknown type '{}' specified for parameter".format(param['type']))
+ raise KeyError(
+ "Unknown type '{}' specified for parameter".format(param["type"])
+ )
def load_result_param(self, param):
"""
Loads a result parameter. Creates a temporary destination where the result should go to and returns this location
so it can be sent to the algorithm as parameter.
"""
- if param['type'] in ['vector', 'file', 'table', 'regex']:
+ if param["type"] in ["vector", "file", "table", "regex"]:
outdir = tempfile.mkdtemp()
self.cleanup_paths.append(outdir)
- if isinstance(param['name'], str):
- basename = os.path.basename(param['name'])
+ if isinstance(param["name"], str):
+ basename = os.path.basename(param["name"])
else:
- basename = os.path.basename(param['name'][0])
+ basename = os.path.basename(param["name"][0])
filepath = self.uri_path_join(outdir, basename)
return filepath
- elif param['type'] == 'rasterhash':
+ elif param["type"] == "rasterhash":
outdir = tempfile.mkdtemp()
self.cleanup_paths.append(outdir)
- basename = 'raster.tif'
+ basename = "raster.tif"
filepath = os.path.join(outdir, basename)
return filepath
- elif param['type'] == 'directory':
+ elif param["type"] == "directory":
outdir = tempfile.mkdtemp()
return outdir
- raise KeyError("Unknown type '{}' specified for parameter".format(param['type']))
+ raise KeyError(
+ "Unknown type '{}' specified for parameter".format(param["type"])
+ )
def load_layers(self, id, param):
layers = []
- if param['type'] in ('vector', 'table'):
- if isinstance(param['name'], str) or 'uri' in param:
+ if param["type"] in ("vector", "table"):
+ if isinstance(param["name"], str) or "uri" in param:
layers.append(self.load_layer(id, param))
else:
- for n in param['name']:
+ for n in param["name"]:
layer_param = deepcopy(param)
- layer_param['name'] = n
+ layer_param["name"] = n
layers.append(self.load_layer(id, layer_param))
else:
layers.append(self.load_layer(id, param))
@@ -242,37 +261,39 @@ def load_layer(self, id, param):
filepath = self.filepath_from_param(param)
- if 'in_place' in param and param['in_place']:
+ if "in_place" in param and param["in_place"]:
# check if alg modifies layer in place
tmpdir = tempfile.mkdtemp()
self.cleanup_paths.append(tmpdir)
path, file_name = os.path.split(filepath)
base, ext = os.path.splitext(file_name)
- for file in glob.glob(os.path.join(path, '{}.*'.format(base))):
+ for file in glob.glob(os.path.join(path, f"{base}.*")):
shutil.copy(os.path.join(path, file), tmpdir)
filepath = os.path.join(tmpdir, file_name)
self.in_place_layers[id] = filepath
- if param['type'] in ('vector', 'table'):
- gmlrex = r'\.gml\b'
+ if param["type"] in ("vector", "table"):
+ gmlrex = r"\.gml\b"
if re.search(gmlrex, filepath, re.IGNORECASE):
# ewwwww - we have to force SRS detection for GML files, otherwise they'll be loaded
# with no srs
- filepath += '|option:FORCE_SRS_DETECTION=YES'
+ filepath += "|option:FORCE_SRS_DETECTION=YES"
if filepath in self.vector_layer_params:
return self.vector_layer_params[filepath]
options = QgsVectorLayer.LayerOptions()
options.loadDefaultStyle = False
- lyr = QgsVectorLayer(filepath, param['name'], 'ogr', options)
+ lyr = QgsVectorLayer(filepath, param["name"], "ogr", options)
self.vector_layer_params[filepath] = lyr
- elif param['type'] == 'raster':
+ elif param["type"] == "raster":
options = QgsRasterLayer.LayerOptions()
options.loadDefaultStyle = False
- lyr = QgsRasterLayer(filepath, param['name'], 'gdal', options)
+ lyr = QgsRasterLayer(filepath, param["name"], "gdal", options)
- self.assertTrue(lyr.isValid(), 'Could not load layer "{}" from param {}'.format(filepath, param))
+ self.assertTrue(
+ lyr.isValid(), f'Could not load layer "{filepath}" from param {param}'
+ )
QgsProject.instance().addMapLayer(lyr)
return lyr
@@ -281,13 +302,13 @@ def filepath_from_param(self, param):
Creates a filepath from a param
"""
prefix = processingTestDataPath()
- if 'location' in param and param['location'] == 'qgs':
+ if "location" in param and param["location"] == "qgs":
prefix = unitTestDataPath()
- if 'uri' in param:
- path = param['uri']
+ if "uri" in param:
+ path = param["uri"]
else:
- path = param['name']
+ path = param["name"]
if not path:
return None
@@ -295,10 +316,10 @@ def filepath_from_param(self, param):
return self.uri_path_join(prefix, path)
def uri_path_join(self, prefix, filepath):
- if filepath.startswith('ogr:'):
+ if filepath.startswith("ogr:"):
if not prefix[-1] == os.path.sep:
prefix += os.path.sep
- filepath = re.sub(r"dbname='", "dbname='{}".format(prefix), filepath)
+ filepath = re.sub(r"dbname='", f"dbname='{prefix}", filepath)
else:
filepath = os.path.join(prefix, filepath)
@@ -309,88 +330,105 @@ def check_results(self, results, context, params, expected):
Checks if result produced by an algorithm matches with the expected specification.
"""
for id, expected_result in expected.items():
- if expected_result['type'] in ('vector', 'table'):
- if 'compare' in expected_result and not expected_result['compare']:
+ if expected_result["type"] in ("vector", "table"):
+ if "compare" in expected_result and not expected_result["compare"]:
# skipping the comparison, so just make sure output is valid
if isinstance(results[id], QgsMapLayer):
result_lyr = results[id]
else:
- result_lyr = QgsProcessingUtils.mapLayerFromString(results[id], context)
+ result_lyr = QgsProcessingUtils.mapLayerFromString(
+ results[id], context
+ )
self.assertTrue(result_lyr.isValid())
continue
expected_lyrs = self.load_layers(id, expected_result)
- if 'in_place_result' in expected_result:
- result_lyr = QgsProcessingUtils.mapLayerFromString(self.in_place_layers[id], context)
+ if "in_place_result" in expected_result:
+ result_lyr = QgsProcessingUtils.mapLayerFromString(
+ self.in_place_layers[id], context
+ )
self.assertTrue(result_lyr.isValid(), self.in_place_layers[id])
else:
try:
results[id]
except KeyError as e:
- raise KeyError('Expected result {} does not exist in {}'.format(str(e), list(results.keys())))
+ raise KeyError(
+ f"Expected result {str(e)} does not exist in {list(results.keys())}"
+ )
if isinstance(results[id], QgsMapLayer):
result_lyr = results[id]
else:
string = results[id]
- gmlrex = r'\.gml\b'
+ gmlrex = r"\.gml\b"
if re.search(gmlrex, string, re.IGNORECASE):
# ewwwww - we have to force SRS detection for GML files, otherwise they'll be loaded
# with no srs
- string += '|option:FORCE_SRS_DETECTION=YES'
+ string += "|option:FORCE_SRS_DETECTION=YES"
- result_lyr = QgsProcessingUtils.mapLayerFromString(string, context)
+ result_lyr = QgsProcessingUtils.mapLayerFromString(
+ string, context
+ )
self.assertTrue(result_lyr, results[id])
- compare = expected_result.get('compare', {})
- pk = expected_result.get('pk', None)
+ compare = expected_result.get("compare", {})
+ pk = expected_result.get("pk", None)
if len(expected_lyrs) == 1:
- self.assertLayersEqual(expected_lyrs[0], result_lyr, compare=compare, pk=pk)
+ self.assertLayersEqual(
+ expected_lyrs[0], result_lyr, compare=compare, pk=pk
+ )
else:
res = False
for l in expected_lyrs:
if self.checkLayersEqual(l, result_lyr, compare=compare, pk=pk):
res = True
break
- self.assertTrue(res, 'Could not find matching layer in expected results')
-
- elif 'rasterhash' == expected_result['type']:
- print("id:{} result:{}".format(id, results[id]))
- self.assertTrue(os.path.exists(results[id]), 'File does not exist: {}, {}'.format(results[id], params))
+ self.assertTrue(
+ res, "Could not find matching layer in expected results"
+ )
+
+ elif "rasterhash" == expected_result["type"]:
+ print(f"id:{id} result:{results[id]}")
+ self.assertTrue(
+ os.path.exists(results[id]),
+ f"File does not exist: {results[id]}, {params}",
+ )
dataset = gdal.Open(results[id], GA_ReadOnly)
dataArray = nan_to_num(dataset.ReadAsArray(0))
strhash = hashlib.sha224(dataArray.data).hexdigest()
- if not isinstance(expected_result['hash'], str):
- self.assertIn(strhash, expected_result['hash'])
+ if not isinstance(expected_result["hash"], str):
+ self.assertIn(strhash, expected_result["hash"])
else:
- self.assertEqual(strhash, expected_result['hash'])
- elif 'file' == expected_result['type']:
+ self.assertEqual(strhash, expected_result["hash"])
+ elif "file" == expected_result["type"]:
result_filepath = results[id]
- if isinstance(expected_result.get('name'), list):
+ if isinstance(expected_result.get("name"), list):
# test to see if any match expected
- for path in expected_result['name']:
- expected_filepath = self.filepath_from_param({'name': path})
+ for path in expected_result["name"]:
+ expected_filepath = self.filepath_from_param({"name": path})
if self.checkFilesEqual(expected_filepath, result_filepath):
break
else:
- expected_filepath = self.filepath_from_param({'name': expected_result['name'][0]})
+ expected_filepath = self.filepath_from_param(
+ {"name": expected_result["name"][0]}
+ )
else:
expected_filepath = self.filepath_from_param(expected_result)
self.assertFilesEqual(expected_filepath, result_filepath)
- elif 'directory' == expected_result['type']:
+ elif "directory" == expected_result["type"]:
expected_dirpath = self.filepath_from_param(expected_result)
result_dirpath = results[id]
self.assertDirectoriesEqual(expected_dirpath, result_dirpath)
- elif 'regex' == expected_result['type']:
+ elif "regex" == expected_result["type"]:
with open(results[id]) as file:
data = file.read()
- for rule in expected_result.get('rules', []):
+ for rule in expected_result.get("rules", []):
self.assertRegex(data, rule)
@@ -411,9 +449,9 @@ def tearDownClass(cls):
def testAlgorithmCompliance(self):
for p in QgsApplication.processingRegistry().providers():
- print('testing provider {}'.format(p.id()))
+ print(f"testing provider {p.id()}")
for a in p.algorithms():
- print('testing algorithm {}'.format(a.id()))
+ print(f"testing algorithm {a.id()}")
self.check_algorithm(a)
def check_algorithm(self, alg):
@@ -421,5 +459,5 @@ def check_algorithm(self, alg):
alg.helpUrl()
-if __name__ == '__main__':
+if __name__ == "__main__":
nose2.main()
diff --git a/python/plugins/grassprovider/tests/grass_algorithms_imagery_test.py b/python/plugins/grassprovider/tests/grass_algorithms_imagery_test.py
index 7e2baa9b6914..84bd78e4e510 100644
--- a/python/plugins/grassprovider/tests/grass_algorithms_imagery_test.py
+++ b/python/plugins/grassprovider/tests/grass_algorithms_imagery_test.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Médéric Ribreux'
-__date__ = 'May 2016'
-__copyright__ = '(C) 2016, Médéric Ribreux'
+__author__ = "Médéric Ribreux"
+__date__ = "May 2016"
+__copyright__ = "(C) 2016, Médéric Ribreux"
import AlgorithmsTestBase
@@ -25,10 +25,7 @@
import shutil
from qgis.core import QgsApplication
-from qgis.testing import (
- QgisTestCase,
- start_app
-)
+from qgis.testing import QgisTestCase, start_app
from grassprovider.grass_provider import GrassProvider
from grassprovider.grass_utils import GrassUtils
@@ -51,8 +48,8 @@ def tearDownClass(cls):
shutil.rmtree(path)
def definition_file(self):
- return 'grass_algorithms_imagery_tests.yaml'
+ return "grass_algorithms_imagery_tests.yaml"
-if __name__ == '__main__':
+if __name__ == "__main__":
nose2.main()
diff --git a/python/plugins/grassprovider/tests/grass_algorithms_raster_test_pt1.py b/python/plugins/grassprovider/tests/grass_algorithms_raster_test_pt1.py
index b26a79ef9522..36ef165d006f 100644
--- a/python/plugins/grassprovider/tests/grass_algorithms_raster_test_pt1.py
+++ b/python/plugins/grassprovider/tests/grass_algorithms_raster_test_pt1.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Médéric Ribreux'
-__date__ = 'May 2016'
-__copyright__ = '(C) 2016, Médéric Ribreux'
+__author__ = "Médéric Ribreux"
+__date__ = "May 2016"
+__copyright__ = "(C) 2016, Médéric Ribreux"
import AlgorithmsTestBase
@@ -25,11 +25,7 @@
import shutil
from qgis.core import QgsApplication
-from qgis.testing import (
- QgisTestCase,
- start_app
-
-)
+from qgis.testing import QgisTestCase, start_app
from grassprovider.grass_provider import GrassProvider
from grassprovider.grass_utils import GrassUtils
@@ -52,8 +48,8 @@ def tearDownClass(cls):
shutil.rmtree(path)
def definition_file(self):
- return 'grass_algorithms_raster_tests1.yaml'
+ return "grass_algorithms_raster_tests1.yaml"
-if __name__ == '__main__':
+if __name__ == "__main__":
nose2.main()
diff --git a/python/plugins/grassprovider/tests/grass_algorithms_raster_test_pt2.py b/python/plugins/grassprovider/tests/grass_algorithms_raster_test_pt2.py
index 9870ba662f2e..bd75ff27849e 100644
--- a/python/plugins/grassprovider/tests/grass_algorithms_raster_test_pt2.py
+++ b/python/plugins/grassprovider/tests/grass_algorithms_raster_test_pt2.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Médéric Ribreux'
-__date__ = 'May 2016'
-__copyright__ = '(C) 2016, Médéric Ribreux'
+__author__ = "Médéric Ribreux"
+__date__ = "May 2016"
+__copyright__ = "(C) 2016, Médéric Ribreux"
import AlgorithmsTestBase
@@ -26,20 +26,13 @@
import os
import tempfile
-from qgis.core import (
- QgsApplication,
- QgsProcessingContext,
- QgsProcessingFeedback
-)
-from qgis.testing import (
- QgisTestCase,
- start_app
-)
+from qgis.core import QgsApplication, QgsProcessingContext, QgsProcessingFeedback
+from qgis.testing import QgisTestCase, start_app
from grassprovider.grass_provider import GrassProvider
from grassprovider.grass_utils import GrassUtils
-testDataPath = os.path.join(os.path.dirname(__file__), 'testdata')
+testDataPath = os.path.join(os.path.dirname(__file__), "testdata")
class TestGrassAlgorithmsRasterTest(QgisTestCase, AlgorithmsTestBase.AlgorithmsTest):
@@ -63,36 +56,42 @@ def tearDownClass(cls):
shutil.rmtree(path)
def definition_file(self):
- return 'grass_algorithms_raster_tests2.yaml'
+ return "grass_algorithms_raster_tests2.yaml"
def testNeighbors(self):
context = QgsProcessingContext()
- input_raster = os.path.join(testDataPath, 'custom', 'grass7', 'float_raster.tif')
+ input_raster = os.path.join(
+ testDataPath, "custom", "grass7", "float_raster.tif"
+ )
- alg = QgsApplication.processingRegistry().createAlgorithmById('grass:r.neighbors')
+ alg = QgsApplication.processingRegistry().createAlgorithmById(
+ "grass:r.neighbors"
+ )
self.assertIsNotNone(alg)
- temp_file = os.path.join(self.temp_dir, 'grass_output.tif')
+ temp_file = os.path.join(self.temp_dir, "grass_output.tif")
# Test an even integer for neighborhood size
- parameters = {'input': input_raster,
- 'selection': None,
- 'method': 0,
- 'size': 4,
- 'gauss': None,
- 'quantile': '',
- '-c': False,
- '-a': False,
- 'weight': '',
- 'output': temp_file,
- 'GRASS_REGION_PARAMETER': None,
- 'GRASS_REGION_CELLSIZE_PARAMETER': 0,
- 'GRASS_RASTER_FORMAT_OPT': '',
- 'GRASS_RASTER_FORMAT_META': ''}
+ parameters = {
+ "input": input_raster,
+ "selection": None,
+ "method": 0,
+ "size": 4,
+ "gauss": None,
+ "quantile": "",
+ "-c": False,
+ "-a": False,
+ "weight": "",
+ "output": temp_file,
+ "GRASS_REGION_PARAMETER": None,
+ "GRASS_REGION_CELLSIZE_PARAMETER": 0,
+ "GRASS_RASTER_FORMAT_OPT": "",
+ "GRASS_RASTER_FORMAT_META": "",
+ }
ok, msg = alg.checkParameterValues(parameters, context)
self.assertFalse(ok)
-if __name__ == '__main__':
+if __name__ == "__main__":
nose2.main()
diff --git a/python/plugins/grassprovider/tests/grass_algorithms_vector_test.py b/python/plugins/grassprovider/tests/grass_algorithms_vector_test.py
index d324df1e89eb..dd660f412542 100644
--- a/python/plugins/grassprovider/tests/grass_algorithms_vector_test.py
+++ b/python/plugins/grassprovider/tests/grass_algorithms_vector_test.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Nyall Dawson'
-__date__ = 'March 2018'
-__copyright__ = '(C) 2018, Nyall Dawson'
+__author__ = "Nyall Dawson"
+__date__ = "March 2018"
+__copyright__ = "(C) 2018, Nyall Dawson"
import AlgorithmsTestBase
@@ -27,24 +27,23 @@
import tempfile
import re
-from qgis.core import (QgsVectorLayer,
- QgsApplication,
- QgsFeature,
- QgsGeometry,
- QgsPointXY,
- QgsProcessingContext,
- QgsProject,
- QgsProcessingFeedback,
- QgsProcessingFeatureSourceDefinition)
-from qgis.testing import (
- QgisTestCase,
- start_app
+from qgis.core import (
+ QgsVectorLayer,
+ QgsApplication,
+ QgsFeature,
+ QgsGeometry,
+ QgsPointXY,
+ QgsProcessingContext,
+ QgsProject,
+ QgsProcessingFeedback,
+ QgsProcessingFeatureSourceDefinition,
)
+from qgis.testing import QgisTestCase, start_app
from grassprovider.grass_provider import GrassProvider
from grassprovider.grass_utils import GrassUtils
-testDataPath = os.path.join(os.path.dirname(__file__), 'testdata')
+testDataPath = os.path.join(os.path.dirname(__file__), "testdata")
class TestGrassAlgorithmsVectorTest(QgisTestCase, AlgorithmsTestBase.AlgorithmsTest):
@@ -68,12 +67,15 @@ def tearDownClass(cls):
shutil.rmtree(path)
def definition_file(self):
- return 'grass_algorithms_vector_tests.yaml'
+ return "grass_algorithms_vector_tests.yaml"
def testMemoryLayerInput(self):
# create a memory layer and add to project and context
- layer = QgsVectorLayer("Point?crs=epsg:3857&field=fldtxt:string&field=fldint:integer",
- "testmem", "memory")
+ layer = QgsVectorLayer(
+ "Point?crs=epsg:3857&field=fldtxt:string&field=fldint:integer",
+ "testmem",
+ "memory",
+ )
self.assertTrue(layer.isValid())
pr = layer.dataProvider()
f = QgsFeature()
@@ -88,30 +90,32 @@ def testMemoryLayerInput(self):
context = QgsProcessingContext()
context.setProject(QgsProject.instance())
- alg = QgsApplication.processingRegistry().createAlgorithmById('grass:v.buffer')
+ alg = QgsApplication.processingRegistry().createAlgorithmById("grass:v.buffer")
self.assertIsNotNone(alg)
- temp_file = os.path.join(self.temp_dir, 'grass_output.shp')
- parameters = {'input': 'testmem',
- 'cats': '',
- 'where': '',
- 'type': [0, 1, 4],
- 'distance': 1,
- 'minordistance': None,
- 'angle': 0,
- 'column': None,
- 'scale': 1,
- 'tolerance': 0.01,
- '-s': False,
- '-c': False,
- '-t': False,
- 'output': temp_file,
- 'GRASS_REGION_PARAMETER': None,
- 'GRASS_SNAP_TOLERANCE_PARAMETER': -1,
- 'GRASS_MIN_AREA_PARAMETER': 0.0001,
- 'GRASS_OUTPUT_TYPE_PARAMETER': 0,
- 'GRASS_VECTOR_DSCO': '',
- 'GRASS_VECTOR_LCO': ''}
+ temp_file = os.path.join(self.temp_dir, "grass_output.shp")
+ parameters = {
+ "input": "testmem",
+ "cats": "",
+ "where": "",
+ "type": [0, 1, 4],
+ "distance": 1,
+ "minordistance": None,
+ "angle": 0,
+ "column": None,
+ "scale": 1,
+ "tolerance": 0.01,
+ "-s": False,
+ "-c": False,
+ "-t": False,
+ "output": temp_file,
+ "GRASS_REGION_PARAMETER": None,
+ "GRASS_SNAP_TOLERANCE_PARAMETER": -1,
+ "GRASS_MIN_AREA_PARAMETER": 0.0001,
+ "GRASS_OUTPUT_TYPE_PARAMETER": 0,
+ "GRASS_VECTOR_DSCO": "",
+ "GRASS_VECTOR_LCO": "",
+ }
feedback = QgsProcessingFeedback()
results, ok = alg.run(parameters, context, feedback)
@@ -119,7 +123,7 @@ def testMemoryLayerInput(self):
self.assertTrue(os.path.exists(temp_file))
# make sure that layer has correct features
- res = QgsVectorLayer(temp_file, 'res')
+ res = QgsVectorLayer(temp_file, "res")
self.assertTrue(res.isValid())
self.assertEqual(res.featureCount(), 2)
@@ -127,8 +131,11 @@ def testMemoryLayerInput(self):
def testFeatureSourceInput(self):
# create a memory layer and add to project and context
- layer = QgsVectorLayer("Point?crs=epsg:3857&field=fldtxt:string&field=fldint:integer",
- "testmem", "memory")
+ layer = QgsVectorLayer(
+ "Point?crs=epsg:3857&field=fldtxt:string&field=fldint:integer",
+ "testmem",
+ "memory",
+ )
self.assertTrue(layer.isValid())
pr = layer.dataProvider()
f = QgsFeature()
@@ -148,29 +155,31 @@ def testFeatureSourceInput(self):
context = QgsProcessingContext()
context.setProject(QgsProject.instance())
- alg = QgsApplication.processingRegistry().createAlgorithmById('grass:v.buffer')
+ alg = QgsApplication.processingRegistry().createAlgorithmById("grass:v.buffer")
self.assertIsNotNone(alg)
- temp_file = os.path.join(self.temp_dir, 'grass_output_sel.shp')
- parameters = {'input': QgsProcessingFeatureSourceDefinition('testmem', True),
- 'cats': '',
- 'where': '',
- 'type': [0, 1, 4],
- 'distance': 1,
- 'minordistance': None,
- 'angle': 0,
- 'column': None,
- 'scale': 1,
- 'tolerance': 0.01,
- '-s': False,
- '-c': False,
- '-t': False,
- 'output': temp_file,
- 'GRASS_REGION_PARAMETER': None,
- 'GRASS_SNAP_TOLERANCE_PARAMETER': -1,
- 'GRASS_MIN_AREA_PARAMETER': 0.0001,
- 'GRASS_OUTPUT_TYPE_PARAMETER': 0,
- 'GRASS_VECTOR_DSCO': '',
- 'GRASS_VECTOR_LCO': ''}
+ temp_file = os.path.join(self.temp_dir, "grass_output_sel.shp")
+ parameters = {
+ "input": QgsProcessingFeatureSourceDefinition("testmem", True),
+ "cats": "",
+ "where": "",
+ "type": [0, 1, 4],
+ "distance": 1,
+ "minordistance": None,
+ "angle": 0,
+ "column": None,
+ "scale": 1,
+ "tolerance": 0.01,
+ "-s": False,
+ "-c": False,
+ "-t": False,
+ "output": temp_file,
+ "GRASS_REGION_PARAMETER": None,
+ "GRASS_SNAP_TOLERANCE_PARAMETER": -1,
+ "GRASS_MIN_AREA_PARAMETER": 0.0001,
+ "GRASS_OUTPUT_TYPE_PARAMETER": 0,
+ "GRASS_VECTOR_DSCO": "",
+ "GRASS_VECTOR_LCO": "",
+ }
feedback = QgsProcessingFeedback()
results, ok = alg.run(parameters, context, feedback)
@@ -178,7 +187,7 @@ def testFeatureSourceInput(self):
self.assertTrue(os.path.exists(temp_file))
# make sure that layer has correct features
- res = QgsVectorLayer(temp_file, 'res')
+ res = QgsVectorLayer(temp_file, "res")
self.assertTrue(res.isValid())
self.assertEqual(res.featureCount(), 1)
@@ -186,8 +195,11 @@ def testFeatureSourceInput(self):
def testOutputToGeopackage(self):
# create a memory layer and add to project and context
- layer = QgsVectorLayer("Point?crs=epsg:3857&field=fldtxt:string&field=fldint:integer",
- "testmem", "memory")
+ layer = QgsVectorLayer(
+ "Point?crs=epsg:3857&field=fldtxt:string&field=fldint:integer",
+ "testmem",
+ "memory",
+ )
self.assertTrue(layer.isValid())
pr = layer.dataProvider()
f = QgsFeature()
@@ -202,30 +214,32 @@ def testOutputToGeopackage(self):
context = QgsProcessingContext()
context.setProject(QgsProject.instance())
- alg = QgsApplication.processingRegistry().createAlgorithmById('grass:v.buffer')
+ alg = QgsApplication.processingRegistry().createAlgorithmById("grass:v.buffer")
self.assertIsNotNone(alg)
- temp_file = os.path.join(self.temp_dir, 'grass_output.gpkg')
- parameters = {'input': 'testmem',
- 'cats': '',
- 'where': '',
- 'type': [0, 1, 4],
- 'distance': 1,
- 'minordistance': None,
- 'angle': 0,
- 'column': None,
- 'scale': 1,
- 'tolerance': 0.01,
- '-s': False,
- '-c': False,
- '-t': False,
- 'output': temp_file,
- 'GRASS_REGION_PARAMETER': None,
- 'GRASS_SNAP_TOLERANCE_PARAMETER': -1,
- 'GRASS_MIN_AREA_PARAMETER': 0.0001,
- 'GRASS_OUTPUT_TYPE_PARAMETER': 0,
- 'GRASS_VECTOR_DSCO': '',
- 'GRASS_VECTOR_LCO': ''}
+ temp_file = os.path.join(self.temp_dir, "grass_output.gpkg")
+ parameters = {
+ "input": "testmem",
+ "cats": "",
+ "where": "",
+ "type": [0, 1, 4],
+ "distance": 1,
+ "minordistance": None,
+ "angle": 0,
+ "column": None,
+ "scale": 1,
+ "tolerance": 0.01,
+ "-s": False,
+ "-c": False,
+ "-t": False,
+ "output": temp_file,
+ "GRASS_REGION_PARAMETER": None,
+ "GRASS_SNAP_TOLERANCE_PARAMETER": -1,
+ "GRASS_MIN_AREA_PARAMETER": 0.0001,
+ "GRASS_OUTPUT_TYPE_PARAMETER": 0,
+ "GRASS_VECTOR_DSCO": "",
+ "GRASS_VECTOR_LCO": "",
+ }
feedback = QgsProcessingFeedback()
results, ok = alg.run(parameters, context, feedback)
@@ -233,7 +247,7 @@ def testOutputToGeopackage(self):
self.assertTrue(os.path.exists(temp_file))
# make sure that layer has correct features
- res = QgsVectorLayer(temp_file, 'res')
+ res = QgsVectorLayer(temp_file, "res")
self.assertTrue(res.isValid())
self.assertEqual(res.featureCount(), 2)
@@ -241,73 +255,109 @@ def testOutputToGeopackage(self):
def testVectorLayerInput(self):
context = QgsProcessingContext()
- alg = QgsApplication.processingRegistry().createAlgorithmById('grass7:v.buffer')
+ alg = QgsApplication.processingRegistry().createAlgorithmById("grass7:v.buffer")
self.assertIsNotNone(alg)
self.assertFalse(alg.commands)
def get_command(alg):
command = alg.commands[-1]
command = re.sub(r'output=".*?"', 'output="###"', command)
- command = command.replace(testDataPath, 'testdata')
+ command = command.replace(testDataPath, "testdata")
return command
# GML source
- source = os.path.join(testDataPath, 'points.gml')
+ source = os.path.join(testDataPath, "points.gml")
vl = QgsVectorLayer(source)
self.assertTrue(vl.isValid())
- alg.loadVectorLayer('test_layer', vl, context, external=False)
- self.assertEqual(get_command(alg), 'v.in.ogr min_area=None snap=None input="testdata/points.gml" output="###" --overwrite -o')
+ alg.loadVectorLayer("test_layer", vl, context, external=False)
+ self.assertEqual(
+ get_command(alg),
+ 'v.in.ogr min_area=None snap=None input="testdata/points.gml" output="###" --overwrite -o',
+ )
# try with external -- not support for GML, so should fall back to v.in.ogr
- alg.loadVectorLayer('test_layer', vl, context, external=True)
- self.assertEqual(get_command(alg), 'v.in.ogr min_area=None snap=None input="testdata/points.gml" output="###" --overwrite -o')
+ alg.loadVectorLayer("test_layer", vl, context, external=True)
+ self.assertEqual(
+ get_command(alg),
+ 'v.in.ogr min_area=None snap=None input="testdata/points.gml" output="###" --overwrite -o',
+ )
# SHP source
- source = os.path.join(testDataPath, 'lines_z.shp')
+ source = os.path.join(testDataPath, "lines_z.shp")
vl = QgsVectorLayer(source)
self.assertTrue(vl.isValid())
- alg.loadVectorLayer('test_layer', vl, context, external=False)
- self.assertEqual(get_command(alg), 'v.in.ogr min_area=None snap=None input="testdata/lines_z.shp" output="###" --overwrite -o')
+ alg.loadVectorLayer("test_layer", vl, context, external=False)
+ self.assertEqual(
+ get_command(alg),
+ 'v.in.ogr min_area=None snap=None input="testdata/lines_z.shp" output="###" --overwrite -o',
+ )
# try with external -- should work for shapefile
- alg.loadVectorLayer('test_layer', vl, context, external=True)
- self.assertEqual(get_command(alg), 'v.external input="testdata/lines_z.shp" output="###" --overwrite -o')
+ alg.loadVectorLayer("test_layer", vl, context, external=True)
+ self.assertEqual(
+ get_command(alg),
+ 'v.external input="testdata/lines_z.shp" output="###" --overwrite -o',
+ )
# GPKG source
- source = os.path.join(testDataPath, 'pol.gpkg')
- vl = QgsVectorLayer(source + '|layername=pol2')
+ source = os.path.join(testDataPath, "pol.gpkg")
+ vl = QgsVectorLayer(source + "|layername=pol2")
self.assertTrue(vl.isValid())
- alg.loadVectorLayer('test_layer', vl, context, external=False)
- self.assertEqual(get_command(alg), 'v.in.ogr min_area=None snap=None input="testdata/pol.gpkg" layer="pol2" output="###" --overwrite -o')
+ alg.loadVectorLayer("test_layer", vl, context, external=False)
+ self.assertEqual(
+ get_command(alg),
+ 'v.in.ogr min_area=None snap=None input="testdata/pol.gpkg" layer="pol2" output="###" --overwrite -o',
+ )
# try with external -- should work for Geopackage (although grass itself tends to crash here!)
- alg.loadVectorLayer('test_layer', vl, context, external=True)
- self.assertEqual(get_command(alg), 'v.external input="testdata/pol.gpkg" layer="pol2" output="###" --overwrite -o')
+ alg.loadVectorLayer("test_layer", vl, context, external=True)
+ self.assertEqual(
+ get_command(alg),
+ 'v.external input="testdata/pol.gpkg" layer="pol2" output="###" --overwrite -o',
+ )
# different layer
- source = os.path.join(testDataPath, 'pol.gpkg')
- vl = QgsVectorLayer(source + '|layername=pol3')
+ source = os.path.join(testDataPath, "pol.gpkg")
+ vl = QgsVectorLayer(source + "|layername=pol3")
self.assertTrue(vl.isValid())
- alg.loadVectorLayer('test_layer', vl, context, external=False)
- self.assertEqual(get_command(alg), 'v.in.ogr min_area=None snap=None input="testdata/pol.gpkg" layer="pol3" output="###" --overwrite -o')
- alg.loadVectorLayer('test_layer', vl, context, external=True)
- self.assertEqual(get_command(alg), 'v.external input="testdata/pol.gpkg" layer="pol3" output="###" --overwrite -o')
+ alg.loadVectorLayer("test_layer", vl, context, external=False)
+ self.assertEqual(
+ get_command(alg),
+ 'v.in.ogr min_area=None snap=None input="testdata/pol.gpkg" layer="pol3" output="###" --overwrite -o',
+ )
+ alg.loadVectorLayer("test_layer", vl, context, external=True)
+ self.assertEqual(
+ get_command(alg),
+ 'v.external input="testdata/pol.gpkg" layer="pol3" output="###" --overwrite -o',
+ )
# GPKG no layer: you get what you get and you don't get upset
- source = os.path.join(testDataPath, 'pol.gpkg')
+ source = os.path.join(testDataPath, "pol.gpkg")
vl = QgsVectorLayer(source)
self.assertTrue(vl.isValid())
- alg.loadVectorLayer('test_layer', vl, context, external=False)
- self.assertEqual(get_command(alg), 'v.in.ogr min_area=None snap=None input="testdata/pol.gpkg" output="###" --overwrite -o')
- alg.loadVectorLayer('test_layer', vl, context, external=True)
- self.assertEqual(get_command(alg), 'v.external input="testdata/pol.gpkg" output="###" --overwrite -o')
+ alg.loadVectorLayer("test_layer", vl, context, external=False)
+ self.assertEqual(
+ get_command(alg),
+ 'v.in.ogr min_area=None snap=None input="testdata/pol.gpkg" output="###" --overwrite -o',
+ )
+ alg.loadVectorLayer("test_layer", vl, context, external=True)
+ self.assertEqual(
+ get_command(alg),
+ 'v.external input="testdata/pol.gpkg" output="###" --overwrite -o',
+ )
# layer with filter
- vl = QgsVectorLayer(source + '|layername=pol3')
+ vl = QgsVectorLayer(source + "|layername=pol3")
self.assertTrue(vl.isValid())
- vl.setSubsetString('"field"=\'value\'')
- alg.loadVectorLayer('test_layer', vl, context, external=False)
- self.assertEqual(get_command(alg), 'v.in.ogr min_area=None snap=None input="testdata/pol.gpkg" layer="pol3" output="###" --overwrite -o where="\\"field\\"=\'value\'"')
- alg.loadVectorLayer('test_layer', vl, context, external=True)
- self.assertEqual(get_command(alg), 'v.external input="testdata/pol.gpkg" layer="pol3" output="###" --overwrite -o where="\\"field\\"=\'value\'"')
-
-
-if __name__ == '__main__':
+ vl.setSubsetString("\"field\"='value'")
+ alg.loadVectorLayer("test_layer", vl, context, external=False)
+ self.assertEqual(
+ get_command(alg),
+ 'v.in.ogr min_area=None snap=None input="testdata/pol.gpkg" layer="pol3" output="###" --overwrite -o where="\\"field\\"=\'value\'"',
+ )
+ alg.loadVectorLayer("test_layer", vl, context, external=True)
+ self.assertEqual(
+ get_command(alg),
+ 'v.external input="testdata/pol.gpkg" layer="pol3" output="###" --overwrite -o where="\\"field\\"=\'value\'"',
+ )
+
+
+if __name__ == "__main__":
nose2.main()
diff --git a/python/plugins/processing/ProcessingPlugin.py b/python/plugins/processing/ProcessingPlugin.py
index 0b3452b638d9..07a743785087 100644
--- a/python/plugins/processing/ProcessingPlugin.py
+++ b/python/plugins/processing/ProcessingPlugin.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'August 2012'
-__copyright__ = '(C) 2012, Victor Olaya'
+__author__ = "Victor Olaya"
+__date__ = "August 2012"
+__copyright__ = "(C) 2012, Victor Olaya"
import shutil
import os
@@ -25,20 +25,24 @@
from typing import List
from functools import partial
-from qgis.core import (QgsApplication,
- QgsProcessingUtils,
- QgsProcessingModelAlgorithm,
- QgsProcessingAlgorithm,
- QgsDataItemProvider,
- QgsDataProvider,
- QgsDataItem,
- QgsMapLayerType,
- QgsMimeDataUtils,
- QgsSettings)
-from qgis.gui import (QgsGui,
- QgsOptionsWidgetFactory,
- QgsCustomDropHandler,
- QgsProcessingHistoryDialog)
+from qgis.core import (
+ QgsApplication,
+ QgsProcessingUtils,
+ QgsProcessingModelAlgorithm,
+ QgsProcessingAlgorithm,
+ QgsDataItemProvider,
+ QgsDataProvider,
+ QgsDataItem,
+ QgsMapLayerType,
+ QgsMimeDataUtils,
+ QgsSettings,
+)
+from qgis.gui import (
+ QgsGui,
+ QgsOptionsWidgetFactory,
+ QgsCustomDropHandler,
+ QgsProcessingHistoryDialog,
+)
from qgis.PyQt.QtCore import (
QObject,
Qt,
@@ -47,17 +51,10 @@
QDir,
QFileInfo,
pyqtSlot,
- QMetaObject
-)
-from qgis.PyQt.QtWidgets import (
- QWidget,
- QMenu,
- QAction
-)
-from qgis.PyQt.QtGui import (
- QIcon,
- QKeySequence
+ QMetaObject,
)
+from qgis.PyQt.QtWidgets import QWidget, QMenu, QAction
+from qgis.PyQt.QtGui import QIcon, QKeySequence
from qgis.utils import iface
from processing.core.Processing import Processing
@@ -66,8 +63,10 @@
from processing.gui.ResultsDock import ResultsDock
from processing.gui.MessageDialog import MessageDialog
from processing.gui.MessageBarProgress import MessageBarProgress
-from processing.gui.AlgorithmLocatorFilter import (AlgorithmLocatorFilter,
- InPlaceAlgorithmLocatorFilter)
+from processing.gui.AlgorithmLocatorFilter import (
+ AlgorithmLocatorFilter,
+ InPlaceAlgorithmLocatorFilter,
+)
from processing.gui.Postprocessing import handleAlgorithmResults
from processing.gui.AlgorithmExecutor import execute, execute_in_place
from processing.gui.AlgorithmDialog import AlgorithmDialog
@@ -76,7 +75,13 @@
from processing.modeler.ModelerDialog import ModelerDialog
from processing.tools.system import tempHelpFolder
from processing.tools import dataobjects
-from processing.gui.menus import removeMenus, initializeMenus, createMenus, createButtons, removeButtons
+from processing.gui.menus import (
+ removeMenus,
+ initializeMenus,
+ createMenus,
+ createButtons,
+ removeButtons,
+)
from processing.core.ProcessingResults import resultsList
pluginPath = os.path.dirname(__file__)
@@ -88,7 +93,7 @@ def __init__(self):
super(QgsOptionsWidgetFactory, self).__init__()
def icon(self):
- return QgsApplication.getThemeIcon('/processingAlgorithm.svg')
+ return QgsApplication.getThemeIcon("/processingAlgorithm.svg")
def createWidget(self, parent):
return ConfigOptionsPage(parent)
@@ -97,7 +102,7 @@ def createWidget(self, parent):
class ProcessingDropHandler(QgsCustomDropHandler):
def handleFileDrop(self, file):
- if not file.lower().endswith('.model3'):
+ if not file.lower().endswith(".model3"):
return False
return self.runAlg(file)
@@ -107,7 +112,7 @@ def runAlg(file):
if not alg.fromFile(file):
return False
- alg.setProvider(QgsApplication.processingRegistry().providerById('model'))
+ alg.setProvider(QgsApplication.processingRegistry().providerById("model"))
dlg = AlgorithmDialog(alg, parent=iface.mainWindow())
dlg.show()
# do NOT remove!!!! if you do then sip forgets the python subclass of AlgorithmDialog and you get a broken
@@ -116,7 +121,7 @@ def runAlg(file):
return True
def customUriProviderKey(self):
- return 'processing'
+ return "processing"
def handleCustomUriDrop(self, uri):
path = uri.uri
@@ -155,9 +160,13 @@ def editModel(self):
dlg.show()
def actions(self, parent):
- run_model_action = QAction(QCoreApplication.translate('ProcessingPlugin', '&Run Model…'), parent)
+ run_model_action = QAction(
+ QCoreApplication.translate("ProcessingPlugin", "&Run Model…"), parent
+ )
run_model_action.triggered.connect(self.runModel)
- edit_model_action = QAction(QCoreApplication.translate('ProcessingPlugin', '&Edit Model…'), parent)
+ edit_model_action = QAction(
+ QCoreApplication.translate("ProcessingPlugin", "&Edit Model…"), parent
+ )
edit_model_action.triggered.connect(self.editModel)
return [run_model_action, edit_model_action]
@@ -168,7 +177,7 @@ def __init__(self):
super().__init__()
def name(self):
- return 'processing'
+ return "processing"
def capabilities(self):
return QgsDataProvider.DataCapability.File
@@ -176,7 +185,7 @@ def capabilities(self):
def createDataItem(self, path, parentItem):
file_info = QFileInfo(path)
- if file_info.suffix().lower() == 'model3':
+ if file_info.suffix().lower() == "model3":
alg = QgsProcessingModelAlgorithm()
if alg.fromFile(path):
return ProcessingModelItem(parentItem, alg.name(), path)
@@ -194,7 +203,7 @@ def __init__(self, iface):
self.locator_filter = None
self.edit_features_locator_filter = None
self.initialized = False
- self._gui_connections: List[QMetaObject.Connection] = []
+ self._gui_connections: list[QMetaObject.Connection] = []
self.initProcessing()
def initProcessing(self):
@@ -209,13 +218,15 @@ def initGui(self):
# port old log, ONCE ONLY!
settings = QgsSettings()
if not settings.value("/Processing/hasPortedOldLog", False, bool):
- processing_history_provider = QgsGui.historyProviderRegistry().providerById('processing')
+ processing_history_provider = QgsGui.historyProviderRegistry().providerById(
+ "processing"
+ )
if processing_history_provider:
processing_history_provider.portOldLog()
settings.setValue("/Processing/hasPortedOldLog", True)
self.options_factory = ProcessingOptionsFactory()
- self.options_factory.setTitle(self.tr('Processing'))
+ self.options_factory.setTitle(self.tr("Processing"))
iface.registerOptionsWidgetFactory(self.options_factory)
self.drop_handler = ProcessingDropHandler()
iface.registerCustomDropHandler(self.drop_handler)
@@ -225,15 +236,17 @@ def initGui(self):
iface.registerLocatorFilter(self.locator_filter)
# Invalidate the locator filter for in-place when active layer changes
self._gui_connections.append(
- iface.currentLayerChanged.connect(lambda _: self.iface.invalidateLocatorResults())
+ iface.currentLayerChanged.connect(
+ lambda _: self.iface.invalidateLocatorResults()
+ )
)
self.edit_features_locator_filter = InPlaceAlgorithmLocatorFilter()
iface.registerLocatorFilter(self.edit_features_locator_filter)
- QgsGui.historyProviderRegistry().providerById('processing').executePython.connect(
- self._execute_history_commands
- )
- QgsGui.historyProviderRegistry().providerById('processing').createTest.connect(
+ QgsGui.historyProviderRegistry().providerById(
+ "processing"
+ ).executePython.connect(self._execute_history_commands)
+ QgsGui.historyProviderRegistry().providerById("processing").createTest.connect(
self.create_test
)
@@ -245,50 +258,69 @@ def initGui(self):
self.toolbox.executeWithGui.connect(self.executeAlgorithm)
self.resultsDock = ResultsDock()
- self.iface.addDockWidget(Qt.DockWidgetArea.RightDockWidgetArea, self.resultsDock)
+ self.iface.addDockWidget(
+ Qt.DockWidgetArea.RightDockWidgetArea, self.resultsDock
+ )
self.resultsDock.hide()
self.menu = QMenu(self.iface.mainWindow().menuBar())
- self.menu.setObjectName('processing')
- self.menu.setTitle(self.tr('Pro&cessing'))
+ self.menu.setObjectName("processing")
+ self.menu.setTitle(self.tr("Pro&cessing"))
- self.toolboxAction = QAction(self.tr('&Toolbox'), self.iface.mainWindow())
+ self.toolboxAction = QAction(self.tr("&Toolbox"), self.iface.mainWindow())
self.toolboxAction.setCheckable(True)
- self.toolboxAction.setObjectName('toolboxAction')
+ self.toolboxAction.setObjectName("toolboxAction")
self.toolboxAction.setIcon(
- QgsApplication.getThemeIcon("/processingAlgorithm.svg"))
- self.iface.registerMainWindowAction(self.toolboxAction,
- QKeySequence('Ctrl+Alt+T').toString(QKeySequence.SequenceFormat.NativeText))
+ QgsApplication.getThemeIcon("/processingAlgorithm.svg")
+ )
+ self.iface.registerMainWindowAction(
+ self.toolboxAction,
+ QKeySequence("Ctrl+Alt+T").toString(QKeySequence.SequenceFormat.NativeText),
+ )
self.toolboxAction.toggled.connect(self.openToolbox)
- self.iface.attributesToolBar().insertAction(self.iface.actionOpenStatisticalSummary(), self.toolboxAction)
+ self.iface.attributesToolBar().insertAction(
+ self.iface.actionOpenStatisticalSummary(), self.toolboxAction
+ )
self.menu.addAction(self.toolboxAction)
self.modelerAction = QAction(
QgsApplication.getThemeIcon("/processingModel.svg"),
- QCoreApplication.translate('ProcessingPlugin', '&Model Designer…'), self.iface.mainWindow())
- self.modelerAction.setObjectName('modelerAction')
+ QCoreApplication.translate("ProcessingPlugin", "&Model Designer…"),
+ self.iface.mainWindow(),
+ )
+ self.modelerAction.setObjectName("modelerAction")
self.modelerAction.triggered.connect(self.openModeler)
- self.iface.registerMainWindowAction(self.modelerAction,
- QKeySequence('Ctrl+Alt+G').toString(QKeySequence.SequenceFormat.NativeText))
+ self.iface.registerMainWindowAction(
+ self.modelerAction,
+ QKeySequence("Ctrl+Alt+G").toString(QKeySequence.SequenceFormat.NativeText),
+ )
self.menu.addAction(self.modelerAction)
self.historyAction = QAction(
QgsApplication.getThemeIcon("/mIconHistory.svg"),
- QCoreApplication.translate('ProcessingPlugin', '&History…'), self.iface.mainWindow())
- self.historyAction.setObjectName('historyAction')
+ QCoreApplication.translate("ProcessingPlugin", "&History…"),
+ self.iface.mainWindow(),
+ )
+ self.historyAction.setObjectName("historyAction")
self.historyAction.triggered.connect(self.openHistory)
- self.iface.registerMainWindowAction(self.historyAction,
- QKeySequence('Ctrl+Alt+H').toString(QKeySequence.SequenceFormat.NativeText))
+ self.iface.registerMainWindowAction(
+ self.historyAction,
+ QKeySequence("Ctrl+Alt+H").toString(QKeySequence.SequenceFormat.NativeText),
+ )
self.menu.addAction(self.historyAction)
self.toolbox.processingToolbar.addAction(self.historyAction)
self.resultsAction = QAction(
QgsApplication.getThemeIcon("/processingResult.svg"),
- self.tr('&Results Viewer'), self.iface.mainWindow())
- self.resultsAction.setObjectName('resultsViewer')
+ self.tr("&Results Viewer"),
+ self.iface.mainWindow(),
+ )
+ self.resultsAction.setObjectName("resultsViewer")
self.resultsAction.setCheckable(True)
- self.iface.registerMainWindowAction(self.resultsAction,
- QKeySequence('Ctrl+Alt+R').toString(QKeySequence.SequenceFormat.NativeText))
+ self.iface.registerMainWindowAction(
+ self.resultsAction,
+ QKeySequence("Ctrl+Alt+R").toString(QKeySequence.SequenceFormat.NativeText),
+ )
self.menu.addAction(self.resultsAction)
self.toolbox.processingToolbar.addAction(self.resultsAction)
@@ -299,8 +331,10 @@ def initGui(self):
self.editInPlaceAction = QAction(
QgsApplication.getThemeIcon("/mActionProcessSelected.svg"),
- self.tr('Edit Features In-Place'), self.iface.mainWindow())
- self.editInPlaceAction.setObjectName('editInPlaceFeatures')
+ self.tr("Edit Features In-Place"),
+ self.iface.mainWindow(),
+ )
+ self.editInPlaceAction.setObjectName("editInPlaceFeatures")
self.editInPlaceAction.setCheckable(True)
self.editInPlaceAction.toggled.connect(self.editSelected)
self.menu.addAction(self.editInPlaceAction)
@@ -310,14 +344,15 @@ def initGui(self):
self.optionsAction = QAction(
QgsApplication.getThemeIcon("/mActionOptions.svg"),
- self.tr('Options'), self.iface.mainWindow())
- self.optionsAction.setObjectName('optionsAction')
+ self.tr("Options"),
+ self.iface.mainWindow(),
+ )
+ self.optionsAction.setObjectName("optionsAction")
self.optionsAction.triggered.connect(self.openProcessingOptions)
self.toolbox.processingToolbar.addAction(self.optionsAction)
menuBar = self.iface.mainWindow().menuBar()
- menuBar.insertMenu(
- self.iface.firstRightStandardMenu().menuAction(), self.menu)
+ menuBar.insertMenu(self.iface.firstRightStandardMenu().menuAction(), self.menu)
self.menu.addSeparator()
@@ -334,10 +369,14 @@ def initGui(self):
self.iface.currentLayerChanged.connect(self.sync_in_place_button_state)
)
self._gui_connections.append(
- self.iface.mapCanvas().selectionChanged.connect(self.sync_in_place_button_state)
+ self.iface.mapCanvas().selectionChanged.connect(
+ self.sync_in_place_button_state
+ )
)
self._gui_connections.append(
- self.iface.actionToggleEditing().triggered.connect(partial(self.sync_in_place_button_state, None))
+ self.iface.actionToggleEditing().triggered.connect(
+ partial(self.sync_in_place_button_state, None)
+ )
)
self.sync_in_place_button_state()
@@ -346,7 +385,9 @@ def initGui(self):
self.projectMenuAction = None
self.projectMenuSeparator = None
- self.projectProvider = QgsApplication.instance().processingRegistry().providerById("project")
+ self.projectProvider = (
+ QgsApplication.instance().processingRegistry().providerById("project")
+ )
self._gui_connections.append(
self.projectProvider.algorithmsLoaded.connect(self.updateProjectModelMenu)
)
@@ -356,7 +397,9 @@ def updateProjectModelMenu(self):
if self.projectMenuAction is None:
self.projectModelsMenu = QMenu(self.tr("Models"))
- self.projectMenuAction = self.iface.projectMenu().insertMenu(self.iface.projectMenu().children()[-1], self.projectModelsMenu)
+ self.projectMenuAction = self.iface.projectMenu().insertMenu(
+ self.iface.projectMenu().children()[-1], self.projectModelsMenu
+ )
self.projectMenuAction.setParent(self.projectModelsMenu)
self.iface.projectMenu().insertSeparator(self.projectMenuAction)
@@ -366,12 +409,27 @@ def updateProjectModelMenu(self):
modelSubMenu = self.projectModelsMenu.addMenu(model.name())
modelSubMenu.setParent(self.projectModelsMenu)
action = QAction(self.tr("Execute…"), modelSubMenu)
- action.triggered.connect(partial(self.executeAlgorithm, model.id(), self.projectModelsMenu, self.toolbox.in_place_mode))
+ action.triggered.connect(
+ partial(
+ self.executeAlgorithm,
+ model.id(),
+ self.projectModelsMenu,
+ self.toolbox.in_place_mode,
+ )
+ )
modelSubMenu.addAction(action)
if model.flags() & QgsProcessingAlgorithm.Flag.FlagSupportsBatch:
action = QAction(self.tr("Execute as Batch Process…"), modelSubMenu)
modelSubMenu.addAction(action)
- action.triggered.connect(partial(self.executeAlgorithm, model.id(), self.projectModelsMenu, self.toolbox.in_place_mode, True))
+ action.triggered.connect(
+ partial(
+ self.executeAlgorithm,
+ model.id(),
+ self.projectModelsMenu,
+ self.toolbox.in_place_mode,
+ True,
+ )
+ )
@pyqtSlot(str, QWidget, bool, bool)
def executeAlgorithm(self, alg_id, parent, in_place=False, as_batch=False):
@@ -389,19 +447,25 @@ def executeAlgorithm(self, alg_id, parent, in_place=False, as_batch=False):
config = {}
if in_place:
- config['IN_PLACE'] = True
+ config["IN_PLACE"] = True
- alg = QgsApplication.instance().processingRegistry().createAlgorithmById(alg_id, config)
+ alg = (
+ QgsApplication.instance()
+ .processingRegistry()
+ .createAlgorithmById(alg_id, config)
+ )
if alg is not None:
ok, message = alg.canExecute()
if not ok:
dlg = MessageDialog()
- dlg.setTitle(self.tr('Error executing algorithm'))
+ dlg.setTitle(self.tr("Error executing algorithm"))
dlg.setMessage(
- self.tr('This algorithm cannot '
- 'be run :-( \n{0}').format(message))
+ self.tr(
+ "This algorithm cannot " "be run :-( \n{0}"
+ ).format(message)
+ )
dlg.exec()
return
@@ -410,16 +474,26 @@ def executeAlgorithm(self, alg_id, parent, in_place=False, as_batch=False):
dlg.show()
dlg.exec()
else:
- in_place_input_parameter_name = 'INPUT'
- if hasattr(alg, 'inputParameterName'):
+ in_place_input_parameter_name = "INPUT"
+ if hasattr(alg, "inputParameterName"):
in_place_input_parameter_name = alg.inputParameterName()
- if in_place and not [d for d in alg.parameterDefinitions() if d.name() not in (in_place_input_parameter_name, 'OUTPUT')]:
+ if in_place and not [
+ d
+ for d in alg.parameterDefinitions()
+ if d.name() not in (in_place_input_parameter_name, "OUTPUT")
+ ]:
parameters = {}
feedback = MessageBarProgress(algname=alg.displayName())
ok, results = execute_in_place(alg, parameters, feedback=feedback)
if ok:
- iface.messageBar().pushSuccess('', self.tr('{algname} completed. %n feature(s) processed.', n=results['__count']).format(algname=alg.displayName()))
+ iface.messageBar().pushSuccess(
+ "",
+ self.tr(
+ "{algname} completed. %n feature(s) processed.",
+ n=results["__count"],
+ ).format(algname=alg.displayName()),
+ )
feedback.close()
# MessageBarProgress handles errors
return
@@ -458,14 +532,20 @@ def sync_in_place_button_state(self, layer=None):
old_enabled_state = self.editInPlaceAction.isEnabled()
- new_enabled_state = layer is not None and layer.type() == QgsMapLayerType.VectorLayer
+ new_enabled_state = (
+ layer is not None and layer.type() == QgsMapLayerType.VectorLayer
+ )
self.editInPlaceAction.setEnabled(new_enabled_state)
if new_enabled_state != old_enabled_state:
- self.toolbox.set_in_place_edit_mode(new_enabled_state and self.editInPlaceAction.isChecked())
+ self.toolbox.set_in_place_edit_mode(
+ new_enabled_state and self.editInPlaceAction.isChecked()
+ )
def openProcessingOptions(self):
- self.iface.showOptionsDialog(self.iface.mainWindow(), currentPage='processingOptions')
+ self.iface.showOptionsDialog(
+ self.iface.mainWindow(), currentPage="processingOptions"
+ )
def unload(self):
for connection in self._gui_connections:
@@ -507,12 +587,12 @@ def unload(self):
self.iface.projectMenu().removeAction(self.projectMenuSeparator)
self.projectMenuSeparator = None
- QgsGui.historyProviderRegistry().providerById('processing').executePython.disconnect(
- self._execute_history_commands
- )
- QgsGui.historyProviderRegistry().providerById('processing').createTest.disconnect(
- self.create_test
- )
+ QgsGui.historyProviderRegistry().providerById(
+ "processing"
+ ).executePython.disconnect(self._execute_history_commands)
+ QgsGui.historyProviderRegistry().providerById(
+ "processing"
+ ).createTest.disconnect(self.create_test)
Processing.deinitialize()
@@ -528,7 +608,7 @@ def openModeler(self):
dlg.show()
def updateModel(self):
- model_provider = QgsApplication.processingRegistry().providerById('model')
+ model_provider = QgsApplication.processingRegistry().providerById("model")
model_provider.refreshAlgorithms()
def openResults(self):
@@ -543,7 +623,9 @@ def openHistory(self):
dlg.show()
def tr(self, message, disambiguation=None, n=-1):
- return QCoreApplication.translate('ProcessingPlugin', message, disambiguation=disambiguation, n=n)
+ return QCoreApplication.translate(
+ "ProcessingPlugin", message, disambiguation=disambiguation, n=n
+ )
def editSelected(self, enabled):
self.toolbox.set_in_place_edit_mode(enabled)
diff --git a/python/plugins/processing/__init__.py b/python/plugins/processing/__init__.py
index 672241adf36b..a343cfe84204 100644
--- a/python/plugins/processing/__init__.py
+++ b/python/plugins/processing/__init__.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'August 2012'
-__copyright__ = '(C) 2012, Victor Olaya'
+__author__ = "Victor Olaya"
+__date__ = "August 2012"
+__copyright__ = "(C) 2012, Victor Olaya"
from processing.tools.dataobjects import * # NOQA
from processing.tools.dataobjects import createContext
@@ -27,7 +27,7 @@
run,
runAndLoadResults,
createAlgorithmDialog,
- execAlgorithmDialog
+ execAlgorithmDialog,
)
from processing.tools.vector import * # NOQA
from processing.tools.raster import * # NOQA
@@ -52,4 +52,5 @@
def classFactory(iface):
from processing.ProcessingPlugin import ProcessingPlugin
+
return ProcessingPlugin(iface)
diff --git a/python/plugins/processing/algs/gdal/AssignProjection.py b/python/plugins/processing/algs/gdal/AssignProjection.py
index c827e074dcf0..837b3b0c6b4f 100644
--- a/python/plugins/processing/algs/gdal/AssignProjection.py
+++ b/python/plugins/processing/algs/gdal/AssignProjection.py
@@ -15,19 +15,21 @@
***************************************************************************
"""
-__author__ = 'Alexander Bruy'
-__date__ = 'January 2016'
-__copyright__ = '(C) 2016, Alexander Bruy'
+__author__ = "Alexander Bruy"
+__date__ = "January 2016"
+__copyright__ = "(C) 2016, Alexander Bruy"
import os
from qgis.PyQt.QtGui import QIcon
-from qgis.core import (QgsProcessingException,
- QgsProcessingParameterRasterLayer,
- QgsProcessingParameterCrs,
- QgsProcessingOutputRasterLayer,
- QgsProcessingContext)
+from qgis.core import (
+ QgsProcessingException,
+ QgsProcessingParameterRasterLayer,
+ QgsProcessingParameterCrs,
+ QgsProcessingOutputRasterLayer,
+ QgsProcessingContext,
+)
from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm
from processing.algs.gdal.GdalUtils import GdalUtils
@@ -37,49 +39,56 @@
class AssignProjection(GdalAlgorithm):
- INPUT = 'INPUT'
- CRS = 'CRS'
- OUTPUT = 'OUTPUT'
+ INPUT = "INPUT"
+ CRS = "CRS"
+ OUTPUT = "OUTPUT"
def __init__(self):
super().__init__()
def initAlgorithm(self, config=None):
- self.addParameter(QgsProcessingParameterRasterLayer(self.INPUT,
- self.tr('Input layer')))
- self.addParameter(QgsProcessingParameterCrs(self.CRS,
- self.tr('Desired CRS')))
+ self.addParameter(
+ QgsProcessingParameterRasterLayer(self.INPUT, self.tr("Input layer"))
+ )
+ self.addParameter(QgsProcessingParameterCrs(self.CRS, self.tr("Desired CRS")))
- self.addOutput(QgsProcessingOutputRasterLayer(self.OUTPUT,
- self.tr('Layer with projection')))
+ self.addOutput(
+ QgsProcessingOutputRasterLayer(
+ self.OUTPUT, self.tr("Layer with projection")
+ )
+ )
def name(self):
- return 'assignprojection'
+ return "assignprojection"
def displayName(self):
- return self.tr('Assign projection')
+ return self.tr("Assign projection")
def icon(self):
- return QIcon(os.path.join(pluginPath, 'images', 'gdaltools', 'projection-add.png'))
+ return QIcon(
+ os.path.join(pluginPath, "images", "gdaltools", "projection-add.png")
+ )
def tags(self):
- tags = self.tr('assign,set,transform,reproject,crs,srs').split(',')
+ tags = self.tr("assign,set,transform,reproject,crs,srs").split(",")
tags.extend(super().tags())
return tags
def group(self):
- return self.tr('Raster projections')
+ return self.tr("Raster projections")
def groupId(self):
- return 'rasterprojections'
+ return "rasterprojections"
def commandName(self):
- return 'gdal_edit'
+ return "gdal_edit"
def getConsoleCommands(self, parameters, context, feedback, executing=True):
inLayer = self.parameterAsRasterLayer(parameters, self.INPUT, context)
if inLayer is None:
- raise QgsProcessingException(self.invalidRasterError(parameters, self.INPUT))
+ raise QgsProcessingException(
+ self.invalidRasterError(parameters, self.INPUT)
+ )
input_details = GdalUtils.gdal_connection_details_from_layer(inLayer)
fileName = inLayer.source()
@@ -87,9 +96,9 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True):
crs = self.parameterAsCrs(parameters, self.CRS, context)
arguments = [
- '-a_srs',
+ "-a_srs",
GdalUtils.gdal_crs_string(crs),
- input_details.connection_string
+ input_details.connection_string,
]
if input_details.open_options:
@@ -100,7 +109,10 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True):
self.setOutputValue(self.OUTPUT, fileName)
- return [self.commandName() + ('.bat' if isWindows() else '.py'), GdalUtils.escapeAndJoin(arguments)]
+ return [
+ self.commandName() + (".bat" if isWindows() else ".py"),
+ GdalUtils.escapeAndJoin(arguments),
+ ]
def postProcessAlgorithm(self, context, feedback):
# get output value
diff --git a/python/plugins/processing/algs/gdal/Buffer.py b/python/plugins/processing/algs/gdal/Buffer.py
index d3f23497bf44..63a97eec98fd 100644
--- a/python/plugins/processing/algs/gdal/Buffer.py
+++ b/python/plugins/processing/algs/gdal/Buffer.py
@@ -15,92 +15,125 @@
***************************************************************************
"""
-__author__ = 'Giovanni Manghi'
-__date__ = 'January 2015'
-__copyright__ = '(C) 2015, Giovanni Manghi'
-
-from qgis.core import (QgsProcessing,
- QgsProcessingParameterDistance,
- QgsProcessingParameterDefinition,
- QgsProcessingParameterFeatureSource,
- QgsProcessingParameterField,
- QgsProcessingParameterString,
- QgsProcessingParameterNumber,
- QgsProcessingException,
- QgsProcessingParameterBoolean,
- QgsProcessingParameterVectorDestination)
+__author__ = "Giovanni Manghi"
+__date__ = "January 2015"
+__copyright__ = "(C) 2015, Giovanni Manghi"
+
+from qgis.core import (
+ QgsProcessing,
+ QgsProcessingParameterDistance,
+ QgsProcessingParameterDefinition,
+ QgsProcessingParameterFeatureSource,
+ QgsProcessingParameterField,
+ QgsProcessingParameterString,
+ QgsProcessingParameterNumber,
+ QgsProcessingException,
+ QgsProcessingParameterBoolean,
+ QgsProcessingParameterVectorDestination,
+)
from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm
from processing.algs.gdal.GdalUtils import GdalUtils
class Buffer(GdalAlgorithm):
- INPUT = 'INPUT'
- FIELD = 'FIELD'
- GEOMETRY = 'GEOMETRY'
- DISTANCE = 'DISTANCE'
- DISSOLVE = 'DISSOLVE'
- EXPLODE_COLLECTIONS = 'EXPLODE_COLLECTIONS'
- OPTIONS = 'OPTIONS'
- OUTPUT = 'OUTPUT'
+ INPUT = "INPUT"
+ FIELD = "FIELD"
+ GEOMETRY = "GEOMETRY"
+ DISTANCE = "DISTANCE"
+ DISSOLVE = "DISSOLVE"
+ EXPLODE_COLLECTIONS = "EXPLODE_COLLECTIONS"
+ OPTIONS = "OPTIONS"
+ OUTPUT = "OUTPUT"
def __init__(self):
super().__init__()
def initAlgorithm(self, config=None):
- self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT,
- self.tr('Input layer')))
- self.addParameter(QgsProcessingParameterString(self.GEOMETRY,
- self.tr('Geometry column name'),
- defaultValue='geometry'))
- self.addParameter(QgsProcessingParameterDistance(self.DISTANCE,
- self.tr('Buffer distance'),
- parentParameterName=self.INPUT,
- defaultValue=10.0))
- self.addParameter(QgsProcessingParameterField(self.FIELD,
- self.tr('Dissolve by attribute'),
- None,
- self.INPUT,
- QgsProcessingParameterField.DataType.Any,
- optional=True))
- self.addParameter(QgsProcessingParameterBoolean(self.DISSOLVE,
- self.tr('Dissolve all results'),
- defaultValue=False))
- self.addParameter(QgsProcessingParameterBoolean(self.EXPLODE_COLLECTIONS,
- self.tr('Produce one feature for each geometry in any kind of geometry collection in the source file'),
- defaultValue=False))
-
- options_param = QgsProcessingParameterString(self.OPTIONS,
- self.tr('Additional creation options'),
- defaultValue='',
- optional=True)
- options_param.setFlags(options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
+ self.addParameter(
+ QgsProcessingParameterFeatureSource(self.INPUT, self.tr("Input layer"))
+ )
+ self.addParameter(
+ QgsProcessingParameterString(
+ self.GEOMETRY, self.tr("Geometry column name"), defaultValue="geometry"
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterDistance(
+ self.DISTANCE,
+ self.tr("Buffer distance"),
+ parentParameterName=self.INPUT,
+ defaultValue=10.0,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterField(
+ self.FIELD,
+ self.tr("Dissolve by attribute"),
+ None,
+ self.INPUT,
+ QgsProcessingParameterField.DataType.Any,
+ optional=True,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterBoolean(
+ self.DISSOLVE, self.tr("Dissolve all results"), defaultValue=False
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterBoolean(
+ self.EXPLODE_COLLECTIONS,
+ self.tr(
+ "Produce one feature for each geometry in any kind of geometry collection in the source file"
+ ),
+ defaultValue=False,
+ )
+ )
+
+ options_param = QgsProcessingParameterString(
+ self.OPTIONS,
+ self.tr("Additional creation options"),
+ defaultValue="",
+ optional=True,
+ )
+ options_param.setFlags(
+ options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
self.addParameter(options_param)
- self.addParameter(QgsProcessingParameterVectorDestination(self.OUTPUT,
- self.tr('Buffer'),
- QgsProcessing.SourceType.TypeVectorPolygon))
+ self.addParameter(
+ QgsProcessingParameterVectorDestination(
+ self.OUTPUT,
+ self.tr("Buffer"),
+ QgsProcessing.SourceType.TypeVectorPolygon,
+ )
+ )
def name(self):
- return 'buffervectors'
+ return "buffervectors"
def displayName(self):
- return self.tr('Buffer vectors')
+ return self.tr("Buffer vectors")
def group(self):
- return self.tr('Vector geoprocessing')
+ return self.tr("Vector geoprocessing")
def groupId(self):
- return 'vectorgeoprocessing'
+ return "vectorgeoprocessing"
def commandName(self):
- return 'ogr2ogr'
+ return "ogr2ogr"
def getConsoleCommands(self, parameters, context, feedback, executing=True):
source = self.parameterAsSource(parameters, self.INPUT, context)
if source is None:
- raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT))
+ raise QgsProcessingException(
+ self.invalidSourceError(parameters, self.INPUT)
+ )
fields = source.fields()
- source_details = self.getOgrCompatibleSource(self.INPUT, parameters, context, feedback, executing)
+ source_details = self.getOgrCompatibleSource(
+ self.INPUT, parameters, context, feedback, executing
+ )
geometry = self.parameterAsString(parameters, self.GEOMETRY, context)
distance = self.parameterAsDouble(parameters, self.DISTANCE, context)
@@ -112,19 +145,16 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True):
output_details = GdalUtils.gdal_connection_details_from_uri(outFile, context)
- other_fields_exist = any(
- True for f in fields
- if f.name() != geometry
- )
+ other_fields_exist = any(True for f in fields if f.name() != geometry)
- other_fields = ',*' if other_fields_exist else ''
+ other_fields = ",*" if other_fields_exist else ""
arguments = [
output_details.connection_string,
source_details.connection_string,
- '-dialect',
- 'sqlite',
- '-sql'
+ "-dialect",
+ "sqlite",
+ "-sql",
]
if dissolve or fieldName:
@@ -138,7 +168,7 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True):
arguments.append(sql)
if self.parameterAsBoolean(parameters, self.EXPLODE_COLLECTIONS, context):
- arguments.append('-explodecollections')
+ arguments.append("-explodecollections")
if source_details.open_options:
arguments.extend(source_details.open_options_as_arguments())
@@ -150,6 +180,6 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True):
arguments.append(options)
if output_details.format:
- arguments.append(f'-f {output_details.format}')
+ arguments.append(f"-f {output_details.format}")
return [self.commandName(), GdalUtils.escapeAndJoin(arguments)]
diff --git a/python/plugins/processing/algs/gdal/ClipRasterByExtent.py b/python/plugins/processing/algs/gdal/ClipRasterByExtent.py
index 399db17a5c60..73db5af85939 100644
--- a/python/plugins/processing/algs/gdal/ClipRasterByExtent.py
+++ b/python/plugins/processing/algs/gdal/ClipRasterByExtent.py
@@ -15,24 +15,26 @@
***************************************************************************
"""
-__author__ = 'Alexander Bruy'
-__date__ = 'September 2013'
-__copyright__ = '(C) 2013, Alexander Bruy'
+__author__ = "Alexander Bruy"
+__date__ = "September 2013"
+__copyright__ = "(C) 2013, Alexander Bruy"
import os
from qgis.PyQt.QtGui import QIcon
-from qgis.core import (QgsRasterFileWriter,
- QgsProcessingException,
- QgsProcessingParameterDefinition,
- QgsProcessingParameterRasterLayer,
- QgsProcessingParameterEnum,
- QgsProcessingParameterExtent,
- QgsProcessingParameterString,
- QgsProcessingParameterNumber,
- QgsProcessingParameterBoolean,
- QgsProcessingParameterRasterDestination)
+from qgis.core import (
+ QgsRasterFileWriter,
+ QgsProcessingException,
+ QgsProcessingParameterDefinition,
+ QgsProcessingParameterRasterLayer,
+ QgsProcessingParameterEnum,
+ QgsProcessingParameterExtent,
+ QgsProcessingParameterString,
+ QgsProcessingParameterNumber,
+ QgsProcessingParameterBoolean,
+ QgsProcessingParameterRasterDestination,
+)
from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm
from processing.algs.gdal.GdalUtils import GdalUtils
@@ -40,75 +42,114 @@
class ClipRasterByExtent(GdalAlgorithm):
- INPUT = 'INPUT'
- EXTENT = 'PROJWIN'
- OVERCRS = 'OVERCRS'
- NODATA = 'NODATA'
- OPTIONS = 'OPTIONS'
- DATA_TYPE = 'DATA_TYPE'
- EXTRA = 'EXTRA'
- OUTPUT = 'OUTPUT'
+ INPUT = "INPUT"
+ EXTENT = "PROJWIN"
+ OVERCRS = "OVERCRS"
+ NODATA = "NODATA"
+ OPTIONS = "OPTIONS"
+ DATA_TYPE = "DATA_TYPE"
+ EXTRA = "EXTRA"
+ OUTPUT = "OUTPUT"
def __init__(self):
super().__init__()
def initAlgorithm(self, config=None):
- self.TYPES = [self.tr('Use Input Layer Data Type'), 'Byte', 'Int16', 'UInt16', 'UInt32', 'Int32', 'Float32', 'Float64', 'CInt16', 'CInt32', 'CFloat32', 'CFloat64', 'Int8']
-
- self.addParameter(QgsProcessingParameterRasterLayer(self.INPUT,
- self.tr('Input layer')))
- self.addParameter(QgsProcessingParameterExtent(self.EXTENT,
- self.tr('Clipping extent')))
- self.addParameter(QgsProcessingParameterBoolean(self.OVERCRS,
- self.tr('Override the projection for the output file'),
- defaultValue=False))
- self.addParameter(QgsProcessingParameterNumber(self.NODATA,
- self.tr('Assign a specified NoData value to output bands'),
- type=QgsProcessingParameterNumber.Type.Double,
- defaultValue=None,
- optional=True))
-
- options_param = QgsProcessingParameterString(self.OPTIONS,
- self.tr('Additional creation options'),
- defaultValue='',
- optional=True)
- options_param.setFlags(options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
- options_param.setMetadata({'widget_wrapper': {'widget_type': 'rasteroptions'}})
+ self.TYPES = [
+ self.tr("Use Input Layer Data Type"),
+ "Byte",
+ "Int16",
+ "UInt16",
+ "UInt32",
+ "Int32",
+ "Float32",
+ "Float64",
+ "CInt16",
+ "CInt32",
+ "CFloat32",
+ "CFloat64",
+ "Int8",
+ ]
+
+ self.addParameter(
+ QgsProcessingParameterRasterLayer(self.INPUT, self.tr("Input layer"))
+ )
+ self.addParameter(
+ QgsProcessingParameterExtent(self.EXTENT, self.tr("Clipping extent"))
+ )
+ self.addParameter(
+ QgsProcessingParameterBoolean(
+ self.OVERCRS,
+ self.tr("Override the projection for the output file"),
+ defaultValue=False,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterNumber(
+ self.NODATA,
+ self.tr("Assign a specified NoData value to output bands"),
+ type=QgsProcessingParameterNumber.Type.Double,
+ defaultValue=None,
+ optional=True,
+ )
+ )
+
+ options_param = QgsProcessingParameterString(
+ self.OPTIONS,
+ self.tr("Additional creation options"),
+ defaultValue="",
+ optional=True,
+ )
+ options_param.setFlags(
+ options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
+ options_param.setMetadata({"widget_wrapper": {"widget_type": "rasteroptions"}})
self.addParameter(options_param)
- dataType_param = QgsProcessingParameterEnum(self.DATA_TYPE,
- self.tr('Output data type'),
- self.TYPES,
- allowMultiple=False,
- defaultValue=0)
- dataType_param.setFlags(dataType_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
+ dataType_param = QgsProcessingParameterEnum(
+ self.DATA_TYPE,
+ self.tr("Output data type"),
+ self.TYPES,
+ allowMultiple=False,
+ defaultValue=0,
+ )
+ dataType_param.setFlags(
+ dataType_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
self.addParameter(dataType_param)
- extra_param = QgsProcessingParameterString(self.EXTRA,
- self.tr('Additional command-line parameters'),
- defaultValue=None,
- optional=True)
- extra_param.setFlags(extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
+ extra_param = QgsProcessingParameterString(
+ self.EXTRA,
+ self.tr("Additional command-line parameters"),
+ defaultValue=None,
+ optional=True,
+ )
+ extra_param.setFlags(
+ extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
self.addParameter(extra_param)
- self.addParameter(QgsProcessingParameterRasterDestination(self.OUTPUT,
- self.tr('Clipped (extent)')))
+ self.addParameter(
+ QgsProcessingParameterRasterDestination(
+ self.OUTPUT, self.tr("Clipped (extent)")
+ )
+ )
def name(self):
- return 'cliprasterbyextent'
+ return "cliprasterbyextent"
def displayName(self):
- return self.tr('Clip raster by extent')
+ return self.tr("Clip raster by extent")
def group(self):
- return self.tr('Raster extraction')
+ return self.tr("Raster extraction")
def groupId(self):
- return 'rasterextraction'
+ return "rasterextraction"
def icon(self):
- return QIcon(os.path.join(pluginPath, 'images', 'gdaltools', 'raster-clip.png'))
+ return QIcon(os.path.join(pluginPath, "images", "gdaltools", "raster-clip.png"))
def commandName(self):
return "gdal_translate"
@@ -116,7 +157,11 @@ def commandName(self):
def getConsoleCommands(self, parameters, context, feedback, executing=True):
inLayer = self.parameterAsRasterLayer(parameters, self.INPUT, context)
if inLayer is None:
- raise QgsProcessingException('Invalid input layer {}'.format(parameters[self.INPUT] if self.INPUT in parameters else 'INPUT'))
+ raise QgsProcessingException(
+ "Invalid input layer {}".format(
+ parameters[self.INPUT] if self.INPUT in parameters else "INPUT"
+ )
+ )
input_details = GdalUtils.gdal_connection_details_from_layer(inLayer)
bbox = self.parameterAsExtent(parameters, self.EXTENT, context, inLayer.crs())
@@ -132,39 +177,43 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True):
arguments = []
if not bbox.isNull():
- arguments.extend([
- '-projwin',
- str(bbox.xMinimum()),
- str(bbox.yMaximum()),
- str(bbox.xMaximum()),
- str(bbox.yMinimum()),
- ])
+ arguments.extend(
+ [
+ "-projwin",
+ str(bbox.xMinimum()),
+ str(bbox.yMaximum()),
+ str(bbox.xMaximum()),
+ str(bbox.yMinimum()),
+ ]
+ )
crs = inLayer.crs()
if override_crs and crs.isValid():
- arguments.append(f'-a_srs {GdalUtils.gdal_crs_string(crs)}')
+ arguments.append(f"-a_srs {GdalUtils.gdal_crs_string(crs)}")
if nodata is not None:
- arguments.append(f'-a_nodata {nodata}')
+ arguments.append(f"-a_nodata {nodata}")
data_type = self.parameterAsEnum(parameters, self.DATA_TYPE, context)
if data_type:
- if self.TYPES[data_type] == 'Int8' and GdalUtils.version() < 3070000:
- raise QgsProcessingException(self.tr('Int8 data type requires GDAL version 3.7 or later'))
+ if self.TYPES[data_type] == "Int8" and GdalUtils.version() < 3070000:
+ raise QgsProcessingException(
+ self.tr("Int8 data type requires GDAL version 3.7 or later")
+ )
- arguments.append('-ot ' + self.TYPES[data_type])
+ arguments.append("-ot " + self.TYPES[data_type])
output_format = QgsRasterFileWriter.driverForExtension(os.path.splitext(out)[1])
if not output_format:
- raise QgsProcessingException(self.tr('Output format is invalid'))
+ raise QgsProcessingException(self.tr("Output format is invalid"))
- arguments.append('-of')
+ arguments.append("-of")
arguments.append(output_format)
if options:
arguments.extend(GdalUtils.parseCreationOptions(options))
- if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ''):
+ if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ""):
extra = self.parameterAsString(parameters, self.EXTRA, context)
arguments.append(extra)
diff --git a/python/plugins/processing/algs/gdal/ClipRasterByMask.py b/python/plugins/processing/algs/gdal/ClipRasterByMask.py
index ba2ec1f4aab7..a05c22ed5f81 100644
--- a/python/plugins/processing/algs/gdal/ClipRasterByMask.py
+++ b/python/plugins/processing/algs/gdal/ClipRasterByMask.py
@@ -15,27 +15,29 @@
***************************************************************************
"""
-__author__ = 'Alexander Bruy'
-__date__ = 'September 2013'
-__copyright__ = '(C) 2013, Alexander Bruy'
+__author__ = "Alexander Bruy"
+__date__ = "September 2013"
+__copyright__ = "(C) 2013, Alexander Bruy"
import os
from qgis.PyQt.QtGui import QIcon
-from qgis.core import (QgsRasterFileWriter,
- QgsProcessing,
- QgsProcessingException,
- QgsProcessingParameterDefinition,
- QgsProcessingParameterFeatureSource,
- QgsProcessingParameterRasterLayer,
- QgsProcessingParameterCrs,
- QgsProcessingParameterEnum,
- QgsProcessingParameterExtent,
- QgsProcessingParameterString,
- QgsProcessingParameterNumber,
- QgsProcessingParameterBoolean,
- QgsProcessingParameterRasterDestination)
+from qgis.core import (
+ QgsRasterFileWriter,
+ QgsProcessing,
+ QgsProcessingException,
+ QgsProcessingParameterDefinition,
+ QgsProcessingParameterFeatureSource,
+ QgsProcessingParameterRasterLayer,
+ QgsProcessingParameterCrs,
+ QgsProcessingParameterEnum,
+ QgsProcessingParameterExtent,
+ QgsProcessingParameterString,
+ QgsProcessingParameterNumber,
+ QgsProcessingParameterBoolean,
+ QgsProcessingParameterRasterDestination,
+)
from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm
from processing.algs.gdal.GdalUtils import GdalUtils
@@ -43,130 +45,209 @@
class ClipRasterByMask(GdalAlgorithm):
- INPUT = 'INPUT'
- MASK = 'MASK'
- SOURCE_CRS = 'SOURCE_CRS'
- TARGET_CRS = 'TARGET_CRS'
- EXTENT = 'TARGET_EXTENT'
- NODATA = 'NODATA'
- ALPHA_BAND = 'ALPHA_BAND'
- CROP_TO_CUTLINE = 'CROP_TO_CUTLINE'
- KEEP_RESOLUTION = 'KEEP_RESOLUTION'
- SET_RESOLUTION = 'SET_RESOLUTION'
- X_RESOLUTION = 'X_RESOLUTION'
- Y_RESOLUTION = 'Y_RESOLUTION'
- OPTIONS = 'OPTIONS'
- DATA_TYPE = 'DATA_TYPE'
- MULTITHREADING = 'MULTITHREADING'
- EXTRA = 'EXTRA'
- OUTPUT = 'OUTPUT'
+ INPUT = "INPUT"
+ MASK = "MASK"
+ SOURCE_CRS = "SOURCE_CRS"
+ TARGET_CRS = "TARGET_CRS"
+ EXTENT = "TARGET_EXTENT"
+ NODATA = "NODATA"
+ ALPHA_BAND = "ALPHA_BAND"
+ CROP_TO_CUTLINE = "CROP_TO_CUTLINE"
+ KEEP_RESOLUTION = "KEEP_RESOLUTION"
+ SET_RESOLUTION = "SET_RESOLUTION"
+ X_RESOLUTION = "X_RESOLUTION"
+ Y_RESOLUTION = "Y_RESOLUTION"
+ OPTIONS = "OPTIONS"
+ DATA_TYPE = "DATA_TYPE"
+ MULTITHREADING = "MULTITHREADING"
+ EXTRA = "EXTRA"
+ OUTPUT = "OUTPUT"
def __init__(self):
super().__init__()
def initAlgorithm(self, config=None):
- self.TYPES = [self.tr('Use Input Layer Data Type'), 'Byte', 'Int16', 'UInt16', 'UInt32', 'Int32', 'Float32', 'Float64', 'CInt16', 'CInt32', 'CFloat32', 'CFloat64', 'Int8']
-
- self.addParameter(QgsProcessingParameterRasterLayer(self.INPUT,
- self.tr('Input layer')))
- self.addParameter(QgsProcessingParameterFeatureSource(self.MASK,
- self.tr('Mask layer'),
- [QgsProcessing.SourceType.TypeVectorPolygon]))
- self.addParameter(QgsProcessingParameterCrs(self.SOURCE_CRS,
- self.tr('Source CRS'),
- optional=True))
- self.addParameter(QgsProcessingParameterCrs(self.TARGET_CRS,
- self.tr('Target CRS'),
- optional=True))
- self.addParameter(QgsProcessingParameterExtent(self.EXTENT,
- self.tr('Target extent'),
- optional=True))
- self.addParameter(QgsProcessingParameterNumber(self.NODATA,
- self.tr('Assign a specified NoData value to output bands'),
- type=QgsProcessingParameterNumber.Type.Double,
- defaultValue=None,
- optional=True))
- self.addParameter(QgsProcessingParameterBoolean(self.ALPHA_BAND,
- self.tr('Create an output alpha band'),
- defaultValue=False))
- self.addParameter(QgsProcessingParameterBoolean(self.CROP_TO_CUTLINE,
- self.tr('Match the extent of the clipped raster to the extent of the mask layer'),
- defaultValue=True))
- self.addParameter(QgsProcessingParameterBoolean(self.KEEP_RESOLUTION,
- self.tr('Keep resolution of input raster'),
- defaultValue=False))
- self.addParameter(QgsProcessingParameterBoolean(self.SET_RESOLUTION,
- self.tr('Set output file resolution'),
- defaultValue=False))
- self.addParameter(QgsProcessingParameterNumber(self.X_RESOLUTION,
- self.tr('X Resolution to output bands'),
- type=QgsProcessingParameterNumber.Type.Double,
- defaultValue=None,
- optional=True))
- self.addParameter(QgsProcessingParameterNumber(self.Y_RESOLUTION,
- self.tr('Y Resolution to output bands'),
- type=QgsProcessingParameterNumber.Type.Double,
- defaultValue=None,
- optional=True))
-
- multithreading_param = QgsProcessingParameterBoolean(self.MULTITHREADING,
- self.tr('Use multithreaded warping implementation'),
- defaultValue=False)
- multithreading_param.setFlags(multithreading_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
+ self.TYPES = [
+ self.tr("Use Input Layer Data Type"),
+ "Byte",
+ "Int16",
+ "UInt16",
+ "UInt32",
+ "Int32",
+ "Float32",
+ "Float64",
+ "CInt16",
+ "CInt32",
+ "CFloat32",
+ "CFloat64",
+ "Int8",
+ ]
+
+ self.addParameter(
+ QgsProcessingParameterRasterLayer(self.INPUT, self.tr("Input layer"))
+ )
+ self.addParameter(
+ QgsProcessingParameterFeatureSource(
+ self.MASK,
+ self.tr("Mask layer"),
+ [QgsProcessing.SourceType.TypeVectorPolygon],
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterCrs(
+ self.SOURCE_CRS, self.tr("Source CRS"), optional=True
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterCrs(
+ self.TARGET_CRS, self.tr("Target CRS"), optional=True
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterExtent(
+ self.EXTENT, self.tr("Target extent"), optional=True
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterNumber(
+ self.NODATA,
+ self.tr("Assign a specified NoData value to output bands"),
+ type=QgsProcessingParameterNumber.Type.Double,
+ defaultValue=None,
+ optional=True,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterBoolean(
+ self.ALPHA_BAND,
+ self.tr("Create an output alpha band"),
+ defaultValue=False,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterBoolean(
+ self.CROP_TO_CUTLINE,
+ self.tr(
+ "Match the extent of the clipped raster to the extent of the mask layer"
+ ),
+ defaultValue=True,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterBoolean(
+ self.KEEP_RESOLUTION,
+ self.tr("Keep resolution of input raster"),
+ defaultValue=False,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterBoolean(
+ self.SET_RESOLUTION,
+ self.tr("Set output file resolution"),
+ defaultValue=False,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterNumber(
+ self.X_RESOLUTION,
+ self.tr("X Resolution to output bands"),
+ type=QgsProcessingParameterNumber.Type.Double,
+ defaultValue=None,
+ optional=True,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterNumber(
+ self.Y_RESOLUTION,
+ self.tr("Y Resolution to output bands"),
+ type=QgsProcessingParameterNumber.Type.Double,
+ defaultValue=None,
+ optional=True,
+ )
+ )
+
+ multithreading_param = QgsProcessingParameterBoolean(
+ self.MULTITHREADING,
+ self.tr("Use multithreaded warping implementation"),
+ defaultValue=False,
+ )
+ multithreading_param.setFlags(
+ multithreading_param.flags()
+ | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
self.addParameter(multithreading_param)
- options_param = QgsProcessingParameterString(self.OPTIONS,
- self.tr('Additional creation options'),
- defaultValue='',
- optional=True)
- options_param.setFlags(options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
- options_param.setMetadata({'widget_wrapper': {'widget_type': 'rasteroptions'}})
+ options_param = QgsProcessingParameterString(
+ self.OPTIONS,
+ self.tr("Additional creation options"),
+ defaultValue="",
+ optional=True,
+ )
+ options_param.setFlags(
+ options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
+ options_param.setMetadata({"widget_wrapper": {"widget_type": "rasteroptions"}})
self.addParameter(options_param)
- dataType_param = QgsProcessingParameterEnum(self.DATA_TYPE,
- self.tr('Output data type'),
- self.TYPES,
- allowMultiple=False,
- defaultValue=0)
- dataType_param.setFlags(dataType_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
+ dataType_param = QgsProcessingParameterEnum(
+ self.DATA_TYPE,
+ self.tr("Output data type"),
+ self.TYPES,
+ allowMultiple=False,
+ defaultValue=0,
+ )
+ dataType_param.setFlags(
+ dataType_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
self.addParameter(dataType_param)
- extra_param = QgsProcessingParameterString(self.EXTRA,
- self.tr('Additional command-line parameters'),
- defaultValue=None,
- optional=True)
- extra_param.setFlags(extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
+ extra_param = QgsProcessingParameterString(
+ self.EXTRA,
+ self.tr("Additional command-line parameters"),
+ defaultValue=None,
+ optional=True,
+ )
+ extra_param.setFlags(
+ extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
self.addParameter(extra_param)
- self.addParameter(QgsProcessingParameterRasterDestination(self.OUTPUT,
- self.tr('Clipped (mask)')))
+ self.addParameter(
+ QgsProcessingParameterRasterDestination(
+ self.OUTPUT, self.tr("Clipped (mask)")
+ )
+ )
def name(self):
- return 'cliprasterbymasklayer'
+ return "cliprasterbymasklayer"
def displayName(self):
- return self.tr('Clip raster by mask layer')
+ return self.tr("Clip raster by mask layer")
def icon(self):
- return QIcon(os.path.join(pluginPath, 'images', 'gdaltools', 'raster-clip.png'))
+ return QIcon(os.path.join(pluginPath, "images", "gdaltools", "raster-clip.png"))
def group(self):
- return self.tr('Raster extraction')
+ return self.tr("Raster extraction")
def groupId(self):
- return 'rasterextraction'
+ return "rasterextraction"
def commandName(self):
- return 'gdalwarp'
+ return "gdalwarp"
def getConsoleCommands(self, parameters, context, feedback, executing=True):
inLayer = self.parameterAsRasterLayer(parameters, self.INPUT, context)
if inLayer is None:
- raise QgsProcessingException(self.invalidRasterError(parameters, self.INPUT))
+ raise QgsProcessingException(
+ self.invalidRasterError(parameters, self.INPUT)
+ )
input_details = GdalUtils.gdal_connection_details_from_layer(inLayer)
- mask_details = self.getOgrCompatibleSource(self.MASK, parameters, context, feedback, executing)
+ mask_details = self.getOgrCompatibleSource(
+ self.MASK, parameters, context, feedback, executing
+ )
sourceCrs = self.parameterAsCrs(parameters, self.SOURCE_CRS, context)
targetCrs = self.parameterAsCrs(parameters, self.TARGET_CRS, context)
@@ -182,80 +263,88 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True):
out = self.parameterAsOutputLayer(parameters, self.OUTPUT, context)
self.setOutputValue(self.OUTPUT, out)
- arguments = ['-overwrite']
+ arguments = ["-overwrite"]
if sourceCrs.isValid():
- arguments.append('-s_srs')
+ arguments.append("-s_srs")
arguments.append(GdalUtils.gdal_crs_string(sourceCrs))
if targetCrs.isValid():
- arguments.append('-t_srs')
+ arguments.append("-t_srs")
arguments.append(GdalUtils.gdal_crs_string(targetCrs))
if not bbox.isNull():
- arguments.append('-te')
+ arguments.append("-te")
arguments.append(str(bbox.xMinimum()))
arguments.append(str(bbox.yMinimum()))
arguments.append(str(bbox.xMaximum()))
arguments.append(str(bbox.yMaximum()))
- arguments.append('-te_srs')
+ arguments.append("-te_srs")
arguments.append(GdalUtils.gdal_crs_string(bboxCrs))
data_type = self.parameterAsEnum(parameters, self.DATA_TYPE, context)
if data_type:
- if self.TYPES[data_type] == 'Int8' and GdalUtils.version() < 3070000:
- raise QgsProcessingException(self.tr('Int8 data type requires GDAL version 3.7 or later'))
+ if self.TYPES[data_type] == "Int8" and GdalUtils.version() < 3070000:
+ raise QgsProcessingException(
+ self.tr("Int8 data type requires GDAL version 3.7 or later")
+ )
- arguments.append('-ot ' + self.TYPES[data_type])
+ arguments.append("-ot " + self.TYPES[data_type])
output_format = QgsRasterFileWriter.driverForExtension(os.path.splitext(out)[1])
if not output_format:
- raise QgsProcessingException(self.tr('Output format is invalid'))
+ raise QgsProcessingException(self.tr("Output format is invalid"))
- arguments.append('-of')
+ arguments.append("-of")
arguments.append(output_format)
if self.parameterAsBoolean(parameters, self.KEEP_RESOLUTION, context):
- arguments.append('-tr')
+ arguments.append("-tr")
arguments.append(str(inLayer.rasterUnitsPerPixelX()))
arguments.append(str(-inLayer.rasterUnitsPerPixelY()))
- arguments.append('-tap')
+ arguments.append("-tap")
if self.parameterAsBoolean(parameters, self.SET_RESOLUTION, context):
- arguments.append('-tr')
- if self.X_RESOLUTION in parameters and parameters[self.X_RESOLUTION] is not None:
+ arguments.append("-tr")
+ if (
+ self.X_RESOLUTION in parameters
+ and parameters[self.X_RESOLUTION] is not None
+ ):
xres = self.parameterAsDouble(parameters, self.X_RESOLUTION, context)
- arguments.append(f'{xres}')
+ arguments.append(f"{xres}")
else:
arguments.append(str(inLayer.rasterUnitsPerPixelX()))
- if self.Y_RESOLUTION in parameters and parameters[self.Y_RESOLUTION] is not None:
+ if (
+ self.Y_RESOLUTION in parameters
+ and parameters[self.Y_RESOLUTION] is not None
+ ):
yres = self.parameterAsDouble(parameters, self.Y_RESOLUTION, context)
- arguments.append(f'{yres}')
+ arguments.append(f"{yres}")
else:
arguments.append(str(-inLayer.rasterUnitsPerPixelY()))
- arguments.append('-tap')
+ arguments.append("-tap")
- arguments.append('-cutline')
+ arguments.append("-cutline")
arguments.append(mask_details.connection_string)
- arguments.append('-cl')
+ arguments.append("-cl")
arguments.append(mask_details.layer_name)
if self.parameterAsBoolean(parameters, self.CROP_TO_CUTLINE, context):
- arguments.append('-crop_to_cutline')
+ arguments.append("-crop_to_cutline")
if self.parameterAsBoolean(parameters, self.ALPHA_BAND, context):
- arguments.append('-dstalpha')
+ arguments.append("-dstalpha")
if nodata is not None:
- arguments.append(f'-dstnodata {nodata}')
+ arguments.append(f"-dstnodata {nodata}")
if self.parameterAsBoolean(parameters, self.MULTITHREADING, context):
- arguments.append('-multi')
+ arguments.append("-multi")
if options:
arguments.extend(GdalUtils.parseCreationOptions(options))
- if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ''):
+ if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ""):
extra = self.parameterAsString(parameters, self.EXTRA, context)
arguments.append(extra)
diff --git a/python/plugins/processing/algs/gdal/ClipVectorByExtent.py b/python/plugins/processing/algs/gdal/ClipVectorByExtent.py
index 6d739ed3ded4..5676a92ae0c0 100644
--- a/python/plugins/processing/algs/gdal/ClipVectorByExtent.py
+++ b/python/plugins/processing/algs/gdal/ClipVectorByExtent.py
@@ -15,86 +15,100 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'November 2012'
-__copyright__ = '(C) 2012, Victor Olaya'
-
-from qgis.core import (QgsProcessingException,
- QgsProcessingParameterDefinition,
- QgsProcessingParameterFeatureSource,
- QgsProcessingParameterExtent,
- QgsProcessingParameterString,
- QgsProcessingParameterVectorDestination)
+__author__ = "Victor Olaya"
+__date__ = "November 2012"
+__copyright__ = "(C) 2012, Victor Olaya"
+
+from qgis.core import (
+ QgsProcessingException,
+ QgsProcessingParameterDefinition,
+ QgsProcessingParameterFeatureSource,
+ QgsProcessingParameterExtent,
+ QgsProcessingParameterString,
+ QgsProcessingParameterVectorDestination,
+)
from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm
from processing.algs.gdal.GdalUtils import GdalUtils
class ClipVectorByExtent(GdalAlgorithm):
- INPUT = 'INPUT'
- EXTENT = 'EXTENT'
- OPTIONS = 'OPTIONS'
- OUTPUT = 'OUTPUT'
+ INPUT = "INPUT"
+ EXTENT = "EXTENT"
+ OPTIONS = "OPTIONS"
+ OUTPUT = "OUTPUT"
def __init__(self):
super().__init__()
def initAlgorithm(self, config=None):
- self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT,
- self.tr('Input layer')))
- self.addParameter(QgsProcessingParameterExtent(self.EXTENT,
- self.tr('Clipping extent')))
-
- options_param = QgsProcessingParameterString(self.OPTIONS,
- self.tr('Additional creation options'),
- defaultValue='',
- optional=True)
- options_param.setFlags(options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
+ self.addParameter(
+ QgsProcessingParameterFeatureSource(self.INPUT, self.tr("Input layer"))
+ )
+ self.addParameter(
+ QgsProcessingParameterExtent(self.EXTENT, self.tr("Clipping extent"))
+ )
+
+ options_param = QgsProcessingParameterString(
+ self.OPTIONS,
+ self.tr("Additional creation options"),
+ defaultValue="",
+ optional=True,
+ )
+ options_param.setFlags(
+ options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
self.addParameter(options_param)
- self.addParameter(QgsProcessingParameterVectorDestination(self.OUTPUT,
- self.tr('Clipped (extent)')))
+ self.addParameter(
+ QgsProcessingParameterVectorDestination(
+ self.OUTPUT, self.tr("Clipped (extent)")
+ )
+ )
def name(self):
- return 'clipvectorbyextent'
+ return "clipvectorbyextent"
def displayName(self):
- return self.tr('Clip vector by extent')
+ return self.tr("Clip vector by extent")
def group(self):
- return self.tr('Vector geoprocessing')
+ return self.tr("Vector geoprocessing")
def groupId(self):
- return 'vectorgeoprocessing'
+ return "vectorgeoprocessing"
def commandName(self):
- return 'ogr2ogr'
+ return "ogr2ogr"
def getConsoleCommands(self, parameters, context, feedback, executing=True):
- input_details = self.getOgrCompatibleSource(self.INPUT, parameters, context, feedback, executing)
+ input_details = self.getOgrCompatibleSource(
+ self.INPUT, parameters, context, feedback, executing
+ )
source = self.parameterAsSource(parameters, self.INPUT, context)
if source is None:
- raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT))
+ raise QgsProcessingException(
+ self.invalidSourceError(parameters, self.INPUT)
+ )
- extent = self.parameterAsExtent(parameters, self.EXTENT, context, source.sourceCrs())
+ extent = self.parameterAsExtent(
+ parameters, self.EXTENT, context, source.sourceCrs()
+ )
options = self.parameterAsString(parameters, self.OPTIONS, context)
outFile = self.parameterAsOutputLayer(parameters, self.OUTPUT, context)
self.setOutputValue(self.OUTPUT, outFile)
- output_details = GdalUtils.gdal_connection_details_from_uri(
- outFile,
- context)
+ output_details = GdalUtils.gdal_connection_details_from_uri(outFile, context)
arguments = [
- '-spat',
+ "-spat",
str(extent.xMinimum()),
str(extent.yMaximum()),
str(extent.xMaximum()),
str(extent.yMinimum()),
- '-clipsrc spat_extent',
-
+ "-clipsrc spat_extent",
output_details.connection_string,
input_details.connection_string,
- input_details.layer_name
+ input_details.layer_name,
]
if input_details.open_options:
@@ -107,6 +121,6 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True):
arguments.append(options)
if output_details.format:
- arguments.append(f'-f {output_details.format}')
+ arguments.append(f"-f {output_details.format}")
return [self.commandName(), GdalUtils.escapeAndJoin(arguments)]
diff --git a/python/plugins/processing/algs/gdal/ClipVectorByMask.py b/python/plugins/processing/algs/gdal/ClipVectorByMask.py
index 8401d640ddc4..cdf4793c8cc0 100644
--- a/python/plugins/processing/algs/gdal/ClipVectorByMask.py
+++ b/python/plugins/processing/algs/gdal/ClipVectorByMask.py
@@ -15,67 +15,88 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'November 2012'
-__copyright__ = '(C) 2012, Victor Olaya'
-
-from qgis.core import (QgsProcessing,
- QgsProcessingAlgorithm,
- QgsProcessingParameterDefinition,
- QgsProcessingParameterString,
- QgsProcessingParameterFeatureSource,
- QgsProcessingParameterVectorDestination)
+__author__ = "Victor Olaya"
+__date__ = "November 2012"
+__copyright__ = "(C) 2012, Victor Olaya"
+
+from qgis.core import (
+ QgsProcessing,
+ QgsProcessingAlgorithm,
+ QgsProcessingParameterDefinition,
+ QgsProcessingParameterString,
+ QgsProcessingParameterFeatureSource,
+ QgsProcessingParameterVectorDestination,
+)
from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm
from processing.algs.gdal.GdalUtils import GdalUtils
class ClipVectorByMask(GdalAlgorithm):
- INPUT = 'INPUT'
- MASK = 'MASK'
- OPTIONS = 'OPTIONS'
- OUTPUT = 'OUTPUT'
+ INPUT = "INPUT"
+ MASK = "MASK"
+ OPTIONS = "OPTIONS"
+ OUTPUT = "OUTPUT"
def __init__(self):
super().__init__()
def flags(self):
- return QgsProcessingAlgorithm.Flag.FlagSupportsBatch | QgsProcessingAlgorithm.Flag.FlagRequiresMatchingCrs # cannot cancel!
+ return (
+ QgsProcessingAlgorithm.Flag.FlagSupportsBatch
+ | QgsProcessingAlgorithm.Flag.FlagRequiresMatchingCrs
+ ) # cannot cancel!
def initAlgorithm(self, config=None):
- self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT,
- self.tr('Input layer')))
- self.addParameter(QgsProcessingParameterFeatureSource(self.MASK,
- self.tr('Mask layer'),
- [QgsProcessing.SourceType.TypeVectorPolygon]))
-
- options_param = QgsProcessingParameterString(self.OPTIONS,
- self.tr('Additional creation options'),
- defaultValue='',
- optional=True)
- options_param.setFlags(options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
+ self.addParameter(
+ QgsProcessingParameterFeatureSource(self.INPUT, self.tr("Input layer"))
+ )
+ self.addParameter(
+ QgsProcessingParameterFeatureSource(
+ self.MASK,
+ self.tr("Mask layer"),
+ [QgsProcessing.SourceType.TypeVectorPolygon],
+ )
+ )
+
+ options_param = QgsProcessingParameterString(
+ self.OPTIONS,
+ self.tr("Additional creation options"),
+ defaultValue="",
+ optional=True,
+ )
+ options_param.setFlags(
+ options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
self.addParameter(options_param)
- self.addParameter(QgsProcessingParameterVectorDestination(self.OUTPUT,
- self.tr('Clipped (mask)')))
+ self.addParameter(
+ QgsProcessingParameterVectorDestination(
+ self.OUTPUT, self.tr("Clipped (mask)")
+ )
+ )
def name(self):
- return 'clipvectorbypolygon'
+ return "clipvectorbypolygon"
def displayName(self):
- return self.tr('Clip vector by mask layer')
+ return self.tr("Clip vector by mask layer")
def group(self):
- return self.tr('Vector geoprocessing')
+ return self.tr("Vector geoprocessing")
def groupId(self):
- return 'vectorgeoprocessing'
+ return "vectorgeoprocessing"
def commandName(self):
- return 'ogr2ogr'
+ return "ogr2ogr"
def getConsoleCommands(self, parameters, context, feedback, executing=True):
- input_details = self.getOgrCompatibleSource(self.INPUT, parameters, context, feedback, executing)
- mask_details = self.getOgrCompatibleSource(self.MASK, parameters, context, feedback, executing)
+ input_details = self.getOgrCompatibleSource(
+ self.INPUT, parameters, context, feedback, executing
+ )
+ mask_details = self.getOgrCompatibleSource(
+ self.MASK, parameters, context, feedback, executing
+ )
options = self.parameterAsString(parameters, self.OPTIONS, context)
outFile = self.parameterAsOutputLayer(parameters, self.OUTPUT, context)
self.setOutputValue(self.OUTPUT, outFile)
@@ -83,11 +104,10 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True):
output_details = GdalUtils.gdal_connection_details_from_uri(outFile, context)
arguments = [
- '-clipsrc',
+ "-clipsrc",
mask_details.connection_string,
- '-clipsrclayer',
+ "-clipsrclayer",
mask_details.layer_name,
-
output_details.connection_string,
input_details.connection_string,
input_details.layer_name,
@@ -103,6 +123,6 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True):
arguments.append(options)
if output_details.format:
- arguments.append(f'-f {output_details.format}')
+ arguments.append(f"-f {output_details.format}")
return [self.commandName(), GdalUtils.escapeAndJoin(arguments)]
diff --git a/python/plugins/processing/algs/gdal/ColorRelief.py b/python/plugins/processing/algs/gdal/ColorRelief.py
index e8f5f93fc905..4a1c2303f527 100644
--- a/python/plugins/processing/algs/gdal/ColorRelief.py
+++ b/python/plugins/processing/algs/gdal/ColorRelief.py
@@ -15,96 +15,128 @@
***************************************************************************
"""
-__author__ = 'Alexander Bruy'
-__date__ = 'October 2013'
-__copyright__ = '(C) 2013, Alexander Bruy'
+__author__ = "Alexander Bruy"
+__date__ = "October 2013"
+__copyright__ = "(C) 2013, Alexander Bruy"
import os
-from qgis.core import (QgsRasterFileWriter,
- QgsProcessingException,
- QgsProcessingParameterDefinition,
- QgsProcessingParameterRasterLayer,
- QgsProcessingParameterBand,
- QgsProcessingParameterBoolean,
- QgsProcessingParameterEnum,
- QgsProcessingParameterFile,
- QgsProcessingParameterString,
- QgsProcessingParameterRasterDestination)
+from qgis.core import (
+ QgsRasterFileWriter,
+ QgsProcessingException,
+ QgsProcessingParameterDefinition,
+ QgsProcessingParameterRasterLayer,
+ QgsProcessingParameterBand,
+ QgsProcessingParameterBoolean,
+ QgsProcessingParameterEnum,
+ QgsProcessingParameterFile,
+ QgsProcessingParameterString,
+ QgsProcessingParameterRasterDestination,
+)
from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm
from processing.algs.gdal.GdalUtils import GdalUtils
class ColorRelief(GdalAlgorithm):
- INPUT = 'INPUT'
- BAND = 'BAND'
- COMPUTE_EDGES = 'COMPUTE_EDGES'
- COLOR_TABLE = 'COLOR_TABLE'
- MATCH_MODE = 'MATCH_MODE'
- OPTIONS = 'OPTIONS'
- EXTRA = 'EXTRA'
- OUTPUT = 'OUTPUT'
+ INPUT = "INPUT"
+ BAND = "BAND"
+ COMPUTE_EDGES = "COMPUTE_EDGES"
+ COLOR_TABLE = "COLOR_TABLE"
+ MATCH_MODE = "MATCH_MODE"
+ OPTIONS = "OPTIONS"
+ EXTRA = "EXTRA"
+ OUTPUT = "OUTPUT"
def __init__(self):
super().__init__()
def initAlgorithm(self, config=None):
- self.modes = ((self.tr('Use strict color matching'), '-exact_color_entry'),
- (self.tr('Use closest RGBA quadruplet'), '-nearest_color_entry'),
- (self.tr('Use smoothly blended colors'), ''))
-
- self.addParameter(QgsProcessingParameterRasterLayer(self.INPUT,
- self.tr('Input layer')))
- self.addParameter(QgsProcessingParameterBand(self.BAND,
- self.tr('Band number'),
- 1,
- parentLayerParameterName=self.INPUT))
- self.addParameter(QgsProcessingParameterBoolean(self.COMPUTE_EDGES,
- self.tr('Compute edges'),
- defaultValue=False))
- self.addParameter(QgsProcessingParameterFile(self.COLOR_TABLE,
- self.tr('Color configuration file')))
- self.addParameter(QgsProcessingParameterEnum(self.MATCH_MODE,
- self.tr('Matching mode'),
- options=[i[0] for i in self.modes],
- defaultValue=2))
-
- options_param = QgsProcessingParameterString(self.OPTIONS,
- self.tr('Additional creation options'),
- defaultValue='',
- optional=True)
- options_param.setFlags(options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
- options_param.setMetadata({'widget_wrapper': {'widget_type': 'rasteroptions'}})
+ self.modes = (
+ (self.tr("Use strict color matching"), "-exact_color_entry"),
+ (self.tr("Use closest RGBA quadruplet"), "-nearest_color_entry"),
+ (self.tr("Use smoothly blended colors"), ""),
+ )
+
+ self.addParameter(
+ QgsProcessingParameterRasterLayer(self.INPUT, self.tr("Input layer"))
+ )
+ self.addParameter(
+ QgsProcessingParameterBand(
+ self.BAND,
+ self.tr("Band number"),
+ 1,
+ parentLayerParameterName=self.INPUT,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterBoolean(
+ self.COMPUTE_EDGES, self.tr("Compute edges"), defaultValue=False
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterFile(
+ self.COLOR_TABLE, self.tr("Color configuration file")
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterEnum(
+ self.MATCH_MODE,
+ self.tr("Matching mode"),
+ options=[i[0] for i in self.modes],
+ defaultValue=2,
+ )
+ )
+
+ options_param = QgsProcessingParameterString(
+ self.OPTIONS,
+ self.tr("Additional creation options"),
+ defaultValue="",
+ optional=True,
+ )
+ options_param.setFlags(
+ options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
+ options_param.setMetadata({"widget_wrapper": {"widget_type": "rasteroptions"}})
self.addParameter(options_param)
- extra_param = QgsProcessingParameterString(self.EXTRA,
- self.tr('Additional command-line parameters'),
- defaultValue=None,
- optional=True)
- extra_param.setFlags(extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
+ extra_param = QgsProcessingParameterString(
+ self.EXTRA,
+ self.tr("Additional command-line parameters"),
+ defaultValue=None,
+ optional=True,
+ )
+ extra_param.setFlags(
+ extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
self.addParameter(extra_param)
- self.addParameter(QgsProcessingParameterRasterDestination(self.OUTPUT, self.tr('Color relief')))
+ self.addParameter(
+ QgsProcessingParameterRasterDestination(
+ self.OUTPUT, self.tr("Color relief")
+ )
+ )
def name(self):
- return 'colorrelief'
+ return "colorrelief"
def displayName(self):
- return self.tr('Color relief')
+ return self.tr("Color relief")
def group(self):
- return self.tr('Raster analysis')
+ return self.tr("Raster analysis")
def groupId(self):
- return 'rasteranalysis'
+ return "rasteranalysis"
def commandName(self):
- return 'gdaldem'
+ return "gdaldem"
def getConsoleCommands(self, parameters, context, feedback, executing=True):
- arguments = ['color-relief']
+ arguments = ["color-relief"]
inLayer = self.parameterAsRasterLayer(parameters, self.INPUT, context)
if inLayer is None:
- raise QgsProcessingException(self.invalidRasterError(parameters, self.INPUT))
+ raise QgsProcessingException(
+ self.invalidRasterError(parameters, self.INPUT)
+ )
input_details = GdalUtils.gdal_connection_details_from_layer(inLayer)
arguments.append(input_details.connection_string)
@@ -116,19 +148,19 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True):
output_format = QgsRasterFileWriter.driverForExtension(os.path.splitext(out)[1])
if not output_format:
- raise QgsProcessingException(self.tr('Output format is invalid'))
+ raise QgsProcessingException(self.tr("Output format is invalid"))
- arguments.append('-of')
+ arguments.append("-of")
arguments.append(output_format)
- arguments.append('-b')
+ arguments.append("-b")
arguments.append(str(self.parameterAsInt(parameters, self.BAND, context)))
if self.parameterAsBoolean(parameters, self.COMPUTE_EDGES, context):
- arguments.append('-compute_edges')
+ arguments.append("-compute_edges")
mode = self.modes[self.parameterAsEnum(parameters, self.MATCH_MODE, context)][1]
- if mode != '':
+ if mode != "":
arguments.append(mode)
options = self.parameterAsString(parameters, self.OPTIONS, context)
@@ -138,7 +170,7 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True):
if input_details.credential_options:
arguments.extend(input_details.credential_options_as_arguments())
- if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ''):
+ if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ""):
extra = self.parameterAsString(parameters, self.EXTRA, context)
arguments.append(extra)
diff --git a/python/plugins/processing/algs/gdal/Datasources2Vrt.py b/python/plugins/processing/algs/gdal/Datasources2Vrt.py
index b8a90f561609..7ea5b8f0092d 100644
--- a/python/plugins/processing/algs/gdal/Datasources2Vrt.py
+++ b/python/plugins/processing/algs/gdal/Datasources2Vrt.py
@@ -15,63 +15,72 @@
***************************************************************************
"""
-__author__ = 'Luigi Pirelli'
-__date__ = 'May 2015'
-__copyright__ = '(C) 2015, Luigi Pirelli'
+__author__ = "Luigi Pirelli"
+__date__ = "May 2015"
+__copyright__ = "(C) 2015, Luigi Pirelli"
import html
import pathlib
from qgis.PyQt.QtCore import QCoreApplication
-from qgis.core import (QgsProcessing,
- QgsProcessingException,
- QgsProcessingParameterMultipleLayers,
- QgsProcessingParameterBoolean,
- QgsProcessingParameterVectorDestination,
- QgsProcessingOutputString,
- QgsProcessingParameters
- )
+from qgis.core import (
+ QgsProcessing,
+ QgsProcessingException,
+ QgsProcessingParameterMultipleLayers,
+ QgsProcessingParameterBoolean,
+ QgsProcessingParameterVectorDestination,
+ QgsProcessingOutputString,
+ QgsProcessingParameters,
+)
from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm
from processing.algs.gdal.GdalUtils import GdalUtils
class Datasources2Vrt(GdalAlgorithm):
- INPUT = 'INPUT'
- UNIONED = 'UNIONED'
- OUTPUT = 'OUTPUT'
- VRT_STRING = 'VRT_STRING'
+ INPUT = "INPUT"
+ UNIONED = "UNIONED"
+ OUTPUT = "OUTPUT"
+ VRT_STRING = "VRT_STRING"
def createCustomParametersWidget(self, parent):
return None
def group(self):
- return self.tr('Vector miscellaneous')
+ return self.tr("Vector miscellaneous")
def groupId(self):
- return 'vectormiscellaneous'
+ return "vectormiscellaneous"
def name(self):
- return 'buildvirtualvector'
+ return "buildvirtualvector"
def displayName(self):
- return self.tr('Build virtual vector')
+ return self.tr("Build virtual vector")
def tags(self):
- return ['ogr', 'gdal', 'vrt', 'create']
+ return ["ogr", "gdal", "vrt", "create"]
def shortHelpString(self):
- return self.tr("This algorithm creates a virtual layer that contains a set of vector layers.")
+ return self.tr(
+ "This algorithm creates a virtual layer that contains a set of vector layers."
+ )
def __init__(self):
super().__init__()
def initAlgorithm(self, config=None):
- self.addParameter(QgsProcessingParameterMultipleLayers(self.INPUT,
- self.tr('Input datasources'),
- QgsProcessing.SourceType.TypeVector))
- self.addParameter(QgsProcessingParameterBoolean(self.UNIONED,
- self.tr('Create "unioned" VRT'),
- defaultValue=False))
+ self.addParameter(
+ QgsProcessingParameterMultipleLayers(
+ self.INPUT,
+ self.tr("Input datasources"),
+ QgsProcessing.SourceType.TypeVector,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterBoolean(
+ self.UNIONED, self.tr('Create "unioned" VRT'), defaultValue=False
+ )
+ )
class ParameterVectorVrtDestination(QgsProcessingParameterVectorDestination):
@@ -83,31 +92,39 @@ def clone(self):
return copy
def defaultFileExtension(self):
- return 'vrt'
+ return "vrt"
def createFileFilter(self):
- return '{} (*.vrt *.VRT)'.format(QCoreApplication.translate("GdalAlgorithm", 'VRT files'))
+ return "{} (*.vrt *.VRT)".format(
+ QCoreApplication.translate("GdalAlgorithm", "VRT files")
+ )
def supportedOutputRasterLayerExtensions(self):
- return ['vrt']
+ return ["vrt"]
def isSupportedOutputValue(self, value, context):
- output_path = QgsProcessingParameters.parameterAsOutputLayer(self, value, context, testOnly=True)
- if pathlib.Path(output_path).suffix.lower() != '.vrt':
- return False, QCoreApplication.translate("GdalAlgorithm", 'Output filename must use a .vrt extension')
- return True, ''
-
- self.addParameter(ParameterVectorVrtDestination(self.OUTPUT,
- self.tr('Virtual vector')))
- self.addOutput(QgsProcessingOutputString(self.VRT_STRING,
- self.tr('Virtual string')))
+ output_path = QgsProcessingParameters.parameterAsOutputLayer(
+ self, value, context, testOnly=True
+ )
+ if pathlib.Path(output_path).suffix.lower() != ".vrt":
+ return False, QCoreApplication.translate(
+ "GdalAlgorithm", "Output filename must use a .vrt extension"
+ )
+ return True, ""
+
+ self.addParameter(
+ ParameterVectorVrtDestination(self.OUTPUT, self.tr("Virtual vector"))
+ )
+ self.addOutput(
+ QgsProcessingOutputString(self.VRT_STRING, self.tr("Virtual string"))
+ )
def processAlgorithm(self, parameters, context, feedback):
input_layers = self.parameterAsLayerList(parameters, self.INPUT, context)
unioned = self.parameterAsBoolean(parameters, self.UNIONED, context)
vrtPath = self.parameterAsOutputLayer(parameters, self.OUTPUT, context)
- vrt = ''
+ vrt = ""
if unioned:
vrt += ''
@@ -121,20 +138,20 @@ def processAlgorithm(self, parameters, context, feedback):
layerName = GdalUtils.ogrLayerName(layer.source())
vrt += f''
- vrt += f'{html.escape(basePath, True)} '
- vrt += f'{html.escape(layerName, True)} '
- vrt += ' '
+ vrt += f"{html.escape(basePath, True)} "
+ vrt += f"{html.escape(layerName, True)} "
+ vrt += ""
feedback.setProgress(int(current * total))
if unioned:
- vrt += ' '
- vrt += ' '
+ vrt += ""
+ vrt += " "
- with open(vrtPath, 'w', encoding='utf-8') as f:
+ with open(vrtPath, "w", encoding="utf-8") as f:
f.write(vrt)
return {self.OUTPUT: vrtPath, self.VRT_STRING: vrt}
def commandName(self):
- return ''
+ return ""
diff --git a/python/plugins/processing/algs/gdal/Dissolve.py b/python/plugins/processing/algs/gdal/Dissolve.py
index 8430a5142778..133dca5e585c 100644
--- a/python/plugins/processing/algs/gdal/Dissolve.py
+++ b/python/plugins/processing/algs/gdal/Dissolve.py
@@ -15,104 +15,137 @@
***************************************************************************
"""
-__author__ = 'Giovanni Manghi'
-__date__ = 'January 2015'
-__copyright__ = '(C) 2015, Giovanni Manghi'
-
-from qgis.core import (QgsProcessingException,
- QgsProcessingParameterDefinition,
- QgsProcessingParameterFeatureSource,
- QgsProcessingParameterField,
- QgsProcessingParameterString,
- QgsProcessingParameterBoolean,
- QgsProcessingParameterVectorDestination)
+__author__ = "Giovanni Manghi"
+__date__ = "January 2015"
+__copyright__ = "(C) 2015, Giovanni Manghi"
+
+from qgis.core import (
+ QgsProcessingException,
+ QgsProcessingParameterDefinition,
+ QgsProcessingParameterFeatureSource,
+ QgsProcessingParameterField,
+ QgsProcessingParameterString,
+ QgsProcessingParameterBoolean,
+ QgsProcessingParameterVectorDestination,
+)
from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm
from processing.algs.gdal.GdalUtils import GdalUtils
class Dissolve(GdalAlgorithm):
- INPUT = 'INPUT'
- FIELD = 'FIELD'
- GEOMETRY = 'GEOMETRY'
- EXPLODE_COLLECTIONS = 'EXPLODE_COLLECTIONS'
- KEEP_ATTRIBUTES = 'KEEP_ATTRIBUTES'
- COUNT_FEATURES = 'COUNT_FEATURES'
- COMPUTE_AREA = 'COMPUTE_AREA'
- COMPUTE_STATISTICS = 'COMPUTE_STATISTICS'
- STATISTICS_ATTRIBUTE = 'STATISTICS_ATTRIBUTE'
- OPTIONS = 'OPTIONS'
- OUTPUT = 'OUTPUT'
+ INPUT = "INPUT"
+ FIELD = "FIELD"
+ GEOMETRY = "GEOMETRY"
+ EXPLODE_COLLECTIONS = "EXPLODE_COLLECTIONS"
+ KEEP_ATTRIBUTES = "KEEP_ATTRIBUTES"
+ COUNT_FEATURES = "COUNT_FEATURES"
+ COMPUTE_AREA = "COMPUTE_AREA"
+ COMPUTE_STATISTICS = "COMPUTE_STATISTICS"
+ STATISTICS_ATTRIBUTE = "STATISTICS_ATTRIBUTE"
+ OPTIONS = "OPTIONS"
+ OUTPUT = "OUTPUT"
def __init__(self):
super().__init__()
def initAlgorithm(self, config=None):
- self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT,
- self.tr('Input layer')))
- self.addParameter(QgsProcessingParameterField(self.FIELD,
- self.tr('Dissolve field'),
- None,
- self.INPUT,
- QgsProcessingParameterField.DataType.Any, optional=True))
- self.addParameter(QgsProcessingParameterString(self.GEOMETRY,
- self.tr('Geometry column name'),
- defaultValue='geometry'))
+ self.addParameter(
+ QgsProcessingParameterFeatureSource(self.INPUT, self.tr("Input layer"))
+ )
+ self.addParameter(
+ QgsProcessingParameterField(
+ self.FIELD,
+ self.tr("Dissolve field"),
+ None,
+ self.INPUT,
+ QgsProcessingParameterField.DataType.Any,
+ optional=True,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterString(
+ self.GEOMETRY, self.tr("Geometry column name"), defaultValue="geometry"
+ )
+ )
params = [
- QgsProcessingParameterBoolean(self.EXPLODE_COLLECTIONS,
- self.tr('Produce one feature for each geometry in any kind of geometry collection in the source file'),
- defaultValue=False,),
- QgsProcessingParameterBoolean(self.KEEP_ATTRIBUTES,
- self.tr('Keep input attributes'),
- defaultValue=False),
- QgsProcessingParameterBoolean(self.COUNT_FEATURES,
- self.tr('Count dissolved features'),
- defaultValue=False),
- QgsProcessingParameterBoolean(self.COMPUTE_AREA,
- self.tr('Compute area and perimeter of dissolved features'),
- defaultValue=False),
- QgsProcessingParameterBoolean(self.COMPUTE_STATISTICS,
- self.tr('Compute min/max/sum/mean for attribute'),
- defaultValue=False),
- QgsProcessingParameterField(self.STATISTICS_ATTRIBUTE,
- self.tr('Numeric attribute to calculate statistics on'),
- None,
- self.INPUT,
- QgsProcessingParameterField.DataType.Numeric,
- optional=True),
- QgsProcessingParameterString(self.OPTIONS,
- self.tr('Additional creation options'),
- defaultValue='',
- optional=True)
+ QgsProcessingParameterBoolean(
+ self.EXPLODE_COLLECTIONS,
+ self.tr(
+ "Produce one feature for each geometry in any kind of geometry collection in the source file"
+ ),
+ defaultValue=False,
+ ),
+ QgsProcessingParameterBoolean(
+ self.KEEP_ATTRIBUTES,
+ self.tr("Keep input attributes"),
+ defaultValue=False,
+ ),
+ QgsProcessingParameterBoolean(
+ self.COUNT_FEATURES,
+ self.tr("Count dissolved features"),
+ defaultValue=False,
+ ),
+ QgsProcessingParameterBoolean(
+ self.COMPUTE_AREA,
+ self.tr("Compute area and perimeter of dissolved features"),
+ defaultValue=False,
+ ),
+ QgsProcessingParameterBoolean(
+ self.COMPUTE_STATISTICS,
+ self.tr("Compute min/max/sum/mean for attribute"),
+ defaultValue=False,
+ ),
+ QgsProcessingParameterField(
+ self.STATISTICS_ATTRIBUTE,
+ self.tr("Numeric attribute to calculate statistics on"),
+ None,
+ self.INPUT,
+ QgsProcessingParameterField.DataType.Numeric,
+ optional=True,
+ ),
+ QgsProcessingParameterString(
+ self.OPTIONS,
+ self.tr("Additional creation options"),
+ defaultValue="",
+ optional=True,
+ ),
]
for param in params:
- param.setFlags(param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
+ param.setFlags(
+ param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
self.addParameter(param)
- self.addParameter(QgsProcessingParameterVectorDestination(self.OUTPUT,
- self.tr('Dissolved')))
+ self.addParameter(
+ QgsProcessingParameterVectorDestination(self.OUTPUT, self.tr("Dissolved"))
+ )
def name(self):
- return 'dissolve'
+ return "dissolve"
def displayName(self):
- return self.tr('Dissolve')
+ return self.tr("Dissolve")
def group(self):
- return self.tr('Vector geoprocessing')
+ return self.tr("Vector geoprocessing")
def groupId(self):
- return 'vectorgeoprocessing'
+ return "vectorgeoprocessing"
def commandName(self):
- return 'ogr2ogr'
+ return "ogr2ogr"
def getConsoleCommands(self, parameters, context, feedback, executing=True):
source = self.parameterAsSource(parameters, self.INPUT, context)
if source is None:
- raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT))
+ raise QgsProcessingException(
+ self.invalidSourceError(parameters, self.INPUT)
+ )
fields = source.fields()
- input_details = self.getOgrCompatibleSource(self.INPUT, parameters, context, feedback, executing)
+ input_details = self.getOgrCompatibleSource(
+ self.INPUT, parameters, context, feedback, executing
+ )
geometry = self.parameterAsString(parameters, self.GEOMETRY, context)
fieldName = self.parameterAsString(parameters, self.FIELD, context)
@@ -122,51 +155,66 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True):
output_details = GdalUtils.gdal_connection_details_from_uri(outFile, context)
- other_fields_exist = any(
- True for f in fields
- if f.name() != geometry
- )
+ other_fields_exist = any(True for f in fields if f.name() != geometry)
- other_fields = ',*' if other_fields_exist else ''
+ other_fields = ",*" if other_fields_exist else ""
arguments = [
output_details.connection_string,
input_details.connection_string,
- '-nlt PROMOTE_TO_MULTI',
- '-dialect',
- 'sqlite',
- '-sql',
+ "-nlt PROMOTE_TO_MULTI",
+ "-dialect",
+ "sqlite",
+ "-sql",
]
tokens = []
if self.parameterAsBoolean(parameters, self.COUNT_FEATURES, context):
- tokens.append(f'COUNT({geometry}) AS count')
+ tokens.append(f"COUNT({geometry}) AS count")
if self.parameterAsBoolean(parameters, self.COMPUTE_AREA, context):
- tokens.append('SUM(ST_Area({0})) AS area, ST_Perimeter(ST_Union({0})) AS perimeter'.format(geometry))
-
- statsField = self.parameterAsString(parameters, self.STATISTICS_ATTRIBUTE, context)
- if statsField and self.parameterAsBoolean(parameters, self.COMPUTE_STATISTICS, context):
- tokens.append('SUM("{0}") AS sum, MIN("{0}") AS min, MAX("{0}") AS max, AVG("{0}") AS avg'.format(statsField))
-
- params = ','.join(tokens)
+ tokens.append(
+ "SUM(ST_Area({0})) AS area, ST_Perimeter(ST_Union({0})) AS perimeter".format(
+ geometry
+ )
+ )
+
+ statsField = self.parameterAsString(
+ parameters, self.STATISTICS_ATTRIBUTE, context
+ )
+ if statsField and self.parameterAsBoolean(
+ parameters, self.COMPUTE_STATISTICS, context
+ ):
+ tokens.append(
+ 'SUM("{0}") AS sum, MIN("{0}") AS min, MAX("{0}") AS max, AVG("{0}") AS avg'.format(
+ statsField
+ )
+ )
+
+ params = ",".join(tokens)
if params:
- params = ', ' + params
+ params = ", " + params
- group_by = ''
+ group_by = ""
if fieldName:
group_by = f' GROUP BY "{fieldName}"'
if self.parameterAsBoolean(parameters, self.KEEP_ATTRIBUTES, context):
sql = f'SELECT ST_Union({geometry}) AS {geometry}{other_fields}{params} FROM "{input_details.layer_name}"{group_by}'
else:
- sql = 'SELECT ST_Union({}) AS {}{}{} FROM "{}"{}'.format(geometry, geometry, f', "{fieldName}"' if fieldName else '',
- params, input_details.layer_name, group_by)
+ sql = 'SELECT ST_Union({}) AS {}{}{} FROM "{}"{}'.format(
+ geometry,
+ geometry,
+ f', "{fieldName}"' if fieldName else "",
+ params,
+ input_details.layer_name,
+ group_by,
+ )
arguments.append(sql)
if self.parameterAsBoolean(parameters, self.EXPLODE_COLLECTIONS, context):
- arguments.append('-explodecollections')
+ arguments.append("-explodecollections")
if input_details.open_options:
arguments.extend(input_details.open_options_as_arguments())
@@ -178,6 +226,6 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True):
arguments.append(options)
if output_details.format:
- arguments.append(f'-f {output_details.format}')
+ arguments.append(f"-f {output_details.format}")
return [self.commandName(), GdalUtils.escapeAndJoin(arguments)]
diff --git a/python/plugins/processing/algs/gdal/ExecuteSql.py b/python/plugins/processing/algs/gdal/ExecuteSql.py
index 3f30867b353b..e866395a1620 100644
--- a/python/plugins/processing/algs/gdal/ExecuteSql.py
+++ b/python/plugins/processing/algs/gdal/ExecuteSql.py
@@ -15,75 +15,91 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'November 2012'
-__copyright__ = '(C) 2012, Victor Olaya'
-
-from qgis.core import (QgsProcessingException,
- QgsProcessingParameterDefinition,
- QgsProcessingParameterFeatureSource,
- QgsProcessingParameterEnum,
- QgsProcessingParameterString,
- QgsProcessingParameterVectorDestination)
+__author__ = "Victor Olaya"
+__date__ = "November 2012"
+__copyright__ = "(C) 2012, Victor Olaya"
+
+from qgis.core import (
+ QgsProcessingException,
+ QgsProcessingParameterDefinition,
+ QgsProcessingParameterFeatureSource,
+ QgsProcessingParameterEnum,
+ QgsProcessingParameterString,
+ QgsProcessingParameterVectorDestination,
+)
from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm
from processing.algs.gdal.GdalUtils import GdalUtils
class ExecuteSql(GdalAlgorithm):
- INPUT = 'INPUT'
- SQL = 'SQL'
- DIALECT = 'DIALECT'
- OPTIONS = 'OPTIONS'
- OUTPUT = 'OUTPUT'
+ INPUT = "INPUT"
+ SQL = "SQL"
+ DIALECT = "DIALECT"
+ OPTIONS = "OPTIONS"
+ OUTPUT = "OUTPUT"
def __init__(self):
super().__init__()
def initAlgorithm(self, config=None):
- self.dialects = ((self.tr('None'), ''),
- (self.tr('OGR SQL'), 'ogrsql'),
- (self.tr('SQLite'), 'sqlite'))
-
- self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT,
- self.tr('Input layer')))
- self.addParameter(QgsProcessingParameterString(self.SQL,
- self.tr('SQL expression'),
- defaultValue=''))
- self.addParameter(QgsProcessingParameterEnum(self.DIALECT,
- self.tr('SQL dialect'),
- options=[i[0] for i in self.dialects],
- allowMultiple=False,
- defaultValue=0))
-
- options_param = QgsProcessingParameterString(self.OPTIONS,
- self.tr('Additional creation options'),
- defaultValue='',
- optional=True)
- options_param.setFlags(options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
+ self.dialects = (
+ (self.tr("None"), ""),
+ (self.tr("OGR SQL"), "ogrsql"),
+ (self.tr("SQLite"), "sqlite"),
+ )
+
+ self.addParameter(
+ QgsProcessingParameterFeatureSource(self.INPUT, self.tr("Input layer"))
+ )
+ self.addParameter(
+ QgsProcessingParameterString(
+ self.SQL, self.tr("SQL expression"), defaultValue=""
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterEnum(
+ self.DIALECT,
+ self.tr("SQL dialect"),
+ options=[i[0] for i in self.dialects],
+ allowMultiple=False,
+ defaultValue=0,
+ )
+ )
+
+ options_param = QgsProcessingParameterString(
+ self.OPTIONS,
+ self.tr("Additional creation options"),
+ defaultValue="",
+ optional=True,
+ )
+ options_param.setFlags(
+ options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
self.addParameter(options_param)
- self.addParameter(QgsProcessingParameterVectorDestination(self.OUTPUT,
- self.tr('SQL result')))
+ self.addParameter(
+ QgsProcessingParameterVectorDestination(self.OUTPUT, self.tr("SQL result"))
+ )
def name(self):
- return 'executesql'
+ return "executesql"
def displayName(self):
- return self.tr('Execute SQL')
+ return self.tr("Execute SQL")
def group(self):
- return self.tr('Vector miscellaneous')
+ return self.tr("Vector miscellaneous")
def groupId(self):
- return 'vectormiscellaneous'
+ return "vectormiscellaneous"
def commandName(self):
return "ogr2ogr"
def getConsoleCommands(self, parameters, context, feedback, executing=True):
- input_details = self.getOgrCompatibleSource(self.INPUT,
- parameters, context,
- feedback, executing)
+ input_details = self.getOgrCompatibleSource(
+ self.INPUT, parameters, context, feedback, executing
+ )
sql = self.parameterAsString(parameters, self.SQL, context)
options = self.parameterAsString(parameters, self.OPTIONS, context)
outFile = self.parameterAsOutputLayer(parameters, self.OUTPUT, context)
@@ -93,17 +109,20 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True):
if not sql:
raise QgsProcessingException(
- self.tr('Empty SQL. Please enter valid SQL expression and try again.'))
+ self.tr("Empty SQL. Please enter valid SQL expression and try again.")
+ )
arguments = [
output_details.connection_string,
input_details.connection_string,
- '-sql',
- sql
+ "-sql",
+ sql,
]
- dialect = self.dialects[self.parameterAsEnum(parameters, self.DIALECT, context)][1]
+ dialect = self.dialects[
+ self.parameterAsEnum(parameters, self.DIALECT, context)
+ ][1]
if dialect:
- arguments.append('-dialect')
+ arguments.append("-dialect")
arguments.append(dialect)
if input_details.open_options:
@@ -116,6 +135,6 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True):
arguments.append(options)
if output_details.format:
- arguments.append(f'-f {output_details.format}')
+ arguments.append(f"-f {output_details.format}")
return [self.commandName(), GdalUtils.escapeAndJoin(arguments)]
diff --git a/python/plugins/processing/algs/gdal/GdalAlgorithm.py b/python/plugins/processing/algs/gdal/GdalAlgorithm.py
index d896673a45ca..6ce5279ba254 100644
--- a/python/plugins/processing/algs/gdal/GdalAlgorithm.py
+++ b/python/plugins/processing/algs/gdal/GdalAlgorithm.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'August 2012'
-__copyright__ = '(C) 2012, Victor Olaya'
+__author__ = "Victor Olaya"
+__date__ = "August 2012"
+__copyright__ = "(C) 2012, Victor Olaya"
import os
import re
@@ -25,23 +25,23 @@
from qgis.PyQt.QtCore import QUrl, QCoreApplication
-from qgis.core import (QgsApplication,
- QgsVectorFileWriter,
- QgsProcessingFeatureSourceDefinition,
- QgsProcessingAlgorithm,
- QgsProcessingContext,
- QgsProcessingFeedback,
- QgsProviderRegistry,
- QgsDataSourceUri)
+from qgis.core import (
+ QgsApplication,
+ QgsVectorFileWriter,
+ QgsProcessingFeatureSourceDefinition,
+ QgsProcessingAlgorithm,
+ QgsProcessingContext,
+ QgsProcessingFeedback,
+ QgsProviderRegistry,
+ QgsDataSourceUri,
+)
from processing.algs.gdal.GdalAlgorithmDialog import GdalAlgorithmDialog
-from processing.algs.gdal.GdalUtils import (
- GdalUtils,
- GdalConnectionDetails
-)
+from processing.algs.gdal.GdalUtils import GdalUtils, GdalConnectionDetails
-pluginPath = os.path.normpath(os.path.join(
- os.path.split(os.path.dirname(__file__))[0], os.pardir))
+pluginPath = os.path.normpath(
+ os.path.join(os.path.split(os.path.dirname(__file__))[0], os.pardir)
+)
class GdalAlgorithm(QgsProcessingAlgorithm):
@@ -54,7 +54,7 @@ def icon(self):
return QgsApplication.getThemeIcon("/providerGdal.svg")
def tags(self):
- return ['ogr', 'gdal', self.commandName()]
+ return ["ogr", "gdal", self.commandName()]
def svgIconPath(self):
return QgsApplication.iconPath("providerGdal.svg")
@@ -68,76 +68,102 @@ def createCustomParametersWidget(self, parent):
def getConsoleCommands(self, parameters, context, feedback, executing=True):
return None
- def getOgrCompatibleSource(self,
- parameter_name: str,
- parameters: Dict,
- context: QgsProcessingContext,
- feedback: QgsProcessingFeedback,
- executing: bool) -> GdalConnectionDetails:
+ def getOgrCompatibleSource(
+ self,
+ parameter_name: str,
+ parameters: dict,
+ context: QgsProcessingContext,
+ feedback: QgsProcessingFeedback,
+ executing: bool,
+ ) -> GdalConnectionDetails:
"""
Interprets a parameter as a GDAL connection details
"""
- if not executing and parameter_name in parameters and isinstance(parameters[parameter_name], QgsProcessingFeatureSourceDefinition):
+ if (
+ not executing
+ and parameter_name in parameters
+ and isinstance(
+ parameters[parameter_name], QgsProcessingFeatureSourceDefinition
+ )
+ ):
# if not executing, then we throw away all 'selected features only' settings
# since these have no meaning for command line gdal use, and we don't want to force
# an export of selected features only to a temporary file just to show the command!
parameters = {parameter_name: parameters[parameter_name].source}
input_layer = self.parameterAsVectorLayer(parameters, parameter_name, context)
- if input_layer is None or input_layer.providerType() in ('memory', 'grass'):
+ if input_layer is None or input_layer.providerType() in ("memory", "grass"):
if executing:
# parameter is not a vector layer - try to convert to a source compatible with OGR
# and extract selection if required
- ogr_data_path = self.parameterAsCompatibleSourceLayerPath(parameters, parameter_name, context,
- QgsVectorFileWriter.supportedFormatExtensions(),
- QgsVectorFileWriter.supportedFormatExtensions()[0],
- feedback=feedback)
+ ogr_data_path = self.parameterAsCompatibleSourceLayerPath(
+ parameters,
+ parameter_name,
+ context,
+ QgsVectorFileWriter.supportedFormatExtensions(),
+ QgsVectorFileWriter.supportedFormatExtensions()[0],
+ feedback=feedback,
+ )
return GdalConnectionDetails(
connection_string=ogr_data_path,
- layer_name=GdalUtils.ogrLayerName(ogr_data_path)
+ layer_name=GdalUtils.ogrLayerName(ogr_data_path),
)
else:
# not executing - don't waste time converting incompatible sources, just return dummy strings
# for the command preview (since the source isn't compatible with OGR, it has no meaning anyway and can't
# be run directly in the command line)
return GdalConnectionDetails(
- connection_string='path_to_data_file',
- layer_name='layer_name'
+ connection_string="path_to_data_file", layer_name="layer_name"
)
- elif input_layer.providerType() == 'ogr':
- if executing and (isinstance(parameters[parameter_name], QgsProcessingFeatureSourceDefinition) and parameters[parameter_name].selectedFeaturesOnly) \
- or input_layer.subsetString():
+ elif input_layer.providerType() == "ogr":
+ if (
+ executing
+ and (
+ isinstance(
+ parameters[parameter_name], QgsProcessingFeatureSourceDefinition
+ )
+ and parameters[parameter_name].selectedFeaturesOnly
+ )
+ or input_layer.subsetString()
+ ):
# parameter is a vector layer, with OGR data provider
# so extract selection if required
- ogr_data_path = self.parameterAsCompatibleSourceLayerPath(parameters, parameter_name, context,
- QgsVectorFileWriter.supportedFormatExtensions(),
- feedback=feedback)
- parts = QgsProviderRegistry.instance().decodeUri('ogr', ogr_data_path)
- ogr_data_path = parts['path']
- if 'layerName' in parts and parts['layerName']:
- ogr_layer_name = parts['layerName']
+ ogr_data_path = self.parameterAsCompatibleSourceLayerPath(
+ parameters,
+ parameter_name,
+ context,
+ QgsVectorFileWriter.supportedFormatExtensions(),
+ feedback=feedback,
+ )
+ parts = QgsProviderRegistry.instance().decodeUri("ogr", ogr_data_path)
+ ogr_data_path = parts["path"]
+ if "layerName" in parts and parts["layerName"]:
+ ogr_layer_name = parts["layerName"]
else:
ogr_layer_name = GdalUtils.ogrLayerName(ogr_data_path)
return GdalConnectionDetails(
connection_string=ogr_data_path,
layer_name=ogr_layer_name,
- open_options=parts.get('openOptions', None),
- credential_options=parts.get('credentialOptions', None)
+ open_options=parts.get("openOptions", None),
+ credential_options=parts.get("credentialOptions", None),
)
else:
# either not using the selection, or
# not executing - don't worry about 'selected features only' handling. It has no meaning
# for the command line preview since it has no meaning outside of a QGIS session!
- connection_details = GdalUtils.gdal_connection_details_from_layer(input_layer)
- connection_details.layer_name = GdalUtils.ogrLayerName(input_layer.source())
+ connection_details = GdalUtils.gdal_connection_details_from_layer(
+ input_layer
+ )
+ connection_details.layer_name = GdalUtils.ogrLayerName(
+ input_layer.source()
+ )
return connection_details
- elif input_layer.providerType().lower() == 'wfs':
+ elif input_layer.providerType().lower() == "wfs":
uri = QgsDataSourceUri(input_layer.source())
- baseUrl = uri.param('url').split('?')[0]
+ baseUrl = uri.param("url").split("?")[0]
return GdalConnectionDetails(
- connection_string=f"WFS:{baseUrl}",
- layer_name=uri.param('typename')
+ connection_string=f"WFS:{baseUrl}", layer_name=uri.param("typename")
)
# vector layer, but not OGR - get OGR compatible path
@@ -150,7 +176,9 @@ def setOutputValue(self, name, value):
self.output_values[name] = value
def processAlgorithm(self, parameters, context, feedback):
- commands = self.getConsoleCommands(parameters, context, feedback, executing=True)
+ commands = self.getConsoleCommands(
+ parameters, context, feedback, executing=True
+ )
GdalUtils.runGdal(commands, feedback)
# auto generate outputs
@@ -164,18 +192,17 @@ def processAlgorithm(self, parameters, context, feedback):
return results
def commandName(self):
- parameters = {
- param.name(): "1"
- for param in self.parameterDefinitions()
- }
+ parameters = {param.name(): "1" for param in self.parameterDefinitions()}
context = QgsProcessingContext()
feedback = QgsProcessingFeedback()
- name = self.getConsoleCommands(parameters, context, feedback, executing=False)[0]
+ name = self.getConsoleCommands(parameters, context, feedback, executing=False)[
+ 0
+ ]
if name.endswith(".py"):
name = name[:-3]
return name
- def tr(self, string, context=''):
- if context == '':
+ def tr(self, string, context=""):
+ if context == "":
context = self.__class__.__name__
return QCoreApplication.translate(context, string)
diff --git a/python/plugins/processing/algs/gdal/GdalAlgorithmDialog.py b/python/plugins/processing/algs/gdal/GdalAlgorithmDialog.py
index f2ac01f5bb8f..618af021698f 100644
--- a/python/plugins/processing/algs/gdal/GdalAlgorithmDialog.py
+++ b/python/plugins/processing/algs/gdal/GdalAlgorithmDialog.py
@@ -15,31 +15,35 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'May 2015'
-__copyright__ = '(C) 2015, Victor Olaya'
+__author__ = "Victor Olaya"
+__date__ = "May 2015"
+__copyright__ = "(C) 2015, Victor Olaya"
from qgis.PyQt.QtCore import QCoreApplication
-from qgis.PyQt.QtWidgets import (QWidget,
- QVBoxLayout,
- QPushButton,
- QLabel,
- QPlainTextEdit,
- QLineEdit,
- QComboBox,
- QCheckBox,
- QSizePolicy,
- QDialogButtonBox)
+from qgis.PyQt.QtWidgets import (
+ QWidget,
+ QVBoxLayout,
+ QPushButton,
+ QLabel,
+ QPlainTextEdit,
+ QLineEdit,
+ QComboBox,
+ QCheckBox,
+ QSizePolicy,
+ QDialogButtonBox,
+)
from qgis.core import (
QgsProcessingException,
QgsProcessingFeedback,
- QgsProcessingParameterDefinition
+ QgsProcessingParameterDefinition,
+)
+from qgis.gui import (
+ QgsMessageBar,
+ QgsProjectionSelectionWidget,
+ QgsProcessingAlgorithmDialogBase,
+ QgsProcessingLayerOutputDestinationWidget,
)
-from qgis.gui import (QgsMessageBar,
- QgsProjectionSelectionWidget,
- QgsProcessingAlgorithmDialogBase,
- QgsProcessingLayerOutputDestinationWidget)
from processing.gui.AlgorithmDialog import AlgorithmDialog
from processing.gui.AlgorithmDialogBase import AlgorithmDialogBase
@@ -124,30 +128,48 @@ def parametersHaveChanged(self):
# messy as all heck, but we don't want to call the dialog's implementation of
# createProcessingParameters as we want to catch the exceptions raised by the
# parameter panel instead...
- parameters = {} if self.dialog.mainWidget() is None else self.dialog.mainWidget().createProcessingParameters()
+ parameters = (
+ {}
+ if self.dialog.mainWidget() is None
+ else self.dialog.mainWidget().createProcessingParameters()
+ )
for output in self.algorithm().destinationParameterDefinitions():
if not output.name() in parameters or parameters[output.name()] is None:
- if not output.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional:
+ if (
+ not output.flags()
+ & QgsProcessingParameterDefinition.Flag.FlagOptional
+ ):
parameters[output.name()] = self.tr("[temporary file]")
for p in self.algorithm().parameterDefinitions():
if p.flags() & QgsProcessingParameterDefinition.Flag.FlagHidden:
continue
- if p.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional and p.name() not in parameters:
+ if (
+ p.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional
+ and p.name() not in parameters
+ ):
continue
- if p.name() not in parameters or not p.checkValueIsAcceptable(parameters[p.name()]):
+ if p.name() not in parameters or not p.checkValueIsAcceptable(
+ parameters[p.name()]
+ ):
# not ready yet
- self.text.setPlainText('')
+ self.text.setPlainText("")
return
try:
- commands = self.algorithm().getConsoleCommands(parameters, context, feedback, executing=False)
- commands = [c for c in commands if c not in ['cmd.exe', '/C ']]
+ commands = self.algorithm().getConsoleCommands(
+ parameters, context, feedback, executing=False
+ )
+ commands = [c for c in commands if c not in ["cmd.exe", "/C "]]
self.text.setPlainText(" ".join(commands))
except QgsProcessingException as e:
self.text.setPlainText(str(e))
except AlgorithmDialogBase.InvalidParameterValue as e:
- self.text.setPlainText(self.tr("Invalid value for parameter '{0}'").format(e.parameter.description()))
+ self.text.setPlainText(
+ self.tr("Invalid value for parameter '{0}'").format(
+ e.parameter.description()
+ )
+ )
except AlgorithmDialogBase.InvalidOutputExtension as e:
self.text.setPlainText(e.message)
diff --git a/python/plugins/processing/algs/gdal/GdalAlgorithmProvider.py b/python/plugins/processing/algs/gdal/GdalAlgorithmProvider.py
index 7b1baea846e2..ad88e08d2860 100644
--- a/python/plugins/processing/algs/gdal/GdalAlgorithmProvider.py
+++ b/python/plugins/processing/algs/gdal/GdalAlgorithmProvider.py
@@ -15,18 +15,16 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'August 2012'
-__copyright__ = '(C) 2012, Victor Olaya'
+__author__ = "Victor Olaya"
+__date__ = "August 2012"
+__copyright__ = "(C) 2012, Victor Olaya"
import os
from osgeo import gdal
from qgis.PyQt.QtCore import QCoreApplication
-from qgis.core import (QgsApplication,
- QgsProcessingProvider,
- QgsRuntimeProfiler)
+from qgis.core import QgsApplication, QgsProcessingProvider, QgsRuntimeProfiler
from processing.core.ProcessingConfig import ProcessingConfig, Setting
from .GdalUtils import GdalUtils
@@ -90,8 +88,9 @@
# from .ogr2ogrtabletopostgislist import Ogr2OgrTableToPostGisList
-pluginPath = os.path.normpath(os.path.join(
- os.path.split(os.path.dirname(__file__))[0], os.pardir))
+pluginPath = os.path.normpath(
+ os.path.join(os.path.split(os.path.dirname(__file__))[0], os.pardir)
+)
gdal.UseExceptions()
@@ -101,38 +100,41 @@ class GdalAlgorithmProvider(QgsProcessingProvider):
def __init__(self):
super().__init__()
self.algs = []
- QgsApplication.processingRegistry().addAlgorithmAlias('qgis:buildvirtualvector', 'gdal:buildvirtualvector')
+ QgsApplication.processingRegistry().addAlgorithmAlias(
+ "qgis:buildvirtualvector", "gdal:buildvirtualvector"
+ )
def load(self):
- with QgsRuntimeProfiler.profile('GDAL Provider'):
+ with QgsRuntimeProfiler.profile("GDAL Provider"):
ProcessingConfig.settingIcons[self.name()] = self.icon()
- ProcessingConfig.addSetting(Setting(self.name(), 'ACTIVATE_GDAL',
- self.tr('Activate'), True))
+ ProcessingConfig.addSetting(
+ Setting(self.name(), "ACTIVATE_GDAL", self.tr("Activate"), True)
+ )
ProcessingConfig.readSettings()
self.refreshAlgorithms()
return True
def unload(self):
- ProcessingConfig.removeSetting('ACTIVATE_GDAL')
+ ProcessingConfig.removeSetting("ACTIVATE_GDAL")
def isActive(self):
- return ProcessingConfig.getSetting('ACTIVATE_GDAL')
+ return ProcessingConfig.getSetting("ACTIVATE_GDAL")
def setActive(self, active):
- ProcessingConfig.setSettingValue('ACTIVATE_GDAL', active)
+ ProcessingConfig.setSettingValue("ACTIVATE_GDAL", active)
def name(self):
- return 'GDAL'
+ return "GDAL"
def longName(self):
version = GdalUtils.readableVersion()
- return f'GDAL ({version})'
+ return f"GDAL ({version})"
def id(self):
- return 'gdal'
+ return "gdal"
def helpId(self):
- return 'gdal'
+ return "gdal"
def icon(self):
return QgsApplication.getThemeIcon("/providerGdal.svg")
@@ -220,7 +222,7 @@ def supportsNonFileBasedOutput(self):
"""
return False
- def tr(self, string, context=''):
- if context == '':
- context = 'GdalAlgorithmProvider'
+ def tr(self, string, context=""):
+ if context == "":
+ context = "GdalAlgorithmProvider"
return QCoreApplication.translate(context, string)
diff --git a/python/plugins/processing/algs/gdal/GdalUtils.py b/python/plugins/processing/algs/gdal/GdalUtils.py
index c4a2f21498bb..dde752aef547 100644
--- a/python/plugins/processing/algs/gdal/GdalUtils.py
+++ b/python/plugins/processing/algs/gdal/GdalUtils.py
@@ -15,15 +15,11 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'August 2012'
-__copyright__ = '(C) 2012, Victor Olaya'
-
-from typing import (
- Dict,
- List,
- Optional
-)
+__author__ = "Victor Olaya"
+__date__ = "August 2012"
+__copyright__ = "(C) 2012, Victor Olaya"
+
+from typing import Dict, List, Optional
import os
import subprocess
import platform
@@ -49,13 +45,10 @@
QgsProcessingException,
QgsProviderRegistry,
QgsMapLayer,
- QgsProcessingContext
+ QgsProcessingContext,
)
-from qgis.PyQt.QtCore import (
- QCoreApplication,
- QProcess
-)
+from qgis.PyQt.QtCore import QCoreApplication, QProcess
@dataclass
@@ -63,35 +56,37 @@ class GdalConnectionDetails:
"""
Encapsulates connection details for a layer
"""
+
connection_string: Optional[str] = None
format: Optional[str] = None
- open_options: Optional[List[str]] = None
+ open_options: Optional[list[str]] = None
layer_name: Optional[str] = None
- credential_options: Optional[Dict] = None
+ credential_options: Optional[dict] = None
- def open_options_as_arguments(self) -> List[str]:
+ def open_options_as_arguments(self) -> list[str]:
"""
Returns any open options as a list of arguments
"""
res = []
for option in self.open_options:
- res.append(f'-oo {option}')
+ res.append(f"-oo {option}")
return res
- def credential_options_as_arguments(self) -> List[str]:
+ def credential_options_as_arguments(self) -> list[str]:
"""
Returns any credential options as a list of arguments
"""
res = []
for key, value in self.credential_options.items():
- res.append(f'--config {key} {value}')
+ res.append(f"--config {key} {value}")
return res
try:
from osgeo import gdal, ogr
+
gdal.UseExceptions()
ogr.UseExceptions()
@@ -101,7 +96,7 @@ def credential_options_as_arguments(self) -> List[str]:
class GdalUtils:
- GDAL_HELP_PATH = 'GDAL_HELP_PATH'
+ GDAL_HELP_PATH = "GDAL_HELP_PATH"
supportedRasters = None
supportedOutputRasters = None
@@ -110,44 +105,50 @@ class GdalUtils:
def runGdal(commands, feedback=None):
if feedback is None:
feedback = QgsProcessingFeedback()
- envval = os.getenv('PATH')
+ envval = os.getenv("PATH")
# We need to give some extra hints to get things picked up on OS X
isDarwin = False
try:
- isDarwin = platform.system() == 'Darwin'
+ isDarwin = platform.system() == "Darwin"
except OSError: # https://travis-ci.org/m-kuhn/QGIS#L1493-L1526
pass
- if isDarwin and os.path.isfile(os.path.join(QgsApplication.prefixPath(), "bin", "gdalinfo")):
+ if isDarwin and os.path.isfile(
+ os.path.join(QgsApplication.prefixPath(), "bin", "gdalinfo")
+ ):
# Looks like there's a bundled gdal. Let's use it.
- os.environ['PATH'] = "{}{}{}".format(os.path.join(QgsApplication.prefixPath(), "bin"), os.pathsep, envval)
- os.environ['DYLD_LIBRARY_PATH'] = os.path.join(QgsApplication.prefixPath(), "lib")
+ os.environ["PATH"] = "{}{}{}".format(
+ os.path.join(QgsApplication.prefixPath(), "bin"), os.pathsep, envval
+ )
+ os.environ["DYLD_LIBRARY_PATH"] = os.path.join(
+ QgsApplication.prefixPath(), "lib"
+ )
else:
# Other platforms should use default gdal finder codepath
settings = QgsSettings()
- path = settings.value('/GdalTools/gdalPath', '')
+ path = settings.value("/GdalTools/gdalPath", "")
if not path.lower() in envval.lower().split(os.pathsep):
- envval += f'{os.pathsep}{path}'
- os.putenv('PATH', envval)
+ envval += f"{os.pathsep}{path}"
+ os.putenv("PATH", envval)
- fused_command = ' '.join([str(c) for c in commands])
- QgsMessageLog.logMessage(fused_command, 'Processing', Qgis.MessageLevel.Info)
- feedback.pushInfo(GdalUtils.tr('GDAL command:'))
+ fused_command = " ".join([str(c) for c in commands])
+ QgsMessageLog.logMessage(fused_command, "Processing", Qgis.MessageLevel.Info)
+ feedback.pushInfo(GdalUtils.tr("GDAL command:"))
feedback.pushCommandInfo(fused_command)
- feedback.pushInfo(GdalUtils.tr('GDAL command output:'))
+ feedback.pushInfo(GdalUtils.tr("GDAL command output:"))
- loglines = [GdalUtils.tr('GDAL execution console output')]
+ loglines = [GdalUtils.tr("GDAL execution console output")]
# create string list of number from 0 to 99
progress_string_list = [str(a) for a in range(0, 100)]
def on_stdout(ba):
- val = ba.data().decode('UTF-8')
+ val = ba.data().decode("UTF-8")
# catch progress reports
- if val == '100 - done.':
+ if val == "100 - done.":
on_stdout.progress = 100
feedback.setProgress(on_stdout.progress)
else:
# remove any number of trailing "." or ".." strings
- match = re.match(r'.*?(\d+)\.+\s*$', val)
+ match = re.match(r".*?(\d+)\.+\s*$", val)
found_number = False
if match:
int_val = match.group(1)
@@ -156,31 +157,31 @@ def on_stdout(ba):
feedback.setProgress(on_stdout.progress)
found_number = True
- if not found_number and val == '.':
+ if not found_number and val == ".":
on_stdout.progress += 2.5
feedback.setProgress(on_stdout.progress)
on_stdout.buffer += val
- if on_stdout.buffer.endswith('\n') or on_stdout.buffer.endswith('\r'):
+ if on_stdout.buffer.endswith("\n") or on_stdout.buffer.endswith("\r"):
# flush buffer
feedback.pushConsoleInfo(on_stdout.buffer.rstrip())
loglines.append(on_stdout.buffer.rstrip())
- on_stdout.buffer = ''
+ on_stdout.buffer = ""
on_stdout.progress = 0
- on_stdout.buffer = ''
+ on_stdout.buffer = ""
def on_stderr(ba):
- val = ba.data().decode('UTF-8')
+ val = ba.data().decode("UTF-8")
on_stderr.buffer += val
- if on_stderr.buffer.endswith('\n') or on_stderr.buffer.endswith('\r'):
+ if on_stderr.buffer.endswith("\n") or on_stderr.buffer.endswith("\r"):
# flush buffer
feedback.reportError(on_stderr.buffer.rstrip())
loglines.append(on_stderr.buffer.rstrip())
- on_stderr.buffer = ''
+ on_stderr.buffer = ""
- on_stderr.buffer = ''
+ on_stderr.buffer = ""
command, *arguments = QgsRunProcess.splitCommand(fused_command)
proc = QgsBlockingProcess(command, arguments)
@@ -189,15 +190,26 @@ def on_stderr(ba):
res = proc.run(feedback)
if feedback.isCanceled() and res != 0:
- feedback.pushInfo(GdalUtils.tr('Process was canceled and did not complete'))
- elif not feedback.isCanceled() and proc.exitStatus() == QProcess.ExitStatus.CrashExit:
- raise QgsProcessingException(GdalUtils.tr('Process was unexpectedly terminated'))
+ feedback.pushInfo(GdalUtils.tr("Process was canceled and did not complete"))
+ elif (
+ not feedback.isCanceled()
+ and proc.exitStatus() == QProcess.ExitStatus.CrashExit
+ ):
+ raise QgsProcessingException(
+ GdalUtils.tr("Process was unexpectedly terminated")
+ )
elif res == 0:
- feedback.pushInfo(GdalUtils.tr('Process completed successfully'))
+ feedback.pushInfo(GdalUtils.tr("Process completed successfully"))
elif proc.processError() == QProcess.ProcessError.FailedToStart:
- raise QgsProcessingException(GdalUtils.tr('Process {} failed to start. Either {} is missing, or you may have insufficient permissions to run the program.').format(command, command))
+ raise QgsProcessingException(
+ GdalUtils.tr(
+ "Process {} failed to start. Either {} is missing, or you may have insufficient permissions to run the program."
+ ).format(command, command)
+ )
else:
- feedback.reportError(GdalUtils.tr('Process returned error code {}').format(res))
+ feedback.reportError(
+ GdalUtils.tr("Process returned error code {}").format(res)
+ )
return loglines
@@ -214,8 +226,8 @@ def getSupportedRasters():
GdalUtils.supportedRasters = {}
GdalUtils.supportedOutputRasters = {}
- GdalUtils.supportedRasters['GTiff'] = ['tif', 'tiff']
- GdalUtils.supportedOutputRasters['GTiff'] = ['tif', 'tiff']
+ GdalUtils.supportedRasters["GTiff"] = ["tif", "tiff"]
+ GdalUtils.supportedOutputRasters["GTiff"] = ["tif", "tiff"]
for i in range(gdal.GetDriverCount()):
driver = gdal.GetDriver(i)
@@ -223,19 +235,21 @@ def getSupportedRasters():
continue
shortName = driver.ShortName
metadata = driver.GetMetadata()
- if gdal.DCAP_RASTER not in metadata \
- or metadata[gdal.DCAP_RASTER] != 'YES':
+ if gdal.DCAP_RASTER not in metadata or metadata[gdal.DCAP_RASTER] != "YES":
continue
if gdal.DMD_EXTENSIONS in metadata:
- extensions = metadata[gdal.DMD_EXTENSIONS].split(' ')
+ extensions = metadata[gdal.DMD_EXTENSIONS].split(" ")
if extensions:
GdalUtils.supportedRasters[shortName] = extensions
# Only creatable rasters can be referenced in output rasters
- if ((gdal.DCAP_CREATE in metadata and
- metadata[gdal.DCAP_CREATE] == 'YES') or
- (gdal.DCAP_CREATECOPY in metadata and
- metadata[gdal.DCAP_CREATECOPY] == 'YES')):
+ if (
+ gdal.DCAP_CREATE in metadata
+ and metadata[gdal.DCAP_CREATE] == "YES"
+ ) or (
+ gdal.DCAP_CREATECOPY in metadata
+ and metadata[gdal.DCAP_CREATECOPY] == "YES"
+ ):
GdalUtils.supportedOutputRasters[shortName] = extensions
return GdalUtils.supportedRasters
@@ -257,10 +271,10 @@ def getSupportedRasterExtensions():
allexts = []
for exts in list(GdalUtils.getSupportedRasters().values()):
for ext in exts:
- if ext not in allexts and ext not in ['', 'tif', 'tiff']:
+ if ext not in allexts and ext not in ["", "tif", "tiff"]:
allexts.append(ext)
allexts.sort()
- allexts[0:0] = ['tif', 'tiff']
+ allexts[0:0] = ["tif", "tiff"]
return allexts
@staticmethod
@@ -268,63 +282,62 @@ def getSupportedOutputRasterExtensions():
allexts = []
for exts in list(GdalUtils.getSupportedOutputRasters().values()):
for ext in exts:
- if ext not in allexts and ext not in ['', 'tif', 'tiff']:
+ if ext not in allexts and ext not in ["", "tif", "tiff"]:
allexts.append(ext)
allexts.sort()
- allexts[0:0] = ['tif', 'tiff']
+ allexts[0:0] = ["tif", "tiff"]
return allexts
@staticmethod
def getVectorDriverFromFileName(filename):
ext = os.path.splitext(filename)[1]
- if ext == '':
- return 'ESRI Shapefile'
+ if ext == "":
+ return "ESRI Shapefile"
formats = QgsVectorFileWriter.supportedFiltersAndFormats()
for format in formats:
if ext in format.filterString:
return format.driverName
- return 'ESRI Shapefile'
+ return "ESRI Shapefile"
@staticmethod
def getFormatShortNameFromFilename(filename):
- ext = filename[filename.rfind('.') + 1:]
+ ext = filename[filename.rfind(".") + 1 :]
supported = GdalUtils.getSupportedRasters()
for name in list(supported.keys()):
exts = supported[name]
if ext in exts:
return name
- return 'GTiff'
+ return "GTiff"
@staticmethod
def escapeAndJoin(strList):
- escChars = [' ', '&', '(', ')', '"', ';']
- joined = ''
+ escChars = [" ", "&", "(", ")", '"', ";"]
+ joined = ""
for s in strList:
if not isinstance(s, str):
s = str(s)
# don't escape if command starts with - and isn't a negative number, e.g. -9999
- if s and re.match(r'^([^-]|-\d)', s) and any(c in s for c in escChars):
- escaped = '"' + s.replace('\\', '\\\\').replace('"', '"""') \
- + '"'
+ if s and re.match(r"^([^-]|-\d)", s) and any(c in s for c in escChars):
+ escaped = '"' + s.replace("\\", "\\\\").replace('"', '"""') + '"'
else:
escaped = s
if escaped is not None:
- joined += escaped + ' '
+ joined += escaped + " "
return joined.strip()
@staticmethod
def version():
- return int(gdal.VersionInfo('VERSION_NUM'))
+ return int(gdal.VersionInfo("VERSION_NUM"))
@staticmethod
def readableVersion():
- return gdal.VersionInfo('RELEASE_NAME')
+ return gdal.VersionInfo("RELEASE_NAME")
@staticmethod
def gdal_connection_details_from_uri(
- uri: str,
- context: QgsProcessingContext) -> GdalConnectionDetails:
+ uri: str, context: QgsProcessingContext
+ ) -> GdalConnectionDetails:
"""
Generates GDAL connection details from layer source
"""
@@ -332,10 +345,7 @@ def gdal_connection_details_from_uri(
if layer is None:
path, ext = os.path.splitext(uri)
_format = QgsVectorFileWriter.driverForExtension(ext)
- return GdalConnectionDetails(
- connection_string=uri,
- format=f'"{_format}"'
- )
+ return GdalConnectionDetails(connection_string=uri, format=f'"{_format}"')
return GdalUtils.gdal_connection_details_from_layer(layer)
@@ -345,15 +355,14 @@ def gdal_connection_details_from_layer(layer: QgsMapLayer) -> GdalConnectionDeta
Builds GDAL connection details from a QGIS map layer
"""
provider = layer.providerType()
- if provider == 'spatialite':
+ if provider == "spatialite":
# dbname='/geodata/osm_ch.sqlite' table="places" (Geometry) sql=
regex = re.compile("dbname='(.+)'")
r = regex.search(str(layer.source()))
return GdalConnectionDetails(
- connection_string=r.groups()[0],
- format='"SQLite"'
+ connection_string=r.groups()[0], format='"SQLite"'
)
- elif provider == 'postgres':
+ elif provider == "postgres":
# dbname='ktryjh_iuuqef' host=spacialdb.com port=9999
# user='ktryjh_iuuqef' password='xyqwer' sslmode=disable
# key='gid' estimatedmetadata=true srid=4326 type=MULTIPOLYGON
@@ -366,7 +375,9 @@ def gdal_connection_details_from_layer(layer: QgsMapLayer) -> GdalConnectionDeta
try:
conn = psycopg2.connect(dsUri.connectionInfo())
except psycopg2.OperationalError:
- (ok, user, passwd) = QgsCredentials.instance().get(conninfo, dsUri.username(), dsUri.password())
+ (ok, user, passwd) = QgsCredentials.instance().get(
+ conninfo, dsUri.username(), dsUri.password()
+ )
if not ok:
break
@@ -374,34 +385,32 @@ def gdal_connection_details_from_layer(layer: QgsMapLayer) -> GdalConnectionDeta
dsUri.setPassword(passwd)
if not conn:
- raise RuntimeError('Could not connect to PostgreSQL database - check connection info')
+ raise RuntimeError(
+ "Could not connect to PostgreSQL database - check connection info"
+ )
if ok:
QgsCredentials.instance().put(conninfo, user, passwd)
return GdalConnectionDetails(
- connection_string=f"PG:{dsUri.connectionInfo()}",
- format='"PostgreSQL"'
+ connection_string=f"PG:{dsUri.connectionInfo()}", format='"PostgreSQL"'
)
- elif provider == 'mssql':
+ elif provider == "mssql":
# 'dbname=\'db_name\' host=myHost estimatedmetadata=true
# srid=27700 type=MultiPolygon table="dbo"."my_table"
# #(Shape) sql='
dsUri = layer.dataProvider().uri()
- ogrstr = 'MSSQL:'
- ogrstr += f'database={dsUri.database()};'
- ogrstr += f'server={dsUri.host()};'
+ ogrstr = "MSSQL:"
+ ogrstr += f"database={dsUri.database()};"
+ ogrstr += f"server={dsUri.host()};"
if dsUri.username() != "":
- ogrstr += f'uid={dsUri.username()};'
+ ogrstr += f"uid={dsUri.username()};"
else:
- ogrstr += 'trusted_connection=yes;'
- if dsUri.password() != '':
- ogrstr += f'pwd={dsUri.password()};'
- ogrstr += f'tables={dsUri.table()}'
- return GdalConnectionDetails(
- connection_string=ogrstr,
- format='"MSSQL"'
- )
+ ogrstr += "trusted_connection=yes;"
+ if dsUri.password() != "":
+ ogrstr += f"pwd={dsUri.password()};"
+ ogrstr += f"tables={dsUri.table()}"
+ return GdalConnectionDetails(connection_string=ogrstr, format='"MSSQL"')
elif provider == "oracle":
# OCI:user/password@host:port/service:table
dsUri = QgsDataSourceUri(layer.dataProvider().dataSourceUri())
@@ -415,7 +424,7 @@ def gdal_connection_details_from_layer(layer: QgsMapLayer) -> GdalConnectionDeta
if dsUri.host() != "":
ogrstr += delim + dsUri.host()
delim = ""
- if dsUri.port() not in ["", '1521']:
+ if dsUri.port() not in ["", "1521"]:
ogrstr += ":" + dsUri.port()
ogrstr += "/"
if dsUri.database() != "":
@@ -424,56 +433,50 @@ def gdal_connection_details_from_layer(layer: QgsMapLayer) -> GdalConnectionDeta
ogrstr += delim + dsUri.database()
if ogrstr == "OCI:":
- raise RuntimeError('Invalid oracle data source - check connection info')
+ raise RuntimeError("Invalid oracle data source - check connection info")
ogrstr += ":"
if dsUri.schema() != "":
ogrstr += dsUri.schema() + "."
ogrstr += dsUri.table()
- return GdalConnectionDetails(
- connection_string=ogrstr,
- format='"OCI"'
- )
+ return GdalConnectionDetails(connection_string=ogrstr, format='"OCI"')
elif provider.lower() == "wfs":
uri = QgsDataSourceUri(layer.source())
- baseUrl = uri.param('url').split('?')[0]
+ baseUrl = uri.param("url").split("?")[0]
return GdalConnectionDetails(
- connection_string=f"WFS:{baseUrl}",
- format='"WFS"'
+ connection_string=f"WFS:{baseUrl}", format='"WFS"'
)
elif provider.lower() == "ogr":
- parts = QgsProviderRegistry.instance().decodeUri('ogr',
- layer.source())
- if 'path' in parts:
- path = parts['path']
- if 'vsiPrefix' in parts:
- path = parts['vsiPrefix'] + path
-
- _, ext = os.path.splitext(parts['path'])
+ parts = QgsProviderRegistry.instance().decodeUri("ogr", layer.source())
+ if "path" in parts:
+ path = parts["path"]
+ if "vsiPrefix" in parts:
+ path = parts["vsiPrefix"] + path
+
+ _, ext = os.path.splitext(parts["path"])
format = QgsVectorFileWriter.driverForExtension(ext)
return GdalConnectionDetails(
connection_string=path,
format=f'"{format}"',
- open_options=parts.get('openOptions', None),
- credential_options=parts.get('credentialOptions', None)
+ open_options=parts.get("openOptions", None),
+ credential_options=parts.get("credentialOptions", None),
)
elif provider.lower() == "gdal":
- parts = QgsProviderRegistry.instance().decodeUri('gdal',
- layer.source())
- if 'path' in parts:
- path = parts['path']
- if 'vsiPrefix' in parts:
- path = parts['vsiPrefix'] + path
+ parts = QgsProviderRegistry.instance().decodeUri("gdal", layer.source())
+ if "path" in parts:
+ path = parts["path"]
+ if "vsiPrefix" in parts:
+ path = parts["vsiPrefix"] + path
return GdalConnectionDetails(
connection_string=path,
- open_options=parts.get('openOptions', None),
- credential_options=parts.get('credentialOptions', None)
+ open_options=parts.get("openOptions", None),
+ credential_options=parts.get("credentialOptions", None),
)
- elif provider == 'postgresraster':
- gdal_source = ''
+ elif provider == "postgresraster":
+ gdal_source = ""
uri = layer.dataProvider().uri()
gdal_source = f"PG: {uri.connectionInfo()}"
schema = uri.schema()
@@ -481,28 +484,28 @@ def gdal_connection_details_from_layer(layer: QgsMapLayer) -> GdalConnectionDeta
gdal_source += f" schema='{schema}'"
table = uri.table()
gdal_source += f" table='{table}'"
- column = uri.param('column') or uri.geometryColumn()
+ column = uri.param("column") or uri.geometryColumn()
if column:
gdal_source += f" column='{column}'"
- is_tiled = any([layer.dataProvider().xSize() != layer.dataProvider().xBlockSize(),
- layer.dataProvider().ySize() != layer.dataProvider().yBlockSize()])
+ is_tiled = any(
+ [
+ layer.dataProvider().xSize() != layer.dataProvider().xBlockSize(),
+ layer.dataProvider().ySize() != layer.dataProvider().yBlockSize(),
+ ]
+ )
gdal_source += f" mode={2 if is_tiled else 1}"
where = layer.dataProvider().subsetString()
if where:
gdal_source += f" where='{where}'"
return GdalConnectionDetails(
- connection_string=gdal_source,
- format='"PostGISRaster"'
+ connection_string=gdal_source, format='"PostGISRaster"'
)
ogrstr = str(layer.source()).split("|")[0]
path, ext = os.path.splitext(ogrstr)
format = QgsVectorFileWriter.driverForExtension(ext)
- return GdalConnectionDetails(
- connection_string=ogrstr,
- format=f'"{format}"'
- )
+ return GdalConnectionDetails(connection_string=ogrstr, format=f'"{format}"')
@staticmethod
def ogrOutputLayerName(uri):
@@ -512,31 +515,31 @@ def ogrOutputLayerName(uri):
@staticmethod
def ogrLayerName(uri):
uri = uri.strip('"')
- if ' table=' in uri:
+ if " table=" in uri:
# table="schema"."table"
re_table_schema = re.compile(' table="([^"]*)"\\."([^"]*)"')
r = re_table_schema.search(uri)
if r:
- return r.groups()[0] + '.' + r.groups()[1]
+ return r.groups()[0] + "." + r.groups()[1]
# table="table"
re_table = re.compile(' table="([^"]*)"')
r = re_table.search(uri)
if r:
return r.groups()[0]
- elif 'layername' in uri:
- regex = re.compile('(layername=)([^|]*)')
+ elif "layername" in uri:
+ regex = re.compile("(layername=)([^|]*)")
r = regex.search(uri)
return r.groups()[1]
- fields = uri.split('|')
+ fields = uri.split("|")
basePath = fields[0]
fields = fields[1:]
layerid = 0
for f in fields:
- if f.startswith('layername='):
- return f.split('=')[1]
- if f.startswith('layerid='):
- layerid = int(f.split('=')[1])
+ if f.startswith("layername="):
+ return f.split("=")[1]
+ if f.startswith("layerid="):
+ layerid = int(f.split("=")[1])
try:
ds = gdal.OpenEx(basePath, gdal.OF_VECTOR)
@@ -553,14 +556,16 @@ def ogrLayerName(uri):
@staticmethod
def parseCreationOptions(value):
- parts = value.split('|')
+ parts = value.split("|")
options = []
for p in parts:
- options.extend(['-co', p])
+ options.extend(["-co", p])
return options
@staticmethod
- def writeLayerParameterToTextFile(filename, alg, parameters, parameter_name, context, quote=True, executing=False):
+ def writeLayerParameterToTextFile(
+ filename, alg, parameters, parameter_name, context, quote=True, executing=False
+ ):
listFile = QgsProcessingUtils.generateTempFilename(filename, context)
if executing:
@@ -572,8 +577,8 @@ def writeLayerParameterToTextFile(filename, alg, parameters, parameter_name, con
else:
layers.append(layer_details.connection_string)
- with open(listFile, 'w') as f:
- f.write('\n'.join(layers))
+ with open(listFile, "w") as f:
+ f.write("\n".join(layers))
return listFile
@@ -585,13 +590,17 @@ def gdal_crs_string(crs):
:param crs: crs to convert
:return: gdal friendly string
"""
- if crs.authid().upper().startswith('EPSG:') or crs.authid().upper().startswith('IGNF:') or crs.authid().upper().startswith('ESRI:'):
+ if (
+ crs.authid().upper().startswith("EPSG:")
+ or crs.authid().upper().startswith("IGNF:")
+ or crs.authid().upper().startswith("ESRI:")
+ ):
return crs.authid()
return crs.toWkt(QgsCoordinateReferenceSystem.WktVariant.WKT_PREFERRED_GDAL)
@classmethod
- def tr(cls, string, context=''):
- if context == '':
+ def tr(cls, string, context=""):
+ if context == "":
context = cls.__name__
return QCoreApplication.translate(context, string)
diff --git a/python/plugins/processing/algs/gdal/GridAverage.py b/python/plugins/processing/algs/gdal/GridAverage.py
index 167ccdd0965b..ce1c8f1da428 100644
--- a/python/plugins/processing/algs/gdal/GridAverage.py
+++ b/python/plugins/processing/algs/gdal/GridAverage.py
@@ -15,24 +15,26 @@
***************************************************************************
"""
-__author__ = 'Alexander Bruy'
-__date__ = 'October 2013'
-__copyright__ = '(C) 2013, Alexander Bruy'
+__author__ = "Alexander Bruy"
+__date__ = "October 2013"
+__copyright__ = "(C) 2013, Alexander Bruy"
import os
from qgis.PyQt.QtGui import QIcon
-from qgis.core import (QgsRasterFileWriter,
- QgsProcessing,
- QgsProcessingException,
- QgsProcessingParameterDefinition,
- QgsProcessingParameterFeatureSource,
- QgsProcessingParameterEnum,
- QgsProcessingParameterField,
- QgsProcessingParameterNumber,
- QgsProcessingParameterString,
- QgsProcessingParameterRasterDestination)
+from qgis.core import (
+ QgsRasterFileWriter,
+ QgsProcessing,
+ QgsProcessingException,
+ QgsProcessingParameterDefinition,
+ QgsProcessingParameterFeatureSource,
+ QgsProcessingParameterEnum,
+ QgsProcessingParameterField,
+ QgsProcessingParameterNumber,
+ QgsProcessingParameterString,
+ QgsProcessingParameterRasterDestination,
+)
from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm
from processing.algs.gdal.GdalUtils import GdalUtils
@@ -40,149 +42,219 @@
class GridAverage(GdalAlgorithm):
- INPUT = 'INPUT'
- Z_FIELD = 'Z_FIELD'
- RADIUS_1 = 'RADIUS_1'
- RADIUS_2 = 'RADIUS_2'
- MIN_POINTS = 'MIN_POINTS'
- ANGLE = 'ANGLE'
- NODATA = 'NODATA'
- OPTIONS = 'OPTIONS'
- EXTRA = 'EXTRA'
- DATA_TYPE = 'DATA_TYPE'
- OUTPUT = 'OUTPUT'
-
- TYPES = ['Byte', 'Int16', 'UInt16', 'UInt32', 'Int32', 'Float32', 'Float64', 'CInt16', 'CInt32', 'CFloat32', 'CFloat64', 'Int8']
+ INPUT = "INPUT"
+ Z_FIELD = "Z_FIELD"
+ RADIUS_1 = "RADIUS_1"
+ RADIUS_2 = "RADIUS_2"
+ MIN_POINTS = "MIN_POINTS"
+ ANGLE = "ANGLE"
+ NODATA = "NODATA"
+ OPTIONS = "OPTIONS"
+ EXTRA = "EXTRA"
+ DATA_TYPE = "DATA_TYPE"
+ OUTPUT = "OUTPUT"
+
+ TYPES = [
+ "Byte",
+ "Int16",
+ "UInt16",
+ "UInt32",
+ "Int32",
+ "Float32",
+ "Float64",
+ "CInt16",
+ "CInt32",
+ "CFloat32",
+ "CFloat64",
+ "Int8",
+ ]
def __init__(self):
super().__init__()
def initAlgorithm(self, config=None):
- self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT,
- self.tr('Point layer'),
- [QgsProcessing.SourceType.TypeVectorPoint]))
-
- z_field_param = QgsProcessingParameterField(self.Z_FIELD,
- self.tr('Z value from field'),
- None,
- self.INPUT,
- QgsProcessingParameterField.DataType.Numeric,
- optional=True)
- z_field_param.setFlags(z_field_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
+ self.addParameter(
+ QgsProcessingParameterFeatureSource(
+ self.INPUT,
+ self.tr("Point layer"),
+ [QgsProcessing.SourceType.TypeVectorPoint],
+ )
+ )
+
+ z_field_param = QgsProcessingParameterField(
+ self.Z_FIELD,
+ self.tr("Z value from field"),
+ None,
+ self.INPUT,
+ QgsProcessingParameterField.DataType.Numeric,
+ optional=True,
+ )
+ z_field_param.setFlags(
+ z_field_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
self.addParameter(z_field_param)
- self.addParameter(QgsProcessingParameterNumber(self.RADIUS_1,
- self.tr('The first radius of search ellipse'),
- type=QgsProcessingParameterNumber.Type.Double,
- minValue=0.0,
- defaultValue=0.0))
- self.addParameter(QgsProcessingParameterNumber(self.RADIUS_2,
- self.tr('The second radius of search ellipse'),
- type=QgsProcessingParameterNumber.Type.Double,
- minValue=0.0,
- defaultValue=0.0))
- self.addParameter(QgsProcessingParameterNumber(self.ANGLE,
- self.tr('Angle of search ellipse rotation in degrees (counter clockwise)'),
- type=QgsProcessingParameterNumber.Type.Double,
- minValue=0.0,
- maxValue=360.0,
- defaultValue=0.0))
- self.addParameter(QgsProcessingParameterNumber(self.MIN_POINTS,
- self.tr('Minimum number of data points to use'),
- type=QgsProcessingParameterNumber.Type.Integer,
- minValue=0,
- defaultValue=0))
- self.addParameter(QgsProcessingParameterNumber(self.NODATA,
- self.tr('NODATA marker to fill empty points'),
- type=QgsProcessingParameterNumber.Type.Double,
- defaultValue=0.0))
-
- options_param = QgsProcessingParameterString(self.OPTIONS,
- self.tr('Additional creation options'),
- defaultValue='',
- optional=True)
- options_param.setFlags(options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
- options_param.setMetadata({'widget_wrapper': {'widget_type': 'rasteroptions'}})
+ self.addParameter(
+ QgsProcessingParameterNumber(
+ self.RADIUS_1,
+ self.tr("The first radius of search ellipse"),
+ type=QgsProcessingParameterNumber.Type.Double,
+ minValue=0.0,
+ defaultValue=0.0,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterNumber(
+ self.RADIUS_2,
+ self.tr("The second radius of search ellipse"),
+ type=QgsProcessingParameterNumber.Type.Double,
+ minValue=0.0,
+ defaultValue=0.0,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterNumber(
+ self.ANGLE,
+ self.tr(
+ "Angle of search ellipse rotation in degrees (counter clockwise)"
+ ),
+ type=QgsProcessingParameterNumber.Type.Double,
+ minValue=0.0,
+ maxValue=360.0,
+ defaultValue=0.0,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterNumber(
+ self.MIN_POINTS,
+ self.tr("Minimum number of data points to use"),
+ type=QgsProcessingParameterNumber.Type.Integer,
+ minValue=0,
+ defaultValue=0,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterNumber(
+ self.NODATA,
+ self.tr("NODATA marker to fill empty points"),
+ type=QgsProcessingParameterNumber.Type.Double,
+ defaultValue=0.0,
+ )
+ )
+
+ options_param = QgsProcessingParameterString(
+ self.OPTIONS,
+ self.tr("Additional creation options"),
+ defaultValue="",
+ optional=True,
+ )
+ options_param.setFlags(
+ options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
+ options_param.setMetadata({"widget_wrapper": {"widget_type": "rasteroptions"}})
self.addParameter(options_param)
- extra_param = QgsProcessingParameterString(self.EXTRA,
- self.tr('Additional command-line parameters'),
- defaultValue=None,
- optional=True)
- extra_param.setFlags(extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
+ extra_param = QgsProcessingParameterString(
+ self.EXTRA,
+ self.tr("Additional command-line parameters"),
+ defaultValue=None,
+ optional=True,
+ )
+ extra_param.setFlags(
+ extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
self.addParameter(extra_param)
- dataType_param = QgsProcessingParameterEnum(self.DATA_TYPE,
- self.tr('Output data type'),
- self.TYPES,
- allowMultiple=False,
- defaultValue=5)
- dataType_param.setFlags(dataType_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
+ dataType_param = QgsProcessingParameterEnum(
+ self.DATA_TYPE,
+ self.tr("Output data type"),
+ self.TYPES,
+ allowMultiple=False,
+ defaultValue=5,
+ )
+ dataType_param.setFlags(
+ dataType_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
self.addParameter(dataType_param)
- self.addParameter(QgsProcessingParameterRasterDestination(self.OUTPUT,
- self.tr('Interpolated (moving average)')))
+ self.addParameter(
+ QgsProcessingParameterRasterDestination(
+ self.OUTPUT, self.tr("Interpolated (moving average)")
+ )
+ )
def name(self):
- return 'gridaverage'
+ return "gridaverage"
def displayName(self):
- return self.tr('Grid (Moving average)')
+ return self.tr("Grid (Moving average)")
def group(self):
- return self.tr('Raster analysis')
+ return self.tr("Raster analysis")
def groupId(self):
- return 'rasteranalysis'
+ return "rasteranalysis"
def icon(self):
- return QIcon(os.path.join(pluginPath, 'images', 'gdaltools', 'grid.png'))
+ return QIcon(os.path.join(pluginPath, "images", "gdaltools", "grid.png"))
def commandName(self):
- return 'gdal_grid'
+ return "gdal_grid"
def getConsoleCommands(self, parameters, context, feedback, executing=True):
- input_details = self.getOgrCompatibleSource(self.INPUT,
- parameters, context,
- feedback, executing)
+ input_details = self.getOgrCompatibleSource(
+ self.INPUT, parameters, context, feedback, executing
+ )
- arguments = ['-l']
+ arguments = ["-l"]
arguments.append(input_details.layer_name)
fieldName = self.parameterAsString(parameters, self.Z_FIELD, context)
if fieldName:
- arguments.append('-zfield')
+ arguments.append("-zfield")
arguments.append(fieldName)
- params = 'average'
- params += f':radius1={self.parameterAsDouble(parameters, self.RADIUS_1, context)}'
- params += f':radius2={self.parameterAsDouble(parameters, self.RADIUS_2, context)}'
- params += f':angle={self.parameterAsDouble(parameters, self.ANGLE, context)}'
- params += f':min_points={self.parameterAsInt(parameters, self.MIN_POINTS, context)}'
- params += f':nodata={self.parameterAsDouble(parameters, self.NODATA, context)}'
-
- arguments.append('-a')
+ params = "average"
+ params += (
+ f":radius1={self.parameterAsDouble(parameters, self.RADIUS_1, context)}"
+ )
+ params += (
+ f":radius2={self.parameterAsDouble(parameters, self.RADIUS_2, context)}"
+ )
+ params += f":angle={self.parameterAsDouble(parameters, self.ANGLE, context)}"
+ params += (
+ f":min_points={self.parameterAsInt(parameters, self.MIN_POINTS, context)}"
+ )
+ params += f":nodata={self.parameterAsDouble(parameters, self.NODATA, context)}"
+
+ arguments.append("-a")
arguments.append(params)
data_type = self.parameterAsEnum(parameters, self.DATA_TYPE, context)
- if self.TYPES[data_type] == 'Int8' and GdalUtils.version() < 3070000:
- raise QgsProcessingException(self.tr('Int8 data type requires GDAL version 3.7 or later'))
+ if self.TYPES[data_type] == "Int8" and GdalUtils.version() < 3070000:
+ raise QgsProcessingException(
+ self.tr("Int8 data type requires GDAL version 3.7 or later")
+ )
- arguments.append('-ot ' + self.TYPES[data_type])
+ arguments.append("-ot " + self.TYPES[data_type])
out = self.parameterAsOutputLayer(parameters, self.OUTPUT, context)
self.setOutputValue(self.OUTPUT, out)
output_format = QgsRasterFileWriter.driverForExtension(os.path.splitext(out)[1])
if not output_format:
- raise QgsProcessingException(self.tr('Output format is invalid'))
+ raise QgsProcessingException(self.tr("Output format is invalid"))
- arguments.append('-of')
+ arguments.append("-of")
arguments.append(output_format)
if input_details.open_options:
if GdalUtils.version() < 3070000:
- raise QgsProcessingException(self.tr('Open options are not supported by gdal_grid version {} (requires GDAL version 3.7 or later)'.format(GdalUtils.readableVersion())))
+ raise QgsProcessingException(
+ self.tr(
+ f"Open options are not supported by gdal_grid version {GdalUtils.readableVersion()} (requires GDAL version 3.7 or later)"
+ )
+ )
arguments.extend(input_details.open_options_as_arguments())
@@ -190,7 +262,7 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True):
if options:
arguments.extend(GdalUtils.parseCreationOptions(options))
- if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ''):
+ if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ""):
extra = self.parameterAsString(parameters, self.EXTRA, context)
arguments.append(extra)
diff --git a/python/plugins/processing/algs/gdal/GridDataMetrics.py b/python/plugins/processing/algs/gdal/GridDataMetrics.py
index 7eb604033264..f7b61cdd3a5f 100644
--- a/python/plugins/processing/algs/gdal/GridDataMetrics.py
+++ b/python/plugins/processing/algs/gdal/GridDataMetrics.py
@@ -15,24 +15,26 @@
***************************************************************************
"""
-__author__ = 'Alexander Bruy'
-__date__ = 'October 2013'
-__copyright__ = '(C) 2013, Alexander Bruy'
+__author__ = "Alexander Bruy"
+__date__ = "October 2013"
+__copyright__ = "(C) 2013, Alexander Bruy"
import os
from qgis.PyQt.QtGui import QIcon
-from qgis.core import (QgsRasterFileWriter,
- QgsProcessing,
- QgsProcessingException,
- QgsProcessingParameterDefinition,
- QgsProcessingParameterFeatureSource,
- QgsProcessingParameterEnum,
- QgsProcessingParameterField,
- QgsProcessingParameterNumber,
- QgsProcessingParameterString,
- QgsProcessingParameterRasterDestination)
+from qgis.core import (
+ QgsRasterFileWriter,
+ QgsProcessing,
+ QgsProcessingException,
+ QgsProcessingParameterDefinition,
+ QgsProcessingParameterFeatureSource,
+ QgsProcessingParameterEnum,
+ QgsProcessingParameterField,
+ QgsProcessingParameterNumber,
+ QgsProcessingParameterString,
+ QgsProcessingParameterRasterDestination,
+)
from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm
from processing.algs.gdal.GdalUtils import GdalUtils
@@ -40,163 +42,236 @@
class GridDataMetrics(GdalAlgorithm):
- INPUT = 'INPUT'
- Z_FIELD = 'Z_FIELD'
- METRIC = 'METRIC'
- RADIUS_1 = 'RADIUS_1'
- RADIUS_2 = 'RADIUS_2'
- MIN_POINTS = 'MIN_POINTS'
- ANGLE = 'ANGLE'
- NODATA = 'NODATA'
- OPTIONS = 'OPTIONS'
- EXTRA = 'EXTRA'
- DATA_TYPE = 'DATA_TYPE'
- OUTPUT = 'OUTPUT'
-
- TYPES = ['Byte', 'Int16', 'UInt16', 'UInt32', 'Int32', 'Float32', 'Float64', 'CInt16', 'CInt32', 'CFloat32', 'CFloat64', 'Int8']
+ INPUT = "INPUT"
+ Z_FIELD = "Z_FIELD"
+ METRIC = "METRIC"
+ RADIUS_1 = "RADIUS_1"
+ RADIUS_2 = "RADIUS_2"
+ MIN_POINTS = "MIN_POINTS"
+ ANGLE = "ANGLE"
+ NODATA = "NODATA"
+ OPTIONS = "OPTIONS"
+ EXTRA = "EXTRA"
+ DATA_TYPE = "DATA_TYPE"
+ OUTPUT = "OUTPUT"
+
+ TYPES = [
+ "Byte",
+ "Int16",
+ "UInt16",
+ "UInt32",
+ "Int32",
+ "Float32",
+ "Float64",
+ "CInt16",
+ "CInt32",
+ "CFloat32",
+ "CFloat64",
+ "Int8",
+ ]
def __init__(self):
super().__init__()
def initAlgorithm(self, config=None):
- self.metrics = ((self.tr('Minimum'), 'minimum'),
- (self.tr('Maximum'), 'maximum'),
- (self.tr('Range'), 'range'),
- (self.tr('Count'), 'count'),
- (self.tr('Average distance'), 'average_distance'),
- (self.tr('Average distance between points'), 'average_distance_pts'))
-
- self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT,
- self.tr('Point layer'),
- [QgsProcessing.SourceType.TypeVectorPoint]))
-
- z_field_param = QgsProcessingParameterField(self.Z_FIELD,
- self.tr('Z value from field'),
- None,
- self.INPUT,
- QgsProcessingParameterField.DataType.Numeric,
- optional=True)
- z_field_param.setFlags(z_field_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
+ self.metrics = (
+ (self.tr("Minimum"), "minimum"),
+ (self.tr("Maximum"), "maximum"),
+ (self.tr("Range"), "range"),
+ (self.tr("Count"), "count"),
+ (self.tr("Average distance"), "average_distance"),
+ (self.tr("Average distance between points"), "average_distance_pts"),
+ )
+
+ self.addParameter(
+ QgsProcessingParameterFeatureSource(
+ self.INPUT,
+ self.tr("Point layer"),
+ [QgsProcessing.SourceType.TypeVectorPoint],
+ )
+ )
+
+ z_field_param = QgsProcessingParameterField(
+ self.Z_FIELD,
+ self.tr("Z value from field"),
+ None,
+ self.INPUT,
+ QgsProcessingParameterField.DataType.Numeric,
+ optional=True,
+ )
+ z_field_param.setFlags(
+ z_field_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
self.addParameter(z_field_param)
- self.addParameter(QgsProcessingParameterEnum(self.METRIC,
- self.tr('Data metric to use'),
- options=[i[0] for i in self.metrics],
- allowMultiple=False,
- defaultValue=0))
- self.addParameter(QgsProcessingParameterNumber(self.RADIUS_1,
- self.tr('The first radius of search ellipse'),
- type=QgsProcessingParameterNumber.Type.Double,
- minValue=0.0,
- defaultValue=0.0))
- self.addParameter(QgsProcessingParameterNumber(self.RADIUS_2,
- self.tr('The second radius of search ellipse'),
- type=QgsProcessingParameterNumber.Type.Double,
- minValue=0.0,
- defaultValue=0.0))
- self.addParameter(QgsProcessingParameterNumber(self.ANGLE,
- self.tr('Angle of search ellipse rotation in degrees (counter clockwise)'),
- type=QgsProcessingParameterNumber.Type.Double,
- minValue=0.0,
- maxValue=360.0,
- defaultValue=0.0))
- self.addParameter(QgsProcessingParameterNumber(self.MIN_POINTS,
- self.tr('Minimum number of data points to use'),
- type=QgsProcessingParameterNumber.Type.Integer,
- minValue=0,
- defaultValue=0))
- self.addParameter(QgsProcessingParameterNumber(self.NODATA,
- self.tr('NODATA marker to fill empty points'),
- type=QgsProcessingParameterNumber.Type.Double,
- defaultValue=0.0))
-
- options_param = QgsProcessingParameterString(self.OPTIONS,
- self.tr('Additional creation options'),
- defaultValue='',
- optional=True)
- options_param.setFlags(options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
- options_param.setMetadata({'widget_wrapper': {'widget_type': 'rasteroptions'}})
+ self.addParameter(
+ QgsProcessingParameterEnum(
+ self.METRIC,
+ self.tr("Data metric to use"),
+ options=[i[0] for i in self.metrics],
+ allowMultiple=False,
+ defaultValue=0,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterNumber(
+ self.RADIUS_1,
+ self.tr("The first radius of search ellipse"),
+ type=QgsProcessingParameterNumber.Type.Double,
+ minValue=0.0,
+ defaultValue=0.0,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterNumber(
+ self.RADIUS_2,
+ self.tr("The second radius of search ellipse"),
+ type=QgsProcessingParameterNumber.Type.Double,
+ minValue=0.0,
+ defaultValue=0.0,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterNumber(
+ self.ANGLE,
+ self.tr(
+ "Angle of search ellipse rotation in degrees (counter clockwise)"
+ ),
+ type=QgsProcessingParameterNumber.Type.Double,
+ minValue=0.0,
+ maxValue=360.0,
+ defaultValue=0.0,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterNumber(
+ self.MIN_POINTS,
+ self.tr("Minimum number of data points to use"),
+ type=QgsProcessingParameterNumber.Type.Integer,
+ minValue=0,
+ defaultValue=0,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterNumber(
+ self.NODATA,
+ self.tr("NODATA marker to fill empty points"),
+ type=QgsProcessingParameterNumber.Type.Double,
+ defaultValue=0.0,
+ )
+ )
+
+ options_param = QgsProcessingParameterString(
+ self.OPTIONS,
+ self.tr("Additional creation options"),
+ defaultValue="",
+ optional=True,
+ )
+ options_param.setFlags(
+ options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
+ options_param.setMetadata({"widget_wrapper": {"widget_type": "rasteroptions"}})
self.addParameter(options_param)
- extra_param = QgsProcessingParameterString(self.EXTRA,
- self.tr('Additional command-line parameters'),
- defaultValue=None,
- optional=True)
- extra_param.setFlags(extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
+ extra_param = QgsProcessingParameterString(
+ self.EXTRA,
+ self.tr("Additional command-line parameters"),
+ defaultValue=None,
+ optional=True,
+ )
+ extra_param.setFlags(
+ extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
self.addParameter(extra_param)
- dataType_param = QgsProcessingParameterEnum(self.DATA_TYPE,
- self.tr('Output data type'),
- self.TYPES,
- allowMultiple=False,
- defaultValue=5)
- dataType_param.setFlags(dataType_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
+ dataType_param = QgsProcessingParameterEnum(
+ self.DATA_TYPE,
+ self.tr("Output data type"),
+ self.TYPES,
+ allowMultiple=False,
+ defaultValue=5,
+ )
+ dataType_param.setFlags(
+ dataType_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
self.addParameter(dataType_param)
- self.addParameter(QgsProcessingParameterRasterDestination(self.OUTPUT,
- self.tr('Interpolated (data metrics)')))
+ self.addParameter(
+ QgsProcessingParameterRasterDestination(
+ self.OUTPUT, self.tr("Interpolated (data metrics)")
+ )
+ )
def name(self):
- return 'griddatametrics'
+ return "griddatametrics"
def displayName(self):
- return self.tr('Grid (Data metrics)')
+ return self.tr("Grid (Data metrics)")
def icon(self):
- return QIcon(os.path.join(pluginPath, 'images', 'gdaltools', 'grid.png'))
+ return QIcon(os.path.join(pluginPath, "images", "gdaltools", "grid.png"))
def group(self):
- return self.tr('Raster analysis')
+ return self.tr("Raster analysis")
def groupId(self):
- return 'rasteranalysis'
+ return "rasteranalysis"
def commandName(self):
- return 'gdal_grid'
+ return "gdal_grid"
def getConsoleCommands(self, parameters, context, feedback, executing=True):
- input_details = self.getOgrCompatibleSource(self.INPUT,
- parameters, context,
- feedback, executing)
-
- arguments = [
- '-l',
- input_details.layer_name
- ]
+ input_details = self.getOgrCompatibleSource(
+ self.INPUT, parameters, context, feedback, executing
+ )
+
+ arguments = ["-l", input_details.layer_name]
fieldName = self.parameterAsString(parameters, self.Z_FIELD, context)
if fieldName:
- arguments.append('-zfield')
+ arguments.append("-zfield")
arguments.append(fieldName)
params = self.metrics[self.parameterAsEnum(parameters, self.METRIC, context)][1]
- params += f':radius1={self.parameterAsDouble(parameters, self.RADIUS_1, context)}'
- params += f':radius2={self.parameterAsDouble(parameters, self.RADIUS_2, context)}'
- params += f':angle={self.parameterAsDouble(parameters, self.ANGLE, context)}'
- params += f':min_points={self.parameterAsInt(parameters, self.MIN_POINTS, context)}'
- params += f':nodata={self.parameterAsDouble(parameters, self.NODATA, context)}'
-
- arguments.append('-a')
+ params += (
+ f":radius1={self.parameterAsDouble(parameters, self.RADIUS_1, context)}"
+ )
+ params += (
+ f":radius2={self.parameterAsDouble(parameters, self.RADIUS_2, context)}"
+ )
+ params += f":angle={self.parameterAsDouble(parameters, self.ANGLE, context)}"
+ params += (
+ f":min_points={self.parameterAsInt(parameters, self.MIN_POINTS, context)}"
+ )
+ params += f":nodata={self.parameterAsDouble(parameters, self.NODATA, context)}"
+
+ arguments.append("-a")
arguments.append(params)
data_type = self.parameterAsEnum(parameters, self.DATA_TYPE, context)
- if self.TYPES[data_type] == 'Int8' and GdalUtils.version() < 3070000:
- raise QgsProcessingException(self.tr('Int8 data type requires GDAL version 3.7 or later'))
+ if self.TYPES[data_type] == "Int8" and GdalUtils.version() < 3070000:
+ raise QgsProcessingException(
+ self.tr("Int8 data type requires GDAL version 3.7 or later")
+ )
- arguments.append('-ot ' + self.TYPES[data_type])
+ arguments.append("-ot " + self.TYPES[data_type])
out = self.parameterAsOutputLayer(parameters, self.OUTPUT, context)
self.setOutputValue(self.OUTPUT, out)
output_format = QgsRasterFileWriter.driverForExtension(os.path.splitext(out)[1])
if not output_format:
- raise QgsProcessingException(self.tr('Output format is invalid'))
+ raise QgsProcessingException(self.tr("Output format is invalid"))
- arguments.append('-of')
+ arguments.append("-of")
arguments.append(output_format)
if input_details.open_options:
if GdalUtils.version() < 3070000:
- raise QgsProcessingException(self.tr('Open options are not supported by gdal_grid version {} (requires GDAL version 3.7 or later)'.format(GdalUtils.readableVersion())))
+ raise QgsProcessingException(
+ self.tr(
+ f"Open options are not supported by gdal_grid version {GdalUtils.readableVersion()} (requires GDAL version 3.7 or later)"
+ )
+ )
arguments.extend(input_details.open_options_as_arguments())
@@ -205,7 +280,7 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True):
if options:
arguments.extend(GdalUtils.parseCreationOptions(options))
- if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ''):
+ if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ""):
extra = self.parameterAsString(parameters, self.EXTRA, context)
arguments.append(extra)
diff --git a/python/plugins/processing/algs/gdal/GridInverseDistance.py b/python/plugins/processing/algs/gdal/GridInverseDistance.py
index 77e2e57fd5a4..3b2ad0a81542 100644
--- a/python/plugins/processing/algs/gdal/GridInverseDistance.py
+++ b/python/plugins/processing/algs/gdal/GridInverseDistance.py
@@ -15,24 +15,26 @@
***************************************************************************
"""
-__author__ = 'Alexander Bruy'
-__date__ = 'October 2013'
-__copyright__ = '(C) 2013, Alexander Bruy'
+__author__ = "Alexander Bruy"
+__date__ = "October 2013"
+__copyright__ = "(C) 2013, Alexander Bruy"
import os
from qgis.PyQt.QtGui import QIcon
-from qgis.core import (QgsRasterFileWriter,
- QgsProcessing,
- QgsProcessingException,
- QgsProcessingParameterDefinition,
- QgsProcessingParameterFeatureSource,
- QgsProcessingParameterEnum,
- QgsProcessingParameterField,
- QgsProcessingParameterNumber,
- QgsProcessingParameterString,
- QgsProcessingParameterRasterDestination)
+from qgis.core import (
+ QgsRasterFileWriter,
+ QgsProcessing,
+ QgsProcessingException,
+ QgsProcessingParameterDefinition,
+ QgsProcessingParameterFeatureSource,
+ QgsProcessingParameterEnum,
+ QgsProcessingParameterField,
+ QgsProcessingParameterNumber,
+ QgsProcessingParameterString,
+ QgsProcessingParameterRasterDestination,
+)
from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm
from processing.algs.gdal.GdalUtils import GdalUtils
@@ -40,172 +42,255 @@
class GridInverseDistance(GdalAlgorithm):
- INPUT = 'INPUT'
- Z_FIELD = 'Z_FIELD'
- POWER = 'POWER'
- SMOOTHING = 'SMOOTHING'
- RADIUS_1 = 'RADIUS_1'
- RADIUS_2 = 'RADIUS_2'
- MAX_POINTS = 'MAX_POINTS'
- MIN_POINTS = 'MIN_POINTS'
- ANGLE = 'ANGLE'
- NODATA = 'NODATA'
- OPTIONS = 'OPTIONS'
- EXTRA = 'EXTRA'
- DATA_TYPE = 'DATA_TYPE'
- OUTPUT = 'OUTPUT'
-
- TYPES = ['Byte', 'Int16', 'UInt16', 'UInt32', 'Int32', 'Float32', 'Float64', 'CInt16', 'CInt32', 'CFloat32', 'CFloat64', 'Int8']
+ INPUT = "INPUT"
+ Z_FIELD = "Z_FIELD"
+ POWER = "POWER"
+ SMOOTHING = "SMOOTHING"
+ RADIUS_1 = "RADIUS_1"
+ RADIUS_2 = "RADIUS_2"
+ MAX_POINTS = "MAX_POINTS"
+ MIN_POINTS = "MIN_POINTS"
+ ANGLE = "ANGLE"
+ NODATA = "NODATA"
+ OPTIONS = "OPTIONS"
+ EXTRA = "EXTRA"
+ DATA_TYPE = "DATA_TYPE"
+ OUTPUT = "OUTPUT"
+
+ TYPES = [
+ "Byte",
+ "Int16",
+ "UInt16",
+ "UInt32",
+ "Int32",
+ "Float32",
+ "Float64",
+ "CInt16",
+ "CInt32",
+ "CFloat32",
+ "CFloat64",
+ "Int8",
+ ]
def __init__(self):
super().__init__()
def initAlgorithm(self, config=None):
- self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT,
- self.tr('Point layer'),
- [QgsProcessing.SourceType.TypeVectorPoint]))
-
- z_field_param = QgsProcessingParameterField(self.Z_FIELD,
- self.tr('Z value from field'),
- None,
- self.INPUT,
- QgsProcessingParameterField.DataType.Numeric,
- optional=True)
- z_field_param.setFlags(z_field_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
+ self.addParameter(
+ QgsProcessingParameterFeatureSource(
+ self.INPUT,
+ self.tr("Point layer"),
+ [QgsProcessing.SourceType.TypeVectorPoint],
+ )
+ )
+
+ z_field_param = QgsProcessingParameterField(
+ self.Z_FIELD,
+ self.tr("Z value from field"),
+ None,
+ self.INPUT,
+ QgsProcessingParameterField.DataType.Numeric,
+ optional=True,
+ )
+ z_field_param.setFlags(
+ z_field_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
self.addParameter(z_field_param)
- self.addParameter(QgsProcessingParameterNumber(self.POWER,
- self.tr('Weighting power'),
- type=QgsProcessingParameterNumber.Type.Double,
- minValue=0.0,
- maxValue=100.0,
- defaultValue=2.0))
- self.addParameter(QgsProcessingParameterNumber(self.SMOOTHING,
- self.tr('Smoothing'),
- type=QgsProcessingParameterNumber.Type.Double,
- minValue=0.0,
- defaultValue=0.0))
- self.addParameter(QgsProcessingParameterNumber(self.RADIUS_1,
- self.tr('The first radius of search ellipse'),
- type=QgsProcessingParameterNumber.Type.Double,
- minValue=0.0,
- defaultValue=0.0))
- self.addParameter(QgsProcessingParameterNumber(self.RADIUS_2,
- self.tr('The second radius of search ellipse'),
- type=QgsProcessingParameterNumber.Type.Double,
- minValue=0.0,
- defaultValue=0.0))
- self.addParameter(QgsProcessingParameterNumber(self.ANGLE,
- self.tr('Angle of search ellipse rotation in degrees (counter clockwise)'),
- type=QgsProcessingParameterNumber.Type.Double,
- minValue=0.0,
- maxValue=360.0,
- defaultValue=0.0))
- self.addParameter(QgsProcessingParameterNumber(self.MAX_POINTS,
- self.tr('Maximum number of data points to use'),
- type=QgsProcessingParameterNumber.Type.Integer,
- minValue=0,
- defaultValue=0))
- self.addParameter(QgsProcessingParameterNumber(self.MIN_POINTS,
- self.tr('Minimum number of data points to use'),
- type=QgsProcessingParameterNumber.Type.Integer,
- minValue=0,
- defaultValue=0))
- self.addParameter(QgsProcessingParameterNumber(self.NODATA,
- self.tr('NODATA marker to fill empty points'),
- type=QgsProcessingParameterNumber.Type.Double,
- defaultValue=0.0))
-
- options_param = QgsProcessingParameterString(self.OPTIONS,
- self.tr('Additional creation options'),
- defaultValue='',
- optional=True)
- options_param.setFlags(options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
- options_param.setMetadata({'widget_wrapper': {'widget_type': 'rasteroptions'}})
+ self.addParameter(
+ QgsProcessingParameterNumber(
+ self.POWER,
+ self.tr("Weighting power"),
+ type=QgsProcessingParameterNumber.Type.Double,
+ minValue=0.0,
+ maxValue=100.0,
+ defaultValue=2.0,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterNumber(
+ self.SMOOTHING,
+ self.tr("Smoothing"),
+ type=QgsProcessingParameterNumber.Type.Double,
+ minValue=0.0,
+ defaultValue=0.0,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterNumber(
+ self.RADIUS_1,
+ self.tr("The first radius of search ellipse"),
+ type=QgsProcessingParameterNumber.Type.Double,
+ minValue=0.0,
+ defaultValue=0.0,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterNumber(
+ self.RADIUS_2,
+ self.tr("The second radius of search ellipse"),
+ type=QgsProcessingParameterNumber.Type.Double,
+ minValue=0.0,
+ defaultValue=0.0,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterNumber(
+ self.ANGLE,
+ self.tr(
+ "Angle of search ellipse rotation in degrees (counter clockwise)"
+ ),
+ type=QgsProcessingParameterNumber.Type.Double,
+ minValue=0.0,
+ maxValue=360.0,
+ defaultValue=0.0,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterNumber(
+ self.MAX_POINTS,
+ self.tr("Maximum number of data points to use"),
+ type=QgsProcessingParameterNumber.Type.Integer,
+ minValue=0,
+ defaultValue=0,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterNumber(
+ self.MIN_POINTS,
+ self.tr("Minimum number of data points to use"),
+ type=QgsProcessingParameterNumber.Type.Integer,
+ minValue=0,
+ defaultValue=0,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterNumber(
+ self.NODATA,
+ self.tr("NODATA marker to fill empty points"),
+ type=QgsProcessingParameterNumber.Type.Double,
+ defaultValue=0.0,
+ )
+ )
+
+ options_param = QgsProcessingParameterString(
+ self.OPTIONS,
+ self.tr("Additional creation options"),
+ defaultValue="",
+ optional=True,
+ )
+ options_param.setFlags(
+ options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
+ options_param.setMetadata({"widget_wrapper": {"widget_type": "rasteroptions"}})
self.addParameter(options_param)
- extra_param = QgsProcessingParameterString(self.EXTRA,
- self.tr('Additional command-line parameters'),
- defaultValue=None,
- optional=True)
- extra_param.setFlags(extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
+ extra_param = QgsProcessingParameterString(
+ self.EXTRA,
+ self.tr("Additional command-line parameters"),
+ defaultValue=None,
+ optional=True,
+ )
+ extra_param.setFlags(
+ extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
self.addParameter(extra_param)
- dataType_param = QgsProcessingParameterEnum(self.DATA_TYPE,
- self.tr('Output data type'),
- self.TYPES,
- allowMultiple=False,
- defaultValue=5)
- dataType_param.setFlags(dataType_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
+ dataType_param = QgsProcessingParameterEnum(
+ self.DATA_TYPE,
+ self.tr("Output data type"),
+ self.TYPES,
+ allowMultiple=False,
+ defaultValue=5,
+ )
+ dataType_param.setFlags(
+ dataType_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
self.addParameter(dataType_param)
- self.addParameter(QgsProcessingParameterRasterDestination(self.OUTPUT,
- self.tr('Interpolated (IDW)')))
+ self.addParameter(
+ QgsProcessingParameterRasterDestination(
+ self.OUTPUT, self.tr("Interpolated (IDW)")
+ )
+ )
def name(self):
- return 'gridinversedistance'
+ return "gridinversedistance"
def displayName(self):
- return self.tr('Grid (Inverse distance to a power)')
+ return self.tr("Grid (Inverse distance to a power)")
def group(self):
- return self.tr('Raster analysis')
+ return self.tr("Raster analysis")
def groupId(self):
- return 'rasteranalysis'
+ return "rasteranalysis"
def icon(self):
- return QIcon(os.path.join(pluginPath, 'images', 'gdaltools', 'grid.png'))
+ return QIcon(os.path.join(pluginPath, "images", "gdaltools", "grid.png"))
def commandName(self):
- return 'gdal_grid'
+ return "gdal_grid"
def getConsoleCommands(self, parameters, context, feedback, executing=True):
- input_details = self.getOgrCompatibleSource(self.INPUT,
- parameters, context,
- feedback, executing)
-
- arguments = [
- '-l',
- input_details.layer_name
- ]
+ input_details = self.getOgrCompatibleSource(
+ self.INPUT, parameters, context, feedback, executing
+ )
+
+ arguments = ["-l", input_details.layer_name]
fieldName = self.parameterAsString(parameters, self.Z_FIELD, context)
if fieldName:
- arguments.append('-zfield')
+ arguments.append("-zfield")
arguments.append(fieldName)
- params = 'invdist'
- params += f':power={self.parameterAsDouble(parameters, self.POWER, context)}'
- params += f':smoothing={self.parameterAsDouble(parameters, self.SMOOTHING, context)}'
- params += f':radius1={self.parameterAsDouble(parameters, self.RADIUS_1, context)}'
- params += f':radius2={self.parameterAsDouble(parameters, self.RADIUS_2, context)}'
- params += f':angle={self.parameterAsDouble(parameters, self.ANGLE, context)}'
- params += f':max_points={self.parameterAsInt(parameters, self.MAX_POINTS, context)}'
- params += f':min_points={self.parameterAsInt(parameters, self.MIN_POINTS, context)}'
- params += f':nodata={self.parameterAsDouble(parameters, self.NODATA, context)}'
-
- arguments.append('-a')
+ params = "invdist"
+ params += f":power={self.parameterAsDouble(parameters, self.POWER, context)}"
+ params += (
+ f":smoothing={self.parameterAsDouble(parameters, self.SMOOTHING, context)}"
+ )
+ params += (
+ f":radius1={self.parameterAsDouble(parameters, self.RADIUS_1, context)}"
+ )
+ params += (
+ f":radius2={self.parameterAsDouble(parameters, self.RADIUS_2, context)}"
+ )
+ params += f":angle={self.parameterAsDouble(parameters, self.ANGLE, context)}"
+ params += (
+ f":max_points={self.parameterAsInt(parameters, self.MAX_POINTS, context)}"
+ )
+ params += (
+ f":min_points={self.parameterAsInt(parameters, self.MIN_POINTS, context)}"
+ )
+ params += f":nodata={self.parameterAsDouble(parameters, self.NODATA, context)}"
+
+ arguments.append("-a")
arguments.append(params)
data_type = self.parameterAsEnum(parameters, self.DATA_TYPE, context)
- if self.TYPES[data_type] == 'Int8' and GdalUtils.version() < 3070000:
- raise QgsProcessingException(self.tr('Int8 data type requires GDAL version 3.7 or later'))
+ if self.TYPES[data_type] == "Int8" and GdalUtils.version() < 3070000:
+ raise QgsProcessingException(
+ self.tr("Int8 data type requires GDAL version 3.7 or later")
+ )
- arguments.append('-ot ' + self.TYPES[data_type])
+ arguments.append("-ot " + self.TYPES[data_type])
out = self.parameterAsOutputLayer(parameters, self.OUTPUT, context)
self.setOutputValue(self.OUTPUT, out)
output_format = QgsRasterFileWriter.driverForExtension(os.path.splitext(out)[1])
if not output_format:
- raise QgsProcessingException(self.tr('Output format is invalid'))
+ raise QgsProcessingException(self.tr("Output format is invalid"))
- arguments.append('-of')
+ arguments.append("-of")
arguments.append(output_format)
if input_details.open_options:
if GdalUtils.version() < 3070000:
- raise QgsProcessingException(self.tr('Open options are not supported by gdal_grid version {} (requires GDAL version 3.7 or later)'.format(GdalUtils.readableVersion())))
+ raise QgsProcessingException(
+ self.tr(
+ f"Open options are not supported by gdal_grid version {GdalUtils.readableVersion()} (requires GDAL version 3.7 or later)"
+ )
+ )
arguments.extend(input_details.open_options_as_arguments())
@@ -213,7 +298,7 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True):
if options:
arguments.extend(GdalUtils.parseCreationOptions(options))
- if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ''):
+ if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ""):
extra = self.parameterAsString(parameters, self.EXTRA, context)
arguments.append(extra)
diff --git a/python/plugins/processing/algs/gdal/GridInverseDistanceNearestNeighbor.py b/python/plugins/processing/algs/gdal/GridInverseDistanceNearestNeighbor.py
index 26e13f00b2b0..bce14acfdc97 100644
--- a/python/plugins/processing/algs/gdal/GridInverseDistanceNearestNeighbor.py
+++ b/python/plugins/processing/algs/gdal/GridInverseDistanceNearestNeighbor.py
@@ -15,24 +15,26 @@
***************************************************************************
"""
-__author__ = 'Alexander Bruy'
-__date__ = 'September 2017'
-__copyright__ = '(C) 2017, Alexander Bruy'
+__author__ = "Alexander Bruy"
+__date__ = "September 2017"
+__copyright__ = "(C) 2017, Alexander Bruy"
import os
from qgis.PyQt.QtGui import QIcon
-from qgis.core import (QgsRasterFileWriter,
- QgsProcessing,
- QgsProcessingException,
- QgsProcessingParameterDefinition,
- QgsProcessingParameterFeatureSource,
- QgsProcessingParameterEnum,
- QgsProcessingParameterField,
- QgsProcessingParameterNumber,
- QgsProcessingParameterString,
- QgsProcessingParameterRasterDestination)
+from qgis.core import (
+ QgsRasterFileWriter,
+ QgsProcessing,
+ QgsProcessingException,
+ QgsProcessingParameterDefinition,
+ QgsProcessingParameterFeatureSource,
+ QgsProcessingParameterEnum,
+ QgsProcessingParameterField,
+ QgsProcessingParameterNumber,
+ QgsProcessingParameterString,
+ QgsProcessingParameterRasterDestination,
+)
from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm
from processing.algs.gdal.GdalUtils import GdalUtils
@@ -40,157 +42,226 @@
class GridInverseDistanceNearestNeighbor(GdalAlgorithm):
- INPUT = 'INPUT'
- Z_FIELD = 'Z_FIELD'
- POWER = 'POWER'
- SMOOTHING = 'SMOOTHING'
- RADIUS = 'RADIUS'
- MAX_POINTS = 'MAX_POINTS'
- MIN_POINTS = 'MIN_POINTS'
- NODATA = 'NODATA'
- OPTIONS = 'OPTIONS'
- EXTRA = 'EXTRA'
- DATA_TYPE = 'DATA_TYPE'
- OUTPUT = 'OUTPUT'
-
- TYPES = ['Byte', 'Int16', 'UInt16', 'UInt32', 'Int32', 'Float32', 'Float64', 'CInt16', 'CInt32', 'CFloat32', 'CFloat64', 'Int8']
+ INPUT = "INPUT"
+ Z_FIELD = "Z_FIELD"
+ POWER = "POWER"
+ SMOOTHING = "SMOOTHING"
+ RADIUS = "RADIUS"
+ MAX_POINTS = "MAX_POINTS"
+ MIN_POINTS = "MIN_POINTS"
+ NODATA = "NODATA"
+ OPTIONS = "OPTIONS"
+ EXTRA = "EXTRA"
+ DATA_TYPE = "DATA_TYPE"
+ OUTPUT = "OUTPUT"
+
+ TYPES = [
+ "Byte",
+ "Int16",
+ "UInt16",
+ "UInt32",
+ "Int32",
+ "Float32",
+ "Float64",
+ "CInt16",
+ "CInt32",
+ "CFloat32",
+ "CFloat64",
+ "Int8",
+ ]
def __init__(self):
super().__init__()
def initAlgorithm(self, config=None):
- self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT,
- self.tr('Point layer'),
- [QgsProcessing.SourceType.TypeVectorPoint]))
-
- z_field_param = QgsProcessingParameterField(self.Z_FIELD,
- self.tr('Z value from field'),
- None,
- self.INPUT,
- QgsProcessingParameterField.DataType.Numeric,
- optional=True)
- z_field_param.setFlags(z_field_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
+ self.addParameter(
+ QgsProcessingParameterFeatureSource(
+ self.INPUT,
+ self.tr("Point layer"),
+ [QgsProcessing.SourceType.TypeVectorPoint],
+ )
+ )
+
+ z_field_param = QgsProcessingParameterField(
+ self.Z_FIELD,
+ self.tr("Z value from field"),
+ None,
+ self.INPUT,
+ QgsProcessingParameterField.DataType.Numeric,
+ optional=True,
+ )
+ z_field_param.setFlags(
+ z_field_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
self.addParameter(z_field_param)
- self.addParameter(QgsProcessingParameterNumber(self.POWER,
- self.tr('Weighting power'),
- type=QgsProcessingParameterNumber.Type.Double,
- minValue=0.0,
- maxValue=100.0,
- defaultValue=2.0))
- self.addParameter(QgsProcessingParameterNumber(self.SMOOTHING,
- self.tr('Smoothing'),
- type=QgsProcessingParameterNumber.Type.Double,
- minValue=0.0,
- defaultValue=0.0))
- self.addParameter(QgsProcessingParameterNumber(self.RADIUS,
- self.tr('The radius of the search circle'),
- type=QgsProcessingParameterNumber.Type.Double,
- minValue=0.0,
- defaultValue=1.0))
- self.addParameter(QgsProcessingParameterNumber(self.MAX_POINTS,
- self.tr('Maximum number of data points to use'),
- type=QgsProcessingParameterNumber.Type.Integer,
- minValue=0,
- defaultValue=12))
- self.addParameter(QgsProcessingParameterNumber(self.MIN_POINTS,
- self.tr('Minimum number of data points to use'),
- type=QgsProcessingParameterNumber.Type.Integer,
- minValue=0,
- defaultValue=0))
- self.addParameter(QgsProcessingParameterNumber(self.NODATA,
- self.tr('NODATA marker to fill empty points'),
- type=QgsProcessingParameterNumber.Type.Double,
- defaultValue=0.0))
-
- options_param = QgsProcessingParameterString(self.OPTIONS,
- self.tr('Additional creation options'),
- defaultValue='',
- optional=True)
- options_param.setFlags(options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
- options_param.setMetadata({'widget_wrapper': {'widget_type': 'rasteroptions'}})
+ self.addParameter(
+ QgsProcessingParameterNumber(
+ self.POWER,
+ self.tr("Weighting power"),
+ type=QgsProcessingParameterNumber.Type.Double,
+ minValue=0.0,
+ maxValue=100.0,
+ defaultValue=2.0,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterNumber(
+ self.SMOOTHING,
+ self.tr("Smoothing"),
+ type=QgsProcessingParameterNumber.Type.Double,
+ minValue=0.0,
+ defaultValue=0.0,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterNumber(
+ self.RADIUS,
+ self.tr("The radius of the search circle"),
+ type=QgsProcessingParameterNumber.Type.Double,
+ minValue=0.0,
+ defaultValue=1.0,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterNumber(
+ self.MAX_POINTS,
+ self.tr("Maximum number of data points to use"),
+ type=QgsProcessingParameterNumber.Type.Integer,
+ minValue=0,
+ defaultValue=12,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterNumber(
+ self.MIN_POINTS,
+ self.tr("Minimum number of data points to use"),
+ type=QgsProcessingParameterNumber.Type.Integer,
+ minValue=0,
+ defaultValue=0,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterNumber(
+ self.NODATA,
+ self.tr("NODATA marker to fill empty points"),
+ type=QgsProcessingParameterNumber.Type.Double,
+ defaultValue=0.0,
+ )
+ )
+
+ options_param = QgsProcessingParameterString(
+ self.OPTIONS,
+ self.tr("Additional creation options"),
+ defaultValue="",
+ optional=True,
+ )
+ options_param.setFlags(
+ options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
+ options_param.setMetadata({"widget_wrapper": {"widget_type": "rasteroptions"}})
self.addParameter(options_param)
- extra_param = QgsProcessingParameterString(self.EXTRA,
- self.tr('Additional command-line parameters'),
- defaultValue=None,
- optional=True)
- extra_param.setFlags(extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
+ extra_param = QgsProcessingParameterString(
+ self.EXTRA,
+ self.tr("Additional command-line parameters"),
+ defaultValue=None,
+ optional=True,
+ )
+ extra_param.setFlags(
+ extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
self.addParameter(extra_param)
- dataType_param = QgsProcessingParameterEnum(self.DATA_TYPE,
- self.tr('Output data type'),
- self.TYPES,
- allowMultiple=False,
- defaultValue=5)
- dataType_param.setFlags(dataType_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
+ dataType_param = QgsProcessingParameterEnum(
+ self.DATA_TYPE,
+ self.tr("Output data type"),
+ self.TYPES,
+ allowMultiple=False,
+ defaultValue=5,
+ )
+ dataType_param.setFlags(
+ dataType_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
self.addParameter(dataType_param)
- self.addParameter(QgsProcessingParameterRasterDestination(self.OUTPUT,
- self.tr('Interpolated (IDW with NN search)')))
+ self.addParameter(
+ QgsProcessingParameterRasterDestination(
+ self.OUTPUT, self.tr("Interpolated (IDW with NN search)")
+ )
+ )
def name(self):
- return 'gridinversedistancenearestneighbor'
+ return "gridinversedistancenearestneighbor"
def displayName(self):
- return self.tr('Grid (IDW with nearest neighbor searching)')
+ return self.tr("Grid (IDW with nearest neighbor searching)")
def group(self):
- return self.tr('Raster analysis')
+ return self.tr("Raster analysis")
def groupId(self):
- return 'rasteranalysis'
+ return "rasteranalysis"
def icon(self):
- return QIcon(os.path.join(pluginPath, 'images', 'gdaltools', 'grid.png'))
+ return QIcon(os.path.join(pluginPath, "images", "gdaltools", "grid.png"))
def commandName(self):
- return 'gdal_grid'
+ return "gdal_grid"
def getConsoleCommands(self, parameters, context, feedback, executing=True):
- input_details = self.getOgrCompatibleSource(self.INPUT,
- parameters, context,
- feedback, executing)
-
- arguments = [
- '-l',
- input_details.layer_name
- ]
+ input_details = self.getOgrCompatibleSource(
+ self.INPUT, parameters, context, feedback, executing
+ )
+
+ arguments = ["-l", input_details.layer_name]
fieldName = self.parameterAsString(parameters, self.Z_FIELD, context)
if fieldName:
- arguments.append('-zfield')
+ arguments.append("-zfield")
arguments.append(fieldName)
- params = 'invdistnn'
- params += f':power={self.parameterAsDouble(parameters, self.POWER, context)}'
- params += f':smoothing={self.parameterAsDouble(parameters, self.SMOOTHING, context)}'
- params += f':radius={self.parameterAsDouble(parameters, self.RADIUS, context)}'
- params += f':max_points={self.parameterAsInt(parameters, self.MAX_POINTS, context)}'
- params += f':min_points={self.parameterAsInt(parameters, self.MIN_POINTS, context)}'
- params += f':nodata={self.parameterAsDouble(parameters, self.NODATA, context)}'
-
- arguments.append('-a')
+ params = "invdistnn"
+ params += f":power={self.parameterAsDouble(parameters, self.POWER, context)}"
+ params += (
+ f":smoothing={self.parameterAsDouble(parameters, self.SMOOTHING, context)}"
+ )
+ params += f":radius={self.parameterAsDouble(parameters, self.RADIUS, context)}"
+ params += (
+ f":max_points={self.parameterAsInt(parameters, self.MAX_POINTS, context)}"
+ )
+ params += (
+ f":min_points={self.parameterAsInt(parameters, self.MIN_POINTS, context)}"
+ )
+ params += f":nodata={self.parameterAsDouble(parameters, self.NODATA, context)}"
+
+ arguments.append("-a")
arguments.append(params)
data_type = self.parameterAsEnum(parameters, self.DATA_TYPE, context)
- if self.TYPES[data_type] == 'Int8' and GdalUtils.version() < 3070000:
- raise QgsProcessingException(self.tr('Int8 data type requires GDAL version 3.7 or later'))
+ if self.TYPES[data_type] == "Int8" and GdalUtils.version() < 3070000:
+ raise QgsProcessingException(
+ self.tr("Int8 data type requires GDAL version 3.7 or later")
+ )
- arguments.append('-ot ' + self.TYPES[data_type])
+ arguments.append("-ot " + self.TYPES[data_type])
out = self.parameterAsOutputLayer(parameters, self.OUTPUT, context)
self.setOutputValue(self.OUTPUT, out)
output_format = QgsRasterFileWriter.driverForExtension(os.path.splitext(out)[1])
if not output_format:
- raise QgsProcessingException(self.tr('Output format is invalid'))
+ raise QgsProcessingException(self.tr("Output format is invalid"))
- arguments.append('-of')
+ arguments.append("-of")
arguments.append(output_format)
if input_details.open_options:
if GdalUtils.version() < 3070000:
- raise QgsProcessingException(self.tr('Open options are not supported by gdal_grid version {} (requires GDAL version 3.7 or later)'.format(GdalUtils.readableVersion())))
+ raise QgsProcessingException(
+ self.tr(
+ f"Open options are not supported by gdal_grid version {GdalUtils.readableVersion()} (requires GDAL version 3.7 or later)"
+ )
+ )
arguments.extend(input_details.open_options_as_arguments())
@@ -198,7 +269,7 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True):
if options:
arguments.extend(GdalUtils.parseCreationOptions(options))
- if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ''):
+ if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ""):
extra = self.parameterAsString(parameters, self.EXTRA, context)
arguments.append(extra)
diff --git a/python/plugins/processing/algs/gdal/GridLinear.py b/python/plugins/processing/algs/gdal/GridLinear.py
index f3ec203d8966..bd40da18f5ba 100644
--- a/python/plugins/processing/algs/gdal/GridLinear.py
+++ b/python/plugins/processing/algs/gdal/GridLinear.py
@@ -15,24 +15,26 @@
***************************************************************************
"""
-__author__ = 'Alexander Bruy'
-__date__ = 'September 2017'
-__copyright__ = '(C) 2017, Alexander Bruy'
+__author__ = "Alexander Bruy"
+__date__ = "September 2017"
+__copyright__ = "(C) 2017, Alexander Bruy"
import os
from qgis.PyQt.QtGui import QIcon
-from qgis.core import (QgsRasterFileWriter,
- QgsProcessing,
- QgsProcessingException,
- QgsProcessingParameterDefinition,
- QgsProcessingParameterFeatureSource,
- QgsProcessingParameterEnum,
- QgsProcessingParameterField,
- QgsProcessingParameterNumber,
- QgsProcessingParameterString,
- QgsProcessingParameterRasterDestination)
+from qgis.core import (
+ QgsRasterFileWriter,
+ QgsProcessing,
+ QgsProcessingException,
+ QgsProcessingParameterDefinition,
+ QgsProcessingParameterFeatureSource,
+ QgsProcessingParameterEnum,
+ QgsProcessingParameterField,
+ QgsProcessingParameterNumber,
+ QgsProcessingParameterString,
+ QgsProcessingParameterRasterDestination,
+)
from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm
from processing.algs.gdal.GdalUtils import GdalUtils
@@ -41,128 +43,175 @@
class GridLinear(GdalAlgorithm):
- INPUT = 'INPUT'
- Z_FIELD = 'Z_FIELD'
- RADIUS = 'RADIUS'
- NODATA = 'NODATA'
- OPTIONS = 'OPTIONS'
- EXTRA = 'EXTRA'
- DATA_TYPE = 'DATA_TYPE'
- OUTPUT = 'OUTPUT'
-
- TYPES = ['Byte', 'Int16', 'UInt16', 'UInt32', 'Int32', 'Float32', 'Float64', 'CInt16', 'CInt32', 'CFloat32', 'CFloat64', 'Int8']
+ INPUT = "INPUT"
+ Z_FIELD = "Z_FIELD"
+ RADIUS = "RADIUS"
+ NODATA = "NODATA"
+ OPTIONS = "OPTIONS"
+ EXTRA = "EXTRA"
+ DATA_TYPE = "DATA_TYPE"
+ OUTPUT = "OUTPUT"
+
+ TYPES = [
+ "Byte",
+ "Int16",
+ "UInt16",
+ "UInt32",
+ "Int32",
+ "Float32",
+ "Float64",
+ "CInt16",
+ "CInt32",
+ "CFloat32",
+ "CFloat64",
+ "Int8",
+ ]
def __init__(self):
super().__init__()
def initAlgorithm(self, config=None):
- self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT,
- self.tr('Point layer'),
- [QgsProcessing.SourceType.TypeVectorPoint]))
-
- z_field_param = QgsProcessingParameterField(self.Z_FIELD,
- self.tr('Z value from field'),
- None,
- self.INPUT,
- QgsProcessingParameterField.DataType.Numeric,
- optional=True)
- z_field_param.setFlags(z_field_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
+ self.addParameter(
+ QgsProcessingParameterFeatureSource(
+ self.INPUT,
+ self.tr("Point layer"),
+ [QgsProcessing.SourceType.TypeVectorPoint],
+ )
+ )
+
+ z_field_param = QgsProcessingParameterField(
+ self.Z_FIELD,
+ self.tr("Z value from field"),
+ None,
+ self.INPUT,
+ QgsProcessingParameterField.DataType.Numeric,
+ optional=True,
+ )
+ z_field_param.setFlags(
+ z_field_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
self.addParameter(z_field_param)
- self.addParameter(QgsProcessingParameterNumber(self.RADIUS,
- self.tr('Search distance '),
- type=QgsProcessingParameterNumber.Type.Double,
- minValue=-1.0,
- defaultValue=-1.0))
- self.addParameter(QgsProcessingParameterNumber(self.NODATA,
- self.tr('NODATA marker to fill empty points'),
- type=QgsProcessingParameterNumber.Type.Double,
- defaultValue=0.0))
-
- options_param = QgsProcessingParameterString(self.OPTIONS,
- self.tr('Additional creation options'),
- defaultValue='',
- optional=True)
- options_param.setFlags(options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
- options_param.setMetadata({'widget_wrapper': {'widget_type': 'rasteroptions'}})
+ self.addParameter(
+ QgsProcessingParameterNumber(
+ self.RADIUS,
+ self.tr("Search distance "),
+ type=QgsProcessingParameterNumber.Type.Double,
+ minValue=-1.0,
+ defaultValue=-1.0,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterNumber(
+ self.NODATA,
+ self.tr("NODATA marker to fill empty points"),
+ type=QgsProcessingParameterNumber.Type.Double,
+ defaultValue=0.0,
+ )
+ )
+
+ options_param = QgsProcessingParameterString(
+ self.OPTIONS,
+ self.tr("Additional creation options"),
+ defaultValue="",
+ optional=True,
+ )
+ options_param.setFlags(
+ options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
+ options_param.setMetadata({"widget_wrapper": {"widget_type": "rasteroptions"}})
self.addParameter(options_param)
- extra_param = QgsProcessingParameterString(self.EXTRA,
- self.tr('Additional command-line parameters'),
- defaultValue=None,
- optional=True)
- extra_param.setFlags(extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
+ extra_param = QgsProcessingParameterString(
+ self.EXTRA,
+ self.tr("Additional command-line parameters"),
+ defaultValue=None,
+ optional=True,
+ )
+ extra_param.setFlags(
+ extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
self.addParameter(extra_param)
- dataType_param = QgsProcessingParameterEnum(self.DATA_TYPE,
- self.tr('Output data type'),
- self.TYPES,
- allowMultiple=False,
- defaultValue=5)
- dataType_param.setFlags(dataType_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
+ dataType_param = QgsProcessingParameterEnum(
+ self.DATA_TYPE,
+ self.tr("Output data type"),
+ self.TYPES,
+ allowMultiple=False,
+ defaultValue=5,
+ )
+ dataType_param.setFlags(
+ dataType_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
self.addParameter(dataType_param)
- self.addParameter(QgsProcessingParameterRasterDestination(self.OUTPUT,
- self.tr('Interpolated (Linear)')))
+ self.addParameter(
+ QgsProcessingParameterRasterDestination(
+ self.OUTPUT, self.tr("Interpolated (Linear)")
+ )
+ )
def name(self):
- return 'gridlinear'
+ return "gridlinear"
def displayName(self):
- return self.tr('Grid (Linear)')
+ return self.tr("Grid (Linear)")
def group(self):
- return self.tr('Raster analysis')
+ return self.tr("Raster analysis")
def groupId(self):
- return 'rasteranalysis'
+ return "rasteranalysis"
def icon(self):
- return QIcon(os.path.join(pluginPath, 'images', 'gdaltools', 'grid.png'))
+ return QIcon(os.path.join(pluginPath, "images", "gdaltools", "grid.png"))
def commandName(self):
- return 'gdal_grid'
+ return "gdal_grid"
def getConsoleCommands(self, parameters, context, feedback, executing=True):
- input_details = self.getOgrCompatibleSource(self.INPUT,
- parameters, context,
- feedback, executing)
-
- arguments = [
- '-l',
- input_details.layer_name
- ]
+ input_details = self.getOgrCompatibleSource(
+ self.INPUT, parameters, context, feedback, executing
+ )
+
+ arguments = ["-l", input_details.layer_name]
fieldName = self.parameterAsString(parameters, self.Z_FIELD, context)
if fieldName:
- arguments.append('-zfield')
+ arguments.append("-zfield")
arguments.append(fieldName)
- params = 'linear'
- params += f':radius={self.parameterAsDouble(parameters, self.RADIUS, context)}'
- params += f':nodata={self.parameterAsDouble(parameters, self.NODATA, context)}'
+ params = "linear"
+ params += f":radius={self.parameterAsDouble(parameters, self.RADIUS, context)}"
+ params += f":nodata={self.parameterAsDouble(parameters, self.NODATA, context)}"
- arguments.append('-a')
+ arguments.append("-a")
arguments.append(params)
data_type = self.parameterAsEnum(parameters, self.DATA_TYPE, context)
- if self.TYPES[data_type] == 'Int8' and GdalUtils.version() < 3070000:
- raise QgsProcessingException(self.tr('Int8 data type requires GDAL version 3.7 or later'))
+ if self.TYPES[data_type] == "Int8" and GdalUtils.version() < 3070000:
+ raise QgsProcessingException(
+ self.tr("Int8 data type requires GDAL version 3.7 or later")
+ )
- arguments.append('-ot ' + self.TYPES[data_type])
+ arguments.append("-ot " + self.TYPES[data_type])
out = self.parameterAsOutputLayer(parameters, self.OUTPUT, context)
self.setOutputValue(self.OUTPUT, out)
output_format = QgsRasterFileWriter.driverForExtension(os.path.splitext(out)[1])
if not output_format:
- raise QgsProcessingException(self.tr('Output format is invalid'))
+ raise QgsProcessingException(self.tr("Output format is invalid"))
- arguments.append('-of')
+ arguments.append("-of")
arguments.append(output_format)
if input_details.open_options:
if GdalUtils.version() < 3070000:
- raise QgsProcessingException(self.tr('Open options are not supported by gdal_grid version {} (requires GDAL version 3.7 or later)'.format(GdalUtils.readableVersion())))
+ raise QgsProcessingException(
+ self.tr(
+ f"Open options are not supported by gdal_grid version {GdalUtils.readableVersion()} (requires GDAL version 3.7 or later)"
+ )
+ )
arguments.extend(input_details.open_options_as_arguments())
@@ -170,7 +219,7 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True):
if options:
arguments.extend(GdalUtils.parseCreationOptions(options))
- if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ''):
+ if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ""):
extra = self.parameterAsString(parameters, self.EXTRA, context)
arguments.append(extra)
diff --git a/python/plugins/processing/algs/gdal/GridNearestNeighbor.py b/python/plugins/processing/algs/gdal/GridNearestNeighbor.py
index fd43b9f8eba3..94cc7f34a1c6 100644
--- a/python/plugins/processing/algs/gdal/GridNearestNeighbor.py
+++ b/python/plugins/processing/algs/gdal/GridNearestNeighbor.py
@@ -15,24 +15,26 @@
***************************************************************************
"""
-__author__ = 'Alexander Bruy'
-__date__ = 'October 2013'
-__copyright__ = '(C) 2013, Alexander Bruy'
+__author__ = "Alexander Bruy"
+__date__ = "October 2013"
+__copyright__ = "(C) 2013, Alexander Bruy"
import os
from qgis.PyQt.QtGui import QIcon
-from qgis.core import (QgsRasterFileWriter,
- QgsProcessing,
- QgsProcessingException,
- QgsProcessingParameterDefinition,
- QgsProcessingParameterFeatureSource,
- QgsProcessingParameterEnum,
- QgsProcessingParameterField,
- QgsProcessingParameterNumber,
- QgsProcessingParameterString,
- QgsProcessingParameterRasterDestination)
+from qgis.core import (
+ QgsRasterFileWriter,
+ QgsProcessing,
+ QgsProcessingException,
+ QgsProcessingParameterDefinition,
+ QgsProcessingParameterFeatureSource,
+ QgsProcessingParameterEnum,
+ QgsProcessingParameterField,
+ QgsProcessingParameterNumber,
+ QgsProcessingParameterString,
+ QgsProcessingParameterRasterDestination,
+)
from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm
from processing.algs.gdal.GdalUtils import GdalUtils
@@ -40,141 +42,204 @@
class GridNearestNeighbor(GdalAlgorithm):
- INPUT = 'INPUT'
- Z_FIELD = 'Z_FIELD'
- RADIUS_1 = 'RADIUS_1'
- RADIUS_2 = 'RADIUS_2'
- ANGLE = 'ANGLE'
- NODATA = 'NODATA'
- OPTIONS = 'OPTIONS'
- EXTRA = 'EXTRA'
- DATA_TYPE = 'DATA_TYPE'
- OUTPUT = 'OUTPUT'
-
- TYPES = ['Byte', 'Int16', 'UInt16', 'UInt32', 'Int32', 'Float32', 'Float64', 'CInt16', 'CInt32', 'CFloat32', 'CFloat64', 'Int8']
+ INPUT = "INPUT"
+ Z_FIELD = "Z_FIELD"
+ RADIUS_1 = "RADIUS_1"
+ RADIUS_2 = "RADIUS_2"
+ ANGLE = "ANGLE"
+ NODATA = "NODATA"
+ OPTIONS = "OPTIONS"
+ EXTRA = "EXTRA"
+ DATA_TYPE = "DATA_TYPE"
+ OUTPUT = "OUTPUT"
+
+ TYPES = [
+ "Byte",
+ "Int16",
+ "UInt16",
+ "UInt32",
+ "Int32",
+ "Float32",
+ "Float64",
+ "CInt16",
+ "CInt32",
+ "CFloat32",
+ "CFloat64",
+ "Int8",
+ ]
def __init__(self):
super().__init__()
def initAlgorithm(self, config=None):
- self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT,
- self.tr('Point layer'),
- [QgsProcessing.SourceType.TypeVectorPoint]))
-
- z_field_param = QgsProcessingParameterField(self.Z_FIELD,
- self.tr('Z value from field'),
- None,
- self.INPUT,
- QgsProcessingParameterField.DataType.Numeric,
- optional=True)
- z_field_param.setFlags(z_field_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
+ self.addParameter(
+ QgsProcessingParameterFeatureSource(
+ self.INPUT,
+ self.tr("Point layer"),
+ [QgsProcessing.SourceType.TypeVectorPoint],
+ )
+ )
+
+ z_field_param = QgsProcessingParameterField(
+ self.Z_FIELD,
+ self.tr("Z value from field"),
+ None,
+ self.INPUT,
+ QgsProcessingParameterField.DataType.Numeric,
+ optional=True,
+ )
+ z_field_param.setFlags(
+ z_field_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
self.addParameter(z_field_param)
- self.addParameter(QgsProcessingParameterNumber(self.RADIUS_1,
- self.tr('The first radius of search ellipse'),
- type=QgsProcessingParameterNumber.Type.Double,
- minValue=0.0,
- defaultValue=0.0))
- self.addParameter(QgsProcessingParameterNumber(self.RADIUS_2,
- self.tr('The second radius of search ellipse'),
- type=QgsProcessingParameterNumber.Type.Double,
- minValue=0.0,
- defaultValue=0.0))
- self.addParameter(QgsProcessingParameterNumber(self.ANGLE,
- self.tr('Angle of search ellipse rotation in degrees (counter clockwise)'),
- type=QgsProcessingParameterNumber.Type.Double,
- minValue=0.0,
- maxValue=360.0,
- defaultValue=0.0))
- self.addParameter(QgsProcessingParameterNumber(self.NODATA,
- self.tr('NODATA marker to fill empty points'),
- type=QgsProcessingParameterNumber.Type.Double,
- defaultValue=0.0))
-
- options_param = QgsProcessingParameterString(self.OPTIONS,
- self.tr('Additional creation options'),
- defaultValue='',
- optional=True)
- options_param.setFlags(options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
- options_param.setMetadata({'widget_wrapper': {'widget_type': 'rasteroptions'}})
+ self.addParameter(
+ QgsProcessingParameterNumber(
+ self.RADIUS_1,
+ self.tr("The first radius of search ellipse"),
+ type=QgsProcessingParameterNumber.Type.Double,
+ minValue=0.0,
+ defaultValue=0.0,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterNumber(
+ self.RADIUS_2,
+ self.tr("The second radius of search ellipse"),
+ type=QgsProcessingParameterNumber.Type.Double,
+ minValue=0.0,
+ defaultValue=0.0,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterNumber(
+ self.ANGLE,
+ self.tr(
+ "Angle of search ellipse rotation in degrees (counter clockwise)"
+ ),
+ type=QgsProcessingParameterNumber.Type.Double,
+ minValue=0.0,
+ maxValue=360.0,
+ defaultValue=0.0,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterNumber(
+ self.NODATA,
+ self.tr("NODATA marker to fill empty points"),
+ type=QgsProcessingParameterNumber.Type.Double,
+ defaultValue=0.0,
+ )
+ )
+
+ options_param = QgsProcessingParameterString(
+ self.OPTIONS,
+ self.tr("Additional creation options"),
+ defaultValue="",
+ optional=True,
+ )
+ options_param.setFlags(
+ options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
+ options_param.setMetadata({"widget_wrapper": {"widget_type": "rasteroptions"}})
self.addParameter(options_param)
- extra_param = QgsProcessingParameterString(self.EXTRA,
- self.tr('Additional command-line parameters'),
- defaultValue=None,
- optional=True)
- extra_param.setFlags(extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
+ extra_param = QgsProcessingParameterString(
+ self.EXTRA,
+ self.tr("Additional command-line parameters"),
+ defaultValue=None,
+ optional=True,
+ )
+ extra_param.setFlags(
+ extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
self.addParameter(extra_param)
- dataType_param = QgsProcessingParameterEnum(self.DATA_TYPE,
- self.tr('Output data type'),
- self.TYPES,
- allowMultiple=False,
- defaultValue=5)
- dataType_param.setFlags(dataType_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
+ dataType_param = QgsProcessingParameterEnum(
+ self.DATA_TYPE,
+ self.tr("Output data type"),
+ self.TYPES,
+ allowMultiple=False,
+ defaultValue=5,
+ )
+ dataType_param.setFlags(
+ dataType_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
self.addParameter(dataType_param)
- self.addParameter(QgsProcessingParameterRasterDestination(self.OUTPUT,
- self.tr('Interpolated (Nearest neighbor)')))
+ self.addParameter(
+ QgsProcessingParameterRasterDestination(
+ self.OUTPUT, self.tr("Interpolated (Nearest neighbor)")
+ )
+ )
def name(self):
- return 'gridnearestneighbor'
+ return "gridnearestneighbor"
def displayName(self):
- return self.tr('Grid (Nearest neighbor)')
+ return self.tr("Grid (Nearest neighbor)")
def group(self):
- return self.tr('Raster analysis')
+ return self.tr("Raster analysis")
def groupId(self):
- return 'rasteranalysis'
+ return "rasteranalysis"
def icon(self):
- return QIcon(os.path.join(pluginPath, 'images', 'gdaltools', 'grid.png'))
+ return QIcon(os.path.join(pluginPath, "images", "gdaltools", "grid.png"))
def commandName(self):
- return 'gdal_grid'
+ return "gdal_grid"
def getConsoleCommands(self, parameters, context, feedback, executing=True):
- input_details = self.getOgrCompatibleSource(self.INPUT, parameters, context, feedback, executing)
+ input_details = self.getOgrCompatibleSource(
+ self.INPUT, parameters, context, feedback, executing
+ )
- arguments = [
- '-l',
- input_details.layer_name
- ]
+ arguments = ["-l", input_details.layer_name]
fieldName = self.parameterAsString(parameters, self.Z_FIELD, context)
if fieldName:
- arguments.append('-zfield')
+ arguments.append("-zfield")
arguments.append(fieldName)
- params = 'nearest'
- params += f':radius1={self.parameterAsDouble(parameters, self.RADIUS_1, context)}'
- params += f':radius2={self.parameterAsDouble(parameters, self.RADIUS_2, context)}'
- params += f':angle={self.parameterAsDouble(parameters, self.ANGLE, context)}'
- params += f':nodata={self.parameterAsDouble(parameters, self.NODATA, context)}'
-
- arguments.append('-a')
+ params = "nearest"
+ params += (
+ f":radius1={self.parameterAsDouble(parameters, self.RADIUS_1, context)}"
+ )
+ params += (
+ f":radius2={self.parameterAsDouble(parameters, self.RADIUS_2, context)}"
+ )
+ params += f":angle={self.parameterAsDouble(parameters, self.ANGLE, context)}"
+ params += f":nodata={self.parameterAsDouble(parameters, self.NODATA, context)}"
+
+ arguments.append("-a")
arguments.append(params)
data_type = self.parameterAsEnum(parameters, self.DATA_TYPE, context)
- if self.TYPES[data_type] == 'Int8' and GdalUtils.version() < 3070000:
- raise QgsProcessingException(self.tr('Int8 data type requires GDAL version 3.7 or later'))
+ if self.TYPES[data_type] == "Int8" and GdalUtils.version() < 3070000:
+ raise QgsProcessingException(
+ self.tr("Int8 data type requires GDAL version 3.7 or later")
+ )
- arguments.append('-ot ' + self.TYPES[data_type])
+ arguments.append("-ot " + self.TYPES[data_type])
out = self.parameterAsOutputLayer(parameters, self.OUTPUT, context)
self.setOutputValue(self.OUTPUT, out)
output_format = QgsRasterFileWriter.driverForExtension(os.path.splitext(out)[1])
if not output_format:
- raise QgsProcessingException(self.tr('Output format is invalid'))
+ raise QgsProcessingException(self.tr("Output format is invalid"))
- arguments.append('-of')
+ arguments.append("-of")
arguments.append(output_format)
if input_details.open_options:
if GdalUtils.version() < 3070000:
- raise QgsProcessingException(self.tr('Open options are not supported by gdal_grid version {} (requires GDAL version 3.7 or later)'.format(GdalUtils.readableVersion())))
+ raise QgsProcessingException(
+ self.tr(
+ f"Open options are not supported by gdal_grid version {GdalUtils.readableVersion()} (requires GDAL version 3.7 or later)"
+ )
+ )
arguments.extend(input_details.open_options_as_arguments())
@@ -182,7 +247,7 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True):
if options:
arguments.extend(GdalUtils.parseCreationOptions(options))
- if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ''):
+ if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ""):
extra = self.parameterAsString(parameters, self.EXTRA, context)
arguments.append(extra)
diff --git a/python/plugins/processing/algs/gdal/OffsetCurve.py b/python/plugins/processing/algs/gdal/OffsetCurve.py
index 503b6d4249a1..043fb7827c70 100644
--- a/python/plugins/processing/algs/gdal/OffsetCurve.py
+++ b/python/plugins/processing/algs/gdal/OffsetCurve.py
@@ -15,76 +15,102 @@
***************************************************************************
"""
-__author__ = 'Giovanni Manghi'
-__date__ = 'January 2015'
-__copyright__ = '(C) 2015, Giovanni Manghi'
-
-from qgis.core import (QgsProcessing,
- QgsProcessingParameterDefinition,
- QgsProcessingParameterDistance,
- QgsProcessingParameterFeatureSource,
- QgsProcessingParameterString,
- QgsProcessingException,
- QgsProcessingParameterVectorDestination)
+__author__ = "Giovanni Manghi"
+__date__ = "January 2015"
+__copyright__ = "(C) 2015, Giovanni Manghi"
+
+from qgis.core import (
+ QgsProcessing,
+ QgsProcessingParameterDefinition,
+ QgsProcessingParameterDistance,
+ QgsProcessingParameterFeatureSource,
+ QgsProcessingParameterString,
+ QgsProcessingException,
+ QgsProcessingParameterVectorDestination,
+)
from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm
from processing.algs.gdal.GdalUtils import GdalUtils
class OffsetCurve(GdalAlgorithm):
- INPUT = 'INPUT'
- GEOMETRY = 'GEOMETRY'
- DISTANCE = 'DISTANCE'
- OPTIONS = 'OPTIONS'
- OUTPUT = 'OUTPUT'
+ INPUT = "INPUT"
+ GEOMETRY = "GEOMETRY"
+ DISTANCE = "DISTANCE"
+ OPTIONS = "OPTIONS"
+ OUTPUT = "OUTPUT"
def __init__(self):
super().__init__()
def initAlgorithm(self, config=None):
- self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT,
- self.tr('Input layer'),
- [QgsProcessing.SourceType.TypeVectorLine]))
- self.addParameter(QgsProcessingParameterString(self.GEOMETRY,
- self.tr('Geometry column name'),
- defaultValue='geometry'))
- self.addParameter(QgsProcessingParameterDistance(self.DISTANCE,
- self.tr('Offset distance (left-sided: positive, right-sided: negative)'),
- parentParameterName=self.INPUT,
- defaultValue=10))
-
- options_param = QgsProcessingParameterString(self.OPTIONS,
- self.tr('Additional creation options'),
- defaultValue='',
- optional=True)
- options_param.setFlags(options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
+ self.addParameter(
+ QgsProcessingParameterFeatureSource(
+ self.INPUT,
+ self.tr("Input layer"),
+ [QgsProcessing.SourceType.TypeVectorLine],
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterString(
+ self.GEOMETRY, self.tr("Geometry column name"), defaultValue="geometry"
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterDistance(
+ self.DISTANCE,
+ self.tr(
+ "Offset distance (left-sided: positive, right-sided: negative)"
+ ),
+ parentParameterName=self.INPUT,
+ defaultValue=10,
+ )
+ )
+
+ options_param = QgsProcessingParameterString(
+ self.OPTIONS,
+ self.tr("Additional creation options"),
+ defaultValue="",
+ optional=True,
+ )
+ options_param.setFlags(
+ options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
self.addParameter(options_param)
- self.addParameter(QgsProcessingParameterVectorDestination(self.OUTPUT,
- self.tr('Offset curve'),
- QgsProcessing.SourceType.TypeVectorLine))
+ self.addParameter(
+ QgsProcessingParameterVectorDestination(
+ self.OUTPUT,
+ self.tr("Offset curve"),
+ QgsProcessing.SourceType.TypeVectorLine,
+ )
+ )
def name(self):
- return 'offsetcurve'
+ return "offsetcurve"
def displayName(self):
- return self.tr('Offset curve')
+ return self.tr("Offset curve")
def group(self):
- return self.tr('Vector geoprocessing')
+ return self.tr("Vector geoprocessing")
def groupId(self):
- return 'vectorgeoprocessing'
+ return "vectorgeoprocessing"
def commandName(self):
- return 'ogr2ogr'
+ return "ogr2ogr"
def getConsoleCommands(self, parameters, context, feedback, executing=True):
source = self.parameterAsSource(parameters, self.INPUT, context)
if source is None:
- raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT))
+ raise QgsProcessingException(
+ self.invalidSourceError(parameters, self.INPUT)
+ )
fields = source.fields()
- input_details = self.getOgrCompatibleSource(self.INPUT, parameters, context, feedback, executing)
+ input_details = self.getOgrCompatibleSource(
+ self.INPUT, parameters, context, feedback, executing
+ )
geometry = self.parameterAsString(parameters, self.GEOMETRY, context)
distance = self.parameterAsDouble(parameters, self.DISTANCE, context)
options = self.parameterAsString(parameters, self.OPTIONS, context)
@@ -93,19 +119,16 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True):
output_details = GdalUtils.gdal_connection_details_from_uri(outFile, context)
- other_fields_exist = any(
- True for f in fields
- if f.name() != geometry
- )
+ other_fields_exist = any(True for f in fields if f.name() != geometry)
- other_fields = ',*' if other_fields_exist else ''
+ other_fields = ",*" if other_fields_exist else ""
arguments = [
output_details.connection_string,
input_details.connection_string,
- '-dialect',
- 'sqlite',
- '-sql'
+ "-dialect",
+ "sqlite",
+ "-sql",
]
sql = f'SELECT ST_OffsetCurve({geometry}, {distance}) AS {geometry}{other_fields} FROM "{input_details.layer_name}"'
arguments.append(sql)
@@ -120,6 +143,6 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True):
arguments.append(options)
if output_details.format:
- arguments.append(f'-f {output_details.format}')
+ arguments.append(f"-f {output_details.format}")
- return ['ogr2ogr', GdalUtils.escapeAndJoin(arguments)]
+ return ["ogr2ogr", GdalUtils.escapeAndJoin(arguments)]
diff --git a/python/plugins/processing/algs/gdal/OgrToPostGis.py b/python/plugins/processing/algs/gdal/OgrToPostGis.py
index 39012eedcc97..5bfcd6b63bb0 100644
--- a/python/plugins/processing/algs/gdal/OgrToPostGis.py
+++ b/python/plugins/processing/algs/gdal/OgrToPostGis.py
@@ -15,19 +15,21 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'November 2012'
-__copyright__ = '(C) 2012, Victor Olaya'
+__author__ = "Victor Olaya"
+__date__ = "November 2012"
+__copyright__ = "(C) 2012, Victor Olaya"
-from qgis.core import (QgsProcessing,
- QgsProcessingException,
- QgsProcessingParameterFeatureSource,
- QgsProcessingParameterString,
- QgsProcessingParameterEnum,
- QgsProcessingParameterCrs,
- QgsProcessingParameterField,
- QgsProcessingParameterExtent,
- QgsProcessingParameterBoolean)
+from qgis.core import (
+ QgsProcessing,
+ QgsProcessingException,
+ QgsProcessingParameterFeatureSource,
+ QgsProcessingParameterString,
+ QgsProcessingParameterEnum,
+ QgsProcessingParameterCrs,
+ QgsProcessingParameterField,
+ QgsProcessingParameterExtent,
+ QgsProcessingParameterBoolean,
+)
from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm
from processing.algs.gdal.GdalUtils import GdalUtils
@@ -36,166 +38,324 @@
class OgrToPostGis(GdalAlgorithm):
- INPUT = 'INPUT'
- SHAPE_ENCODING = 'SHAPE_ENCODING'
- GTYPE = 'GTYPE'
- GEOMTYPE = ['', 'NONE', 'GEOMETRY', 'POINT', 'LINESTRING', 'POLYGON', 'GEOMETRYCOLLECTION', 'MULTIPOINT',
- 'MULTIPOLYGON', 'MULTILINESTRING', 'CIRCULARSTRING', 'COMPOUNDCURVE', 'CURVEPOLYGON', 'MULTICURVE',
- 'MULTISURFACE', 'CONVERT_TO_LINEAR', 'CONVERT_TO_CURVE']
- S_SRS = 'S_SRS'
- T_SRS = 'T_SRS'
- A_SRS = 'A_SRS'
- HOST = 'HOST'
- PORT = 'PORT'
- USER = 'USER'
- DBNAME = 'DBNAME'
- PASSWORD = 'PASSWORD'
- SCHEMA = 'SCHEMA'
- TABLE = 'TABLE'
- PK = 'PK'
- PRIMARY_KEY = 'PRIMARY_KEY'
- GEOCOLUMN = 'GEOCOLUMN'
- DIM = 'DIM'
- DIMLIST = ['2', '3', '4']
- SIMPLIFY = 'SIMPLIFY'
- SEGMENTIZE = 'SEGMENTIZE'
- SPAT = 'SPAT'
- CLIP = 'CLIP'
- FIELDS = 'FIELDS'
- WHERE = 'WHERE'
- GT = 'GT'
- OVERWRITE = 'OVERWRITE'
- APPEND = 'APPEND'
- ADDFIELDS = 'ADDFIELDS'
- LAUNDER = 'LAUNDER'
- INDEX = 'INDEX'
- SKIPFAILURES = 'SKIPFAILURES'
- PRECISION = 'PRECISION'
- MAKEVALID = 'MAKEVALID'
- PROMOTETOMULTI = 'PROMOTETOMULTI'
- OPTIONS = 'OPTIONS'
+ INPUT = "INPUT"
+ SHAPE_ENCODING = "SHAPE_ENCODING"
+ GTYPE = "GTYPE"
+ GEOMTYPE = [
+ "",
+ "NONE",
+ "GEOMETRY",
+ "POINT",
+ "LINESTRING",
+ "POLYGON",
+ "GEOMETRYCOLLECTION",
+ "MULTIPOINT",
+ "MULTIPOLYGON",
+ "MULTILINESTRING",
+ "CIRCULARSTRING",
+ "COMPOUNDCURVE",
+ "CURVEPOLYGON",
+ "MULTICURVE",
+ "MULTISURFACE",
+ "CONVERT_TO_LINEAR",
+ "CONVERT_TO_CURVE",
+ ]
+ S_SRS = "S_SRS"
+ T_SRS = "T_SRS"
+ A_SRS = "A_SRS"
+ HOST = "HOST"
+ PORT = "PORT"
+ USER = "USER"
+ DBNAME = "DBNAME"
+ PASSWORD = "PASSWORD"
+ SCHEMA = "SCHEMA"
+ TABLE = "TABLE"
+ PK = "PK"
+ PRIMARY_KEY = "PRIMARY_KEY"
+ GEOCOLUMN = "GEOCOLUMN"
+ DIM = "DIM"
+ DIMLIST = ["2", "3", "4"]
+ SIMPLIFY = "SIMPLIFY"
+ SEGMENTIZE = "SEGMENTIZE"
+ SPAT = "SPAT"
+ CLIP = "CLIP"
+ FIELDS = "FIELDS"
+ WHERE = "WHERE"
+ GT = "GT"
+ OVERWRITE = "OVERWRITE"
+ APPEND = "APPEND"
+ ADDFIELDS = "ADDFIELDS"
+ LAUNDER = "LAUNDER"
+ INDEX = "INDEX"
+ SKIPFAILURES = "SKIPFAILURES"
+ PRECISION = "PRECISION"
+ MAKEVALID = "MAKEVALID"
+ PROMOTETOMULTI = "PROMOTETOMULTI"
+ OPTIONS = "OPTIONS"
def __init__(self):
super().__init__()
def initAlgorithm(self, config=None):
- self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT,
- self.tr('Input layer'),
- types=[QgsProcessing.SourceType.TypeVector]))
- self.addParameter(QgsProcessingParameterString(self.SHAPE_ENCODING,
- self.tr('Shape encoding'), "", optional=True))
- self.addParameter(QgsProcessingParameterEnum(self.GTYPE,
- self.tr('Output geometry type'), options=self.GEOMTYPE,
- defaultValue=0))
- self.addParameter(QgsProcessingParameterCrs(self.A_SRS,
- self.tr('Assign an output CRS'), defaultValue='', optional=True))
- self.addParameter(QgsProcessingParameterCrs(self.T_SRS,
- self.tr('Reproject to this CRS on output '), defaultValue='',
- optional=True))
- self.addParameter(QgsProcessingParameterCrs(self.S_SRS,
- self.tr('Override source CRS'), defaultValue='', optional=True))
- self.addParameter(QgsProcessingParameterString(self.HOST,
- self.tr('Host'), defaultValue='localhost', optional=True))
- self.addParameter(QgsProcessingParameterString(self.PORT,
- self.tr('Port'), defaultValue='5432', optional=True))
- self.addParameter(QgsProcessingParameterString(self.USER,
- self.tr('Username'), defaultValue='', optional=True))
- self.addParameter(QgsProcessingParameterString(self.DBNAME,
- self.tr('Database name'), defaultValue='', optional=True))
- self.addParameter(QgsProcessingParameterString(self.PASSWORD,
- self.tr('Password'), defaultValue='', optional=True))
- self.addParameter(QgsProcessingParameterString(self.SCHEMA,
- self.tr('Schema name'), defaultValue='public', optional=True))
- self.addParameter(QgsProcessingParameterString(self.TABLE,
- self.tr('Table name, leave blank to use input name'),
- defaultValue='', optional=True))
- self.addParameter(QgsProcessingParameterString(self.PK,
- self.tr('Primary key (new field)'), defaultValue='id',
- optional=True))
- self.addParameter(QgsProcessingParameterField(self.PRIMARY_KEY,
- self.tr(
- 'Primary key (existing field, used if the above option is left empty)'),
- parentLayerParameterName=self.INPUT, optional=True))
- self.addParameter(QgsProcessingParameterString(self.GEOCOLUMN,
- self.tr('Geometry column name'), defaultValue='geom',
- optional=True))
- self.addParameter(QgsProcessingParameterEnum(self.DIM,
- self.tr('Vector dimensions'), options=self.DIMLIST,
- defaultValue=0))
- self.addParameter(QgsProcessingParameterString(self.SIMPLIFY,
- self.tr('Distance tolerance for simplification'),
- defaultValue='', optional=True))
- self.addParameter(QgsProcessingParameterString(self.SEGMENTIZE,
- self.tr('Maximum distance between 2 nodes (densification)'),
- defaultValue='', optional=True))
- self.addParameter(QgsProcessingParameterExtent(self.SPAT,
- self.tr(
- 'Select features by extent (defined in input layer CRS)'),
- optional=True))
- self.addParameter(QgsProcessingParameterBoolean(self.CLIP,
- self.tr(
- 'Clip the input layer using the above (rectangle) extent'),
- defaultValue=False))
- self.addParameter(QgsProcessingParameterField(self.FIELDS,
- self.tr('Fields to include (leave empty to use all fields)'),
- parentLayerParameterName=self.INPUT,
- allowMultiple=True, optional=True))
- self.addParameter(QgsProcessingParameterString(self.WHERE,
- self.tr(
- 'Select features using a SQL "WHERE" statement (Ex: column=\'value\')'),
- defaultValue='', optional=True))
- self.addParameter(QgsProcessingParameterString(self.GT,
- self.tr('Group N features per transaction (Default: 20000)'),
- defaultValue='', optional=True))
- self.addParameter(QgsProcessingParameterBoolean(self.OVERWRITE,
- self.tr('Overwrite existing table'), defaultValue=True))
- self.addParameter(QgsProcessingParameterBoolean(self.APPEND,
- self.tr('Append to existing table'), defaultValue=False))
- self.addParameter(QgsProcessingParameterBoolean(self.ADDFIELDS,
- self.tr('Append and add new fields to existing table'),
- defaultValue=False))
- self.addParameter(QgsProcessingParameterBoolean(self.LAUNDER,
- self.tr('Do not launder columns/table names'),
- defaultValue=False))
- self.addParameter(QgsProcessingParameterBoolean(self.INDEX,
- self.tr('Do not create spatial index'), defaultValue=False))
- self.addParameter(QgsProcessingParameterBoolean(self.SKIPFAILURES,
- self.tr(
- 'Continue after a failure, skipping the failed feature'),
- defaultValue=False))
- self.addParameter(QgsProcessingParameterBoolean(self.MAKEVALID,
- self.tr(
- 'Validate geometries based on Simple Features specification'),
- defaultValue=False))
- self.addParameter(QgsProcessingParameterBoolean(self.PROMOTETOMULTI,
- self.tr('Promote to Multipart'),
- defaultValue=True))
- self.addParameter(QgsProcessingParameterBoolean(self.PRECISION,
- self.tr('Keep width and precision of input attributes'),
- defaultValue=True))
- self.addParameter(QgsProcessingParameterString(self.OPTIONS,
- self.tr('Additional creation options'), defaultValue='',
- optional=True))
+ self.addParameter(
+ QgsProcessingParameterFeatureSource(
+ self.INPUT,
+ self.tr("Input layer"),
+ types=[QgsProcessing.SourceType.TypeVector],
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterString(
+ self.SHAPE_ENCODING, self.tr("Shape encoding"), "", optional=True
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterEnum(
+ self.GTYPE,
+ self.tr("Output geometry type"),
+ options=self.GEOMTYPE,
+ defaultValue=0,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterCrs(
+ self.A_SRS,
+ self.tr("Assign an output CRS"),
+ defaultValue="",
+ optional=True,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterCrs(
+ self.T_SRS,
+ self.tr("Reproject to this CRS on output "),
+ defaultValue="",
+ optional=True,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterCrs(
+ self.S_SRS,
+ self.tr("Override source CRS"),
+ defaultValue="",
+ optional=True,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterString(
+ self.HOST, self.tr("Host"), defaultValue="localhost", optional=True
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterString(
+ self.PORT, self.tr("Port"), defaultValue="5432", optional=True
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterString(
+ self.USER, self.tr("Username"), defaultValue="", optional=True
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterString(
+ self.DBNAME, self.tr("Database name"), defaultValue="", optional=True
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterString(
+ self.PASSWORD, self.tr("Password"), defaultValue="", optional=True
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterString(
+ self.SCHEMA,
+ self.tr("Schema name"),
+ defaultValue="public",
+ optional=True,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterString(
+ self.TABLE,
+ self.tr("Table name, leave blank to use input name"),
+ defaultValue="",
+ optional=True,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterString(
+ self.PK,
+ self.tr("Primary key (new field)"),
+ defaultValue="id",
+ optional=True,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterField(
+ self.PRIMARY_KEY,
+ self.tr(
+ "Primary key (existing field, used if the above option is left empty)"
+ ),
+ parentLayerParameterName=self.INPUT,
+ optional=True,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterString(
+ self.GEOCOLUMN,
+ self.tr("Geometry column name"),
+ defaultValue="geom",
+ optional=True,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterEnum(
+ self.DIM,
+ self.tr("Vector dimensions"),
+ options=self.DIMLIST,
+ defaultValue=0,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterString(
+ self.SIMPLIFY,
+ self.tr("Distance tolerance for simplification"),
+ defaultValue="",
+ optional=True,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterString(
+ self.SEGMENTIZE,
+ self.tr("Maximum distance between 2 nodes (densification)"),
+ defaultValue="",
+ optional=True,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterExtent(
+ self.SPAT,
+ self.tr("Select features by extent (defined in input layer CRS)"),
+ optional=True,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterBoolean(
+ self.CLIP,
+ self.tr("Clip the input layer using the above (rectangle) extent"),
+ defaultValue=False,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterField(
+ self.FIELDS,
+ self.tr("Fields to include (leave empty to use all fields)"),
+ parentLayerParameterName=self.INPUT,
+ allowMultiple=True,
+ optional=True,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterString(
+ self.WHERE,
+ self.tr(
+ "Select features using a SQL \"WHERE\" statement (Ex: column='value')"
+ ),
+ defaultValue="",
+ optional=True,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterString(
+ self.GT,
+ self.tr("Group N features per transaction (Default: 20000)"),
+ defaultValue="",
+ optional=True,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterBoolean(
+ self.OVERWRITE, self.tr("Overwrite existing table"), defaultValue=True
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterBoolean(
+ self.APPEND, self.tr("Append to existing table"), defaultValue=False
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterBoolean(
+ self.ADDFIELDS,
+ self.tr("Append and add new fields to existing table"),
+ defaultValue=False,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterBoolean(
+ self.LAUNDER,
+ self.tr("Do not launder columns/table names"),
+ defaultValue=False,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterBoolean(
+ self.INDEX, self.tr("Do not create spatial index"), defaultValue=False
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterBoolean(
+ self.SKIPFAILURES,
+ self.tr("Continue after a failure, skipping the failed feature"),
+ defaultValue=False,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterBoolean(
+ self.MAKEVALID,
+ self.tr("Validate geometries based on Simple Features specification"),
+ defaultValue=False,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterBoolean(
+ self.PROMOTETOMULTI, self.tr("Promote to Multipart"), defaultValue=True
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterBoolean(
+ self.PRECISION,
+ self.tr("Keep width and precision of input attributes"),
+ defaultValue=True,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterString(
+ self.OPTIONS,
+ self.tr("Additional creation options"),
+ defaultValue="",
+ optional=True,
+ )
+ )
def name(self):
- return 'importvectorintopostgisdatabasenewconnection'
+ return "importvectorintopostgisdatabasenewconnection"
def displayName(self):
- return self.tr('Export to PostgreSQL (new connection)')
+ return self.tr("Export to PostgreSQL (new connection)")
def shortDescription(self):
- return self.tr('Exports a vector layer to a new PostgreSQL database connection')
+ return self.tr("Exports a vector layer to a new PostgreSQL database connection")
def tags(self):
- t = self.tr('import,into,postgis,database,vector').split(',')
+ t = self.tr("import,into,postgis,database,vector").split(",")
t.extend(super().tags())
return t
def group(self):
- return self.tr('Vector miscellaneous')
+ return self.tr("Vector miscellaneous")
def groupId(self):
- return 'vectormiscellaneous'
+ return "vectormiscellaneous"
def getConnectionString(self, parameters, context):
host = self.parameterAsString(parameters, self.HOST, context)
@@ -206,23 +366,27 @@ def getConnectionString(self, parameters, context):
schema = self.parameterAsString(parameters, self.SCHEMA, context)
arguments = []
if host:
- arguments.append('host=' + host)
+ arguments.append("host=" + host)
if port:
- arguments.append('port=' + str(port))
+ arguments.append("port=" + str(port))
if dbname:
- arguments.append('dbname=' + dbname)
+ arguments.append("dbname=" + dbname)
if password:
- arguments.append('password=' + password)
+ arguments.append("password=" + password)
if schema:
- arguments.append('active_schema=' + schema)
+ arguments.append("active_schema=" + schema)
if user:
- arguments.append('user=' + user)
+ arguments.append("user=" + user)
return GdalUtils.escapeAndJoin(arguments)
def getConsoleCommands(self, parameters, context, feedback, executing=True):
- input_details = self.getOgrCompatibleSource(self.INPUT, parameters, context, feedback, executing)
+ input_details = self.getOgrCompatibleSource(
+ self.INPUT, parameters, context, feedback, executing
+ )
if not input_details.layer_name:
- raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT))
+ raise QgsProcessingException(
+ self.invalidSourceError(parameters, self.INPUT)
+ )
shapeEncoding = self.parameterAsString(parameters, self.SHAPE_ENCODING, context)
ssrs = self.parameterAsCrs(parameters, self.S_SRS, context)
@@ -242,7 +406,7 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True):
spat = self.parameterAsExtent(parameters, self.SPAT, context)
clip = self.parameterAsBoolean(parameters, self.CLIP, context)
include_fields = self.parameterAsFields(parameters, self.FIELDS, context)
- fields_string = '-select "' + ','.join(include_fields) + '"'
+ fields_string = '-select "' + ",".join(include_fields) + '"'
where = self.parameterAsString(parameters, self.WHERE, context)
wherestring = '-where "' + where + '"'
gt = self.parameterAsString(parameters, self.GT, context)
@@ -255,21 +419,20 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True):
indexstring = "-lco SPATIAL_INDEX=OFF"
skipfailures = self.parameterAsBoolean(parameters, self.SKIPFAILURES, context)
make_valid = self.parameterAsBoolean(parameters, self.MAKEVALID, context)
- promotetomulti = self.parameterAsBoolean(parameters, self.PROMOTETOMULTI, context)
+ promotetomulti = self.parameterAsBoolean(
+ parameters, self.PROMOTETOMULTI, context
+ )
precision = self.parameterAsBoolean(parameters, self.PRECISION, context)
options = self.parameterAsString(parameters, self.OPTIONS, context)
- arguments = [
- '-progress',
- '--config PG_USE_COPY YES'
- ]
+ arguments = ["-progress", "--config PG_USE_COPY YES"]
if len(shapeEncoding) > 0:
- arguments.append('--config')
- arguments.append('SHAPE_ENCODING')
+ arguments.append("--config")
+ arguments.append("SHAPE_ENCODING")
arguments.append(shapeEncoding)
- arguments.append('-f')
- arguments.append('PostgreSQL')
- arguments.append('PG:' + self.getConnectionString(parameters, context))
+ arguments.append("-f")
+ arguments.append("PostgreSQL")
+ arguments.append("PG:" + self.getConnectionString(parameters, context))
arguments.append(dimstring)
arguments.append(input_details.connection_string)
arguments.append(input_details.layer_name)
@@ -280,18 +443,25 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True):
if append and overwrite:
raise QgsProcessingException(
self.tr(
- 'Only one of "Overwrite existing table" or "Append to existing table" can be enabled at a time.'))
+ 'Only one of "Overwrite existing table" or "Append to existing table" can be enabled at a time.'
+ )
+ )
elif append:
- arguments.append('-append')
+ arguments.append("-append")
if include_fields:
arguments.append(fields_string)
if addfields:
- arguments.append('-addfields')
+ arguments.append("-addfields")
if overwrite:
- arguments.append('-overwrite')
- if len(self.GEOMTYPE[self.parameterAsEnum(parameters, self.GTYPE, context)]) > 0:
- arguments.append('-nlt')
- arguments.append(self.GEOMTYPE[self.parameterAsEnum(parameters, self.GTYPE, context)])
+ arguments.append("-overwrite")
+ if (
+ len(self.GEOMTYPE[self.parameterAsEnum(parameters, self.GTYPE, context)])
+ > 0
+ ):
+ arguments.append("-nlt")
+ arguments.append(
+ self.GEOMTYPE[self.parameterAsEnum(parameters, self.GTYPE, context)]
+ )
if len(geocolumn) > 0:
arguments.append(geocolumnstring)
if pk:
@@ -301,52 +471,63 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True):
if len(table) == 0:
table = input_details.layer_name.lower()
if schema:
- table = f'{schema}.{table}'
- arguments.append('-nln')
+ table = f"{schema}.{table}"
+ arguments.append("-nln")
arguments.append(table)
if ssrs.isValid():
- arguments.append('-s_srs')
+ arguments.append("-s_srs")
arguments.append(GdalUtils.gdal_crs_string(ssrs))
if tsrs.isValid():
- arguments.append('-t_srs')
+ arguments.append("-t_srs")
arguments.append(GdalUtils.gdal_crs_string(tsrs))
if asrs.isValid():
- arguments.append('-a_srs')
+ arguments.append("-a_srs")
arguments.append(GdalUtils.gdal_crs_string(asrs))
if not spat.isNull():
- arguments.append('-spat')
+ arguments.append("-spat")
arguments.append(spat.xMinimum())
arguments.append(spat.yMinimum())
arguments.append(spat.xMaximum())
arguments.append(spat.yMaximum())
if clip:
- arguments.append('-clipsrc spat_extent')
+ arguments.append("-clipsrc spat_extent")
if skipfailures:
- arguments.append('-skipfailures')
+ arguments.append("-skipfailures")
if where:
arguments.append(wherestring)
if len(simplify) > 0:
- arguments.append('-simplify')
+ arguments.append("-simplify")
arguments.append(simplify)
if len(segmentize) > 0:
- arguments.append('-segmentize')
+ arguments.append("-segmentize")
arguments.append(segmentize)
if len(gt) > 0:
- arguments.append('-gt')
+ arguments.append("-gt")
arguments.append(gt)
if make_valid:
- arguments.append('-makevalid')
- if promotetomulti and self.GEOMTYPE[self.parameterAsEnum(parameters, self.GTYPE, context)]:
- if self.GEOMTYPE[self.parameterAsEnum(parameters, self.GTYPE, context)] == 'CONVERT_TO_LINEAR':
- arguments.append('-nlt PROMOTE_TO_MULTI')
+ arguments.append("-makevalid")
+ if (
+ promotetomulti
+ and self.GEOMTYPE[self.parameterAsEnum(parameters, self.GTYPE, context)]
+ ):
+ if (
+ self.GEOMTYPE[self.parameterAsEnum(parameters, self.GTYPE, context)]
+ == "CONVERT_TO_LINEAR"
+ ):
+ arguments.append("-nlt PROMOTE_TO_MULTI")
else:
raise QgsProcessingException(
self.tr(
- 'Only one of "Promote to Multipart" or "Output geometry type" (excluding Convert to Linear) can be enabled.'))
- elif promotetomulti and not self.GEOMTYPE[self.parameterAsEnum(parameters, self.GTYPE, context)]:
- arguments.append('-nlt PROMOTE_TO_MULTI')
+ 'Only one of "Promote to Multipart" or "Output geometry type" (excluding Convert to Linear) can be enabled.'
+ )
+ )
+ elif (
+ promotetomulti
+ and not self.GEOMTYPE[self.parameterAsEnum(parameters, self.GTYPE, context)]
+ ):
+ arguments.append("-nlt PROMOTE_TO_MULTI")
if precision is False:
- arguments.append('-lco PRECISION=NO')
+ arguments.append("-lco PRECISION=NO")
if input_details.open_options:
arguments.extend(input_details.open_options_as_arguments())
@@ -358,10 +539,9 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True):
arguments.append(options)
if isWindows():
- return ['cmd.exe', '/C ', 'ogr2ogr.exe',
- GdalUtils.escapeAndJoin(arguments)]
+ return ["cmd.exe", "/C ", "ogr2ogr.exe", GdalUtils.escapeAndJoin(arguments)]
else:
- return ['ogr2ogr', GdalUtils.escapeAndJoin(arguments)]
+ return ["ogr2ogr", GdalUtils.escapeAndJoin(arguments)]
def commandName(self):
- return 'ogr2ogr'
+ return "ogr2ogr"
diff --git a/python/plugins/processing/algs/gdal/OneSideBuffer.py b/python/plugins/processing/algs/gdal/OneSideBuffer.py
index 3abd451edd27..f9b85b56dec1 100644
--- a/python/plugins/processing/algs/gdal/OneSideBuffer.py
+++ b/python/plugins/processing/algs/gdal/OneSideBuffer.py
@@ -15,102 +15,142 @@
***************************************************************************
"""
-__author__ = 'Giovanni Manghi'
-__date__ = 'January 2015'
-__copyright__ = '(C) 2015, Giovanni Manghi'
-
-from qgis.core import (QgsProcessing,
- QgsProcessingException,
- QgsProcessingParameterDefinition,
- QgsProcessingParameterDistance,
- QgsProcessingParameterFeatureSource,
- QgsProcessingParameterEnum,
- QgsProcessingParameterField,
- QgsProcessingParameterString,
- QgsProcessingParameterBoolean,
- QgsProcessingParameterVectorDestination)
+__author__ = "Giovanni Manghi"
+__date__ = "January 2015"
+__copyright__ = "(C) 2015, Giovanni Manghi"
+
+from qgis.core import (
+ QgsProcessing,
+ QgsProcessingException,
+ QgsProcessingParameterDefinition,
+ QgsProcessingParameterDistance,
+ QgsProcessingParameterFeatureSource,
+ QgsProcessingParameterEnum,
+ QgsProcessingParameterField,
+ QgsProcessingParameterString,
+ QgsProcessingParameterBoolean,
+ QgsProcessingParameterVectorDestination,
+)
from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm
from processing.algs.gdal.GdalUtils import GdalUtils
class OneSideBuffer(GdalAlgorithm):
- INPUT = 'INPUT'
- FIELD = 'FIELD'
- BUFFER_SIDE = 'BUFFER_SIDE'
- GEOMETRY = 'GEOMETRY'
- DISTANCE = 'DISTANCE'
- DISSOLVE = 'DISSOLVE'
- EXPLODE_COLLECTIONS = 'EXPLODE_COLLECTIONS'
- OPTIONS = 'OPTIONS'
- OUTPUT = 'OUTPUT'
+ INPUT = "INPUT"
+ FIELD = "FIELD"
+ BUFFER_SIDE = "BUFFER_SIDE"
+ GEOMETRY = "GEOMETRY"
+ DISTANCE = "DISTANCE"
+ DISSOLVE = "DISSOLVE"
+ EXPLODE_COLLECTIONS = "EXPLODE_COLLECTIONS"
+ OPTIONS = "OPTIONS"
+ OUTPUT = "OUTPUT"
def __init__(self):
super().__init__()
def initAlgorithm(self, config=None):
- self.bufferSides = [self.tr('Right'), self.tr('Left')]
-
- self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT,
- self.tr('Input layer'),
- [QgsProcessing.SourceType.TypeVectorLine]))
- self.addParameter(QgsProcessingParameterString(self.GEOMETRY,
- self.tr('Geometry column name'),
- defaultValue='geometry'))
- self.addParameter(QgsProcessingParameterDistance(self.DISTANCE,
- self.tr('Buffer distance'),
- defaultValue=10,
- parentParameterName=self.INPUT))
- self.addParameter(QgsProcessingParameterEnum(self.BUFFER_SIDE,
- self.tr('Buffer side'),
- options=self.bufferSides,
- allowMultiple=False,
- defaultValue=0))
- self.addParameter(QgsProcessingParameterField(self.FIELD,
- self.tr('Dissolve by attribute'),
- None,
- self.INPUT,
- QgsProcessingParameterField.DataType.Any,
- optional=True))
- self.addParameter(QgsProcessingParameterBoolean(self.DISSOLVE,
- self.tr('Dissolve all results'),
- defaultValue=False))
- self.addParameter(QgsProcessingParameterBoolean(self.EXPLODE_COLLECTIONS,
- self.tr('Produce one feature for each geometry in any kind of geometry collection in the source file'),
- defaultValue=False))
-
- options_param = QgsProcessingParameterString(self.OPTIONS,
- self.tr('Additional creation options'),
- defaultValue='',
- optional=True)
- options_param.setFlags(options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
+ self.bufferSides = [self.tr("Right"), self.tr("Left")]
+
+ self.addParameter(
+ QgsProcessingParameterFeatureSource(
+ self.INPUT,
+ self.tr("Input layer"),
+ [QgsProcessing.SourceType.TypeVectorLine],
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterString(
+ self.GEOMETRY, self.tr("Geometry column name"), defaultValue="geometry"
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterDistance(
+ self.DISTANCE,
+ self.tr("Buffer distance"),
+ defaultValue=10,
+ parentParameterName=self.INPUT,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterEnum(
+ self.BUFFER_SIDE,
+ self.tr("Buffer side"),
+ options=self.bufferSides,
+ allowMultiple=False,
+ defaultValue=0,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterField(
+ self.FIELD,
+ self.tr("Dissolve by attribute"),
+ None,
+ self.INPUT,
+ QgsProcessingParameterField.DataType.Any,
+ optional=True,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterBoolean(
+ self.DISSOLVE, self.tr("Dissolve all results"), defaultValue=False
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterBoolean(
+ self.EXPLODE_COLLECTIONS,
+ self.tr(
+ "Produce one feature for each geometry in any kind of geometry collection in the source file"
+ ),
+ defaultValue=False,
+ )
+ )
+
+ options_param = QgsProcessingParameterString(
+ self.OPTIONS,
+ self.tr("Additional creation options"),
+ defaultValue="",
+ optional=True,
+ )
+ options_param.setFlags(
+ options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
self.addParameter(options_param)
- self.addParameter(QgsProcessingParameterVectorDestination(self.OUTPUT,
- self.tr('One-sided buffer'),
- QgsProcessing.SourceType.TypeVectorPolygon))
+ self.addParameter(
+ QgsProcessingParameterVectorDestination(
+ self.OUTPUT,
+ self.tr("One-sided buffer"),
+ QgsProcessing.SourceType.TypeVectorPolygon,
+ )
+ )
def name(self):
- return 'onesidebuffer'
+ return "onesidebuffer"
def displayName(self):
- return self.tr('One side buffer')
+ return self.tr("One side buffer")
def group(self):
- return self.tr('Vector geoprocessing')
+ return self.tr("Vector geoprocessing")
def groupId(self):
- return 'vectorgeoprocessing'
+ return "vectorgeoprocessing"
def commandName(self):
- return 'ogr2ogr'
+ return "ogr2ogr"
def getConsoleCommands(self, parameters, context, feedback, executing=True):
source = self.parameterAsSource(parameters, self.INPUT, context)
if source is None:
- raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT))
+ raise QgsProcessingException(
+ self.invalidSourceError(parameters, self.INPUT)
+ )
fields = source.fields()
- input_details = self.getOgrCompatibleSource(self.INPUT, parameters, context, feedback, executing)
+ input_details = self.getOgrCompatibleSource(
+ self.INPUT, parameters, context, feedback, executing
+ )
geometry = self.parameterAsString(parameters, self.GEOMETRY, context)
distance = self.parameterAsDouble(parameters, self.DISTANCE, context)
side = self.parameterAsEnum(parameters, self.BUFFER_SIDE, context)
@@ -122,19 +162,16 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True):
output_details = GdalUtils.gdal_connection_details_from_uri(outFile, context)
- other_fields_exist = any(
- True for f in fields
- if f.name() != geometry
- )
+ other_fields_exist = any(True for f in fields if f.name() != geometry)
- other_fields = ',*' if other_fields_exist else ''
+ other_fields = ",*" if other_fields_exist else ""
arguments = [
output_details.connection_string,
input_details.connection_string,
- '-dialect',
- 'sqlite',
- '-sql'
+ "-dialect",
+ "sqlite",
+ "-sql",
]
if dissolve or fieldName:
@@ -148,7 +185,7 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True):
arguments.append(sql)
if self.parameterAsBoolean(parameters, self.EXPLODE_COLLECTIONS, context):
- arguments.append('-explodecollections')
+ arguments.append("-explodecollections")
if input_details.open_options:
arguments.extend(input_details.open_options_as_arguments())
@@ -160,6 +197,6 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True):
arguments.append(options)
if output_details.format:
- arguments.append(f'-f {output_details.format}')
+ arguments.append(f"-f {output_details.format}")
- return ['ogr2ogr', GdalUtils.escapeAndJoin(arguments)]
+ return ["ogr2ogr", GdalUtils.escapeAndJoin(arguments)]
diff --git a/python/plugins/processing/algs/gdal/PointsAlongLines.py b/python/plugins/processing/algs/gdal/PointsAlongLines.py
index 3d3f5daf7b3b..7b68237a027a 100644
--- a/python/plugins/processing/algs/gdal/PointsAlongLines.py
+++ b/python/plugins/processing/algs/gdal/PointsAlongLines.py
@@ -15,79 +15,105 @@
***************************************************************************
"""
-__author__ = 'Giovanni Manghi'
-__date__ = 'January 2015'
-__copyright__ = '(C) 2015, Giovanni Manghi'
-
-from qgis.core import (QgsProcessingException,
- QgsProcessingParameterFeatureSource,
- QgsProcessingParameterString,
- QgsProcessingParameterNumber,
- QgsProcessingParameterVectorDestination,
- QgsProcessingParameterDefinition,
- QgsProcessing)
+__author__ = "Giovanni Manghi"
+__date__ = "January 2015"
+__copyright__ = "(C) 2015, Giovanni Manghi"
+
+from qgis.core import (
+ QgsProcessingException,
+ QgsProcessingParameterFeatureSource,
+ QgsProcessingParameterString,
+ QgsProcessingParameterNumber,
+ QgsProcessingParameterVectorDestination,
+ QgsProcessingParameterDefinition,
+ QgsProcessing,
+)
from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm
from processing.algs.gdal.GdalUtils import GdalUtils
class PointsAlongLines(GdalAlgorithm):
- INPUT = 'INPUT'
- GEOMETRY = 'GEOMETRY'
- DISTANCE = 'DISTANCE'
- OPTIONS = 'OPTIONS'
- OUTPUT = 'OUTPUT'
+ INPUT = "INPUT"
+ GEOMETRY = "GEOMETRY"
+ DISTANCE = "DISTANCE"
+ OPTIONS = "OPTIONS"
+ OUTPUT = "OUTPUT"
def __init__(self):
super().__init__()
def initAlgorithm(self, config=None):
- self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT,
- self.tr('Input layer'),
- [QgsProcessing.SourceType.TypeVectorLine]))
- self.addParameter(QgsProcessingParameterString(self.GEOMETRY,
- self.tr('Geometry column name'),
- defaultValue='geometry'))
- self.addParameter(QgsProcessingParameterNumber(self.DISTANCE,
- self.tr('Distance from line start represented as fraction of line length'),
- type=QgsProcessingParameterNumber.Type.Double,
- minValue=0,
- maxValue=1,
- defaultValue=0.5))
-
- options_param = QgsProcessingParameterString(self.OPTIONS,
- self.tr('Additional creation options'),
- defaultValue='',
- optional=True)
- options_param.setFlags(options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
+ self.addParameter(
+ QgsProcessingParameterFeatureSource(
+ self.INPUT,
+ self.tr("Input layer"),
+ [QgsProcessing.SourceType.TypeVectorLine],
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterString(
+ self.GEOMETRY, self.tr("Geometry column name"), defaultValue="geometry"
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterNumber(
+ self.DISTANCE,
+ self.tr(
+ "Distance from line start represented as fraction of line length"
+ ),
+ type=QgsProcessingParameterNumber.Type.Double,
+ minValue=0,
+ maxValue=1,
+ defaultValue=0.5,
+ )
+ )
+
+ options_param = QgsProcessingParameterString(
+ self.OPTIONS,
+ self.tr("Additional creation options"),
+ defaultValue="",
+ optional=True,
+ )
+ options_param.setFlags(
+ options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
self.addParameter(options_param)
- self.addParameter(QgsProcessingParameterVectorDestination(self.OUTPUT,
- self.tr('Points along lines'),
- QgsProcessing.SourceType.TypeVectorPoint))
+ self.addParameter(
+ QgsProcessingParameterVectorDestination(
+ self.OUTPUT,
+ self.tr("Points along lines"),
+ QgsProcessing.SourceType.TypeVectorPoint,
+ )
+ )
def name(self):
- return 'pointsalonglines'
+ return "pointsalonglines"
def displayName(self):
- return self.tr('Points along lines')
+ return self.tr("Points along lines")
def group(self):
- return self.tr('Vector geoprocessing')
+ return self.tr("Vector geoprocessing")
def groupId(self):
- return 'vectorgeoprocessing'
+ return "vectorgeoprocessing"
def commandName(self):
- return 'ogr2ogr'
+ return "ogr2ogr"
def getConsoleCommands(self, parameters, context, feedback, executing=True):
source = self.parameterAsSource(parameters, self.INPUT, context)
if source is None:
- raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT))
+ raise QgsProcessingException(
+ self.invalidSourceError(parameters, self.INPUT)
+ )
fields = source.fields()
- input_details = self.getOgrCompatibleSource(self.INPUT, parameters, context, feedback, executing)
+ input_details = self.getOgrCompatibleSource(
+ self.INPUT, parameters, context, feedback, executing
+ )
distance = self.parameterAsDouble(parameters, self.DISTANCE, context)
geometry = self.parameterAsString(parameters, self.GEOMETRY, context)
outFile = self.parameterAsOutputLayer(parameters, self.OUTPUT, context)
@@ -96,33 +122,29 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True):
output_details = GdalUtils.gdal_connection_details_from_uri(outFile, context)
- other_fields_exist = any(
- f for f in fields
- if f.name() != geometry
- )
+ other_fields_exist = any(f for f in fields if f.name() != geometry)
- other_fields = ',*' if other_fields_exist else ''
+ other_fields = ",*" if other_fields_exist else ""
arguments = [
output_details.connection_string,
input_details.connection_string,
- '-dialect',
- 'sqlite',
- '-sql',
- f'SELECT ST_Line_Interpolate_Point({geometry}, {distance}) AS {geometry}{other_fields} FROM "{input_details.layer_name}"'
+ "-dialect",
+ "sqlite",
+ "-sql",
+ f'SELECT ST_Line_Interpolate_Point({geometry}, {distance}) AS {geometry}{other_fields} FROM "{input_details.layer_name}"',
]
if input_details.open_options:
arguments.extend(input_details.open_options_as_arguments())
if input_details.credential_options:
- arguments.extend(
- input_details.credential_options_as_arguments())
+ arguments.extend(input_details.credential_options_as_arguments())
if options:
arguments.append(options)
if output_details.format:
- arguments.append(f'-f {output_details.format}')
+ arguments.append(f"-f {output_details.format}")
- return ['ogr2ogr', GdalUtils.escapeAndJoin(arguments)]
+ return ["ogr2ogr", GdalUtils.escapeAndJoin(arguments)]
diff --git a/python/plugins/processing/algs/gdal/aspect.py b/python/plugins/processing/algs/gdal/aspect.py
index 33848481081f..72c021fa85aa 100644
--- a/python/plugins/processing/algs/gdal/aspect.py
+++ b/python/plugins/processing/algs/gdal/aspect.py
@@ -15,20 +15,22 @@
***************************************************************************
"""
-__author__ = 'Alexander Bruy'
-__date__ = 'October 2013'
-__copyright__ = '(C) 2013, Alexander Bruy'
+__author__ = "Alexander Bruy"
+__date__ = "October 2013"
+__copyright__ = "(C) 2013, Alexander Bruy"
import os
-from qgis.core import (QgsProcessingException,
- QgsRasterFileWriter,
- QgsProcessingParameterDefinition,
- QgsProcessingParameterRasterLayer,
- QgsProcessingParameterBand,
- QgsProcessingParameterBoolean,
- QgsProcessingParameterString,
- QgsProcessingParameterRasterDestination)
+from qgis.core import (
+ QgsProcessingException,
+ QgsRasterFileWriter,
+ QgsProcessingParameterDefinition,
+ QgsProcessingParameterRasterLayer,
+ QgsProcessingParameterBand,
+ QgsProcessingParameterBoolean,
+ QgsProcessingParameterString,
+ QgsProcessingParameterRasterDestination,
+)
from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm
from processing.algs.gdal.GdalUtils import GdalUtils
@@ -36,75 +38,107 @@
class aspect(GdalAlgorithm):
- INPUT = 'INPUT'
- BAND = 'BAND'
- COMPUTE_EDGES = 'COMPUTE_EDGES'
- ZEVENBERGEN = 'ZEVENBERGEN'
- TRIG_ANGLE = 'TRIG_ANGLE'
- ZERO_FLAT = 'ZERO_FLAT'
- OPTIONS = 'OPTIONS'
- EXTRA = 'EXTRA'
- OUTPUT = 'OUTPUT'
+ INPUT = "INPUT"
+ BAND = "BAND"
+ COMPUTE_EDGES = "COMPUTE_EDGES"
+ ZEVENBERGEN = "ZEVENBERGEN"
+ TRIG_ANGLE = "TRIG_ANGLE"
+ ZERO_FLAT = "ZERO_FLAT"
+ OPTIONS = "OPTIONS"
+ EXTRA = "EXTRA"
+ OUTPUT = "OUTPUT"
def __init__(self):
super().__init__()
def initAlgorithm(self, config=None):
- self.addParameter(QgsProcessingParameterRasterLayer(self.INPUT, self.tr('Input layer')))
- self.addParameter(QgsProcessingParameterBand(self.BAND,
- self.tr('Band number'),
- 1,
- parentLayerParameterName=self.INPUT))
- self.addParameter(QgsProcessingParameterBoolean(self.TRIG_ANGLE,
- self.tr('Return trigonometric angle instead of azimuth'),
- defaultValue=False))
- self.addParameter(QgsProcessingParameterBoolean(self.ZERO_FLAT,
- self.tr('Return 0 for flat instead of -9999'),
- defaultValue=False))
- self.addParameter(QgsProcessingParameterBoolean(self.COMPUTE_EDGES,
- self.tr('Compute edges'),
- defaultValue=False))
- self.addParameter(QgsProcessingParameterBoolean(self.ZEVENBERGEN,
- self.tr("Use Zevenbergen&Thorne formula instead of the Horn's one"),
- defaultValue=False))
-
- options_param = QgsProcessingParameterString(self.OPTIONS,
- self.tr('Additional creation options'),
- defaultValue='',
- optional=True)
- options_param.setFlags(options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
- options_param.setMetadata({'widget_wrapper': {'widget_type': 'rasteroptions'}})
+ self.addParameter(
+ QgsProcessingParameterRasterLayer(self.INPUT, self.tr("Input layer"))
+ )
+ self.addParameter(
+ QgsProcessingParameterBand(
+ self.BAND,
+ self.tr("Band number"),
+ 1,
+ parentLayerParameterName=self.INPUT,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterBoolean(
+ self.TRIG_ANGLE,
+ self.tr("Return trigonometric angle instead of azimuth"),
+ defaultValue=False,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterBoolean(
+ self.ZERO_FLAT,
+ self.tr("Return 0 for flat instead of -9999"),
+ defaultValue=False,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterBoolean(
+ self.COMPUTE_EDGES, self.tr("Compute edges"), defaultValue=False
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterBoolean(
+ self.ZEVENBERGEN,
+ self.tr("Use Zevenbergen&Thorne formula instead of the Horn's one"),
+ defaultValue=False,
+ )
+ )
+
+ options_param = QgsProcessingParameterString(
+ self.OPTIONS,
+ self.tr("Additional creation options"),
+ defaultValue="",
+ optional=True,
+ )
+ options_param.setFlags(
+ options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
+ options_param.setMetadata({"widget_wrapper": {"widget_type": "rasteroptions"}})
self.addParameter(options_param)
- extra_param = QgsProcessingParameterString(self.EXTRA,
- self.tr('Additional command-line parameters'),
- defaultValue=None,
- optional=True)
- extra_param.setFlags(extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
+ extra_param = QgsProcessingParameterString(
+ self.EXTRA,
+ self.tr("Additional command-line parameters"),
+ defaultValue=None,
+ optional=True,
+ )
+ extra_param.setFlags(
+ extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
self.addParameter(extra_param)
- self.addParameter(QgsProcessingParameterRasterDestination(self.OUTPUT, self.tr('Aspect')))
+ self.addParameter(
+ QgsProcessingParameterRasterDestination(self.OUTPUT, self.tr("Aspect"))
+ )
def name(self):
- return 'aspect'
+ return "aspect"
def displayName(self):
- return self.tr('Aspect')
+ return self.tr("Aspect")
def group(self):
- return self.tr('Raster analysis')
+ return self.tr("Raster analysis")
def groupId(self):
- return 'rasteranalysis'
+ return "rasteranalysis"
def commandName(self):
- return 'gdaldem'
+ return "gdaldem"
def getConsoleCommands(self, parameters, context, feedback, executing=True):
- arguments = ['aspect']
+ arguments = ["aspect"]
inLayer = self.parameterAsRasterLayer(parameters, self.INPUT, context)
if inLayer is None:
- raise QgsProcessingException(self.invalidRasterError(parameters, self.INPUT))
+ raise QgsProcessingException(
+ self.invalidRasterError(parameters, self.INPUT)
+ )
input_details = GdalUtils.gdal_connection_details_from_layer(inLayer)
arguments.append(input_details.connection_string)
@@ -115,26 +149,26 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True):
output_format = QgsRasterFileWriter.driverForExtension(os.path.splitext(out)[1])
if not output_format:
- raise QgsProcessingException(self.tr('Output format is invalid'))
+ raise QgsProcessingException(self.tr("Output format is invalid"))
- arguments.append('-of')
+ arguments.append("-of")
arguments.append(output_format)
- arguments.append('-b')
+ arguments.append("-b")
arguments.append(str(self.parameterAsInt(parameters, self.BAND, context)))
if self.parameterAsBoolean(parameters, self.TRIG_ANGLE, context):
- arguments.append('-trigonometric')
+ arguments.append("-trigonometric")
if self.parameterAsBoolean(parameters, self.ZERO_FLAT, context):
- arguments.append('-zero_for_flat')
+ arguments.append("-zero_for_flat")
if self.parameterAsBoolean(parameters, self.COMPUTE_EDGES, context):
- arguments.append('-compute_edges')
+ arguments.append("-compute_edges")
if self.parameterAsBoolean(parameters, self.ZEVENBERGEN, context):
- arguments.append('-alg')
- arguments.append('ZevenbergenThorne')
+ arguments.append("-alg")
+ arguments.append("ZevenbergenThorne")
options = self.parameterAsString(parameters, self.OPTIONS, context)
if options:
@@ -143,7 +177,7 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True):
if input_details.credential_options:
arguments.extend(input_details.credential_options_as_arguments())
- if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ''):
+ if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ""):
extra = self.parameterAsString(parameters, self.EXTRA, context)
arguments.append(extra)
diff --git a/python/plugins/processing/algs/gdal/buildvrt.py b/python/plugins/processing/algs/gdal/buildvrt.py
index 7707cdc91859..74728de91703 100644
--- a/python/plugins/processing/algs/gdal/buildvrt.py
+++ b/python/plugins/processing/algs/gdal/buildvrt.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Radoslaw Guzinski'
-__date__ = 'October 2014'
-__copyright__ = '(C) 2014, Radoslaw Guzinski'
+__author__ = "Radoslaw Guzinski"
+__date__ = "October 2014"
+__copyright__ = "(C) 2014, Radoslaw Guzinski"
import os
import pathlib
@@ -25,19 +25,21 @@
from qgis.PyQt.QtCore import QCoreApplication
from qgis.PyQt.QtGui import QIcon
-from qgis.core import (QgsProcessingAlgorithm,
- QgsProcessing,
- QgsProcessingParameterDefinition,
- QgsProperty,
- QgsProcessingParameters,
- QgsProcessingParameterMultipleLayers,
- QgsProcessingParameterEnum,
- QgsProcessingParameterBoolean,
- QgsProcessingParameterRasterDestination,
- QgsProcessingParameterCrs,
- QgsProcessingParameterString,
- QgsProcessingOutputLayerDefinition,
- QgsProcessingUtils)
+from qgis.core import (
+ QgsProcessingAlgorithm,
+ QgsProcessing,
+ QgsProcessingParameterDefinition,
+ QgsProperty,
+ QgsProcessingParameters,
+ QgsProcessingParameterMultipleLayers,
+ QgsProcessingParameterEnum,
+ QgsProcessingParameterBoolean,
+ QgsProcessingParameterRasterDestination,
+ QgsProcessingParameterCrs,
+ QgsProcessingParameterString,
+ QgsProcessingOutputLayerDefinition,
+ QgsProcessingUtils,
+)
from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm
from processing.algs.gdal.GdalUtils import GdalUtils
@@ -45,16 +47,16 @@
class buildvrt(GdalAlgorithm):
- INPUT = 'INPUT'
- OUTPUT = 'OUTPUT'
- RESOLUTION = 'RESOLUTION'
- SEPARATE = 'SEPARATE'
- PROJ_DIFFERENCE = 'PROJ_DIFFERENCE'
- ADD_ALPHA = 'ADD_ALPHA'
- ASSIGN_CRS = 'ASSIGN_CRS'
- RESAMPLING = 'RESAMPLING'
- SRC_NODATA = 'SRC_NODATA'
- EXTRA = 'EXTRA'
+ INPUT = "INPUT"
+ OUTPUT = "OUTPUT"
+ RESOLUTION = "RESOLUTION"
+ SEPARATE = "SEPARATE"
+ PROJ_DIFFERENCE = "PROJ_DIFFERENCE"
+ ADD_ALPHA = "ADD_ALPHA"
+ ASSIGN_CRS = "ASSIGN_CRS"
+ RESAMPLING = "RESAMPLING"
+ SRC_NODATA = "SRC_NODATA"
+ EXTRA = "EXTRA"
def __init__(self):
super().__init__()
@@ -71,141 +73,209 @@ def clone(self):
return copy
def defaultFileExtension(self):
- return 'vrt'
+ return "vrt"
def createFileFilter(self):
- return '{} (*.vrt *.VRT)'.format(QCoreApplication.translate("GdalAlgorithm", 'VRT files'))
+ return "{} (*.vrt *.VRT)".format(
+ QCoreApplication.translate("GdalAlgorithm", "VRT files")
+ )
def supportedOutputRasterLayerExtensions(self):
- return ['vrt']
+ return ["vrt"]
def parameterAsOutputLayer(self, definition, value, context):
- return super(QgsProcessingParameterRasterDestination, self).parameterAsOutputLayer(definition, value, context)
+ return super(
+ QgsProcessingParameterRasterDestination, self
+ ).parameterAsOutputLayer(definition, value, context)
def isSupportedOutputValue(self, value, context):
- output_path = QgsProcessingParameters.parameterAsOutputLayer(self, value, context, testOnly=True)
- if pathlib.Path(output_path).suffix.lower() != '.vrt':
- return False, QCoreApplication.translate("GdalAlgorithm", 'Output filename must use a .vrt extension')
- return True, ''
-
- self.RESAMPLING_OPTIONS = ((self.tr('Nearest Neighbour'), 'nearest'),
- (self.tr('Bilinear (2x2 Kernel)'), 'bilinear'),
- (self.tr('Cubic (4x4 Kernel)'), 'cubic'),
- (self.tr('Cubic B-Spline (4x4 Kernel)'), 'cubicspline'),
- (self.tr('Lanczos (6x6 Kernel)'), 'lanczos'),
- (self.tr('Average'), 'average'),
- (self.tr('Mode'), 'mode'))
-
- self.RESOLUTION_OPTIONS = ((self.tr('Average'), 'average'),
- (self.tr('Highest'), 'highest'),
- (self.tr('Lowest'), 'lowest'))
-
- self.addParameter(QgsProcessingParameterMultipleLayers(self.INPUT,
- self.tr('Input layers'),
- QgsProcessing.SourceType.TypeRaster))
- self.addParameter(QgsProcessingParameterEnum(self.RESOLUTION,
- self.tr('Resolution'),
- options=[i[0] for i in self.RESOLUTION_OPTIONS],
- defaultValue=0))
-
- separate_param = QgsProcessingParameterBoolean(self.SEPARATE,
- self.tr('Place each input file into a separate band'),
- defaultValue=True)
+ output_path = QgsProcessingParameters.parameterAsOutputLayer(
+ self, value, context, testOnly=True
+ )
+ if pathlib.Path(output_path).suffix.lower() != ".vrt":
+ return False, QCoreApplication.translate(
+ "GdalAlgorithm", "Output filename must use a .vrt extension"
+ )
+ return True, ""
+
+ self.RESAMPLING_OPTIONS = (
+ (self.tr("Nearest Neighbour"), "nearest"),
+ (self.tr("Bilinear (2x2 Kernel)"), "bilinear"),
+ (self.tr("Cubic (4x4 Kernel)"), "cubic"),
+ (self.tr("Cubic B-Spline (4x4 Kernel)"), "cubicspline"),
+ (self.tr("Lanczos (6x6 Kernel)"), "lanczos"),
+ (self.tr("Average"), "average"),
+ (self.tr("Mode"), "mode"),
+ )
+
+ self.RESOLUTION_OPTIONS = (
+ (self.tr("Average"), "average"),
+ (self.tr("Highest"), "highest"),
+ (self.tr("Lowest"), "lowest"),
+ )
+
+ self.addParameter(
+ QgsProcessingParameterMultipleLayers(
+ self.INPUT, self.tr("Input layers"), QgsProcessing.SourceType.TypeRaster
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterEnum(
+ self.RESOLUTION,
+ self.tr("Resolution"),
+ options=[i[0] for i in self.RESOLUTION_OPTIONS],
+ defaultValue=0,
+ )
+ )
+
+ separate_param = QgsProcessingParameterBoolean(
+ self.SEPARATE,
+ self.tr("Place each input file into a separate band"),
+ defaultValue=True,
+ )
# default to not using separate bands is a friendlier option, but we can't change the parameter's actual
# defaultValue without breaking API!
separate_param.setGuiDefaultValueOverride(False)
self.addParameter(separate_param)
- self.addParameter(QgsProcessingParameterBoolean(self.PROJ_DIFFERENCE,
- self.tr('Allow projection difference'),
- defaultValue=False))
-
- add_alpha_param = QgsProcessingParameterBoolean(self.ADD_ALPHA,
- self.tr('Add alpha mask band to VRT when source raster has none'),
- defaultValue=False)
- add_alpha_param.setFlags(add_alpha_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
+ self.addParameter(
+ QgsProcessingParameterBoolean(
+ self.PROJ_DIFFERENCE,
+ self.tr("Allow projection difference"),
+ defaultValue=False,
+ )
+ )
+
+ add_alpha_param = QgsProcessingParameterBoolean(
+ self.ADD_ALPHA,
+ self.tr("Add alpha mask band to VRT when source raster has none"),
+ defaultValue=False,
+ )
+ add_alpha_param.setFlags(
+ add_alpha_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
self.addParameter(add_alpha_param)
- assign_crs = QgsProcessingParameterCrs(self.ASSIGN_CRS,
- self.tr('Override projection for the output file'),
- defaultValue=None, optional=True)
- assign_crs.setFlags(assign_crs.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
+ assign_crs = QgsProcessingParameterCrs(
+ self.ASSIGN_CRS,
+ self.tr("Override projection for the output file"),
+ defaultValue=None,
+ optional=True,
+ )
+ assign_crs.setFlags(
+ assign_crs.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
self.addParameter(assign_crs)
- resampling = QgsProcessingParameterEnum(self.RESAMPLING,
- self.tr('Resampling algorithm'),
- options=[i[0] for i in self.RESAMPLING_OPTIONS],
- defaultValue=0)
- resampling.setFlags(resampling.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
+ resampling = QgsProcessingParameterEnum(
+ self.RESAMPLING,
+ self.tr("Resampling algorithm"),
+ options=[i[0] for i in self.RESAMPLING_OPTIONS],
+ defaultValue=0,
+ )
+ resampling.setFlags(
+ resampling.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
self.addParameter(resampling)
- src_nodata_param = QgsProcessingParameterString(self.SRC_NODATA,
- self.tr('Nodata value(s) for input bands (space separated)'),
- defaultValue=None,
- optional=True)
- src_nodata_param.setFlags(src_nodata_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
+ src_nodata_param = QgsProcessingParameterString(
+ self.SRC_NODATA,
+ self.tr("Nodata value(s) for input bands (space separated)"),
+ defaultValue=None,
+ optional=True,
+ )
+ src_nodata_param.setFlags(
+ src_nodata_param.flags()
+ | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
self.addParameter(src_nodata_param)
- extra_param = QgsProcessingParameterString(self.EXTRA,
- self.tr('Additional command-line parameters'),
- defaultValue=None,
- optional=True)
- extra_param.setFlags(extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
+ extra_param = QgsProcessingParameterString(
+ self.EXTRA,
+ self.tr("Additional command-line parameters"),
+ defaultValue=None,
+ optional=True,
+ )
+ extra_param.setFlags(
+ extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
self.addParameter(extra_param)
- self.addParameter(ParameterVrtDestination(self.OUTPUT, QCoreApplication.translate("ParameterVrtDestination", 'Virtual')))
+ self.addParameter(
+ ParameterVrtDestination(
+ self.OUTPUT,
+ QCoreApplication.translate("ParameterVrtDestination", "Virtual"),
+ )
+ )
def name(self):
- return 'buildvirtualraster'
+ return "buildvirtualraster"
def displayName(self):
- return QCoreApplication.translate("buildvrt", 'Build virtual raster')
+ return QCoreApplication.translate("buildvrt", "Build virtual raster")
def icon(self):
- return QIcon(os.path.join(pluginPath, 'images', 'gdaltools', 'vrt.png'))
+ return QIcon(os.path.join(pluginPath, "images", "gdaltools", "vrt.png"))
def group(self):
- return QCoreApplication.translate("buildvrt", 'Raster miscellaneous')
+ return QCoreApplication.translate("buildvrt", "Raster miscellaneous")
def groupId(self):
- return 'rastermiscellaneous'
+ return "rastermiscellaneous"
def commandName(self):
return "gdalbuildvrt"
def getConsoleCommands(self, parameters, context, feedback, executing=True):
arguments = [
- '-overwrite',
- '-resolution',
- self.RESOLUTION_OPTIONS[self.parameterAsEnum(parameters, self.RESOLUTION, context)][1]
+ "-overwrite",
+ "-resolution",
+ self.RESOLUTION_OPTIONS[
+ self.parameterAsEnum(parameters, self.RESOLUTION, context)
+ ][1],
]
if self.parameterAsBoolean(parameters, buildvrt.SEPARATE, context):
- arguments.append('-separate')
+ arguments.append("-separate")
if self.parameterAsBoolean(parameters, buildvrt.PROJ_DIFFERENCE, context):
- arguments.append('-allow_projection_difference')
+ arguments.append("-allow_projection_difference")
if self.parameterAsBoolean(parameters, buildvrt.ADD_ALPHA, context):
- arguments.append('-addalpha')
+ arguments.append("-addalpha")
crs = self.parameterAsCrs(parameters, self.ASSIGN_CRS, context)
if crs.isValid():
- arguments.append('-a_srs')
+ arguments.append("-a_srs")
arguments.append(GdalUtils.gdal_crs_string(crs))
- arguments.append('-r')
- arguments.append(self.RESAMPLING_OPTIONS[self.parameterAsEnum(parameters, self.RESAMPLING, context)][1])
-
- if self.SRC_NODATA in parameters and parameters[self.SRC_NODATA] not in (None, ''):
+ arguments.append("-r")
+ arguments.append(
+ self.RESAMPLING_OPTIONS[
+ self.parameterAsEnum(parameters, self.RESAMPLING, context)
+ ][1]
+ )
+
+ if self.SRC_NODATA in parameters and parameters[self.SRC_NODATA] not in (
+ None,
+ "",
+ ):
nodata = self.parameterAsString(parameters, self.SRC_NODATA, context)
- arguments.append('-srcnodata')
+ arguments.append("-srcnodata")
arguments.append(nodata)
- if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ''):
+ if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ""):
extra = self.parameterAsString(parameters, self.EXTRA, context)
arguments.append(extra)
# Always write input files to a text file in case there are many of them and the
# length of the command will be longer then allowed in command prompt
- list_file = GdalUtils.writeLayerParameterToTextFile(filename='buildvrtInputFiles.txt', alg=self, parameters=parameters, parameter_name=self.INPUT, context=context, executing=executing, quote=False)
- arguments.append('-input_file_list')
+ list_file = GdalUtils.writeLayerParameterToTextFile(
+ filename="buildvrtInputFiles.txt",
+ alg=self,
+ parameters=parameters,
+ parameter_name=self.INPUT,
+ context=context,
+ executing=executing,
+ quote=False,
+ )
+ arguments.append("-input_file_list")
arguments.append(list_file)
out = self.parameterAsOutputLayer(parameters, self.OUTPUT, context)
diff --git a/python/plugins/processing/algs/gdal/contour.py b/python/plugins/processing/algs/gdal/contour.py
index 5a98ad63023a..d85e1aa876d1 100644
--- a/python/plugins/processing/algs/gdal/contour.py
+++ b/python/plugins/processing/algs/gdal/contour.py
@@ -15,23 +15,25 @@
***************************************************************************
"""
-__author__ = 'Alexander Bruy'
-__date__ = 'September 2013'
-__copyright__ = '(C) 2013, Alexander Bruy'
+__author__ = "Alexander Bruy"
+__date__ = "September 2013"
+__copyright__ = "(C) 2013, Alexander Bruy"
import os
from qgis.PyQt.QtGui import QIcon
-from qgis.core import (QgsProcessing,
- QgsProcessingException,
- QgsProcessingParameterDefinition,
- QgsProcessingParameterRasterLayer,
- QgsProcessingParameterBand,
- QgsProcessingParameterString,
- QgsProcessingParameterNumber,
- QgsProcessingParameterBoolean,
- QgsProcessingParameterVectorDestination)
+from qgis.core import (
+ QgsProcessing,
+ QgsProcessingException,
+ QgsProcessingParameterDefinition,
+ QgsProcessingParameterRasterLayer,
+ QgsProcessingParameterBand,
+ QgsProcessingParameterString,
+ QgsProcessingParameterNumber,
+ QgsProcessingParameterBoolean,
+ QgsProcessingParameterVectorDestination,
+)
from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm
from processing.algs.gdal.GdalUtils import GdalUtils
@@ -39,106 +41,151 @@
class contour(GdalAlgorithm):
- INPUT = 'INPUT'
- BAND = 'BAND'
- INTERVAL = 'INTERVAL'
- FIELD_NAME = 'FIELD_NAME'
- CREATE_3D = 'CREATE_3D'
- IGNORE_NODATA = 'IGNORE_NODATA'
- NODATA = 'NODATA'
- OFFSET = 'OFFSET'
- EXTRA = 'EXTRA'
- OPTIONS = 'OPTIONS'
- OUTPUT = 'OUTPUT'
+ INPUT = "INPUT"
+ BAND = "BAND"
+ INTERVAL = "INTERVAL"
+ FIELD_NAME = "FIELD_NAME"
+ CREATE_3D = "CREATE_3D"
+ IGNORE_NODATA = "IGNORE_NODATA"
+ NODATA = "NODATA"
+ OFFSET = "OFFSET"
+ EXTRA = "EXTRA"
+ OPTIONS = "OPTIONS"
+ OUTPUT = "OUTPUT"
def __init__(self):
super().__init__()
def initAlgorithm(self, config=None):
- self.addParameter(QgsProcessingParameterRasterLayer(self.INPUT,
- self.tr('Input layer')))
- self.addParameter(QgsProcessingParameterBand(self.BAND,
- self.tr('Band number'),
- 1,
- parentLayerParameterName=self.INPUT))
- self.addParameter(QgsProcessingParameterNumber(self.INTERVAL,
- self.tr('Interval between contour lines'),
- type=QgsProcessingParameterNumber.Type.Double,
- minValue=0.0,
- defaultValue=10.0))
- self.addParameter(QgsProcessingParameterString(self.FIELD_NAME,
- self.tr('Attribute name (if not set, no elevation attribute is attached)'),
- defaultValue='ELEV',
- optional=True))
-
- create_3d_param = QgsProcessingParameterBoolean(self.CREATE_3D,
- self.tr('Produce 3D vector'),
- defaultValue=False)
- create_3d_param.setFlags(create_3d_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
+ self.addParameter(
+ QgsProcessingParameterRasterLayer(self.INPUT, self.tr("Input layer"))
+ )
+ self.addParameter(
+ QgsProcessingParameterBand(
+ self.BAND,
+ self.tr("Band number"),
+ 1,
+ parentLayerParameterName=self.INPUT,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterNumber(
+ self.INTERVAL,
+ self.tr("Interval between contour lines"),
+ type=QgsProcessingParameterNumber.Type.Double,
+ minValue=0.0,
+ defaultValue=10.0,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterString(
+ self.FIELD_NAME,
+ self.tr(
+ "Attribute name (if not set, no elevation attribute is attached)"
+ ),
+ defaultValue="ELEV",
+ optional=True,
+ )
+ )
+
+ create_3d_param = QgsProcessingParameterBoolean(
+ self.CREATE_3D, self.tr("Produce 3D vector"), defaultValue=False
+ )
+ create_3d_param.setFlags(
+ create_3d_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
self.addParameter(create_3d_param)
- ignore_nodata_param = QgsProcessingParameterBoolean(self.IGNORE_NODATA,
- self.tr('Treat all raster values as valid'),
- defaultValue=False)
- ignore_nodata_param.setFlags(ignore_nodata_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
+ ignore_nodata_param = QgsProcessingParameterBoolean(
+ self.IGNORE_NODATA,
+ self.tr("Treat all raster values as valid"),
+ defaultValue=False,
+ )
+ ignore_nodata_param.setFlags(
+ ignore_nodata_param.flags()
+ | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
self.addParameter(ignore_nodata_param)
- nodata_param = QgsProcessingParameterNumber(self.NODATA,
- self.tr('Input pixel value to treat as NoData'),
- type=QgsProcessingParameterNumber.Type.Double,
- defaultValue=None,
- optional=True)
- nodata_param.setFlags(nodata_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
+ nodata_param = QgsProcessingParameterNumber(
+ self.NODATA,
+ self.tr("Input pixel value to treat as NoData"),
+ type=QgsProcessingParameterNumber.Type.Double,
+ defaultValue=None,
+ optional=True,
+ )
+ nodata_param.setFlags(
+ nodata_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
self.addParameter(nodata_param)
- offset_param = QgsProcessingParameterNumber(self.OFFSET,
- self.tr('Offset from zero relative to which to interpret intervals'),
- type=QgsProcessingParameterNumber.Type.Double,
- defaultValue=0.0,
- optional=True)
- nodata_param.setFlags(offset_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
+ offset_param = QgsProcessingParameterNumber(
+ self.OFFSET,
+ self.tr("Offset from zero relative to which to interpret intervals"),
+ type=QgsProcessingParameterNumber.Type.Double,
+ defaultValue=0.0,
+ optional=True,
+ )
+ nodata_param.setFlags(
+ offset_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
self.addParameter(offset_param)
- extra_param = QgsProcessingParameterString(self.EXTRA,
- self.tr('Additional command-line parameters'),
- defaultValue=None,
- optional=True)
- extra_param.setFlags(extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
+ extra_param = QgsProcessingParameterString(
+ self.EXTRA,
+ self.tr("Additional command-line parameters"),
+ defaultValue=None,
+ optional=True,
+ )
+ extra_param.setFlags(
+ extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
self.addParameter(extra_param)
# TODO: remove in QGIS 4
- options_param = QgsProcessingParameterString(self.OPTIONS,
- self.tr('Additional creation options'),
- defaultValue='',
- optional=True)
- options_param.setFlags(options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagHidden)
+ options_param = QgsProcessingParameterString(
+ self.OPTIONS,
+ self.tr("Additional creation options"),
+ defaultValue="",
+ optional=True,
+ )
+ options_param.setFlags(
+ options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagHidden
+ )
self.addParameter(options_param)
- self.addParameter(QgsProcessingParameterVectorDestination(
- self.OUTPUT, self.tr('Contours'), QgsProcessing.SourceType.TypeVectorLine))
+ self.addParameter(
+ QgsProcessingParameterVectorDestination(
+ self.OUTPUT,
+ self.tr("Contours"),
+ QgsProcessing.SourceType.TypeVectorLine,
+ )
+ )
def name(self):
- return 'contour'
+ return "contour"
def displayName(self):
- return self.tr('Contour')
+ return self.tr("Contour")
def icon(self):
- return QIcon(os.path.join(pluginPath, 'images', 'gdaltools', 'contour.png'))
+ return QIcon(os.path.join(pluginPath, "images", "gdaltools", "contour.png"))
def group(self):
- return self.tr('Raster extraction')
+ return self.tr("Raster extraction")
def groupId(self):
- return 'rasterextraction'
+ return "rasterextraction"
def commandName(self):
- return 'gdal_contour'
+ return "gdal_contour"
def _buildArgsList(self, parameters, context, feedback, executing):
inLayer = self.parameterAsRasterLayer(parameters, self.INPUT, context)
if inLayer is None:
- raise QgsProcessingException(self.invalidRasterError(parameters, self.INPUT))
+ raise QgsProcessingException(
+ self.invalidRasterError(parameters, self.INPUT)
+ )
input_details = GdalUtils.gdal_connection_details_from_layer(inLayer)
fieldName = self.parameterAsString(parameters, self.FIELD_NAME, context)
@@ -152,36 +199,35 @@ def _buildArgsList(self, parameters, context, feedback, executing):
self.setOutputValue(self.OUTPUT, outFile)
output_details = GdalUtils.gdal_connection_details_from_uri(outFile, context)
- arguments = [
- '-b',
- str(self.parameterAsInt(parameters, self.BAND, context))
- ]
+ arguments = ["-b", str(self.parameterAsInt(parameters, self.BAND, context))]
if fieldName:
- arguments.append('-a')
+ arguments.append("-a")
arguments.append(fieldName)
- arguments.append('-i')
- arguments.append(str(self.parameterAsDouble(parameters, self.INTERVAL, context)))
+ arguments.append("-i")
+ arguments.append(
+ str(self.parameterAsDouble(parameters, self.INTERVAL, context))
+ )
if self.parameterAsBoolean(parameters, self.CREATE_3D, context):
- arguments.append('-3d')
+ arguments.append("-3d")
if self.parameterAsBoolean(parameters, self.IGNORE_NODATA, context):
- arguments.append('-inodata')
+ arguments.append("-inodata")
if nodata is not None:
- arguments.append(f'-snodata {nodata}')
+ arguments.append(f"-snodata {nodata}")
if offset:
- arguments.append(f'-off {offset}')
+ arguments.append(f"-off {offset}")
if output_details.format:
- arguments.append(f'-f {output_details.format}')
+ arguments.append(f"-f {output_details.format}")
if input_details.credential_options:
arguments.extend(input_details.credential_options_as_arguments())
- if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ''):
+ if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ""):
extra = self.parameterAsString(parameters, self.EXTRA, context)
arguments.append(extra)
@@ -200,8 +246,8 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True):
class contour_polygon(contour):
- FIELD_NAME_MIN = 'FIELD_NAME_MIN'
- FIELD_NAME_MAX = 'FIELD_NAME_MAX'
+ FIELD_NAME_MIN = "FIELD_NAME_MIN"
+ FIELD_NAME_MAX = "FIELD_NAME_MAX"
def __init__(self):
super().__init__()
@@ -211,26 +257,39 @@ def initAlgorithm(self, config=None):
# FIELD_NAME isn't used in polygon mode
self.removeParameter(contour.FIELD_NAME)
- self.addParameter(QgsProcessingParameterString(self.FIELD_NAME_MIN,
- self.tr('Attribute name for minimum elevation of contour polygon'),
- defaultValue='ELEV_MIN',
- optional=True))
-
- self.addParameter(QgsProcessingParameterString(self.FIELD_NAME_MAX,
- self.tr('Attribute name for maximum elevation of contour polygon'),
- defaultValue='ELEV_MAX',
- optional=True))
+ self.addParameter(
+ QgsProcessingParameterString(
+ self.FIELD_NAME_MIN,
+ self.tr("Attribute name for minimum elevation of contour polygon"),
+ defaultValue="ELEV_MIN",
+ optional=True,
+ )
+ )
+
+ self.addParameter(
+ QgsProcessingParameterString(
+ self.FIELD_NAME_MAX,
+ self.tr("Attribute name for maximum elevation of contour polygon"),
+ defaultValue="ELEV_MAX",
+ optional=True,
+ )
+ )
# Need to replace the output parameter, as we are producing a different type of output
self.removeParameter(contour.OUTPUT)
- self.addParameter(QgsProcessingParameterVectorDestination(
- contour.OUTPUT, self.tr('Contours'), QgsProcessing.SourceType.TypeVectorPolygon))
+ self.addParameter(
+ QgsProcessingParameterVectorDestination(
+ contour.OUTPUT,
+ self.tr("Contours"),
+ QgsProcessing.SourceType.TypeVectorPolygon,
+ )
+ )
def name(self):
- return 'contour_polygon'
+ return "contour_polygon"
def displayName(self):
- return self.tr('Contour Polygons')
+ return self.tr("Contour Polygons")
def getConsoleCommands(self, parameters, context, feedback, executing=True):
arguments = self._buildArgsList(parameters, context, feedback, executing)
@@ -240,11 +299,11 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True):
if fieldNameMin:
arguments.insert(0, fieldNameMin)
- arguments.insert(0, '-amin')
+ arguments.insert(0, "-amin")
if fieldNameMax:
arguments.insert(0, fieldNameMax)
- arguments.insert(0, '-amax')
+ arguments.insert(0, "-amax")
arguments.insert(0, "-p")
diff --git a/python/plugins/processing/algs/gdal/extractprojection.py b/python/plugins/processing/algs/gdal/extractprojection.py
index e51a07048ed5..ff34e77e4cc2 100644
--- a/python/plugins/processing/algs/gdal/extractprojection.py
+++ b/python/plugins/processing/algs/gdal/extractprojection.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Alexander Bruy'
-__date__ = 'September 2013'
-__copyright__ = '(C) 2013, Alexander Bruy'
+__author__ = "Alexander Bruy"
+__date__ = "September 2013"
+__copyright__ = "(C) 2013, Alexander Bruy"
import os
@@ -27,9 +27,11 @@
from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm
from qgis.core import QgsProcessingException
-from qgis.core import (QgsProcessingParameterRasterLayer,
- QgsProcessingParameterBoolean,
- QgsProcessingOutputFile)
+from qgis.core import (
+ QgsProcessingParameterRasterLayer,
+ QgsProcessingParameterBoolean,
+ QgsProcessingOutputFile,
+)
pluginPath = os.path.split(os.path.split(os.path.dirname(__file__))[0])[0]
@@ -38,61 +40,58 @@
class ExtractProjection(GdalAlgorithm):
- INPUT = 'INPUT'
- PRJ_FILE_CREATE = 'PRJ_FILE_CREATE'
- WORLD_FILE = 'WORLD_FILE'
- PRJ_FILE = 'PRJ_FILE'
+ INPUT = "INPUT"
+ PRJ_FILE_CREATE = "PRJ_FILE_CREATE"
+ WORLD_FILE = "WORLD_FILE"
+ PRJ_FILE = "PRJ_FILE"
def __init__(self):
super().__init__()
def initAlgorithm(self, config=None):
- self.addParameter(QgsProcessingParameterRasterLayer(
- self.INPUT,
- self.tr('Input file')))
- self.addParameter(QgsProcessingParameterBoolean(
- self.PRJ_FILE_CREATE,
- self.tr('Create also .prj file'), False))
- self.addOutput(QgsProcessingOutputFile(
- self.WORLD_FILE,
- self.tr('World file')))
- self.addOutput(QgsProcessingOutputFile(
- self.PRJ_FILE,
- self.tr('ESRI Shapefile prj file')))
+ self.addParameter(
+ QgsProcessingParameterRasterLayer(self.INPUT, self.tr("Input file"))
+ )
+ self.addParameter(
+ QgsProcessingParameterBoolean(
+ self.PRJ_FILE_CREATE, self.tr("Create also .prj file"), False
+ )
+ )
+ self.addOutput(QgsProcessingOutputFile(self.WORLD_FILE, self.tr("World file")))
+ self.addOutput(
+ QgsProcessingOutputFile(self.PRJ_FILE, self.tr("ESRI Shapefile prj file"))
+ )
def name(self):
- return 'extractprojection'
+ return "extractprojection"
def displayName(self):
- return self.tr('Extract projection')
+ return self.tr("Extract projection")
def icon(self):
- return QIcon(os.path.join(pluginPath, 'images', 'gdaltools',
- 'projection-export.png'))
+ return QIcon(
+ os.path.join(pluginPath, "images", "gdaltools", "projection-export.png")
+ )
def group(self):
- return self.tr('Raster projections')
+ return self.tr("Raster projections")
def groupId(self):
- return 'rasterprojections'
+ return "rasterprojections"
def commandName(self):
- return 'extractprojection'
+ return "extractprojection"
- def getConsoleCommands(self, parameters, context, feedback,
- executing=True):
+ def getConsoleCommands(self, parameters, context, feedback, executing=True):
return [self.commandName()]
def processAlgorithm(self, parameters, context, feedback):
- createPrj = self.parameterAsBoolean(parameters,
- self.PRJ_FILE_CREATE,
- context)
- raster = self.parameterAsRasterLayer(parameters, self.INPUT,
- context)
- if raster.dataProvider().name() != 'gdal':
- raise QgsProcessingException(self.tr('This algorithm can '
- 'only be used with '
- 'GDAL raster layers'))
+ createPrj = self.parameterAsBoolean(parameters, self.PRJ_FILE_CREATE, context)
+ raster = self.parameterAsRasterLayer(parameters, self.INPUT, context)
+ if raster.dataProvider().name() != "gdal":
+ raise QgsProcessingException(
+ self.tr("This algorithm can " "only be used with " "GDAL raster layers")
+ )
rasterPath = raster.source()
rasterDS = gdal.Open(rasterPath, gdal.GA_ReadOnly)
geotransform = rasterDS.GetGeoTransform()
@@ -105,36 +104,38 @@ def processAlgorithm(self, parameters, context, feedback):
outFileName = inFileName[0]
# this is not a good idea as it won't work with an extension like .jpeg
# outFileExt = '.' + inFileName[1][1:4:2] + 'w'
- if (len(inFileName[1]) < 4):
- outFileExt = '.wld'
+ if len(inFileName[1]) < 4:
+ outFileExt = ".wld"
else:
- outFileExt = inFileName[1][0:2] + inFileName[1][-1] + 'w'
+ outFileExt = inFileName[1][0:2] + inFileName[1][-1] + "w"
results = {}
- if crs != '' and createPrj:
+ if crs != "" and createPrj:
tmp = osr.SpatialReference()
tmp.ImportFromWkt(crs)
tmp.MorphToESRI()
crs = tmp.ExportToWkt()
tmp = None
- with open(outFileName + '.prj', 'w', encoding='utf-8') as prj:
+ with open(outFileName + ".prj", "w", encoding="utf-8") as prj:
prj.write(crs)
- results[self.PRJ_FILE] = outFileName + '.prj'
+ results[self.PRJ_FILE] = outFileName + ".prj"
else:
results[self.PRJ_FILE] = None
- with open(outFileName + outFileExt, 'w') as wld:
- wld.write('%0.8f\n' % geotransform[1])
- wld.write('%0.8f\n' % geotransform[4])
- wld.write('%0.8f\n' % geotransform[2])
- wld.write('%0.8f\n' % geotransform[5])
- wld.write('%0.8f\n' % (geotransform[0]
- + 0.5 * geotransform[1]
- + 0.5 * geotransform[2]))
- wld.write('%0.8f\n' % (geotransform[3]
- + 0.5 * geotransform[4]
- + 0.5 * geotransform[5]))
+ with open(outFileName + outFileExt, "w") as wld:
+ wld.write("%0.8f\n" % geotransform[1])
+ wld.write("%0.8f\n" % geotransform[4])
+ wld.write("%0.8f\n" % geotransform[2])
+ wld.write("%0.8f\n" % geotransform[5])
+ wld.write(
+ "%0.8f\n"
+ % (geotransform[0] + 0.5 * geotransform[1] + 0.5 * geotransform[2])
+ )
+ wld.write(
+ "%0.8f\n"
+ % (geotransform[3] + 0.5 * geotransform[4] + 0.5 * geotransform[5])
+ )
results[self.WORLD_FILE] = outFileName + outFileExt
return results
diff --git a/python/plugins/processing/algs/gdal/fillnodata.py b/python/plugins/processing/algs/gdal/fillnodata.py
index b313c0294c6a..8e7143b5f3eb 100644
--- a/python/plugins/processing/algs/gdal/fillnodata.py
+++ b/python/plugins/processing/algs/gdal/fillnodata.py
@@ -15,22 +15,24 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'August 2012'
-__copyright__ = '(C) 2012, Victor Olaya'
+__author__ = "Victor Olaya"
+__date__ = "August 2012"
+__copyright__ = "(C) 2012, Victor Olaya"
import os
-from qgis.core import (QgsProcessingAlgorithm,
- QgsRasterFileWriter,
- QgsProcessingException,
- QgsProcessingParameterDefinition,
- QgsProcessingParameterRasterLayer,
- QgsProcessingParameterBand,
- QgsProcessingParameterNumber,
- QgsProcessingParameterBoolean,
- QgsProcessingParameterString,
- QgsProcessingParameterRasterDestination)
+from qgis.core import (
+ QgsProcessingAlgorithm,
+ QgsRasterFileWriter,
+ QgsProcessingException,
+ QgsProcessingParameterDefinition,
+ QgsProcessingParameterRasterLayer,
+ QgsProcessingParameterBand,
+ QgsProcessingParameterNumber,
+ QgsProcessingParameterBoolean,
+ QgsProcessingParameterString,
+ QgsProcessingParameterRasterDestination,
+)
from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm
from processing.tools.system import isWindows
from processing.algs.gdal.GdalUtils import GdalUtils
@@ -39,80 +41,114 @@
class fillnodata(GdalAlgorithm):
- INPUT = 'INPUT'
- BAND = 'BAND'
- DISTANCE = 'DISTANCE'
- ITERATIONS = 'ITERATIONS'
- NO_MASK = 'NO_MASK'
- MASK_LAYER = 'MASK_LAYER'
- OPTIONS = 'OPTIONS'
- EXTRA = 'EXTRA'
- OUTPUT = 'OUTPUT'
+ INPUT = "INPUT"
+ BAND = "BAND"
+ DISTANCE = "DISTANCE"
+ ITERATIONS = "ITERATIONS"
+ NO_MASK = "NO_MASK"
+ MASK_LAYER = "MASK_LAYER"
+ OPTIONS = "OPTIONS"
+ EXTRA = "EXTRA"
+ OUTPUT = "OUTPUT"
def __init__(self):
super().__init__()
def initAlgorithm(self, config=None):
- self.addParameter(QgsProcessingParameterRasterLayer(self.INPUT, self.tr('Input layer')))
- self.addParameter(QgsProcessingParameterBand(self.BAND,
- self.tr('Band number'),
- 1,
- parentLayerParameterName=self.INPUT))
- self.addParameter(QgsProcessingParameterNumber(self.DISTANCE,
- self.tr('Maximum distance (in pixels) to search out for values to interpolate'),
- type=QgsProcessingParameterNumber.Type.Integer,
- minValue=0,
- defaultValue=10))
- self.addParameter(QgsProcessingParameterNumber(self.ITERATIONS,
- self.tr('Number of smoothing iterations to run after the interpolation'),
- type=QgsProcessingParameterNumber.Type.Integer,
- minValue=0,
- defaultValue=0))
+ self.addParameter(
+ QgsProcessingParameterRasterLayer(self.INPUT, self.tr("Input layer"))
+ )
+ self.addParameter(
+ QgsProcessingParameterBand(
+ self.BAND,
+ self.tr("Band number"),
+ 1,
+ parentLayerParameterName=self.INPUT,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterNumber(
+ self.DISTANCE,
+ self.tr(
+ "Maximum distance (in pixels) to search out for values to interpolate"
+ ),
+ type=QgsProcessingParameterNumber.Type.Integer,
+ minValue=0,
+ defaultValue=10,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterNumber(
+ self.ITERATIONS,
+ self.tr(
+ "Number of smoothing iterations to run after the interpolation"
+ ),
+ type=QgsProcessingParameterNumber.Type.Integer,
+ minValue=0,
+ defaultValue=0,
+ )
+ )
# The -nomask option is no longer supported since GDAL 3.4 and
# it doesn't work as expected even using GDAL < 3.4 https://github.com/OSGeo/gdal/pull/4201
- nomask_param = QgsProcessingParameterBoolean(self.NO_MASK,
- self.tr('Do not use the default validity mask for the input band'),
- defaultValue=False,
- optional=True)
- nomask_param.setFlags(nomask_param.flags() | QgsProcessingParameterDefinition.Flag.FlagHidden)
+ nomask_param = QgsProcessingParameterBoolean(
+ self.NO_MASK,
+ self.tr("Do not use the default validity mask for the input band"),
+ defaultValue=False,
+ optional=True,
+ )
+ nomask_param.setFlags(
+ nomask_param.flags() | QgsProcessingParameterDefinition.Flag.FlagHidden
+ )
self.addParameter(nomask_param)
- self.addParameter(QgsProcessingParameterRasterLayer(self.MASK_LAYER,
- self.tr('Validity mask'),
- optional=True))
-
- options_param = QgsProcessingParameterString(self.OPTIONS,
- self.tr('Additional creation options'),
- defaultValue='',
- optional=True)
- options_param.setFlags(options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
- options_param.setMetadata({'widget_wrapper': {'widget_type': 'rasteroptions'}})
+ self.addParameter(
+ QgsProcessingParameterRasterLayer(
+ self.MASK_LAYER, self.tr("Validity mask"), optional=True
+ )
+ )
+
+ options_param = QgsProcessingParameterString(
+ self.OPTIONS,
+ self.tr("Additional creation options"),
+ defaultValue="",
+ optional=True,
+ )
+ options_param.setFlags(
+ options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
+ options_param.setMetadata({"widget_wrapper": {"widget_type": "rasteroptions"}})
self.addParameter(options_param)
- extra_param = QgsProcessingParameterString(self.EXTRA,
- self.tr('Additional command-line parameters'),
- defaultValue=None,
- optional=True)
- extra_param.setFlags(extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
+ extra_param = QgsProcessingParameterString(
+ self.EXTRA,
+ self.tr("Additional command-line parameters"),
+ defaultValue=None,
+ optional=True,
+ )
+ extra_param.setFlags(
+ extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
self.addParameter(extra_param)
- self.addParameter(QgsProcessingParameterRasterDestination(self.OUTPUT, self.tr('Filled')))
+ self.addParameter(
+ QgsProcessingParameterRasterDestination(self.OUTPUT, self.tr("Filled"))
+ )
def name(self):
- return 'fillnodata'
+ return "fillnodata"
def displayName(self):
- return self.tr('Fill NoData')
+ return self.tr("Fill NoData")
def group(self):
- return self.tr('Raster analysis')
+ return self.tr("Raster analysis")
def groupId(self):
- return 'rasteranalysis'
+ return "rasteranalysis"
def commandName(self):
- return 'gdal_fillnodata'
+ return "gdal_fillnodata"
def flags(self):
return super().flags() | QgsProcessingAlgorithm.Flag.FlagDisplayNameIsLiteral
@@ -120,7 +156,9 @@ def flags(self):
def getConsoleCommands(self, parameters, context, feedback, executing=True):
raster = self.parameterAsRasterLayer(parameters, self.INPUT, context)
if raster is None:
- raise QgsProcessingException(self.invalidRasterError(parameters, self.INPUT))
+ raise QgsProcessingException(
+ self.invalidRasterError(parameters, self.INPUT)
+ )
input_details = GdalUtils.gdal_connection_details_from_layer(raster)
out = self.parameterAsOutputLayer(parameters, self.OUTPUT, context)
@@ -129,34 +167,34 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True):
arguments = [
input_details.connection_string,
out,
- '-md',
+ "-md",
str(self.parameterAsInt(parameters, self.DISTANCE, context)),
]
nIterations = self.parameterAsInt(parameters, self.ITERATIONS, context)
if nIterations:
- arguments.append('-si')
+ arguments.append("-si")
arguments.append(str(nIterations))
- arguments.append('-b')
+ arguments.append("-b")
arguments.append(str(self.parameterAsInt(parameters, self.BAND, context)))
mask = self.parameterAsRasterLayer(parameters, self.MASK_LAYER, context)
if mask:
- arguments.append('-mask')
+ arguments.append("-mask")
arguments.append(mask.source())
output_format = QgsRasterFileWriter.driverForExtension(os.path.splitext(out)[1])
if not output_format:
- raise QgsProcessingException(self.tr('Output format is invalid'))
+ raise QgsProcessingException(self.tr("Output format is invalid"))
- arguments.append('-of')
+ arguments.append("-of")
arguments.append(output_format)
if input_details.credential_options:
arguments.extend(input_details.credential_options_as_arguments())
- if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ''):
+ if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ""):
extra = self.parameterAsString(parameters, self.EXTRA, context)
arguments.append(extra)
@@ -165,4 +203,7 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True):
if options:
arguments.extend(GdalUtils.parseCreationOptions(options))
- return [self.commandName() + ('.bat' if isWindows() else '.py'), GdalUtils.escapeAndJoin(arguments)]
+ return [
+ self.commandName() + (".bat" if isWindows() else ".py"),
+ GdalUtils.escapeAndJoin(arguments),
+ ]
diff --git a/python/plugins/processing/algs/gdal/gdal2tiles.py b/python/plugins/processing/algs/gdal/gdal2tiles.py
index 6e3ba4e6524d..ad60c3284b9f 100644
--- a/python/plugins/processing/algs/gdal/gdal2tiles.py
+++ b/python/plugins/processing/algs/gdal/gdal2tiles.py
@@ -15,209 +15,264 @@
***************************************************************************
"""
-__author__ = 'Médéric Ribreux'
-__date__ = 'January 2016'
-__copyright__ = '(C) 2016, Médéric Ribreux'
-
-from qgis.core import (QgsProcessingAlgorithm,
- QgsProcessingException,
- QgsProcessingParameterDefinition,
- QgsProcessingParameterRasterLayer,
- QgsProcessingParameterCrs,
- QgsProcessingParameterEnum,
- QgsProcessingParameterString,
- QgsProcessingParameterNumber,
- QgsProcessingParameterBoolean,
- QgsProcessingParameterFolderDestination)
+__author__ = "Médéric Ribreux"
+__date__ = "January 2016"
+__copyright__ = "(C) 2016, Médéric Ribreux"
+
+from qgis.core import (
+ QgsProcessingAlgorithm,
+ QgsProcessingException,
+ QgsProcessingParameterDefinition,
+ QgsProcessingParameterRasterLayer,
+ QgsProcessingParameterCrs,
+ QgsProcessingParameterEnum,
+ QgsProcessingParameterString,
+ QgsProcessingParameterNumber,
+ QgsProcessingParameterBoolean,
+ QgsProcessingParameterFolderDestination,
+)
from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm
from processing.algs.gdal.GdalUtils import GdalUtils
from processing.tools.system import isWindows
class gdal2tiles(GdalAlgorithm):
- INPUT = 'INPUT'
- PROFILE = 'PROFILE'
- RESAMPLING = 'RESAMPLING'
- ZOOM = 'ZOOM'
- SOURCE_CRS = 'SOURCE_CRS'
- NODATA = 'NODATA'
- KML = 'KML'
- NO_KML = 'NO_KML'
- URL = 'URL'
- VIEWER = 'VIEWER'
- TITLE = 'TITLE'
- COPYRIGHT = 'COPYRIGHT'
- GOOGLE_KEY = 'GOOGLE_KEY'
- BING_KEY = 'BING_KEY'
- RESUME = 'RESUME'
- OUTPUT = 'OUTPUT'
+ INPUT = "INPUT"
+ PROFILE = "PROFILE"
+ RESAMPLING = "RESAMPLING"
+ ZOOM = "ZOOM"
+ SOURCE_CRS = "SOURCE_CRS"
+ NODATA = "NODATA"
+ KML = "KML"
+ NO_KML = "NO_KML"
+ URL = "URL"
+ VIEWER = "VIEWER"
+ TITLE = "TITLE"
+ COPYRIGHT = "COPYRIGHT"
+ GOOGLE_KEY = "GOOGLE_KEY"
+ BING_KEY = "BING_KEY"
+ RESUME = "RESUME"
+ OUTPUT = "OUTPUT"
def __init__(self):
super().__init__()
def initAlgorithm(self, config=None):
- self.profiles = ((self.tr('Mercator'), 'mercator'),
- (self.tr('Geodetic'), 'geodetic'),
- (self.tr('Raster'), 'raster'))
-
- self.methods = ((self.tr('Average'), 'average'),
- (self.tr('Nearest Neighbour'), 'near'),
- (self.tr('Bilinear (2x2 Kernel)'), 'bilinear'),
- (self.tr('Cubic (4x4 Kernel)'), 'cubic'),
- (self.tr('Cubic B-Spline (4x4 Kernel)'), 'cubicspline'),
- (self.tr('Lanczos (6x6 Kernel)'), 'lanczos'),
- (self.tr('Antialias'), 'antialias'))
-
- self.viewers = ((self.tr('All'), 'all'),
- (self.tr('GoogleMaps'), 'google'),
- (self.tr('OpenLayers'), 'openlayers'),
- (self.tr('Leaflet'), 'leaflet'),
- (self.tr('None'), 'none'))
-
- self.addParameter(QgsProcessingParameterRasterLayer(self.INPUT, self.tr('Input layer')))
- self.addParameter(QgsProcessingParameterEnum(self.PROFILE,
- self.tr('Tile cutting profile'),
- options=[i[0] for i in self.profiles],
- allowMultiple=False,
- defaultValue=0))
- self.addParameter(QgsProcessingParameterString(self.ZOOM,
- self.tr('Zoom levels to render'),
- defaultValue='',
- optional=True))
- self.addParameter(QgsProcessingParameterEnum(self.VIEWER,
- self.tr('Web viewer to generate'),
- options=[i[0] for i in self.viewers],
- allowMultiple=False,
- defaultValue=0))
- self.addParameter(QgsProcessingParameterString(self.TITLE,
- self.tr('Title of the map'),
- optional=True))
- self.addParameter(QgsProcessingParameterString(self.COPYRIGHT,
- self.tr('Copyright of the map'),
- optional=True))
+ self.profiles = (
+ (self.tr("Mercator"), "mercator"),
+ (self.tr("Geodetic"), "geodetic"),
+ (self.tr("Raster"), "raster"),
+ )
+
+ self.methods = (
+ (self.tr("Average"), "average"),
+ (self.tr("Nearest Neighbour"), "near"),
+ (self.tr("Bilinear (2x2 Kernel)"), "bilinear"),
+ (self.tr("Cubic (4x4 Kernel)"), "cubic"),
+ (self.tr("Cubic B-Spline (4x4 Kernel)"), "cubicspline"),
+ (self.tr("Lanczos (6x6 Kernel)"), "lanczos"),
+ (self.tr("Antialias"), "antialias"),
+ )
+
+ self.viewers = (
+ (self.tr("All"), "all"),
+ (self.tr("GoogleMaps"), "google"),
+ (self.tr("OpenLayers"), "openlayers"),
+ (self.tr("Leaflet"), "leaflet"),
+ (self.tr("None"), "none"),
+ )
+
+ self.addParameter(
+ QgsProcessingParameterRasterLayer(self.INPUT, self.tr("Input layer"))
+ )
+ self.addParameter(
+ QgsProcessingParameterEnum(
+ self.PROFILE,
+ self.tr("Tile cutting profile"),
+ options=[i[0] for i in self.profiles],
+ allowMultiple=False,
+ defaultValue=0,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterString(
+ self.ZOOM,
+ self.tr("Zoom levels to render"),
+ defaultValue="",
+ optional=True,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterEnum(
+ self.VIEWER,
+ self.tr("Web viewer to generate"),
+ options=[i[0] for i in self.viewers],
+ allowMultiple=False,
+ defaultValue=0,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterString(
+ self.TITLE, self.tr("Title of the map"), optional=True
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterString(
+ self.COPYRIGHT, self.tr("Copyright of the map"), optional=True
+ )
+ )
params = [
- QgsProcessingParameterEnum(self.RESAMPLING,
- self.tr('Resampling method'),
- options=[i[0] for i in self.methods],
- allowMultiple=False,
- defaultValue=0),
- QgsProcessingParameterCrs(self.SOURCE_CRS,
- self.tr('The spatial reference system used for the source input data'),
- optional=True),
- QgsProcessingParameterNumber(self.NODATA,
- self.tr('Transparency value to assign to the input data'),
- type=QgsProcessingParameterNumber.Type.Double,
- defaultValue=0,
- optional=True),
- QgsProcessingParameterString(self.URL,
- self.tr('URL address where the generated tiles are going to be published'),
- optional=True),
- QgsProcessingParameterString(self.GOOGLE_KEY,
- self.tr('Google Maps API key (http://code.google.com/apis/maps/signup.html)'),
- optional=True),
- QgsProcessingParameterString(self.BING_KEY,
- self.tr('Bing Maps API key (https://www.bingmapsportal.com/)'),
- optional=True),
- QgsProcessingParameterBoolean(self.RESUME,
- self.tr('Generate only missing files'),
- defaultValue=False),
- QgsProcessingParameterBoolean(self.KML,
- self.tr('Generate KML for Google Earth'),
- defaultValue=False),
- QgsProcessingParameterBoolean(self.NO_KML,
- self.tr('Avoid automatic generation of KML files for EPSG:4326'),
- defaultValue=False)
+ QgsProcessingParameterEnum(
+ self.RESAMPLING,
+ self.tr("Resampling method"),
+ options=[i[0] for i in self.methods],
+ allowMultiple=False,
+ defaultValue=0,
+ ),
+ QgsProcessingParameterCrs(
+ self.SOURCE_CRS,
+ self.tr("The spatial reference system used for the source input data"),
+ optional=True,
+ ),
+ QgsProcessingParameterNumber(
+ self.NODATA,
+ self.tr("Transparency value to assign to the input data"),
+ type=QgsProcessingParameterNumber.Type.Double,
+ defaultValue=0,
+ optional=True,
+ ),
+ QgsProcessingParameterString(
+ self.URL,
+ self.tr(
+ "URL address where the generated tiles are going to be published"
+ ),
+ optional=True,
+ ),
+ QgsProcessingParameterString(
+ self.GOOGLE_KEY,
+ self.tr(
+ "Google Maps API key (http://code.google.com/apis/maps/signup.html)"
+ ),
+ optional=True,
+ ),
+ QgsProcessingParameterString(
+ self.BING_KEY,
+ self.tr("Bing Maps API key (https://www.bingmapsportal.com/)"),
+ optional=True,
+ ),
+ QgsProcessingParameterBoolean(
+ self.RESUME, self.tr("Generate only missing files"), defaultValue=False
+ ),
+ QgsProcessingParameterBoolean(
+ self.KML, self.tr("Generate KML for Google Earth"), defaultValue=False
+ ),
+ QgsProcessingParameterBoolean(
+ self.NO_KML,
+ self.tr("Avoid automatic generation of KML files for EPSG:4326"),
+ defaultValue=False,
+ ),
]
for param in params:
- param.setFlags(param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
+ param.setFlags(
+ param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
self.addParameter(param)
- self.addParameter(QgsProcessingParameterFolderDestination(self.OUTPUT,
- self.tr('Output directory')))
+ self.addParameter(
+ QgsProcessingParameterFolderDestination(
+ self.OUTPUT, self.tr("Output directory")
+ )
+ )
def name(self):
- return 'gdal2tiles'
+ return "gdal2tiles"
def displayName(self):
- return self.tr('gdal2tiles')
+ return self.tr("gdal2tiles")
def group(self):
- return self.tr('Raster miscellaneous')
+ return self.tr("Raster miscellaneous")
def groupId(self):
- return 'rastermiscellaneous'
+ return "rastermiscellaneous"
def commandName(self):
- return 'gdal2tiles'
+ return "gdal2tiles"
def flags(self):
return super().flags() | QgsProcessingAlgorithm.Flag.FlagDisplayNameIsLiteral
def getConsoleCommands(self, parameters, context, feedback, executing=True):
arguments = [
- '-p',
+ "-p",
self.profiles[self.parameterAsEnum(parameters, self.PROFILE, context)][1],
]
zoom = self.parameterAsString(parameters, self.ZOOM, context)
if zoom:
- arguments.append('-z')
+ arguments.append("-z")
arguments.append(str(zoom))
- arguments.append('-w')
- arguments.append(self.viewers[self.parameterAsEnum(parameters, self.VIEWER, context)][1])
+ arguments.append("-w")
+ arguments.append(
+ self.viewers[self.parameterAsEnum(parameters, self.VIEWER, context)][1]
+ )
title = self.parameterAsString(parameters, self.TITLE, context)
if title:
- arguments.append('-t')
+ arguments.append("-t")
arguments.append(title)
copying = self.parameterAsString(parameters, self.COPYRIGHT, context)
if copying:
- arguments.append('-c')
+ arguments.append("-c")
arguments.append(copying)
- arguments.append('-r')
- arguments.append(self.methods[self.parameterAsEnum(parameters, self.RESAMPLING, context)][1])
+ arguments.append("-r")
+ arguments.append(
+ self.methods[self.parameterAsEnum(parameters, self.RESAMPLING, context)][1]
+ )
crs = self.parameterAsCrs(parameters, self.SOURCE_CRS, context)
if crs.isValid():
- arguments.append('-s')
+ arguments.append("-s")
arguments.append(GdalUtils.gdal_crs_string(crs))
if self.NODATA in parameters and parameters[self.NODATA] is not None:
nodata = self.parameterAsDouble(parameters, self.NODATA, context)
- arguments.append('-a')
+ arguments.append("-a")
arguments.append(str(nodata))
url = self.parameterAsString(parameters, self.URL, context)
if url:
- arguments.append('-u')
+ arguments.append("-u")
arguments.append(url)
key = self.parameterAsString(parameters, self.GOOGLE_KEY, context)
if key:
- arguments.append('-g')
+ arguments.append("-g")
arguments.append(key)
key = self.parameterAsString(parameters, self.BING_KEY, context)
if key:
- arguments.append('-b')
+ arguments.append("-b")
arguments.append(key)
if self.parameterAsBoolean(parameters, self.RESUME, context):
- arguments.append('-e')
+ arguments.append("-e")
if self.parameterAsBoolean(parameters, self.KML, context):
- arguments.append('-k')
+ arguments.append("-k")
if self.parameterAsBoolean(parameters, self.NO_KML, context):
- arguments.append('-n')
+ arguments.append("-n")
inLayer = self.parameterAsRasterLayer(parameters, self.INPUT, context)
if inLayer is None:
- raise QgsProcessingException(self.invalidRasterError(parameters, self.INPUT))
+ raise QgsProcessingException(
+ self.invalidRasterError(parameters, self.INPUT)
+ )
input_details = GdalUtils.gdal_connection_details_from_layer(inLayer)
@@ -227,4 +282,7 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True):
if input_details.credential_options:
arguments.extend(input_details.credential_options_as_arguments())
- return [self.commandName() + ('.bat' if isWindows() else '.py'), GdalUtils.escapeAndJoin(arguments)]
+ return [
+ self.commandName() + (".bat" if isWindows() else ".py"),
+ GdalUtils.escapeAndJoin(arguments),
+ ]
diff --git a/python/plugins/processing/algs/gdal/gdal2xyz.py b/python/plugins/processing/algs/gdal/gdal2xyz.py
index 4b23bd172259..c56fc2d86419 100644
--- a/python/plugins/processing/algs/gdal/gdal2xyz.py
+++ b/python/plugins/processing/algs/gdal/gdal2xyz.py
@@ -15,112 +15,149 @@
***************************************************************************
"""
-__author__ = 'Alexander Bruy'
-__date__ = 'September 2013'
-__copyright__ = '(C) 2013, Alexander Bruy'
-
-from qgis.core import (QgsProcessingAlgorithm,
- QgsProcessingException,
- QgsProcessingParameterRasterLayer,
- QgsProcessingParameterBand,
- QgsProcessingParameterBoolean,
- QgsProcessingParameterFileDestination,
- QgsProcessingParameterNumber
- )
+__author__ = "Alexander Bruy"
+__date__ = "September 2013"
+__copyright__ = "(C) 2013, Alexander Bruy"
+
+from qgis.core import (
+ QgsProcessingAlgorithm,
+ QgsProcessingException,
+ QgsProcessingParameterRasterLayer,
+ QgsProcessingParameterBand,
+ QgsProcessingParameterBoolean,
+ QgsProcessingParameterFileDestination,
+ QgsProcessingParameterNumber,
+)
from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm
from processing.algs.gdal.GdalUtils import GdalUtils
from processing.tools.system import isWindows
class gdal2xyz(GdalAlgorithm):
- INPUT = 'INPUT'
- BAND = 'BAND'
- SRCNODATA = 'NODATA_INPUT'
- DSTNODATA = 'NODATA_OUTPUT'
- SKIPNODATA = 'SKIP_NODATA'
- CSV = 'CSV'
- OUTPUT = 'OUTPUT'
+ INPUT = "INPUT"
+ BAND = "BAND"
+ SRCNODATA = "NODATA_INPUT"
+ DSTNODATA = "NODATA_OUTPUT"
+ SKIPNODATA = "SKIP_NODATA"
+ CSV = "CSV"
+ OUTPUT = "OUTPUT"
def __init__(self):
super().__init__()
def initAlgorithm(self, config=None):
- self.addParameter(QgsProcessingParameterRasterLayer(self.INPUT,
- self.tr('Input layer')))
- self.addParameter(QgsProcessingParameterBand(self.BAND,
- self.tr('Band number'),
- 1,
- parentLayerParameterName=self.INPUT))
-
- self.addParameter(QgsProcessingParameterNumber(self.SRCNODATA,
- self.tr('Input pixel value to treat as NoData'),
- optional=True)) # GDAL > 3.6.3
- self.addParameter(QgsProcessingParameterNumber(self.DSTNODATA,
- self.tr('Assign specified NoData value to output'),
- optional=True)) # GDAL > 3.6.3
- self.addParameter(QgsProcessingParameterBoolean(self.SKIPNODATA,
- self.tr('Do not output NoData values'),
- defaultValue=False)) # GDAL > 3.3
- self.addParameter(QgsProcessingParameterBoolean(self.CSV,
- self.tr('Output comma-separated values'),
- defaultValue=False))
- self.addParameter(QgsProcessingParameterFileDestination(self.OUTPUT,
- self.tr('XYZ ASCII file'),
- self.tr('CSV files (*.csv)')))
+ self.addParameter(
+ QgsProcessingParameterRasterLayer(self.INPUT, self.tr("Input layer"))
+ )
+ self.addParameter(
+ QgsProcessingParameterBand(
+ self.BAND,
+ self.tr("Band number"),
+ 1,
+ parentLayerParameterName=self.INPUT,
+ )
+ )
+
+ self.addParameter(
+ QgsProcessingParameterNumber(
+ self.SRCNODATA,
+ self.tr("Input pixel value to treat as NoData"),
+ optional=True,
+ )
+ ) # GDAL > 3.6.3
+ self.addParameter(
+ QgsProcessingParameterNumber(
+ self.DSTNODATA,
+ self.tr("Assign specified NoData value to output"),
+ optional=True,
+ )
+ ) # GDAL > 3.6.3
+ self.addParameter(
+ QgsProcessingParameterBoolean(
+ self.SKIPNODATA,
+ self.tr("Do not output NoData values"),
+ defaultValue=False,
+ )
+ ) # GDAL > 3.3
+ self.addParameter(
+ QgsProcessingParameterBoolean(
+ self.CSV, self.tr("Output comma-separated values"), defaultValue=False
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterFileDestination(
+ self.OUTPUT, self.tr("XYZ ASCII file"), self.tr("CSV files (*.csv)")
+ )
+ )
def name(self):
- return 'gdal2xyz'
+ return "gdal2xyz"
def displayName(self):
- return self.tr('gdal2xyz')
+ return self.tr("gdal2xyz")
def group(self):
- return self.tr('Raster conversion')
+ return self.tr("Raster conversion")
def groupId(self):
- return 'rasterconversion'
+ return "rasterconversion"
def commandName(self):
- return 'gdal2xyz'
+ return "gdal2xyz"
def flags(self):
return super().flags() | QgsProcessingAlgorithm.Flag.FlagDisplayNameIsLiteral
def getConsoleCommands(self, parameters, context, feedback, executing=True):
- arguments = [
- '-band',
- str(self.parameterAsInt(parameters, self.BAND, context))
- ]
+ arguments = ["-band", str(self.parameterAsInt(parameters, self.BAND, context))]
if self.SRCNODATA in parameters and parameters[self.SRCNODATA] is not None:
- if GdalUtils.version() > 3060300: # src/dstnodata broken <= 3.6.3 https://github.com/OSGeo/gdal/issues/7410
+ if (
+ GdalUtils.version() > 3060300
+ ): # src/dstnodata broken <= 3.6.3 https://github.com/OSGeo/gdal/issues/7410
srcnodata = self.parameterAsDouble(parameters, self.SRCNODATA, context)
- arguments.append('-srcnodata')
+ arguments.append("-srcnodata")
arguments.append(srcnodata)
else:
- raise QgsProcessingException(self.tr('The source nodata option (-srcnodata) is only available on GDAL 3.6.4 or later'))
+ raise QgsProcessingException(
+ self.tr(
+ "The source nodata option (-srcnodata) is only available on GDAL 3.6.4 or later"
+ )
+ )
if self.DSTNODATA in parameters and parameters[self.DSTNODATA] is not None:
- if GdalUtils.version() > 3060300: # src/dstnodata broken <= 3.6.3 https://github.com/OSGeo/gdal/issues/7410
+ if (
+ GdalUtils.version() > 3060300
+ ): # src/dstnodata broken <= 3.6.3 https://github.com/OSGeo/gdal/issues/7410
dstnodata = self.parameterAsDouble(parameters, self.DSTNODATA, context)
- arguments.append('-dstnodata')
+ arguments.append("-dstnodata")
arguments.append(dstnodata)
else:
- raise QgsProcessingException(self.tr('The destination nodata option (-dstnodata) is only available on GDAL 3.6.4 or later'))
+ raise QgsProcessingException(
+ self.tr(
+ "The destination nodata option (-dstnodata) is only available on GDAL 3.6.4 or later"
+ )
+ )
if self.SKIPNODATA in parameters:
if GdalUtils.version() >= 3030000: # skipnodata added at GDAL 3.3
if self.parameterAsBoolean(parameters, self.SKIPNODATA, context):
- arguments.append('-skipnodata')
+ arguments.append("-skipnodata")
else:
- raise QgsProcessingException(self.tr('The skip nodata option (-skipnodata) is only available on GDAL 3.3 or later'))
+ raise QgsProcessingException(
+ self.tr(
+ "The skip nodata option (-skipnodata) is only available on GDAL 3.3 or later"
+ )
+ )
if self.parameterAsBoolean(parameters, self.CSV, context):
- arguments.append('-csv')
+ arguments.append("-csv")
raster = self.parameterAsRasterLayer(parameters, self.INPUT, context)
if raster is None:
- raise QgsProcessingException(self.invalidRasterError(parameters, self.INPUT))
+ raise QgsProcessingException(
+ self.invalidRasterError(parameters, self.INPUT)
+ )
input_details = GdalUtils.gdal_connection_details_from_layer(raster)
@@ -130,4 +167,7 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True):
if input_details.credential_options:
arguments.extend(input_details.credential_options_as_arguments())
- return [self.commandName() + ('.bat' if isWindows() else '.py'), GdalUtils.escapeAndJoin(arguments)]
+ return [
+ self.commandName() + (".bat" if isWindows() else ".py"),
+ GdalUtils.escapeAndJoin(arguments),
+ ]
diff --git a/python/plugins/processing/algs/gdal/gdaladdo.py b/python/plugins/processing/algs/gdal/gdaladdo.py
index 57fedb07229a..1a89afba1e16 100644
--- a/python/plugins/processing/algs/gdal/gdaladdo.py
+++ b/python/plugins/processing/algs/gdal/gdaladdo.py
@@ -15,21 +15,23 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'August 2012'
-__copyright__ = '(C) 2012, Victor Olaya'
+__author__ = "Victor Olaya"
+__date__ = "August 2012"
+__copyright__ = "(C) 2012, Victor Olaya"
import os
from qgis.PyQt.QtGui import QIcon
-from qgis.core import (QgsProcessingException,
- QgsProcessingParameterDefinition,
- QgsProcessingParameterRasterLayer,
- QgsProcessingParameterEnum,
- QgsProcessingParameterString,
- QgsProcessingParameterBoolean,
- QgsProcessingOutputRasterLayer)
+from qgis.core import (
+ QgsProcessingException,
+ QgsProcessingParameterDefinition,
+ QgsProcessingParameterRasterLayer,
+ QgsProcessingParameterEnum,
+ QgsProcessingParameterString,
+ QgsProcessingParameterBoolean,
+ QgsProcessingOutputRasterLayer,
+)
from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm
from processing.algs.gdal.GdalUtils import GdalUtils
@@ -37,114 +39,151 @@
class gdaladdo(GdalAlgorithm):
- INPUT = 'INPUT'
- LEVELS = 'LEVELS'
- CLEAN = 'CLEAN'
- RESAMPLING = 'RESAMPLING'
- FORMAT = 'FORMAT'
- EXTRA = 'EXTRA'
- OUTPUT = 'OUTPUT'
+ INPUT = "INPUT"
+ LEVELS = "LEVELS"
+ CLEAN = "CLEAN"
+ RESAMPLING = "RESAMPLING"
+ FORMAT = "FORMAT"
+ EXTRA = "EXTRA"
+ OUTPUT = "OUTPUT"
def __init__(self):
super().__init__()
def initAlgorithm(self, config=None):
- self.methods = ((self.tr('Nearest Neighbour (default)'), 'nearest'),
- (self.tr('Average'), 'average'),
- (self.tr('Gaussian'), 'gauss'),
- (self.tr('Cubic (4x4 Kernel)'), 'cubic'),
- (self.tr('Cubic B-Spline (4x4 Kernel)'), 'cubicspline'),
- (self.tr('Lanczos (6x6 Kernel)'), 'lanczos'),
- (self.tr('Average MP'), 'average_mp'),
- (self.tr('Average in Mag/Phase Space'), 'average_magphase'),
- (self.tr('Mode'), 'mode'))
-
- self.formats = (self.tr('Internal (if possible)'),
- self.tr('External (GTiff .ovr)'),
- self.tr('External (ERDAS Imagine .aux)'))
-
- self.addParameter(QgsProcessingParameterRasterLayer(self.INPUT,
- self.tr('Input layer')))
- self.addParameter(QgsProcessingParameterBoolean(self.CLEAN,
- self.tr('Remove all existing overviews'),
- defaultValue=False))
+ self.methods = (
+ (self.tr("Nearest Neighbour (default)"), "nearest"),
+ (self.tr("Average"), "average"),
+ (self.tr("Gaussian"), "gauss"),
+ (self.tr("Cubic (4x4 Kernel)"), "cubic"),
+ (self.tr("Cubic B-Spline (4x4 Kernel)"), "cubicspline"),
+ (self.tr("Lanczos (6x6 Kernel)"), "lanczos"),
+ (self.tr("Average MP"), "average_mp"),
+ (self.tr("Average in Mag/Phase Space"), "average_magphase"),
+ (self.tr("Mode"), "mode"),
+ )
+
+ self.formats = (
+ self.tr("Internal (if possible)"),
+ self.tr("External (GTiff .ovr)"),
+ self.tr("External (ERDAS Imagine .aux)"),
+ )
+
+ self.addParameter(
+ QgsProcessingParameterRasterLayer(self.INPUT, self.tr("Input layer"))
+ )
+ self.addParameter(
+ QgsProcessingParameterBoolean(
+ self.CLEAN, self.tr("Remove all existing overviews"), defaultValue=False
+ )
+ )
if GdalUtils.version() < 230000:
- self.addParameter(QgsProcessingParameterString(self.LEVELS,
- self.tr('Overview levels'),
- defaultValue='2 4 8 16'))
+ self.addParameter(
+ QgsProcessingParameterString(
+ self.LEVELS, self.tr("Overview levels"), defaultValue="2 4 8 16"
+ )
+ )
params = []
if GdalUtils.version() >= 230000:
- params.append(QgsProcessingParameterString(self.LEVELS,
- self.tr('Overview levels (e.g. 2 4 8 16)'),
- defaultValue=None,
- optional=True))
- params.append(QgsProcessingParameterEnum(self.RESAMPLING,
- self.tr('Resampling method'),
- options=[i[0] for i in self.methods],
- allowMultiple=False,
- defaultValue=None,
- optional=True))
- params.append(QgsProcessingParameterEnum(self.FORMAT,
- self.tr('Overviews format'),
- options=self.formats,
- allowMultiple=False,
- defaultValue=0,
- optional=True))
- params.append(QgsProcessingParameterString(self.EXTRA,
- self.tr('Additional command-line parameters'),
- defaultValue=None,
- optional=True))
+ params.append(
+ QgsProcessingParameterString(
+ self.LEVELS,
+ self.tr("Overview levels (e.g. 2 4 8 16)"),
+ defaultValue=None,
+ optional=True,
+ )
+ )
+ params.append(
+ QgsProcessingParameterEnum(
+ self.RESAMPLING,
+ self.tr("Resampling method"),
+ options=[i[0] for i in self.methods],
+ allowMultiple=False,
+ defaultValue=None,
+ optional=True,
+ )
+ )
+ params.append(
+ QgsProcessingParameterEnum(
+ self.FORMAT,
+ self.tr("Overviews format"),
+ options=self.formats,
+ allowMultiple=False,
+ defaultValue=0,
+ optional=True,
+ )
+ )
+ params.append(
+ QgsProcessingParameterString(
+ self.EXTRA,
+ self.tr("Additional command-line parameters"),
+ defaultValue=None,
+ optional=True,
+ )
+ )
for p in params:
p.setFlags(p.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
self.addParameter(p)
- self.addOutput(QgsProcessingOutputRasterLayer(self.OUTPUT, self.tr('Pyramidized')))
+ self.addOutput(
+ QgsProcessingOutputRasterLayer(self.OUTPUT, self.tr("Pyramidized"))
+ )
def name(self):
- return 'overviews'
+ return "overviews"
def displayName(self):
- return self.tr('Build overviews (pyramids)')
+ return self.tr("Build overviews (pyramids)")
def group(self):
- return self.tr('Raster miscellaneous')
+ return self.tr("Raster miscellaneous")
def groupId(self):
- return 'rastermiscellaneous'
+ return "rastermiscellaneous"
def icon(self):
- return QIcon(os.path.join(pluginPath, 'images', 'gdaltools', 'raster-overview.png'))
+ return QIcon(
+ os.path.join(pluginPath, "images", "gdaltools", "raster-overview.png")
+ )
def commandName(self):
- return 'gdaladdo'
+ return "gdaladdo"
def getConsoleCommands(self, parameters, context, feedback, executing=True):
inLayer = self.parameterAsRasterLayer(parameters, self.INPUT, context)
if inLayer is None:
- raise QgsProcessingException(self.invalidRasterError(parameters, self.INPUT))
+ raise QgsProcessingException(
+ self.invalidRasterError(parameters, self.INPUT)
+ )
input_details = GdalUtils.gdal_connection_details_from_layer(inLayer)
arguments = [input_details.connection_string]
if self.RESAMPLING in parameters and parameters[self.RESAMPLING] is not None:
- arguments.append('-r')
- arguments.append(self.methods[self.parameterAsEnum(parameters, self.RESAMPLING, context)][1])
+ arguments.append("-r")
+ arguments.append(
+ self.methods[
+ self.parameterAsEnum(parameters, self.RESAMPLING, context)
+ ][1]
+ )
ovrFormat = self.parameterAsEnum(parameters, self.FORMAT, context)
if ovrFormat == 1:
- arguments.append('-ro')
+ arguments.append("-ro")
elif ovrFormat == 2:
- arguments.extend('--config USE_RRD YES'.split(' '))
+ arguments.extend("--config USE_RRD YES".split(" "))
if self.parameterAsBoolean(parameters, self.CLEAN, context):
- arguments.append('-clean')
+ arguments.append("-clean")
- if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ''):
+ if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ""):
extra = self.parameterAsString(parameters, self.EXTRA, context)
arguments.append(extra)
- arguments.extend(self.parameterAsString(parameters, self.LEVELS, context).split(' '))
+ arguments.extend(
+ self.parameterAsString(parameters, self.LEVELS, context).split(" ")
+ )
if input_details.credential_options:
arguments.extend(input_details.credential_options_as_arguments())
diff --git a/python/plugins/processing/algs/gdal/gdalcalc.py b/python/plugins/processing/algs/gdal/gdalcalc.py
index 4380cc41751f..c8c1cf2b8851 100644
--- a/python/plugins/processing/algs/gdal/gdalcalc.py
+++ b/python/plugins/processing/algs/gdal/gdalcalc.py
@@ -15,19 +15,21 @@
***************************************************************************
"""
-__author__ = 'Giovanni Manghi'
-__date__ = 'January 2015'
-__copyright__ = '(C) 2015, Giovanni Manghi'
-
-from qgis.core import (QgsProcessingException,
- QgsProcessingParameterDefinition,
- QgsProcessingParameterRasterLayer,
- QgsProcessingParameterBand,
- QgsProcessingParameterNumber,
- QgsProcessingParameterEnum,
- QgsProcessingParameterExtent,
- QgsProcessingParameterString,
- QgsProcessingParameterRasterDestination)
+__author__ = "Giovanni Manghi"
+__date__ = "January 2015"
+__copyright__ = "(C) 2015, Giovanni Manghi"
+
+from qgis.core import (
+ QgsProcessingException,
+ QgsProcessingParameterDefinition,
+ QgsProcessingParameterRasterLayer,
+ QgsProcessingParameterBand,
+ QgsProcessingParameterNumber,
+ QgsProcessingParameterEnum,
+ QgsProcessingParameterExtent,
+ QgsProcessingParameterString,
+ QgsProcessingParameterRasterDestination,
+)
from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm
from processing.algs.gdal.GdalUtils import GdalUtils
@@ -35,31 +37,44 @@
class gdalcalc(GdalAlgorithm):
- INPUT_A = 'INPUT_A'
- INPUT_B = 'INPUT_B'
- INPUT_C = 'INPUT_C'
- INPUT_D = 'INPUT_D'
- INPUT_E = 'INPUT_E'
- INPUT_F = 'INPUT_F'
- BAND_A = 'BAND_A'
- BAND_B = 'BAND_B'
- BAND_C = 'BAND_C'
- BAND_D = 'BAND_D'
- BAND_E = 'BAND_E'
- BAND_F = 'BAND_F'
- FORMULA = 'FORMULA'
+ INPUT_A = "INPUT_A"
+ INPUT_B = "INPUT_B"
+ INPUT_C = "INPUT_C"
+ INPUT_D = "INPUT_D"
+ INPUT_E = "INPUT_E"
+ INPUT_F = "INPUT_F"
+ BAND_A = "BAND_A"
+ BAND_B = "BAND_B"
+ BAND_C = "BAND_C"
+ BAND_D = "BAND_D"
+ BAND_E = "BAND_E"
+ BAND_F = "BAND_F"
+ FORMULA = "FORMULA"
# TODO QGIS 4.0 : Rename EXTENT_OPT to EXTENT
- EXTENT_OPT = 'EXTENT_OPT'
- EXTENT_OPTIONS = ['ignore', 'fail', 'union', 'intersect']
+ EXTENT_OPT = "EXTENT_OPT"
+ EXTENT_OPTIONS = ["ignore", "fail", "union", "intersect"]
# TODO QGIS 4.0 : Rename EXTENT to PROJWIN or CUSTOM_EXTENT
- EXTENT = 'PROJWIN'
- OUTPUT = 'OUTPUT'
- NO_DATA = 'NO_DATA'
- OPTIONS = 'OPTIONS'
- EXTRA = 'EXTRA'
- RTYPE = 'RTYPE'
-
- TYPE = ['Byte', 'Int16', 'UInt16', 'UInt32', 'Int32', 'Float32', 'Float64', 'CInt16', 'CInt32', 'CFloat32', 'CFloat64', 'Int8']
+ EXTENT = "PROJWIN"
+ OUTPUT = "OUTPUT"
+ NO_DATA = "NO_DATA"
+ OPTIONS = "OPTIONS"
+ EXTRA = "EXTRA"
+ RTYPE = "RTYPE"
+
+ TYPE = [
+ "Byte",
+ "Int16",
+ "UInt16",
+ "UInt32",
+ "Int32",
+ "Float32",
+ "Float64",
+ "CInt16",
+ "CInt32",
+ "CFloat32",
+ "CFloat64",
+ "Int8",
+ ]
def __init__(self):
super().__init__()
@@ -67,140 +82,172 @@ def __init__(self):
def initAlgorithm(self, config=None):
self.addParameter(
QgsProcessingParameterRasterLayer(
- self.INPUT_A,
- self.tr('Input layer A'),
- optional=False))
+ self.INPUT_A, self.tr("Input layer A"), optional=False
+ )
+ )
self.addParameter(
QgsProcessingParameterBand(
self.BAND_A,
- self.tr('Number of raster band for A'),
- parentLayerParameterName=self.INPUT_A))
+ self.tr("Number of raster band for A"),
+ parentLayerParameterName=self.INPUT_A,
+ )
+ )
self.addParameter(
QgsProcessingParameterRasterLayer(
- self.INPUT_B,
- self.tr('Input layer B'),
- optional=True))
+ self.INPUT_B, self.tr("Input layer B"), optional=True
+ )
+ )
self.addParameter(
QgsProcessingParameterBand(
self.BAND_B,
- self.tr('Number of raster band for B'),
+ self.tr("Number of raster band for B"),
parentLayerParameterName=self.INPUT_B,
- optional=True))
+ optional=True,
+ )
+ )
self.addParameter(
QgsProcessingParameterRasterLayer(
- self.INPUT_C,
- self.tr('Input layer C'),
- optional=True))
+ self.INPUT_C, self.tr("Input layer C"), optional=True
+ )
+ )
self.addParameter(
QgsProcessingParameterBand(
self.BAND_C,
- self.tr('Number of raster band for C'),
+ self.tr("Number of raster band for C"),
parentLayerParameterName=self.INPUT_C,
- optional=True))
+ optional=True,
+ )
+ )
self.addParameter(
QgsProcessingParameterRasterLayer(
- self.INPUT_D,
- self.tr('Input layer D'),
- optional=True))
+ self.INPUT_D, self.tr("Input layer D"), optional=True
+ )
+ )
self.addParameter(
QgsProcessingParameterBand(
self.BAND_D,
- self.tr('Number of raster band for D'),
+ self.tr("Number of raster band for D"),
parentLayerParameterName=self.INPUT_D,
- optional=True))
+ optional=True,
+ )
+ )
self.addParameter(
QgsProcessingParameterRasterLayer(
- self.INPUT_E,
- self.tr('Input layer E'),
- optional=True))
+ self.INPUT_E, self.tr("Input layer E"), optional=True
+ )
+ )
self.addParameter(
QgsProcessingParameterBand(
self.BAND_E,
- self.tr('Number of raster band for E'),
+ self.tr("Number of raster band for E"),
parentLayerParameterName=self.INPUT_E,
- optional=True))
+ optional=True,
+ )
+ )
self.addParameter(
QgsProcessingParameterRasterLayer(
- self.INPUT_F,
- self.tr('Input layer F'),
- optional=True))
+ self.INPUT_F, self.tr("Input layer F"), optional=True
+ )
+ )
self.addParameter(
QgsProcessingParameterBand(
self.BAND_F,
- self.tr('Number of raster band for F'),
+ self.tr("Number of raster band for F"),
parentLayerParameterName=self.INPUT_F,
- optional=True))
+ optional=True,
+ )
+ )
self.addParameter(
QgsProcessingParameterString(
self.FORMULA,
- self.tr('Calculation in gdalnumeric syntax using +-/* or any numpy array functions (i.e. logical_and())'),
- 'A*2',
- optional=False))
+ self.tr(
+ "Calculation in gdalnumeric syntax using +-/* or any numpy array functions (i.e. logical_and())"
+ ),
+ "A*2",
+ optional=False,
+ )
+ )
self.addParameter(
QgsProcessingParameterNumber(
self.NO_DATA,
- self.tr('Set output NoData value'),
+ self.tr("Set output NoData value"),
type=QgsProcessingParameterNumber.Type.Double,
defaultValue=None,
- optional=True))
+ optional=True,
+ )
+ )
if GdalUtils.version() >= 3030000:
extent_opt_param = QgsProcessingParameterEnum(
self.EXTENT_OPT,
- self.tr('Handling of extent differences'),
+ self.tr("Handling of extent differences"),
options=[o.title() for o in self.EXTENT_OPTIONS],
- defaultValue=0)
- extent_opt_param.setHelp(self.tr('This option determines how to handle rasters with different extents'))
+ defaultValue=0,
+ )
+ extent_opt_param.setHelp(
+ self.tr(
+ "This option determines how to handle rasters with different extents"
+ )
+ )
self.addParameter(extent_opt_param)
if GdalUtils.version() >= 3030000:
- extent_param = QgsProcessingParameterExtent(self.EXTENT,
- self.tr('Output extent'),
- optional=True)
- extent_param.setHelp(self.tr('Custom extent of the output raster'))
+ extent_param = QgsProcessingParameterExtent(
+ self.EXTENT, self.tr("Output extent"), optional=True
+ )
+ extent_param.setHelp(self.tr("Custom extent of the output raster"))
self.addParameter(extent_param)
self.addParameter(
QgsProcessingParameterEnum(
self.RTYPE,
- self.tr('Output raster type'),
+ self.tr("Output raster type"),
options=self.TYPE,
- defaultValue=5))
-
- options_param = QgsProcessingParameterString(self.OPTIONS,
- self.tr('Additional creation options'),
- defaultValue='',
- optional=True)
- options_param.setFlags(options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
- options_param.setMetadata({'widget_wrapper': {'widget_type': 'rasteroptions'}})
+ defaultValue=5,
+ )
+ )
+
+ options_param = QgsProcessingParameterString(
+ self.OPTIONS,
+ self.tr("Additional creation options"),
+ defaultValue="",
+ optional=True,
+ )
+ options_param.setFlags(
+ options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
+ options_param.setMetadata({"widget_wrapper": {"widget_type": "rasteroptions"}})
self.addParameter(options_param)
- extra_param = QgsProcessingParameterString(self.EXTRA,
- self.tr('Additional command-line parameters'),
- defaultValue=None,
- optional=True)
- extra_param.setFlags(extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
+ extra_param = QgsProcessingParameterString(
+ self.EXTRA,
+ self.tr("Additional command-line parameters"),
+ defaultValue=None,
+ optional=True,
+ )
+ extra_param.setFlags(
+ extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
self.addParameter(extra_param)
self.addParameter(
- QgsProcessingParameterRasterDestination(
- self.OUTPUT,
- self.tr('Calculated')))
+ QgsProcessingParameterRasterDestination(self.OUTPUT, self.tr("Calculated"))
+ )
def name(self):
- return 'rastercalculator'
+ return "rastercalculator"
def displayName(self):
- return self.tr('Raster calculator')
+ return self.tr("Raster calculator")
def group(self):
- return self.tr('Raster miscellaneous')
+ return self.tr("Raster miscellaneous")
def groupId(self):
- return 'rastermiscellaneous'
+ return "rastermiscellaneous"
def commandName(self):
- return 'gdal_calc'
+ return "gdal_calc"
def getConsoleCommands(self, parameters, context, feedback, executing=True):
@@ -213,26 +260,37 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True):
noData = None
arguments = [
- '--overwrite',
+ "--overwrite",
f'--calc "{formula}"',
- '--format',
+ "--format",
GdalUtils.getFormatShortNameFromFilename(out),
]
rtype = self.parameterAsEnum(parameters, self.RTYPE, context)
- if self.TYPE[rtype] in ['CInt16', 'CInt32', 'CFloat32', 'CFloat64'] and GdalUtils.version() < 3050300:
- raise QgsProcessingException(self.tr('{} data type requires GDAL version 3.5.3 or later').format(self.TYPE[rtype]))
- if self.TYPE[rtype] == 'Int8' and GdalUtils.version() < 3070000:
- raise QgsProcessingException(self.tr('Int8 data type requires GDAL version 3.7 or later'))
-
- arguments.append('--type ' + self.TYPE[rtype])
+ if (
+ self.TYPE[rtype] in ["CInt16", "CInt32", "CFloat32", "CFloat64"]
+ and GdalUtils.version() < 3050300
+ ):
+ raise QgsProcessingException(
+ self.tr("{} data type requires GDAL version 3.5.3 or later").format(
+ self.TYPE[rtype]
+ )
+ )
+ if self.TYPE[rtype] == "Int8" and GdalUtils.version() < 3070000:
+ raise QgsProcessingException(
+ self.tr("Int8 data type requires GDAL version 3.7 or later")
+ )
+
+ arguments.append("--type " + self.TYPE[rtype])
if noData is not None:
- arguments.append('--NoDataValue')
+ arguments.append("--NoDataValue")
arguments.append(noData)
layer_a = self.parameterAsRasterLayer(parameters, self.INPUT_A, context)
if layer_a is None:
- raise QgsProcessingException(self.invalidRasterError(parameters, self.INPUT_A))
+ raise QgsProcessingException(
+ self.invalidRasterError(parameters, self.INPUT_A)
+ )
layer_a_details = GdalUtils.gdal_connection_details_from_layer(layer_a)
def all_equal(iterator):
@@ -245,107 +303,165 @@ def all_equal(iterator):
# Check GDAL version for projwin and extent options (GDAL 3.3 is required)
if GdalUtils.version() < 3030000 and self.EXTENT in parameters.keys():
- raise QgsProcessingException(self.tr('The custom output extent option (--projwin) is only available on GDAL 3.3 or later'))
+ raise QgsProcessingException(
+ self.tr(
+ "The custom output extent option (--projwin) is only available on GDAL 3.3 or later"
+ )
+ )
if GdalUtils.version() < 3030000 and self.EXTENT_OPT in parameters.keys():
- raise QgsProcessingException(self.tr('The output extent option (--extent) is only available on GDAL 3.3 or later'))
+ raise QgsProcessingException(
+ self.tr(
+ "The output extent option (--extent) is only available on GDAL 3.3 or later"
+ )
+ )
# --projwin and --extent option are mutually exclusive
- if (self.EXTENT in parameters.keys() and parameters[self.EXTENT] is not None) and (self.EXTENT_OPT in parameters.keys() and parameters[self.EXTENT_OPT] != 0):
- raise QgsProcessingException(self.tr('The custom output extent option (--projwin) and output extent option (--extent) are mutually exclusive'))
+ if (
+ self.EXTENT in parameters.keys() and parameters[self.EXTENT] is not None
+ ) and (
+ self.EXTENT_OPT in parameters.keys() and parameters[self.EXTENT_OPT] != 0
+ ):
+ raise QgsProcessingException(
+ self.tr(
+ "The custom output extent option (--projwin) and output extent option (--extent) are mutually exclusive"
+ )
+ )
# If extent option is defined, pixel size and SRS of all input raster must be the same
if self.EXTENT_OPT in parameters.keys() and parameters[self.EXTENT_OPT] != 0:
pixel_size_X, pixel_size_Y, srs = [], [], []
- for input_layer in [self.INPUT_A, self.INPUT_B, self.INPUT_C, self.INPUT_D, self.INPUT_E, self.INPUT_F]:
+ for input_layer in [
+ self.INPUT_A,
+ self.INPUT_B,
+ self.INPUT_C,
+ self.INPUT_D,
+ self.INPUT_E,
+ self.INPUT_F,
+ ]:
if input_layer in parameters and parameters[input_layer] is not None:
- layer = self.parameterAsRasterLayer(parameters, input_layer, context)
+ layer = self.parameterAsRasterLayer(
+ parameters, input_layer, context
+ )
pixel_size_X.append(layer.rasterUnitsPerPixelX())
pixel_size_Y.append(layer.rasterUnitsPerPixelY())
srs.append(layer.crs().authid())
- if not (all_equal(pixel_size_X) and all_equal(pixel_size_Y) and all_equal(srs)):
- raise QgsProcessingException(self.tr('For all output extent options, the pixel size (resolution) and SRS (Spatial Reference System) of all the input rasters must be the same'))
-
- extent = self.EXTENT_OPTIONS[self.parameterAsEnum(parameters, self.EXTENT_OPT, context)]
- if extent != 'ignore':
- arguments.append(f'--extent={extent}')
+ if not (
+ all_equal(pixel_size_X) and all_equal(pixel_size_Y) and all_equal(srs)
+ ):
+ raise QgsProcessingException(
+ self.tr(
+ "For all output extent options, the pixel size (resolution) and SRS (Spatial Reference System) of all the input rasters must be the same"
+ )
+ )
+
+ extent = self.EXTENT_OPTIONS[
+ self.parameterAsEnum(parameters, self.EXTENT_OPT, context)
+ ]
+ if extent != "ignore":
+ arguments.append(f"--extent={extent}")
bbox = self.parameterAsExtent(parameters, self.EXTENT, context, layer_a.crs())
if not bbox.isNull():
- arguments.append('--projwin')
+ arguments.append("--projwin")
arguments.append(str(bbox.xMinimum()))
arguments.append(str(bbox.yMaximum()))
arguments.append(str(bbox.xMaximum()))
arguments.append(str(bbox.yMinimum()))
- arguments.append('-A')
+ arguments.append("-A")
arguments.append(layer_a_details.connection_string)
if self.parameterAsString(parameters, self.BAND_A, context):
- arguments.append('--A_band ' + self.parameterAsString(parameters, self.BAND_A, context))
+ arguments.append(
+ "--A_band " + self.parameterAsString(parameters, self.BAND_A, context)
+ )
if self.INPUT_B in parameters and parameters[self.INPUT_B] is not None:
layer_b = self.parameterAsRasterLayer(parameters, self.INPUT_B, context)
if layer_b is None:
- raise QgsProcessingException(self.invalidRasterError(parameters, self.INPUT_B))
- input_b_details = GdalUtils.gdal_connection_details_from_layer(
- layer_b)
- arguments.append('-B')
+ raise QgsProcessingException(
+ self.invalidRasterError(parameters, self.INPUT_B)
+ )
+ input_b_details = GdalUtils.gdal_connection_details_from_layer(layer_b)
+ arguments.append("-B")
arguments.append(input_b_details.connection_string)
if self.parameterAsString(parameters, self.BAND_B, context):
- arguments.append('--B_band ' + self.parameterAsString(parameters, self.BAND_B, context))
+ arguments.append(
+ "--B_band "
+ + self.parameterAsString(parameters, self.BAND_B, context)
+ )
if self.INPUT_C in parameters and parameters[self.INPUT_C] is not None:
layer_c = self.parameterAsRasterLayer(parameters, self.INPUT_C, context)
if layer_c is None:
- raise QgsProcessingException(self.invalidRasterError(parameters, self.INPUT_C))
- input_c_details = GdalUtils.gdal_connection_details_from_layer(
- layer_c)
- arguments.append('-C')
+ raise QgsProcessingException(
+ self.invalidRasterError(parameters, self.INPUT_C)
+ )
+ input_c_details = GdalUtils.gdal_connection_details_from_layer(layer_c)
+ arguments.append("-C")
arguments.append(input_c_details.connection_string)
if self.parameterAsString(parameters, self.BAND_C, context):
- arguments.append('--C_band ' + self.parameterAsString(parameters, self.BAND_C, context))
+ arguments.append(
+ "--C_band "
+ + self.parameterAsString(parameters, self.BAND_C, context)
+ )
if self.INPUT_D in parameters and parameters[self.INPUT_D] is not None:
layer_d = self.parameterAsRasterLayer(parameters, self.INPUT_D, context)
if layer_d is None:
- raise QgsProcessingException(self.invalidRasterError(parameters, self.INPUT_D))
- input_d_details = GdalUtils.gdal_connection_details_from_layer(
- layer_d)
- arguments.append('-D')
+ raise QgsProcessingException(
+ self.invalidRasterError(parameters, self.INPUT_D)
+ )
+ input_d_details = GdalUtils.gdal_connection_details_from_layer(layer_d)
+ arguments.append("-D")
arguments.append(input_d_details.connection_string)
if self.parameterAsString(parameters, self.BAND_D, context):
- arguments.append('--D_band ' + self.parameterAsString(parameters, self.BAND_D, context))
+ arguments.append(
+ "--D_band "
+ + self.parameterAsString(parameters, self.BAND_D, context)
+ )
if self.INPUT_E in parameters and parameters[self.INPUT_E] is not None:
layer_e = self.parameterAsRasterLayer(parameters, self.INPUT_E, context)
if layer_e is None:
- raise QgsProcessingException(self.invalidRasterError(parameters, self.INPUT_E))
- input_e_details = GdalUtils.gdal_connection_details_from_layer(
- layer_e)
- arguments.append('-E')
+ raise QgsProcessingException(
+ self.invalidRasterError(parameters, self.INPUT_E)
+ )
+ input_e_details = GdalUtils.gdal_connection_details_from_layer(layer_e)
+ arguments.append("-E")
arguments.append(input_e_details.connection_string)
if self.parameterAsString(parameters, self.BAND_E, context):
- arguments.append('--E_band ' + self.parameterAsString(parameters, self.BAND_E, context))
+ arguments.append(
+ "--E_band "
+ + self.parameterAsString(parameters, self.BAND_E, context)
+ )
if self.INPUT_F in parameters and parameters[self.INPUT_F] is not None:
layer_f = self.parameterAsRasterLayer(parameters, self.INPUT_F, context)
if layer_f is None:
- raise QgsProcessingException(self.invalidRasterError(parameters, self.INPUT_F))
- input_f_details = GdalUtils.gdal_connection_details_from_layer(
- layer_f)
- arguments.append('-F')
+ raise QgsProcessingException(
+ self.invalidRasterError(parameters, self.INPUT_F)
+ )
+ input_f_details = GdalUtils.gdal_connection_details_from_layer(layer_f)
+ arguments.append("-F")
arguments.append(input_f_details.connection_string)
if self.parameterAsString(parameters, self.BAND_F, context):
- arguments.append('--F_band ' + self.parameterAsString(parameters, self.BAND_F, context))
+ arguments.append(
+ "--F_band "
+ + self.parameterAsString(parameters, self.BAND_F, context)
+ )
options = self.parameterAsString(parameters, self.OPTIONS, context)
if options:
- parts = options.split('|')
+ parts = options.split("|")
for p in parts:
- arguments.append('--co ' + p)
+ arguments.append("--co " + p)
- if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ''):
+ if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ""):
extra = self.parameterAsString(parameters, self.EXTRA, context)
arguments.append(extra)
- arguments.append('--outfile')
+ arguments.append("--outfile")
arguments.append(out)
- return [self.commandName() + ('.bat' if isWindows() else '.py'), GdalUtils.escapeAndJoin(arguments)]
+ return [
+ self.commandName() + (".bat" if isWindows() else ".py"),
+ GdalUtils.escapeAndJoin(arguments),
+ ]
diff --git a/python/plugins/processing/algs/gdal/gdalinfo.py b/python/plugins/processing/algs/gdal/gdalinfo.py
index a3cd207bcf2c..3a99f6d67f3e 100644
--- a/python/plugins/processing/algs/gdal/gdalinfo.py
+++ b/python/plugins/processing/algs/gdal/gdalinfo.py
@@ -15,19 +15,21 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'August 2012'
-__copyright__ = '(C) 2012, Victor Olaya'
+__author__ = "Victor Olaya"
+__date__ = "August 2012"
+__copyright__ = "(C) 2012, Victor Olaya"
import os
from qgis.PyQt.QtGui import QIcon
-from qgis.core import (QgsProcessingException,
- QgsProcessingParameterDefinition,
- QgsProcessingParameterString,
- QgsProcessingParameterRasterLayer,
- QgsProcessingParameterBoolean,
- QgsProcessingParameterFileDestination)
+from qgis.core import (
+ QgsProcessingException,
+ QgsProcessingParameterDefinition,
+ QgsProcessingParameterString,
+ QgsProcessingParameterRasterLayer,
+ QgsProcessingParameterBoolean,
+ QgsProcessingParameterFileDestination,
+)
from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm
from processing.algs.gdal.GdalUtils import GdalUtils
@@ -35,80 +37,105 @@
class gdalinfo(GdalAlgorithm):
- INPUT = 'INPUT'
- MIN_MAX = 'MIN_MAX'
- STATS = 'STATS'
- NO_GCP = 'NOGCP'
- NO_METADATA = 'NO_METADATA'
- EXTRA = 'EXTRA'
- OUTPUT = 'OUTPUT'
+ INPUT = "INPUT"
+ MIN_MAX = "MIN_MAX"
+ STATS = "STATS"
+ NO_GCP = "NOGCP"
+ NO_METADATA = "NO_METADATA"
+ EXTRA = "EXTRA"
+ OUTPUT = "OUTPUT"
def __init__(self):
super().__init__()
def initAlgorithm(self, config=None):
- self.addParameter(QgsProcessingParameterRasterLayer(self.INPUT,
- self.tr('Input layer')))
- self.addParameter(QgsProcessingParameterBoolean(self.MIN_MAX,
- self.tr('Force computation of the actual min/max values for each band'),
- defaultValue=False))
- self.addParameter(QgsProcessingParameterBoolean(self.STATS,
- self.tr('Read and display image statistics (force computation if necessary)'),
- defaultValue=False))
- self.addParameter(QgsProcessingParameterBoolean(self.NO_GCP,
- self.tr('Suppress GCP info'),
- defaultValue=False))
- self.addParameter(QgsProcessingParameterBoolean(self.NO_METADATA,
- self.tr('Suppress metadata info'),
- defaultValue=False))
-
- extra_param = QgsProcessingParameterString(self.EXTRA,
- self.tr('Additional command-line parameters'),
- defaultValue=None,
- optional=True)
- extra_param.setFlags(extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
+ self.addParameter(
+ QgsProcessingParameterRasterLayer(self.INPUT, self.tr("Input layer"))
+ )
+ self.addParameter(
+ QgsProcessingParameterBoolean(
+ self.MIN_MAX,
+ self.tr("Force computation of the actual min/max values for each band"),
+ defaultValue=False,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterBoolean(
+ self.STATS,
+ self.tr(
+ "Read and display image statistics (force computation if necessary)"
+ ),
+ defaultValue=False,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterBoolean(
+ self.NO_GCP, self.tr("Suppress GCP info"), defaultValue=False
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterBoolean(
+ self.NO_METADATA, self.tr("Suppress metadata info"), defaultValue=False
+ )
+ )
+
+ extra_param = QgsProcessingParameterString(
+ self.EXTRA,
+ self.tr("Additional command-line parameters"),
+ defaultValue=None,
+ optional=True,
+ )
+ extra_param.setFlags(
+ extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
self.addParameter(extra_param)
- self.addParameter(QgsProcessingParameterFileDestination(self.OUTPUT,
- self.tr('Layer information'),
- self.tr('HTML files (*.html)')))
+ self.addParameter(
+ QgsProcessingParameterFileDestination(
+ self.OUTPUT,
+ self.tr("Layer information"),
+ self.tr("HTML files (*.html)"),
+ )
+ )
def name(self):
- return 'gdalinfo'
+ return "gdalinfo"
def displayName(self):
- return self.tr('Raster information')
+ return self.tr("Raster information")
def group(self):
- return self.tr('Raster miscellaneous')
+ return self.tr("Raster miscellaneous")
def groupId(self):
- return 'rastermiscellaneous'
+ return "rastermiscellaneous"
def icon(self):
- return QIcon(os.path.join(pluginPath, 'images', 'gdaltools', 'raster-info.png'))
+ return QIcon(os.path.join(pluginPath, "images", "gdaltools", "raster-info.png"))
def commandName(self):
- return 'gdalinfo'
+ return "gdalinfo"
def getConsoleCommands(self, parameters, context, feedback, executing=True):
arguments = []
if self.parameterAsBoolean(parameters, self.MIN_MAX, context):
- arguments.append('-mm')
+ arguments.append("-mm")
if self.parameterAsBoolean(parameters, self.STATS, context):
- arguments.append('-stats')
+ arguments.append("-stats")
if self.parameterAsBoolean(parameters, self.NO_GCP, context):
- arguments.append('-nogcp')
+ arguments.append("-nogcp")
if self.parameterAsBoolean(parameters, self.NO_METADATA, context):
- arguments.append('-nomd')
+ arguments.append("-nomd")
- if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ''):
+ if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ""):
extra = self.parameterAsString(parameters, self.EXTRA, context)
arguments.append(extra)
raster = self.parameterAsRasterLayer(parameters, self.INPUT, context)
if raster is None:
- raise QgsProcessingException(self.invalidRasterError(parameters, self.INPUT))
+ raise QgsProcessingException(
+ self.invalidRasterError(parameters, self.INPUT)
+ )
input_details = GdalUtils.gdal_connection_details_from_layer(raster)
arguments.append(input_details.connection_string)
@@ -121,12 +148,14 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True):
return [self.commandName(), GdalUtils.escapeAndJoin(arguments)]
def processAlgorithm(self, parameters, context, feedback):
- console_output = GdalUtils.runGdal(self.getConsoleCommands(parameters, context, feedback), feedback)
+ console_output = GdalUtils.runGdal(
+ self.getConsoleCommands(parameters, context, feedback), feedback
+ )
output = self.parameterAsFileOutput(parameters, self.OUTPUT, context)
- with open(output, 'w') as f:
- f.write('')
+ with open(output, "w") as f:
+ f.write("")
for s in console_output[1:]:
f.write(str(s))
- f.write(' ')
+ f.write(" ")
return {self.OUTPUT: output}
diff --git a/python/plugins/processing/algs/gdal/gdaltindex.py b/python/plugins/processing/algs/gdal/gdaltindex.py
index 4d6aa530f915..5fd3ff34143a 100644
--- a/python/plugins/processing/algs/gdal/gdaltindex.py
+++ b/python/plugins/processing/algs/gdal/gdaltindex.py
@@ -15,25 +15,27 @@
***************************************************************************
"""
-__author__ = 'Pedro Venancio'
-__date__ = 'February 2015'
-__copyright__ = '(C) 2015, Pedro Venancio'
+__author__ = "Pedro Venancio"
+__date__ = "February 2015"
+__copyright__ = "(C) 2015, Pedro Venancio"
import os
from qgis.PyQt.QtGui import QIcon
-from qgis.core import (QgsMapLayer,
- QgsProcessing,
- QgsProcessingAlgorithm,
- QgsProcessingException,
- QgsProcessingParameterCrs,
- QgsProcessingParameterEnum,
- QgsProcessingParameterString,
- QgsProcessingParameterBoolean,
- QgsProcessingParameterDefinition,
- QgsProcessingParameterMultipleLayers,
- QgsProcessingParameterVectorDestination)
+from qgis.core import (
+ QgsMapLayer,
+ QgsProcessing,
+ QgsProcessingAlgorithm,
+ QgsProcessingException,
+ QgsProcessingParameterCrs,
+ QgsProcessingParameterEnum,
+ QgsProcessingParameterString,
+ QgsProcessingParameterBoolean,
+ QgsProcessingParameterDefinition,
+ QgsProcessingParameterMultipleLayers,
+ QgsProcessingParameterVectorDestination,
+)
from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm
from processing.algs.gdal.GdalUtils import GdalUtils
@@ -41,78 +43,112 @@
class gdaltindex(GdalAlgorithm):
- LAYERS = 'LAYERS'
- PATH_FIELD_NAME = 'PATH_FIELD_NAME'
- ABSOLUTE_PATH = 'ABSOLUTE_PATH'
- PROJ_DIFFERENCE = 'PROJ_DIFFERENCE'
- TARGET_CRS = 'TARGET_CRS'
- CRS_FIELD_NAME = 'CRS_FIELD_NAME'
- CRS_FORMAT = 'CRS_FORMAT'
- OUTPUT = 'OUTPUT'
+ LAYERS = "LAYERS"
+ PATH_FIELD_NAME = "PATH_FIELD_NAME"
+ ABSOLUTE_PATH = "ABSOLUTE_PATH"
+ PROJ_DIFFERENCE = "PROJ_DIFFERENCE"
+ TARGET_CRS = "TARGET_CRS"
+ CRS_FIELD_NAME = "CRS_FIELD_NAME"
+ CRS_FORMAT = "CRS_FORMAT"
+ OUTPUT = "OUTPUT"
def __init__(self):
super().__init__()
def initAlgorithm(self, config=None):
- self.formats = ((self.tr('Auto'), 'AUTO'),
- (self.tr('Well-known text (WKT)'), 'WKT'),
- (self.tr('EPSG'), 'EPSG'),
- (self.tr('Proj.4'), 'PROJ'))
-
- self.addParameter(QgsProcessingParameterMultipleLayers(self.LAYERS,
- self.tr('Input files'),
- QgsProcessing.SourceType.TypeRaster))
- self.addParameter(QgsProcessingParameterString(self.PATH_FIELD_NAME,
- self.tr('Field name to hold the file path to the indexed rasters'),
- defaultValue='location'))
- self.addParameter(QgsProcessingParameterBoolean(self.ABSOLUTE_PATH,
- self.tr('Store absolute path to the indexed rasters'),
- defaultValue=False))
- self.addParameter(QgsProcessingParameterBoolean(self.PROJ_DIFFERENCE,
- self.tr('Skip files with different projection reference'),
- defaultValue=False))
-
- target_crs_param = QgsProcessingParameterCrs(self.TARGET_CRS,
- self.tr('Transform geometries to the given CRS'),
- optional=True)
- target_crs_param.setFlags(target_crs_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
+ self.formats = (
+ (self.tr("Auto"), "AUTO"),
+ (self.tr("Well-known text (WKT)"), "WKT"),
+ (self.tr("EPSG"), "EPSG"),
+ (self.tr("Proj.4"), "PROJ"),
+ )
+
+ self.addParameter(
+ QgsProcessingParameterMultipleLayers(
+ self.LAYERS, self.tr("Input files"), QgsProcessing.SourceType.TypeRaster
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterString(
+ self.PATH_FIELD_NAME,
+ self.tr("Field name to hold the file path to the indexed rasters"),
+ defaultValue="location",
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterBoolean(
+ self.ABSOLUTE_PATH,
+ self.tr("Store absolute path to the indexed rasters"),
+ defaultValue=False,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterBoolean(
+ self.PROJ_DIFFERENCE,
+ self.tr("Skip files with different projection reference"),
+ defaultValue=False,
+ )
+ )
+
+ target_crs_param = QgsProcessingParameterCrs(
+ self.TARGET_CRS,
+ self.tr("Transform geometries to the given CRS"),
+ optional=True,
+ )
+ target_crs_param.setFlags(
+ target_crs_param.flags()
+ | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
self.addParameter(target_crs_param)
- crs_field_param = QgsProcessingParameterString(self.CRS_FIELD_NAME,
- self.tr('The name of the field to store the SRS of each tile'),
- optional=True)
- crs_field_param.setFlags(crs_field_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
+ crs_field_param = QgsProcessingParameterString(
+ self.CRS_FIELD_NAME,
+ self.tr("The name of the field to store the SRS of each tile"),
+ optional=True,
+ )
+ crs_field_param.setFlags(
+ crs_field_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
self.addParameter(crs_field_param)
- crs_format_param = QgsProcessingParameterEnum(self.CRS_FORMAT,
- self.tr('The format in which the CRS of each tile must be written'),
- options=[i[0] for i in self.formats],
- allowMultiple=False,
- defaultValue=0)
- crs_format_param.setFlags(crs_format_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
+ crs_format_param = QgsProcessingParameterEnum(
+ self.CRS_FORMAT,
+ self.tr("The format in which the CRS of each tile must be written"),
+ options=[i[0] for i in self.formats],
+ allowMultiple=False,
+ defaultValue=0,
+ )
+ crs_format_param.setFlags(
+ crs_format_param.flags()
+ | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
self.addParameter(crs_format_param)
- self.addParameter(QgsProcessingParameterVectorDestination(self.OUTPUT,
- self.tr('Tile index'),
- QgsProcessing.SourceType.TypeVectorPolygon))
+ self.addParameter(
+ QgsProcessingParameterVectorDestination(
+ self.OUTPUT,
+ self.tr("Tile index"),
+ QgsProcessing.SourceType.TypeVectorPolygon,
+ )
+ )
def name(self):
- return 'tileindex'
+ return "tileindex"
def displayName(self):
- return self.tr('Tile index')
+ return self.tr("Tile index")
def group(self):
- return self.tr('Raster miscellaneous')
+ return self.tr("Raster miscellaneous")
def groupId(self):
- return 'rastermiscellaneous'
+ return "rastermiscellaneous"
def icon(self):
- return QIcon(os.path.join(pluginPath, 'images', 'gdaltools', 'tiles.png'))
+ return QIcon(os.path.join(pluginPath, "images", "gdaltools", "tiles.png"))
def commandName(self):
- return 'gdaltindex'
+ return "gdaltindex"
def getConsoleCommands(self, parameters, context, feedback, executing=True):
crs_field = self.parameterAsString(parameters, self.CRS_FIELD_NAME, context)
@@ -124,35 +160,43 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True):
output_details = GdalUtils.gdal_connection_details_from_uri(outFile, context)
arguments = [
- '-tileindex',
+ "-tileindex",
self.parameterAsString(parameters, self.PATH_FIELD_NAME, context),
]
if self.parameterAsBoolean(parameters, self.ABSOLUTE_PATH, context):
- arguments.append('-write_absolute_path')
+ arguments.append("-write_absolute_path")
if self.parameterAsBoolean(parameters, self.PROJ_DIFFERENCE, context):
- arguments.append('-skip_different_projection')
+ arguments.append("-skip_different_projection")
if crs_field:
- arguments.append(f'-src_srs_name {crs_field}')
+ arguments.append(f"-src_srs_name {crs_field}")
if crs_format:
- arguments.append(f'-src_srs_format {self.formats[crs_format][1]}')
+ arguments.append(f"-src_srs_format {self.formats[crs_format][1]}")
if target_crs.isValid():
- arguments.append('-t_srs')
+ arguments.append("-t_srs")
arguments.append(GdalUtils.gdal_crs_string(target_crs))
if output_details.format:
- arguments.append(f'-f {output_details.format}')
+ arguments.append(f"-f {output_details.format}")
arguments.append(output_details.connection_string)
# Always write input files to a text file in case there are many of them and the
# length of the command will be longer then allowed in command prompt
- list_file = GdalUtils.writeLayerParameterToTextFile(filename='tile_index_files.txt', alg=self, parameters=parameters, parameter_name=self.LAYERS, context=context, quote=True, executing=executing)
- arguments.append('--optfile')
+ list_file = GdalUtils.writeLayerParameterToTextFile(
+ filename="tile_index_files.txt",
+ alg=self,
+ parameters=parameters,
+ parameter_name=self.LAYERS,
+ context=context,
+ quote=True,
+ executing=executing,
+ )
+ arguments.append("--optfile")
arguments.append(list_file)
return [self.commandName(), GdalUtils.escapeAndJoin(arguments)]
diff --git a/python/plugins/processing/algs/gdal/hillshade.py b/python/plugins/processing/algs/gdal/hillshade.py
index 40897d4ca71c..4ab62a0c87a2 100644
--- a/python/plugins/processing/algs/gdal/hillshade.py
+++ b/python/plugins/processing/algs/gdal/hillshade.py
@@ -15,21 +15,23 @@
***************************************************************************
"""
-__author__ = 'Alexander Bruy'
-__date__ = 'October 2013'
-__copyright__ = '(C) 2013, Alexander Bruy'
+__author__ = "Alexander Bruy"
+__date__ = "October 2013"
+__copyright__ = "(C) 2013, Alexander Bruy"
import os
-from qgis.core import (QgsRasterFileWriter,
- QgsProcessingException,
- QgsProcessingParameterDefinition,
- QgsProcessingParameterRasterLayer,
- QgsProcessingParameterBand,
- QgsProcessingParameterBoolean,
- QgsProcessingParameterNumber,
- QgsProcessingParameterString,
- QgsProcessingParameterRasterDestination)
+from qgis.core import (
+ QgsRasterFileWriter,
+ QgsProcessingException,
+ QgsProcessingParameterDefinition,
+ QgsProcessingParameterRasterLayer,
+ QgsProcessingParameterBand,
+ QgsProcessingParameterBoolean,
+ QgsProcessingParameterNumber,
+ QgsProcessingParameterString,
+ QgsProcessingParameterRasterDestination,
+)
from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm
from processing.algs.gdal.GdalUtils import GdalUtils
@@ -37,100 +39,146 @@
class hillshade(GdalAlgorithm):
- INPUT = 'INPUT'
- BAND = 'BAND'
- COMPUTE_EDGES = 'COMPUTE_EDGES'
- ZEVENBERGEN = 'ZEVENBERGEN'
- Z_FACTOR = 'Z_FACTOR'
- SCALE = 'SCALE'
- AZIMUTH = 'AZIMUTH'
- ALTITUDE = 'ALTITUDE'
- COMBINED = 'COMBINED'
- MULTIDIRECTIONAL = 'MULTIDIRECTIONAL'
- OPTIONS = 'OPTIONS'
- EXTRA = 'EXTRA'
- OUTPUT = 'OUTPUT'
+ INPUT = "INPUT"
+ BAND = "BAND"
+ COMPUTE_EDGES = "COMPUTE_EDGES"
+ ZEVENBERGEN = "ZEVENBERGEN"
+ Z_FACTOR = "Z_FACTOR"
+ SCALE = "SCALE"
+ AZIMUTH = "AZIMUTH"
+ ALTITUDE = "ALTITUDE"
+ COMBINED = "COMBINED"
+ MULTIDIRECTIONAL = "MULTIDIRECTIONAL"
+ OPTIONS = "OPTIONS"
+ EXTRA = "EXTRA"
+ OUTPUT = "OUTPUT"
def __init__(self):
super().__init__()
def initAlgorithm(self, config=None):
- self.addParameter(QgsProcessingParameterRasterLayer(self.INPUT, self.tr('Input layer')))
- self.addParameter(QgsProcessingParameterBand(self.BAND,
- self.tr('Band number'),
- 1,
- parentLayerParameterName=self.INPUT))
- self.addParameter(QgsProcessingParameterNumber(self.Z_FACTOR,
- self.tr('Z factor (vertical exaggeration)'),
- type=QgsProcessingParameterNumber.Type.Double,
- minValue=0.0,
- defaultValue=1.0))
- self.addParameter(QgsProcessingParameterNumber(self.SCALE,
- self.tr('Scale (ratio of vertical units to horizontal)'),
- type=QgsProcessingParameterNumber.Type.Double,
- minValue=0.0,
- defaultValue=1.0))
- self.addParameter(QgsProcessingParameterNumber(self.AZIMUTH,
- self.tr('Azimuth of the light'),
- type=QgsProcessingParameterNumber.Type.Double,
- minValue=0.0,
- maxValue=360,
- defaultValue=315.0))
- self.addParameter(QgsProcessingParameterNumber(self.ALTITUDE,
- self.tr('Altitude of the light'),
- type=QgsProcessingParameterNumber.Type.Double,
- minValue=0.0,
- defaultValue=45.0))
- self.addParameter(QgsProcessingParameterBoolean(self.COMPUTE_EDGES,
- self.tr('Compute edges'),
- defaultValue=False))
- self.addParameter(QgsProcessingParameterBoolean(self.ZEVENBERGEN,
- self.tr("Use Zevenbergen&Thorne formula instead of the Horn's one"),
- defaultValue=False))
- self.addParameter(QgsProcessingParameterBoolean(self.COMBINED,
- self.tr("Combined shading"),
- defaultValue=False))
- self.addParameter(QgsProcessingParameterBoolean(self.MULTIDIRECTIONAL,
- self.tr("Multidirectional shading"),
- defaultValue=False))
-
- options_param = QgsProcessingParameterString(self.OPTIONS,
- self.tr('Additional creation options'),
- defaultValue='',
- optional=True)
- options_param.setFlags(options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
- options_param.setMetadata({'widget_wrapper': {'widget_type': 'rasteroptions'}})
+ self.addParameter(
+ QgsProcessingParameterRasterLayer(self.INPUT, self.tr("Input layer"))
+ )
+ self.addParameter(
+ QgsProcessingParameterBand(
+ self.BAND,
+ self.tr("Band number"),
+ 1,
+ parentLayerParameterName=self.INPUT,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterNumber(
+ self.Z_FACTOR,
+ self.tr("Z factor (vertical exaggeration)"),
+ type=QgsProcessingParameterNumber.Type.Double,
+ minValue=0.0,
+ defaultValue=1.0,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterNumber(
+ self.SCALE,
+ self.tr("Scale (ratio of vertical units to horizontal)"),
+ type=QgsProcessingParameterNumber.Type.Double,
+ minValue=0.0,
+ defaultValue=1.0,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterNumber(
+ self.AZIMUTH,
+ self.tr("Azimuth of the light"),
+ type=QgsProcessingParameterNumber.Type.Double,
+ minValue=0.0,
+ maxValue=360,
+ defaultValue=315.0,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterNumber(
+ self.ALTITUDE,
+ self.tr("Altitude of the light"),
+ type=QgsProcessingParameterNumber.Type.Double,
+ minValue=0.0,
+ defaultValue=45.0,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterBoolean(
+ self.COMPUTE_EDGES, self.tr("Compute edges"), defaultValue=False
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterBoolean(
+ self.ZEVENBERGEN,
+ self.tr("Use Zevenbergen&Thorne formula instead of the Horn's one"),
+ defaultValue=False,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterBoolean(
+ self.COMBINED, self.tr("Combined shading"), defaultValue=False
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterBoolean(
+ self.MULTIDIRECTIONAL,
+ self.tr("Multidirectional shading"),
+ defaultValue=False,
+ )
+ )
+
+ options_param = QgsProcessingParameterString(
+ self.OPTIONS,
+ self.tr("Additional creation options"),
+ defaultValue="",
+ optional=True,
+ )
+ options_param.setFlags(
+ options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
+ options_param.setMetadata({"widget_wrapper": {"widget_type": "rasteroptions"}})
self.addParameter(options_param)
- extra_param = QgsProcessingParameterString(self.EXTRA,
- self.tr('Additional command-line parameters'),
- defaultValue=None,
- optional=True)
- extra_param.setFlags(extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
+ extra_param = QgsProcessingParameterString(
+ self.EXTRA,
+ self.tr("Additional command-line parameters"),
+ defaultValue=None,
+ optional=True,
+ )
+ extra_param.setFlags(
+ extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
self.addParameter(extra_param)
- self.addParameter(QgsProcessingParameterRasterDestination(self.OUTPUT, self.tr('Hillshade')))
+ self.addParameter(
+ QgsProcessingParameterRasterDestination(self.OUTPUT, self.tr("Hillshade"))
+ )
def name(self):
- return 'hillshade'
+ return "hillshade"
def displayName(self):
- return self.tr('Hillshade')
+ return self.tr("Hillshade")
def group(self):
- return self.tr('Raster analysis')
+ return self.tr("Raster analysis")
def groupId(self):
- return 'rasteranalysis'
+ return "rasteranalysis"
def commandName(self):
- return 'gdaldem'
+ return "gdaldem"
def getConsoleCommands(self, parameters, context, feedback, executing=True):
- arguments = ['hillshade']
+ arguments = ["hillshade"]
inLayer = self.parameterAsRasterLayer(parameters, self.INPUT, context)
if inLayer is None:
- raise QgsProcessingException(self.invalidRasterError(parameters, self.INPUT))
+ raise QgsProcessingException(
+ self.invalidRasterError(parameters, self.INPUT)
+ )
input_details = GdalUtils.gdal_connection_details_from_layer(inLayer)
arguments.append(input_details.connection_string)
@@ -141,52 +189,61 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True):
output_format = QgsRasterFileWriter.driverForExtension(os.path.splitext(out)[1])
if not output_format:
- raise QgsProcessingException(self.tr('Output format is invalid'))
+ raise QgsProcessingException(self.tr("Output format is invalid"))
- arguments.append('-of')
+ arguments.append("-of")
arguments.append(output_format)
- arguments.append('-b')
+ arguments.append("-b")
arguments.append(str(self.parameterAsInt(parameters, self.BAND, context)))
- arguments.append('-z')
- arguments.append(str(self.parameterAsDouble(parameters, self.Z_FACTOR, context)))
- arguments.append('-s')
+ arguments.append("-z")
+ arguments.append(
+ str(self.parameterAsDouble(parameters, self.Z_FACTOR, context))
+ )
+ arguments.append("-s")
arguments.append(str(self.parameterAsDouble(parameters, self.SCALE, context)))
- multidirectional = self.parameterAsBoolean(parameters, self.MULTIDIRECTIONAL, context)
+ multidirectional = self.parameterAsBoolean(
+ parameters, self.MULTIDIRECTIONAL, context
+ )
# azimuth and multidirectional are mutually exclusive
if not multidirectional:
- arguments.append('-az')
- arguments.append(str(self.parameterAsDouble(parameters, self.AZIMUTH, context)))
+ arguments.append("-az")
+ arguments.append(
+ str(self.parameterAsDouble(parameters, self.AZIMUTH, context))
+ )
- arguments.append('-alt')
- arguments.append(str(self.parameterAsDouble(parameters, self.ALTITUDE, context)))
+ arguments.append("-alt")
+ arguments.append(
+ str(self.parameterAsDouble(parameters, self.ALTITUDE, context))
+ )
if self.parameterAsBoolean(parameters, self.COMPUTE_EDGES, context):
- arguments.append('-compute_edges')
+ arguments.append("-compute_edges")
if self.parameterAsBoolean(parameters, self.ZEVENBERGEN, context):
- arguments.append('-alg')
- arguments.append('ZevenbergenThorne')
+ arguments.append("-alg")
+ arguments.append("ZevenbergenThorne")
combined = self.parameterAsBoolean(parameters, self.COMBINED, context)
if combined and not multidirectional:
- arguments.append('-combined')
+ arguments.append("-combined")
elif multidirectional and not combined:
- arguments.append('-multidirectional')
+ arguments.append("-multidirectional")
elif multidirectional and combined:
- raise QgsProcessingException(self.tr('Options -multirectional and -combined are mutually exclusive.'))
+ raise QgsProcessingException(
+ self.tr("Options -multirectional and -combined are mutually exclusive.")
+ )
options = self.parameterAsString(parameters, self.OPTIONS, context)
if options:
arguments.extend(GdalUtils.parseCreationOptions(options))
- if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ''):
+ if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ""):
extra = self.parameterAsString(parameters, self.EXTRA, context)
arguments.append(extra)
if input_details.credential_options:
- arguments.extend(
- input_details.credential_options_as_arguments())
+ arguments.extend(input_details.credential_options_as_arguments())
return [self.commandName(), GdalUtils.escapeAndJoin(arguments)]
diff --git a/python/plugins/processing/algs/gdal/merge.py b/python/plugins/processing/algs/gdal/merge.py
index b807c4c2ad5b..323c4fb26095 100644
--- a/python/plugins/processing/algs/gdal/merge.py
+++ b/python/plugins/processing/algs/gdal/merge.py
@@ -15,24 +15,26 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'August 2012'
-__copyright__ = '(C) 2012, Victor Olaya'
+__author__ = "Victor Olaya"
+__date__ = "August 2012"
+__copyright__ = "(C) 2012, Victor Olaya"
import os
from qgis.PyQt.QtGui import QIcon
-from qgis.core import (QgsRasterFileWriter,
- QgsProcessing,
- QgsProcessingException,
- QgsProcessingParameterDefinition,
- QgsProcessingParameterMultipleLayers,
- QgsProcessingParameterEnum,
- QgsProcessingParameterString,
- QgsProcessingParameterBoolean,
- QgsProcessingParameterNumber,
- QgsProcessingParameterRasterDestination)
+from qgis.core import (
+ QgsRasterFileWriter,
+ QgsProcessing,
+ QgsProcessingException,
+ QgsProcessingParameterDefinition,
+ QgsProcessingParameterMultipleLayers,
+ QgsProcessingParameterEnum,
+ QgsProcessingParameterString,
+ QgsProcessingParameterBoolean,
+ QgsProcessingParameterNumber,
+ QgsProcessingParameterRasterDestination,
+)
from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm
from processing.algs.gdal.GdalUtils import GdalUtils
@@ -42,89 +44,134 @@
class merge(GdalAlgorithm):
- INPUT = 'INPUT'
- PCT = 'PCT'
- SEPARATE = 'SEPARATE'
- OPTIONS = 'OPTIONS'
- EXTRA = 'EXTRA'
- DATA_TYPE = 'DATA_TYPE'
- NODATA_INPUT = 'NODATA_INPUT'
- NODATA_OUTPUT = 'NODATA_OUTPUT'
- OUTPUT = 'OUTPUT'
-
- TYPES = ['Byte', 'Int16', 'UInt16', 'UInt32', 'Int32', 'Float32', 'Float64', 'CInt16', 'CInt32', 'CFloat32', 'CFloat64', 'Int8']
+ INPUT = "INPUT"
+ PCT = "PCT"
+ SEPARATE = "SEPARATE"
+ OPTIONS = "OPTIONS"
+ EXTRA = "EXTRA"
+ DATA_TYPE = "DATA_TYPE"
+ NODATA_INPUT = "NODATA_INPUT"
+ NODATA_OUTPUT = "NODATA_OUTPUT"
+ OUTPUT = "OUTPUT"
+
+ TYPES = [
+ "Byte",
+ "Int16",
+ "UInt16",
+ "UInt32",
+ "Int32",
+ "Float32",
+ "Float64",
+ "CInt16",
+ "CInt32",
+ "CFloat32",
+ "CFloat64",
+ "Int8",
+ ]
def __init__(self):
super().__init__()
def initAlgorithm(self, config=None):
- self.addParameter(QgsProcessingParameterMultipleLayers(self.INPUT,
- self.tr('Input layers'),
- QgsProcessing.SourceType.TypeRaster))
- self.addParameter(QgsProcessingParameterBoolean(self.PCT,
- self.tr('Grab pseudocolor table from first layer'),
- defaultValue=False))
- self.addParameter(QgsProcessingParameterBoolean(self.SEPARATE,
- self.tr('Place each input file into a separate band'),
- defaultValue=False))
-
- nodata_param = QgsProcessingParameterNumber(self.NODATA_INPUT,
- self.tr('Input pixel value to treat as NoData'),
- type=QgsProcessingParameterNumber.Type.Double,
- defaultValue=None,
- optional=True)
- nodata_param.setFlags(nodata_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
+ self.addParameter(
+ QgsProcessingParameterMultipleLayers(
+ self.INPUT, self.tr("Input layers"), QgsProcessing.SourceType.TypeRaster
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterBoolean(
+ self.PCT,
+ self.tr("Grab pseudocolor table from first layer"),
+ defaultValue=False,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterBoolean(
+ self.SEPARATE,
+ self.tr("Place each input file into a separate band"),
+ defaultValue=False,
+ )
+ )
+
+ nodata_param = QgsProcessingParameterNumber(
+ self.NODATA_INPUT,
+ self.tr("Input pixel value to treat as NoData"),
+ type=QgsProcessingParameterNumber.Type.Double,
+ defaultValue=None,
+ optional=True,
+ )
+ nodata_param.setFlags(
+ nodata_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
self.addParameter(nodata_param)
- nodata_out_param = QgsProcessingParameterNumber(self.NODATA_OUTPUT,
- self.tr('Assign specified NoData value to output'),
- type=QgsProcessingParameterNumber.Type.Double,
- defaultValue=None,
- optional=True)
- nodata_out_param.setFlags(nodata_out_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
+ nodata_out_param = QgsProcessingParameterNumber(
+ self.NODATA_OUTPUT,
+ self.tr("Assign specified NoData value to output"),
+ type=QgsProcessingParameterNumber.Type.Double,
+ defaultValue=None,
+ optional=True,
+ )
+ nodata_out_param.setFlags(
+ nodata_out_param.flags()
+ | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
self.addParameter(nodata_out_param)
- options_param = QgsProcessingParameterString(self.OPTIONS,
- self.tr('Additional creation options'),
- defaultValue='',
- optional=True)
- options_param.setFlags(options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
- options_param.setMetadata({'widget_wrapper': {'widget_type': 'rasteroptions'}})
+ options_param = QgsProcessingParameterString(
+ self.OPTIONS,
+ self.tr("Additional creation options"),
+ defaultValue="",
+ optional=True,
+ )
+ options_param.setFlags(
+ options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
+ options_param.setMetadata({"widget_wrapper": {"widget_type": "rasteroptions"}})
self.addParameter(options_param)
- extra_param = QgsProcessingParameterString(self.EXTRA,
- self.tr('Additional command-line parameters'),
- defaultValue=None,
- optional=True)
- extra_param.setFlags(extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
+ extra_param = QgsProcessingParameterString(
+ self.EXTRA,
+ self.tr("Additional command-line parameters"),
+ defaultValue=None,
+ optional=True,
+ )
+ extra_param.setFlags(
+ extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
self.addParameter(extra_param)
- self.addParameter(QgsProcessingParameterEnum(self.DATA_TYPE,
- self.tr('Output data type'),
- self.TYPES,
- allowMultiple=False,
- defaultValue=5))
+ self.addParameter(
+ QgsProcessingParameterEnum(
+ self.DATA_TYPE,
+ self.tr("Output data type"),
+ self.TYPES,
+ allowMultiple=False,
+ defaultValue=5,
+ )
+ )
- self.addParameter(QgsProcessingParameterRasterDestination(self.OUTPUT,
- self.tr('Merged')))
+ self.addParameter(
+ QgsProcessingParameterRasterDestination(self.OUTPUT, self.tr("Merged"))
+ )
def name(self):
- return 'merge'
+ return "merge"
def displayName(self):
- return self.tr('Merge')
+ return self.tr("Merge")
def group(self):
- return self.tr('Raster miscellaneous')
+ return self.tr("Raster miscellaneous")
def groupId(self):
- return 'rastermiscellaneous'
+ return "rastermiscellaneous"
def icon(self):
- return QIcon(os.path.join(pluginPath, 'images', 'gdaltools', 'merge.png'))
+ return QIcon(os.path.join(pluginPath, "images", "gdaltools", "merge.png"))
def commandName(self):
- return 'gdal_merge'
+ return "gdal_merge"
def getConsoleCommands(self, parameters, context, feedback, executing=True):
out = self.parameterAsOutputLayer(parameters, self.OUTPUT, context)
@@ -132,49 +179,72 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True):
arguments = []
if self.parameterAsBoolean(parameters, self.PCT, context):
- arguments.append('-pct')
+ arguments.append("-pct")
if self.parameterAsBoolean(parameters, self.SEPARATE, context):
- arguments.append('-separate')
-
- if self.NODATA_INPUT in parameters and parameters[self.NODATA_INPUT] is not None:
- nodata_input = self.parameterAsDouble(parameters, self.NODATA_INPUT, context)
- arguments.append('-n')
+ arguments.append("-separate")
+
+ if (
+ self.NODATA_INPUT in parameters
+ and parameters[self.NODATA_INPUT] is not None
+ ):
+ nodata_input = self.parameterAsDouble(
+ parameters, self.NODATA_INPUT, context
+ )
+ arguments.append("-n")
arguments.append(str(nodata_input))
- if self.NODATA_OUTPUT in parameters and parameters[self.NODATA_OUTPUT] is not None:
- nodata_output = self.parameterAsDouble(parameters, self.NODATA_OUTPUT, context)
- arguments.append('-a_nodata')
+ if (
+ self.NODATA_OUTPUT in parameters
+ and parameters[self.NODATA_OUTPUT] is not None
+ ):
+ nodata_output = self.parameterAsDouble(
+ parameters, self.NODATA_OUTPUT, context
+ )
+ arguments.append("-a_nodata")
arguments.append(str(nodata_output))
data_type = self.parameterAsEnum(parameters, self.DATA_TYPE, context)
- if self.TYPES[data_type] == 'Int8' and GdalUtils.version() < 3070000:
- raise QgsProcessingException(self.tr('Int8 data type requires GDAL version 3.7 or later'))
+ if self.TYPES[data_type] == "Int8" and GdalUtils.version() < 3070000:
+ raise QgsProcessingException(
+ self.tr("Int8 data type requires GDAL version 3.7 or later")
+ )
- arguments.append('-ot ' + self.TYPES[data_type])
+ arguments.append("-ot " + self.TYPES[data_type])
output_format = QgsRasterFileWriter.driverForExtension(os.path.splitext(out)[1])
if not output_format:
- raise QgsProcessingException(self.tr('Output format is invalid'))
+ raise QgsProcessingException(self.tr("Output format is invalid"))
- arguments.append('-of')
+ arguments.append("-of")
arguments.append(output_format)
options = self.parameterAsString(parameters, self.OPTIONS, context)
if options:
arguments.extend(GdalUtils.parseCreationOptions(options))
- if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ''):
+ if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ""):
extra = self.parameterAsString(parameters, self.EXTRA, context)
arguments.append(extra)
- arguments.append('-o')
+ arguments.append("-o")
arguments.append(out)
# Always write input files to a text file in case there are many of them and the
# length of the command will be longer then allowed in command prompt
- list_file = GdalUtils.writeLayerParameterToTextFile(filename='mergeInputFiles.txt', alg=self, parameters=parameters, parameter_name=self.INPUT, context=context, quote=True, executing=executing)
- arguments.append('--optfile')
+ list_file = GdalUtils.writeLayerParameterToTextFile(
+ filename="mergeInputFiles.txt",
+ alg=self,
+ parameters=parameters,
+ parameter_name=self.INPUT,
+ context=context,
+ quote=True,
+ executing=executing,
+ )
+ arguments.append("--optfile")
arguments.append(list_file)
- return [self.commandName() + ('.bat' if isWindows() else '.py'), GdalUtils.escapeAndJoin(arguments)]
+ return [
+ self.commandName() + (".bat" if isWindows() else ".py"),
+ GdalUtils.escapeAndJoin(arguments),
+ ]
diff --git a/python/plugins/processing/algs/gdal/nearblack.py b/python/plugins/processing/algs/gdal/nearblack.py
index 3156f5b24dcd..db3ba5cdc18a 100644
--- a/python/plugins/processing/algs/gdal/nearblack.py
+++ b/python/plugins/processing/algs/gdal/nearblack.py
@@ -15,22 +15,24 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'August 2012'
-__copyright__ = '(C) 2012, Victor Olaya'
+__author__ = "Victor Olaya"
+__date__ = "August 2012"
+__copyright__ = "(C) 2012, Victor Olaya"
import os
from qgis.PyQt.QtGui import QIcon
-from qgis.core import (QgsRasterFileWriter,
- QgsProcessingException,
- QgsProcessingParameterDefinition,
- QgsProcessingParameterRasterLayer,
- QgsProcessingParameterBoolean,
- QgsProcessingParameterNumber,
- QgsProcessingParameterString,
- QgsProcessingParameterRasterDestination)
+from qgis.core import (
+ QgsRasterFileWriter,
+ QgsProcessingException,
+ QgsProcessingParameterDefinition,
+ QgsProcessingParameterRasterLayer,
+ QgsProcessingParameterBoolean,
+ QgsProcessingParameterNumber,
+ QgsProcessingParameterString,
+ QgsProcessingParameterRasterDestination,
+)
from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm
from processing.algs.gdal.GdalUtils import GdalUtils
@@ -39,66 +41,88 @@
class nearblack(GdalAlgorithm):
- INPUT = 'INPUT'
- NEAR = 'NEAR'
- WHITE = 'WHITE'
- OPTIONS = 'OPTIONS'
- EXTRA = 'EXTRA'
- OUTPUT = 'OUTPUT'
+ INPUT = "INPUT"
+ NEAR = "NEAR"
+ WHITE = "WHITE"
+ OPTIONS = "OPTIONS"
+ EXTRA = "EXTRA"
+ OUTPUT = "OUTPUT"
def __init__(self):
super().__init__()
def initAlgorithm(self, config=None):
- self.addParameter(QgsProcessingParameterRasterLayer(self.INPUT, self.tr('Input layer')))
- self.addParameter(QgsProcessingParameterNumber(self.NEAR,
- self.tr('How far from black (white)'),
- type=QgsProcessingParameterNumber.Type.Integer,
- minValue=0,
- defaultValue=15))
- self.addParameter(QgsProcessingParameterBoolean(self.WHITE,
- self.tr('Search for nearly white pixels instead of nearly black'),
- defaultValue=False))
-
- options_param = QgsProcessingParameterString(self.OPTIONS,
- self.tr('Additional creation options'),
- defaultValue='',
- optional=True)
- options_param.setFlags(options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
- options_param.setMetadata({'widget_wrapper': {'widget_type': 'rasteroptions'}})
+ self.addParameter(
+ QgsProcessingParameterRasterLayer(self.INPUT, self.tr("Input layer"))
+ )
+ self.addParameter(
+ QgsProcessingParameterNumber(
+ self.NEAR,
+ self.tr("How far from black (white)"),
+ type=QgsProcessingParameterNumber.Type.Integer,
+ minValue=0,
+ defaultValue=15,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterBoolean(
+ self.WHITE,
+ self.tr("Search for nearly white pixels instead of nearly black"),
+ defaultValue=False,
+ )
+ )
+
+ options_param = QgsProcessingParameterString(
+ self.OPTIONS,
+ self.tr("Additional creation options"),
+ defaultValue="",
+ optional=True,
+ )
+ options_param.setFlags(
+ options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
+ options_param.setMetadata({"widget_wrapper": {"widget_type": "rasteroptions"}})
self.addParameter(options_param)
- extra_param = QgsProcessingParameterString(self.EXTRA,
- self.tr('Additional command-line parameters'),
- defaultValue=None,
- optional=True)
- extra_param.setFlags(extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
+ extra_param = QgsProcessingParameterString(
+ self.EXTRA,
+ self.tr("Additional command-line parameters"),
+ defaultValue=None,
+ optional=True,
+ )
+ extra_param.setFlags(
+ extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
self.addParameter(extra_param)
- self.addParameter(QgsProcessingParameterRasterDestination(self.OUTPUT, self.tr('Nearblack')))
+ self.addParameter(
+ QgsProcessingParameterRasterDestination(self.OUTPUT, self.tr("Nearblack"))
+ )
def name(self):
- return 'nearblack'
+ return "nearblack"
def displayName(self):
- return self.tr('Near black')
+ return self.tr("Near black")
def group(self):
- return self.tr('Raster analysis')
+ return self.tr("Raster analysis")
def groupId(self):
- return 'rasteranalysis'
+ return "rasteranalysis"
def icon(self):
- return QIcon(os.path.join(pluginPath, 'images', 'gdaltools', 'nearblack.png'))
+ return QIcon(os.path.join(pluginPath, "images", "gdaltools", "nearblack.png"))
def commandName(self):
- return 'nearblack'
+ return "nearblack"
def getConsoleCommands(self, parameters, context, feedback, executing=True):
inLayer = self.parameterAsRasterLayer(parameters, self.INPUT, context)
if inLayer is None:
- raise QgsProcessingException(self.invalidRasterError(parameters, self.INPUT))
+ raise QgsProcessingException(
+ self.invalidRasterError(parameters, self.INPUT)
+ )
input_details = GdalUtils.gdal_connection_details_from_layer(inLayer)
out = self.parameterAsOutputLayer(parameters, self.OUTPUT, context)
@@ -106,20 +130,20 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True):
output_format = QgsRasterFileWriter.driverForExtension(os.path.splitext(out)[1])
if not output_format:
- raise QgsProcessingException(self.tr('Output format is invalid'))
+ raise QgsProcessingException(self.tr("Output format is invalid"))
arguments = [
input_details.connection_string,
- '-of',
+ "-of",
output_format,
- '-o',
+ "-o",
out,
- '-near',
- str(self.parameterAsInt(parameters, self.NEAR, context))
+ "-near",
+ str(self.parameterAsInt(parameters, self.NEAR, context)),
]
if self.parameterAsBoolean(parameters, self.WHITE, context):
- arguments.append('-white')
+ arguments.append("-white")
if input_details.credential_options:
arguments.extend(input_details.credential_options_as_arguments())
@@ -128,7 +152,7 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True):
if options:
arguments.extend(GdalUtils.parseCreationOptions(options))
- if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ''):
+ if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ""):
extra = self.parameterAsString(parameters, self.EXTRA, context)
arguments.append(extra)
diff --git a/python/plugins/processing/algs/gdal/ogr2ogr.py b/python/plugins/processing/algs/gdal/ogr2ogr.py
index f030ca6bd6a0..3040b8242eac 100644
--- a/python/plugins/processing/algs/gdal/ogr2ogr.py
+++ b/python/plugins/processing/algs/gdal/ogr2ogr.py
@@ -15,83 +15,111 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'November 2012'
-__copyright__ = '(C) 2012, Victor Olaya'
+__author__ = "Victor Olaya"
+__date__ = "November 2012"
+__copyright__ = "(C) 2012, Victor Olaya"
import os
-from qgis.core import (QgsProcessing,
- QgsProcessingException,
- QgsProcessingParameterBoolean,
- QgsProcessingParameterDefinition,
- QgsProcessingParameterFeatureSource,
- QgsProcessingParameterString,
- QgsProcessingParameterVectorDestination)
+from qgis.core import (
+ QgsProcessing,
+ QgsProcessingException,
+ QgsProcessingParameterBoolean,
+ QgsProcessingParameterDefinition,
+ QgsProcessingParameterFeatureSource,
+ QgsProcessingParameterString,
+ QgsProcessingParameterVectorDestination,
+)
from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm
from processing.algs.gdal.GdalUtils import GdalUtils
class ogr2ogr(GdalAlgorithm):
- INPUT = 'INPUT'
- CONVERT_ALL_LAYERS = 'CONVERT_ALL_LAYERS'
- OPTIONS = 'OPTIONS'
- OUTPUT = 'OUTPUT'
+ INPUT = "INPUT"
+ CONVERT_ALL_LAYERS = "CONVERT_ALL_LAYERS"
+ OPTIONS = "OPTIONS"
+ OUTPUT = "OUTPUT"
def __init__(self):
super().__init__()
def initAlgorithm(self, config=None):
- self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT,
- self.tr('Input layer'),
- types=[QgsProcessing.SourceType.TypeVector]))
-
- convert_all_layers_param = QgsProcessingParameterBoolean(self.CONVERT_ALL_LAYERS,
- self.tr('Convert all layers from dataset'), defaultValue=False)
- convert_all_layers_param.setHelp(self.tr("Use convert all layers to convert a whole dataset. "
- "Supported output formats for this option are GPKG and GML."))
+ self.addParameter(
+ QgsProcessingParameterFeatureSource(
+ self.INPUT,
+ self.tr("Input layer"),
+ types=[QgsProcessing.SourceType.TypeVector],
+ )
+ )
+
+ convert_all_layers_param = QgsProcessingParameterBoolean(
+ self.CONVERT_ALL_LAYERS,
+ self.tr("Convert all layers from dataset"),
+ defaultValue=False,
+ )
+ convert_all_layers_param.setHelp(
+ self.tr(
+ "Use convert all layers to convert a whole dataset. "
+ "Supported output formats for this option are GPKG and GML."
+ )
+ )
self.addParameter(convert_all_layers_param)
- options_param = QgsProcessingParameterString(self.OPTIONS,
- self.tr('Additional creation options'),
- defaultValue='',
- optional=True)
- options_param.setFlags(options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
+ options_param = QgsProcessingParameterString(
+ self.OPTIONS,
+ self.tr("Additional creation options"),
+ defaultValue="",
+ optional=True,
+ )
+ options_param.setFlags(
+ options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
self.addParameter(options_param)
- self.addParameter(QgsProcessingParameterVectorDestination(self.OUTPUT,
- self.tr('Converted')))
+ self.addParameter(
+ QgsProcessingParameterVectorDestination(self.OUTPUT, self.tr("Converted"))
+ )
def name(self):
- return 'convertformat'
+ return "convertformat"
def displayName(self):
- return self.tr('Convert format')
+ return self.tr("Convert format")
def group(self):
- return self.tr('Vector conversion')
+ return self.tr("Vector conversion")
def groupId(self):
- return 'vectorconversion'
+ return "vectorconversion"
def commandName(self):
- return 'ogr2ogr'
+ return "ogr2ogr"
def getConsoleCommands(self, parameters, context, feedback, executing=True):
- input_details = self.getOgrCompatibleSource(self.INPUT, parameters, context, feedback, executing)
- convertAllLayers = self.parameterAsBoolean(parameters, self.CONVERT_ALL_LAYERS, context)
+ input_details = self.getOgrCompatibleSource(
+ self.INPUT, parameters, context, feedback, executing
+ )
+ convertAllLayers = self.parameterAsBoolean(
+ parameters, self.CONVERT_ALL_LAYERS, context
+ )
options = self.parameterAsString(parameters, self.OPTIONS, context)
outFile = self.parameterAsOutputLayer(parameters, self.OUTPUT, context)
self.setOutputValue(self.OUTPUT, outFile)
output_details = GdalUtils.gdal_connection_details_from_uri(outFile, context)
- if output_details.format in ('SQLite', 'GPKG') and os.path.isfile(output_details.connection_string):
- raise QgsProcessingException(self.tr('Output file "{}" already exists.').format(output_details.connection_string))
+ if output_details.format in ("SQLite", "GPKG") and os.path.isfile(
+ output_details.connection_string
+ ):
+ raise QgsProcessingException(
+ self.tr('Output file "{}" already exists.').format(
+ output_details.connection_string
+ )
+ )
arguments = []
if output_details.format:
- arguments.append(f'-f {output_details.format}')
+ arguments.append(f"-f {output_details.format}")
if input_details.open_options:
arguments.extend(input_details.open_options_as_arguments())
@@ -107,12 +135,13 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True):
if not convertAllLayers:
arguments.append(input_details.layer_name)
- return ['ogr2ogr', GdalUtils.escapeAndJoin(arguments)]
+ return ["ogr2ogr", GdalUtils.escapeAndJoin(arguments)]
def shortHelpString(self):
- return self.tr("The algorithm converts simple features data between file formats.\n\n"
- "Use convert all layers to convert a whole dataset.\n"
- "Supported output formats for this option are:\n"
- "- GPKG\n"
- "- GML"
- )
+ return self.tr(
+ "The algorithm converts simple features data between file formats.\n\n"
+ "Use convert all layers to convert a whole dataset.\n"
+ "Supported output formats for this option are:\n"
+ "- GPKG\n"
+ "- GML"
+ )
diff --git a/python/plugins/processing/algs/gdal/ogr2ogrtopostgislist.py b/python/plugins/processing/algs/gdal/ogr2ogrtopostgislist.py
index c6645a8bcf8c..364d684067a6 100644
--- a/python/plugins/processing/algs/gdal/ogr2ogrtopostgislist.py
+++ b/python/plugins/processing/algs/gdal/ogr2ogrtopostgislist.py
@@ -15,25 +15,27 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'November 2012'
-__copyright__ = '(C) 2012, Victor Olaya'
+__author__ = "Victor Olaya"
+__date__ = "November 2012"
+__copyright__ = "(C) 2012, Victor Olaya"
-from qgis.core import (QgsProcessing,
- QgsProcessingParameterFeatureSource,
- QgsProcessingParameterString,
- QgsProcessingParameterEnum,
- QgsProcessingParameterCrs,
- QgsProcessingParameterField,
- QgsProcessingParameterExtent,
- QgsProcessingParameterBoolean,
- QgsProcessingParameterProviderConnection,
- QgsProcessingParameterDatabaseSchema,
- QgsProcessingParameterDatabaseTable,
- QgsProviderRegistry,
- QgsProcessingException,
- QgsProviderConnectionException,
- QgsDataSourceUri)
+from qgis.core import (
+ QgsProcessing,
+ QgsProcessingParameterFeatureSource,
+ QgsProcessingParameterString,
+ QgsProcessingParameterEnum,
+ QgsProcessingParameterCrs,
+ QgsProcessingParameterField,
+ QgsProcessingParameterExtent,
+ QgsProcessingParameterBoolean,
+ QgsProcessingParameterProviderConnection,
+ QgsProcessingParameterDatabaseSchema,
+ QgsProcessingParameterDatabaseTable,
+ QgsProviderRegistry,
+ QgsProcessingException,
+ QgsProviderConnectionException,
+ QgsDataSourceUri,
+)
from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm
from processing.algs.gdal.GdalUtils import GdalUtils
@@ -42,44 +44,60 @@
class Ogr2OgrToPostGisList(GdalAlgorithm):
- DATABASE = 'DATABASE'
- INPUT = 'INPUT'
- SHAPE_ENCODING = 'SHAPE_ENCODING'
- GTYPE = 'GTYPE'
- GEOMTYPE = ['', 'NONE', 'GEOMETRY', 'POINT', 'LINESTRING', 'POLYGON', 'GEOMETRYCOLLECTION', 'MULTIPOINT',
- 'MULTIPOLYGON', 'MULTILINESTRING', 'CIRCULARSTRING', 'COMPOUNDCURVE', 'CURVEPOLYGON', 'MULTICURVE',
- 'MULTISURFACE', 'CONVERT_TO_LINEAR', 'CONVERT_TO_CURVE']
- S_SRS = 'S_SRS'
- T_SRS = 'T_SRS'
- A_SRS = 'A_SRS'
- HOST = 'HOST'
- PORT = 'PORT'
- USER = 'USER'
- DBNAME = 'DBNAME'
- PASSWORD = 'PASSWORD'
- SCHEMA = 'SCHEMA'
- TABLE = 'TABLE'
- PK = 'PK'
- PRIMARY_KEY = 'PRIMARY_KEY'
- GEOCOLUMN = 'GEOCOLUMN'
- DIM = 'DIM'
- DIMLIST = ['2', '3', '4']
- SIMPLIFY = 'SIMPLIFY'
- SEGMENTIZE = 'SEGMENTIZE'
- SPAT = 'SPAT'
- CLIP = 'CLIP'
- WHERE = 'WHERE'
- GT = 'GT'
- OVERWRITE = 'OVERWRITE'
- APPEND = 'APPEND'
- ADDFIELDS = 'ADDFIELDS'
- LAUNDER = 'LAUNDER'
- INDEX = 'INDEX'
- SKIPFAILURES = 'SKIPFAILURES'
- PRECISION = 'PRECISION'
- MAKEVALID = 'MAKEVALID'
- PROMOTETOMULTI = 'PROMOTETOMULTI'
- OPTIONS = 'OPTIONS'
+ DATABASE = "DATABASE"
+ INPUT = "INPUT"
+ SHAPE_ENCODING = "SHAPE_ENCODING"
+ GTYPE = "GTYPE"
+ GEOMTYPE = [
+ "",
+ "NONE",
+ "GEOMETRY",
+ "POINT",
+ "LINESTRING",
+ "POLYGON",
+ "GEOMETRYCOLLECTION",
+ "MULTIPOINT",
+ "MULTIPOLYGON",
+ "MULTILINESTRING",
+ "CIRCULARSTRING",
+ "COMPOUNDCURVE",
+ "CURVEPOLYGON",
+ "MULTICURVE",
+ "MULTISURFACE",
+ "CONVERT_TO_LINEAR",
+ "CONVERT_TO_CURVE",
+ ]
+ S_SRS = "S_SRS"
+ T_SRS = "T_SRS"
+ A_SRS = "A_SRS"
+ HOST = "HOST"
+ PORT = "PORT"
+ USER = "USER"
+ DBNAME = "DBNAME"
+ PASSWORD = "PASSWORD"
+ SCHEMA = "SCHEMA"
+ TABLE = "TABLE"
+ PK = "PK"
+ PRIMARY_KEY = "PRIMARY_KEY"
+ GEOCOLUMN = "GEOCOLUMN"
+ DIM = "DIM"
+ DIMLIST = ["2", "3", "4"]
+ SIMPLIFY = "SIMPLIFY"
+ SEGMENTIZE = "SEGMENTIZE"
+ SPAT = "SPAT"
+ CLIP = "CLIP"
+ WHERE = "WHERE"
+ GT = "GT"
+ OVERWRITE = "OVERWRITE"
+ APPEND = "APPEND"
+ ADDFIELDS = "ADDFIELDS"
+ LAUNDER = "LAUNDER"
+ INDEX = "INDEX"
+ SKIPFAILURES = "SKIPFAILURES"
+ PRECISION = "PRECISION"
+ MAKEVALID = "MAKEVALID"
+ PROMOTETOMULTI = "PROMOTETOMULTI"
+ OPTIONS = "OPTIONS"
def __init__(self):
super().__init__()
@@ -87,139 +105,265 @@ def __init__(self):
def initAlgorithm(self, config=None):
db_param = QgsProcessingParameterProviderConnection(
- self.DATABASE,
- self.tr('Database (connection name)'), 'postgres')
+ self.DATABASE, self.tr("Database (connection name)"), "postgres"
+ )
self.addParameter(db_param)
- self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT,
- self.tr('Input layer'),
- types=[QgsProcessing.SourceType.TypeVector]))
- self.addParameter(QgsProcessingParameterString(self.SHAPE_ENCODING,
- self.tr('Shape encoding'), "", optional=True))
- self.addParameter(QgsProcessingParameterEnum(self.GTYPE,
- self.tr('Output geometry type'), options=self.GEOMTYPE,
- defaultValue=0))
- self.addParameter(QgsProcessingParameterCrs(self.A_SRS,
- self.tr('Assign an output CRS'), defaultValue='', optional=True))
- self.addParameter(QgsProcessingParameterCrs(self.T_SRS,
- self.tr('Reproject to this CRS on output '), defaultValue='',
- optional=True))
- self.addParameter(QgsProcessingParameterCrs(self.S_SRS,
- self.tr('Override source CRS'), defaultValue='', optional=True))
+ self.addParameter(
+ QgsProcessingParameterFeatureSource(
+ self.INPUT,
+ self.tr("Input layer"),
+ types=[QgsProcessing.SourceType.TypeVector],
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterString(
+ self.SHAPE_ENCODING, self.tr("Shape encoding"), "", optional=True
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterEnum(
+ self.GTYPE,
+ self.tr("Output geometry type"),
+ options=self.GEOMTYPE,
+ defaultValue=0,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterCrs(
+ self.A_SRS,
+ self.tr("Assign an output CRS"),
+ defaultValue="",
+ optional=True,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterCrs(
+ self.T_SRS,
+ self.tr("Reproject to this CRS on output "),
+ defaultValue="",
+ optional=True,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterCrs(
+ self.S_SRS,
+ self.tr("Override source CRS"),
+ defaultValue="",
+ optional=True,
+ )
+ )
schema_param = QgsProcessingParameterDatabaseSchema(
self.SCHEMA,
- self.tr('Schema (schema name)'), defaultValue='public', connectionParameterName=self.DATABASE,
- optional=True)
+ self.tr("Schema (schema name)"),
+ defaultValue="public",
+ connectionParameterName=self.DATABASE,
+ optional=True,
+ )
self.addParameter(schema_param)
table_param = QgsProcessingParameterDatabaseTable(
self.TABLE,
- self.tr('Table to import to (leave blank to use layer name)'), defaultValue=None,
+ self.tr("Table to import to (leave blank to use layer name)"),
+ defaultValue=None,
connectionParameterName=self.DATABASE,
- schemaParameterName=self.SCHEMA, optional=True, allowNewTableNames=True)
+ schemaParameterName=self.SCHEMA,
+ optional=True,
+ allowNewTableNames=True,
+ )
self.addParameter(table_param)
- self.addParameter(QgsProcessingParameterString(self.PK,
- self.tr('Primary key (new field)'), defaultValue='id',
- optional=True))
- self.addParameter(QgsProcessingParameterField(self.PRIMARY_KEY,
- self.tr(
- 'Primary key (existing field, used if the above option is left empty)'),
- parentLayerParameterName=self.INPUT, optional=True))
- self.addParameter(QgsProcessingParameterString(self.GEOCOLUMN,
- self.tr('Geometry column name'), defaultValue='geom',
- optional=True))
- self.addParameter(QgsProcessingParameterEnum(self.DIM,
- self.tr('Vector dimensions'), options=self.DIMLIST,
- defaultValue=0))
- self.addParameter(QgsProcessingParameterString(self.SIMPLIFY,
- self.tr('Distance tolerance for simplification'),
- defaultValue='', optional=True))
- self.addParameter(QgsProcessingParameterString(self.SEGMENTIZE,
- self.tr('Maximum distance between 2 nodes (densification)'),
- defaultValue='', optional=True))
- self.addParameter(QgsProcessingParameterExtent(self.SPAT,
- self.tr(
- 'Select features by extent (defined in input layer CRS)'),
- optional=True))
- self.addParameter(QgsProcessingParameterBoolean(self.CLIP,
- self.tr(
- 'Clip the input layer using the above (rectangle) extent'),
- defaultValue=False))
- self.addParameter(QgsProcessingParameterString(self.WHERE,
- self.tr(
- 'Select features using a SQL "WHERE" statement (Ex: column=\'value\')'),
- defaultValue='', optional=True))
- self.addParameter(QgsProcessingParameterString(self.GT,
- self.tr('Group N features per transaction (Default: 20000)'),
- defaultValue='', optional=True))
- self.addParameter(QgsProcessingParameterBoolean(self.OVERWRITE,
- self.tr('Overwrite existing table'), defaultValue=True))
- self.addParameter(QgsProcessingParameterBoolean(self.APPEND,
- self.tr('Append to existing table'), defaultValue=False))
- self.addParameter(QgsProcessingParameterBoolean(self.ADDFIELDS,
- self.tr('Append and add new fields to existing table'),
- defaultValue=False))
- self.addParameter(QgsProcessingParameterBoolean(self.LAUNDER,
- self.tr('Do not launder columns/table names'),
- defaultValue=False))
- self.addParameter(QgsProcessingParameterBoolean(self.INDEX,
- self.tr('Do not create spatial index'), defaultValue=False))
- self.addParameter(QgsProcessingParameterBoolean(self.SKIPFAILURES,
- self.tr(
- 'Continue after a failure, skipping the failed feature'),
- defaultValue=False))
- self.addParameter(QgsProcessingParameterBoolean(self.MAKEVALID,
- self.tr(
- 'Validate geometries based on Simple Features specification'),
- defaultValue=False))
- self.addParameter(QgsProcessingParameterBoolean(self.PROMOTETOMULTI,
- self.tr('Promote to Multipart'),
- defaultValue=True))
- self.addParameter(QgsProcessingParameterBoolean(self.PRECISION,
- self.tr('Keep width and precision of input attributes'),
- defaultValue=True))
- self.addParameter(QgsProcessingParameterString(self.OPTIONS,
- self.tr('Additional creation options'), defaultValue='',
- optional=True))
+ self.addParameter(
+ QgsProcessingParameterString(
+ self.PK,
+ self.tr("Primary key (new field)"),
+ defaultValue="id",
+ optional=True,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterField(
+ self.PRIMARY_KEY,
+ self.tr(
+ "Primary key (existing field, used if the above option is left empty)"
+ ),
+ parentLayerParameterName=self.INPUT,
+ optional=True,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterString(
+ self.GEOCOLUMN,
+ self.tr("Geometry column name"),
+ defaultValue="geom",
+ optional=True,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterEnum(
+ self.DIM,
+ self.tr("Vector dimensions"),
+ options=self.DIMLIST,
+ defaultValue=0,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterString(
+ self.SIMPLIFY,
+ self.tr("Distance tolerance for simplification"),
+ defaultValue="",
+ optional=True,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterString(
+ self.SEGMENTIZE,
+ self.tr("Maximum distance between 2 nodes (densification)"),
+ defaultValue="",
+ optional=True,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterExtent(
+ self.SPAT,
+ self.tr("Select features by extent (defined in input layer CRS)"),
+ optional=True,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterBoolean(
+ self.CLIP,
+ self.tr("Clip the input layer using the above (rectangle) extent"),
+ defaultValue=False,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterString(
+ self.WHERE,
+ self.tr(
+ "Select features using a SQL \"WHERE\" statement (Ex: column='value')"
+ ),
+ defaultValue="",
+ optional=True,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterString(
+ self.GT,
+ self.tr("Group N features per transaction (Default: 20000)"),
+ defaultValue="",
+ optional=True,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterBoolean(
+ self.OVERWRITE, self.tr("Overwrite existing table"), defaultValue=True
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterBoolean(
+ self.APPEND, self.tr("Append to existing table"), defaultValue=False
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterBoolean(
+ self.ADDFIELDS,
+ self.tr("Append and add new fields to existing table"),
+ defaultValue=False,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterBoolean(
+ self.LAUNDER,
+ self.tr("Do not launder columns/table names"),
+ defaultValue=False,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterBoolean(
+ self.INDEX, self.tr("Do not create spatial index"), defaultValue=False
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterBoolean(
+ self.SKIPFAILURES,
+ self.tr("Continue after a failure, skipping the failed feature"),
+ defaultValue=False,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterBoolean(
+ self.MAKEVALID,
+ self.tr("Validate geometries based on Simple Features specification"),
+ defaultValue=False,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterBoolean(
+ self.PROMOTETOMULTI, self.tr("Promote to Multipart"), defaultValue=True
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterBoolean(
+ self.PRECISION,
+ self.tr("Keep width and precision of input attributes"),
+ defaultValue=True,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterString(
+ self.OPTIONS,
+ self.tr("Additional creation options"),
+ defaultValue="",
+ optional=True,
+ )
+ )
def name(self):
- return 'importvectorintopostgisdatabaseavailableconnections'
+ return "importvectorintopostgisdatabaseavailableconnections"
def displayName(self):
- return self.tr('Export to PostgreSQL (available connections)')
+ return self.tr("Export to PostgreSQL (available connections)")
def shortDescription(self):
- return self.tr('Exports a vector layer to an existing PostgreSQL database connection')
+ return self.tr(
+ "Exports a vector layer to an existing PostgreSQL database connection"
+ )
def tags(self):
- t = self.tr('import,into,postgis,database,vector').split(',')
+ t = self.tr("import,into,postgis,database,vector").split(",")
t.extend(super().tags())
return t
def group(self):
- return self.tr('Vector miscellaneous')
+ return self.tr("Vector miscellaneous")
def groupId(self):
- return 'vectormiscellaneous'
+ return "vectormiscellaneous"
def getConsoleCommands(self, parameters, context, feedback, executing=True):
- connection_name = self.parameterAsConnectionName(parameters, self.DATABASE, context)
+ connection_name = self.parameterAsConnectionName(
+ parameters, self.DATABASE, context
+ )
if not connection_name:
- raise QgsProcessingException(
- self.tr('No connection specified'))
+ raise QgsProcessingException(self.tr("No connection specified"))
# resolve connection details to uri
try:
- md = QgsProviderRegistry.instance().providerMetadata('postgres')
+ md = QgsProviderRegistry.instance().providerMetadata("postgres")
conn = md.createConnection(connection_name)
except QgsProviderConnectionException:
raise QgsProcessingException(
- self.tr('Could not retrieve connection details for {}').format(connection_name))
+ self.tr("Could not retrieve connection details for {}").format(
+ connection_name
+ )
+ )
uri = conn.uri()
- input_details = self.getOgrCompatibleSource(self.INPUT, parameters, context, feedback, executing)
+ input_details = self.getOgrCompatibleSource(
+ self.INPUT, parameters, context, feedback, executing
+ )
shapeEncoding = self.parameterAsString(parameters, self.SHAPE_ENCODING, context)
ssrs = self.parameterAsCrs(parameters, self.S_SRS, context)
tsrs = self.parameterAsCrs(parameters, self.T_SRS, context)
@@ -249,24 +393,23 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True):
indexstring = "-lco SPATIAL_INDEX=OFF"
skipfailures = self.parameterAsBoolean(parameters, self.SKIPFAILURES, context)
make_valid = self.parameterAsBoolean(parameters, self.MAKEVALID, context)
- promotetomulti = self.parameterAsBoolean(parameters, self.PROMOTETOMULTI, context)
+ promotetomulti = self.parameterAsBoolean(
+ parameters, self.PROMOTETOMULTI, context
+ )
precision = self.parameterAsBoolean(parameters, self.PRECISION, context)
options = self.parameterAsString(parameters, self.OPTIONS, context)
- arguments = [
- '-progress',
- '--config PG_USE_COPY YES'
- ]
+ arguments = ["-progress", "--config PG_USE_COPY YES"]
if shapeEncoding:
- arguments.append('--config')
- arguments.append('SHAPE_ENCODING')
+ arguments.append("--config")
+ arguments.append("SHAPE_ENCODING")
arguments.append(shapeEncoding)
- arguments.append('-f')
- arguments.append('PostgreSQL')
+ arguments.append("-f")
+ arguments.append("PostgreSQL")
- connection_parts = QgsDataSourceUri(uri).connectionInfo(executing).split(' ')
- connection_parts.append('active_schema={}'.format(schema or 'public'))
- arguments.append('PG:{}'.format(' '.join(connection_parts)))
+ connection_parts = QgsDataSourceUri(uri).connectionInfo(executing).split(" ")
+ connection_parts.append("active_schema={}".format(schema or "public"))
+ arguments.append("PG:{}".format(" ".join(connection_parts)))
arguments.append(dimstring)
arguments.append(input_details.connection_string)
@@ -278,16 +421,23 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True):
if append and overwrite:
raise QgsProcessingException(
self.tr(
- 'Only one of "Overwrite existing table" or "Append to existing table" can be enabled at a time.'))
+ 'Only one of "Overwrite existing table" or "Append to existing table" can be enabled at a time.'
+ )
+ )
elif append:
- arguments.append('-append')
+ arguments.append("-append")
if addfields:
- arguments.append('-addfields')
+ arguments.append("-addfields")
if overwrite:
- arguments.append('-overwrite')
- if len(self.GEOMTYPE[self.parameterAsEnum(parameters, self.GTYPE, context)]) > 0:
- arguments.append('-nlt')
- arguments.append(self.GEOMTYPE[self.parameterAsEnum(parameters, self.GTYPE, context)])
+ arguments.append("-overwrite")
+ if (
+ len(self.GEOMTYPE[self.parameterAsEnum(parameters, self.GTYPE, context)])
+ > 0
+ ):
+ arguments.append("-nlt")
+ arguments.append(
+ self.GEOMTYPE[self.parameterAsEnum(parameters, self.GTYPE, context)]
+ )
if len(geocolumn) > 0:
arguments.append(geocolumnstring)
if pk:
@@ -297,53 +447,64 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True):
if len(table) == 0:
table = input_details.layer_name.lower()
if schema:
- table = f'{schema}.{table}'
- arguments.append('-nln')
+ table = f"{schema}.{table}"
+ arguments.append("-nln")
arguments.append(table)
if ssrs.isValid():
- arguments.append('-s_srs')
+ arguments.append("-s_srs")
arguments.append(GdalUtils.gdal_crs_string(ssrs))
if tsrs.isValid():
- arguments.append('-t_srs')
+ arguments.append("-t_srs")
arguments.append(GdalUtils.gdal_crs_string(tsrs))
if asrs.isValid():
- arguments.append('-a_srs')
+ arguments.append("-a_srs")
arguments.append(GdalUtils.gdal_crs_string(asrs))
if not spat.isNull():
- arguments.append('-spat')
+ arguments.append("-spat")
arguments.append(spat.xMinimum())
arguments.append(spat.yMinimum())
arguments.append(spat.xMaximum())
arguments.append(spat.yMaximum())
if clip:
- arguments.append('-clipsrc spat_extent')
+ arguments.append("-clipsrc spat_extent")
if skipfailures:
- arguments.append('-skipfailures')
+ arguments.append("-skipfailures")
if where:
arguments.append(wherestring)
if len(simplify) > 0:
- arguments.append('-simplify')
+ arguments.append("-simplify")
arguments.append(simplify)
if len(segmentize) > 0:
- arguments.append('-segmentize')
+ arguments.append("-segmentize")
arguments.append(segmentize)
if len(gt) > 0:
- arguments.append('-gt')
+ arguments.append("-gt")
arguments.append(gt)
if make_valid:
- arguments.append('-makevalid')
- if promotetomulti and self.GEOMTYPE[self.parameterAsEnum(parameters, self.GTYPE, context)]:
- if self.GEOMTYPE[self.parameterAsEnum(parameters, self.GTYPE, context)] == 'CONVERT_TO_LINEAR':
- arguments.append('-nlt PROMOTE_TO_MULTI')
+ arguments.append("-makevalid")
+ if (
+ promotetomulti
+ and self.GEOMTYPE[self.parameterAsEnum(parameters, self.GTYPE, context)]
+ ):
+ if (
+ self.GEOMTYPE[self.parameterAsEnum(parameters, self.GTYPE, context)]
+ == "CONVERT_TO_LINEAR"
+ ):
+ arguments.append("-nlt PROMOTE_TO_MULTI")
else:
raise QgsProcessingException(
self.tr(
- 'Only one of "Promote to Multipart" or "Output geometry type" (excluding Convert to Linear) can be enabled.'))
+ 'Only one of "Promote to Multipart" or "Output geometry type" (excluding Convert to Linear) can be enabled.'
+ )
+ )
- elif promotetomulti and not self.GEOMTYPE[self.parameterAsEnum(parameters, self.GTYPE, context)]:
- arguments.append('-nlt PROMOTE_TO_MULTI')
+ elif (
+ promotetomulti
+ and not self.GEOMTYPE[self.parameterAsEnum(parameters, self.GTYPE, context)]
+ ):
+ arguments.append("-nlt PROMOTE_TO_MULTI")
if precision is False:
- arguments.append('-lco PRECISION=NO')
+ arguments.append("-lco PRECISION=NO")
if input_details.open_options:
arguments.extend(input_details.open_options_as_arguments())
@@ -355,10 +516,9 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True):
arguments.append(options)
if isWindows():
- return ['cmd.exe', '/C ', 'ogr2ogr.exe',
- GdalUtils.escapeAndJoin(arguments)]
+ return ["cmd.exe", "/C ", "ogr2ogr.exe", GdalUtils.escapeAndJoin(arguments)]
else:
- return ['ogr2ogr', GdalUtils.escapeAndJoin(arguments)]
+ return ["ogr2ogr", GdalUtils.escapeAndJoin(arguments)]
def commandName(self):
return "ogr2ogr"
diff --git a/python/plugins/processing/algs/gdal/ogrinfo.py b/python/plugins/processing/algs/gdal/ogrinfo.py
index 9fcb4e650c91..77deb97c863f 100644
--- a/python/plugins/processing/algs/gdal/ogrinfo.py
+++ b/python/plugins/processing/algs/gdal/ogrinfo.py
@@ -15,106 +15,137 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'November 2012'
-__copyright__ = '(C) 2012, Victor Olaya'
-
-from qgis.core import (QgsProcessingException,
- QgsProcessingParameterVectorLayer,
- QgsProcessingParameterBoolean,
- QgsProcessingParameterDefinition,
- QgsProcessingParameterString,
- QgsProcessingParameterFileDestination)
+__author__ = "Victor Olaya"
+__date__ = "November 2012"
+__copyright__ = "(C) 2012, Victor Olaya"
+
+from qgis.core import (
+ QgsProcessingException,
+ QgsProcessingParameterVectorLayer,
+ QgsProcessingParameterBoolean,
+ QgsProcessingParameterDefinition,
+ QgsProcessingParameterString,
+ QgsProcessingParameterFileDestination,
+)
from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm
from processing.algs.gdal.GdalUtils import GdalUtils
class ogrinfo(GdalAlgorithm):
- INPUT = 'INPUT'
- ALL_LAYERS = 'ALL_LAYERS'
- SUMMARY_ONLY = 'SUMMARY_ONLY'
- NO_METADATA = 'NO_METADATA'
- EXTRA = 'EXTRA'
- OUTPUT = 'OUTPUT'
+ INPUT = "INPUT"
+ ALL_LAYERS = "ALL_LAYERS"
+ SUMMARY_ONLY = "SUMMARY_ONLY"
+ NO_METADATA = "NO_METADATA"
+ EXTRA = "EXTRA"
+ OUTPUT = "OUTPUT"
def __init__(self):
super().__init__()
def initAlgorithm(self, config=None):
- self.addParameter(QgsProcessingParameterVectorLayer(self.INPUT,
- self.tr('Input layer')))
- self.addParameter(QgsProcessingParameterBoolean(self.ALL_LAYERS,
- self.tr('Enable listing of all layers in the dataset'),
- defaultValue=False))
- if self.name() == 'ogrinfo':
- self.addParameter(QgsProcessingParameterBoolean(self.SUMMARY_ONLY,
- self.tr('Summary output only'),
- defaultValue=True))
+ self.addParameter(
+ QgsProcessingParameterVectorLayer(self.INPUT, self.tr("Input layer"))
+ )
+ self.addParameter(
+ QgsProcessingParameterBoolean(
+ self.ALL_LAYERS,
+ self.tr("Enable listing of all layers in the dataset"),
+ defaultValue=False,
+ )
+ )
+ if self.name() == "ogrinfo":
+ self.addParameter(
+ QgsProcessingParameterBoolean(
+ self.SUMMARY_ONLY, self.tr("Summary output only"), defaultValue=True
+ )
+ )
else:
- self.addParameter(QgsProcessingParameterBoolean(self.FEATURES,
- self.tr('Enable listing of features'),
- defaultValue=False))
-
- self.addParameter(QgsProcessingParameterBoolean(self.NO_METADATA,
- self.tr('Suppress metadata info'),
- defaultValue=False))
-
- extra_param = QgsProcessingParameterString(self.EXTRA,
- self.tr('Additional command-line parameters'),
- defaultValue=None,
- optional=True)
- extra_param.setFlags(extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
+ self.addParameter(
+ QgsProcessingParameterBoolean(
+ self.FEATURES,
+ self.tr("Enable listing of features"),
+ defaultValue=False,
+ )
+ )
+
+ self.addParameter(
+ QgsProcessingParameterBoolean(
+ self.NO_METADATA, self.tr("Suppress metadata info"), defaultValue=False
+ )
+ )
+
+ extra_param = QgsProcessingParameterString(
+ self.EXTRA,
+ self.tr("Additional command-line parameters"),
+ defaultValue=None,
+ optional=True,
+ )
+ extra_param.setFlags(
+ extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
self.addParameter(extra_param)
- if self.name() == 'ogrinfo':
- self.addParameter(QgsProcessingParameterFileDestination(self.OUTPUT,
- self.tr('Layer information'),
- self.tr('HTML files (*.html)')))
+ if self.name() == "ogrinfo":
+ self.addParameter(
+ QgsProcessingParameterFileDestination(
+ self.OUTPUT,
+ self.tr("Layer information"),
+ self.tr("HTML files (*.html)"),
+ )
+ )
else:
- self.addParameter(QgsProcessingParameterFileDestination(self.OUTPUT,
- self.tr('Layer information'),
- self.tr('JSON files (*.json)')))
+ self.addParameter(
+ QgsProcessingParameterFileDestination(
+ self.OUTPUT,
+ self.tr("Layer information"),
+ self.tr("JSON files (*.json)"),
+ )
+ )
def name(self):
- return 'ogrinfo'
+ return "ogrinfo"
def displayName(self):
- return self.tr('Vector information')
+ return self.tr("Vector information")
def group(self):
- return self.tr('Vector miscellaneous')
+ return self.tr("Vector miscellaneous")
def groupId(self):
- return 'vectormiscellaneous'
+ return "vectormiscellaneous"
def commandName(self):
- return 'ogrinfo'
+ return "ogrinfo"
def getConsoleCommands(self, parameters, context, feedback, executing=True):
- if self.name() == 'ogrinfo':
- arguments = ['-al']
+ if self.name() == "ogrinfo":
+ arguments = ["-al"]
else:
- arguments = ['-json']
+ arguments = ["-json"]
- if self.name() == 'ogrinfo':
+ if self.name() == "ogrinfo":
if self.parameterAsBoolean(parameters, self.SUMMARY_ONLY, context):
- arguments.append('-so')
+ arguments.append("-so")
else:
if self.parameterAsBoolean(parameters, self.FEATURES, context):
- arguments.append('-features')
+ arguments.append("-features")
if self.parameterAsBoolean(parameters, self.NO_METADATA, context):
- arguments.append('-nomd')
+ arguments.append("-nomd")
- if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ''):
+ if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ""):
extra = self.parameterAsString(parameters, self.EXTRA, context)
arguments.append(extra)
inLayer = self.parameterAsVectorLayer(parameters, self.INPUT, context)
if inLayer is None:
- raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT))
+ raise QgsProcessingException(
+ self.invalidSourceError(parameters, self.INPUT)
+ )
- input_details = self.getOgrCompatibleSource(self.INPUT, parameters, context, feedback, executing)
+ input_details = self.getOgrCompatibleSource(
+ self.INPUT, parameters, context, feedback, executing
+ )
arguments.append(input_details.connection_string)
if not self.parameterAsBoolean(parameters, self.ALL_LAYERS, context):
arguments.append(input_details.layer_name)
@@ -128,30 +159,34 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True):
return [self.commandName(), GdalUtils.escapeAndJoin(arguments)]
def processAlgorithm(self, parameters, context, feedback):
- console_output = GdalUtils.runGdal(self.getConsoleCommands(parameters, context, feedback), feedback)
+ console_output = GdalUtils.runGdal(
+ self.getConsoleCommands(parameters, context, feedback), feedback
+ )
output = self.parameterAsFileOutput(parameters, self.OUTPUT, context)
- with open(output, 'w') as f:
- f.write('')
+ with open(output, "w") as f:
+ f.write("")
for s in console_output[1:]:
f.write(str(s))
- f.write(' ')
+ f.write(" ")
return {self.OUTPUT: output}
class ogrinfojson(ogrinfo):
- FEATURES = 'FEATURES'
+ FEATURES = "FEATURES"
def name(self):
- return 'ogrinfojson'
+ return "ogrinfojson"
def displayName(self):
- return self.tr('Vector information (JSON)')
+ return self.tr("Vector information (JSON)")
def processAlgorithm(self, parameters, context, feedback):
- console_output = GdalUtils.runGdal(self.getConsoleCommands(parameters, context, feedback))
+ console_output = GdalUtils.runGdal(
+ self.getConsoleCommands(parameters, context, feedback)
+ )
output = self.parameterAsFileOutput(parameters, self.OUTPUT, context)
- with open(output, 'w', newline='') as f:
+ with open(output, "w", newline="") as f:
for s in console_output[1:]:
f.write(str(s))
diff --git a/python/plugins/processing/algs/gdal/pansharp.py b/python/plugins/processing/algs/gdal/pansharp.py
index 5b62045737ae..b7e6c1cfe0bf 100644
--- a/python/plugins/processing/algs/gdal/pansharp.py
+++ b/python/plugins/processing/algs/gdal/pansharp.py
@@ -15,19 +15,21 @@
***************************************************************************
"""
-__author__ = 'Alexander Bruy'
-__date__ = 'March 2019'
-__copyright__ = '(C) 2019, Alexander Bruy'
+__author__ = "Alexander Bruy"
+__date__ = "March 2019"
+__copyright__ = "(C) 2019, Alexander Bruy"
import os
-from qgis.core import (QgsRasterFileWriter,
- QgsProcessingException,
- QgsProcessingParameterDefinition,
- QgsProcessingParameterRasterLayer,
- QgsProcessingParameterEnum,
- QgsProcessingParameterString,
- QgsProcessingParameterRasterDestination)
+from qgis.core import (
+ QgsRasterFileWriter,
+ QgsProcessingException,
+ QgsProcessingParameterDefinition,
+ QgsProcessingParameterRasterLayer,
+ QgsProcessingParameterEnum,
+ QgsProcessingParameterString,
+ QgsProcessingParameterRasterDestination,
+)
from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm
from processing.algs.gdal.GdalUtils import GdalUtils
@@ -37,107 +39,141 @@
class pansharp(GdalAlgorithm):
- SPECTRAL = 'SPECTRAL'
- PANCHROMATIC = 'PANCHROMATIC'
- RESAMPLING = 'RESAMPLING'
- OPTIONS = 'OPTIONS'
- EXTRA = 'EXTRA'
- OUTPUT = 'OUTPUT'
+ SPECTRAL = "SPECTRAL"
+ PANCHROMATIC = "PANCHROMATIC"
+ RESAMPLING = "RESAMPLING"
+ OPTIONS = "OPTIONS"
+ EXTRA = "EXTRA"
+ OUTPUT = "OUTPUT"
def __init__(self):
super().__init__()
def initAlgorithm(self, config=None):
- self.methods = ((self.tr('Nearest Neighbour'), 'nearest'),
- (self.tr('Bilinear (2x2 Kernel)'), 'bilinear'),
- (self.tr('Cubic (4x4 Kernel)'), 'cubic'),
- (self.tr('Cubic B-Spline (4x4 Kernel)'), 'cubicspline'),
- (self.tr('Lanczos (6x6 Kernel)'), 'lanczos'),
- (self.tr('Average'), 'average'))
-
- self.addParameter(QgsProcessingParameterRasterLayer(self.SPECTRAL,
- self.tr('Spectral dataset')))
- self.addParameter(QgsProcessingParameterRasterLayer(self.PANCHROMATIC,
- self.tr('Panchromatic dataset')))
-
- resampling_param = QgsProcessingParameterEnum(self.RESAMPLING,
- self.tr('Resampling algorithm'),
- options=[i[0] for i in self.methods],
- defaultValue=2)
- resampling_param.setFlags(resampling_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
+ self.methods = (
+ (self.tr("Nearest Neighbour"), "nearest"),
+ (self.tr("Bilinear (2x2 Kernel)"), "bilinear"),
+ (self.tr("Cubic (4x4 Kernel)"), "cubic"),
+ (self.tr("Cubic B-Spline (4x4 Kernel)"), "cubicspline"),
+ (self.tr("Lanczos (6x6 Kernel)"), "lanczos"),
+ (self.tr("Average"), "average"),
+ )
+
+ self.addParameter(
+ QgsProcessingParameterRasterLayer(
+ self.SPECTRAL, self.tr("Spectral dataset")
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterRasterLayer(
+ self.PANCHROMATIC, self.tr("Panchromatic dataset")
+ )
+ )
+
+ resampling_param = QgsProcessingParameterEnum(
+ self.RESAMPLING,
+ self.tr("Resampling algorithm"),
+ options=[i[0] for i in self.methods],
+ defaultValue=2,
+ )
+ resampling_param.setFlags(
+ resampling_param.flags()
+ | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
self.addParameter(resampling_param)
- options_param = QgsProcessingParameterString(self.OPTIONS,
- self.tr('Additional creation options'),
- defaultValue='',
- optional=True)
- options_param.setFlags(options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
- options_param.setMetadata({'widget_wrapper': {'widget_type': 'rasteroptions'}})
+ options_param = QgsProcessingParameterString(
+ self.OPTIONS,
+ self.tr("Additional creation options"),
+ defaultValue="",
+ optional=True,
+ )
+ options_param.setFlags(
+ options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
+ options_param.setMetadata({"widget_wrapper": {"widget_type": "rasteroptions"}})
self.addParameter(options_param)
- extra_param = QgsProcessingParameterString(self.EXTRA,
- self.tr('Additional command-line parameters'),
- defaultValue=None,
- optional=True)
- extra_param.setFlags(extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
+ extra_param = QgsProcessingParameterString(
+ self.EXTRA,
+ self.tr("Additional command-line parameters"),
+ defaultValue=None,
+ optional=True,
+ )
+ extra_param.setFlags(
+ extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
self.addParameter(extra_param)
- self.addParameter(QgsProcessingParameterRasterDestination(self.OUTPUT,
- self.tr('Output')))
+ self.addParameter(
+ QgsProcessingParameterRasterDestination(self.OUTPUT, self.tr("Output"))
+ )
def name(self):
- return 'pansharp'
+ return "pansharp"
def displayName(self):
- return self.tr('Pansharpening')
+ return self.tr("Pansharpening")
def group(self):
- return self.tr('Raster miscellaneous')
+ return self.tr("Raster miscellaneous")
def groupId(self):
- return 'rastermiscellaneous'
+ return "rastermiscellaneous"
def commandName(self):
- return 'gdal_pansharpen'
+ return "gdal_pansharpen"
def getConsoleCommands(self, parameters, context, feedback, executing=True):
spectral = self.parameterAsRasterLayer(parameters, self.SPECTRAL, context)
if spectral is None:
- raise QgsProcessingException(self.invalidRasterError(parameters, self.SPECTRAL))
+ raise QgsProcessingException(
+ self.invalidRasterError(parameters, self.SPECTRAL)
+ )
spectral_input_details = GdalUtils.gdal_connection_details_from_layer(spectral)
- panchromatic = self.parameterAsRasterLayer(parameters, self.PANCHROMATIC, context)
+ panchromatic = self.parameterAsRasterLayer(
+ parameters, self.PANCHROMATIC, context
+ )
if panchromatic is None:
- raise QgsProcessingException(self.invalidRasterError(parameters, self.PANCHROMATIC))
+ raise QgsProcessingException(
+ self.invalidRasterError(parameters, self.PANCHROMATIC)
+ )
panchromatic_input_details = GdalUtils.gdal_connection_details_from_layer(
- panchromatic)
+ panchromatic
+ )
out = self.parameterAsOutputLayer(parameters, self.OUTPUT, context)
self.setOutputValue(self.OUTPUT, out)
output_format = QgsRasterFileWriter.driverForExtension(os.path.splitext(out)[1])
if not output_format:
- raise QgsProcessingException(self.tr('Output format is invalid'))
+ raise QgsProcessingException(self.tr("Output format is invalid"))
arguments = [
panchromatic_input_details.connection_string,
spectral_input_details.connection_string,
out,
- '-r',
+ "-r",
self.methods[self.parameterAsEnum(parameters, self.RESAMPLING, context)][1],
- '-of',
- output_format
+ "-of",
+ output_format,
]
if panchromatic_input_details.credential_options:
- arguments.extend(panchromatic_input_details.credential_options_as_arguments())
+ arguments.extend(
+ panchromatic_input_details.credential_options_as_arguments()
+ )
options = self.parameterAsString(parameters, self.OPTIONS, context)
if options:
arguments.extend(GdalUtils.parseCreationOptions(options))
- if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ''):
+ if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ""):
extra = self.parameterAsString(parameters, self.EXTRA, context)
arguments.append(extra)
- return [self.commandName() + ('.bat' if isWindows() else '.py'), GdalUtils.escapeAndJoin(arguments)]
+ return [
+ self.commandName() + (".bat" if isWindows() else ".py"),
+ GdalUtils.escapeAndJoin(arguments),
+ ]
diff --git a/python/plugins/processing/algs/gdal/pct2rgb.py b/python/plugins/processing/algs/gdal/pct2rgb.py
index e6b91ab71e3a..3410c0a53109 100644
--- a/python/plugins/processing/algs/gdal/pct2rgb.py
+++ b/python/plugins/processing/algs/gdal/pct2rgb.py
@@ -15,20 +15,22 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'August 2012'
-__copyright__ = '(C) 2012, Victor Olaya'
+__author__ = "Victor Olaya"
+__date__ = "August 2012"
+__copyright__ = "(C) 2012, Victor Olaya"
import os
from qgis.PyQt.QtGui import QIcon
-from qgis.core import (QgsRasterFileWriter,
- QgsProcessingException,
- QgsProcessingParameterRasterLayer,
- QgsProcessingParameterBand,
- QgsProcessingParameterBoolean,
- QgsProcessingParameterRasterDestination)
+from qgis.core import (
+ QgsRasterFileWriter,
+ QgsProcessingException,
+ QgsProcessingParameterRasterLayer,
+ QgsProcessingParameterBand,
+ QgsProcessingParameterBoolean,
+ QgsProcessingParameterRasterDestination,
+)
from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm
from processing.tools.system import isWindows
from processing.algs.gdal.GdalUtils import GdalUtils
@@ -37,70 +39,86 @@
class pct2rgb(GdalAlgorithm):
- INPUT = 'INPUT'
- BAND = 'BAND'
- RGBA = 'RGBA'
- OUTPUT = 'OUTPUT'
+ INPUT = "INPUT"
+ BAND = "BAND"
+ RGBA = "RGBA"
+ OUTPUT = "OUTPUT"
def __init__(self):
super().__init__()
def initAlgorithm(self, config=None):
- self.addParameter(QgsProcessingParameterRasterLayer(self.INPUT, self.tr('Input layer')))
- self.addParameter(QgsProcessingParameterBand(self.BAND,
- self.tr('Band number'),
- 1,
- parentLayerParameterName=self.INPUT))
- self.addParameter(QgsProcessingParameterBoolean(self.RGBA,
- self.tr('Generate a RGBA file'),
- defaultValue=False))
- self.addParameter(QgsProcessingParameterRasterDestination(self.OUTPUT, self.tr('PCT to RGB')))
+ self.addParameter(
+ QgsProcessingParameterRasterLayer(self.INPUT, self.tr("Input layer"))
+ )
+ self.addParameter(
+ QgsProcessingParameterBand(
+ self.BAND,
+ self.tr("Band number"),
+ 1,
+ parentLayerParameterName=self.INPUT,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterBoolean(
+ self.RGBA, self.tr("Generate a RGBA file"), defaultValue=False
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterRasterDestination(self.OUTPUT, self.tr("PCT to RGB"))
+ )
def name(self):
- return 'pcttorgb'
+ return "pcttorgb"
def displayName(self):
- return self.tr('PCT to RGB')
+ return self.tr("PCT to RGB")
def group(self):
- return self.tr('Raster conversion')
+ return self.tr("Raster conversion")
def groupId(self):
- return 'rasterconversion'
+ return "rasterconversion"
def icon(self):
- return QIcon(os.path.join(pluginPath, 'images', 'gdaltools', '8-to-24-bits.png'))
+ return QIcon(
+ os.path.join(pluginPath, "images", "gdaltools", "8-to-24-bits.png")
+ )
def commandName(self):
- return 'pct2rgb'
+ return "pct2rgb"
def getConsoleCommands(self, parameters, context, feedback, executing=True):
inLayer = self.parameterAsRasterLayer(parameters, self.INPUT, context)
if inLayer is None:
- raise QgsProcessingException(self.invalidRasterError(parameters, self.INPUT))
- input_details = GdalUtils.gdal_connection_details_from_layer(
- inLayer)
+ raise QgsProcessingException(
+ self.invalidRasterError(parameters, self.INPUT)
+ )
+ input_details = GdalUtils.gdal_connection_details_from_layer(inLayer)
out = self.parameterAsOutputLayer(parameters, self.OUTPUT, context)
self.setOutputValue(self.OUTPUT, out)
output_format = QgsRasterFileWriter.driverForExtension(os.path.splitext(out)[1])
if not output_format:
- raise QgsProcessingException(self.tr('Output format is invalid'))
+ raise QgsProcessingException(self.tr("Output format is invalid"))
arguments = [
input_details.connection_string,
out,
- '-of',
+ "-of",
output_format,
- '-b',
+ "-b",
str(self.parameterAsInt(parameters, self.BAND, context)),
]
if self.parameterAsBoolean(parameters, self.RGBA, context):
- arguments.append('-rgba')
+ arguments.append("-rgba")
if input_details.credential_options:
arguments.extend(input_details.credential_options_as_arguments())
- return [self.commandName() + ('.bat' if isWindows() else '.py'), GdalUtils.escapeAndJoin(arguments)]
+ return [
+ self.commandName() + (".bat" if isWindows() else ".py"),
+ GdalUtils.escapeAndJoin(arguments),
+ ]
diff --git a/python/plugins/processing/algs/gdal/polygonize.py b/python/plugins/processing/algs/gdal/polygonize.py
index 62c22192c733..4419e0dfdf74 100644
--- a/python/plugins/processing/algs/gdal/polygonize.py
+++ b/python/plugins/processing/algs/gdal/polygonize.py
@@ -15,22 +15,24 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'August 2012'
-__copyright__ = '(C) 2012, Victor Olaya'
+__author__ = "Victor Olaya"
+__date__ = "August 2012"
+__copyright__ = "(C) 2012, Victor Olaya"
import os
from qgis.PyQt.QtGui import QIcon
-from qgis.core import (QgsProcessing,
- QgsProcessingException,
- QgsProcessingParameterDefinition,
- QgsProcessingParameterRasterLayer,
- QgsProcessingParameterBand,
- QgsProcessingParameterString,
- QgsProcessingParameterBoolean,
- QgsProcessingParameterVectorDestination)
+from qgis.core import (
+ QgsProcessing,
+ QgsProcessingException,
+ QgsProcessingParameterDefinition,
+ QgsProcessingParameterRasterLayer,
+ QgsProcessingParameterBand,
+ QgsProcessingParameterString,
+ QgsProcessingParameterBoolean,
+ QgsProcessingParameterVectorDestination,
+)
from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm
from processing.tools.system import isWindows
from processing.algs.gdal.GdalUtils import GdalUtils
@@ -39,77 +41,98 @@
class polygonize(GdalAlgorithm):
- INPUT = 'INPUT'
- BAND = 'BAND'
- FIELD = 'FIELD'
- EIGHT_CONNECTEDNESS = 'EIGHT_CONNECTEDNESS'
- EXTRA = 'EXTRA'
- OUTPUT = 'OUTPUT'
+ INPUT = "INPUT"
+ BAND = "BAND"
+ FIELD = "FIELD"
+ EIGHT_CONNECTEDNESS = "EIGHT_CONNECTEDNESS"
+ EXTRA = "EXTRA"
+ OUTPUT = "OUTPUT"
def __init__(self):
super().__init__()
def initAlgorithm(self, config=None):
- self.addParameter(QgsProcessingParameterRasterLayer(self.INPUT, self.tr('Input layer')))
- self.addParameter(QgsProcessingParameterBand(self.BAND,
- self.tr('Band number'),
- 1,
- parentLayerParameterName=self.INPUT))
- self.addParameter(QgsProcessingParameterString(self.FIELD,
- self.tr('Name of the field to create'),
- defaultValue='DN'))
- self.addParameter(QgsProcessingParameterBoolean(self.EIGHT_CONNECTEDNESS,
- self.tr('Use 8-connectedness'),
- defaultValue=False))
-
- extra_param = QgsProcessingParameterString(self.EXTRA,
- self.tr('Additional command-line parameters'),
- defaultValue=None,
- optional=True)
- extra_param.setFlags(extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
+ self.addParameter(
+ QgsProcessingParameterRasterLayer(self.INPUT, self.tr("Input layer"))
+ )
+ self.addParameter(
+ QgsProcessingParameterBand(
+ self.BAND,
+ self.tr("Band number"),
+ 1,
+ parentLayerParameterName=self.INPUT,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterString(
+ self.FIELD, self.tr("Name of the field to create"), defaultValue="DN"
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterBoolean(
+ self.EIGHT_CONNECTEDNESS,
+ self.tr("Use 8-connectedness"),
+ defaultValue=False,
+ )
+ )
+
+ extra_param = QgsProcessingParameterString(
+ self.EXTRA,
+ self.tr("Additional command-line parameters"),
+ defaultValue=None,
+ optional=True,
+ )
+ extra_param.setFlags(
+ extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
self.addParameter(extra_param)
- self.addParameter(QgsProcessingParameterVectorDestination(self.OUTPUT,
- self.tr('Vectorized'),
- QgsProcessing.SourceType.TypeVectorPolygon))
+ self.addParameter(
+ QgsProcessingParameterVectorDestination(
+ self.OUTPUT,
+ self.tr("Vectorized"),
+ QgsProcessing.SourceType.TypeVectorPolygon,
+ )
+ )
def name(self):
- return 'polygonize'
+ return "polygonize"
def displayName(self):
- return self.tr('Polygonize (raster to vector)')
+ return self.tr("Polygonize (raster to vector)")
def group(self):
- return self.tr('Raster conversion')
+ return self.tr("Raster conversion")
def groupId(self):
- return 'rasterconversion'
+ return "rasterconversion"
def icon(self):
- return QIcon(os.path.join(pluginPath, 'images', 'gdaltools', 'polygonize.png'))
+ return QIcon(os.path.join(pluginPath, "images", "gdaltools", "polygonize.png"))
def commandName(self):
- return 'gdal_polygonize'
+ return "gdal_polygonize"
def getConsoleCommands(self, parameters, context, feedback, executing=True):
arguments = []
if self.parameterAsBoolean(parameters, self.EIGHT_CONNECTEDNESS, context):
- arguments.append('-8')
+ arguments.append("-8")
- if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ''):
+ if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ""):
extra = self.parameterAsString(parameters, self.EXTRA, context)
arguments.append(extra)
inLayer = self.parameterAsRasterLayer(parameters, self.INPUT, context)
if inLayer is None:
- raise QgsProcessingException(self.invalidRasterError(parameters, self.INPUT))
- input_details = GdalUtils.gdal_connection_details_from_layer(
- inLayer)
+ raise QgsProcessingException(
+ self.invalidRasterError(parameters, self.INPUT)
+ )
+ input_details = GdalUtils.gdal_connection_details_from_layer(inLayer)
arguments.append(input_details.connection_string)
- arguments.append('-b')
+ arguments.append("-b")
arguments.append(str(self.parameterAsInt(parameters, self.BAND, context)))
outFile = self.parameterAsOutputLayer(parameters, self.OUTPUT, context)
@@ -117,7 +140,7 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True):
output_details = GdalUtils.gdal_connection_details_from_uri(outFile, context)
if output_details.format:
- arguments.append(f'-f {output_details.format}')
+ arguments.append(f"-f {output_details.format}")
arguments.append(output_details.connection_string)
@@ -129,4 +152,7 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True):
if input_details.credential_options:
arguments.extend(input_details.credential_options_as_arguments())
- return [self.commandName() + ('.bat' if isWindows() else '.py'), GdalUtils.escapeAndJoin(arguments)]
+ return [
+ self.commandName() + (".bat" if isWindows() else ".py"),
+ GdalUtils.escapeAndJoin(arguments),
+ ]
diff --git a/python/plugins/processing/algs/gdal/proximity.py b/python/plugins/processing/algs/gdal/proximity.py
index 44cfe6dbf6b2..acc21fa4b38b 100644
--- a/python/plugins/processing/algs/gdal/proximity.py
+++ b/python/plugins/processing/algs/gdal/proximity.py
@@ -15,23 +15,25 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'August 2012'
-__copyright__ = '(C) 2012, Victor Olaya'
+__author__ = "Victor Olaya"
+__date__ = "August 2012"
+__copyright__ = "(C) 2012, Victor Olaya"
import os
from qgis.PyQt.QtGui import QIcon
-from qgis.core import (QgsRasterFileWriter,
- QgsProcessingException,
- QgsProcessingParameterDefinition,
- QgsProcessingParameterRasterLayer,
- QgsProcessingParameterBand,
- QgsProcessingParameterEnum,
- QgsProcessingParameterString,
- QgsProcessingParameterNumber,
- QgsProcessingParameterRasterDestination)
+from qgis.core import (
+ QgsRasterFileWriter,
+ QgsProcessingException,
+ QgsProcessingParameterDefinition,
+ QgsProcessingParameterRasterLayer,
+ QgsProcessingParameterBand,
+ QgsProcessingParameterEnum,
+ QgsProcessingParameterString,
+ QgsProcessingParameterNumber,
+ QgsProcessingParameterRasterDestination,
+)
from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm
from processing.algs.gdal.GdalUtils import GdalUtils
@@ -41,108 +43,168 @@
class proximity(GdalAlgorithm):
- INPUT = 'INPUT'
- BAND = 'BAND'
- VALUES = 'VALUES'
- MAX_DISTANCE = 'MAX_DISTANCE'
- REPLACE = 'REPLACE'
- UNITS = 'UNITS'
- NODATA = 'NODATA'
- OPTIONS = 'OPTIONS'
- EXTRA = 'EXTRA'
- DATA_TYPE = 'DATA_TYPE'
- OUTPUT = 'OUTPUT'
-
- TYPES = ['Byte', 'Int16', 'UInt16', 'UInt32', 'Int32', 'Float32', 'Float64', 'CInt16', 'CInt32', 'CFloat32', 'CFloat64', 'Int8']
+ INPUT = "INPUT"
+ BAND = "BAND"
+ VALUES = "VALUES"
+ MAX_DISTANCE = "MAX_DISTANCE"
+ REPLACE = "REPLACE"
+ UNITS = "UNITS"
+ NODATA = "NODATA"
+ OPTIONS = "OPTIONS"
+ EXTRA = "EXTRA"
+ DATA_TYPE = "DATA_TYPE"
+ OUTPUT = "OUTPUT"
+
+ TYPES = [
+ "Byte",
+ "Int16",
+ "UInt16",
+ "UInt32",
+ "Int32",
+ "Float32",
+ "Float64",
+ "CInt16",
+ "CInt32",
+ "CFloat32",
+ "CFloat64",
+ "Int8",
+ ]
def icon(self):
- return QIcon(os.path.join(pluginPath, 'images', 'gdaltools', 'proximity.png'))
+ return QIcon(os.path.join(pluginPath, "images", "gdaltools", "proximity.png"))
def __init__(self):
super().__init__()
def initAlgorithm(self, config=None):
- self.distanceUnits = ((self.tr('Georeferenced coordinates'), 'GEO'),
- (self.tr('Pixel coordinates'), 'PIXEL'))
-
- self.addParameter(QgsProcessingParameterRasterLayer(self.INPUT,
- self.tr('Input layer')))
- self.addParameter(QgsProcessingParameterBand(self.BAND,
- self.tr('Band number'),
- 1,
- parentLayerParameterName=self.INPUT))
- self.addParameter(QgsProcessingParameterString(self.VALUES,
- self.tr('A list of pixel values in the source image to be considered target pixels'),
- optional=True))
- self.addParameter(QgsProcessingParameterEnum(self.UNITS,
- self.tr('Distance units'),
- options=[i[0] for i in self.distanceUnits],
- allowMultiple=False,
- defaultValue=1))
- self.addParameter(QgsProcessingParameterNumber(self.MAX_DISTANCE,
- self.tr('The maximum distance to be generated'),
- type=QgsProcessingParameterNumber.Type.Double,
- minValue=0.0,
- defaultValue=0.0,
- optional=True))
- self.addParameter(QgsProcessingParameterNumber(self.REPLACE,
- self.tr('Value to be applied to all pixels that are within the -maxdist of target pixels'),
- type=QgsProcessingParameterNumber.Type.Double,
- defaultValue=0.0,
- optional=True))
- self.addParameter(QgsProcessingParameterNumber(self.NODATA,
- self.tr('Nodata value to use for the destination proximity raster'),
- type=QgsProcessingParameterNumber.Type.Double,
- defaultValue=0.0,
- optional=True))
-
- options_param = QgsProcessingParameterString(self.OPTIONS,
- self.tr('Additional creation options'),
- defaultValue='',
- optional=True)
- options_param.setFlags(options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
- options_param.setMetadata({'widget_wrapper': {'widget_type': 'rasteroptions'}})
+ self.distanceUnits = (
+ (self.tr("Georeferenced coordinates"), "GEO"),
+ (self.tr("Pixel coordinates"), "PIXEL"),
+ )
+
+ self.addParameter(
+ QgsProcessingParameterRasterLayer(self.INPUT, self.tr("Input layer"))
+ )
+ self.addParameter(
+ QgsProcessingParameterBand(
+ self.BAND,
+ self.tr("Band number"),
+ 1,
+ parentLayerParameterName=self.INPUT,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterString(
+ self.VALUES,
+ self.tr(
+ "A list of pixel values in the source image to be considered target pixels"
+ ),
+ optional=True,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterEnum(
+ self.UNITS,
+ self.tr("Distance units"),
+ options=[i[0] for i in self.distanceUnits],
+ allowMultiple=False,
+ defaultValue=1,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterNumber(
+ self.MAX_DISTANCE,
+ self.tr("The maximum distance to be generated"),
+ type=QgsProcessingParameterNumber.Type.Double,
+ minValue=0.0,
+ defaultValue=0.0,
+ optional=True,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterNumber(
+ self.REPLACE,
+ self.tr(
+ "Value to be applied to all pixels that are within the -maxdist of target pixels"
+ ),
+ type=QgsProcessingParameterNumber.Type.Double,
+ defaultValue=0.0,
+ optional=True,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterNumber(
+ self.NODATA,
+ self.tr("Nodata value to use for the destination proximity raster"),
+ type=QgsProcessingParameterNumber.Type.Double,
+ defaultValue=0.0,
+ optional=True,
+ )
+ )
+
+ options_param = QgsProcessingParameterString(
+ self.OPTIONS,
+ self.tr("Additional creation options"),
+ defaultValue="",
+ optional=True,
+ )
+ options_param.setFlags(
+ options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
+ options_param.setMetadata({"widget_wrapper": {"widget_type": "rasteroptions"}})
self.addParameter(options_param)
- extra_param = QgsProcessingParameterString(self.EXTRA,
- self.tr('Additional command-line parameters'),
- defaultValue=None,
- optional=True)
- extra_param.setFlags(extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
+ extra_param = QgsProcessingParameterString(
+ self.EXTRA,
+ self.tr("Additional command-line parameters"),
+ defaultValue=None,
+ optional=True,
+ )
+ extra_param.setFlags(
+ extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
self.addParameter(extra_param)
- dataType_param = QgsProcessingParameterEnum(self.DATA_TYPE,
- self.tr('Output data type'),
- self.TYPES,
- allowMultiple=False,
- defaultValue=5)
- dataType_param.setFlags(dataType_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
+ dataType_param = QgsProcessingParameterEnum(
+ self.DATA_TYPE,
+ self.tr("Output data type"),
+ self.TYPES,
+ allowMultiple=False,
+ defaultValue=5,
+ )
+ dataType_param.setFlags(
+ dataType_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
self.addParameter(dataType_param)
- self.addParameter(QgsProcessingParameterRasterDestination(self.OUTPUT,
- self.tr('Proximity map')))
+ self.addParameter(
+ QgsProcessingParameterRasterDestination(
+ self.OUTPUT, self.tr("Proximity map")
+ )
+ )
def name(self):
- return 'proximity'
+ return "proximity"
def displayName(self):
- return self.tr('Proximity (raster distance)')
+ return self.tr("Proximity (raster distance)")
def group(self):
- return self.tr('Raster analysis')
+ return self.tr("Raster analysis")
def groupId(self):
- return 'rasteranalysis'
+ return "rasteranalysis"
def commandName(self):
- return 'gdal_proximity'
+ return "gdal_proximity"
def getConsoleCommands(self, parameters, context, feedback, executing=True):
inLayer = self.parameterAsRasterLayer(parameters, self.INPUT, context)
if inLayer is None:
- raise QgsProcessingException(self.invalidRasterError(parameters, self.INPUT))
- input_details = GdalUtils.gdal_connection_details_from_layer(
- inLayer)
+ raise QgsProcessingException(
+ self.invalidRasterError(parameters, self.INPUT)
+ )
+ input_details = GdalUtils.gdal_connection_details_from_layer(inLayer)
distance = self.parameterAsDouble(parameters, self.MAX_DISTANCE, context)
replaceValue = self.parameterAsDouble(parameters, self.REPLACE, context)
@@ -155,47 +217,50 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True):
self.setOutputValue(self.OUTPUT, out)
arguments = [
- '-srcband',
+ "-srcband",
str(self.parameterAsInt(parameters, self.BAND, context)),
- '-distunits',
-
- self.distanceUnits[self.parameterAsEnum(parameters, self.UNITS, context)][1]
+ "-distunits",
+ self.distanceUnits[self.parameterAsEnum(parameters, self.UNITS, context)][
+ 1
+ ],
]
values = self.parameterAsString(parameters, self.VALUES, context)
if values:
- arguments.append('-values')
+ arguments.append("-values")
arguments.append(values)
if distance:
- arguments.append('-maxdist')
+ arguments.append("-maxdist")
arguments.append(str(distance))
if nodata is not None:
- arguments.append('-nodata')
+ arguments.append("-nodata")
arguments.append(str(nodata))
if replaceValue:
- arguments.append('-fixed-buf-val')
+ arguments.append("-fixed-buf-val")
arguments.append(str(replaceValue))
data_type = self.parameterAsEnum(parameters, self.DATA_TYPE, context)
- if self.TYPES[data_type] == 'Int8' and GdalUtils.version() < 3070000:
- raise QgsProcessingException(self.tr('Int8 data type requires GDAL version 3.7 or later'))
+ if self.TYPES[data_type] == "Int8" and GdalUtils.version() < 3070000:
+ raise QgsProcessingException(
+ self.tr("Int8 data type requires GDAL version 3.7 or later")
+ )
- arguments.append('-ot ' + self.TYPES[data_type])
+ arguments.append("-ot " + self.TYPES[data_type])
output_format = QgsRasterFileWriter.driverForExtension(os.path.splitext(out)[1])
if not output_format:
- raise QgsProcessingException(self.tr('Output format is invalid'))
+ raise QgsProcessingException(self.tr("Output format is invalid"))
- arguments.append('-of')
+ arguments.append("-of")
arguments.append(output_format)
if options:
arguments.extend(GdalUtils.parseCreationOptions(options))
- if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ''):
+ if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ""):
extra = self.parameterAsString(parameters, self.EXTRA, context)
arguments.append(extra)
@@ -205,4 +270,7 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True):
if input_details.credential_options:
arguments.extend(input_details.credential_options_as_arguments())
- return [self.commandName() + ('.bat' if isWindows() else '.py'), GdalUtils.escapeAndJoin(arguments)]
+ return [
+ self.commandName() + (".bat" if isWindows() else ".py"),
+ GdalUtils.escapeAndJoin(arguments),
+ ]
diff --git a/python/plugins/processing/algs/gdal/rasterize.py b/python/plugins/processing/algs/gdal/rasterize.py
index cacd5369b323..0dda96cd9e3d 100644
--- a/python/plugins/processing/algs/gdal/rasterize.py
+++ b/python/plugins/processing/algs/gdal/rasterize.py
@@ -15,25 +15,28 @@
***************************************************************************
"""
-__author__ = 'Alexander Bruy'
-__date__ = 'September 2013'
-__copyright__ = '(C) 2013, Alexander Bruy'
+__author__ = "Alexander Bruy"
+__date__ = "September 2013"
+__copyright__ = "(C) 2013, Alexander Bruy"
import os
from qgis.PyQt.QtGui import QIcon
-from qgis.core import (QgsRasterFileWriter,
- QgsProcessingException,
- QgsProcessingParameterDefinition,
- QgsProcessingParameterFeatureSource,
- QgsProcessingParameterField,
- QgsProcessingParameterNumber,
- QgsProcessingParameterString,
- QgsProcessingParameterEnum,
- QgsProcessingParameterExtent,
- QgsProcessingParameterBoolean,
- QgsProcessingParameterRasterDestination, NULL)
+from qgis.core import (
+ QgsRasterFileWriter,
+ QgsProcessingException,
+ QgsProcessingParameterDefinition,
+ QgsProcessingParameterFeatureSource,
+ QgsProcessingParameterField,
+ QgsProcessingParameterNumber,
+ QgsProcessingParameterString,
+ QgsProcessingParameterEnum,
+ QgsProcessingParameterExtent,
+ QgsProcessingParameterBoolean,
+ QgsProcessingParameterRasterDestination,
+ NULL,
+)
from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm
from processing.algs.gdal.GdalUtils import GdalUtils
@@ -41,203 +44,270 @@
class rasterize(GdalAlgorithm):
- INPUT = 'INPUT'
- FIELD = 'FIELD'
- BURN = 'BURN'
- USE_Z = 'USE_Z'
- WIDTH = 'WIDTH'
- HEIGHT = 'HEIGHT'
- UNITS = 'UNITS'
- NODATA = 'NODATA'
- EXTENT = 'EXTENT'
- INIT = 'INIT'
- INVERT = 'INVERT'
- ALL_TOUCH = 'ALL_TOUCH'
- OPTIONS = 'OPTIONS'
- DATA_TYPE = 'DATA_TYPE'
- EXTRA = 'EXTRA'
- OUTPUT = 'OUTPUT'
-
- TYPES = ['Byte', 'Int16', 'UInt16', 'UInt32', 'Int32', 'Float32', 'Float64', 'CInt16', 'CInt32', 'CFloat32', 'CFloat64', 'Int8']
+ INPUT = "INPUT"
+ FIELD = "FIELD"
+ BURN = "BURN"
+ USE_Z = "USE_Z"
+ WIDTH = "WIDTH"
+ HEIGHT = "HEIGHT"
+ UNITS = "UNITS"
+ NODATA = "NODATA"
+ EXTENT = "EXTENT"
+ INIT = "INIT"
+ INVERT = "INVERT"
+ ALL_TOUCH = "ALL_TOUCH"
+ OPTIONS = "OPTIONS"
+ DATA_TYPE = "DATA_TYPE"
+ EXTRA = "EXTRA"
+ OUTPUT = "OUTPUT"
+
+ TYPES = [
+ "Byte",
+ "Int16",
+ "UInt16",
+ "UInt32",
+ "Int32",
+ "Float32",
+ "Float64",
+ "CInt16",
+ "CInt32",
+ "CFloat32",
+ "CFloat64",
+ "Int8",
+ ]
def __init__(self):
super().__init__()
def initAlgorithm(self, config=None):
- self.units = [self.tr("Pixels"),
- self.tr("Georeferenced units")]
-
- self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT,
- self.tr('Input layer')))
- self.addParameter(QgsProcessingParameterField(self.FIELD,
- self.tr('Field to use for a burn-in value'),
- None,
- self.INPUT,
- QgsProcessingParameterField.DataType.Numeric,
- optional=True))
- self.addParameter(QgsProcessingParameterNumber(self.BURN,
- self.tr('A fixed value to burn'),
- type=QgsProcessingParameterNumber.Type.Double,
- defaultValue=0.0,
- optional=True))
- self.addParameter(QgsProcessingParameterBoolean(self.USE_Z,
- self.tr('Burn value extracted from the "Z" values of the feature'),
- defaultValue=False,
- optional=True))
- self.addParameter(QgsProcessingParameterEnum(self.UNITS,
- self.tr('Output raster size units'),
- self.units))
- self.addParameter(QgsProcessingParameterNumber(self.WIDTH,
- self.tr('Width/Horizontal resolution'),
- type=QgsProcessingParameterNumber.Type.Double,
- minValue=0.0,
- defaultValue=0.0))
- self.addParameter(QgsProcessingParameterNumber(self.HEIGHT,
- self.tr('Height/Vertical resolution'),
- type=QgsProcessingParameterNumber.Type.Double,
- minValue=0.0,
- defaultValue=0.0))
- self.addParameter(QgsProcessingParameterExtent(self.EXTENT,
- self.tr('Output extent'),
- optional=True))
- nodataParam = QgsProcessingParameterNumber(self.NODATA,
- self.tr('Assign a specified NoData value to output bands'),
- type=QgsProcessingParameterNumber.Type.Double,
- optional=True)
+ self.units = [self.tr("Pixels"), self.tr("Georeferenced units")]
+
+ self.addParameter(
+ QgsProcessingParameterFeatureSource(self.INPUT, self.tr("Input layer"))
+ )
+ self.addParameter(
+ QgsProcessingParameterField(
+ self.FIELD,
+ self.tr("Field to use for a burn-in value"),
+ None,
+ self.INPUT,
+ QgsProcessingParameterField.DataType.Numeric,
+ optional=True,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterNumber(
+ self.BURN,
+ self.tr("A fixed value to burn"),
+ type=QgsProcessingParameterNumber.Type.Double,
+ defaultValue=0.0,
+ optional=True,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterBoolean(
+ self.USE_Z,
+ self.tr('Burn value extracted from the "Z" values of the feature'),
+ defaultValue=False,
+ optional=True,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterEnum(
+ self.UNITS, self.tr("Output raster size units"), self.units
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterNumber(
+ self.WIDTH,
+ self.tr("Width/Horizontal resolution"),
+ type=QgsProcessingParameterNumber.Type.Double,
+ minValue=0.0,
+ defaultValue=0.0,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterNumber(
+ self.HEIGHT,
+ self.tr("Height/Vertical resolution"),
+ type=QgsProcessingParameterNumber.Type.Double,
+ minValue=0.0,
+ defaultValue=0.0,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterExtent(
+ self.EXTENT, self.tr("Output extent"), optional=True
+ )
+ )
+ nodataParam = QgsProcessingParameterNumber(
+ self.NODATA,
+ self.tr("Assign a specified NoData value to output bands"),
+ type=QgsProcessingParameterNumber.Type.Double,
+ optional=True,
+ )
nodataParam.setGuiDefaultValueOverride(NULL)
self.addParameter(nodataParam)
- options_param = QgsProcessingParameterString(self.OPTIONS,
- self.tr('Additional creation options'),
- defaultValue='',
- optional=True)
- options_param.setFlags(options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
- options_param.setMetadata({'widget_wrapper': {'widget_type': 'rasteroptions'}})
+ options_param = QgsProcessingParameterString(
+ self.OPTIONS,
+ self.tr("Additional creation options"),
+ defaultValue="",
+ optional=True,
+ )
+ options_param.setFlags(
+ options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
+ options_param.setMetadata({"widget_wrapper": {"widget_type": "rasteroptions"}})
self.addParameter(options_param)
- dataType_param = QgsProcessingParameterEnum(self.DATA_TYPE,
- self.tr('Output data type'),
- self.TYPES,
- allowMultiple=False,
- defaultValue=5)
- dataType_param.setFlags(dataType_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
+ dataType_param = QgsProcessingParameterEnum(
+ self.DATA_TYPE,
+ self.tr("Output data type"),
+ self.TYPES,
+ allowMultiple=False,
+ defaultValue=5,
+ )
+ dataType_param.setFlags(
+ dataType_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
self.addParameter(dataType_param)
- init_param = QgsProcessingParameterNumber(self.INIT,
- self.tr('Pre-initialize the output image with value'),
- type=QgsProcessingParameterNumber.Type.Double,
- optional=True)
- init_param.setFlags(init_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
+ init_param = QgsProcessingParameterNumber(
+ self.INIT,
+ self.tr("Pre-initialize the output image with value"),
+ type=QgsProcessingParameterNumber.Type.Double,
+ optional=True,
+ )
+ init_param.setFlags(
+ init_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
self.addParameter(init_param)
- invert_param = QgsProcessingParameterBoolean(self.INVERT,
- self.tr('Invert rasterization'),
- defaultValue=False)
- invert_param.setFlags(invert_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
+ invert_param = QgsProcessingParameterBoolean(
+ self.INVERT, self.tr("Invert rasterization"), defaultValue=False
+ )
+ invert_param.setFlags(
+ invert_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
self.addParameter(invert_param)
- extra_param = QgsProcessingParameterString(self.EXTRA,
- self.tr('Additional command-line parameters'),
- defaultValue=None,
- optional=True)
- extra_param.setFlags(extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
+ extra_param = QgsProcessingParameterString(
+ self.EXTRA,
+ self.tr("Additional command-line parameters"),
+ defaultValue=None,
+ optional=True,
+ )
+ extra_param.setFlags(
+ extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
self.addParameter(extra_param)
- self.addParameter(QgsProcessingParameterRasterDestination(self.OUTPUT,
- self.tr('Rasterized')))
+ self.addParameter(
+ QgsProcessingParameterRasterDestination(self.OUTPUT, self.tr("Rasterized"))
+ )
def name(self):
- return 'rasterize'
+ return "rasterize"
def displayName(self):
- return self.tr('Rasterize (vector to raster)')
+ return self.tr("Rasterize (vector to raster)")
def group(self):
- return self.tr('Vector conversion')
+ return self.tr("Vector conversion")
def groupId(self):
- return 'vectorconversion'
+ return "vectorconversion"
def icon(self):
- return QIcon(os.path.join(pluginPath, 'images', 'gdaltools', 'rasterize.png'))
+ return QIcon(os.path.join(pluginPath, "images", "gdaltools", "rasterize.png"))
def commandName(self):
- return 'gdal_rasterize'
+ return "gdal_rasterize"
def getConsoleCommands(self, parameters, context, feedback, executing=True):
source = self.parameterAsSource(parameters, self.INPUT, context)
if source is None:
- raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT))
-
- input_details = self.getOgrCompatibleSource(self.INPUT, parameters, context, feedback, executing)
- arguments = [
- '-l',
- input_details.layer_name
- ]
+ raise QgsProcessingException(
+ self.invalidSourceError(parameters, self.INPUT)
+ )
+
+ input_details = self.getOgrCompatibleSource(
+ self.INPUT, parameters, context, feedback, executing
+ )
+ arguments = ["-l", input_details.layer_name]
fieldName = self.parameterAsString(parameters, self.FIELD, context)
use_z = self.parameterAsBoolean(parameters, self.USE_Z, context)
if use_z:
- arguments.append('-3d')
+ arguments.append("-3d")
elif fieldName:
- arguments.append('-a')
+ arguments.append("-a")
arguments.append(fieldName)
else:
- arguments.append('-burn')
+ arguments.append("-burn")
arguments.append(self.parameterAsDouble(parameters, self.BURN, context))
units = self.parameterAsEnum(parameters, self.UNITS, context)
if units == 0:
- arguments.append('-ts')
+ arguments.append("-ts")
else:
- arguments.append('-tr')
+ arguments.append("-tr")
arguments.append(self.parameterAsDouble(parameters, self.WIDTH, context))
arguments.append(self.parameterAsDouble(parameters, self.HEIGHT, context))
if self.INIT in parameters and parameters[self.INIT] is not None:
initValue = self.parameterAsDouble(parameters, self.INIT, context)
- arguments.append('-init')
+ arguments.append("-init")
arguments.append(initValue)
if self.parameterAsBoolean(parameters, self.INVERT, context):
- arguments.append('-i')
+ arguments.append("-i")
if self.parameterAsBoolean(parameters, self.ALL_TOUCH, context):
- arguments.append('-at')
+ arguments.append("-at")
if self.NODATA in parameters and parameters[self.NODATA] is not None:
nodata = self.parameterAsDouble(parameters, self.NODATA, context)
- arguments.append('-a_nodata')
+ arguments.append("-a_nodata")
arguments.append(nodata)
- extent = self.parameterAsExtent(parameters, self.EXTENT, context, source.sourceCrs())
+ extent = self.parameterAsExtent(
+ parameters, self.EXTENT, context, source.sourceCrs()
+ )
if not extent.isNull():
- arguments.append('-te')
+ arguments.append("-te")
arguments.append(extent.xMinimum())
arguments.append(extent.yMinimum())
arguments.append(extent.xMaximum())
arguments.append(extent.yMaximum())
data_type = self.parameterAsEnum(parameters, self.DATA_TYPE, context)
- if self.TYPES[data_type] == 'Int8' and GdalUtils.version() < 3070000:
- raise QgsProcessingException(self.tr('Int8 data type requires GDAL version 3.7 or later'))
+ if self.TYPES[data_type] == "Int8" and GdalUtils.version() < 3070000:
+ raise QgsProcessingException(
+ self.tr("Int8 data type requires GDAL version 3.7 or later")
+ )
- arguments.append('-ot ' + self.TYPES[data_type])
+ arguments.append("-ot " + self.TYPES[data_type])
out = self.parameterAsOutputLayer(parameters, self.OUTPUT, context)
self.setOutputValue(self.OUTPUT, out)
output_format = QgsRasterFileWriter.driverForExtension(os.path.splitext(out)[1])
if not output_format:
- raise QgsProcessingException(self.tr('Output format is invalid'))
+ raise QgsProcessingException(self.tr("Output format is invalid"))
- arguments.append('-of')
+ arguments.append("-of")
arguments.append(output_format)
if input_details.open_options:
if GdalUtils.version() < 3070000:
- raise QgsProcessingException(self.tr(
- 'Open options are not supported by gdal_rasterize version {} (requires GDAL version 3.7 or later)'.format(
- GdalUtils.readableVersion())))
+ raise QgsProcessingException(
+ self.tr(
+ "Open options are not supported by gdal_rasterize version {} (requires GDAL version 3.7 or later)".format(
+ GdalUtils.readableVersion()
+ )
+ )
+ )
arguments.extend(input_details.open_options_as_arguments())
@@ -248,7 +318,7 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True):
if options:
arguments.extend(GdalUtils.parseCreationOptions(options))
- if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ''):
+ if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ""):
extra = self.parameterAsString(parameters, self.EXTRA, context)
arguments.append(extra)
diff --git a/python/plugins/processing/algs/gdal/rasterize_over.py b/python/plugins/processing/algs/gdal/rasterize_over.py
index dce80ad423ab..31867dc2b0fd 100644
--- a/python/plugins/processing/algs/gdal/rasterize_over.py
+++ b/python/plugins/processing/algs/gdal/rasterize_over.py
@@ -15,22 +15,24 @@
***************************************************************************
"""
-__author__ = 'Alexander Bruy'
-__date__ = 'September 2013'
-__copyright__ = '(C) 2013, Alexander Bruy'
+__author__ = "Alexander Bruy"
+__date__ = "September 2013"
+__copyright__ = "(C) 2013, Alexander Bruy"
import os
from qgis.PyQt.QtGui import QIcon
-from qgis.core import (QgsProcessingException,
- QgsProcessingParameterDefinition,
- QgsProcessingParameterFeatureSource,
- QgsProcessingParameterField,
- QgsProcessingParameterRasterLayer,
- QgsProcessingParameterString,
- QgsProcessingParameterBoolean,
- QgsProcessingOutputRasterLayer)
+from qgis.core import (
+ QgsProcessingException,
+ QgsProcessingParameterDefinition,
+ QgsProcessingParameterFeatureSource,
+ QgsProcessingParameterField,
+ QgsProcessingParameterRasterLayer,
+ QgsProcessingParameterString,
+ QgsProcessingParameterBoolean,
+ QgsProcessingOutputRasterLayer,
+)
from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm
from processing.algs.gdal.GdalUtils import GdalUtils
@@ -38,92 +40,108 @@
class rasterize_over(GdalAlgorithm):
- INPUT = 'INPUT'
- FIELD = 'FIELD'
- INPUT_RASTER = 'INPUT_RASTER'
- ADD = 'ADD'
- EXTRA = 'EXTRA'
- OUTPUT = 'OUTPUT'
+ INPUT = "INPUT"
+ FIELD = "FIELD"
+ INPUT_RASTER = "INPUT_RASTER"
+ ADD = "ADD"
+ EXTRA = "EXTRA"
+ OUTPUT = "OUTPUT"
def __init__(self):
super().__init__()
def initAlgorithm(self, config=None):
- self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT,
- self.tr('Input vector layer')))
- self.addParameter(QgsProcessingParameterRasterLayer(self.INPUT_RASTER,
- self.tr('Input raster layer')))
- self.addParameter(QgsProcessingParameterField(self.FIELD,
- self.tr('Field to use for burn in value'),
- None,
- self.INPUT,
- QgsProcessingParameterField.DataType.Numeric,
- optional=False))
+ self.addParameter(
+ QgsProcessingParameterFeatureSource(
+ self.INPUT, self.tr("Input vector layer")
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterRasterLayer(
+ self.INPUT_RASTER, self.tr("Input raster layer")
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterField(
+ self.FIELD,
+ self.tr("Field to use for burn in value"),
+ None,
+ self.INPUT,
+ QgsProcessingParameterField.DataType.Numeric,
+ optional=False,
+ )
+ )
params = [
- QgsProcessingParameterBoolean(self.ADD,
- self.tr('Add burn in values to existing raster values'),
- defaultValue=False,
- ),
- QgsProcessingParameterString(self.EXTRA,
- self.tr('Additional command-line parameters'),
- defaultValue=None,
- optional=True)
+ QgsProcessingParameterBoolean(
+ self.ADD,
+ self.tr("Add burn in values to existing raster values"),
+ defaultValue=False,
+ ),
+ QgsProcessingParameterString(
+ self.EXTRA,
+ self.tr("Additional command-line parameters"),
+ defaultValue=None,
+ optional=True,
+ ),
]
for p in params:
p.setFlags(p.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
self.addParameter(p)
- self.addOutput(QgsProcessingOutputRasterLayer(self.OUTPUT,
- self.tr('Rasterized')))
+ self.addOutput(
+ QgsProcessingOutputRasterLayer(self.OUTPUT, self.tr("Rasterized"))
+ )
def name(self):
- return 'rasterize_over'
+ return "rasterize_over"
def displayName(self):
- return self.tr('Rasterize (overwrite with attribute)')
+ return self.tr("Rasterize (overwrite with attribute)")
def group(self):
- return self.tr('Vector conversion')
+ return self.tr("Vector conversion")
def groupId(self):
- return 'vectorconversion'
+ return "vectorconversion"
def icon(self):
- return QIcon(os.path.join(pluginPath, 'images', 'gdaltools', 'rasterize.png'))
+ return QIcon(os.path.join(pluginPath, "images", "gdaltools", "rasterize.png"))
def commandName(self):
- return 'gdal_rasterize'
+ return "gdal_rasterize"
def getConsoleCommands(self, parameters, context, feedback, executing=True):
- input_details = self.getOgrCompatibleSource(self.INPUT, parameters, context, feedback, executing)
+ input_details = self.getOgrCompatibleSource(
+ self.INPUT, parameters, context, feedback, executing
+ )
inLayer = self.parameterAsRasterLayer(parameters, self.INPUT_RASTER, context)
if inLayer is None:
- raise QgsProcessingException(self.invalidRasterError(parameters, self.INPUT_RASTER))
- input_raster_details = GdalUtils.gdal_connection_details_from_layer(
- inLayer)
+ raise QgsProcessingException(
+ self.invalidRasterError(parameters, self.INPUT_RASTER)
+ )
+ input_raster_details = GdalUtils.gdal_connection_details_from_layer(inLayer)
fieldName = self.parameterAsString(parameters, self.FIELD, context)
self.setOutputValue(self.OUTPUT, inLayer.source())
- arguments = [
- '-l',
- input_details.layer_name,
- '-a',
- fieldName
- ]
+ arguments = ["-l", input_details.layer_name, "-a", fieldName]
if self.parameterAsBool(parameters, self.ADD, context):
- arguments.append('-add')
+ arguments.append("-add")
- if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ''):
+ if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ""):
extra = self.parameterAsString(parameters, self.EXTRA, context)
arguments.append(extra)
if input_details.open_options:
if GdalUtils.version() < 3070000:
- raise QgsProcessingException(self.tr(
- 'Open options are not supported by gdal_rasterize version {} (requires GDAL version 3.7 or later)'.format(
- GdalUtils.readableVersion())))
+ raise QgsProcessingException(
+ self.tr(
+ "Open options are not supported by gdal_rasterize version {} (requires GDAL version 3.7 or later)".format(
+ GdalUtils.readableVersion()
+ )
+ )
+ )
arguments.extend(input_details.open_options_as_arguments())
diff --git a/python/plugins/processing/algs/gdal/rasterize_over_fixed_value.py b/python/plugins/processing/algs/gdal/rasterize_over_fixed_value.py
index 5767596a2d35..0a11de412ae9 100644
--- a/python/plugins/processing/algs/gdal/rasterize_over_fixed_value.py
+++ b/python/plugins/processing/algs/gdal/rasterize_over_fixed_value.py
@@ -15,22 +15,24 @@
***************************************************************************
"""
-__author__ = 'Alexander Bruy'
-__date__ = 'September 2013'
-__copyright__ = '(C) 2013, Alexander Bruy'
+__author__ = "Alexander Bruy"
+__date__ = "September 2013"
+__copyright__ = "(C) 2013, Alexander Bruy"
import os
from qgis.PyQt.QtGui import QIcon
-from qgis.core import (QgsProcessingException,
- QgsProcessingParameterDefinition,
- QgsProcessingParameterFeatureSource,
- QgsProcessingParameterRasterLayer,
- QgsProcessingParameterNumber,
- QgsProcessingParameterString,
- QgsProcessingParameterBoolean,
- QgsProcessingOutputRasterLayer)
+from qgis.core import (
+ QgsProcessingException,
+ QgsProcessingParameterDefinition,
+ QgsProcessingParameterFeatureSource,
+ QgsProcessingParameterRasterLayer,
+ QgsProcessingParameterNumber,
+ QgsProcessingParameterString,
+ QgsProcessingParameterBoolean,
+ QgsProcessingOutputRasterLayer,
+)
from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm
from processing.algs.gdal.GdalUtils import GdalUtils
@@ -38,92 +40,114 @@
class rasterize_over_fixed_value(GdalAlgorithm):
- INPUT = 'INPUT'
- INPUT_RASTER = 'INPUT_RASTER'
- ADD = 'ADD'
- EXTRA = 'EXTRA'
- BURN = 'BURN'
- OUTPUT = 'OUTPUT'
+ INPUT = "INPUT"
+ INPUT_RASTER = "INPUT_RASTER"
+ ADD = "ADD"
+ EXTRA = "EXTRA"
+ BURN = "BURN"
+ OUTPUT = "OUTPUT"
def __init__(self):
super().__init__()
def initAlgorithm(self, config=None):
- self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT,
- self.tr('Input vector layer')))
- self.addParameter(QgsProcessingParameterRasterLayer(self.INPUT_RASTER,
- self.tr('Input raster layer')))
- self.addParameter(QgsProcessingParameterNumber(self.BURN,
- self.tr('A fixed value to burn'),
- type=QgsProcessingParameterNumber.Type.Double,
- defaultValue=0.0))
+ self.addParameter(
+ QgsProcessingParameterFeatureSource(
+ self.INPUT, self.tr("Input vector layer")
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterRasterLayer(
+ self.INPUT_RASTER, self.tr("Input raster layer")
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterNumber(
+ self.BURN,
+ self.tr("A fixed value to burn"),
+ type=QgsProcessingParameterNumber.Type.Double,
+ defaultValue=0.0,
+ )
+ )
params = [
- QgsProcessingParameterBoolean(self.ADD,
- self.tr('Add burn in values to existing raster values'),
- defaultValue=False),
- QgsProcessingParameterString(self.EXTRA,
- self.tr('Additional command-line parameters'),
- defaultValue=None,
- optional=True)
+ QgsProcessingParameterBoolean(
+ self.ADD,
+ self.tr("Add burn in values to existing raster values"),
+ defaultValue=False,
+ ),
+ QgsProcessingParameterString(
+ self.EXTRA,
+ self.tr("Additional command-line parameters"),
+ defaultValue=None,
+ optional=True,
+ ),
]
for p in params:
p.setFlags(p.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
self.addParameter(p)
- self.addOutput(QgsProcessingOutputRasterLayer(self.OUTPUT,
- self.tr('Rasterized')))
+ self.addOutput(
+ QgsProcessingOutputRasterLayer(self.OUTPUT, self.tr("Rasterized"))
+ )
def name(self):
- return 'rasterize_over_fixed_value'
+ return "rasterize_over_fixed_value"
def displayName(self):
- return self.tr('Rasterize (overwrite with fixed value)')
+ return self.tr("Rasterize (overwrite with fixed value)")
def group(self):
- return self.tr('Vector conversion')
+ return self.tr("Vector conversion")
def groupId(self):
- return 'vectorconversion'
+ return "vectorconversion"
def icon(self):
- return QIcon(os.path.join(pluginPath, 'images', 'gdaltools', 'rasterize.png'))
+ return QIcon(os.path.join(pluginPath, "images", "gdaltools", "rasterize.png"))
def commandName(self):
- return 'gdal_rasterize'
+ return "gdal_rasterize"
def getConsoleCommands(self, parameters, context, feedback, executing=True):
- input_details = self.getOgrCompatibleSource(self.INPUT, parameters, context, feedback, executing)
+ input_details = self.getOgrCompatibleSource(
+ self.INPUT, parameters, context, feedback, executing
+ )
inLayer = self.parameterAsRasterLayer(parameters, self.INPUT_RASTER, context)
if inLayer is None:
- raise QgsProcessingException(self.invalidRasterError(parameters, self.INPUT_RASTER))
- input_raster_details = GdalUtils.gdal_connection_details_from_layer(
- inLayer)
+ raise QgsProcessingException(
+ self.invalidRasterError(parameters, self.INPUT_RASTER)
+ )
+ input_raster_details = GdalUtils.gdal_connection_details_from_layer(inLayer)
self.setOutputValue(self.OUTPUT, inLayer.source())
arguments = [
- '-l',
+ "-l",
input_details.layer_name,
- '-burn',
+ "-burn",
str(self.parameterAsDouble(parameters, self.BURN, context)),
]
if self.parameterAsBool(parameters, self.ADD, context):
- arguments.append('-add')
+ arguments.append("-add")
if input_details.open_options:
if GdalUtils.version() < 3070000:
- raise QgsProcessingException(self.tr(
- 'Open options are not supported by gdal_rasterize version {} (requires GDAL version 3.7 or later)'.format(
- GdalUtils.readableVersion())))
+ raise QgsProcessingException(
+ self.tr(
+ "Open options are not supported by gdal_rasterize version {} (requires GDAL version 3.7 or later)".format(
+ GdalUtils.readableVersion()
+ )
+ )
+ )
arguments.extend(input_details.open_options_as_arguments())
if input_details.credential_options:
arguments.extend(input_details.credential_options_as_arguments())
- if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ''):
+ if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ""):
extra = self.parameterAsString(parameters, self.EXTRA, context)
arguments.append(extra)
diff --git a/python/plugins/processing/algs/gdal/rearrange_bands.py b/python/plugins/processing/algs/gdal/rearrange_bands.py
index 3569f1bbee86..6d0163f76662 100644
--- a/python/plugins/processing/algs/gdal/rearrange_bands.py
+++ b/python/plugins/processing/algs/gdal/rearrange_bands.py
@@ -15,22 +15,24 @@
***************************************************************************
"""
-__author__ = 'Mathieu Pellerin'
-__date__ = 'August 2018'
-__copyright__ = '(C) 2018, Mathieu Pellerin'
+__author__ = "Mathieu Pellerin"
+__date__ = "August 2018"
+__copyright__ = "(C) 2018, Mathieu Pellerin"
import os
from qgis.PyQt.QtGui import QIcon
-from qgis.core import (QgsRasterFileWriter,
- QgsProcessingException,
- QgsProcessingParameterEnum,
- QgsProcessingParameterDefinition,
- QgsProcessingParameterRasterLayer,
- QgsProcessingParameterBand,
- QgsProcessingParameterString,
- QgsProcessingParameterRasterDestination)
+from qgis.core import (
+ QgsRasterFileWriter,
+ QgsProcessingException,
+ QgsProcessingParameterEnum,
+ QgsProcessingParameterDefinition,
+ QgsProcessingParameterRasterLayer,
+ QgsProcessingParameterBand,
+ QgsProcessingParameterString,
+ QgsProcessingParameterRasterDestination,
+)
from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm
from processing.algs.gdal.GdalUtils import GdalUtils
@@ -38,95 +40,126 @@
class rearrange_bands(GdalAlgorithm):
- INPUT = 'INPUT'
- BANDS = 'BANDS'
- OPTIONS = 'OPTIONS'
- DATA_TYPE = 'DATA_TYPE'
- OUTPUT = 'OUTPUT'
+ INPUT = "INPUT"
+ BANDS = "BANDS"
+ OPTIONS = "OPTIONS"
+ DATA_TYPE = "DATA_TYPE"
+ OUTPUT = "OUTPUT"
def __init__(self):
super().__init__()
def initAlgorithm(self, config=None):
- self.TYPES = [self.tr('Use Input Layer Data Type'), 'Byte', 'Int16', 'UInt16', 'UInt32', 'Int32', 'Float32', 'Float64', 'CInt16', 'CInt32', 'CFloat32', 'CFloat64', 'Int8']
-
- self.addParameter(QgsProcessingParameterRasterLayer(self.INPUT, self.tr('Input layer')))
- self.addParameter(QgsProcessingParameterBand(self.BANDS,
- self.tr('Selected band(s)'),
- None,
- self.INPUT,
- allowMultiple=True))
-
- options_param = QgsProcessingParameterString(self.OPTIONS,
- self.tr('Additional creation options'),
- defaultValue='',
- optional=True)
- options_param.setFlags(options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
- options_param.setMetadata({'widget_wrapper': {'widget_type': 'rasteroptions'}})
+ self.TYPES = [
+ self.tr("Use Input Layer Data Type"),
+ "Byte",
+ "Int16",
+ "UInt16",
+ "UInt32",
+ "Int32",
+ "Float32",
+ "Float64",
+ "CInt16",
+ "CInt32",
+ "CFloat32",
+ "CFloat64",
+ "Int8",
+ ]
+
+ self.addParameter(
+ QgsProcessingParameterRasterLayer(self.INPUT, self.tr("Input layer"))
+ )
+ self.addParameter(
+ QgsProcessingParameterBand(
+ self.BANDS,
+ self.tr("Selected band(s)"),
+ None,
+ self.INPUT,
+ allowMultiple=True,
+ )
+ )
+
+ options_param = QgsProcessingParameterString(
+ self.OPTIONS,
+ self.tr("Additional creation options"),
+ defaultValue="",
+ optional=True,
+ )
+ options_param.setFlags(
+ options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
+ options_param.setMetadata({"widget_wrapper": {"widget_type": "rasteroptions"}})
self.addParameter(options_param)
- dataType_param = QgsProcessingParameterEnum(self.DATA_TYPE,
- self.tr('Output data type'),
- self.TYPES,
- allowMultiple=False,
- defaultValue=0)
- dataType_param.setFlags(dataType_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
+ dataType_param = QgsProcessingParameterEnum(
+ self.DATA_TYPE,
+ self.tr("Output data type"),
+ self.TYPES,
+ allowMultiple=False,
+ defaultValue=0,
+ )
+ dataType_param.setFlags(
+ dataType_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
self.addParameter(dataType_param)
- self.addParameter(QgsProcessingParameterRasterDestination(self.OUTPUT,
- self.tr('Converted')))
+ self.addParameter(
+ QgsProcessingParameterRasterDestination(self.OUTPUT, self.tr("Converted"))
+ )
def name(self):
- return 'rearrange_bands'
+ return "rearrange_bands"
def displayName(self):
- return self.tr('Rearrange bands')
+ return self.tr("Rearrange bands")
def group(self):
- return self.tr('Raster conversion')
+ return self.tr("Raster conversion")
def groupId(self):
- return 'rasterconversion'
+ return "rasterconversion"
def icon(self):
- return QIcon(os.path.join(pluginPath, 'images', 'gdaltools', 'translate.png'))
+ return QIcon(os.path.join(pluginPath, "images", "gdaltools", "translate.png"))
def shortHelpString(self):
- return self.tr("This algorithm creates a new raster using selected band(s) from a given raster layer.\n\n"
- "The algorithm also makes it possible to reorder the bands for the newly-created raster.")
+ return self.tr(
+ "This algorithm creates a new raster using selected band(s) from a given raster layer.\n\n"
+ "The algorithm also makes it possible to reorder the bands for the newly-created raster."
+ )
def commandName(self):
- return 'gdal_translate'
+ return "gdal_translate"
def getConsoleCommands(self, parameters, context, feedback, executing=True):
inLayer = self.parameterAsRasterLayer(parameters, self.INPUT, context)
if inLayer is None:
- raise QgsProcessingException(self.invalidRasterError(parameters, self.INPUT))
- input_details = GdalUtils.gdal_connection_details_from_layer(
- inLayer)
+ raise QgsProcessingException(
+ self.invalidRasterError(parameters, self.INPUT)
+ )
+ input_details = GdalUtils.gdal_connection_details_from_layer(inLayer)
out = self.parameterAsOutputLayer(parameters, self.OUTPUT, context)
self.setOutputValue(self.OUTPUT, out)
bands = self.parameterAsInts(parameters, self.BANDS, context)
- arguments = [
- f'-b {band}'
- for band in bands
- ]
+ arguments = [f"-b {band}" for band in bands]
data_type = self.parameterAsEnum(parameters, self.DATA_TYPE, context)
if data_type:
- if self.TYPES[data_type] == 'Int8' and GdalUtils.version() < 3070000:
- raise QgsProcessingException(self.tr('Int8 data type requires GDAL version 3.7 or later'))
+ if self.TYPES[data_type] == "Int8" and GdalUtils.version() < 3070000:
+ raise QgsProcessingException(
+ self.tr("Int8 data type requires GDAL version 3.7 or later")
+ )
- arguments.append('-ot ' + self.TYPES[data_type])
+ arguments.append("-ot " + self.TYPES[data_type])
output_format = QgsRasterFileWriter.driverForExtension(os.path.splitext(out)[1])
if not output_format:
- raise QgsProcessingException(self.tr('Output format is invalid'))
+ raise QgsProcessingException(self.tr("Output format is invalid"))
- arguments.append('-of')
+ arguments.append("-of")
arguments.append(output_format)
options = self.parameterAsString(parameters, self.OPTIONS, context)
diff --git a/python/plugins/processing/algs/gdal/retile.py b/python/plugins/processing/algs/gdal/retile.py
index 38c7c8cf2fa4..085ec67ec4d6 100644
--- a/python/plugins/processing/algs/gdal/retile.py
+++ b/python/plugins/processing/algs/gdal/retile.py
@@ -15,202 +15,268 @@
***************************************************************************
"""
-__author__ = 'Médéric Ribreux'
-__date__ = 'January 2016'
-__copyright__ = '(C) 2016, Médéric Ribreux'
-
-from qgis.core import (QgsProcessing,
- QgsProcessingException,
- QgsProcessingParameterDefinition,
- QgsProcessingParameterMultipleLayers,
- QgsProcessingParameterCrs,
- QgsProcessingParameterEnum,
- QgsProcessingParameterString,
- QgsProcessingParameterNumber,
- QgsProcessingParameterBoolean,
- QgsProcessingParameterFileDestination,
- QgsProcessingParameterFolderDestination)
+__author__ = "Médéric Ribreux"
+__date__ = "January 2016"
+__copyright__ = "(C) 2016, Médéric Ribreux"
+
+from qgis.core import (
+ QgsProcessing,
+ QgsProcessingException,
+ QgsProcessingParameterDefinition,
+ QgsProcessingParameterMultipleLayers,
+ QgsProcessingParameterCrs,
+ QgsProcessingParameterEnum,
+ QgsProcessingParameterString,
+ QgsProcessingParameterNumber,
+ QgsProcessingParameterBoolean,
+ QgsProcessingParameterFileDestination,
+ QgsProcessingParameterFolderDestination,
+)
from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm
from processing.algs.gdal.GdalUtils import GdalUtils
from processing.tools.system import isWindows
class retile(GdalAlgorithm):
- INPUT = 'INPUT'
- TILE_SIZE_X = 'TILE_SIZE_X'
- TILE_SIZE_Y = 'TILE_SIZE_Y'
- OVERLAP = 'OVERLAP'
- LEVELS = 'LEVELS'
-
- SOURCE_CRS = 'SOURCE_CRS'
- FORMAT = 'FORMAT'
- RESAMPLING = 'RESAMPLING'
- OPTIONS = 'OPTIONS'
- EXTRA = 'EXTRA'
- DATA_TYPE = 'DATA_TYPE'
- DELIMITER = 'DELIMITER'
- ONLY_PYRAMIDS = 'ONLY_PYRAMIDS'
- DIR_FOR_ROW = 'DIR_FOR_ROW'
- OUTPUT = 'OUTPUT'
- OUTPUT_CSV = 'OUTPUT_CSV'
-
- TYPES = ['Byte', 'Int16', 'UInt16', 'UInt32', 'Int32', 'Float32', 'Float64', 'CInt16', 'CInt32', 'CFloat32', 'CFloat64', 'Int8']
+ INPUT = "INPUT"
+ TILE_SIZE_X = "TILE_SIZE_X"
+ TILE_SIZE_Y = "TILE_SIZE_Y"
+ OVERLAP = "OVERLAP"
+ LEVELS = "LEVELS"
+
+ SOURCE_CRS = "SOURCE_CRS"
+ FORMAT = "FORMAT"
+ RESAMPLING = "RESAMPLING"
+ OPTIONS = "OPTIONS"
+ EXTRA = "EXTRA"
+ DATA_TYPE = "DATA_TYPE"
+ DELIMITER = "DELIMITER"
+ ONLY_PYRAMIDS = "ONLY_PYRAMIDS"
+ DIR_FOR_ROW = "DIR_FOR_ROW"
+ OUTPUT = "OUTPUT"
+ OUTPUT_CSV = "OUTPUT_CSV"
+
+ TYPES = [
+ "Byte",
+ "Int16",
+ "UInt16",
+ "UInt32",
+ "Int32",
+ "Float32",
+ "Float64",
+ "CInt16",
+ "CInt32",
+ "CFloat32",
+ "CFloat64",
+ "Int8",
+ ]
def __init__(self):
super().__init__()
def initAlgorithm(self, config=None):
- self.methods = ((self.tr('Nearest Neighbour'), 'near'),
- (self.tr('Bilinear (2x2 Kernel)'), 'bilinear'),
- (self.tr('Cubic (4x4 Kernel)'), 'cubic'),
- (self.tr('Cubic B-Spline (4x4 Kernel)'), 'cubicspline'),
- (self.tr('Lanczos (6x6 Kernel)'), 'lanczos'),)
-
- self.addParameter(QgsProcessingParameterMultipleLayers(self.INPUT,
- self.tr('Input files'),
- QgsProcessing.SourceType.TypeRaster))
- self.addParameter(QgsProcessingParameterNumber(self.TILE_SIZE_X,
- self.tr('Tile width'),
- type=QgsProcessingParameterNumber.Type.Integer,
- minValue=0,
- defaultValue=256))
- self.addParameter(QgsProcessingParameterNumber(self.TILE_SIZE_Y,
- self.tr('Tile height'),
- type=QgsProcessingParameterNumber.Type.Integer,
- minValue=0,
- defaultValue=256))
- self.addParameter(QgsProcessingParameterNumber(self.OVERLAP,
- self.tr('Overlap in pixels between consecutive tiles'),
- type=QgsProcessingParameterNumber.Type.Integer,
- minValue=0,
- defaultValue=0))
- self.addParameter(QgsProcessingParameterNumber(self.LEVELS,
- self.tr('Number of pyramids levels to build'),
- type=QgsProcessingParameterNumber.Type.Integer,
- minValue=0,
- defaultValue=1))
+ self.methods = (
+ (self.tr("Nearest Neighbour"), "near"),
+ (self.tr("Bilinear (2x2 Kernel)"), "bilinear"),
+ (self.tr("Cubic (4x4 Kernel)"), "cubic"),
+ (self.tr("Cubic B-Spline (4x4 Kernel)"), "cubicspline"),
+ (self.tr("Lanczos (6x6 Kernel)"), "lanczos"),
+ )
+
+ self.addParameter(
+ QgsProcessingParameterMultipleLayers(
+ self.INPUT, self.tr("Input files"), QgsProcessing.SourceType.TypeRaster
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterNumber(
+ self.TILE_SIZE_X,
+ self.tr("Tile width"),
+ type=QgsProcessingParameterNumber.Type.Integer,
+ minValue=0,
+ defaultValue=256,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterNumber(
+ self.TILE_SIZE_Y,
+ self.tr("Tile height"),
+ type=QgsProcessingParameterNumber.Type.Integer,
+ minValue=0,
+ defaultValue=256,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterNumber(
+ self.OVERLAP,
+ self.tr("Overlap in pixels between consecutive tiles"),
+ type=QgsProcessingParameterNumber.Type.Integer,
+ minValue=0,
+ defaultValue=0,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterNumber(
+ self.LEVELS,
+ self.tr("Number of pyramids levels to build"),
+ type=QgsProcessingParameterNumber.Type.Integer,
+ minValue=0,
+ defaultValue=1,
+ )
+ )
params = [
- QgsProcessingParameterCrs(self.SOURCE_CRS,
- self.tr('Source coordinate reference system'),
- optional=True,
- ),
- QgsProcessingParameterEnum(self.RESAMPLING,
- self.tr('Resampling method'),
- options=[i[0] for i in self.methods],
- allowMultiple=False,
- defaultValue=0),
- QgsProcessingParameterString(self.DELIMITER,
- self.tr('Column delimiter used in the CSV file'),
- defaultValue=';',
- optional=True)
-
+ QgsProcessingParameterCrs(
+ self.SOURCE_CRS,
+ self.tr("Source coordinate reference system"),
+ optional=True,
+ ),
+ QgsProcessingParameterEnum(
+ self.RESAMPLING,
+ self.tr("Resampling method"),
+ options=[i[0] for i in self.methods],
+ allowMultiple=False,
+ defaultValue=0,
+ ),
+ QgsProcessingParameterString(
+ self.DELIMITER,
+ self.tr("Column delimiter used in the CSV file"),
+ defaultValue=";",
+ optional=True,
+ ),
]
- options_param = QgsProcessingParameterString(self.OPTIONS,
- self.tr('Additional creation options'),
- defaultValue='',
- optional=True)
- options_param.setMetadata({'widget_wrapper': {'widget_type': 'rasteroptions'}})
+ options_param = QgsProcessingParameterString(
+ self.OPTIONS,
+ self.tr("Additional creation options"),
+ defaultValue="",
+ optional=True,
+ )
+ options_param.setMetadata({"widget_wrapper": {"widget_type": "rasteroptions"}})
params.append(options_param)
- params.append(QgsProcessingParameterString(self.EXTRA,
- self.tr('Additional command-line parameters'),
- defaultValue=None,
- optional=True))
-
- params.append(QgsProcessingParameterEnum(self.DATA_TYPE,
- self.tr('Output data type'),
- self.TYPES,
- allowMultiple=False,
- defaultValue=5))
-
- params.append(QgsProcessingParameterBoolean(self.ONLY_PYRAMIDS,
- self.tr('Build only the pyramids'),
- defaultValue=False))
- params.append(QgsProcessingParameterBoolean(self.DIR_FOR_ROW,
- self.tr('Use separate directory for each tiles row'),
- defaultValue=False))
+ params.append(
+ QgsProcessingParameterString(
+ self.EXTRA,
+ self.tr("Additional command-line parameters"),
+ defaultValue=None,
+ optional=True,
+ )
+ )
+
+ params.append(
+ QgsProcessingParameterEnum(
+ self.DATA_TYPE,
+ self.tr("Output data type"),
+ self.TYPES,
+ allowMultiple=False,
+ defaultValue=5,
+ )
+ )
+
+ params.append(
+ QgsProcessingParameterBoolean(
+ self.ONLY_PYRAMIDS,
+ self.tr("Build only the pyramids"),
+ defaultValue=False,
+ )
+ )
+ params.append(
+ QgsProcessingParameterBoolean(
+ self.DIR_FOR_ROW,
+ self.tr("Use separate directory for each tiles row"),
+ defaultValue=False,
+ )
+ )
for param in params:
- param.setFlags(param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
+ param.setFlags(
+ param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
self.addParameter(param)
- self.addParameter(QgsProcessingParameterFolderDestination(self.OUTPUT,
- self.tr('Output directory')))
-
- output_csv_param = QgsProcessingParameterFileDestination(self.OUTPUT_CSV,
- self.tr('CSV file containing the tile(s) georeferencing information'),
- 'CSV files (*.csv)',
- optional=True)
+ self.addParameter(
+ QgsProcessingParameterFolderDestination(
+ self.OUTPUT, self.tr("Output directory")
+ )
+ )
+
+ output_csv_param = QgsProcessingParameterFileDestination(
+ self.OUTPUT_CSV,
+ self.tr("CSV file containing the tile(s) georeferencing information"),
+ "CSV files (*.csv)",
+ optional=True,
+ )
output_csv_param.setCreateByDefault(False)
self.addParameter(output_csv_param)
def name(self):
- return 'retile'
+ return "retile"
def displayName(self):
- return self.tr('Retile')
+ return self.tr("Retile")
def group(self):
- return self.tr('Raster miscellaneous')
+ return self.tr("Raster miscellaneous")
def groupId(self):
- return 'rastermiscellaneous'
+ return "rastermiscellaneous"
def commandName(self):
return "gdal_retile"
def getConsoleCommands(self, parameters, context, feedback, executing=True):
arguments = [
- '-ps',
+ "-ps",
str(self.parameterAsInt(parameters, self.TILE_SIZE_X, context)),
str(self.parameterAsInt(parameters, self.TILE_SIZE_Y, context)),
-
- '-overlap',
+ "-overlap",
str(self.parameterAsInt(parameters, self.OVERLAP, context)),
-
- '-levels',
- str(self.parameterAsInt(parameters, self.LEVELS, context))
+ "-levels",
+ str(self.parameterAsInt(parameters, self.LEVELS, context)),
]
crs = self.parameterAsCrs(parameters, self.SOURCE_CRS, context)
if crs.isValid():
- arguments.append('-s_srs')
+ arguments.append("-s_srs")
arguments.append(GdalUtils.gdal_crs_string(crs))
- arguments.append('-r')
- arguments.append(self.methods[self.parameterAsEnum(parameters, self.RESAMPLING, context)][1])
+ arguments.append("-r")
+ arguments.append(
+ self.methods[self.parameterAsEnum(parameters, self.RESAMPLING, context)][1]
+ )
data_type = self.parameterAsEnum(parameters, self.DATA_TYPE, context)
- if self.TYPES[data_type] == 'Int8' and GdalUtils.version() < 3070000:
- raise QgsProcessingException(self.tr('Int8 data type requires GDAL version 3.7 or later'))
+ if self.TYPES[data_type] == "Int8" and GdalUtils.version() < 3070000:
+ raise QgsProcessingException(
+ self.tr("Int8 data type requires GDAL version 3.7 or later")
+ )
- arguments.append('-ot ' + self.TYPES[data_type])
+ arguments.append("-ot " + self.TYPES[data_type])
options = self.parameterAsString(parameters, self.OPTIONS, context)
if options:
arguments.extend(GdalUtils.parseCreationOptions(options))
- if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ''):
+ if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ""):
extra = self.parameterAsString(parameters, self.EXTRA, context)
arguments.append(extra)
if self.parameterAsBoolean(parameters, self.DIR_FOR_ROW, context):
- arguments.append('-useDirForEachRow')
+ arguments.append("-useDirForEachRow")
if self.parameterAsBoolean(parameters, self.ONLY_PYRAMIDS, context):
- arguments.append('-pyramidOnly')
+ arguments.append("-pyramidOnly")
csvFile = self.parameterAsFileOutput(parameters, self.OUTPUT_CSV, context)
if csvFile:
- arguments.append('-csv')
+ arguments.append("-csv")
arguments.append(csvFile)
delimiter = self.parameterAsString(parameters, self.DELIMITER, context)
if delimiter:
- arguments.append('-csvDelim')
+ arguments.append("-csvDelim")
arguments.append(delimiter)
- arguments.append('-targetDir')
+ arguments.append("-targetDir")
arguments.append(self.parameterAsString(parameters, self.OUTPUT, context))
input_layers = self.parameterAsLayerList(parameters, self.INPUT, context)
@@ -222,8 +288,12 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True):
if layer_details.credential_options:
credential_options.extend(
- layer_details.credential_options_as_arguments())
+ layer_details.credential_options_as_arguments()
+ )
arguments.extend(layers)
arguments.extend(credential_options)
- return [self.commandName() + ('.bat' if isWindows() else '.py'), GdalUtils.escapeAndJoin(arguments)]
+ return [
+ self.commandName() + (".bat" if isWindows() else ".py"),
+ GdalUtils.escapeAndJoin(arguments),
+ ]
diff --git a/python/plugins/processing/algs/gdal/rgb2pct.py b/python/plugins/processing/algs/gdal/rgb2pct.py
index 406a85e7f859..8bc9ab9b6cda 100644
--- a/python/plugins/processing/algs/gdal/rgb2pct.py
+++ b/python/plugins/processing/algs/gdal/rgb2pct.py
@@ -15,19 +15,21 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'August 2012'
-__copyright__ = '(C) 2012, Victor Olaya'
+__author__ = "Victor Olaya"
+__date__ = "August 2012"
+__copyright__ = "(C) 2012, Victor Olaya"
import os
from qgis.PyQt.QtGui import QIcon
-from qgis.core import (QgsRasterFileWriter,
- QgsProcessingException,
- QgsProcessingParameterRasterLayer,
- QgsProcessingParameterNumber,
- QgsProcessingParameterRasterDestination)
+from qgis.core import (
+ QgsRasterFileWriter,
+ QgsProcessingException,
+ QgsProcessingParameterRasterLayer,
+ QgsProcessingParameterNumber,
+ QgsProcessingParameterRasterDestination,
+)
from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm
from processing.algs.gdal.GdalUtils import GdalUtils
from processing.tools.system import isWindows
@@ -36,41 +38,51 @@
class rgb2pct(GdalAlgorithm):
- INPUT = 'INPUT'
- OUTPUT = 'OUTPUT'
- NCOLORS = 'NCOLORS'
+ INPUT = "INPUT"
+ OUTPUT = "OUTPUT"
+ NCOLORS = "NCOLORS"
def __init__(self):
super().__init__()
def initAlgorithm(self, config=None):
- self.addParameter(QgsProcessingParameterRasterLayer(self.INPUT, self.tr('Input layer')))
- self.addParameter(QgsProcessingParameterNumber(self.NCOLORS,
- self.tr('Number of colors'),
- type=QgsProcessingParameterNumber.Type.Integer,
- minValue=0,
- maxValue=255,
- defaultValue=2))
-
- self.addParameter(QgsProcessingParameterRasterDestination(self.OUTPUT, self.tr('RGB to PCT')))
+ self.addParameter(
+ QgsProcessingParameterRasterLayer(self.INPUT, self.tr("Input layer"))
+ )
+ self.addParameter(
+ QgsProcessingParameterNumber(
+ self.NCOLORS,
+ self.tr("Number of colors"),
+ type=QgsProcessingParameterNumber.Type.Integer,
+ minValue=0,
+ maxValue=255,
+ defaultValue=2,
+ )
+ )
+
+ self.addParameter(
+ QgsProcessingParameterRasterDestination(self.OUTPUT, self.tr("RGB to PCT"))
+ )
def name(self):
- return 'rgbtopct'
+ return "rgbtopct"
def displayName(self):
- return self.tr('RGB to PCT')
+ return self.tr("RGB to PCT")
def group(self):
- return self.tr('Raster conversion')
+ return self.tr("Raster conversion")
def groupId(self):
- return 'rasterconversion'
+ return "rasterconversion"
def icon(self):
- return QIcon(os.path.join(pluginPath, 'images', 'gdaltools', '24-to-8-bits.png'))
+ return QIcon(
+ os.path.join(pluginPath, "images", "gdaltools", "24-to-8-bits.png")
+ )
def commandName(self):
- return 'rgb2pct'
+ return "rgb2pct"
def getConsoleCommands(self, parameters, context, feedback, executing=True):
out = self.parameterAsOutputLayer(parameters, self.OUTPUT, context)
@@ -78,24 +90,28 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True):
raster = self.parameterAsRasterLayer(parameters, self.INPUT, context)
if raster is None:
- raise QgsProcessingException(self.invalidRasterError(parameters, self.INPUT))
- input_details = GdalUtils.gdal_connection_details_from_layer(
- raster)
+ raise QgsProcessingException(
+ self.invalidRasterError(parameters, self.INPUT)
+ )
+ input_details = GdalUtils.gdal_connection_details_from_layer(raster)
output_format = QgsRasterFileWriter.driverForExtension(os.path.splitext(out)[1])
if not output_format:
- raise QgsProcessingException(self.tr('Output format is invalid'))
+ raise QgsProcessingException(self.tr("Output format is invalid"))
arguments = [
- '-n',
+ "-n",
str(self.parameterAsInt(parameters, self.NCOLORS, context)),
- '-of',
+ "-of",
output_format,
input_details.connection_string,
- out
+ out,
]
if input_details.credential_options:
arguments.extend(input_details.credential_options_as_arguments())
- return [self.commandName() + ('.bat' if isWindows() else '.py'), GdalUtils.escapeAndJoin(arguments)]
+ return [
+ self.commandName() + (".bat" if isWindows() else ".py"),
+ GdalUtils.escapeAndJoin(arguments),
+ ]
diff --git a/python/plugins/processing/algs/gdal/roughness.py b/python/plugins/processing/algs/gdal/roughness.py
index 4a5be6dddbe0..e02b85ce4598 100644
--- a/python/plugins/processing/algs/gdal/roughness.py
+++ b/python/plugins/processing/algs/gdal/roughness.py
@@ -15,20 +15,22 @@
***************************************************************************
"""
-__author__ = 'Alexander Bruy'
-__date__ = 'October 2013'
-__copyright__ = '(C) 2013, Alexander Bruy'
+__author__ = "Alexander Bruy"
+__date__ = "October 2013"
+__copyright__ = "(C) 2013, Alexander Bruy"
import os
-from qgis.core import (QgsRasterFileWriter,
- QgsProcessingException,
- QgsProcessingParameterDefinition,
- QgsProcessingParameterRasterLayer,
- QgsProcessingParameterBand,
- QgsProcessingParameterString,
- QgsProcessingParameterBoolean,
- QgsProcessingParameterRasterDestination)
+from qgis.core import (
+ QgsRasterFileWriter,
+ QgsProcessingException,
+ QgsProcessingParameterDefinition,
+ QgsProcessingParameterRasterLayer,
+ QgsProcessingParameterBand,
+ QgsProcessingParameterString,
+ QgsProcessingParameterBoolean,
+ QgsProcessingParameterRasterDestination,
+)
from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm
from processing.algs.gdal.GdalUtils import GdalUtils
@@ -37,76 +39,91 @@
class roughness(GdalAlgorithm):
- INPUT = 'INPUT'
- BAND = 'BAND'
- COMPUTE_EDGES = 'COMPUTE_EDGES'
- OPTIONS = 'OPTIONS'
- OUTPUT = 'OUTPUT'
+ INPUT = "INPUT"
+ BAND = "BAND"
+ COMPUTE_EDGES = "COMPUTE_EDGES"
+ OPTIONS = "OPTIONS"
+ OUTPUT = "OUTPUT"
def __init__(self):
super().__init__()
def initAlgorithm(self, config=None):
- self.addParameter(QgsProcessingParameterRasterLayer(self.INPUT, self.tr('Input layer')))
- self.addParameter(QgsProcessingParameterBand(self.BAND,
- self.tr('Band number'),
- 1,
- parentLayerParameterName=self.INPUT))
- self.addParameter(QgsProcessingParameterBoolean(self.COMPUTE_EDGES,
- self.tr('Compute edges'),
- defaultValue=False))
-
- options_param = QgsProcessingParameterString(self.OPTIONS,
- self.tr('Additional creation options'),
- defaultValue='',
- optional=True)
- options_param.setFlags(options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
- options_param.setMetadata({'widget_wrapper': {'widget_type': 'rasteroptions'}})
+ self.addParameter(
+ QgsProcessingParameterRasterLayer(self.INPUT, self.tr("Input layer"))
+ )
+ self.addParameter(
+ QgsProcessingParameterBand(
+ self.BAND,
+ self.tr("Band number"),
+ 1,
+ parentLayerParameterName=self.INPUT,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterBoolean(
+ self.COMPUTE_EDGES, self.tr("Compute edges"), defaultValue=False
+ )
+ )
+
+ options_param = QgsProcessingParameterString(
+ self.OPTIONS,
+ self.tr("Additional creation options"),
+ defaultValue="",
+ optional=True,
+ )
+ options_param.setFlags(
+ options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
+ options_param.setMetadata({"widget_wrapper": {"widget_type": "rasteroptions"}})
self.addParameter(options_param)
- self.addParameter(QgsProcessingParameterRasterDestination(self.OUTPUT, self.tr('Roughness')))
+ self.addParameter(
+ QgsProcessingParameterRasterDestination(self.OUTPUT, self.tr("Roughness"))
+ )
def name(self):
- return 'roughness'
+ return "roughness"
def displayName(self):
- return self.tr('Roughness')
+ return self.tr("Roughness")
def group(self):
- return self.tr('Raster analysis')
+ return self.tr("Raster analysis")
def groupId(self):
- return 'rasteranalysis'
+ return "rasteranalysis"
def commandName(self):
- return 'gdaldem'
+ return "gdaldem"
def getConsoleCommands(self, parameters, context, feedback, executing=True):
inLayer = self.parameterAsRasterLayer(parameters, self.INPUT, context)
if inLayer is None:
- raise QgsProcessingException(self.invalidRasterError(parameters, self.INPUT))
- input_details = GdalUtils.gdal_connection_details_from_layer(
- inLayer)
+ raise QgsProcessingException(
+ self.invalidRasterError(parameters, self.INPUT)
+ )
+ input_details = GdalUtils.gdal_connection_details_from_layer(inLayer)
out = self.parameterAsOutputLayer(parameters, self.OUTPUT, context)
self.setOutputValue(self.OUTPUT, out)
output_format = QgsRasterFileWriter.driverForExtension(os.path.splitext(out)[1])
if not output_format:
- raise QgsProcessingException(self.tr('Output format is invalid'))
+ raise QgsProcessingException(self.tr("Output format is invalid"))
arguments = [
- 'roughness',
+ "roughness",
input_details.connection_string,
out,
- '-of',
+ "-of",
output_format,
- '-b',
- str(self.parameterAsInt(parameters, self.BAND, context))
+ "-b",
+ str(self.parameterAsInt(parameters, self.BAND, context)),
]
if self.parameterAsBoolean(parameters, self.COMPUTE_EDGES, context):
- arguments.append('-compute_edges')
+ arguments.append("-compute_edges")
if input_details.credential_options:
arguments.extend(input_details.credential_options_as_arguments())
diff --git a/python/plugins/processing/algs/gdal/sieve.py b/python/plugins/processing/algs/gdal/sieve.py
index eac503d81c8c..806693e876a6 100644
--- a/python/plugins/processing/algs/gdal/sieve.py
+++ b/python/plugins/processing/algs/gdal/sieve.py
@@ -15,22 +15,24 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'August 2012'
-__copyright__ = '(C) 2012, Victor Olaya'
+__author__ = "Victor Olaya"
+__date__ = "August 2012"
+__copyright__ = "(C) 2012, Victor Olaya"
import os
from qgis.PyQt.QtGui import QIcon
-from qgis.core import (QgsRasterFileWriter,
- QgsProcessingException,
- QgsProcessingParameterDefinition,
- QgsProcessingParameterRasterLayer,
- QgsProcessingParameterNumber,
- QgsProcessingParameterBoolean,
- QgsProcessingParameterString,
- QgsProcessingParameterRasterDestination)
+from qgis.core import (
+ QgsRasterFileWriter,
+ QgsProcessingException,
+ QgsProcessingParameterDefinition,
+ QgsProcessingParameterRasterLayer,
+ QgsProcessingParameterNumber,
+ QgsProcessingParameterBoolean,
+ QgsProcessingParameterString,
+ QgsProcessingParameterRasterDestination,
+)
from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm
from processing.tools.system import isWindows
from processing.algs.gdal.GdalUtils import GdalUtils
@@ -39,80 +41,101 @@
class sieve(GdalAlgorithm):
- INPUT = 'INPUT'
- THRESHOLD = 'THRESHOLD'
- EIGHT_CONNECTEDNESS = 'EIGHT_CONNECTEDNESS'
- NO_MASK = 'NO_MASK'
- MASK_LAYER = 'MASK_LAYER'
- EXTRA = 'EXTRA'
- OUTPUT = 'OUTPUT'
+ INPUT = "INPUT"
+ THRESHOLD = "THRESHOLD"
+ EIGHT_CONNECTEDNESS = "EIGHT_CONNECTEDNESS"
+ NO_MASK = "NO_MASK"
+ MASK_LAYER = "MASK_LAYER"
+ EXTRA = "EXTRA"
+ OUTPUT = "OUTPUT"
def __init__(self):
super().__init__()
def initAlgorithm(self, config=None):
- self.addParameter(QgsProcessingParameterRasterLayer(self.INPUT, self.tr('Input layer')))
- self.addParameter(QgsProcessingParameterNumber(self.THRESHOLD,
- self.tr('Threshold'),
- type=QgsProcessingParameterNumber.Type.Integer,
- minValue=0,
- defaultValue=10))
- self.addParameter(QgsProcessingParameterBoolean(self.EIGHT_CONNECTEDNESS,
- self.tr('Use 8-connectedness'),
- defaultValue=False))
- self.addParameter(QgsProcessingParameterBoolean(self.NO_MASK,
- self.tr('Do not use the default validity mask for the input band'),
- defaultValue=False))
- self.addParameter(QgsProcessingParameterRasterLayer(self.MASK_LAYER,
- self.tr('Validity mask'),
- optional=True))
-
- extra_param = QgsProcessingParameterString(self.EXTRA,
- self.tr('Additional command-line parameters'),
- defaultValue=None,
- optional=True)
- extra_param.setFlags(extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
+ self.addParameter(
+ QgsProcessingParameterRasterLayer(self.INPUT, self.tr("Input layer"))
+ )
+ self.addParameter(
+ QgsProcessingParameterNumber(
+ self.THRESHOLD,
+ self.tr("Threshold"),
+ type=QgsProcessingParameterNumber.Type.Integer,
+ minValue=0,
+ defaultValue=10,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterBoolean(
+ self.EIGHT_CONNECTEDNESS,
+ self.tr("Use 8-connectedness"),
+ defaultValue=False,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterBoolean(
+ self.NO_MASK,
+ self.tr("Do not use the default validity mask for the input band"),
+ defaultValue=False,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterRasterLayer(
+ self.MASK_LAYER, self.tr("Validity mask"), optional=True
+ )
+ )
+
+ extra_param = QgsProcessingParameterString(
+ self.EXTRA,
+ self.tr("Additional command-line parameters"),
+ defaultValue=None,
+ optional=True,
+ )
+ extra_param.setFlags(
+ extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
self.addParameter(extra_param)
- self.addParameter(QgsProcessingParameterRasterDestination(self.OUTPUT, self.tr('Sieved')))
+ self.addParameter(
+ QgsProcessingParameterRasterDestination(self.OUTPUT, self.tr("Sieved"))
+ )
def name(self):
- return 'sieve'
+ return "sieve"
def displayName(self):
- return self.tr('Sieve')
+ return self.tr("Sieve")
def group(self):
- return self.tr('Raster analysis')
+ return self.tr("Raster analysis")
def groupId(self):
- return 'rasteranalysis'
+ return "rasteranalysis"
def icon(self):
- return QIcon(os.path.join(pluginPath, 'images', 'gdaltools', 'sieve.png'))
+ return QIcon(os.path.join(pluginPath, "images", "gdaltools", "sieve.png"))
def commandName(self):
- return 'gdal_sieve'
+ return "gdal_sieve"
def getConsoleCommands(self, parameters, context, feedback, executing=True):
arguments = [
- '-st',
+ "-st",
str(self.parameterAsInt(parameters, self.THRESHOLD, context)),
]
if self.parameterAsBoolean(parameters, self.EIGHT_CONNECTEDNESS, context):
- arguments.append('-8')
+ arguments.append("-8")
else:
- arguments.append('-4')
+ arguments.append("-4")
if self.parameterAsBoolean(parameters, self.NO_MASK, context):
- arguments.append('-nomask')
+ arguments.append("-nomask")
mask = self.parameterAsRasterLayer(parameters, self.MASK_LAYER, context)
if mask:
- mask_details = GdalUtils.gdal_connection_details_from_layer(
- mask)
- arguments.append('-mask')
+ mask_details = GdalUtils.gdal_connection_details_from_layer(mask)
+ arguments.append("-mask")
arguments.append(mask_details.connection_string)
out = self.parameterAsOutputLayer(parameters, self.OUTPUT, context)
@@ -120,20 +143,21 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True):
output_format = QgsRasterFileWriter.driverForExtension(os.path.splitext(out)[1])
if not output_format:
- raise QgsProcessingException(self.tr('Output format is invalid'))
+ raise QgsProcessingException(self.tr("Output format is invalid"))
- arguments.append('-of')
+ arguments.append("-of")
arguments.append(output_format)
- if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ''):
+ if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ""):
extra = self.parameterAsString(parameters, self.EXTRA, context)
arguments.append(extra)
raster = self.parameterAsRasterLayer(parameters, self.INPUT, context)
if raster is None:
- raise QgsProcessingException(self.invalidRasterError(parameters, self.INPUT))
- input_details = GdalUtils.gdal_connection_details_from_layer(
- raster)
+ raise QgsProcessingException(
+ self.invalidRasterError(parameters, self.INPUT)
+ )
+ input_details = GdalUtils.gdal_connection_details_from_layer(raster)
arguments.append(input_details.connection_string)
arguments.append(out)
@@ -141,4 +165,7 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True):
if input_details.credential_options:
arguments.extend(input_details.credential_options_as_arguments())
- return [self.commandName() + ('.bat' if isWindows() else '.py'), GdalUtils.escapeAndJoin(arguments)]
+ return [
+ self.commandName() + (".bat" if isWindows() else ".py"),
+ GdalUtils.escapeAndJoin(arguments),
+ ]
diff --git a/python/plugins/processing/algs/gdal/slope.py b/python/plugins/processing/algs/gdal/slope.py
index e7a0cbff8974..c709662ed30f 100644
--- a/python/plugins/processing/algs/gdal/slope.py
+++ b/python/plugins/processing/algs/gdal/slope.py
@@ -15,21 +15,23 @@
***************************************************************************
"""
-__author__ = 'Alexander Bruy'
-__date__ = 'October 2013'
-__copyright__ = '(C) 2013, Alexander Bruy'
+__author__ = "Alexander Bruy"
+__date__ = "October 2013"
+__copyright__ = "(C) 2013, Alexander Bruy"
import os
-from qgis.core import (QgsRasterFileWriter,
- QgsProcessingException,
- QgsProcessingParameterDefinition,
- QgsProcessingParameterRasterLayer,
- QgsProcessingParameterBand,
- QgsProcessingParameterNumber,
- QgsProcessingParameterString,
- QgsProcessingParameterBoolean,
- QgsProcessingParameterRasterDestination)
+from qgis.core import (
+ QgsRasterFileWriter,
+ QgsProcessingException,
+ QgsProcessingParameterDefinition,
+ QgsProcessingParameterRasterLayer,
+ QgsProcessingParameterBand,
+ QgsProcessingParameterNumber,
+ QgsProcessingParameterString,
+ QgsProcessingParameterBoolean,
+ QgsProcessingParameterRasterDestination,
+)
from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm
from processing.algs.gdal.GdalUtils import GdalUtils
@@ -37,107 +39,138 @@
class slope(GdalAlgorithm):
- INPUT = 'INPUT'
- BAND = 'BAND'
- AS_PERCENT = 'AS_PERCENT'
- SCALE = 'SCALE'
- COMPUTE_EDGES = 'COMPUTE_EDGES'
- ZEVENBERGEN = 'ZEVENBERGEN'
- OPTIONS = 'OPTIONS'
- EXTRA = 'EXTRA'
- OUTPUT = 'OUTPUT'
+ INPUT = "INPUT"
+ BAND = "BAND"
+ AS_PERCENT = "AS_PERCENT"
+ SCALE = "SCALE"
+ COMPUTE_EDGES = "COMPUTE_EDGES"
+ ZEVENBERGEN = "ZEVENBERGEN"
+ OPTIONS = "OPTIONS"
+ EXTRA = "EXTRA"
+ OUTPUT = "OUTPUT"
def __init__(self):
super().__init__()
def initAlgorithm(self, config=None):
- self.addParameter(QgsProcessingParameterRasterLayer(self.INPUT, self.tr('Input layer')))
- self.addParameter(QgsProcessingParameterBand(self.BAND,
- self.tr('Band number'),
- 1,
- parentLayerParameterName=self.INPUT))
- self.addParameter(QgsProcessingParameterNumber(self.SCALE,
- self.tr('Ratio of vertical units to horizontal'),
- type=QgsProcessingParameterNumber.Type.Double,
- minValue=0.0,
- defaultValue=1.0))
- self.addParameter(QgsProcessingParameterBoolean(self.AS_PERCENT,
- self.tr('Slope expressed as percent instead of degrees'),
- defaultValue=False))
- self.addParameter(QgsProcessingParameterBoolean(self.COMPUTE_EDGES,
- self.tr('Compute edges'),
- defaultValue=False))
- self.addParameter(QgsProcessingParameterBoolean(self.ZEVENBERGEN,
- self.tr("Use Zevenbergen&Thorne formula instead of the Horn's one"),
- defaultValue=False))
-
- options_param = QgsProcessingParameterString(self.OPTIONS,
- self.tr('Additional creation options'),
- defaultValue='',
- optional=True)
- options_param.setFlags(options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
- options_param.setMetadata({'widget_wrapper': {'widget_type': 'rasteroptions'}})
+ self.addParameter(
+ QgsProcessingParameterRasterLayer(self.INPUT, self.tr("Input layer"))
+ )
+ self.addParameter(
+ QgsProcessingParameterBand(
+ self.BAND,
+ self.tr("Band number"),
+ 1,
+ parentLayerParameterName=self.INPUT,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterNumber(
+ self.SCALE,
+ self.tr("Ratio of vertical units to horizontal"),
+ type=QgsProcessingParameterNumber.Type.Double,
+ minValue=0.0,
+ defaultValue=1.0,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterBoolean(
+ self.AS_PERCENT,
+ self.tr("Slope expressed as percent instead of degrees"),
+ defaultValue=False,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterBoolean(
+ self.COMPUTE_EDGES, self.tr("Compute edges"), defaultValue=False
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterBoolean(
+ self.ZEVENBERGEN,
+ self.tr("Use Zevenbergen&Thorne formula instead of the Horn's one"),
+ defaultValue=False,
+ )
+ )
+
+ options_param = QgsProcessingParameterString(
+ self.OPTIONS,
+ self.tr("Additional creation options"),
+ defaultValue="",
+ optional=True,
+ )
+ options_param.setFlags(
+ options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
+ options_param.setMetadata({"widget_wrapper": {"widget_type": "rasteroptions"}})
self.addParameter(options_param)
- extra_param = QgsProcessingParameterString(self.EXTRA,
- self.tr('Additional command-line parameters'),
- defaultValue=None,
- optional=True)
- extra_param.setFlags(extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
+ extra_param = QgsProcessingParameterString(
+ self.EXTRA,
+ self.tr("Additional command-line parameters"),
+ defaultValue=None,
+ optional=True,
+ )
+ extra_param.setFlags(
+ extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
self.addParameter(extra_param)
- self.addParameter(QgsProcessingParameterRasterDestination(self.OUTPUT, self.tr('Slope')))
+ self.addParameter(
+ QgsProcessingParameterRasterDestination(self.OUTPUT, self.tr("Slope"))
+ )
def name(self):
- return 'slope'
+ return "slope"
def displayName(self):
- return self.tr('Slope')
+ return self.tr("Slope")
def group(self):
- return self.tr('Raster analysis')
+ return self.tr("Raster analysis")
def groupId(self):
- return 'rasteranalysis'
+ return "rasteranalysis"
def commandName(self):
- return 'gdaldem'
+ return "gdaldem"
def getConsoleCommands(self, parameters, context, feedback, executing=True):
inLayer = self.parameterAsRasterLayer(parameters, self.INPUT, context)
if inLayer is None:
- raise QgsProcessingException(self.invalidRasterError(parameters, self.INPUT))
- input_details = GdalUtils.gdal_connection_details_from_layer(
- inLayer)
+ raise QgsProcessingException(
+ self.invalidRasterError(parameters, self.INPUT)
+ )
+ input_details = GdalUtils.gdal_connection_details_from_layer(inLayer)
out = self.parameterAsOutputLayer(parameters, self.OUTPUT, context)
self.setOutputValue(self.OUTPUT, out)
output_format = QgsRasterFileWriter.driverForExtension(os.path.splitext(out)[1])
if not output_format:
- raise QgsProcessingException(self.tr('Output format is invalid'))
+ raise QgsProcessingException(self.tr("Output format is invalid"))
arguments = [
- 'slope',
+ "slope",
input_details.connection_string,
out,
- '-of',
+ "-of",
output_format,
- '-b',
+ "-b",
str(self.parameterAsInt(parameters, self.BAND, context)),
- '-s',
+ "-s",
str(self.parameterAsDouble(parameters, self.SCALE, context)),
]
if self.parameterAsBoolean(parameters, self.AS_PERCENT, context):
- arguments.append('-p')
+ arguments.append("-p")
if self.parameterAsBoolean(parameters, self.COMPUTE_EDGES, context):
- arguments.append('-compute_edges')
+ arguments.append("-compute_edges")
if self.parameterAsBoolean(parameters, self.ZEVENBERGEN, context):
- arguments.append('-alg')
- arguments.append('ZevenbergenThorne')
+ arguments.append("-alg")
+ arguments.append("ZevenbergenThorne")
if input_details.credential_options:
arguments.extend(input_details.credential_options_as_arguments())
@@ -146,7 +179,7 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True):
if options:
arguments.extend(GdalUtils.parseCreationOptions(options))
- if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ''):
+ if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ""):
extra = self.parameterAsString(parameters, self.EXTRA, context)
arguments.append(extra)
diff --git a/python/plugins/processing/algs/gdal/tpi.py b/python/plugins/processing/algs/gdal/tpi.py
index ecd9971da807..77fe1352b33a 100644
--- a/python/plugins/processing/algs/gdal/tpi.py
+++ b/python/plugins/processing/algs/gdal/tpi.py
@@ -15,19 +15,21 @@
***************************************************************************
"""
-__author__ = 'Alexander Bruy'
-__date__ = 'October 2013'
-__copyright__ = '(C) 2013, Alexander Bruy'
+__author__ = "Alexander Bruy"
+__date__ = "October 2013"
+__copyright__ = "(C) 2013, Alexander Bruy"
import os
-from qgis.core import (QgsProcessingException,
- QgsProcessingParameterDefinition,
- QgsProcessingParameterRasterLayer,
- QgsProcessingParameterBand,
- QgsProcessingParameterString,
- QgsProcessingParameterBoolean,
- QgsProcessingParameterRasterDestination)
+from qgis.core import (
+ QgsProcessingException,
+ QgsProcessingParameterDefinition,
+ QgsProcessingParameterRasterLayer,
+ QgsProcessingParameterBand,
+ QgsProcessingParameterString,
+ QgsProcessingParameterBoolean,
+ QgsProcessingParameterRasterDestination,
+)
from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm
from processing.algs.gdal.GdalUtils import GdalUtils
@@ -35,68 +37,85 @@
class tpi(GdalAlgorithm):
- INPUT = 'INPUT'
- BAND = 'BAND'
- COMPUTE_EDGES = 'COMPUTE_EDGES'
- OPTIONS = 'OPTIONS'
- OUTPUT = 'OUTPUT'
+ INPUT = "INPUT"
+ BAND = "BAND"
+ COMPUTE_EDGES = "COMPUTE_EDGES"
+ OPTIONS = "OPTIONS"
+ OUTPUT = "OUTPUT"
def __init__(self):
super().__init__()
def initAlgorithm(self, config=None):
- self.addParameter(QgsProcessingParameterRasterLayer(self.INPUT, self.tr('Input layer')))
- self.addParameter(QgsProcessingParameterBand(self.BAND,
- self.tr('Band number'),
- 1,
- parentLayerParameterName=self.INPUT))
- self.addParameter(QgsProcessingParameterBoolean(self.COMPUTE_EDGES,
- self.tr('Compute edges'),
- defaultValue=False))
-
- options_param = QgsProcessingParameterString(self.OPTIONS,
- self.tr('Additional creation options'),
- defaultValue='',
- optional=True)
- options_param.setFlags(options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
- options_param.setMetadata({'widget_wrapper': {'widget_type': 'rasteroptions'}})
+ self.addParameter(
+ QgsProcessingParameterRasterLayer(self.INPUT, self.tr("Input layer"))
+ )
+ self.addParameter(
+ QgsProcessingParameterBand(
+ self.BAND,
+ self.tr("Band number"),
+ 1,
+ parentLayerParameterName=self.INPUT,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterBoolean(
+ self.COMPUTE_EDGES, self.tr("Compute edges"), defaultValue=False
+ )
+ )
+
+ options_param = QgsProcessingParameterString(
+ self.OPTIONS,
+ self.tr("Additional creation options"),
+ defaultValue="",
+ optional=True,
+ )
+ options_param.setFlags(
+ options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
+ options_param.setMetadata({"widget_wrapper": {"widget_type": "rasteroptions"}})
self.addParameter(options_param)
- self.addParameter(QgsProcessingParameterRasterDestination(self.OUTPUT, self.tr('Topographic Position Index')))
+ self.addParameter(
+ QgsProcessingParameterRasterDestination(
+ self.OUTPUT, self.tr("Topographic Position Index")
+ )
+ )
def name(self):
- return 'tpitopographicpositionindex'
+ return "tpitopographicpositionindex"
def displayName(self):
- return self.tr('Topographic Position Index (TPI)')
+ return self.tr("Topographic Position Index (TPI)")
def group(self):
- return self.tr('Raster analysis')
+ return self.tr("Raster analysis")
def groupId(self):
- return 'rasteranalysis'
+ return "rasteranalysis"
def commandName(self):
- return 'gdaldem'
+ return "gdaldem"
def getConsoleCommands(self, parameters, context, feedback, executing=True):
- arguments = ['TPI']
+ arguments = ["TPI"]
inLayer = self.parameterAsRasterLayer(parameters, self.INPUT, context)
if inLayer is None:
- raise QgsProcessingException(self.invalidRasterError(parameters, self.INPUT))
- input_details = GdalUtils.gdal_connection_details_from_layer(
- inLayer)
+ raise QgsProcessingException(
+ self.invalidRasterError(parameters, self.INPUT)
+ )
+ input_details = GdalUtils.gdal_connection_details_from_layer(inLayer)
arguments.append(input_details.connection_string)
out = self.parameterAsOutputLayer(parameters, self.OUTPUT, context)
self.setOutputValue(self.OUTPUT, out)
arguments.append(out)
- arguments.append('-b')
+ arguments.append("-b")
arguments.append(str(self.parameterAsInt(parameters, self.BAND, context)))
if self.parameterAsBoolean(parameters, self.COMPUTE_EDGES, context):
- arguments.append('-compute_edges')
+ arguments.append("-compute_edges")
if input_details.credential_options:
arguments.extend(input_details.credential_options_as_arguments())
diff --git a/python/plugins/processing/algs/gdal/translate.py b/python/plugins/processing/algs/gdal/translate.py
index b07847326dd7..d820daac0862 100644
--- a/python/plugins/processing/algs/gdal/translate.py
+++ b/python/plugins/processing/algs/gdal/translate.py
@@ -15,24 +15,26 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'August 2012'
-__copyright__ = '(C) 2012, Victor Olaya'
+__author__ = "Victor Olaya"
+__date__ = "August 2012"
+__copyright__ = "(C) 2012, Victor Olaya"
import os
from qgis.PyQt.QtGui import QIcon
-from qgis.core import (QgsRasterFileWriter,
- QgsProcessingException,
- QgsProcessingParameterDefinition,
- QgsProcessingParameterRasterLayer,
- QgsProcessingParameterNumber,
- QgsProcessingParameterBoolean,
- QgsProcessingParameterString,
- QgsProcessingParameterEnum,
- QgsProcessingParameterCrs,
- QgsProcessingParameterRasterDestination)
+from qgis.core import (
+ QgsRasterFileWriter,
+ QgsProcessingException,
+ QgsProcessingParameterDefinition,
+ QgsProcessingParameterRasterLayer,
+ QgsProcessingParameterNumber,
+ QgsProcessingParameterBoolean,
+ QgsProcessingParameterString,
+ QgsProcessingParameterEnum,
+ QgsProcessingParameterCrs,
+ QgsProcessingParameterRasterDestination,
+)
from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm
from processing.algs.gdal.GdalUtils import GdalUtils
@@ -40,86 +42,128 @@
class translate(GdalAlgorithm):
- INPUT = 'INPUT'
- TARGET_CRS = 'TARGET_CRS'
- NODATA = 'NODATA'
- COPY_SUBDATASETS = 'COPY_SUBDATASETS'
- OPTIONS = 'OPTIONS'
- EXTRA = 'EXTRA'
- DATA_TYPE = 'DATA_TYPE'
- OUTPUT = 'OUTPUT'
+ INPUT = "INPUT"
+ TARGET_CRS = "TARGET_CRS"
+ NODATA = "NODATA"
+ COPY_SUBDATASETS = "COPY_SUBDATASETS"
+ OPTIONS = "OPTIONS"
+ EXTRA = "EXTRA"
+ DATA_TYPE = "DATA_TYPE"
+ OUTPUT = "OUTPUT"
def __init__(self):
super().__init__()
def initAlgorithm(self, config=None):
- self.TYPES = [self.tr('Use Input Layer Data Type'), 'Byte', 'Int16', 'UInt16', 'UInt32', 'Int32', 'Float32', 'Float64', 'CInt16', 'CInt32', 'CFloat32', 'CFloat64', 'Int8']
-
- self.addParameter(QgsProcessingParameterRasterLayer(self.INPUT, self.tr('Input layer')))
- self.addParameter(QgsProcessingParameterCrs(self.TARGET_CRS,
- self.tr('Override the projection for the output file'),
- defaultValue=None,
- optional=True))
- self.addParameter(QgsProcessingParameterNumber(self.NODATA,
- self.tr('Assign a specified NoData value to output bands'),
- type=QgsProcessingParameterNumber.Type.Double,
- defaultValue=None,
- optional=True))
- self.addParameter(QgsProcessingParameterBoolean(self.COPY_SUBDATASETS,
- self.tr('Copy all subdatasets of this file to individual output files'),
- defaultValue=False))
-
- options_param = QgsProcessingParameterString(self.OPTIONS,
- self.tr('Additional creation options'),
- defaultValue='',
- optional=True)
- options_param.setFlags(options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
- options_param.setMetadata({'widget_wrapper': {'widget_type': 'rasteroptions'}})
+ self.TYPES = [
+ self.tr("Use Input Layer Data Type"),
+ "Byte",
+ "Int16",
+ "UInt16",
+ "UInt32",
+ "Int32",
+ "Float32",
+ "Float64",
+ "CInt16",
+ "CInt32",
+ "CFloat32",
+ "CFloat64",
+ "Int8",
+ ]
+
+ self.addParameter(
+ QgsProcessingParameterRasterLayer(self.INPUT, self.tr("Input layer"))
+ )
+ self.addParameter(
+ QgsProcessingParameterCrs(
+ self.TARGET_CRS,
+ self.tr("Override the projection for the output file"),
+ defaultValue=None,
+ optional=True,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterNumber(
+ self.NODATA,
+ self.tr("Assign a specified NoData value to output bands"),
+ type=QgsProcessingParameterNumber.Type.Double,
+ defaultValue=None,
+ optional=True,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterBoolean(
+ self.COPY_SUBDATASETS,
+ self.tr("Copy all subdatasets of this file to individual output files"),
+ defaultValue=False,
+ )
+ )
+
+ options_param = QgsProcessingParameterString(
+ self.OPTIONS,
+ self.tr("Additional creation options"),
+ defaultValue="",
+ optional=True,
+ )
+ options_param.setFlags(
+ options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
+ options_param.setMetadata({"widget_wrapper": {"widget_type": "rasteroptions"}})
self.addParameter(options_param)
- extra_param = QgsProcessingParameterString(self.EXTRA,
- self.tr('Additional command-line parameters'),
- defaultValue=None,
- optional=True)
- extra_param.setFlags(extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
+ extra_param = QgsProcessingParameterString(
+ self.EXTRA,
+ self.tr("Additional command-line parameters"),
+ defaultValue=None,
+ optional=True,
+ )
+ extra_param.setFlags(
+ extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
self.addParameter(extra_param)
- dataType_param = QgsProcessingParameterEnum(self.DATA_TYPE,
- self.tr('Output data type'),
- self.TYPES,
- allowMultiple=False,
- defaultValue=0)
- dataType_param.setFlags(dataType_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
+ dataType_param = QgsProcessingParameterEnum(
+ self.DATA_TYPE,
+ self.tr("Output data type"),
+ self.TYPES,
+ allowMultiple=False,
+ defaultValue=0,
+ )
+ dataType_param.setFlags(
+ dataType_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
self.addParameter(dataType_param)
- self.addParameter(QgsProcessingParameterRasterDestination(self.OUTPUT,
- self.tr('Converted')))
+ self.addParameter(
+ QgsProcessingParameterRasterDestination(self.OUTPUT, self.tr("Converted"))
+ )
def name(self):
- return 'translate'
+ return "translate"
def displayName(self):
- return self.tr('Translate (convert format)')
+ return self.tr("Translate (convert format)")
def group(self):
- return self.tr('Raster conversion')
+ return self.tr("Raster conversion")
def groupId(self):
- return 'rasterconversion'
+ return "rasterconversion"
def icon(self):
- return QIcon(os.path.join(pluginPath, 'images', 'gdaltools', 'translate.png'))
+ return QIcon(os.path.join(pluginPath, "images", "gdaltools", "translate.png"))
def commandName(self):
- return 'gdal_translate'
+ return "gdal_translate"
def getConsoleCommands(self, parameters, context, feedback, executing=True):
inLayer = self.parameterAsRasterLayer(parameters, self.INPUT, context)
if inLayer is None:
- raise QgsProcessingException(self.invalidRasterError(parameters, self.INPUT))
- input_details = GdalUtils.gdal_connection_details_from_layer(
- inLayer)
+ raise QgsProcessingException(
+ self.invalidRasterError(parameters, self.INPUT)
+ )
+ input_details = GdalUtils.gdal_connection_details_from_layer(inLayer)
out = self.parameterAsOutputLayer(parameters, self.OUTPUT, context)
self.setOutputValue(self.OUTPUT, out)
@@ -132,35 +176,37 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True):
crs = self.parameterAsCrs(parameters, self.TARGET_CRS, context)
if crs.isValid():
- arguments.append('-a_srs')
+ arguments.append("-a_srs")
arguments.append(GdalUtils.gdal_crs_string(crs))
if nodata is not None:
- arguments.append('-a_nodata')
+ arguments.append("-a_nodata")
arguments.append(nodata)
if self.parameterAsBoolean(parameters, self.COPY_SUBDATASETS, context):
- arguments.append('-sds')
+ arguments.append("-sds")
data_type = self.parameterAsEnum(parameters, self.DATA_TYPE, context)
if data_type:
- if self.TYPES[data_type] == 'Int8' and GdalUtils.version() < 3070000:
- raise QgsProcessingException(self.tr('Int8 data type requires GDAL version 3.7 or later'))
+ if self.TYPES[data_type] == "Int8" and GdalUtils.version() < 3070000:
+ raise QgsProcessingException(
+ self.tr("Int8 data type requires GDAL version 3.7 or later")
+ )
- arguments.append('-ot ' + self.TYPES[data_type])
+ arguments.append("-ot " + self.TYPES[data_type])
output_format = QgsRasterFileWriter.driverForExtension(os.path.splitext(out)[1])
if not output_format:
- raise QgsProcessingException(self.tr('Output format is invalid'))
+ raise QgsProcessingException(self.tr("Output format is invalid"))
- arguments.append('-of')
+ arguments.append("-of")
arguments.append(output_format)
options = self.parameterAsString(parameters, self.OPTIONS, context)
if options:
arguments.extend(GdalUtils.parseCreationOptions(options))
- if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ''):
+ if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ""):
extra = self.parameterAsString(parameters, self.EXTRA, context)
arguments.append(extra)
diff --git a/python/plugins/processing/algs/gdal/tri.py b/python/plugins/processing/algs/gdal/tri.py
index 0b5a2c94b581..44b29014f9a6 100644
--- a/python/plugins/processing/algs/gdal/tri.py
+++ b/python/plugins/processing/algs/gdal/tri.py
@@ -15,19 +15,21 @@
***************************************************************************
"""
-__author__ = 'Alexander Bruy'
-__date__ = 'October 2013'
-__copyright__ = '(C) 2013, Alexander Bruy'
+__author__ = "Alexander Bruy"
+__date__ = "October 2013"
+__copyright__ = "(C) 2013, Alexander Bruy"
import os
-from qgis.core import (QgsProcessingException,
- QgsProcessingParameterDefinition,
- QgsProcessingParameterRasterLayer,
- QgsProcessingParameterBand,
- QgsProcessingParameterString,
- QgsProcessingParameterBoolean,
- QgsProcessingParameterRasterDestination)
+from qgis.core import (
+ QgsProcessingException,
+ QgsProcessingParameterDefinition,
+ QgsProcessingParameterRasterLayer,
+ QgsProcessingParameterBand,
+ QgsProcessingParameterString,
+ QgsProcessingParameterBoolean,
+ QgsProcessingParameterRasterDestination,
+)
from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm
from processing.algs.gdal.GdalUtils import GdalUtils
@@ -35,70 +37,87 @@
class tri(GdalAlgorithm):
- INPUT = 'INPUT'
- BAND = 'BAND'
- COMPUTE_EDGES = 'COMPUTE_EDGES'
- OPTIONS = 'OPTIONS'
- OUTPUT = 'OUTPUT'
+ INPUT = "INPUT"
+ BAND = "BAND"
+ COMPUTE_EDGES = "COMPUTE_EDGES"
+ OPTIONS = "OPTIONS"
+ OUTPUT = "OUTPUT"
def __init__(self):
super().__init__()
def initAlgorithm(self, config=None):
- self.addParameter(QgsProcessingParameterRasterLayer(self.INPUT, self.tr('Input layer')))
- self.addParameter(QgsProcessingParameterBand(self.BAND,
- self.tr('Band number'),
- 1,
- parentLayerParameterName=self.INPUT))
- self.addParameter(QgsProcessingParameterBoolean(self.COMPUTE_EDGES,
- self.tr('Compute edges'),
- defaultValue=False))
-
- options_param = QgsProcessingParameterString(self.OPTIONS,
- self.tr('Additional creation options'),
- defaultValue='',
- optional=True)
- options_param.setFlags(options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
- options_param.setMetadata({'widget_wrapper': {'widget_type': 'rasteroptions'}})
+ self.addParameter(
+ QgsProcessingParameterRasterLayer(self.INPUT, self.tr("Input layer"))
+ )
+ self.addParameter(
+ QgsProcessingParameterBand(
+ self.BAND,
+ self.tr("Band number"),
+ 1,
+ parentLayerParameterName=self.INPUT,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterBoolean(
+ self.COMPUTE_EDGES, self.tr("Compute edges"), defaultValue=False
+ )
+ )
+
+ options_param = QgsProcessingParameterString(
+ self.OPTIONS,
+ self.tr("Additional creation options"),
+ defaultValue="",
+ optional=True,
+ )
+ options_param.setFlags(
+ options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
+ options_param.setMetadata({"widget_wrapper": {"widget_type": "rasteroptions"}})
self.addParameter(options_param)
- self.addParameter(QgsProcessingParameterRasterDestination(self.OUTPUT, self.tr('Terrain Ruggedness Index')))
+ self.addParameter(
+ QgsProcessingParameterRasterDestination(
+ self.OUTPUT, self.tr("Terrain Ruggedness Index")
+ )
+ )
def name(self):
- return 'triterrainruggednessindex'
+ return "triterrainruggednessindex"
def displayName(self):
- return self.tr('Terrain Ruggedness Index (TRI)')
+ return self.tr("Terrain Ruggedness Index (TRI)")
def group(self):
- return self.tr('Raster analysis')
+ return self.tr("Raster analysis")
def groupId(self):
- return 'rasteranalysis'
+ return "rasteranalysis"
def commandName(self):
- return 'gdaldem'
+ return "gdaldem"
def getConsoleCommands(self, parameters, context, feedback, executing=True):
inLayer = self.parameterAsRasterLayer(parameters, self.INPUT, context)
if inLayer is None:
- raise QgsProcessingException(self.invalidRasterError(parameters, self.INPUT))
- input_details = GdalUtils.gdal_connection_details_from_layer(
- inLayer)
+ raise QgsProcessingException(
+ self.invalidRasterError(parameters, self.INPUT)
+ )
+ input_details = GdalUtils.gdal_connection_details_from_layer(inLayer)
out = self.parameterAsOutputLayer(parameters, self.OUTPUT, context)
self.setOutputValue(self.OUTPUT, out)
arguments = [
- 'TRI',
+ "TRI",
input_details.connection_string,
out,
- '-b',
+ "-b",
str(self.parameterAsInt(parameters, self.BAND, context)),
]
if self.parameterAsBoolean(parameters, self.COMPUTE_EDGES, context):
- arguments.append('-compute_edges')
+ arguments.append("-compute_edges")
if input_details.credential_options:
arguments.extend(input_details.credential_options_as_arguments())
diff --git a/python/plugins/processing/algs/gdal/viewshed.py b/python/plugins/processing/algs/gdal/viewshed.py
index 50d0f4e90305..b908cc6bdafd 100644
--- a/python/plugins/processing/algs/gdal/viewshed.py
+++ b/python/plugins/processing/algs/gdal/viewshed.py
@@ -15,22 +15,24 @@
***************************************************************************
"""
-__author__ = 'Alexander Bruy'
-__date__ = 'October 2019'
-__copyright__ = '(C) 2019, Alexander Bruy'
+__author__ = "Alexander Bruy"
+__date__ = "October 2019"
+__copyright__ = "(C) 2019, Alexander Bruy"
import os
-from qgis.core import (QgsRasterFileWriter,
- QgsProcessingException,
- QgsProcessingParameterDefinition,
- QgsProcessingParameterRasterLayer,
- QgsProcessingParameterBand,
- QgsProcessingParameterPoint,
- QgsProcessingParameterNumber,
- QgsProcessingParameterDistance,
- QgsProcessingParameterString,
- QgsProcessingParameterRasterDestination)
+from qgis.core import (
+ QgsRasterFileWriter,
+ QgsProcessingException,
+ QgsProcessingParameterDefinition,
+ QgsProcessingParameterRasterLayer,
+ QgsProcessingParameterBand,
+ QgsProcessingParameterPoint,
+ QgsProcessingParameterNumber,
+ QgsProcessingParameterDistance,
+ QgsProcessingParameterString,
+ QgsProcessingParameterRasterDestination,
+)
from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm
from processing.algs.gdal.GdalUtils import GdalUtils
@@ -38,83 +40,111 @@
class viewshed(GdalAlgorithm):
- INPUT = 'INPUT'
- BAND = 'BAND'
- OBSERVER = 'OBSERVER'
- OBSERVER_HEIGHT = 'OBSERVER_HEIGHT'
- TARGET_HEIGHT = 'TARGET_HEIGHT'
- MAX_DISTANCE = 'MAX_DISTANCE'
- OPTIONS = 'OPTIONS'
- EXTRA = 'EXTRA'
- OUTPUT = 'OUTPUT'
+ INPUT = "INPUT"
+ BAND = "BAND"
+ OBSERVER = "OBSERVER"
+ OBSERVER_HEIGHT = "OBSERVER_HEIGHT"
+ TARGET_HEIGHT = "TARGET_HEIGHT"
+ MAX_DISTANCE = "MAX_DISTANCE"
+ OPTIONS = "OPTIONS"
+ EXTRA = "EXTRA"
+ OUTPUT = "OUTPUT"
def __init__(self):
super().__init__()
def initAlgorithm(self, config=None):
- self.addParameter(QgsProcessingParameterRasterLayer(self.INPUT,
- self.tr('Input layer')))
- self.addParameter(QgsProcessingParameterBand(self.BAND,
- self.tr('Band number'),
- 1,
- parentLayerParameterName=self.INPUT))
- self.addParameter(QgsProcessingParameterPoint(self.OBSERVER,
- self.tr('Observer location')))
- self.addParameter(QgsProcessingParameterNumber(self.OBSERVER_HEIGHT,
- self.tr('Observer height, DEM units'),
- type=QgsProcessingParameterNumber.Type.Double,
- minValue=0.0,
- defaultValue=1.0))
- self.addParameter(QgsProcessingParameterNumber(self.TARGET_HEIGHT,
- self.tr('Target height, DEM units'),
- type=QgsProcessingParameterNumber.Type.Double,
- minValue=0.0,
- defaultValue=1.0))
- self.addParameter(QgsProcessingParameterDistance(self.MAX_DISTANCE,
- self.tr('Maximum distance from observer to compute visibility'),
- parentParameterName=self.INPUT,
- minValue=0.0,
- defaultValue=100.0))
-
- options_param = QgsProcessingParameterString(self.OPTIONS,
- self.tr('Additional creation options'),
- defaultValue='',
- optional=True)
- options_param.setFlags(options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
- options_param.setMetadata({'widget_wrapper': {'widget_type': 'rasteroptions'}})
+ self.addParameter(
+ QgsProcessingParameterRasterLayer(self.INPUT, self.tr("Input layer"))
+ )
+ self.addParameter(
+ QgsProcessingParameterBand(
+ self.BAND,
+ self.tr("Band number"),
+ 1,
+ parentLayerParameterName=self.INPUT,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterPoint(self.OBSERVER, self.tr("Observer location"))
+ )
+ self.addParameter(
+ QgsProcessingParameterNumber(
+ self.OBSERVER_HEIGHT,
+ self.tr("Observer height, DEM units"),
+ type=QgsProcessingParameterNumber.Type.Double,
+ minValue=0.0,
+ defaultValue=1.0,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterNumber(
+ self.TARGET_HEIGHT,
+ self.tr("Target height, DEM units"),
+ type=QgsProcessingParameterNumber.Type.Double,
+ minValue=0.0,
+ defaultValue=1.0,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterDistance(
+ self.MAX_DISTANCE,
+ self.tr("Maximum distance from observer to compute visibility"),
+ parentParameterName=self.INPUT,
+ minValue=0.0,
+ defaultValue=100.0,
+ )
+ )
+
+ options_param = QgsProcessingParameterString(
+ self.OPTIONS,
+ self.tr("Additional creation options"),
+ defaultValue="",
+ optional=True,
+ )
+ options_param.setFlags(
+ options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
+ options_param.setMetadata({"widget_wrapper": {"widget_type": "rasteroptions"}})
self.addParameter(options_param)
- extra_param = QgsProcessingParameterString(self.EXTRA,
- self.tr('Additional command-line parameters'),
- defaultValue=None,
- optional=True)
- extra_param.setFlags(extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
+ extra_param = QgsProcessingParameterString(
+ self.EXTRA,
+ self.tr("Additional command-line parameters"),
+ defaultValue=None,
+ optional=True,
+ )
+ extra_param.setFlags(
+ extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
self.addParameter(extra_param)
- self.addParameter(QgsProcessingParameterRasterDestination(self.OUTPUT,
- self.tr('Output')))
+ self.addParameter(
+ QgsProcessingParameterRasterDestination(self.OUTPUT, self.tr("Output"))
+ )
def name(self):
- return 'viewshed'
+ return "viewshed"
def displayName(self):
- return self.tr('Viewshed')
+ return self.tr("Viewshed")
def group(self):
- return self.tr('Raster miscellaneous')
+ return self.tr("Raster miscellaneous")
def groupId(self):
- return 'rastermiscellaneous'
+ return "rastermiscellaneous"
def commandName(self):
- return 'gdal_viewshed'
+ return "gdal_viewshed"
def getConsoleCommands(self, parameters, context, feedback, executing=True):
dem = self.parameterAsRasterLayer(parameters, self.INPUT, context)
if dem is None:
- raise QgsProcessingException(self.invalidRasterError(parameters, self.INPUT))
- dem_input_details = GdalUtils.gdal_connection_details_from_layer(
- dem)
+ raise QgsProcessingException(
+ self.invalidRasterError(parameters, self.INPUT)
+ )
+ dem_input_details = GdalUtils.gdal_connection_details_from_layer(dem)
out = self.parameterAsOutputLayer(parameters, self.OUTPUT, context)
self.setOutputValue(self.OUTPUT, out)
@@ -122,28 +152,27 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True):
observer = self.parameterAsPoint(parameters, self.OBSERVER, context, dem.crs())
arguments = [
- '-b',
- f'{self.parameterAsInt(parameters, self.BAND, context)}',
- '-ox',
- f'{observer.x()}',
- '-oy',
- f'{observer.y()}',
- '-oz',
- f'{self.parameterAsDouble(parameters, self.OBSERVER_HEIGHT, context)}',
- '-tz',
- f'{self.parameterAsDouble(parameters, self.TARGET_HEIGHT, context)}',
- '-md',
- f'{self.parameterAsDouble(parameters, self.MAX_DISTANCE, context)}',
-
- '-f',
- QgsRasterFileWriter.driverForExtension(os.path.splitext(out)[1])
+ "-b",
+ f"{self.parameterAsInt(parameters, self.BAND, context)}",
+ "-ox",
+ f"{observer.x()}",
+ "-oy",
+ f"{observer.y()}",
+ "-oz",
+ f"{self.parameterAsDouble(parameters, self.OBSERVER_HEIGHT, context)}",
+ "-tz",
+ f"{self.parameterAsDouble(parameters, self.TARGET_HEIGHT, context)}",
+ "-md",
+ f"{self.parameterAsDouble(parameters, self.MAX_DISTANCE, context)}",
+ "-f",
+ QgsRasterFileWriter.driverForExtension(os.path.splitext(out)[1]),
]
options = self.parameterAsString(parameters, self.OPTIONS, context)
if options:
arguments.extend(GdalUtils.parseCreationOptions(options))
- if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ''):
+ if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ""):
extra = self.parameterAsString(parameters, self.EXTRA, context)
arguments.append(extra)
diff --git a/python/plugins/processing/algs/gdal/warp.py b/python/plugins/processing/algs/gdal/warp.py
index ea9aa16a7551..f1fe96b19928 100644
--- a/python/plugins/processing/algs/gdal/warp.py
+++ b/python/plugins/processing/algs/gdal/warp.py
@@ -15,25 +15,26 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'August 2012'
-__copyright__ = '(C) 2012, Victor Olaya'
+__author__ = "Victor Olaya"
+__date__ = "August 2012"
+__copyright__ = "(C) 2012, Victor Olaya"
import os
from qgis.PyQt.QtGui import QIcon
-from qgis.core import (QgsRasterFileWriter,
- QgsProcessingException,
- QgsProcessingParameterDefinition,
- QgsProcessingParameterRasterLayer,
- QgsProcessingParameterCrs,
- QgsProcessingParameterNumber,
- QgsProcessingParameterEnum,
- QgsProcessingParameterBoolean,
- QgsProcessingParameterExtent,
- QgsProcessingParameterString,
- QgsProcessingParameterRasterDestination,
- )
+from qgis.core import (
+ QgsRasterFileWriter,
+ QgsProcessingException,
+ QgsProcessingParameterDefinition,
+ QgsProcessingParameterRasterLayer,
+ QgsProcessingParameterCrs,
+ QgsProcessingParameterNumber,
+ QgsProcessingParameterEnum,
+ QgsProcessingParameterBoolean,
+ QgsProcessingParameterExtent,
+ QgsProcessingParameterString,
+ QgsProcessingParameterRasterDestination,
+)
from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm
from processing.algs.gdal.GdalUtils import GdalUtils
@@ -42,135 +43,198 @@
class warp(GdalAlgorithm):
- INPUT = 'INPUT'
- SOURCE_CRS = 'SOURCE_CRS'
- TARGET_CRS = 'TARGET_CRS'
- NODATA = 'NODATA'
- TARGET_RESOLUTION = 'TARGET_RESOLUTION'
- OPTIONS = 'OPTIONS'
- RESAMPLING = 'RESAMPLING'
- DATA_TYPE = 'DATA_TYPE'
- TARGET_EXTENT = 'TARGET_EXTENT'
- TARGET_EXTENT_CRS = 'TARGET_EXTENT_CRS'
- MULTITHREADING = 'MULTITHREADING'
- EXTRA = 'EXTRA'
- OUTPUT = 'OUTPUT'
+ INPUT = "INPUT"
+ SOURCE_CRS = "SOURCE_CRS"
+ TARGET_CRS = "TARGET_CRS"
+ NODATA = "NODATA"
+ TARGET_RESOLUTION = "TARGET_RESOLUTION"
+ OPTIONS = "OPTIONS"
+ RESAMPLING = "RESAMPLING"
+ DATA_TYPE = "DATA_TYPE"
+ TARGET_EXTENT = "TARGET_EXTENT"
+ TARGET_EXTENT_CRS = "TARGET_EXTENT_CRS"
+ MULTITHREADING = "MULTITHREADING"
+ EXTRA = "EXTRA"
+ OUTPUT = "OUTPUT"
def __init__(self):
super().__init__()
def initAlgorithm(self, config=None):
- self.methods = ((self.tr('Nearest Neighbour'), 'near'),
- (self.tr('Bilinear (2x2 Kernel)'), 'bilinear'),
- (self.tr('Cubic (4x4 Kernel)'), 'cubic'),
- (self.tr('Cubic B-Spline (4x4 Kernel)'), 'cubicspline'),
- (self.tr('Lanczos (6x6 Kernel)'), 'lanczos'),
- (self.tr('Average'), 'average'),
- (self.tr('Mode'), 'mode'),
- (self.tr('Maximum'), 'max'),
- (self.tr('Minimum'), 'min'),
- (self.tr('Median'), 'med'),
- (self.tr('First Quartile (Q1)'), 'q1'),
- (self.tr('Third Quartile (Q3)'), 'q3'))
-
- self.TYPES = [self.tr('Use Input Layer Data Type'), 'Byte', 'Int16', 'UInt16', 'UInt32', 'Int32', 'Float32', 'Float64', 'CInt16', 'CInt32', 'CFloat32', 'CFloat64', 'Int8']
-
- self.addParameter(QgsProcessingParameterRasterLayer(self.INPUT, self.tr('Input layer')))
- self.addParameter(QgsProcessingParameterCrs(self.SOURCE_CRS,
- self.tr('Source CRS'),
- optional=True))
- self.addParameter(QgsProcessingParameterCrs(self.TARGET_CRS,
- self.tr('Target CRS'),
- optional=True))
- self.addParameter(QgsProcessingParameterEnum(self.RESAMPLING,
- self.tr('Resampling method to use'),
- options=[i[0] for i in self.methods],
- defaultValue=0))
- self.addParameter(QgsProcessingParameterNumber(self.NODATA,
- self.tr('Nodata value for output bands'),
- type=QgsProcessingParameterNumber.Type.Double,
- defaultValue=None,
- optional=True))
- self.addParameter(QgsProcessingParameterNumber(self.TARGET_RESOLUTION,
- self.tr('Output file resolution in target georeferenced units'),
- type=QgsProcessingParameterNumber.Type.Double,
- minValue=0.0,
- defaultValue=None,
- optional=True))
-
- options_param = QgsProcessingParameterString(self.OPTIONS,
- self.tr('Additional creation options'),
- defaultValue='',
- optional=True)
- options_param.setFlags(options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
- options_param.setMetadata({'widget_wrapper': {'widget_type': 'rasteroptions'}})
+ self.methods = (
+ (self.tr("Nearest Neighbour"), "near"),
+ (self.tr("Bilinear (2x2 Kernel)"), "bilinear"),
+ (self.tr("Cubic (4x4 Kernel)"), "cubic"),
+ (self.tr("Cubic B-Spline (4x4 Kernel)"), "cubicspline"),
+ (self.tr("Lanczos (6x6 Kernel)"), "lanczos"),
+ (self.tr("Average"), "average"),
+ (self.tr("Mode"), "mode"),
+ (self.tr("Maximum"), "max"),
+ (self.tr("Minimum"), "min"),
+ (self.tr("Median"), "med"),
+ (self.tr("First Quartile (Q1)"), "q1"),
+ (self.tr("Third Quartile (Q3)"), "q3"),
+ )
+
+ self.TYPES = [
+ self.tr("Use Input Layer Data Type"),
+ "Byte",
+ "Int16",
+ "UInt16",
+ "UInt32",
+ "Int32",
+ "Float32",
+ "Float64",
+ "CInt16",
+ "CInt32",
+ "CFloat32",
+ "CFloat64",
+ "Int8",
+ ]
+
+ self.addParameter(
+ QgsProcessingParameterRasterLayer(self.INPUT, self.tr("Input layer"))
+ )
+ self.addParameter(
+ QgsProcessingParameterCrs(
+ self.SOURCE_CRS, self.tr("Source CRS"), optional=True
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterCrs(
+ self.TARGET_CRS, self.tr("Target CRS"), optional=True
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterEnum(
+ self.RESAMPLING,
+ self.tr("Resampling method to use"),
+ options=[i[0] for i in self.methods],
+ defaultValue=0,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterNumber(
+ self.NODATA,
+ self.tr("Nodata value for output bands"),
+ type=QgsProcessingParameterNumber.Type.Double,
+ defaultValue=None,
+ optional=True,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterNumber(
+ self.TARGET_RESOLUTION,
+ self.tr("Output file resolution in target georeferenced units"),
+ type=QgsProcessingParameterNumber.Type.Double,
+ minValue=0.0,
+ defaultValue=None,
+ optional=True,
+ )
+ )
+
+ options_param = QgsProcessingParameterString(
+ self.OPTIONS,
+ self.tr("Additional creation options"),
+ defaultValue="",
+ optional=True,
+ )
+ options_param.setFlags(
+ options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
+ options_param.setMetadata({"widget_wrapper": {"widget_type": "rasteroptions"}})
self.addParameter(options_param)
- dataType_param = QgsProcessingParameterEnum(self.DATA_TYPE,
- self.tr('Output data type'),
- self.TYPES,
- allowMultiple=False,
- defaultValue=0)
- dataType_param.setFlags(dataType_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
+ dataType_param = QgsProcessingParameterEnum(
+ self.DATA_TYPE,
+ self.tr("Output data type"),
+ self.TYPES,
+ allowMultiple=False,
+ defaultValue=0,
+ )
+ dataType_param.setFlags(
+ dataType_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
self.addParameter(dataType_param)
- target_extent_param = QgsProcessingParameterExtent(self.TARGET_EXTENT,
- self.tr('Georeferenced extents of output file to be created'),
- optional=True)
- target_extent_param.setFlags(target_extent_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
+ target_extent_param = QgsProcessingParameterExtent(
+ self.TARGET_EXTENT,
+ self.tr("Georeferenced extents of output file to be created"),
+ optional=True,
+ )
+ target_extent_param.setFlags(
+ target_extent_param.flags()
+ | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
self.addParameter(target_extent_param)
- target_extent_crs_param = QgsProcessingParameterCrs(self.TARGET_EXTENT_CRS,
- self.tr('CRS of the target raster extent'),
- optional=True)
- target_extent_crs_param.setFlags(target_extent_crs_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
+ target_extent_crs_param = QgsProcessingParameterCrs(
+ self.TARGET_EXTENT_CRS,
+ self.tr("CRS of the target raster extent"),
+ optional=True,
+ )
+ target_extent_crs_param.setFlags(
+ target_extent_crs_param.flags()
+ | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
self.addParameter(target_extent_crs_param)
- multithreading_param = QgsProcessingParameterBoolean(self.MULTITHREADING,
- self.tr('Use multithreaded warping implementation'),
- defaultValue=False)
- multithreading_param.setFlags(multithreading_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
+ multithreading_param = QgsProcessingParameterBoolean(
+ self.MULTITHREADING,
+ self.tr("Use multithreaded warping implementation"),
+ defaultValue=False,
+ )
+ multithreading_param.setFlags(
+ multithreading_param.flags()
+ | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
self.addParameter(multithreading_param)
- extra_param = QgsProcessingParameterString(self.EXTRA,
- self.tr('Additional command-line parameters'),
- defaultValue=None,
- optional=True)
- extra_param.setFlags(extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
+ extra_param = QgsProcessingParameterString(
+ self.EXTRA,
+ self.tr("Additional command-line parameters"),
+ defaultValue=None,
+ optional=True,
+ )
+ extra_param.setFlags(
+ extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
self.addParameter(extra_param)
- self.addParameter(QgsProcessingParameterRasterDestination(self.OUTPUT,
- self.tr('Reprojected')))
+ self.addParameter(
+ QgsProcessingParameterRasterDestination(self.OUTPUT, self.tr("Reprojected"))
+ )
def name(self):
- return 'warpreproject'
+ return "warpreproject"
def displayName(self):
- return self.tr('Warp (reproject)')
+ return self.tr("Warp (reproject)")
def group(self):
- return self.tr('Raster projections')
+ return self.tr("Raster projections")
def groupId(self):
- return 'rasterprojections'
+ return "rasterprojections"
def icon(self):
- return QIcon(os.path.join(pluginPath, 'images', 'gdaltools', 'warp.png'))
+ return QIcon(os.path.join(pluginPath, "images", "gdaltools", "warp.png"))
def commandName(self):
- return 'gdalwarp'
+ return "gdalwarp"
def tags(self):
- tags = self.tr('transform,reproject,crs,srs,resample').split(',')
+ tags = self.tr("transform,reproject,crs,srs,resample").split(",")
tags.extend(super().tags())
return tags
def getConsoleCommands(self, parameters, context, feedback, executing=True):
inLayer = self.parameterAsRasterLayer(parameters, self.INPUT, context)
if inLayer is None:
- raise QgsProcessingException(self.invalidRasterError(parameters, self.INPUT))
- input_details = GdalUtils.gdal_connection_details_from_layer(
- inLayer)
+ raise QgsProcessingException(
+ self.invalidRasterError(parameters, self.INPUT)
+ )
+ input_details = GdalUtils.gdal_connection_details_from_layer(inLayer)
sourceCrs = self.parameterAsCrs(parameters, self.SOURCE_CRS, context)
targetCrs = self.parameterAsCrs(parameters, self.TARGET_CRS, context)
@@ -180,30 +244,32 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True):
nodata = None
resolution = self.parameterAsDouble(parameters, self.TARGET_RESOLUTION, context)
- arguments = ['-overwrite']
+ arguments = ["-overwrite"]
if sourceCrs.isValid():
- arguments.append('-s_srs')
+ arguments.append("-s_srs")
arguments.append(GdalUtils.gdal_crs_string(sourceCrs))
if targetCrs.isValid():
- arguments.append('-t_srs')
+ arguments.append("-t_srs")
arguments.append(GdalUtils.gdal_crs_string(targetCrs))
if nodata is not None:
- arguments.append('-dstnodata')
+ arguments.append("-dstnodata")
arguments.append(str(nodata))
if resolution:
- arguments.append('-tr')
+ arguments.append("-tr")
arguments.append(str(resolution))
arguments.append(str(resolution))
- arguments.append('-r')
- arguments.append(self.methods[self.parameterAsEnum(parameters, self.RESAMPLING, context)][1])
+ arguments.append("-r")
+ arguments.append(
+ self.methods[self.parameterAsEnum(parameters, self.RESAMPLING, context)][1]
+ )
extent = self.parameterAsExtent(parameters, self.TARGET_EXTENT, context)
if not extent.isNull():
- arguments.append('-te')
+ arguments.append("-te")
arguments.append(extent.xMinimum())
arguments.append(extent.yMinimum())
arguments.append(extent.xMaximum())
@@ -211,34 +277,36 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True):
extentCrs = self.parameterAsCrs(parameters, self.TARGET_EXTENT_CRS, context)
if extentCrs.isValid():
- arguments.append('-te_srs')
+ arguments.append("-te_srs")
arguments.append(GdalUtils.gdal_crs_string(extentCrs))
if self.parameterAsBoolean(parameters, self.MULTITHREADING, context):
- arguments.append('-multi')
+ arguments.append("-multi")
data_type = self.parameterAsEnum(parameters, self.DATA_TYPE, context)
if data_type:
- if self.TYPES[data_type] == 'Int8' and GdalUtils.version() < 3070000:
- raise QgsProcessingException(self.tr('Int8 data type requires GDAL version 3.7 or later'))
+ if self.TYPES[data_type] == "Int8" and GdalUtils.version() < 3070000:
+ raise QgsProcessingException(
+ self.tr("Int8 data type requires GDAL version 3.7 or later")
+ )
- arguments.append('-ot ' + self.TYPES[data_type])
+ arguments.append("-ot " + self.TYPES[data_type])
out = self.parameterAsOutputLayer(parameters, self.OUTPUT, context)
self.setOutputValue(self.OUTPUT, out)
output_format = QgsRasterFileWriter.driverForExtension(os.path.splitext(out)[1])
if not output_format:
- raise QgsProcessingException(self.tr('Output format is invalid'))
+ raise QgsProcessingException(self.tr("Output format is invalid"))
- arguments.append('-of')
+ arguments.append("-of")
arguments.append(output_format)
options = self.parameterAsString(parameters, self.OPTIONS, context)
if options:
arguments.extend(GdalUtils.parseCreationOptions(options))
- if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ''):
+ if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ""):
extra = self.parameterAsString(parameters, self.EXTRA, context)
arguments.append(extra)
diff --git a/python/plugins/processing/algs/help/__init__.py b/python/plugins/processing/algs/help/__init__.py
index 3e6cd60eaec4..b2001ff4bad7 100644
--- a/python/plugins/processing/algs/help/__init__.py
+++ b/python/plugins/processing/algs/help/__init__.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'January 2016'
-__copyright__ = '(C) 2016, Victor Olaya'
+__author__ = "Victor Olaya"
+__date__ = "January 2016"
+__copyright__ = "(C) 2016, Victor Olaya"
import os
import codecs
@@ -37,25 +37,29 @@ def loadShortHelp():
for f in os.listdir(path):
if f.endswith("yaml"):
filename = os.path.join(path, f)
- with codecs.open(filename, encoding='utf-8') as stream:
+ with codecs.open(filename, encoding="utf-8") as stream:
with warnings.catch_warnings():
warnings.filterwarnings("ignore", category=DeprecationWarning)
for k, v in yaml.load(stream, Loader=yaml.SafeLoader).items():
if v is None:
continue
- h[k] = QCoreApplication.translate(f"{f[:-5].upper()}Algorithm", v)
+ h[k] = QCoreApplication.translate(
+ f"{f[:-5].upper()}Algorithm", v
+ )
version = ".".join(Qgis.QGIS_VERSION.split(".")[0:2])
- overrideLocale = QgsSettings().value('locale/overrideFlag', False, bool)
+ overrideLocale = QgsSettings().value("locale/overrideFlag", False, bool)
if not overrideLocale:
locale = QLocale.system().name()[:2]
else:
- locale = QgsSettings().value('locale/userLocale', '')
+ locale = QgsSettings().value("locale/userLocale", "")
locale = locale.split("_")[0]
def replace(s):
if s is not None:
- return s.replace("{qgisdocs}", f"https://docs.qgis.org/{version}/{locale}/docs")
+ return s.replace(
+ "{qgisdocs}", f"https://docs.qgis.org/{version}/{locale}/docs"
+ )
else:
return None
diff --git a/python/plugins/processing/algs/qgis/BarPlot.py b/python/plugins/processing/algs/qgis/BarPlot.py
index f17162870da9..bc2985839d91 100644
--- a/python/plugins/processing/algs/qgis/BarPlot.py
+++ b/python/plugins/processing/algs/qgis/BarPlot.py
@@ -15,18 +15,20 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'January 2013'
-__copyright__ = '(C) 2013, Victor Olaya'
+__author__ = "Victor Olaya"
+__date__ = "January 2013"
+__copyright__ = "(C) 2013, Victor Olaya"
import warnings
-from qgis.core import (QgsFeatureRequest,
- QgsProcessingParameterFeatureSource,
- QgsProcessingParameterField,
- QgsProcessingException,
- QgsProcessingParameterFileDestination,
- QgsProcessingParameterString,)
+from qgis.core import (
+ QgsFeatureRequest,
+ QgsProcessingParameterFeatureSource,
+ QgsProcessingParameterField,
+ QgsProcessingException,
+ QgsProcessingParameterFileDestination,
+ QgsProcessingParameterString,
+)
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
from processing.tools import vector
@@ -34,55 +36,73 @@
class BarPlot(QgisAlgorithm):
- INPUT = 'INPUT'
- OUTPUT = 'OUTPUT'
- NAME_FIELD = 'NAME_FIELD'
- VALUE_FIELD = 'VALUE_FIELD'
- TITLE = 'TITLE'
+ INPUT = "INPUT"
+ OUTPUT = "OUTPUT"
+ NAME_FIELD = "NAME_FIELD"
+ VALUE_FIELD = "VALUE_FIELD"
+ TITLE = "TITLE"
XAXIS_TITLE = "XAXIS_TITLE"
YAXIS_TITLE = "YAXIS_TITLE"
def group(self):
- return self.tr('Plots')
+ return self.tr("Plots")
def groupId(self):
- return 'plots'
+ return "plots"
def __init__(self):
super().__init__()
def initAlgorithm(self, config=None):
- self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT,
- self.tr('Input layer')))
- self.addParameter(QgsProcessingParameterField(self.NAME_FIELD,
- self.tr('Category name field'),
- None, self.INPUT, QgsProcessingParameterField.DataType.Any))
- self.addParameter(QgsProcessingParameterField(self.VALUE_FIELD,
- self.tr('Value field'),
- None, self.INPUT, QgsProcessingParameterField.DataType.Numeric))
-
- self.addParameter(QgsProcessingParameterFileDestination(self.OUTPUT, self.tr('Bar plot'), self.tr('HTML files (*.html)')))
-
- self.addParameter(QgsProcessingParameterString(
- self.TITLE,
- self.tr('Title'),
- optional=True))
-
- self.addParameter(QgsProcessingParameterString(
- self.XAXIS_TITLE,
- self.tr('X-axis title'),
- optional=True))
-
- self.addParameter(QgsProcessingParameterString(
- self.YAXIS_TITLE,
- self.tr('Y-axis title'),
- optional=True))
+ self.addParameter(
+ QgsProcessingParameterFeatureSource(self.INPUT, self.tr("Input layer"))
+ )
+ self.addParameter(
+ QgsProcessingParameterField(
+ self.NAME_FIELD,
+ self.tr("Category name field"),
+ None,
+ self.INPUT,
+ QgsProcessingParameterField.DataType.Any,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterField(
+ self.VALUE_FIELD,
+ self.tr("Value field"),
+ None,
+ self.INPUT,
+ QgsProcessingParameterField.DataType.Numeric,
+ )
+ )
+
+ self.addParameter(
+ QgsProcessingParameterFileDestination(
+ self.OUTPUT, self.tr("Bar plot"), self.tr("HTML files (*.html)")
+ )
+ )
+
+ self.addParameter(
+ QgsProcessingParameterString(self.TITLE, self.tr("Title"), optional=True)
+ )
+
+ self.addParameter(
+ QgsProcessingParameterString(
+ self.XAXIS_TITLE, self.tr("X-axis title"), optional=True
+ )
+ )
+
+ self.addParameter(
+ QgsProcessingParameterString(
+ self.YAXIS_TITLE, self.tr("Y-axis title"), optional=True
+ )
+ )
def name(self):
- return 'barplot'
+ return "barplot"
def displayName(self):
- return self.tr('Bar plot')
+ return self.tr("Bar plot")
def processAlgorithm(self, parameters, context, feedback):
try:
@@ -93,11 +113,18 @@ def processAlgorithm(self, parameters, context, feedback):
import plotly as plt
import plotly.graph_objs as go
except ImportError:
- raise QgsProcessingException(QCoreApplication.translate('BarPlot', 'This algorithm requires the Python “plotly” library. Please install this library and try again.'))
+ raise QgsProcessingException(
+ QCoreApplication.translate(
+ "BarPlot",
+ "This algorithm requires the Python “plotly” library. Please install this library and try again.",
+ )
+ )
source = self.parameterAsSource(parameters, self.INPUT, context)
if source is None:
- raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT))
+ raise QgsProcessingException(
+ self.invalidSourceError(parameters, self.INPUT)
+ )
namefieldname = self.parameterAsString(parameters, self.NAME_FIELD, context)
valuefieldname = self.parameterAsString(parameters, self.VALUE_FIELD, context)
@@ -121,16 +148,24 @@ def processAlgorithm(self, parameters, context, feedback):
values = vector.values(source, valuefieldname)
- x_var = vector.convert_nulls([i[namefieldname] for i in source.getFeatures(QgsFeatureRequest().setFlags(QgsFeatureRequest.Flag.NoGeometry))], '')
+ x_var = vector.convert_nulls(
+ [
+ i[namefieldname]
+ for i in source.getFeatures(
+ QgsFeatureRequest().setFlags(QgsFeatureRequest.Flag.NoGeometry)
+ )
+ ],
+ "",
+ )
- data = [go.Bar(x=x_var,
- y=values[valuefieldname])]
+ data = [go.Bar(x=x_var, y=values[valuefieldname])]
fig = go.Figure(
data=data,
layout_title_text=title,
layout_xaxis_title=xaxis_title,
- layout_yaxis_title=yaxis_title)
+ layout_yaxis_title=yaxis_title,
+ )
fig.write_html(output)
diff --git a/python/plugins/processing/algs/qgis/BoxPlot.py b/python/plugins/processing/algs/qgis/BoxPlot.py
index 55d2d5ba7b7e..ff31b05bcda0 100644
--- a/python/plugins/processing/algs/qgis/BoxPlot.py
+++ b/python/plugins/processing/algs/qgis/BoxPlot.py
@@ -15,19 +15,21 @@
***************************************************************************
"""
-__author__ = 'Matteo Ghetta'
-__date__ = 'March 2017'
-__copyright__ = '(C) 2017, Matteo Ghetta'
+__author__ = "Matteo Ghetta"
+__date__ = "March 2017"
+__copyright__ = "(C) 2017, Matteo Ghetta"
import warnings
-from qgis.core import (QgsProcessingException,
- QgsProcessingParameterFeatureSource,
- QgsProcessingParameterField,
- QgsProcessingParameterEnum,
- QgsProcessingParameterFileDestination,
- QgsFeatureRequest,
- QgsProcessingParameterString)
+from qgis.core import (
+ QgsProcessingException,
+ QgsProcessingParameterFeatureSource,
+ QgsProcessingParameterField,
+ QgsProcessingParameterEnum,
+ QgsProcessingParameterFileDestination,
+ QgsFeatureRequest,
+ QgsProcessingParameterString,
+)
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
from processing.tools import vector
@@ -35,66 +37,85 @@
class BoxPlot(QgisAlgorithm):
- INPUT = 'INPUT'
- OUTPUT = 'OUTPUT'
- NAME_FIELD = 'NAME_FIELD'
- VALUE_FIELD = 'VALUE_FIELD'
- MSD = 'MSD'
- TITLE = 'TITLE'
+ INPUT = "INPUT"
+ OUTPUT = "OUTPUT"
+ NAME_FIELD = "NAME_FIELD"
+ VALUE_FIELD = "VALUE_FIELD"
+ MSD = "MSD"
+ TITLE = "TITLE"
XAXIS_TITLE = "XAXIS_TITLE"
YAXIS_TITLE = "YAXIS_TITLE"
def group(self):
- return self.tr('Plots')
+ return self.tr("Plots")
def groupId(self):
- return 'plots'
+ return "plots"
def __init__(self):
super().__init__()
def initAlgorithm(self, config=None):
- self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT,
- self.tr('Input layer')))
- self.addParameter(QgsProcessingParameterField(self.NAME_FIELD,
- self.tr('Category name field'),
- parentLayerParameterName=self.INPUT,
- type=QgsProcessingParameterField.DataType.Any))
- self.addParameter(QgsProcessingParameterField(self.VALUE_FIELD,
- self.tr('Value field'),
- parentLayerParameterName=self.INPUT,
- type=QgsProcessingParameterField.DataType.Numeric))
- msd = [self.tr('Show Mean'),
- self.tr('Show Standard Deviation'),
- self.tr('Don\'t show Mean and Standard Deviation')
- ]
- self.addParameter(QgsProcessingParameterEnum(
- self.MSD,
- self.tr('Additional Statistic Lines'),
- options=msd, defaultValue=0))
-
- self.addParameter(QgsProcessingParameterString(
- self.TITLE,
- self.tr('Title'),
- optional=True))
-
- self.addParameter(QgsProcessingParameterString(
- self.XAXIS_TITLE,
- self.tr('X-axis title'),
- optional=True))
-
- self.addParameter(QgsProcessingParameterString(
- self.YAXIS_TITLE,
- self.tr('Y-axis title'),
- optional=True))
-
- self.addParameter(QgsProcessingParameterFileDestination(self.OUTPUT, self.tr('Box plot'), self.tr('HTML files (*.html)')))
+ self.addParameter(
+ QgsProcessingParameterFeatureSource(self.INPUT, self.tr("Input layer"))
+ )
+ self.addParameter(
+ QgsProcessingParameterField(
+ self.NAME_FIELD,
+ self.tr("Category name field"),
+ parentLayerParameterName=self.INPUT,
+ type=QgsProcessingParameterField.DataType.Any,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterField(
+ self.VALUE_FIELD,
+ self.tr("Value field"),
+ parentLayerParameterName=self.INPUT,
+ type=QgsProcessingParameterField.DataType.Numeric,
+ )
+ )
+ msd = [
+ self.tr("Show Mean"),
+ self.tr("Show Standard Deviation"),
+ self.tr("Don't show Mean and Standard Deviation"),
+ ]
+ self.addParameter(
+ QgsProcessingParameterEnum(
+ self.MSD,
+ self.tr("Additional Statistic Lines"),
+ options=msd,
+ defaultValue=0,
+ )
+ )
+
+ self.addParameter(
+ QgsProcessingParameterString(self.TITLE, self.tr("Title"), optional=True)
+ )
+
+ self.addParameter(
+ QgsProcessingParameterString(
+ self.XAXIS_TITLE, self.tr("X-axis title"), optional=True
+ )
+ )
+
+ self.addParameter(
+ QgsProcessingParameterString(
+ self.YAXIS_TITLE, self.tr("Y-axis title"), optional=True
+ )
+ )
+
+ self.addParameter(
+ QgsProcessingParameterFileDestination(
+ self.OUTPUT, self.tr("Box plot"), self.tr("HTML files (*.html)")
+ )
+ )
def name(self):
- return 'boxplot'
+ return "boxplot"
def displayName(self):
- return self.tr('Box plot')
+ return self.tr("Box plot")
def processAlgorithm(self, parameters, context, feedback):
try:
@@ -105,11 +126,18 @@ def processAlgorithm(self, parameters, context, feedback):
import plotly as plt
import plotly.graph_objs as go
except ImportError:
- raise QgsProcessingException(QCoreApplication.translate('BoxPlot', 'This algorithm requires the Python “plotly” library. Please install this library and try again.'))
+ raise QgsProcessingException(
+ QCoreApplication.translate(
+ "BoxPlot",
+ "This algorithm requires the Python “plotly” library. Please install this library and try again.",
+ )
+ )
source = self.parameterAsSource(parameters, self.INPUT, context)
if source is None:
- raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT))
+ raise QgsProcessingException(
+ self.invalidSourceError(parameters, self.INPUT)
+ )
namefieldname = self.parameterAsString(parameters, self.NAME_FIELD, context)
valuefieldname = self.parameterAsString(parameters, self.VALUE_FIELD, context)
@@ -134,26 +162,34 @@ def processAlgorithm(self, parameters, context, feedback):
values = vector.values(source, valuefieldname)
x_index = source.fields().lookupField(namefieldname)
- x_var = vector.convert_nulls([i[namefieldname] for i in source.getFeatures(QgsFeatureRequest().setFlags(QgsFeatureRequest.Flag.NoGeometry).setSubsetOfAttributes([x_index]))], '')
+ x_var = vector.convert_nulls(
+ [
+ i[namefieldname]
+ for i in source.getFeatures(
+ QgsFeatureRequest()
+ .setFlags(QgsFeatureRequest.Flag.NoGeometry)
+ .setSubsetOfAttributes([x_index])
+ )
+ ],
+ "",
+ )
msdIndex = self.parameterAsEnum(parameters, self.MSD, context)
msd = True
if msdIndex == 1:
- msd = 'sd'
+ msd = "sd"
elif msdIndex == 2:
msd = False
- data = [go.Box(
- x=x_var,
- y=values[valuefieldname],
- boxmean=msd)]
+ data = [go.Box(x=x_var, y=values[valuefieldname], boxmean=msd)]
fig = go.Figure(
data=data,
layout_title_text=title,
layout_xaxis_title=xaxis_title,
- layout_yaxis_title=yaxis_title)
+ layout_yaxis_title=yaxis_title,
+ )
fig.write_html(output)
diff --git a/python/plugins/processing/algs/qgis/Buffer.py b/python/plugins/processing/algs/qgis/Buffer.py
index 80e5f352f3fb..8ae866643040 100644
--- a/python/plugins/processing/algs/qgis/Buffer.py
+++ b/python/plugins/processing/algs/qgis/Buffer.py
@@ -15,19 +15,27 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'August 2012'
-__copyright__ = '(C) 2012, Victor Olaya'
+__author__ = "Victor Olaya"
+__date__ = "August 2012"
+__copyright__ = "(C) 2012, Victor Olaya"
-from qgis.core import (Qgis,
- QgsFeature,
- QgsGeometry,
- QgsFeatureRequest,
- QgsFeatureSink)
+from qgis.core import Qgis, QgsFeature, QgsGeometry, QgsFeatureRequest, QgsFeatureSink
-def buffering(feedback, context, sink, distance, field, useField, source, dissolve, segments, endCapStyle=1,
- joinStyle=1, miterLimit=2):
+def buffering(
+ feedback,
+ context,
+ sink,
+ distance,
+ field,
+ useField,
+ source,
+ dissolve,
+ segments,
+ endCapStyle=1,
+ joinStyle=1,
+ miterLimit=2,
+):
if useField:
field = source.fields().lookupField(field)
@@ -42,7 +50,9 @@ def buffering(feedback, context, sink, distance, field, useField, source, dissol
if useField:
attributes_to_fetch.append(field)
- features = source.getFeatures(QgsFeatureRequest().setSubsetOfAttributes(attributes_to_fetch))
+ features = source.getFeatures(
+ QgsFeatureRequest().setSubsetOfAttributes(attributes_to_fetch)
+ )
buffered_geometries = []
for inFeat in features:
if feedback.isCanceled():
@@ -56,7 +66,15 @@ def buffering(feedback, context, sink, distance, field, useField, source, dissol
inGeom = inFeat.geometry()
- buffered_geometries.append(inGeom.buffer(float(value), segments, Qgis.EndCapStyle(endCapStyle), Qgis.JoinStyle(joinStyle), miterLimit))
+ buffered_geometries.append(
+ inGeom.buffer(
+ float(value),
+ segments,
+ Qgis.EndCapStyle(endCapStyle),
+ Qgis.JoinStyle(joinStyle),
+ miterLimit,
+ )
+ )
current += 1
feedback.setProgress(int(current * total))
@@ -80,7 +98,13 @@ def buffering(feedback, context, sink, distance, field, useField, source, dissol
value = distance
inGeom = inFeat.geometry()
outFeat = QgsFeature()
- outGeom = inGeom.buffer(float(value), segments, Qgis.EndCapStyle(endCapStyle), Qgis.JoinStyle(joinStyle), miterLimit)
+ outGeom = inGeom.buffer(
+ float(value),
+ segments,
+ Qgis.EndCapStyle(endCapStyle),
+ Qgis.JoinStyle(joinStyle),
+ miterLimit,
+ )
outFeat.setGeometry(outGeom)
outFeat.setAttributes(attrs)
sink.addFeature(outFeat, QgsFeatureSink.Flag.FastInsert)
diff --git a/python/plugins/processing/algs/qgis/CheckValidity.py b/python/plugins/processing/algs/qgis/CheckValidity.py
index 013daabef381..27f6c0439301 100644
--- a/python/plugins/processing/algs/qgis/CheckValidity.py
+++ b/python/plugins/processing/algs/qgis/CheckValidity.py
@@ -15,33 +15,35 @@
***************************************************************************
"""
-__author__ = 'Arnaud Morvan'
-__date__ = 'May 2015'
-__copyright__ = '(C) 2015, Arnaud Morvan'
+__author__ = "Arnaud Morvan"
+__date__ = "May 2015"
+__copyright__ = "(C) 2015, Arnaud Morvan"
import os
from qgis.PyQt.QtGui import QIcon
from qgis.PyQt.QtCore import QMetaType
-from qgis.core import (Qgis,
- QgsApplication,
- QgsSettings,
- QgsGeometry,
- QgsFeature,
- QgsField,
- QgsFeatureRequest,
- QgsFeatureSink,
- QgsWkbTypes,
- QgsFields,
- QgsProcessing,
- QgsProcessingException,
- QgsProcessingFeatureSource,
- QgsProcessingParameterFeatureSource,
- QgsProcessingParameterEnum,
- QgsProcessingParameterFeatureSink,
- QgsProcessingOutputNumber,
- QgsProcessingParameterBoolean)
+from qgis.core import (
+ Qgis,
+ QgsApplication,
+ QgsSettings,
+ QgsGeometry,
+ QgsFeature,
+ QgsField,
+ QgsFeatureRequest,
+ QgsFeatureSink,
+ QgsWkbTypes,
+ QgsFields,
+ QgsProcessing,
+ QgsProcessingException,
+ QgsProcessingFeatureSource,
+ QgsProcessingParameterFeatureSource,
+ QgsProcessingParameterEnum,
+ QgsProcessingParameterFeatureSink,
+ QgsProcessingOutputNumber,
+ QgsProcessingParameterBoolean,
+)
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
settings_method_key = "/digitizing/validate-geometries"
@@ -49,15 +51,15 @@
class CheckValidity(QgisAlgorithm):
- INPUT_LAYER = 'INPUT_LAYER'
- METHOD = 'METHOD'
- VALID_OUTPUT = 'VALID_OUTPUT'
- VALID_COUNT = 'VALID_COUNT'
- INVALID_OUTPUT = 'INVALID_OUTPUT'
- INVALID_COUNT = 'INVALID_COUNT'
- ERROR_OUTPUT = 'ERROR_OUTPUT'
- ERROR_COUNT = 'ERROR_COUNT'
- IGNORE_RING_SELF_INTERSECTION = 'IGNORE_RING_SELF_INTERSECTION'
+ INPUT_LAYER = "INPUT_LAYER"
+ METHOD = "METHOD"
+ VALID_OUTPUT = "VALID_OUTPUT"
+ VALID_COUNT = "VALID_COUNT"
+ INVALID_OUTPUT = "INVALID_OUTPUT"
+ INVALID_COUNT = "INVALID_COUNT"
+ ERROR_OUTPUT = "ERROR_OUTPUT"
+ ERROR_COUNT = "ERROR_COUNT"
+ IGNORE_RING_SELF_INTERSECTION = "IGNORE_RING_SELF_INTERSECTION"
def icon(self):
return QgsApplication.getThemeIcon("/algorithms/mAlgorithmCheckGeometry.svg")
@@ -66,51 +68,99 @@ def svgIconPath(self):
return QgsApplication.iconPath("/algorithms/mAlgorithmCheckGeometry.svg")
def group(self):
- return self.tr('Vector geometry')
+ return self.tr("Vector geometry")
def groupId(self):
- return 'vectorgeometry'
+ return "vectorgeometry"
def tags(self):
- return self.tr('valid,invalid,detect,error').split(',')
+ return self.tr("valid,invalid,detect,error").split(",")
def __init__(self):
super().__init__()
def initAlgorithm(self, config=None):
- self.methods = [self.tr('The one selected in digitizing settings'),
- 'QGIS',
- 'GEOS']
-
- self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT_LAYER,
- self.tr('Input layer')))
- self.addParameter(QgsProcessingParameterEnum(self.METHOD,
- self.tr('Method'), self.methods, defaultValue=2))
- self.parameterDefinition(self.METHOD).setMetadata({
- 'widget_wrapper': {
- 'useCheckBoxes': True,
- 'columns': 3}})
+ self.methods = [
+ self.tr("The one selected in digitizing settings"),
+ "QGIS",
+ "GEOS",
+ ]
+
+ self.addParameter(
+ QgsProcessingParameterFeatureSource(
+ self.INPUT_LAYER, self.tr("Input layer")
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterEnum(
+ self.METHOD, self.tr("Method"), self.methods, defaultValue=2
+ )
+ )
+ self.parameterDefinition(self.METHOD).setMetadata(
+ {"widget_wrapper": {"useCheckBoxes": True, "columns": 3}}
+ )
- self.addParameter(QgsProcessingParameterBoolean(self.IGNORE_RING_SELF_INTERSECTION,
- self.tr('Ignore ring self intersections'), defaultValue=False))
+ self.addParameter(
+ QgsProcessingParameterBoolean(
+ self.IGNORE_RING_SELF_INTERSECTION,
+ self.tr("Ignore ring self intersections"),
+ defaultValue=False,
+ )
+ )
- self.addParameter(QgsProcessingParameterFeatureSink(self.VALID_OUTPUT, self.tr('Valid output'), QgsProcessing.SourceType.TypeVectorAnyGeometry, None, True))
- self.addOutput(QgsProcessingOutputNumber(self.VALID_COUNT, self.tr('Count of valid features')))
+ self.addParameter(
+ QgsProcessingParameterFeatureSink(
+ self.VALID_OUTPUT,
+ self.tr("Valid output"),
+ QgsProcessing.SourceType.TypeVectorAnyGeometry,
+ None,
+ True,
+ )
+ )
+ self.addOutput(
+ QgsProcessingOutputNumber(
+ self.VALID_COUNT, self.tr("Count of valid features")
+ )
+ )
- self.addParameter(QgsProcessingParameterFeatureSink(self.INVALID_OUTPUT, self.tr('Invalid output'), QgsProcessing.SourceType.TypeVectorAnyGeometry, None, True))
- self.addOutput(QgsProcessingOutputNumber(self.INVALID_COUNT, self.tr('Count of invalid features')))
+ self.addParameter(
+ QgsProcessingParameterFeatureSink(
+ self.INVALID_OUTPUT,
+ self.tr("Invalid output"),
+ QgsProcessing.SourceType.TypeVectorAnyGeometry,
+ None,
+ True,
+ )
+ )
+ self.addOutput(
+ QgsProcessingOutputNumber(
+ self.INVALID_COUNT, self.tr("Count of invalid features")
+ )
+ )
- self.addParameter(QgsProcessingParameterFeatureSink(self.ERROR_OUTPUT, self.tr('Error output'), QgsProcessing.SourceType.TypeVectorAnyGeometry, None, True))
- self.addOutput(QgsProcessingOutputNumber(self.ERROR_COUNT, self.tr('Count of errors')))
+ self.addParameter(
+ QgsProcessingParameterFeatureSink(
+ self.ERROR_OUTPUT,
+ self.tr("Error output"),
+ QgsProcessing.SourceType.TypeVectorAnyGeometry,
+ None,
+ True,
+ )
+ )
+ self.addOutput(
+ QgsProcessingOutputNumber(self.ERROR_COUNT, self.tr("Count of errors"))
+ )
def name(self):
- return 'checkvalidity'
+ return "checkvalidity"
def displayName(self):
- return self.tr('Check validity')
+ return self.tr("Check validity")
def processAlgorithm(self, parameters, context, feedback):
- ignore_ring_self_intersection = self.parameterAsBoolean(parameters, self.IGNORE_RING_SELF_INTERSECTION, context)
+ ignore_ring_self_intersection = self.parameterAsBoolean(
+ parameters, self.IGNORE_RING_SELF_INTERSECTION, context
+ )
method_param = self.parameterAsEnum(parameters, self.METHOD, context)
if method_param == 0:
settings = QgsSettings()
@@ -123,29 +173,60 @@ def processAlgorithm(self, parameters, context, feedback):
method, parameters, context, feedback, ignore_ring_self_intersection
)
- def doCheck(self, method, parameters, context, feedback, ignore_ring_self_intersection):
- flags = QgsGeometry.ValidityFlag.FlagAllowSelfTouchingHoles if ignore_ring_self_intersection else QgsGeometry.ValidityFlags()
+ def doCheck(
+ self, method, parameters, context, feedback, ignore_ring_self_intersection
+ ):
+ flags = (
+ QgsGeometry.ValidityFlag.FlagAllowSelfTouchingHoles
+ if ignore_ring_self_intersection
+ else QgsGeometry.ValidityFlags()
+ )
source = self.parameterAsSource(parameters, self.INPUT_LAYER, context)
if source is None:
- raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT_LAYER))
-
- (valid_output_sink, valid_output_dest_id) = self.parameterAsSink(parameters, self.VALID_OUTPUT, context,
- source.fields(), source.wkbType(), source.sourceCrs())
+ raise QgsProcessingException(
+ self.invalidSourceError(parameters, self.INPUT_LAYER)
+ )
+
+ (valid_output_sink, valid_output_dest_id) = self.parameterAsSink(
+ parameters,
+ self.VALID_OUTPUT,
+ context,
+ source.fields(),
+ source.wkbType(),
+ source.sourceCrs(),
+ )
valid_count = 0
invalid_fields = source.fields()
- invalid_fields.append(QgsField('_errors', QMetaType.Type.QString, 'string', 255))
- (invalid_output_sink, invalid_output_dest_id) = self.parameterAsSink(parameters, self.INVALID_OUTPUT, context,
- invalid_fields, source.wkbType(), source.sourceCrs())
+ invalid_fields.append(
+ QgsField("_errors", QMetaType.Type.QString, "string", 255)
+ )
+ (invalid_output_sink, invalid_output_dest_id) = self.parameterAsSink(
+ parameters,
+ self.INVALID_OUTPUT,
+ context,
+ invalid_fields,
+ source.wkbType(),
+ source.sourceCrs(),
+ )
invalid_count = 0
error_fields = QgsFields()
- error_fields.append(QgsField('message', QMetaType.Type.QString, 'string', 255))
- (error_output_sink, error_output_dest_id) = self.parameterAsSink(parameters, self.ERROR_OUTPUT, context,
- error_fields, QgsWkbTypes.Type.Point, source.sourceCrs())
+ error_fields.append(QgsField("message", QMetaType.Type.QString, "string", 255))
+ (error_output_sink, error_output_dest_id) = self.parameterAsSink(
+ parameters,
+ self.ERROR_OUTPUT,
+ context,
+ error_fields,
+ QgsWkbTypes.Type.Point,
+ source.sourceCrs(),
+ )
error_count = 0
- features = source.getFeatures(QgsFeatureRequest(), QgsProcessingFeatureSource.Flag.FlagSkipGeometryValidityChecks)
+ features = source.getFeatures(
+ QgsFeatureRequest(),
+ QgsProcessingFeatureSource.Flag.FlagSkipGeometryValidityChecks,
+ )
total = 100.0 / source.featureCount() if source.featureCount() else 0
for current, inFeat in enumerate(features):
if feedback.isCanceled():
@@ -155,7 +236,9 @@ def doCheck(self, method, parameters, context, feedback, ignore_ring_self_inters
valid = True
if not geom.isNull() and not geom.isEmpty():
- errors = list(geom.validateGeometry(Qgis.GeometryValidationEngine(method), flags))
+ errors = list(
+ geom.validateGeometry(Qgis.GeometryValidationEngine(method), flags)
+ )
if errors:
valid = False
reasons = []
@@ -165,14 +248,16 @@ def doCheck(self, method, parameters, context, feedback, ignore_ring_self_inters
errFeat.setGeometry(error_geom)
errFeat.setAttributes([error.what()])
if error_output_sink:
- error_output_sink.addFeature(errFeat, QgsFeatureSink.Flag.FastInsert)
+ error_output_sink.addFeature(
+ errFeat, QgsFeatureSink.Flag.FastInsert
+ )
error_count += 1
reasons.append(error.what())
reason = "\n".join(reasons)
if len(reason) > 255:
- reason = reason[:252] + '…'
+ reason = reason[:252] + "…"
attrs.append(reason)
outFeat = QgsFeature()
@@ -181,12 +266,16 @@ def doCheck(self, method, parameters, context, feedback, ignore_ring_self_inters
if valid:
if valid_output_sink:
- valid_output_sink.addFeature(outFeat, QgsFeatureSink.Flag.FastInsert)
+ valid_output_sink.addFeature(
+ outFeat, QgsFeatureSink.Flag.FastInsert
+ )
valid_count += 1
else:
if invalid_output_sink:
- invalid_output_sink.addFeature(outFeat, QgsFeatureSink.Flag.FastInsert)
+ invalid_output_sink.addFeature(
+ outFeat, QgsFeatureSink.Flag.FastInsert
+ )
invalid_count += 1
feedback.setProgress(int(current * total))
@@ -194,7 +283,7 @@ def doCheck(self, method, parameters, context, feedback, ignore_ring_self_inters
results = {
self.VALID_COUNT: valid_count,
self.INVALID_COUNT: invalid_count,
- self.ERROR_COUNT: error_count
+ self.ERROR_COUNT: error_count,
}
if valid_output_sink:
valid_output_sink.finalize()
diff --git a/python/plugins/processing/algs/qgis/Climb.py b/python/plugins/processing/algs/qgis/Climb.py
index 219ea184b36c..cc5efaa48489 100644
--- a/python/plugins/processing/algs/qgis/Climb.py
+++ b/python/plugins/processing/algs/qgis/Climb.py
@@ -16,9 +16,9 @@
***************************************************************************/
"""
-__author__ = 'Håvard Tveite'
-__date__ = '2019-03-01'
-__copyright__ = '(C) 2019 by Håvard Tveite'
+__author__ = "Håvard Tveite"
+__date__ = "2019-03-01"
+__copyright__ = "(C) 2019 by Håvard Tveite"
import os
import math
@@ -26,45 +26,47 @@
from qgis.PyQt.QtGui import QIcon
from qgis.PyQt.QtCore import QMetaType
-from qgis.core import (QgsProcessing,
- QgsFeatureSink,
- QgsProcessingAlgorithm,
- QgsProcessingParameterFeatureSource,
- QgsProcessingParameterFeatureSink,
- QgsProcessingOutputNumber,
- QgsProcessingException,
- QgsProcessingUtils,
- QgsWkbTypes,
- QgsFields,
- QgsField)
+from qgis.core import (
+ QgsProcessing,
+ QgsFeatureSink,
+ QgsProcessingAlgorithm,
+ QgsProcessingParameterFeatureSource,
+ QgsProcessingParameterFeatureSink,
+ QgsProcessingOutputNumber,
+ QgsProcessingException,
+ QgsProcessingUtils,
+ QgsWkbTypes,
+ QgsFields,
+ QgsField,
+)
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
class Climb(QgisAlgorithm):
- INPUT = 'INPUT'
- OUTPUT = 'OUTPUT'
-
- TOTALCLIMB = 'TOTALCLIMB'
- TOTALDESCENT = 'TOTALDESCENT'
- MINELEVATION = 'MINELEVATION'
- MAXELEVATION = 'MAXELEVATION'
- CLIMBATTRIBUTE = 'climb'
- DESCENTATTRIBUTE = 'descent'
- MINELEVATTRIBUTE = 'minelev'
- MAXELEVATTRIBUTE = 'maxelev'
+ INPUT = "INPUT"
+ OUTPUT = "OUTPUT"
+
+ TOTALCLIMB = "TOTALCLIMB"
+ TOTALDESCENT = "TOTALDESCENT"
+ MINELEVATION = "MINELEVATION"
+ MAXELEVATION = "MAXELEVATION"
+ CLIMBATTRIBUTE = "climb"
+ DESCENTATTRIBUTE = "descent"
+ MINELEVATTRIBUTE = "minelev"
+ MAXELEVATTRIBUTE = "maxelev"
def name(self):
- return 'climbalongline'
+ return "climbalongline"
def displayName(self):
- return self.tr('Climb along line')
+ return self.tr("Climb along line")
def group(self):
- return self.tr('Vector analysis')
+ return self.tr("Vector analysis")
def groupId(self):
- return 'vectoranalysis'
+ return "vectoranalysis"
def __init__(self):
super().__init__()
@@ -73,53 +75,34 @@ def initAlgorithm(self, config=None):
self.addParameter(
QgsProcessingParameterFeatureSource(
self.INPUT,
- self.tr('Line layer'),
- [QgsProcessing.SourceType.TypeVectorLine]
+ self.tr("Line layer"),
+ [QgsProcessing.SourceType.TypeVectorLine],
)
)
self.addParameter(
- QgsProcessingParameterFeatureSink(
- self.OUTPUT,
- self.tr('Climb layer')
- )
+ QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr("Climb layer"))
)
self.addOutput(
- QgsProcessingOutputNumber(
- self.TOTALCLIMB,
- self.tr('Total climb')
- )
+ QgsProcessingOutputNumber(self.TOTALCLIMB, self.tr("Total climb"))
)
self.addOutput(
- QgsProcessingOutputNumber(
- self.TOTALDESCENT,
- self.tr('Total descent')
- )
+ QgsProcessingOutputNumber(self.TOTALDESCENT, self.tr("Total descent"))
)
self.addOutput(
- QgsProcessingOutputNumber(
- self.MINELEVATION,
- self.tr('Minimum elevation')
- )
+ QgsProcessingOutputNumber(self.MINELEVATION, self.tr("Minimum elevation"))
)
self.addOutput(
- QgsProcessingOutputNumber(
- self.MAXELEVATION,
- self.tr('Maximum elevation')
- )
+ QgsProcessingOutputNumber(self.MAXELEVATION, self.tr("Maximum elevation"))
)
def processAlgorithm(self, parameters, context, feedback):
- source = self.parameterAsSource(
- parameters,
- self.INPUT,
- context
- )
+ source = self.parameterAsSource(parameters, self.INPUT, context)
fcount = source.featureCount()
source_fields = source.fields()
@@ -127,7 +110,11 @@ def processAlgorithm(self, parameters, context, feedback):
hasZ = QgsWkbTypes.hasZ(source.wkbType())
if not hasZ:
- raise QgsProcessingException(self.tr('The layer does not have Z values. If you have a DEM, use the Drape algorithm to extract Z values.'))
+ raise QgsProcessingException(
+ self.tr(
+ "The layer does not have Z values. If you have a DEM, use the Drape algorithm to extract Z values."
+ )
+ )
thefields = QgsFields()
climbindex = -1
@@ -147,19 +134,21 @@ def processAlgorithm(self, parameters, context, feedback):
layerwithz = source
- (sink, dest_id) = self.parameterAsSink(parameters,
- self.OUTPUT,
- context,
- out_fields,
- layerwithz.wkbType(),
- source.sourceCrs())
+ (sink, dest_id) = self.parameterAsSink(
+ parameters,
+ self.OUTPUT,
+ context,
+ out_fields,
+ layerwithz.wkbType(),
+ source.sourceCrs(),
+ )
# get features from source (with z values)
features = layerwithz.getFeatures()
totalclimb = 0
totaldescent = 0
- minelevation = float('Infinity')
- maxelevation = float('-Infinity')
+ minelevation = float("Infinity")
+ maxelevation = float("-Infinity")
no_z_nodes = []
no_geometry = []
@@ -169,16 +158,12 @@ def processAlgorithm(self, parameters, context, feedback):
break
climb = 0
descent = 0
- minelev = float('Infinity')
- maxelev = float('-Infinity')
+ minelev = float("Infinity")
+ maxelev = float("-Infinity")
# In case of multigeometries we need to do the parts
parts = feature.geometry().constParts()
if not feature.hasGeometry():
- no_geometry.append(self.tr(
- 'Feature: {feature_id}'.format(
- feature_id=feature.id())
- )
- )
+ no_geometry.append(self.tr(f"Feature: {feature.id()}"))
for partnumber, part in enumerate(parts):
# Calculate the climb
first = True
@@ -186,12 +171,14 @@ def processAlgorithm(self, parameters, context, feedback):
for idx, v in enumerate(part.vertices()):
zval = v.z()
if math.isnan(zval):
- no_z_nodes.append(self.tr(
- 'Feature: {feature_id}, part: {part_id}, point: {point_id}'.format(
- feature_id=feature.id(),
- part_id=partnumber,
- point_id=idx)
- )
+ no_z_nodes.append(
+ self.tr(
+ "Feature: {feature_id}, part: {part_id}, point: {point_id}".format(
+ feature_id=feature.id(),
+ part_id=partnumber,
+ point_id=idx,
+ )
+ )
)
continue
if first:
@@ -212,13 +199,7 @@ def processAlgorithm(self, parameters, context, feedback):
totaldescent += descent
# Set the attribute values
# Append the attributes to the end of the existing ones
- attrs = [
- climb,
- descent,
- minelev,
- maxelev,
- *feature.attributes()
- ]
+ attrs = [climb, descent, minelev, maxelev, *feature.attributes()]
# Set the final attribute list
feature.setAttributes(attrs)
# Add a feature to the sink
@@ -229,22 +210,29 @@ def processAlgorithm(self, parameters, context, feedback):
if fcount > 0:
feedback.setProgress(int(100 * current / fcount))
- feedback.pushInfo(self.tr(
- 'The following features do not have geometry: {no_geometry_report}'.format(
- no_geometry_report=(', '.join(no_geometry)))
- )
+ feedback.pushInfo(
+ self.tr(
+ "The following features do not have geometry: {no_geometry_report}".format(
+ no_geometry_report=(", ".join(no_geometry))
+ )
+ )
)
- feedback.pushInfo(self.tr(
- 'The following points do not have Z values: {no_z_report}'.format(
- no_z_report=(', '.join(no_z_nodes)))
- )
+ feedback.pushInfo(
+ self.tr(
+ "The following points do not have Z values: {no_z_report}".format(
+ no_z_report=(", ".join(no_z_nodes))
+ )
+ )
)
sink.finalize()
# Return the results
- return {self.OUTPUT: dest_id, self.TOTALCLIMB: totalclimb,
- self.TOTALDESCENT: totaldescent,
- self.MINELEVATION: minelevation,
- self.MAXELEVATION: maxelevation}
+ return {
+ self.OUTPUT: dest_id,
+ self.TOTALCLIMB: totalclimb,
+ self.TOTALDESCENT: totaldescent,
+ self.MINELEVATION: minelevation,
+ self.MAXELEVATION: maxelevation,
+ }
diff --git a/python/plugins/processing/algs/qgis/DefineProjection.py b/python/plugins/processing/algs/qgis/DefineProjection.py
index 473eb3a4be51..5b1db6673b50 100644
--- a/python/plugins/processing/algs/qgis/DefineProjection.py
+++ b/python/plugins/processing/algs/qgis/DefineProjection.py
@@ -15,20 +15,22 @@
***************************************************************************
"""
-__author__ = 'Alexander Bruy'
-__date__ = 'January 2016'
-__copyright__ = '(C) 2016, Alexander Bruy'
+__author__ = "Alexander Bruy"
+__date__ = "January 2016"
+__copyright__ = "(C) 2016, Alexander Bruy"
import os
import re
-from qgis.core import (QgsProcessing,
- QgsProcessingAlgorithm,
- QgsProcessingParameterVectorLayer,
- QgsProcessingParameterCrs,
- QgsProcessingOutputVectorLayer,
- QgsCoordinateReferenceSystem,
- QgsProjUtils)
+from qgis.core import (
+ QgsProcessing,
+ QgsProcessingAlgorithm,
+ QgsProcessingParameterVectorLayer,
+ QgsProcessingParameterCrs,
+ QgsProcessingOutputVectorLayer,
+ QgsCoordinateReferenceSystem,
+ QgsProjUtils,
+)
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
@@ -36,36 +38,44 @@
class DefineProjection(QgisAlgorithm):
- INPUT = 'INPUT'
- CRS = 'CRS'
+ INPUT = "INPUT"
+ CRS = "CRS"
def group(self):
- return self.tr('Vector general')
+ return self.tr("Vector general")
def groupId(self):
- return 'vectorgeneral'
+ return "vectorgeneral"
def __init__(self):
super().__init__()
def initAlgorithm(self, config=None):
- self.addParameter(QgsProcessingParameterVectorLayer(self.INPUT,
- self.tr('Input Shapefile'), types=[QgsProcessing.SourceType.TypeVectorAnyGeometry]))
- self.addParameter(QgsProcessingParameterCrs(self.CRS, 'CRS', 'EPSG:4326'))
- self.addOutput(QgsProcessingOutputVectorLayer(self.INPUT,
- self.tr('Layer with projection')))
+ self.addParameter(
+ QgsProcessingParameterVectorLayer(
+ self.INPUT,
+ self.tr("Input Shapefile"),
+ types=[QgsProcessing.SourceType.TypeVectorAnyGeometry],
+ )
+ )
+ self.addParameter(QgsProcessingParameterCrs(self.CRS, "CRS", "EPSG:4326"))
+ self.addOutput(
+ QgsProcessingOutputVectorLayer(self.INPUT, self.tr("Layer with projection"))
+ )
def name(self):
- return 'definecurrentprojection'
+ return "definecurrentprojection"
def displayName(self):
- return self.tr('Define Shapefile projection')
+ return self.tr("Define Shapefile projection")
def tags(self):
- return self.tr('layer,shp,prj,qpj,change,alter').split(',')
+ return self.tr("layer,shp,prj,qpj,change,alter").split(",")
def shortDescription(self):
- return self.tr('Changes a Shapefile\'s projection to a new CRS without reprojecting features')
+ return self.tr(
+ "Changes a Shapefile's projection to a new CRS without reprojecting features"
+ )
def flags(self):
return super().flags() | QgsProcessingAlgorithm.Flag.FlagNoThreading
@@ -76,21 +86,23 @@ def processAlgorithm(self, parameters, context, feedback):
provider = layer.dataProvider()
ds = provider.dataSourceUri()
- p = re.compile(r'\|.*')
- dsPath = p.sub('', ds)
+ p = re.compile(r"\|.*")
+ dsPath = p.sub("", ds)
- if dsPath.lower().endswith('.shp'):
+ if dsPath.lower().endswith(".shp"):
dsPath = dsPath[:-4]
wkt = crs.toWkt(QgsCoordinateReferenceSystem.WktVariant.WKT1_ESRI)
- with open(dsPath + '.prj', 'w', encoding='utf-8') as f:
+ with open(dsPath + ".prj", "w", encoding="utf-8") as f:
f.write(wkt)
- qpjFile = dsPath + '.qpj'
+ qpjFile = dsPath + ".qpj"
if os.path.exists(qpjFile):
os.remove(qpjFile)
else:
- feedback.pushConsoleInfo(self.tr("Data source isn't a Shapefile, skipping .prj/.qpj creation"))
+ feedback.pushConsoleInfo(
+ self.tr("Data source isn't a Shapefile, skipping .prj/.qpj creation")
+ )
layer.setCrs(crs)
layer.triggerRepaint()
diff --git a/python/plugins/processing/algs/qgis/EliminateSelection.py b/python/plugins/processing/algs/qgis/EliminateSelection.py
index 71ee00554684..c0d7031ae16c 100644
--- a/python/plugins/processing/algs/qgis/EliminateSelection.py
+++ b/python/plugins/processing/algs/qgis/EliminateSelection.py
@@ -15,26 +15,28 @@
***************************************************************************
"""
-__author__ = 'Bernhard Ströbl'
-__date__ = 'January 2017'
-__copyright__ = '(C) 2017, Bernhard Ströbl'
+__author__ = "Bernhard Ströbl"
+__date__ = "January 2017"
+__copyright__ = "(C) 2017, Bernhard Ströbl"
import os
from qgis.PyQt.QtGui import QIcon
-from qgis.core import (QgsApplication,
- QgsFeatureRequest,
- QgsFeature,
- QgsFeatureSink,
- QgsGeometry,
- QgsProcessingAlgorithm,
- QgsProcessingException,
- QgsProcessingUtils,
- QgsProcessingParameterVectorLayer,
- QgsProcessingParameterEnum,
- QgsProcessing,
- QgsProcessingParameterFeatureSink)
+from qgis.core import (
+ QgsApplication,
+ QgsFeatureRequest,
+ QgsFeature,
+ QgsFeatureSink,
+ QgsGeometry,
+ QgsProcessingAlgorithm,
+ QgsProcessingException,
+ QgsProcessingUtils,
+ QgsProcessingParameterVectorLayer,
+ QgsProcessingParameterEnum,
+ QgsProcessing,
+ QgsProcessingParameterFeatureSink,
+)
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
@@ -42,9 +44,9 @@
class EliminateSelection(QgisAlgorithm):
- INPUT = 'INPUT'
- OUTPUT = 'OUTPUT'
- MODE = 'MODE'
+ INPUT = "INPUT"
+ OUTPUT = "OUTPUT"
+ MODE = "MODE"
MODE_LARGEST_AREA = 0
MODE_SMALLEST_AREA = 1
@@ -57,49 +59,85 @@ def svgIconPath(self):
return QgsApplication.iconPath("/algorithms/mAlgorithmDissolve.svg")
def group(self):
- return self.tr('Vector geometry')
+ return self.tr("Vector geometry")
def groupId(self):
- return 'vectorgeometry'
+ return "vectorgeometry"
def __init__(self):
super().__init__()
def flags(self):
- return super().flags() | QgsProcessingAlgorithm.Flag.FlagNoThreading | QgsProcessingAlgorithm.Flag.FlagNotAvailableInStandaloneTool
+ return (
+ super().flags()
+ | QgsProcessingAlgorithm.Flag.FlagNoThreading
+ | QgsProcessingAlgorithm.Flag.FlagNotAvailableInStandaloneTool
+ )
def initAlgorithm(self, config=None):
- self.modes = [self.tr('Largest Area'),
- self.tr('Smallest Area'),
- self.tr('Largest Common Boundary')]
-
- self.addParameter(QgsProcessingParameterVectorLayer(self.INPUT,
- self.tr('Input layer'), [QgsProcessing.SourceType.TypeVectorPolygon]))
- self.addParameter(QgsProcessingParameterEnum(self.MODE,
- self.tr('Merge selection with the neighbouring polygon with the'),
- options=self.modes))
-
- self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Eliminated'), QgsProcessing.SourceType.TypeVectorPolygon))
+ self.modes = [
+ self.tr("Largest Area"),
+ self.tr("Smallest Area"),
+ self.tr("Largest Common Boundary"),
+ ]
+
+ self.addParameter(
+ QgsProcessingParameterVectorLayer(
+ self.INPUT,
+ self.tr("Input layer"),
+ [QgsProcessing.SourceType.TypeVectorPolygon],
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterEnum(
+ self.MODE,
+ self.tr("Merge selection with the neighbouring polygon with the"),
+ options=self.modes,
+ )
+ )
+
+ self.addParameter(
+ QgsProcessingParameterFeatureSink(
+ self.OUTPUT,
+ self.tr("Eliminated"),
+ QgsProcessing.SourceType.TypeVectorPolygon,
+ )
+ )
def name(self):
- return 'eliminateselectedpolygons'
+ return "eliminateselectedpolygons"
def displayName(self):
- return self.tr('Eliminate selected polygons')
+ return self.tr("Eliminate selected polygons")
def processAlgorithm(self, parameters, context, feedback):
inLayer = self.parameterAsVectorLayer(parameters, self.INPUT, context)
- boundary = self.parameterAsEnum(parameters, self.MODE, context) == self.MODE_BOUNDARY
- smallestArea = self.parameterAsEnum(parameters, self.MODE, context) == self.MODE_SMALLEST_AREA
+ boundary = (
+ self.parameterAsEnum(parameters, self.MODE, context) == self.MODE_BOUNDARY
+ )
+ smallestArea = (
+ self.parameterAsEnum(parameters, self.MODE, context)
+ == self.MODE_SMALLEST_AREA
+ )
if inLayer.selectedFeatureCount() == 0:
- feedback.reportError(self.tr('{0}: (No selection in input layer "{1}")').format(self.displayName(), parameters[self.INPUT]))
+ feedback.reportError(
+ self.tr('{0}: (No selection in input layer "{1}")').format(
+ self.displayName(), parameters[self.INPUT]
+ )
+ )
featToEliminate = []
selFeatIds = inLayer.selectedFeatureIds()
- (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
- inLayer.fields(), inLayer.wkbType(), inLayer.sourceCrs())
+ (sink, dest_id) = self.parameterAsSink(
+ parameters,
+ self.OUTPUT,
+ context,
+ inLayer.fields(),
+ inLayer.wkbType(),
+ inLayer.sourceCrs(),
+ )
if sink is None:
raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT))
@@ -147,7 +185,8 @@ def processAlgorithm(self, parameters, context, feedback):
geom2Eliminate = feat.geometry()
bbox = geom2Eliminate.boundingBox()
fit = processLayer.getFeatures(
- QgsFeatureRequest().setFilterRect(bbox).setSubsetOfAttributes([]))
+ QgsFeatureRequest().setFilterRect(bbox).setSubsetOfAttributes([])
+ )
mergeWithFid = None
mergeWithGeom = None
max = 0
@@ -211,7 +250,10 @@ def processAlgorithm(self, parameters, context, feedback):
madeProgress = True
else:
raise QgsProcessingException(
- self.tr('Could not replace geometry of feature with id {0}').format(mergeWithFid))
+ self.tr(
+ "Could not replace geometry of feature with id {0}"
+ ).format(mergeWithFid)
+ )
start = start + add
feedback.setProgress(start)
@@ -224,12 +266,14 @@ def processAlgorithm(self, parameters, context, feedback):
# End while
if not processLayer.commitChanges():
- raise QgsProcessingException(self.tr('Could not commit changes'))
+ raise QgsProcessingException(self.tr("Could not commit changes"))
for feature in featNotEliminated:
if feedback.isCanceled():
break
- processLayer.dataProvider().addFeature(feature, QgsFeatureSink.Flag.FastInsert)
+ processLayer.dataProvider().addFeature(
+ feature, QgsFeatureSink.Flag.FastInsert
+ )
return {self.OUTPUT: dest_id}
diff --git a/python/plugins/processing/algs/qgis/ExecuteSQL.py b/python/plugins/processing/algs/qgis/ExecuteSQL.py
index 4fb42ba62269..c4e353d15b40 100644
--- a/python/plugins/processing/algs/qgis/ExecuteSQL.py
+++ b/python/plugins/processing/algs/qgis/ExecuteSQL.py
@@ -15,115 +15,149 @@
***************************************************************************
"""
-__author__ = 'Hugo Mercier'
-__date__ = 'January 2016'
-__copyright__ = '(C) 2016, Hugo Mercier'
-
-from qgis.core import (Qgis,
- QgsVirtualLayerDefinition,
- QgsVectorLayer,
- QgsWkbTypes,
- QgsProcessingAlgorithm,
- QgsProcessingParameterMultipleLayers,
- QgsProcessingParameterDefinition,
- QgsExpression,
- QgsProcessingUtils,
- QgsProcessingParameterString,
- QgsProcessingParameterEnum,
- QgsProcessingParameterCrs,
- QgsProcessingParameterFeatureSink,
- QgsFeatureSink,
- QgsProcessingException,
- QgsVectorFileWriter,
- QgsProject)
+__author__ = "Hugo Mercier"
+__date__ = "January 2016"
+__copyright__ = "(C) 2016, Hugo Mercier"
+
+from qgis.core import (
+ Qgis,
+ QgsVirtualLayerDefinition,
+ QgsVectorLayer,
+ QgsWkbTypes,
+ QgsProcessingAlgorithm,
+ QgsProcessingParameterMultipleLayers,
+ QgsProcessingParameterDefinition,
+ QgsExpression,
+ QgsProcessingUtils,
+ QgsProcessingParameterString,
+ QgsProcessingParameterEnum,
+ QgsProcessingParameterCrs,
+ QgsProcessingParameterFeatureSink,
+ QgsFeatureSink,
+ QgsProcessingException,
+ QgsVectorFileWriter,
+ QgsProject,
+)
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
class ParameterExecuteSql(QgsProcessingParameterDefinition):
- def __init__(self, name='', description=''):
+ def __init__(self, name="", description=""):
super().__init__(name, description)
- self.setMetadata({
- 'widget_wrapper': 'processing.algs.qgis.ui.ExecuteSQLWidget.ExecuteSQLWidgetWrapper'
- })
+ self.setMetadata(
+ {
+ "widget_wrapper": "processing.algs.qgis.ui.ExecuteSQLWidget.ExecuteSQLWidgetWrapper"
+ }
+ )
def type(self):
- return 'execute_sql'
+ return "execute_sql"
def clone(self):
return ParameterExecuteSql(self.name(), self.description())
class ExecuteSQL(QgisAlgorithm):
- """ This algorithm allows executing an SQL query on a set of input
+ """This algorithm allows executing an SQL query on a set of input
vector layers thanks to the virtual layer provider
"""
- INPUT_DATASOURCES = 'INPUT_DATASOURCES'
- INPUT_QUERY = 'INPUT_QUERY'
- INPUT_UID_FIELD = 'INPUT_UID_FIELD'
- INPUT_GEOMETRY_FIELD = 'INPUT_GEOMETRY_FIELD'
- INPUT_GEOMETRY_TYPE = 'INPUT_GEOMETRY_TYPE'
- INPUT_GEOMETRY_CRS = 'INPUT_GEOMETRY_CRS'
- OUTPUT = 'OUTPUT'
+ INPUT_DATASOURCES = "INPUT_DATASOURCES"
+ INPUT_QUERY = "INPUT_QUERY"
+ INPUT_UID_FIELD = "INPUT_UID_FIELD"
+ INPUT_GEOMETRY_FIELD = "INPUT_GEOMETRY_FIELD"
+ INPUT_GEOMETRY_TYPE = "INPUT_GEOMETRY_TYPE"
+ INPUT_GEOMETRY_CRS = "INPUT_GEOMETRY_CRS"
+ OUTPUT = "OUTPUT"
def group(self):
- return self.tr('Vector general')
+ return self.tr("Vector general")
def groupId(self):
- return 'vectorgeneral'
+ return "vectorgeneral"
def __init__(self):
super().__init__()
self.geometry_types = [
- (None, self.tr('Autodetect')),
- (Qgis.WkbType.NoGeometry, self.tr('No geometry')),
- (Qgis.WkbType.Point, self.tr('Point')),
- (Qgis.WkbType.LineString, self.tr('LineString')),
- (Qgis.WkbType.Polygon, self.tr('Polygon')),
- (Qgis.WkbType.MultiPoint, self.tr('MultiPoint')),
- (Qgis.WkbType.MultiLineString, self.tr('MultiLineString')),
- (Qgis.WkbType.MultiPolygon, self.tr('MultiPolygon'))]
+ (None, self.tr("Autodetect")),
+ (Qgis.WkbType.NoGeometry, self.tr("No geometry")),
+ (Qgis.WkbType.Point, self.tr("Point")),
+ (Qgis.WkbType.LineString, self.tr("LineString")),
+ (Qgis.WkbType.Polygon, self.tr("Polygon")),
+ (Qgis.WkbType.MultiPoint, self.tr("MultiPoint")),
+ (Qgis.WkbType.MultiLineString, self.tr("MultiLineString")),
+ (Qgis.WkbType.MultiPolygon, self.tr("MultiPolygon")),
+ ]
def flags(self):
return super().flags() | QgsProcessingAlgorithm.Flag.FlagNoThreading
def initAlgorithm(self, config=None):
- self.addParameter(QgsProcessingParameterMultipleLayers(name=self.INPUT_DATASOURCES,
- description=self.tr('Input data sources (called input1, .., inputN in the query)'),
- optional=True))
-
- self.addParameter(ParameterExecuteSql(name=self.INPUT_QUERY, description=self.tr('SQL query')))
-
- self.addParameter(QgsProcessingParameterString(name=self.INPUT_UID_FIELD,
- description=self.tr('Unique identifier field'), optional=True))
-
- self.addParameter(QgsProcessingParameterString(name=self.INPUT_GEOMETRY_FIELD,
- description=self.tr('Geometry field'), optional=True))
-
- self.addParameter(QgsProcessingParameterEnum(self.INPUT_GEOMETRY_TYPE,
- self.tr('Geometry type'),
- options=[t[1] for t in self.geometry_types],
- defaultValue=0))
-
- self.addParameter(QgsProcessingParameterCrs(self.INPUT_GEOMETRY_CRS,
- self.tr('CRS'), optional=True))
-
- self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('SQL Output')))
+ self.addParameter(
+ QgsProcessingParameterMultipleLayers(
+ name=self.INPUT_DATASOURCES,
+ description=self.tr(
+ "Input data sources (called input1, .., inputN in the query)"
+ ),
+ optional=True,
+ )
+ )
+
+ self.addParameter(
+ ParameterExecuteSql(name=self.INPUT_QUERY, description=self.tr("SQL query"))
+ )
+
+ self.addParameter(
+ QgsProcessingParameterString(
+ name=self.INPUT_UID_FIELD,
+ description=self.tr("Unique identifier field"),
+ optional=True,
+ )
+ )
+
+ self.addParameter(
+ QgsProcessingParameterString(
+ name=self.INPUT_GEOMETRY_FIELD,
+ description=self.tr("Geometry field"),
+ optional=True,
+ )
+ )
+
+ self.addParameter(
+ QgsProcessingParameterEnum(
+ self.INPUT_GEOMETRY_TYPE,
+ self.tr("Geometry type"),
+ options=[t[1] for t in self.geometry_types],
+ defaultValue=0,
+ )
+ )
+
+ self.addParameter(
+ QgsProcessingParameterCrs(
+ self.INPUT_GEOMETRY_CRS, self.tr("CRS"), optional=True
+ )
+ )
+
+ self.addParameter(
+ QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr("SQL Output"))
+ )
def name(self):
- return 'executesql'
+ return "executesql"
def displayName(self):
- return self.tr('Execute SQL')
+ return self.tr("Execute SQL")
def processAlgorithm(self, parameters, context, feedback):
layers = self.parameterAsLayerList(parameters, self.INPUT_DATASOURCES, context)
query = self.parameterAsString(parameters, self.INPUT_QUERY, context)
uid_field = self.parameterAsString(parameters, self.INPUT_UID_FIELD, context)
- geometry_field = self.parameterAsString(parameters, self.INPUT_GEOMETRY_FIELD, context)
+ geometry_field = self.parameterAsString(
+ parameters, self.INPUT_GEOMETRY_FIELD, context
+ )
geometry_type = self.geometry_types[
self.parameterAsEnum(parameters, self.INPUT_GEOMETRY_TYPE, context)
][0]
@@ -138,17 +172,21 @@ def processAlgorithm(self, parameters, context, feedback):
# belongs to temporary QgsMapLayerStore, not project.
# So, we write them to disk is this is the case.
if context.project() and not context.project().mapLayer(layer.id()):
- basename = "memorylayer." + QgsVectorFileWriter.supportedFormatExtensions()[0]
+ basename = (
+ "memorylayer." + QgsVectorFileWriter.supportedFormatExtensions()[0]
+ )
tmp_path = QgsProcessingUtils.generateTempFilename(basename, context)
QgsVectorFileWriter.writeAsVectorFormat(
- layer, tmp_path, layer.dataProvider().encoding())
- df.addSource(f'input{layerIdx + 1}', tmp_path, "ogr")
+ layer, tmp_path, layer.dataProvider().encoding()
+ )
+ df.addSource(f"input{layerIdx + 1}", tmp_path, "ogr")
else:
- df.addSource(f'input{layerIdx + 1}', layer.id())
+ df.addSource(f"input{layerIdx + 1}", layer.id())
- if query == '':
+ if query == "":
raise QgsProcessingException(
- self.tr('Empty SQL. Please enter valid SQL expression and try again.'))
+ self.tr("Empty SQL. Please enter valid SQL expression and try again.")
+ )
localContext = self.createExpressionContext(parameters, context)
expandedQuery = QgsExpression.replaceExpressionText(query, localContext)
df.setQuery(expandedQuery)
@@ -173,12 +211,14 @@ def processAlgorithm(self, parameters, context, feedback):
if vLayer.wkbType() == QgsWkbTypes.Type.Unknown:
raise QgsProcessingException(self.tr("Cannot find geometry field"))
- (sink, dest_id) = self.parameterAsSink(parameters,
- self.OUTPUT,
- context,
- vLayer.fields(),
- vLayer.wkbType(),
- vLayer.crs())
+ (sink, dest_id) = self.parameterAsSink(
+ parameters,
+ self.OUTPUT,
+ context,
+ vLayer.fields(),
+ vLayer.wkbType(),
+ vLayer.crs(),
+ )
if sink is None:
raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT))
diff --git a/python/plugins/processing/algs/qgis/ExportGeometryInfo.py b/python/plugins/processing/algs/qgis/ExportGeometryInfo.py
index 33d0c25c6b95..fe84aaffcdc5 100644
--- a/python/plugins/processing/algs/qgis/ExportGeometryInfo.py
+++ b/python/plugins/processing/algs/qgis/ExportGeometryInfo.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'August 2012'
-__copyright__ = '(C) 2012, Victor Olaya'
+__author__ = "Victor Olaya"
+__date__ = "August 2012"
+__copyright__ = "(C) 2012, Victor Olaya"
import os
import math
@@ -25,22 +25,24 @@
from qgis.PyQt.QtGui import QIcon
from qgis.PyQt.QtCore import QMetaType
-from qgis.core import (NULL,
- Qgis,
- QgsApplication,
- QgsCoordinateTransform,
- QgsField,
- QgsFields,
- QgsWkbTypes,
- QgsPointXY,
- QgsFeatureSink,
- QgsDistanceArea,
- QgsProcessingUtils,
- QgsProcessingException,
- QgsProcessingParameterFeatureSource,
- QgsProcessingParameterEnum,
- QgsProcessingParameterFeatureSink,
- QgsUnitTypes)
+from qgis.core import (
+ NULL,
+ Qgis,
+ QgsApplication,
+ QgsCoordinateTransform,
+ QgsField,
+ QgsFields,
+ QgsWkbTypes,
+ QgsPointXY,
+ QgsFeatureSink,
+ QgsDistanceArea,
+ QgsProcessingUtils,
+ QgsProcessingException,
+ QgsProcessingParameterFeatureSource,
+ QgsProcessingParameterEnum,
+ QgsProcessingParameterFeatureSink,
+ QgsUnitTypes,
+)
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
@@ -48,24 +50,30 @@
class ExportGeometryInfo(QgisAlgorithm):
- INPUT = 'INPUT'
- METHOD = 'CALC_METHOD'
- OUTPUT = 'OUTPUT'
+ INPUT = "INPUT"
+ METHOD = "CALC_METHOD"
+ OUTPUT = "OUTPUT"
def icon(self):
- return QgsApplication.getThemeIcon("/algorithms/mAlgorithmAddGeometryAttributes.svg")
+ return QgsApplication.getThemeIcon(
+ "/algorithms/mAlgorithmAddGeometryAttributes.svg"
+ )
def svgIconPath(self):
- return QgsApplication.iconPath("/algorithms/mAlgorithmAddGeometryAttributes.svg")
+ return QgsApplication.iconPath(
+ "/algorithms/mAlgorithmAddGeometryAttributes.svg"
+ )
def tags(self):
- return self.tr('export,add,information,measurements,areas,lengths,perimeters,latitudes,longitudes,x,y,z,extract,points,lines,polygons,sinuosity,fields').split(',')
+ return self.tr(
+ "export,add,information,measurements,areas,lengths,perimeters,latitudes,longitudes,x,y,z,extract,points,lines,polygons,sinuosity,fields"
+ ).split(",")
def group(self):
- return self.tr('Vector geometry')
+ return self.tr("Vector geometry")
def groupId(self):
- return 'vectorgeometry'
+ return "vectorgeometry"
def __init__(self):
super().__init__()
@@ -74,27 +82,40 @@ def __init__(self):
self.distance_area = None
self.distance_conversion_factor = 1
self.area_conversion_factor = 1
- self.calc_methods = [self.tr('Layer CRS'),
- self.tr('Project CRS'),
- self.tr('Ellipsoidal')]
+ self.calc_methods = [
+ self.tr("Layer CRS"),
+ self.tr("Project CRS"),
+ self.tr("Ellipsoidal"),
+ ]
def initAlgorithm(self, config=None):
- self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT,
- self.tr('Input layer')))
- self.addParameter(QgsProcessingParameterEnum(self.METHOD,
- self.tr('Calculate using'), options=self.calc_methods, defaultValue=0))
- self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Added geom info')))
+ self.addParameter(
+ QgsProcessingParameterFeatureSource(self.INPUT, self.tr("Input layer"))
+ )
+ self.addParameter(
+ QgsProcessingParameterEnum(
+ self.METHOD,
+ self.tr("Calculate using"),
+ options=self.calc_methods,
+ defaultValue=0,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr("Added geom info"))
+ )
def name(self):
- return 'exportaddgeometrycolumns'
+ return "exportaddgeometrycolumns"
def displayName(self):
- return self.tr('Add geometry attributes')
+ return self.tr("Add geometry attributes")
def processAlgorithm(self, parameters, context, feedback):
source = self.parameterAsSource(parameters, self.INPUT, context)
if source is None:
- raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT))
+ raise QgsProcessingException(
+ self.invalidSourceError(parameters, self.INPUT)
+ )
method = self.parameterAsEnum(parameters, self.METHOD, context)
@@ -102,30 +123,36 @@ def processAlgorithm(self, parameters, context, feedback):
fields = source.fields()
new_fields = QgsFields()
- if QgsWkbTypes.geometryType(wkb_type) == QgsWkbTypes.GeometryType.PolygonGeometry:
- new_fields.append(QgsField('area', QMetaType.Type.Double))
- new_fields.append(QgsField('perimeter', QMetaType.Type.Double))
- elif QgsWkbTypes.geometryType(wkb_type) == QgsWkbTypes.GeometryType.LineGeometry:
- new_fields.append(QgsField('length', QMetaType.Type.Double))
+ if (
+ QgsWkbTypes.geometryType(wkb_type)
+ == QgsWkbTypes.GeometryType.PolygonGeometry
+ ):
+ new_fields.append(QgsField("area", QMetaType.Type.Double))
+ new_fields.append(QgsField("perimeter", QMetaType.Type.Double))
+ elif (
+ QgsWkbTypes.geometryType(wkb_type) == QgsWkbTypes.GeometryType.LineGeometry
+ ):
+ new_fields.append(QgsField("length", QMetaType.Type.Double))
if not QgsWkbTypes.isMultiType(source.wkbType()):
- new_fields.append(QgsField('straightdis', QMetaType.Type.Double))
- new_fields.append(QgsField('sinuosity', QMetaType.Type.Double))
+ new_fields.append(QgsField("straightdis", QMetaType.Type.Double))
+ new_fields.append(QgsField("sinuosity", QMetaType.Type.Double))
else:
if QgsWkbTypes.isMultiType(source.wkbType()):
- new_fields.append(QgsField('numparts', QMetaType.Type.Int))
+ new_fields.append(QgsField("numparts", QMetaType.Type.Int))
else:
- new_fields.append(QgsField('xcoord', QMetaType.Type.Double))
- new_fields.append(QgsField('ycoord', QMetaType.Type.Double))
+ new_fields.append(QgsField("xcoord", QMetaType.Type.Double))
+ new_fields.append(QgsField("ycoord", QMetaType.Type.Double))
if QgsWkbTypes.hasZ(source.wkbType()):
self.export_z = True
- new_fields.append(QgsField('zcoord', QMetaType.Type.Double))
+ new_fields.append(QgsField("zcoord", QMetaType.Type.Double))
if QgsWkbTypes.hasM(source.wkbType()):
self.export_m = True
- new_fields.append(QgsField('mvalue', QMetaType.Type.Double))
+ new_fields.append(QgsField("mvalue", QMetaType.Type.Double))
fields = QgsProcessingUtils.combineFields(fields, new_fields)
- (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
- fields, wkb_type, source.sourceCrs())
+ (sink, dest_id) = self.parameterAsSink(
+ parameters, self.OUTPUT, context, fields, wkb_type, source.sourceCrs()
+ )
if sink is None:
raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT))
@@ -138,19 +165,27 @@ def processAlgorithm(self, parameters, context, feedback):
self.distance_area = QgsDistanceArea()
if method == 2:
- self.distance_area.setSourceCrs(source.sourceCrs(), context.transformContext())
+ self.distance_area.setSourceCrs(
+ source.sourceCrs(), context.transformContext()
+ )
self.distance_area.setEllipsoid(context.ellipsoid())
- self.distance_conversion_factor = QgsUnitTypes.fromUnitToUnitFactor(self.distance_area.lengthUnits(),
- context.distanceUnit())
+ self.distance_conversion_factor = QgsUnitTypes.fromUnitToUnitFactor(
+ self.distance_area.lengthUnits(), context.distanceUnit()
+ )
- self.area_conversion_factor = QgsUnitTypes.fromUnitToUnitFactor(self.distance_area.areaUnits(),
- context.areaUnit())
+ self.area_conversion_factor = QgsUnitTypes.fromUnitToUnitFactor(
+ self.distance_area.areaUnits(), context.areaUnit()
+ )
elif method == 1:
if not context.project():
- raise QgsProcessingException(self.tr('No project is available in this context'))
- coordTransform = QgsCoordinateTransform(source.sourceCrs(), context.project().crs(), context.project())
+ raise QgsProcessingException(
+ self.tr("No project is available in this context")
+ )
+ coordTransform = QgsCoordinateTransform(
+ source.sourceCrs(), context.project().crs(), context.project()
+ )
features = source.getFeatures()
total = 100.0 / source.featureCount() if source.featureCount() else 0
@@ -208,13 +243,24 @@ def line_attributes(self, geometry):
curve = geometry.constGet()
p1 = curve.startPoint()
p2 = curve.endPoint()
- straight_distance = self.distance_conversion_factor * self.distance_area.measureLine(QgsPointXY(p1), QgsPointXY(p2))
+ straight_distance = (
+ self.distance_conversion_factor
+ * self.distance_area.measureLine(QgsPointXY(p1), QgsPointXY(p2))
+ )
sinuosity = curve.sinuosity()
if math.isnan(sinuosity):
sinuosity = NULL
- return [self.distance_conversion_factor * self.distance_area.measureLength(geometry), straight_distance, sinuosity]
+ return [
+ self.distance_conversion_factor
+ * self.distance_area.measureLength(geometry),
+ straight_distance,
+ sinuosity,
+ ]
def polygon_attributes(self, geometry):
area = self.area_conversion_factor * self.distance_area.measureArea(geometry)
- perimeter = self.distance_conversion_factor * self.distance_area.measurePerimeter(geometry)
+ perimeter = (
+ self.distance_conversion_factor
+ * self.distance_area.measurePerimeter(geometry)
+ )
return [area, perimeter]
diff --git a/python/plugins/processing/algs/qgis/FieldPyculator.py b/python/plugins/processing/algs/qgis/FieldPyculator.py
index d08ab657c984..eed8ddc09e01 100644
--- a/python/plugins/processing/algs/qgis/FieldPyculator.py
+++ b/python/plugins/processing/algs/qgis/FieldPyculator.py
@@ -15,38 +15,40 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya & NextGIS'
-__date__ = 'August 2012'
-__copyright__ = '(C) 2012, Victor Olaya & NextGIS'
+__author__ = "Victor Olaya & NextGIS"
+__date__ = "August 2012"
+__copyright__ = "(C) 2012, Victor Olaya & NextGIS"
import sys
from qgis.PyQt.QtCore import QMetaType
-from qgis.core import (Qgis,
- QgsProcessingException,
- QgsField,
- QgsFields,
- QgsFeatureSink,
- QgsProcessing,
- QgsProcessingParameterFeatureSource,
- QgsProcessingParameterString,
- QgsProcessingParameterEnum,
- QgsProcessingParameterNumber,
- QgsProcessingParameterFeatureSink,
- QgsVariantUtils)
+from qgis.core import (
+ Qgis,
+ QgsProcessingException,
+ QgsField,
+ QgsFields,
+ QgsFeatureSink,
+ QgsProcessing,
+ QgsProcessingParameterFeatureSource,
+ QgsProcessingParameterString,
+ QgsProcessingParameterEnum,
+ QgsProcessingParameterNumber,
+ QgsProcessingParameterFeatureSink,
+ QgsVariantUtils,
+)
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
class FieldsPyculator(QgisAlgorithm):
- INPUT = 'INPUT'
- FIELD_NAME = 'FIELD_NAME'
- FIELD_TYPE = 'FIELD_TYPE'
- FIELD_LENGTH = 'FIELD_LENGTH'
- FIELD_PRECISION = 'FIELD_PRECISION'
- GLOBAL = 'GLOBAL'
- FORMULA = 'FORMULA'
- OUTPUT = 'OUTPUT'
- RESULT_VAR_NAME = 'value'
+ INPUT = "INPUT"
+ FIELD_NAME = "FIELD_NAME"
+ FIELD_TYPE = "FIELD_TYPE"
+ FIELD_LENGTH = "FIELD_LENGTH"
+ FIELD_PRECISION = "FIELD_PRECISION"
+ GLOBAL = "GLOBAL"
+ FORMULA = "FORMULA"
+ OUTPUT = "OUTPUT"
+ RESULT_VAR_NAME = "value"
def flags(self):
# This algorithm represents a security risk, due to the use
@@ -54,69 +56,105 @@ def flags(self):
return super().flags() | Qgis.ProcessingAlgorithmFlag.SecurityRisk
def group(self):
- return self.tr('Vector table')
+ return self.tr("Vector table")
def groupId(self):
- return 'vectortable'
+ return "vectortable"
def __init__(self):
super().__init__()
def initAlgorithm(self, config=None):
- self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT, self.tr('Input layer'),
- types=[QgsProcessing.SourceType.TypeVector]))
- self.addParameter(QgsProcessingParameterString(self.FIELD_NAME,
- self.tr('Result field name'), defaultValue='NewField'))
-
- types = [(QMetaType.Type.Int, QMetaType.Type.UnknownType),
- (QMetaType.Type.Double, QMetaType.Type.UnknownType),
- (QMetaType.Type.QString, QMetaType.Type.UnknownType),
- (QMetaType.Type.Bool, QMetaType.Type.UnknownType),
- (QMetaType.Type.QDate, QMetaType.Type.UnknownType),
- (QMetaType.Type.QTime, QMetaType.Type.UnknownType),
- (QMetaType.Type.QDateTime, QMetaType.Type.UnknownType),
- (QMetaType.Type.QByteArray, QMetaType.Type.UnknownType),
- (QMetaType.Type.QStringList, QMetaType.Type.QString),
- (QMetaType.Type.QVariantList, QMetaType.Type.Int),
- (QMetaType.Type.QVariantList, QMetaType.Type.Double)]
+ self.addParameter(
+ QgsProcessingParameterFeatureSource(
+ self.INPUT,
+ self.tr("Input layer"),
+ types=[QgsProcessing.SourceType.TypeVector],
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterString(
+ self.FIELD_NAME, self.tr("Result field name"), defaultValue="NewField"
+ )
+ )
+
+ types = [
+ (QMetaType.Type.Int, QMetaType.Type.UnknownType),
+ (QMetaType.Type.Double, QMetaType.Type.UnknownType),
+ (QMetaType.Type.QString, QMetaType.Type.UnknownType),
+ (QMetaType.Type.Bool, QMetaType.Type.UnknownType),
+ (QMetaType.Type.QDate, QMetaType.Type.UnknownType),
+ (QMetaType.Type.QTime, QMetaType.Type.UnknownType),
+ (QMetaType.Type.QDateTime, QMetaType.Type.UnknownType),
+ (QMetaType.Type.QByteArray, QMetaType.Type.UnknownType),
+ (QMetaType.Type.QStringList, QMetaType.Type.QString),
+ (QMetaType.Type.QVariantList, QMetaType.Type.Int),
+ (QMetaType.Type.QVariantList, QMetaType.Type.Double),
+ ]
type_names = []
type_icons = []
for type_name, subtype_name in types:
- type_names.append(QgsVariantUtils.typeToDisplayString(type_name, subtype_name))
+ type_names.append(
+ QgsVariantUtils.typeToDisplayString(type_name, subtype_name)
+ )
type_icons.append(QgsFields.iconForFieldType(type_name, subtype_name))
- param = QgsProcessingParameterEnum('FIELD_TYPE', 'Field type', options=type_names)
- param.setMetadata({'widget_wrapper': {'icons': type_icons}})
+ param = QgsProcessingParameterEnum(
+ "FIELD_TYPE", "Field type", options=type_names
+ )
+ param.setMetadata({"widget_wrapper": {"icons": type_icons}})
self.addParameter(param)
- self.addParameter(QgsProcessingParameterNumber(self.FIELD_LENGTH,
- self.tr('Field length'), minValue=0,
- defaultValue=10))
- self.addParameter(QgsProcessingParameterNumber(self.FIELD_PRECISION,
- self.tr('Field precision'), minValue=0, maxValue=15,
- defaultValue=3))
- self.addParameter(QgsProcessingParameterString(self.GLOBAL,
- self.tr('Global expression'), multiLine=True, optional=True))
- self.addParameter(QgsProcessingParameterString(self.FORMULA,
- self.tr('Formula'), defaultValue='value = ', multiLine=True))
- self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT,
- self.tr('Calculated')))
+ self.addParameter(
+ QgsProcessingParameterNumber(
+ self.FIELD_LENGTH, self.tr("Field length"), minValue=0, defaultValue=10
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterNumber(
+ self.FIELD_PRECISION,
+ self.tr("Field precision"),
+ minValue=0,
+ maxValue=15,
+ defaultValue=3,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterString(
+ self.GLOBAL, self.tr("Global expression"), multiLine=True, optional=True
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterString(
+ self.FORMULA,
+ self.tr("Formula"),
+ defaultValue="value = ",
+ multiLine=True,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr("Calculated"))
+ )
def name(self):
- return 'advancedpythonfieldcalculator'
+ return "advancedpythonfieldcalculator"
def displayName(self):
- return self.tr('Advanced Python field calculator')
+ return self.tr("Advanced Python field calculator")
def processAlgorithm(self, parameters, context, feedback):
source = self.parameterAsSource(parameters, self.INPUT, context)
if source is None:
- raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT))
+ raise QgsProcessingException(
+ self.invalidSourceError(parameters, self.INPUT)
+ )
field_name = self.parameterAsString(parameters, self.FIELD_NAME, context)
field_type = QMetaType.Type.UnknownType
field_sub_type = QMetaType.Type.UnknownType
- field_type_parameter = self.parameterAsEnum(parameters, self.FIELD_TYPE, context)
+ field_type_parameter = self.parameterAsEnum(
+ parameters, self.FIELD_TYPE, context
+ )
if field_type_parameter == 0: # Integer
field_type = QMetaType.Type.Int
elif field_type_parameter == 1: # Float
@@ -149,45 +187,57 @@ def processAlgorithm(self, parameters, context, feedback):
globalExpression = self.parameterAsString(parameters, self.GLOBAL, context)
fields = source.fields()
- field = QgsField(field_name, field_type, '', width, precision, '', field_sub_type)
+ field = QgsField(
+ field_name, field_type, "", width, precision, "", field_sub_type
+ )
fields.append(field)
new_ns = {}
- (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
- fields, source.wkbType(), source.sourceCrs())
+ (sink, dest_id) = self.parameterAsSink(
+ parameters,
+ self.OUTPUT,
+ context,
+ fields,
+ source.wkbType(),
+ source.sourceCrs(),
+ )
if sink is None:
raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT))
# Run global code
- if globalExpression.strip() != '':
+ if globalExpression.strip() != "":
try:
- bytecode = compile(globalExpression, '', 'exec')
+ bytecode = compile(globalExpression, "", "exec")
exec(bytecode, new_ns)
except:
raise QgsProcessingException(
- self.tr("FieldPyculator code execute error. Global code block can't be executed!\n{0}\n{1}").format(
- str(sys.exc_info()[0].__name__), str(sys.exc_info()[1])))
+ self.tr(
+ "FieldPyculator code execute error. Global code block can't be executed!\n{0}\n{1}"
+ ).format(str(sys.exc_info()[0].__name__), str(sys.exc_info()[1]))
+ )
# Replace all fields tags
fields = source.fields()
for num, field in enumerate(fields):
field_name = str(field.name())
- replval = '__attr[' + str(num) + ']'
- code = code.replace('<' + field_name + '>', replval)
+ replval = "__attr[" + str(num) + "]"
+ code = code.replace("<" + field_name + ">", replval)
# Replace all special vars
- code = code.replace('$id', '__id')
- code = code.replace('$geom', '__geom')
- need_id = code.find('__id') != -1
- need_geom = code.find('__geom') != -1
- need_attrs = code.find('__attr') != -1
+ code = code.replace("$id", "__id")
+ code = code.replace("$geom", "__geom")
+ need_id = code.find("__id") != -1
+ need_geom = code.find("__geom") != -1
+ need_attrs = code.find("__attr") != -1
# Compile
try:
- bytecode = compile(code, '', 'exec')
+ bytecode = compile(code, "", "exec")
except:
raise QgsProcessingException(
- self.tr("FieldPyculator code execute error. Field code block can't be executed!\n{0}\n{1}").format(
- str(sys.exc_info()[0].__name__), str(sys.exc_info()[1])))
+ self.tr(
+ "FieldPyculator code execute error. Field code block can't be executed!\n{0}\n{1}"
+ ).format(str(sys.exc_info()[0].__name__), str(sys.exc_info()[1]))
+ )
# Run
features = source.getFeatures()
@@ -203,15 +253,15 @@ def processAlgorithm(self, parameters, context, feedback):
# Add needed vars
if need_id:
- new_ns['__id'] = feat_id
+ new_ns["__id"] = feat_id
if need_geom:
geom = feat.geometry()
- new_ns['__geom'] = geom
+ new_ns["__geom"] = geom
if need_attrs:
pyattrs = [a for a in attrs]
- new_ns['__attr'] = pyattrs
+ new_ns["__attr"] = pyattrs
# Clear old result
if self.RESULT_VAR_NAME in new_ns:
@@ -223,9 +273,12 @@ def processAlgorithm(self, parameters, context, feedback):
# Check result
if self.RESULT_VAR_NAME not in new_ns:
raise QgsProcessingException(
- self.tr("FieldPyculator code execute error\n"
- "Field code block does not return '{0}' variable! "
- "Please declare this variable in your code!").format(self.RESULT_VAR_NAME))
+ self.tr(
+ "FieldPyculator code execute error\n"
+ "Field code block does not return '{0}' variable! "
+ "Please declare this variable in your code!"
+ ).format(self.RESULT_VAR_NAME)
+ )
# Write feature
attrs.append(new_ns[self.RESULT_VAR_NAME])
diff --git a/python/plugins/processing/algs/qgis/FindProjection.py b/python/plugins/processing/algs/qgis/FindProjection.py
index 10e85f67151b..ddcd4cf52aea 100644
--- a/python/plugins/processing/algs/qgis/FindProjection.py
+++ b/python/plugins/processing/algs/qgis/FindProjection.py
@@ -15,27 +15,29 @@
***************************************************************************
"""
-__author__ = 'Nyall Dawson'
-__date__ = 'February 2017'
-__copyright__ = '(C) 2017, Nyall Dawson'
+__author__ = "Nyall Dawson"
+__date__ = "February 2017"
+__copyright__ = "(C) 2017, Nyall Dawson"
import os
-from qgis.core import (QgsGeometry,
- QgsFeature,
- QgsFeatureSink,
- QgsField,
- QgsFields,
- QgsCoordinateReferenceSystem,
- QgsCoordinateTransform,
- QgsCoordinateTransformContext,
- QgsWkbTypes,
- QgsProcessingException,
- QgsProcessingParameterFeatureSource,
- QgsProcessingParameterExtent,
- QgsProcessingParameterCrs,
- QgsProcessingParameterFeatureSink,
- QgsProcessingParameterDefinition)
+from qgis.core import (
+ QgsGeometry,
+ QgsFeature,
+ QgsFeatureSink,
+ QgsField,
+ QgsFields,
+ QgsCoordinateReferenceSystem,
+ QgsCoordinateTransform,
+ QgsCoordinateTransformContext,
+ QgsWkbTypes,
+ QgsProcessingException,
+ QgsProcessingParameterFeatureSource,
+ QgsProcessingParameterExtent,
+ QgsProcessingParameterCrs,
+ QgsProcessingParameterFeatureSink,
+ QgsProcessingParameterDefinition,
+)
from qgis.PyQt.QtCore import QMetaType
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
@@ -44,48 +46,59 @@
class FindProjection(QgisAlgorithm):
- INPUT = 'INPUT'
- TARGET_AREA = 'TARGET_AREA'
- TARGET_AREA_CRS = 'TARGET_AREA_CRS'
- OUTPUT = 'OUTPUT'
+ INPUT = "INPUT"
+ TARGET_AREA = "TARGET_AREA"
+ TARGET_AREA_CRS = "TARGET_AREA_CRS"
+ OUTPUT = "OUTPUT"
def tags(self):
- return self.tr('crs,srs,coordinate,reference,system,guess,estimate,finder,determine').split(',')
+ return self.tr(
+ "crs,srs,coordinate,reference,system,guess,estimate,finder,determine"
+ ).split(",")
def group(self):
- return self.tr('Vector general')
+ return self.tr("Vector general")
def groupId(self):
- return 'vectorgeneral'
+ return "vectorgeneral"
def __init__(self):
super().__init__()
def initAlgorithm(self, config=None):
- self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT,
- self.tr('Input layer')))
- extent_parameter = QgsProcessingParameterExtent(self.TARGET_AREA,
- self.tr('Target area for layer'))
+ self.addParameter(
+ QgsProcessingParameterFeatureSource(self.INPUT, self.tr("Input layer"))
+ )
+ extent_parameter = QgsProcessingParameterExtent(
+ self.TARGET_AREA, self.tr("Target area for layer")
+ )
self.addParameter(extent_parameter)
# deprecated
- crs_param = QgsProcessingParameterCrs(self.TARGET_AREA_CRS, 'Target area CRS', optional=True)
- crs_param.setFlags(crs_param.flags() | QgsProcessingParameterDefinition.Flag.FlagHidden)
+ crs_param = QgsProcessingParameterCrs(
+ self.TARGET_AREA_CRS, "Target area CRS", optional=True
+ )
+ crs_param.setFlags(
+ crs_param.flags() | QgsProcessingParameterDefinition.Flag.FlagHidden
+ )
self.addParameter(crs_param)
- self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT,
- self.tr('CRS candidates')))
+ self.addParameter(
+ QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr("CRS candidates"))
+ )
def name(self):
- return 'findprojection'
+ return "findprojection"
def displayName(self):
- return self.tr('Find projection')
+ return self.tr("Find projection")
def processAlgorithm(self, parameters, context, feedback):
source = self.parameterAsSource(parameters, self.INPUT, context)
if source is None:
- raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT))
+ raise QgsProcessingException(
+ self.invalidSourceError(parameters, self.INPUT)
+ )
extent = self.parameterAsExtent(parameters, self.TARGET_AREA, context)
target_crs = self.parameterAsExtentCrs(parameters, self.TARGET_AREA, context)
@@ -97,10 +110,16 @@ def processAlgorithm(self, parameters, context, feedback):
target_geom = QgsGeometry.fromRect(extent)
fields = QgsFields()
- fields.append(QgsField('auth_id', QMetaType.Type.QString, '', 20))
-
- (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
- fields, QgsWkbTypes.Type.NoGeometry, QgsCoordinateReferenceSystem())
+ fields.append(QgsField("auth_id", QMetaType.Type.QString, "", 20))
+
+ (sink, dest_id) = self.parameterAsSink(
+ parameters,
+ self.OUTPUT,
+ context,
+ fields,
+ QgsWkbTypes.Type.NoGeometry,
+ QgsCoordinateReferenceSystem(),
+ )
if sink is None:
raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT))
@@ -124,7 +143,9 @@ def processAlgorithm(self, parameters, context, feedback):
if not candidate_crs.isValid():
continue
- transform_candidate = QgsCoordinateTransform(candidate_crs, target_crs, transform_context)
+ transform_candidate = QgsCoordinateTransform(
+ candidate_crs, target_crs, transform_context
+ )
transform_candidate.setBallparkTransformsAreAppropriate(True)
transform_candidate.disableFallbackOperationHandler(True)
transformed_bounds = QgsGeometry(layer_bounds)
@@ -136,7 +157,11 @@ def processAlgorithm(self, parameters, context, feedback):
try:
if engine.intersects(transformed_bounds.constGet()):
- feedback.pushInfo(self.tr('Found candidate CRS: {}').format(candidate_crs.authid()))
+ feedback.pushInfo(
+ self.tr("Found candidate CRS: {}").format(
+ candidate_crs.authid()
+ )
+ )
f = QgsFeature(fields)
f.setAttributes([candidate_crs.authid()])
sink.addFeature(f, QgsFeatureSink.Flag.FastInsert)
@@ -147,7 +172,7 @@ def processAlgorithm(self, parameters, context, feedback):
feedback.setProgress(int(current * total))
if found_results == 0:
- feedback.reportError(self.tr('No matching projections found'))
+ feedback.reportError(self.tr("No matching projections found"))
sink.finalize()
return {self.OUTPUT: dest_id}
diff --git a/python/plugins/processing/algs/qgis/GeometryConvert.py b/python/plugins/processing/algs/qgis/GeometryConvert.py
index 773e313088db..7857c3b9b5ed 100644
--- a/python/plugins/processing/algs/qgis/GeometryConvert.py
+++ b/python/plugins/processing/algs/qgis/GeometryConvert.py
@@ -15,64 +15,75 @@
***************************************************************************
"""
-__author__ = 'Michael Minn'
-__date__ = 'May 2010'
-__copyright__ = '(C) 2010, Michael Minn'
-
-from qgis.core import (QgsFeature,
- QgsGeometry,
- QgsMultiPoint,
- QgsMultiLineString,
- QgsLineString,
- QgsPolygon,
- QgsFeatureSink,
- QgsWkbTypes,
- QgsProcessingException,
- QgsProcessingParameterFeatureSource,
- QgsProcessingParameterEnum,
- QgsProcessingParameterFeatureSink)
+__author__ = "Michael Minn"
+__date__ = "May 2010"
+__copyright__ = "(C) 2010, Michael Minn"
+
+from qgis.core import (
+ QgsFeature,
+ QgsGeometry,
+ QgsMultiPoint,
+ QgsMultiLineString,
+ QgsLineString,
+ QgsPolygon,
+ QgsFeatureSink,
+ QgsWkbTypes,
+ QgsProcessingException,
+ QgsProcessingParameterFeatureSource,
+ QgsProcessingParameterEnum,
+ QgsProcessingParameterFeatureSink,
+)
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
class GeometryConvert(QgisAlgorithm):
- INPUT = 'INPUT'
- TYPE = 'TYPE'
- OUTPUT = 'OUTPUT'
+ INPUT = "INPUT"
+ TYPE = "TYPE"
+ OUTPUT = "OUTPUT"
def group(self):
- return self.tr('Vector geometry')
+ return self.tr("Vector geometry")
def groupId(self):
- return 'vectorgeometry'
+ return "vectorgeometry"
def __init__(self):
super().__init__()
def initAlgorithm(self, config=None):
- self.types = [self.tr('Centroids'),
- self.tr('Nodes'),
- self.tr('Linestrings'),
- self.tr('Multilinestrings'),
- self.tr('Polygons')]
+ self.types = [
+ self.tr("Centroids"),
+ self.tr("Nodes"),
+ self.tr("Linestrings"),
+ self.tr("Multilinestrings"),
+ self.tr("Polygons"),
+ ]
- self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT,
- self.tr('Input layer')))
- self.addParameter(QgsProcessingParameterEnum(self.TYPE,
- self.tr('New geometry type'), options=self.types))
+ self.addParameter(
+ QgsProcessingParameterFeatureSource(self.INPUT, self.tr("Input layer"))
+ )
+ self.addParameter(
+ QgsProcessingParameterEnum(
+ self.TYPE, self.tr("New geometry type"), options=self.types
+ )
+ )
- self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT,
- self.tr('Converted')))
+ self.addParameter(
+ QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr("Converted"))
+ )
def name(self):
- return 'convertgeometrytype'
+ return "convertgeometrytype"
def displayName(self):
- return self.tr('Convert geometry type')
+ return self.tr("Convert geometry type")
def processAlgorithm(self, parameters, context, feedback):
source = self.parameterAsSource(parameters, self.INPUT, context)
if source is None:
- raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT))
+ raise QgsProcessingException(
+ self.invalidSourceError(parameters, self.INPUT)
+ )
index = self.parameterAsEnum(parameters, self.TYPE, context)
@@ -103,8 +114,14 @@ def processAlgorithm(self, parameters, context, feedback):
if QgsWkbTypes.hasZ(source.wkbType()):
newType = QgsWkbTypes.addZ(newType)
- (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
- source.fields(), newType, source.sourceCrs())
+ (sink, dest_id) = self.parameterAsSink(
+ parameters,
+ self.OUTPUT,
+ context,
+ source.fields(),
+ newType,
+ source.sourceCrs(),
+ )
if sink is None:
raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT))
@@ -161,10 +178,19 @@ def convertToNodes(self, geom):
return [QgsGeometry(mp)]
def convertToLineStrings(self, geom):
- if QgsWkbTypes.geometryType(geom.wkbType()) == QgsWkbTypes.GeometryType.PointGeometry:
+ if (
+ QgsWkbTypes.geometryType(geom.wkbType())
+ == QgsWkbTypes.GeometryType.PointGeometry
+ ):
raise QgsProcessingException(
- self.tr('Cannot convert from {0} to LineStrings').format(QgsWkbTypes.displayString(geom.wkbType())))
- elif QgsWkbTypes.geometryType(geom.wkbType()) == QgsWkbTypes.GeometryType.LineGeometry:
+ self.tr("Cannot convert from {0} to LineStrings").format(
+ QgsWkbTypes.displayString(geom.wkbType())
+ )
+ )
+ elif (
+ QgsWkbTypes.geometryType(geom.wkbType())
+ == QgsWkbTypes.GeometryType.LineGeometry
+ ):
if QgsWkbTypes.isMultiType(geom.wkbType()):
return geom.asGeometryCollection()
else:
@@ -178,10 +204,19 @@ def convertToLineStrings(self, geom):
return boundary.asGeometryCollection()
def convertToMultiLineStrings(self, geom):
- if QgsWkbTypes.geometryType(geom.wkbType()) == QgsWkbTypes.GeometryType.PointGeometry:
+ if (
+ QgsWkbTypes.geometryType(geom.wkbType())
+ == QgsWkbTypes.GeometryType.PointGeometry
+ ):
raise QgsProcessingException(
- self.tr('Cannot convert from {0} to MultiLineStrings').format(QgsWkbTypes.displayString(geom.wkbType())))
- elif QgsWkbTypes.geometryType(geom.wkbType()) == QgsWkbTypes.GeometryType.LineGeometry:
+ self.tr("Cannot convert from {0} to MultiLineStrings").format(
+ QgsWkbTypes.displayString(geom.wkbType())
+ )
+ )
+ elif (
+ QgsWkbTypes.geometryType(geom.wkbType())
+ == QgsWkbTypes.GeometryType.LineGeometry
+ ):
if QgsWkbTypes.isMultiType(geom.wkbType()):
return [geom]
else:
@@ -195,10 +230,20 @@ def convertToMultiLineStrings(self, geom):
return [QgsGeometry(geom.constGet().boundary())]
def convertToPolygon(self, geom):
- if QgsWkbTypes.geometryType(geom.wkbType()) == QgsWkbTypes.GeometryType.PointGeometry and geom.constGet().nCoordinates() < 3:
+ if (
+ QgsWkbTypes.geometryType(geom.wkbType())
+ == QgsWkbTypes.GeometryType.PointGeometry
+ and geom.constGet().nCoordinates() < 3
+ ):
raise QgsProcessingException(
- self.tr('Cannot convert from Point to Polygon').format(QgsWkbTypes.displayString(geom.wkbType())))
- elif QgsWkbTypes.geometryType(geom.wkbType()) == QgsWkbTypes.GeometryType.PointGeometry:
+ self.tr("Cannot convert from Point to Polygon").format(
+ QgsWkbTypes.displayString(geom.wkbType())
+ )
+ )
+ elif (
+ QgsWkbTypes.geometryType(geom.wkbType())
+ == QgsWkbTypes.GeometryType.PointGeometry
+ ):
# multipoint with at least 3 points
# TODO: mega inefficient - needs rework when geometry iterators land
# (but at least it doesn't lose Z/M values)
@@ -212,7 +257,10 @@ def convertToPolygon(self, geom):
p = QgsPolygon()
p.setExteriorRing(linestring)
return [QgsGeometry(p)]
- elif QgsWkbTypes.geometryType(geom.wkbType()) == QgsWkbTypes.GeometryType.LineGeometry:
+ elif (
+ QgsWkbTypes.geometryType(geom.wkbType())
+ == QgsWkbTypes.GeometryType.LineGeometry
+ ):
if QgsWkbTypes.isMultiType(geom.wkbType()):
parts = []
for i in range(geom.constGet().numGeometries()):
diff --git a/python/plugins/processing/algs/qgis/Heatmap.py b/python/plugins/processing/algs/qgis/Heatmap.py
index 619722d203d8..f333e96fa17c 100644
--- a/python/plugins/processing/algs/qgis/Heatmap.py
+++ b/python/plugins/processing/algs/qgis/Heatmap.py
@@ -15,27 +15,29 @@
***************************************************************************
"""
-__author__ = 'Nyall Dawson'
-__date__ = 'November 2016'
-__copyright__ = '(C) 2016, Nyall Dawson'
+__author__ = "Nyall Dawson"
+__date__ = "November 2016"
+__copyright__ = "(C) 2016, Nyall Dawson"
import os
from collections import OrderedDict
from qgis.PyQt.QtGui import QIcon
-from qgis.core import (QgsApplication,
- QgsFeatureRequest,
- QgsRasterFileWriter,
- QgsProcessing,
- QgsProcessingException,
- QgsProcessingParameterFeatureSource,
- QgsProcessingParameterNumber,
- QgsProcessingParameterDistance,
- QgsProcessingParameterField,
- QgsProcessingParameterEnum,
- QgsProcessingParameterDefinition,
- QgsProcessingParameterRasterDestination)
+from qgis.core import (
+ QgsApplication,
+ QgsFeatureRequest,
+ QgsRasterFileWriter,
+ QgsProcessing,
+ QgsProcessingException,
+ QgsProcessingParameterFeatureSource,
+ QgsProcessingParameterNumber,
+ QgsProcessingParameterDistance,
+ QgsProcessingParameterField,
+ QgsProcessingParameterEnum,
+ QgsProcessingParameterDefinition,
+ QgsProcessingParameterRasterDestination,
+)
from qgis.analysis import QgsKernelDensityEstimation
@@ -45,130 +47,226 @@
class Heatmap(QgisAlgorithm):
- INPUT = 'INPUT'
- RADIUS = 'RADIUS'
- RADIUS_FIELD = 'RADIUS_FIELD'
- WEIGHT_FIELD = 'WEIGHT_FIELD'
- PIXEL_SIZE = 'PIXEL_SIZE'
- KERNEL = 'KERNEL'
- DECAY = 'DECAY'
- OUTPUT_VALUE = 'OUTPUT_VALUE'
- OUTPUT = 'OUTPUT'
+ INPUT = "INPUT"
+ RADIUS = "RADIUS"
+ RADIUS_FIELD = "RADIUS_FIELD"
+ WEIGHT_FIELD = "WEIGHT_FIELD"
+ PIXEL_SIZE = "PIXEL_SIZE"
+ KERNEL = "KERNEL"
+ DECAY = "DECAY"
+ OUTPUT_VALUE = "OUTPUT_VALUE"
+ OUTPUT = "OUTPUT"
def icon(self):
return QgsApplication.getThemeIcon("/heatmap.svg")
def tags(self):
- return self.tr('heatmap,kde,hotspot').split(',')
+ return self.tr("heatmap,kde,hotspot").split(",")
def group(self):
- return self.tr('Interpolation')
+ return self.tr("Interpolation")
def groupId(self):
- return 'interpolation'
+ return "interpolation"
def name(self):
- return 'heatmapkerneldensityestimation'
+ return "heatmapkerneldensityestimation"
def displayName(self):
- return self.tr('Heatmap (Kernel Density Estimation)')
+ return self.tr("Heatmap (Kernel Density Estimation)")
def __init__(self):
super().__init__()
def initAlgorithm(self, config=None):
- self.KERNELS = OrderedDict([(self.tr('Quartic'), QgsKernelDensityEstimation.KernelShape.KernelQuartic),
- (self.tr('Triangular'), QgsKernelDensityEstimation.KernelShape.KernelTriangular),
- (self.tr('Uniform'), QgsKernelDensityEstimation.KernelShape.KernelUniform),
- (self.tr('Triweight'), QgsKernelDensityEstimation.KernelShape.KernelTriweight),
- (self.tr('Epanechnikov'), QgsKernelDensityEstimation.KernelShape.KernelEpanechnikov)])
-
- self.OUTPUT_VALUES = OrderedDict([(self.tr('Raw'), QgsKernelDensityEstimation.OutputValues.OutputRaw),
- (self.tr('Scaled'), QgsKernelDensityEstimation.OutputValues.OutputScaled)])
-
- self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT,
- self.tr('Point layer'),
- [QgsProcessing.SourceType.TypeVectorPoint]))
-
- self.addParameter(QgsProcessingParameterDistance(self.RADIUS,
- self.tr('Radius'),
- 100.0, self.INPUT, False, 0.0))
-
- radius_field_param = QgsProcessingParameterField(self.RADIUS_FIELD,
- self.tr('Radius from field'),
- None,
- self.INPUT,
- QgsProcessingParameterField.DataType.Numeric,
- optional=True
- )
- radius_field_param.setFlags(radius_field_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
+ self.KERNELS = OrderedDict(
+ [
+ (
+ self.tr("Quartic"),
+ QgsKernelDensityEstimation.KernelShape.KernelQuartic,
+ ),
+ (
+ self.tr("Triangular"),
+ QgsKernelDensityEstimation.KernelShape.KernelTriangular,
+ ),
+ (
+ self.tr("Uniform"),
+ QgsKernelDensityEstimation.KernelShape.KernelUniform,
+ ),
+ (
+ self.tr("Triweight"),
+ QgsKernelDensityEstimation.KernelShape.KernelTriweight,
+ ),
+ (
+ self.tr("Epanechnikov"),
+ QgsKernelDensityEstimation.KernelShape.KernelEpanechnikov,
+ ),
+ ]
+ )
+
+ self.OUTPUT_VALUES = OrderedDict(
+ [
+ (self.tr("Raw"), QgsKernelDensityEstimation.OutputValues.OutputRaw),
+ (
+ self.tr("Scaled"),
+ QgsKernelDensityEstimation.OutputValues.OutputScaled,
+ ),
+ ]
+ )
+
+ self.addParameter(
+ QgsProcessingParameterFeatureSource(
+ self.INPUT,
+ self.tr("Point layer"),
+ [QgsProcessing.SourceType.TypeVectorPoint],
+ )
+ )
+
+ self.addParameter(
+ QgsProcessingParameterDistance(
+ self.RADIUS, self.tr("Radius"), 100.0, self.INPUT, False, 0.0
+ )
+ )
+
+ radius_field_param = QgsProcessingParameterField(
+ self.RADIUS_FIELD,
+ self.tr("Radius from field"),
+ None,
+ self.INPUT,
+ QgsProcessingParameterField.DataType.Numeric,
+ optional=True,
+ )
+ radius_field_param.setFlags(
+ radius_field_param.flags()
+ | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
self.addParameter(radius_field_param)
class ParameterHeatmapPixelSize(QgsProcessingParameterNumber):
- def __init__(self, name='', description='', parent_layer=None, radius_param=None, radius_field_param=None, minValue=None,
- default=None, optional=False):
- QgsProcessingParameterNumber.__init__(self, name, description, QgsProcessingParameterNumber.Type.Double, default, optional, minValue)
+ def __init__(
+ self,
+ name="",
+ description="",
+ parent_layer=None,
+ radius_param=None,
+ radius_field_param=None,
+ minValue=None,
+ default=None,
+ optional=False,
+ ):
+ QgsProcessingParameterNumber.__init__(
+ self,
+ name,
+ description,
+ QgsProcessingParameterNumber.Type.Double,
+ default,
+ optional,
+ minValue,
+ )
self.parent_layer = parent_layer
self.radius_param = radius_param
self.radius_field_param = radius_field_param
def clone(self):
- return ParameterHeatmapPixelSize(self.name(), self.description(), self.parent_layer, self.radius_param, self.radius_field_param, self.minimum(), self.maximum(), self.defaultValue((), self.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional))
-
- pixel_size_param = ParameterHeatmapPixelSize(self.PIXEL_SIZE,
- self.tr('Output raster size'),
- parent_layer=self.INPUT,
- radius_param=self.RADIUS,
- radius_field_param=self.RADIUS_FIELD,
- minValue=0.0,
- default=0.1)
- pixel_size_param.setMetadata({
- 'widget_wrapper': {
- 'class': 'processing.algs.qgis.ui.HeatmapWidgets.HeatmapPixelSizeWidgetWrapper'}})
+ return ParameterHeatmapPixelSize(
+ self.name(),
+ self.description(),
+ self.parent_layer,
+ self.radius_param,
+ self.radius_field_param,
+ self.minimum(),
+ self.maximum(),
+ self.defaultValue(
+ (),
+ self.flags()
+ & QgsProcessingParameterDefinition.Flag.FlagOptional,
+ ),
+ )
+
+ pixel_size_param = ParameterHeatmapPixelSize(
+ self.PIXEL_SIZE,
+ self.tr("Output raster size"),
+ parent_layer=self.INPUT,
+ radius_param=self.RADIUS,
+ radius_field_param=self.RADIUS_FIELD,
+ minValue=0.0,
+ default=0.1,
+ )
+ pixel_size_param.setMetadata(
+ {
+ "widget_wrapper": {
+ "class": "processing.algs.qgis.ui.HeatmapWidgets.HeatmapPixelSizeWidgetWrapper"
+ }
+ }
+ )
self.addParameter(pixel_size_param)
- weight_field_param = QgsProcessingParameterField(self.WEIGHT_FIELD,
- self.tr('Weight from field'),
- None,
- self.INPUT,
- QgsProcessingParameterField.DataType.Numeric,
- optional=True
- )
- weight_field_param.setFlags(weight_field_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
+ weight_field_param = QgsProcessingParameterField(
+ self.WEIGHT_FIELD,
+ self.tr("Weight from field"),
+ None,
+ self.INPUT,
+ QgsProcessingParameterField.DataType.Numeric,
+ optional=True,
+ )
+ weight_field_param.setFlags(
+ weight_field_param.flags()
+ | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
self.addParameter(weight_field_param)
keys = list(self.KERNELS.keys())
- kernel_shape_param = QgsProcessingParameterEnum(self.KERNEL,
- self.tr('Kernel shape'),
- keys,
- allowMultiple=False,
- defaultValue=0)
- kernel_shape_param.setFlags(kernel_shape_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
+ kernel_shape_param = QgsProcessingParameterEnum(
+ self.KERNEL,
+ self.tr("Kernel shape"),
+ keys,
+ allowMultiple=False,
+ defaultValue=0,
+ )
+ kernel_shape_param.setFlags(
+ kernel_shape_param.flags()
+ | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
self.addParameter(kernel_shape_param)
- decay_ratio = QgsProcessingParameterNumber(self.DECAY,
- self.tr('Decay ratio (Triangular kernels only)'),
- QgsProcessingParameterNumber.Type.Double,
- 0.0, True, -100.0, 100.0)
- decay_ratio.setFlags(decay_ratio.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
+ decay_ratio = QgsProcessingParameterNumber(
+ self.DECAY,
+ self.tr("Decay ratio (Triangular kernels only)"),
+ QgsProcessingParameterNumber.Type.Double,
+ 0.0,
+ True,
+ -100.0,
+ 100.0,
+ )
+ decay_ratio.setFlags(
+ decay_ratio.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
self.addParameter(decay_ratio)
keys = list(self.OUTPUT_VALUES.keys())
- output_scaling = QgsProcessingParameterEnum(self.OUTPUT_VALUE,
- self.tr('Output value scaling'),
- keys,
- allowMultiple=False,
- defaultValue=0)
- output_scaling.setFlags(output_scaling.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
+ output_scaling = QgsProcessingParameterEnum(
+ self.OUTPUT_VALUE,
+ self.tr("Output value scaling"),
+ keys,
+ allowMultiple=False,
+ defaultValue=0,
+ )
+ output_scaling.setFlags(
+ output_scaling.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
self.addParameter(output_scaling)
- self.addParameter(QgsProcessingParameterRasterDestination(self.OUTPUT, self.tr('Heatmap')))
+ self.addParameter(
+ QgsProcessingParameterRasterDestination(self.OUTPUT, self.tr("Heatmap"))
+ )
def processAlgorithm(self, parameters, context, feedback):
source = self.parameterAsSource(parameters, self.INPUT, context)
if source is None:
- raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT))
+ raise QgsProcessingException(
+ self.invalidSourceError(parameters, self.INPUT)
+ )
radius = self.parameterAsDouble(parameters, self.RADIUS, context)
kernel_shape = self.parameterAsEnum(parameters, self.KERNEL, context)
@@ -176,7 +274,9 @@ def processAlgorithm(self, parameters, context, feedback):
decay = self.parameterAsDouble(parameters, self.DECAY, context)
output_values = self.parameterAsEnum(parameters, self.OUTPUT_VALUE, context)
outputFile = self.parameterAsOutputLayer(parameters, self.OUTPUT, context)
- output_format = QgsRasterFileWriter.driverForExtension(os.path.splitext(outputFile)[1])
+ output_format = QgsRasterFileWriter.driverForExtension(
+ os.path.splitext(outputFile)[1]
+ )
weight_field = self.parameterAsString(parameters, self.WEIGHT_FIELD, context)
radius_field = self.parameterAsString(parameters, self.RADIUS_FIELD, context)
@@ -202,8 +302,7 @@ def processAlgorithm(self, parameters, context, feedback):
kde = QgsKernelDensityEstimation(kde_params, outputFile, output_format)
if kde.prepare() != QgsKernelDensityEstimation.Result.Success:
- raise QgsProcessingException(
- self.tr('Could not create destination layer'))
+ raise QgsProcessingException(self.tr("Could not create destination layer"))
request = QgsFeatureRequest()
request.setSubsetOfAttributes(attrs)
@@ -214,12 +313,13 @@ def processAlgorithm(self, parameters, context, feedback):
break
if kde.addFeature(f) != QgsKernelDensityEstimation.Result.Success:
- feedback.reportError(self.tr('Error adding feature with ID {} to heatmap').format(f.id()))
+ feedback.reportError(
+ self.tr("Error adding feature with ID {} to heatmap").format(f.id())
+ )
feedback.setProgress(int(current * total))
if kde.finalise() != QgsKernelDensityEstimation.Result.Success:
- raise QgsProcessingException(
- self.tr('Could not save destination layer'))
+ raise QgsProcessingException(self.tr("Could not save destination layer"))
return {self.OUTPUT: outputFile}
diff --git a/python/plugins/processing/algs/qgis/HubDistanceLines.py b/python/plugins/processing/algs/qgis/HubDistanceLines.py
index 25e5e495e19d..75fd57c458b8 100644
--- a/python/plugins/processing/algs/qgis/HubDistanceLines.py
+++ b/python/plugins/processing/algs/qgis/HubDistanceLines.py
@@ -15,88 +15,116 @@
***************************************************************************
"""
-__author__ = 'Michael Minn'
-__date__ = 'May 2010'
-__copyright__ = '(C) 2010, Michael Minn'
+__author__ = "Michael Minn"
+__date__ = "May 2010"
+__copyright__ = "(C) 2010, Michael Minn"
from qgis.PyQt.QtCore import QMetaType
-from qgis.core import (QgsField,
- QgsGeometry,
- QgsDistanceArea,
- QgsFeature,
- QgsFeatureSink,
- QgsFeatureRequest,
- QgsWkbTypes,
- QgsUnitTypes,
- QgsProcessing,
- QgsProcessingParameterFeatureSource,
- QgsProcessingParameterField,
- QgsProcessingParameterEnum,
- QgsProcessingParameterFeatureSink,
- QgsProcessingException,
- QgsSpatialIndex)
+from qgis.core import (
+ QgsField,
+ QgsGeometry,
+ QgsDistanceArea,
+ QgsFeature,
+ QgsFeatureSink,
+ QgsFeatureRequest,
+ QgsWkbTypes,
+ QgsUnitTypes,
+ QgsProcessing,
+ QgsProcessingParameterFeatureSource,
+ QgsProcessingParameterField,
+ QgsProcessingParameterEnum,
+ QgsProcessingParameterFeatureSink,
+ QgsProcessingException,
+ QgsSpatialIndex,
+)
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
from math import sqrt
class HubDistanceLines(QgisAlgorithm):
- INPUT = 'INPUT'
- HUBS = 'HUBS'
- FIELD = 'FIELD'
- UNIT = 'UNIT'
- OUTPUT = 'OUTPUT'
-
- LAYER_UNITS = 'LAYER_UNITS'
-
- UNITS = [QgsUnitTypes.DistanceUnit.DistanceMeters,
- QgsUnitTypes.DistanceUnit.DistanceFeet,
- QgsUnitTypes.DistanceUnit.DistanceMiles,
- QgsUnitTypes.DistanceUnit.DistanceKilometers,
- LAYER_UNITS
- ]
+ INPUT = "INPUT"
+ HUBS = "HUBS"
+ FIELD = "FIELD"
+ UNIT = "UNIT"
+ OUTPUT = "OUTPUT"
+
+ LAYER_UNITS = "LAYER_UNITS"
+
+ UNITS = [
+ QgsUnitTypes.DistanceUnit.DistanceMeters,
+ QgsUnitTypes.DistanceUnit.DistanceFeet,
+ QgsUnitTypes.DistanceUnit.DistanceMiles,
+ QgsUnitTypes.DistanceUnit.DistanceKilometers,
+ LAYER_UNITS,
+ ]
def group(self):
- return self.tr('Vector analysis')
+ return self.tr("Vector analysis")
def groupId(self):
- return 'vectoranalysis'
+ return "vectoranalysis"
def __init__(self):
super().__init__()
def initAlgorithm(self, config=None):
- self.units = [self.tr('Meters'),
- self.tr('Feet'),
- self.tr('Miles'),
- self.tr('Kilometers'),
- self.tr('Layer units')]
-
- self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT,
- self.tr('Source points layer')))
- self.addParameter(QgsProcessingParameterFeatureSource(self.HUBS,
- self.tr('Destination hubs layer')))
- self.addParameter(QgsProcessingParameterField(self.FIELD,
- self.tr('Hub layer name attribute'), parentLayerParameterName=self.HUBS))
- self.addParameter(QgsProcessingParameterEnum(self.UNIT,
- self.tr('Measurement unit'), self.units))
-
- self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Hub distance'), QgsProcessing.SourceType.TypeVectorLine))
+ self.units = [
+ self.tr("Meters"),
+ self.tr("Feet"),
+ self.tr("Miles"),
+ self.tr("Kilometers"),
+ self.tr("Layer units"),
+ ]
+
+ self.addParameter(
+ QgsProcessingParameterFeatureSource(
+ self.INPUT, self.tr("Source points layer")
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterFeatureSource(
+ self.HUBS, self.tr("Destination hubs layer")
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterField(
+ self.FIELD,
+ self.tr("Hub layer name attribute"),
+ parentLayerParameterName=self.HUBS,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterEnum(
+ self.UNIT, self.tr("Measurement unit"), self.units
+ )
+ )
+
+ self.addParameter(
+ QgsProcessingParameterFeatureSink(
+ self.OUTPUT,
+ self.tr("Hub distance"),
+ QgsProcessing.SourceType.TypeVectorLine,
+ )
+ )
def name(self):
- return 'distancetonearesthublinetohub'
+ return "distancetonearesthublinetohub"
def displayName(self):
- return self.tr('Distance to nearest hub (line to hub)')
+ return self.tr("Distance to nearest hub (line to hub)")
def processAlgorithm(self, parameters, context, feedback):
if parameters[self.INPUT] == parameters[self.HUBS]:
raise QgsProcessingException(
- self.tr('Same layer given for both hubs and spokes'))
+ self.tr("Same layer given for both hubs and spokes")
+ )
point_source = self.parameterAsSource(parameters, self.INPUT, context)
if point_source is None:
- raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT))
+ raise QgsProcessingException(
+ self.invalidSourceError(parameters, self.INPUT)
+ )
hub_source = self.parameterAsSource(parameters, self.HUBS, context)
if hub_source is None:
@@ -107,15 +135,27 @@ def processAlgorithm(self, parameters, context, feedback):
units = self.UNITS[self.parameterAsEnum(parameters, self.UNIT, context)]
fields = point_source.fields()
- fields.append(QgsField('HubName', QMetaType.Type.QString))
- fields.append(QgsField('HubDist', QMetaType.Type.Double))
-
- (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
- fields, QgsWkbTypes.Type.LineString, point_source.sourceCrs())
+ fields.append(QgsField("HubName", QMetaType.Type.QString))
+ fields.append(QgsField("HubDist", QMetaType.Type.Double))
+
+ (sink, dest_id) = self.parameterAsSink(
+ parameters,
+ self.OUTPUT,
+ context,
+ fields,
+ QgsWkbTypes.Type.LineString,
+ point_source.sourceCrs(),
+ )
if sink is None:
raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT))
- index = QgsSpatialIndex(hub_source.getFeatures(QgsFeatureRequest().setSubsetOfAttributes([]).setDestinationCrs(point_source.sourceCrs(), context.transformContext())))
+ index = QgsSpatialIndex(
+ hub_source.getFeatures(
+ QgsFeatureRequest()
+ .setSubsetOfAttributes([])
+ .setDestinationCrs(point_source.sourceCrs(), context.transformContext())
+ )
+ )
distance = QgsDistanceArea()
distance.setSourceCrs(point_source.sourceCrs(), context.transformContext())
@@ -123,7 +163,9 @@ def processAlgorithm(self, parameters, context, feedback):
# Scan source points, find nearest hub, and write to output file
features = point_source.getFeatures()
- total = 100.0 / point_source.featureCount() if point_source.featureCount() else 0
+ total = (
+ 100.0 / point_source.featureCount() if point_source.featureCount() else 0
+ )
for current, f in enumerate(features):
if feedback.isCanceled():
break
@@ -137,12 +179,23 @@ def processAlgorithm(self, parameters, context, feedback):
if len(neighbors) == 0:
continue
- ft = next(hub_source.getFeatures(QgsFeatureRequest().setFilterFid(neighbors[0]).setSubsetOfAttributes([fieldName], hub_source.fields()).setDestinationCrs(point_source.sourceCrs(), context.transformContext())))
+ ft = next(
+ hub_source.getFeatures(
+ QgsFeatureRequest()
+ .setFilterFid(neighbors[0])
+ .setSubsetOfAttributes([fieldName], hub_source.fields())
+ .setDestinationCrs(
+ point_source.sourceCrs(), context.transformContext()
+ )
+ )
+ )
closest = ft.geometry().boundingBox().center()
hubDist = distance.measureLine(src, closest)
if units != self.LAYER_UNITS:
- hub_dist_in_desired_units = distance.convertLengthMeasurement(hubDist, units)
+ hub_dist_in_desired_units = distance.convertLengthMeasurement(
+ hubDist, units
+ )
else:
hub_dist_in_desired_units = hubDist
diff --git a/python/plugins/processing/algs/qgis/HubDistancePoints.py b/python/plugins/processing/algs/qgis/HubDistancePoints.py
index e9b8a4649b76..602c1799d070 100644
--- a/python/plugins/processing/algs/qgis/HubDistancePoints.py
+++ b/python/plugins/processing/algs/qgis/HubDistancePoints.py
@@ -15,85 +15,113 @@
***************************************************************************
"""
-__author__ = 'Michael Minn'
-__date__ = 'May 2010'
-__copyright__ = '(C) 2010, Michael Minn'
+__author__ = "Michael Minn"
+__date__ = "May 2010"
+__copyright__ = "(C) 2010, Michael Minn"
from qgis.PyQt.QtCore import QMetaType
-from qgis.core import (QgsField,
- QgsGeometry,
- QgsFeatureSink,
- QgsDistanceArea,
- QgsFeature,
- QgsFeatureRequest,
- QgsSpatialIndex,
- QgsWkbTypes,
- QgsUnitTypes,
- QgsProcessing,
- QgsProcessingParameterFeatureSource,
- QgsProcessingParameterField,
- QgsProcessingParameterEnum,
- QgsProcessingParameterFeatureSink,
- QgsProcessingException)
+from qgis.core import (
+ QgsField,
+ QgsGeometry,
+ QgsFeatureSink,
+ QgsDistanceArea,
+ QgsFeature,
+ QgsFeatureRequest,
+ QgsSpatialIndex,
+ QgsWkbTypes,
+ QgsUnitTypes,
+ QgsProcessing,
+ QgsProcessingParameterFeatureSource,
+ QgsProcessingParameterField,
+ QgsProcessingParameterEnum,
+ QgsProcessingParameterFeatureSink,
+ QgsProcessingException,
+)
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
class HubDistancePoints(QgisAlgorithm):
- INPUT = 'INPUT'
- HUBS = 'HUBS'
- FIELD = 'FIELD'
- UNIT = 'UNIT'
- OUTPUT = 'OUTPUT'
- LAYER_UNITS = 'LAYER_UNITS'
-
- UNITS = [QgsUnitTypes.DistanceUnit.DistanceMeters,
- QgsUnitTypes.DistanceUnit.DistanceFeet,
- QgsUnitTypes.DistanceUnit.DistanceMiles,
- QgsUnitTypes.DistanceUnit.DistanceKilometers,
- LAYER_UNITS
- ]
+ INPUT = "INPUT"
+ HUBS = "HUBS"
+ FIELD = "FIELD"
+ UNIT = "UNIT"
+ OUTPUT = "OUTPUT"
+ LAYER_UNITS = "LAYER_UNITS"
+
+ UNITS = [
+ QgsUnitTypes.DistanceUnit.DistanceMeters,
+ QgsUnitTypes.DistanceUnit.DistanceFeet,
+ QgsUnitTypes.DistanceUnit.DistanceMiles,
+ QgsUnitTypes.DistanceUnit.DistanceKilometers,
+ LAYER_UNITS,
+ ]
def group(self):
- return self.tr('Vector analysis')
+ return self.tr("Vector analysis")
def groupId(self):
- return 'vectoranalysis'
+ return "vectoranalysis"
def __init__(self):
super().__init__()
def initAlgorithm(self, config=None):
- self.units = [self.tr('Meters'),
- self.tr('Feet'),
- self.tr('Miles'),
- self.tr('Kilometers'),
- self.tr('Layer units')]
-
- self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT,
- self.tr('Source points layer')))
- self.addParameter(QgsProcessingParameterFeatureSource(self.HUBS,
- self.tr('Destination hubs layer')))
- self.addParameter(QgsProcessingParameterField(self.FIELD,
- self.tr('Hub layer name attribute'), parentLayerParameterName=self.HUBS))
- self.addParameter(QgsProcessingParameterEnum(self.UNIT,
- self.tr('Measurement unit'), self.units))
-
- self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Hub distance'), QgsProcessing.SourceType.TypeVectorPoint))
+ self.units = [
+ self.tr("Meters"),
+ self.tr("Feet"),
+ self.tr("Miles"),
+ self.tr("Kilometers"),
+ self.tr("Layer units"),
+ ]
+
+ self.addParameter(
+ QgsProcessingParameterFeatureSource(
+ self.INPUT, self.tr("Source points layer")
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterFeatureSource(
+ self.HUBS, self.tr("Destination hubs layer")
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterField(
+ self.FIELD,
+ self.tr("Hub layer name attribute"),
+ parentLayerParameterName=self.HUBS,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterEnum(
+ self.UNIT, self.tr("Measurement unit"), self.units
+ )
+ )
+
+ self.addParameter(
+ QgsProcessingParameterFeatureSink(
+ self.OUTPUT,
+ self.tr("Hub distance"),
+ QgsProcessing.SourceType.TypeVectorPoint,
+ )
+ )
def name(self):
- return 'distancetonearesthubpoints'
+ return "distancetonearesthubpoints"
def displayName(self):
- return self.tr('Distance to nearest hub (points)')
+ return self.tr("Distance to nearest hub (points)")
def processAlgorithm(self, parameters, context, feedback):
if parameters[self.INPUT] == parameters[self.HUBS]:
raise QgsProcessingException(
- self.tr('Same layer given for both hubs and spokes'))
+ self.tr("Same layer given for both hubs and spokes")
+ )
point_source = self.parameterAsSource(parameters, self.INPUT, context)
if point_source is None:
- raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT))
+ raise QgsProcessingException(
+ self.invalidSourceError(parameters, self.INPUT)
+ )
hub_source = self.parameterAsSource(parameters, self.HUBS, context)
if hub_source is None:
@@ -104,15 +132,27 @@ def processAlgorithm(self, parameters, context, feedback):
units = self.UNITS[self.parameterAsEnum(parameters, self.UNIT, context)]
fields = point_source.fields()
- fields.append(QgsField('HubName', QMetaType.Type.QString))
- fields.append(QgsField('HubDist', QMetaType.Type.Double))
-
- (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
- fields, QgsWkbTypes.Type.Point, point_source.sourceCrs())
+ fields.append(QgsField("HubName", QMetaType.Type.QString))
+ fields.append(QgsField("HubDist", QMetaType.Type.Double))
+
+ (sink, dest_id) = self.parameterAsSink(
+ parameters,
+ self.OUTPUT,
+ context,
+ fields,
+ QgsWkbTypes.Type.Point,
+ point_source.sourceCrs(),
+ )
if sink is None:
raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT))
- index = QgsSpatialIndex(hub_source.getFeatures(QgsFeatureRequest().setSubsetOfAttributes([]).setDestinationCrs(point_source.sourceCrs(), context.transformContext())))
+ index = QgsSpatialIndex(
+ hub_source.getFeatures(
+ QgsFeatureRequest()
+ .setSubsetOfAttributes([])
+ .setDestinationCrs(point_source.sourceCrs(), context.transformContext())
+ )
+ )
distance = QgsDistanceArea()
distance.setSourceCrs(point_source.sourceCrs(), context.transformContext())
@@ -120,7 +160,9 @@ def processAlgorithm(self, parameters, context, feedback):
# Scan source points, find nearest hub, and write to output file
features = point_source.getFeatures()
- total = 100.0 / point_source.featureCount() if point_source.featureCount() else 0
+ total = (
+ 100.0 / point_source.featureCount() if point_source.featureCount() else 0
+ )
for current, f in enumerate(features):
if feedback.isCanceled():
break
@@ -135,12 +177,23 @@ def processAlgorithm(self, parameters, context, feedback):
if len(neighbors) == 0:
continue
- ft = next(hub_source.getFeatures(QgsFeatureRequest().setFilterFid(neighbors[0]).setSubsetOfAttributes([fieldName], hub_source.fields()).setDestinationCrs(point_source.sourceCrs(), context.transformContext())))
+ ft = next(
+ hub_source.getFeatures(
+ QgsFeatureRequest()
+ .setFilterFid(neighbors[0])
+ .setSubsetOfAttributes([fieldName], hub_source.fields())
+ .setDestinationCrs(
+ point_source.sourceCrs(), context.transformContext()
+ )
+ )
+ )
closest = ft.geometry().boundingBox().center()
hubDist = distance.measureLine(src, closest)
if units != self.LAYER_UNITS:
- hub_dist_in_desired_units = distance.convertLengthMeasurement(hubDist, units)
+ hub_dist_in_desired_units = distance.convertLengthMeasurement(
+ hubDist, units
+ )
else:
hub_dist_in_desired_units = hubDist
diff --git a/python/plugins/processing/algs/qgis/HypsometricCurves.py b/python/plugins/processing/algs/qgis/HypsometricCurves.py
index bcc8d9170882..bbbfd58b6882 100644
--- a/python/plugins/processing/algs/qgis/HypsometricCurves.py
+++ b/python/plugins/processing/algs/qgis/HypsometricCurves.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Alexander Bruy'
-__date__ = 'November 2014'
-__copyright__ = '(C) 2014, Alexander Bruy'
+__author__ = "Alexander Bruy"
+__date__ = "November 2014"
+__copyright__ = "(C) 2014, Alexander Bruy"
import os
import csv
@@ -28,16 +28,18 @@
ogr.UseExceptions()
osr.UseExceptions()
-from qgis.core import (QgsRectangle,
- QgsGeometry,
- QgsFeatureRequest,
- QgsProcessingException,
- QgsProcessing,
- QgsProcessingParameterBoolean,
- QgsProcessingParameterNumber,
- QgsProcessingParameterRasterLayer,
- QgsProcessingParameterFeatureSource,
- QgsProcessingParameterFolderDestination)
+from qgis.core import (
+ QgsRectangle,
+ QgsGeometry,
+ QgsFeatureRequest,
+ QgsProcessingException,
+ QgsProcessing,
+ QgsProcessingParameterBoolean,
+ QgsProcessingParameterNumber,
+ QgsProcessingParameterRasterLayer,
+ QgsProcessingParameterFeatureSource,
+ QgsProcessingParameterFolderDestination,
+)
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
from processing.tools import raster
@@ -46,45 +48,71 @@
class HypsometricCurves(QgisAlgorithm):
- INPUT_DEM = 'INPUT_DEM'
- BOUNDARY_LAYER = 'BOUNDARY_LAYER'
- STEP = 'STEP'
- USE_PERCENTAGE = 'USE_PERCENTAGE'
- OUTPUT_DIRECTORY = 'OUTPUT_DIRECTORY'
+ INPUT_DEM = "INPUT_DEM"
+ BOUNDARY_LAYER = "BOUNDARY_LAYER"
+ STEP = "STEP"
+ USE_PERCENTAGE = "USE_PERCENTAGE"
+ OUTPUT_DIRECTORY = "OUTPUT_DIRECTORY"
def group(self):
- return self.tr('Raster terrain analysis')
+ return self.tr("Raster terrain analysis")
def groupId(self):
- return 'rasterterrainanalysis'
+ return "rasterterrainanalysis"
def __init__(self):
super().__init__()
def initAlgorithm(self, config=None):
- self.addParameter(QgsProcessingParameterRasterLayer(self.INPUT_DEM,
- self.tr('DEM to analyze')))
- self.addParameter(QgsProcessingParameterFeatureSource(self.BOUNDARY_LAYER,
- self.tr('Boundary layer'), [QgsProcessing.SourceType.TypeVectorPolygon]))
- self.addParameter(QgsProcessingParameterNumber(self.STEP,
- self.tr('Step'), type=QgsProcessingParameterNumber.Type.Double, minValue=0.0, defaultValue=100.0))
- self.addParameter(QgsProcessingParameterBoolean(self.USE_PERCENTAGE,
- self.tr('Use % of area instead of absolute value'), defaultValue=False))
-
- self.addParameter(QgsProcessingParameterFolderDestination(self.OUTPUT_DIRECTORY,
- self.tr('Hypsometric curves')))
+ self.addParameter(
+ QgsProcessingParameterRasterLayer(self.INPUT_DEM, self.tr("DEM to analyze"))
+ )
+ self.addParameter(
+ QgsProcessingParameterFeatureSource(
+ self.BOUNDARY_LAYER,
+ self.tr("Boundary layer"),
+ [QgsProcessing.SourceType.TypeVectorPolygon],
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterNumber(
+ self.STEP,
+ self.tr("Step"),
+ type=QgsProcessingParameterNumber.Type.Double,
+ minValue=0.0,
+ defaultValue=100.0,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterBoolean(
+ self.USE_PERCENTAGE,
+ self.tr("Use % of area instead of absolute value"),
+ defaultValue=False,
+ )
+ )
+
+ self.addParameter(
+ QgsProcessingParameterFolderDestination(
+ self.OUTPUT_DIRECTORY, self.tr("Hypsometric curves")
+ )
+ )
def name(self):
- return 'hypsometriccurves'
+ return "hypsometriccurves"
def displayName(self):
- return self.tr('Hypsometric curves')
+ return self.tr("Hypsometric curves")
def processAlgorithm(self, parameters, context, feedback):
try:
import numpy
except ImportError:
- raise QgsProcessingException(QCoreApplication.translate('HypsometricCurves', 'This algorithm requires the Python “numpy” library. Please install this library and try again.'))
+ raise QgsProcessingException(
+ QCoreApplication.translate(
+ "HypsometricCurves",
+ "This algorithm requires the Python “numpy” library. Please install this library and try again.",
+ )
+ )
raster_layer = self.parameterAsRasterLayer(parameters, self.INPUT_DEM, context)
target_crs = raster_layer.crs()
@@ -92,7 +120,9 @@ def processAlgorithm(self, parameters, context, feedback):
source = self.parameterAsSource(parameters, self.BOUNDARY_LAYER, context)
if source is None:
- raise QgsProcessingException(self.invalidSourceError(parameters, self.BOUNDARY_LAYER))
+ raise QgsProcessingException(
+ self.invalidSourceError(parameters, self.BOUNDARY_LAYER)
+ )
step = self.parameterAsDouble(parameters, self.STEP, context)
percentage = self.parameterAsBoolean(parameters, self.USE_PERCENTAGE, context)
@@ -111,19 +141,25 @@ def processAlgorithm(self, parameters, context, feedback):
rasterXSize = rasterDS.RasterXSize
rasterYSize = rasterDS.RasterYSize
- rasterBBox = QgsRectangle(geoTransform[0],
- geoTransform[3] - cellYSize * rasterYSize,
- geoTransform[0] + cellXSize * rasterXSize,
- geoTransform[3])
+ rasterBBox = QgsRectangle(
+ geoTransform[0],
+ geoTransform[3] - cellYSize * rasterYSize,
+ geoTransform[0] + cellXSize * rasterXSize,
+ geoTransform[3],
+ )
rasterGeom = QgsGeometry.fromRect(rasterBBox)
crs = osr.SpatialReference()
crs.ImportFromProj4(str(target_crs.toProj()))
- memVectorDriver = ogr.GetDriverByName('Memory')
- memRasterDriver = gdal.GetDriverByName('MEM')
+ memVectorDriver = ogr.GetDriverByName("Memory")
+ memRasterDriver = gdal.GetDriverByName("MEM")
- features = source.getFeatures(QgsFeatureRequest().setDestinationCrs(target_crs, context.transformContext()))
+ features = source.getFeatures(
+ QgsFeatureRequest().setDestinationCrs(
+ target_crs, context.transformContext()
+ )
+ )
total = 100.0 / source.featureCount() if source.featureCount() else 0
for current, f in enumerate(features):
@@ -138,12 +174,16 @@ def processAlgorithm(self, parameters, context, feedback):
if intersectedGeom.isEmpty():
feedback.pushInfo(
- self.tr('Feature {0} does not intersect raster or '
- 'entirely located in NODATA area').format(f.id()))
+ self.tr(
+ "Feature {0} does not intersect raster or "
+ "entirely located in NODATA area"
+ ).format(f.id())
+ )
continue
fName = os.path.join(
- outputPath, f'histogram_{source.sourceName()}_{f.id()}.csv')
+ outputPath, f"histogram_{source.sourceName()}_{f.id()}.csv"
+ )
ogrGeom = ogr.CreateGeometryFromWkt(intersectedGeom.asWkt())
bbox = intersectedGeom.boundingBox()
@@ -163,8 +203,10 @@ def processAlgorithm(self, parameters, context, feedback):
if srcOffset[2] == 0 or srcOffset[3] == 0:
feedback.pushInfo(
- self.tr('Feature {0} is smaller than raster '
- 'cell size').format(f.id()))
+ self.tr("Feature {0} is smaller than raster " "cell size").format(
+ f.id()
+ )
+ )
continue
newGeoTransform = (
@@ -173,30 +215,35 @@ def processAlgorithm(self, parameters, context, feedback):
0.0,
geoTransform[3] + srcOffset[1] * geoTransform[5],
0.0,
- geoTransform[5]
+ geoTransform[5],
)
- memVDS = memVectorDriver.CreateDataSource('out')
- memLayer = memVDS.CreateLayer('poly', crs, ogr.wkbPolygon)
+ memVDS = memVectorDriver.CreateDataSource("out")
+ memLayer = memVDS.CreateLayer("poly", crs, ogr.wkbPolygon)
ft = ogr.Feature(memLayer.GetLayerDefn())
ft.SetGeometry(ogrGeom)
memLayer.CreateFeature(ft)
ft.Destroy()
- rasterizedDS = memRasterDriver.Create('', srcOffset[2],
- srcOffset[3], 1, gdal.GDT_Byte)
+ rasterizedDS = memRasterDriver.Create(
+ "", srcOffset[2], srcOffset[3], 1, gdal.GDT_Byte
+ )
rasterizedDS.SetGeoTransform(newGeoTransform)
gdal.RasterizeLayer(rasterizedDS, [1], memLayer, burn_values=[1])
rasterizedArray = rasterizedDS.ReadAsArray()
srcArray = numpy.nan_to_num(srcArray)
- masked = numpy.ma.MaskedArray(srcArray,
- mask=numpy.logical_or(srcArray == noData,
- numpy.logical_not(rasterizedArray)))
+ masked = numpy.ma.MaskedArray(
+ srcArray,
+ mask=numpy.logical_or(
+ srcArray == noData, numpy.logical_not(rasterizedArray)
+ ),
+ )
- self.calculateHypsometry(f.id(), fName, feedback, masked,
- cellXSize, cellYSize, percentage, step)
+ self.calculateHypsometry(
+ f.id(), fName, feedback, masked, cellXSize, cellYSize, percentage, step
+ )
memVDS = None
rasterizedDS = None
@@ -206,14 +253,16 @@ def processAlgorithm(self, parameters, context, feedback):
return {self.OUTPUT_DIRECTORY: outputPath}
- def calculateHypsometry(self, fid, fName, feedback, data, pX, pY,
- percentage, step):
+ def calculateHypsometry(self, fid, fName, feedback, data, pX, pY, percentage, step):
out = dict()
d = data.compressed()
if d.size == 0:
feedback.pushInfo(
- self.tr('Feature {0} does not intersect raster or '
- 'entirely located in NODATA area').format(fid))
+ self.tr(
+ "Feature {0} does not intersect raster or "
+ "entirely located in NODATA area"
+ ).format(fid)
+ )
return
minValue = d.min()
@@ -241,9 +290,9 @@ def calculateHypsometry(self, fid, fName, feedback, data, pX, pY,
out[i[0]] = i[1] + out[prev]
prev = i[0]
- with open(fName, 'w', newline='', encoding='utf-8') as out_file:
+ with open(fName, "w", newline="", encoding="utf-8") as out_file:
writer = csv.writer(out_file)
- writer.writerow([self.tr('Area'), self.tr('Elevation')])
+ writer.writerow([self.tr("Area"), self.tr("Elevation")])
for i in sorted(out.items()):
writer.writerow([i[1], i[0]])
diff --git a/python/plugins/processing/algs/qgis/IdwInterpolation.py b/python/plugins/processing/algs/qgis/IdwInterpolation.py
index 98b5e84b1afc..65f9b910bd72 100644
--- a/python/plugins/processing/algs/qgis/IdwInterpolation.py
+++ b/python/plugins/processing/algs/qgis/IdwInterpolation.py
@@ -15,97 +15,129 @@
***************************************************************************
"""
-__author__ = 'Alexander Bruy'
-__date__ = 'October 2016'
-__copyright__ = '(C) 2016, Alexander Bruy'
+__author__ = "Alexander Bruy"
+__date__ = "October 2016"
+__copyright__ = "(C) 2016, Alexander Bruy"
import os
import math
from qgis.PyQt.QtGui import QIcon
-from qgis.core import (QgsRectangle,
- QgsProcessingUtils,
- QgsProcessingParameterNumber,
- QgsProcessingParameterExtent,
- QgsProcessingParameterDefinition,
- QgsProcessingParameterRasterDestination,
- QgsProcessingException)
-from qgis.analysis import (QgsInterpolator,
- QgsIDWInterpolator,
- QgsGridFileWriter)
+from qgis.core import (
+ QgsRectangle,
+ QgsProcessingUtils,
+ QgsProcessingParameterNumber,
+ QgsProcessingParameterExtent,
+ QgsProcessingParameterDefinition,
+ QgsProcessingParameterRasterDestination,
+ QgsProcessingException,
+)
+from qgis.analysis import QgsInterpolator, QgsIDWInterpolator, QgsGridFileWriter
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
-from processing.algs.qgis.ui.InterpolationWidgets import ParameterInterpolationData, ParameterPixelSize
+from processing.algs.qgis.ui.InterpolationWidgets import (
+ ParameterInterpolationData,
+ ParameterPixelSize,
+)
pluginPath = os.path.split(os.path.split(os.path.dirname(__file__))[0])[0]
class IdwInterpolation(QgisAlgorithm):
- INTERPOLATION_DATA = 'INTERPOLATION_DATA'
- DISTANCE_COEFFICIENT = 'DISTANCE_COEFFICIENT'
- PIXEL_SIZE = 'PIXEL_SIZE'
- COLUMNS = 'COLUMNS'
- ROWS = 'ROWS'
- EXTENT = 'EXTENT'
- OUTPUT = 'OUTPUT'
+ INTERPOLATION_DATA = "INTERPOLATION_DATA"
+ DISTANCE_COEFFICIENT = "DISTANCE_COEFFICIENT"
+ PIXEL_SIZE = "PIXEL_SIZE"
+ COLUMNS = "COLUMNS"
+ ROWS = "ROWS"
+ EXTENT = "EXTENT"
+ OUTPUT = "OUTPUT"
def icon(self):
- return QIcon(os.path.join(pluginPath, 'images', 'interpolation.png'))
+ return QIcon(os.path.join(pluginPath, "images", "interpolation.png"))
def group(self):
- return self.tr('Interpolation')
+ return self.tr("Interpolation")
def groupId(self):
- return 'interpolation'
+ return "interpolation"
def __init__(self):
super().__init__()
def initAlgorithm(self, config=None):
- self.addParameter(ParameterInterpolationData(self.INTERPOLATION_DATA,
- self.tr('Input layer(s)')))
- self.addParameter(QgsProcessingParameterNumber(self.DISTANCE_COEFFICIENT,
- self.tr('Distance coefficient P'), type=QgsProcessingParameterNumber.Type.Double,
- minValue=0.0, maxValue=99.99, defaultValue=2.0))
- self.addParameter(QgsProcessingParameterExtent(self.EXTENT,
- self.tr('Extent'),
- optional=False))
- pixel_size_param = ParameterPixelSize(self.PIXEL_SIZE,
- self.tr('Output raster size'),
- layersData=self.INTERPOLATION_DATA,
- extent=self.EXTENT,
- minValue=0.0,
- default=0.1)
+ self.addParameter(
+ ParameterInterpolationData(
+ self.INTERPOLATION_DATA, self.tr("Input layer(s)")
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterNumber(
+ self.DISTANCE_COEFFICIENT,
+ self.tr("Distance coefficient P"),
+ type=QgsProcessingParameterNumber.Type.Double,
+ minValue=0.0,
+ maxValue=99.99,
+ defaultValue=2.0,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterExtent(self.EXTENT, self.tr("Extent"), optional=False)
+ )
+ pixel_size_param = ParameterPixelSize(
+ self.PIXEL_SIZE,
+ self.tr("Output raster size"),
+ layersData=self.INTERPOLATION_DATA,
+ extent=self.EXTENT,
+ minValue=0.0,
+ default=0.1,
+ )
self.addParameter(pixel_size_param)
- cols_param = QgsProcessingParameterNumber(self.COLUMNS,
- self.tr('Number of columns'),
- optional=True,
- minValue=0, maxValue=10000000)
- cols_param.setFlags(cols_param.flags() | QgsProcessingParameterDefinition.Flag.FlagHidden)
+ cols_param = QgsProcessingParameterNumber(
+ self.COLUMNS,
+ self.tr("Number of columns"),
+ optional=True,
+ minValue=0,
+ maxValue=10000000,
+ )
+ cols_param.setFlags(
+ cols_param.flags() | QgsProcessingParameterDefinition.Flag.FlagHidden
+ )
self.addParameter(cols_param)
- rows_param = QgsProcessingParameterNumber(self.ROWS,
- self.tr('Number of rows'),
- optional=True,
- minValue=0, maxValue=10000000)
- rows_param.setFlags(rows_param.flags() | QgsProcessingParameterDefinition.Flag.FlagHidden)
+ rows_param = QgsProcessingParameterNumber(
+ self.ROWS,
+ self.tr("Number of rows"),
+ optional=True,
+ minValue=0,
+ maxValue=10000000,
+ )
+ rows_param.setFlags(
+ rows_param.flags() | QgsProcessingParameterDefinition.Flag.FlagHidden
+ )
self.addParameter(rows_param)
- self.addParameter(QgsProcessingParameterRasterDestination(self.OUTPUT,
- self.tr('Interpolated')))
+ self.addParameter(
+ QgsProcessingParameterRasterDestination(
+ self.OUTPUT, self.tr("Interpolated")
+ )
+ )
def name(self):
- return 'idwinterpolation'
+ return "idwinterpolation"
def displayName(self):
- return self.tr('IDW interpolation')
+ return self.tr("IDW interpolation")
def processAlgorithm(self, parameters, context, feedback):
- interpolationData = ParameterInterpolationData.parseValue(parameters[self.INTERPOLATION_DATA])
- coefficient = self.parameterAsDouble(parameters, self.DISTANCE_COEFFICIENT, context)
+ interpolationData = ParameterInterpolationData.parseValue(
+ parameters[self.INTERPOLATION_DATA]
+ )
+ coefficient = self.parameterAsDouble(
+ parameters, self.DISTANCE_COEFFICIENT, context
+ )
bbox = self.parameterAsExtent(parameters, self.EXTENT, context)
pixel_size = self.parameterAsDouble(parameters, self.PIXEL_SIZE, context)
output = self.parameterAsOutputLayer(parameters, self.OUTPUT, context)
@@ -119,12 +151,13 @@ def processAlgorithm(self, parameters, context, feedback):
if interpolationData is None:
raise QgsProcessingException(
- self.tr('You need to specify at least one input layer.'))
+ self.tr("You need to specify at least one input layer.")
+ )
layerData = []
layers = []
- for i, row in enumerate(interpolationData.split('::|::')):
- v = row.split('::~::')
+ for i, row in enumerate(interpolationData.split("::|::")):
+ v = row.split("::~::")
data = QgsInterpolator.LayerData()
# need to keep a reference until interpolation is complete
@@ -135,13 +168,19 @@ def processAlgorithm(self, parameters, context, feedback):
data.valueSource = int(v[1])
data.interpolationAttribute = int(v[2])
- if data.valueSource == QgsInterpolator.ValueSource.ValueAttribute and data.interpolationAttribute == -1:
- raise QgsProcessingException(self.tr(
- 'Layer {} is set to use a value attribute, but no attribute was set').format(i + 1))
-
- if v[3] == '0':
+ if (
+ data.valueSource == QgsInterpolator.ValueSource.ValueAttribute
+ and data.interpolationAttribute == -1
+ ):
+ raise QgsProcessingException(
+ self.tr(
+ "Layer {} is set to use a value attribute, but no attribute was set"
+ ).format(i + 1)
+ )
+
+ if v[3] == "0":
data.sourceType = QgsInterpolator.SourceType.SourcePoints
- elif v[3] == '1':
+ elif v[3] == "1":
data.sourceType = QgsInterpolator.SourceType.SourceStructureLines
else:
data.sourceType = QgsInterpolator.SourceType.SourceBreakLines
@@ -150,11 +189,7 @@ def processAlgorithm(self, parameters, context, feedback):
interpolator = QgsIDWInterpolator(layerData)
interpolator.setDistanceCoefficient(coefficient)
- writer = QgsGridFileWriter(interpolator,
- output,
- bbox,
- columns,
- rows)
+ writer = QgsGridFileWriter(interpolator, output, bbox, columns, rows)
writer.writeFile(feedback)
return {self.OUTPUT: output}
diff --git a/python/plugins/processing/algs/qgis/ImportIntoSpatialite.py b/python/plugins/processing/algs/qgis/ImportIntoSpatialite.py
index 1923f991fb90..124344882c61 100644
--- a/python/plugins/processing/algs/qgis/ImportIntoSpatialite.py
+++ b/python/plugins/processing/algs/qgis/ImportIntoSpatialite.py
@@ -15,156 +15,228 @@
***************************************************************************
"""
-__author__ = 'Mathieu Pellerin'
-__date__ = 'October 2016'
-__copyright__ = '(C) 2012, Mathieu Pellerin'
-
-from qgis.core import (QgsDataSourceUri,
- QgsFeatureSink,
- QgsProcessingAlgorithm,
- QgsVectorLayerExporter,
- QgsProcessing,
- QgsProcessingException,
- QgsProcessingParameterFeatureSource,
- QgsProcessingParameterVectorLayer,
- QgsProcessingParameterField,
- QgsProcessingParameterString,
- QgsProcessingParameterBoolean,
- QgsWkbTypes,
- QgsProviderRegistry,
- QgsProviderConnectionException,
- QgsAbstractDatabaseProviderConnection)
+__author__ = "Mathieu Pellerin"
+__date__ = "October 2016"
+__copyright__ = "(C) 2012, Mathieu Pellerin"
+
+from qgis.core import (
+ QgsDataSourceUri,
+ QgsFeatureSink,
+ QgsProcessingAlgorithm,
+ QgsVectorLayerExporter,
+ QgsProcessing,
+ QgsProcessingException,
+ QgsProcessingParameterFeatureSource,
+ QgsProcessingParameterVectorLayer,
+ QgsProcessingParameterField,
+ QgsProcessingParameterString,
+ QgsProcessingParameterBoolean,
+ QgsWkbTypes,
+ QgsProviderRegistry,
+ QgsProviderConnectionException,
+ QgsAbstractDatabaseProviderConnection,
+)
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
class ImportIntoSpatialite(QgisAlgorithm):
- DATABASE = 'DATABASE'
- TABLENAME = 'TABLENAME'
- INPUT = 'INPUT'
- OVERWRITE = 'OVERWRITE'
- CREATEINDEX = 'CREATEINDEX'
- GEOMETRY_COLUMN = 'GEOMETRY_COLUMN'
- LOWERCASE_NAMES = 'LOWERCASE_NAMES'
- DROP_STRING_LENGTH = 'DROP_STRING_LENGTH'
- FORCE_SINGLEPART = 'FORCE_SINGLEPART'
- PRIMARY_KEY = 'PRIMARY_KEY'
- ENCODING = 'ENCODING'
+ DATABASE = "DATABASE"
+ TABLENAME = "TABLENAME"
+ INPUT = "INPUT"
+ OVERWRITE = "OVERWRITE"
+ CREATEINDEX = "CREATEINDEX"
+ GEOMETRY_COLUMN = "GEOMETRY_COLUMN"
+ LOWERCASE_NAMES = "LOWERCASE_NAMES"
+ DROP_STRING_LENGTH = "DROP_STRING_LENGTH"
+ FORCE_SINGLEPART = "FORCE_SINGLEPART"
+ PRIMARY_KEY = "PRIMARY_KEY"
+ ENCODING = "ENCODING"
def group(self):
- return self.tr('Database')
+ return self.tr("Database")
def groupId(self):
- return 'database'
+ return "database"
def __init__(self):
super().__init__()
def initAlgorithm(self, config=None):
- self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT, self.tr('Layer to import'),
- types=[QgsProcessing.SourceType.TypeVector]))
- self.addParameter(QgsProcessingParameterVectorLayer(self.DATABASE, self.tr('File database'), optional=False))
self.addParameter(
- QgsProcessingParameterString(self.TABLENAME, self.tr('Table to import to (leave blank to use layer name)'),
- optional=True))
- self.addParameter(QgsProcessingParameterField(self.PRIMARY_KEY, self.tr('Primary key field'), None, self.INPUT,
- QgsProcessingParameterField.DataType.Any, False, True))
- self.addParameter(QgsProcessingParameterString(self.GEOMETRY_COLUMN, self.tr('Geometry column'), 'geom'))
- self.addParameter(QgsProcessingParameterString(self.ENCODING, self.tr('Encoding'), 'UTF-8', optional=True))
- self.addParameter(QgsProcessingParameterBoolean(self.OVERWRITE, self.tr('Overwrite'), True))
- self.addParameter(QgsProcessingParameterBoolean(self.CREATEINDEX, self.tr('Create spatial index'), True))
+ QgsProcessingParameterFeatureSource(
+ self.INPUT,
+ self.tr("Layer to import"),
+ types=[QgsProcessing.SourceType.TypeVector],
+ )
+ )
self.addParameter(
- QgsProcessingParameterBoolean(self.LOWERCASE_NAMES, self.tr('Convert field names to lowercase'), True))
- self.addParameter(QgsProcessingParameterBoolean(self.DROP_STRING_LENGTH,
- self.tr('Drop length constraints on character fields'), False))
- self.addParameter(QgsProcessingParameterBoolean(self.FORCE_SINGLEPART,
- self.tr('Create single-part geometries instead of multi-part'),
- False))
+ QgsProcessingParameterVectorLayer(
+ self.DATABASE, self.tr("File database"), optional=False
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterString(
+ self.TABLENAME,
+ self.tr("Table to import to (leave blank to use layer name)"),
+ optional=True,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterField(
+ self.PRIMARY_KEY,
+ self.tr("Primary key field"),
+ None,
+ self.INPUT,
+ QgsProcessingParameterField.DataType.Any,
+ False,
+ True,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterString(
+ self.GEOMETRY_COLUMN, self.tr("Geometry column"), "geom"
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterString(
+ self.ENCODING, self.tr("Encoding"), "UTF-8", optional=True
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterBoolean(self.OVERWRITE, self.tr("Overwrite"), True)
+ )
+ self.addParameter(
+ QgsProcessingParameterBoolean(
+ self.CREATEINDEX, self.tr("Create spatial index"), True
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterBoolean(
+ self.LOWERCASE_NAMES, self.tr("Convert field names to lowercase"), True
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterBoolean(
+ self.DROP_STRING_LENGTH,
+ self.tr("Drop length constraints on character fields"),
+ False,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterBoolean(
+ self.FORCE_SINGLEPART,
+ self.tr("Create single-part geometries instead of multi-part"),
+ False,
+ )
+ )
def flags(self):
return super().flags() | QgsProcessingAlgorithm.Flag.FlagNoThreading
def name(self):
- return 'importintospatialite'
+ return "importintospatialite"
def displayName(self):
- return self.tr('Export to SpatiaLite')
+ return self.tr("Export to SpatiaLite")
def shortDescription(self):
- return self.tr('Exports a vector layer to a SpatiaLite database')
+ return self.tr("Exports a vector layer to a SpatiaLite database")
def tags(self):
- return self.tr('import,table,layer,into,copy').split(',')
+ return self.tr("import,table,layer,into,copy").split(",")
def processAlgorithm(self, parameters, context, feedback):
database = self.parameterAsVectorLayer(parameters, self.DATABASE, context)
databaseuri = database.dataProvider().dataSourceUri()
uri = QgsDataSourceUri(databaseuri)
- if uri.database() == '':
- if '|layername' in databaseuri:
- databaseuri = databaseuri[:databaseuri.find('|layername')]
- elif '|layerid' in databaseuri:
- databaseuri = databaseuri[:databaseuri.find('|layerid')]
- uri = QgsDataSourceUri('dbname=\'%s\'' % (databaseuri))
+ if uri.database() == "":
+ if "|layername" in databaseuri:
+ databaseuri = databaseuri[: databaseuri.find("|layername")]
+ elif "|layerid" in databaseuri:
+ databaseuri = databaseuri[: databaseuri.find("|layerid")]
+ uri = QgsDataSourceUri("dbname='%s'" % (databaseuri))
try:
- md = QgsProviderRegistry.instance().providerMetadata('spatialite')
+ md = QgsProviderRegistry.instance().providerMetadata("spatialite")
conn = md.createConnection(uri.uri(), {})
except QgsProviderConnectionException:
- raise QgsProcessingException(self.tr('Could not connect to {}').format(uri.uri()))
+ raise QgsProcessingException(
+ self.tr("Could not connect to {}").format(uri.uri())
+ )
overwrite = self.parameterAsBoolean(parameters, self.OVERWRITE, context)
createIndex = self.parameterAsBoolean(parameters, self.CREATEINDEX, context)
- convertLowerCase = self.parameterAsBoolean(parameters, self.LOWERCASE_NAMES, context)
- dropStringLength = self.parameterAsBoolean(parameters, self.DROP_STRING_LENGTH, context)
- forceSinglePart = self.parameterAsBoolean(parameters, self.FORCE_SINGLEPART, context)
- primaryKeyField = self.parameterAsString(parameters, self.PRIMARY_KEY, context) or 'id'
+ convertLowerCase = self.parameterAsBoolean(
+ parameters, self.LOWERCASE_NAMES, context
+ )
+ dropStringLength = self.parameterAsBoolean(
+ parameters, self.DROP_STRING_LENGTH, context
+ )
+ forceSinglePart = self.parameterAsBoolean(
+ parameters, self.FORCE_SINGLEPART, context
+ )
+ primaryKeyField = (
+ self.parameterAsString(parameters, self.PRIMARY_KEY, context) or "id"
+ )
encoding = self.parameterAsString(parameters, self.ENCODING, context)
source = self.parameterAsSource(parameters, self.INPUT, context)
if source is None:
- raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT))
+ raise QgsProcessingException(
+ self.invalidSourceError(parameters, self.INPUT)
+ )
table = self.parameterAsString(parameters, self.TABLENAME, context)
if table:
table.strip()
- if not table or table == '':
+ if not table or table == "":
table = source.sourceName()
- table = table.replace('.', '_')
- table = table.replace(' ', '').lower()
- providerName = 'spatialite'
+ table = table.replace(".", "_")
+ table = table.replace(" ", "").lower()
+ providerName = "spatialite"
geomColumn = self.parameterAsString(parameters, self.GEOMETRY_COLUMN, context)
if not geomColumn:
- geomColumn = 'geom'
+ geomColumn = "geom"
options = {}
if overwrite:
- options['overwrite'] = True
+ options["overwrite"] = True
if convertLowerCase:
- options['lowercaseFieldNames'] = True
+ options["lowercaseFieldNames"] = True
geomColumn = geomColumn.lower()
if dropStringLength:
- options['dropStringConstraints'] = True
+ options["dropStringConstraints"] = True
if forceSinglePart:
- options['forceSinglePartGeometryType'] = True
+ options["forceSinglePartGeometryType"] = True
# Clear geometry column for non-geometry tables
if source.wkbType() == QgsWkbTypes.Type.NoGeometry:
geomColumn = None
- uri.setDataSource('', table, geomColumn, '', primaryKeyField)
+ uri.setDataSource("", table, geomColumn, "", primaryKeyField)
if encoding:
- options['fileEncoding'] = encoding
-
- exporter = QgsVectorLayerExporter(uri.uri(), providerName, source.fields(),
- source.wkbType(), source.sourceCrs(), overwrite, options)
+ options["fileEncoding"] = encoding
+
+ exporter = QgsVectorLayerExporter(
+ uri.uri(),
+ providerName,
+ source.fields(),
+ source.wkbType(),
+ source.sourceCrs(),
+ overwrite,
+ options,
+ )
if exporter.errorCode() != QgsVectorLayerExporter.ExportError.NoError:
raise QgsProcessingException(
- self.tr('Error importing to Spatialite\n{0}').format(exporter.errorMessage()))
+ self.tr("Error importing to Spatialite\n{0}").format(
+ exporter.errorMessage()
+ )
+ )
features = source.getFeatures()
total = 100.0 / source.featureCount() if source.featureCount() else 0
@@ -180,14 +252,19 @@ def processAlgorithm(self, parameters, context, feedback):
exporter.flushBuffer()
if exporter.errorCode() != QgsVectorLayerExporter.ExportError.NoError:
raise QgsProcessingException(
- self.tr('Error importing to Spatialite\n{0}').format(exporter.errorMessage()))
+ self.tr("Error importing to Spatialite\n{0}").format(
+ exporter.errorMessage()
+ )
+ )
if geomColumn and createIndex:
try:
options = QgsAbstractDatabaseProviderConnection.SpatialIndexOptions()
options.geometryColumnName = geomColumn
- conn.createSpatialIndex('', table, options)
+ conn.createSpatialIndex("", table, options)
except QgsProviderConnectionException as e:
- raise QgsProcessingException(self.tr('Error creating spatial index:\n{0}').format(e))
+ raise QgsProcessingException(
+ self.tr("Error creating spatial index:\n{0}").format(e)
+ )
return {}
diff --git a/python/plugins/processing/algs/qgis/KNearestConcaveHull.py b/python/plugins/processing/algs/qgis/KNearestConcaveHull.py
index ce968f6278ed..aa108b839776 100644
--- a/python/plugins/processing/algs/qgis/KNearestConcaveHull.py
+++ b/python/plugins/processing/algs/qgis/KNearestConcaveHull.py
@@ -18,9 +18,9 @@
***************************************************************************/
"""
-__author__ = 'Detlev Neumann'
-__date__ = 'November 2014'
-__copyright__ = '(C) 2014, Detlev Neumann'
+__author__ = "Detlev Neumann"
+__date__ = "November 2014"
+__copyright__ = "(C) 2014, Detlev Neumann"
import os.path
import math
@@ -28,41 +28,43 @@
from qgis.PyQt.QtGui import QIcon
from qgis.PyQt.QtCore import QMetaType
-from qgis.core import (QgsApplication,
- QgsExpression,
- QgsFeature,
- QgsFeatureRequest,
- QgsFeatureSink,
- QgsField,
- QgsFields,
- QgsGeometry,
- QgsProcessing,
- QgsProcessingAlgorithm,
- QgsProcessingException,
- QgsProcessingParameterFeatureSink,
- QgsProcessingParameterFeatureSource,
- QgsProcessingParameterField,
- QgsProcessingParameterNumber,
- QgsPoint,
- QgsPointXY,
- QgsWkbTypes)
+from qgis.core import (
+ QgsApplication,
+ QgsExpression,
+ QgsFeature,
+ QgsFeatureRequest,
+ QgsFeatureSink,
+ QgsField,
+ QgsFields,
+ QgsGeometry,
+ QgsProcessing,
+ QgsProcessingAlgorithm,
+ QgsProcessingException,
+ QgsProcessingParameterFeatureSink,
+ QgsProcessingParameterFeatureSource,
+ QgsProcessingParameterField,
+ QgsProcessingParameterNumber,
+ QgsPoint,
+ QgsPointXY,
+ QgsWkbTypes,
+)
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
class KNearestConcaveHull(QgisAlgorithm):
- KNEIGHBORS = 'KNEIGHBORS'
- INPUT = 'INPUT'
- OUTPUT = 'OUTPUT'
- FIELD = 'FIELD'
+ KNEIGHBORS = "KNEIGHBORS"
+ INPUT = "INPUT"
+ OUTPUT = "OUTPUT"
+ FIELD = "FIELD"
def name(self):
- return 'knearestconcavehull'
+ return "knearestconcavehull"
def displayName(self):
- return self.tr('Concave hull (k-nearest neighbor)')
+ return self.tr("Concave hull (k-nearest neighbor)")
def shortDescription(self):
- return self.tr('Creates a concave hull using the k-nearest neighbor algorithm.')
+ return self.tr("Creates a concave hull using the k-nearest neighbor algorithm.")
def icon(self):
return QgsApplication.getThemeIcon("/algorithms/mAlgorithmConcaveHull.svg")
@@ -71,35 +73,59 @@ def svgIconPath(self):
return QgsApplication.iconPath("/algorithms/mAlgorithmConcaveHull.svg")
def group(self):
- return self.tr('Vector geometry')
+ return self.tr("Vector geometry")
def groupId(self):
- return 'vectorgeometry'
+ return "vectorgeometry"
def flags(self):
- return super().flags() | QgsProcessingAlgorithm.Flag.FlagDeprecated | QgsProcessingAlgorithm.Flag.FlagNotAvailableInStandaloneTool
+ return (
+ super().flags()
+ | QgsProcessingAlgorithm.Flag.FlagDeprecated
+ | QgsProcessingAlgorithm.Flag.FlagNotAvailableInStandaloneTool
+ )
def __init__(self):
super().__init__()
def initAlgorithm(self, config=None):
- self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT,
- self.tr('Input layer')))
- self.addParameter(QgsProcessingParameterNumber(self.KNEIGHBORS,
- self.tr('Number of neighboring points to consider (a lower number is more concave, a higher number is smoother)'),
- QgsProcessingParameterNumber.Type.Integer,
- defaultValue=3, minValue=3))
- self.addParameter(QgsProcessingParameterField(self.FIELD,
- self.tr('Field (set if creating concave hulls by class)'),
- parentLayerParameterName=self.INPUT, optional=True))
- self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Concave hull'),
- QgsProcessing.SourceType.TypeVectorPolygon))
+ self.addParameter(
+ QgsProcessingParameterFeatureSource(self.INPUT, self.tr("Input layer"))
+ )
+ self.addParameter(
+ QgsProcessingParameterNumber(
+ self.KNEIGHBORS,
+ self.tr(
+ "Number of neighboring points to consider (a lower number is more concave, a higher number is smoother)"
+ ),
+ QgsProcessingParameterNumber.Type.Integer,
+ defaultValue=3,
+ minValue=3,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterField(
+ self.FIELD,
+ self.tr("Field (set if creating concave hulls by class)"),
+ parentLayerParameterName=self.INPUT,
+ optional=True,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterFeatureSink(
+ self.OUTPUT,
+ self.tr("Concave hull"),
+ QgsProcessing.SourceType.TypeVectorPolygon,
+ )
+ )
def processAlgorithm(self, parameters, context, feedback):
# Get variables from dialog
source = self.parameterAsSource(parameters, self.INPUT, context)
if source is None:
- raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT))
+ raise QgsProcessingException(
+ self.invalidSourceError(parameters, self.INPUT)
+ )
field_name = self.parameterAsString(parameters, self.FIELD, context)
kneighbors = self.parameterAsInt(parameters, self.KNEIGHBORS, context)
@@ -108,7 +134,7 @@ def processAlgorithm(self, parameters, context, feedback):
field_index = -1
fields = QgsFields()
- fields.append(QgsField('id', QMetaType.Type.Int, '', 20))
+ fields.append(QgsField("id", QMetaType.Type.Int, "", 20))
current = 0
@@ -116,13 +142,23 @@ def processAlgorithm(self, parameters, context, feedback):
if use_field:
field_index = source.fields().lookupField(field_name)
if field_index >= 0:
- fields.append(source.fields()[field_index]) # Add a field with the name of the grouping field
+ fields.append(
+ source.fields()[field_index]
+ ) # Add a field with the name of the grouping field
# Initialize writer
- (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
- fields, QgsWkbTypes.Type.Polygon, source.sourceCrs())
+ (sink, dest_id) = self.parameterAsSink(
+ parameters,
+ self.OUTPUT,
+ context,
+ fields,
+ QgsWkbTypes.Type.Polygon,
+ source.sourceCrs(),
+ )
if sink is None:
- raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT))
+ raise QgsProcessingException(
+ self.invalidSinkError(parameters, self.OUTPUT)
+ )
success = False
fid = 0
@@ -133,7 +169,9 @@ def processAlgorithm(self, parameters, context, feedback):
for unique in unique_values:
points = []
- filter = QgsExpression.createFieldEqualityExpression(field_name, unique)
+ filter = QgsExpression.createFieldEqualityExpression(
+ field_name, unique
+ )
request = QgsFeatureRequest().setFilterExpression(filter)
request.setSubsetOfAttributes([])
# Get features with the grouping attribute equal to the current grouping value
@@ -150,7 +188,9 @@ def processAlgorithm(self, parameters, context, feedback):
out_feature = QgsFeature()
the_hull = concave_hull(points, kneighbors)
if the_hull:
- vertex = [QgsPointXY(point[0], point[1]) for point in the_hull]
+ vertex = [
+ QgsPointXY(point[0], point[1]) for point in the_hull
+ ]
poly = QgsGeometry().fromPolygonXY([vertex])
out_feature.setGeometry(poly)
@@ -160,19 +200,29 @@ def processAlgorithm(self, parameters, context, feedback):
success = True # at least one polygon created
fid += 1
if not success:
- raise QgsProcessingException('No hulls could be created. Most likely there were not at least three unique points in any of the groups.')
+ raise QgsProcessingException(
+ "No hulls could be created. Most likely there were not at least three unique points in any of the groups."
+ )
sink.finalize()
else:
# Field parameter provided but can't read from it
- raise QgsProcessingException('Unable to find grouping field')
+ raise QgsProcessingException("Unable to find grouping field")
else:
# Not grouped by field
# Initialize writer
- (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
- fields, QgsWkbTypes.Type.Polygon, source.sourceCrs())
+ (sink, dest_id) = self.parameterAsSink(
+ parameters,
+ self.OUTPUT,
+ context,
+ fields,
+ QgsWkbTypes.Type.Polygon,
+ source.sourceCrs(),
+ )
if sink is None:
- raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT))
+ raise QgsProcessingException(
+ self.invalidSinkError(parameters, self.OUTPUT)
+ )
points = []
request = QgsFeatureRequest()
@@ -200,9 +250,13 @@ def processAlgorithm(self, parameters, context, feedback):
sink.addFeature(out_feature, QgsFeatureSink.Flag.FastInsert)
else:
# the_hull returns None only when there are less than three points after cleaning
- raise QgsProcessingException('At least three unique points are required to create a concave hull.')
+ raise QgsProcessingException(
+ "At least three unique points are required to create a concave hull."
+ )
else:
- raise QgsProcessingException('At least three points are required to create a concave hull.')
+ raise QgsProcessingException(
+ "At least three points are required to create a concave hull."
+ )
sink.finalize()
@@ -225,7 +279,9 @@ def find_min_y_point(list_of_points):
"""
min_y_pt = list_of_points[0]
for point in list_of_points[1:]:
- if point[1] < min_y_pt[1] or (point[1] == min_y_pt[1] and point[0] < min_y_pt[0]):
+ if point[1] < min_y_pt[1] or (
+ point[1] == min_y_pt[1] and point[0] < min_y_pt[0]
+ ):
min_y_pt = point
return min_y_pt
@@ -254,7 +310,9 @@ def euclidean_distance(point1, point2):
:param point2: tuple (x, y)
:return: float
"""
- return math.sqrt(math.pow(point1[0] - point2[0], 2) + math.pow(point1[1] - point2[1], 2))
+ return math.sqrt(
+ math.pow(point1[0] - point2[0], 2) + math.pow(point1[1] - point2[1], 2)
+ )
def nearest_points(list_of_points, point, k):
@@ -272,7 +330,9 @@ def nearest_points(list_of_points, point, k):
# their respective index of list *list_of_distances*
list_of_distances = []
for index in range(len(list_of_points)):
- list_of_distances.append((euclidean_distance(list_of_points[index], point), index))
+ list_of_distances.append(
+ (euclidean_distance(list_of_points[index], point), index)
+ )
# sort distances in ascending order
list_of_distances.sort()
@@ -335,16 +395,24 @@ def intersect(line1, line2):
a2 = line2[1][1] - line2[0][1]
b2 = line2[0][0] - line2[1][0]
c2 = a2 * line2[0][0] + b2 * line2[0][1]
- tmp = (a1 * b2 - a2 * b1)
+ tmp = a1 * b2 - a2 * b1
if tmp == 0:
return False
sx = (c1 * b2 - c2 * b1) / tmp
- if (sx > line1[0][0] and sx > line1[1][0]) or (sx > line2[0][0] and sx > line2[1][0]) or\
- (sx < line1[0][0] and sx < line1[1][0]) or (sx < line2[0][0] and sx < line2[1][0]):
+ if (
+ (sx > line1[0][0] and sx > line1[1][0])
+ or (sx > line2[0][0] and sx > line2[1][0])
+ or (sx < line1[0][0] and sx < line1[1][0])
+ or (sx < line2[0][0] and sx < line2[1][0])
+ ):
return False
sy = (a1 * c2 - a2 * c1) / tmp
- if (sy > line1[0][1] and sy > line1[1][1]) or (sy > line2[0][1] and sy > line2[1][1]) or\
- (sy < line1[0][1] and sy < line1[1][1]) or (sy < line2[0][1] and sy < line2[1][1]):
+ if (
+ (sy > line1[0][1] and sy > line1[1][1])
+ or (sy > line2[0][1] and sy > line2[1][1])
+ or (sy < line1[0][1] and sy < line1[1][1])
+ or (sy < line2[0][1] and sy < line2[1][1])
+ ):
return False
return True
@@ -516,7 +584,10 @@ def concave_hull(points_list, k):
its = False
while its is False and (j < len(hull) - last_point):
- its = intersect((hull[step - 2], c_points[i]), (hull[step - 2 - j], hull[step - 1 - j]))
+ its = intersect(
+ (hull[step - 2], c_points[i]),
+ (hull[step - 2 - j], hull[step - 1 - j]),
+ )
j += 1
# there is no candidate to which the connecting line does not intersect any existing segment, so the
diff --git a/python/plugins/processing/algs/qgis/LinesToPolygons.py b/python/plugins/processing/algs/qgis/LinesToPolygons.py
index 7a0e457aae48..fb5bfbd68ed3 100644
--- a/python/plugins/processing/algs/qgis/LinesToPolygons.py
+++ b/python/plugins/processing/algs/qgis/LinesToPolygons.py
@@ -15,27 +15,29 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'August 2012'
-__copyright__ = '(C) 2012, Victor Olaya'
+__author__ = "Victor Olaya"
+__date__ = "August 2012"
+__copyright__ = "(C) 2012, Victor Olaya"
import os
from qgis.PyQt.QtGui import QIcon
-from qgis.core import (QgsApplication,
- QgsFeature,
- QgsGeometry,
- QgsGeometryCollection,
- QgsPolygon,
- QgsMultiPolygon,
- QgsMultiSurface,
- QgsWkbTypes,
- QgsFeatureSink,
- QgsProcessing,
- QgsProcessingParameterFeatureSource,
- QgsProcessingParameterFeatureSink,
- QgsProcessingUtils)
+from qgis.core import (
+ QgsApplication,
+ QgsFeature,
+ QgsGeometry,
+ QgsGeometryCollection,
+ QgsPolygon,
+ QgsMultiPolygon,
+ QgsMultiSurface,
+ QgsWkbTypes,
+ QgsFeatureSink,
+ QgsProcessing,
+ QgsProcessingParameterFeatureSource,
+ QgsProcessingParameterFeatureSink,
+ QgsProcessingUtils,
+)
from processing.algs.qgis.QgisAlgorithm import QgisFeatureBasedAlgorithm
from processing.tools import dataobjects, vector
@@ -52,25 +54,25 @@ def svgIconPath(self):
return QgsApplication.iconPath("/algorithms/mAlgorithmLineToPolygon.svg")
def tags(self):
- return self.tr('line,polygon,convert').split(',')
+ return self.tr("line,polygon,convert").split(",")
def group(self):
- return self.tr('Vector geometry')
+ return self.tr("Vector geometry")
def groupId(self):
- return 'vectorgeometry'
+ return "vectorgeometry"
def __init__(self):
super().__init__()
def name(self):
- return 'linestopolygons'
+ return "linestopolygons"
def displayName(self):
- return self.tr('Lines to polygons')
+ return self.tr("Lines to polygons")
def outputName(self):
- return self.tr('Polygons')
+ return self.tr("Polygons")
def outputType(self):
return QgsProcessing.SourceType.TypeVectorPolygon
@@ -85,7 +87,11 @@ def processFeature(self, feature, context, feedback):
if feature.hasGeometry():
feature.setGeometry(QgsGeometry(self.convertToPolygons(feature.geometry())))
if feature.geometry().isEmpty():
- feedback.reportError(self.tr("One or more line ignored due to geometry not having a minimum of three vertices."))
+ feedback.reportError(
+ self.tr(
+ "One or more line ignored due to geometry not having a minimum of three vertices."
+ )
+ )
return [feature]
def supportInPlaceEdit(self, layer):
@@ -93,9 +99,15 @@ def supportInPlaceEdit(self, layer):
def convertWkbToPolygons(self, wkb):
multi_wkb = QgsWkbTypes.Type.NoGeometry
- if QgsWkbTypes.singleType(QgsWkbTypes.flatType(wkb)) == QgsWkbTypes.Type.LineString:
+ if (
+ QgsWkbTypes.singleType(QgsWkbTypes.flatType(wkb))
+ == QgsWkbTypes.Type.LineString
+ ):
multi_wkb = QgsWkbTypes.Type.MultiPolygon
- elif QgsWkbTypes.singleType(QgsWkbTypes.flatType(wkb)) == QgsWkbTypes.Type.CompoundCurve:
+ elif (
+ QgsWkbTypes.singleType(QgsWkbTypes.flatType(wkb))
+ == QgsWkbTypes.Type.CompoundCurve
+ ):
multi_wkb = QgsWkbTypes.Type.MultiSurface
if QgsWkbTypes.hasM(wkb):
multi_wkb = QgsWkbTypes.addM(multi_wkb)
diff --git a/python/plugins/processing/algs/qgis/MeanAndStdDevPlot.py b/python/plugins/processing/algs/qgis/MeanAndStdDevPlot.py
index acf235e7d5a5..24263c7e611f 100644
--- a/python/plugins/processing/algs/qgis/MeanAndStdDevPlot.py
+++ b/python/plugins/processing/algs/qgis/MeanAndStdDevPlot.py
@@ -15,16 +15,18 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'January 2013'
-__copyright__ = '(C) 2013, Victor Olaya'
+__author__ = "Victor Olaya"
+__date__ = "January 2013"
+__copyright__ = "(C) 2013, Victor Olaya"
import warnings
-from qgis.core import (QgsProcessingParameterFeatureSource,
- QgsProcessingParameterField,
- QgsProcessingException,
- QgsProcessingParameterFileDestination)
+from qgis.core import (
+ QgsProcessingParameterFeatureSource,
+ QgsProcessingParameterField,
+ QgsProcessingException,
+ QgsProcessingParameterFileDestination,
+)
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
from processing.tools import vector
@@ -33,38 +35,52 @@
class MeanAndStdDevPlot(QgisAlgorithm):
- INPUT = 'INPUT'
- OUTPUT = 'OUTPUT'
- NAME_FIELD = 'NAME_FIELD'
- VALUE_FIELD = 'VALUE_FIELD'
+ INPUT = "INPUT"
+ OUTPUT = "OUTPUT"
+ NAME_FIELD = "NAME_FIELD"
+ VALUE_FIELD = "VALUE_FIELD"
def group(self):
- return self.tr('Plots')
+ return self.tr("Plots")
def groupId(self):
- return 'plots'
+ return "plots"
def __init__(self):
super().__init__()
def initAlgorithm(self, config=None):
- self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT,
- self.tr('Input table')))
- self.addParameter(QgsProcessingParameterField(self.NAME_FIELD,
- self.tr('Category name field'), parentLayerParameterName=self.INPUT,
- type=QgsProcessingParameterField.DataType.Any))
- self.addParameter(QgsProcessingParameterField(self.VALUE_FIELD,
- self.tr('Value field'),
- parentLayerParameterName=self.INPUT,
- type=QgsProcessingParameterField.DataType.Numeric))
-
- self.addParameter(QgsProcessingParameterFileDestination(self.OUTPUT, self.tr('Plot'), self.tr('HTML files (*.html)')))
+ self.addParameter(
+ QgsProcessingParameterFeatureSource(self.INPUT, self.tr("Input table"))
+ )
+ self.addParameter(
+ QgsProcessingParameterField(
+ self.NAME_FIELD,
+ self.tr("Category name field"),
+ parentLayerParameterName=self.INPUT,
+ type=QgsProcessingParameterField.DataType.Any,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterField(
+ self.VALUE_FIELD,
+ self.tr("Value field"),
+ parentLayerParameterName=self.INPUT,
+ type=QgsProcessingParameterField.DataType.Numeric,
+ )
+ )
+
+ self.addParameter(
+ QgsProcessingParameterFileDestination(
+ self.OUTPUT, self.tr("Plot"), self.tr("HTML files (*.html)")
+ )
+ )
def name(self):
- return 'meanandstandarddeviationplot'
+ return "meanandstandarddeviationplot"
def displayName(self):
- return self.tr('Mean and standard deviation plot')
+ return self.tr("Mean and standard deviation plot")
def processAlgorithm(self, parameters, context, feedback):
try:
@@ -75,11 +91,18 @@ def processAlgorithm(self, parameters, context, feedback):
import plotly as plt
import plotly.graph_objs as go
except ImportError:
- raise QgsProcessingException(QCoreApplication.translate('MeanAndStdDevPlot', 'This algorithm requires the Python “plotly” library. Please install this library and try again.'))
+ raise QgsProcessingException(
+ QCoreApplication.translate(
+ "MeanAndStdDevPlot",
+ "This algorithm requires the Python “plotly” library. Please install this library and try again.",
+ )
+ )
source = self.parameterAsSource(parameters, self.INPUT, context)
if source is None:
- raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT))
+ raise QgsProcessingException(
+ self.invalidSourceError(parameters, self.INPUT)
+ )
namefieldname = self.parameterAsString(parameters, self.NAME_FIELD, context)
valuefieldname = self.parameterAsString(parameters, self.VALUE_FIELD, context)
@@ -96,12 +119,7 @@ def processAlgorithm(self, parameters, context, feedback):
else:
d[v].append(values[valuefieldname][i])
- data = [
- go.Box(y=list(v),
- boxmean='sd',
- name=k)
- for k, v in d.items()
- ]
+ data = [go.Box(y=list(v), boxmean="sd", name=k) for k, v in d.items()]
plt.offline.plot(data, filename=output, auto_open=False)
return {self.OUTPUT: output}
diff --git a/python/plugins/processing/algs/qgis/MinimumBoundingGeometry.py b/python/plugins/processing/algs/qgis/MinimumBoundingGeometry.py
index 28f9914f0824..bf85f48efda0 100644
--- a/python/plugins/processing/algs/qgis/MinimumBoundingGeometry.py
+++ b/python/plugins/processing/algs/qgis/MinimumBoundingGeometry.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Nyall Dawson'
-__date__ = 'September 2017'
-__copyright__ = '(C) 2017, Nyall Dawson'
+__author__ = "Nyall Dawson"
+__date__ = "September 2017"
+__copyright__ = "(C) 2017, Nyall Dawson"
import os
import math
@@ -25,23 +25,25 @@
from qgis.PyQt.QtGui import QIcon
from qgis.PyQt.QtCore import QMetaType
-from qgis.core import (QgsApplication,
- QgsField,
- QgsFeatureSink,
- QgsGeometry,
- QgsWkbTypes,
- QgsFeatureRequest,
- QgsFields,
- QgsRectangle,
- QgsProcessingException,
- QgsProcessingParameterFeatureSource,
- QgsProcessingParameterField,
- QgsProcessingParameterEnum,
- QgsProcessingParameterFeatureSink,
- QgsProcessing,
- QgsFeature,
- QgsVertexId,
- QgsMultiPoint)
+from qgis.core import (
+ QgsApplication,
+ QgsField,
+ QgsFeatureSink,
+ QgsGeometry,
+ QgsWkbTypes,
+ QgsFeatureRequest,
+ QgsFields,
+ QgsRectangle,
+ QgsProcessingException,
+ QgsProcessingParameterFeatureSource,
+ QgsProcessingParameterField,
+ QgsProcessingParameterEnum,
+ QgsProcessingParameterFeatureSink,
+ QgsProcessing,
+ QgsFeature,
+ QgsVertexId,
+ QgsMultiPoint,
+)
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
@@ -49,10 +51,10 @@
class MinimumBoundingGeometry(QgisAlgorithm):
- INPUT = 'INPUT'
- OUTPUT = 'OUTPUT'
- TYPE = 'TYPE'
- FIELD = 'FIELD'
+ INPUT = "INPUT"
+ OUTPUT = "OUTPUT"
+ TYPE = "TYPE"
+ FIELD = "FIELD"
def icon(self):
return QgsApplication.getThemeIcon("/algorithms/mAlgorithmConvexHull.svg")
@@ -61,45 +63,62 @@ def svgIconPath(self):
return QgsApplication.iconPath("/algorithms/mAlgorithmConvexHull.svg")
def group(self):
- return self.tr('Vector geometry')
+ return self.tr("Vector geometry")
def groupId(self):
- return 'vectorgeometry'
+ return "vectorgeometry"
def __init__(self):
super().__init__()
- self.type_names = [self.tr('Envelope (Bounding Box)'),
- self.tr('Minimum Oriented Rectangle'),
- self.tr('Minimum Enclosing Circle'),
- self.tr('Convex Hull')]
+ self.type_names = [
+ self.tr("Envelope (Bounding Box)"),
+ self.tr("Minimum Oriented Rectangle"),
+ self.tr("Minimum Enclosing Circle"),
+ self.tr("Convex Hull"),
+ ]
def initAlgorithm(self, config=None):
- self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT,
- self.tr('Input layer')))
- self.addParameter(QgsProcessingParameterField(self.FIELD,
- self.tr(
- 'Field (optional, set if features should be grouped by class)'),
- parentLayerParameterName=self.INPUT, optional=True))
- self.addParameter(QgsProcessingParameterEnum(self.TYPE,
- self.tr('Geometry type'), options=self.type_names))
- self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Bounding geometry'),
- QgsProcessing.SourceType.TypeVectorPolygon))
+ self.addParameter(
+ QgsProcessingParameterFeatureSource(self.INPUT, self.tr("Input layer"))
+ )
+ self.addParameter(
+ QgsProcessingParameterField(
+ self.FIELD,
+ self.tr("Field (optional, set if features should be grouped by class)"),
+ parentLayerParameterName=self.INPUT,
+ optional=True,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterEnum(
+ self.TYPE, self.tr("Geometry type"), options=self.type_names
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterFeatureSink(
+ self.OUTPUT,
+ self.tr("Bounding geometry"),
+ QgsProcessing.SourceType.TypeVectorPolygon,
+ )
+ )
def name(self):
- return 'minimumboundinggeometry'
+ return "minimumboundinggeometry"
def displayName(self):
- return self.tr('Minimum bounding geometry')
+ return self.tr("Minimum bounding geometry")
def tags(self):
return self.tr(
- 'bounding,box,bounds,envelope,minimum,oriented,rectangle,enclosing,circle,convex,hull,generalization').split(
- ',')
+ "bounding,box,bounds,envelope,minimum,oriented,rectangle,enclosing,circle,convex,hull,generalization"
+ ).split(",")
def processAlgorithm(self, parameters, context, feedback):
source = self.parameterAsSource(parameters, self.INPUT, context)
if source is None:
- raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT))
+ raise QgsProcessingException(
+ self.invalidSourceError(parameters, self.INPUT)
+ )
field_name = self.parameterAsString(parameters, self.FIELD, context)
type = self.parameterAsEnum(parameters, self.TYPE, context)
@@ -108,7 +127,7 @@ def processAlgorithm(self, parameters, context, feedback):
field_index = -1
fields = QgsFields()
- fields.append(QgsField('id', QMetaType.Type.Int, '', 20))
+ fields.append(QgsField("id", QMetaType.Type.Int, "", 20))
if use_field:
# keep original field type, name and parameters
@@ -117,28 +136,34 @@ def processAlgorithm(self, parameters, context, feedback):
fields.append(source.fields()[field_index])
if type == 0:
# envelope
- fields.append(QgsField('width', QMetaType.Type.Double, '', 20, 6))
- fields.append(QgsField('height', QMetaType.Type.Double, '', 20, 6))
- fields.append(QgsField('area', QMetaType.Type.Double, '', 20, 6))
- fields.append(QgsField('perimeter', QMetaType.Type.Double, '', 20, 6))
+ fields.append(QgsField("width", QMetaType.Type.Double, "", 20, 6))
+ fields.append(QgsField("height", QMetaType.Type.Double, "", 20, 6))
+ fields.append(QgsField("area", QMetaType.Type.Double, "", 20, 6))
+ fields.append(QgsField("perimeter", QMetaType.Type.Double, "", 20, 6))
elif type == 1:
# oriented rect
- fields.append(QgsField('width', QMetaType.Type.Double, '', 20, 6))
- fields.append(QgsField('height', QMetaType.Type.Double, '', 20, 6))
- fields.append(QgsField('angle', QMetaType.Type.Double, '', 20, 6))
- fields.append(QgsField('area', QMetaType.Type.Double, '', 20, 6))
- fields.append(QgsField('perimeter', QMetaType.Type.Double, '', 20, 6))
+ fields.append(QgsField("width", QMetaType.Type.Double, "", 20, 6))
+ fields.append(QgsField("height", QMetaType.Type.Double, "", 20, 6))
+ fields.append(QgsField("angle", QMetaType.Type.Double, "", 20, 6))
+ fields.append(QgsField("area", QMetaType.Type.Double, "", 20, 6))
+ fields.append(QgsField("perimeter", QMetaType.Type.Double, "", 20, 6))
elif type == 2:
# circle
- fields.append(QgsField('radius', QMetaType.Type.Double, '', 20, 6))
- fields.append(QgsField('area', QMetaType.Type.Double, '', 20, 6))
+ fields.append(QgsField("radius", QMetaType.Type.Double, "", 20, 6))
+ fields.append(QgsField("area", QMetaType.Type.Double, "", 20, 6))
elif type == 3:
# convex hull
- fields.append(QgsField('area', QMetaType.Type.Double, '', 20, 6))
- fields.append(QgsField('perimeter', QMetaType.Type.Double, '', 20, 6))
-
- (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
- fields, QgsWkbTypes.Type.Polygon, source.sourceCrs())
+ fields.append(QgsField("area", QMetaType.Type.Double, "", 20, 6))
+ fields.append(QgsField("perimeter", QMetaType.Type.Double, "", 20, 6))
+
+ (sink, dest_id) = self.parameterAsSink(
+ parameters,
+ self.OUTPUT,
+ context,
+ fields,
+ QgsWkbTypes.Type.Polygon,
+ source.sourceCrs(),
+ )
if sink is None:
raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT))
@@ -146,7 +171,9 @@ def processAlgorithm(self, parameters, context, feedback):
geometry_dict = {}
bounds_dict = {}
total = 50.0 / source.featureCount() if source.featureCount() else 1
- features = source.getFeatures(QgsFeatureRequest().setSubsetOfAttributes([field_index]))
+ features = source.getFeatures(
+ QgsFeatureRequest().setSubsetOfAttributes([field_index])
+ )
for current, f in enumerate(features):
if feedback.isCanceled():
break
@@ -159,7 +186,9 @@ def processAlgorithm(self, parameters, context, feedback):
if f[field_index] not in bounds_dict:
bounds_dict[f[field_index]] = f.geometry().boundingBox()
else:
- bounds_dict[f[field_index]].combineExtentWith(f.geometry().boundingBox())
+ bounds_dict[f[field_index]].combineExtentWith(
+ f.geometry().boundingBox()
+ )
else:
if f[field_index] not in geometry_dict:
geometry_dict[f[field_index]] = [f.geometry()]
@@ -179,7 +208,16 @@ def processAlgorithm(self, parameters, context, feedback):
# envelope
feature = QgsFeature()
feature.setGeometry(QgsGeometry.fromRect(rect))
- feature.setAttributes([current, group, rect.width(), rect.height(), rect.area(), rect.perimeter()])
+ feature.setAttributes(
+ [
+ current,
+ group,
+ rect.width(),
+ rect.height(),
+ rect.area(),
+ rect.perimeter(),
+ ]
+ )
sink.addFeature(feature, QgsFeatureSink.Flag.FastInsert)
geometry_dict[group] = None
@@ -192,7 +230,9 @@ def processAlgorithm(self, parameters, context, feedback):
if feedback.isCanceled():
break
- feature = self.createFeature(feedback, current, type, geometries, group)
+ feature = self.createFeature(
+ feedback, current, type, geometries, group
+ )
sink.addFeature(feature, QgsFeatureSink.Flag.FastInsert)
geometry_dict[group] = None
@@ -221,7 +261,15 @@ def processAlgorithm(self, parameters, context, feedback):
if type == 0:
feature = QgsFeature()
feature.setGeometry(QgsGeometry.fromRect(bounds))
- feature.setAttributes([0, bounds.width(), bounds.height(), bounds.area(), bounds.perimeter()])
+ feature.setAttributes(
+ [
+ 0,
+ bounds.width(),
+ bounds.height(),
+ bounds.area(),
+ bounds.perimeter(),
+ ]
+ )
else:
feature = self.createFeature(feedback, 0, type, geometry_queue)
sink.addFeature(feature, QgsFeatureSink.Flag.FastInsert)
@@ -262,7 +310,9 @@ def createFeature(self, feedback, feature_id, type, geometries, class_field=None
attrs.append(rect.perimeter())
elif type == 1:
# oriented rect
- output_geometry, area, angle, width, height = geometry.orientedMinimumBoundingBox()
+ output_geometry, area, angle, width, height = (
+ geometry.orientedMinimumBoundingBox()
+ )
attrs.append(width)
attrs.append(height)
attrs.append(angle)
@@ -270,7 +320,9 @@ def createFeature(self, feedback, feature_id, type, geometries, class_field=None
attrs.append(2 * width + 2 * height)
elif type == 2:
# circle
- output_geometry, center, radius = geometry.minimalEnclosingCircle(segments=72)
+ output_geometry, center, radius = geometry.minimalEnclosingCircle(
+ segments=72
+ )
attrs.append(radius)
attrs.append(math.pi * radius * radius)
elif type == 3:
diff --git a/python/plugins/processing/algs/qgis/PointDistance.py b/python/plugins/processing/algs/qgis/PointDistance.py
index 7b1be14e82e9..73e2e2d78af1 100644
--- a/python/plugins/processing/algs/qgis/PointDistance.py
+++ b/python/plugins/processing/algs/qgis/PointDistance.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'August 2012'
-__copyright__ = '(C) 2012, Victor Olaya'
+__author__ = "Victor Olaya"
+__date__ = "August 2012"
+__copyright__ = "(C) 2012, Victor Olaya"
import os
import math
@@ -25,24 +25,26 @@
from qgis.PyQt.QtGui import QIcon
from qgis.PyQt.QtCore import QMetaType
-from qgis.core import (QgsApplication,
- QgsFeatureRequest,
- QgsField,
- QgsFields,
- QgsProject,
- QgsFeature,
- QgsGeometry,
- QgsDistanceArea,
- QgsFeatureSink,
- QgsProcessingParameterFeatureSource,
- QgsProcessing,
- QgsProcessingException,
- QgsProcessingParameterEnum,
- QgsProcessingParameterField,
- QgsProcessingParameterNumber,
- QgsProcessingParameterFeatureSink,
- QgsSpatialIndex,
- QgsWkbTypes)
+from qgis.core import (
+ QgsApplication,
+ QgsFeatureRequest,
+ QgsField,
+ QgsFields,
+ QgsProject,
+ QgsFeature,
+ QgsGeometry,
+ QgsDistanceArea,
+ QgsFeatureSink,
+ QgsProcessingParameterFeatureSource,
+ QgsProcessing,
+ QgsProcessingException,
+ QgsProcessingParameterEnum,
+ QgsProcessingParameterField,
+ QgsProcessingParameterNumber,
+ QgsProcessingParameterFeatureSink,
+ QgsSpatialIndex,
+ QgsWkbTypes,
+)
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
@@ -50,13 +52,13 @@
class PointDistance(QgisAlgorithm):
- INPUT = 'INPUT'
- INPUT_FIELD = 'INPUT_FIELD'
- TARGET = 'TARGET'
- TARGET_FIELD = 'TARGET_FIELD'
- MATRIX_TYPE = 'MATRIX_TYPE'
- NEAREST_POINTS = 'NEAREST_POINTS'
- OUTPUT = 'OUTPUT'
+ INPUT = "INPUT"
+ INPUT_FIELD = "INPUT_FIELD"
+ TARGET = "TARGET"
+ TARGET_FIELD = "TARGET_FIELD"
+ MATRIX_TYPE = "MATRIX_TYPE"
+ NEAREST_POINTS = "NEAREST_POINTS"
+ OUTPUT = "OUTPUT"
def icon(self):
return QgsApplication.getThemeIcon("/algorithms/mAlgorithmDistanceMatrix.svg")
@@ -65,61 +67,110 @@ def svgIconPath(self):
return QgsApplication.iconPath("/algorithms/mAlgorithmDistanceMatrix.svg")
def group(self):
- return self.tr('Vector analysis')
+ return self.tr("Vector analysis")
def groupId(self):
- return 'vectoranalysis'
+ return "vectoranalysis"
def __init__(self):
super().__init__()
def initAlgorithm(self, config=None):
- self.mat_types = [self.tr('Linear (N*k x 3) distance matrix'),
- self.tr('Standard (N x T) distance matrix'),
- self.tr('Summary distance matrix (mean, std. dev., min, max)')]
-
- self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT,
- self.tr('Input point layer'),
- [QgsProcessing.SourceType.TypeVectorPoint]))
- self.addParameter(QgsProcessingParameterField(self.INPUT_FIELD,
- self.tr('Input unique ID field'),
- parentLayerParameterName=self.INPUT,
- type=QgsProcessingParameterField.DataType.Any))
- self.addParameter(QgsProcessingParameterFeatureSource(self.TARGET,
- self.tr('Target point layer'),
- [QgsProcessing.SourceType.TypeVectorPoint]))
- self.addParameter(QgsProcessingParameterField(self.TARGET_FIELD,
- self.tr('Target unique ID field'),
- parentLayerParameterName=self.TARGET,
- type=QgsProcessingParameterField.DataType.Any))
- self.addParameter(QgsProcessingParameterEnum(self.MATRIX_TYPE,
- self.tr('Output matrix type'), options=self.mat_types, defaultValue=0))
- self.addParameter(QgsProcessingParameterNumber(self.NEAREST_POINTS,
- self.tr('Use only the nearest (k) target points'), type=QgsProcessingParameterNumber.Type.Integer, minValue=0, defaultValue=0))
-
- self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Distance matrix'), QgsProcessing.SourceType.TypeVectorPoint))
+ self.mat_types = [
+ self.tr("Linear (N*k x 3) distance matrix"),
+ self.tr("Standard (N x T) distance matrix"),
+ self.tr("Summary distance matrix (mean, std. dev., min, max)"),
+ ]
+
+ self.addParameter(
+ QgsProcessingParameterFeatureSource(
+ self.INPUT,
+ self.tr("Input point layer"),
+ [QgsProcessing.SourceType.TypeVectorPoint],
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterField(
+ self.INPUT_FIELD,
+ self.tr("Input unique ID field"),
+ parentLayerParameterName=self.INPUT,
+ type=QgsProcessingParameterField.DataType.Any,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterFeatureSource(
+ self.TARGET,
+ self.tr("Target point layer"),
+ [QgsProcessing.SourceType.TypeVectorPoint],
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterField(
+ self.TARGET_FIELD,
+ self.tr("Target unique ID field"),
+ parentLayerParameterName=self.TARGET,
+ type=QgsProcessingParameterField.DataType.Any,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterEnum(
+ self.MATRIX_TYPE,
+ self.tr("Output matrix type"),
+ options=self.mat_types,
+ defaultValue=0,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterNumber(
+ self.NEAREST_POINTS,
+ self.tr("Use only the nearest (k) target points"),
+ type=QgsProcessingParameterNumber.Type.Integer,
+ minValue=0,
+ defaultValue=0,
+ )
+ )
+
+ self.addParameter(
+ QgsProcessingParameterFeatureSink(
+ self.OUTPUT,
+ self.tr("Distance matrix"),
+ QgsProcessing.SourceType.TypeVectorPoint,
+ )
+ )
def name(self):
- return 'distancematrix'
+ return "distancematrix"
def displayName(self):
- return self.tr('Distance matrix')
+ return self.tr("Distance matrix")
def processAlgorithm(self, parameters, context, feedback):
source = self.parameterAsSource(parameters, self.INPUT, context)
if source is None:
- raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT))
+ raise QgsProcessingException(
+ self.invalidSourceError(parameters, self.INPUT)
+ )
if QgsWkbTypes.isMultiType(source.wkbType()):
- raise QgsProcessingException(self.tr('Input point layer is a MultiPoint layer - first convert to single points before using this algorithm.'))
+ raise QgsProcessingException(
+ self.tr(
+ "Input point layer is a MultiPoint layer - first convert to single points before using this algorithm."
+ )
+ )
source_field = self.parameterAsString(parameters, self.INPUT_FIELD, context)
target_source = self.parameterAsSource(parameters, self.TARGET, context)
if target_source is None:
- raise QgsProcessingException(self.invalidSourceError(parameters, self.TARGET))
+ raise QgsProcessingException(
+ self.invalidSourceError(parameters, self.TARGET)
+ )
if QgsWkbTypes.isMultiType(target_source.wkbType()):
- raise QgsProcessingException(self.tr('Target point layer is a MultiPoint layer - first convert to single points before using this algorithm.'))
+ raise QgsProcessingException(
+ self.tr(
+ "Target point layer is a MultiPoint layer - first convert to single points before using this algorithm."
+ )
+ )
target_field = self.parameterAsString(parameters, self.TARGET_FIELD, context)
same_source_and_target = parameters[self.INPUT] == parameters[self.TARGET]
@@ -131,19 +182,58 @@ def processAlgorithm(self, parameters, context, feedback):
if matType == 0:
# Linear distance matrix
- return self.linearMatrix(parameters, context, source, source_field, target_source, target_field, same_source_and_target,
- matType, nPoints, feedback)
+ return self.linearMatrix(
+ parameters,
+ context,
+ source,
+ source_field,
+ target_source,
+ target_field,
+ same_source_and_target,
+ matType,
+ nPoints,
+ feedback,
+ )
elif matType == 1:
# Standard distance matrix
- return self.regularMatrix(parameters, context, source, source_field, target_source, target_field,
- nPoints, feedback)
+ return self.regularMatrix(
+ parameters,
+ context,
+ source,
+ source_field,
+ target_source,
+ target_field,
+ nPoints,
+ feedback,
+ )
elif matType == 2:
# Summary distance matrix
- return self.linearMatrix(parameters, context, source, source_field, target_source, target_field, same_source_and_target,
- matType, nPoints, feedback)
-
- def linearMatrix(self, parameters, context, source, inField, target_source, targetField, same_source_and_target,
- matType, nPoints, feedback):
+ return self.linearMatrix(
+ parameters,
+ context,
+ source,
+ source_field,
+ target_source,
+ target_field,
+ same_source_and_target,
+ matType,
+ nPoints,
+ feedback,
+ )
+
+ def linearMatrix(
+ self,
+ parameters,
+ context,
+ source,
+ inField,
+ target_source,
+ targetField,
+ same_source_and_target,
+ matType,
+ nPoints,
+ feedback,
+ ):
if same_source_and_target:
# need to fetch an extra point from the index, since the closest match will always be the same
@@ -155,32 +245,46 @@ def linearMatrix(self, parameters, context, source, inField, target_source, targ
fields = QgsFields()
input_id_field = source.fields()[inIdx]
- input_id_field.setName('InputID')
+ input_id_field.setName("InputID")
fields.append(input_id_field)
if matType == 0:
target_id_field = target_source.fields()[outIdx]
- target_id_field.setName('TargetID')
+ target_id_field.setName("TargetID")
fields.append(target_id_field)
- fields.append(QgsField('Distance', QMetaType.Type.Double))
+ fields.append(QgsField("Distance", QMetaType.Type.Double))
else:
- fields.append(QgsField('MEAN', QMetaType.Type.Double))
- fields.append(QgsField('STDDEV', QMetaType.Type.Double))
- fields.append(QgsField('MIN', QMetaType.Type.Double))
- fields.append(QgsField('MAX', QMetaType.Type.Double))
-
- out_wkb = QgsWkbTypes.multiType(source.wkbType()) if matType == 0 else source.wkbType()
- (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
- fields, out_wkb, source.sourceCrs())
+ fields.append(QgsField("MEAN", QMetaType.Type.Double))
+ fields.append(QgsField("STDDEV", QMetaType.Type.Double))
+ fields.append(QgsField("MIN", QMetaType.Type.Double))
+ fields.append(QgsField("MAX", QMetaType.Type.Double))
+
+ out_wkb = (
+ QgsWkbTypes.multiType(source.wkbType())
+ if matType == 0
+ else source.wkbType()
+ )
+ (sink, dest_id) = self.parameterAsSink(
+ parameters, self.OUTPUT, context, fields, out_wkb, source.sourceCrs()
+ )
if sink is None:
raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT))
- index = QgsSpatialIndex(target_source.getFeatures(QgsFeatureRequest().setSubsetOfAttributes([]).setDestinationCrs(source.sourceCrs(), context.transformContext())), feedback)
+ index = QgsSpatialIndex(
+ target_source.getFeatures(
+ QgsFeatureRequest()
+ .setSubsetOfAttributes([])
+ .setDestinationCrs(source.sourceCrs(), context.transformContext())
+ ),
+ feedback,
+ )
distArea = QgsDistanceArea()
distArea.setSourceCrs(source.sourceCrs(), context.transformContext())
distArea.setEllipsoid(context.ellipsoid())
- features = source.getFeatures(QgsFeatureRequest().setSubsetOfAttributes([inIdx]))
+ features = source.getFeatures(
+ QgsFeatureRequest().setSubsetOfAttributes([inIdx])
+ )
total = 100.0 / source.featureCount() if source.featureCount() else 0
for current, inFeat in enumerate(features):
if feedback.isCanceled():
@@ -191,7 +295,12 @@ def linearMatrix(self, parameters, context, source, inField, target_source, targ
featList = index.nearestNeighbor(inGeom.asPoint(), nPoints)
distList = []
vari = 0.0
- request = QgsFeatureRequest().setFilterFids(featList).setSubsetOfAttributes([outIdx]).setDestinationCrs(source.sourceCrs(), context.transformContext())
+ request = (
+ QgsFeatureRequest()
+ .setFilterFids(featList)
+ .setSubsetOfAttributes([outIdx])
+ .setDestinationCrs(source.sourceCrs(), context.transformContext())
+ )
for outFeat in target_source.getFeatures(request):
if feedback.isCanceled():
break
@@ -201,12 +310,13 @@ def linearMatrix(self, parameters, context, source, inField, target_source, targ
outID = outFeat[outIdx]
outGeom = outFeat.geometry()
- dist = distArea.measureLine(inGeom.asPoint(),
- outGeom.asPoint())
+ dist = distArea.measureLine(inGeom.asPoint(), outGeom.asPoint())
if matType == 0:
out_feature = QgsFeature()
- out_geom = QgsGeometry.unaryUnion([inFeat.geometry(), outFeat.geometry()])
+ out_geom = QgsGeometry.unaryUnion(
+ [inFeat.geometry(), outFeat.geometry()]
+ )
out_feature.setGeometry(out_geom)
out_feature.setAttributes([inID, outID, dist])
sink.addFeature(out_feature, QgsFeatureSink.Flag.FastInsert)
@@ -221,7 +331,9 @@ def linearMatrix(self, parameters, context, source, inField, target_source, targ
out_feature = QgsFeature()
out_feature.setGeometry(inFeat.geometry())
- out_feature.setAttributes([inID, mean, vari, min(distList), max(distList)])
+ out_feature.setAttributes(
+ [inID, mean, vari, min(distList), max(distList)]
+ )
sink.addFeature(out_feature, QgsFeatureSink.Flag.FastInsert)
feedback.setProgress(int(current * total))
@@ -229,8 +341,17 @@ def linearMatrix(self, parameters, context, source, inField, target_source, targ
sink.finalize()
return {self.OUTPUT: dest_id}
- def regularMatrix(self, parameters, context, source, inField, target_source, targetField,
- nPoints, feedback):
+ def regularMatrix(
+ self,
+ parameters,
+ context,
+ source,
+ inField,
+ target_source,
+ targetField,
+ nPoints,
+ feedback,
+ ):
distArea = QgsDistanceArea()
distArea.setSourceCrs(source.sourceCrs(), context.transformContext())
@@ -239,12 +360,21 @@ def regularMatrix(self, parameters, context, source, inField, target_source, tar
inIdx = source.fields().lookupField(inField)
targetIdx = target_source.fields().lookupField(targetField)
- index = QgsSpatialIndex(target_source.getFeatures(QgsFeatureRequest().setSubsetOfAttributes([]).setDestinationCrs(source.sourceCrs(), context.transformContext())), feedback)
+ index = QgsSpatialIndex(
+ target_source.getFeatures(
+ QgsFeatureRequest()
+ .setSubsetOfAttributes([])
+ .setDestinationCrs(source.sourceCrs(), context.transformContext())
+ ),
+ feedback,
+ )
first = True
sink = None
dest_id = None
- features = source.getFeatures(QgsFeatureRequest().setSubsetOfAttributes([inIdx]))
+ features = source.getFeatures(
+ QgsFeatureRequest().setSubsetOfAttributes([inIdx])
+ )
total = 100.0 / source.featureCount() if source.featureCount() else 0
for current, inFeat in enumerate(features):
if feedback.isCanceled():
@@ -256,23 +386,40 @@ def regularMatrix(self, parameters, context, source, inField, target_source, tar
first = False
fields = QgsFields()
input_id_field = source.fields()[inIdx]
- input_id_field.setName('ID')
+ input_id_field.setName("ID")
fields.append(input_id_field)
- for f in target_source.getFeatures(QgsFeatureRequest().setFilterFids(featList).setSubsetOfAttributes([targetIdx]).setDestinationCrs(source.sourceCrs(), context.transformContext())):
+ for f in target_source.getFeatures(
+ QgsFeatureRequest()
+ .setFilterFids(featList)
+ .setSubsetOfAttributes([targetIdx])
+ .setDestinationCrs(source.sourceCrs(), context.transformContext())
+ ):
fields.append(QgsField(str(f[targetField]), QMetaType.Type.Double))
- (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
- fields, source.wkbType(), source.sourceCrs())
+ (sink, dest_id) = self.parameterAsSink(
+ parameters,
+ self.OUTPUT,
+ context,
+ fields,
+ source.wkbType(),
+ source.sourceCrs(),
+ )
if sink is None:
- raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT))
+ raise QgsProcessingException(
+ self.invalidSinkError(parameters, self.OUTPUT)
+ )
data = [inFeat[inField]]
- for target in target_source.getFeatures(QgsFeatureRequest().setSubsetOfAttributes([]).setFilterFids(featList).setDestinationCrs(source.sourceCrs(), context.transformContext())):
+ for target in target_source.getFeatures(
+ QgsFeatureRequest()
+ .setSubsetOfAttributes([])
+ .setFilterFids(featList)
+ .setDestinationCrs(source.sourceCrs(), context.transformContext())
+ ):
if feedback.isCanceled():
break
outGeom = target.geometry()
- dist = distArea.measureLine(inGeom.asPoint(),
- outGeom.asPoint())
+ dist = distArea.measureLine(inGeom.asPoint(), outGeom.asPoint())
data.append(dist)
out_feature = QgsFeature()
diff --git a/python/plugins/processing/algs/qgis/PointsDisplacement.py b/python/plugins/processing/algs/qgis/PointsDisplacement.py
index b93f146347b2..dfb2ba6fdb22 100644
--- a/python/plugins/processing/algs/qgis/PointsDisplacement.py
+++ b/python/plugins/processing/algs/qgis/PointsDisplacement.py
@@ -15,77 +15,109 @@
***************************************************************************
"""
-__author__ = 'Alexander Bruy'
-__date__ = 'July 2013'
-__copyright__ = '(C) 2013, Alexander Bruy'
+__author__ = "Alexander Bruy"
+__date__ = "July 2013"
+__copyright__ = "(C) 2013, Alexander Bruy"
import math
-from qgis.core import (QgsFeatureSink,
- QgsGeometry,
- QgsPointXY,
- QgsSpatialIndex,
- QgsRectangle,
- QgsProcessing,
- QgsProcessingException,
- QgsProcessingParameterFeatureSource,
- QgsProcessingParameterDistance,
- QgsProcessingParameterBoolean,
- QgsProcessingParameterFeatureSink)
+from qgis.core import (
+ QgsFeatureSink,
+ QgsGeometry,
+ QgsPointXY,
+ QgsSpatialIndex,
+ QgsRectangle,
+ QgsProcessing,
+ QgsProcessingException,
+ QgsProcessingParameterFeatureSource,
+ QgsProcessingParameterDistance,
+ QgsProcessingParameterBoolean,
+ QgsProcessingParameterFeatureSink,
+)
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
class PointsDisplacement(QgisAlgorithm):
- INPUT = 'INPUT'
- DISTANCE = 'DISTANCE'
- PROXIMITY = 'PROXIMITY'
- HORIZONTAL = 'HORIZONTAL'
- OUTPUT = 'OUTPUT'
+ INPUT = "INPUT"
+ DISTANCE = "DISTANCE"
+ PROXIMITY = "PROXIMITY"
+ HORIZONTAL = "HORIZONTAL"
+ OUTPUT = "OUTPUT"
def group(self):
- return self.tr('Vector geometry')
+ return self.tr("Vector geometry")
def groupId(self):
- return 'vectorgeometry'
+ return "vectorgeometry"
def __init__(self):
super().__init__()
def initAlgorithm(self, config=None):
- self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT,
- self.tr('Input layer'), [QgsProcessing.SourceType.TypeVectorPoint]))
- param = QgsProcessingParameterDistance(self.PROXIMITY,
- self.tr('Minimum distance to other points'), parentParameterName='INPUT',
- minValue=0.00001, defaultValue=1.0)
- param.setMetadata({'widget_wrapper': {'decimals': 5}})
+ self.addParameter(
+ QgsProcessingParameterFeatureSource(
+ self.INPUT,
+ self.tr("Input layer"),
+ [QgsProcessing.SourceType.TypeVectorPoint],
+ )
+ )
+ param = QgsProcessingParameterDistance(
+ self.PROXIMITY,
+ self.tr("Minimum distance to other points"),
+ parentParameterName="INPUT",
+ minValue=0.00001,
+ defaultValue=1.0,
+ )
+ param.setMetadata({"widget_wrapper": {"decimals": 5}})
self.addParameter(param)
- param = QgsProcessingParameterDistance(self.DISTANCE,
- self.tr('Displacement distance'), parentParameterName='INPUT',
- minValue=0.00001, defaultValue=1.0)
- param.setMetadata({'widget_wrapper': {'decimals': 5}})
+ param = QgsProcessingParameterDistance(
+ self.DISTANCE,
+ self.tr("Displacement distance"),
+ parentParameterName="INPUT",
+ minValue=0.00001,
+ defaultValue=1.0,
+ )
+ param.setMetadata({"widget_wrapper": {"decimals": 5}})
self.addParameter(param)
- self.addParameter(QgsProcessingParameterBoolean(self.HORIZONTAL,
- self.tr('Horizontal distribution for two point case')))
- self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Displaced'), QgsProcessing.SourceType.TypeVectorPoint))
+ self.addParameter(
+ QgsProcessingParameterBoolean(
+ self.HORIZONTAL, self.tr("Horizontal distribution for two point case")
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterFeatureSink(
+ self.OUTPUT,
+ self.tr("Displaced"),
+ QgsProcessing.SourceType.TypeVectorPoint,
+ )
+ )
def name(self):
- return 'pointsdisplacement'
+ return "pointsdisplacement"
def displayName(self):
- return self.tr('Points displacement')
+ return self.tr("Points displacement")
def processAlgorithm(self, parameters, context, feedback):
source = self.parameterAsSource(parameters, self.INPUT, context)
if source is None:
- raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT))
+ raise QgsProcessingException(
+ self.invalidSourceError(parameters, self.INPUT)
+ )
proximity = self.parameterAsDouble(parameters, self.PROXIMITY, context)
radius = self.parameterAsDouble(parameters, self.DISTANCE, context)
horizontal = self.parameterAsBoolean(parameters, self.HORIZONTAL, context)
- (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
- source.fields(), source.wkbType(), source.sourceCrs())
+ (sink, dest_id) = self.parameterAsSink(
+ parameters,
+ self.OUTPUT,
+ context,
+ source.fields(),
+ source.wkbType(),
+ source.sourceCrs(),
+ )
if sink is None:
raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT))
@@ -94,7 +126,12 @@ def processAlgorithm(self, parameters, context, feedback):
total = 100.0 / source.featureCount() if source.featureCount() else 0
def searchRect(p):
- return QgsRectangle(p.x() - proximity, p.y() - proximity, p.x() + proximity, p.y() + proximity)
+ return QgsRectangle(
+ p.x() - proximity,
+ p.y() - proximity,
+ p.x() + proximity,
+ p.y() + proximity,
+ )
index = QgsSpatialIndex()
@@ -136,8 +173,10 @@ def searchRect(p):
# calculate new centroid of group
old_center = group_locations[min_dist_feature_id]
- group_locations[min_dist_feature_id] = QgsPointXY((old_center.x() * len(group) + point.x()) / (len(group) + 1.0),
- (old_center.y() * len(group) + point.y()) / (len(group) + 1.0))
+ group_locations[min_dist_feature_id] = QgsPointXY(
+ (old_center.x() * len(group) + point.x()) / (len(group) + 1.0),
+ (old_center.y() * len(group) + point.y()) / (len(group) + 1.0),
+ )
# add to a group
clustered_groups[group_index_pos].append(f)
group_index[f.id()] = group_index_pos
diff --git a/python/plugins/processing/algs/qgis/PointsFromLines.py b/python/plugins/processing/algs/qgis/PointsFromLines.py
index 755819ef078e..0c702561684c 100644
--- a/python/plugins/processing/algs/qgis/PointsFromLines.py
+++ b/python/plugins/processing/algs/qgis/PointsFromLines.py
@@ -15,25 +15,27 @@
***************************************************************************
"""
-__author__ = 'Alexander Bruy'
-__date__ = 'August 2013'
-__copyright__ = '(C) 2013, Alexander Bruy'
+__author__ = "Alexander Bruy"
+__date__ = "August 2013"
+__copyright__ = "(C) 2013, Alexander Bruy"
from osgeo import gdal
from qgis.PyQt.QtCore import QMetaType
-from qgis.core import (QgsFeature,
- QgsFeatureSink,
- QgsFields,
- QgsField,
- QgsGeometry,
- QgsPointXY,
- QgsWkbTypes,
- QgsProcessing,
- QgsProcessingException,
- QgsFeatureRequest,
- QgsProcessingParameterRasterLayer,
- QgsProcessingParameterFeatureSource,
- QgsProcessingParameterFeatureSink)
+from qgis.core import (
+ QgsFeature,
+ QgsFeatureSink,
+ QgsFields,
+ QgsField,
+ QgsGeometry,
+ QgsPointXY,
+ QgsWkbTypes,
+ QgsProcessing,
+ QgsProcessingException,
+ QgsFeatureRequest,
+ QgsProcessingParameterRasterLayer,
+ QgsProcessingParameterFeatureSource,
+ QgsProcessingParameterFeatureSink,
+)
from processing.tools import raster
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
@@ -41,39 +43,57 @@
class PointsFromLines(QgisAlgorithm):
- INPUT_RASTER = 'INPUT_RASTER'
- RASTER_BAND = 'RASTER_BAND'
- INPUT_VECTOR = 'INPUT_VECTOR'
- OUTPUT = 'OUTPUT'
+ INPUT_RASTER = "INPUT_RASTER"
+ RASTER_BAND = "RASTER_BAND"
+ INPUT_VECTOR = "INPUT_VECTOR"
+ OUTPUT = "OUTPUT"
def group(self):
- return self.tr('Vector creation')
+ return self.tr("Vector creation")
def groupId(self):
- return 'vectorcreation'
+ return "vectorcreation"
def __init__(self):
super().__init__()
def initAlgorithm(self, config=None):
- self.addParameter(QgsProcessingParameterRasterLayer(self.INPUT_RASTER,
- self.tr('Raster layer')))
- self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT_VECTOR,
- self.tr('Vector layer'), [QgsProcessing.SourceType.TypeVectorLine]))
- self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Points along lines'), QgsProcessing.SourceType.TypeVectorPoint))
+ self.addParameter(
+ QgsProcessingParameterRasterLayer(
+ self.INPUT_RASTER, self.tr("Raster layer")
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterFeatureSource(
+ self.INPUT_VECTOR,
+ self.tr("Vector layer"),
+ [QgsProcessing.SourceType.TypeVectorLine],
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterFeatureSink(
+ self.OUTPUT,
+ self.tr("Points along lines"),
+ QgsProcessing.SourceType.TypeVectorPoint,
+ )
+ )
def name(self):
- return 'generatepointspixelcentroidsalongline'
+ return "generatepointspixelcentroidsalongline"
def displayName(self):
- return self.tr('Generate points (pixel centroids) along line')
+ return self.tr("Generate points (pixel centroids) along line")
def processAlgorithm(self, parameters, context, feedback):
source = self.parameterAsSource(parameters, self.INPUT_VECTOR, context)
if source is None:
- raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT_VECTOR))
+ raise QgsProcessingException(
+ self.invalidSourceError(parameters, self.INPUT_VECTOR)
+ )
- raster_layer = self.parameterAsRasterLayer(parameters, self.INPUT_RASTER, context)
+ raster_layer = self.parameterAsRasterLayer(
+ parameters, self.INPUT_RASTER, context
+ )
rasterPath = raster_layer.source()
rasterDS = gdal.Open(rasterPath, gdal.GA_ReadOnly)
@@ -81,12 +101,18 @@ def processAlgorithm(self, parameters, context, feedback):
rasterDS = None
fields = QgsFields()
- fields.append(QgsField('id', QMetaType.Type.Int, '', 10, 0))
- fields.append(QgsField('line_id', QMetaType.Type.Int, '', 10, 0))
- fields.append(QgsField('point_id', QMetaType.Type.Int, '', 10, 0))
-
- (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
- fields, QgsWkbTypes.Type.Point, raster_layer.crs())
+ fields.append(QgsField("id", QMetaType.Type.Int, "", 10, 0))
+ fields.append(QgsField("line_id", QMetaType.Type.Int, "", 10, 0))
+ fields.append(QgsField("point_id", QMetaType.Type.Int, "", 10, 0))
+
+ (sink, dest_id) = self.parameterAsSink(
+ parameters,
+ self.OUTPUT,
+ context,
+ fields,
+ QgsWkbTypes.Type.Point,
+ raster_layer.crs(),
+ )
if sink is None:
raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT))
@@ -97,7 +123,11 @@ def processAlgorithm(self, parameters, context, feedback):
self.lineId = 0
self.pointId = 0
- features = source.getFeatures(QgsFeatureRequest().setDestinationCrs(raster_layer.crs(), context.transformContext()))
+ features = source.getFeatures(
+ QgsFeatureRequest().setDestinationCrs(
+ raster_layer.crs(), context.transformContext()
+ )
+ )
total = 100.0 / source.featureCount() if source.featureCount() else 0
for current, f in enumerate(features):
if feedback.isCanceled():
@@ -114,13 +144,10 @@ def processAlgorithm(self, parameters, context, feedback):
p1 = line[i]
p2 = line[i + 1]
- (x1, y1) = raster.mapToPixel(p1.x(), p1.y(),
- geoTransform)
- (x2, y2) = raster.mapToPixel(p2.x(), p2.y(),
- geoTransform)
+ (x1, y1) = raster.mapToPixel(p1.x(), p1.y(), geoTransform)
+ (x2, y2) = raster.mapToPixel(p2.x(), p2.y(), geoTransform)
- self.buildLine(x1, y1, x2, y2, geoTransform,
- sink, outFeature)
+ self.buildLine(x1, y1, x2, y2, geoTransform, sink, outFeature)
else:
points = geom.asPolyline()
for i in range(len(points) - 1):
@@ -130,8 +157,7 @@ def processAlgorithm(self, parameters, context, feedback):
(x1, y1) = raster.mapToPixel(p1.x(), p1.y(), geoTransform)
(x2, y2) = raster.mapToPixel(p2.x(), p2.y(), geoTransform)
- self.buildLine(x1, y1, x2, y2, geoTransform, sink,
- outFeature)
+ self.buildLine(x1, y1, x2, y2, geoTransform, sink, outFeature)
self.pointId = 0
self.lineId += 1
@@ -198,9 +224,9 @@ def createPoint(self, pX, pY, geoTransform, writer, feature):
(x, y) = raster.pixelToMap(pX, pY, geoTransform)
feature.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(x, y)))
- feature['id'] = self.fid
- feature['line_id'] = self.lineId
- feature['point_id'] = self.pointId
+ feature["id"] = self.fid
+ feature["line_id"] = self.lineId
+ feature["point_id"] = self.pointId
self.fid += 1
self.pointId += 1
diff --git a/python/plugins/processing/algs/qgis/PolarPlot.py b/python/plugins/processing/algs/qgis/PolarPlot.py
index 07fa5e5e55ee..96f214629dc3 100644
--- a/python/plugins/processing/algs/qgis/PolarPlot.py
+++ b/python/plugins/processing/algs/qgis/PolarPlot.py
@@ -15,16 +15,18 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'January 2013'
-__copyright__ = '(C) 2013, Victor Olaya'
+__author__ = "Victor Olaya"
+__date__ = "January 2013"
+__copyright__ = "(C) 2013, Victor Olaya"
import warnings
-from qgis.core import (QgsProcessingException,
- QgsProcessingParameterFeatureSource,
- QgsProcessingParameterField,
- QgsProcessingParameterFileDestination)
+from qgis.core import (
+ QgsProcessingException,
+ QgsProcessingParameterFeatureSource,
+ QgsProcessingParameterField,
+ QgsProcessingParameterFileDestination,
+)
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
from processing.tools import vector
@@ -32,37 +34,51 @@
class PolarPlot(QgisAlgorithm):
- INPUT = 'INPUT'
- OUTPUT = 'OUTPUT'
- NAME_FIELD = 'NAME_FIELD'
- VALUE_FIELD = 'VALUE_FIELD'
+ INPUT = "INPUT"
+ OUTPUT = "OUTPUT"
+ NAME_FIELD = "NAME_FIELD"
+ VALUE_FIELD = "VALUE_FIELD"
def group(self):
- return self.tr('Plots')
+ return self.tr("Plots")
def groupId(self):
- return 'plots'
+ return "plots"
def __init__(self):
super().__init__()
def initAlgorithm(self, config=None):
- self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT,
- self.tr('Input layer')))
- self.addParameter(QgsProcessingParameterField(self.NAME_FIELD,
- self.tr('Category name field'), parentLayerParameterName=self.INPUT)) # FIXME unused?
- self.addParameter(QgsProcessingParameterField(self.VALUE_FIELD,
- self.tr('Value field'),
- parentLayerParameterName=self.INPUT,
- type=QgsProcessingParameterField.DataType.Numeric))
-
- self.addParameter(QgsProcessingParameterFileDestination(self.OUTPUT, self.tr('Polar plot'), self.tr('HTML files (*.html)')))
+ self.addParameter(
+ QgsProcessingParameterFeatureSource(self.INPUT, self.tr("Input layer"))
+ )
+ self.addParameter(
+ QgsProcessingParameterField(
+ self.NAME_FIELD,
+ self.tr("Category name field"),
+ parentLayerParameterName=self.INPUT,
+ )
+ ) # FIXME unused?
+ self.addParameter(
+ QgsProcessingParameterField(
+ self.VALUE_FIELD,
+ self.tr("Value field"),
+ parentLayerParameterName=self.INPUT,
+ type=QgsProcessingParameterField.DataType.Numeric,
+ )
+ )
+
+ self.addParameter(
+ QgsProcessingParameterFileDestination(
+ self.OUTPUT, self.tr("Polar plot"), self.tr("HTML files (*.html)")
+ )
+ )
def name(self):
- return 'polarplot'
+ return "polarplot"
def displayName(self):
- return self.tr('Polar plot')
+ return self.tr("Polar plot")
def processAlgorithm(self, parameters, context, feedback):
try:
@@ -73,26 +89,46 @@ def processAlgorithm(self, parameters, context, feedback):
import plotly as plt
import plotly.graph_objs as go
except ImportError:
- raise QgsProcessingException(QCoreApplication.translate('PolarPlot', 'This algorithm requires the Python “plotly” library. Please install this library and try again.'))
+ raise QgsProcessingException(
+ QCoreApplication.translate(
+ "PolarPlot",
+ "This algorithm requires the Python “plotly” library. Please install this library and try again.",
+ )
+ )
try:
import numpy as np
except ImportError:
- raise QgsProcessingException(QCoreApplication.translate('PolarPlot', 'This algorithm requires the Python “numpy” library. Please install this library and try again.'))
+ raise QgsProcessingException(
+ QCoreApplication.translate(
+ "PolarPlot",
+ "This algorithm requires the Python “numpy” library. Please install this library and try again.",
+ )
+ )
source = self.parameterAsSource(parameters, self.INPUT, context)
if source is None:
- raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT))
+ raise QgsProcessingException(
+ self.invalidSourceError(parameters, self.INPUT)
+ )
- namefieldname = self.parameterAsString(parameters, self.NAME_FIELD, context) # NOQA FIXME unused?
+ namefieldname = self.parameterAsString(
+ parameters, self.NAME_FIELD, context
+ ) # NOQA FIXME unused?
valuefieldname = self.parameterAsString(parameters, self.VALUE_FIELD, context)
output = self.parameterAsFileOutput(parameters, self.OUTPUT, context)
values = vector.values(source, valuefieldname)
- data = [go.Barpolar(r=values[valuefieldname],
- theta=np.degrees(np.arange(0.0, 2 * np.pi, 2 * np.pi / len(values[valuefieldname]))))]
+ data = [
+ go.Barpolar(
+ r=values[valuefieldname],
+ theta=np.degrees(
+ np.arange(0.0, 2 * np.pi, 2 * np.pi / len(values[valuefieldname]))
+ ),
+ )
+ ]
plt.offline.plot(data, filename=output, auto_open=False)
diff --git a/python/plugins/processing/algs/qgis/PostGISExecuteAndLoadSQL.py b/python/plugins/processing/algs/qgis/PostGISExecuteAndLoadSQL.py
index ce8eab29bb4a..f312164b6c47 100644
--- a/python/plugins/processing/algs/qgis/PostGISExecuteAndLoadSQL.py
+++ b/python/plugins/processing/algs/qgis/PostGISExecuteAndLoadSQL.py
@@ -17,109 +17,132 @@
***************************************************************************
"""
-__author__ = 'Anita Graser'
-__date__ = 'May 2018'
-__copyright__ = '(C) 2018, Anita Graser'
-
-from qgis.core import (QgsProcessingException,
- QgsProcessingParameterString,
- QgsVectorLayer,
- QgsDataSourceUri,
- QgsProcessing,
- QgsProcessingOutputVectorLayer,
- QgsProcessingContext,
- QgsProcessingParameterProviderConnection,
- QgsProviderRegistry,
- QgsProviderConnectionException,
- QgsProcessingAlgorithm
- )
+__author__ = "Anita Graser"
+__date__ = "May 2018"
+__copyright__ = "(C) 2018, Anita Graser"
+
+from qgis.core import (
+ QgsProcessingException,
+ QgsProcessingParameterString,
+ QgsVectorLayer,
+ QgsDataSourceUri,
+ QgsProcessing,
+ QgsProcessingOutputVectorLayer,
+ QgsProcessingContext,
+ QgsProcessingParameterProviderConnection,
+ QgsProviderRegistry,
+ QgsProviderConnectionException,
+ QgsProcessingAlgorithm,
+)
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
class PostGISExecuteAndLoadSQL(QgisAlgorithm):
- DATABASE = 'DATABASE'
- SQL = 'SQL'
- OUTPUT = 'OUTPUT'
- ID_FIELD = 'ID_FIELD'
- GEOMETRY_FIELD = 'GEOMETRY_FIELD'
+ DATABASE = "DATABASE"
+ SQL = "SQL"
+ OUTPUT = "OUTPUT"
+ ID_FIELD = "ID_FIELD"
+ GEOMETRY_FIELD = "GEOMETRY_FIELD"
def group(self):
- return self.tr('Database')
+ return self.tr("Database")
def groupId(self):
- return 'database'
+ return "database"
def __init__(self):
super().__init__()
def flags(self):
- return super().flags() | QgsProcessingAlgorithm.Flag.FlagNotAvailableInStandaloneTool | QgsProcessingAlgorithm.Flag.FlagRequiresProject
+ return (
+ super().flags()
+ | QgsProcessingAlgorithm.Flag.FlagNotAvailableInStandaloneTool
+ | QgsProcessingAlgorithm.Flag.FlagRequiresProject
+ )
def initAlgorithm(self, config=None):
db_param = QgsProcessingParameterProviderConnection(
- self.DATABASE,
- self.tr('Database (connection name)'), 'postgres')
+ self.DATABASE, self.tr("Database (connection name)"), "postgres"
+ )
self.addParameter(db_param)
- self.addParameter(QgsProcessingParameterString(
- self.SQL,
- self.tr('SQL query'),
- multiLine=True))
- self.addParameter(QgsProcessingParameterString(
- self.ID_FIELD,
- self.tr('Unique ID field name'),
- defaultValue='id'))
- self.addParameter(QgsProcessingParameterString(
- self.GEOMETRY_FIELD,
- self.tr('Geometry field name'),
- defaultValue='geom',
- optional=True))
- self.addOutput(QgsProcessingOutputVectorLayer(
- self.OUTPUT,
- self.tr("Output layer"),
- QgsProcessing.SourceType.TypeVectorAnyGeometry))
+ self.addParameter(
+ QgsProcessingParameterString(self.SQL, self.tr("SQL query"), multiLine=True)
+ )
+ self.addParameter(
+ QgsProcessingParameterString(
+ self.ID_FIELD, self.tr("Unique ID field name"), defaultValue="id"
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterString(
+ self.GEOMETRY_FIELD,
+ self.tr("Geometry field name"),
+ defaultValue="geom",
+ optional=True,
+ )
+ )
+ self.addOutput(
+ QgsProcessingOutputVectorLayer(
+ self.OUTPUT,
+ self.tr("Output layer"),
+ QgsProcessing.SourceType.TypeVectorAnyGeometry,
+ )
+ )
def name(self):
- return 'postgisexecuteandloadsql'
+ return "postgisexecuteandloadsql"
def displayName(self):
- return self.tr('PostgreSQL execute and load SQL')
+ return self.tr("PostgreSQL execute and load SQL")
def shortDescription(self):
- return self.tr('Executes a SQL command on a PostgreSQL database and loads the result as a table')
+ return self.tr(
+ "Executes a SQL command on a PostgreSQL database and loads the result as a table"
+ )
def tags(self):
- return self.tr('postgis,table,database').split(',')
+ return self.tr("postgis,table,database").split(",")
def processAlgorithm(self, parameters, context, feedback):
- connection_name = self.parameterAsConnectionName(parameters, self.DATABASE, context)
+ connection_name = self.parameterAsConnectionName(
+ parameters, self.DATABASE, context
+ )
id_field = self.parameterAsString(parameters, self.ID_FIELD, context)
- geom_field = self.parameterAsString(
- parameters, self.GEOMETRY_FIELD, context)
+ geom_field = self.parameterAsString(parameters, self.GEOMETRY_FIELD, context)
# resolve connection details to uri
try:
- md = QgsProviderRegistry.instance().providerMetadata('postgres')
+ md = QgsProviderRegistry.instance().providerMetadata("postgres")
conn = md.createConnection(connection_name)
except QgsProviderConnectionException:
- raise QgsProcessingException(self.tr('Could not retrieve connection details for {}').format(connection_name))
+ raise QgsProcessingException(
+ self.tr("Could not retrieve connection details for {}").format(
+ connection_name
+ )
+ )
uri = QgsDataSourceUri(conn.uri())
sql = self.parameterAsString(parameters, self.SQL, context)
- sql = sql.replace('\n', ' ')
- uri.setDataSource("", "(" + sql.rstrip(';') + ")", geom_field, "", id_field)
+ sql = sql.replace("\n", " ")
+ uri.setDataSource("", "(" + sql.rstrip(";") + ")", geom_field, "", id_field)
vlayer = QgsVectorLayer(uri.uri(), "layername", "postgres")
if not vlayer.isValid():
- raise QgsProcessingException(self.tr("""This layer is invalid!
- Please check the PostGIS log for error messages."""))
+ raise QgsProcessingException(
+ self.tr(
+ """This layer is invalid!
+ Please check the PostGIS log for error messages."""
+ )
+ )
context.temporaryLayerStore().addMapLayer(vlayer)
context.addLayerToLoadOnCompletion(
vlayer.id(),
- QgsProcessingContext.LayerDetails('SQL layer',
- context.project(),
- self.OUTPUT))
+ QgsProcessingContext.LayerDetails(
+ "SQL layer", context.project(), self.OUTPUT
+ ),
+ )
return {self.OUTPUT: vlayer.id()}
diff --git a/python/plugins/processing/algs/qgis/QgisAlgorithm.py b/python/plugins/processing/algs/qgis/QgisAlgorithm.py
index 7e850cf5a6ac..f0bf95805527 100644
--- a/python/plugins/processing/algs/qgis/QgisAlgorithm.py
+++ b/python/plugins/processing/algs/qgis/QgisAlgorithm.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Nyall Dawson'
-__date__ = 'May2017'
-__copyright__ = '(C) 2017, Nyall Dawson'
+__author__ = "Nyall Dawson"
+__date__ = "May2017"
+__copyright__ = "(C) 2017, Nyall Dawson"
from qgis.core import QgsProcessingAlgorithm, QgsProcessingFeatureBasedAlgorithm
from qgis.PyQt.QtCore import QCoreApplication
@@ -32,13 +32,13 @@ def __init__(self):
def shortHelpString(self):
return shortHelp.get(self.id(), None)
- def tr(self, string, context=''):
- if context == '':
+ def tr(self, string, context=""):
+ if context == "":
context = self.__class__.__name__
return QCoreApplication.translate(context, string)
- def trAlgorithm(self, string, context=''):
- if context == '':
+ def trAlgorithm(self, string, context=""):
+ if context == "":
context = self.__class__.__name__
return string, QCoreApplication.translate(context, string)
@@ -54,13 +54,13 @@ def __init__(self):
def shortHelpString(self):
return shortHelp.get(self.id(), None)
- def tr(self, string, context=''):
- if context == '':
+ def tr(self, string, context=""):
+ if context == "":
context = self.__class__.__name__
return QCoreApplication.translate(context, string)
- def trAlgorithm(self, string, context=''):
- if context == '':
+ def trAlgorithm(self, string, context=""):
+ if context == "":
context = self.__class__.__name__
return string, QCoreApplication.translate(context, string)
diff --git a/python/plugins/processing/algs/qgis/QgisAlgorithmProvider.py b/python/plugins/processing/algs/qgis/QgisAlgorithmProvider.py
index 4705e863842d..6a540340b9cd 100644
--- a/python/plugins/processing/algs/qgis/QgisAlgorithmProvider.py
+++ b/python/plugins/processing/algs/qgis/QgisAlgorithmProvider.py
@@ -15,15 +15,13 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'December 2012'
-__copyright__ = '(C) 2012, Victor Olaya'
+__author__ = "Victor Olaya"
+__date__ = "December 2012"
+__copyright__ = "(C) 2012, Victor Olaya"
import os
-from qgis.core import (QgsApplication,
- QgsProcessingProvider,
- QgsRuntimeProfiler)
+from qgis.core import QgsApplication, QgsProcessingProvider, QgsRuntimeProfiler
from qgis.PyQt.QtCore import QCoreApplication
@@ -80,75 +78,80 @@
class QgisAlgorithmProvider(QgsProcessingProvider):
- fieldMappingParameterName = QCoreApplication.translate('Processing', 'Fields Mapper')
+ fieldMappingParameterName = QCoreApplication.translate(
+ "Processing", "Fields Mapper"
+ )
def __init__(self):
super().__init__()
- QgsApplication.processingRegistry().addAlgorithmAlias('qgis:rectanglesovalsdiamondsfixed', 'native:rectanglesovalsdiamonds')
+ QgsApplication.processingRegistry().addAlgorithmAlias(
+ "qgis:rectanglesovalsdiamondsfixed", "native:rectanglesovalsdiamonds"
+ )
def getAlgs(self):
- algs = [BarPlot(),
- BoxPlot(),
- CheckValidity(),
- Climb(),
- DefineProjection(),
- EliminateSelection(),
- ExecuteSQL(),
- ExportGeometryInfo(),
- FieldsPyculator(),
- FindProjection(),
- GeometryConvert(),
- Heatmap(),
- HubDistanceLines(),
- HubDistancePoints(),
- HypsometricCurves(),
- IdwInterpolation(),
- ImportIntoSpatialite(),
- KNearestConcaveHull(),
- LinesToPolygons(),
- MeanAndStdDevPlot(),
- MinimumBoundingGeometry(),
- PointDistance(),
- PointsDisplacement(),
- PointsFromLines(),
- PolarPlot(),
- PostGISExecuteAndLoadSQL(),
- RandomExtractWithinSubsets(),
- RandomPointsAlongLines(),
- RandomPointsLayer(),
- RandomPointsPolygons(),
- RandomSelection(),
- RandomSelectionWithinSubsets(),
- RasterCalculator(),
- RasterLayerHistogram(),
- RectanglesOvalsDiamondsVariable(),
- RegularPoints(),
- Relief(),
- SelectByAttribute(),
- SelectByExpression(),
- SetRasterStyle(),
- SetVectorStyle(),
- StatisticsByCategories(),
- TextToFloat(),
- TinInterpolation(),
- TopoColor(),
- UniqueValues(),
- VariableDistanceBuffer(),
- VectorLayerHistogram(),
- VectorLayerScatterplot(),
- VectorLayerScatterplot3D(),
- ]
+ algs = [
+ BarPlot(),
+ BoxPlot(),
+ CheckValidity(),
+ Climb(),
+ DefineProjection(),
+ EliminateSelection(),
+ ExecuteSQL(),
+ ExportGeometryInfo(),
+ FieldsPyculator(),
+ FindProjection(),
+ GeometryConvert(),
+ Heatmap(),
+ HubDistanceLines(),
+ HubDistancePoints(),
+ HypsometricCurves(),
+ IdwInterpolation(),
+ ImportIntoSpatialite(),
+ KNearestConcaveHull(),
+ LinesToPolygons(),
+ MeanAndStdDevPlot(),
+ MinimumBoundingGeometry(),
+ PointDistance(),
+ PointsDisplacement(),
+ PointsFromLines(),
+ PolarPlot(),
+ PostGISExecuteAndLoadSQL(),
+ RandomExtractWithinSubsets(),
+ RandomPointsAlongLines(),
+ RandomPointsLayer(),
+ RandomPointsPolygons(),
+ RandomSelection(),
+ RandomSelectionWithinSubsets(),
+ RasterCalculator(),
+ RasterLayerHistogram(),
+ RectanglesOvalsDiamondsVariable(),
+ RegularPoints(),
+ Relief(),
+ SelectByAttribute(),
+ SelectByExpression(),
+ SetRasterStyle(),
+ SetVectorStyle(),
+ StatisticsByCategories(),
+ TextToFloat(),
+ TinInterpolation(),
+ TopoColor(),
+ UniqueValues(),
+ VariableDistanceBuffer(),
+ VectorLayerHistogram(),
+ VectorLayerScatterplot(),
+ VectorLayerScatterplot3D(),
+ ]
return algs
def id(self):
- return 'qgis'
+ return "qgis"
def helpId(self):
- return 'qgis'
+ return "qgis"
def name(self):
- return 'QGIS'
+ return "QGIS"
def icon(self):
return QgsApplication.getThemeIcon("/providerQgis.svg")
@@ -161,7 +164,7 @@ def loadAlgorithms(self):
self.addAlgorithm(a)
def load(self):
- with QgsRuntimeProfiler.profile('QGIS Python Provider'):
+ with QgsRuntimeProfiler.profile("QGIS Python Provider"):
success = super().load()
return success
diff --git a/python/plugins/processing/algs/qgis/RandomExtractWithinSubsets.py b/python/plugins/processing/algs/qgis/RandomExtractWithinSubsets.py
index 55d517e68519..639d990a1ccb 100644
--- a/python/plugins/processing/algs/qgis/RandomExtractWithinSubsets.py
+++ b/python/plugins/processing/algs/qgis/RandomExtractWithinSubsets.py
@@ -15,70 +15,94 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'August 2012'
-__copyright__ = '(C) 2012, Victor Olaya'
+__author__ = "Victor Olaya"
+__date__ = "August 2012"
+__copyright__ = "(C) 2012, Victor Olaya"
import random
-from qgis.core import (QgsFeatureSink,
- QgsProcessingException,
- QgsProcessingParameterFeatureSource,
- QgsProcessingParameterEnum,
- QgsProcessingParameterField,
- QgsProcessingParameterNumber,
- QgsProcessingParameterFeatureSink,
- QgsProcessingFeatureSource,
- QgsFeatureRequest)
+from qgis.core import (
+ QgsFeatureSink,
+ QgsProcessingException,
+ QgsProcessingParameterFeatureSource,
+ QgsProcessingParameterEnum,
+ QgsProcessingParameterField,
+ QgsProcessingParameterNumber,
+ QgsProcessingParameterFeatureSink,
+ QgsProcessingFeatureSource,
+ QgsFeatureRequest,
+)
from collections import defaultdict
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
class RandomExtractWithinSubsets(QgisAlgorithm):
- INPUT = 'INPUT'
- METHOD = 'METHOD'
- NUMBER = 'NUMBER'
- FIELD = 'FIELD'
- OUTPUT = 'OUTPUT'
+ INPUT = "INPUT"
+ METHOD = "METHOD"
+ NUMBER = "NUMBER"
+ FIELD = "FIELD"
+ OUTPUT = "OUTPUT"
def group(self):
- return self.tr('Vector selection')
+ return self.tr("Vector selection")
def groupId(self):
- return 'vectorselection'
+ return "vectorselection"
def __init__(self):
super().__init__()
def initAlgorithm(self, config=None):
- self.methods = [self.tr('Number of selected features'),
- self.tr('Percentage of selected features')]
-
- self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT,
- self.tr('Input layer')))
-
- self.addParameter(QgsProcessingParameterField(self.FIELD,
- self.tr('ID field'), None, self.INPUT))
-
- self.addParameter(QgsProcessingParameterEnum(self.METHOD,
- self.tr('Method'), self.methods, False, 0))
-
- self.addParameter(QgsProcessingParameterNumber(self.NUMBER,
- self.tr('Number/percentage of selected features'), QgsProcessingParameterNumber.Type.Integer,
- 10, False, 0.0))
-
- self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Extracted (random stratified)')))
+ self.methods = [
+ self.tr("Number of selected features"),
+ self.tr("Percentage of selected features"),
+ ]
+
+ self.addParameter(
+ QgsProcessingParameterFeatureSource(self.INPUT, self.tr("Input layer"))
+ )
+
+ self.addParameter(
+ QgsProcessingParameterField(
+ self.FIELD, self.tr("ID field"), None, self.INPUT
+ )
+ )
+
+ self.addParameter(
+ QgsProcessingParameterEnum(
+ self.METHOD, self.tr("Method"), self.methods, False, 0
+ )
+ )
+
+ self.addParameter(
+ QgsProcessingParameterNumber(
+ self.NUMBER,
+ self.tr("Number/percentage of selected features"),
+ QgsProcessingParameterNumber.Type.Integer,
+ 10,
+ False,
+ 0.0,
+ )
+ )
+
+ self.addParameter(
+ QgsProcessingParameterFeatureSink(
+ self.OUTPUT, self.tr("Extracted (random stratified)")
+ )
+ )
def name(self):
- return 'randomextractwithinsubsets'
+ return "randomextractwithinsubsets"
def displayName(self):
- return self.tr('Random extract within subsets')
+ return self.tr("Random extract within subsets")
def processAlgorithm(self, parameters, context, feedback):
source = self.parameterAsSource(parameters, self.INPUT, context)
if source is None:
- raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT))
+ raise QgsProcessingException(
+ self.invalidSourceError(parameters, self.INPUT)
+ )
method = self.parameterAsEnum(parameters, self.METHOD, context)
@@ -86,24 +110,39 @@ def processAlgorithm(self, parameters, context, feedback):
index = source.fields().lookupField(field)
- features = source.getFeatures(QgsFeatureRequest(), QgsProcessingFeatureSource.Flag.FlagSkipGeometryValidityChecks)
+ features = source.getFeatures(
+ QgsFeatureRequest(),
+ QgsProcessingFeatureSource.Flag.FlagSkipGeometryValidityChecks,
+ )
featureCount = source.featureCount()
unique = source.uniqueValues(index)
value = self.parameterAsInt(parameters, self.NUMBER, context)
if method == 0:
if value > featureCount:
raise QgsProcessingException(
- self.tr('Selected number is greater that feature count. '
- 'Choose lesser value and try again.'))
+ self.tr(
+ "Selected number is greater that feature count. "
+ "Choose lesser value and try again."
+ )
+ )
else:
if value > 100:
raise QgsProcessingException(
- self.tr("Percentage can't be greater than 100. Set "
- "correct value and try again."))
+ self.tr(
+ "Percentage can't be greater than 100. Set "
+ "correct value and try again."
+ )
+ )
value = value / 100.0
- (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
- source.fields(), source.wkbType(), source.sourceCrs())
+ (sink, dest_id) = self.parameterAsSink(
+ parameters,
+ self.OUTPUT,
+ context,
+ source.fields(),
+ source.wkbType(),
+ source.sourceCrs(),
+ )
if sink is None:
raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT))
@@ -122,12 +161,15 @@ def processAlgorithm(self, parameters, context, feedback):
selValue = value if method != 1 else int(round(value * len(subset), 0))
if selValue > len(subset):
selValue = len(subset)
- feedback.reportError(self.tr(
- 'Subset "{}" is smaller than requested number of features.').format(k))
+ feedback.reportError(
+ self.tr(
+ 'Subset "{}" is smaller than requested number of features.'
+ ).format(k)
+ )
selran.extend(random.sample(subset, selValue))
total = 100.0 / featureCount if featureCount else 1
- for (i, feat) in enumerate(selran):
+ for i, feat in enumerate(selran):
if feedback.isCanceled():
break
sink.addFeature(feat, QgsFeatureSink.Flag.FastInsert)
diff --git a/python/plugins/processing/algs/qgis/RandomPointsAlongLines.py b/python/plugins/processing/algs/qgis/RandomPointsAlongLines.py
index 0876744a87c8..5e67a9db0848 100644
--- a/python/plugins/processing/algs/qgis/RandomPointsAlongLines.py
+++ b/python/plugins/processing/algs/qgis/RandomPointsAlongLines.py
@@ -15,72 +15,97 @@
***************************************************************************
"""
-__author__ = 'Alexander Bruy'
-__date__ = 'April 2014'
-__copyright__ = '(C) 2014, Alexander Bruy'
+__author__ = "Alexander Bruy"
+__date__ = "April 2014"
+__copyright__ = "(C) 2014, Alexander Bruy"
import random
from qgis.PyQt.QtCore import QMetaType
-from qgis.core import (Qgis,
- QgsField,
- QgsFeatureSink,
- QgsFeature,
- QgsFields,
- QgsGeometry,
- QgsPointXY,
- QgsWkbTypes,
- QgsSpatialIndex,
- QgsFeatureRequest,
- QgsDistanceArea,
- QgsProject,
- QgsProcessing,
- QgsProcessingException,
- QgsProcessingParameterDistance,
- QgsProcessingParameterNumber,
- QgsProcessingParameterFeatureSource,
- QgsProcessingParameterFeatureSink,
- QgsProcessingParameterDefinition)
+from qgis.core import (
+ Qgis,
+ QgsField,
+ QgsFeatureSink,
+ QgsFeature,
+ QgsFields,
+ QgsGeometry,
+ QgsPointXY,
+ QgsWkbTypes,
+ QgsSpatialIndex,
+ QgsFeatureRequest,
+ QgsDistanceArea,
+ QgsProject,
+ QgsProcessing,
+ QgsProcessingException,
+ QgsProcessingParameterDistance,
+ QgsProcessingParameterNumber,
+ QgsProcessingParameterFeatureSource,
+ QgsProcessingParameterFeatureSink,
+ QgsProcessingParameterDefinition,
+)
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
from processing.tools import vector
class RandomPointsAlongLines(QgisAlgorithm):
- INPUT = 'INPUT'
- POINTS_NUMBER = 'POINTS_NUMBER'
- MIN_DISTANCE = 'MIN_DISTANCE'
- OUTPUT = 'OUTPUT'
+ INPUT = "INPUT"
+ POINTS_NUMBER = "POINTS_NUMBER"
+ MIN_DISTANCE = "MIN_DISTANCE"
+ OUTPUT = "OUTPUT"
def group(self):
- return self.tr('Vector creation')
+ return self.tr("Vector creation")
def groupId(self):
- return 'vectorcreation'
+ return "vectorcreation"
def __init__(self):
super().__init__()
def initAlgorithm(self, config=None):
- self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT,
- self.tr('Input layer'),
- [QgsProcessing.SourceType.TypeVectorLine]))
- self.addParameter(QgsProcessingParameterNumber(self.POINTS_NUMBER,
- self.tr('Number of points'),
- QgsProcessingParameterNumber.Type.Integer,
- 1, False, 1, 1000000000))
- self.addParameter(QgsProcessingParameterDistance(self.MIN_DISTANCE,
- self.tr('Minimum distance between points'),
- 0, self.INPUT, False, 0, 1000000000))
- self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT,
- self.tr('Random points'),
- type=QgsProcessing.SourceType.TypeVectorPoint))
+ self.addParameter(
+ QgsProcessingParameterFeatureSource(
+ self.INPUT,
+ self.tr("Input layer"),
+ [QgsProcessing.SourceType.TypeVectorLine],
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterNumber(
+ self.POINTS_NUMBER,
+ self.tr("Number of points"),
+ QgsProcessingParameterNumber.Type.Integer,
+ 1,
+ False,
+ 1,
+ 1000000000,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterDistance(
+ self.MIN_DISTANCE,
+ self.tr("Minimum distance between points"),
+ 0,
+ self.INPUT,
+ False,
+ 0,
+ 1000000000,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterFeatureSink(
+ self.OUTPUT,
+ self.tr("Random points"),
+ type=QgsProcessing.SourceType.TypeVectorPoint,
+ )
+ )
def name(self):
- return 'randompointsalongline'
+ return "randompointsalongline"
def displayName(self):
- return self.tr('Random points along line')
+ return self.tr("Random points along line")
def documentationFlags(self):
return Qgis.ProcessingAlgorithmDocumentationFlag.RegeneratesPrimaryKey
@@ -88,16 +113,25 @@ def documentationFlags(self):
def processAlgorithm(self, parameters, context, feedback):
source = self.parameterAsSource(parameters, self.INPUT, context)
if source is None:
- raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT))
+ raise QgsProcessingException(
+ self.invalidSourceError(parameters, self.INPUT)
+ )
pointCount = self.parameterAsDouble(parameters, self.POINTS_NUMBER, context)
minDistance = self.parameterAsDouble(parameters, self.MIN_DISTANCE, context)
fields = QgsFields()
- fields.append(QgsField('id', QMetaType.Type.Int, '', 10, 0))
-
- (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
- fields, QgsWkbTypes.Type.Point, source.sourceCrs(), QgsFeatureSink.SinkFlag.RegeneratePrimaryKey)
+ fields.append(QgsField("id", QMetaType.Type.Int, "", 10, 0))
+
+ (sink, dest_id) = self.parameterAsSink(
+ parameters,
+ self.OUTPUT,
+ context,
+ fields,
+ QgsWkbTypes.Type.Point,
+ source.sourceCrs(),
+ QgsFeatureSink.SinkFlag.RegeneratePrimaryKey,
+ )
if sink is None:
raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT))
@@ -126,7 +160,11 @@ def processAlgorithm(self, parameters, context, feedback):
# pick random feature
fid = random.choice(ids)
try:
- f = next(source.getFeatures(request.setFilterFid(fid).setSubsetOfAttributes([])))
+ f = next(
+ source.getFeatures(
+ request.setFilterFid(fid).setSubsetOfAttributes([])
+ )
+ )
except StopIteration:
ids.remove(fid)
continue
@@ -172,7 +210,7 @@ def processAlgorithm(self, parameters, context, feedback):
f = QgsFeature(nPoints)
f.initAttributes(1)
f.setFields(fields)
- f.setAttribute('id', nPoints)
+ f.setAttribute("id", nPoints)
f.setGeometry(geom)
sink.addFeature(f, QgsFeatureSink.Flag.FastInsert)
index.addFeature(f)
@@ -182,8 +220,12 @@ def processAlgorithm(self, parameters, context, feedback):
nIterations += 1
if nPoints < pointCount:
- feedback.pushInfo(self.tr('Could not generate requested number of random points. '
- 'Maximum number of attempts exceeded.'))
+ feedback.pushInfo(
+ self.tr(
+ "Could not generate requested number of random points. "
+ "Maximum number of attempts exceeded."
+ )
+ )
sink.finalize()
return {self.OUTPUT: dest_id}
diff --git a/python/plugins/processing/algs/qgis/RandomPointsLayer.py b/python/plugins/processing/algs/qgis/RandomPointsLayer.py
index 2d7eee82cdfd..0b6422131304 100644
--- a/python/plugins/processing/algs/qgis/RandomPointsLayer.py
+++ b/python/plugins/processing/algs/qgis/RandomPointsLayer.py
@@ -15,33 +15,35 @@
***************************************************************************
"""
-__author__ = 'Alexander Bruy'
-__date__ = 'April 2014'
-__copyright__ = '(C) 2014, Alexander Bruy'
+__author__ = "Alexander Bruy"
+__date__ = "April 2014"
+__copyright__ = "(C) 2014, Alexander Bruy"
import os
import random
from qgis.PyQt.QtGui import QIcon
from qgis.PyQt.QtCore import QMetaType
-from qgis.core import (Qgis,
- QgsApplication,
- QgsField,
- QgsFeatureSink,
- QgsFeature,
- QgsFields,
- QgsGeometry,
- QgsPointXY,
- QgsWkbTypes,
- QgsSpatialIndex,
- QgsFeatureRequest,
- QgsProcessing,
- QgsProcessingException,
- QgsProcessingParameterNumber,
- QgsProcessingParameterDistance,
- QgsProcessingParameterFeatureSource,
- QgsProcessingParameterFeatureSink,
- QgsProcessingParameterDefinition)
+from qgis.core import (
+ Qgis,
+ QgsApplication,
+ QgsField,
+ QgsFeatureSink,
+ QgsFeature,
+ QgsFields,
+ QgsGeometry,
+ QgsPointXY,
+ QgsWkbTypes,
+ QgsSpatialIndex,
+ QgsFeatureRequest,
+ QgsProcessing,
+ QgsProcessingException,
+ QgsProcessingParameterNumber,
+ QgsProcessingParameterDistance,
+ QgsProcessingParameterFeatureSource,
+ QgsProcessingParameterFeatureSink,
+ QgsProcessingParameterDefinition,
+)
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
from processing.tools import vector
@@ -50,46 +52,73 @@
class RandomPointsLayer(QgisAlgorithm):
- INPUT = 'INPUT'
- POINTS_NUMBER = 'POINTS_NUMBER'
- MIN_DISTANCE = 'MIN_DISTANCE'
- OUTPUT = 'OUTPUT'
+ INPUT = "INPUT"
+ POINTS_NUMBER = "POINTS_NUMBER"
+ MIN_DISTANCE = "MIN_DISTANCE"
+ OUTPUT = "OUTPUT"
def icon(self):
- return QgsApplication.getThemeIcon("/algorithms/mAlgorithmRandomPointsWithinExtent.svg")
+ return QgsApplication.getThemeIcon(
+ "/algorithms/mAlgorithmRandomPointsWithinExtent.svg"
+ )
def svgIconPath(self):
- return QgsApplication.iconPath("/algorithms/mAlgorithmRandomPointsWithinExtent.svg")
+ return QgsApplication.iconPath(
+ "/algorithms/mAlgorithmRandomPointsWithinExtent.svg"
+ )
def group(self):
- return self.tr('Vector creation')
+ return self.tr("Vector creation")
def groupId(self):
- return 'vectorcreation'
+ return "vectorcreation"
def __init__(self):
super().__init__()
def initAlgorithm(self, config=None):
- self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT,
- self.tr('Input layer'),
- [QgsProcessing.SourceType.TypeVectorPolygon]))
- self.addParameter(QgsProcessingParameterNumber(self.POINTS_NUMBER,
- self.tr('Number of points'),
- QgsProcessingParameterNumber.Type.Integer,
- 1, False, 1, 1000000000))
- self.addParameter(QgsProcessingParameterDistance(self.MIN_DISTANCE,
- self.tr('Minimum distance between points'),
- 0, self.INPUT, False, 0, 1000000000))
- self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT,
- self.tr('Random points'),
- type=QgsProcessing.SourceType.TypeVectorPoint))
+ self.addParameter(
+ QgsProcessingParameterFeatureSource(
+ self.INPUT,
+ self.tr("Input layer"),
+ [QgsProcessing.SourceType.TypeVectorPolygon],
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterNumber(
+ self.POINTS_NUMBER,
+ self.tr("Number of points"),
+ QgsProcessingParameterNumber.Type.Integer,
+ 1,
+ False,
+ 1,
+ 1000000000,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterDistance(
+ self.MIN_DISTANCE,
+ self.tr("Minimum distance between points"),
+ 0,
+ self.INPUT,
+ False,
+ 0,
+ 1000000000,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterFeatureSink(
+ self.OUTPUT,
+ self.tr("Random points"),
+ type=QgsProcessing.SourceType.TypeVectorPoint,
+ )
+ )
def name(self):
- return 'randompointsinlayerbounds'
+ return "randompointsinlayerbounds"
def displayName(self):
- return self.tr('Random points in layer bounds')
+ return self.tr("Random points in layer bounds")
def documentationFlags(self):
return Qgis.ProcessingAlgorithmDocumentationFlag.RegeneratesPrimaryKey
@@ -97,7 +126,9 @@ def documentationFlags(self):
def processAlgorithm(self, parameters, context, feedback):
source = self.parameterAsSource(parameters, self.INPUT, context)
if source is None:
- raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT))
+ raise QgsProcessingException(
+ self.invalidSourceError(parameters, self.INPUT)
+ )
pointCount = self.parameterAsDouble(parameters, self.POINTS_NUMBER, context)
minDistance = self.parameterAsDouble(parameters, self.MIN_DISTANCE, context)
@@ -106,10 +137,17 @@ def processAlgorithm(self, parameters, context, feedback):
sourceIndex = QgsSpatialIndex(source, feedback)
fields = QgsFields()
- fields.append(QgsField('id', QMetaType.Type.Int, '', 10, 0))
-
- (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
- fields, QgsWkbTypes.Type.Point, source.sourceCrs(), QgsFeatureSink.SinkFlag.RegeneratePrimaryKey)
+ fields.append(QgsField("id", QMetaType.Type.Int, "", 10, 0))
+
+ (sink, dest_id) = self.parameterAsSink(
+ parameters,
+ self.OUTPUT,
+ context,
+ fields,
+ QgsWkbTypes.Type.Point,
+ source.sourceCrs(),
+ QgsFeatureSink.SinkFlag.RegeneratePrimaryKey,
+ )
if sink is None:
raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT))
@@ -133,9 +171,10 @@ def processAlgorithm(self, parameters, context, feedback):
p = QgsPointXY(rx, ry)
geom = QgsGeometry.fromPointXY(p)
ids = sourceIndex.intersects(geom.buffer(5, 5).boundingBox())
- if len(ids) > 0 and \
- vector.checkMinDistance(p, index, minDistance, points):
- request = QgsFeatureRequest().setFilterFids(ids).setSubsetOfAttributes([])
+ if len(ids) > 0 and vector.checkMinDistance(p, index, minDistance, points):
+ request = (
+ QgsFeatureRequest().setFilterFids(ids).setSubsetOfAttributes([])
+ )
for f in source.getFeatures(request):
if feedback.isCanceled():
break
@@ -145,7 +184,7 @@ def processAlgorithm(self, parameters, context, feedback):
f = QgsFeature(nPoints)
f.initAttributes(1)
f.setFields(fields)
- f.setAttribute('id', nPoints)
+ f.setAttribute("id", nPoints)
f.setGeometry(geom)
sink.addFeature(f, QgsFeatureSink.Flag.FastInsert)
index.addFeature(f)
@@ -155,8 +194,12 @@ def processAlgorithm(self, parameters, context, feedback):
nIterations += 1
if nPoints < pointCount:
- feedback.pushInfo(self.tr('Could not generate requested number of random points. '
- 'Maximum number of attempts exceeded.'))
+ feedback.pushInfo(
+ self.tr(
+ "Could not generate requested number of random points. "
+ "Maximum number of attempts exceeded."
+ )
+ )
sink.finalize()
return {self.OUTPUT: dest_id}
diff --git a/python/plugins/processing/algs/qgis/RandomPointsPolygons.py b/python/plugins/processing/algs/qgis/RandomPointsPolygons.py
index 3d700e9d701b..c970a4f3ce80 100644
--- a/python/plugins/processing/algs/qgis/RandomPointsPolygons.py
+++ b/python/plugins/processing/algs/qgis/RandomPointsPolygons.py
@@ -15,37 +15,39 @@
***************************************************************************
"""
-__author__ = 'Alexander Bruy'
-__date__ = 'April 2014'
-__copyright__ = '(C) 2014, Alexander Bruy'
+__author__ = "Alexander Bruy"
+__date__ = "April 2014"
+__copyright__ = "(C) 2014, Alexander Bruy"
import os
import random
from qgis.PyQt.QtCore import QMetaType
-from qgis.core import (Qgis,
- QgsApplication,
- QgsField,
- QgsFeatureSink,
- QgsFeature,
- QgsFields,
- QgsGeometry,
- QgsPointXY,
- QgsWkbTypes,
- QgsSpatialIndex,
- QgsExpression,
- QgsDistanceArea,
- QgsPropertyDefinition,
- QgsProcessing,
- QgsProcessingException,
- QgsProcessingParameters,
- QgsProcessingParameterDefinition,
- QgsProcessingParameterNumber,
- QgsProcessingParameterDistance,
- QgsProcessingParameterFeatureSource,
- QgsProcessingParameterFeatureSink,
- QgsProcessingParameterExpression,
- QgsProcessingParameterEnum)
+from qgis.core import (
+ Qgis,
+ QgsApplication,
+ QgsField,
+ QgsFeatureSink,
+ QgsFeature,
+ QgsFields,
+ QgsGeometry,
+ QgsPointXY,
+ QgsWkbTypes,
+ QgsSpatialIndex,
+ QgsExpression,
+ QgsDistanceArea,
+ QgsPropertyDefinition,
+ QgsProcessing,
+ QgsProcessingException,
+ QgsProcessingParameters,
+ QgsProcessingParameterDefinition,
+ QgsProcessingParameterNumber,
+ QgsProcessingParameterDistance,
+ QgsProcessingParameterFeatureSource,
+ QgsProcessingParameterFeatureSink,
+ QgsProcessingParameterExpression,
+ QgsProcessingParameterEnum,
+)
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
from processing.tools import vector
@@ -54,70 +56,101 @@
class RandomPointsPolygons(QgisAlgorithm):
- INPUT = 'INPUT'
- VALUE = 'VALUE'
- EXPRESSION = 'EXPRESSION'
- MIN_DISTANCE = 'MIN_DISTANCE'
- STRATEGY = 'STRATEGY'
- OUTPUT = 'OUTPUT'
+ INPUT = "INPUT"
+ VALUE = "VALUE"
+ EXPRESSION = "EXPRESSION"
+ MIN_DISTANCE = "MIN_DISTANCE"
+ STRATEGY = "STRATEGY"
+ OUTPUT = "OUTPUT"
def icon(self):
- return QgsApplication.getThemeIcon("/algorithms/mAlgorithmRandomPointsWithinPolygon.svg")
+ return QgsApplication.getThemeIcon(
+ "/algorithms/mAlgorithmRandomPointsWithinPolygon.svg"
+ )
def svgIconPath(self):
- return QgsApplication.iconPath("/algorithms/mAlgorithmRandomPointsWithinPolygon.svg")
+ return QgsApplication.iconPath(
+ "/algorithms/mAlgorithmRandomPointsWithinPolygon.svg"
+ )
def group(self):
- return self.tr('Vector creation')
+ return self.tr("Vector creation")
def groupId(self):
- return 'vectorcreation'
+ return "vectorcreation"
def __init__(self):
super().__init__()
def initAlgorithm(self, config=None):
- self.strategies = [self.tr('Points count'),
- self.tr('Points density')]
-
- self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT,
- self.tr('Input layer'),
- [QgsProcessing.SourceType.TypeVectorPolygon]))
- self.addParameter(QgsProcessingParameterEnum(self.STRATEGY,
- self.tr('Sampling strategy'),
- self.strategies,
- False,
- 0))
- value_param = QgsProcessingParameterNumber(self.VALUE,
- self.tr('Point count or density'),
- QgsProcessingParameterNumber.Type.Double,
- 1,
- minValue=0)
+ self.strategies = [self.tr("Points count"), self.tr("Points density")]
+
+ self.addParameter(
+ QgsProcessingParameterFeatureSource(
+ self.INPUT,
+ self.tr("Input layer"),
+ [QgsProcessing.SourceType.TypeVectorPolygon],
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterEnum(
+ self.STRATEGY, self.tr("Sampling strategy"), self.strategies, False, 0
+ )
+ )
+ value_param = QgsProcessingParameterNumber(
+ self.VALUE,
+ self.tr("Point count or density"),
+ QgsProcessingParameterNumber.Type.Double,
+ 1,
+ minValue=0,
+ )
value_param.setIsDynamic(True)
value_param.setDynamicLayerParameterName(self.INPUT)
value_param.setDynamicPropertyDefinition(
- QgsPropertyDefinition("Value", self.tr("Point count or density"), QgsPropertyDefinition.StandardPropertyTemplate.Double))
+ QgsPropertyDefinition(
+ "Value",
+ self.tr("Point count or density"),
+ QgsPropertyDefinition.StandardPropertyTemplate.Double,
+ )
+ )
self.addParameter(value_param)
# deprecated expression parameter - overrides value parameter if set
- exp_param = QgsProcessingParameterExpression(self.EXPRESSION,
- self.tr('Expression'), optional=True,
- parentLayerParameterName=self.INPUT)
- exp_param.setFlags(exp_param.flags() | QgsProcessingParameterDefinition.Flag.FlagHidden)
+ exp_param = QgsProcessingParameterExpression(
+ self.EXPRESSION,
+ self.tr("Expression"),
+ optional=True,
+ parentLayerParameterName=self.INPUT,
+ )
+ exp_param.setFlags(
+ exp_param.flags() | QgsProcessingParameterDefinition.Flag.FlagHidden
+ )
self.addParameter(exp_param)
- self.addParameter(QgsProcessingParameterDistance(self.MIN_DISTANCE,
- self.tr('Minimum distance between points'),
- None, self.INPUT, True, 0, 1000000000))
- self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT,
- self.tr('Random points'),
- type=QgsProcessing.SourceType.TypeVectorPoint))
+ self.addParameter(
+ QgsProcessingParameterDistance(
+ self.MIN_DISTANCE,
+ self.tr("Minimum distance between points"),
+ None,
+ self.INPUT,
+ True,
+ 0,
+ 1000000000,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterFeatureSink(
+ self.OUTPUT,
+ self.tr("Random points"),
+ type=QgsProcessing.SourceType.TypeVectorPoint,
+ )
+ )
def name(self):
- return 'randompointsinsidepolygons'
+ return "randompointsinsidepolygons"
def displayName(self):
- return self.tr('Random points inside polygons')
+ return self.tr("Random points inside polygons")
def documentationFlags(self):
return Qgis.ProcessingAlgorithmDocumentationFlag.RegeneratesPrimaryKey
@@ -125,10 +158,15 @@ def documentationFlags(self):
def processAlgorithm(self, parameters, context, feedback):
source = self.parameterAsSource(parameters, self.INPUT, context)
if source is None:
- raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT))
+ raise QgsProcessingException(
+ self.invalidSourceError(parameters, self.INPUT)
+ )
strategy = self.parameterAsEnum(parameters, self.STRATEGY, context)
- if self.MIN_DISTANCE in parameters and parameters[self.MIN_DISTANCE] is not None:
+ if (
+ self.MIN_DISTANCE in parameters
+ and parameters[self.MIN_DISTANCE] is not None
+ ):
minDistance = self.parameterAsDouble(parameters, self.MIN_DISTANCE, context)
else:
minDistance = None
@@ -137,7 +175,9 @@ def processAlgorithm(self, parameters, context, feedback):
dynamic_value = QgsProcessingParameters.isDynamic(parameters, "VALUE")
value_property = None
if self.EXPRESSION in parameters and parameters[self.EXPRESSION] is not None:
- expression = QgsExpression(self.parameterAsString(parameters, self.EXPRESSION, context))
+ expression = QgsExpression(
+ self.parameterAsString(parameters, self.EXPRESSION, context)
+ )
value = None
if expression.hasParserError():
raise QgsProcessingException(expression.parserErrorString())
@@ -149,11 +189,17 @@ def processAlgorithm(self, parameters, context, feedback):
value = self.parameterAsDouble(parameters, self.VALUE, context)
fields = QgsFields()
- fields.append(QgsField('id', QMetaType.Type.Int, '', 10, 0))
-
- (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
- fields, QgsWkbTypes.Type.Point, source.sourceCrs(),
- QgsFeatureSink.SinkFlag.RegeneratePrimaryKey)
+ fields.append(QgsField("id", QMetaType.Type.Int, "", 10, 0))
+
+ (sink, dest_id) = self.parameterAsSink(
+ parameters,
+ self.OUTPUT,
+ context,
+ fields,
+ QgsWkbTypes.Type.Point,
+ source.sourceCrs(),
+ QgsFeatureSink.SinkFlag.RegeneratePrimaryKey,
+ )
if sink is None:
raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT))
@@ -178,12 +224,17 @@ def processAlgorithm(self, parameters, context, feedback):
if value_property is not None or expression is not None:
expressionContext.setFeature(f)
if value_property:
- this_value, _ = value_property.valueAsDouble(expressionContext, value)
+ this_value, _ = value_property.valueAsDouble(
+ expressionContext, value
+ )
else:
this_value = expression.evaluate(expressionContext)
if expression.hasEvalError():
feedback.pushInfo(
- self.tr('Evaluation error for feature ID {}: {}').format(f.id(), expression.evalErrorString()))
+ self.tr("Evaluation error for feature ID {}: {}").format(
+ f.id(), expression.evalErrorString()
+ )
+ )
continue
fGeom = f.geometry()
@@ -197,7 +248,11 @@ def processAlgorithm(self, parameters, context, feedback):
pointCount = int(round(this_value * da.measureArea(fGeom)))
if pointCount == 0:
- feedback.pushInfo(self.tr("Skip feature {} as number of points for it is 0.").format(f.id()))
+ feedback.pushInfo(
+ self.tr("Skip feature {} as number of points for it is 0.").format(
+ f.id()
+ )
+ )
continue
index = None
@@ -221,12 +276,14 @@ def processAlgorithm(self, parameters, context, feedback):
p = QgsPointXY(rx, ry)
geom = QgsGeometry.fromPointXY(p)
- if engine.contains(geom.constGet()) and \
- (not minDistance or vector.checkMinDistance(p, index, minDistance, points)):
+ if engine.contains(geom.constGet()) and (
+ not minDistance
+ or vector.checkMinDistance(p, index, minDistance, points)
+ ):
f = QgsFeature(nPoints)
f.initAttributes(1)
f.setFields(fields)
- f.setAttribute('id', pointId)
+ f.setAttribute("id", pointId)
f.setGeometry(geom)
sink.addFeature(f, QgsFeatureSink.Flag.FastInsert)
if minDistance:
@@ -234,12 +291,18 @@ def processAlgorithm(self, parameters, context, feedback):
points[nPoints] = p
nPoints += 1
pointId += 1
- feedback.setProgress(current_progress + int(nPoints * feature_total))
+ feedback.setProgress(
+ current_progress + int(nPoints * feature_total)
+ )
nIterations += 1
if nPoints < pointCount:
- feedback.pushInfo(self.tr('Could not generate requested number of random '
- 'points. Maximum number of attempts exceeded.'))
+ feedback.pushInfo(
+ self.tr(
+ "Could not generate requested number of random "
+ "points. Maximum number of attempts exceeded."
+ )
+ )
feedback.setProgress(100)
sink.finalize()
diff --git a/python/plugins/processing/algs/qgis/RandomSelection.py b/python/plugins/processing/algs/qgis/RandomSelection.py
index 448c2d6e5f9a..57e753f11413 100644
--- a/python/plugins/processing/algs/qgis/RandomSelection.py
+++ b/python/plugins/processing/algs/qgis/RandomSelection.py
@@ -15,24 +15,26 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'August 2012'
-__copyright__ = '(C) 2012, Victor Olaya'
+__author__ = "Victor Olaya"
+__date__ = "August 2012"
+__copyright__ = "(C) 2012, Victor Olaya"
import os
import random
from qgis.PyQt.QtGui import QIcon
-from qgis.core import (QgsApplication,
- QgsFeatureSink,
- QgsProcessingException,
- QgsProcessingUtils,
- QgsProcessingAlgorithm,
- QgsProcessingParameterVectorLayer,
- QgsProcessingParameterEnum,
- QgsProcessingParameterNumber,
- QgsProcessingParameterFeatureSink,
- QgsProcessingOutputVectorLayer)
+from qgis.core import (
+ QgsApplication,
+ QgsFeatureSink,
+ QgsProcessingException,
+ QgsProcessingUtils,
+ QgsProcessingAlgorithm,
+ QgsProcessingParameterVectorLayer,
+ QgsProcessingParameterEnum,
+ QgsProcessingParameterNumber,
+ QgsProcessingParameterFeatureSink,
+ QgsProcessingOutputVectorLayer,
+)
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
@@ -40,10 +42,10 @@
class RandomSelection(QgisAlgorithm):
- INPUT = 'INPUT'
- OUTPUT = 'OUTPUT'
- METHOD = 'METHOD'
- NUMBER = 'NUMBER'
+ INPUT = "INPUT"
+ OUTPUT = "OUTPUT"
+ METHOD = "METHOD"
+ NUMBER = "NUMBER"
def icon(self):
return QgsApplication.getThemeIcon("/algorithms/mAlgorithmSelectRandom.svg")
@@ -52,35 +54,54 @@ def svgIconPath(self):
return QgsApplication.iconPath("/algorithms/mAlgorithmSelectRandom.svg")
def group(self):
- return self.tr('Vector selection')
+ return self.tr("Vector selection")
def groupId(self):
- return 'vectorselection'
+ return "vectorselection"
def flags(self):
- return super().flags() | QgsProcessingAlgorithm.Flag.FlagNoThreading | QgsProcessingAlgorithm.Flag.FlagNotAvailableInStandaloneTool
+ return (
+ super().flags()
+ | QgsProcessingAlgorithm.Flag.FlagNoThreading
+ | QgsProcessingAlgorithm.Flag.FlagNotAvailableInStandaloneTool
+ )
def __init__(self):
super().__init__()
def initAlgorithm(self, config=None):
- self.methods = [self.tr('Number of selected features'),
- self.tr('Percentage of selected features')]
-
- self.addParameter(QgsProcessingParameterVectorLayer(self.INPUT,
- self.tr('Input layer')))
- self.addParameter(QgsProcessingParameterEnum(self.METHOD,
- self.tr('Method'), self.methods, False, 0))
- self.addParameter(QgsProcessingParameterNumber(self.NUMBER,
- self.tr('Number/percentage of selected features'), QgsProcessingParameterNumber.Type.Integer,
- 10, False, 0.0))
- self.addOutput(QgsProcessingOutputVectorLayer(self.OUTPUT, self.tr('Selected (random)')))
+ self.methods = [
+ self.tr("Number of selected features"),
+ self.tr("Percentage of selected features"),
+ ]
+
+ self.addParameter(
+ QgsProcessingParameterVectorLayer(self.INPUT, self.tr("Input layer"))
+ )
+ self.addParameter(
+ QgsProcessingParameterEnum(
+ self.METHOD, self.tr("Method"), self.methods, False, 0
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterNumber(
+ self.NUMBER,
+ self.tr("Number/percentage of selected features"),
+ QgsProcessingParameterNumber.Type.Integer,
+ 10,
+ False,
+ 0.0,
+ )
+ )
+ self.addOutput(
+ QgsProcessingOutputVectorLayer(self.OUTPUT, self.tr("Selected (random)"))
+ )
def name(self):
- return 'randomselection'
+ return "randomselection"
def displayName(self):
- return self.tr('Random selection')
+ return self.tr("Random selection")
def processAlgorithm(self, parameters, context, feedback):
layer = self.parameterAsVectorLayer(parameters, self.INPUT, context)
@@ -92,13 +113,19 @@ def processAlgorithm(self, parameters, context, feedback):
if method == 0:
if value > len(ids):
raise QgsProcessingException(
- self.tr('Selected number is greater than feature count. '
- 'Choose a lower value and try again.'))
+ self.tr(
+ "Selected number is greater than feature count. "
+ "Choose a lower value and try again."
+ )
+ )
else:
if value > 100:
raise QgsProcessingException(
- self.tr("Percentage can't be greater than 100. Set a "
- "different value and try again."))
+ self.tr(
+ "Percentage can't be greater than 100. Set a "
+ "different value and try again."
+ )
+ )
value = int(round(value / 100.0, 4) * len(ids))
selran = random.sample(ids, value)
diff --git a/python/plugins/processing/algs/qgis/RandomSelectionWithinSubsets.py b/python/plugins/processing/algs/qgis/RandomSelectionWithinSubsets.py
index 4a55b483b3d5..37b8542642fc 100644
--- a/python/plugins/processing/algs/qgis/RandomSelectionWithinSubsets.py
+++ b/python/plugins/processing/algs/qgis/RandomSelectionWithinSubsets.py
@@ -15,26 +15,28 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'August 2012'
-__copyright__ = '(C) 2012, Victor Olaya'
+__author__ = "Victor Olaya"
+__date__ = "August 2012"
+__copyright__ = "(C) 2012, Victor Olaya"
import os
import random
from qgis.PyQt.QtGui import QIcon
-from qgis.core import (QgsApplication,
- QgsFeatureRequest,
- QgsProcessingException,
- QgsProcessingUtils,
- QgsProcessingAlgorithm,
- QgsProcessingParameterVectorLayer,
- QgsProcessingParameterEnum,
- QgsProcessingParameterField,
- QgsProcessingParameterNumber,
- QgsProcessingParameterFeatureSink,
- QgsProcessingOutputVectorLayer)
+from qgis.core import (
+ QgsApplication,
+ QgsFeatureRequest,
+ QgsProcessingException,
+ QgsProcessingUtils,
+ QgsProcessingAlgorithm,
+ QgsProcessingParameterVectorLayer,
+ QgsProcessingParameterEnum,
+ QgsProcessingParameterField,
+ QgsProcessingParameterNumber,
+ QgsProcessingParameterFeatureSink,
+ QgsProcessingOutputVectorLayer,
+)
from collections import defaultdict
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
@@ -42,11 +44,11 @@
class RandomSelectionWithinSubsets(QgisAlgorithm):
- INPUT = 'INPUT'
- METHOD = 'METHOD'
- NUMBER = 'NUMBER'
- FIELD = 'FIELD'
- OUTPUT = 'OUTPUT'
+ INPUT = "INPUT"
+ METHOD = "METHOD"
+ NUMBER = "NUMBER"
+ FIELD = "FIELD"
+ OUTPUT = "OUTPUT"
def icon(self):
return QgsApplication.getThemeIcon("/algorithms/mAlgorithmSelectRandom.svg")
@@ -55,38 +57,61 @@ def svgIconPath(self):
return QgsApplication.iconPath("/algorithms/mAlgorithmSelectRandom.svg")
def group(self):
- return self.tr('Vector selection')
+ return self.tr("Vector selection")
def groupId(self):
- return 'vectorselection'
+ return "vectorselection"
def __init__(self):
super().__init__()
def flags(self):
- return super().flags() | QgsProcessingAlgorithm.Flag.FlagNoThreading | QgsProcessingAlgorithm.Flag.FlagNotAvailableInStandaloneTool
+ return (
+ super().flags()
+ | QgsProcessingAlgorithm.Flag.FlagNoThreading
+ | QgsProcessingAlgorithm.Flag.FlagNotAvailableInStandaloneTool
+ )
def initAlgorithm(self, config=None):
- self.methods = [self.tr('Number of selected features'),
- self.tr('Percentage of selected features')]
-
- self.addParameter(QgsProcessingParameterVectorLayer(self.INPUT,
- self.tr('Input layer')))
- self.addParameter(QgsProcessingParameterField(self.FIELD,
- self.tr('ID field'), None, self.INPUT))
- self.addParameter(QgsProcessingParameterEnum(self.METHOD,
- self.tr('Method'), self.methods, False, 0))
- self.addParameter(QgsProcessingParameterNumber(self.NUMBER,
- self.tr('Number/percentage of selected features'),
- QgsProcessingParameterNumber.Type.Integer,
- 10, False, 0.0))
- self.addOutput(QgsProcessingOutputVectorLayer(self.OUTPUT, self.tr('Selected (stratified random)')))
+ self.methods = [
+ self.tr("Number of selected features"),
+ self.tr("Percentage of selected features"),
+ ]
+
+ self.addParameter(
+ QgsProcessingParameterVectorLayer(self.INPUT, self.tr("Input layer"))
+ )
+ self.addParameter(
+ QgsProcessingParameterField(
+ self.FIELD, self.tr("ID field"), None, self.INPUT
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterEnum(
+ self.METHOD, self.tr("Method"), self.methods, False, 0
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterNumber(
+ self.NUMBER,
+ self.tr("Number/percentage of selected features"),
+ QgsProcessingParameterNumber.Type.Integer,
+ 10,
+ False,
+ 0.0,
+ )
+ )
+ self.addOutput(
+ QgsProcessingOutputVectorLayer(
+ self.OUTPUT, self.tr("Selected (stratified random)")
+ )
+ )
def name(self):
- return 'randomselectionwithinsubsets'
+ return "randomselectionwithinsubsets"
def displayName(self):
- return self.tr('Random selection within subsets')
+ return self.tr("Random selection within subsets")
def processAlgorithm(self, parameters, context, feedback):
layer = self.parameterAsVectorLayer(parameters, self.INPUT, context)
@@ -102,13 +127,19 @@ def processAlgorithm(self, parameters, context, feedback):
if method == 0:
if value > featureCount:
raise QgsProcessingException(
- self.tr('Selected number is greater that feature count. '
- 'Choose lesser value and try again.'))
+ self.tr(
+ "Selected number is greater that feature count. "
+ "Choose lesser value and try again."
+ )
+ )
else:
if value > 100:
raise QgsProcessingException(
- self.tr("Percentage can't be greater than 100. Set a "
- "different value and try again."))
+ self.tr(
+ "Percentage can't be greater than 100. Set a "
+ "different value and try again."
+ )
+ )
value = value / 100.0
total = 100.0 / (featureCount * len(unique)) if featureCount else 1
@@ -116,7 +147,11 @@ def processAlgorithm(self, parameters, context, feedback):
if len(unique) != featureCount:
classes = defaultdict(list)
- features = layer.getFeatures(QgsFeatureRequest().setFlags(QgsFeatureRequest.Flag.NoGeometry).setSubsetOfAttributes([index]))
+ features = layer.getFeatures(
+ QgsFeatureRequest()
+ .setFlags(QgsFeatureRequest.Flag.NoGeometry)
+ .setSubsetOfAttributes([index])
+ )
for i, feature in enumerate(features):
if feedback.isCanceled():
@@ -133,11 +168,17 @@ def processAlgorithm(self, parameters, context, feedback):
selValue = value if method != 1 else int(round(value * len(subset), 0))
if selValue > len(subset):
selValue = len(subset)
- feedback.reportError(self.tr('Subset "{}" is smaller than requested number of features.').format(k))
+ feedback.reportError(
+ self.tr(
+ 'Subset "{}" is smaller than requested number of features.'
+ ).format(k)
+ )
selran.extend(random.sample(subset, selValue))
layer.selectByIds(selran)
else:
- layer.selectByIds(list(range(featureCount))) # FIXME: implies continuous feature ids
+ layer.selectByIds(
+ list(range(featureCount))
+ ) # FIXME: implies continuous feature ids
return {self.OUTPUT: parameters[self.INPUT]}
diff --git a/python/plugins/processing/algs/qgis/RasterCalculator.py b/python/plugins/processing/algs/qgis/RasterCalculator.py
index 38f414bf3205..6dcf76f8c273 100644
--- a/python/plugins/processing/algs/qgis/RasterCalculator.py
+++ b/python/plugins/processing/algs/qgis/RasterCalculator.py
@@ -15,45 +15,47 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'November 2016'
-__copyright__ = '(C) 2016, Victor Olaya'
+__author__ = "Victor Olaya"
+__date__ = "November 2016"
+__copyright__ = "(C) 2016, Victor Olaya"
import os
import math
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
from processing.algs.gdal.GdalUtils import GdalUtils
-from qgis.core import (QgsProcessing,
- QgsProcessingAlgorithm,
- QgsProcessingException,
- QgsProcessingUtils,
- QgsProcessingParameterCrs,
- QgsProcessingParameterMultipleLayers,
- QgsProcessingParameterNumber,
- QgsProcessingParameterExtent,
- QgsProcessingParameterRasterDestination,
- QgsProcessingParameterRasterLayer,
- QgsProcessingOutputRasterLayer,
- QgsProcessingParameterString,
- QgsCoordinateTransform,
- QgsMapLayer)
+from qgis.core import (
+ QgsProcessing,
+ QgsProcessingAlgorithm,
+ QgsProcessingException,
+ QgsProcessingUtils,
+ QgsProcessingParameterCrs,
+ QgsProcessingParameterMultipleLayers,
+ QgsProcessingParameterNumber,
+ QgsProcessingParameterExtent,
+ QgsProcessingParameterRasterDestination,
+ QgsProcessingParameterRasterLayer,
+ QgsProcessingOutputRasterLayer,
+ QgsProcessingParameterString,
+ QgsCoordinateTransform,
+ QgsMapLayer,
+)
from qgis.PyQt.QtCore import QObject
from qgis.analysis import QgsRasterCalculator, QgsRasterCalculatorEntry
class RasterCalculator(QgisAlgorithm):
- LAYERS = 'LAYERS'
- EXTENT = 'EXTENT'
- CELLSIZE = 'CELLSIZE'
- EXPRESSION = 'EXPRESSION'
- CRS = 'CRS'
- OUTPUT = 'OUTPUT'
+ LAYERS = "LAYERS"
+ EXTENT = "EXTENT"
+ CELLSIZE = "CELLSIZE"
+ EXPRESSION = "EXPRESSION"
+ CRS = "CRS"
+ OUTPUT = "OUTPUT"
def group(self):
- return self.tr('Raster analysis')
+ return self.tr("Raster analysis")
def groupId(self):
- return 'rasteranalysis'
+ return "rasteranalysis"
def __init__(self):
super().__init__()
@@ -61,42 +63,67 @@ def __init__(self):
def initAlgorithm(self, config=None):
class ParameterRasterCalculatorExpression(QgsProcessingParameterString):
- def __init__(self, name='', description='', multiLine=False):
+ def __init__(self, name="", description="", multiLine=False):
super().__init__(name, description, multiLine=multiLine)
- self.setMetadata({
- 'widget_wrapper': 'processing.algs.qgis.ui.RasterCalculatorWidgets.ExpressionWidgetWrapper'
- })
+ self.setMetadata(
+ {
+ "widget_wrapper": "processing.algs.qgis.ui.RasterCalculatorWidgets.ExpressionWidgetWrapper"
+ }
+ )
def type(self):
- return 'raster_calc_expression'
+ return "raster_calc_expression"
def clone(self):
- return ParameterRasterCalculatorExpression(self.name(), self.description(), self.multiLine())
-
- self.addParameter(ParameterRasterCalculatorExpression(self.EXPRESSION, self.tr('Expression'),
- multiLine=True))
- self.addParameter(QgsProcessingParameterMultipleLayers(self.LAYERS,
- self.tr('Reference layer(s) (used for automated extent, cellsize, and CRS)'),
- layerType=QgsProcessing.SourceType.TypeRaster,
- optional=True))
- self.addParameter(QgsProcessingParameterNumber(self.CELLSIZE,
- self.tr('Cell size (use 0 or empty to set it automatically)'),
- type=QgsProcessingParameterNumber.Type.Double,
- minValue=0.0, defaultValue=0.0, optional=True))
- self.addParameter(QgsProcessingParameterExtent(self.EXTENT,
- self.tr('Output extent'),
- optional=True))
- self.addParameter(QgsProcessingParameterCrs(self.CRS, 'Output CRS', optional=True))
- self.addParameter(QgsProcessingParameterRasterDestination(self.OUTPUT, self.tr('Output')))
+ return ParameterRasterCalculatorExpression(
+ self.name(), self.description(), self.multiLine()
+ )
+
+ self.addParameter(
+ ParameterRasterCalculatorExpression(
+ self.EXPRESSION, self.tr("Expression"), multiLine=True
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterMultipleLayers(
+ self.LAYERS,
+ self.tr(
+ "Reference layer(s) (used for automated extent, cellsize, and CRS)"
+ ),
+ layerType=QgsProcessing.SourceType.TypeRaster,
+ optional=True,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterNumber(
+ self.CELLSIZE,
+ self.tr("Cell size (use 0 or empty to set it automatically)"),
+ type=QgsProcessingParameterNumber.Type.Double,
+ minValue=0.0,
+ defaultValue=0.0,
+ optional=True,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterExtent(
+ self.EXTENT, self.tr("Output extent"), optional=True
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterCrs(self.CRS, "Output CRS", optional=True)
+ )
+ self.addParameter(
+ QgsProcessingParameterRasterDestination(self.OUTPUT, self.tr("Output"))
+ )
def flags(self):
return super().flags() | QgsProcessingAlgorithm.Flag.FlagDeprecated
def name(self):
- return 'rastercalculator'
+ return "rastercalculator"
def displayName(self):
- return self.tr('Raster calculator')
+ return self.tr("Raster calculator")
def processAlgorithm(self, parameters, context, feedback):
expression = self.parameterAsString(parameters, self.EXPRESSION, context)
@@ -109,18 +136,24 @@ def processAlgorithm(self, parameters, context, feedback):
crs = self.parameterAsCrs(parameters, self.CRS, context)
if crs is None or not crs.isValid():
if not layers:
- raise QgsProcessingException(self.tr("No reference layer selected nor CRS provided"))
+ raise QgsProcessingException(
+ self.tr("No reference layer selected nor CRS provided")
+ )
else:
crs = list(layersDict.values())[0].crs()
bbox = self.parameterAsExtent(parameters, self.EXTENT, context)
if bbox.isNull() and not layers:
- raise QgsProcessingException(self.tr("No reference layer selected nor extent box provided"))
+ raise QgsProcessingException(
+ self.tr("No reference layer selected nor extent box provided")
+ )
if not bbox.isNull():
bboxCrs = self.parameterAsExtentCrs(parameters, self.EXTENT, context)
if bboxCrs != crs:
- transform = QgsCoordinateTransform(bboxCrs, crs, context.transformContext())
+ transform = QgsCoordinateTransform(
+ bboxCrs, crs, context.transformContext()
+ )
bbox = transform.transformBoundingBox(bbox)
if bbox.isNull() and layers:
@@ -128,12 +161,16 @@ def processAlgorithm(self, parameters, context, feedback):
cellsize = self.parameterAsDouble(parameters, self.CELLSIZE, context)
if cellsize == 0 and not layers:
- raise QgsProcessingException(self.tr("No reference layer selected nor cellsize value provided"))
+ raise QgsProcessingException(
+ self.tr("No reference layer selected nor cellsize value provided")
+ )
def _cellsize(layer):
ext = layer.extent()
if layer.crs() != crs:
- transform = QgsCoordinateTransform(layer.crs(), crs, context.transformContext())
+ transform = QgsCoordinateTransform(
+ layer.crs(), crs, context.transformContext()
+ )
ext = transform.transformBoundingBox(ext)
return (ext.xMaximum() - ext.xMinimum()) / layer.width()
@@ -141,14 +178,18 @@ def _cellsize(layer):
cellsize = min([_cellsize(lyr) for lyr in layersDict.values()])
# check for layers available in the model
- layersDictCopy = layersDict.copy() # need a shallow copy because next calls invalidate iterator
+ layersDictCopy = (
+ layersDict.copy()
+ ) # need a shallow copy because next calls invalidate iterator
for lyr in layersDictCopy.values():
expression = self.mappedNameToLayer(lyr, expression, layersDict, context)
# check for layers available in the project
if context.project():
for lyr in QgsProcessingUtils.compatibleRasterLayers(context.project()):
- expression = self.mappedNameToLayer(lyr, expression, layersDict, context)
+ expression = self.mappedNameToLayer(
+ lyr, expression, layersDict, context
+ )
# create the list of layers to be passed as inputs to RasterCalculaltor
# at this phase expression has been modified to match available layers
@@ -156,7 +197,7 @@ def _cellsize(layer):
entries = []
for name, lyr in layersDict.items():
for n in range(lyr.bandCount()):
- ref = f'{name:s}@{n + 1:d}'
+ ref = f"{name:s}@{n + 1:d}"
if ref in expression:
entry = QgsRasterCalculatorEntry()
@@ -176,26 +217,30 @@ def _cellsize(layer):
height = round((bbox.yMaximum() - bbox.yMinimum()) / cellsize)
driverName = GdalUtils.getFormatShortNameFromFilename(output)
- calc = QgsRasterCalculator(expression,
- output,
- driverName,
- bbox,
- crs,
- width,
- height,
- entries,
- context.transformContext())
+ calc = QgsRasterCalculator(
+ expression,
+ output,
+ driverName,
+ bbox,
+ crs,
+ width,
+ height,
+ entries,
+ context.transformContext(),
+ )
res = calc.processCalculation(feedback)
if res == QgsRasterCalculator.Result.ParserError:
raise QgsProcessingException(self.tr("Error parsing formula"))
elif res == QgsRasterCalculator.Result.CalculationError:
- raise QgsProcessingException(self.tr("An error occurred while performing the calculation"))
+ raise QgsProcessingException(
+ self.tr("An error occurred while performing the calculation")
+ )
return {self.OUTPUT: output}
def mappedNameToLayer(self, lyr, expression, layersDict, context):
- '''Try to identify if a real layer is mapped in the expression with a symbolic name.'''
+ """Try to identify if a real layer is mapped in the expression with a symbolic name."""
nameToMap = lyr.source()
@@ -224,10 +269,15 @@ def mappedNameToLayer(self, lyr, expression, layersDict, context):
layerInContext = expContextAlgInputsScope.variable(varName)
- if not isinstance(layerInContext, str) and not isinstance(layerInContext, QgsMapLayer):
+ if not isinstance(layerInContext, str) and not isinstance(
+ layerInContext, QgsMapLayer
+ ):
continue
- if isinstance(layerInContext, QgsMapLayer) and nameToMap not in layerInContext.source():
+ if (
+ isinstance(layerInContext, QgsMapLayer)
+ and nameToMap not in layerInContext.source()
+ ):
continue
varDescription = expContextAlgInputsScope.description(varName)
@@ -247,12 +297,14 @@ def mappedNameToLayer(self, lyr, expression, layersDict, context):
# HAVE to use the same translated string as in
# https://github.com/qgis/QGIS/blob/master/src/core/processing/models/qgsprocessingmodelalgorithm.cpp#L516
translatedDesc = self.tr("Output '%1' from algorithm '%2'")
- elementZero = translatedDesc.split(" ")[0] # For english the string result should be "Output"
+ elementZero = translatedDesc.split(" ")[
+ 0
+ ] # For english the string result should be "Output"
elements = varDescription.split(" ")
if len(elements) > 1 and elements[0] == elementZero:
# remove heading QObject.tr"Output ") string. Note adding a space at the end of elementZero!
- varDescription = varDescription[len(elementZero) + 1:]
+ varDescription = varDescription[len(elementZero) + 1 :]
# check if cleaned varDescription is present in the expression
# if not skip it
diff --git a/python/plugins/processing/algs/qgis/RasterLayerHistogram.py b/python/plugins/processing/algs/qgis/RasterLayerHistogram.py
index df63eb28e143..92c787e3dde4 100644
--- a/python/plugins/processing/algs/qgis/RasterLayerHistogram.py
+++ b/python/plugins/processing/algs/qgis/RasterLayerHistogram.py
@@ -15,17 +15,19 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'January 2013'
-__copyright__ = '(C) 2013, Victor Olaya'
+__author__ = "Victor Olaya"
+__date__ = "January 2013"
+__copyright__ = "(C) 2013, Victor Olaya"
import warnings
-from qgis.core import (QgsProcessingParameterRasterLayer,
- QgsProcessingParameterBand,
- QgsProcessingParameterNumber,
- QgsProcessingParameterFileDestination,
- QgsProcessingException)
+from qgis.core import (
+ QgsProcessingParameterRasterLayer,
+ QgsProcessingParameterBand,
+ QgsProcessingParameterNumber,
+ QgsProcessingParameterFileDestination,
+ QgsProcessingException,
+)
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
from processing.tools import raster
@@ -34,37 +36,44 @@
class RasterLayerHistogram(QgisAlgorithm):
- INPUT = 'INPUT'
- BINS = 'BINS'
- OUTPUT = 'OUTPUT'
- BAND = 'BAND'
+ INPUT = "INPUT"
+ BINS = "BINS"
+ OUTPUT = "OUTPUT"
+ BAND = "BAND"
def group(self):
- return self.tr('Plots')
+ return self.tr("Plots")
def groupId(self):
- return 'plots'
+ return "plots"
def __init__(self):
super().__init__()
def initAlgorithm(self, config=None):
- self.addParameter(QgsProcessingParameterRasterLayer(self.INPUT,
- self.tr('Input layer')))
- self.addParameter(QgsProcessingParameterBand(self.BAND,
- self.tr('Band number'),
- 1,
- self.INPUT))
- self.addParameter(QgsProcessingParameterNumber(self.BINS,
- self.tr('number of bins'), minValue=2, defaultValue=10))
-
- self.addParameter(QgsProcessingParameterFileDestination(self.OUTPUT, self.tr('Histogram'), self.tr('HTML files (*.html)')))
+ self.addParameter(
+ QgsProcessingParameterRasterLayer(self.INPUT, self.tr("Input layer"))
+ )
+ self.addParameter(
+ QgsProcessingParameterBand(self.BAND, self.tr("Band number"), 1, self.INPUT)
+ )
+ self.addParameter(
+ QgsProcessingParameterNumber(
+ self.BINS, self.tr("number of bins"), minValue=2, defaultValue=10
+ )
+ )
+
+ self.addParameter(
+ QgsProcessingParameterFileDestination(
+ self.OUTPUT, self.tr("Histogram"), self.tr("HTML files (*.html)")
+ )
+ )
def name(self):
- return 'rasterlayerhistogram'
+ return "rasterlayerhistogram"
def displayName(self):
- return self.tr('Raster layer histogram')
+ return self.tr("Raster layer histogram")
def processAlgorithm(self, parameters, context, feedback):
try:
@@ -75,7 +84,12 @@ def processAlgorithm(self, parameters, context, feedback):
import plotly as plt
import plotly.graph_objs as go
except ImportError:
- raise QgsProcessingException(QCoreApplication.translate('RasterLayerHistogram', 'This algorithm requires the Python “plotly” library. Please install this library and try again.'))
+ raise QgsProcessingException(
+ QCoreApplication.translate(
+ "RasterLayerHistogram",
+ "This algorithm requires the Python “plotly” library. Please install this library and try again.",
+ )
+ )
layer = self.parameterAsRasterLayer(parameters, self.INPUT, context)
band = self.parameterAsInt(parameters, self.BAND, context)
@@ -86,13 +100,8 @@ def processAlgorithm(self, parameters, context, feedback):
# ALERT: this is potentially blocking if the layer is too big
values = raster.scanraster(layer, feedback, band)
- valueslist = [
- v
- for v in values
- if v is not None
- ]
- data = [go.Histogram(x=valueslist,
- nbinsx=nbins)]
+ valueslist = [v for v in values if v is not None]
+ data = [go.Histogram(x=valueslist, nbinsx=nbins)]
plt.offline.plot(data, filename=output, auto_open=False)
return {self.OUTPUT: output}
diff --git a/python/plugins/processing/algs/qgis/RectanglesOvalsDiamondsVariable.py b/python/plugins/processing/algs/qgis/RectanglesOvalsDiamondsVariable.py
index a209d4ce7005..68b420394d0b 100644
--- a/python/plugins/processing/algs/qgis/RectanglesOvalsDiamondsVariable.py
+++ b/python/plugins/processing/algs/qgis/RectanglesOvalsDiamondsVariable.py
@@ -15,45 +15,47 @@
***************************************************************************
"""
-__author__ = 'Alexander Bruy'
-__date__ = 'August 2012'
-__copyright__ = '(C) 2012, Victor Olaya'
+__author__ = "Alexander Bruy"
+__date__ = "August 2012"
+__copyright__ = "(C) 2012, Victor Olaya"
import math
from qgis.PyQt.QtCore import QCoreApplication
-from qgis.core import (NULL,
- QgsWkbTypes,
- QgsFeature,
- QgsFeatureSink,
- QgsGeometry,
- QgsPointXY,
- QgsProcessing,
- QgsProcessingException,
- QgsProcessingAlgorithm,
- QgsProcessingParameterField,
- QgsProcessingParameterFeatureSource,
- QgsProcessingParameterEnum,
- QgsProcessingParameterNumber,
- QgsProcessingParameterFeatureSink)
+from qgis.core import (
+ NULL,
+ QgsWkbTypes,
+ QgsFeature,
+ QgsFeatureSink,
+ QgsGeometry,
+ QgsPointXY,
+ QgsProcessing,
+ QgsProcessingException,
+ QgsProcessingAlgorithm,
+ QgsProcessingParameterField,
+ QgsProcessingParameterFeatureSource,
+ QgsProcessingParameterEnum,
+ QgsProcessingParameterNumber,
+ QgsProcessingParameterFeatureSink,
+)
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
class RectanglesOvalsDiamondsVariable(QgisAlgorithm):
- INPUT = 'INPUT'
- SHAPE = 'SHAPE'
- WIDTH = 'WIDTH'
- HEIGHT = 'HEIGHT'
- ROTATION = 'ROTATION'
- SEGMENTS = 'SEGMENTS'
- OUTPUT = 'OUTPUT'
+ INPUT = "INPUT"
+ SHAPE = "SHAPE"
+ WIDTH = "WIDTH"
+ HEIGHT = "HEIGHT"
+ ROTATION = "ROTATION"
+ SEGMENTS = "SEGMENTS"
+ OUTPUT = "OUTPUT"
def group(self):
- return self.tr('Vector geometry')
+ return self.tr("Vector geometry")
def groupId(self):
- return 'vectorgeometry'
+ return "vectorgeometry"
def __init__(self):
super().__init__()
@@ -62,47 +64,76 @@ def flags(self):
return super().flags() | QgsProcessingAlgorithm.Flag.FlagDeprecated
def initAlgorithm(self, config=None):
- self.shapes = [self.tr('Rectangles'), self.tr('Diamonds'), self.tr('Ovals')]
-
- self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT,
- self.tr('Input layer'),
- [QgsProcessing.SourceType.TypeVectorPoint]))
-
- self.addParameter(QgsProcessingParameterEnum(self.SHAPE,
- self.tr('Buffer shape'), options=self.shapes))
-
- self.addParameter(QgsProcessingParameterField(self.WIDTH,
- self.tr('Width field'),
- parentLayerParameterName=self.INPUT,
- type=QgsProcessingParameterField.DataType.Numeric))
- self.addParameter(QgsProcessingParameterField(self.HEIGHT,
- self.tr('Height field'),
- parentLayerParameterName=self.INPUT,
- type=QgsProcessingParameterField.DataType.Numeric))
- self.addParameter(QgsProcessingParameterField(self.ROTATION,
- self.tr('Rotation field'),
- parentLayerParameterName=self.INPUT,
- type=QgsProcessingParameterField.DataType.Numeric,
- optional=True))
- self.addParameter(QgsProcessingParameterNumber(self.SEGMENTS,
- self.tr('Number of segments'),
- minValue=1,
- defaultValue=36))
-
- self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT,
- self.tr('Output'),
- type=QgsProcessing.SourceType.TypeVectorPolygon))
+ self.shapes = [self.tr("Rectangles"), self.tr("Diamonds"), self.tr("Ovals")]
+
+ self.addParameter(
+ QgsProcessingParameterFeatureSource(
+ self.INPUT,
+ self.tr("Input layer"),
+ [QgsProcessing.SourceType.TypeVectorPoint],
+ )
+ )
+
+ self.addParameter(
+ QgsProcessingParameterEnum(
+ self.SHAPE, self.tr("Buffer shape"), options=self.shapes
+ )
+ )
+
+ self.addParameter(
+ QgsProcessingParameterField(
+ self.WIDTH,
+ self.tr("Width field"),
+ parentLayerParameterName=self.INPUT,
+ type=QgsProcessingParameterField.DataType.Numeric,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterField(
+ self.HEIGHT,
+ self.tr("Height field"),
+ parentLayerParameterName=self.INPUT,
+ type=QgsProcessingParameterField.DataType.Numeric,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterField(
+ self.ROTATION,
+ self.tr("Rotation field"),
+ parentLayerParameterName=self.INPUT,
+ type=QgsProcessingParameterField.DataType.Numeric,
+ optional=True,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterNumber(
+ self.SEGMENTS,
+ self.tr("Number of segments"),
+ minValue=1,
+ defaultValue=36,
+ )
+ )
+
+ self.addParameter(
+ QgsProcessingParameterFeatureSink(
+ self.OUTPUT,
+ self.tr("Output"),
+ type=QgsProcessing.SourceType.TypeVectorPolygon,
+ )
+ )
def name(self):
- return 'rectanglesovalsdiamondsvariable'
+ return "rectanglesovalsdiamondsvariable"
def displayName(self):
- return self.tr('Rectangles, ovals, diamonds (variable)')
+ return self.tr("Rectangles, ovals, diamonds (variable)")
def processAlgorithm(self, parameters, context, feedback):
source = self.parameterAsSource(parameters, self.INPUT, context)
if source is None:
- raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT))
+ raise QgsProcessingException(
+ self.invalidSourceError(parameters, self.INPUT)
+ )
shape = self.parameterAsEnum(parameters, self.SHAPE, context)
@@ -111,8 +142,14 @@ def processAlgorithm(self, parameters, context, feedback):
rotation_field = self.parameterAsString(parameters, self.ROTATION, context)
segments = self.parameterAsInt(parameters, self.SEGMENTS, context)
- (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
- source.fields(), QgsWkbTypes.Type.Polygon, source.sourceCrs())
+ (sink, dest_id) = self.parameterAsSink(
+ parameters,
+ self.OUTPUT,
+ context,
+ source.fields(),
+ QgsWkbTypes.Type.Polygon,
+ source.sourceCrs(),
+ )
if sink is None:
raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT))
@@ -148,14 +185,20 @@ def rectangles(self, sink, source, width, height, rotation, feedback):
angle = feat[rotation]
# block 0/NULL width or height, but allow 0 as angle value
if not w or not h:
- feedback.pushInfo(QCoreApplication.translate('RectanglesOvalsDiamondsVariable', 'Feature {} has empty '
- 'width or height. '
- 'Skipping…').format(feat.id()))
+ feedback.pushInfo(
+ QCoreApplication.translate(
+ "RectanglesOvalsDiamondsVariable",
+ "Feature {} has empty " "width or height. " "Skipping…",
+ ).format(feat.id())
+ )
continue
if angle is NULL:
- feedback.pushInfo(QCoreApplication.translate('RectanglesOvalsDiamondsVariable', 'Feature {} has empty '
- 'angle. '
- 'Skipping…').format(feat.id()))
+ feedback.pushInfo(
+ QCoreApplication.translate(
+ "RectanglesOvalsDiamondsVariable",
+ "Feature {} has empty " "angle. " "Skipping…",
+ ).format(feat.id())
+ )
continue
xOffset = w / 2.0
@@ -165,9 +208,21 @@ def rectangles(self, sink, source, width, height, rotation, feedback):
point = feat.geometry().asPoint()
x = point.x()
y = point.y()
- points = [(-xOffset, -yOffset), (-xOffset, yOffset), (xOffset, yOffset), (xOffset, -yOffset)]
- polygon = [[QgsPointXY(i[0] * math.cos(phi) + i[1] * math.sin(phi) + x,
- -i[0] * math.sin(phi) + i[1] * math.cos(phi) + y) for i in points]]
+ points = [
+ (-xOffset, -yOffset),
+ (-xOffset, yOffset),
+ (xOffset, yOffset),
+ (xOffset, -yOffset),
+ ]
+ polygon = [
+ [
+ QgsPointXY(
+ i[0] * math.cos(phi) + i[1] * math.sin(phi) + x,
+ -i[0] * math.sin(phi) + i[1] * math.cos(phi) + y,
+ )
+ for i in points
+ ]
+ ]
ft.setGeometry(QgsGeometry.fromPolygonXY(polygon))
ft.setAttributes(feat.attributes())
@@ -185,9 +240,12 @@ def rectangles(self, sink, source, width, height, rotation, feedback):
w = feat[width]
h = feat[height]
if not w or not h:
- feedback.pushInfo(QCoreApplication.translate('RectanglesOvalsDiamondsVariable', 'Feature {} has empty '
- 'width or height. '
- 'Skipping…').format(feat.id()))
+ feedback.pushInfo(
+ QCoreApplication.translate(
+ "RectanglesOvalsDiamondsVariable",
+ "Feature {} has empty " "width or height. " "Skipping…",
+ ).format(feat.id())
+ )
continue
xOffset = w / 2.0
@@ -196,7 +254,12 @@ def rectangles(self, sink, source, width, height, rotation, feedback):
point = feat.geometry().asPoint()
x = point.x()
y = point.y()
- points = [(-xOffset, -yOffset), (-xOffset, yOffset), (xOffset, yOffset), (xOffset, -yOffset)]
+ points = [
+ (-xOffset, -yOffset),
+ (-xOffset, yOffset),
+ (xOffset, yOffset),
+ (xOffset, -yOffset),
+ ]
polygon = [[QgsPointXY(i[0] + x, i[1] + y) for i in points]]
ft.setGeometry(QgsGeometry.fromPolygonXY(polygon))
@@ -223,14 +286,20 @@ def diamonds(self, sink, source, width, height, rotation, feedback):
angle = feat[rotation]
# block 0/NULL width or height, but allow 0 as angle value
if not w or not h:
- feedback.pushInfo(QCoreApplication.translate('RectanglesOvalsDiamondsVariable', 'Feature {} has empty '
- 'width or height. '
- 'Skipping…').format(feat.id()))
+ feedback.pushInfo(
+ QCoreApplication.translate(
+ "RectanglesOvalsDiamondsVariable",
+ "Feature {} has empty " "width or height. " "Skipping…",
+ ).format(feat.id())
+ )
continue
if angle is NULL:
- feedback.pushInfo(QCoreApplication.translate('RectanglesOvalsDiamondsVariable', 'Feature {} has empty '
- 'angle. '
- 'Skipping…').format(feat.id()))
+ feedback.pushInfo(
+ QCoreApplication.translate(
+ "RectanglesOvalsDiamondsVariable",
+ "Feature {} has empty " "angle. " "Skipping…",
+ ).format(feat.id())
+ )
continue
xOffset = w / 2.0
@@ -240,9 +309,21 @@ def diamonds(self, sink, source, width, height, rotation, feedback):
point = feat.geometry().asPoint()
x = point.x()
y = point.y()
- points = [(0.0, -yOffset), (-xOffset, 0.0), (0.0, yOffset), (xOffset, 0.0)]
- polygon = [[QgsPointXY(i[0] * math.cos(phi) + i[1] * math.sin(phi) + x,
- -i[0] * math.sin(phi) + i[1] * math.cos(phi) + y) for i in points]]
+ points = [
+ (0.0, -yOffset),
+ (-xOffset, 0.0),
+ (0.0, yOffset),
+ (xOffset, 0.0),
+ ]
+ polygon = [
+ [
+ QgsPointXY(
+ i[0] * math.cos(phi) + i[1] * math.sin(phi) + x,
+ -i[0] * math.sin(phi) + i[1] * math.cos(phi) + y,
+ )
+ for i in points
+ ]
+ ]
ft.setGeometry(QgsGeometry.fromPolygonXY(polygon))
ft.setAttributes(feat.attributes())
@@ -259,9 +340,12 @@ def diamonds(self, sink, source, width, height, rotation, feedback):
w = feat[width]
h = feat[height]
if not w or not h:
- feedback.pushInfo(QCoreApplication.translate('RectanglesOvalsDiamondsVariable', 'Feature {} has empty '
- 'width or height. '
- 'Skipping…').format(feat.id()))
+ feedback.pushInfo(
+ QCoreApplication.translate(
+ "RectanglesOvalsDiamondsVariable",
+ "Feature {} has empty " "width or height. " "Skipping…",
+ ).format(feat.id())
+ )
continue
xOffset = w / 2.0
@@ -270,7 +354,12 @@ def diamonds(self, sink, source, width, height, rotation, feedback):
point = feat.geometry().asPoint()
x = point.x()
y = point.y()
- points = [(0.0, -yOffset), (-xOffset, 0.0), (0.0, yOffset), (xOffset, 0.0)]
+ points = [
+ (0.0, -yOffset),
+ (-xOffset, 0.0),
+ (0.0, yOffset),
+ (xOffset, 0.0),
+ ]
polygon = [[QgsPointXY(i[0] + x, i[1] + y) for i in points]]
ft.setGeometry(QgsGeometry.fromPolygonXY(polygon))
@@ -296,14 +385,20 @@ def ovals(self, sink, source, width, height, rotation, segments, feedback):
angle = feat[rotation]
# block 0/NULL width or height, but allow 0 as angle value
if not w or not h:
- feedback.pushInfo(QCoreApplication.translate('RectanglesOvalsDiamondsVariable', 'Feature {} has empty '
- 'width or height. '
- 'Skipping…').format(feat.id()))
+ feedback.pushInfo(
+ QCoreApplication.translate(
+ "RectanglesOvalsDiamondsVariable",
+ "Feature {} has empty " "width or height. " "Skipping…",
+ ).format(feat.id())
+ )
continue
if angle == NULL:
- feedback.pushInfo(QCoreApplication.translate('RectanglesOvalsDiamondsVariable', 'Feature {} has empty '
- 'angle. '
- 'Skipping…').format(feat.id()))
+ feedback.pushInfo(
+ QCoreApplication.translate(
+ "RectanglesOvalsDiamondsVariable",
+ "Feature {} has empty " "angle. " "Skipping…",
+ ).format(feat.id())
+ )
continue
xOffset = w / 2.0
@@ -318,8 +413,15 @@ def ovals(self, sink, source, width, height, rotation, segments, feedback):
for t in [(2 * math.pi) / segments * i for i in range(segments)]
]
- polygon = [[QgsPointXY(i[0] * math.cos(phi) + i[1] * math.sin(phi) + x,
- -i[0] * math.sin(phi) + i[1] * math.cos(phi) + y) for i in points]]
+ polygon = [
+ [
+ QgsPointXY(
+ i[0] * math.cos(phi) + i[1] * math.sin(phi) + x,
+ -i[0] * math.sin(phi) + i[1] * math.cos(phi) + y,
+ )
+ for i in points
+ ]
+ ]
ft.setGeometry(QgsGeometry.fromPolygonXY(polygon))
ft.setAttributes(feat.attributes())
@@ -336,9 +438,12 @@ def ovals(self, sink, source, width, height, rotation, segments, feedback):
w = feat[width]
h = feat[height]
if not w or not h:
- feedback.pushInfo(QCoreApplication.translate('RectanglesOvalsDiamondsVariable', 'Feature {} has empty '
- 'width or height. '
- 'Skipping…').format(feat.id()))
+ feedback.pushInfo(
+ QCoreApplication.translate(
+ "RectanglesOvalsDiamondsVariable",
+ "Feature {} has empty " "width or height. " "Skipping…",
+ ).format(feat.id())
+ )
continue
xOffset = w / 2.0
diff --git a/python/plugins/processing/algs/qgis/RegularPoints.py b/python/plugins/processing/algs/qgis/RegularPoints.py
index 738dcd624381..672b1d745fbd 100644
--- a/python/plugins/processing/algs/qgis/RegularPoints.py
+++ b/python/plugins/processing/algs/qgis/RegularPoints.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Alexander Bruy'
-__date__ = 'September 2014'
-__copyright__ = '(C) 2014, Alexander Bruy'
+__author__ = "Alexander Bruy"
+__date__ = "September 2014"
+__copyright__ = "(C) 2014, Alexander Bruy"
import os
from random import seed, uniform
@@ -25,21 +25,23 @@
from qgis.PyQt.QtGui import QIcon
from qgis.PyQt.QtCore import QMetaType
-from qgis.core import (QgsApplication,
- QgsFields,
- QgsFeatureSink,
- QgsField,
- QgsFeature,
- QgsWkbTypes,
- QgsGeometry,
- QgsPoint,
- QgsProcessing,
- QgsProcessingException,
- QgsProcessingParameterDistance,
- QgsProcessingParameterExtent,
- QgsProcessingParameterBoolean,
- QgsProcessingParameterCrs,
- QgsProcessingParameterFeatureSink)
+from qgis.core import (
+ QgsApplication,
+ QgsFields,
+ QgsFeatureSink,
+ QgsField,
+ QgsFeature,
+ QgsWkbTypes,
+ QgsGeometry,
+ QgsPoint,
+ QgsProcessing,
+ QgsProcessingException,
+ QgsProcessingParameterDistance,
+ QgsProcessingParameterExtent,
+ QgsProcessingParameterBoolean,
+ QgsProcessingParameterCrs,
+ QgsProcessingParameterFeatureSink,
+)
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
@@ -47,13 +49,13 @@
class RegularPoints(QgisAlgorithm):
- EXTENT = 'EXTENT'
- SPACING = 'SPACING'
- INSET = 'INSET'
- RANDOMIZE = 'RANDOMIZE'
- IS_SPACING = 'IS_SPACING'
- OUTPUT = 'OUTPUT'
- CRS = 'CRS'
+ EXTENT = "EXTENT"
+ SPACING = "SPACING"
+ INSET = "INSET"
+ RANDOMIZE = "RANDOMIZE"
+ IS_SPACING = "IS_SPACING"
+ OUTPUT = "OUTPUT"
+ CRS = "CRS"
def icon(self):
return QgsApplication.getThemeIcon("/algorithms/mAlgorithmRegularPoints.svg")
@@ -62,35 +64,69 @@ def svgIconPath(self):
return QgsApplication.iconPath("/algorithms/mAlgorithmRegularPoints.svg")
def group(self):
- return self.tr('Vector creation')
+ return self.tr("Vector creation")
def groupId(self):
- return 'vectorcreation'
+ return "vectorcreation"
def __init__(self):
super().__init__()
def initAlgorithm(self, config=None):
- self.addParameter(QgsProcessingParameterExtent(self.EXTENT,
- self.tr('Input extent'), optional=False))
- self.addParameter(QgsProcessingParameterDistance(self.SPACING,
- self.tr('Point spacing/count'), 100, self.CRS, False, 0.000001))
- self.addParameter(QgsProcessingParameterDistance(self.INSET,
- self.tr('Initial inset from corner (LH side)'), 0.0, self.CRS, False, 0.0))
- self.addParameter(QgsProcessingParameterBoolean(self.RANDOMIZE,
- self.tr('Apply random offset to point spacing'), False))
- self.addParameter(QgsProcessingParameterBoolean(self.IS_SPACING,
- self.tr('Use point spacing'), True))
- self.addParameter(QgsProcessingParameterCrs(self.CRS,
- self.tr('Output layer CRS'), 'ProjectCrs'))
-
- self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Regular points'), QgsProcessing.SourceType.TypeVectorPoint))
+ self.addParameter(
+ QgsProcessingParameterExtent(
+ self.EXTENT, self.tr("Input extent"), optional=False
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterDistance(
+ self.SPACING,
+ self.tr("Point spacing/count"),
+ 100,
+ self.CRS,
+ False,
+ 0.000001,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterDistance(
+ self.INSET,
+ self.tr("Initial inset from corner (LH side)"),
+ 0.0,
+ self.CRS,
+ False,
+ 0.0,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterBoolean(
+ self.RANDOMIZE, self.tr("Apply random offset to point spacing"), False
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterBoolean(
+ self.IS_SPACING, self.tr("Use point spacing"), True
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterCrs(
+ self.CRS, self.tr("Output layer CRS"), "ProjectCrs"
+ )
+ )
+
+ self.addParameter(
+ QgsProcessingParameterFeatureSink(
+ self.OUTPUT,
+ self.tr("Regular points"),
+ QgsProcessing.SourceType.TypeVectorPoint,
+ )
+ )
def name(self):
- return 'regularpoints'
+ return "regularpoints"
def displayName(self):
- return self.tr('Regular points')
+ return self.tr("Regular points")
def processAlgorithm(self, parameters, context, feedback):
spacing = self.parameterAsDouble(parameters, self.SPACING, context)
@@ -101,10 +137,11 @@ def processAlgorithm(self, parameters, context, feedback):
extent = self.parameterAsExtent(parameters, self.EXTENT, context, crs)
fields = QgsFields()
- fields.append(QgsField('id', QMetaType.Type.Int, '', 10, 0))
+ fields.append(QgsField("id", QMetaType.Type.Int, "", 10, 0))
- (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
- fields, QgsWkbTypes.Type.Point, crs)
+ (sink, dest_id) = self.parameterAsSink(
+ parameters, self.OUTPUT, context, fields, QgsWkbTypes.Type.Point, crs
+ )
if sink is None:
raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT))
@@ -137,9 +174,12 @@ def processAlgorithm(self, parameters, context, feedback):
break
if randomize:
- geom = QgsGeometry(QgsPoint(
- uniform(x - (pSpacing / 2.0), x + (pSpacing / 2.0)),
- uniform(y - (pSpacing / 2.0), y + (pSpacing / 2.0))))
+ geom = QgsGeometry(
+ QgsPoint(
+ uniform(x - (pSpacing / 2.0), x + (pSpacing / 2.0)),
+ uniform(y - (pSpacing / 2.0), y + (pSpacing / 2.0)),
+ )
+ )
else:
geom = QgsGeometry(QgsPoint(x, y))
diff --git a/python/plugins/processing/algs/qgis/Relief.py b/python/plugins/processing/algs/qgis/Relief.py
index e20be453631e..b737b058fba4 100644
--- a/python/plugins/processing/algs/qgis/Relief.py
+++ b/python/plugins/processing/algs/qgis/Relief.py
@@ -15,23 +15,25 @@
***************************************************************************
"""
-__author__ = 'Alexander Bruy'
-__date__ = 'December 2016'
-__copyright__ = '(C) 2016, Alexander Bruy'
+__author__ = "Alexander Bruy"
+__date__ = "December 2016"
+__copyright__ = "(C) 2016, Alexander Bruy"
import os
from qgis.PyQt.QtGui import QIcon, QColor
from qgis.analysis import QgsRelief
-from qgis.core import (QgsProcessingParameterDefinition,
- QgsProcessingParameterRasterLayer,
- QgsProcessingParameterNumber,
- QgsProcessingParameterBoolean,
- QgsProcessingParameterRasterDestination,
- QgsProcessingParameterFileDestination,
- QgsRasterFileWriter,
- QgsProcessingException)
+from qgis.core import (
+ QgsProcessingParameterDefinition,
+ QgsProcessingParameterRasterLayer,
+ QgsProcessingParameterNumber,
+ QgsProcessingParameterBoolean,
+ QgsProcessingParameterRasterDestination,
+ QgsProcessingParameterFileDestination,
+ QgsRasterFileWriter,
+ QgsProcessingException,
+)
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
pluginPath = os.path.split(os.path.split(os.path.dirname(__file__))[0])[0]
@@ -39,96 +41,124 @@
class ParameterReliefColors(QgsProcessingParameterDefinition):
- def __init__(self, name='', description='', parent=None, optional=True):
+ def __init__(self, name="", description="", parent=None, optional=True):
super().__init__(name, description, None, optional)
self.parent = parent
- self.setMetadata({'widget_wrapper': 'processing.algs.qgis.ui.ReliefColorsWidget.ReliefColorsWidgetWrapper'})
+ self.setMetadata(
+ {
+ "widget_wrapper": "processing.algs.qgis.ui.ReliefColorsWidget.ReliefColorsWidgetWrapper"
+ }
+ )
def type(self):
- return 'relief_colors'
+ return "relief_colors"
def clone(self):
- return ParameterReliefColors(self.name(), self.description(), self.parent,
- self.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional)
+ return ParameterReliefColors(
+ self.name(),
+ self.description(),
+ self.parent,
+ self.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional,
+ )
@staticmethod
def valueToColors(value):
if value is None:
return None
- if value == '':
+ if value == "":
return None
if isinstance(value, str):
- return value.split(';')
+ return value.split(";")
else:
return ParameterReliefColors.colorsToString(value)
@staticmethod
def colorsToString(colors):
- return ';'.join('{:f}, {:f}, {:d}, {:d}, {:d}'.format(c[0],
- c[1],
- c[2],
- c[3],
- c[4])
- for c in colors)
+ return ";".join(
+ f"{c[0]:f}, {c[1]:f}, {c[2]:d}, {c[3]:d}, {c[4]:d}" for c in colors
+ )
class Relief(QgisAlgorithm):
- INPUT = 'INPUT'
- Z_FACTOR = 'Z_FACTOR'
- AUTO_COLORS = 'AUTO_COLORS'
- COLORS = 'COLORS'
- OUTPUT = 'OUTPUT'
- FREQUENCY_DISTRIBUTION = 'FREQUENCY_DISTRIBUTION'
+ INPUT = "INPUT"
+ Z_FACTOR = "Z_FACTOR"
+ AUTO_COLORS = "AUTO_COLORS"
+ COLORS = "COLORS"
+ OUTPUT = "OUTPUT"
+ FREQUENCY_DISTRIBUTION = "FREQUENCY_DISTRIBUTION"
def icon(self):
- return QIcon(os.path.join(pluginPath, 'images', 'dem.png'))
+ return QIcon(os.path.join(pluginPath, "images", "dem.png"))
def group(self):
- return self.tr('Raster terrain analysis')
+ return self.tr("Raster terrain analysis")
def groupId(self):
- return 'rasterterrainanalysis'
+ return "rasterterrainanalysis"
def __init__(self):
super().__init__()
def initAlgorithm(self, config=None):
- self.addParameter(QgsProcessingParameterRasterLayer(self.INPUT,
- self.tr('Elevation layer')))
- self.addParameter(QgsProcessingParameterNumber(self.Z_FACTOR,
- self.tr('Z factor'), type=QgsProcessingParameterNumber.Type.Double,
- minValue=0.00, defaultValue=1.0))
- self.addParameter(QgsProcessingParameterBoolean(self.AUTO_COLORS,
- self.tr('Generate relief classes automatically'),
- defaultValue=False))
- self.addParameter(ParameterReliefColors(self.COLORS,
- self.tr('Relief colors'),
- self.INPUT,
- True))
- self.addParameter(QgsProcessingParameterRasterDestination(self.OUTPUT,
- self.tr('Relief')))
- self.addParameter(QgsProcessingParameterFileDestination(self.FREQUENCY_DISTRIBUTION,
- self.tr('Frequency distribution'),
- 'CSV files (*.csv)',
- optional=True,
- createByDefault=False))
+ self.addParameter(
+ QgsProcessingParameterRasterLayer(self.INPUT, self.tr("Elevation layer"))
+ )
+ self.addParameter(
+ QgsProcessingParameterNumber(
+ self.Z_FACTOR,
+ self.tr("Z factor"),
+ type=QgsProcessingParameterNumber.Type.Double,
+ minValue=0.00,
+ defaultValue=1.0,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterBoolean(
+ self.AUTO_COLORS,
+ self.tr("Generate relief classes automatically"),
+ defaultValue=False,
+ )
+ )
+ self.addParameter(
+ ParameterReliefColors(
+ self.COLORS, self.tr("Relief colors"), self.INPUT, True
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterRasterDestination(self.OUTPUT, self.tr("Relief"))
+ )
+ self.addParameter(
+ QgsProcessingParameterFileDestination(
+ self.FREQUENCY_DISTRIBUTION,
+ self.tr("Frequency distribution"),
+ "CSV files (*.csv)",
+ optional=True,
+ createByDefault=False,
+ )
+ )
def name(self):
- return 'relief'
+ return "relief"
def displayName(self):
- return self.tr('Relief')
+ return self.tr("Relief")
def processAlgorithm(self, parameters, context, feedback):
- inputFile = self.parameterAsRasterLayer(parameters, self.INPUT, context).source()
+ inputFile = self.parameterAsRasterLayer(
+ parameters, self.INPUT, context
+ ).source()
zFactor = self.parameterAsDouble(parameters, self.Z_FACTOR, context)
automaticColors = self.parameterAsBoolean(parameters, self.AUTO_COLORS, context)
outputFile = self.parameterAsOutputLayer(parameters, self.OUTPUT, context)
- frequencyDistribution = self.parameterAsFileOutput(parameters, self.FREQUENCY_DISTRIBUTION, context)
+ frequencyDistribution = self.parameterAsFileOutput(
+ parameters, self.FREQUENCY_DISTRIBUTION, context
+ )
- outputFormat = QgsRasterFileWriter.driverForExtension(os.path.splitext(outputFile)[1])
+ outputFormat = QgsRasterFileWriter.driverForExtension(
+ os.path.splitext(outputFile)[1]
+ )
relief = QgsRelief(inputFile, outputFile, outputFormat)
@@ -138,14 +168,17 @@ def processAlgorithm(self, parameters, context, feedback):
colors = ParameterReliefColors.valueToColors(parameters[self.COLORS])
if colors is None or len(colors) == 0:
raise QgsProcessingException(
- self.tr('Specify relief colors or activate "Generate relief classes automatically" option.'))
+ self.tr(
+ 'Specify relief colors or activate "Generate relief classes automatically" option.'
+ )
+ )
reliefColors = []
for c in colors:
- v = c.split(',')
- color = QgsRelief.ReliefColor(QColor(int(v[2]), int(v[3]), int(v[4])),
- float(v[0]),
- float(v[1]))
+ v = c.split(",")
+ color = QgsRelief.ReliefColor(
+ QColor(int(v[2]), int(v[3]), int(v[4])), float(v[0]), float(v[1])
+ )
reliefColors.append(color)
relief.setReliefColors(reliefColors)
@@ -154,18 +187,25 @@ def processAlgorithm(self, parameters, context, feedback):
relief.exportFrequencyDistributionToCsv(frequencyDistribution)
res = relief.processRaster(feedback)
if res == 1:
- raise QgsProcessingException(self.tr('Can not open input file.'))
+ raise QgsProcessingException(self.tr("Can not open input file."))
elif res == 2:
- raise QgsProcessingException(self.tr('Can not get GDAL driver for output file.'))
+ raise QgsProcessingException(
+ self.tr("Can not get GDAL driver for output file.")
+ )
elif res == 3:
- raise QgsProcessingException(self.tr('Can not create output file.'))
+ raise QgsProcessingException(self.tr("Can not create output file."))
elif res == 4:
- raise QgsProcessingException(self.tr('Can not get input band.'))
+ raise QgsProcessingException(self.tr("Can not get input band."))
elif res == 5:
- raise QgsProcessingException(self.tr('Can not create output bands.'))
+ raise QgsProcessingException(self.tr("Can not create output bands."))
elif res == 6:
- raise QgsProcessingException(self.tr('Output raster size is too small (at least 3 rows needed).'))
+ raise QgsProcessingException(
+ self.tr("Output raster size is too small (at least 3 rows needed).")
+ )
elif res == 7:
- feedback.pushInfo(self.tr('Canceled.'))
+ feedback.pushInfo(self.tr("Canceled."))
- return {self.OUTPUT: outputFile, self.FREQUENCY_DISTRIBUTION: frequencyDistribution}
+ return {
+ self.OUTPUT: outputFile,
+ self.FREQUENCY_DISTRIBUTION: frequencyDistribution,
+ }
diff --git a/python/plugins/processing/algs/qgis/SelectByAttribute.py b/python/plugins/processing/algs/qgis/SelectByAttribute.py
index c911da4796c6..e22655a14e72 100644
--- a/python/plugins/processing/algs/qgis/SelectByAttribute.py
+++ b/python/plugins/processing/algs/qgis/SelectByAttribute.py
@@ -15,140 +15,170 @@
***************************************************************************
"""
-__author__ = 'Michael Minn'
-__date__ = 'May 2010'
-__copyright__ = '(C) 2010, Michael Minn'
+__author__ = "Michael Minn"
+__date__ = "May 2010"
+__copyright__ = "(C) 2010, Michael Minn"
from qgis.PyQt.QtCore import QMetaType
-from qgis.core import (QgsExpression,
- QgsVectorLayer,
- QgsProcessing,
- QgsProcessingException,
- QgsProcessingAlgorithm,
- QgsProcessingParameterVectorLayer,
- QgsProcessingParameterField,
- QgsProcessingParameterEnum,
- QgsProcessingParameterString,
- QgsProcessingOutputVectorLayer)
+from qgis.core import (
+ QgsExpression,
+ QgsVectorLayer,
+ QgsProcessing,
+ QgsProcessingException,
+ QgsProcessingAlgorithm,
+ QgsProcessingParameterVectorLayer,
+ QgsProcessingParameterField,
+ QgsProcessingParameterEnum,
+ QgsProcessingParameterString,
+ QgsProcessingOutputVectorLayer,
+)
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
class SelectByAttribute(QgisAlgorithm):
- INPUT = 'INPUT'
- FIELD = 'FIELD'
- OPERATOR = 'OPERATOR'
- VALUE = 'VALUE'
- METHOD = 'METHOD'
- OUTPUT = 'OUTPUT'
-
- OPERATORS = ['=',
- '<>',
- '>',
- '>=',
- '<',
- '<=',
- 'begins with',
- 'contains',
- 'is null',
- 'is not null',
- 'does not contain'
- ]
- STRING_OPERATORS = ['begins with',
- 'contains',
- 'does not contain']
+ INPUT = "INPUT"
+ FIELD = "FIELD"
+ OPERATOR = "OPERATOR"
+ VALUE = "VALUE"
+ METHOD = "METHOD"
+ OUTPUT = "OUTPUT"
+
+ OPERATORS = [
+ "=",
+ "<>",
+ ">",
+ ">=",
+ "<",
+ "<=",
+ "begins with",
+ "contains",
+ "is null",
+ "is not null",
+ "does not contain",
+ ]
+ STRING_OPERATORS = ["begins with", "contains", "does not contain"]
def tags(self):
- return self.tr('select,attribute,value,contains,null,field').split(',')
+ return self.tr("select,attribute,value,contains,null,field").split(",")
def group(self):
- return self.tr('Vector selection')
+ return self.tr("Vector selection")
def groupId(self):
- return 'vectorselection'
+ return "vectorselection"
def __init__(self):
super().__init__()
def flags(self):
- return super().flags() | QgsProcessingAlgorithm.Flag.FlagNoThreading | QgsProcessingAlgorithm.Flag.FlagNotAvailableInStandaloneTool
+ return (
+ super().flags()
+ | QgsProcessingAlgorithm.Flag.FlagNoThreading
+ | QgsProcessingAlgorithm.Flag.FlagNotAvailableInStandaloneTool
+ )
def initAlgorithm(self, config=None):
- self.operators = ['=',
- '≠',
- '>',
- '≥',
- '<',
- '≤',
- self.tr('begins with'),
- self.tr('contains'),
- self.tr('is null'),
- self.tr('is not null'),
- self.tr('does not contain')
- ]
-
- self.methods = [self.tr('creating new selection'),
- self.tr('adding to current selection'),
- self.tr('removing from current selection'),
- self.tr('selecting within current selection')]
-
- self.addParameter(QgsProcessingParameterVectorLayer(self.INPUT,
- self.tr('Input layer'),
- types=[QgsProcessing.SourceType.TypeVector]))
- self.addParameter(QgsProcessingParameterField(self.FIELD,
- self.tr('Selection attribute'),
- parentLayerParameterName=self.INPUT))
- self.addParameter(QgsProcessingParameterEnum(self.OPERATOR,
- self.tr('Operator'), self.operators, defaultValue=0))
- self.addParameter(QgsProcessingParameterString(self.VALUE,
- self.tr('Value'),
- optional=True))
- self.addParameter(QgsProcessingParameterEnum(self.METHOD,
- self.tr('Modify current selection by'),
- self.methods,
- defaultValue=0))
-
- self.addOutput(QgsProcessingOutputVectorLayer(self.OUTPUT, self.tr('Selected (attribute)')))
+ self.operators = [
+ "=",
+ "≠",
+ ">",
+ "≥",
+ "<",
+ "≤",
+ self.tr("begins with"),
+ self.tr("contains"),
+ self.tr("is null"),
+ self.tr("is not null"),
+ self.tr("does not contain"),
+ ]
+
+ self.methods = [
+ self.tr("creating new selection"),
+ self.tr("adding to current selection"),
+ self.tr("removing from current selection"),
+ self.tr("selecting within current selection"),
+ ]
+
+ self.addParameter(
+ QgsProcessingParameterVectorLayer(
+ self.INPUT,
+ self.tr("Input layer"),
+ types=[QgsProcessing.SourceType.TypeVector],
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterField(
+ self.FIELD,
+ self.tr("Selection attribute"),
+ parentLayerParameterName=self.INPUT,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterEnum(
+ self.OPERATOR, self.tr("Operator"), self.operators, defaultValue=0
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterString(self.VALUE, self.tr("Value"), optional=True)
+ )
+ self.addParameter(
+ QgsProcessingParameterEnum(
+ self.METHOD,
+ self.tr("Modify current selection by"),
+ self.methods,
+ defaultValue=0,
+ )
+ )
+
+ self.addOutput(
+ QgsProcessingOutputVectorLayer(self.OUTPUT, self.tr("Selected (attribute)"))
+ )
def name(self):
- return 'selectbyattribute'
+ return "selectbyattribute"
def displayName(self):
- return self.tr('Select by attribute')
+ return self.tr("Select by attribute")
def processAlgorithm(self, parameters, context, feedback):
layer = self.parameterAsVectorLayer(parameters, self.INPUT, context)
fieldName = self.parameterAsString(parameters, self.FIELD, context)
- operator = self.OPERATORS[self.parameterAsEnum(parameters, self.OPERATOR, context)]
+ operator = self.OPERATORS[
+ self.parameterAsEnum(parameters, self.OPERATOR, context)
+ ]
value = self.parameterAsString(parameters, self.VALUE, context)
fields = layer.fields()
idx = fields.lookupField(fieldName)
if idx < 0:
- raise QgsProcessingException(self.tr("Field '{}' was not found in layer").format(fieldName))
+ raise QgsProcessingException(
+ self.tr("Field '{}' was not found in layer").format(fieldName)
+ )
fieldType = fields[idx].type()
if fieldType != QMetaType.Type.QString and operator in self.STRING_OPERATORS:
- op = ''.join('"%s", ' % o for o in self.STRING_OPERATORS)
+ op = "".join('"%s", ' % o for o in self.STRING_OPERATORS)
raise QgsProcessingException(
- self.tr('Operators {0} can be used only with string fields.').format(op))
+ self.tr("Operators {0} can be used only with string fields.").format(op)
+ )
field_ref = QgsExpression.quotedColumnRef(fieldName)
quoted_val = QgsExpression.quotedValue(value)
- if operator == 'is null':
- expression_string = f'{field_ref} IS NULL'
- elif operator == 'is not null':
- expression_string = f'{field_ref} IS NOT NULL'
- elif operator == 'begins with':
+ if operator == "is null":
+ expression_string = f"{field_ref} IS NULL"
+ elif operator == "is not null":
+ expression_string = f"{field_ref} IS NOT NULL"
+ elif operator == "begins with":
expression_string = f"{field_ref} LIKE '{value}%'"
- elif operator == 'contains':
+ elif operator == "contains":
expression_string = f"{field_ref} LIKE '%{value}%'"
- elif operator == 'does not contain':
+ elif operator == "does not contain":
expression_string = f"{field_ref} NOT LIKE '%{value}%'"
else:
- expression_string = f'{field_ref} {operator} {quoted_val}'
+ expression_string = f"{field_ref} {operator} {quoted_val}"
method = self.parameterAsEnum(parameters, self.METHOD, context)
if method == 0:
diff --git a/python/plugins/processing/algs/qgis/SelectByExpression.py b/python/plugins/processing/algs/qgis/SelectByExpression.py
index 271ab2600ea1..840cf6bd33d7 100644
--- a/python/plugins/processing/algs/qgis/SelectByExpression.py
+++ b/python/plugins/processing/algs/qgis/SelectByExpression.py
@@ -14,60 +14,87 @@
***************************************************************************
"""
-__author__ = 'Michael Douchin'
-__date__ = 'July 2014'
-__copyright__ = '(C) 2014, Michael Douchin'
-
-from qgis.core import (QgsExpression,
- QgsProcessing,
- QgsVectorLayer,
- QgsProcessingAlgorithm,
- QgsProcessingException,
- QgsProcessingParameterVectorLayer,
- QgsProcessingParameterExpression,
- QgsProcessingParameterEnum,
- QgsProcessingOutputVectorLayer)
+__author__ = "Michael Douchin"
+__date__ = "July 2014"
+__copyright__ = "(C) 2014, Michael Douchin"
+
+from qgis.core import (
+ QgsExpression,
+ QgsProcessing,
+ QgsVectorLayer,
+ QgsProcessingAlgorithm,
+ QgsProcessingException,
+ QgsProcessingParameterVectorLayer,
+ QgsProcessingParameterExpression,
+ QgsProcessingParameterEnum,
+ QgsProcessingOutputVectorLayer,
+)
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
class SelectByExpression(QgisAlgorithm):
- INPUT = 'INPUT'
- EXPRESSION = 'EXPRESSION'
- OUTPUT = 'OUTPUT'
- METHOD = 'METHOD'
+ INPUT = "INPUT"
+ EXPRESSION = "EXPRESSION"
+ OUTPUT = "OUTPUT"
+ METHOD = "METHOD"
def group(self):
- return self.tr('Vector selection')
+ return self.tr("Vector selection")
def groupId(self):
- return 'vectorselection'
+ return "vectorselection"
def __init__(self):
super().__init__()
def flags(self):
- return super().flags() | QgsProcessingAlgorithm.Flag.FlagNoThreading | QgsProcessingAlgorithm.Flag.FlagNotAvailableInStandaloneTool
+ return (
+ super().flags()
+ | QgsProcessingAlgorithm.Flag.FlagNoThreading
+ | QgsProcessingAlgorithm.Flag.FlagNotAvailableInStandaloneTool
+ )
def initAlgorithm(self, config=None):
- self.methods = [self.tr('creating new selection'),
- self.tr('adding to current selection'),
- self.tr('removing from current selection'),
- self.tr('selecting within current selection')]
-
- self.addParameter(QgsProcessingParameterVectorLayer(self.INPUT, self.tr('Input layer'), types=[QgsProcessing.SourceType.TypeVector]))
-
- self.addParameter(QgsProcessingParameterExpression(self.EXPRESSION,
- self.tr('Expression'), parentLayerParameterName=self.INPUT))
- self.addParameter(QgsProcessingParameterEnum(self.METHOD,
- self.tr('Modify current selection by'), self.methods, defaultValue=0))
-
- self.addOutput(QgsProcessingOutputVectorLayer(self.OUTPUT, self.tr('Selected (attribute)')))
+ self.methods = [
+ self.tr("creating new selection"),
+ self.tr("adding to current selection"),
+ self.tr("removing from current selection"),
+ self.tr("selecting within current selection"),
+ ]
+
+ self.addParameter(
+ QgsProcessingParameterVectorLayer(
+ self.INPUT,
+ self.tr("Input layer"),
+ types=[QgsProcessing.SourceType.TypeVector],
+ )
+ )
+
+ self.addParameter(
+ QgsProcessingParameterExpression(
+ self.EXPRESSION,
+ self.tr("Expression"),
+ parentLayerParameterName=self.INPUT,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterEnum(
+ self.METHOD,
+ self.tr("Modify current selection by"),
+ self.methods,
+ defaultValue=0,
+ )
+ )
+
+ self.addOutput(
+ QgsProcessingOutputVectorLayer(self.OUTPUT, self.tr("Selected (attribute)"))
+ )
def name(self):
- return 'selectbyexpression'
+ return "selectbyexpression"
def displayName(self):
- return self.tr('Select by expression')
+ return self.tr("Select by expression")
def processAlgorithm(self, parameters, context, feedback):
layer = self.parameterAsVectorLayer(parameters, self.INPUT, context)
diff --git a/python/plugins/processing/algs/qgis/SetRasterStyle.py b/python/plugins/processing/algs/qgis/SetRasterStyle.py
index b4f884517c56..a6ce2e718b6d 100644
--- a/python/plugins/processing/algs/qgis/SetRasterStyle.py
+++ b/python/plugins/processing/algs/qgis/SetRasterStyle.py
@@ -15,50 +15,61 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'August 2012'
-__copyright__ = '(C) 2012, Victor Olaya'
+__author__ = "Victor Olaya"
+__date__ = "August 2012"
+__copyright__ = "(C) 2012, Victor Olaya"
import os
from qgis.PyQt.QtXml import QDomDocument
-from qgis.core import (QgsProcessingAlgorithm,
- QgsProcessingParameterRasterLayer,
- QgsProcessingParameterFile,
- QgsProcessingOutputRasterLayer)
+from qgis.core import (
+ QgsProcessingAlgorithm,
+ QgsProcessingParameterRasterLayer,
+ QgsProcessingParameterFile,
+ QgsProcessingOutputRasterLayer,
+)
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
class SetRasterStyle(QgisAlgorithm):
- INPUT = 'INPUT'
- STYLE = 'STYLE'
- OUTPUT = 'OUTPUT'
+ INPUT = "INPUT"
+ STYLE = "STYLE"
+ OUTPUT = "OUTPUT"
def group(self):
- return self.tr('Raster tools')
+ return self.tr("Raster tools")
def groupId(self):
- return 'rastertools'
+ return "rastertools"
def __init__(self):
super().__init__()
def flags(self):
- return super().flags() | QgsProcessingAlgorithm.Flag.FlagNoThreading | QgsProcessingAlgorithm.Flag.FlagDeprecated | QgsProcessingAlgorithm.Flag.FlagNotAvailableInStandaloneTool
+ return (
+ super().flags()
+ | QgsProcessingAlgorithm.Flag.FlagNoThreading
+ | QgsProcessingAlgorithm.Flag.FlagDeprecated
+ | QgsProcessingAlgorithm.Flag.FlagNotAvailableInStandaloneTool
+ )
def initAlgorithm(self, config=None):
- self.addParameter(QgsProcessingParameterRasterLayer(self.INPUT,
- self.tr('Raster layer')))
- self.addParameter(QgsProcessingParameterFile(self.STYLE,
- self.tr('Style file'), extension='qml'))
- self.addOutput(QgsProcessingOutputRasterLayer(self.INPUT, self.tr('Styled')))
+ self.addParameter(
+ QgsProcessingParameterRasterLayer(self.INPUT, self.tr("Raster layer"))
+ )
+ self.addParameter(
+ QgsProcessingParameterFile(
+ self.STYLE, self.tr("Style file"), extension="qml"
+ )
+ )
+ self.addOutput(QgsProcessingOutputRasterLayer(self.INPUT, self.tr("Styled")))
def name(self):
- return 'setstyleforrasterlayer'
+ return "setstyleforrasterlayer"
def displayName(self):
- return self.tr('Set style for raster layer')
+ return self.tr("Set style for raster layer")
def processAlgorithm(self, parameters, context, feedback):
layer = self.parameterAsRasterLayer(parameters, self.INPUT, context)
diff --git a/python/plugins/processing/algs/qgis/SetVectorStyle.py b/python/plugins/processing/algs/qgis/SetVectorStyle.py
index 2aea85e27c53..a61dc33151c3 100644
--- a/python/plugins/processing/algs/qgis/SetVectorStyle.py
+++ b/python/plugins/processing/algs/qgis/SetVectorStyle.py
@@ -15,47 +15,57 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'August 2012'
-__copyright__ = '(C) 2012, Victor Olaya'
+__author__ = "Victor Olaya"
+__date__ = "August 2012"
+__copyright__ = "(C) 2012, Victor Olaya"
-from qgis.core import (QgsProcessingAlgorithm,
- QgsProcessingParameterFile,
- QgsProcessingParameterVectorLayer,
- QgsProcessingOutputVectorLayer)
+from qgis.core import (
+ QgsProcessingAlgorithm,
+ QgsProcessingParameterFile,
+ QgsProcessingParameterVectorLayer,
+ QgsProcessingOutputVectorLayer,
+)
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
class SetVectorStyle(QgisAlgorithm):
- INPUT = 'INPUT'
- STYLE = 'STYLE'
- OUTPUT = 'OUTPUT'
+ INPUT = "INPUT"
+ STYLE = "STYLE"
+ OUTPUT = "OUTPUT"
def group(self):
- return self.tr('Vector general')
+ return self.tr("Vector general")
def groupId(self):
- return 'vectorgeneral'
+ return "vectorgeneral"
def __init__(self):
super().__init__()
def flags(self):
- return super().flags() | QgsProcessingAlgorithm.Flag.FlagNoThreading | QgsProcessingAlgorithm.Flag.FlagDeprecated | QgsProcessingAlgorithm.Flag.FlagNotAvailableInStandaloneTool
+ return (
+ super().flags()
+ | QgsProcessingAlgorithm.Flag.FlagNoThreading
+ | QgsProcessingAlgorithm.Flag.FlagDeprecated
+ | QgsProcessingAlgorithm.Flag.FlagNotAvailableInStandaloneTool
+ )
def initAlgorithm(self, config=None):
- self.addParameter(QgsProcessingParameterVectorLayer(self.INPUT,
- self.tr('Vector layer')))
- self.addParameter(QgsProcessingParameterFile(self.STYLE,
- self.tr('Style file'), extension='qml'))
- self.addOutput(QgsProcessingOutputVectorLayer(self.INPUT,
- self.tr('Styled')))
+ self.addParameter(
+ QgsProcessingParameterVectorLayer(self.INPUT, self.tr("Vector layer"))
+ )
+ self.addParameter(
+ QgsProcessingParameterFile(
+ self.STYLE, self.tr("Style file"), extension="qml"
+ )
+ )
+ self.addOutput(QgsProcessingOutputVectorLayer(self.INPUT, self.tr("Styled")))
def name(self):
- return 'setstyleforvectorlayer'
+ return "setstyleforvectorlayer"
def displayName(self):
- return self.tr('Set style for vector layer')
+ return self.tr("Set style for vector layer")
def processAlgorithm(self, parameters, context, feedback):
layer = self.parameterAsVectorLayer(parameters, self.INPUT, context)
diff --git a/python/plugins/processing/algs/qgis/StatisticsByCategories.py b/python/plugins/processing/algs/qgis/StatisticsByCategories.py
index 2c84f605a851..3b3cc86fda45 100644
--- a/python/plugins/processing/algs/qgis/StatisticsByCategories.py
+++ b/python/plugins/processing/algs/qgis/StatisticsByCategories.py
@@ -15,28 +15,30 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'September 2012'
-__copyright__ = '(C) 2012, Victor Olaya'
-
-from qgis.core import (QgsProcessingParameterFeatureSource,
- QgsStatisticalSummary,
- QgsDateTimeStatisticalSummary,
- QgsStringStatisticalSummary,
- QgsFeatureRequest,
- QgsApplication,
- QgsProcessingException,
- QgsProcessingParameterField,
- QgsProcessingParameterFeatureSink,
- QgsFields,
- QgsField,
- QgsWkbTypes,
- QgsCoordinateReferenceSystem,
- QgsFeature,
- QgsFeatureSink,
- QgsProcessing,
- QgsProcessingFeatureSource,
- NULL)
+__author__ = "Victor Olaya"
+__date__ = "September 2012"
+__copyright__ = "(C) 2012, Victor Olaya"
+
+from qgis.core import (
+ QgsProcessingParameterFeatureSource,
+ QgsStatisticalSummary,
+ QgsDateTimeStatisticalSummary,
+ QgsStringStatisticalSummary,
+ QgsFeatureRequest,
+ QgsApplication,
+ QgsProcessingException,
+ QgsProcessingParameterField,
+ QgsProcessingParameterFeatureSink,
+ QgsFields,
+ QgsField,
+ QgsWkbTypes,
+ QgsCoordinateReferenceSystem,
+ QgsFeature,
+ QgsFeatureSink,
+ QgsProcessing,
+ QgsProcessingFeatureSource,
+ NULL,
+)
from qgis.PyQt.QtCore import QMetaType
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
@@ -44,20 +46,22 @@
class StatisticsByCategories(QgisAlgorithm):
- INPUT = 'INPUT'
- VALUES_FIELD_NAME = 'VALUES_FIELD_NAME'
- CATEGORIES_FIELD_NAME = 'CATEGORIES_FIELD_NAME'
- OUTPUT = 'OUTPUT'
+ INPUT = "INPUT"
+ VALUES_FIELD_NAME = "VALUES_FIELD_NAME"
+ CATEGORIES_FIELD_NAME = "CATEGORIES_FIELD_NAME"
+ OUTPUT = "OUTPUT"
def group(self):
- return self.tr('Vector analysis')
+ return self.tr("Vector analysis")
def groupId(self):
- return 'vectoranalysis'
+ return "vectoranalysis"
def tags(self):
- return self.tr('groups,stats,statistics,table,layer,sum,maximum,minimum,mean,average,standard,deviation,'
- 'count,distinct,unique,variance,median,quartile,range,majority,minority,histogram,distinct,summary').split(',')
+ return self.tr(
+ "groups,stats,statistics,table,layer,sum,maximum,minimum,mean,average,standard,deviation,"
+ "count,distinct,unique,variance,median,quartile,range,majority,minority,histogram,distinct,summary"
+ ).split(",")
def icon(self):
return QgsApplication.getThemeIcon("/algorithms/mAlgorithmBasicStatistics.svg")
@@ -69,33 +73,58 @@ def __init__(self):
super().__init__()
def initAlgorithm(self, config=None):
- self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT,
- self.tr('Input vector layer'),
- types=[QgsProcessing.SourceType.TypeVector]))
- self.addParameter(QgsProcessingParameterField(self.VALUES_FIELD_NAME,
- self.tr(
- 'Field to calculate statistics on (if empty, only count is calculated)'),
- parentLayerParameterName=self.INPUT, optional=True))
- self.addParameter(QgsProcessingParameterField(self.CATEGORIES_FIELD_NAME,
- self.tr('Field(s) with categories'),
- parentLayerParameterName=self.INPUT,
- type=QgsProcessingParameterField.DataType.Any, allowMultiple=True))
-
- self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Statistics by category')))
+ self.addParameter(
+ QgsProcessingParameterFeatureSource(
+ self.INPUT,
+ self.tr("Input vector layer"),
+ types=[QgsProcessing.SourceType.TypeVector],
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterField(
+ self.VALUES_FIELD_NAME,
+ self.tr(
+ "Field to calculate statistics on (if empty, only count is calculated)"
+ ),
+ parentLayerParameterName=self.INPUT,
+ optional=True,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterField(
+ self.CATEGORIES_FIELD_NAME,
+ self.tr("Field(s) with categories"),
+ parentLayerParameterName=self.INPUT,
+ type=QgsProcessingParameterField.DataType.Any,
+ allowMultiple=True,
+ )
+ )
+
+ self.addParameter(
+ QgsProcessingParameterFeatureSink(
+ self.OUTPUT, self.tr("Statistics by category")
+ )
+ )
def name(self):
- return 'statisticsbycategories'
+ return "statisticsbycategories"
def displayName(self):
- return self.tr('Statistics by categories')
+ return self.tr("Statistics by categories")
def processAlgorithm(self, parameters, context, feedback):
source = self.parameterAsSource(parameters, self.INPUT, context)
if source is None:
- raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT))
+ raise QgsProcessingException(
+ self.invalidSourceError(parameters, self.INPUT)
+ )
- value_field_name = self.parameterAsString(parameters, self.VALUES_FIELD_NAME, context)
- category_field_names = self.parameterAsFields(parameters, self.CATEGORIES_FIELD_NAME, context)
+ value_field_name = self.parameterAsString(
+ parameters, self.VALUES_FIELD_NAME, context
+ )
+ category_field_names = self.parameterAsFields(
+ parameters, self.CATEGORIES_FIELD_NAME, context
+ )
value_field_index = source.fields().lookupField(value_field_name)
if value_field_index >= 0:
@@ -109,7 +138,11 @@ def processAlgorithm(self, parameters, context, feedback):
for field_name in category_field_names:
c = source.fields().lookupField(field_name)
if c == -1:
- raise QgsProcessingException(self.tr('Field "{field_name}" does not exist.').format(field_name=field_name))
+ raise QgsProcessingException(
+ self.tr('Field "{field_name}" does not exist.').format(
+ field_name=field_name
+ )
+ )
category_field_indexes.append(c)
fields.append(source.fields().at(c))
@@ -122,45 +155,49 @@ def addField(name):
fields.append(field)
if value_field is None:
- field_type = 'none'
- fields.append(QgsField('count', QMetaType.Type.Int))
+ field_type = "none"
+ fields.append(QgsField("count", QMetaType.Type.Int))
elif value_field.isNumeric():
- field_type = 'numeric'
- fields.append(QgsField('count', QMetaType.Type.Int))
- fields.append(QgsField('unique', QMetaType.Type.Int))
- fields.append(QgsField('min', QMetaType.Type.Double))
- fields.append(QgsField('max', QMetaType.Type.Double))
- fields.append(QgsField('range', QMetaType.Type.Double))
- fields.append(QgsField('sum', QMetaType.Type.Double))
- fields.append(QgsField('mean', QMetaType.Type.Double))
- fields.append(QgsField('median', QMetaType.Type.Double))
- fields.append(QgsField('stddev', QMetaType.Type.Double))
- fields.append(QgsField('minority', QMetaType.Type.Double))
- fields.append(QgsField('majority', QMetaType.Type.Double))
- fields.append(QgsField('q1', QMetaType.Type.Double))
- fields.append(QgsField('q3', QMetaType.Type.Double))
- fields.append(QgsField('iqr', QMetaType.Type.Double))
- elif value_field.type() in (QMetaType.Type.QDate, QMetaType.Type.QTime, QMetaType.Type.QDateTime):
- field_type = 'datetime'
- fields.append(QgsField('count', QMetaType.Type.Int))
- fields.append(QgsField('unique', QMetaType.Type.Int))
- fields.append(QgsField('empty', QMetaType.Type.Int))
- fields.append(QgsField('filled', QMetaType.Type.Int))
+ field_type = "numeric"
+ fields.append(QgsField("count", QMetaType.Type.Int))
+ fields.append(QgsField("unique", QMetaType.Type.Int))
+ fields.append(QgsField("min", QMetaType.Type.Double))
+ fields.append(QgsField("max", QMetaType.Type.Double))
+ fields.append(QgsField("range", QMetaType.Type.Double))
+ fields.append(QgsField("sum", QMetaType.Type.Double))
+ fields.append(QgsField("mean", QMetaType.Type.Double))
+ fields.append(QgsField("median", QMetaType.Type.Double))
+ fields.append(QgsField("stddev", QMetaType.Type.Double))
+ fields.append(QgsField("minority", QMetaType.Type.Double))
+ fields.append(QgsField("majority", QMetaType.Type.Double))
+ fields.append(QgsField("q1", QMetaType.Type.Double))
+ fields.append(QgsField("q3", QMetaType.Type.Double))
+ fields.append(QgsField("iqr", QMetaType.Type.Double))
+ elif value_field.type() in (
+ QMetaType.Type.QDate,
+ QMetaType.Type.QTime,
+ QMetaType.Type.QDateTime,
+ ):
+ field_type = "datetime"
+ fields.append(QgsField("count", QMetaType.Type.Int))
+ fields.append(QgsField("unique", QMetaType.Type.Int))
+ fields.append(QgsField("empty", QMetaType.Type.Int))
+ fields.append(QgsField("filled", QMetaType.Type.Int))
# keep same data type for these fields
- addField('min')
- addField('max')
+ addField("min")
+ addField("max")
else:
- field_type = 'string'
- fields.append(QgsField('count', QMetaType.Type.Int))
- fields.append(QgsField('unique', QMetaType.Type.Int))
- fields.append(QgsField('empty', QMetaType.Type.Int))
- fields.append(QgsField('filled', QMetaType.Type.Int))
+ field_type = "string"
+ fields.append(QgsField("count", QMetaType.Type.Int))
+ fields.append(QgsField("unique", QMetaType.Type.Int))
+ fields.append(QgsField("empty", QMetaType.Type.Int))
+ fields.append(QgsField("filled", QMetaType.Type.Int))
# keep same data type for these fields
- addField('min')
- addField('max')
- fields.append(QgsField('min_length', QMetaType.Type.Int))
- fields.append(QgsField('max_length', QMetaType.Type.Int))
- fields.append(QgsField('mean_length', QMetaType.Type.Double))
+ addField("min")
+ addField("max")
+ fields.append(QgsField("min_length", QMetaType.Type.Int))
+ fields.append(QgsField("max_length", QMetaType.Type.Int))
+ fields.append(QgsField("mean_length", QMetaType.Type.Double))
request = QgsFeatureRequest().setFlags(QgsFeatureRequest.Flag.NoGeometry)
if value_field is not None:
@@ -169,10 +206,12 @@ def addField(name):
attrs = []
attrs.extend(category_field_indexes)
request.setSubsetOfAttributes(attrs)
- features = source.getFeatures(request, QgsProcessingFeatureSource.Flag.FlagSkipGeometryValidityChecks)
+ features = source.getFeatures(
+ request, QgsProcessingFeatureSource.Flag.FlagSkipGeometryValidityChecks
+ )
total = 50.0 / source.featureCount() if source.featureCount() else 0
- if field_type == 'none':
- values = defaultdict(lambda: 0)
+ if field_type == "none":
+ values = defaultdict(int)
else:
values = defaultdict(list)
for current, feat in enumerate(features):
@@ -182,17 +221,17 @@ def addField(name):
feedback.setProgress(int(current * total))
attrs = feat.attributes()
cat = tuple([attrs[c] for c in category_field_indexes])
- if field_type == 'none':
+ if field_type == "none":
values[cat] += 1
continue
- if field_type == 'numeric':
+ if field_type == "numeric":
if attrs[value_field_index] == NULL:
continue
else:
value = float(attrs[value_field_index])
- elif field_type == 'string':
+ elif field_type == "string":
if attrs[value_field_index] == NULL:
- value = ''
+ value = ""
else:
value = str(attrs[value_field_index])
elif attrs[value_field_index] == NULL:
@@ -201,16 +240,22 @@ def addField(name):
value = attrs[value_field_index]
values[cat].append(value)
- (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
- fields, QgsWkbTypes.Type.NoGeometry, QgsCoordinateReferenceSystem())
+ (sink, dest_id) = self.parameterAsSink(
+ parameters,
+ self.OUTPUT,
+ context,
+ fields,
+ QgsWkbTypes.Type.NoGeometry,
+ QgsCoordinateReferenceSystem(),
+ )
if sink is None:
raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT))
- if field_type == 'none':
+ if field_type == "none":
self.saveCounts(values, sink, feedback)
- elif field_type == 'numeric':
+ elif field_type == "numeric":
self.calcNumericStats(values, sink, feedback)
- elif field_type == 'datetime':
+ elif field_type == "datetime":
self.calcDateTimeStats(values, sink, feedback)
else:
self.calcStringStats(values, sink, feedback)
@@ -244,20 +289,25 @@ def calcNumericStats(self, values, sink, feedback):
stat.calculate(v)
f = QgsFeature()
- f.setAttributes(list(cat) + [stat.count(),
- stat.variety(),
- stat.min(),
- stat.max(),
- stat.range(),
- stat.sum(),
- stat.mean(),
- stat.median(),
- stat.stDev(),
- stat.minority(),
- stat.majority(),
- stat.firstQuartile(),
- stat.thirdQuartile(),
- stat.interQuartileRange()])
+ f.setAttributes(
+ list(cat)
+ + [
+ stat.count(),
+ stat.variety(),
+ stat.min(),
+ stat.max(),
+ stat.range(),
+ stat.sum(),
+ stat.mean(),
+ stat.median(),
+ stat.stDev(),
+ stat.minority(),
+ stat.majority(),
+ stat.firstQuartile(),
+ stat.thirdQuartile(),
+ stat.interQuartileRange(),
+ ]
+ )
sink.addFeature(f, QgsFeatureSink.Flag.FastInsert)
current += 1
@@ -275,13 +325,17 @@ def calcDateTimeStats(self, values, sink, feedback):
stat.calculate(v)
f = QgsFeature()
- f.setAttributes(list(cat) + [stat.count(),
- stat.countDistinct(),
- stat.countMissing(),
- stat.count() - stat.countMissing(),
- stat.statistic(QgsDateTimeStatisticalSummary.Statistic.Min),
- stat.statistic(QgsDateTimeStatisticalSummary.Statistic.Max)
- ])
+ f.setAttributes(
+ list(cat)
+ + [
+ stat.count(),
+ stat.countDistinct(),
+ stat.countMissing(),
+ stat.count() - stat.countMissing(),
+ stat.statistic(QgsDateTimeStatisticalSummary.Statistic.Min),
+ stat.statistic(QgsDateTimeStatisticalSummary.Statistic.Max),
+ ]
+ )
sink.addFeature(f, QgsFeatureSink.Flag.FastInsert)
current += 1
@@ -299,16 +353,20 @@ def calcStringStats(self, values, sink, feedback):
stat.calculate(v)
f = QgsFeature()
- f.setAttributes(list(cat) + [stat.count(),
- stat.countDistinct(),
- stat.countMissing(),
- stat.count() - stat.countMissing(),
- stat.min(),
- stat.max(),
- stat.minLength(),
- stat.maxLength(),
- stat.meanLength()
- ])
+ f.setAttributes(
+ list(cat)
+ + [
+ stat.count(),
+ stat.countDistinct(),
+ stat.countMissing(),
+ stat.count() - stat.countMissing(),
+ stat.min(),
+ stat.max(),
+ stat.minLength(),
+ stat.maxLength(),
+ stat.meanLength(),
+ ]
+ )
sink.addFeature(f, QgsFeatureSink.Flag.FastInsert)
current += 1
diff --git a/python/plugins/processing/algs/qgis/TextToFloat.py b/python/plugins/processing/algs/qgis/TextToFloat.py
index 310a7f0b4def..0b6b398a1640 100644
--- a/python/plugins/processing/algs/qgis/TextToFloat.py
+++ b/python/plugins/processing/algs/qgis/TextToFloat.py
@@ -15,26 +15,28 @@
***************************************************************************
"""
-__author__ = 'Michael Minn'
-__date__ = 'May 2010'
-__copyright__ = '(C) 2010, Michael Minn'
+__author__ = "Michael Minn"
+__date__ = "May 2010"
+__copyright__ = "(C) 2010, Michael Minn"
from qgis.PyQt.QtCore import QMetaType
-from qgis.core import (QgsField,
- QgsProcessing,
- QgsProcessingParameterField,
- QgsProcessingFeatureSource)
+from qgis.core import (
+ QgsField,
+ QgsProcessing,
+ QgsProcessingParameterField,
+ QgsProcessingFeatureSource,
+)
from processing.algs.qgis.QgisAlgorithm import QgisFeatureBasedAlgorithm
class TextToFloat(QgisFeatureBasedAlgorithm):
- FIELD = 'FIELD'
+ FIELD = "FIELD"
def group(self):
- return self.tr('Vector table')
+ return self.tr("Vector table")
def groupId(self):
- return 'vectortable'
+ return "vectortable"
def __init__(self):
super().__init__()
@@ -42,20 +44,23 @@ def __init__(self):
self.field_idx = -1
def initParameters(self, config=None):
- self.addParameter(QgsProcessingParameterField(self.FIELD,
- self.tr('Text attribute to convert to float'),
- parentLayerParameterName='INPUT',
- type=QgsProcessingParameterField.DataType.String
- ))
+ self.addParameter(
+ QgsProcessingParameterField(
+ self.FIELD,
+ self.tr("Text attribute to convert to float"),
+ parentLayerParameterName="INPUT",
+ type=QgsProcessingParameterField.DataType.String,
+ )
+ )
def name(self):
- return 'texttofloat'
+ return "texttofloat"
def displayName(self):
- return self.tr('Text to float')
+ return self.tr("Text to float")
def outputName(self):
- return self.tr('Float from text')
+ return self.tr("Float from text")
def inputLayerTypes(self):
return [QgsProcessing.SourceType.TypeVector]
@@ -63,7 +68,9 @@ def inputLayerTypes(self):
def outputFields(self, inputFields):
self.field_idx = inputFields.lookupField(self.field_name)
if self.field_idx >= 0:
- inputFields[self.field_idx] = QgsField(self.field_name, QMetaType.Type.Double, '', 24, 15)
+ inputFields[self.field_idx] = QgsField(
+ self.field_name, QMetaType.Type.Double, "", 24, 15
+ )
return inputFields
def prepareAlgorithm(self, parameters, context, feedback):
@@ -79,8 +86,8 @@ def sourceFlags(self):
def processFeature(self, feature, context, feedback):
value = feature[self.field_idx]
try:
- if '%' in value:
- feature[self.field_idx] = float(value.replace('%', '')) / 100.0
+ if "%" in value:
+ feature[self.field_idx] = float(value.replace("%", "")) / 100.0
else:
feature[self.field_idx] = float(value)
except:
diff --git a/python/plugins/processing/algs/qgis/TinInterpolation.py b/python/plugins/processing/algs/qgis/TinInterpolation.py
index 772654c91e79..51af0fc9932d 100644
--- a/python/plugins/processing/algs/qgis/TinInterpolation.py
+++ b/python/plugins/processing/algs/qgis/TinInterpolation.py
@@ -15,112 +15,139 @@
***************************************************************************
"""
-__author__ = 'Alexander Bruy'
-__date__ = 'October 2016'
-__copyright__ = '(C) 2016, Alexander Bruy'
+__author__ = "Alexander Bruy"
+__date__ = "October 2016"
+__copyright__ = "(C) 2016, Alexander Bruy"
import os
import math
from qgis.PyQt.QtGui import QIcon
-from qgis.core import (QgsProcessingUtils,
- QgsProcessing,
- QgsProcessingParameterEnum,
- QgsProcessingParameterNumber,
- QgsProcessingParameterExtent,
- QgsProcessingParameterDefinition,
- QgsProcessingParameterRasterDestination,
- QgsWkbTypes,
- QgsProcessingParameterFeatureSink,
- QgsProcessingException,
- QgsCoordinateReferenceSystem)
-from qgis.analysis import (QgsInterpolator,
- QgsTinInterpolator,
- QgsGridFileWriter)
+from qgis.core import (
+ QgsProcessingUtils,
+ QgsProcessing,
+ QgsProcessingParameterEnum,
+ QgsProcessingParameterNumber,
+ QgsProcessingParameterExtent,
+ QgsProcessingParameterDefinition,
+ QgsProcessingParameterRasterDestination,
+ QgsWkbTypes,
+ QgsProcessingParameterFeatureSink,
+ QgsProcessingException,
+ QgsCoordinateReferenceSystem,
+)
+from qgis.analysis import QgsInterpolator, QgsTinInterpolator, QgsGridFileWriter
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
-from processing.algs.qgis.ui.InterpolationWidgets import ParameterInterpolationData, ParameterPixelSize
+from processing.algs.qgis.ui.InterpolationWidgets import (
+ ParameterInterpolationData,
+ ParameterPixelSize,
+)
pluginPath = os.path.split(os.path.split(os.path.dirname(__file__))[0])[0]
class TinInterpolation(QgisAlgorithm):
- INTERPOLATION_DATA = 'INTERPOLATION_DATA'
- METHOD = 'METHOD'
- PIXEL_SIZE = 'PIXEL_SIZE'
- COLUMNS = 'COLUMNS'
- ROWS = 'ROWS'
- EXTENT = 'EXTENT'
- OUTPUT = 'OUTPUT'
- TRIANGULATION = 'TRIANGULATION'
+ INTERPOLATION_DATA = "INTERPOLATION_DATA"
+ METHOD = "METHOD"
+ PIXEL_SIZE = "PIXEL_SIZE"
+ COLUMNS = "COLUMNS"
+ ROWS = "ROWS"
+ EXTENT = "EXTENT"
+ OUTPUT = "OUTPUT"
+ TRIANGULATION = "TRIANGULATION"
def icon(self):
- return QIcon(os.path.join(pluginPath, 'images', 'interpolation.png'))
+ return QIcon(os.path.join(pluginPath, "images", "interpolation.png"))
def group(self):
- return self.tr('Interpolation')
+ return self.tr("Interpolation")
def groupId(self):
- return 'interpolation'
+ return "interpolation"
def __init__(self):
super().__init__()
def initAlgorithm(self, config=None):
- self.METHODS = [self.tr('Linear'),
- self.tr('Clough-Toucher (cubic)')
- ]
-
- self.addParameter(ParameterInterpolationData(self.INTERPOLATION_DATA,
- self.tr('Input layer(s)')))
- self.addParameter(QgsProcessingParameterEnum(self.METHOD,
- self.tr('Interpolation method'),
- options=self.METHODS,
- defaultValue=0))
- self.addParameter(QgsProcessingParameterExtent(self.EXTENT,
- self.tr('Extent'),
- optional=False))
- pixel_size_param = ParameterPixelSize(self.PIXEL_SIZE,
- self.tr('Output raster size'),
- layersData=self.INTERPOLATION_DATA,
- extent=self.EXTENT,
- minValue=0.0,
- default=0.1)
+ self.METHODS = [self.tr("Linear"), self.tr("Clough-Toucher (cubic)")]
+
+ self.addParameter(
+ ParameterInterpolationData(
+ self.INTERPOLATION_DATA, self.tr("Input layer(s)")
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterEnum(
+ self.METHOD,
+ self.tr("Interpolation method"),
+ options=self.METHODS,
+ defaultValue=0,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterExtent(self.EXTENT, self.tr("Extent"), optional=False)
+ )
+ pixel_size_param = ParameterPixelSize(
+ self.PIXEL_SIZE,
+ self.tr("Output raster size"),
+ layersData=self.INTERPOLATION_DATA,
+ extent=self.EXTENT,
+ minValue=0.0,
+ default=0.1,
+ )
self.addParameter(pixel_size_param)
- cols_param = QgsProcessingParameterNumber(self.COLUMNS,
- self.tr('Number of columns'),
- optional=True,
- minValue=0, maxValue=10000000)
- cols_param.setFlags(cols_param.flags() | QgsProcessingParameterDefinition.Flag.FlagHidden)
+ cols_param = QgsProcessingParameterNumber(
+ self.COLUMNS,
+ self.tr("Number of columns"),
+ optional=True,
+ minValue=0,
+ maxValue=10000000,
+ )
+ cols_param.setFlags(
+ cols_param.flags() | QgsProcessingParameterDefinition.Flag.FlagHidden
+ )
self.addParameter(cols_param)
- rows_param = QgsProcessingParameterNumber(self.ROWS,
- self.tr('Number of rows'),
- optional=True,
- minValue=0, maxValue=10000000)
- rows_param.setFlags(rows_param.flags() | QgsProcessingParameterDefinition.Flag.FlagHidden)
+ rows_param = QgsProcessingParameterNumber(
+ self.ROWS,
+ self.tr("Number of rows"),
+ optional=True,
+ minValue=0,
+ maxValue=10000000,
+ )
+ rows_param.setFlags(
+ rows_param.flags() | QgsProcessingParameterDefinition.Flag.FlagHidden
+ )
self.addParameter(rows_param)
- self.addParameter(QgsProcessingParameterRasterDestination(self.OUTPUT,
- self.tr('Interpolated')))
-
- triangulation_file_param = QgsProcessingParameterFeatureSink(self.TRIANGULATION,
- self.tr('Triangulation'),
- type=QgsProcessing.SourceType.TypeVectorLine,
- optional=True)
+ self.addParameter(
+ QgsProcessingParameterRasterDestination(
+ self.OUTPUT, self.tr("Interpolated")
+ )
+ )
+
+ triangulation_file_param = QgsProcessingParameterFeatureSink(
+ self.TRIANGULATION,
+ self.tr("Triangulation"),
+ type=QgsProcessing.SourceType.TypeVectorLine,
+ optional=True,
+ )
triangulation_file_param.setCreateByDefault(False)
self.addParameter(triangulation_file_param)
def name(self):
- return 'tininterpolation'
+ return "tininterpolation"
def displayName(self):
- return self.tr('TIN interpolation')
+ return self.tr("TIN interpolation")
def processAlgorithm(self, parameters, context, feedback):
- interpolationData = ParameterInterpolationData.parseValue(parameters[self.INTERPOLATION_DATA])
+ interpolationData = ParameterInterpolationData.parseValue(
+ parameters[self.INTERPOLATION_DATA]
+ )
method = self.parameterAsEnum(parameters, self.METHOD, context)
bbox = self.parameterAsExtent(parameters, self.EXTENT, context)
pixel_size = self.parameterAsDouble(parameters, self.PIXEL_SIZE, context)
@@ -135,13 +162,14 @@ def processAlgorithm(self, parameters, context, feedback):
if interpolationData is None:
raise QgsProcessingException(
- self.tr('You need to specify at least one input layer.'))
+ self.tr("You need to specify at least one input layer.")
+ )
layerData = []
layers = []
crs = QgsCoordinateReferenceSystem()
- for i, row in enumerate(interpolationData.split('::|::')):
- v = row.split('::~::')
+ for i, row in enumerate(interpolationData.split("::|::")):
+ v = row.split("::~::")
data = QgsInterpolator.LayerData()
# need to keep a reference until interpolation is complete
@@ -154,13 +182,19 @@ def processAlgorithm(self, parameters, context, feedback):
data.valueSource = int(v[1])
data.interpolationAttribute = int(v[2])
- if data.valueSource == QgsInterpolator.ValueSource.ValueAttribute and data.interpolationAttribute == -1:
- raise QgsProcessingException(self.tr(
- 'Layer {} is set to use a value attribute, but no attribute was set').format(i + 1))
-
- if v[3] == '0':
+ if (
+ data.valueSource == QgsInterpolator.ValueSource.ValueAttribute
+ and data.interpolationAttribute == -1
+ ):
+ raise QgsProcessingException(
+ self.tr(
+ "Layer {} is set to use a value attribute, but no attribute was set"
+ ).format(i + 1)
+ )
+
+ if v[3] == "0":
data.sourceType = QgsInterpolator.SourceType.SourcePoints
- elif v[3] == '1':
+ elif v[3] == "1":
data.sourceType = QgsInterpolator.SourceType.SourceStructureLines
else:
data.sourceType = QgsInterpolator.SourceType.SourceBreakLines
@@ -171,18 +205,20 @@ def processAlgorithm(self, parameters, context, feedback):
else:
interpolationMethod = QgsTinInterpolator.TinInterpolation.CloughTocher
- (triangulation_sink, triangulation_dest_id) = self.parameterAsSink(parameters, self.TRIANGULATION, context,
- QgsTinInterpolator.triangulationFields(), QgsWkbTypes.Type.LineString, crs)
+ (triangulation_sink, triangulation_dest_id) = self.parameterAsSink(
+ parameters,
+ self.TRIANGULATION,
+ context,
+ QgsTinInterpolator.triangulationFields(),
+ QgsWkbTypes.Type.LineString,
+ crs,
+ )
interpolator = QgsTinInterpolator(layerData, interpolationMethod, feedback)
if triangulation_sink is not None:
interpolator.setTriangulationSink(triangulation_sink)
- writer = QgsGridFileWriter(interpolator,
- output,
- bbox,
- columns,
- rows)
+ writer = QgsGridFileWriter(interpolator, output, bbox, columns, rows)
writer.writeFile(feedback)
if triangulation_sink:
diff --git a/python/plugins/processing/algs/qgis/TopoColors.py b/python/plugins/processing/algs/qgis/TopoColors.py
index 92c7dcace9d2..0e279cc516cb 100644
--- a/python/plugins/processing/algs/qgis/TopoColors.py
+++ b/python/plugins/processing/algs/qgis/TopoColors.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Nyall Dawson'
-__date__ = 'February 2017'
-__copyright__ = '(C) 2017, Nyall Dawson'
+__author__ = "Nyall Dawson"
+__date__ = "February 2017"
+__copyright__ = "(C) 2017, Nyall Dawson"
import os
import operator
@@ -25,19 +25,21 @@
from collections import defaultdict
-from qgis.core import (QgsField,
- QgsFeatureSink,
- QgsGeometry,
- QgsSpatialIndex,
- QgsPointXY,
- NULL,
- QgsProcessing,
- QgsProcessingException,
- QgsProcessingParameterFeatureSource,
- QgsProcessingParameterDistance,
- QgsProcessingParameterNumber,
- QgsProcessingParameterEnum,
- QgsProcessingParameterFeatureSink)
+from qgis.core import (
+ QgsField,
+ QgsFeatureSink,
+ QgsGeometry,
+ QgsSpatialIndex,
+ QgsPointXY,
+ NULL,
+ QgsProcessing,
+ QgsProcessingException,
+ QgsProcessingParameterFeatureSource,
+ QgsProcessingParameterDistance,
+ QgsProcessingParameterNumber,
+ QgsProcessingParameterEnum,
+ QgsProcessingParameterFeatureSink,
+)
from qgis.PyQt.QtCore import QMetaType
@@ -47,84 +49,122 @@
class TopoColor(QgisAlgorithm):
- INPUT = 'INPUT'
- MIN_COLORS = 'MIN_COLORS'
- MIN_DISTANCE = 'MIN_DISTANCE'
- BALANCE = 'BALANCE'
- OUTPUT = 'OUTPUT'
+ INPUT = "INPUT"
+ MIN_COLORS = "MIN_COLORS"
+ MIN_DISTANCE = "MIN_DISTANCE"
+ BALANCE = "BALANCE"
+ OUTPUT = "OUTPUT"
def tags(self):
- return self.tr('topocolor,colors,graph,adjacent,assign').split(',')
+ return self.tr("topocolor,colors,graph,adjacent,assign").split(",")
def group(self):
- return self.tr('Cartography')
+ return self.tr("Cartography")
def groupId(self):
- return 'cartography'
+ return "cartography"
def __init__(self):
super().__init__()
def initAlgorithm(self, config=None):
- self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT,
- self.tr('Input layer'),
- [QgsProcessing.SourceType.TypeVectorPolygon]))
- self.addParameter(QgsProcessingParameterNumber(self.MIN_COLORS,
- self.tr('Minimum number of colors'), minValue=1, maxValue=1000,
- defaultValue=4))
- self.addParameter(QgsProcessingParameterDistance(self.MIN_DISTANCE,
- self.tr('Minimum distance between features'),
- parentParameterName=self.INPUT, minValue=0.0,
- defaultValue=0.0))
- balance_by = [self.tr('By feature count'),
- self.tr('By assigned area'),
- self.tr('By distance between colors')]
- self.addParameter(QgsProcessingParameterEnum(
- self.BALANCE,
- self.tr('Balance color assignment'),
- options=balance_by, defaultValue=0))
+ self.addParameter(
+ QgsProcessingParameterFeatureSource(
+ self.INPUT,
+ self.tr("Input layer"),
+ [QgsProcessing.SourceType.TypeVectorPolygon],
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterNumber(
+ self.MIN_COLORS,
+ self.tr("Minimum number of colors"),
+ minValue=1,
+ maxValue=1000,
+ defaultValue=4,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterDistance(
+ self.MIN_DISTANCE,
+ self.tr("Minimum distance between features"),
+ parentParameterName=self.INPUT,
+ minValue=0.0,
+ defaultValue=0.0,
+ )
+ )
+ balance_by = [
+ self.tr("By feature count"),
+ self.tr("By assigned area"),
+ self.tr("By distance between colors"),
+ ]
+ self.addParameter(
+ QgsProcessingParameterEnum(
+ self.BALANCE,
+ self.tr("Balance color assignment"),
+ options=balance_by,
+ defaultValue=0,
+ )
+ )
self.addParameter(
- QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Colored'), QgsProcessing.SourceType.TypeVectorPolygon))
+ QgsProcessingParameterFeatureSink(
+ self.OUTPUT,
+ self.tr("Colored"),
+ QgsProcessing.SourceType.TypeVectorPolygon,
+ )
+ )
def name(self):
- return 'topologicalcoloring'
+ return "topologicalcoloring"
def displayName(self):
- return self.tr('Topological coloring')
+ return self.tr("Topological coloring")
def processAlgorithm(self, parameters, context, feedback):
source = self.parameterAsSource(parameters, self.INPUT, context)
if source is None:
- raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT))
+ raise QgsProcessingException(
+ self.invalidSourceError(parameters, self.INPUT)
+ )
min_colors = self.parameterAsInt(parameters, self.MIN_COLORS, context)
balance_by = self.parameterAsEnum(parameters, self.BALANCE, context)
min_distance = self.parameterAsDouble(parameters, self.MIN_DISTANCE, context)
fields = source.fields()
- fields.append(QgsField('color_id', QMetaType.Type.Int))
-
- (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
- fields, source.wkbType(), source.sourceCrs())
+ fields.append(QgsField("color_id", QMetaType.Type.Int))
+
+ (sink, dest_id) = self.parameterAsSink(
+ parameters,
+ self.OUTPUT,
+ context,
+ fields,
+ source.wkbType(),
+ source.sourceCrs(),
+ )
if sink is None:
raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT))
features = {f.id(): f for f in source.getFeatures()}
- topology, id_graph = self.compute_graph(features, feedback, min_distance=min_distance)
- feature_colors = ColoringAlgorithm.balanced(features,
- balance=balance_by,
- graph=topology,
- feedback=feedback,
- min_colors=min_colors)
+ topology, id_graph = self.compute_graph(
+ features, feedback, min_distance=min_distance
+ )
+ feature_colors = ColoringAlgorithm.balanced(
+ features,
+ balance=balance_by,
+ graph=topology,
+ feedback=feedback,
+ min_colors=min_colors,
+ )
if len(feature_colors) == 0:
return {self.OUTPUT: dest_id}
max_colors = max(feature_colors.values())
- feedback.pushInfo(self.tr('{} colors required').format(max_colors))
+ feedback.pushInfo(self.tr("{} colors required").format(max_colors))
total = 20.0 / len(features)
current = 0
@@ -149,14 +189,16 @@ def processAlgorithm(self, parameters, context, feedback):
@staticmethod
def compute_graph(features, feedback, create_id_graph=False, min_distance=0):
- """ compute topology from a layer/field """
+ """compute topology from a layer/field"""
s = Graph(sort_graph=False)
id_graph = None
if create_id_graph:
id_graph = Graph(sort_graph=True)
# skip features without geometry
- features_with_geometry = {f_id: f for (f_id, f) in features.items() if f.hasGeometry()}
+ features_with_geometry = {
+ f_id: f for (f_id, f) in features.items() if f.hasGeometry()
+ }
total = 70.0 / len(features_with_geometry) if features_with_geometry else 1
index = QgsSpatialIndex()
@@ -213,9 +255,12 @@ def balanced(features, graph, feedback, balance=0, min_colors=4):
neighbour_count[feature_id] += len(neighbours)
# sort features by neighbour count - we want to handle those with more neighbours first
- sorted_by_count = [feature_id for feature_id in sorted(neighbour_count.items(),
- key=operator.itemgetter(1),
- reverse=True)]
+ sorted_by_count = [
+ feature_id
+ for feature_id in sorted(
+ neighbour_count.items(), key=operator.itemgetter(1), reverse=True
+ )
+ ]
# counts for each color already assigned
color_counts = defaultdict(int)
color_areas = defaultdict(float)
@@ -226,7 +271,7 @@ def balanced(features, graph, feedback, balance=0, min_colors=4):
total = 10.0 / len(sorted_by_count) if sorted_by_count else 1
i = 0
- for (feature_id, n) in sorted_by_count:
+ for feature_id, n in sorted_by_count:
if feedback.isCanceled():
break
@@ -244,23 +289,35 @@ def balanced(features, graph, feedback, balance=0, min_colors=4):
if len(available_colors) == 0:
# no existing colors available for this feature, so add new color to pool and repeat
min_colors += 1
- return ColoringAlgorithm.balanced(features, graph, feedback, balance, min_colors)
+ return ColoringAlgorithm.balanced(
+ features, graph, feedback, balance, min_colors
+ )
else:
if balance == 0:
# choose least used available color
- counts = [(c, v) for c, v in color_counts.items() if c in available_colors]
+ counts = [
+ (c, v) for c, v in color_counts.items() if c in available_colors
+ ]
feature_color = sorted(counts, key=operator.itemgetter(1))[0][0]
color_counts[feature_color] += 1
elif balance == 1:
- areas = [(c, v) for c, v in color_areas.items() if c in available_colors]
+ areas = [
+ (c, v) for c, v in color_areas.items() if c in available_colors
+ ]
feature_color = sorted(areas, key=operator.itemgetter(1))[0][0]
color_areas[feature_color] += features[feature_id].geometry().area()
elif balance == 2:
min_distances = {c: sys.float_info.max for c in available_colors}
- this_feature_centroid = features[feature_id].geometry().centroid().constGet()
+ this_feature_centroid = (
+ features[feature_id].geometry().centroid().constGet()
+ )
# find features for all available colors
- other_features = {f_id: c for (f_id, c) in feature_colors.items() if c in available_colors}
+ other_features = {
+ f_id: c
+ for (f_id, c) in feature_colors.items()
+ if c in available_colors
+ }
# loop through these, and calculate the minimum distance from this feature to the nearest
# feature with each assigned color
@@ -277,7 +334,9 @@ def balanced(features, graph, feedback, balance=0, min_colors=4):
# choose color such that minimum distance is maximised! ie we want MAXIMAL separation between
# features with the same color
- feature_color = sorted(min_distances, key=min_distances.__getitem__, reverse=True)[0]
+ feature_color = sorted(
+ min_distances, key=min_distances.__getitem__, reverse=True
+ )[0]
feature_colors[feature_id] = feature_color
diff --git a/python/plugins/processing/algs/qgis/UniqueValues.py b/python/plugins/processing/algs/qgis/UniqueValues.py
index 4d2df71ac8d1..87201c92d4a1 100644
--- a/python/plugins/processing/algs/qgis/UniqueValues.py
+++ b/python/plugins/processing/algs/qgis/UniqueValues.py
@@ -15,31 +15,33 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'August 2012'
-__copyright__ = '(C) 2012, Victor Olaya'
+__author__ = "Victor Olaya"
+__date__ = "August 2012"
+__copyright__ = "(C) 2012, Victor Olaya"
import os
import codecs
from qgis.PyQt.QtGui import QIcon
-from qgis.core import (QgsApplication,
- QgsCoordinateReferenceSystem,
- QgsWkbTypes,
- QgsFeature,
- QgsFeatureSink,
- QgsFeatureRequest,
- QgsFields,
- QgsProcessing,
- QgsProcessingException,
- QgsProcessingParameterField,
- QgsProcessingParameterFeatureSource,
- QgsProcessingParameterFeatureSink,
- QgsProcessingOutputNumber,
- QgsProcessingOutputString,
- QgsProcessingFeatureSource,
- QgsProcessingParameterFileDestination)
+from qgis.core import (
+ QgsApplication,
+ QgsCoordinateReferenceSystem,
+ QgsWkbTypes,
+ QgsFeature,
+ QgsFeatureSink,
+ QgsFeatureRequest,
+ QgsFields,
+ QgsProcessing,
+ QgsProcessingException,
+ QgsProcessingParameterField,
+ QgsProcessingParameterFeatureSource,
+ QgsProcessingParameterFeatureSink,
+ QgsProcessingOutputNumber,
+ QgsProcessingOutputString,
+ QgsProcessingFeatureSource,
+ QgsProcessingParameterFileDestination,
+)
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
@@ -47,12 +49,12 @@
class UniqueValues(QgisAlgorithm):
- INPUT = 'INPUT'
- FIELDS = 'FIELDS'
- TOTAL_VALUES = 'TOTAL_VALUES'
- UNIQUE_VALUES = 'UNIQUE_VALUES'
- OUTPUT = 'OUTPUT'
- OUTPUT_HTML_FILE = 'OUTPUT_HTML_FILE'
+ INPUT = "INPUT"
+ FIELDS = "FIELDS"
+ TOTAL_VALUES = "TOTAL_VALUES"
+ UNIQUE_VALUES = "UNIQUE_VALUES"
+ OUTPUT = "OUTPUT"
+ OUTPUT_HTML_FILE = "OUTPUT_HTML_FILE"
def icon(self):
return QgsApplication.getThemeIcon("/algorithms/mAlgorithmUniqueValues.svg")
@@ -61,37 +63,66 @@ def svgIconPath(self):
return QgsApplication.iconPath("/algorithms/mAlgorithmUniqueValues.svg")
def group(self):
- return self.tr('Vector analysis')
+ return self.tr("Vector analysis")
def groupId(self):
- return 'vectoranalysis'
+ return "vectoranalysis"
def __init__(self):
super().__init__()
def initAlgorithm(self, config=None):
- self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT,
- self.tr('Input layer'), types=[QgsProcessing.SourceType.TypeVector]))
- self.addParameter(QgsProcessingParameterField(self.FIELDS,
- self.tr('Target field(s)'),
- parentLayerParameterName=self.INPUT, type=QgsProcessingParameterField.DataType.Any, allowMultiple=True))
-
- self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Unique values'), optional=True, defaultValue=None))
-
- self.addParameter(QgsProcessingParameterFileDestination(self.OUTPUT_HTML_FILE, self.tr('HTML report'), self.tr('HTML files (*.html)'), None, True))
- self.addOutput(QgsProcessingOutputNumber(self.TOTAL_VALUES, self.tr('Total unique values')))
- self.addOutput(QgsProcessingOutputString(self.UNIQUE_VALUES, self.tr('Unique values')))
+ self.addParameter(
+ QgsProcessingParameterFeatureSource(
+ self.INPUT,
+ self.tr("Input layer"),
+ types=[QgsProcessing.SourceType.TypeVector],
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterField(
+ self.FIELDS,
+ self.tr("Target field(s)"),
+ parentLayerParameterName=self.INPUT,
+ type=QgsProcessingParameterField.DataType.Any,
+ allowMultiple=True,
+ )
+ )
+
+ self.addParameter(
+ QgsProcessingParameterFeatureSink(
+ self.OUTPUT, self.tr("Unique values"), optional=True, defaultValue=None
+ )
+ )
+
+ self.addParameter(
+ QgsProcessingParameterFileDestination(
+ self.OUTPUT_HTML_FILE,
+ self.tr("HTML report"),
+ self.tr("HTML files (*.html)"),
+ None,
+ True,
+ )
+ )
+ self.addOutput(
+ QgsProcessingOutputNumber(self.TOTAL_VALUES, self.tr("Total unique values"))
+ )
+ self.addOutput(
+ QgsProcessingOutputString(self.UNIQUE_VALUES, self.tr("Unique values"))
+ )
def name(self):
- return 'listuniquevalues'
+ return "listuniquevalues"
def displayName(self):
- return self.tr('List unique values')
+ return self.tr("List unique values")
def processAlgorithm(self, parameters, context, feedback):
source = self.parameterAsSource(parameters, self.INPUT, context)
if source is None:
- raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT))
+ raise QgsProcessingException(
+ self.invalidSourceError(parameters, self.INPUT)
+ )
field_names = self.parameterAsFields(parameters, self.FIELDS, context)
@@ -100,13 +131,21 @@ def processAlgorithm(self, parameters, context, feedback):
for field_name in field_names:
field_index = source.fields().lookupField(field_name)
if field_index < 0:
- feedback.reportError(self.tr('Invalid field name {}').format(field_name))
+ feedback.reportError(
+ self.tr("Invalid field name {}").format(field_name)
+ )
continue
field = source.fields()[field_index]
fields.append(field)
field_indices.append(field_index)
- (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
- fields, QgsWkbTypes.Type.NoGeometry, QgsCoordinateReferenceSystem())
+ (sink, dest_id) = self.parameterAsSink(
+ parameters,
+ self.OUTPUT,
+ context,
+ fields,
+ QgsWkbTypes.Type.NoGeometry,
+ QgsCoordinateReferenceSystem(),
+ )
results = {}
values = set()
@@ -120,7 +159,12 @@ def processAlgorithm(self, parameters, context, feedback):
request = QgsFeatureRequest().setFlags(QgsFeatureRequest.Flag.NoGeometry)
request.setSubsetOfAttributes(field_indices)
total = 100.0 / source.featureCount() if source.featureCount() else 0
- for current, f in enumerate(source.getFeatures(request, QgsProcessingFeatureSource.Flag.FlagSkipGeometryValidityChecks)):
+ for current, f in enumerate(
+ source.getFeatures(
+ request,
+ QgsProcessingFeatureSource.Flag.FlagSkipGeometryValidityChecks,
+ )
+ ):
if feedback.isCanceled():
break
@@ -139,24 +183,29 @@ def processAlgorithm(self, parameters, context, feedback):
sink.finalize()
results[self.OUTPUT] = dest_id
- output_file = self.parameterAsFileOutput(parameters, self.OUTPUT_HTML_FILE, context)
+ output_file = self.parameterAsFileOutput(
+ parameters, self.OUTPUT_HTML_FILE, context
+ )
if output_file:
self.createHTML(output_file, values)
results[self.OUTPUT_HTML_FILE] = output_file
results[self.TOTAL_VALUES] = len(values)
- results[self.UNIQUE_VALUES] = ';'.join(','.join(str(attr) for attr in v) for v in
- values)
+ results[self.UNIQUE_VALUES] = ";".join(
+ ",".join(str(attr) for attr in v) for v in values
+ )
return results
def createHTML(self, outputFile, algData):
- with codecs.open(outputFile, 'w', encoding='utf-8') as f:
- f.write('')
- f.write(' ')
- f.write(self.tr('Total unique values: ') + str(len(algData)) + '
')
- f.write(self.tr('Unique values:
'))
- f.write('")
diff --git a/python/plugins/processing/algs/qgis/VariableDistanceBuffer.py b/python/plugins/processing/algs/qgis/VariableDistanceBuffer.py
index 6cded3f48c5f..c7c47f0767f1 100644
--- a/python/plugins/processing/algs/qgis/VariableDistanceBuffer.py
+++ b/python/plugins/processing/algs/qgis/VariableDistanceBuffer.py
@@ -15,25 +15,27 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'August 2012'
-__copyright__ = '(C) 2012, Victor Olaya'
+__author__ = "Victor Olaya"
+__date__ = "August 2012"
+__copyright__ = "(C) 2012, Victor Olaya"
import os
from qgis.PyQt.QtGui import QIcon
-from qgis.core import (QgsApplication,
- QgsWkbTypes,
- QgsProcessing,
- QgsProcessingException,
- QgsProcessingAlgorithm,
- QgsProcessingParameterFeatureSource,
- QgsProcessingParameterField,
- QgsProcessingParameterNumber,
- QgsProcessingParameterBoolean,
- QgsProcessingParameterEnum,
- QgsProcessingParameterFeatureSink)
+from qgis.core import (
+ QgsApplication,
+ QgsWkbTypes,
+ QgsProcessing,
+ QgsProcessingException,
+ QgsProcessingAlgorithm,
+ QgsProcessingParameterFeatureSource,
+ QgsProcessingParameterField,
+ QgsProcessingParameterNumber,
+ QgsProcessingParameterBoolean,
+ QgsProcessingParameterEnum,
+ QgsProcessingParameterFeatureSink,
+)
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
from . import Buffer as buff
@@ -42,14 +44,14 @@
class VariableDistanceBuffer(QgisAlgorithm):
- INPUT = 'INPUT'
- OUTPUT = 'OUTPUT'
- FIELD = 'FIELD'
- SEGMENTS = 'SEGMENTS'
- DISSOLVE = 'DISSOLVE'
- END_CAP_STYLE = 'END_CAP_STYLE'
- JOIN_STYLE = 'JOIN_STYLE'
- MITER_LIMIT = 'MITER_LIMIT'
+ INPUT = "INPUT"
+ OUTPUT = "OUTPUT"
+ FIELD = "FIELD"
+ SEGMENTS = "SEGMENTS"
+ DISSOLVE = "DISSOLVE"
+ END_CAP_STYLE = "END_CAP_STYLE"
+ JOIN_STYLE = "JOIN_STYLE"
+ MITER_LIMIT = "MITER_LIMIT"
def icon(self):
return QgsApplication.getThemeIcon("/algorithms/mAlgorithmBuffer.svg")
@@ -58,75 +60,131 @@ def svgIconPath(self):
return QgsApplication.iconPath("/algorithms/mAlgorithmBuffer.svg")
def group(self):
- return self.tr('Vector geometry')
+ return self.tr("Vector geometry")
def groupId(self):
- return 'vectorgeometry'
+ return "vectorgeometry"
def __init__(self):
super().__init__()
def flags(self):
- return QgsProcessingAlgorithm.Flag.FlagSupportsBatch | QgsProcessingAlgorithm.Flag.FlagCanCancel | QgsProcessingAlgorithm.Flag.FlagDeprecated
+ return (
+ QgsProcessingAlgorithm.Flag.FlagSupportsBatch
+ | QgsProcessingAlgorithm.Flag.FlagCanCancel
+ | QgsProcessingAlgorithm.Flag.FlagDeprecated
+ )
def initAlgorithm(self, config=None):
- self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT,
- self.tr('Input layer')))
-
- self.addParameter(QgsProcessingParameterField(self.FIELD,
- self.tr('Distance field'), parentLayerParameterName=self.INPUT))
- self.addParameter(QgsProcessingParameterNumber(self.SEGMENTS,
- self.tr('Segments'), type=QgsProcessingParameterNumber.Type.Integer,
- minValue=1, defaultValue=5))
- self.addParameter(QgsProcessingParameterBoolean(self.DISSOLVE,
- self.tr('Dissolve result'), defaultValue=False))
- self.end_cap_styles = [self.tr('Round'),
- 'Flat',
- 'Square']
- self.addParameter(QgsProcessingParameterEnum(
- self.END_CAP_STYLE,
- self.tr('End cap style'),
- options=self.end_cap_styles, defaultValue=0))
- self.join_styles = [self.tr('Round'),
- 'Miter',
- 'Bevel']
- self.addParameter(QgsProcessingParameterEnum(
- self.JOIN_STYLE,
- self.tr('Join style'),
- options=self.join_styles, defaultValue=0))
- self.addParameter(QgsProcessingParameterNumber(self.MITER_LIMIT,
- self.tr('Miter limit'), type=QgsProcessingParameterNumber.Type.Double,
- minValue=0, defaultValue=2))
+ self.addParameter(
+ QgsProcessingParameterFeatureSource(self.INPUT, self.tr("Input layer"))
+ )
+
+ self.addParameter(
+ QgsProcessingParameterField(
+ self.FIELD,
+ self.tr("Distance field"),
+ parentLayerParameterName=self.INPUT,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterNumber(
+ self.SEGMENTS,
+ self.tr("Segments"),
+ type=QgsProcessingParameterNumber.Type.Integer,
+ minValue=1,
+ defaultValue=5,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterBoolean(
+ self.DISSOLVE, self.tr("Dissolve result"), defaultValue=False
+ )
+ )
+ self.end_cap_styles = [self.tr("Round"), "Flat", "Square"]
+ self.addParameter(
+ QgsProcessingParameterEnum(
+ self.END_CAP_STYLE,
+ self.tr("End cap style"),
+ options=self.end_cap_styles,
+ defaultValue=0,
+ )
+ )
+ self.join_styles = [self.tr("Round"), "Miter", "Bevel"]
+ self.addParameter(
+ QgsProcessingParameterEnum(
+ self.JOIN_STYLE,
+ self.tr("Join style"),
+ options=self.join_styles,
+ defaultValue=0,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterNumber(
+ self.MITER_LIMIT,
+ self.tr("Miter limit"),
+ type=QgsProcessingParameterNumber.Type.Double,
+ minValue=0,
+ defaultValue=2,
+ )
+ )
self.addParameter(
- QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Buffer'), QgsProcessing.SourceType.TypeVectorPolygon))
+ QgsProcessingParameterFeatureSink(
+ self.OUTPUT,
+ self.tr("Buffer"),
+ QgsProcessing.SourceType.TypeVectorPolygon,
+ )
+ )
def name(self):
- return 'variabledistancebuffer'
+ return "variabledistancebuffer"
def displayName(self):
- return self.tr('Variable distance buffer')
+ return self.tr("Variable distance buffer")
def processAlgorithm(self, parameters, context, feedback):
source = self.parameterAsSource(parameters, self.INPUT, context)
if source is None:
- raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT))
+ raise QgsProcessingException(
+ self.invalidSourceError(parameters, self.INPUT)
+ )
dissolve = self.parameterAsBoolean(parameters, self.DISSOLVE, context)
segments = self.parameterAsInt(parameters, self.SEGMENTS, context)
- end_cap_style = self.parameterAsEnum(parameters, self.END_CAP_STYLE, context) + 1
+ end_cap_style = (
+ self.parameterAsEnum(parameters, self.END_CAP_STYLE, context) + 1
+ )
join_style = self.parameterAsEnum(parameters, self.JOIN_STYLE, context) + 1
miter_limit = self.parameterAsDouble(parameters, self.MITER_LIMIT, context)
field = self.parameterAsString(parameters, self.FIELD, context)
- (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
- source.fields(), QgsWkbTypes.Type.Polygon, source.sourceCrs())
+ (sink, dest_id) = self.parameterAsSink(
+ parameters,
+ self.OUTPUT,
+ context,
+ source.fields(),
+ QgsWkbTypes.Type.Polygon,
+ source.sourceCrs(),
+ )
if sink is None:
raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT))
- buff.buffering(feedback, context, sink, 0, field, True, source, dissolve, segments, end_cap_style,
- join_style, miter_limit)
+ buff.buffering(
+ feedback,
+ context,
+ sink,
+ 0,
+ field,
+ True,
+ source,
+ dissolve,
+ segments,
+ end_cap_style,
+ join_style,
+ miter_limit,
+ )
sink.finalize()
return {self.OUTPUT: dest_id}
diff --git a/python/plugins/processing/algs/qgis/VectorLayerHistogram.py b/python/plugins/processing/algs/qgis/VectorLayerHistogram.py
index 9ffa8f236070..7d57f2eb8309 100644
--- a/python/plugins/processing/algs/qgis/VectorLayerHistogram.py
+++ b/python/plugins/processing/algs/qgis/VectorLayerHistogram.py
@@ -15,17 +15,19 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'January 2013'
-__copyright__ = '(C) 2013, Victor Olaya'
+__author__ = "Victor Olaya"
+__date__ = "January 2013"
+__copyright__ = "(C) 2013, Victor Olaya"
import warnings
-from qgis.core import (QgsProcessingException,
- QgsProcessingParameterFeatureSource,
- QgsProcessingParameterField,
- QgsProcessingParameterNumber,
- QgsProcessingParameterFileDestination)
+from qgis.core import (
+ QgsProcessingException,
+ QgsProcessingParameterFeatureSource,
+ QgsProcessingParameterField,
+ QgsProcessingParameterNumber,
+ QgsProcessingParameterFileDestination,
+)
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
from processing.tools import vector
@@ -33,36 +35,49 @@
class VectorLayerHistogram(QgisAlgorithm):
- INPUT = 'INPUT'
- OUTPUT = 'OUTPUT'
- FIELD = 'FIELD'
- BINS = 'BINS'
+ INPUT = "INPUT"
+ OUTPUT = "OUTPUT"
+ FIELD = "FIELD"
+ BINS = "BINS"
def group(self):
- return self.tr('Plots')
+ return self.tr("Plots")
def groupId(self):
- return 'plots'
+ return "plots"
def __init__(self):
super().__init__()
def initAlgorithm(self, config=None):
- self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT,
- self.tr('Input layer')))
- self.addParameter(QgsProcessingParameterField(self.FIELD,
- self.tr('Attribute'), parentLayerParameterName=self.INPUT,
- type=QgsProcessingParameterField.DataType.Numeric))
- self.addParameter(QgsProcessingParameterNumber(self.BINS,
- self.tr('number of bins'), minValue=2, defaultValue=10))
-
- self.addParameter(QgsProcessingParameterFileDestination(self.OUTPUT, self.tr('Histogram'), self.tr('HTML files (*.html)')))
+ self.addParameter(
+ QgsProcessingParameterFeatureSource(self.INPUT, self.tr("Input layer"))
+ )
+ self.addParameter(
+ QgsProcessingParameterField(
+ self.FIELD,
+ self.tr("Attribute"),
+ parentLayerParameterName=self.INPUT,
+ type=QgsProcessingParameterField.DataType.Numeric,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterNumber(
+ self.BINS, self.tr("number of bins"), minValue=2, defaultValue=10
+ )
+ )
+
+ self.addParameter(
+ QgsProcessingParameterFileDestination(
+ self.OUTPUT, self.tr("Histogram"), self.tr("HTML files (*.html)")
+ )
+ )
def name(self):
- return 'vectorlayerhistogram'
+ return "vectorlayerhistogram"
def displayName(self):
- return self.tr('Vector layer histogram')
+ return self.tr("Vector layer histogram")
def processAlgorithm(self, parameters, context, feedback):
try:
@@ -73,11 +88,18 @@ def processAlgorithm(self, parameters, context, feedback):
import plotly as plt
import plotly.graph_objs as go
except ImportError:
- raise QgsProcessingException(QCoreApplication.translate('VectorLayerHistogram', 'This algorithm requires the Python “plotly” library. Please install this library and try again.'))
+ raise QgsProcessingException(
+ QCoreApplication.translate(
+ "VectorLayerHistogram",
+ "This algorithm requires the Python “plotly” library. Please install this library and try again.",
+ )
+ )
source = self.parameterAsSource(parameters, self.INPUT, context)
if source is None:
- raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT))
+ raise QgsProcessingException(
+ self.invalidSourceError(parameters, self.INPUT)
+ )
fieldname = self.parameterAsString(parameters, self.FIELD, context)
bins = self.parameterAsInt(parameters, self.BINS, context)
@@ -86,8 +108,7 @@ def processAlgorithm(self, parameters, context, feedback):
values = vector.values(source, fieldname)
- data = [go.Histogram(x=values[fieldname],
- nbinsx=bins)]
+ data = [go.Histogram(x=values[fieldname], nbinsx=bins)]
plt.offline.plot(data, filename=output, auto_open=False)
return {self.OUTPUT: output}
diff --git a/python/plugins/processing/algs/qgis/VectorLayerScatterplot.py b/python/plugins/processing/algs/qgis/VectorLayerScatterplot.py
index b53fe434344f..8f2c6ea0348d 100644
--- a/python/plugins/processing/algs/qgis/VectorLayerScatterplot.py
+++ b/python/plugins/processing/algs/qgis/VectorLayerScatterplot.py
@@ -15,17 +15,19 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'January 2013'
-__copyright__ = '(C) 2013, Victor Olaya'
+__author__ = "Victor Olaya"
+__date__ = "January 2013"
+__copyright__ = "(C) 2013, Victor Olaya"
import warnings
-from qgis.core import (QgsProcessingException,
- QgsProcessingParameterFeatureSource,
- QgsProcessingParameterField,
- QgsProcessingParameterFileDestination,
- QgsProcessingParameterString,
- QgsProcessingParameterBoolean)
+from qgis.core import (
+ QgsProcessingException,
+ QgsProcessingParameterFeatureSource,
+ QgsProcessingParameterField,
+ QgsProcessingParameterFileDestination,
+ QgsProcessingParameterString,
+ QgsProcessingParameterBoolean,
+)
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
from processing.tools import vector
@@ -34,71 +36,91 @@
class VectorLayerScatterplot(QgisAlgorithm):
- INPUT = 'INPUT'
- OUTPUT = 'OUTPUT'
- XFIELD = 'XFIELD'
- YFIELD = 'YFIELD'
- TITLE = 'TITLE'
+ INPUT = "INPUT"
+ OUTPUT = "OUTPUT"
+ XFIELD = "XFIELD"
+ YFIELD = "YFIELD"
+ TITLE = "TITLE"
XAXIS_TITLE = "XAXIS_TITLE"
YAXIS_TITLE = "YAXIS_TITLE"
XAXIS_LOG = "XAXIS_LOG"
YAXIS_LOG = "YAXIS_LOG"
def group(self):
- return self.tr('Plots')
+ return self.tr("Plots")
def groupId(self):
- return 'plots'
+ return "plots"
def __init__(self):
super().__init__()
def initAlgorithm(self, config=None):
- self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT,
- self.tr('Input layer')))
- self.addParameter(QgsProcessingParameterField(self.XFIELD,
- self.tr('X attribute'),
- parentLayerParameterName=self.INPUT,
- type=QgsProcessingParameterField.DataType.Numeric))
- self.addParameter(QgsProcessingParameterField(self.YFIELD,
- self.tr('Y attribute'),
- parentLayerParameterName=self.INPUT,
- type=QgsProcessingParameterField.DataType.Numeric))
-
- self.addParameter(QgsProcessingParameterString(
- self.TITLE,
- self.tr('Title'),
- optional=True))
-
- self.addParameter(QgsProcessingParameterString(
- self.XAXIS_TITLE,
- self.tr('X-axis title'),
- optional=True))
-
- self.addParameter(QgsProcessingParameterString(
- self.YAXIS_TITLE,
- self.tr('Y-axis title'),
- optional=True))
-
- self.addParameter(QgsProcessingParameterBoolean(
- self.XAXIS_LOG,
- self.tr('Use logarithmic scale for x-axis'),
- defaultValue=False,
- optional=True))
-
- self.addParameter(QgsProcessingParameterBoolean(
- self.YAXIS_LOG,
- self.tr('Use logarithmic scale for y-axis'),
- defaultValue=False,
- optional=True))
-
- self.addParameter(QgsProcessingParameterFileDestination(self.OUTPUT, self.tr('Scatterplot'), self.tr('HTML files (*.html)')))
+ self.addParameter(
+ QgsProcessingParameterFeatureSource(self.INPUT, self.tr("Input layer"))
+ )
+ self.addParameter(
+ QgsProcessingParameterField(
+ self.XFIELD,
+ self.tr("X attribute"),
+ parentLayerParameterName=self.INPUT,
+ type=QgsProcessingParameterField.DataType.Numeric,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterField(
+ self.YFIELD,
+ self.tr("Y attribute"),
+ parentLayerParameterName=self.INPUT,
+ type=QgsProcessingParameterField.DataType.Numeric,
+ )
+ )
+
+ self.addParameter(
+ QgsProcessingParameterString(self.TITLE, self.tr("Title"), optional=True)
+ )
+
+ self.addParameter(
+ QgsProcessingParameterString(
+ self.XAXIS_TITLE, self.tr("X-axis title"), optional=True
+ )
+ )
+
+ self.addParameter(
+ QgsProcessingParameterString(
+ self.YAXIS_TITLE, self.tr("Y-axis title"), optional=True
+ )
+ )
+
+ self.addParameter(
+ QgsProcessingParameterBoolean(
+ self.XAXIS_LOG,
+ self.tr("Use logarithmic scale for x-axis"),
+ defaultValue=False,
+ optional=True,
+ )
+ )
+
+ self.addParameter(
+ QgsProcessingParameterBoolean(
+ self.YAXIS_LOG,
+ self.tr("Use logarithmic scale for y-axis"),
+ defaultValue=False,
+ optional=True,
+ )
+ )
+
+ self.addParameter(
+ QgsProcessingParameterFileDestination(
+ self.OUTPUT, self.tr("Scatterplot"), self.tr("HTML files (*.html)")
+ )
+ )
def name(self):
- return 'vectorlayerscatterplot'
+ return "vectorlayerscatterplot"
def displayName(self):
- return self.tr('Vector layer scatterplot')
+ return self.tr("Vector layer scatterplot")
def processAlgorithm(self, parameters, context, feedback):
try:
@@ -109,11 +131,18 @@ def processAlgorithm(self, parameters, context, feedback):
import plotly as plt
import plotly.graph_objs as go
except ImportError:
- raise QgsProcessingException(QCoreApplication.translate('VectorLayerScatterplot', 'This algorithm requires the Python “plotly” library. Please install this library and try again.'))
+ raise QgsProcessingException(
+ QCoreApplication.translate(
+ "VectorLayerScatterplot",
+ "This algorithm requires the Python “plotly” library. Please install this library and try again.",
+ )
+ )
source = self.parameterAsSource(parameters, self.INPUT, context)
if source is None:
- raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT))
+ raise QgsProcessingException(
+ self.invalidSourceError(parameters, self.INPUT)
+ )
xfieldname = self.parameterAsString(parameters, self.XFIELD, context)
yfieldname = self.parameterAsString(parameters, self.YFIELD, context)
@@ -138,14 +167,13 @@ def processAlgorithm(self, parameters, context, feedback):
output = self.parameterAsFileOutput(parameters, self.OUTPUT, context)
values = vector.values(source, xfieldname, yfieldname)
- data = [go.Scatter(x=values[xfieldname],
- y=values[yfieldname],
- mode='markers')]
+ data = [go.Scatter(x=values[xfieldname], y=values[yfieldname], mode="markers")]
fig = go.Figure(
data=data,
layout_title_text=title,
layout_xaxis_title=xaxis_title,
- layout_yaxis_title=yaxis_title)
+ layout_yaxis_title=yaxis_title,
+ )
if xaxis_log:
fig.update_xaxes(type="log")
diff --git a/python/plugins/processing/algs/qgis/VectorLayerScatterplot3D.py b/python/plugins/processing/algs/qgis/VectorLayerScatterplot3D.py
index 2039a4657431..9cb0c103f95f 100644
--- a/python/plugins/processing/algs/qgis/VectorLayerScatterplot3D.py
+++ b/python/plugins/processing/algs/qgis/VectorLayerScatterplot3D.py
@@ -15,16 +15,18 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'January 2013'
-__copyright__ = '(C) 2013, Victor Olaya'
+__author__ = "Victor Olaya"
+__date__ = "January 2013"
+__copyright__ = "(C) 2013, Victor Olaya"
import warnings
-from qgis.core import (QgsProcessingParameterFeatureSource,
- QgsProcessingParameterField,
- QgsProcessingParameterFileDestination,
- QgsProcessingException,
- QgsProcessingParameterString)
+from qgis.core import (
+ QgsProcessingParameterFeatureSource,
+ QgsProcessingParameterField,
+ QgsProcessingParameterFileDestination,
+ QgsProcessingException,
+ QgsProcessingParameterString,
+)
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
@@ -34,68 +36,87 @@
class VectorLayerScatterplot3D(QgisAlgorithm):
- INPUT = 'INPUT'
- OUTPUT = 'OUTPUT'
- XFIELD = 'XFIELD'
- YFIELD = 'YFIELD'
- ZFIELD = 'ZFIELD'
- TITLE = 'TITLE'
+ INPUT = "INPUT"
+ OUTPUT = "OUTPUT"
+ XFIELD = "XFIELD"
+ YFIELD = "YFIELD"
+ ZFIELD = "ZFIELD"
+ TITLE = "TITLE"
XAXIS_TITLE = "XAXIS_TITLE"
YAXIS_TITLE = "YAXIS_TITLE"
ZAXIS_TITLE = "ZAXIS_TITLE"
def group(self):
- return self.tr('Plots')
+ return self.tr("Plots")
def groupId(self):
- return 'plots'
+ return "plots"
def __init__(self):
super().__init__()
def initAlgorithm(self, config=None):
- self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT,
- self.tr('Input layer')))
- self.addParameter(QgsProcessingParameterField(self.XFIELD,
- self.tr('X attribute'),
- parentLayerParameterName=self.INPUT,
- type=QgsProcessingParameterField.DataType.Numeric))
- self.addParameter(QgsProcessingParameterField(self.YFIELD,
- self.tr('Y attribute'),
- parentLayerParameterName=self.INPUT,
- type=QgsProcessingParameterField.DataType.Numeric))
- self.addParameter(QgsProcessingParameterField(self.ZFIELD,
- self.tr('Z attribute'),
- parentLayerParameterName=self.INPUT,
- type=QgsProcessingParameterField.DataType.Numeric))
-
- self.addParameter(QgsProcessingParameterString(
- self.TITLE,
- self.tr('Title'),
- optional=True))
-
- self.addParameter(QgsProcessingParameterString(
- self.XAXIS_TITLE,
- self.tr('X-axis title'),
- optional=True))
-
- self.addParameter(QgsProcessingParameterString(
- self.YAXIS_TITLE,
- self.tr('Y-axis title'),
- optional=True))
-
- self.addParameter(QgsProcessingParameterString(
- self.ZAXIS_TITLE,
- self.tr('Z-axis title'),
- optional=True))
-
- self.addParameter(QgsProcessingParameterFileDestination(self.OUTPUT, self.tr('Scatterplot 3D'), self.tr('HTML files (*.html)')))
+ self.addParameter(
+ QgsProcessingParameterFeatureSource(self.INPUT, self.tr("Input layer"))
+ )
+ self.addParameter(
+ QgsProcessingParameterField(
+ self.XFIELD,
+ self.tr("X attribute"),
+ parentLayerParameterName=self.INPUT,
+ type=QgsProcessingParameterField.DataType.Numeric,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterField(
+ self.YFIELD,
+ self.tr("Y attribute"),
+ parentLayerParameterName=self.INPUT,
+ type=QgsProcessingParameterField.DataType.Numeric,
+ )
+ )
+ self.addParameter(
+ QgsProcessingParameterField(
+ self.ZFIELD,
+ self.tr("Z attribute"),
+ parentLayerParameterName=self.INPUT,
+ type=QgsProcessingParameterField.DataType.Numeric,
+ )
+ )
+
+ self.addParameter(
+ QgsProcessingParameterString(self.TITLE, self.tr("Title"), optional=True)
+ )
+
+ self.addParameter(
+ QgsProcessingParameterString(
+ self.XAXIS_TITLE, self.tr("X-axis title"), optional=True
+ )
+ )
+
+ self.addParameter(
+ QgsProcessingParameterString(
+ self.YAXIS_TITLE, self.tr("Y-axis title"), optional=True
+ )
+ )
+
+ self.addParameter(
+ QgsProcessingParameterString(
+ self.ZAXIS_TITLE, self.tr("Z-axis title"), optional=True
+ )
+ )
+
+ self.addParameter(
+ QgsProcessingParameterFileDestination(
+ self.OUTPUT, self.tr("Scatterplot 3D"), self.tr("HTML files (*.html)")
+ )
+ )
def name(self):
- return 'scatter3dplot'
+ return "scatter3dplot"
def displayName(self):
- return self.tr('Vector layer scatterplot 3D')
+ return self.tr("Vector layer scatterplot 3D")
def processAlgorithm(self, parameters, context, feedback):
try:
@@ -106,11 +127,18 @@ def processAlgorithm(self, parameters, context, feedback):
import plotly as plt
import plotly.graph_objs as go
except ImportError:
- raise QgsProcessingException(QCoreApplication.translate('VectorLayerScatterplot3D', 'This algorithm requires the Python “plotly” library. Please install this library and try again.'))
+ raise QgsProcessingException(
+ QCoreApplication.translate(
+ "VectorLayerScatterplot3D",
+ "This algorithm requires the Python “plotly” library. Please install this library and try again.",
+ )
+ )
source = self.parameterAsSource(parameters, self.INPUT, context)
if source is None:
- raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT))
+ raise QgsProcessingException(
+ self.invalidSourceError(parameters, self.INPUT)
+ )
xfieldname = self.parameterAsString(parameters, self.XFIELD, context)
yfieldname = self.parameterAsString(parameters, self.YFIELD, context)
@@ -136,18 +164,22 @@ def processAlgorithm(self, parameters, context, feedback):
values = vector.values(source, xfieldname, yfieldname, zfieldname)
- data = [go.Scatter3d(
+ data = [
+ go.Scatter3d(
x=values[xfieldname],
y=values[yfieldname],
z=values[zfieldname],
- mode='markers')]
+ mode="markers",
+ )
+ ]
fig = go.Figure(
data=data,
layout_title_text=title,
layout_scene_xaxis_title=xaxis_title,
layout_scene_yaxis_title=yaxis_title,
- layout_scene_zaxis_title=zaxis_title)
+ layout_scene_zaxis_title=zaxis_title,
+ )
fig.write_html(output)
diff --git a/python/plugins/processing/algs/qgis/ui/ExecuteSQLWidget.py b/python/plugins/processing/algs/qgis/ui/ExecuteSQLWidget.py
index 830e4d6ed907..9ff825e5c43c 100644
--- a/python/plugins/processing/algs/qgis/ui/ExecuteSQLWidget.py
+++ b/python/plugins/processing/algs/qgis/ui/ExecuteSQLWidget.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Paul Blottiere'
-__date__ = 'November 2018'
-__copyright__ = '(C) 2018, Paul Blottiere'
+__author__ = "Paul Blottiere"
+__date__ = "November 2018"
+__copyright__ = "(C) 2018, Paul Blottiere"
import os
@@ -29,17 +29,15 @@
QgsProcessingParameterString,
QgsProcessingParameterNumber,
QgsExpression,
- QgsProcessingModelChildParameterSource
+ QgsProcessingModelChildParameterSource,
)
from qgis.gui import QgsFieldExpressionWidget
-from processing.gui.wrappers import (WidgetWrapper,
- dialogTypes,
- DIALOG_MODELER)
+from processing.gui.wrappers import WidgetWrapper, dialogTypes, DIALOG_MODELER
pluginPath = os.path.dirname(__file__)
-WIDGET, BASE = uic.loadUiType(os.path.join(pluginPath, 'ExecuteSQLWidgetBase.ui'))
+WIDGET, BASE = uic.loadUiType(os.path.join(pluginPath, "ExecuteSQLWidgetBase.ui"))
class ExecuteSQLWidget(BASE, WIDGET):
@@ -55,7 +53,8 @@ def __init__(self, dialog):
# add model parameters in context scope if called from modeler
if self.dialogType == DIALOG_MODELER:
strings = dialog.getAvailableValuesOfType(
- [QgsProcessingParameterString, QgsProcessingParameterNumber], [])
+ [QgsProcessingParameterString, QgsProcessingParameterNumber], []
+ )
model_params = [dialog.resolveValueDescription(s) for s in strings]
scope = QgsExpressionContextScope()
@@ -71,7 +70,7 @@ def __init__(self, dialog):
def insert(self):
if self.mExpressionWidget.currentText():
- exp = f'[%{self.mExpressionWidget.currentText()}%]'
+ exp = f"[%{self.mExpressionWidget.currentText()}%]"
self.mText.insertPlainText(exp)
def setValue(self, value):
@@ -80,20 +79,32 @@ def setValue(self, value):
if self.dialogType == DIALOG_MODELER:
if isinstance(value, list):
for v in value:
- if isinstance(v, QgsProcessingModelChildParameterSource) \
- and v.source() == Qgis.ProcessingModelChildParameterSource.ExpressionText:
+ if (
+ isinstance(v, QgsProcessingModelChildParameterSource)
+ and v.source()
+ == Qgis.ProcessingModelChildParameterSource.ExpressionText
+ ):
text = v.expressionText()
# replace parameter's name by expression (diverging after model save)
names = QgsExpression.referencedVariables(text)
strings = self.dialog.getAvailableValuesOfType(
- [QgsProcessingParameterString, QgsProcessingParameterNumber], [])
- model_params = [(self.dialog.resolveValueDescription(s), s) for s in strings]
+ [
+ QgsProcessingParameterString,
+ QgsProcessingParameterNumber,
+ ],
+ [],
+ )
+ model_params = [
+ (self.dialog.resolveValueDescription(s), s) for s in strings
+ ]
for k, v in model_params:
if v.parameterName() in names:
- text = text.replace(f'[% @{v.parameterName()} %]', f'[% @{k} %]')
+ text = text.replace(
+ f"[% @{v.parameterName()} %]", f"[% @{k} %]"
+ )
self.mText.setPlainText(text)
@@ -109,7 +120,8 @@ def value(self):
def _expressionValues(self, text):
strings = self.dialog.getAvailableValuesOfType(
- [QgsProcessingParameterString, QgsProcessingParameterNumber], [])
+ [QgsProcessingParameterString, QgsProcessingParameterNumber], []
+ )
model_params = [(self.dialog.resolveValueDescription(s), s) for s in strings]
variables = QgsExpression.referencedVariables(text)
@@ -119,7 +131,7 @@ def _expressionValues(self, text):
for k, v in model_params:
if k in descriptions:
- text = text.replace(f'[% @{k} %]', f'[% @{v.parameterName()} %]')
+ text = text.replace(f"[% @{k} %]", f"[% @{v.parameterName()} %]")
src = QgsProcessingModelChildParameterSource.fromExpressionText(text)
diff --git a/python/plugins/processing/algs/qgis/ui/HeatmapWidgets.py b/python/plugins/processing/algs/qgis/ui/HeatmapWidgets.py
index 9fdee8587466..7d14c4eee1a3 100644
--- a/python/plugins/processing/algs/qgis/ui/HeatmapWidgets.py
+++ b/python/plugins/processing/algs/qgis/ui/HeatmapWidgets.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Nyall Dawson'
-__date__ = 'December 2016'
-__copyright__ = '(C) 2016, Nyall Dawson'
+__author__ = "Nyall Dawson"
+__date__ = "December 2016"
+__copyright__ = "(C) 2016, Nyall Dawson"
from processing.gui.wrappers import WidgetWrapper, DIALOG_STANDARD
from processing.tools import dataobjects
@@ -27,12 +27,10 @@
from qgis.PyQt import uic
from qgis.gui import QgsDoubleSpinBox
-from qgis.core import (QgsRectangle,
- QgsProcessingUtils)
+from qgis.core import QgsRectangle, QgsProcessingUtils
pluginPath = os.path.dirname(__file__)
-WIDGET, BASE = uic.loadUiType(
- os.path.join(pluginPath, 'RasterResolutionWidget.ui'))
+WIDGET, BASE = uic.loadUiType(os.path.join(pluginPath, "RasterResolutionWidget.ui"))
class HeatmapPixelSizeWidget(BASE, WIDGET):
@@ -182,7 +180,9 @@ def createWidget(self):
w.setMinimum(0)
w.setMaximum(99999999999)
w.setDecimals(6)
- w.setToolTip(self.tr('Resolution of each pixel in output raster, in layer units'))
+ w.setToolTip(
+ self.tr("Resolution of each pixel in output raster, in layer units")
+ )
return w
def postInitialize(self, wrappers):
diff --git a/python/plugins/processing/algs/qgis/ui/InterpolationWidgets.py b/python/plugins/processing/algs/qgis/ui/InterpolationWidgets.py
index b3a58ca4206e..84b1a73b9e71 100644
--- a/python/plugins/processing/algs/qgis/ui/InterpolationWidgets.py
+++ b/python/plugins/processing/algs/qgis/ui/InterpolationWidgets.py
@@ -15,20 +15,16 @@
***************************************************************************
"""
-__author__ = 'Alexander Bruy'
-__date__ = 'December 2016'
-__copyright__ = '(C) 2016, Alexander Bruy'
+__author__ = "Alexander Bruy"
+__date__ = "December 2016"
+__copyright__ = "(C) 2016, Alexander Bruy"
import os
-from typing import (
- Optional,
- Union
-)
+from typing import Optional, Union
from qgis.PyQt import uic
from qgis.PyQt.QtCore import pyqtSignal
-from qgis.PyQt.QtWidgets import (QTreeWidgetItem,
- QComboBox)
+from qgis.PyQt.QtWidgets import QTreeWidgetItem, QComboBox
from qgis.core import (
Qgis,
QgsApplication,
@@ -40,7 +36,7 @@
QgsProcessingParameterNumber,
QgsProcessingParameterDefinition,
QgsFieldProxyModel,
- QgsVectorLayer
+ QgsVectorLayer,
)
from qgis.gui import QgsDoubleSpinBox
from qgis.analysis import QgsInterpolator
@@ -53,14 +49,16 @@
class ParameterInterpolationData(QgsProcessingParameterDefinition):
- def __init__(self, name='', description=''):
+ def __init__(self, name="", description=""):
super().__init__(name, description)
- self.setMetadata({
- 'widget_wrapper': 'processing.algs.qgis.ui.InterpolationWidgets.InterpolationDataWidgetWrapper'
- })
+ self.setMetadata(
+ {
+ "widget_wrapper": "processing.algs.qgis.ui.InterpolationWidgets.InterpolationDataWidgetWrapper"
+ }
+ )
def type(self):
- return 'idw_interpolation_data'
+ return "idw_interpolation_data"
def clone(self):
return ParameterInterpolationData(self.name(), self.description())
@@ -70,26 +68,25 @@ def parseValue(value):
if value is None:
return None
- if value == '':
+ if value == "":
return None
if isinstance(value, str):
- return value if value != '' else None
+ return value if value != "" else None
else:
return ParameterInterpolationData.dataToString(value)
@staticmethod
def dataToString(data):
- s = ''
+ s = ""
for c in data:
- s += '{}::~::{}::~::{:d}::~::{:d};'.format(c[0],
- c[1],
- c[2],
- c[3])
+ s += f"{c[0]}::~::{c[1]}::~::{c[2]:d}::~::{c[3]:d};"
return s[:-1]
-WIDGET, BASE = uic.loadUiType(os.path.join(pluginPath, 'interpolationdatawidgetbase.ui'))
+WIDGET, BASE = uic.loadUiType(
+ os.path.join(pluginPath, "interpolationdatawidgetbase.ui")
+)
class InterpolationDataWidget(BASE, WIDGET):
@@ -99,8 +96,8 @@ def __init__(self):
super().__init__(None)
self.setupUi(self)
- self.btnAdd.setIcon(QgsApplication.getThemeIcon('/symbologyAdd.svg'))
- self.btnRemove.setIcon(QgsApplication.getThemeIcon('/symbologyRemove.svg'))
+ self.btnAdd.setIcon(QgsApplication.getThemeIcon("/symbologyAdd.svg"))
+ self.btnRemove.setIcon(QgsApplication.getThemeIcon("/symbologyRemove.svg"))
self.btnAdd.clicked.connect(self.addLayer)
self.btnRemove.clicked.connect(self.removeLayer)
@@ -113,9 +110,9 @@ def __init__(self):
def addLayer(self):
layer = self.cmbLayers.currentLayer()
- attribute = ''
+ attribute = ""
if self.chkUseZCoordinate.isChecked():
- attribute = 'Z_COORD'
+ attribute = "Z_COORD"
else:
attribute = self.cmbFields.currentField()
@@ -152,22 +149,24 @@ def _addLayerData(self, layerName: str, attribute: str):
self.layersTree.addTopLevelItem(item)
comboBox = QComboBox()
- comboBox.addItem(self.tr('Points'))
- comboBox.addItem(self.tr('Structure lines'))
- comboBox.addItem(self.tr('Break lines'))
+ comboBox.addItem(self.tr("Points"))
+ comboBox.addItem(self.tr("Structure lines"))
+ comboBox.addItem(self.tr("Break lines"))
comboBox.setCurrentIndex(0)
self.layersTree.setItemWidget(item, 2, comboBox)
def setValue(self, value: str):
self.layersTree.clear()
- rows = value.split('::|::')
+ rows = value.split("::|::")
for i, r in enumerate(rows):
- v = r.split('::~::')
- layer = QgsProcessingUtils.mapLayerFromString(v[0], dataobjects.createContext())
+ v = r.split("::~::")
+ layer = QgsProcessingUtils.mapLayerFromString(
+ v[0], dataobjects.createContext()
+ )
field_index = int(v[2])
if field_index == -1:
- field_name = 'Z_COORD'
+ field_name = "Z_COORD"
else:
field_name = layer.fields().at(field_index).name()
@@ -179,7 +178,7 @@ def setValue(self, value: str):
self.hasChanged.emit()
def value(self) -> str:
- layers = ''
+ layers = ""
context = dataobjects.createContext()
for i in range(self.layersTree.topLevelItemCount()):
item = self.layersTree.topLevelItem(i)
@@ -195,26 +194,27 @@ def value(self) -> str:
interpolationAttribute = item.text(1)
interpolationSource = QgsInterpolator.ValueSource.ValueAttribute
- if interpolationAttribute == 'Z_COORD':
+ if interpolationAttribute == "Z_COORD":
interpolationSource = QgsInterpolator.ValueSource.ValueZ
fieldIndex = -1
else:
fieldIndex = layer.fields().indexFromName(interpolationAttribute)
- comboBox = self.layersTree.itemWidget(self.layersTree.topLevelItem(i), 2)
+ comboBox = self.layersTree.itemWidget(
+ self.layersTree.topLevelItem(i), 2
+ )
inputTypeName = comboBox.currentText()
- if inputTypeName == self.tr('Points'):
+ if inputTypeName == self.tr("Points"):
inputType = QgsInterpolator.SourceType.SourcePoints
- elif inputTypeName == self.tr('Structure lines'):
+ elif inputTypeName == self.tr("Structure lines"):
inputType = QgsInterpolator.SourceType.SourceStructureLines
else:
inputType = QgsInterpolator.SourceType.SourceBreakLines
- layers += '{}::~::{:d}::~::{:d}::~::{:d}::|::'.format(layer.source(),
- interpolationSource,
- fieldIndex,
- inputType)
- return layers[:-len('::|::')]
+ layers += "{}::~::{:d}::~::{:d}::~::{:d}::|::".format(
+ layer.source(), interpolationSource, fieldIndex, inputType
+ )
+ return layers[: -len("::|::")]
class InterpolationDataWidgetWrapper(WidgetWrapper):
@@ -233,22 +233,49 @@ def value(self):
class ParameterPixelSize(QgsProcessingParameterNumber):
- def __init__(self, name='', description='', layersData=None, extent=None, minValue=None, default=None, optional=False):
- QgsProcessingParameterNumber.__init__(self, name, description, QgsProcessingParameterNumber.Type.Double, default, optional, minValue)
- self.setMetadata({
- 'widget_wrapper': 'processing.algs.qgis.ui.InterpolationWidgets.PixelSizeWidgetWrapper'
- })
+ def __init__(
+ self,
+ name="",
+ description="",
+ layersData=None,
+ extent=None,
+ minValue=None,
+ default=None,
+ optional=False,
+ ):
+ QgsProcessingParameterNumber.__init__(
+ self,
+ name,
+ description,
+ QgsProcessingParameterNumber.Type.Double,
+ default,
+ optional,
+ minValue,
+ )
+ self.setMetadata(
+ {
+ "widget_wrapper": "processing.algs.qgis.ui.InterpolationWidgets.PixelSizeWidgetWrapper"
+ }
+ )
self.layersData = layersData
self.extent = extent
self.layers = []
def clone(self):
- copy = ParameterPixelSize(self.name(), self.description(), self.layersData, self.extent, self.minimum(), self.defaultValue(), self.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional)
+ copy = ParameterPixelSize(
+ self.name(),
+ self.description(),
+ self.layersData,
+ self.extent,
+ self.minimum(),
+ self.defaultValue(),
+ self.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional,
+ )
return copy
-WIDGET, BASE = uic.loadUiType(os.path.join(pluginPath, 'RasterResolutionWidget.ui'))
+WIDGET, BASE = uic.loadUiType(os.path.join(pluginPath, "RasterResolutionWidget.ui"))
class PixelSizeWidget(BASE, WIDGET):
@@ -258,7 +285,9 @@ def __init__(self):
self.setupUi(self)
self.context = dataobjects.createContext()
- self.extent: Optional[Union[QgsReferencedRectangle, QgsRectangle]] = QgsRectangle()
+ self.extent: Optional[Union[QgsReferencedRectangle, QgsRectangle]] = (
+ QgsRectangle()
+ )
self.layers = []
self.mCellXSpinBox.setShowClearButton(False)
@@ -274,8 +303,8 @@ def __init__(self):
def setLayers(self, layersData: str):
self.extent = QgsRectangle()
self.layers = []
- for row in layersData.split(';'):
- v = row.split('::~::')
+ for row in layersData.split(";"):
+ v = row.split("::~::")
# need to keep a reference until interpolation is complete
layer = QgsProcessingUtils.variantToSource(v[0], self.context)
if layer:
@@ -286,16 +315,15 @@ def setLayers(self, layersData: str):
def setExtent(self, extent: Optional[str]):
if extent is not None:
- tokens = extent.split(' ')[0].split(',')
+ tokens = extent.split(" ")[0].split(",")
ext = QgsRectangle(
- float(tokens[0]),
- float(tokens[2]),
- float(tokens[1]),
- float(tokens[3]))
+ float(tokens[0]), float(tokens[2]), float(tokens[1]), float(tokens[3])
+ )
if len(tokens) > 1:
self.extent = QgsReferencedRectangle(
- ext, QgsCoordinateReferenceSystem(tokens[1][1:-1]))
+ ext, QgsCoordinateReferenceSystem(tokens[1][1:-1])
+ )
else:
self.extent = ext
@@ -386,7 +414,9 @@ def createWidget(self):
w.setMinimum(0)
w.setMaximum(99999999999)
w.setDecimals(6)
- w.setToolTip(self.tr('Resolution of each pixel in output raster, in layer units'))
+ w.setToolTip(
+ self.tr("Resolution of each pixel in output raster, in layer units")
+ )
return w
def postInitialize(self, wrappers):
diff --git a/python/plugins/processing/algs/qgis/ui/RasterCalculatorWidgets.py b/python/plugins/processing/algs/qgis/ui/RasterCalculatorWidgets.py
index df030e4a0c0e..47cc4ea95dec 100644
--- a/python/plugins/processing/algs/qgis/ui/RasterCalculatorWidgets.py
+++ b/python/plugins/processing/algs/qgis/ui/RasterCalculatorWidgets.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'November 2016'
-__copyright__ = '(C) 2016, Victor Olaya'
+__author__ = "Victor Olaya"
+__date__ = "November 2016"
+__copyright__ = "(C) 2016, Victor Olaya"
import os
from functools import partial
@@ -28,15 +28,23 @@
from qgis.PyQt import uic
from qgis.PyQt.QtCore import Qt
from qgis.PyQt.QtGui import QTextCursor
-from qgis.PyQt.QtWidgets import (QLineEdit, QPushButton, QLabel,
- QComboBox, QSpacerItem, QSizePolicy,
- QListWidgetItem)
-
-from qgis.core import (QgsProcessingUtils,
- QgsProcessingParameterDefinition,
- QgsProcessingParameterRasterLayer,
- QgsProcessingOutputRasterLayer,
- QgsProject)
+from qgis.PyQt.QtWidgets import (
+ QLineEdit,
+ QPushButton,
+ QLabel,
+ QComboBox,
+ QSpacerItem,
+ QSizePolicy,
+ QListWidgetItem,
+)
+
+from qgis.core import (
+ QgsProcessingUtils,
+ QgsProcessingParameterDefinition,
+ QgsProcessingParameterRasterLayer,
+ QgsProcessingOutputRasterLayer,
+ QgsProject,
+)
from processing.gui.wrappers import WidgetWrapper, DIALOG_STANDARD, DIALOG_BATCH
from processing.gui.BatchInputSelectionPanel import BatchInputSelectionPanel
@@ -49,7 +57,8 @@
pluginPath = os.path.dirname(__file__)
WIDGET_ADD_NEW, BASE_ADD_NEW = uic.loadUiType(
- os.path.join(pluginPath, 'AddNewExpressionDialog.ui'))
+ os.path.join(pluginPath, "AddNewExpressionDialog.ui")
+)
class AddNewExpressionDialog(BASE_ADD_NEW, WIDGET_ADD_NEW):
@@ -74,7 +83,8 @@ def okPressed(self):
WIDGET_DLG, BASE_DLG = uic.loadUiType(
- os.path.join(pluginPath, 'PredefinedExpressionDialog.ui'))
+ os.path.join(pluginPath, "PredefinedExpressionDialog.ui")
+)
class PredefinedExpressionDialog(BASE_DLG, WIDGET_DLG):
@@ -86,7 +96,7 @@ def __init__(self, expression, options):
self.filledExpression = None
self.options = options
self.expression = expression
- self.variables = set(re.findall(r'\[.*?\]', expression))
+ self.variables = set(re.findall(r"\[.*?\]", expression))
self.comboBoxes = {}
for variable in self.variables:
label = QLabel(variable[1:-1])
@@ -97,7 +107,9 @@ def __init__(self, expression, options):
self.groupBox.layout().addWidget(label)
self.groupBox.layout().addWidget(combo)
- verticalSpacer = QSpacerItem(20, 40, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding)
+ verticalSpacer = QSpacerItem(
+ 20, 40, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding
+ )
self.groupBox.layout().addItem(verticalSpacer)
self.buttonBox.rejected.connect(self.cancelPressed)
@@ -109,13 +121,13 @@ def cancelPressed(self):
def okPressed(self):
self.filledExpression = self.expression
for name, combo in self.comboBoxes.items():
- self.filledExpression = self.filledExpression.replace(name,
- self.options[combo.currentText()])
+ self.filledExpression = self.filledExpression.replace(
+ name, self.options[combo.currentText()]
+ )
self.close()
-WIDGET, BASE = uic.loadUiType(
- os.path.join(pluginPath, 'RasterCalculatorWidget.ui'))
+WIDGET, BASE = uic.loadUiType(os.path.join(pluginPath, "RasterCalculatorWidget.ui"))
class ExpressionWidget(BASE, WIDGET):
@@ -133,10 +145,16 @@ def doubleClicked(item):
def addButtonText(text):
if any(c for c in text if c.islower()):
self.text.insertPlainText(f" {text}()")
- self.text.moveCursor(QTextCursor.MoveOperation.PreviousCharacter, QTextCursor.MoveMode.MoveAnchor)
+ self.text.moveCursor(
+ QTextCursor.MoveOperation.PreviousCharacter,
+ QTextCursor.MoveMode.MoveAnchor,
+ )
else:
self.text.insertPlainText(f" {text} ")
- buttons = [b for b in self.buttonsGroupBox.children()if isinstance(b, QPushButton)]
+
+ buttons = [
+ b for b in self.buttonsGroupBox.children() if isinstance(b, QPushButton)
+ ]
for button in buttons:
button.clicked.connect(partial(addButtonText, button.text()))
self.listWidget.itemDoubleClicked.connect(doubleClicked)
@@ -154,25 +172,33 @@ def addButtonText(text):
self.text.textChanged.connect(self.expressionValid)
def expressionValid(self):
- errorString = ''
- testNode = QgsRasterCalcNode.parseRasterCalcString(self.text.toPlainText(), errorString)
+ errorString = ""
+ testNode = QgsRasterCalcNode.parseRasterCalcString(
+ self.text.toPlainText(), errorString
+ )
if not self.text.toPlainText():
- self.expressionErrorLabel.setText(self.tr('Expression is empty'))
+ self.expressionErrorLabel.setText(self.tr("Expression is empty"))
self.expressionErrorLabel.setStyleSheet("QLabel { color: black; }")
return False
if testNode:
- self.expressionErrorLabel.setText(self.tr('Expression is valid'))
- self.expressionErrorLabel.setStyleSheet("QLabel { color: green; font-weight: bold; }")
+ self.expressionErrorLabel.setText(self.tr("Expression is valid"))
+ self.expressionErrorLabel.setStyleSheet(
+ "QLabel { color: green; font-weight: bold; }"
+ )
return True
- self.expressionErrorLabel.setText(self.tr('Expression is not valid ') + errorString)
- self.expressionErrorLabel.setStyleSheet("QLabel { color : red; font-weight: bold; }")
+ self.expressionErrorLabel.setText(
+ self.tr("Expression is not valid ") + errorString
+ )
+ self.expressionErrorLabel.setStyleSheet(
+ "QLabel { color : red; font-weight: bold; }"
+ )
return False
def expsFile(self):
- return os.path.join(userFolder(), 'rastercalcexpressions.json')
+ return os.path.join(userFolder(), "rastercalcexpressions.json")
def addPredefined(self):
expression = self.expressions[self.comboPredefined.currentText()]
@@ -186,7 +212,7 @@ def savePredefined(self):
used = [v for v in self.options.values() if v in exp]
for i, v in enumerate(used):
- exp = exp.replace(v, f'[{chr(97 + i)}]')
+ exp = exp.replace(v, f"[{chr(97 + i)}]")
dlg = AddNewExpressionDialog(exp)
dlg.exec()
@@ -210,7 +236,7 @@ def _find_source(name):
for entry in entries:
if entry.ref == name:
return entry.raster.source()
- return ''
+ return ""
for name in options.keys():
item = QListWidgetItem(name, self.listWidget)
@@ -240,14 +266,25 @@ def _get_options(self):
def createWidget(self):
if self.dialogType == DIALOG_STANDARD:
- if iface is not None and iface.layerTreeView() is not None and iface.layerTreeView().layerTreeModel() is not None:
+ if (
+ iface is not None
+ and iface.layerTreeView() is not None
+ and iface.layerTreeView().layerTreeModel() is not None
+ ):
iface.layerTreeView().layerTreeModel().dataChanged.connect(self.refresh)
return self._panel(self._get_options())
elif self.dialogType == DIALOG_BATCH:
return QLineEdit()
else:
- layers = self.dialog.getAvailableValuesOfType([QgsProcessingParameterRasterLayer], [QgsProcessingOutputRasterLayer])
- options = {self.dialog.resolveValueDescription(lyr): f"{self.dialog.resolveValueDescription(lyr)}@1" for lyr in layers}
+ layers = self.dialog.getAvailableValuesOfType(
+ [QgsProcessingParameterRasterLayer], [QgsProcessingOutputRasterLayer]
+ )
+ options = {
+ self.dialog.resolveValueDescription(
+ lyr
+ ): f"{self.dialog.resolveValueDescription(lyr)}@1"
+ for lyr in layers
+ }
self.widget = self._panel(options)
return self.widget
@@ -275,7 +312,9 @@ class LayersListWidgetWrapper(WidgetWrapper):
def createWidget(self):
if self.dialogType == DIALOG_BATCH:
- widget = BatchInputSelectionPanel(self.parameterDefinition(), self.row, self.col, self.dialog)
+ widget = BatchInputSelectionPanel(
+ self.parameterDefinition(), self.row, self.col, self.dialog
+ )
widget.valueChanged.connect(lambda: self.widgetValueHasChanged.emit(self))
return widget
else:
@@ -291,17 +330,27 @@ def value(self):
return self.param.setValue(self.widget.selectedoptions)
else:
if self.param.datatype == dataobjects.TYPE_RASTER:
- options = QgsProcessingUtils.compatibleRasterLayers(QgsProject.instance(), False)
+ options = QgsProcessingUtils.compatibleRasterLayers(
+ QgsProject.instance(), False
+ )
elif self.param.datatype == dataobjects.TYPE_VECTOR_ANY:
- options = QgsProcessingUtils.compatibleVectorLayers(QgsProject.instance(), [], False)
+ options = QgsProcessingUtils.compatibleVectorLayers(
+ QgsProject.instance(), [], False
+ )
else:
- options = QgsProcessingUtils.compatibleVectorLayers(QgsProject.instance(), [self.param.datatype], False)
+ options = QgsProcessingUtils.compatibleVectorLayers(
+ QgsProject.instance(), [self.param.datatype], False
+ )
return [options[i] for i in self.widget.selectedoptions]
elif self.dialogType == DIALOG_BATCH:
return self.widget.getText()
else:
options = self._getOptions()
values = [options[i] for i in self.widget.selectedoptions]
- if len(values) == 0 and not self.parameterDefinition().flags() & QgsProcessingParameterDefinition.Flag.FlagOptional:
+ if (
+ len(values) == 0
+ and not self.parameterDefinition().flags()
+ & QgsProcessingParameterDefinition.Flag.FlagOptional
+ ):
raise InvalidParameterValue()
return values
diff --git a/python/plugins/processing/algs/qgis/ui/ReliefColorsWidget.py b/python/plugins/processing/algs/qgis/ui/ReliefColorsWidget.py
index 874183a4ad5b..0fee724bde99 100644
--- a/python/plugins/processing/algs/qgis/ui/ReliefColorsWidget.py
+++ b/python/plugins/processing/algs/qgis/ui/ReliefColorsWidget.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Alexander Bruy'
-__date__ = 'December 2016'
-__copyright__ = '(C) 2016, Alexander Bruy'
+__author__ = "Alexander Bruy"
+__date__ = "December 2016"
+__copyright__ = "(C) 2016, Alexander Bruy"
import os
import codecs
@@ -25,12 +25,13 @@
from qgis.PyQt import uic
from qgis.PyQt.QtCore import pyqtSlot, QDir
from qgis.PyQt.QtGui import QColor, QBrush
-from qgis.PyQt.QtWidgets import (QTreeWidgetItem,
- QFileDialog,
- QMessageBox,
- QInputDialog,
- QColorDialog
- )
+from qgis.PyQt.QtWidgets import (
+ QTreeWidgetItem,
+ QFileDialog,
+ QMessageBox,
+ QInputDialog,
+ QColorDialog,
+)
from qgis.PyQt.QtXml import QDomDocument
from qgis.core import QgsApplication, QgsMapLayer
@@ -40,7 +41,7 @@
from processing.tools import system
pluginPath = os.path.dirname(__file__)
-WIDGET, BASE = uic.loadUiType(os.path.join(pluginPath, 'reliefcolorswidgetbase.ui'))
+WIDGET, BASE = uic.loadUiType(os.path.join(pluginPath, "reliefcolorswidgetbase.ui"))
class ReliefColorsWidget(BASE, WIDGET):
@@ -49,21 +50,21 @@ def __init__(self):
super().__init__(None)
self.setupUi(self)
- self.btnAdd.setIcon(QgsApplication.getThemeIcon('/symbologyAdd.svg'))
- self.btnRemove.setIcon(QgsApplication.getThemeIcon('/symbologyRemove.svg'))
- self.btnUp.setIcon(QgsApplication.getThemeIcon('/mActionArrowUp.svg'))
- self.btnDown.setIcon(QgsApplication.getThemeIcon('/mActionArrowDown.svg'))
- self.btnLoad.setIcon(QgsApplication.getThemeIcon('/mActionFileOpen.svg'))
- self.btnSave.setIcon(QgsApplication.getThemeIcon('/mActionFileSave.svg'))
- self.btnAuto.setIcon(QgsApplication.getThemeIcon('/mActionReload.svg'))
+ self.btnAdd.setIcon(QgsApplication.getThemeIcon("/symbologyAdd.svg"))
+ self.btnRemove.setIcon(QgsApplication.getThemeIcon("/symbologyRemove.svg"))
+ self.btnUp.setIcon(QgsApplication.getThemeIcon("/mActionArrowUp.svg"))
+ self.btnDown.setIcon(QgsApplication.getThemeIcon("/mActionArrowDown.svg"))
+ self.btnLoad.setIcon(QgsApplication.getThemeIcon("/mActionFileOpen.svg"))
+ self.btnSave.setIcon(QgsApplication.getThemeIcon("/mActionFileSave.svg"))
+ self.btnAuto.setIcon(QgsApplication.getThemeIcon("/mActionReload.svg"))
self.layer = None
@pyqtSlot()
def on_btnAdd_clicked(self):
item = QTreeWidgetItem()
- item.setText(0, '0.00')
- item.setText(1, '0.00')
+ item.setText(0, "0.00")
+ item.setText(1, "0.00")
item.setBackground(2, QBrush(QColor(127, 127, 127)))
self.reliefClassTree.addTopLevelItem(item)
@@ -96,63 +97,76 @@ def on_btnUp_clicked(self):
@pyqtSlot()
def on_btnLoad_clicked(self):
- fileName, _ = QFileDialog.getOpenFileName(None,
- self.tr('Import Colors and elevations from XML'),
- QDir.homePath(),
- self.tr('XML files (*.xml *.XML)'))
- if fileName == '':
+ fileName, _ = QFileDialog.getOpenFileName(
+ None,
+ self.tr("Import Colors and elevations from XML"),
+ QDir.homePath(),
+ self.tr("XML files (*.xml *.XML)"),
+ )
+ if fileName == "":
return
doc = QDomDocument()
- with codecs.open(fileName, 'r', encoding='utf-8') as f:
+ with codecs.open(fileName, "r", encoding="utf-8") as f:
content = f.read()
if not doc.setContent(content):
- QMessageBox.critical(None,
- self.tr('Error parsing XML'),
- self.tr('The XML file could not be loaded'))
+ QMessageBox.critical(
+ None,
+ self.tr("Error parsing XML"),
+ self.tr("The XML file could not be loaded"),
+ )
return
self.reliefClassTree.clear()
- reliefColorList = doc.elementsByTagName('ReliefColor')
+ reliefColorList = doc.elementsByTagName("ReliefColor")
for i in range(reliefColorList.length()):
elem = reliefColorList.at(i).toElement()
item = QTreeWidgetItem()
- item.setText(0, elem.attribute('MinElevation'))
- item.setText(1, elem.attribute('MaxElevation'))
- item.setBackground(2, QBrush(QColor(int(elem.attribute('red')),
- int(elem.attribute('green')),
- int(elem.attribute('blue')))))
+ item.setText(0, elem.attribute("MinElevation"))
+ item.setText(1, elem.attribute("MaxElevation"))
+ item.setBackground(
+ 2,
+ QBrush(
+ QColor(
+ int(elem.attribute("red")),
+ int(elem.attribute("green")),
+ int(elem.attribute("blue")),
+ )
+ ),
+ )
self.reliefClassTree.addTopLevelItem(item)
@pyqtSlot()
def on_btnSave_clicked(self):
- fileName, _ = QFileDialog.getSaveFileName(None,
- self.tr('Export Colors and elevations as XML'),
- QDir.homePath(),
- self.tr('XML files (*.xml *.XML)'))
-
- if fileName == '':
+ fileName, _ = QFileDialog.getSaveFileName(
+ None,
+ self.tr("Export Colors and elevations as XML"),
+ QDir.homePath(),
+ self.tr("XML files (*.xml *.XML)"),
+ )
+
+ if fileName == "":
return
- if not fileName.lower().endswith('.xml'):
- fileName += '.xml'
+ if not fileName.lower().endswith(".xml"):
+ fileName += ".xml"
doc = QDomDocument()
- colorsElem = doc.createElement('ReliefColors')
+ colorsElem = doc.createElement("ReliefColors")
doc.appendChild(colorsElem)
colors = self.reliefColors()
for c in colors:
- elem = doc.createElement('ReliefColor')
- elem.setAttribute('MinElevation', str(c.minElevation))
- elem.setAttribute('MaxElevation', str(c.maxElevation))
- elem.setAttribute('red', str(c.color.red()))
- elem.setAttribute('green', str(c.color.green()))
- elem.setAttribute('blue', str(c.color.blue()))
+ elem = doc.createElement("ReliefColor")
+ elem.setAttribute("MinElevation", str(c.minElevation))
+ elem.setAttribute("MaxElevation", str(c.maxElevation))
+ elem.setAttribute("red", str(c.color.red()))
+ elem.setAttribute("green", str(c.color.green()))
+ elem.setAttribute("blue", str(c.color.blue()))
colorsElem.appendChild(elem)
- with codecs.open(fileName, 'w', encoding='utf-8') as f:
+ with codecs.open(fileName, "w", encoding="utf-8") as f:
f.write(doc.toString(2))
@pyqtSlot()
@@ -160,7 +174,7 @@ def on_btnAuto_clicked(self):
if self.layer is None:
return
- relief = QgsRelief(self.layer, system.getTempFilename(), 'GTiff')
+ relief = QgsRelief(self.layer, system.getTempFilename(), "GTiff")
colors = relief.calculateOptimizedReliefClasses()
self.populateColors(colors)
@@ -170,25 +184,31 @@ def on_reliefClassTree_itemDoubleClicked(self, item, column):
return
if column == 0:
- d, ok = QInputDialog.getDouble(None,
- self.tr('Enter lower elevation class bound'),
- self.tr('Elevation'),
- float(item.text(0)),
- decimals=2)
+ d, ok = QInputDialog.getDouble(
+ None,
+ self.tr("Enter lower elevation class bound"),
+ self.tr("Elevation"),
+ float(item.text(0)),
+ decimals=2,
+ )
if ok:
item.setText(0, str(d))
elif column == 1:
- d, ok = QInputDialog.getDouble(None,
- self.tr('Enter upper elevation class bound'),
- self.tr('Elevation'),
- float(item.text(1)),
- decimals=2)
+ d, ok = QInputDialog.getDouble(
+ None,
+ self.tr("Enter upper elevation class bound"),
+ self.tr("Elevation"),
+ float(item.text(1)),
+ decimals=2,
+ )
if ok:
item.setText(1, str(d))
elif column == 2:
- c = QColorDialog.getColor(item.background(2).color(),
- None,
- self.tr('Select color for relief class'))
+ c = QColorDialog.getColor(
+ item.background(2).color(),
+ None,
+ self.tr("Select color for relief class"),
+ )
if c.isValid():
item.setBackground(2, QBrush(c))
@@ -197,9 +217,9 @@ def reliefColors(self):
for i in range(self.reliefClassTree.topLevelItemCount()):
item = self.reliefClassTree.topLevelItem(i)
if item:
- c = QgsRelief.ReliefColor(item.background(2).color(),
- float(item.text(0)),
- float(item.text(1)))
+ c = QgsRelief.ReliefColor(
+ item.background(2).color(), float(item.text(0)), float(item.text(1))
+ )
colors.append(c)
return colors
@@ -217,9 +237,9 @@ def setLayer(self, layer):
def setValue(self, value):
self.reliefClassTree.clear()
- rows = value.split(';')
+ rows = value.split(";")
for r in rows:
- v = r.split(',')
+ v = r.split(",")
item = QTreeWidgetItem()
item.setText(0, v[0])
item.setText(1, v[1])
@@ -229,13 +249,15 @@ def setValue(self, value):
def value(self):
rColors = self.reliefColors()
- colors = ''
+ colors = ""
for c in rColors:
- colors += '{:f}, {:f}, {:d}, {:d}, {:d};'.format(c.minElevation,
- c.maxElevation,
- c.color.red(),
- c.color.green(),
- c.color.blue())
+ colors += "{:f}, {:f}, {:d}, {:d}, {:d};".format(
+ c.minElevation,
+ c.maxElevation,
+ c.color.red(),
+ c.color.green(),
+ c.color.blue(),
+ )
return colors[:-1]
diff --git a/python/plugins/processing/core/Processing.py b/python/plugins/processing/core/Processing.py
index e178cfa7cece..5cf03d80baac 100644
--- a/python/plugins/processing/core/Processing.py
+++ b/python/plugins/processing/core/Processing.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'August 2012'
-__copyright__ = '(C) 2012, Victor Olaya'
+__author__ = "Victor Olaya"
+__date__ = "August 2012"
+__copyright__ = "(C) 2012, Victor Olaya"
import os
import traceback
@@ -27,20 +27,22 @@
from qgis.PyQt.QtGui import QCursor
from qgis.utils import iface
-from qgis.core import (QgsMessageLog,
- QgsApplication,
- QgsMapLayer,
- QgsProcessingProvider,
- QgsProcessingAlgorithm,
- QgsProcessingException,
- QgsProcessingParameterDefinition,
- QgsProcessingOutputVectorLayer,
- QgsProcessingOutputRasterLayer,
- QgsProcessingOutputPointCloudLayer,
- QgsProcessingOutputMapLayer,
- QgsProcessingOutputMultipleLayers,
- QgsProcessingFeedback,
- QgsRuntimeProfiler)
+from qgis.core import (
+ QgsMessageLog,
+ QgsApplication,
+ QgsMapLayer,
+ QgsProcessingProvider,
+ QgsProcessingAlgorithm,
+ QgsProcessingException,
+ QgsProcessingParameterDefinition,
+ QgsProcessingOutputVectorLayer,
+ QgsProcessingOutputRasterLayer,
+ QgsProcessingOutputPointCloudLayer,
+ QgsProcessingOutputMapLayer,
+ QgsProcessingOutputMultipleLayers,
+ QgsProcessingFeedback,
+ QgsRuntimeProfiler,
+)
from qgis.analysis import QgsNativeAlgorithms
import processing
@@ -51,14 +53,16 @@
from processing.script import ScriptUtils
from processing.tools import dataobjects
-with QgsRuntimeProfiler.profile('Import QGIS Provider'):
+with QgsRuntimeProfiler.profile("Import QGIS Provider"):
from processing.algs.qgis.QgisAlgorithmProvider import QgisAlgorithmProvider # NOQA
-with QgsRuntimeProfiler.profile('Import GDAL Provider'):
+with QgsRuntimeProfiler.profile("Import GDAL Provider"):
from processing.algs.gdal.GdalAlgorithmProvider import GdalAlgorithmProvider # NOQA
-with QgsRuntimeProfiler.profile('Import Script Provider'):
- from processing.script.ScriptAlgorithmProvider import ScriptAlgorithmProvider # NOQA
+with QgsRuntimeProfiler.profile("Import Script Provider"):
+ from processing.script.ScriptAlgorithmProvider import (
+ ScriptAlgorithmProvider,
+ ) # NOQA
# should be loaded last - ensures that all dependent algorithms are available when loading models
from processing.modeler.ModelerAlgorithmProvider import ModelerAlgorithmProvider # NOQA
@@ -70,32 +74,51 @@ class Processing:
@staticmethod
def activateProvider(providerOrName, activate=True):
- provider_id = providerOrName.id() if isinstance(providerOrName, QgsProcessingProvider) else providerOrName
+ provider_id = (
+ providerOrName.id()
+ if isinstance(providerOrName, QgsProcessingProvider)
+ else providerOrName
+ )
provider = QgsApplication.processingRegistry().providerById(provider_id)
try:
provider.setActive(True)
provider.refreshAlgorithms()
except:
# provider could not be activated
- QgsMessageLog.logMessage(Processing.tr('Error: Provider {0} could not be activated\n').format(provider_id),
- Processing.tr("Processing"))
+ QgsMessageLog.logMessage(
+ Processing.tr("Error: Provider {0} could not be activated\n").format(
+ provider_id
+ ),
+ Processing.tr("Processing"),
+ )
@staticmethod
def initialize():
- if "script" in [p.id() for p in QgsApplication.processingRegistry().providers()]:
+ if "script" in [
+ p.id() for p in QgsApplication.processingRegistry().providers()
+ ]:
return
- with QgsRuntimeProfiler.profile('Initialize'):
+ with QgsRuntimeProfiler.profile("Initialize"):
# add native provider if not already added
- if "native" not in [p.id() for p in QgsApplication.processingRegistry().providers()]:
- QgsApplication.processingRegistry().addProvider(QgsNativeAlgorithms(QgsApplication.processingRegistry()))
+ if "native" not in [
+ p.id() for p in QgsApplication.processingRegistry().providers()
+ ]:
+ QgsApplication.processingRegistry().addProvider(
+ QgsNativeAlgorithms(QgsApplication.processingRegistry())
+ )
# add 3d provider if available and not already added
- if "3d" not in [p.id() for p in QgsApplication.processingRegistry().providers()]:
+ if "3d" not in [
+ p.id() for p in QgsApplication.processingRegistry().providers()
+ ]:
try:
from qgis._3d import Qgs3DAlgorithms
- QgsApplication.processingRegistry().addProvider(Qgs3DAlgorithms(QgsApplication.processingRegistry()))
+
+ QgsApplication.processingRegistry().addProvider(
+ Qgs3DAlgorithms(QgsApplication.processingRegistry())
+ )
except ImportError:
# no 3d library available
pass
@@ -104,25 +127,23 @@ def initialize():
basic_providers = [
QgisAlgorithmProvider,
GdalAlgorithmProvider,
- ScriptAlgorithmProvider
+ ScriptAlgorithmProvider,
]
# model providers are deferred for qgis_process startup
- if QgsApplication.platform() != 'qgis_process':
- basic_providers.extend([
- ModelerAlgorithmProvider,
- ProjectProvider
- ])
+ if QgsApplication.platform() != "qgis_process":
+ basic_providers.extend([ModelerAlgorithmProvider, ProjectProvider])
for c in basic_providers:
p = c()
if QgsApplication.processingRegistry().addProvider(p):
Processing.BASIC_PROVIDERS.append(p)
- if QgsApplication.platform() == 'external':
+ if QgsApplication.platform() == "external":
# for external applications we must also load the builtin providers stored in separate plugins
try:
from grassprovider.grass_provider import GrassProvider
+
p = GrassProvider()
if QgsApplication.processingRegistry().addProvider(p):
Processing.BASIC_PROVIDERS.append(p)
@@ -142,9 +163,7 @@ def perform_deferred_model_initialization():
# Add the model providers
# note that we don't add the Project Provider, as this cannot be called
# from qgis_process
- model_providers = [
- ModelerAlgorithmProvider
- ]
+ model_providers = [ModelerAlgorithmProvider]
for c in model_providers:
p = c()
@@ -169,7 +188,7 @@ def runAlgorithm(algOrName, parameters, onFinish=None, feedback=None, context=No
feedback = QgsProcessingFeedback()
if alg is None:
- msg = Processing.tr('Error: Algorithm {0} not found\n').format(algOrName)
+ msg = Processing.tr("Error: Algorithm {0} not found\n").format(algOrName)
feedback.reportError(msg)
raise QgsProcessingException(msg)
@@ -181,18 +200,22 @@ def runAlgorithm(algOrName, parameters, onFinish=None, feedback=None, context=No
ok, msg = alg.checkParameterValues(parameters, context)
if not ok:
- msg = Processing.tr('Unable to execute algorithm\n{0}').format(msg)
+ msg = Processing.tr("Unable to execute algorithm\n{0}").format(msg)
feedback.reportError(msg)
raise QgsProcessingException(msg)
if not alg.validateInputCrs(parameters, context):
feedback.pushInfo(
- Processing.tr('Warning: Not all input layers use the same CRS.\nThis can cause unexpected results.'))
-
- ret, results = execute(alg, parameters, context, feedback, catch_exceptions=False)
+ Processing.tr(
+ "Warning: Not all input layers use the same CRS.\nThis can cause unexpected results."
+ )
+ )
+
+ ret, results = execute(
+ alg, parameters, context, feedback, catch_exceptions=False
+ )
if ret:
- feedback.pushInfo(
- Processing.tr('Results: {}').format(results))
+ feedback.pushInfo(Processing.tr("Results: {}").format(results))
if onFinish is not None:
onFinish(alg, context, feedback)
@@ -202,19 +225,33 @@ def runAlgorithm(algOrName, parameters, onFinish=None, feedback=None, context=No
if out.name() not in results:
continue
- if isinstance(out, (QgsProcessingOutputVectorLayer, QgsProcessingOutputRasterLayer, QgsProcessingOutputPointCloudLayer, QgsProcessingOutputMapLayer)):
+ if isinstance(
+ out,
+ (
+ QgsProcessingOutputVectorLayer,
+ QgsProcessingOutputRasterLayer,
+ QgsProcessingOutputPointCloudLayer,
+ QgsProcessingOutputMapLayer,
+ ),
+ ):
result = results[out.name()]
if not isinstance(result, QgsMapLayer):
- layer = context.takeResultLayer(result) # transfer layer ownership out of context
+ layer = context.takeResultLayer(
+ result
+ ) # transfer layer ownership out of context
if layer:
- results[out.name()] = layer # replace layer string ref with actual layer (+ownership)
+ results[out.name()] = (
+ layer # replace layer string ref with actual layer (+ownership)
+ )
elif isinstance(out, QgsProcessingOutputMultipleLayers):
result = results[out.name()]
if result:
layers_result = []
for l in result:
if not isinstance(l, QgsMapLayer):
- layer = context.takeResultLayer(l) # transfer layer ownership out of context
+ layer = context.takeResultLayer(
+ l
+ ) # transfer layer ownership out of context
if layer:
layers_result.append(layer)
else:
@@ -222,8 +259,9 @@ def runAlgorithm(algOrName, parameters, onFinish=None, feedback=None, context=No
else:
layers_result.append(l)
- results[
- out.name()] = layers_result # replace layers strings ref with actual layers (+ownership)
+ results[out.name()] = (
+ layers_result # replace layers strings ref with actual layers (+ownership)
+ )
else:
msg = Processing.tr("There were errors executing the algorithm.")
@@ -235,7 +273,7 @@ def runAlgorithm(algOrName, parameters, onFinish=None, feedback=None, context=No
return results
@staticmethod
- def tr(string, context=''):
- if context == '':
- context = 'Processing'
+ def tr(string, context=""):
+ if context == "":
+ context = "Processing"
return QCoreApplication.translate(context, string)
diff --git a/python/plugins/processing/core/ProcessingConfig.py b/python/plugins/processing/core/ProcessingConfig.py
index 07921576be17..2b9d67650cb4 100644
--- a/python/plugins/processing/core/ProcessingConfig.py
+++ b/python/plugins/processing/core/ProcessingConfig.py
@@ -15,20 +15,22 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'August 2012'
-__copyright__ = '(C) 2012, Victor Olaya'
+__author__ = "Victor Olaya"
+__date__ = "August 2012"
+__copyright__ = "(C) 2012, Victor Olaya"
import os
import tempfile
from qgis.PyQt.QtCore import QCoreApplication, QObject, pyqtSignal
-from qgis.core import (NULL,
- QgsApplication,
- QgsSettings,
- QgsVectorFileWriter,
- QgsRasterFileWriter,
- QgsProcessingUtils)
+from qgis.core import (
+ NULL,
+ QgsApplication,
+ QgsSettings,
+ QgsVectorFileWriter,
+ QgsRasterFileWriter,
+ QgsProcessingUtils,
+)
from processing.tools.system import defaultOutputFolder
import processing.tools.dataobjects
from multiprocessing import cpu_count
@@ -42,26 +44,26 @@ class SettingsWatcher(QObject):
class ProcessingConfig:
- OUTPUT_FOLDER = 'OUTPUTS_FOLDER'
- RASTER_STYLE = 'RASTER_STYLE'
- VECTOR_POINT_STYLE = 'VECTOR_POINT_STYLE'
- VECTOR_LINE_STYLE = 'VECTOR_LINE_STYLE'
- VECTOR_POLYGON_STYLE = 'VECTOR_POLYGON_STYLE'
- FILTER_INVALID_GEOMETRIES = 'FILTER_INVALID_GEOMETRIES'
- PREFER_FILENAME_AS_LAYER_NAME = 'prefer-filename-as-layer-name'
- KEEP_DIALOG_OPEN = 'KEEP_DIALOG_OPEN'
- PRE_EXECUTION_SCRIPT = 'PRE_EXECUTION_SCRIPT'
- POST_EXECUTION_SCRIPT = 'POST_EXECUTION_SCRIPT'
- SHOW_CRS_DEF = 'SHOW_CRS_DEF'
- WARN_UNMATCHING_CRS = 'WARN_UNMATCHING_CRS'
- SHOW_PROVIDERS_TOOLTIP = 'SHOW_PROVIDERS_TOOLTIP'
- SHOW_ALGORITHMS_KNOWN_ISSUES = 'SHOW_ALGORITHMS_KNOWN_ISSUES'
- MAX_THREADS = 'MAX_THREADS'
- DEFAULT_OUTPUT_RASTER_LAYER_EXT = 'default-output-raster-ext'
- DEFAULT_OUTPUT_VECTOR_LAYER_EXT = 'default-output-vector-ext'
- TEMP_PATH = 'temp-path'
- RESULTS_GROUP_NAME = 'RESULTS_GROUP_NAME'
- VECTOR_FEATURE_COUNT = 'VECTOR_FEATURE_COUNT'
+ OUTPUT_FOLDER = "OUTPUTS_FOLDER"
+ RASTER_STYLE = "RASTER_STYLE"
+ VECTOR_POINT_STYLE = "VECTOR_POINT_STYLE"
+ VECTOR_LINE_STYLE = "VECTOR_LINE_STYLE"
+ VECTOR_POLYGON_STYLE = "VECTOR_POLYGON_STYLE"
+ FILTER_INVALID_GEOMETRIES = "FILTER_INVALID_GEOMETRIES"
+ PREFER_FILENAME_AS_LAYER_NAME = "prefer-filename-as-layer-name"
+ KEEP_DIALOG_OPEN = "KEEP_DIALOG_OPEN"
+ PRE_EXECUTION_SCRIPT = "PRE_EXECUTION_SCRIPT"
+ POST_EXECUTION_SCRIPT = "POST_EXECUTION_SCRIPT"
+ SHOW_CRS_DEF = "SHOW_CRS_DEF"
+ WARN_UNMATCHING_CRS = "WARN_UNMATCHING_CRS"
+ SHOW_PROVIDERS_TOOLTIP = "SHOW_PROVIDERS_TOOLTIP"
+ SHOW_ALGORITHMS_KNOWN_ISSUES = "SHOW_ALGORITHMS_KNOWN_ISSUES"
+ MAX_THREADS = "MAX_THREADS"
+ DEFAULT_OUTPUT_RASTER_LAYER_EXT = "default-output-raster-ext"
+ DEFAULT_OUTPUT_VECTOR_LAYER_EXT = "default-output-vector-ext"
+ TEMP_PATH = "temp-path"
+ RESULTS_GROUP_NAME = "RESULTS_GROUP_NAME"
+ VECTOR_FEATURE_COUNT = "VECTOR_FEATURE_COUNT"
settings = {}
settingIcons = {}
@@ -69,128 +71,213 @@ class ProcessingConfig:
@staticmethod
def initialize():
icon = QgsApplication.getThemeIcon("/processingAlgorithm.svg")
- ProcessingConfig.settingIcons['General'] = icon
- ProcessingConfig.addSetting(Setting(
- ProcessingConfig.tr('General'),
- ProcessingConfig.KEEP_DIALOG_OPEN,
- ProcessingConfig.tr('Keep dialog open after running an algorithm'), True))
- ProcessingConfig.addSetting(Setting(
- ProcessingConfig.tr('General'),
- ProcessingConfig.PREFER_FILENAME_AS_LAYER_NAME,
- ProcessingConfig.tr('Prefer output filename for layer names'), True,
- hasSettingEntry=True))
- ProcessingConfig.addSetting(Setting(
- ProcessingConfig.tr('General'),
- ProcessingConfig.SHOW_PROVIDERS_TOOLTIP,
- ProcessingConfig.tr('Show tooltip when there are disabled providers'), True))
- ProcessingConfig.addSetting(Setting(
- ProcessingConfig.tr('General'),
- ProcessingConfig.OUTPUT_FOLDER,
- ProcessingConfig.tr('Output folder'), defaultOutputFolder(),
- valuetype=Setting.FOLDER))
- ProcessingConfig.addSetting(Setting(
- ProcessingConfig.tr('General'),
- ProcessingConfig.SHOW_CRS_DEF,
- ProcessingConfig.tr('Show layer CRS definition in selection boxes'), True))
- ProcessingConfig.addSetting(Setting(
- ProcessingConfig.tr('General'),
- ProcessingConfig.WARN_UNMATCHING_CRS,
- ProcessingConfig.tr("Warn before executing if parameter CRS's do not match"), True))
- ProcessingConfig.addSetting(Setting(
- ProcessingConfig.tr('General'),
- ProcessingConfig.SHOW_ALGORITHMS_KNOWN_ISSUES,
- ProcessingConfig.tr("Show algorithms with known issues"), False))
- ProcessingConfig.addSetting(Setting(
- ProcessingConfig.tr('General'),
- ProcessingConfig.RASTER_STYLE,
- ProcessingConfig.tr('Style for raster layers'), '',
- valuetype=Setting.FILE))
- ProcessingConfig.addSetting(Setting(
- ProcessingConfig.tr('General'),
- ProcessingConfig.VECTOR_POINT_STYLE,
- ProcessingConfig.tr('Style for point layers'), '',
- valuetype=Setting.FILE))
- ProcessingConfig.addSetting(Setting(
- ProcessingConfig.tr('General'),
- ProcessingConfig.VECTOR_LINE_STYLE,
- ProcessingConfig.tr('Style for line layers'), '',
- valuetype=Setting.FILE))
- ProcessingConfig.addSetting(Setting(
- ProcessingConfig.tr('General'),
- ProcessingConfig.VECTOR_POLYGON_STYLE,
- ProcessingConfig.tr('Style for polygon layers'), '',
- valuetype=Setting.FILE))
- ProcessingConfig.addSetting(Setting(
- ProcessingConfig.tr('General'),
- ProcessingConfig.PRE_EXECUTION_SCRIPT,
- ProcessingConfig.tr('Pre-execution script'), '',
- valuetype=Setting.FILE))
- ProcessingConfig.addSetting(Setting(
- ProcessingConfig.tr('General'),
- ProcessingConfig.POST_EXECUTION_SCRIPT,
- ProcessingConfig.tr('Post-execution script'), '',
- valuetype=Setting.FILE))
-
- invalidFeaturesOptions = [ProcessingConfig.tr('Do not filter (better performance)'),
- ProcessingConfig.tr('Skip (ignore) features with invalid geometries'),
- ProcessingConfig.tr('Stop algorithm execution when a geometry is invalid')]
- ProcessingConfig.addSetting(Setting(
- ProcessingConfig.tr('General'),
- ProcessingConfig.FILTER_INVALID_GEOMETRIES,
- ProcessingConfig.tr('Invalid features filtering'),
- invalidFeaturesOptions[2],
- valuetype=Setting.SELECTION,
- options=invalidFeaturesOptions))
-
- threads = QgsApplication.maxThreads() # if user specified limit for rendering, lets keep that as default here, otherwise max
- threads = cpu_count() if threads == -1 else threads # if unset, maxThreads() returns -1
- ProcessingConfig.addSetting(Setting(
- ProcessingConfig.tr('General'),
- ProcessingConfig.MAX_THREADS,
- ProcessingConfig.tr('Max Threads'), threads,
- valuetype=Setting.INT))
+ ProcessingConfig.settingIcons["General"] = icon
+ ProcessingConfig.addSetting(
+ Setting(
+ ProcessingConfig.tr("General"),
+ ProcessingConfig.KEEP_DIALOG_OPEN,
+ ProcessingConfig.tr("Keep dialog open after running an algorithm"),
+ True,
+ )
+ )
+ ProcessingConfig.addSetting(
+ Setting(
+ ProcessingConfig.tr("General"),
+ ProcessingConfig.PREFER_FILENAME_AS_LAYER_NAME,
+ ProcessingConfig.tr("Prefer output filename for layer names"),
+ True,
+ hasSettingEntry=True,
+ )
+ )
+ ProcessingConfig.addSetting(
+ Setting(
+ ProcessingConfig.tr("General"),
+ ProcessingConfig.SHOW_PROVIDERS_TOOLTIP,
+ ProcessingConfig.tr("Show tooltip when there are disabled providers"),
+ True,
+ )
+ )
+ ProcessingConfig.addSetting(
+ Setting(
+ ProcessingConfig.tr("General"),
+ ProcessingConfig.OUTPUT_FOLDER,
+ ProcessingConfig.tr("Output folder"),
+ defaultOutputFolder(),
+ valuetype=Setting.FOLDER,
+ )
+ )
+ ProcessingConfig.addSetting(
+ Setting(
+ ProcessingConfig.tr("General"),
+ ProcessingConfig.SHOW_CRS_DEF,
+ ProcessingConfig.tr("Show layer CRS definition in selection boxes"),
+ True,
+ )
+ )
+ ProcessingConfig.addSetting(
+ Setting(
+ ProcessingConfig.tr("General"),
+ ProcessingConfig.WARN_UNMATCHING_CRS,
+ ProcessingConfig.tr(
+ "Warn before executing if parameter CRS's do not match"
+ ),
+ True,
+ )
+ )
+ ProcessingConfig.addSetting(
+ Setting(
+ ProcessingConfig.tr("General"),
+ ProcessingConfig.SHOW_ALGORITHMS_KNOWN_ISSUES,
+ ProcessingConfig.tr("Show algorithms with known issues"),
+ False,
+ )
+ )
+ ProcessingConfig.addSetting(
+ Setting(
+ ProcessingConfig.tr("General"),
+ ProcessingConfig.RASTER_STYLE,
+ ProcessingConfig.tr("Style for raster layers"),
+ "",
+ valuetype=Setting.FILE,
+ )
+ )
+ ProcessingConfig.addSetting(
+ Setting(
+ ProcessingConfig.tr("General"),
+ ProcessingConfig.VECTOR_POINT_STYLE,
+ ProcessingConfig.tr("Style for point layers"),
+ "",
+ valuetype=Setting.FILE,
+ )
+ )
+ ProcessingConfig.addSetting(
+ Setting(
+ ProcessingConfig.tr("General"),
+ ProcessingConfig.VECTOR_LINE_STYLE,
+ ProcessingConfig.tr("Style for line layers"),
+ "",
+ valuetype=Setting.FILE,
+ )
+ )
+ ProcessingConfig.addSetting(
+ Setting(
+ ProcessingConfig.tr("General"),
+ ProcessingConfig.VECTOR_POLYGON_STYLE,
+ ProcessingConfig.tr("Style for polygon layers"),
+ "",
+ valuetype=Setting.FILE,
+ )
+ )
+ ProcessingConfig.addSetting(
+ Setting(
+ ProcessingConfig.tr("General"),
+ ProcessingConfig.PRE_EXECUTION_SCRIPT,
+ ProcessingConfig.tr("Pre-execution script"),
+ "",
+ valuetype=Setting.FILE,
+ )
+ )
+ ProcessingConfig.addSetting(
+ Setting(
+ ProcessingConfig.tr("General"),
+ ProcessingConfig.POST_EXECUTION_SCRIPT,
+ ProcessingConfig.tr("Post-execution script"),
+ "",
+ valuetype=Setting.FILE,
+ )
+ )
+
+ invalidFeaturesOptions = [
+ ProcessingConfig.tr("Do not filter (better performance)"),
+ ProcessingConfig.tr("Skip (ignore) features with invalid geometries"),
+ ProcessingConfig.tr("Stop algorithm execution when a geometry is invalid"),
+ ]
+ ProcessingConfig.addSetting(
+ Setting(
+ ProcessingConfig.tr("General"),
+ ProcessingConfig.FILTER_INVALID_GEOMETRIES,
+ ProcessingConfig.tr("Invalid features filtering"),
+ invalidFeaturesOptions[2],
+ valuetype=Setting.SELECTION,
+ options=invalidFeaturesOptions,
+ )
+ )
+
+ threads = (
+ QgsApplication.maxThreads()
+ ) # if user specified limit for rendering, lets keep that as default here, otherwise max
+ threads = (
+ cpu_count() if threads == -1 else threads
+ ) # if unset, maxThreads() returns -1
+ ProcessingConfig.addSetting(
+ Setting(
+ ProcessingConfig.tr("General"),
+ ProcessingConfig.MAX_THREADS,
+ ProcessingConfig.tr("Max Threads"),
+ threads,
+ valuetype=Setting.INT,
+ )
+ )
extensions = QgsVectorFileWriter.supportedFormatExtensions()
- ProcessingConfig.addSetting(Setting(
- ProcessingConfig.tr('General'),
- ProcessingConfig.DEFAULT_OUTPUT_VECTOR_LAYER_EXT,
- ProcessingConfig.tr('Default output vector layer extension'),
- QgsVectorFileWriter.supportedFormatExtensions()[0],
- valuetype=Setting.SELECTION_STORE_STRING,
- options=extensions,
- hasSettingEntry=True))
+ ProcessingConfig.addSetting(
+ Setting(
+ ProcessingConfig.tr("General"),
+ ProcessingConfig.DEFAULT_OUTPUT_VECTOR_LAYER_EXT,
+ ProcessingConfig.tr("Default output vector layer extension"),
+ QgsVectorFileWriter.supportedFormatExtensions()[0],
+ valuetype=Setting.SELECTION_STORE_STRING,
+ options=extensions,
+ hasSettingEntry=True,
+ )
+ )
extensions = QgsRasterFileWriter.supportedFormatExtensions()
- ProcessingConfig.addSetting(Setting(
- ProcessingConfig.tr('General'),
- ProcessingConfig.DEFAULT_OUTPUT_RASTER_LAYER_EXT,
- ProcessingConfig.tr('Default output raster layer extension'),
- 'tif',
- valuetype=Setting.SELECTION_STORE_STRING,
- options=extensions,
- hasSettingEntry=True))
-
- ProcessingConfig.addSetting(Setting(
- ProcessingConfig.tr('General'),
- ProcessingConfig.TEMP_PATH,
- ProcessingConfig.tr('Override temporary output folder path'), None,
- valuetype=Setting.FOLDER,
- placeholder=ProcessingConfig.tr('Leave blank for default'),
- hasSettingEntry=True))
-
- ProcessingConfig.addSetting(Setting(
- ProcessingConfig.tr('General'),
- ProcessingConfig.RESULTS_GROUP_NAME,
- ProcessingConfig.tr("Results group name"),
- "",
- valuetype=Setting.STRING,
- placeholder=ProcessingConfig.tr("Leave blank to avoid loading results in a predetermined group")
- ))
-
- ProcessingConfig.addSetting(Setting(
- ProcessingConfig.tr('General'),
- ProcessingConfig.VECTOR_FEATURE_COUNT,
- ProcessingConfig.tr('Show feature count for output vector layers'), False))
+ ProcessingConfig.addSetting(
+ Setting(
+ ProcessingConfig.tr("General"),
+ ProcessingConfig.DEFAULT_OUTPUT_RASTER_LAYER_EXT,
+ ProcessingConfig.tr("Default output raster layer extension"),
+ "tif",
+ valuetype=Setting.SELECTION_STORE_STRING,
+ options=extensions,
+ hasSettingEntry=True,
+ )
+ )
+
+ ProcessingConfig.addSetting(
+ Setting(
+ ProcessingConfig.tr("General"),
+ ProcessingConfig.TEMP_PATH,
+ ProcessingConfig.tr("Override temporary output folder path"),
+ None,
+ valuetype=Setting.FOLDER,
+ placeholder=ProcessingConfig.tr("Leave blank for default"),
+ hasSettingEntry=True,
+ )
+ )
+
+ ProcessingConfig.addSetting(
+ Setting(
+ ProcessingConfig.tr("General"),
+ ProcessingConfig.RESULTS_GROUP_NAME,
+ ProcessingConfig.tr("Results group name"),
+ "",
+ valuetype=Setting.STRING,
+ placeholder=ProcessingConfig.tr(
+ "Leave blank to avoid loading results in a predetermined group"
+ ),
+ )
+ )
+
+ ProcessingConfig.addSetting(
+ Setting(
+ ProcessingConfig.tr("General"),
+ ProcessingConfig.VECTOR_FEATURE_COUNT,
+ ProcessingConfig.tr("Show feature count for output vector layers"),
+ False,
+ )
+ )
@staticmethod
def setGroupIcon(group, icon):
@@ -198,7 +285,7 @@ def setGroupIcon(group, icon):
@staticmethod
def getGroupIcon(group):
- if group == ProcessingConfig.tr('General'):
+ if group == ProcessingConfig.tr("General"):
return QgsApplication.getThemeIcon("/processingAlgorithm.svg")
if group in ProcessingConfig.settingIcons:
return ProcessingConfig.settingIcons[group]
@@ -215,7 +302,7 @@ def removeSetting(name):
@staticmethod
def getSettings():
- '''Return settings as a dict with group names as keys and lists of settings as values'''
+ """Return settings as a dict with group names as keys and lists of settings as values"""
settings = {}
for setting in list(ProcessingConfig.settings.values()):
if setting.group not in settings:
@@ -251,21 +338,23 @@ def getSetting(name, readable=False):
def setSettingValue(name, value):
if name in list(ProcessingConfig.settings.keys()):
if ProcessingConfig.settings[name].valuetype == Setting.SELECTION:
- ProcessingConfig.settings[name].setValue(ProcessingConfig.settings[name].options[value])
+ ProcessingConfig.settings[name].setValue(
+ ProcessingConfig.settings[name].options[value]
+ )
else:
ProcessingConfig.settings[name].setValue(value)
ProcessingConfig.settings[name].save()
@staticmethod
- def tr(string, context=''):
- if context == '':
- context = 'ProcessingConfig'
+ def tr(string, context=""):
+ if context == "":
+ context = "ProcessingConfig"
return QCoreApplication.translate(context, string)
class Setting:
- """A simple config parameter that will appear on the config dialog.
- """
+ """A simple config parameter that will appear on the config dialog."""
+
STRING = 0
FILE = 1
FOLDER = 2
@@ -275,14 +364,27 @@ class Setting:
MULTIPLE_FOLDERS = 6
SELECTION_STORE_STRING = 7
- def __init__(self, group, name, description, default, hidden=False, valuetype=None,
- validator=None, options=None, placeholder="", hasSettingEntry=False):
+ def __init__(
+ self,
+ group,
+ name,
+ description,
+ default,
+ hidden=False,
+ valuetype=None,
+ validator=None,
+ options=None,
+ placeholder="",
+ hasSettingEntry=False,
+ ):
"""
hasSettingEntry is true if the given setting is part of QgsSettingsRegistry entries
"""
self.group = group
self.name = name
- self.qname = ("qgis/configuration/" if hasSettingEntry else "Processing/Configuration/") + self.name
+ self.qname = (
+ "qgis/configuration/" if hasSettingEntry else "Processing/Configuration/"
+ ) + self.name
self.description = description
self.default = default
self.hidden = hidden
@@ -298,38 +400,52 @@ def __init__(self, group, name, description, default, hidden=False, valuetype=No
if validator is None:
if self.valuetype == self.FLOAT:
+
def checkFloat(v):
try:
float(v)
except ValueError:
- raise ValueError(self.tr('Wrong parameter value:\n{0}').format(v))
+ raise ValueError(
+ self.tr("Wrong parameter value:\n{0}").format(v)
+ )
validator = checkFloat
elif self.valuetype == self.INT:
+
def checkInt(v):
try:
int(v)
except ValueError:
- raise ValueError(self.tr('Wrong parameter value:\n{0}').format(v))
+ raise ValueError(
+ self.tr("Wrong parameter value:\n{0}").format(v)
+ )
validator = checkInt
elif self.valuetype in [self.FILE, self.FOLDER]:
+
def checkFileOrFolder(v):
if v and not os.path.exists(v):
- raise ValueError(self.tr('Specified path does not exist:\n{0}').format(v))
+ raise ValueError(
+ self.tr("Specified path does not exist:\n{0}").format(v)
+ )
validator = checkFileOrFolder
elif self.valuetype == self.MULTIPLE_FOLDERS:
+
def checkMultipleFolders(v):
- folders = v.split(';')
+ folders = v.split(";")
for f in folders:
if f and not os.path.exists(f):
- raise ValueError(self.tr('Specified path does not exist:\n{0}').format(f))
+ raise ValueError(
+ self.tr("Specified path does not exist:\n{0}").format(f)
+ )
validator = checkMultipleFolders
else:
+
def validator(x):
return True
+
self.validator = validator
self.value = default
@@ -365,9 +481,9 @@ def save(self, qsettings=None):
qsettings.setValue(self.qname, self.value)
def __str__(self):
- return self.name + '=' + str(self.value)
+ return self.name + "=" + str(self.value)
- def tr(self, string, context=''):
- if context == '':
- context = 'ProcessingConfig'
+ def tr(self, string, context=""):
+ if context == "":
+ context = "ProcessingConfig"
return QCoreApplication.translate(context, string)
diff --git a/python/plugins/processing/core/ProcessingResults.py b/python/plugins/processing/core/ProcessingResults.py
index b7d3eb7de93d..9586f0002b82 100644
--- a/python/plugins/processing/core/ProcessingResults.py
+++ b/python/plugins/processing/core/ProcessingResults.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'August 2012'
-__copyright__ = '(C) 2012, Victor Olaya'
+__author__ = "Victor Olaya"
+__date__ = "August 2012"
+__copyright__ = "(C) 2012, Victor Olaya"
from qgis.PyQt.QtCore import QObject, pyqtSignal
diff --git a/python/plugins/processing/core/defaultproviders.py b/python/plugins/processing/core/defaultproviders.py
index 99bf07d26e2f..f65aad5ddd9c 100644
--- a/python/plugins/processing/core/defaultproviders.py
+++ b/python/plugins/processing/core/defaultproviders.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'May 2016'
-__copyright__ = '(C) 2016, Victor Olaya'
+__author__ = "Victor Olaya"
+__date__ = "May 2016"
+__copyright__ = "(C) 2016, Victor Olaya"
def loadDefaultProviders():
diff --git a/python/plugins/processing/core/outputs.py b/python/plugins/processing/core/outputs.py
index 094d27d9711c..a19dca82c93c 100644
--- a/python/plugins/processing/core/outputs.py
+++ b/python/plugins/processing/core/outputs.py
@@ -15,31 +15,33 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'August 2012'
-__copyright__ = '(C) 2012, Victor Olaya'
+__author__ = "Victor Olaya"
+__date__ = "August 2012"
+__copyright__ = "(C) 2012, Victor Olaya"
import sys
-from qgis.core import (QgsExpressionContext,
- QgsExpressionContextUtils,
- QgsExpression,
- QgsExpressionContextScope,
- QgsProject,
- QgsSettings,
- QgsVectorFileWriter,
- QgsProcessingUtils,
- QgsProcessingParameterDefinition,
- QgsProcessingOutputRasterLayer,
- QgsProcessingOutputVectorLayer,
- QgsProcessingOutputMapLayer,
- QgsProcessingOutputHtml,
- QgsProcessingOutputNumber,
- QgsProcessingOutputString,
- QgsProcessingOutputBoolean,
- QgsProcessingOutputFolder,
- QgsProcessingOutputMultipleLayers,
- QgsProcessingOutputPointCloudLayer)
+from qgis.core import (
+ QgsExpressionContext,
+ QgsExpressionContextUtils,
+ QgsExpression,
+ QgsExpressionContextScope,
+ QgsProject,
+ QgsSettings,
+ QgsVectorFileWriter,
+ QgsProcessingUtils,
+ QgsProcessingParameterDefinition,
+ QgsProcessingOutputRasterLayer,
+ QgsProcessingOutputVectorLayer,
+ QgsProcessingOutputMapLayer,
+ QgsProcessingOutputHtml,
+ QgsProcessingOutputNumber,
+ QgsProcessingOutputString,
+ QgsProcessingOutputBoolean,
+ QgsProcessingOutputFolder,
+ QgsProcessingOutputMultipleLayers,
+ QgsProcessingOutputPointCloudLayer,
+)
def getOutputFromString(s):
@@ -51,22 +53,22 @@ def getOutputFromString(s):
return clazz(*params)
else:
tokens = s.split("=")
- if tokens[1].lower()[: len('output')] != 'output':
+ if tokens[1].lower()[: len("output")] != "output":
return None
name = tokens[0]
description = tokens[0]
- token = tokens[1].strip()[len('output') + 1:]
+ token = tokens[1].strip()[len("output") + 1 :]
out = None
- if token.lower().strip().startswith('outputraster'):
+ if token.lower().strip().startswith("outputraster"):
out = QgsProcessingOutputRasterLayer(name, description)
- elif token.lower().strip() == 'outputvector':
+ elif token.lower().strip() == "outputvector":
out = QgsProcessingOutputVectorLayer(name, description)
- elif token.lower().strip() == 'outputlayer':
+ elif token.lower().strip() == "outputlayer":
out = QgsProcessingOutputMapLayer(name, description)
- elif token.lower().strip() == 'outputmultilayers':
+ elif token.lower().strip() == "outputmultilayers":
out = QgsProcessingOutputMultipleLayers(name, description)
# elif token.lower().strip() == 'vector point':
# out = OutputVector(datatype=[dataobjects.TYPE_VECTOR_POINT])
@@ -76,22 +78,22 @@ def getOutputFromString(s):
# out = OutputVector(datatype=[OutputVector.TYPE_VECTOR_POLYGON])
# elif token.lower().strip().startswith('table'):
# out = OutputTable()
- elif token.lower().strip().startswith('outputhtml'):
+ elif token.lower().strip().startswith("outputhtml"):
out = QgsProcessingOutputHtml(name, description)
# elif token.lower().strip().startswith('file'):
# out = OutputFile()
# ext = token.strip()[len('file') + 1:]
# if ext:
# out.ext = ext
- elif token.lower().strip().startswith('outputfolder'):
+ elif token.lower().strip().startswith("outputfolder"):
out = QgsProcessingOutputFolder(name, description)
- elif token.lower().strip().startswith('outputnumber'):
+ elif token.lower().strip().startswith("outputnumber"):
out = QgsProcessingOutputNumber(name, description)
- elif token.lower().strip().startswith('outputstring'):
+ elif token.lower().strip().startswith("outputstring"):
out = QgsProcessingOutputString(name, description)
- elif token.lower().strip().startswith('outputboolean'):
+ elif token.lower().strip().startswith("outputboolean"):
out = QgsProcessingOutputBoolean(name, description)
- elif token.lower().strip().startswith('outputPointCloud'):
+ elif token.lower().strip().startswith("outputPointCloud"):
out = QgsProcessingOutputPointCloudLayer(name, description)
# elif token.lower().strip().startswith('extent'):
# out = OutputExtent()
diff --git a/python/plugins/processing/core/parameters.py b/python/plugins/processing/core/parameters.py
index b60d4f636b19..1b9fce0872c0 100644
--- a/python/plugins/processing/core/parameters.py
+++ b/python/plugins/processing/core/parameters.py
@@ -15,88 +15,95 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'August 2012'
-__copyright__ = '(C) 2012, Victor Olaya'
+__author__ = "Victor Olaya"
+__date__ = "August 2012"
+__copyright__ = "(C) 2012, Victor Olaya"
import sys
-from qgis.core import (Qgis,
- QgsRasterLayer,
- QgsVectorLayer,
- QgsMapLayer,
- QgsCoordinateReferenceSystem,
- QgsExpression,
- QgsProject,
- QgsRectangle,
- QgsWkbTypes,
- QgsVectorFileWriter,
- QgsProcessing,
- QgsProcessingUtils,
- QgsProcessingParameters,
- QgsProcessingParameterDefinition,
- QgsProcessingParameterRasterLayer,
- QgsProcessingParameterVectorLayer,
- QgsProcessingParameterBand,
- QgsProcessingParameterBoolean,
- QgsProcessingParameterCrs,
- QgsProcessingParameterRange,
- QgsProcessingParameterPoint,
- QgsProcessingParameterGeometry,
- QgsProcessingParameterEnum,
- QgsProcessingParameterExtent,
- QgsProcessingParameterExpression,
- QgsProcessingParameterMatrix,
- QgsProcessingParameterFile,
- QgsProcessingParameterField,
- QgsProcessingParameterVectorDestination,
- QgsProcessingParameterFileDestination,
- QgsProcessingParameterFolderDestination,
- QgsProcessingParameterRasterDestination,
- QgsProcessingParameterPointCloudDestination,
- QgsProcessingParameterString,
- QgsProcessingParameterMapLayer,
- QgsProcessingParameterMultipleLayers,
- QgsProcessingParameterFeatureSource,
- QgsProcessingParameterNumber,
- QgsProcessingParameterColor,
- QgsProcessingParameterPointCloudLayer,
- QgsProcessingParameterAnnotationLayer)
+from qgis.core import (
+ Qgis,
+ QgsRasterLayer,
+ QgsVectorLayer,
+ QgsMapLayer,
+ QgsCoordinateReferenceSystem,
+ QgsExpression,
+ QgsProject,
+ QgsRectangle,
+ QgsWkbTypes,
+ QgsVectorFileWriter,
+ QgsProcessing,
+ QgsProcessingUtils,
+ QgsProcessingParameters,
+ QgsProcessingParameterDefinition,
+ QgsProcessingParameterRasterLayer,
+ QgsProcessingParameterVectorLayer,
+ QgsProcessingParameterBand,
+ QgsProcessingParameterBoolean,
+ QgsProcessingParameterCrs,
+ QgsProcessingParameterRange,
+ QgsProcessingParameterPoint,
+ QgsProcessingParameterGeometry,
+ QgsProcessingParameterEnum,
+ QgsProcessingParameterExtent,
+ QgsProcessingParameterExpression,
+ QgsProcessingParameterMatrix,
+ QgsProcessingParameterFile,
+ QgsProcessingParameterField,
+ QgsProcessingParameterVectorDestination,
+ QgsProcessingParameterFileDestination,
+ QgsProcessingParameterFolderDestination,
+ QgsProcessingParameterRasterDestination,
+ QgsProcessingParameterPointCloudDestination,
+ QgsProcessingParameterString,
+ QgsProcessingParameterMapLayer,
+ QgsProcessingParameterMultipleLayers,
+ QgsProcessingParameterFeatureSource,
+ QgsProcessingParameterNumber,
+ QgsProcessingParameterColor,
+ QgsProcessingParameterPointCloudLayer,
+ QgsProcessingParameterAnnotationLayer,
+)
from qgis.PyQt.QtCore import QCoreApplication
-PARAMETER_NUMBER = 'number'
-PARAMETER_DISTANCE = 'distance'
-PARAMETER_SCALE = 'scale'
-PARAMETER_RASTER = 'raster'
-PARAMETER_TABLE = 'vector'
-PARAMETER_VECTOR = 'source'
-PARAMETER_STRING = 'string'
-PARAMETER_EXPRESSION = 'expression'
-PARAMETER_BOOLEAN = 'boolean'
-PARAMETER_TABLE_FIELD = 'field'
-PARAMETER_EXTENT = 'extent'
-PARAMETER_FILE = 'file'
-PARAMETER_POINT = 'point'
-PARAMETER_GEOMETRY = 'geometry'
-PARAMETER_CRS = 'crs'
-PARAMETER_MULTIPLE = 'multilayer'
-PARAMETER_BAND = 'band'
-PARAMETER_LAYOUTITEM = 'layoutitem'
-PARAMETER_MAP_LAYER = 'layer'
-PARAMETER_RANGE = 'range'
-PARAMETER_ENUM = 'enum'
-PARAMETER_MATRIX = 'matrix'
-PARAMETER_VECTOR_DESTINATION = 'vectorDestination'
-PARAMETER_FILE_DESTINATION = 'fileDestination'
-PARAMETER_FOLDER_DESTINATION = 'folderDestination'
-PARAMETER_RASTER_DESTINATION = 'rasterDestination'
-PARAMETER_POINTCLOUD_DESTINATION = 'pointCloudDestination'
+PARAMETER_NUMBER = "number"
+PARAMETER_DISTANCE = "distance"
+PARAMETER_SCALE = "scale"
+PARAMETER_RASTER = "raster"
+PARAMETER_TABLE = "vector"
+PARAMETER_VECTOR = "source"
+PARAMETER_STRING = "string"
+PARAMETER_EXPRESSION = "expression"
+PARAMETER_BOOLEAN = "boolean"
+PARAMETER_TABLE_FIELD = "field"
+PARAMETER_EXTENT = "extent"
+PARAMETER_FILE = "file"
+PARAMETER_POINT = "point"
+PARAMETER_GEOMETRY = "geometry"
+PARAMETER_CRS = "crs"
+PARAMETER_MULTIPLE = "multilayer"
+PARAMETER_BAND = "band"
+PARAMETER_LAYOUTITEM = "layoutitem"
+PARAMETER_MAP_LAYER = "layer"
+PARAMETER_RANGE = "range"
+PARAMETER_ENUM = "enum"
+PARAMETER_MATRIX = "matrix"
+PARAMETER_VECTOR_DESTINATION = "vectorDestination"
+PARAMETER_FILE_DESTINATION = "fileDestination"
+PARAMETER_FOLDER_DESTINATION = "folderDestination"
+PARAMETER_RASTER_DESTINATION = "rasterDestination"
+PARAMETER_POINTCLOUD_DESTINATION = "pointCloudDestination"
-def getParameterFromString(s, context=''):
+def getParameterFromString(s, context=""):
# Try the parameter definitions used in description files
- if '|' in s and (s.startswith("QgsProcessingParameter") or s.startswith("*QgsProcessingParameter") or s.startswith('Parameter') or s.startswith('*Parameter')):
+ if "|" in s and (
+ s.startswith("QgsProcessingParameter")
+ or s.startswith("*QgsProcessingParameter")
+ or s.startswith("Parameter")
+ or s.startswith("*Parameter")
+ ):
isAdvanced = False
if s.startswith("*"):
s = s[1:]
@@ -109,89 +116,107 @@ def getParameterFromString(s, context=''):
# convert to correct type
if clazz == QgsProcessingParameterRasterLayer:
if len(params) > 3:
- params[3] = True if params[3].lower() == 'true' else False
+ params[3] = True if params[3].lower() == "true" else False
elif clazz == QgsProcessingParameterPointCloudLayer:
if len(params) > 3:
- params[3] = True if params[3].lower() == 'true' else False
+ params[3] = True if params[3].lower() == "true" else False
elif clazz == QgsProcessingParameterAnnotationLayer:
if len(params) > 3:
- params[3] = True if params[3].lower() == 'true' else False
+ params[3] = True if params[3].lower() == "true" else False
elif clazz == QgsProcessingParameterBand:
if len(params) > 4:
- params[4] = True if params[4].lower() == 'true' else False
+ params[4] = True if params[4].lower() == "true" else False
if len(params) > 5:
- params[5] = True if params[5].lower() == 'true' else False
+ params[5] = True if params[5].lower() == "true" else False
elif clazz == QgsProcessingParameterVectorLayer:
if len(params) > 2:
try:
- params[2] = [int(p) for p in params[2].split(';')]
+ params[2] = [int(p) for p in params[2].split(";")]
except ValueError:
- params[2] = [getattr(QgsProcessing, p.split(".")[1]) for p in params[2].split(';')]
+ params[2] = [
+ getattr(QgsProcessing, p.split(".")[1])
+ for p in params[2].split(";")
+ ]
if len(params) > 4:
- params[4] = True if params[4].lower() == 'true' else False
+ params[4] = True if params[4].lower() == "true" else False
elif clazz == QgsProcessingParameterMapLayer:
if len(params) > 3:
- params[3] = True if params[3].lower() == 'true' else False
+ params[3] = True if params[3].lower() == "true" else False
try:
- params[4] = [int(p) for p in params[4].split(';')]
+ params[4] = [int(p) for p in params[4].split(";")]
except ValueError:
- params[4] = [getattr(QgsProcessing, p.split(".")[1]) for p in params[4].split(';')]
+ params[4] = [
+ getattr(QgsProcessing, p.split(".")[1])
+ for p in params[4].split(";")
+ ]
elif clazz == QgsProcessingParameterBoolean:
if len(params) > 2:
- params[2] = True if params[2].lower() == 'true' else False
+ params[2] = True if params[2].lower() == "true" else False
if len(params) > 3:
- params[3] = True if params[3].lower() == 'true' else False
+ params[3] = True if params[3].lower() == "true" else False
elif clazz == QgsProcessingParameterPoint:
if len(params) > 3:
- params[3] = True if params[3].lower() == 'true' else False
+ params[3] = True if params[3].lower() == "true" else False
elif clazz == QgsProcessingParameterGeometry:
if len(params) > 3:
- params[3] = True if params[3].lower() == 'true' else False
+ params[3] = True if params[3].lower() == "true" else False
if len(params) > 4:
try:
- params[4] = [int(p) for p in params[4].split(';')]
+ params[4] = [int(p) for p in params[4].split(";")]
except ValueError:
- params[4] = [getattr(QgsWkbTypes, p.split(".")[1]) for p in params[4].split(';')]
+ params[4] = [
+ getattr(QgsWkbTypes, p.split(".")[1])
+ for p in params[4].split(";")
+ ]
if len(params) > 5:
- params[5] = True if params[5].lower() == 'true' else False
+ params[5] = True if params[5].lower() == "true" else False
elif clazz == QgsProcessingParameterCrs:
if len(params) > 3:
- params[3] = True if params[3].lower() == 'true' else False
+ params[3] = True if params[3].lower() == "true" else False
elif clazz == QgsProcessingParameterRange:
if len(params) > 2:
try:
params[2] = Qgis.ProcessingNumberParameterType(int(params[2]))
except ValueError:
- params[2] = getattr(QgsProcessingParameterNumber, params[2].split(".")[1])
+ params[2] = getattr(
+ QgsProcessingParameterNumber, params[2].split(".")[1]
+ )
if len(params) > 4:
- params[4] = True if params[4].lower() == 'true' else False
+ params[4] = True if params[4].lower() == "true" else False
elif clazz == QgsProcessingParameterExtent:
if len(params) > 3:
- params[3] = True if params[3].lower() == 'true' else False
+ params[3] = True if params[3].lower() == "true" else False
elif clazz == QgsProcessingParameterExpression:
if len(params) > 3:
- params[3] = True if params[3].lower() == 'true' else False
+ params[3] = True if params[3].lower() == "true" else False
elif clazz == QgsProcessingParameterEnum:
if len(params) > 2:
- params[2] = params[2].split(';')
+ params[2] = params[2].split(";")
if len(params) > 3:
- params[3] = True if params[3].lower() == 'true' else False
+ params[3] = True if params[3].lower() == "true" else False
if len(params) > 4:
# For multiple values; default value is a list of int
if params[3] is True:
- params[4] = [int(v) for v in params[4].split(',')] if params[4] is not None else None
+ params[4] = (
+ [int(v) for v in params[4].split(",")]
+ if params[4] is not None
+ else None
+ )
else:
params[4] = int(params[4]) if params[4] is not None else None
if len(params) > 5:
- params[5] = True if params[5].lower() == 'true' else False
+ params[5] = True if params[5].lower() == "true" else False
elif clazz == QgsProcessingParameterFeatureSource:
if len(params) > 2:
try:
- params[2] = [int(p) for p in params[2].split(';')]
+ params[2] = [int(p) for p in params[2].split(";")]
except ValueError:
- params[2] = [getattr(QgsProcessing, p.split(".")[1]) for p in params[2].split(';')]
+ params[2] = [
+ getattr(QgsProcessing, p.split(".")[1])
+ for p in params[2].split(";")
+ ]
if len(params) > 4:
- params[4] = True if params[4].lower() == 'true' else False
+ params[4] = True if params[4].lower() == "true" else False
elif clazz == QgsProcessingParameterMultipleLayers:
if len(params) > 2:
try:
@@ -199,81 +224,99 @@ def getParameterFromString(s, context=''):
except ValueError:
params[2] = getattr(QgsProcessing, params[2].split(".")[1])
if len(params) > 4:
- params[4] = True if params[4].lower() == 'true' else False
+ params[4] = True if params[4].lower() == "true" else False
elif clazz == QgsProcessingParameterMatrix:
if len(params) > 2:
params[2] = int(params[2])
if len(params) > 3:
- params[3] = True if params[3].lower() == 'true' else False
+ params[3] = True if params[3].lower() == "true" else False
if len(params) > 4:
- params[4] = params[4].split(';')
+ params[4] = params[4].split(";")
if len(params) > 6:
- params[6] = True if params[6].lower() == 'true' else False
+ params[6] = True if params[6].lower() == "true" else False
elif clazz == QgsProcessingParameterField:
if len(params) > 4:
try:
- params[4] = Qgis.ProcessingFieldParameterDataType(int(params[4]))
+ params[4] = Qgis.ProcessingFieldParameterDataType(
+ int(params[4])
+ )
except ValueError:
- params[4] = getattr(QgsProcessingParameterField, params[4].split(".")[1])
+ params[4] = getattr(
+ QgsProcessingParameterField, params[4].split(".")[1]
+ )
if len(params) > 5:
- params[5] = True if params[5].lower() == 'true' else False
+ params[5] = True if params[5].lower() == "true" else False
if len(params) > 6:
- params[6] = True if params[6].lower() == 'true' else False
+ params[6] = True if params[6].lower() == "true" else False
if len(params) > 7:
- params[7] = True if params[7].lower() == 'true' else False
+ params[7] = True if params[7].lower() == "true" else False
elif clazz == QgsProcessingParameterFile:
if len(params) > 2:
try:
params[2] = Qgis.ProcessingFileParameterBehavior(int(params[2]))
except ValueError:
- params[2] = getattr(QgsProcessingParameterFile, params[2].split(".")[1])
+ params[2] = getattr(
+ QgsProcessingParameterFile, params[2].split(".")[1]
+ )
if len(params) > 5:
- params[5] = True if params[5].lower() == 'true' else False
+ params[5] = True if params[5].lower() == "true" else False
elif clazz == QgsProcessingParameterNumber:
if len(params) > 2:
try:
params[2] = Qgis.ProcessingNumberParameterType(int(params[2]))
except ValueError:
- params[2] = getattr(QgsProcessingParameterNumber, params[2].split(".")[1])
+ params[2] = getattr(
+ QgsProcessingParameterNumber, params[2].split(".")[1]
+ )
if len(params) > 3:
- params[3] = float(params[3].strip()) if params[3] is not None else None
+ params[3] = (
+ float(params[3].strip()) if params[3] is not None else None
+ )
if len(params) > 4:
- params[4] = True if params[4].lower() == 'true' else False
+ params[4] = True if params[4].lower() == "true" else False
if len(params) > 5:
- params[5] = float(params[5].strip()) if params[5] is not None else -sys.float_info.max + 1
+ params[5] = (
+ float(params[5].strip())
+ if params[5] is not None
+ else -sys.float_info.max + 1
+ )
if len(params) > 6:
- params[6] = float(params[6].strip()) if params[6] is not None else sys.float_info.max - 1
+ params[6] = (
+ float(params[6].strip())
+ if params[6] is not None
+ else sys.float_info.max - 1
+ )
elif clazz == QgsProcessingParameterString:
if len(params) > 3:
- params[3] = True if params[3].lower() == 'true' else False
+ params[3] = True if params[3].lower() == "true" else False
if len(params) > 4:
- params[4] = True if params[4].lower() == 'true' else False
+ params[4] = True if params[4].lower() == "true" else False
elif clazz == QgsProcessingParameterColor:
if len(params) > 3:
- params[3] = True if params[3].lower() == 'true' else False
+ params[3] = True if params[3].lower() == "true" else False
if len(params) > 4:
- params[4] = True if params[4].lower() == 'true' else False
+ params[4] = True if params[4].lower() == "true" else False
elif clazz == QgsProcessingParameterFileDestination:
if len(params) > 4:
- params[4] = True if params[4].lower() == 'true' else False
+ params[4] = True if params[4].lower() == "true" else False
if len(params) > 5:
- params[5] = True if params[5].lower() == 'true' else False
+ params[5] = True if params[5].lower() == "true" else False
elif clazz == QgsProcessingParameterFolderDestination:
if len(params) > 3:
- params[3] = True if params[3].lower() == 'true' else False
+ params[3] = True if params[3].lower() == "true" else False
if len(params) > 4:
- params[4] = True if params[4].lower() == 'true' else False
+ params[4] = True if params[4].lower() == "true" else False
elif clazz == QgsProcessingParameterRasterDestination:
if len(params) > 3:
- params[3] = True if params[3].lower() == 'true' else False
+ params[3] = True if params[3].lower() == "true" else False
if len(params) > 4:
- params[4] = True if params[4].lower() == 'true' else False
+ params[4] = True if params[4].lower() == "true" else False
elif clazz == QgsProcessingParameterPointCloudDestination:
print(params)
if len(params) > 3:
- params[3] = True if params[3].lower() == 'true' else False
+ params[3] = True if params[3].lower() == "true" else False
if len(params) > 4:
- params[4] = True if params[4].lower() == 'true' else False
+ params[4] = True if params[4].lower() == "true" else False
elif clazz == QgsProcessingParameterVectorDestination:
if len(params) > 2:
try:
@@ -281,15 +324,19 @@ def getParameterFromString(s, context=''):
except ValueError:
params[2] = getattr(QgsProcessing, params[2].split(".")[1])
if len(params) > 4:
- params[4] = True if params[4].lower() == 'true' else False
+ params[4] = True if params[4].lower() == "true" else False
if len(params) > 5:
- params[5] = True if params[5].lower() == 'true' else False
+ params[5] = True if params[5].lower() == "true" else False
param = clazz(*params)
if isAdvanced:
- param.setFlags(param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
+ param.setFlags(
+ param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
- param.setDescription(QCoreApplication.translate(context, param.description()))
+ param.setDescription(
+ QCoreApplication.translate(context, param.description())
+ )
return param
else:
diff --git a/python/plugins/processing/gui/AlgorithmDialog.py b/python/plugins/processing/gui/AlgorithmDialog.py
index 091f61df28d0..954623faacd4 100644
--- a/python/plugins/processing/gui/AlgorithmDialog.py
+++ b/python/plugins/processing/gui/AlgorithmDialog.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'August 2012'
-__copyright__ = '(C) 2012, Victor Olaya'
+__author__ = "Victor Olaya"
+__date__ = "August 2012"
+__copyright__ = "(C) 2012, Victor Olaya"
import datetime
import time
@@ -26,17 +26,21 @@
from qgis.PyQt.QtWidgets import QMessageBox, QPushButton, QDialogButtonBox
from qgis.PyQt.QtGui import QColor, QPalette
-from qgis.core import (Qgis,
- QgsApplication,
- QgsProcessingAlgRunnerTask,
- QgsProcessingOutputHtml,
- QgsProcessingAlgorithm,
- QgsProxyProgressTask,
- QgsProcessingFeatureSourceDefinition)
-from qgis.gui import (QgsGui,
- QgsProcessingAlgorithmDialogBase,
- QgsProcessingParametersGenerator,
- QgsProcessingContextGenerator)
+from qgis.core import (
+ Qgis,
+ QgsApplication,
+ QgsProcessingAlgRunnerTask,
+ QgsProcessingOutputHtml,
+ QgsProcessingAlgorithm,
+ QgsProxyProgressTask,
+ QgsProcessingFeatureSourceDefinition,
+)
+from qgis.gui import (
+ QgsGui,
+ QgsProcessingAlgorithmDialogBase,
+ QgsProcessingParametersGenerator,
+ QgsProcessingContextGenerator,
+)
from qgis.utils import iface
from processing.core.ProcessingConfig import ProcessingConfig
@@ -68,23 +72,36 @@ def __init__(self, alg, in_place=False, parent=None):
self.setMainWidget(self.getParametersPanel(alg, self))
if not self.in_place:
- self.runAsBatchButton = QPushButton(QCoreApplication.translate("AlgorithmDialog", "Run as Batch Process…"))
+ self.runAsBatchButton = QPushButton(
+ QCoreApplication.translate("AlgorithmDialog", "Run as Batch Process…")
+ )
self.runAsBatchButton.clicked.connect(self.runAsBatch)
- self.buttonBox().addButton(self.runAsBatchButton,
- QDialogButtonBox.ButtonRole.ResetRole) # reset role to ensure left alignment
+ self.buttonBox().addButton(
+ self.runAsBatchButton, QDialogButtonBox.ButtonRole.ResetRole
+ ) # reset role to ensure left alignment
else:
- in_place_input_parameter_name = 'INPUT'
- if hasattr(alg, 'inputParameterName'):
+ in_place_input_parameter_name = "INPUT"
+ if hasattr(alg, "inputParameterName"):
in_place_input_parameter_name = alg.inputParameterName()
- self.mainWidget().setParameters({in_place_input_parameter_name: self.active_layer})
+ self.mainWidget().setParameters(
+ {in_place_input_parameter_name: self.active_layer}
+ )
self.runAsBatchButton = None
- has_selection = self.active_layer and (self.active_layer.selectedFeatureCount() > 0)
+ has_selection = self.active_layer and (
+ self.active_layer.selectedFeatureCount() > 0
+ )
self.buttonBox().button(QDialogButtonBox.StandardButton.Ok).setText(
- QCoreApplication.translate("AlgorithmDialog", "Modify Selected Features")
- if has_selection else QCoreApplication.translate("AlgorithmDialog", "Modify All Features"))
- self.setWindowTitle(self.windowTitle() + ' | ' + self.active_layer.name())
+ QCoreApplication.translate(
+ "AlgorithmDialog", "Modify Selected Features"
+ )
+ if has_selection
+ else QCoreApplication.translate(
+ "AlgorithmDialog", "Modify All Features"
+ )
+ )
+ self.setWindowTitle(self.windowTitle() + " | " + self.active_layer.name())
self.updateRunButtonVisibility()
@@ -114,35 +131,39 @@ def flag_invalid_parameter_value(self, message: str, widget):
Highlights a parameter with an invalid value
"""
try:
- self.buttonBox().accepted.connect(lambda w=widget:
- w.setPalette(QPalette()))
+ self.buttonBox().accepted.connect(lambda w=widget: w.setPalette(QPalette()))
palette = widget.palette()
palette.setColor(QPalette.ColorRole.Base, QColor(255, 255, 0))
widget.setPalette(palette)
except:
pass
self.messageBar().clearWidgets()
- self.messageBar().pushMessage("", self.tr("Wrong or missing parameter value: {0}").format(
- message),
- level=Qgis.MessageLevel.Warning, duration=5)
+ self.messageBar().pushMessage(
+ "",
+ self.tr("Wrong or missing parameter value: {0}").format(message),
+ level=Qgis.MessageLevel.Warning,
+ duration=5,
+ )
def flag_invalid_output_extension(self, message: str, widget):
"""
Highlights a parameter with an invalid output extension
"""
try:
- self.buttonBox().accepted.connect(lambda w=widget:
- w.setPalette(QPalette()))
+ self.buttonBox().accepted.connect(lambda w=widget: w.setPalette(QPalette()))
palette = widget.palette()
palette.setColor(QPalette.ColorRole.Base, QColor(255, 255, 0))
widget.setPalette(palette)
except:
pass
self.messageBar().clearWidgets()
- self.messageBar().pushMessage("", message,
- level=Qgis.MessageLevel.Warning, duration=5)
+ self.messageBar().pushMessage(
+ "", message, level=Qgis.MessageLevel.Warning, duration=5
+ )
- def createProcessingParameters(self, flags=QgsProcessingParametersGenerator.Flags()):
+ def createProcessingParameters(
+ self, flags=QgsProcessingParametersGenerator.Flags()
+ ):
if self.mainWidget() is None:
return {}
@@ -173,21 +194,31 @@ def runAlgorithm(self):
# messy as all heck, but we don't want to call the dialog's implementation of
# createProcessingParameters as we want to catch the exceptions raised by the
# parameter panel instead...
- parameters = {} if self.mainWidget() is None else self.mainWidget().createProcessingParameters()
-
- if checkCRS and not self.algorithm().validateInputCrs(parameters, self.context):
- reply = QMessageBox.question(self, self.tr("Unmatching CRS's"),
- self.tr('Parameters do not all use the same CRS. This can '
- 'cause unexpected results.\nDo you want to '
- 'continue?'),
- QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No,
- QMessageBox.StandardButton.No)
+ parameters = (
+ {}
+ if self.mainWidget() is None
+ else self.mainWidget().createProcessingParameters()
+ )
+
+ if checkCRS and not self.algorithm().validateInputCrs(
+ parameters, self.context
+ ):
+ reply = QMessageBox.question(
+ self,
+ self.tr("Unmatching CRS's"),
+ self.tr(
+ "Parameters do not all use the same CRS. This can "
+ "cause unexpected results.\nDo you want to "
+ "continue?"
+ ),
+ QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No,
+ QMessageBox.StandardButton.No,
+ )
if reply == QMessageBox.StandardButton.No:
return
ok, msg = self.algorithm().checkParameterValues(parameters, self.context)
if not ok:
- QMessageBox.warning(
- self, self.tr('Unable to execute algorithm'), msg)
+ QMessageBox.warning(self, self.tr("Unable to execute algorithm"), msg)
return
self.blockControlsWhileRunning()
@@ -197,33 +228,51 @@ def runAlgorithm(self):
self.iterateParam = None
for param in self.algorithm().parameterDefinitions():
- if isinstance(parameters.get(param.name(), None), QgsProcessingFeatureSourceDefinition) and parameters[
- param.name()].flags & QgsProcessingFeatureSourceDefinition.Flag.FlagCreateIndividualOutputPerInputFeature:
+ if (
+ isinstance(
+ parameters.get(param.name(), None),
+ QgsProcessingFeatureSourceDefinition,
+ )
+ and parameters[param.name()].flags
+ & QgsProcessingFeatureSourceDefinition.Flag.FlagCreateIndividualOutputPerInputFeature
+ ):
self.iterateParam = param.name()
break
self.clearProgress()
self.feedback.pushVersionInfo(self.algorithm().provider())
- if self.algorithm().provider() and self.algorithm().provider().warningMessage():
+ if (
+ self.algorithm().provider()
+ and self.algorithm().provider().warningMessage()
+ ):
self.feedback.reportError(self.algorithm().provider().warningMessage())
self.feedback.pushInfo(
- QCoreApplication.translate('AlgorithmDialog', 'Algorithm started at: {}').format(
- datetime.datetime.now().replace(microsecond=0).isoformat()
- )
+ QCoreApplication.translate(
+ "AlgorithmDialog", "Algorithm started at: {}"
+ ).format(datetime.datetime.now().replace(microsecond=0).isoformat())
)
self.setInfo(
- QCoreApplication.translate('AlgorithmDialog', 'Algorithm \'{0}\' starting… ').format(
- self.algorithm().displayName()), escapeHtml=False)
+ QCoreApplication.translate(
+ "AlgorithmDialog", "Algorithm '{0}' starting… "
+ ).format(self.algorithm().displayName()),
+ escapeHtml=False,
+ )
- self.feedback.pushInfo(self.tr('Input parameters:'))
+ self.feedback.pushInfo(self.tr("Input parameters:"))
display_params = []
for k, v in parameters.items():
display_params.append(
- "'" + k + "' : " + self.algorithm().parameterDefinition(k).valueAsPythonString(v, self.context))
- self.feedback.pushCommandInfo('{ ' + ', '.join(display_params) + ' }')
- self.feedback.pushInfo('')
+ "'"
+ + k
+ + "' : "
+ + self.algorithm()
+ .parameterDefinition(k)
+ .valueAsPythonString(v, self.context)
+ )
+ self.feedback.pushCommandInfo("{ " + ", ".join(display_params) + " }")
+ self.feedback.pushInfo("")
start_time = time.time()
def elapsed_time(start_time) -> str:
@@ -237,14 +286,21 @@ def elapsed_time(start_time) -> str:
str_seconds = [self.tr("second"), self.tr("seconds")][seconds != 1]
if hours > 0:
- elapsed = '{0:0.2f} {1} ({2} {3} {4} {5} {6:0.0f} {1})'.format(
- delta_t, str_seconds, hours, str_hours, minutes, str_minutes, seconds)
+ elapsed = "{0:0.2f} {1} ({2} {3} {4} {5} {6:0.0f} {1})".format(
+ delta_t,
+ str_seconds,
+ hours,
+ str_hours,
+ minutes,
+ str_minutes,
+ seconds,
+ )
elif minutes > 0:
- elapsed = '{0:0.2f} {1} ({2} {3} {4:0.0f} {1})'.format(
- delta_t, str_seconds, minutes, str_minutes, seconds)
+ elapsed = "{0:0.2f} {1} ({2} {3} {4:0.0f} {1})".format(
+ delta_t, str_seconds, minutes, str_minutes, seconds
+ )
else:
- elapsed = '{:0.2f} {}'.format(
- delta_t, str_seconds)
+ elapsed = f"{delta_t:0.2f} {str_seconds}"
return elapsed
@@ -256,10 +312,21 @@ def elapsed_time(start_time) -> str:
except:
pass
- self.cancelButton().setEnabled(self.algorithm().flags() & QgsProcessingAlgorithm.Flag.FlagCanCancel)
- if executeIterating(self.algorithm(), parameters, self.iterateParam, self.context, self.feedback):
+ self.cancelButton().setEnabled(
+ self.algorithm().flags() & QgsProcessingAlgorithm.Flag.FlagCanCancel
+ )
+ if executeIterating(
+ self.algorithm(),
+ parameters,
+ self.iterateParam,
+ self.context,
+ self.feedback,
+ ):
self.feedback.pushInfo(
- self.tr('Execution completed in {}').format(elapsed_time(start_time)))
+ self.tr("Execution completed in {}").format(
+ elapsed_time(start_time)
+ )
+ )
self.cancelButton().setEnabled(False)
self.finish(True, parameters, self.context, self.feedback)
else:
@@ -267,34 +334,56 @@ def elapsed_time(start_time) -> str:
self.resetGui()
else:
self.history_details = {
- 'python_command': self.algorithm().asPythonCommand(parameters, self.context),
- 'algorithm_id': self.algorithm().id(),
- 'parameters': self.algorithm().asMap(parameters, self.context)
+ "python_command": self.algorithm().asPythonCommand(
+ parameters, self.context
+ ),
+ "algorithm_id": self.algorithm().id(),
+ "parameters": self.algorithm().asMap(parameters, self.context),
}
- process_command, command_ok = self.algorithm().asQgisProcessCommand(parameters, self.context)
+ process_command, command_ok = self.algorithm().asQgisProcessCommand(
+ parameters, self.context
+ )
if command_ok:
- self.history_details['process_command'] = process_command
- self.history_log_id, _ = QgsGui.historyProviderRegistry().addEntry('processing', self.history_details)
+ self.history_details["process_command"] = process_command
+ self.history_log_id, _ = QgsGui.historyProviderRegistry().addEntry(
+ "processing", self.history_details
+ )
- QgsGui.instance().processingRecentAlgorithmLog().push(self.algorithm().id())
- self.cancelButton().setEnabled(self.algorithm().flags() & QgsProcessingAlgorithm.Flag.FlagCanCancel)
+ QgsGui.instance().processingRecentAlgorithmLog().push(
+ self.algorithm().id()
+ )
+ self.cancelButton().setEnabled(
+ self.algorithm().flags() & QgsProcessingAlgorithm.Flag.FlagCanCancel
+ )
def on_complete(ok, results):
if ok:
self.feedback.pushInfo(
- self.tr('Execution completed in {}').format(elapsed_time(start_time)))
- self.feedback.pushFormattedResults(self.algorithm(), self.context, results)
+ self.tr("Execution completed in {}").format(
+ elapsed_time(start_time)
+ )
+ )
+ self.feedback.pushFormattedResults(
+ self.algorithm(), self.context, results
+ )
else:
self.feedback.reportError(
- self.tr('Execution failed after {}').format(elapsed_time(start_time)))
- self.feedback.pushInfo('')
+ self.tr("Execution failed after {}").format(
+ elapsed_time(start_time)
+ )
+ )
+ self.feedback.pushInfo("")
if self.history_log_id is not None:
# can't deepcopy this!
- self.history_details['results'] = {k: v for k, v in results.items() if k != 'CHILD_INPUTS'}
- self.history_details['log'] = self.feedback.htmlLog()
+ self.history_details["results"] = {
+ k: v for k, v in results.items() if k != "CHILD_INPUTS"
+ }
+ self.history_details["log"] = self.feedback.htmlLog()
- QgsGui.historyProviderRegistry().updateEntry(self.history_log_id, self.history_details)
+ QgsGui.historyProviderRegistry().updateEntry(
+ self.history_log_id, self.history_details
+ )
if self.feedback_dialog is not None:
self.feedback_dialog.close()
@@ -303,16 +392,23 @@ def on_complete(ok, results):
self.cancelButton().setEnabled(False)
- self.finish(ok, results, self.context, self.feedback, in_place=self.in_place)
+ self.finish(
+ ok, results, self.context, self.feedback, in_place=self.in_place
+ )
self.feedback = None
self.context = None
- if not self.in_place and not (self.algorithm().flags() & QgsProcessingAlgorithm.Flag.FlagNoThreading):
+ if not self.in_place and not (
+ self.algorithm().flags()
+ & QgsProcessingAlgorithm.Flag.FlagNoThreading
+ ):
# Make sure the Log tab is visible before executing the algorithm
self.showLog()
- task = QgsProcessingAlgRunnerTask(self.algorithm(), parameters, self.context, self.feedback)
+ task = QgsProcessingAlgRunnerTask(
+ self.algorithm(), parameters, self.context, self.feedback
+ )
if task.isCanceled():
on_complete(False, {})
else:
@@ -320,16 +416,24 @@ def on_complete(ok, results):
self.setCurrentTask(task)
else:
self.proxy_progress = QgsProxyProgressTask(
- QCoreApplication.translate("AlgorithmDialog", "Executing “{}”").format(
- self.algorithm().displayName()))
+ QCoreApplication.translate(
+ "AlgorithmDialog", "Executing “{}”"
+ ).format(self.algorithm().displayName())
+ )
QgsApplication.taskManager().addTask(self.proxy_progress)
- self.feedback.progressChanged.connect(self.proxy_progress.setProxyProgress)
+ self.feedback.progressChanged.connect(
+ self.proxy_progress.setProxyProgress
+ )
self.feedback_dialog = self.createProgressDialog()
self.feedback_dialog.show()
if self.in_place:
- ok, results = execute_in_place(self.algorithm(), parameters, self.context, self.feedback)
+ ok, results = execute_in_place(
+ self.algorithm(), parameters, self.context, self.feedback
+ )
else:
- ok, results = execute(self.algorithm(), parameters, self.context, self.feedback)
+ ok, results = execute(
+ self.algorithm(), parameters, self.context, self.feedback
+ )
self.feedback.progressChanged.disconnect()
self.proxy_progress.finalize(ok)
on_complete(ok, results)
@@ -340,29 +444,37 @@ def on_complete(ok, results):
self.flag_invalid_output_extension(e.message, e.widget)
def finish(self, successful, result, context, feedback, in_place=False):
- keepOpen = not successful or ProcessingConfig.getSetting(ProcessingConfig.KEEP_DIALOG_OPEN)
+ keepOpen = not successful or ProcessingConfig.getSetting(
+ ProcessingConfig.KEEP_DIALOG_OPEN
+ )
generated_html_outputs = False
if not in_place and self.iterateParam is None:
# add html results to results dock
for out in self.algorithm().outputDefinitions():
- if isinstance(out, QgsProcessingOutputHtml) and out.name() in result and result[out.name()]:
- resultsList.addResult(icon=self.algorithm().icon(), name=out.description(),
- timestamp=time.localtime(),
- result=result[out.name()])
+ if (
+ isinstance(out, QgsProcessingOutputHtml)
+ and out.name() in result
+ and result[out.name()]
+ ):
+ resultsList.addResult(
+ icon=self.algorithm().icon(),
+ name=out.description(),
+ timestamp=time.localtime(),
+ result=result[out.name()],
+ )
generated_html_outputs = True
- if not handleAlgorithmResults(
- self.algorithm(),
- context,
- feedback,
- result):
+ if not handleAlgorithmResults(self.algorithm(), context, feedback, result):
self.resetGui()
return
self.setExecuted(True)
self.setResults(result)
- self.setInfo(self.tr('Algorithm \'{0}\' finished').format(self.algorithm().displayName()), escapeHtml=False)
+ self.setInfo(
+ self.tr("Algorithm '{0}' finished").format(self.algorithm().displayName()),
+ escapeHtml=False,
+ )
self.algorithmFinished.emit(successful, result)
if not in_place and not keepOpen:
@@ -371,5 +483,9 @@ def finish(self, successful, result, context, feedback, in_place=False):
self.resetGui()
if generated_html_outputs:
self.setInfo(
- self.tr('HTML output has been generated by this algorithm.'
- '\nOpen the results dialog to check it.'), escapeHtml=False)
+ self.tr(
+ "HTML output has been generated by this algorithm."
+ "\nOpen the results dialog to check it."
+ ),
+ escapeHtml=False,
+ )
diff --git a/python/plugins/processing/gui/AlgorithmDialogBase.py b/python/plugins/processing/gui/AlgorithmDialogBase.py
index 84a6660d2da3..518d25d890a3 100644
--- a/python/plugins/processing/gui/AlgorithmDialogBase.py
+++ b/python/plugins/processing/gui/AlgorithmDialogBase.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'August 2012'
-__copyright__ = '(C) 2012, Victor Olaya'
+__author__ = "Victor Olaya"
+__date__ = "August 2012"
+__copyright__ = "(C) 2012, Victor Olaya"
class AlgorithmDialogBase:
diff --git a/python/plugins/processing/gui/AlgorithmExecutor.py b/python/plugins/processing/gui/AlgorithmExecutor.py
index c2dc506e3d11..c1ef9432d449 100644
--- a/python/plugins/processing/gui/AlgorithmExecutor.py
+++ b/python/plugins/processing/gui/AlgorithmExecutor.py
@@ -15,30 +15,32 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'August 2012'
-__copyright__ = '(C) 2012, Victor Olaya'
+__author__ = "Victor Olaya"
+__date__ = "August 2012"
+__copyright__ = "(C) 2012, Victor Olaya"
import sys
from qgis.PyQt.QtCore import QCoreApplication
-from qgis.core import (Qgis,
- QgsApplication,
- QgsFeatureSink,
- QgsProcessingFeedback,
- QgsProcessingUtils,
- QgsMessageLog,
- QgsProcessingException,
- QgsProcessingFeatureSourceDefinition,
- QgsProcessingFeatureSource,
- QgsProcessingParameters,
- QgsProject,
- QgsFeatureRequest,
- QgsFeature,
- QgsExpression,
- QgsWkbTypes,
- QgsGeometry,
- QgsVectorLayerUtils,
- QgsVectorLayer)
+from qgis.core import (
+ Qgis,
+ QgsApplication,
+ QgsFeatureSink,
+ QgsProcessingFeedback,
+ QgsProcessingUtils,
+ QgsMessageLog,
+ QgsProcessingException,
+ QgsProcessingFeatureSourceDefinition,
+ QgsProcessingFeatureSource,
+ QgsProcessingParameters,
+ QgsProject,
+ QgsFeatureRequest,
+ QgsFeature,
+ QgsExpression,
+ QgsWkbTypes,
+ QgsGeometry,
+ QgsVectorLayerUtils,
+ QgsVectorLayer,
+)
from processing.gui.Postprocessing import handleAlgorithmResults
from processing.tools import dataobjects
from qgis.utils import iface
@@ -62,7 +64,9 @@ def execute(alg, parameters, context=None, feedback=None, catch_exceptions=True)
results, ok = alg.run(parameters, context, feedback)
return ok, results
except QgsProcessingException as e:
- QgsMessageLog.logMessage(str(sys.exc_info()[0]), 'Processing', Qgis.MessageLevel.Critical)
+ QgsMessageLog.logMessage(
+ str(sys.exc_info()[0]), "Processing", Qgis.MessageLevel.Critical
+ )
if feedback is not None:
feedback.reportError(e.msg)
return False, {}
@@ -71,7 +75,9 @@ def execute(alg, parameters, context=None, feedback=None, catch_exceptions=True)
return ok, results
-def execute_in_place_run(alg, parameters, context=None, feedback=None, raise_exceptions=False):
+def execute_in_place_run(
+ alg, parameters, context=None, feedback=None, raise_exceptions=False
+):
"""Executes an algorithm modifying features in-place in the input layer.
:param alg: algorithm to run
@@ -96,13 +102,18 @@ def execute_in_place_run(alg, parameters, context=None, feedback=None, raise_exc
# Only feature based algs have sourceFlags
try:
- if alg.sourceFlags() & QgsProcessingFeatureSource.Flag.FlagSkipGeometryValidityChecks:
- context.setInvalidGeometryCheck(QgsFeatureRequest.InvalidGeometryCheck.GeometryNoCheck)
+ if (
+ alg.sourceFlags()
+ & QgsProcessingFeatureSource.Flag.FlagSkipGeometryValidityChecks
+ ):
+ context.setInvalidGeometryCheck(
+ QgsFeatureRequest.InvalidGeometryCheck.GeometryNoCheck
+ )
except AttributeError:
pass
- in_place_input_parameter_name = 'INPUT'
- if hasattr(alg, 'inputParameterName'):
+ in_place_input_parameter_name = "INPUT"
+ if hasattr(alg, "inputParameterName"):
in_place_input_parameter_name = alg.inputParameterName()
active_layer = parameters[in_place_input_parameter_name]
@@ -129,24 +140,36 @@ def execute_in_place_run(alg, parameters, context=None, feedback=None, raise_exc
if not active_layer.isEditable():
if not active_layer.startEditing():
- raise QgsProcessingException(tr("Active layer is not editable (and editing could not be turned on)."))
+ raise QgsProcessingException(
+ tr(
+ "Active layer is not editable (and editing could not be turned on)."
+ )
+ )
if not alg.supportInPlaceEdit(active_layer):
- raise QgsProcessingException(tr("Selected algorithm and parameter configuration are not compatible with in-place modifications."))
+ raise QgsProcessingException(
+ tr(
+ "Selected algorithm and parameter configuration are not compatible with in-place modifications."
+ )
+ )
except QgsProcessingException as e:
if raise_exceptions:
raise e
- QgsMessageLog.logMessage(str(sys.exc_info()[0]), 'Processing', Qgis.MessageLevel.Critical)
+ QgsMessageLog.logMessage(
+ str(sys.exc_info()[0]), "Processing", Qgis.MessageLevel.Critical
+ )
if feedback is not None:
- feedback.reportError(getattr(e, 'msg', str(e)), fatalError=True)
+ feedback.reportError(getattr(e, "msg", str(e)), fatalError=True)
return False, {}
if not active_layer.selectedFeatureIds():
active_layer.selectAll()
# Make sure we are working on selected features only
- parameters[in_place_input_parameter_name] = QgsProcessingFeatureSourceDefinition(active_layer.id(), True)
- parameters['OUTPUT'] = 'memory:'
+ parameters[in_place_input_parameter_name] = QgsProcessingFeatureSourceDefinition(
+ active_layer.id(), True
+ )
+ parameters["OUTPUT"] = "memory:"
req = QgsFeatureRequest(QgsExpression(r"$id < 0"))
req.setFlags(QgsFeatureRequest.Flag.NoGeometry)
@@ -162,15 +185,21 @@ def execute_in_place_run(alg, parameters, context=None, feedback=None, raise_exc
active_layer.beginEditCommand(alg.displayName())
# Checks whether the algorithm has a processFeature method
- if hasattr(alg, 'processFeature'): # in-place feature editing
+ if hasattr(alg, "processFeature"): # in-place feature editing
# Make a clone or it will crash the second time the dialog
# is opened and run
- alg = alg.create({'IN_PLACE': True})
+ alg = alg.create({"IN_PLACE": True})
if not alg.prepare(parameters, context, feedback):
- raise QgsProcessingException(tr("Could not prepare selected algorithm."))
+ raise QgsProcessingException(
+ tr("Could not prepare selected algorithm.")
+ )
# Check again for compatibility after prepare
if not alg.supportInPlaceEdit(active_layer):
- raise QgsProcessingException(tr("Selected algorithm and parameter configuration are not compatible with in-place modifications."))
+ raise QgsProcessingException(
+ tr(
+ "Selected algorithm and parameter configuration are not compatible with in-place modifications."
+ )
+ )
# some algorithms have logic in outputFields/outputCrs/outputWkbType which they require to execute before
# they can start processing features
@@ -182,7 +211,11 @@ def execute_in_place_run(alg, parameters, context=None, feedback=None, raise_exc
iterator_req = QgsFeatureRequest(active_layer.selectedFeatureIds())
iterator_req.setInvalidGeometryCheck(context.invalidGeometryCheck())
feature_iterator = active_layer.getFeatures(iterator_req)
- step = 100 / len(active_layer.selectedFeatureIds()) if active_layer.selectedFeatureIds() else 1
+ step = (
+ 100 / len(active_layer.selectedFeatureIds())
+ if active_layer.selectedFeatureIds()
+ else 1
+ )
current = 0
for current, f in enumerate(feature_iterator):
if feedback.isCanceled():
@@ -195,7 +228,9 @@ def execute_in_place_run(alg, parameters, context=None, feedback=None, raise_exc
context.expressionContext().setFeature(input_feature)
new_features = alg.processFeature(input_feature, context, feedback)
- new_features = QgsVectorLayerUtils.makeFeaturesCompatible(new_features, active_layer)
+ new_features = QgsVectorLayerUtils.makeFeaturesCompatible(
+ new_features, active_layer
+ )
if len(new_features) == 0:
active_layer.deleteFeature(f.id())
@@ -204,7 +239,11 @@ def execute_in_place_run(alg, parameters, context=None, feedback=None, raise_exc
if not f.geometry().equals(new_f.geometry()):
active_layer.changeGeometry(f.id(), new_f.geometry())
if f.attributes() != new_f.attributes():
- active_layer.changeAttributeValues(f.id(), dict(zip(field_idxs, new_f.attributes())), dict(zip(field_idxs, f.attributes())))
+ active_layer.changeAttributeValues(
+ f.id(),
+ dict(zip(field_idxs, new_f.attributes())),
+ dict(zip(field_idxs, f.attributes())),
+ )
new_feature_ids.append(f.id())
else:
active_layer.deleteFeature(f.id())
@@ -214,59 +253,93 @@ def execute_in_place_run(alg, parameters, context=None, feedback=None, raise_exc
# them to createFeatures to manage constraints correctly
features_data = []
for f in new_features:
- features_data.append(QgsVectorLayerUtils.QgsFeatureData(f.geometry(), dict(enumerate(f.attributes()))))
- new_features = QgsVectorLayerUtils.createFeatures(active_layer, features_data, context.expressionContext())
+ features_data.append(
+ QgsVectorLayerUtils.QgsFeatureData(
+ f.geometry(), dict(enumerate(f.attributes()))
+ )
+ )
+ new_features = QgsVectorLayerUtils.createFeatures(
+ active_layer, features_data, context.expressionContext()
+ )
if not active_layer.addFeatures(new_features):
- raise QgsProcessingException(tr("Error adding processed features back into the layer."))
+ raise QgsProcessingException(
+ tr("Error adding processed features back into the layer.")
+ )
new_ids = {f.id() for f in active_layer.getFeatures(req)}
new_feature_ids += list(new_ids - old_ids)
feedback.setProgress(int((current + 1) * step))
- results, ok = {'__count': current + 1}, True
+ results, ok = {"__count": current + 1}, True
else: # Traditional 'run' with delete and add features cycle
# There is no way to know if some features have been skipped
# due to invalid geometries
- if context.invalidGeometryCheck() == QgsFeatureRequest.InvalidGeometryCheck.GeometrySkipInvalid:
+ if (
+ context.invalidGeometryCheck()
+ == QgsFeatureRequest.InvalidGeometryCheck.GeometrySkipInvalid
+ ):
selected_ids = active_layer.selectedFeatureIds()
else:
selected_ids = []
- results, ok = alg.run(parameters, context, feedback, configuration={'IN_PLACE': True})
+ results, ok = alg.run(
+ parameters, context, feedback, configuration={"IN_PLACE": True}
+ )
if ok:
- result_layer = QgsProcessingUtils.mapLayerFromString(results['OUTPUT'], context)
+ result_layer = QgsProcessingUtils.mapLayerFromString(
+ results["OUTPUT"], context
+ )
# TODO: check if features have changed before delete/add cycle
new_features = []
# Check if there are any skipped features
- if context.invalidGeometryCheck() == QgsFeatureRequest.InvalidGeometryCheck.GeometrySkipInvalid:
- missing_ids = list(set(selected_ids) - set(result_layer.allFeatureIds()))
+ if (
+ context.invalidGeometryCheck()
+ == QgsFeatureRequest.InvalidGeometryCheck.GeometrySkipInvalid
+ ):
+ missing_ids = list(
+ set(selected_ids) - set(result_layer.allFeatureIds())
+ )
if missing_ids:
- for f in active_layer.getFeatures(QgsFeatureRequest(missing_ids)):
+ for f in active_layer.getFeatures(
+ QgsFeatureRequest(missing_ids)
+ ):
if not f.geometry().isGeosValid():
new_features.append(f)
active_layer.deleteFeatures(active_layer.selectedFeatureIds())
- regenerate_primary_key = result_layer.customProperty('OnConvertFormatRegeneratePrimaryKey', False)
- sink_flags = QgsFeatureSink.SinkFlags(QgsFeatureSink.SinkFlag.RegeneratePrimaryKey) if regenerate_primary_key \
+ regenerate_primary_key = result_layer.customProperty(
+ "OnConvertFormatRegeneratePrimaryKey", False
+ )
+ sink_flags = (
+ QgsFeatureSink.SinkFlags(
+ QgsFeatureSink.SinkFlag.RegeneratePrimaryKey
+ )
+ if regenerate_primary_key
else QgsFeatureSink.SinkFlags()
+ )
for f in result_layer.getFeatures():
- new_features.extend(QgsVectorLayerUtils.
- makeFeaturesCompatible([f], active_layer, sink_flags))
+ new_features.extend(
+ QgsVectorLayerUtils.makeFeaturesCompatible(
+ [f], active_layer, sink_flags
+ )
+ )
# Get the new ids
old_ids = {f.id() for f in active_layer.getFeatures(req)}
if not active_layer.addFeatures(new_features):
- raise QgsProcessingException(tr("Error adding processed features back into the layer."))
+ raise QgsProcessingException(
+ tr("Error adding processed features back into the layer.")
+ )
new_ids = {f.id() for f in active_layer.getFeatures(req)}
new_feature_ids += list(new_ids - old_ids)
- results['__count'] = len(new_feature_ids)
+ results["__count"] = len(new_feature_ids)
active_layer.endEditCommand()
@@ -282,9 +355,11 @@ def execute_in_place_run(alg, parameters, context=None, feedback=None, raise_exc
active_layer.rollBack()
if raise_exceptions:
raise e
- QgsMessageLog.logMessage(str(sys.exc_info()[0]), 'Processing', Qgis.MessageLevel.Critical)
+ QgsMessageLog.logMessage(
+ str(sys.exc_info()[0]), "Processing", Qgis.MessageLevel.Critical
+ )
if feedback is not None:
- feedback.reportError(getattr(e, 'msg', str(e)), fatalError=True)
+ feedback.reportError(getattr(e, "msg", str(e)), fatalError=True)
return False, {}
@@ -312,19 +387,35 @@ def execute_in_place(alg, parameters, context=None, feedback=None):
if context is None:
context = dataobjects.createContext(feedback)
- in_place_input_parameter_name = 'INPUT'
- if hasattr(alg, 'inputParameterName'):
+ in_place_input_parameter_name = "INPUT"
+ if hasattr(alg, "inputParameterName"):
in_place_input_parameter_name = alg.inputParameterName()
- in_place_input_layer_name = 'INPUT'
- if hasattr(alg, 'inputParameterDescription'):
+ in_place_input_layer_name = "INPUT"
+ if hasattr(alg, "inputParameterDescription"):
in_place_input_layer_name = alg.inputParameterDescription()
- if in_place_input_parameter_name not in parameters or not parameters[in_place_input_parameter_name]:
+ if (
+ in_place_input_parameter_name not in parameters
+ or not parameters[in_place_input_parameter_name]
+ ):
parameters[in_place_input_parameter_name] = iface.activeLayer()
- ok, results = execute_in_place_run(alg, parameters, context=context, feedback=feedback)
+ ok, results = execute_in_place_run(
+ alg, parameters, context=context, feedback=feedback
+ )
if ok:
- if isinstance(parameters[in_place_input_parameter_name], QgsProcessingFeatureSourceDefinition):
- layer = alg.parameterAsVectorLayer({in_place_input_parameter_name: parameters[in_place_input_parameter_name].source}, in_place_input_layer_name, context)
+ if isinstance(
+ parameters[in_place_input_parameter_name],
+ QgsProcessingFeatureSourceDefinition,
+ ):
+ layer = alg.parameterAsVectorLayer(
+ {
+ in_place_input_parameter_name: parameters[
+ in_place_input_parameter_name
+ ].source
+ },
+ in_place_input_layer_name,
+ context,
+ )
elif isinstance(parameters[in_place_input_parameter_name], QgsVectorLayer):
layer = parameters[in_place_input_parameter_name]
if layer:
@@ -338,7 +429,9 @@ def executeIterating(alg, parameters, paramToIter, context, feedback):
if not parameter_definition:
return False
- iter_source = QgsProcessingParameters.parameterAsSource(parameter_definition, parameters, context)
+ iter_source = QgsProcessingParameters.parameterAsSource(
+ parameter_definition, parameters, context
+ )
sink_list = []
if iter_source.featureCount() == 0:
return False
@@ -348,7 +441,13 @@ def executeIterating(alg, parameters, paramToIter, context, feedback):
if feedback.isCanceled():
return False
- sink, sink_id = QgsProcessingUtils.createFeatureSink('memory:', context, iter_source.fields(), iter_source.wkbType(), iter_source.sourceCrs())
+ sink, sink_id = QgsProcessingUtils.createFeatureSink(
+ "memory:",
+ context,
+ iter_source.fields(),
+ iter_source.wkbType(),
+ iter_source.sourceCrs(),
+ )
sink_list.append(sink_id)
sink.addFeature(feat, QgsFeatureSink.Flag.FastInsert)
del sink
@@ -372,8 +471,14 @@ def executeIterating(alg, parameters, paramToIter, context, feedback):
continue
o = outputs[out.name()]
- parameters[out.name()] = QgsProcessingUtils.generateIteratingDestination(o, i, context)
- feedback.setProgressText(QCoreApplication.translate('AlgorithmExecutor', 'Executing iteration {0}/{1}…').format(i + 1, len(sink_list)))
+ parameters[out.name()] = QgsProcessingUtils.generateIteratingDestination(
+ o, i, context
+ )
+ feedback.setProgressText(
+ QCoreApplication.translate(
+ "AlgorithmExecutor", "Executing iteration {0}/{1}…"
+ ).format(i + 1, len(sink_list))
+ )
feedback.setProgress(int((i + 1) * 100 / len(sink_list)))
ret, results = execute(alg, parameters, context, feedback)
if not ret:
@@ -383,7 +488,7 @@ def executeIterating(alg, parameters, paramToIter, context, feedback):
return True
-def tr(string, context=''):
- if context == '':
- context = 'AlgorithmExecutor'
+def tr(string, context=""):
+ if context == "":
+ context = "AlgorithmExecutor"
return QCoreApplication.translate(context, string)
diff --git a/python/plugins/processing/gui/AlgorithmLocatorFilter.py b/python/plugins/processing/gui/AlgorithmLocatorFilter.py
index 4fe3979fe594..a2791df3ab32 100644
--- a/python/plugins/processing/gui/AlgorithmLocatorFilter.py
+++ b/python/plugins/processing/gui/AlgorithmLocatorFilter.py
@@ -15,20 +15,22 @@
***************************************************************************
"""
-__author__ = 'Nyall Dawson'
-__date__ = 'May 2017'
-__copyright__ = '(C) 2017, Nyall Dawson'
-
-from qgis.core import (QgsApplication,
- QgsProcessingAlgorithm,
- QgsProcessingFeatureBasedAlgorithm,
- QgsLocatorFilter,
- QgsLocatorResult,
- QgsProcessing,
- QgsWkbTypes,
- QgsMapLayerType,
- QgsFields,
- QgsStringUtils)
+__author__ = "Nyall Dawson"
+__date__ = "May 2017"
+__copyright__ = "(C) 2017, Nyall Dawson"
+
+from qgis.core import (
+ QgsApplication,
+ QgsProcessingAlgorithm,
+ QgsProcessingFeatureBasedAlgorithm,
+ QgsLocatorFilter,
+ QgsLocatorResult,
+ QgsProcessing,
+ QgsWkbTypes,
+ QgsMapLayerType,
+ QgsFields,
+ QgsStringUtils,
+)
from processing.gui.MessageBarProgress import MessageBarProgress
from processing.gui.MessageDialog import MessageDialog
from processing.gui.AlgorithmDialog import AlgorithmDialog
@@ -46,16 +48,16 @@ def clone(self):
return AlgorithmLocatorFilter()
def name(self):
- return 'processing_alg'
+ return "processing_alg"
def displayName(self):
- return self.tr('Processing Algorithms')
+ return self.tr("Processing Algorithms")
def priority(self):
return QgsLocatorFilter.Priority.Low
def prefix(self):
- return 'a'
+ return "a"
def flags(self):
return QgsLocatorFilter.Flag.FlagFast
@@ -66,8 +68,12 @@ def fetchResults(self, string, context, feedback):
for a in QgsApplication.processingRegistry().algorithms():
if a.flags() & QgsProcessingAlgorithm.Flag.FlagHideFromToolbox:
continue
- if not ProcessingConfig.getSetting(ProcessingConfig.SHOW_ALGORITHMS_KNOWN_ISSUES) and \
- a.flags() & QgsProcessingAlgorithm.Flag.FlagKnownIssues:
+ if (
+ not ProcessingConfig.getSetting(
+ ProcessingConfig.SHOW_ALGORITHMS_KNOWN_ISSUES
+ )
+ and a.flags() & QgsProcessingAlgorithm.Flag.FlagKnownIssues
+ ):
continue
result = QgsLocatorResult()
@@ -77,7 +83,7 @@ def fetchResults(self, string, context, feedback):
result.userData = a.id()
result.score = 0
- if (context.usingPrefix and not string):
+ if context.usingPrefix and not string:
self.resultFetched.emit(result)
if not string:
@@ -98,7 +104,10 @@ def fetchResults(self, string, context, feedback):
tagScore = 1
break
- result.score = QgsStringUtils.fuzzyScore(result.displayString, string) * 0.5 + tagScore * 0.5
+ result.score = (
+ QgsStringUtils.fuzzyScore(result.displayString, string) * 0.5
+ + tagScore * 0.5
+ )
if result.score > 0:
self.resultFetched.emit(result)
@@ -109,7 +118,7 @@ def triggerResult(self, result):
ok, message = alg.canExecute()
if not ok:
dlg = MessageDialog()
- dlg.setTitle(self.tr('Missing dependency'))
+ dlg.setTitle(self.tr("Missing dependency"))
dlg.setMessage(message)
dlg.exec()
return
@@ -140,16 +149,16 @@ def clone(self):
return InPlaceAlgorithmLocatorFilter()
def name(self):
- return 'edit_features'
+ return "edit_features"
def displayName(self):
- return self.tr('Edit Selected Features')
+ return self.tr("Edit Selected Features")
def priority(self):
return QgsLocatorFilter.Priority.Low
def prefix(self):
- return 'ef'
+ return "ef"
def flags(self):
return QgsLocatorFilter.Flag.FlagFast
@@ -158,7 +167,10 @@ def fetchResults(self, string, context, feedback):
# collect results in main thread, since this method is inexpensive and
# accessing the processing registry/current layer is not thread safe
- if iface.activeLayer() is None or iface.activeLayer().type() != QgsMapLayerType.VectorLayer:
+ if (
+ iface.activeLayer() is None
+ or iface.activeLayer().type() != QgsMapLayerType.VectorLayer
+ ):
return
for a in QgsApplication.processingRegistry().algorithms():
@@ -175,7 +187,7 @@ def fetchResults(self, string, context, feedback):
result.userData = a.id()
result.score = 0
- if (context.usingPrefix and not string):
+ if context.usingPrefix and not string:
self.resultFetched.emit(result)
if not string:
@@ -196,29 +208,37 @@ def fetchResults(self, string, context, feedback):
tagScore = 1
break
- result.score = QgsStringUtils.fuzzyScore(result.displayString, string) * 0.5 + tagScore * 0.5
+ result.score = (
+ QgsStringUtils.fuzzyScore(result.displayString, string) * 0.5
+ + tagScore * 0.5
+ )
if result.score > 0:
self.resultFetched.emit(result)
def triggerResult(self, result):
- config = {'IN_PLACE': True}
- alg = QgsApplication.processingRegistry().createAlgorithmById(result.userData, config)
+ config = {"IN_PLACE": True}
+ alg = QgsApplication.processingRegistry().createAlgorithmById(
+ result.userData, config
+ )
if alg:
ok, message = alg.canExecute()
if not ok:
dlg = MessageDialog()
- dlg.setTitle(self.tr('Missing dependency'))
+ dlg.setTitle(self.tr("Missing dependency"))
dlg.setMessage(message)
dlg.exec()
return
- in_place_input_parameter_name = 'INPUT'
- if hasattr(alg, 'inputParameterName'):
+ in_place_input_parameter_name = "INPUT"
+ if hasattr(alg, "inputParameterName"):
in_place_input_parameter_name = alg.inputParameterName()
- if [d for d in alg.parameterDefinitions() if
- d.name() not in (in_place_input_parameter_name, 'OUTPUT')]:
+ if [
+ d
+ for d in alg.parameterDefinitions()
+ if d.name() not in (in_place_input_parameter_name, "OUTPUT")
+ ]:
dlg = alg.createCustomParametersWidget(parent=iface.mainWindow())
if not dlg:
dlg = AlgorithmDialog(alg, True, parent=iface.mainWindow())
diff --git a/python/plugins/processing/gui/AutofillDialog.py b/python/plugins/processing/gui/AutofillDialog.py
index 2a02abd53c48..c5a3e0b1c717 100644
--- a/python/plugins/processing/gui/AutofillDialog.py
+++ b/python/plugins/processing/gui/AutofillDialog.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'August 2012'
-__copyright__ = '(C) 2012, Victor Olaya'
+__author__ = "Victor Olaya"
+__date__ = "August 2012"
+__copyright__ = "(C) 2012, Victor Olaya"
import os
import warnings
@@ -29,8 +29,7 @@
with warnings.catch_warnings():
warnings.filterwarnings("ignore", category=DeprecationWarning)
- WIDGET, BASE = uic.loadUiType(
- os.path.join(pluginPath, 'ui', 'DlgAutofill.ui'))
+ WIDGET, BASE = uic.loadUiType(os.path.join(pluginPath, "ui", "DlgAutofill.ui"))
class AutofillDialog(BASE, WIDGET):
diff --git a/python/plugins/processing/gui/BatchAlgorithmDialog.py b/python/plugins/processing/gui/BatchAlgorithmDialog.py
index c7988ff52d7c..42b66630a672 100644
--- a/python/plugins/processing/gui/BatchAlgorithmDialog.py
+++ b/python/plugins/processing/gui/BatchAlgorithmDialog.py
@@ -15,18 +15,20 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'August 2012'
-__copyright__ = '(C) 2012, Victor Olaya'
+__author__ = "Victor Olaya"
+__date__ = "August 2012"
+__copyright__ = "(C) 2012, Victor Olaya"
import codecs
import time
-from qgis.core import (QgsProcessingOutputHtml,
- QgsProcessingOutputNumber,
- QgsProcessingOutputString,
- QgsProcessingOutputBoolean,
- QgsProject)
+from qgis.core import (
+ QgsProcessingOutputHtml,
+ QgsProcessingOutputNumber,
+ QgsProcessingOutputString,
+ QgsProcessingOutputBoolean,
+ QgsProject,
+)
from qgis.gui import QgsProcessingBatchAlgorithmDialogBase
from qgis.utils import iface
@@ -44,7 +46,9 @@ def __init__(self, alg, parent=None):
self.setAlgorithm(alg)
- self.setWindowTitle(self.tr('Batch Processing - {0}').format(self.algorithm().displayName()))
+ self.setWindowTitle(
+ self.tr("Batch Processing - {0}").format(self.algorithm().displayName())
+ )
self.setMainWidget(BatchPanel(self, self.algorithm()))
self.context = None
@@ -54,6 +58,7 @@ def runAsSingle(self):
self.close()
from processing.gui.AlgorithmDialog import AlgorithmDialog
+
dlg = AlgorithmDialog(self.algorithm().create(), parent=iface.mainWindow())
dlg.show()
dlg.exec()
@@ -79,7 +84,8 @@ def runAlgorithm(self):
row=row,
context=self.processingContext(),
destinationProject=project,
- warnOnInvalid=True)
+ warnOnInvalid=True,
+ )
if ok:
alg_parameters.append(parameters)
if not alg_parameters:
@@ -92,61 +98,84 @@ def handleAlgorithmResults(self, algorithm, context, feedback, parameters):
def loadHtmlResults(self, results, num):
for out in self.algorithm().outputDefinitions():
- if isinstance(out, QgsProcessingOutputHtml) and out.name() in results and results[out.name()]:
- resultsList.addResult(icon=self.algorithm().icon(), name=f'{out.description()} [{num}]',
- result=results[out.name()])
+ if (
+ isinstance(out, QgsProcessingOutputHtml)
+ and out.name() in results
+ and results[out.name()]
+ ):
+ resultsList.addResult(
+ icon=self.algorithm().icon(),
+ name=f"{out.description()} [{num}]",
+ result=results[out.name()],
+ )
def createSummaryTable(self, algorithm_results, errors):
createTable = False
for out in self.algorithm().outputDefinitions():
- if isinstance(out, (QgsProcessingOutputNumber, QgsProcessingOutputString, QgsProcessingOutputBoolean)):
+ if isinstance(
+ out,
+ (
+ QgsProcessingOutputNumber,
+ QgsProcessingOutputString,
+ QgsProcessingOutputBoolean,
+ ),
+ ):
createTable = True
break
if not createTable and not errors:
return
- outputFile = getTempFilename('html')
- with codecs.open(outputFile, 'w', encoding='utf-8') as f:
+ outputFile = getTempFilename("html")
+ with codecs.open(outputFile, "w", encoding="utf-8") as f:
if createTable:
for i, res in enumerate(algorithm_results):
- results = res['results']
- params = res['parameters']
+ results = res["results"]
+ params = res["parameters"]
if i > 0:
- f.write(' \n')
- f.write(self.tr('Parameters \n'))
- f.write('\n')
+ f.write(" \n")
+ f.write(self.tr("Parameters \n"))
+ f.write("\n")
for param in self.algorithm().parameterDefinitions():
if not param.isDestination():
if param.name() in params:
- f.write('{} {} \n'.format(param.description(),
- params[param.name()]))
- f.write('
\n')
- f.write(self.tr('Results \n'))
- f.write('\n')
+ f.write(
+ "{} {} \n".format(
+ param.description(), params[param.name()]
+ )
+ )
+ f.write("
\n")
+ f.write(self.tr("Results \n"))
+ f.write("\n")
for out in self.algorithm().outputDefinitions():
if out.name() in results:
- f.write(f'{out.description()} {results[out.name()]} \n')
- f.write('
\n')
+ f.write(
+ f"{out.description()} {results[out.name()]} \n"
+ )
+ f.write("
\n")
if errors:
- f.write('{} \n'.format(self.tr('Errors')))
+ f.write('{} \n'.format(self.tr("Errors")))
for i, res in enumerate(errors):
- errors = res['errors']
- params = res['parameters']
+ errors = res["errors"]
+ params = res["parameters"]
if i > 0:
- f.write(' \n')
- f.write(self.tr('Parameters \n'))
- f.write('\n')
+ f.write(" \n")
+ f.write(self.tr("Parameters \n"))
+ f.write("\n")
for param in self.algorithm().parameterDefinitions():
if not param.isDestination():
if param.name() in params:
f.write(
- f'{param.description()} {params[param.name()]} \n')
- f.write('
\n')
- f.write('{} \n'.format(self.tr('Error')))
- f.write('{}
\n'.format(' '.join(errors)))
-
- resultsList.addResult(icon=self.algorithm().icon(),
- name=f'{self.algorithm().name()} [summary]', timestamp=time.localtime(),
- result=outputFile)
+ f"{param.description()} {params[param.name()]} \n"
+ )
+ f.write("
\n")
+ f.write("{} \n".format(self.tr("Error")))
+ f.write('{}
\n'.format(" ".join(errors)))
+
+ resultsList.addResult(
+ icon=self.algorithm().icon(),
+ name=f"{self.algorithm().name()} [summary]",
+ timestamp=time.localtime(),
+ result=outputFile,
+ )
diff --git a/python/plugins/processing/gui/BatchInputSelectionPanel.py b/python/plugins/processing/gui/BatchInputSelectionPanel.py
index 6d8d849c4fe4..ef6c62fde695 100644
--- a/python/plugins/processing/gui/BatchInputSelectionPanel.py
+++ b/python/plugins/processing/gui/BatchInputSelectionPanel.py
@@ -15,30 +15,41 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'August 2012'
-__copyright__ = '(C) 2012, Victor Olaya'
+__author__ = "Victor Olaya"
+__date__ = "August 2012"
+__copyright__ = "(C) 2012, Victor Olaya"
import os
from pathlib import Path
from qgis.PyQt.QtCore import pyqtSignal, QCoreApplication
-from qgis.PyQt.QtWidgets import QWidget, QHBoxLayout, QMenu, QPushButton, QLineEdit, QSizePolicy, QAction, QFileDialog
+from qgis.PyQt.QtWidgets import (
+ QWidget,
+ QHBoxLayout,
+ QMenu,
+ QPushButton,
+ QLineEdit,
+ QSizePolicy,
+ QAction,
+ QFileDialog,
+)
from qgis.PyQt.QtGui import QCursor
-from qgis.core import (QgsMapLayer,
- QgsRasterLayer,
- QgsSettings,
- QgsProject,
- QgsProcessing,
- QgsProcessingUtils,
- QgsProcessingParameterMultipleLayers,
- QgsProcessingParameterRasterLayer,
- QgsProcessingParameterVectorLayer,
- QgsProcessingParameterMeshLayer,
- QgsProcessingParameterPointCloudLayer,
- QgsProcessingParameterFeatureSource,
- QgsProcessingParameterMapLayer)
+from qgis.core import (
+ QgsMapLayer,
+ QgsRasterLayer,
+ QgsSettings,
+ QgsProject,
+ QgsProcessing,
+ QgsProcessingUtils,
+ QgsProcessingParameterMultipleLayers,
+ QgsProcessingParameterRasterLayer,
+ QgsProcessingParameterVectorLayer,
+ QgsProcessingParameterMeshLayer,
+ QgsProcessingParameterPointCloudLayer,
+ QgsProcessingParameterFeatureSource,
+ QgsProcessingParameterMapLayer,
+)
from processing.gui.MultipleInputDialog import MultipleInputDialog
@@ -58,15 +69,16 @@ def __init__(self, param, row, col, dialog):
self.horizontalLayout.setSpacing(0)
self.horizontalLayout.setMargin(0)
self.text = QLineEdit()
- self.text.setObjectName('text')
+ self.text.setObjectName("text")
self.text.setMinimumWidth(300)
- self.setValue('')
+ self.setValue("")
self.text.editingFinished.connect(self.textEditingFinished)
- self.text.setSizePolicy(QSizePolicy.Policy.Expanding,
- QSizePolicy.Policy.Expanding)
+ self.text.setSizePolicy(
+ QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding
+ )
self.horizontalLayout.addWidget(self.text)
self.pushButton = QPushButton()
- self.pushButton.setText('…')
+ self.pushButton.setText("…")
self.pushButton.clicked.connect(self.showPopupMenu)
self.horizontalLayout.addWidget(self.pushButton)
self.setLayout(self.horizontalLayout)
@@ -80,20 +92,30 @@ def _table(self):
def showPopupMenu(self):
popupmenu = QMenu()
- if not (isinstance(self.param, QgsProcessingParameterMultipleLayers)
- and self.param.layerType == dataobjects.TYPE_FILE):
+ if not (
+ isinstance(self.param, QgsProcessingParameterMultipleLayers)
+ and self.param.layerType == dataobjects.TYPE_FILE
+ ):
selectLayerAction = QAction(
- QCoreApplication.translate('BatchInputSelectionPanel', 'Select from Open Layers…'), self.pushButton)
+ QCoreApplication.translate(
+ "BatchInputSelectionPanel", "Select from Open Layers…"
+ ),
+ self.pushButton,
+ )
selectLayerAction.triggered.connect(self.showLayerSelectionDialog)
popupmenu.addAction(selectLayerAction)
selectFileAction = QAction(
- QCoreApplication.translate('BatchInputSelectionPanel', 'Select Files…'), self.pushButton)
+ QCoreApplication.translate("BatchInputSelectionPanel", "Select Files…"),
+ self.pushButton,
+ )
selectFileAction.triggered.connect(self.showFileSelectionDialog)
popupmenu.addAction(selectFileAction)
selectDirectoryAction = QAction(
- QCoreApplication.translate('BatchInputSelectionPanel', 'Select Directory…'), self.pushButton)
+ QCoreApplication.translate("BatchInputSelectionPanel", "Select Directory…"),
+ self.pushButton,
+ )
selectDirectoryAction.triggered.connect(self.showDirectorySelectionDialog)
popupmenu.addAction(selectDirectoryAction)
@@ -101,22 +123,27 @@ def showPopupMenu(self):
def showLayerSelectionDialog(self):
layers = []
- if (isinstance(self.param, QgsProcessingParameterRasterLayer)
- or (isinstance(self.param, QgsProcessingParameterMultipleLayers) and
- self.param.layerType() == QgsProcessing.SourceType.TypeRaster)):
+ if isinstance(self.param, QgsProcessingParameterRasterLayer) or (
+ isinstance(self.param, QgsProcessingParameterMultipleLayers)
+ and self.param.layerType() == QgsProcessing.SourceType.TypeRaster
+ ):
layers = QgsProcessingUtils.compatibleRasterLayers(QgsProject.instance())
elif isinstance(self.param, QgsProcessingParameterVectorLayer):
layers = QgsProcessingUtils.compatibleVectorLayers(QgsProject.instance())
elif isinstance(self.param, QgsProcessingParameterMapLayer):
layers = QgsProcessingUtils.compatibleLayers(QgsProject.instance())
- elif (isinstance(self.param, QgsProcessingParameterMeshLayer)
- or (isinstance(self.param, QgsProcessingParameterMultipleLayers) and
- self.param.layerType() == QgsProcessing.SourceType.TypeMesh)):
+ elif isinstance(self.param, QgsProcessingParameterMeshLayer) or (
+ isinstance(self.param, QgsProcessingParameterMultipleLayers)
+ and self.param.layerType() == QgsProcessing.SourceType.TypeMesh
+ ):
layers = QgsProcessingUtils.compatibleMeshLayers(QgsProject.instance())
- elif (isinstance(self.param, QgsProcessingParameterPointCloudLayer)
- or (isinstance(self.param, QgsProcessingParameterMultipleLayers) and
- self.param.layerType() == QgsProcessing.SourceType.TypePointCloud)):
- layers = QgsProcessingUtils.compatiblePointCloudLayers(QgsProject.instance())
+ elif isinstance(self.param, QgsProcessingParameterPointCloudLayer) or (
+ isinstance(self.param, QgsProcessingParameterMultipleLayers)
+ and self.param.layerType() == QgsProcessing.SourceType.TypePointCloud
+ ):
+ layers = QgsProcessingUtils.compatiblePointCloudLayers(
+ QgsProject.instance()
+ )
else:
datatypes = [QgsProcessing.SourceType.TypeVectorAnyGeometry]
if isinstance(self.param, QgsProcessingParameterFeatureSource):
@@ -125,16 +152,23 @@ def showLayerSelectionDialog(self):
datatypes = [self.param.layerType()]
if QgsProcessing.SourceType.TypeVectorAnyGeometry not in datatypes:
- layers = QgsProcessingUtils.compatibleVectorLayers(QgsProject.instance(), datatypes)
+ layers = QgsProcessingUtils.compatibleVectorLayers(
+ QgsProject.instance(), datatypes
+ )
else:
- layers = QgsProcessingUtils.compatibleVectorLayers(QgsProject.instance())
+ layers = QgsProcessingUtils.compatibleVectorLayers(
+ QgsProject.instance()
+ )
dlg = MultipleInputDialog([layer.name() for layer in layers])
dlg.exec()
def generate_layer_id(layer):
# prefer layer name if unique
- if len([l for l in layers if l.name().lower() == layer.name().lower()]) == 1:
+ if (
+ len([l for l in layers if l.name().lower() == layer.name().lower()])
+ == 1
+ ):
return layer.name()
else:
# otherwise fall back to layer id
@@ -146,14 +180,15 @@ def generate_layer_id(layer):
self.setValue(generate_layer_id(layers[selected[0]]))
else:
if isinstance(self.param, QgsProcessingParameterMultipleLayers):
- self.text.setText(';'.join(layers[idx].id() for idx in selected))
+ self.text.setText(";".join(layers[idx].id() for idx in selected))
else:
rowdif = len(selected) - (self._table().rowCount() - self.row)
for i in range(rowdif):
self._panel().addRow()
for i, layeridx in enumerate(selected):
- self._table().cellWidget(i + self.row,
- self.col).setValue(generate_layer_id(layers[layeridx]))
+ self._table().cellWidget(i + self.row, self.col).setValue(
+ generate_layer_id(layers[layeridx])
+ )
def showFileSelectionDialog(self):
self.showFileDialog(seldir=False)
@@ -168,21 +203,23 @@ def showFileDialog(self, seldir):
path = text
elif not seldir and os.path.isdir(os.path.dirname(text)):
path = os.path.dirname(text)
- elif settings.contains('/Processing/LastInputPath'):
- path = str(settings.value('/Processing/LastInputPath'))
+ elif settings.contains("/Processing/LastInputPath"):
+ path = str(settings.value("/Processing/LastInputPath"))
else:
- path = ''
+ path = ""
if not seldir:
ret, selected_filter = QFileDialog.getOpenFileNames(
- self, self.tr('Select Files'), path, self.param.createFileFilter()
+ self, self.tr("Select Files"), path, self.param.createFileFilter()
)
else:
- ret = QFileDialog.getExistingDirectory(self, self.tr('Select Directory'), path)
+ ret = QFileDialog.getExistingDirectory(
+ self, self.tr("Select Directory"), path
+ )
if ret:
if seldir:
- settings.setValue('/Processing/LastInputPath', ret)
+ settings.setValue("/Processing/LastInputPath", ret)
files = []
for pp in Path(ret).rglob("*"):
@@ -191,9 +228,14 @@ def showFileDialog(self, seldir):
p = pp.as_posix()
- if ((isinstance(self.param, QgsProcessingParameterRasterLayer)
- or (isinstance(self.param, QgsProcessingParameterMultipleLayers) and self.param.layerType() == QgsProcessing.SourceType.TypeRaster)) and
- not QgsRasterLayer.isValidRasterFileName(p)):
+ if (
+ isinstance(self.param, QgsProcessingParameterRasterLayer)
+ or (
+ isinstance(self.param, QgsProcessingParameterMultipleLayers)
+ and self.param.layerType()
+ == QgsProcessing.SourceType.TypeRaster
+ )
+ ) and not QgsRasterLayer.isValidRasterFileName(p):
continue
files.append(p)
@@ -203,7 +245,9 @@ def showFileDialog(self, seldir):
else:
files = list(ret)
- settings.setValue('/Processing/LastInputPath', os.path.dirname(str(files[0])))
+ settings.setValue(
+ "/Processing/LastInputPath", os.path.dirname(str(files[0]))
+ )
for i, filename in enumerate(files):
files[i] = dataobjects.getRasterSublayer(filename, self.param)
@@ -212,14 +256,13 @@ def showFileDialog(self, seldir):
self.textEditingFinished()
else:
if isinstance(self.param, QgsProcessingParameterMultipleLayers):
- self.text.setText(';'.join(str(f) for f in files))
+ self.text.setText(";".join(str(f) for f in files))
else:
rowdif = len(files) - (self._table().rowCount() - self.row)
for i in range(rowdif):
self._panel().addRow()
for i, f in enumerate(files):
- self._table().cellWidget(i + self.row,
- self.col).setValue(f)
+ self._table().cellWidget(i + self.row, self.col).setValue(f)
def textEditingFinished(self):
self._value = self.text.text()
diff --git a/python/plugins/processing/gui/BatchOutputSelectionPanel.py b/python/plugins/processing/gui/BatchOutputSelectionPanel.py
index bf68ef455840..3ea50265a597 100644
--- a/python/plugins/processing/gui/BatchOutputSelectionPanel.py
+++ b/python/plugins/processing/gui/BatchOutputSelectionPanel.py
@@ -15,26 +15,35 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'August 2012'
-__copyright__ = '(C) 2012, Victor Olaya'
+__author__ = "Victor Olaya"
+__date__ = "August 2012"
+__copyright__ = "(C) 2012, Victor Olaya"
import os
import re
-from qgis.core import (QgsMapLayer,
- QgsSettings,
- QgsProcessingParameterFolderDestination,
- QgsProcessingParameterRasterLayer,
- QgsProcessingParameterFeatureSource,
- QgsProcessingParameterVectorLayer,
- QgsProcessingParameterMultipleLayers,
- QgsProcessingParameterMapLayer,
- QgsProcessingParameterBoolean,
- QgsProcessingParameterEnum,
- QgsProject,
- QgsProcessingParameterMatrix)
-from qgis.PyQt.QtWidgets import QWidget, QPushButton, QLineEdit, QHBoxLayout, QSizePolicy, QFileDialog
+from qgis.core import (
+ QgsMapLayer,
+ QgsSettings,
+ QgsProcessingParameterFolderDestination,
+ QgsProcessingParameterRasterLayer,
+ QgsProcessingParameterFeatureSource,
+ QgsProcessingParameterVectorLayer,
+ QgsProcessingParameterMultipleLayers,
+ QgsProcessingParameterMapLayer,
+ QgsProcessingParameterBoolean,
+ QgsProcessingParameterEnum,
+ QgsProject,
+ QgsProcessingParameterMatrix,
+)
+from qgis.PyQt.QtWidgets import (
+ QWidget,
+ QPushButton,
+ QLineEdit,
+ QHBoxLayout,
+ QSizePolicy,
+ QFileDialog,
+)
from processing.gui.AutofillDialog import AutofillDialog
@@ -53,13 +62,14 @@ def __init__(self, output, alg, row, col, panel):
self.horizontalLayout.setSpacing(2)
self.horizontalLayout.setMargin(0)
self.text = QLineEdit()
- self.text.setText('')
+ self.text.setText("")
self.text.setMinimumWidth(300)
- self.text.setSizePolicy(QSizePolicy.Policy.Expanding,
- QSizePolicy.Policy.Expanding)
+ self.text.setSizePolicy(
+ QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding
+ )
self.horizontalLayout.addWidget(self.text)
self.pushButton = QPushButton()
- self.pushButton.setText('…')
+ self.pushButton.setText("…")
self.pushButton.clicked.connect(self.showSelectionDialog)
self.horizontalLayout.addWidget(self.pushButton)
self.setLayout(self.horizontalLayout)
@@ -71,48 +81,70 @@ def showSelectionDialog(self):
filefilter = self.output.createFileFilter()
settings = QgsSettings()
- if settings.contains('/Processing/LastBatchOutputPath'):
- path = str(settings.value('/Processing/LastBatchOutputPath'))
+ if settings.contains("/Processing/LastBatchOutputPath"):
+ path = str(settings.value("/Processing/LastBatchOutputPath"))
else:
- path = ''
- filename, selectedFileFilter = QFileDialog.getSaveFileName(self,
- self.tr('Save File'), path, filefilter)
+ path = ""
+ filename, selectedFileFilter = QFileDialog.getSaveFileName(
+ self, self.tr("Save File"), path, filefilter
+ )
if filename:
if not filename.lower().endswith(
- tuple(re.findall("\\*(\\.[a-z]{1,10})", filefilter))):
+ tuple(re.findall("\\*(\\.[a-z]{1,10})", filefilter))
+ ):
ext = re.search("\\*(\\.[a-z]{1,10})", selectedFileFilter)
if ext:
filename += ext.group(1)
- settings.setValue('/Processing/LastBatchOutputPath', os.path.dirname(filename))
+ settings.setValue(
+ "/Processing/LastBatchOutputPath", os.path.dirname(filename)
+ )
dlg = AutofillDialog(self.alg)
dlg.exec()
if dlg.mode is not None:
if dlg.mode == AutofillDialog.DO_NOT_AUTOFILL:
- self.table.cellWidget(self.row,
- self.col).setValue(filename)
+ self.table.cellWidget(self.row, self.col).setValue(filename)
elif dlg.mode == AutofillDialog.FILL_WITH_NUMBERS:
n = self.table.rowCount() - self.row
for i in range(n):
- name = filename[:filename.rfind('.')] \
- + str(i + 1) + filename[filename.rfind('.'):]
- self.table.cellWidget(i + self.row,
- self.col).setValue(name)
+ name = (
+ filename[: filename.rfind(".")]
+ + str(i + 1)
+ + filename[filename.rfind(".") :]
+ )
+ self.table.cellWidget(i + self.row, self.col).setValue(name)
elif dlg.mode == AutofillDialog.FILL_WITH_PARAMETER:
for row in range(self.row, self.table.rowCount()):
v = self.panel.valueForParameter(row - 1, dlg.param_name)
param = self.alg.parameterDefinition(dlg.param_name)
- if isinstance(param, (QgsProcessingParameterRasterLayer,
- QgsProcessingParameterFeatureSource,
- QgsProcessingParameterVectorLayer,
- QgsProcessingParameterMultipleLayers,
- QgsProcessingParameterMapLayer)):
+ if isinstance(
+ param,
+ (
+ QgsProcessingParameterRasterLayer,
+ QgsProcessingParameterFeatureSource,
+ QgsProcessingParameterVectorLayer,
+ QgsProcessingParameterMultipleLayers,
+ QgsProcessingParameterMapLayer,
+ ),
+ ):
if isinstance(v, QgsMapLayer):
s = v.name()
else:
if v in QgsProject.instance().mapLayers():
layer = QgsProject.instance().mapLayer(v)
# value is a layer ID, but we'd prefer to show a layer name if it's unique in the project
- if len([l for _, l in QgsProject.instance().mapLayers().items() if l.name().lower() == layer.name().lower()]) == 1:
+ if (
+ len(
+ [
+ l
+ for _, l in QgsProject.instance()
+ .mapLayers()
+ .items()
+ if l.name().lower()
+ == layer.name().lower()
+ ]
+ )
+ == 1
+ ):
s = layer.name()
else:
# otherwise fall back to layer id
@@ -123,30 +155,33 @@ def showSelectionDialog(self):
s = os.path.basename(v)
s = os.path.splitext(s)[0]
elif isinstance(param, QgsProcessingParameterBoolean):
- s = 'true' if v else 'false'
+ s = "true" if v else "false"
elif isinstance(param, QgsProcessingParameterEnum):
s = param.options()[v]
else:
s = str(v)
- name = filename[:filename.rfind('.')] + s \
- + filename[filename.rfind('.'):]
- self.table.cellWidget(row,
- self.col).setValue(name)
+ name = (
+ filename[: filename.rfind(".")]
+ + s
+ + filename[filename.rfind(".") :]
+ )
+ self.table.cellWidget(row, self.col).setValue(name)
def selectDirectory(self):
settings = QgsSettings()
- if settings.contains('/Processing/LastBatchOutputPath'):
- lastDir = str(settings.value('/Processing/LastBatchOutputPath'))
+ if settings.contains("/Processing/LastBatchOutputPath"):
+ lastDir = str(settings.value("/Processing/LastBatchOutputPath"))
else:
- lastDir = ''
+ lastDir = ""
- dirName = QFileDialog.getExistingDirectory(self,
- self.tr('Output Directory'), lastDir, QFileDialog.Option.ShowDirsOnly)
+ dirName = QFileDialog.getExistingDirectory(
+ self, self.tr("Output Directory"), lastDir, QFileDialog.Option.ShowDirsOnly
+ )
if dirName:
self.table.cellWidget(self.row, self.col).setValue(dirName)
- settings.setValue('/Processing/LastBatchOutputPath', dirName)
+ settings.setValue("/Processing/LastBatchOutputPath", dirName)
def setValue(self, text):
return self.text.setText(text)
diff --git a/python/plugins/processing/gui/BatchPanel.py b/python/plugins/processing/gui/BatchPanel.py
index b3e66e6f42ae..d6b75923543a 100644
--- a/python/plugins/processing/gui/BatchPanel.py
+++ b/python/plugins/processing/gui/BatchPanel.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Alexander Bruy'
-__date__ = 'November 2014'
-__copyright__ = '(C) 2014, Alexander Bruy'
+__author__ = "Alexander Bruy"
+__date__ = "November 2014"
+__copyright__ = "(C) 2014, Alexander Bruy"
import os
import json
@@ -34,7 +34,7 @@
QMessageBox,
QToolButton,
QMenu,
- QAction
+ QAction,
)
# adding to this list? also update the QgsProcessingHistoryProvider executeAlgorithm imports!!
@@ -42,18 +42,14 @@
from qgis.PyQt.QtCore import (
QTime, # NOQA - must be here for saved file evaluation
QDate, # NOQA - must be here for saved file evaluation
- QDateTime # NOQA - must be here for saved file evaluation
+ QDateTime, # NOQA - must be here for saved file evaluation
)
from qgis.PyQt.QtGui import (
QPalette,
QColor, # NOQA - must be here for saved file evaluation
)
-from qgis.PyQt.QtCore import (
- QDir,
- QFileInfo,
- QCoreApplication
-)
+from qgis.PyQt.QtCore import QDir, QFileInfo, QCoreApplication
from qgis.core import (
Qgis,
QgsApplication,
@@ -84,14 +80,14 @@
QgsProcessingUtils,
QgsFileFilterGenerator,
QgsProcessingContext,
- QgsFileUtils
+ QgsFileUtils,
)
from qgis.gui import (
QgsProcessingParameterWidgetContext,
QgsProcessingContextGenerator,
QgsFindFilesByPatternDialog,
QgsExpressionBuilderDialog,
- QgsPanelWidget
+ QgsPanelWidget,
)
from qgis.utils import iface
@@ -106,8 +102,7 @@
with warnings.catch_warnings():
warnings.filterwarnings("ignore", category=DeprecationWarning)
- WIDGET, BASE = uic.loadUiType(
- os.path.join(pluginPath, 'ui', 'widgetBatchPanel.ui'))
+ WIDGET, BASE = uic.loadUiType(os.path.join(pluginPath, "ui", "widgetBatchPanel.ui"))
class BatchPanelFillWidget(QToolButton):
@@ -122,7 +117,7 @@ def __init__(self, parameterDefinition, column, panel, parent=None):
self.column = column
self.panel = panel
- self.setText(QCoreApplication.translate('BatchPanel', 'Autofill…'))
+ self.setText(QCoreApplication.translate("BatchPanel", "Autofill…"))
f = self.font()
f.setItalic(True)
self.setFont(f)
@@ -137,45 +132,73 @@ def createMenu(self):
self.menu.clear()
self.menu.setMinimumWidth(self.width())
- fill_down_action = QAction(self.tr('Fill Down'), self.menu)
+ fill_down_action = QAction(self.tr("Fill Down"), self.menu)
fill_down_action.triggered.connect(self.fillDown)
- fill_down_action.setToolTip(self.tr('Copy the first value down to all other rows'))
+ fill_down_action.setToolTip(
+ self.tr("Copy the first value down to all other rows")
+ )
self.menu.addAction(fill_down_action)
- calculate_by_expression = QAction(QCoreApplication.translate('BatchPanel', 'Calculate by Expression…'),
- self.menu)
- calculate_by_expression.setIcon(QgsApplication.getThemeIcon('/mActionCalculateField.svg'))
+ calculate_by_expression = QAction(
+ QCoreApplication.translate("BatchPanel", "Calculate by Expression…"),
+ self.menu,
+ )
+ calculate_by_expression.setIcon(
+ QgsApplication.getThemeIcon("/mActionCalculateField.svg")
+ )
calculate_by_expression.triggered.connect(self.calculateByExpression)
- calculate_by_expression.setToolTip(self.tr('Calculates parameter values by evaluating an expression'))
+ calculate_by_expression.setToolTip(
+ self.tr("Calculates parameter values by evaluating an expression")
+ )
self.menu.addAction(calculate_by_expression)
- add_by_expression = QAction(QCoreApplication.translate('BatchPanel', 'Add Values by Expression…'),
- self.menu)
+ add_by_expression = QAction(
+ QCoreApplication.translate("BatchPanel", "Add Values by Expression…"),
+ self.menu,
+ )
add_by_expression.triggered.connect(self.addByExpression)
- add_by_expression.setToolTip(self.tr('Adds new parameter values by evaluating an expression'))
+ add_by_expression.setToolTip(
+ self.tr("Adds new parameter values by evaluating an expression")
+ )
self.menu.addAction(add_by_expression)
- if not self.parameterDefinition.isDestination() and isinstance(self.parameterDefinition, QgsFileFilterGenerator):
+ if not self.parameterDefinition.isDestination() and isinstance(
+ self.parameterDefinition, QgsFileFilterGenerator
+ ):
self.menu.addSeparator()
- find_by_pattern_action = QAction(QCoreApplication.translate('BatchPanel', 'Add Files by Pattern…'),
- self.menu)
+ find_by_pattern_action = QAction(
+ QCoreApplication.translate("BatchPanel", "Add Files by Pattern…"),
+ self.menu,
+ )
find_by_pattern_action.triggered.connect(self.addFilesByPattern)
- find_by_pattern_action.setToolTip(self.tr('Adds files by a file pattern match'))
+ find_by_pattern_action.setToolTip(
+ self.tr("Adds files by a file pattern match")
+ )
self.menu.addAction(find_by_pattern_action)
select_file_action = QAction(
- QCoreApplication.translate('BatchInputSelectionPanel', 'Select Files…'), self.menu)
+ QCoreApplication.translate("BatchInputSelectionPanel", "Select Files…"),
+ self.menu,
+ )
select_file_action.triggered.connect(self.showFileSelectionDialog)
self.menu.addAction(select_file_action)
select_directory_action = QAction(
- QCoreApplication.translate('BatchInputSelectionPanel', 'Add All Files from a Directory…'), self.menu)
+ QCoreApplication.translate(
+ "BatchInputSelectionPanel", "Add All Files from a Directory…"
+ ),
+ self.menu,
+ )
select_directory_action.triggered.connect(self.showDirectorySelectionDialog)
self.menu.addAction(select_directory_action)
if not isinstance(self.parameterDefinition, QgsProcessingParameterFile):
select_layer_action = QAction(
- QCoreApplication.translate('BatchInputSelectionPanel', 'Select from Open Layers…'), self.menu)
+ QCoreApplication.translate(
+ "BatchInputSelectionPanel", "Select from Open Layers…"
+ ),
+ self.menu,
+ )
select_layer_action.triggered.connect(self.showLayerSelectionDialog)
self.menu.addAction(select_layer_action)
@@ -219,7 +242,9 @@ def setRowValue(self, row, value, context):
wrapper = self.panel.wrappers[row][self.column]
if wrapper is None:
# e.g. destination header
- self.panel.tblParameters.cellWidget(row + 1, self.column).setValue(str(value))
+ self.panel.tblParameters.cellWidget(row + 1, self.column).setValue(
+ str(value)
+ )
else:
wrapper.setParameterValue(value, context)
@@ -241,19 +266,22 @@ def addFilesByPattern(self):
def showFileSelectionDialog(self):
settings = QgsSettings()
- if settings.contains('/Processing/LastInputPath'):
- path = str(settings.value('/Processing/LastInputPath'))
+ if settings.contains("/Processing/LastInputPath"):
+ path = str(settings.value("/Processing/LastInputPath"))
else:
path = QDir.homePath()
files, selected_filter = QFileDialog.getOpenFileNames(
- self, self.tr('Select Files'), path, self.parameterDefinition.createFileFilter()
+ self,
+ self.tr("Select Files"),
+ path,
+ self.parameterDefinition.createFileFilter(),
)
if not files:
return
- settings.setValue('/Processing/LastInputPath', os.path.dirname(str(files[0])))
+ settings.setValue("/Processing/LastInputPath", os.path.dirname(str(files[0])))
context = dataobjects.createContext()
@@ -265,16 +293,18 @@ def showFileSelectionDialog(self):
def showDirectorySelectionDialog(self):
settings = QgsSettings()
- if settings.contains('/Processing/LastInputPath'):
- path = str(settings.value('/Processing/LastInputPath'))
+ if settings.contains("/Processing/LastInputPath"):
+ path = str(settings.value("/Processing/LastInputPath"))
else:
path = QDir.homePath()
- folder = QFileDialog.getExistingDirectory(self, self.tr('Select Directory'), path)
+ folder = QFileDialog.getExistingDirectory(
+ self, self.tr("Select Directory"), path
+ )
if not folder:
return
- settings.setValue('/Processing/LastInputPath', folder)
+ settings.setValue("/Processing/LastInputPath", folder)
files = []
for pp in Path(folder).rglob("*"):
@@ -283,9 +313,14 @@ def showDirectorySelectionDialog(self):
p = pp.as_posix()
- if isinstance(self.parameterDefinition, QgsProcessingParameterRasterLayer) or (
- isinstance(self.parameterDefinition, QgsProcessingParameterMultipleLayers)
- and self.parameterDefinition.layerType() == QgsProcessing.SourceType.TypeRaster
+ if isinstance(
+ self.parameterDefinition, QgsProcessingParameterRasterLayer
+ ) or (
+ isinstance(
+ self.parameterDefinition, QgsProcessingParameterMultipleLayers
+ )
+ and self.parameterDefinition.layerType()
+ == QgsProcessing.SourceType.TypeRaster
):
if not QgsRasterLayer.isValidRasterFileName(p):
continue
@@ -307,8 +342,11 @@ def showLayerSelectionDialog(self):
layers = []
if isinstance(self.parameterDefinition, QgsProcessingParameterRasterLayer):
layers = QgsProcessingUtils.compatibleRasterLayers(QgsProject.instance())
- elif isinstance(self.parameterDefinition,
- QgsProcessingParameterMultipleLayers) and self.parameterDefinition.layerType() == QgsProcessing.SourceType.TypeRaster:
+ elif (
+ isinstance(self.parameterDefinition, QgsProcessingParameterMultipleLayers)
+ and self.parameterDefinition.layerType()
+ == QgsProcessing.SourceType.TypeRaster
+ ):
layers = QgsProcessingUtils.compatibleRasterLayers(QgsProject.instance())
elif isinstance(self.parameterDefinition, QgsProcessingParameterVectorLayer):
layers = QgsProcessingUtils.compatibleVectorLayers(QgsProject.instance())
@@ -316,25 +354,45 @@ def showLayerSelectionDialog(self):
layers = QgsProcessingUtils.compatibleLayers(QgsProject.instance())
elif isinstance(self.parameterDefinition, QgsProcessingParameterMeshLayer):
layers = QgsProcessingUtils.compatibleMeshLayers(QgsProject.instance())
- elif isinstance(self.parameterDefinition,
- QgsProcessingParameterMultipleLayers) and self.parameterDefinition.layerType() == QgsProcessing.SourceType.TypeMesh:
+ elif (
+ isinstance(self.parameterDefinition, QgsProcessingParameterMultipleLayers)
+ and self.parameterDefinition.layerType()
+ == QgsProcessing.SourceType.TypeMesh
+ ):
layers = QgsProcessingUtils.compatibleMeshLayers(QgsProject.instance())
- elif isinstance(self.parameterDefinition, QgsProcessingParameterPointCloudLayer):
- layers = QgsProcessingUtils.compatiblePointCloudLayers(QgsProject.instance())
- elif isinstance(self.parameterDefinition,
- QgsProcessingParameterMultipleLayers) and self.parameterDefinition.layerType() == QgsProcessing.SourceType.TypePointCloud:
- layers = QgsProcessingUtils.compatiblePointCloudLayers(QgsProject.instance())
+ elif isinstance(
+ self.parameterDefinition, QgsProcessingParameterPointCloudLayer
+ ):
+ layers = QgsProcessingUtils.compatiblePointCloudLayers(
+ QgsProject.instance()
+ )
+ elif (
+ isinstance(self.parameterDefinition, QgsProcessingParameterMultipleLayers)
+ and self.parameterDefinition.layerType()
+ == QgsProcessing.SourceType.TypePointCloud
+ ):
+ layers = QgsProcessingUtils.compatiblePointCloudLayers(
+ QgsProject.instance()
+ )
else:
datatypes = [QgsProcessing.SourceType.TypeVectorAnyGeometry]
- if isinstance(self.parameterDefinition, QgsProcessingParameterFeatureSource):
+ if isinstance(
+ self.parameterDefinition, QgsProcessingParameterFeatureSource
+ ):
datatypes = self.parameterDefinition.dataTypes()
- elif isinstance(self.parameterDefinition, QgsProcessingParameterMultipleLayers):
+ elif isinstance(
+ self.parameterDefinition, QgsProcessingParameterMultipleLayers
+ ):
datatypes = [self.parameterDefinition.layerType()]
if QgsProcessing.SourceType.TypeVectorAnyGeometry not in datatypes:
- layers = QgsProcessingUtils.compatibleVectorLayers(QgsProject.instance(), datatypes)
+ layers = QgsProcessingUtils.compatibleVectorLayers(
+ QgsProject.instance(), datatypes
+ )
else:
- layers = QgsProcessingUtils.compatibleVectorLayers(QgsProject.instance())
+ layers = QgsProcessingUtils.compatibleVectorLayers(
+ QgsProject.instance()
+ )
dlg = MultipleInputDialog([layer.name() for layer in layers])
dlg.exec()
@@ -371,29 +429,35 @@ def populateByExpression(self, adding=False):
expression_context = context.expressionContext()
# use the first row parameter values as a preview during expression creation
- params, ok = self.panel.parametersForRow(row=0,
- context=context,
- warnOnInvalid=False)
- alg_scope = QgsExpressionContextUtils.processingAlgorithmScope(self.panel.alg, params, context)
+ params, ok = self.panel.parametersForRow(
+ row=0, context=context, warnOnInvalid=False
+ )
+ alg_scope = QgsExpressionContextUtils.processingAlgorithmScope(
+ self.panel.alg, params, context
+ )
# create explicit variables corresponding to every parameter
for k, v in params.items():
alg_scope.setVariable(k, v, True)
# add batchCount in the alg scope to be used in the expressions. 0 is only an example value
- alg_scope.setVariable('row_number', 0, False)
+ alg_scope.setVariable("row_number", 0, False)
expression_context.appendScope(alg_scope)
# mark the parameter variables as highlighted for discoverability
highlighted_vars = expression_context.highlightedVariables()
highlighted_vars.extend(list(params.keys()))
- highlighted_vars.append('row_number')
+ highlighted_vars.append("row_number")
expression_context.setHighlightedVariables(highlighted_vars)
- dlg = QgsExpressionBuilderDialog(layer=None, context=context.expressionContext())
+ dlg = QgsExpressionBuilderDialog(
+ layer=None, context=context.expressionContext()
+ )
if adding:
- dlg.setExpectedOutputFormat(self.tr('An array of values corresponding to each new row to add'))
+ dlg.setExpectedOutputFormat(
+ self.tr("An array of values corresponding to each new row to add")
+ )
if not dlg.exec():
return
@@ -413,20 +477,22 @@ def populateByExpression(self, adding=False):
else:
self.panel.tblParameters.setUpdatesEnabled(False)
for row in range(self.panel.batchRowCount()):
- params, ok = self.panel.parametersForRow(row=row,
- context=context,
- warnOnInvalid=False)
+ params, ok = self.panel.parametersForRow(
+ row=row, context=context, warnOnInvalid=False
+ )
# remove previous algorithm scope -- we need to rebuild this completely, using the
# other parameter values from the current row
expression_context.popScope()
- alg_scope = QgsExpressionContextUtils.processingAlgorithmScope(self.panel.alg, params, context)
+ alg_scope = QgsExpressionContextUtils.processingAlgorithmScope(
+ self.panel.alg, params, context
+ )
for k, v in params.items():
alg_scope.setVariable(k, v, True)
# add batch row number as evaluable variable in algorithm scope
- alg_scope.setVariable('row_number', row, False)
+ alg_scope.setVariable("row_number", row, False)
expression_context.appendScope(alg_scope)
@@ -454,11 +520,13 @@ def __init__(self, parent, alg):
self.btnAdvanced.hide()
# Set icons
- self.btnAdd.setIcon(QgsApplication.getThemeIcon('/symbologyAdd.svg'))
- self.btnRemove.setIcon(QgsApplication.getThemeIcon('/symbologyRemove.svg'))
- self.btnOpen.setIcon(QgsApplication.getThemeIcon('/mActionFileOpen.svg'))
- self.btnSave.setIcon(QgsApplication.getThemeIcon('/mActionFileSave.svg'))
- self.btnAdvanced.setIcon(QgsApplication.getThemeIcon("/processingAlgorithm.svg"))
+ self.btnAdd.setIcon(QgsApplication.getThemeIcon("/symbologyAdd.svg"))
+ self.btnRemove.setIcon(QgsApplication.getThemeIcon("/symbologyRemove.svg"))
+ self.btnOpen.setIcon(QgsApplication.getThemeIcon("/mActionFileOpen.svg"))
+ self.btnSave.setIcon(QgsApplication.getThemeIcon("/mActionFileSave.svg"))
+ self.btnAdvanced.setIcon(
+ QgsApplication.getThemeIcon("/processingAlgorithm.svg")
+ )
self.alg = alg
self.parent = parent
@@ -469,7 +537,9 @@ def __init__(self, parent, alg):
self.btnSave.clicked.connect(self.save)
self.btnAdvanced.toggled.connect(self.toggleAdvancedMode)
- self.tblParameters.horizontalHeader().resizeSections(QHeaderView.ResizeMode.ResizeToContents)
+ self.tblParameters.horizontalHeader().resizeSections(
+ QHeaderView.ResizeMode.ResizeToContents
+ )
self.tblParameters.horizontalHeader().setDefaultSectionSize(250)
self.tblParameters.horizontalHeader().setMinimumSectionSize(150)
@@ -502,8 +572,7 @@ def initWidgets(self):
break
# Determine column count
- self.tblParameters.setColumnCount(
- len(self.alg.parameterDefinitions()))
+ self.tblParameters.setColumnCount(len(self.alg.parameterDefinitions()))
# Table headers
column = 0
@@ -511,8 +580,12 @@ def initWidgets(self):
if param.isDestination():
continue
self.tblParameters.setHorizontalHeaderItem(
- column, QTableWidgetItem(param.description()))
- if param.flags() & QgsProcessingParameterDefinition.Flag.FlagAdvanced or param.flags() & QgsProcessingParameterDefinition.Flag.FlagHidden:
+ column, QTableWidgetItem(param.description())
+ )
+ if (
+ param.flags() & QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ or param.flags() & QgsProcessingParameterDefinition.Flag.FlagHidden
+ ):
self.tblParameters.setColumnHidden(column, True)
self.column_to_parameter_definition[column] = param.name()
@@ -522,7 +595,8 @@ def initWidgets(self):
for out in self.alg.destinationParameterDefinitions():
if not out.flags() & QgsProcessingParameterDefinition.Flag.FlagHidden:
self.tblParameters.setHorizontalHeaderItem(
- column, QTableWidgetItem(out.description()))
+ column, QTableWidgetItem(out.description())
+ )
self.column_to_parameter_definition[column] = out.name()
self.parameter_to_column[out.name()] = column
column += 1
@@ -532,8 +606,12 @@ def initWidgets(self):
# Add an empty row to begin
self.addRow()
- self.tblParameters.horizontalHeader().resizeSections(QHeaderView.ResizeMode.ResizeToContents)
- self.tblParameters.verticalHeader().setSectionResizeMode(QHeaderView.ResizeMode.ResizeToContents)
+ self.tblParameters.horizontalHeader().resizeSections(
+ QHeaderView.ResizeMode.ResizeToContents
+ )
+ self.tblParameters.verticalHeader().setSectionResizeMode(
+ QHeaderView.ResizeMode.ResizeToContents
+ )
self.tblParameters.horizontalHeader().setStretchLastSection(True)
def batchRowCount(self):
@@ -552,7 +630,9 @@ def load(self):
message_box.setWindowTitle(self.tr("Security warning"))
message_box.setText(
self.tr(
- "This algorithm is a potential security risk if executed with unchecked inputs, and may result in system damage or data leaks. Only continue if you trust the source of the file. Continue?"))
+ "This algorithm is a potential security risk if executed with unchecked inputs, and may result in system damage or data leaks. Only continue if you trust the source of the file. Continue?"
+ )
+ )
message_box.setIcon(QMessageBox.Icon.Warning)
message_box.addButton(QMessageBox.StandardButton.Yes)
message_box.addButton(QMessageBox.StandardButton.No)
@@ -563,17 +643,20 @@ def load(self):
settings = QgsSettings()
last_path = settings.value("/Processing/LastBatchPath", QDir.homePath())
- filters = ';;'.join([self.tr('Batch Processing files (*.batch)'),
- self.tr('JSON files (*.json)')])
- filename, _ = QFileDialog.getOpenFileName(self,
- self.tr('Open Batch'),
- last_path,
- filters)
+ filters = ";;".join(
+ [
+ self.tr("Batch Processing files (*.batch)"),
+ self.tr("JSON files (*.json)"),
+ ]
+ )
+ filename, _ = QFileDialog.getOpenFileName(
+ self, self.tr("Open Batch"), last_path, filters
+ )
if not filename:
return
last_path = QFileInfo(filename).path()
- settings.setValue('/Processing/LastBatchPath', last_path)
+ settings.setValue("/Processing/LastBatchPath", last_path)
with open(filename) as f:
values = json.load(f)
@@ -583,17 +666,20 @@ def load(self):
else:
QMessageBox.critical(
self,
- self.tr('Load Batch Parameters'),
- self.tr('This file format is unknown and cannot be opened as batch parameters.'))
+ self.tr("Load Batch Parameters"),
+ self.tr(
+ "This file format is unknown and cannot be opened as batch parameters."
+ ),
+ )
else:
self.load_old_json_batch_file(values)
- def load_batch_file_3_40_version(self, values: Dict):
+ def load_batch_file_3_40_version(self, values: dict):
"""
Loads the newer version 3.40 batch parameter JSON format
"""
context = dataobjects.createContext()
- rows: List = values.get(self.ROWS, [])
+ rows: list = values.get(self.ROWS, [])
self.clear()
for row_number, row in enumerate(rows):
@@ -619,14 +705,17 @@ def load_batch_file_3_40_version(self, values: Dict):
widget = self.tblParameters.cellWidget(row_number + 1, column)
widget.setValue(value)
- def load_old_json_batch_file(self, values: List):
+ def load_old_json_batch_file(self, values: list):
"""
Loads the old, insecure batch parameter JSON format
"""
message_box = QMessageBox()
message_box.setWindowTitle(self.tr("Security warning"))
message_box.setText(
- self.tr("Opening older QGIS batch Processing files from an untrusted source can harm your computer. Only continue if you trust the source of the file. Continue?"))
+ self.tr(
+ "Opening older QGIS batch Processing files from an untrusted source can harm your computer. Only continue if you trust the source of the file. Continue?"
+ )
+ )
message_box.setIcon(QMessageBox.Icon.Warning)
message_box.addButton(QMessageBox.StandardButton.Yes)
message_box.addButton(QMessageBox.StandardButton.No)
@@ -663,8 +752,9 @@ def load_old_json_batch_file(self, values: List):
except TypeError:
QMessageBox.critical(
self,
- self.tr('Load Batch Parameters'),
- self.tr('An error occurred while reading the batch parameters file.'))
+ self.tr("Load Batch Parameters"),
+ self.tr("An error occurred while reading the batch parameters file."),
+ )
def save(self):
row_parameters = []
@@ -683,9 +773,12 @@ def save(self):
value = wrapper.parameterValue()
if not param.checkValueIsAcceptable(value, context):
- msg = self.tr('Wrong or missing parameter value: {0} (row {1})').format(
- param.description(), row + 2)
- self.parent.messageBar().pushMessage("", msg, level=Qgis.MessageLevel.Warning, duration=5)
+ msg = self.tr(
+ "Wrong or missing parameter value: {0} (row {1})"
+ ).format(param.description(), row + 2)
+ self.parent.messageBar().pushMessage(
+ "", msg, level=Qgis.MessageLevel.Warning, duration=5
+ )
return
this_row_params[param.name()] = param.valueAsJsonObject(value, context)
@@ -695,34 +788,39 @@ def save(self):
col = self.parameter_to_column[out.name()]
widget = self.tblParameters.cellWidget(row + 1, col)
text = widget.getValue()
- if text.strip() != '':
+ if text.strip() != "":
this_row_outputs[out.name()] = text.strip()
else:
- self.parent.messageBar().pushMessage("",
- self.tr('Wrong or missing output value: {0} (row {1})').format(
- out.description(), row + 2),
- level=Qgis.MessageLevel.Warning, duration=5)
+ self.parent.messageBar().pushMessage(
+ "",
+ self.tr("Wrong or missing output value: {0} (row {1})").format(
+ out.description(), row + 2
+ ),
+ level=Qgis.MessageLevel.Warning,
+ duration=5,
+ )
return
- row_parameters.append({self.PARAMETERS: this_row_params, self.OUTPUTS: this_row_outputs})
+ row_parameters.append(
+ {self.PARAMETERS: this_row_params, self.OUTPUTS: this_row_outputs}
+ )
- output_json = {
- self.FORMAT: self.CURRENT_FORMAT,
- self.ROWS: row_parameters
- }
+ output_json = {self.FORMAT: self.CURRENT_FORMAT, self.ROWS: row_parameters}
settings = QgsSettings()
last_path = settings.value("/Processing/LastBatchPath", QDir.homePath())
- filename, __ = QFileDialog.getSaveFileName(self,
- self.tr('Save Batch'),
- last_path,
- self.tr('Batch Processing files (*.batch)'))
+ filename, __ = QFileDialog.getSaveFileName(
+ self,
+ self.tr("Save Batch"),
+ last_path,
+ self.tr("Batch Processing files (*.batch)"),
+ )
if not filename:
return
- filename = QgsFileUtils.ensureFileNameHasExtension(filename, ['batch'])
+ filename = QgsFileUtils.ensureFileNameHasExtension(filename, ["batch"])
last_path = QFileInfo(filename).path()
- settings.setValue('/Processing/LastBatchPath', last_path)
- with open(filename, 'w') as f:
+ settings.setValue("/Processing/LastBatchPath", last_path)
+ with open(filename, "w") as f:
json.dump(output_json, f, indent=2)
def setCellWrapper(self, row, column, wrapper, context):
@@ -756,8 +854,12 @@ def setCellWrapper(self, row, column, wrapper, context):
def addFillRow(self):
self.tblParameters.setRowCount(1)
for col, name in self.column_to_parameter_definition.items():
- param_definition = self.alg.parameterDefinition(self.column_to_parameter_definition[col])
- self.tblParameters.setCellWidget(0, col, BatchPanelFillWidget(param_definition, col, self))
+ param_definition = self.alg.parameterDefinition(
+ self.column_to_parameter_definition[col]
+ )
+ self.tblParameters.setCellWidget(
+ 0, col, BatchPanelFillWidget(param_definition, col, self)
+ )
def addRow(self, nb=1):
self.tblParameters.setUpdatesEnabled(False)
@@ -774,7 +876,9 @@ def addRow(self, nb=1):
continue
column = self.parameter_to_column[param.name()]
- wrapper = WidgetWrapperFactory.create_wrapper(param, self.parent, row, column)
+ wrapper = WidgetWrapperFactory.create_wrapper(
+ param, self.parent, row, column
+ )
wrappers[param.name()] = wrapper
self.setCellWrapper(row, column, wrapper, context)
@@ -784,8 +888,10 @@ def addRow(self, nb=1):
column = self.parameter_to_column[out.name()]
self.tblParameters.setCellWidget(
- row, column, BatchOutputSelectionPanel(
- out, self.alg, row, column, self))
+ row,
+ column,
+ BatchOutputSelectionPanel(out, self.alg, row, column, self),
+ )
for wrapper in list(wrappers.values()):
wrapper.postInitialize(list(wrappers.values()))
@@ -819,8 +925,15 @@ def removeRows(self):
def toggleAdvancedMode(self, checked):
for param in self.alg.parameterDefinitions():
- if param.flags() & QgsProcessingParameterDefinition.Flag.FlagAdvanced and not (param.flags() & QgsProcessingParameterDefinition.Flag.FlagHidden):
- self.tblParameters.setColumnHidden(self.parameter_to_column[param.name()], not checked)
+ if (
+ param.flags() & QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ and not (
+ param.flags() & QgsProcessingParameterDefinition.Flag.FlagHidden
+ )
+ ):
+ self.tblParameters.setColumnHidden(
+ self.parameter_to_column[param.name()], not checked
+ )
def valueForParameter(self, row, parameter_name):
"""
@@ -829,11 +942,13 @@ def valueForParameter(self, row, parameter_name):
wrapper = self.wrappers[row][self.parameter_to_column[parameter_name]]
return wrapper.parameterValue()
- def parametersForRow(self,
- row: int,
- context: QgsProcessingContext,
- destinationProject: Optional[QgsProject] = None,
- warnOnInvalid: bool = True):
+ def parametersForRow(
+ self,
+ row: int,
+ context: QgsProcessingContext,
+ destinationProject: Optional[QgsProject] = None,
+ warnOnInvalid: bool = True,
+ ):
"""
Returns the parameters dictionary corresponding to a row in the batch table
"""
@@ -844,11 +959,17 @@ def parametersForRow(self,
col = self.parameter_to_column[param.name()]
wrapper = self.wrappers[row][col]
parameters[param.name()] = wrapper.parameterValue()
- if warnOnInvalid and not param.checkValueIsAcceptable(wrapper.parameterValue()):
- self.parent.messageBar().pushMessage("",
- self.tr('Wrong or missing parameter value: {0} (row {1})').format(
- param.description(), row + 2),
- level=Qgis.MessageLevel.Warning, duration=5)
+ if warnOnInvalid and not param.checkValueIsAcceptable(
+ wrapper.parameterValue()
+ ):
+ self.parent.messageBar().pushMessage(
+ "",
+ self.tr("Wrong or missing parameter value: {0} (row {1})").format(
+ param.description(), row + 2
+ ),
+ level=Qgis.MessageLevel.Warning,
+ duration=5,
+ )
return {}, False
count_visible_outputs = 0
@@ -864,25 +985,32 @@ def parametersForRow(self,
if warnOnInvalid:
if not out.checkValueIsAcceptable(text):
msg = self.tr(
- 'Wrong or missing output value: {0} (row {1})').format(
- out.description(), row + 2)
- self.parent.messageBar().pushMessage("", msg,
- level=Qgis.MessageLevel.Warning,
- duration=5)
+ "Wrong or missing output value: {0} (row {1})"
+ ).format(out.description(), row + 2)
+ self.parent.messageBar().pushMessage(
+ "", msg, level=Qgis.MessageLevel.Warning, duration=5
+ )
return {}, False
ok, error = out.isSupportedOutputValue(text, context)
if not ok:
- self.parent.messageBar().pushMessage("", error,
- level=Qgis.MessageLevel.Warning,
- duration=5)
+ self.parent.messageBar().pushMessage(
+ "", error, level=Qgis.MessageLevel.Warning, duration=5
+ )
return {}, False
- if isinstance(out, (QgsProcessingParameterRasterDestination,
- QgsProcessingParameterVectorDestination,
- QgsProcessingParameterFeatureSink)):
+ if isinstance(
+ out,
+ (
+ QgsProcessingParameterRasterDestination,
+ QgsProcessingParameterVectorDestination,
+ QgsProcessingParameterFeatureSink,
+ ),
+ ):
# load rasters and sinks on completion
- parameters[out.name()] = QgsProcessingOutputLayerDefinition(text, destinationProject)
+ parameters[out.name()] = QgsProcessingOutputLayerDefinition(
+ text, destinationProject
+ )
else:
parameters[out.name()] = text
diff --git a/python/plugins/processing/gui/CheckboxesPanel.py b/python/plugins/processing/gui/CheckboxesPanel.py
index a1aa2cb7fcd6..4e1fb0bf020c 100644
--- a/python/plugins/processing/gui/CheckboxesPanel.py
+++ b/python/plugins/processing/gui/CheckboxesPanel.py
@@ -16,9 +16,9 @@
***************************************************************************
"""
-__author__ = 'Arnaud Morvan'
-__date__ = 'January 2015'
-__copyright__ = '(C) 2015, Arnaud Morvan'
+__author__ = "Arnaud Morvan"
+__date__ = "January 2015"
+__copyright__ = "(C) 2015, Arnaud Morvan"
from qgis.PyQt.QtCore import Qt
from qgis.PyQt.QtWidgets import (
@@ -30,7 +30,7 @@
QSpacerItem,
QWidget,
QMenu,
- QAction
+ QAction,
)
from qgis.PyQt.QtGui import QCursor
@@ -63,8 +63,11 @@ def __init__(self, options, multiple, columns=2, parent=None):
self._buttons.append((v, button))
self._buttonGroup.addButton(button, i)
layout.addWidget(button, i % rows, i / rows)
- layout.addItem(QSpacerItem(0, 0, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum),
- 0, columns)
+ layout.addItem(
+ QSpacerItem(0, 0, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum),
+ 0,
+ columns,
+ )
self.setLayout(layout)
if multiple:
@@ -73,34 +76,30 @@ def __init__(self, options, multiple, columns=2, parent=None):
def showPopupMenu(self):
popup_menu = QMenu()
- select_all_action = QAction(self.tr('Select All'), popup_menu)
+ select_all_action = QAction(self.tr("Select All"), popup_menu)
select_all_action.triggered.connect(self.selectAll)
- clear_all_action = QAction(self.tr('Clear Selection'), popup_menu)
+ clear_all_action = QAction(self.tr("Clear Selection"), popup_menu)
clear_all_action.triggered.connect(self.deselectAll)
popup_menu.addAction(select_all_action)
popup_menu.addAction(clear_all_action)
popup_menu.exec(QCursor.pos())
def selectAll(self):
- for (v, button) in self._buttons:
+ for v, button in self._buttons:
button.setChecked(True)
def deselectAll(self):
- for (v, button) in self._buttons:
+ for v, button in self._buttons:
button.setChecked(False)
def value(self):
if self._multiple:
- return [
- v
- for (v, checkbox) in self._buttons
- if checkbox.isChecked()
- ]
+ return [v for (v, checkbox) in self._buttons if checkbox.isChecked()]
else:
return self._options[self._buttonGroup.checkedId()][0]
def setValue(self, value):
- for (v, button) in self._buttons:
+ for v, button in self._buttons:
if self._multiple:
button.setChecked(v in value)
else:
diff --git a/python/plugins/processing/gui/ConfigDialog.py b/python/plugins/processing/gui/ConfigDialog.py
index efc60b27c253..896de8c9b195 100644
--- a/python/plugins/processing/gui/ConfigDialog.py
+++ b/python/plugins/processing/gui/ConfigDialog.py
@@ -15,41 +15,40 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'August 2012'
-__copyright__ = '(C) 2012, Victor Olaya'
+__author__ = "Victor Olaya"
+__date__ = "August 2012"
+__copyright__ = "(C) 2012, Victor Olaya"
import os
import warnings
from qgis.PyQt import uic
from qgis.PyQt.QtCore import Qt, QEvent
-from qgis.PyQt.QtWidgets import (QFileDialog,
- QStyle,
- QMessageBox,
- QStyledItemDelegate,
- QLineEdit,
- QWidget,
- QToolButton,
- QHBoxLayout,
- QComboBox,
- QPushButton,
- QApplication)
-from qgis.PyQt.QtGui import (QIcon,
- QStandardItemModel,
- QStandardItem,
- QCursor)
-
-from qgis.gui import (QgsDoubleSpinBox,
- QgsSpinBox,
- QgsOptionsPageWidget,
- QgsOptionsDialogHighlightWidget)
+from qgis.PyQt.QtWidgets import (
+ QFileDialog,
+ QStyle,
+ QMessageBox,
+ QStyledItemDelegate,
+ QLineEdit,
+ QWidget,
+ QToolButton,
+ QHBoxLayout,
+ QComboBox,
+ QPushButton,
+ QApplication,
+)
+from qgis.PyQt.QtGui import QIcon, QStandardItemModel, QStandardItem, QCursor
+
+from qgis.gui import (
+ QgsDoubleSpinBox,
+ QgsSpinBox,
+ QgsOptionsPageWidget,
+ QgsOptionsDialogHighlightWidget,
+)
from qgis.core import NULL, QgsApplication, QgsSettings
from qgis.utils import OverrideCursor
-from processing.core.ProcessingConfig import (ProcessingConfig,
- settingsWatcher,
- Setting)
+from processing.core.ProcessingConfig import ProcessingConfig, settingsWatcher, Setting
from processing.core.Processing import Processing
from processing.gui.DirectorySelectorDialog import DirectorySelectorDialog
from processing.gui.menus import defaultMenuEntries, menusSettingsGroup
@@ -57,8 +56,7 @@
pluginPath = os.path.split(os.path.dirname(__file__))[0]
with warnings.catch_warnings():
warnings.filterwarnings("ignore", category=DeprecationWarning)
- WIDGET, BASE = uic.loadUiType(
- os.path.join(pluginPath, 'ui', 'DlgConfig.ui'))
+ WIDGET, BASE = uic.loadUiType(os.path.join(pluginPath, "ui", "DlgConfig.ui"))
class ConfigOptionsPage(QgsOptionsPageWidget):
@@ -71,7 +69,7 @@ def __init__(self, parent):
layout.setMargin(0)
self.setLayout(layout)
layout.addWidget(self.config_widget)
- self.setObjectName('processingOptions')
+ self.setObjectName("processingOptions")
self.highlightWidget = ProcessingTreeHighlight(self.config_widget)
self.registerHighlightWidget(self.highlightWidget)
@@ -79,7 +77,7 @@ def apply(self):
self.config_widget.accept()
def helpKey(self):
- return 'processing/index.html'
+ return "processing/index.html"
class ProcessingTreeHighlight(QgsOptionsDialogHighlightWidget):
@@ -95,7 +93,7 @@ def searchText(self, text):
return self.config_dialog.textChanged(text)
def reset(self):
- self.config_dialog.textChanged('')
+ self.config_dialog.textChanged("")
class ConfigDialog(BASE, WIDGET):
@@ -104,7 +102,7 @@ def __init__(self, showSearch=True):
super().__init__(None)
self.setupUi(self)
- self.groupIcon = QgsApplication.getThemeIcon('mIconFolder.svg')
+ self.groupIcon = QgsApplication.getThemeIcon("mIconFolder.svg")
self.model = QStandardItemModel()
self.tree.setModel(self.model)
@@ -113,8 +111,10 @@ def __init__(self, showSearch=True):
self.tree.setItemDelegateForColumn(1, self.delegate)
if showSearch:
- if hasattr(self.searchBox, 'setPlaceholderText'):
- self.searchBox.setPlaceholderText(QApplication.translate('ConfigDialog', 'Search…'))
+ if hasattr(self.searchBox, "setPlaceholderText"):
+ self.searchBox.setPlaceholderText(
+ QApplication.translate("ConfigDialog", "Search…")
+ )
self.searchBox.textChanged.connect(self.textChanged)
else:
self.searchBox.hide()
@@ -130,7 +130,9 @@ def textChanged(self, text=None):
text = str(text.lower())
else:
text = str(self.searchBox.text().lower())
- found = self._filterItem(self.model.invisibleRootItem(), text, False if text else True)
+ found = self._filterItem(
+ self.model.invisibleRootItem(), text, False if text else True
+ )
self.auto_adjust_columns = False
if text:
@@ -148,7 +150,12 @@ def textChanged(self, text=None):
def _filterItem(self, item, text, forceShow=False):
if item.hasChildren():
- show = forceShow or isinstance(item, QStandardItem) and bool(text) and (text in item.text().lower())
+ show = (
+ forceShow
+ or isinstance(item, QStandardItem)
+ and bool(text)
+ and (text in item.text().lower())
+ )
for i in range(item.rowCount()):
child = item.child(i)
show = self._filterItem(child, text, forceShow) or show
@@ -166,8 +173,7 @@ def fillTree(self):
def fillTreeUsingProviders(self):
self.items = {}
self.model.clear()
- self.model.setHorizontalHeaderLabels([self.tr('Setting'),
- self.tr('Value')])
+ self.model.setHorizontalHeaderLabels([self.tr("Setting"), self.tr("Value")])
settings = ProcessingConfig.getSettings()
@@ -176,7 +182,7 @@ def fillTreeUsingProviders(self):
"""
Filter 'General', 'Models' and 'Scripts' items
"""
- priorityKeys = [self.tr('General'), self.tr('Models'), self.tr('Scripts')]
+ priorityKeys = [self.tr("General"), self.tr("Models"), self.tr("Scripts")]
for group in priorityKeys:
groupItem = QStandardItem(group)
icon = ProcessingConfig.getGroupIcon(group)
@@ -203,7 +209,7 @@ def fillTreeUsingProviders(self):
"""
Filter 'Providers' items
"""
- providersItem = QStandardItem(self.tr('Providers'))
+ providersItem = QStandardItem(self.tr("Providers"))
icon = QgsApplication.getThemeIcon("/processingAlgorithm.svg")
providersItem.setIcon(icon)
providersItem.setEditable(False)
@@ -237,8 +243,8 @@ def fillTreeUsingProviders(self):
"""
Filter 'Menus' items
"""
- self.menusItem = QStandardItem(self.tr('Menus'))
- icon = QIcon(os.path.join(pluginPath, 'images', 'menu.png'))
+ self.menusItem = QStandardItem(self.tr("Menus"))
+ icon = QIcon(os.path.join(pluginPath, "images", "menu.png"))
self.menusItem.setIcon(icon)
self.menusItem.setEditable(False)
emptyItem = QStandardItem()
@@ -246,7 +252,7 @@ def fillTreeUsingProviders(self):
rootItem.insertRow(0, [self.menusItem, emptyItem])
- button = QPushButton(self.tr('Reset to defaults'))
+ button = QPushButton(self.tr("Reset to defaults"))
button.clicked.connect(self.resetMenusToDefaults)
layout = QHBoxLayout()
layout.setContentsMargins(0, 0, 0, 0)
@@ -311,13 +317,20 @@ def accept(self):
for setting in list(self.items.keys()):
if setting.group != menusSettingsGroup or self.saveMenus:
if isinstance(setting.value, bool):
- setting.setValue(self.items[setting].checkState() == Qt.CheckState.Checked)
+ setting.setValue(
+ self.items[setting].checkState() == Qt.CheckState.Checked
+ )
else:
try:
setting.setValue(str(self.items[setting].text()))
except ValueError as e:
- QMessageBox.warning(self, self.tr('Wrong value'),
- self.tr('Wrong value for parameter "{0}":\n\n{1}').format(setting.description, str(e)))
+ QMessageBox.warning(
+ self,
+ self.tr("Wrong value"),
+ self.tr('Wrong value for parameter "{0}":\n\n{1}').format(
+ setting.description, str(e)
+ ),
+ )
return
setting.save(qsettings)
@@ -378,7 +391,9 @@ def createEditor(self, parent, options, index):
elif setting.valuetype == Setting.MULTIPLE_FOLDERS:
return MultipleDirectorySelector(parent, setting.placeholder)
else:
- value = self.convertValue(index.model().data(index, Qt.ItemDataRole.EditRole))
+ value = self.convertValue(
+ index.model().data(index, Qt.ItemDataRole.EditRole)
+ )
if isinstance(value, int):
spnBox = QgsSpinBox(parent)
spnBox.setRange(-999999999, 999999999)
@@ -422,7 +437,7 @@ def sizeHint(self, option, index):
return QgsSpinBox().sizeHint()
def eventFilter(self, editor, event):
- if event.type() == QEvent.Type.FocusOut and hasattr(editor, 'canFocusOut'):
+ if event.type() == QEvent.Type.FocusOut and hasattr(editor, "canFocusOut"):
if not editor.canFocusOut:
return False
return QStyledItemDelegate.eventFilter(self, editor, event)
@@ -446,7 +461,7 @@ def __init__(self, parent=None, selectFile=False, placeholder=""):
# create gui
self.btnSelect = QToolButton()
- self.btnSelect.setText('…')
+ self.btnSelect.setText("…")
self.lineEdit = QLineEdit()
self.lineEdit.setPlaceholderText(placeholder)
self.hbl = QHBoxLayout()
@@ -464,15 +479,18 @@ def __init__(self, parent=None, selectFile=False, placeholder=""):
self.btnSelect.clicked.connect(self.select)
def select(self):
- lastDir = ''
+ lastDir = ""
if not self.selectFile:
- selectedPath = QFileDialog.getExistingDirectory(None,
- self.tr('Select directory'), lastDir,
- QFileDialog.Option.ShowDirsOnly)
+ selectedPath = QFileDialog.getExistingDirectory(
+ None,
+ self.tr("Select directory"),
+ lastDir,
+ QFileDialog.Option.ShowDirsOnly,
+ )
else:
- selectedPath, selected_filter = QFileDialog.getOpenFileName(None,
- self.tr('Select file'), lastDir, self.tr('All files (*)')
- )
+ selectedPath, selected_filter = QFileDialog.getOpenFileName(
+ None, self.tr("Select file"), lastDir, self.tr("All files (*)")
+ )
if not selectedPath:
return
@@ -494,7 +512,7 @@ def __init__(self, parent=None, placeholder=""):
# create gui
self.btnSelect = QToolButton()
- self.btnSelect.setText('…')
+ self.btnSelect.setText("…")
self.lineEdit = QLineEdit()
self.lineEdit.setPlaceholderText(placeholder)
self.hbl = QHBoxLayout()
@@ -512,8 +530,8 @@ def __init__(self, parent=None, placeholder=""):
def select(self):
text = self.lineEdit.text()
- if text != '':
- items = text.split(';')
+ if text != "":
+ items = text.split(";")
else:
items = []
diff --git a/python/plugins/processing/gui/ContextAction.py b/python/plugins/processing/gui/ContextAction.py
index 981823495782..8453c6670f22 100644
--- a/python/plugins/processing/gui/ContextAction.py
+++ b/python/plugins/processing/gui/ContextAction.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'August 2012'
-__copyright__ = '(C) 2012, Victor Olaya'
+__author__ = "Victor Olaya"
+__date__ = "August 2012"
+__copyright__ = "(C) 2012, Victor Olaya"
from qgis.PyQt.QtCore import QCoreApplication
from qgis.PyQt.QtGui import QIcon
@@ -33,8 +33,8 @@ def setData(self, itemData, toolbox):
self.itemData = itemData
self.toolbox = toolbox
- def tr(self, string, context=''):
- if context == '':
+ def tr(self, string, context=""):
+ if context == "":
context = self.__class__.__name__
return QCoreApplication.translate(context, string)
diff --git a/python/plugins/processing/gui/DirectorySelectorDialog.py b/python/plugins/processing/gui/DirectorySelectorDialog.py
index b508727eaf6e..dd047749bdb7 100644
--- a/python/plugins/processing/gui/DirectorySelectorDialog.py
+++ b/python/plugins/processing/gui/DirectorySelectorDialog.py
@@ -15,23 +15,30 @@
***************************************************************************
"""
-__author__ = 'Alexander Bruy'
-__date__ = 'May 2016'
-__copyright__ = '(C) 2016, Victor Olaya'
+__author__ = "Alexander Bruy"
+__date__ = "May 2016"
+__copyright__ = "(C) 2016, Victor Olaya"
import os
import warnings
from qgis.PyQt import uic
from qgis.core import QgsSettings
-from qgis.PyQt.QtWidgets import QDialog, QAbstractItemView, QPushButton, QDialogButtonBox, QFileDialog
+from qgis.PyQt.QtWidgets import (
+ QDialog,
+ QAbstractItemView,
+ QPushButton,
+ QDialogButtonBox,
+ QFileDialog,
+)
from qgis.PyQt.QtGui import QStandardItemModel, QStandardItem
pluginPath = os.path.split(os.path.dirname(__file__))[0]
with warnings.catch_warnings():
warnings.filterwarnings("ignore", category=DeprecationWarning)
WIDGET, BASE = uic.loadUiType(
- os.path.join(pluginPath, 'ui', 'DlgMultipleSelection.ui'))
+ os.path.join(pluginPath, "ui", "DlgMultipleSelection.ui")
+ )
class DirectorySelectorDialog(BASE, WIDGET):
@@ -40,20 +47,21 @@ def __init__(self, parent, options):
super().__init__(None)
self.setupUi(self)
- self.lstLayers.setSelectionMode(QAbstractItemView.SelectionMode.ExtendedSelection)
+ self.lstLayers.setSelectionMode(
+ QAbstractItemView.SelectionMode.ExtendedSelection
+ )
self.options = options
# Additional buttons
- self.btnAdd = QPushButton(self.tr('Add'))
- self.buttonBox.addButton(self.btnAdd,
- QDialogButtonBox.ButtonRole.ActionRole)
- self.btnRemove = QPushButton(self.tr('Remove'))
- self.buttonBox.addButton(self.btnRemove,
- QDialogButtonBox.ButtonRole.ActionRole)
- self.btnRemoveAll = QPushButton(self.tr('Remove all'))
- self.buttonBox.addButton(self.btnRemoveAll,
- QDialogButtonBox.ButtonRole.ActionRole)
+ self.btnAdd = QPushButton(self.tr("Add"))
+ self.buttonBox.addButton(self.btnAdd, QDialogButtonBox.ButtonRole.ActionRole)
+ self.btnRemove = QPushButton(self.tr("Remove"))
+ self.buttonBox.addButton(self.btnRemove, QDialogButtonBox.ButtonRole.ActionRole)
+ self.btnRemoveAll = QPushButton(self.tr("Remove all"))
+ self.buttonBox.addButton(
+ self.btnRemoveAll, QDialogButtonBox.ButtonRole.ActionRole
+ )
self.btnAdd.clicked.connect(self.addDirectory)
self.btnRemove.clicked.connect(lambda: self.removeRows())
@@ -82,25 +90,23 @@ def reject(self):
def addDirectory(self):
settings = QgsSettings()
- if settings.contains('/Processing/lastDirectory'):
- path = settings.value('/Processing/lastDirectory')
+ if settings.contains("/Processing/lastDirectory"):
+ path = settings.value("/Processing/lastDirectory")
else:
- path = ''
+ path = ""
- folder = QFileDialog.getExistingDirectory(self,
- self.tr('Select directory'),
- path,
- QFileDialog.Option.ShowDirsOnly)
+ folder = QFileDialog.getExistingDirectory(
+ self, self.tr("Select directory"), path, QFileDialog.Option.ShowDirsOnly
+ )
- if folder == '':
+ if folder == "":
return
model = self.lstLayers.model()
item = QStandardItem(folder)
model.appendRow(item)
- settings.setValue('/Processing/lastDirectory',
- os.path.dirname(folder))
+ settings.setValue("/Processing/lastDirectory", os.path.dirname(folder))
def removeRows(self, removeAll=False):
if removeAll:
@@ -118,4 +124,4 @@ def value(self):
for i in range(model.rowCount()):
folders.append(model.item(i).text())
- return ';'.join(folders)
+ return ";".join(folders)
diff --git a/python/plugins/processing/gui/EditRenderingStylesDialog.py b/python/plugins/processing/gui/EditRenderingStylesDialog.py
index a887d8452788..2662cd3eb2ec 100644
--- a/python/plugins/processing/gui/EditRenderingStylesDialog.py
+++ b/python/plugins/processing/gui/EditRenderingStylesDialog.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'August 2012'
-__copyright__ = '(C) 2012, Victor Olaya'
+__author__ = "Victor Olaya"
+__date__ = "August 2012"
+__copyright__ = "(C) 2012, Victor Olaya"
import os
import warnings
@@ -26,8 +26,7 @@
from qgis.PyQt.QtCore import Qt
from qgis.PyQt.QtWidgets import QDialog, QHeaderView, QTableWidgetItem
-from qgis.core import (QgsProcessingOutputRasterLayer,
- QgsProcessingOutputVectorLayer)
+from qgis.core import QgsProcessingOutputRasterLayer, QgsProcessingOutputVectorLayer
from processing.gui.RenderingStyles import RenderingStyles
from processing.gui.RenderingStyleFilePanel import RenderingStyleFilePanel
@@ -37,7 +36,8 @@
with warnings.catch_warnings():
warnings.filterwarnings("ignore", category=DeprecationWarning)
WIDGET, BASE = uic.loadUiType(
- os.path.join(pluginPath, 'ui', 'DlgRenderingStyles.ui'))
+ os.path.join(pluginPath, "ui", "DlgRenderingStyles.ui")
+ )
class EditRenderingStylesDialog(BASE, WIDGET):
@@ -48,7 +48,9 @@ def __init__(self, alg):
self.alg = alg
- self.tblStyles.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeMode.Stretch)
+ self.tblStyles.horizontalHeader().setSectionResizeMode(
+ QHeaderView.ResizeMode.Stretch
+ )
self.setWindowTitle(self.alg.displayName())
self.valueItems = {}
@@ -58,21 +60,24 @@ def __init__(self, alg):
def setTableContent(self):
numOutputs = 0
for output in self.alg.outputDefinitions():
- if isinstance(output, (QgsProcessingOutputVectorLayer, QgsProcessingOutputRasterLayer)):
+ if isinstance(
+ output, (QgsProcessingOutputVectorLayer, QgsProcessingOutputRasterLayer)
+ ):
numOutputs += 1
self.tblStyles.setRowCount(numOutputs)
i = 0
for output in self.alg.outputDefinitions():
- if isinstance(output, (QgsProcessingOutputVectorLayer, QgsProcessingOutputRasterLayer)):
- item = QTableWidgetItem(output.description() + '<' +
- output.__class__.__name__ + '>')
+ if isinstance(
+ output, (QgsProcessingOutputVectorLayer, QgsProcessingOutputRasterLayer)
+ ):
+ item = QTableWidgetItem(
+ output.description() + "<" + output.__class__.__name__ + ">"
+ )
item.setFlags(Qt.ItemFlag.ItemIsEnabled)
self.tblStyles.setItem(i, 0, item)
item = RenderingStyleFilePanel()
- style = \
- RenderingStyles.getStyle(self.alg.id(),
- output.name())
+ style = RenderingStyles.getStyle(self.alg.id(), output.name())
if style:
item.setText(str(style))
self.valueItems[output.name()] = item
diff --git a/python/plugins/processing/gui/ExtentSelectionPanel.py b/python/plugins/processing/gui/ExtentSelectionPanel.py
index f7d67730e07a..0e911e9d3dcd 100644
--- a/python/plugins/processing/gui/ExtentSelectionPanel.py
+++ b/python/plugins/processing/gui/ExtentSelectionPanel.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'August 2012'
-__copyright__ = '(C) 2012, Victor Olaya'
+__author__ = "Victor Olaya"
+__date__ = "August 2012"
+__copyright__ = "(C) 2012, Victor Olaya"
import os
import warnings
@@ -29,19 +29,21 @@
QDialog,
QVBoxLayout,
QDialogButtonBox,
- QLabel
+ QLabel,
)
from qgis.PyQt.QtGui import QCursor
from qgis.PyQt.QtCore import QCoreApplication, pyqtSignal
from qgis.gui import QgsMapLayerComboBox
from qgis.utils import iface
-from qgis.core import (Qgis,
- QgsProcessingParameterDefinition,
- QgsProcessingParameters,
- QgsProject,
- QgsReferencedRectangle,
- QgsMapLayerProxyModel)
+from qgis.core import (
+ Qgis,
+ QgsProcessingParameterDefinition,
+ QgsProcessingParameters,
+ QgsProject,
+ QgsReferencedRectangle,
+ QgsMapLayerProxyModel,
+)
from processing.gui.RectangleMapTool import RectangleMapTool
from processing.core.ProcessingConfig import ProcessingConfig
from processing.tools.dataobjects import createContext
@@ -51,25 +53,33 @@
with warnings.catch_warnings():
warnings.filterwarnings("ignore", category=DeprecationWarning)
WIDGET, BASE = uic.loadUiType(
- os.path.join(pluginPath, 'ui', 'widgetBaseSelector.ui'))
+ os.path.join(pluginPath, "ui", "widgetBaseSelector.ui")
+ )
class LayerSelectionDialog(QDialog):
def __init__(self, parent=None):
super().__init__(parent)
- self.setWindowTitle(self.tr('Select Extent'))
+ self.setWindowTitle(self.tr("Select Extent"))
vl = QVBoxLayout()
- vl.addWidget(QLabel(self.tr('Use extent from')))
+ vl.addWidget(QLabel(self.tr("Use extent from")))
self.combo = QgsMapLayerComboBox()
self.combo.setFilters(
- Qgis.LayerFilter.HasGeometry | Qgis.LayerFilter.RasterLayer | Qgis.LayerFilter.MeshLayer)
- self.combo.setShowCrs(ProcessingConfig.getSetting(ProcessingConfig.SHOW_CRS_DEF))
+ Qgis.LayerFilter.HasGeometry
+ | Qgis.LayerFilter.RasterLayer
+ | Qgis.LayerFilter.MeshLayer
+ )
+ self.combo.setShowCrs(
+ ProcessingConfig.getSetting(ProcessingConfig.SHOW_CRS_DEF)
+ )
vl.addWidget(self.combo)
self.button_box = QDialogButtonBox()
- self.button_box.setStandardButtons(QDialogButtonBox.StandardButton.Cancel | QDialogButtonBox.StandardButton.Ok)
+ self.button_box.setStandardButtons(
+ QDialogButtonBox.StandardButton.Cancel | QDialogButtonBox.StandardButton.Ok
+ )
self.button_box.accepted.connect(self.accept)
self.button_box.rejected.connect(self.reject)
@@ -94,9 +104,10 @@ def __init__(self, dialog, param):
self.crs = QgsProject.instance().crs()
if self.param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional:
- if hasattr(self.leText, 'setPlaceholderText'):
+ if hasattr(self.leText, "setPlaceholderText"):
self.leText.setPlaceholderText(
- self.tr('[Leave blank to use min covering extent]'))
+ self.tr("[Leave blank to use min covering extent]")
+ )
self.btnSelect.clicked.connect(self.selectExtent)
@@ -111,14 +122,22 @@ def __init__(self, dialog, param):
if param.defaultValue() is not None:
context = createContext()
- rect = QgsProcessingParameters.parameterAsExtent(param, {param.name(): param.defaultValue()}, context)
- crs = QgsProcessingParameters.parameterAsExtentCrs(param, {param.name(): param.defaultValue()}, context)
+ rect = QgsProcessingParameters.parameterAsExtent(
+ param, {param.name(): param.defaultValue()}, context
+ )
+ crs = QgsProcessingParameters.parameterAsExtentCrs(
+ param, {param.name(): param.defaultValue()}, context
+ )
if not rect.isNull():
try:
- s = '{},{},{},{}'.format(
- rect.xMinimum(), rect.xMaximum(), rect.yMinimum(), rect.yMaximum())
+ s = "{},{},{},{}".format(
+ rect.xMinimum(),
+ rect.xMaximum(),
+ rect.yMinimum(),
+ rect.yMaximum(),
+ )
if crs.isValid():
- s += ' [' + crs.authid() + ']'
+ s += " [" + crs.authid() + "]"
self.crs = crs
self.leText.setText(s)
except:
@@ -127,13 +146,16 @@ def __init__(self, dialog, param):
def selectExtent(self):
popupmenu = QMenu()
useCanvasExtentAction = QAction(
- QCoreApplication.translate("ExtentSelectionPanel", 'Use Canvas Extent'),
- self.btnSelect)
+ QCoreApplication.translate("ExtentSelectionPanel", "Use Canvas Extent"),
+ self.btnSelect,
+ )
useLayerExtentAction = QAction(
- QCoreApplication.translate("ExtentSelectionPanel", 'Use Layer Extent…'),
- self.btnSelect)
+ QCoreApplication.translate("ExtentSelectionPanel", "Use Layer Extent…"),
+ self.btnSelect,
+ )
selectOnCanvasAction = QAction(
- self.tr('Select Extent on Canvas'), self.btnSelect)
+ self.tr("Select Extent on Canvas"), self.btnSelect
+ )
popupmenu.addAction(useCanvasExtentAction)
popupmenu.addAction(selectOnCanvasAction)
@@ -146,16 +168,15 @@ def selectExtent(self):
if self.param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional:
useMincoveringExtentAction = QAction(
- self.tr('Use Min Covering Extent from Input Layers'),
- self.btnSelect)
- useMincoveringExtentAction.triggered.connect(
- self.useMinCoveringExtent)
+ self.tr("Use Min Covering Extent from Input Layers"), self.btnSelect
+ )
+ useMincoveringExtentAction.triggered.connect(self.useMinCoveringExtent)
popupmenu.addAction(useMincoveringExtentAction)
popupmenu.exec(QCursor.pos())
def useMinCoveringExtent(self):
- self.leText.setText('')
+ self.leText.setText("")
def useLayerExtent(self):
dlg = LayerSelectionDialog(self)
@@ -164,8 +185,12 @@ def useLayerExtent(self):
self.setValueFromRect(QgsReferencedRectangle(layer.extent(), layer.crs()))
def useCanvasExtent(self):
- self.setValueFromRect(QgsReferencedRectangle(iface.mapCanvas().extent(),
- iface.mapCanvas().mapSettings().destinationCrs()))
+ self.setValueFromRect(
+ QgsReferencedRectangle(
+ iface.mapCanvas().extent(),
+ iface.mapCanvas().mapSettings().destinationCrs(),
+ )
+ )
def selectOnCanvas(self):
canvas = iface.mapCanvas()
@@ -177,15 +202,14 @@ def updateExtent(self):
self.setValueFromRect(r)
def setValueFromRect(self, r):
- s = '{},{},{},{}'.format(
- r.xMinimum(), r.xMaximum(), r.yMinimum(), r.yMaximum())
+ s = f"{r.xMinimum()},{r.xMaximum()},{r.yMinimum()},{r.yMaximum()}"
try:
self.crs = r.crs()
except:
self.crs = QgsProject.instance().crs()
if self.crs.isValid():
- s += ' [' + self.crs.authid() + ']'
+ s += " [" + self.crs.authid() + "]"
self.leText.setText(s)
self.tool.reset()
@@ -196,7 +220,7 @@ def setValueFromRect(self, r):
self.dialog.activateWindow()
def getValue(self):
- if str(self.leText.text()).strip() != '':
+ if str(self.leText.text()).strip() != "":
return str(self.leText.text())
else:
return None
diff --git a/python/plugins/processing/gui/FileSelectionPanel.py b/python/plugins/processing/gui/FileSelectionPanel.py
index 7479b8bca48e..104297d32dfb 100644
--- a/python/plugins/processing/gui/FileSelectionPanel.py
+++ b/python/plugins/processing/gui/FileSelectionPanel.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'August 2012'
-__copyright__ = '(C) 2012, Victor Olaya'
+__author__ = "Victor Olaya"
+__date__ = "August 2012"
+__copyright__ = "(C) 2012, Victor Olaya"
import os
import warnings
@@ -33,7 +33,8 @@
with warnings.catch_warnings():
warnings.filterwarnings("ignore", category=DeprecationWarning)
WIDGET, BASE = uic.loadUiType(
- os.path.join(pluginPath, 'ui', 'widgetBaseSelector.ui'))
+ os.path.join(pluginPath, "ui", "widgetBaseSelector.ui")
+ )
class FileSelectionPanel(BASE, WIDGET):
@@ -42,7 +43,7 @@ def __init__(self, isFolder, ext=None):
super().__init__(None)
self.setupUi(self)
- self.ext = ext or '*'
+ self.ext = ext or "*"
self.isFolder = isFolder
self.btnSelect.clicked.connect(self.showSelectionDialog)
@@ -55,30 +56,38 @@ def showSelectionDialog(self):
path = text
elif os.path.isdir(os.path.dirname(text)):
path = os.path.dirname(text)
- elif settings.contains('/Processing/LastInputPath'):
- path = settings.value('/Processing/LastInputPath')
+ elif settings.contains("/Processing/LastInputPath"):
+ path = settings.value("/Processing/LastInputPath")
else:
- path = ''
+ path = ""
if self.isFolder:
- folder = QFileDialog.getExistingDirectory(self,
- self.tr('Select Folder'), path)
+ folder = QFileDialog.getExistingDirectory(
+ self, self.tr("Select Folder"), path
+ )
if folder:
self.leText.setText(folder)
- settings.setValue('/Processing/LastInputPath',
- os.path.dirname(folder))
+ settings.setValue("/Processing/LastInputPath", os.path.dirname(folder))
else:
- filenames, selected_filter = QFileDialog.getOpenFileNames(self,
- self.tr('Select File'), path, self.tr('{} files').format(self.ext.upper()) + ' (*.' + self.ext + self.tr(');;All files (*.*)'))
+ filenames, selected_filter = QFileDialog.getOpenFileNames(
+ self,
+ self.tr("Select File"),
+ path,
+ self.tr("{} files").format(self.ext.upper())
+ + " (*."
+ + self.ext
+ + self.tr(");;All files (*.*)"),
+ )
if filenames:
- self.leText.setText(';'.join(filenames))
- settings.setValue('/Processing/LastInputPath',
- os.path.dirname(filenames[0]))
+ self.leText.setText(";".join(filenames))
+ settings.setValue(
+ "/Processing/LastInputPath", os.path.dirname(filenames[0])
+ )
def getValue(self):
s = self.leText.text()
if isWindows():
- s = s.replace('\\', '/')
+ s = s.replace("\\", "/")
return s
def setText(self, text):
diff --git a/python/plugins/processing/gui/FixedTableDialog.py b/python/plugins/processing/gui/FixedTableDialog.py
index 79c996304106..9d76f7e3160c 100644
--- a/python/plugins/processing/gui/FixedTableDialog.py
+++ b/python/plugins/processing/gui/FixedTableDialog.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'August 2012'
-__copyright__ = '(C) 2012, Victor Olaya'
+__author__ = "Victor Olaya"
+__date__ = "August 2012"
+__copyright__ = "(C) 2012, Victor Olaya"
import os
import warnings
@@ -25,15 +25,19 @@
from qgis.gui import QgsGui
from qgis.PyQt import uic
-from qgis.PyQt.QtWidgets import QDialog, QPushButton, QAbstractItemView, QDialogButtonBox
+from qgis.PyQt.QtWidgets import (
+ QDialog,
+ QPushButton,
+ QAbstractItemView,
+ QDialogButtonBox,
+)
from qgis.PyQt.QtGui import QStandardItemModel, QStandardItem
pluginPath = os.path.split(os.path.dirname(__file__))[0]
with warnings.catch_warnings():
warnings.filterwarnings("ignore", category=DeprecationWarning)
- WIDGET, BASE = uic.loadUiType(
- os.path.join(pluginPath, 'ui', 'DlgFixedTable.ui'))
+ WIDGET, BASE = uic.loadUiType(os.path.join(pluginPath, "ui", "DlgFixedTable.ui"))
class FixedTableDialog(BASE, WIDGET):
@@ -50,22 +54,23 @@ def __init__(self, param, table):
QgsGui.instance().enableAutoGeometryRestore(self)
- self.tblView.setSelectionBehavior(QAbstractItemView.SelectionBehavior.SelectRows)
+ self.tblView.setSelectionBehavior(
+ QAbstractItemView.SelectionBehavior.SelectRows
+ )
self.tblView.setSelectionMode(QAbstractItemView.SelectionMode.ExtendedSelection)
self.param = param
self.rettable = None
# Additional buttons
- self.btnAdd = QPushButton(self.tr('Add row'))
- self.buttonBox.addButton(self.btnAdd,
- QDialogButtonBox.ButtonRole.ActionRole)
- self.btnRemove = QPushButton(self.tr('Remove row(s)'))
- self.buttonBox.addButton(self.btnRemove,
- QDialogButtonBox.ButtonRole.ActionRole)
- self.btnRemoveAll = QPushButton(self.tr('Remove all'))
- self.buttonBox.addButton(self.btnRemoveAll,
- QDialogButtonBox.ButtonRole.ActionRole)
+ self.btnAdd = QPushButton(self.tr("Add row"))
+ self.buttonBox.addButton(self.btnAdd, QDialogButtonBox.ButtonRole.ActionRole)
+ self.btnRemove = QPushButton(self.tr("Remove row(s)"))
+ self.buttonBox.addButton(self.btnRemove, QDialogButtonBox.ButtonRole.ActionRole)
+ self.btnRemoveAll = QPushButton(self.tr("Remove all"))
+ self.buttonBox.addButton(
+ self.btnRemoveAll, QDialogButtonBox.ButtonRole.ActionRole
+ )
self.btnAdd.clicked.connect(self.addRow)
self.btnRemove.clicked.connect(lambda: self.removeRows())
@@ -118,5 +123,5 @@ def removeRows(self, removeAll=False):
self.tblView.setUpdatesEnabled(True)
def addRow(self):
- items = [QStandardItem('0') for i in range(self.tblView.model().columnCount())]
+ items = [QStandardItem("0") for i in range(self.tblView.model().columnCount())]
self.tblView.model().appendRow(items)
diff --git a/python/plugins/processing/gui/FixedTablePanel.py b/python/plugins/processing/gui/FixedTablePanel.py
index d12c7637579b..70758ce13383 100644
--- a/python/plugins/processing/gui/FixedTablePanel.py
+++ b/python/plugins/processing/gui/FixedTablePanel.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'August 2012'
-__copyright__ = '(C) 2012, Victor Olaya'
+__author__ = "Victor Olaya"
+__date__ = "August 2012"
+__copyright__ = "(C) 2012, Victor Olaya"
import os
import warnings
@@ -31,7 +31,8 @@
with warnings.catch_warnings():
warnings.filterwarnings("ignore", category=DeprecationWarning)
WIDGET, BASE = uic.loadUiType(
- os.path.join(pluginPath, 'ui', 'widgetBaseSelector.ui'))
+ os.path.join(pluginPath, "ui", "widgetBaseSelector.ui")
+ )
class FixedTablePanel(BASE, WIDGET):
@@ -48,16 +49,22 @@ def __init__(self, param, parent=None):
self.table = []
for row in range(param.numberRows()):
for col in range(len(param.headers())):
- self.table.append('0')
+ self.table.append("0")
self.leText.setText(
- self.tr('Fixed table {0}x{1}').format(param.numberRows(), len(param.headers())))
+ self.tr("Fixed table {0}x{1}").format(
+ param.numberRows(), len(param.headers())
+ )
+ )
self.btnSelect.clicked.connect(self.showFixedTableDialog)
def updateSummaryText(self):
- self.leText.setText(self.tr('Fixed table {0}x{1}').format(
- len(self.table) // len(self.param.headers()), len(self.param.headers())))
+ self.leText.setText(
+ self.tr("Fixed table {0}x{1}").format(
+ len(self.table) // len(self.param.headers()), len(self.param.headers())
+ )
+ )
def setValue(self, value):
self.table = value
diff --git a/python/plugins/processing/gui/Help2Html.py b/python/plugins/processing/gui/Help2Html.py
index c5dcef956242..a8cdeba4d833 100644
--- a/python/plugins/processing/gui/Help2Html.py
+++ b/python/plugins/processing/gui/Help2Html.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'August 2012'
-__copyright__ = '(C) 2012, Victor Olaya'
+__author__ = "Victor Olaya"
+__date__ = "August 2012"
+__copyright__ = "(C) 2012, Victor Olaya"
import os
import re
@@ -27,17 +27,19 @@
from processing.tools import system
-ALG_DESC = 'ALG_DESC'
-ALG_CREATOR = 'ALG_CREATOR'
-ALG_HELP_CREATOR = 'ALG_HELP_CREATOR'
-ALG_VERSION = 'ALG_VERSION'
+ALG_DESC = "ALG_DESC"
+ALG_CREATOR = "ALG_CREATOR"
+ALG_HELP_CREATOR = "ALG_HELP_CREATOR"
+ALG_VERSION = "ALG_VERSION"
-exps = [(r"\*(.*?)\*", r"\1 "),
- ("``(.*?)``", r'\1 '),
- ("(.*?)\n==+\n+?", r'\1 '),
- ("(.*?)\n--+\n+?", r'\1 '),
- (r"::(\s*\n(\s*\n)*((\s+).*?\n)(((\4).*?\n)|(\s*\n))*)", r"\1 "),
- ("\n+", "")]
+exps = [
+ (r"\*(.*?)\*", r"\1 "),
+ ("``(.*?)``", r'\1 '),
+ ("(.*?)\n==+\n+?", r"
\1 "),
+ ("(.*?)\n--+\n+?", r"\1 "),
+ (r"::(\s*\n(\s*\n)*((\s+).*?\n)(((\4).*?\n)|(\s*\n))*)", r"\1 "),
+ ("\n+", ""),
+]
def getHtmlFromRstFile(rst):
@@ -60,9 +62,9 @@ def getHtmlFromHelpFile(alg, helpFile):
descriptions = json.load(f)
content = getHtmlFromDescriptionsDict(alg, descriptions)
- algGroup, algName = alg.id().split(':')
+ algGroup, algName = alg.id().split(":")
filePath = os.path.join(system.tempHelpFolder(), f"{algGroup}_{algName}.html")
- with open(filePath, 'w', encoding='utf-8') as f:
+ with open(filePath, "w", encoding="utf-8") as f:
f.write(content)
return QUrl.fromLocalFile(filePath).toString()
except:
@@ -70,21 +72,27 @@ def getHtmlFromHelpFile(alg, helpFile):
def getHtmlFromDescriptionsDict(alg, descriptions):
- s = tr('
Algorithm description \n')
- s += '' + getDescription(ALG_DESC, descriptions) + '
\n'
- s += tr('Input parameters \n')
+ s = tr("Algorithm description \n")
+ s += "" + getDescription(ALG_DESC, descriptions) + "
\n"
+ s += tr("Input parameters \n")
for param in alg.parameterDefinitions():
- s += '' + param.description() + ' \n'
- s += '' + getDescription(param.name(), descriptions) + '
\n'
- s += tr('Outputs \n')
+ s += "" + param.description() + " \n"
+ s += "" + getDescription(param.name(), descriptions) + "
\n"
+ s += tr("Outputs \n")
for out in alg.outputs:
- s += '' + out.description() + ' \n'
- s += '' + getDescription(out.name(), descriptions) + '
\n'
- s += ' '
- s += tr('Algorithm author: {0}
').format(getDescription(ALG_CREATOR, descriptions))
- s += tr('Help author: {0}
').format(getDescription(ALG_HELP_CREATOR, descriptions))
- s += tr('Algorithm version: {0}
').format(getDescription(ALG_VERSION, descriptions))
- s += ''
+ s += "" + out.description() + " \n"
+ s += "" + getDescription(out.name(), descriptions) + "
\n"
+ s += " "
+ s += tr('Algorithm author: {0}
').format(
+ getDescription(ALG_CREATOR, descriptions)
+ )
+ s += tr('Help author: {0}
').format(
+ getDescription(ALG_HELP_CREATOR, descriptions)
+ )
+ s += tr('Algorithm version: {0}
').format(
+ getDescription(ALG_VERSION, descriptions)
+ )
+ s += ""
return s
@@ -92,8 +100,8 @@ def getDescription(name, descriptions):
if name in descriptions:
return str(descriptions[name]).replace("\n", " ")
else:
- return ''
+ return ""
def tr(string):
- return QCoreApplication.translate('Help2Html', string)
+ return QCoreApplication.translate("Help2Html", string)
diff --git a/python/plugins/processing/gui/ListMultiselectWidget.py b/python/plugins/processing/gui/ListMultiselectWidget.py
index f675ebe99680..22c13c3b51e5 100644
--- a/python/plugins/processing/gui/ListMultiselectWidget.py
+++ b/python/plugins/processing/gui/ListMultiselectWidget.py
@@ -15,18 +15,20 @@
***************************************************************************
"""
-__author__ = 'Marco Bernasocchi'
-__date__ = 'June 2016'
-__copyright__ = '(C) 2016, Marco Bernasocchi'
-
-from qgis.PyQt.QtWidgets import (QGroupBox,
- QPushButton,
- QSizePolicy,
- QLabel,
- QHBoxLayout,
- QVBoxLayout,
- QListWidget,
- QAbstractItemView)
+__author__ = "Marco Bernasocchi"
+__date__ = "June 2016"
+__copyright__ = "(C) 2016, Marco Bernasocchi"
+
+from qgis.PyQt.QtWidgets import (
+ QGroupBox,
+ QPushButton,
+ QSizePolicy,
+ QLabel,
+ QHBoxLayout,
+ QVBoxLayout,
+ QListWidget,
+ QAbstractItemView,
+)
from qgis.PyQt.QtGui import QFont
from qgis.PyQt.QtCore import Qt, QSize, pyqtSignal
@@ -152,8 +154,7 @@ def _do_move(self, fromList, toList):
self.selection_changed.emit()
def _setupUI(self):
- self.setSizePolicy(
- QSizePolicy.Policy.Preferred, QSizePolicy.Policy.Preferred)
+ self.setSizePolicy(QSizePolicy.Policy.Preferred, QSizePolicy.Policy.Preferred)
self.setMinimumHeight(180)
@@ -166,7 +167,7 @@ def _setupUI(self):
self.deselected_widget = QListWidget(self)
self._set_list_widget_defaults(self.deselected_widget)
deselected_label = QLabel()
- deselected_label.setText('Deselected')
+ deselected_label.setText("Deselected")
deselected_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
deselected_label.setFont(italic_font)
deselected_v_layout = QVBoxLayout()
@@ -177,7 +178,7 @@ def _setupUI(self):
self.selected_widget = QListWidget(self)
self._set_list_widget_defaults(self.selected_widget)
selected_label = QLabel()
- selected_label.setText('Selected')
+ selected_label.setText("Selected")
selected_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
selected_label.setFont(italic_font)
selected_v_layout = QVBoxLayout()
@@ -188,14 +189,14 @@ def _setupUI(self):
self.buttons_vertical_layout = QVBoxLayout()
self.buttons_vertical_layout.setContentsMargins(0, -1, 0, -1)
- self.select_all_btn = SmallQPushButton('>>')
- self.deselect_all_btn = SmallQPushButton('<<')
- self.select_btn = SmallQPushButton('>')
- self.deselect_btn = SmallQPushButton('<')
- self.select_btn.setToolTip('Add the selected items')
- self.deselect_btn.setToolTip('Remove the selected items')
- self.select_all_btn.setToolTip('Add all')
- self.deselect_all_btn.setToolTip('Remove all')
+ self.select_all_btn = SmallQPushButton(">>")
+ self.deselect_all_btn = SmallQPushButton("<<")
+ self.select_btn = SmallQPushButton(">")
+ self.deselect_btn = SmallQPushButton("<")
+ self.select_btn.setToolTip("Add the selected items")
+ self.deselect_btn.setToolTip("Remove the selected items")
+ self.select_all_btn.setToolTip("Add all")
+ self.deselect_all_btn.setToolTip("Remove all")
# add buttons
spacer_label = QLabel() # pragmatic way to create a spacer with
@@ -229,6 +230,7 @@ def __init__(self, text):
QPushButton.__init__(self)
self.setText(text)
buttons_size_policy = QSizePolicy(
- QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Fixed)
+ QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Fixed
+ )
self.setSizePolicy(buttons_size_policy)
self.setMaximumSize(QSize(30, 30))
diff --git a/python/plugins/processing/gui/MessageBarProgress.py b/python/plugins/processing/gui/MessageBarProgress.py
index aa464b31368b..552cb5ca0e35 100644
--- a/python/plugins/processing/gui/MessageBarProgress.py
+++ b/python/plugins/processing/gui/MessageBarProgress.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'April 2013'
-__copyright__ = '(C) 2013, Victor Olaya'
+__author__ = "Victor Olaya"
+__date__ = "April 2013"
+__copyright__ = "(C) 2013, Victor Olaya"
from qgis.PyQt.QtCore import Qt, QCoreApplication
from qgis.PyQt.QtWidgets import QProgressBar
@@ -32,15 +32,19 @@ def __init__(self, algname=None):
QgsProcessingFeedback.__init__(self)
self.msg = []
- self.progressMessageBar = \
- iface.messageBar().createMessage(self.tr('Executing algorithm {} '.format(algname if algname else '')))
+ self.progressMessageBar = iface.messageBar().createMessage(
+ self.tr("Executing algorithm {} ".format(algname if algname else ""))
+ )
self.progress = QProgressBar()
self.progressChanged.connect(self.set_progress_bar_value)
self.progress.setMaximum(100)
- self.progress.setAlignment(Qt.AlignmentFlag.AlignLeft | Qt.AlignmentFlag.AlignVCenter)
+ self.progress.setAlignment(
+ Qt.AlignmentFlag.AlignLeft | Qt.AlignmentFlag.AlignVCenter
+ )
self.progressMessageBar.layout().addWidget(self.progress)
- self.message_bar_item = iface.messageBar().pushWidget(self.progressMessageBar,
- Qgis.MessageLevel.Info)
+ self.message_bar_item = iface.messageBar().pushWidget(
+ self.progressMessageBar, Qgis.MessageLevel.Info
+ )
def set_progress_bar_value(self, progress: float):
"""
@@ -55,12 +59,16 @@ def reportError(self, msg, fatalError=False):
def close(self):
if self.msg:
dlg = MessageDialog()
- dlg.setTitle(QCoreApplication.translate('MessageBarProgress', 'Problem executing algorithm'))
+ dlg.setTitle(
+ QCoreApplication.translate(
+ "MessageBarProgress", "Problem executing algorithm"
+ )
+ )
dlg.setMessage(" ".join(self.msg))
dlg.exec()
iface.messageBar().popWidget(self.message_bar_item)
- def tr(self, string, context=''):
- if context == '':
- context = 'MessageBarProgress'
+ def tr(self, string, context=""):
+ if context == "":
+ context = "MessageBarProgress"
return QCoreApplication.translate(context, string)
diff --git a/python/plugins/processing/gui/MessageDialog.py b/python/plugins/processing/gui/MessageDialog.py
index 5c99b4c75c05..e9d6fe86c437 100644
--- a/python/plugins/processing/gui/MessageDialog.py
+++ b/python/plugins/processing/gui/MessageDialog.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Alexander Bruy'
-__date__ = 'October 2014'
-__copyright__ = '(C) 2014, Alexander Bruy'
+__author__ = "Alexander Bruy"
+__date__ = "October 2014"
+__copyright__ = "(C) 2014, Alexander Bruy"
import os
import warnings
@@ -31,8 +31,7 @@
pluginPath = os.path.split(os.path.dirname(__file__))[0]
with warnings.catch_warnings():
warnings.filterwarnings("ignore", category=DeprecationWarning)
- WIDGET, BASE = uic.loadUiType(
- os.path.join(pluginPath, 'ui', 'DlgMessage.ui'))
+ WIDGET, BASE = uic.loadUiType(os.path.join(pluginPath, "ui", "DlgMessage.ui"))
class MessageDialog(BASE, WIDGET):
@@ -52,7 +51,7 @@ def setMessage(self, message):
def openLink(self, url):
if url.toString() == "log":
self.close()
- logDock = iface.mainWindow().findChild(QDockWidget, 'MessageLog')
+ logDock = iface.mainWindow().findChild(QDockWidget, "MessageLog")
logDock.show()
else:
QDesktopServices.openUrl(url)
diff --git a/python/plugins/processing/gui/MultipleFileInputDialog.py b/python/plugins/processing/gui/MultipleFileInputDialog.py
index 72372cdf4eed..f13756408442 100644
--- a/python/plugins/processing/gui/MultipleFileInputDialog.py
+++ b/python/plugins/processing/gui/MultipleFileInputDialog.py
@@ -19,9 +19,9 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'August 2012'
-__copyright__ = '(C) 2012, Victor Olaya'
+__author__ = "Victor Olaya"
+__date__ = "August 2012"
+__copyright__ = "(C) 2012, Victor Olaya"
import os
import warnings
@@ -29,7 +29,13 @@
from qgis.core import QgsSettings
from qgis.PyQt import uic
from qgis.PyQt.QtCore import QByteArray
-from qgis.PyQt.QtWidgets import QDialog, QAbstractItemView, QPushButton, QDialogButtonBox, QFileDialog
+from qgis.PyQt.QtWidgets import (
+ QDialog,
+ QAbstractItemView,
+ QPushButton,
+ QDialogButtonBox,
+ QFileDialog,
+)
from qgis.PyQt.QtGui import QStandardItemModel, QStandardItem
pluginPath = os.path.split(os.path.dirname(__file__))[0]
@@ -37,7 +43,8 @@
with warnings.catch_warnings():
warnings.filterwarnings("ignore", category=DeprecationWarning)
WIDGET, BASE = uic.loadUiType(
- os.path.join(pluginPath, 'ui', 'DlgMultipleSelection.ui'))
+ os.path.join(pluginPath, "ui", "DlgMultipleSelection.ui")
+ )
class MultipleFileInputDialog(BASE, WIDGET):
@@ -46,33 +53,40 @@ def __init__(self, options):
super().__init__(None)
self.setupUi(self)
- self.lstLayers.setSelectionMode(QAbstractItemView.SelectionMode.ExtendedSelection)
+ self.lstLayers.setSelectionMode(
+ QAbstractItemView.SelectionMode.ExtendedSelection
+ )
self.selectedoptions = options
# Additional buttons
- self.btnAdd = QPushButton(self.tr('Add file'))
- self.buttonBox.addButton(self.btnAdd,
- QDialogButtonBox.ButtonRole.ActionRole)
- self.btnRemove = QPushButton(self.tr('Remove file(s)'))
- self.buttonBox.addButton(self.btnRemove,
- QDialogButtonBox.ButtonRole.ActionRole)
- self.btnRemoveAll = QPushButton(self.tr('Remove all'))
- self.buttonBox.addButton(self.btnRemoveAll,
- QDialogButtonBox.ButtonRole.ActionRole)
+ self.btnAdd = QPushButton(self.tr("Add file"))
+ self.buttonBox.addButton(self.btnAdd, QDialogButtonBox.ButtonRole.ActionRole)
+ self.btnRemove = QPushButton(self.tr("Remove file(s)"))
+ self.buttonBox.addButton(self.btnRemove, QDialogButtonBox.ButtonRole.ActionRole)
+ self.btnRemoveAll = QPushButton(self.tr("Remove all"))
+ self.buttonBox.addButton(
+ self.btnRemoveAll, QDialogButtonBox.ButtonRole.ActionRole
+ )
self.btnAdd.clicked.connect(self.addFile)
self.btnRemove.clicked.connect(lambda: self.removeRows())
self.btnRemoveAll.clicked.connect(lambda: self.removeRows(True))
self.settings = QgsSettings()
- self.restoreGeometry(self.settings.value("/Processing/multipleFileInputDialogGeometry", QByteArray()))
+ self.restoreGeometry(
+ self.settings.value(
+ "/Processing/multipleFileInputDialogGeometry", QByteArray()
+ )
+ )
self.populateList()
self.finished.connect(self.saveWindowGeometry)
def saveWindowGeometry(self):
- self.settings.setValue("/Processing/multipleInputDialogGeometry", self.saveGeometry())
+ self.settings.setValue(
+ "/Processing/multipleInputDialogGeometry", self.saveGeometry()
+ )
def populateList(self):
model = QStandardItemModel()
@@ -95,13 +109,14 @@ def reject(self):
def addFile(self):
settings = QgsSettings()
- if settings.contains('/Processing/LastInputPath'):
- path = settings.value('/Processing/LastInputPath')
+ if settings.contains("/Processing/LastInputPath"):
+ path = settings.value("/Processing/LastInputPath")
else:
- path = ''
+ path = ""
- files, selected_filter = QFileDialog.getOpenFileNames(self,
- self.tr('Select File(s)'), path, self.tr('All files (*.*)'))
+ files, selected_filter = QFileDialog.getOpenFileNames(
+ self, self.tr("Select File(s)"), path, self.tr("All files (*.*)")
+ )
if len(files) == 0:
return
@@ -111,8 +126,7 @@ def addFile(self):
item = QStandardItem(filePath)
model.appendRow(item)
- settings.setValue('/Processing/LastInputPath',
- os.path.dirname(files[0]))
+ settings.setValue("/Processing/LastInputPath", os.path.dirname(files[0]))
def removeRows(self, removeAll=False):
if removeAll:
diff --git a/python/plugins/processing/gui/MultipleInputDialog.py b/python/plugins/processing/gui/MultipleInputDialog.py
index 383788fe7006..927248f3b175 100644
--- a/python/plugins/processing/gui/MultipleInputDialog.py
+++ b/python/plugins/processing/gui/MultipleInputDialog.py
@@ -15,29 +15,38 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'August 2012'
-__copyright__ = '(C) 2012, Victor Olaya'
+__author__ = "Victor Olaya"
+__date__ = "August 2012"
+__copyright__ = "(C) 2012, Victor Olaya"
import os
import warnings
from pathlib import Path
-from qgis.core import (QgsSettings,
- QgsProcessing,
- QgsVectorFileWriter,
- QgsProviderRegistry,
- QgsProcessingModelChildParameterSource)
+from qgis.core import (
+ QgsSettings,
+ QgsProcessing,
+ QgsVectorFileWriter,
+ QgsProviderRegistry,
+ QgsProcessingModelChildParameterSource,
+)
from qgis.PyQt import uic
from qgis.PyQt.QtCore import Qt, QByteArray, QCoreApplication
-from qgis.PyQt.QtWidgets import QDialog, QAbstractItemView, QPushButton, QDialogButtonBox, QFileDialog
+from qgis.PyQt.QtWidgets import (
+ QDialog,
+ QAbstractItemView,
+ QPushButton,
+ QDialogButtonBox,
+ QFileDialog,
+)
from qgis.PyQt.QtGui import QStandardItemModel, QStandardItem
pluginPath = os.path.split(os.path.dirname(__file__))[0]
with warnings.catch_warnings():
warnings.filterwarnings("ignore", category=DeprecationWarning)
WIDGET, BASE = uic.loadUiType(
- os.path.join(pluginPath, 'ui', 'DlgMultipleSelection.ui'))
+ os.path.join(pluginPath, "ui", "DlgMultipleSelection.ui")
+ )
class MultipleInputDialog(BASE, WIDGET):
@@ -58,48 +67,63 @@ def __init__(self, options, selectedoptions=None, datatype=None):
self.selectedoptions = selectedoptions or []
# Additional buttons
- self.btnSelectAll = QPushButton(self.tr('Select All'))
- self.buttonBox.addButton(self.btnSelectAll,
- QDialogButtonBox.ButtonRole.ActionRole)
- self.btnClearSelection = QPushButton(self.tr('Clear Selection'))
- self.buttonBox.addButton(self.btnClearSelection,
- QDialogButtonBox.ButtonRole.ActionRole)
- self.btnToggleSelection = QPushButton(self.tr('Toggle Selection'))
- self.buttonBox.addButton(self.btnToggleSelection,
- QDialogButtonBox.ButtonRole.ActionRole)
+ self.btnSelectAll = QPushButton(self.tr("Select All"))
+ self.buttonBox.addButton(
+ self.btnSelectAll, QDialogButtonBox.ButtonRole.ActionRole
+ )
+ self.btnClearSelection = QPushButton(self.tr("Clear Selection"))
+ self.buttonBox.addButton(
+ self.btnClearSelection, QDialogButtonBox.ButtonRole.ActionRole
+ )
+ self.btnToggleSelection = QPushButton(self.tr("Toggle Selection"))
+ self.buttonBox.addButton(
+ self.btnToggleSelection, QDialogButtonBox.ButtonRole.ActionRole
+ )
if self.datatype is not None:
- btnAddFile = QPushButton(QCoreApplication.translate("MultipleInputDialog", 'Add File(s)…'))
+ btnAddFile = QPushButton(
+ QCoreApplication.translate("MultipleInputDialog", "Add File(s)…")
+ )
btnAddFile.clicked.connect(self.addFiles)
- self.buttonBox.addButton(btnAddFile,
- QDialogButtonBox.ButtonRole.ActionRole)
+ self.buttonBox.addButton(btnAddFile, QDialogButtonBox.ButtonRole.ActionRole)
- btnAddDir = QPushButton(QCoreApplication.translate("MultipleInputDialog", 'Add Directory…'))
+ btnAddDir = QPushButton(
+ QCoreApplication.translate("MultipleInputDialog", "Add Directory…")
+ )
btnAddDir.clicked.connect(self.addDirectory)
- self.buttonBox.addButton(btnAddDir,
- QDialogButtonBox.ButtonRole.ActionRole)
+ self.buttonBox.addButton(btnAddDir, QDialogButtonBox.ButtonRole.ActionRole)
self.btnSelectAll.clicked.connect(lambda: self.selectAll(True))
self.btnClearSelection.clicked.connect(lambda: self.selectAll(False))
self.btnToggleSelection.clicked.connect(self.toggleSelection)
self.settings = QgsSettings()
- self.restoreGeometry(self.settings.value("/Processing/multipleInputDialogGeometry", QByteArray()))
+ self.restoreGeometry(
+ self.settings.value("/Processing/multipleInputDialogGeometry", QByteArray())
+ )
- self.lstLayers.setSelectionMode(QAbstractItemView.SelectionMode.ExtendedSelection)
+ self.lstLayers.setSelectionMode(
+ QAbstractItemView.SelectionMode.ExtendedSelection
+ )
self.lstLayers.setDragDropMode(QAbstractItemView.DragDropMode.InternalMove)
self.populateList()
self.finished.connect(self.saveWindowGeometry)
def saveWindowGeometry(self):
- self.settings.setValue("/Processing/multipleInputDialogGeometry", self.saveGeometry())
+ self.settings.setValue(
+ "/Processing/multipleInputDialogGeometry", self.saveGeometry()
+ )
def populateList(self):
self.model = QStandardItemModel()
for value, text in self.options:
item = QStandardItem(text)
item.setData(value, Qt.ItemDataRole.UserRole)
- item.setCheckState(Qt.CheckState.Checked if value in self.selectedoptions else Qt.CheckState.Unchecked)
+ item.setCheckState(
+ Qt.CheckState.Checked
+ if value in self.selectedoptions
+ else Qt.CheckState.Unchecked
+ )
item.setCheckable(True)
item.setDropEnabled(False)
self.model.appendRow(item)
@@ -143,12 +167,16 @@ def getItemsToModify(self):
def selectAll(self, value):
for item in self.getItemsToModify():
- item.setCheckState(Qt.CheckState.Checked if value else Qt.CheckState.Unchecked)
+ item.setCheckState(
+ Qt.CheckState.Checked if value else Qt.CheckState.Unchecked
+ )
def toggleSelection(self):
for item in self.getItemsToModify():
checked = item.checkState() == Qt.CheckState.Checked
- item.setCheckState(Qt.CheckState.Unchecked if checked else Qt.CheckState.Checked)
+ item.setCheckState(
+ Qt.CheckState.Unchecked if checked else Qt.CheckState.Checked
+ )
def getFileFilter(self, datatype):
"""
@@ -159,25 +187,29 @@ def getFileFilter(self, datatype):
if datatype == QgsProcessing.SourceType.TypeRaster:
return QgsProviderRegistry.instance().fileRasterFilters()
elif datatype == QgsProcessing.SourceType.TypeFile:
- return self.tr('All files (*.*)')
+ return self.tr("All files (*.*)")
else:
exts = QgsVectorFileWriter.supportedFormatExtensions()
for i in range(len(exts)):
- exts[i] = self.tr('{0} files (*.{1})').format(exts[i].upper(), exts[i].lower())
- return self.tr('All files (*.*)') + ';;' + ';;'.join(exts)
+ exts[i] = self.tr("{0} files (*.{1})").format(
+ exts[i].upper(), exts[i].lower()
+ )
+ return self.tr("All files (*.*)") + ";;" + ";;".join(exts)
def addFiles(self):
filter = self.getFileFilter(self.datatype)
settings = QgsSettings()
- path = str(settings.value('/Processing/LastInputPath'))
+ path = str(settings.value("/Processing/LastInputPath"))
- ret, selected_filter = QFileDialog.getOpenFileNames(self, self.tr('Select File(s)'),
- path, filter)
+ ret, selected_filter = QFileDialog.getOpenFileNames(
+ self, self.tr("Select File(s)"), path, filter
+ )
if ret:
files = list(ret)
- settings.setValue('/Processing/LastInputPath',
- os.path.dirname(str(files[0])))
+ settings.setValue(
+ "/Processing/LastInputPath", os.path.dirname(str(files[0]))
+ )
for filename in files:
item = QStandardItem(filename)
item.setData(filename, Qt.ItemDataRole.UserRole)
@@ -188,17 +220,19 @@ def addFiles(self):
def addDirectory(self):
settings = QgsSettings()
- path = str(settings.value('/Processing/LastInputPath'))
+ path = str(settings.value("/Processing/LastInputPath"))
- ret = QFileDialog.getExistingDirectory(self, self.tr('Select File(s)'), path)
+ ret = QFileDialog.getExistingDirectory(self, self.tr("Select File(s)"), path)
if ret:
exts = []
if self.datatype == QgsProcessing.SourceType.TypeVector:
exts = QgsVectorFileWriter.supportedFormatExtensions()
elif self.datatype == QgsProcessing.SourceType.TypeRaster:
- for t in QgsProviderRegistry.instance().fileRasterFilters().split(';;')[1:]:
- for e in t[t.index('(') + 1:-1].split(' '):
+ for t in (
+ QgsProviderRegistry.instance().fileRasterFilters().split(";;")[1:]
+ ):
+ for e in t[t.index("(") + 1 : -1].split(" "):
if e != "*.*" and e.startswith("*."):
exts.append(e[2:])
@@ -214,7 +248,7 @@ def addDirectory(self):
files.append(p)
- settings.setValue('/Processing/LastInputPath', ret)
+ settings.setValue("/Processing/LastInputPath", ret)
for filename in files:
item = QStandardItem(filename)
diff --git a/python/plugins/processing/gui/MultipleInputPanel.py b/python/plugins/processing/gui/MultipleInputPanel.py
index 1f7c17c2f287..eba87fd35f62 100644
--- a/python/plugins/processing/gui/MultipleInputPanel.py
+++ b/python/plugins/processing/gui/MultipleInputPanel.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'August 2012'
-__copyright__ = '(C) 2012, Victor Olaya'
+__author__ = "Victor Olaya"
+__date__ = "August 2012"
+__copyright__ = "(C) 2012, Victor Olaya"
import os
import warnings
@@ -26,7 +26,7 @@
from qgis.PyQt import uic
from qgis.PyQt.QtCore import pyqtSignal
-''
+""
from processing.gui.MultipleInputDialog import MultipleInputDialog
from processing.gui.MultipleFileInputDialog import MultipleFileInputDialog
@@ -35,7 +35,8 @@
with warnings.catch_warnings():
warnings.filterwarnings("ignore", category=DeprecationWarning)
WIDGET, BASE = uic.loadUiType(
- os.path.join(pluginPath, 'ui', 'widgetBaseSelector.ui'))
+ os.path.join(pluginPath, "ui", "widgetBaseSelector.ui")
+ )
class MultipleInputPanel(BASE, WIDGET):
@@ -46,7 +47,7 @@ def __init__(self, options=None, datatype=None):
self.setupUi(self)
self.leText.setEnabled(False)
- self.leText.setText(self.tr('0 elements selected'))
+ self.leText.setText(self.tr("0 elements selected"))
self.btnSelect.clicked.connect(self.showSelectionDialog)
@@ -58,23 +59,29 @@ def setSelectedItems(self, selected):
# No checking is performed!
self.selectedoptions = selected
self.leText.setText(
- self.tr('{0} elements selected').format(len(self.selectedoptions)))
+ self.tr("{0} elements selected").format(len(self.selectedoptions))
+ )
def showSelectionDialog(self):
if self.datatype == QgsProcessing.SourceType.TypeFile:
dlg = MultipleFileInputDialog(self.selectedoptions)
else:
- dlg = MultipleInputDialog(self.options, self.selectedoptions, datatype=self.datatype)
+ dlg = MultipleInputDialog(
+ self.options, self.selectedoptions, datatype=self.datatype
+ )
dlg.exec()
if dlg.selectedoptions is not None:
self.selectedoptions = dlg.selectedoptions
self.leText.setText(
- self.tr('{0} elements selected').format(len(self.selectedoptions)))
+ self.tr("{0} elements selected").format(len(self.selectedoptions))
+ )
self.selectionChanged.emit()
def updateForOptions(self, options):
selectedoptions = []
- selected = [self.options[i] if isinstance(i, int) else i for i in self.selectedoptions]
+ selected = [
+ self.options[i] if isinstance(i, int) else i for i in self.selectedoptions
+ ]
for sel in selected:
if not isinstance(sel, int):
try:
diff --git a/python/plugins/processing/gui/NumberInputPanel.py b/python/plugins/processing/gui/NumberInputPanel.py
index 969bdf2907af..3a9ece5b36c8 100644
--- a/python/plugins/processing/gui/NumberInputPanel.py
+++ b/python/plugins/processing/gui/NumberInputPanel.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'August 2012'
-__copyright__ = '(C) 2012, Victor Olaya'
+__author__ = "Victor Olaya"
+__date__ = "August 2012"
+__copyright__ = "(C) 2012, Victor Olaya"
import os
import math
@@ -41,7 +41,7 @@
QgsProcessingParameterDefinition,
QgsProcessingModelChildParameterSource,
QgsProcessingFeatureSourceDefinition,
- QgsProcessingUtils
+ QgsProcessingUtils,
)
from qgis.gui import QgsExpressionBuilderDialog
from processing.tools.dataobjects import createExpressionContext, createContext
@@ -50,9 +50,11 @@
with warnings.catch_warnings():
warnings.filterwarnings("ignore", category=DeprecationWarning)
NUMBER_WIDGET, NUMBER_BASE = uic.loadUiType(
- os.path.join(pluginPath, 'ui', 'widgetNumberSelector.ui'))
+ os.path.join(pluginPath, "ui", "widgetNumberSelector.ui")
+ )
WIDGET, BASE = uic.loadUiType(
- os.path.join(pluginPath, 'ui', 'widgetBaseSelector.ui'))
+ os.path.join(pluginPath, "ui", "widgetBaseSelector.ui")
+ )
class ModelerNumberInputPanel(BASE, WIDGET):
@@ -80,15 +82,19 @@ def __init__(self, param, modelParametersDialog):
def showExpressionsBuilder(self):
context = createExpressionContext()
processing_context = createContext()
- scope = self.modelParametersDialog.model.createExpressionContextScopeForChildAlgorithm(self.modelParametersDialog.childId, processing_context)
+ scope = self.modelParametersDialog.model.createExpressionContextScopeForChildAlgorithm(
+ self.modelParametersDialog.childId, processing_context
+ )
context.appendScope(scope)
highlighted = scope.variableNames()
context.setHighlightedVariables(highlighted)
- dlg = QgsExpressionBuilderDialog(None, str(self.leText.text()), self, 'generic', context)
+ dlg = QgsExpressionBuilderDialog(
+ None, str(self.leText.text()), self, "generic", context
+ )
- dlg.setWindowTitle(self.tr('Expression Based Input'))
+ dlg.setWindowTitle(self.tr("Expression Based Input"))
if dlg.exec() == QDialog.DialogCode.Accepted:
exp = QgsExpression(dlg.expressionText())
if not exp.hasParserError():
@@ -99,22 +105,34 @@ def getValue(self):
for param in self.modelParametersDialog.model.parameterDefinitions():
if isinstance(param, QgsProcessingParameterNumber):
if "@" + param.name() == value.strip():
- return QgsProcessingModelChildParameterSource.fromModelParameter(param.name())
+ return QgsProcessingModelChildParameterSource.fromModelParameter(
+ param.name()
+ )
for alg in list(self.modelParametersDialog.model.childAlgorithms().values()):
for out in alg.algorithm().outputDefinitions():
- if isinstance(out, QgsProcessingOutputNumber) and f"@{alg.childId()}_{out.name()}" == value.strip():
- return QgsProcessingModelChildParameterSource.fromChildOutput(alg.childId(), out.outputName())
+ if (
+ isinstance(out, QgsProcessingOutputNumber)
+ and f"@{alg.childId()}_{out.name()}" == value.strip()
+ ):
+ return QgsProcessingModelChildParameterSource.fromChildOutput(
+ alg.childId(), out.outputName()
+ )
try:
return float(value.strip())
except:
- return QgsProcessingModelChildParameterSource.fromExpression(self.leText.text())
+ return QgsProcessingModelChildParameterSource.fromExpression(
+ self.leText.text()
+ )
def setValue(self, value):
if isinstance(value, QgsProcessingModelChildParameterSource):
- if value.source() == Qgis.ProcessingModelChildParameterSource.ModelParameter:
- self.leText.setText('@' + value.parameterName())
+ if (
+ value.source()
+ == Qgis.ProcessingModelChildParameterSource.ModelParameter
+ ):
+ self.leText.setText("@" + value.parameterName())
elif value.source() == Qgis.ProcessingModelChildParameterSource.ChildOutput:
name = f"{value.outputChildId()}_{value.outputName()}"
self.leText.setText(name)
@@ -149,7 +167,11 @@ def __init__(self, param):
# Guess reasonable step value
if self.param.maximum() is not None and self.param.minimum() is not None:
try:
- self.spnValue.setSingleStep(self.calculateStep(float(self.param.minimum()), float(self.param.maximum())))
+ self.spnValue.setSingleStep(
+ self.calculateStep(
+ float(self.param.minimum()), float(self.param.maximum())
+ )
+ )
except:
pass
@@ -169,7 +191,7 @@ def __init__(self, param):
min = self.spnValue.minimum() - 1
self.spnValue.setMinimum(min)
self.spnValue.setValue(min)
- self.spnValue.setSpecialValueText(self.tr('Not set'))
+ self.spnValue.setSpecialValueText(self.tr("Not set"))
self.allowing_null = True
if param.defaultValue() is not None:
@@ -201,7 +223,9 @@ def __init__(self, param):
sip.delete(self.btnDataDefined)
self.btnDataDefined = None
else:
- self.btnDataDefined.init(0, QgsProperty(), self.param.dynamicPropertyDefinition())
+ self.btnDataDefined.init(
+ 0, QgsProperty(), self.param.dynamicPropertyDefinition()
+ )
self.btnDataDefined.registerEnabledWidget(self.spnValue, False)
self.spnValue.valueChanged.connect(lambda: self.hasChanged.emit())
@@ -261,27 +285,33 @@ class DistanceInputPanel(NumberInputPanel):
def __init__(self, param):
super().__init__(param)
- self.label = QLabel('')
+ self.label = QLabel("")
self.units_combo = QComboBox()
self.base_units = QgsUnitTypes.DistanceUnit.DistanceUnknownUnit
- for u in (QgsUnitTypes.DistanceUnit.DistanceMeters,
- QgsUnitTypes.DistanceUnit.DistanceKilometers,
- QgsUnitTypes.DistanceUnit.DistanceFeet,
- QgsUnitTypes.DistanceUnit.DistanceMiles,
- QgsUnitTypes.DistanceUnit.DistanceYards):
+ for u in (
+ QgsUnitTypes.DistanceUnit.DistanceMeters,
+ QgsUnitTypes.DistanceUnit.DistanceKilometers,
+ QgsUnitTypes.DistanceUnit.DistanceFeet,
+ QgsUnitTypes.DistanceUnit.DistanceMiles,
+ QgsUnitTypes.DistanceUnit.DistanceYards,
+ ):
self.units_combo.addItem(QgsUnitTypes.toString(u), u)
- label_margin = self.fontMetrics().horizontalAdvance('X')
+ label_margin = self.fontMetrics().horizontalAdvance("X")
self.layout().insertSpacing(1, int(label_margin / 2))
self.layout().insertWidget(2, self.label)
self.layout().insertWidget(3, self.units_combo)
self.layout().insertSpacing(4, int(label_margin / 2))
self.warning_label = QLabel()
- icon = QgsApplication.getThemeIcon('mIconWarning.svg')
+ icon = QgsApplication.getThemeIcon("mIconWarning.svg")
size = max(24, self.spnValue.height() * 0.5)
self.warning_label.setPixmap(icon.pixmap(icon.actualSize(QSize(size, size))))
- self.warning_label.setToolTip(self.tr('Distance is in geographic degrees. Consider reprojecting to a projected local coordinate system for accurate results.'))
+ self.warning_label.setToolTip(
+ self.tr(
+ "Distance is in geographic degrees. Consider reprojecting to a projected local coordinate system for accurate results."
+ )
+ )
self.layout().insertWidget(4, self.warning_label)
self.layout().insertSpacing(5, label_margin)
@@ -296,7 +326,9 @@ def setUnits(self, units):
self.units_combo.setCurrentIndex(self.units_combo.findData(units))
self.units_combo.show()
self.label.hide()
- self.warning_label.setVisible(units == QgsUnitTypes.DistanceUnit.DistanceDegrees)
+ self.warning_label.setVisible(
+ units == QgsUnitTypes.DistanceUnit.DistanceDegrees
+ )
self.base_units = units
def setUnitParameterValue(self, value):
@@ -316,7 +348,9 @@ def getValue(self):
val = super().getValue()
if isinstance(val, float) and self.units_combo.isVisible():
display_unit = self.units_combo.currentData()
- return val * QgsUnitTypes.fromUnitToUnitFactor(display_unit, self.base_units)
+ return val * QgsUnitTypes.fromUnitToUnitFactor(
+ display_unit, self.base_units
+ )
return val
diff --git a/python/plugins/processing/gui/ParametersPanel.py b/python/plugins/processing/gui/ParametersPanel.py
index 2649d95cfe23..c7ddb66ad7c1 100644
--- a/python/plugins/processing/gui/ParametersPanel.py
+++ b/python/plugins/processing/gui/ParametersPanel.py
@@ -19,22 +19,26 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'August 2012'
-__copyright__ = '(C) 2012, Victor Olaya'
-
-from qgis.core import (QgsProcessingParameterDefinition,
- QgsProcessingParameterExtent,
- QgsProject,
- QgsProcessingModelAlgorithm,
- QgsProcessingOutputLayerDefinition)
-from qgis.gui import (QgsProcessingContextGenerator,
- QgsProcessingParameterWidgetContext,
- QgsProcessingParametersWidget,
- QgsGui,
- QgsProcessingGui,
- QgsProcessingParametersGenerator,
- QgsProcessingHiddenWidgetWrapper)
+__author__ = "Victor Olaya"
+__date__ = "August 2012"
+__copyright__ = "(C) 2012, Victor Olaya"
+
+from qgis.core import (
+ QgsProcessingParameterDefinition,
+ QgsProcessingParameterExtent,
+ QgsProject,
+ QgsProcessingModelAlgorithm,
+ QgsProcessingOutputLayerDefinition,
+)
+from qgis.gui import (
+ QgsProcessingContextGenerator,
+ QgsProcessingParameterWidgetContext,
+ QgsProcessingParametersWidget,
+ QgsGui,
+ QgsProcessingGui,
+ QgsProcessingParametersGenerator,
+ QgsProcessingHiddenWidgetWrapper,
+)
from qgis.utils import iface
from processing.gui.wrappers import WidgetWrapperFactory, WidgetWrapper
@@ -92,8 +96,8 @@ def initWidgets(self):
if isinstance(self.algorithm(), QgsProcessingModelAlgorithm):
widget_context.setModel(self.algorithm())
- in_place_input_parameter_name = 'INPUT'
- if hasattr(self.algorithm(), 'inputParameterName'):
+ in_place_input_parameter_name = "INPUT"
+ if hasattr(self.algorithm(), "inputParameterName"):
in_place_input_parameter_name = self.algorithm().inputParameterName()
# Create widgets and put them in layouts
@@ -104,12 +108,17 @@ def initWidgets(self):
if param.isDestination():
continue
else:
- if self.in_place and param.name() in (in_place_input_parameter_name, 'OUTPUT'):
+ if self.in_place and param.name() in (
+ in_place_input_parameter_name,
+ "OUTPUT",
+ ):
# don't show the input/output parameter widgets in in-place mode
# we still need to CREATE them, because other wrappers may need to interact
# with them (e.g. those parameters which need the input layer for field
# selections/crs properties/etc)
- self.wrappers[param.name()] = QgsProcessingHiddenWidgetWrapper(param, QgsProcessingGui.WidgetType.Standard, self)
+ self.wrappers[param.name()] = QgsProcessingHiddenWidgetWrapper(
+ param, QgsProcessingGui.WidgetType.Standard, self
+ )
self.wrappers[param.name()].setLinkedVectorLayer(self.active_layer)
continue
@@ -146,9 +155,12 @@ def initWidgets(self):
elif is_python_wrapper:
desc = param.description()
if isinstance(param, QgsProcessingParameterExtent):
- desc += self.tr(' (xmin, xmax, ymin, ymax)')
- if param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional:
- desc += self.tr(' [optional]')
+ desc += self.tr(" (xmin, xmax, ymin, ymax)")
+ if (
+ param.flags()
+ & QgsProcessingParameterDefinition.Flag.FlagOptional
+ ):
+ desc += self.tr(" [optional]")
widget.setText(desc)
self.addParameterWidget(param, widget, stretch)
@@ -157,10 +169,15 @@ def initWidgets(self):
if output.flags() & QgsProcessingParameterDefinition.Flag.FlagHidden:
continue
- if self.in_place and output.name() in (in_place_input_parameter_name, 'OUTPUT'):
+ if self.in_place and output.name() in (
+ in_place_input_parameter_name,
+ "OUTPUT",
+ ):
continue
- wrapper = QgsGui.processingGuiRegistry().createParameterWidgetWrapper(output, QgsProcessingGui.WidgetType.Standard)
+ wrapper = QgsGui.processingGuiRegistry().createParameterWidgetWrapper(
+ output, QgsProcessingGui.WidgetType.Standard
+ )
wrapper.setWidgetContext(widget_context)
wrapper.registerProcessingContextGenerator(self.context_generator)
wrapper.registerProcessingParametersGenerator(self)
@@ -196,8 +213,12 @@ def initWidgets(self):
for wrapper in list(self.wrappers.values()):
wrapper.postInitialize(list(self.wrappers.values()))
- def createProcessingParameters(self, flags=QgsProcessingParametersGenerator.Flags()):
- include_default = not (flags & QgsProcessingParametersGenerator.Flag.SkipDefaultValueParameters)
+ def createProcessingParameters(
+ self, flags=QgsProcessingParametersGenerator.Flags()
+ ):
+ include_default = not (
+ flags & QgsProcessingParametersGenerator.Flag.SkipDefaultValueParameters
+ )
parameters = {}
for p, v in self.extra_parameters.items():
parameters[p] = v
@@ -220,7 +241,10 @@ def createProcessingParameters(self, flags=QgsProcessingParametersGenerator.Flag
else:
widget = wrapper.wrappedWidget()
- if not isinstance(wrapper, QgsProcessingHiddenWidgetWrapper) and widget is None:
+ if (
+ not isinstance(wrapper, QgsProcessingHiddenWidgetWrapper)
+ and widget is None
+ ):
continue
value = wrapper.parameterValue()
@@ -230,8 +254,8 @@ def createProcessingParameters(self, flags=QgsProcessingParametersGenerator.Flag
if not param.checkValueIsAcceptable(value):
raise AlgorithmDialogBase.InvalidParameterValue(param, widget)
else:
- if self.in_place and param.name() == 'OUTPUT':
- parameters[param.name()] = 'memory:'
+ if self.in_place and param.name() == "OUTPUT":
+ parameters[param.name()] = "memory:"
continue
try:
@@ -243,7 +267,7 @@ def createProcessingParameters(self, flags=QgsProcessingParametersGenerator.Flag
value = wrapper.parameterValue()
dest_project = None
- if wrapper.customProperties().get('OPEN_AFTER_RUNNING'):
+ if wrapper.customProperties().get("OPEN_AFTER_RUNNING"):
dest_project = QgsProject.instance()
if value and isinstance(value, QgsProcessingOutputLayerDefinition):
diff --git a/python/plugins/processing/gui/PointMapTool.py b/python/plugins/processing/gui/PointMapTool.py
index 739698a2717a..c2528df86af9 100644
--- a/python/plugins/processing/gui/PointMapTool.py
+++ b/python/plugins/processing/gui/PointMapTool.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Alexander Bruy'
-__date__ = 'February 2016'
-__copyright__ = '(C) 2016, Alexander Bruy'
+__author__ = "Alexander Bruy"
+__date__ = "February 2016"
+__copyright__ = "(C) 2016, Alexander Bruy"
from qgis.PyQt.QtCore import Qt, pyqtSignal
diff --git a/python/plugins/processing/gui/PointSelectionPanel.py b/python/plugins/processing/gui/PointSelectionPanel.py
index 9baf229d965c..65e87eb17fb1 100644
--- a/python/plugins/processing/gui/PointSelectionPanel.py
+++ b/python/plugins/processing/gui/PointSelectionPanel.py
@@ -15,16 +15,14 @@
***************************************************************************
"""
-__author__ = 'Alexander Bruy'
-__date__ = 'February 2016'
-__copyright__ = '(C) 2016, Alexander Bruy'
+__author__ = "Alexander Bruy"
+__date__ = "February 2016"
+__copyright__ = "(C) 2016, Alexander Bruy"
import os
import warnings
-from qgis.core import (QgsProject,
- QgsReferencedPointXY,
- QgsPointXY)
+from qgis.core import QgsProject, QgsReferencedPointXY, QgsPointXY
from qgis.PyQt import uic
from qgis.utils import iface
@@ -36,7 +34,8 @@
with warnings.catch_warnings():
warnings.filterwarnings("ignore", category=DeprecationWarning)
WIDGET, BASE = uic.loadUiType(
- os.path.join(pluginPath, 'ui', 'widgetBaseSelector.ui'))
+ os.path.join(pluginPath, "ui", "widgetBaseSelector.ui")
+ )
class PointSelectionPanel(BASE, WIDGET):
@@ -62,7 +61,7 @@ def __init__(self, dialog, default=None):
self.tool = None
if default:
- tokens = str(default).split(',')
+ tokens = str(default).split(",")
if len(tokens) == 2:
try:
float(tokens[0])
@@ -77,10 +76,10 @@ def selectOnCanvas(self):
self.dialog.showMinimized()
def updatePoint(self, point, button):
- s = f'{point.x()},{point.y()}'
+ s = f"{point.x()},{point.y()}"
self.crs = QgsProject.instance().crs()
if self.crs.isValid():
- s += ' [' + self.crs.authid() + ']'
+ s += " [" + self.crs.authid() + "]"
self.leText.setText(s)
def pointPicked(self):
@@ -91,7 +90,7 @@ def pointPicked(self):
self.dialog.activateWindow()
def getValue(self):
- if str(self.leText.text()).strip() != '':
+ if str(self.leText.text()).strip() != "":
return str(self.leText.text())
else:
return None
diff --git a/python/plugins/processing/gui/Postprocessing.py b/python/plugins/processing/gui/Postprocessing.py
index f1b0fec6b72f..d36ce1f34b53 100644
--- a/python/plugins/processing/gui/Postprocessing.py
+++ b/python/plugins/processing/gui/Postprocessing.py
@@ -15,17 +15,12 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'August 2012'
-__copyright__ = '(C) 2012, Victor Olaya'
+__author__ = "Victor Olaya"
+__date__ = "August 2012"
+__copyright__ = "(C) 2012, Victor Olaya"
import traceback
-from typing import (
- Dict,
- List,
- Optional,
- Tuple
-)
+from typing import Dict, List, Optional, Tuple
from qgis.PyQt.QtCore import QCoreApplication
from qgis.core import (
@@ -39,7 +34,7 @@
QgsProcessingAlgorithm,
QgsLayerTreeLayer,
QgsLayerTreeGroup,
- QgsLayerTreeNode
+ QgsLayerTreeNode,
)
from qgis.utils import iface
@@ -47,14 +42,16 @@
from processing.gui.RenderingStyles import RenderingStyles
-SORT_ORDER_CUSTOM_PROPERTY = '_processing_sort_order'
+SORT_ORDER_CUSTOM_PROPERTY = "_processing_sort_order"
-def determine_output_name(dest_id: str,
- details: QgsProcessingContext.LayerDetails,
- alg: QgsProcessingAlgorithm,
- context: QgsProcessingContext,
- parameters: Dict) -> str:
+def determine_output_name(
+ dest_id: str,
+ details: QgsProcessingContext.LayerDetails,
+ alg: QgsProcessingAlgorithm,
+ context: QgsProcessingContext,
+ parameters: dict,
+) -> str:
"""
If running a model, the execution will arrive here when an
algorithm that is part of that model is executed. We check if
@@ -66,9 +63,9 @@ def determine_output_name(dest_id: str,
continue
output_value = parameters[out.name()]
if hasattr(output_value, "sink"):
- output_value = output_value.sink.valueAsString(
- context.expressionContext()
- )[0]
+ output_value = output_value.sink.valueAsString(context.expressionContext())[
+ 0
+ ]
else:
output_value = str(output_value)
if output_value == dest_id:
@@ -77,9 +74,9 @@ def determine_output_name(dest_id: str,
return details.outputName
-def post_process_layer(output_name: str,
- layer: QgsMapLayer,
- alg: QgsProcessingAlgorithm):
+def post_process_layer(
+ output_name: str, layer: QgsMapLayer, alg: QgsProcessingAlgorithm
+):
"""
Applies post-processing steps to a layer
"""
@@ -92,20 +89,20 @@ def post_process_layer(output_name: str,
style = ProcessingConfig.getSetting(ProcessingConfig.RASTER_STYLE)
elif layer.type() == Qgis.LayerType.Vector:
if layer.geometryType() == QgsWkbTypes.GeometryType.PointGeometry:
- style = ProcessingConfig.getSetting(
- ProcessingConfig.VECTOR_POINT_STYLE)
+ style = ProcessingConfig.getSetting(ProcessingConfig.VECTOR_POINT_STYLE)
elif layer.geometryType() == QgsWkbTypes.GeometryType.LineGeometry:
- style = ProcessingConfig.getSetting(
- ProcessingConfig.VECTOR_LINE_STYLE)
+ style = ProcessingConfig.getSetting(ProcessingConfig.VECTOR_LINE_STYLE)
else:
style = ProcessingConfig.getSetting(
- ProcessingConfig.VECTOR_POLYGON_STYLE)
+ ProcessingConfig.VECTOR_POLYGON_STYLE
+ )
if style:
layer.loadNamedStyle(style)
if layer.type() == Qgis.LayerType.PointCloud:
try:
from qgis._3d import QgsPointCloudLayer3DRenderer
+
if layer.renderer3D() is None:
# If the layer has no 3D renderer and syncing 3D to 2D
# renderer is enabled, we create a renderer and set it up
@@ -119,33 +116,36 @@ def post_process_layer(output_name: str,
QCoreApplication.translate(
"Postprocessing",
"3D library is not available, "
- "can't assign a 3d renderer to a layer."
+ "can't assign a 3d renderer to a layer.",
)
)
-def create_layer_tree_layer(layer: QgsMapLayer,
- details: QgsProcessingContext.LayerDetails) \
- -> QgsLayerTreeLayer:
+def create_layer_tree_layer(
+ layer: QgsMapLayer, details: QgsProcessingContext.LayerDetails
+) -> QgsLayerTreeLayer:
"""
Applies post-processing steps to a QgsLayerTreeLayer created for
an algorithm's output
"""
layer_tree_layer = QgsLayerTreeLayer(layer)
- if ProcessingConfig.getSetting(ProcessingConfig.VECTOR_FEATURE_COUNT) and \
- layer.type() == Qgis.LayerType.Vector:
+ if (
+ ProcessingConfig.getSetting(ProcessingConfig.VECTOR_FEATURE_COUNT)
+ and layer.type() == Qgis.LayerType.Vector
+ ):
layer_tree_layer.setCustomProperty("showFeatureCount", True)
if details.layerSortKey:
- layer_tree_layer.setCustomProperty(SORT_ORDER_CUSTOM_PROPERTY,
- details.layerSortKey)
+ layer_tree_layer.setCustomProperty(
+ SORT_ORDER_CUSTOM_PROPERTY, details.layerSortKey
+ )
return layer_tree_layer
-def get_layer_tree_results_group(details: QgsProcessingContext.LayerDetails,
- context: QgsProcessingContext) \
- -> Optional[QgsLayerTreeGroup]:
+def get_layer_tree_results_group(
+ details: QgsProcessingContext.LayerDetails, context: QgsProcessingContext
+) -> Optional[QgsLayerTreeGroup]:
"""
Returns the destination layer tree group to store results in, or None
if there is no specific destination tree group associated with the layer
@@ -158,13 +158,16 @@ def get_layer_tree_results_group(details: QgsProcessingContext.LayerDetails,
# if a specific results group is specified in Processing settings,
# respect it (and create if necessary)
results_group_name = ProcessingConfig.getSetting(
- ProcessingConfig.RESULTS_GROUP_NAME)
+ ProcessingConfig.RESULTS_GROUP_NAME
+ )
if results_group_name:
results_group = destination_project.layerTreeRoot().findGroup(
- results_group_name)
+ results_group_name
+ )
if not results_group:
results_group = destination_project.layerTreeRoot().insertGroup(
- 0, results_group_name)
+ 0, results_group_name
+ )
results_group.setExpanded(True)
# if this particular output layer has a specific output group assigned,
@@ -175,8 +178,7 @@ def get_layer_tree_results_group(details: QgsProcessingContext.LayerDetails,
group = results_group.findGroup(details.groupName)
if not group:
- group = results_group.insertGroup(
- 0, details.groupName)
+ group = results_group.insertGroup(0, details.groupName)
group.setExpanded(True)
else:
group = results_group
@@ -184,10 +186,12 @@ def get_layer_tree_results_group(details: QgsProcessingContext.LayerDetails,
return group
-def handleAlgorithmResults(alg: QgsProcessingAlgorithm,
- context: QgsProcessingContext,
- feedback: Optional[QgsProcessingFeedback] = None,
- parameters: Optional[Dict] = None):
+def handleAlgorithmResults(
+ alg: QgsProcessingAlgorithm,
+ context: QgsProcessingContext,
+ feedback: Optional[QgsProcessingFeedback] = None,
+ parameters: Optional[dict] = None,
+):
if not parameters:
parameters = {}
if feedback is None:
@@ -195,16 +199,14 @@ def handleAlgorithmResults(alg: QgsProcessingAlgorithm,
wrong_layers = []
feedback.setProgressText(
- QCoreApplication.translate(
- 'Postprocessing',
- 'Loading resulting layers'
- )
+ QCoreApplication.translate("Postprocessing", "Loading resulting layers")
)
i = 0
- added_layers: List[Tuple[Optional[QgsLayerTreeGroup], QgsLayerTreeLayer]] = []
- layers_to_post_process: List[Tuple[QgsMapLayer,
- QgsProcessingContext.LayerDetails]] = []
+ added_layers: list[tuple[Optional[QgsLayerTreeGroup], QgsLayerTreeLayer]] = []
+ layers_to_post_process: list[
+ tuple[QgsMapLayer, QgsProcessingContext.LayerDetails]
+ ] = []
for dest_id, details in context.layersToLoadOnCompletion().items():
if feedback.isCanceled():
@@ -218,9 +220,7 @@ def handleAlgorithmResults(alg: QgsProcessingAlgorithm,
try:
layer = QgsProcessingUtils.mapLayerFromString(
- dest_id,
- context,
- typeHint=details.layerTypeHint
+ dest_id, context, typeHint=details.layerTypeHint
)
if layer is not None:
details.setOutputLayerName(layer)
@@ -256,18 +256,19 @@ def handleAlgorithmResults(alg: QgsProcessingAlgorithm,
except Exception:
QgsMessageLog.logMessage(
QCoreApplication.translate(
- 'Postprocessing',
- "Error loading result layer:"
- ) + "\n" + traceback.format_exc(),
- 'Processing',
- Qgis.MessageLevel.Critical)
+ "Postprocessing", "Error loading result layer:"
+ )
+ + "\n"
+ + traceback.format_exc(),
+ "Processing",
+ Qgis.MessageLevel.Critical,
+ )
wrong_layers.append(str(dest_id))
i += 1
# sort added layer tree layers
sorted_layer_tree_layers = sorted(
- added_layers,
- key=lambda x: x[1].customProperty(SORT_ORDER_CUSTOM_PROPERTY, 0)
+ added_layers, key=lambda x: x[1].customProperty(SORT_ORDER_CUSTOM_PROPERTY, 0)
)
have_set_active_layer = False
@@ -286,10 +287,9 @@ def handleAlgorithmResults(alg: QgsProcessingAlgorithm,
if isinstance(current_selected_node, QgsLayerTreeLayer):
current_node_group = current_selected_node.parent()
current_node_index = current_node_group.children().index(
- current_selected_node)
- current_node_group.insertChildNode(
- current_node_index,
- layer_node)
+ current_selected_node
+ )
+ current_node_group.insertChildNode(current_node_index, layer_node)
elif isinstance(current_selected_node, QgsLayerTreeGroup):
current_selected_node.insertChildNode(0, layer_node)
elif context.project():
@@ -302,10 +302,7 @@ def handleAlgorithmResults(alg: QgsProcessingAlgorithm,
# all layers have been added to the layer tree, so safe to call
# postProcessors now
for layer, details in layers_to_post_process:
- details.postProcessor().postProcessLayer(
- layer,
- context,
- feedback)
+ details.postProcessor().postProcessLayer(layer, context, feedback)
if iface is not None:
iface.layerTreeView().setUpdatesEnabled(True)
@@ -314,14 +311,14 @@ def handleAlgorithmResults(alg: QgsProcessingAlgorithm,
if wrong_layers:
msg = QCoreApplication.translate(
- 'Postprocessing',
- "The following layers were not correctly generated."
+ "Postprocessing", "The following layers were not correctly generated."
)
- msg += "\n" + "\n".join([f"• {lay}" for lay in wrong_layers]) + '\n'
+ msg += "\n" + "\n".join([f"• {lay}" for lay in wrong_layers]) + "\n"
msg += QCoreApplication.translate(
- 'Postprocessing',
+ "Postprocessing",
"You can check the 'Log Messages Panel' in QGIS main window "
- "to find more information about the execution of the algorithm.")
+ "to find more information about the execution of the algorithm.",
+ )
feedback.reportError(msg)
return len(wrong_layers) == 0
diff --git a/python/plugins/processing/gui/ProcessingToolbox.py b/python/plugins/processing/gui/ProcessingToolbox.py
index c380d1ccd5a9..1560ca2d33d9 100644
--- a/python/plugins/processing/gui/ProcessingToolbox.py
+++ b/python/plugins/processing/gui/ProcessingToolbox.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'August 2012'
-__copyright__ = '(C) 2012, Victor Olaya'
+__author__ = "Victor Olaya"
+__date__ = "August 2012"
+__copyright__ = "(C) 2012, Victor Olaya"
import operator
import os
@@ -27,21 +27,20 @@
from qgis.PyQt.QtCore import Qt, QCoreApplication, pyqtSignal
from qgis.PyQt.QtWidgets import QWidget, QToolButton, QMenu, QAction
from qgis.utils import iface
-from qgis.core import (QgsWkbTypes,
- QgsMapLayerType,
- QgsApplication,
- QgsProcessingAlgorithm)
-from qgis.gui import (QgsGui,
- QgsDockWidget,
- QgsProcessingToolboxProxyModel)
+from qgis.core import (
+ QgsWkbTypes,
+ QgsMapLayerType,
+ QgsApplication,
+ QgsProcessingAlgorithm,
+)
+from qgis.gui import QgsGui, QgsDockWidget, QgsProcessingToolboxProxyModel
from processing.gui.Postprocessing import handleAlgorithmResults
from processing.core.ProcessingConfig import ProcessingConfig
from processing.gui.MessageDialog import MessageDialog
from processing.gui.EditRenderingStylesDialog import EditRenderingStylesDialog
from processing.gui.MessageBarProgress import MessageBarProgress
-from processing.gui.ProviderActions import (ProviderActions,
- ProviderContextMenuActions)
+from processing.gui.ProviderActions import ProviderActions, ProviderContextMenuActions
from processing.tools import dataobjects
pluginPath = os.path.split(os.path.dirname(__file__))[0]
@@ -49,13 +48,14 @@
with warnings.catch_warnings():
warnings.filterwarnings("ignore", category=DeprecationWarning)
WIDGET, BASE = uic.loadUiType(
- os.path.join(pluginPath, 'ui', 'ProcessingToolbox.ui'))
+ os.path.join(pluginPath, "ui", "ProcessingToolbox.ui")
+ )
class ProcessingToolbox(QgsDockWidget, WIDGET):
- ALG_ITEM = 'ALG_ITEM'
- PROVIDER_ITEM = 'PROVIDER_ITEM'
- GROUP_ITEM = 'GROUP_ITEM'
+ ALG_ITEM = "ALG_ITEM"
+ PROVIDER_ITEM = "PROVIDER_ITEM"
+ GROUP_ITEM = "GROUP_ITEM"
NAME_ROLE = Qt.ItemDataRole.UserRole
TAG_ROLE = Qt.ItemDataRole.UserRole + 1
@@ -69,13 +69,19 @@ def __init__(self):
self.tipWasClosed = False
self.in_place_mode = False
self.setupUi(self)
- self.setAllowedAreas(Qt.DockWidgetArea.LeftDockWidgetArea | Qt.DockWidgetArea.RightDockWidgetArea)
+ self.setAllowedAreas(
+ Qt.DockWidgetArea.LeftDockWidgetArea | Qt.DockWidgetArea.RightDockWidgetArea
+ )
self.processingToolbar.setIconSize(iface.iconSize(True))
- self.algorithmTree.setRegistry(QgsApplication.processingRegistry(),
- QgsGui.instance().processingRecentAlgorithmLog(),
- QgsGui.instance().processingFavoriteAlgorithmManager())
- filters = QgsProcessingToolboxProxyModel.Filters(QgsProcessingToolboxProxyModel.Filter.FilterToolbox)
+ self.algorithmTree.setRegistry(
+ QgsApplication.processingRegistry(),
+ QgsGui.instance().processingRecentAlgorithmLog(),
+ QgsGui.instance().processingFavoriteAlgorithmManager(),
+ )
+ filters = QgsProcessingToolboxProxyModel.Filters(
+ QgsProcessingToolboxProxyModel.Filter.FilterToolbox
+ )
if ProcessingConfig.getSetting(ProcessingConfig.SHOW_ALGORITHMS_KNOWN_ISSUES):
filters |= QgsProcessingToolboxProxyModel.Filter.FilterShowKnownIssues
self.algorithmTree.setFilters(filters)
@@ -84,8 +90,7 @@ def __init__(self):
self.searchBox.textChanged.connect(self.set_filter_string)
self.searchBox.returnPressed.connect(self.activateCurrent)
- self.algorithmTree.customContextMenuRequested.connect(
- self.showPopupMenu)
+ self.algorithmTree.customContextMenuRequested.connect(self.showPopupMenu)
self.algorithmTree.doubleClicked.connect(self.executeAlgorithm)
self.txtTip.setVisible(self.disabledProviders())
@@ -94,12 +99,14 @@ def openSettings(url):
self.txtTip.setVisible(False)
self.tipWasClosed = True
else:
- iface.showOptionsDialog(iface.mainWindow(), 'processingOptions')
+ iface.showOptionsDialog(iface.mainWindow(), "processingOptions")
self.txtTip.setVisible(self.disabledProviders())
self.txtTip.linkActivated.connect(openSettings)
- if hasattr(self.searchBox, 'setPlaceholderText'):
- self.searchBox.setPlaceholderText(QCoreApplication.translate('ProcessingToolbox', 'Search…'))
+ if hasattr(self.searchBox, "setPlaceholderText"):
+ self.searchBox.setPlaceholderText(
+ QCoreApplication.translate("ProcessingToolbox", "Search…")
+ )
# connect to existing providers
for p in QgsApplication.processingRegistry().providers():
@@ -121,12 +128,16 @@ def set_filter_string(self, string):
self.algorithmTree.setFilterString(string)
def set_in_place_edit_mode(self, enabled):
- filters = QgsProcessingToolboxProxyModel.Filters(QgsProcessingToolboxProxyModel.Filter.FilterToolbox)
+ filters = QgsProcessingToolboxProxyModel.Filters(
+ QgsProcessingToolboxProxyModel.Filter.FilterToolbox
+ )
if ProcessingConfig.getSetting(ProcessingConfig.SHOW_ALGORITHMS_KNOWN_ISSUES):
filters |= QgsProcessingToolboxProxyModel.Filter.FilterShowKnownIssues
if enabled:
- self.algorithmTree.setFilters(filters | QgsProcessingToolboxProxyModel.Filter.FilterInPlace)
+ self.algorithmTree.setFilters(
+ filters | QgsProcessingToolboxProxyModel.Filter.FilterInPlace
+ )
else:
self.algorithmTree.setFilters(filters)
self.in_place_mode = enabled
@@ -150,7 +161,7 @@ def disabledProviders(self):
def addProviderActions(self, provider):
if provider.id() in ProviderActions.actions:
toolbarButton = QToolButton()
- toolbarButton.setObjectName('provideraction_' + provider.id())
+ toolbarButton.setObjectName("provideraction_" + provider.id())
toolbarButton.setIcon(provider.icon())
toolbarButton.setToolTip(provider.name())
toolbarButton.setPopupMode(QToolButton.ToolButtonPopupMode.InstantPopup)
@@ -171,7 +182,7 @@ def addProvider(self, provider_id):
self.addProviderActions(provider)
def removeProvider(self, provider_id):
- button = self.findChild(QToolButton, 'provideraction-' + provider_id)
+ button = self.findChild(QToolButton, "provideraction-" + provider_id)
if button:
self.processingToolbar.removeChild(button)
@@ -180,28 +191,44 @@ def showPopupMenu(self, point):
popupmenu = QMenu()
alg = self.algorithmTree.algorithmForIndex(index)
if alg is not None:
- executeAction = QAction(QCoreApplication.translate('ProcessingToolbox', 'Execute…'), popupmenu)
+ executeAction = QAction(
+ QCoreApplication.translate("ProcessingToolbox", "Execute…"), popupmenu
+ )
executeAction.triggered.connect(self.executeAlgorithm)
popupmenu.addAction(executeAction)
if alg.flags() & QgsProcessingAlgorithm.Flag.FlagSupportsBatch:
executeBatchAction = QAction(
- QCoreApplication.translate('ProcessingToolbox', 'Execute as Batch Process…'),
- popupmenu)
+ QCoreApplication.translate(
+ "ProcessingToolbox", "Execute as Batch Process…"
+ ),
+ popupmenu,
+ )
executeBatchAction.triggered.connect(
- self.executeAlgorithmAsBatchProcess)
+ self.executeAlgorithmAsBatchProcess
+ )
popupmenu.addAction(executeBatchAction)
popupmenu.addSeparator()
editRenderingStylesAction = QAction(
- QCoreApplication.translate('ProcessingToolbox', 'Edit Rendering Styles for Outputs…'),
- popupmenu)
- editRenderingStylesAction.triggered.connect(
- self.editRenderingStyles)
+ QCoreApplication.translate(
+ "ProcessingToolbox", "Edit Rendering Styles for Outputs…"
+ ),
+ popupmenu,
+ )
+ editRenderingStylesAction.triggered.connect(self.editRenderingStyles)
popupmenu.addAction(editRenderingStylesAction)
popupmenu.addSeparator()
- actionText = QCoreApplication.translate('ProcessingToolbox', 'Add to Favorites')
- if QgsGui.instance().processingFavoriteAlgorithmManager().isFavorite(alg.id()):
- actionText = QCoreApplication.translate('ProcessingToolbox', 'Remove from Favorites')
+ actionText = QCoreApplication.translate(
+ "ProcessingToolbox", "Add to Favorites"
+ )
+ if (
+ QgsGui.instance()
+ .processingFavoriteAlgorithmManager()
+ .isFavorite(alg.id())
+ ):
+ actionText = QCoreApplication.translate(
+ "ProcessingToolbox", "Remove from Favorites"
+ )
favoriteAction = QAction(actionText, popupmenu)
favoriteAction.triggered.connect(self.toggleFavorite)
popupmenu.addAction(favoriteAction)
@@ -214,8 +241,7 @@ def showPopupMenu(self, point):
if action.is_separator:
popupmenu.addSeparator()
elif action.isEnabled():
- contextMenuAction = QAction(action.name,
- popupmenu)
+ contextMenuAction = QAction(action.name, popupmenu)
contextMenuAction.setIcon(action.icon())
contextMenuAction.triggered.connect(action.execute)
popupmenu.addAction(contextMenuAction)
@@ -223,7 +249,11 @@ def showPopupMenu(self, point):
popupmenu.exec(self.algorithmTree.mapToGlobal(point))
def editRenderingStyles(self):
- alg = self.algorithmTree.selectedAlgorithm().create() if self.algorithmTree.selectedAlgorithm() is not None else None
+ alg = (
+ self.algorithmTree.selectedAlgorithm().create()
+ if self.algorithmTree.selectedAlgorithm() is not None
+ else None
+ )
if alg is not None:
dlg = EditRenderingStylesDialog(alg)
dlg.exec()
@@ -244,7 +274,11 @@ def executeAlgorithm(self):
def toggleFavorite(self):
alg = self.algorithmTree.selectedAlgorithm()
if alg is not None:
- if QgsGui.instance().processingFavoriteAlgorithmManager().isFavorite(alg.id()):
+ if (
+ QgsGui.instance()
+ .processingFavoriteAlgorithmManager()
+ .isFavorite(alg.id())
+ ):
QgsGui.instance().processingFavoriteAlgorithmManager().remove(alg.id())
else:
QgsGui.instance().processingFavoriteAlgorithmManager().add(alg.id())
diff --git a/python/plugins/processing/gui/ProviderActions.py b/python/plugins/processing/gui/ProviderActions.py
index 604e21e25db9..974fc5694a87 100644
--- a/python/plugins/processing/gui/ProviderActions.py
+++ b/python/plugins/processing/gui/ProviderActions.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Nyall Dawson'
-__date__ = 'April 2017'
-__copyright__ = '(C) 2017, Nyall Dason'
+__author__ = "Nyall Dawson"
+__date__ = "April 2017"
+__copyright__ = "(C) 2017, Nyall Dason"
class ProviderActions:
@@ -25,12 +25,12 @@ class ProviderActions:
@staticmethod
def registerProviderActions(provider, actions):
- """ Adds actions for a provider """
+ """Adds actions for a provider"""
ProviderActions.actions[provider.id()] = actions
@staticmethod
def deregisterProviderActions(provider):
- """ Removes actions for a provider """
+ """Removes actions for a provider"""
if provider.id() in ProviderActions.actions:
del ProviderActions.actions[provider.id()]
@@ -41,11 +41,11 @@ class ProviderContextMenuActions:
@staticmethod
def registerProviderContextMenuActions(actions):
- """ Adds context menu actions for a provider """
+ """Adds context menu actions for a provider"""
ProviderContextMenuActions.actions.extend(actions)
@staticmethod
def deregisterProviderContextMenuActions(actions):
- """ Removes context menu actions for a provider """
+ """Removes context menu actions for a provider"""
for act in actions:
ProviderContextMenuActions.actions.remove(act)
diff --git a/python/plugins/processing/gui/RangePanel.py b/python/plugins/processing/gui/RangePanel.py
index 63bb16cca0b4..f4959c78929e 100644
--- a/python/plugins/processing/gui/RangePanel.py
+++ b/python/plugins/processing/gui/RangePanel.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'August 2012'
-__copyright__ = '(C) 2012, Victor Olaya'
+__author__ = "Victor Olaya"
+__date__ = "August 2012"
+__copyright__ = "(C) 2012, Victor Olaya"
import os
import warnings
@@ -33,7 +33,8 @@
with warnings.catch_warnings():
warnings.filterwarnings("ignore", category=DeprecationWarning)
WIDGET, BASE = uic.loadUiType(
- os.path.join(pluginPath, 'ui', 'widgetRangeSelector.ui'))
+ os.path.join(pluginPath, "ui", "widgetRangeSelector.ui")
+ )
class RangePanel(BASE, WIDGET):
@@ -70,16 +71,16 @@ def setMaxMin(self):
self.hasChanged.emit()
def getValue(self):
- return f'{self.spnMin.value()},{self.spnMax.value()}'
+ return f"{self.spnMin.value()},{self.spnMax.value()}"
def getValues(self):
value = self.getValue()
if value:
- return [float(a) for a in value.split(',')]
+ return [float(a) for a in value.split(",")]
def setValue(self, value):
try:
- values = value.split(',')
+ values = value.split(",")
minVal = float(values[0])
maxVal = float(values[1])
self.spnMin.setValue(float(minVal))
diff --git a/python/plugins/processing/gui/RectangleMapTool.py b/python/plugins/processing/gui/RectangleMapTool.py
index 67e9d06fc329..34563b4a8ece 100644
--- a/python/plugins/processing/gui/RectangleMapTool.py
+++ b/python/plugins/processing/gui/RectangleMapTool.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'August 2012'
-__copyright__ = '(C) 2012, Victor Olaya'
+__author__ = "Victor Olaya"
+__date__ = "August 2012"
+__copyright__ = "(C) 2012, Victor Olaya"
from qgis.PyQt.QtCore import pyqtSignal
from qgis.PyQt.QtGui import QColor
@@ -33,7 +33,9 @@ def __init__(self, canvas):
self.canvas = canvas
QgsMapToolEmitPoint.__init__(self, self.canvas)
- self.rubberBand = QgsRubberBand(self.canvas, QgsWkbTypes.GeometryType.PolygonGeometry)
+ self.rubberBand = QgsRubberBand(
+ self.canvas, QgsWkbTypes.GeometryType.PolygonGeometry
+ )
self.rubberBand.setColor(QColor(255, 0, 0, 100))
self.rubberBand.setWidth(2)
@@ -83,8 +85,10 @@ def showRect(self, startPoint, endPoint):
def rectangle(self):
if self.startPoint is None or self.endPoint is None:
return None
- elif self.startPoint.x() == self.endPoint.x() or \
- self.startPoint.y() == self.endPoint.y():
+ elif (
+ self.startPoint.x() == self.endPoint.x()
+ or self.startPoint.y() == self.endPoint.y()
+ ):
return None
return QgsRectangle(self.startPoint, self.endPoint)
diff --git a/python/plugins/processing/gui/RenderingStyleFilePanel.py b/python/plugins/processing/gui/RenderingStyleFilePanel.py
index 72ef4ff173b0..806cc33602b2 100644
--- a/python/plugins/processing/gui/RenderingStyleFilePanel.py
+++ b/python/plugins/processing/gui/RenderingStyleFilePanel.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'August 2012'
-__copyright__ = '(C) 2012, Victor Olaya'
+__author__ = "Victor Olaya"
+__date__ = "August 2012"
+__copyright__ = "(C) 2012, Victor Olaya"
import os
import warnings
@@ -32,7 +32,8 @@
with warnings.catch_warnings():
warnings.filterwarnings("ignore", category=DeprecationWarning)
WIDGET, BASE = uic.loadUiType(
- os.path.join(pluginPath, 'ui', 'widgetBaseSelector.ui'))
+ os.path.join(pluginPath, "ui", "widgetBaseSelector.ui")
+ )
class RenderingStyleFilePanel(BASE, WIDGET):
@@ -44,9 +45,12 @@ def __init__(self):
self.btnSelect.clicked.connect(self.showSelectionDialog)
def showSelectionDialog(self):
- filename, selected_filter = QFileDialog.getOpenFileName(self,
- self.tr('Select Style File'), '',
- self.tr('QGIS Layer Style File (*.qml *.QML)'))
+ filename, selected_filter = QFileDialog.getOpenFileName(
+ self,
+ self.tr("Select Style File"),
+ "",
+ self.tr("QGIS Layer Style File (*.qml *.QML)"),
+ )
if filename:
self.leText.setText(filename)
@@ -56,5 +60,5 @@ def setText(self, text):
def getValue(self):
s = self.leText.text()
if isWindows():
- s = s.replace('\\', '/')
+ s = s.replace("\\", "/")
return s
diff --git a/python/plugins/processing/gui/RenderingStyles.py b/python/plugins/processing/gui/RenderingStyles.py
index c9ba752aa784..72f483d0af8f 100644
--- a/python/plugins/processing/gui/RenderingStyles.py
+++ b/python/plugins/processing/gui/RenderingStyles.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'August 2012'
-__copyright__ = '(C) 2012, Victor Olaya'
+__author__ = "Victor Olaya"
+__date__ = "August 2012"
+__copyright__ = "(C) 2012, Victor Olaya"
import os
from processing.tools.system import userFolder
@@ -33,31 +33,32 @@ def addAlgStylesAndSave(algname, styles):
@staticmethod
def configFile():
- return os.path.join(userFolder(), 'processing_qgis_styles.conf')
+ return os.path.join(userFolder(), "processing_qgis_styles.conf")
@staticmethod
def loadStyles():
if not os.path.isfile(RenderingStyles.configFile()):
return
with open(RenderingStyles.configFile()) as lines:
- line = lines.readline().strip('\n')
- while line != '':
- tokens = line.split('|')
+ line = lines.readline().strip("\n")
+ while line != "":
+ tokens = line.split("|")
if tokens[0] in list(RenderingStyles.styles.keys()):
RenderingStyles.styles[tokens[0]][tokens[1]] = tokens[2]
else:
alg = {}
alg[tokens[1]] = tokens[2]
RenderingStyles.styles[tokens[0]] = alg
- line = lines.readline().strip('\n')
+ line = lines.readline().strip("\n")
@staticmethod
def saveSettings():
- with open(RenderingStyles.configFile(), 'w') as fout:
+ with open(RenderingStyles.configFile(), "w") as fout:
for alg in list(RenderingStyles.styles.keys()):
for out in list(RenderingStyles.styles[alg].keys()):
- fout.write(alg + '|' + out + '|' +
- RenderingStyles.styles[alg][out] + '\n')
+ fout.write(
+ alg + "|" + out + "|" + RenderingStyles.styles[alg][out] + "\n"
+ )
@staticmethod
def getStyle(algname, outputname):
diff --git a/python/plugins/processing/gui/ResultsDock.py b/python/plugins/processing/gui/ResultsDock.py
index 29ce184978c6..393c817179ee 100644
--- a/python/plugins/processing/gui/ResultsDock.py
+++ b/python/plugins/processing/gui/ResultsDock.py
@@ -15,18 +15,16 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'August 2012'
-__copyright__ = '(C) 2012, Victor Olaya'
+__author__ = "Victor Olaya"
+__date__ = "August 2012"
+__copyright__ = "(C) 2012, Victor Olaya"
import os
import time
import warnings
from qgis.PyQt import uic
-from qgis.PyQt.QtCore import (QUrl,
- QFileInfo,
- QDir)
+from qgis.PyQt.QtCore import QUrl, QFileInfo, QDir
from qgis.gui import QgsDockWidget
from qgis.PyQt.QtGui import QDesktopServices
from qgis.PyQt.QtWidgets import QTreeWidgetItem
@@ -37,8 +35,7 @@
with warnings.catch_warnings():
warnings.filterwarnings("ignore", category=DeprecationWarning)
- WIDGET, BASE = uic.loadUiType(
- os.path.join(pluginPath, 'ui', 'resultsdockbase.ui'))
+ WIDGET, BASE = uic.loadUiType(os.path.join(pluginPath, "ui", "resultsdockbase.ui"))
class ResultsDock(QgsDockWidget, WIDGET):
@@ -90,6 +87,11 @@ class TreeResultItem(QTreeWidgetItem):
def __init__(self, result):
QTreeWidgetItem.__init__(self)
self.setIcon(0, result.icon)
- self.setText(0, '{} [{}]'.format(result.name, time.strftime('%I:%M:%S%p', result.timestamp)))
+ self.setText(
+ 0,
+ "{} [{}]".format(
+ result.name, time.strftime("%I:%M:%S%p", result.timestamp)
+ ),
+ )
self.algorithm = result.name
self.filename = result.filename
diff --git a/python/plugins/processing/gui/TestTools.py b/python/plugins/processing/gui/TestTools.py
index 7d5f8cf93e19..d03ff057ca3b 100644
--- a/python/plugins/processing/gui/TestTools.py
+++ b/python/plugins/processing/gui/TestTools.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'February 2013'
-__copyright__ = '(C) 2013, Victor Olaya'
+__author__ = "Victor Olaya"
+__date__ = "February 2013"
+__copyright__ = "(C) 2013, Victor Olaya"
import os
import posixpath
@@ -31,25 +31,27 @@
from numpy import nan_to_num
-from qgis.core import (QgsApplication,
- QgsProcessing,
- QgsProcessingParameterDefinition,
- QgsProcessingParameterBoolean,
- QgsProcessingParameterNumber,
- QgsProcessingParameterDistance,
- QgsProcessingParameterDuration,
- QgsProcessingParameterFile,
- QgsProcessingParameterBand,
- QgsProcessingParameterString,
- QgsProcessingParameterVectorLayer,
- QgsProcessingParameterFeatureSource,
- QgsProcessingParameterRasterLayer,
- QgsProcessingParameterMultipleLayers,
- QgsProcessingParameterRasterDestination,
- QgsProcessingParameterFeatureSink,
- QgsProcessingParameterVectorDestination,
- QgsProcessingParameterFileDestination,
- QgsProcessingParameterEnum)
+from qgis.core import (
+ QgsApplication,
+ QgsProcessing,
+ QgsProcessingParameterDefinition,
+ QgsProcessingParameterBoolean,
+ QgsProcessingParameterNumber,
+ QgsProcessingParameterDistance,
+ QgsProcessingParameterDuration,
+ QgsProcessingParameterFile,
+ QgsProcessingParameterBand,
+ QgsProcessingParameterString,
+ QgsProcessingParameterVectorLayer,
+ QgsProcessingParameterFeatureSource,
+ QgsProcessingParameterRasterLayer,
+ QgsProcessingParameterMultipleLayers,
+ QgsProcessingParameterRasterDestination,
+ QgsProcessingParameterFeatureSink,
+ QgsProcessingParameterVectorDestination,
+ QgsProcessingParameterFileDestination,
+ QgsProcessingParameterEnum,
+)
from qgis.PyQt.QtCore import QCoreApplication, QMetaObject
from qgis.PyQt.QtWidgets import QDialog, QVBoxLayout, QTextEdit, QMessageBox
@@ -71,13 +73,13 @@ def extractSchemaPath(filepath):
"""
parts = []
schema = None
- localpath = ''
+ localpath = ""
path = filepath
part = True
while part and filepath:
(path, part) = os.path.split(path)
- if part == 'testdata' and not localpath:
+ if part == "testdata" and not localpath:
localparts = parts
localparts.reverse()
# we always want posix style paths here
@@ -88,12 +90,12 @@ def extractSchemaPath(filepath):
parts.reverse()
try:
- testsindex = parts.index('tests')
+ testsindex = parts.index("tests")
except ValueError:
- return '', filepath
+ return "", filepath
- if parts[testsindex - 1] == 'processing':
- schema = 'proc'
+ if parts[testsindex - 1] == "processing":
+ schema = "proc"
return schema, localpath
@@ -111,7 +113,7 @@ def parseParameters(command):
separator = m.group(3)
# Handle special values:
- if result == 'None':
+ if result == "None":
result = None
elif result.lower() == str(True).lower():
result = True
@@ -131,13 +133,13 @@ def splitAlgIdAndParameters(command):
Extracts the algorithm ID and input parameter list from a processing runalg command
"""
exp = re.compile(r"""['"](.*?)['"]\s*,\s*(.*)""")
- m = exp.search(command[len('processing.run('):-1])
+ m = exp.search(command[len("processing.run(") : -1])
alg_id = m.group(1)
params = m.group(2)
# replace QgsCoordinateReferenceSystem('EPSG:4325') with just string value
exp = re.compile(r"""QgsCoordinateReferenceSystem\((['"].*?['"])\)""")
- params = exp.sub('\\1', params)
+ params = exp.sub("\\1", params)
return alg_id, ast.literal_eval(params)
@@ -149,15 +151,18 @@ def createTest(text):
alg = QgsApplication.processingRegistry().createAlgorithmById(alg_id)
- definition['name'] = f'Test ({alg_id})'
- definition['algorithm'] = alg_id
+ definition["name"] = f"Test ({alg_id})"
+ definition["algorithm"] = alg_id
params = {}
results = {}
i = 0
for param in alg.parameterDefinitions():
- if param.flags() & QgsProcessingParameterDefinition.Flag.FlagHidden or param.isDestination():
+ if (
+ param.flags() & QgsProcessingParameterDefinition.Flag.FlagHidden
+ or param.isDestination()
+ ):
continue
if not param.name() in parameters:
@@ -166,27 +171,31 @@ def createTest(text):
i += 1
token = parameters[param.name()]
# Handle empty parameters that are optionals
- if param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional and token is None:
+ if (
+ param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional
+ and token is None
+ ):
continue
- if isinstance(param, (QgsProcessingParameterVectorLayer, QgsProcessingParameterFeatureSource)):
+ if isinstance(
+ param,
+ (QgsProcessingParameterVectorLayer, QgsProcessingParameterFeatureSource),
+ ):
schema, filepath = extractSchemaPath(token)
- p = {
- 'type': 'vector',
- 'name': filepath
- }
+ p = {"type": "vector", "name": filepath}
if not schema:
- p['location'] = '[The source data is not in the testdata directory. Please use data in the processing/tests/testdata folder.]'
+ p["location"] = (
+ "[The source data is not in the testdata directory. Please use data in the processing/tests/testdata folder.]"
+ )
params[param.name()] = p
elif isinstance(param, QgsProcessingParameterRasterLayer):
schema, filepath = extractSchemaPath(token)
- p = {
- 'type': 'raster',
- 'name': filepath
- }
+ p = {"type": "raster", "name": filepath}
if not schema:
- p['location'] = '[The source data is not in the testdata directory. Please use data in the processing/tests/testdata folder.]'
+ p["location"] = (
+ "[The source data is not in the testdata directory. Please use data in the processing/tests/testdata folder.]"
+ )
params[param.name()] = p
elif isinstance(param, QgsProcessingParameterMultipleLayers):
@@ -195,41 +204,44 @@ def createTest(text):
# Handle datatype detection
dataType = param.layerType()
- if dataType in [QgsProcessing.SourceType.TypeVectorAnyGeometry, QgsProcessing.SourceType.TypeVectorPoint, QgsProcessing.SourceType.TypeVectorLine, QgsProcessing.SourceType.TypeVectorPolygon, QgsProcessing.SourceType.TypeVector]:
- dataType = 'vector'
+ if dataType in [
+ QgsProcessing.SourceType.TypeVectorAnyGeometry,
+ QgsProcessing.SourceType.TypeVectorPoint,
+ QgsProcessing.SourceType.TypeVectorLine,
+ QgsProcessing.SourceType.TypeVectorPolygon,
+ QgsProcessing.SourceType.TypeVector,
+ ]:
+ dataType = "vector"
else:
- dataType = 'raster'
+ dataType = "raster"
schema = None
for mp in multiparams:
schema, filepath = extractSchemaPath(mp)
- newparam.append({
- 'type': dataType,
- 'name': filepath
- })
- p = {
- 'type': 'multi',
- 'params': newparam
- }
+ newparam.append({"type": dataType, "name": filepath})
+ p = {"type": "multi", "params": newparam}
if not schema:
- p['location'] = '[The source data is not in the testdata directory. Please use data in the processing/tests/testdata folder.]'
+ p["location"] = (
+ "[The source data is not in the testdata directory. Please use data in the processing/tests/testdata folder.]"
+ )
params[param.name()] = p
elif isinstance(param, QgsProcessingParameterFile):
schema, filepath = extractSchemaPath(token)
- p = {
- 'type': 'file',
- 'name': filepath
- }
+ p = {"type": "file", "name": filepath}
if not schema:
- p['location'] = '[The source data is not in the testdata directory. Please use data in the processing/tests/testdata folder.]'
+ p["location"] = (
+ "[The source data is not in the testdata directory. Please use data in the processing/tests/testdata folder.]"
+ )
params[param.name()] = p
elif isinstance(param, QgsProcessingParameterString):
params[param.name()] = token
elif isinstance(param, QgsProcessingParameterBoolean):
params[param.name()] = token
- elif isinstance(param, (QgsProcessingParameterNumber, QgsProcessingParameterDistance)):
+ elif isinstance(
+ param, (QgsProcessingParameterNumber, QgsProcessingParameterDistance)
+ ):
if param.dataType() == QgsProcessingParameterNumber.Type.Integer:
params[param.name()] = int(token)
else:
@@ -248,9 +260,15 @@ def createTest(text):
token = token[:-1]
params[param.name()] = token
- definition['params'] = params
+ definition["params"] = params
- for i, out in enumerate([out for out in alg.destinationParameterDefinitions() if not out.flags() & QgsProcessingParameterDefinition.Flag.FlagHidden]):
+ for i, out in enumerate(
+ [
+ out
+ for out in alg.destinationParameterDefinitions()
+ if not out.flags() & QgsProcessingParameterDefinition.Flag.FlagHidden
+ ]
+ ):
if not out.name() in parameters:
continue
@@ -258,56 +276,65 @@ def createTest(text):
if isinstance(out, QgsProcessingParameterRasterDestination):
if token is None:
- QMessageBox.warning(None,
- tr('Error'),
- tr('Seems some outputs are temporary '
- 'files. To create test you need to '
- 'redirect all algorithm outputs to '
- 'files'))
+ QMessageBox.warning(
+ None,
+ tr("Error"),
+ tr(
+ "Seems some outputs are temporary "
+ "files. To create test you need to "
+ "redirect all algorithm outputs to "
+ "files"
+ ),
+ )
return
try:
dataset = gdal.Open(token, GA_ReadOnly)
except Exception:
- QMessageBox.warning(None,
- tr('Error'),
- tr('Seems some outputs are temporary '
- 'files. To create test you need to '
- 'redirect all algorithm outputs to '
- 'files'))
+ QMessageBox.warning(
+ None,
+ tr("Error"),
+ tr(
+ "Seems some outputs are temporary "
+ "files. To create test you need to "
+ "redirect all algorithm outputs to "
+ "files"
+ ),
+ )
return
dataArray = nan_to_num(dataset.ReadAsArray(0))
strhash = hashlib.sha224(dataArray.data).hexdigest()
- results[out.name()] = {
- 'type': 'rasterhash',
- 'hash': strhash
- }
- elif isinstance(out, (QgsProcessingParameterVectorDestination, QgsProcessingParameterFeatureSink)):
+ results[out.name()] = {"type": "rasterhash", "hash": strhash}
+ elif isinstance(
+ out,
+ (
+ QgsProcessingParameterVectorDestination,
+ QgsProcessingParameterFeatureSink,
+ ),
+ ):
schema, filepath = extractSchemaPath(token)
- results[out.name()] = {
- 'type': 'vector',
- 'name': filepath
- }
+ results[out.name()] = {"type": "vector", "name": filepath}
if not schema:
- results[out.name()]['location'] = '[The expected result data is not in the testdata directory. Please write it to processing/tests/testdata/expected. Prefer gml files.]'
+ results[out.name()][
+ "location"
+ ] = "[The expected result data is not in the testdata directory. Please write it to processing/tests/testdata/expected. Prefer gml files.]"
elif isinstance(out, QgsProcessingParameterFileDestination):
schema, filepath = extractSchemaPath(token)
- results[out.name()] = {
- 'type': 'file',
- 'name': filepath
- }
+ results[out.name()] = {"type": "file", "name": filepath}
if not schema:
- results[out.name()]['location'] = '[The expected result file is not in the testdata directory. Please redirect the output to processing/tests/testdata/expected.]'
+ results[out.name()][
+ "location"
+ ] = "[The expected result file is not in the testdata directory. Please redirect the output to processing/tests/testdata/expected.]"
- definition['results'] = results
+ definition["results"] = results
dlg = ShowTestDialog(yaml.dump([definition], default_flow_style=False))
dlg.exec()
def tr(string):
- return QCoreApplication.translate('TestTools', string)
+ return QCoreApplication.translate("TestTools", string)
class ShowTestDialog(QDialog):
@@ -316,13 +343,13 @@ def __init__(self, s):
QDialog.__init__(self)
self.setModal(True)
self.resize(600, 400)
- self.setWindowTitle(self.tr('Unit Test'))
+ self.setWindowTitle(self.tr("Unit Test"))
layout = QVBoxLayout()
self.text = QTextEdit()
self.text.setFontFamily("monospace")
self.text.setEnabled(True)
# Add two spaces in front of each text for faster copy/paste
- self.text.setText(' {}'.format(s.replace('\n', '\n ')))
+ self.text.setText(" {}".format(s.replace("\n", "\n ")))
layout.addWidget(self.text)
self.setLayout(layout)
QMetaObject.connectSlotsByName(self)
diff --git a/python/plugins/processing/gui/ToolboxAction.py b/python/plugins/processing/gui/ToolboxAction.py
index bb47e1ec181e..ea8f7ea6d065 100644
--- a/python/plugins/processing/gui/ToolboxAction.py
+++ b/python/plugins/processing/gui/ToolboxAction.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'August 2012'
-__copyright__ = '(C) 2012, Victor Olaya'
+__author__ = "Victor Olaya"
+__date__ = "August 2012"
+__copyright__ = "(C) 2012, Victor Olaya"
from qgis.PyQt.QtCore import QCoreApplication
@@ -32,7 +32,7 @@ def setData(self, toolbox):
def getIcon(self):
return QgsApplication.getThemeIcon("/processingAlgorithm.svg")
- def tr(self, string, context=''):
- if context == '':
+ def tr(self, string, context=""):
+ if context == "":
context = self.__class__.__name__
return QCoreApplication.translate(context, string)
diff --git a/python/plugins/processing/gui/__init__.py b/python/plugins/processing/gui/__init__.py
index 76b7538a24a5..be57526b8c09 100644
--- a/python/plugins/processing/gui/__init__.py
+++ b/python/plugins/processing/gui/__init__.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'August 2013'
-__copyright__ = '(C) 2013, Victor Olaya'
+__author__ = "Victor Olaya"
+__date__ = "August 2013"
+__copyright__ = "(C) 2013, Victor Olaya"
from qgis.PyQt import uic
import logging
diff --git a/python/plugins/processing/gui/menus.py b/python/plugins/processing/gui/menus.py
index 422fae1cbc6b..9f5cebc55381 100644
--- a/python/plugins/processing/gui/menus.py
+++ b/python/plugins/processing/gui/menus.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'February 2016'
-__copyright__ = '(C) 2016, Victor Olaya'
+__author__ = "Victor Olaya"
+__date__ = "February 2016"
+__copyright__ = "(C) 2016, Victor Olaya"
import os
from qgis.PyQt.QtCore import QCoreApplication
@@ -28,7 +28,12 @@
from processing.gui.MessageDialog import MessageDialog
from processing.gui.AlgorithmDialog import AlgorithmDialog
from qgis.utils import iface
-from qgis.core import QgsApplication, QgsMessageLog, QgsStringUtils, QgsProcessingAlgorithm
+from qgis.core import (
+ QgsApplication,
+ QgsMessageLog,
+ QgsStringUtils,
+ QgsProcessingAlgorithm,
+)
from qgis.gui import QgsGui
from processing.gui.MessageBarProgress import MessageBarProgress
from processing.gui.AlgorithmExecutor import execute
@@ -37,7 +42,7 @@
from processing.tools import dataobjects
algorithmsToolbar = None
-menusSettingsGroup = 'Menus'
+menusSettingsGroup = "Menus"
defaultMenuEntries = {}
toolBarButtons = []
toolButton = None
@@ -47,97 +52,137 @@
def initMenusAndToolbars():
global defaultMenuEntries, toolBarButtons, toolButton, toolButtonAction
vectorMenu = iface.vectorMenu().title()
- analysisToolsMenu = vectorMenu + "/" + Processing.tr('&Analysis Tools')
- defaultMenuEntries.update({'qgis:distancematrix': analysisToolsMenu,
- 'native:sumlinelengths': analysisToolsMenu,
- 'native:countpointsinpolygon': analysisToolsMenu,
- 'qgis:listuniquevalues': analysisToolsMenu,
- 'native:basicstatisticsforfields': analysisToolsMenu,
- 'native:nearestneighbouranalysis': analysisToolsMenu,
- 'native:meancoordinates': analysisToolsMenu,
- 'native:lineintersections': analysisToolsMenu})
- researchToolsMenu = vectorMenu + "/" + Processing.tr('&Research Tools')
- defaultMenuEntries.update({'native:creategrid': researchToolsMenu,
- 'qgis:randomselection': researchToolsMenu,
- 'qgis:randomselectionwithinsubsets': researchToolsMenu,
- 'native:randompointsinextent': researchToolsMenu,
- 'qgis:randompointsinlayerbounds': researchToolsMenu,
- 'native:randompointsinpolygons': researchToolsMenu,
- 'qgis:randompointsinsidepolygons': researchToolsMenu,
- 'native:randompointsonlines': researchToolsMenu,
- 'qgis:regularpoints': researchToolsMenu,
- 'native:selectbylocation': researchToolsMenu,
- 'native:selectwithindistance': researchToolsMenu,
- 'native:polygonfromlayerextent': researchToolsMenu})
- geoprocessingToolsMenu = vectorMenu + "/" + Processing.tr('&Geoprocessing Tools')
- defaultMenuEntries.update({'native:buffer': geoprocessingToolsMenu,
- 'native:convexhull': geoprocessingToolsMenu,
- 'native:intersection': geoprocessingToolsMenu,
- 'native:union': geoprocessingToolsMenu,
- 'native:symmetricaldifference': geoprocessingToolsMenu,
- 'native:clip': geoprocessingToolsMenu,
- 'native:difference': geoprocessingToolsMenu,
- 'native:dissolve': geoprocessingToolsMenu,
- 'qgis:eliminateselectedpolygons': geoprocessingToolsMenu})
- geometryToolsMenu = vectorMenu + "/" + Processing.tr('G&eometry Tools')
- defaultMenuEntries.update({'qgis:checkvalidity': geometryToolsMenu,
- 'qgis:exportaddgeometrycolumns': geometryToolsMenu,
- 'native:centroids': geometryToolsMenu,
- 'native:delaunaytriangulation': geometryToolsMenu,
- 'native:voronoipolygons': geometryToolsMenu,
- 'native:simplifygeometries': geometryToolsMenu,
- 'native:densifygeometries': geometryToolsMenu,
- 'native:multiparttosingleparts': geometryToolsMenu,
- 'native:collect': geometryToolsMenu,
- 'native:polygonstolines': geometryToolsMenu,
- 'qgis:linestopolygons': geometryToolsMenu,
- 'native:extractvertices': geometryToolsMenu})
- managementToolsMenu = vectorMenu + "/" + Processing.tr('&Data Management Tools')
- defaultMenuEntries.update({'native:reprojectlayer': managementToolsMenu,
- 'native:joinattributesbylocation': managementToolsMenu,
- 'native:splitvectorlayer': managementToolsMenu,
- 'native:mergevectorlayers': managementToolsMenu,
- 'native:createspatialindex': managementToolsMenu})
+ analysisToolsMenu = vectorMenu + "/" + Processing.tr("&Analysis Tools")
+ defaultMenuEntries.update(
+ {
+ "qgis:distancematrix": analysisToolsMenu,
+ "native:sumlinelengths": analysisToolsMenu,
+ "native:countpointsinpolygon": analysisToolsMenu,
+ "qgis:listuniquevalues": analysisToolsMenu,
+ "native:basicstatisticsforfields": analysisToolsMenu,
+ "native:nearestneighbouranalysis": analysisToolsMenu,
+ "native:meancoordinates": analysisToolsMenu,
+ "native:lineintersections": analysisToolsMenu,
+ }
+ )
+ researchToolsMenu = vectorMenu + "/" + Processing.tr("&Research Tools")
+ defaultMenuEntries.update(
+ {
+ "native:creategrid": researchToolsMenu,
+ "qgis:randomselection": researchToolsMenu,
+ "qgis:randomselectionwithinsubsets": researchToolsMenu,
+ "native:randompointsinextent": researchToolsMenu,
+ "qgis:randompointsinlayerbounds": researchToolsMenu,
+ "native:randompointsinpolygons": researchToolsMenu,
+ "qgis:randompointsinsidepolygons": researchToolsMenu,
+ "native:randompointsonlines": researchToolsMenu,
+ "qgis:regularpoints": researchToolsMenu,
+ "native:selectbylocation": researchToolsMenu,
+ "native:selectwithindistance": researchToolsMenu,
+ "native:polygonfromlayerextent": researchToolsMenu,
+ }
+ )
+ geoprocessingToolsMenu = vectorMenu + "/" + Processing.tr("&Geoprocessing Tools")
+ defaultMenuEntries.update(
+ {
+ "native:buffer": geoprocessingToolsMenu,
+ "native:convexhull": geoprocessingToolsMenu,
+ "native:intersection": geoprocessingToolsMenu,
+ "native:union": geoprocessingToolsMenu,
+ "native:symmetricaldifference": geoprocessingToolsMenu,
+ "native:clip": geoprocessingToolsMenu,
+ "native:difference": geoprocessingToolsMenu,
+ "native:dissolve": geoprocessingToolsMenu,
+ "qgis:eliminateselectedpolygons": geoprocessingToolsMenu,
+ }
+ )
+ geometryToolsMenu = vectorMenu + "/" + Processing.tr("G&eometry Tools")
+ defaultMenuEntries.update(
+ {
+ "qgis:checkvalidity": geometryToolsMenu,
+ "qgis:exportaddgeometrycolumns": geometryToolsMenu,
+ "native:centroids": geometryToolsMenu,
+ "native:delaunaytriangulation": geometryToolsMenu,
+ "native:voronoipolygons": geometryToolsMenu,
+ "native:simplifygeometries": geometryToolsMenu,
+ "native:densifygeometries": geometryToolsMenu,
+ "native:multiparttosingleparts": geometryToolsMenu,
+ "native:collect": geometryToolsMenu,
+ "native:polygonstolines": geometryToolsMenu,
+ "qgis:linestopolygons": geometryToolsMenu,
+ "native:extractvertices": geometryToolsMenu,
+ }
+ )
+ managementToolsMenu = vectorMenu + "/" + Processing.tr("&Data Management Tools")
+ defaultMenuEntries.update(
+ {
+ "native:reprojectlayer": managementToolsMenu,
+ "native:joinattributesbylocation": managementToolsMenu,
+ "native:splitvectorlayer": managementToolsMenu,
+ "native:mergevectorlayers": managementToolsMenu,
+ "native:createspatialindex": managementToolsMenu,
+ }
+ )
rasterMenu = iface.rasterMenu().title()
- defaultMenuEntries.update({'native:alignrasters': rasterMenu})
- projectionsMenu = rasterMenu + "/" + Processing.tr('Projections')
- defaultMenuEntries.update({'gdal:warpreproject': projectionsMenu,
- 'gdal:extractprojection': projectionsMenu,
- 'gdal:assignprojection': projectionsMenu})
- conversionMenu = rasterMenu + "/" + Processing.tr('Conversion')
- defaultMenuEntries.update({'gdal:rasterize': conversionMenu,
- 'gdal:polygonize': conversionMenu,
- 'gdal:translate': conversionMenu,
- 'gdal:rgbtopct': conversionMenu,
- 'gdal:pcttorgb': conversionMenu})
- extractionMenu = rasterMenu + "/" + Processing.tr('Extraction')
- defaultMenuEntries.update({'gdal:contour': extractionMenu,
- 'gdal:cliprasterbyextent': extractionMenu,
- 'gdal:cliprasterbymasklayer': extractionMenu})
- analysisMenu = rasterMenu + "/" + Processing.tr('Analysis')
- defaultMenuEntries.update({'gdal:sieve': analysisMenu,
- 'gdal:nearblack': analysisMenu,
- 'gdal:fillnodata': analysisMenu,
- 'gdal:proximity': analysisMenu,
- 'gdal:griddatametrics': analysisMenu,
- 'gdal:gridaverage': analysisMenu,
- 'gdal:gridinversedistance': analysisMenu,
- 'gdal:gridnearestneighbor': analysisMenu,
- 'gdal:aspect': analysisMenu,
- 'gdal:hillshade': analysisMenu,
- 'gdal:roughness': analysisMenu,
- 'gdal:slope': analysisMenu,
- 'gdal:tpitopographicpositionindex': analysisMenu,
- 'gdal:triterrainruggednessindex': analysisMenu})
- miscMenu = rasterMenu + "/" + Processing.tr('Miscellaneous')
- defaultMenuEntries.update({'gdal:buildvirtualraster': miscMenu,
- 'gdal:merge': miscMenu,
- 'gdal:gdalinfo': miscMenu,
- 'gdal:overviews': miscMenu,
- 'gdal:tileindex': miscMenu})
-
- toolBarButtons = ['native:selectbylocation', 'native:selectwithindistance']
+ defaultMenuEntries.update({"native:alignrasters": rasterMenu})
+ projectionsMenu = rasterMenu + "/" + Processing.tr("Projections")
+ defaultMenuEntries.update(
+ {
+ "gdal:warpreproject": projectionsMenu,
+ "gdal:extractprojection": projectionsMenu,
+ "gdal:assignprojection": projectionsMenu,
+ }
+ )
+ conversionMenu = rasterMenu + "/" + Processing.tr("Conversion")
+ defaultMenuEntries.update(
+ {
+ "gdal:rasterize": conversionMenu,
+ "gdal:polygonize": conversionMenu,
+ "gdal:translate": conversionMenu,
+ "gdal:rgbtopct": conversionMenu,
+ "gdal:pcttorgb": conversionMenu,
+ }
+ )
+ extractionMenu = rasterMenu + "/" + Processing.tr("Extraction")
+ defaultMenuEntries.update(
+ {
+ "gdal:contour": extractionMenu,
+ "gdal:cliprasterbyextent": extractionMenu,
+ "gdal:cliprasterbymasklayer": extractionMenu,
+ }
+ )
+ analysisMenu = rasterMenu + "/" + Processing.tr("Analysis")
+ defaultMenuEntries.update(
+ {
+ "gdal:sieve": analysisMenu,
+ "gdal:nearblack": analysisMenu,
+ "gdal:fillnodata": analysisMenu,
+ "gdal:proximity": analysisMenu,
+ "gdal:griddatametrics": analysisMenu,
+ "gdal:gridaverage": analysisMenu,
+ "gdal:gridinversedistance": analysisMenu,
+ "gdal:gridnearestneighbor": analysisMenu,
+ "gdal:aspect": analysisMenu,
+ "gdal:hillshade": analysisMenu,
+ "gdal:roughness": analysisMenu,
+ "gdal:slope": analysisMenu,
+ "gdal:tpitopographicpositionindex": analysisMenu,
+ "gdal:triterrainruggednessindex": analysisMenu,
+ }
+ )
+ miscMenu = rasterMenu + "/" + Processing.tr("Miscellaneous")
+ defaultMenuEntries.update(
+ {
+ "gdal:buildvirtualraster": miscMenu,
+ "gdal:merge": miscMenu,
+ "gdal:gdalinfo": miscMenu,
+ "gdal:overviews": miscMenu,
+ "gdal:tileindex": miscMenu,
+ }
+ )
+
+ toolBarButtons = ["native:selectbylocation", "native:selectwithindistance"]
toolbar = iface.selectionToolBar()
toolButton = QToolButton(toolbar)
@@ -153,20 +198,27 @@ def initializeMenus():
for m in defaultMenuEntries.keys():
alg = QgsApplication.processingRegistry().algorithmById(m)
if alg is None or alg.id() != m:
- QgsMessageLog.logMessage(Processing.tr('Invalid algorithm ID for menu: {}').format(m),
- Processing.tr('Processing'))
+ QgsMessageLog.logMessage(
+ Processing.tr("Invalid algorithm ID for menu: {}").format(m),
+ Processing.tr("Processing"),
+ )
for provider in QgsApplication.processingRegistry().providers():
for alg in provider.algorithms():
d = defaultMenuEntries.get(alg.id(), "")
- setting = Setting(menusSettingsGroup, "MENU_" + alg.id(),
- "Menu path", d)
+ setting = Setting(menusSettingsGroup, "MENU_" + alg.id(), "Menu path", d)
ProcessingConfig.addSetting(setting)
- setting = Setting(menusSettingsGroup, "BUTTON_" + alg.id(),
- "Add button", False)
+ setting = Setting(
+ menusSettingsGroup, "BUTTON_" + alg.id(), "Add button", False
+ )
ProcessingConfig.addSetting(setting)
- setting = Setting(menusSettingsGroup, "ICON_" + alg.id(),
- "Icon", "", valuetype=Setting.FILE)
+ setting = Setting(
+ menusSettingsGroup,
+ "ICON_" + alg.id(),
+ "Icon",
+ "",
+ valuetype=Setting.FILE,
+ )
ProcessingConfig.addSetting(setting)
ProcessingConfig.readSettings()
@@ -190,7 +242,9 @@ def createMenus():
if menuPath:
paths = menuPath.split("/")
subMenuName = paths[-1] if len(paths) > 1 else ""
- addAlgorithmEntry(alg, paths[0], subMenuName, addButton=addButton, icon=icon)
+ addAlgorithmEntry(
+ alg, paths[0], subMenuName, addButton=addButton, icon=icon
+ )
def removeMenus():
@@ -201,14 +255,19 @@ def removeMenus():
removeAlgorithmEntry(alg, paths[0], paths[-1])
-def addAlgorithmEntry(alg, menuName, submenuName, actionText=None, icon=None, addButton=False):
+def addAlgorithmEntry(
+ alg, menuName, submenuName, actionText=None, icon=None, addButton=False
+):
if actionText is None:
if (QgsGui.higFlags() & QgsGui.HigFlag.HigMenuTextIsTitleCase) and not (
- alg.flags() & QgsProcessingAlgorithm.Flag.FlagDisplayNameIsLiteral):
- alg_title = QgsStringUtils.capitalize(alg.displayName(), QgsStringUtils.Capitalization.TitleCase)
+ alg.flags() & QgsProcessingAlgorithm.Flag.FlagDisplayNameIsLiteral
+ ):
+ alg_title = QgsStringUtils.capitalize(
+ alg.displayName(), QgsStringUtils.Capitalization.TitleCase
+ )
else:
alg_title = alg.displayName()
- actionText = alg_title + QCoreApplication.translate('Processing', '…')
+ actionText = alg_title + QCoreApplication.translate("Processing", "…")
action = QAction(icon or alg.icon(), actionText, iface.mainWindow())
alg_id = alg.id()
action.setData(alg_id)
@@ -226,9 +285,15 @@ def addAlgorithmEntry(alg, menuName, submenuName, actionText=None, icon=None, ad
if addButton:
global algorithmsToolbar
if algorithmsToolbar is None:
- algorithmsToolbar = iface.addToolBar(QCoreApplication.translate('MainWindow', 'Processing Algorithms'))
+ algorithmsToolbar = iface.addToolBar(
+ QCoreApplication.translate("MainWindow", "Processing Algorithms")
+ )
algorithmsToolbar.setObjectName("ProcessingAlgorithms")
- algorithmsToolbar.setToolTip(QCoreApplication.translate('MainWindow', 'Processing Algorithms Toolbar'))
+ algorithmsToolbar.setToolTip(
+ QCoreApplication.translate(
+ "MainWindow", "Processing Algorithms Toolbar"
+ )
+ )
algorithmsToolbar.addAction(action)
@@ -255,20 +320,24 @@ def _executeAlgorithm(alg_id):
alg = QgsApplication.processingRegistry().createAlgorithmById(alg_id)
if alg is None:
dlg = MessageDialog()
- dlg.setTitle(Processing.tr('Missing Algorithm'))
+ dlg.setTitle(Processing.tr("Missing Algorithm"))
dlg.setMessage(
- Processing.tr('The algorithm "{}" is no longer available. (Perhaps a plugin was uninstalled?)').format(
- alg_id))
+ Processing.tr(
+ 'The algorithm "{}" is no longer available. (Perhaps a plugin was uninstalled?)'
+ ).format(alg_id)
+ )
dlg.exec()
return
ok, message = alg.canExecute()
if not ok:
dlg = MessageDialog()
- dlg.setTitle(Processing.tr('Missing Dependency'))
+ dlg.setTitle(Processing.tr("Missing Dependency"))
dlg.setMessage(
- Processing.tr('Missing dependency. This algorithm cannot '
- 'be run :-( \n{0}').format(message))
+ Processing.tr(
+ "Missing dependency. This algorithm cannot " "be run :-( \n{0}"
+ ).format(message)
+ )
dlg.exec()
return
@@ -306,7 +375,8 @@ def getMenu(name, parent):
def findAction(actions, alg):
for action in actions:
if (isinstance(alg, str) and action.data() == alg) or (
- isinstance(alg, QgsProcessingAlgorithm) and action.data() == alg.id()):
+ isinstance(alg, QgsProcessingAlgorithm) and action.data() == alg.id()
+ ):
return action
return None
@@ -318,8 +388,11 @@ def addToolBarButton(index, algId, icon=None, tooltip=None):
if tooltip is None:
if (QgsGui.higFlags() & QgsGui.HigFlag.HigMenuTextIsTitleCase) and not (
- alg.flags() & QgsProcessingAlgorithm.Flag.FlagDisplayNameIsLiteral):
- tooltip = QgsStringUtils.capitalize(alg.displayName(), QgsStringUtils.Capitalization.TitleCase)
+ alg.flags() & QgsProcessingAlgorithm.Flag.FlagDisplayNameIsLiteral
+ ):
+ tooltip = QgsStringUtils.capitalize(
+ alg.displayName(), QgsStringUtils.Capitalization.TitleCase
+ )
else:
tooltip = alg.displayName()
diff --git a/python/plugins/processing/gui/wrappers.py b/python/plugins/processing/gui/wrappers.py
index b445a4f9b5a3..c02622ad143e 100644
--- a/python/plugins/processing/gui/wrappers.py
+++ b/python/plugins/processing/gui/wrappers.py
@@ -16,9 +16,9 @@
***************************************************************************
"""
-__author__ = 'Arnaud Morvan'
-__date__ = 'May 2016'
-__copyright__ = '(C) 2016, Arnaud Morvan'
+__author__ = "Arnaud Morvan"
+__date__ = "May 2016"
+__copyright__ = "(C) 2016, Arnaud Morvan"
import os
import re
@@ -67,7 +67,8 @@
QgsProcessingOutputNumber,
QgsProcessingModelChildParameterSource,
NULL,
- Qgis)
+ Qgis,
+)
from qgis.PyQt.QtWidgets import (
QCheckBox,
@@ -80,7 +81,7 @@
QPlainTextEdit,
QToolButton,
QWidget,
- QSizePolicy
+ QSizePolicy,
)
from qgis.PyQt.QtGui import QIcon
from qgis.gui import (
@@ -95,7 +96,7 @@
QgsRasterBandComboBox,
QgsProcessingGui,
QgsAbstractProcessingParameterWidgetWrapper,
- QgsProcessingMapLayerComboBox
+ QgsProcessingMapLayerComboBox,
)
from qgis.PyQt.QtCore import QVariant, Qt
from qgis.utils import iface
@@ -103,7 +104,11 @@
from processing.core.ProcessingConfig import ProcessingConfig
from processing.modeler.MultilineTextPanel import MultilineTextPanel
-from processing.gui.NumberInputPanel import NumberInputPanel, ModelerNumberInputPanel, DistanceInputPanel
+from processing.gui.NumberInputPanel import (
+ NumberInputPanel,
+ ModelerNumberInputPanel,
+ DistanceInputPanel,
+)
from processing.gui.RangePanel import RangePanel
from processing.gui.PointSelectionPanel import PointSelectionPanel
from processing.gui.FileSelectionPanel import FileSelectionPanel
@@ -126,24 +131,31 @@ class InvalidParameterValue(Exception):
pass
-dialogTypes = {"AlgorithmDialog": DIALOG_STANDARD,
- "ModelerParametersDialog": DIALOG_MODELER,
- "BatchAlgorithmDialog": DIALOG_BATCH}
+dialogTypes = {
+ "AlgorithmDialog": DIALOG_STANDARD,
+ "ModelerParametersDialog": DIALOG_MODELER,
+ "BatchAlgorithmDialog": DIALOG_BATCH,
+}
def getExtendedLayerName(layer):
authid = layer.crs().authid()
- if ProcessingConfig.getSetting(ProcessingConfig.SHOW_CRS_DEF) and authid is not None:
- return f'{layer.name()} [{authid}]'
+ if (
+ ProcessingConfig.getSetting(ProcessingConfig.SHOW_CRS_DEF)
+ and authid is not None
+ ):
+ return f"{layer.name()} [{authid}]"
else:
return layer.name()
class WidgetWrapper(QgsAbstractProcessingParameterWidgetWrapper):
- NOT_SET_OPTION = '~~~~!!!!NOT SET!!!!~~~~~~~'
+ NOT_SET_OPTION = "~~~~!!!!NOT SET!!!!~~~~~~~"
def __init__(self, param, dialog, row=0, col=0, **kwargs):
- self.dialogType = dialogTypes.get(dialog.__class__.__name__, QgsProcessingGui.WidgetType.Standard)
+ self.dialogType = dialogTypes.get(
+ dialog.__class__.__name__, QgsProcessingGui.WidgetType.Standard
+ )
super().__init__(param, self.dialogType)
self.dialog = dialog
@@ -179,11 +191,14 @@ def createLabel(self):
return None
desc = self.parameterDefinition().description()
if isinstance(self.parameterDefinition(), QgsProcessingParameterExtent):
- desc += self.tr(' (xmin, xmax, ymin, ymax)')
+ desc += self.tr(" (xmin, xmax, ymin, ymax)")
if isinstance(self.parameterDefinition(), QgsProcessingParameterPoint):
- desc += self.tr(' (x, y)')
- if self.parameterDefinition().flags() & QgsProcessingParameterDefinition.Flag.FlagOptional:
- desc += self.tr(' [optional]')
+ desc += self.tr(" (x, y)")
+ if (
+ self.parameterDefinition().flags()
+ & QgsProcessingParameterDefinition.Flag.FlagOptional
+ ):
+ desc += self.tr(" [optional]")
label = QLabel(desc)
label.setToolTip(self.parameterDefinition().name())
@@ -225,24 +240,29 @@ def setComboValue(self, value, combobox=None):
def refresh(self):
pass
- def getFileName(self, initial_value=''):
+ def getFileName(self, initial_value=""):
"""Shows a file open dialog"""
settings = QgsSettings()
if os.path.isdir(initial_value):
path = initial_value
elif os.path.isdir(os.path.dirname(initial_value)):
path = os.path.dirname(initial_value)
- elif settings.contains('/Processing/LastInputPath'):
- path = str(settings.value('/Processing/LastInputPath'))
+ elif settings.contains("/Processing/LastInputPath"):
+ path = str(settings.value("/Processing/LastInputPath"))
else:
- path = ''
+ path = ""
# TODO: should use selectedFilter argument for default file format
- filename, selected_filter = QFileDialog.getOpenFileName(self.widget, self.tr('Select File'),
- path, self.parameterDefinition().createFileFilter())
+ filename, selected_filter = QFileDialog.getOpenFileName(
+ self.widget,
+ self.tr("Select File"),
+ path,
+ self.parameterDefinition().createFileFilter(),
+ )
if filename:
- settings.setValue('/Processing/LastInputPath',
- os.path.dirname(str(filename)))
+ settings.setValue(
+ "/Processing/LastInputPath", os.path.dirname(str(filename))
+ )
return filename, selected_filter
@@ -268,7 +288,11 @@ def __init__(self, *args, **kwargs):
"""
from warnings import warn
- warn("BooleanWidgetWrapper is deprecated and will be removed in QGIS 4.0", DeprecationWarning)
+
+ warn(
+ "BooleanWidgetWrapper is deprecated and will be removed in QGIS 4.0",
+ DeprecationWarning,
+ )
def createLabel(self):
if self.dialogType == DIALOG_STANDARD:
@@ -281,14 +305,16 @@ def createWidget(self):
return QCheckBox()
elif self.dialogType == DIALOG_BATCH:
widget = QComboBox()
- widget.addItem(self.tr('Yes'), True)
- widget.addItem(self.tr('No'), False)
+ widget.addItem(self.tr("Yes"), True)
+ widget.addItem(self.tr("No"), False)
return widget
else:
widget = QComboBox()
- widget.addItem(self.tr('Yes'), True)
- widget.addItem(self.tr('No'), False)
- bools = self.dialog.getAvailableValuesOfType(QgsProcessingParameterBoolean, None)
+ widget.addItem(self.tr("Yes"), True)
+ widget.addItem(self.tr("No"), False)
+ bools = self.dialog.getAvailableValuesOfType(
+ QgsProcessingParameterBoolean, None
+ )
for b in bools:
widget.addItem(self.dialog.resolveValueDescription(b), b)
return widget
@@ -318,7 +344,11 @@ def __init__(self, *args, **kwargs):
"""
from warnings import warn
- warn("CrsWidgetWrapper is deprecated and will be removed in QGIS 4.0", DeprecationWarning)
+
+ warn(
+ "CrsWidgetWrapper is deprecated and will be removed in QGIS 4.0",
+ DeprecationWarning,
+ )
def createWidget(self):
if self.dialogType == DIALOG_MODELER:
@@ -337,34 +367,54 @@ def createWidget(self):
widget.setLayout(layout)
self.combo.setEditable(True)
- crss = self.dialog.getAvailableValuesOfType((QgsProcessingParameterCrs, QgsProcessingParameterString), QgsProcessingOutputString)
+ crss = self.dialog.getAvailableValuesOfType(
+ (QgsProcessingParameterCrs, QgsProcessingParameterString),
+ QgsProcessingOutputString,
+ )
for crs in crss:
self.combo.addItem(self.dialog.resolveValueDescription(crs), crs)
- layers = self.dialog.getAvailableValuesOfType([QgsProcessingParameterRasterLayer,
- QgsProcessingParameterVectorLayer,
- QgsProcessingParameterMeshLayer,
- QgsProcessingParameterFeatureSource],
- [QgsProcessingOutputVectorLayer,
- QgsProcessingOutputRasterLayer,
- QgsProcessingOutputMapLayer])
+ layers = self.dialog.getAvailableValuesOfType(
+ [
+ QgsProcessingParameterRasterLayer,
+ QgsProcessingParameterVectorLayer,
+ QgsProcessingParameterMeshLayer,
+ QgsProcessingParameterFeatureSource,
+ ],
+ [
+ QgsProcessingOutputVectorLayer,
+ QgsProcessingOutputRasterLayer,
+ QgsProcessingOutputMapLayer,
+ ],
+ )
for l in layers:
- self.combo.addItem("Crs of layer " + self.dialog.resolveValueDescription(l), l)
+ self.combo.addItem(
+ "Crs of layer " + self.dialog.resolveValueDescription(l), l
+ )
if self.parameterDefinition().defaultValue():
self.combo.setEditText(self.parameterDefinition().defaultValue())
return widget
else:
widget = QgsProjectionSelectionWidget()
- if self.parameterDefinition().flags() & QgsProcessingParameterDefinition.Flag.FlagOptional:
- widget.setOptionVisible(QgsProjectionSelectionWidget.CrsOption.CrsNotSet, True)
+ if (
+ self.parameterDefinition().flags()
+ & QgsProcessingParameterDefinition.Flag.FlagOptional
+ ):
+ widget.setOptionVisible(
+ QgsProjectionSelectionWidget.CrsOption.CrsNotSet, True
+ )
if self.parameterDefinition().defaultValue():
- if self.parameterDefinition().defaultValue() == 'ProjectCrs':
+ if self.parameterDefinition().defaultValue() == "ProjectCrs":
crs = QgsProject.instance().crs()
else:
- crs = QgsCoordinateReferenceSystem(self.parameterDefinition().defaultValue())
+ crs = QgsCoordinateReferenceSystem(
+ self.parameterDefinition().defaultValue()
+ )
widget.setCrs(crs)
else:
- widget.setOptionVisible(QgsProjectionSelectionWidget.CrsOption.CrsNotSet, True)
+ widget.setOptionVisible(
+ QgsProjectionSelectionWidget.CrsOption.CrsNotSet, True
+ )
widget.crsChanged.connect(lambda: self.widgetValueHasChanged.emit(self))
return widget
@@ -384,7 +434,7 @@ def setValue(self, value):
if self.dialogType == DIALOG_MODELER:
self.setComboValue(value, self.combo)
- elif value == 'ProjectCrs':
+ elif value == "ProjectCrs":
self.widget.setCrs(QgsProject.instance().crs())
else:
self.widget.setCrs(QgsCoordinateReferenceSystem(value))
@@ -411,7 +461,11 @@ def __init__(self, *args, **kwargs):
"""
from warnings import warn
- warn("ExtentWidgetWrapper is deprecated and will be removed in QGIS 4.0", DeprecationWarning)
+
+ warn(
+ "ExtentWidgetWrapper is deprecated and will be removed in QGIS 4.0",
+ DeprecationWarning,
+ )
def createWidget(self):
if self.dialogType in (DIALOG_STANDARD, DIALOG_BATCH):
@@ -421,16 +475,27 @@ def createWidget(self):
else:
widget = QComboBox()
widget.setEditable(True)
- extents = self.dialog.getAvailableValuesOfType(QgsProcessingParameterExtent, (QgsProcessingOutputString))
- if self.parameterDefinition().flags() & QgsProcessingParameterDefinition.Flag.FlagOptional:
+ extents = self.dialog.getAvailableValuesOfType(
+ QgsProcessingParameterExtent, (QgsProcessingOutputString)
+ )
+ if (
+ self.parameterDefinition().flags()
+ & QgsProcessingParameterDefinition.Flag.FlagOptional
+ ):
widget.addItem(self.USE_MIN_COVERING_EXTENT, None)
- layers = self.dialog.getAvailableValuesOfType([QgsProcessingParameterFeatureSource,
- QgsProcessingParameterRasterLayer,
- QgsProcessingParameterVectorLayer,
- QgsProcessingParameterMeshLayer],
- [QgsProcessingOutputRasterLayer,
- QgsProcessingOutputVectorLayer,
- QgsProcessingOutputMapLayer])
+ layers = self.dialog.getAvailableValuesOfType(
+ [
+ QgsProcessingParameterFeatureSource,
+ QgsProcessingParameterRasterLayer,
+ QgsProcessingParameterVectorLayer,
+ QgsProcessingParameterMeshLayer,
+ ],
+ [
+ QgsProcessingOutputRasterLayer,
+ QgsProcessingOutputVectorLayer,
+ QgsProcessingOutputMapLayer,
+ ],
+ )
for ex in extents:
widget.addItem(self.dialog.resolveValueDescription(ex), ex)
for l in layers:
@@ -457,14 +522,17 @@ def value(self):
s = str(self.widget.currentText()).strip()
if s:
try:
- tokens = s.split(',')
+ tokens = s.split(",")
if len(tokens) != 4:
raise InvalidParameterValue()
for token in tokens:
float(token)
except:
raise InvalidParameterValue()
- elif self.parameterDefinition().flags() & QgsProcessingParameterDefinition.Flag.FlagOptional:
+ elif (
+ self.parameterDefinition().flags()
+ & QgsProcessingParameterDefinition.Flag.FlagOptional
+ ):
s = None
else:
raise InvalidParameterValue()
@@ -483,15 +551,24 @@ def __init__(self, *args, **kwargs):
"""
from warnings import warn
- warn("PointWidgetWrapper is deprecated and will be removed in QGIS 4.0", DeprecationWarning)
+
+ warn(
+ "PointWidgetWrapper is deprecated and will be removed in QGIS 4.0",
+ DeprecationWarning,
+ )
def createWidget(self):
if self.dialogType in (DIALOG_STANDARD, DIALOG_BATCH):
- return PointSelectionPanel(self.dialog, self.parameterDefinition().defaultValue())
+ return PointSelectionPanel(
+ self.dialog, self.parameterDefinition().defaultValue()
+ )
else:
item = QComboBox()
item.setEditable(True)
- points = self.dialog.getAvailableValuesOfType((QgsProcessingParameterPoint, QgsProcessingParameterString), (QgsProcessingOutputString))
+ points = self.dialog.getAvailableValuesOfType(
+ (QgsProcessingParameterPoint, QgsProcessingParameterString),
+ (QgsProcessingOutputString),
+ )
for p in points:
item.addItem(self.dialog.resolveValueDescription(p), p)
item.setEditText(str(self.parameterDefinition().defaultValue()))
@@ -515,14 +592,17 @@ def value(self):
s = str(self.widget.currentText()).strip()
if s:
try:
- tokens = s.split(',')
+ tokens = s.split(",")
if len(tokens) != 2:
raise InvalidParameterValue()
for token in tokens:
float(token)
except:
raise InvalidParameterValue()
- elif self.parameterDefinition().flags() & QgsProcessingParameterDefinition.Flag.FlagOptional:
+ elif (
+ self.parameterDefinition().flags()
+ & QgsProcessingParameterDefinition.Flag.FlagOptional
+ ):
s = None
else:
raise InvalidParameterValue()
@@ -541,19 +621,38 @@ def __init__(self, *args, **kwargs):
"""
from warnings import warn
- warn("FileWidgetWrapper is deprecated and will be removed in QGIS 4.0", DeprecationWarning)
+
+ warn(
+ "FileWidgetWrapper is deprecated and will be removed in QGIS 4.0",
+ DeprecationWarning,
+ )
def createWidget(self):
if self.dialogType in (DIALOG_STANDARD, DIALOG_BATCH):
- return FileSelectionPanel(self.parameterDefinition().behavior() == QgsProcessingParameterFile.Behavior.Folder,
- self.parameterDefinition().extension())
+ return FileSelectionPanel(
+ self.parameterDefinition().behavior()
+ == QgsProcessingParameterFile.Behavior.Folder,
+ self.parameterDefinition().extension(),
+ )
else:
self.combo = QComboBox()
self.combo.setEditable(True)
- files = self.dialog.getAvailableValuesOfType(QgsProcessingParameterFile, (QgsProcessingOutputRasterLayer, QgsProcessingOutputVectorLayer, QgsProcessingOutputMapLayer, QgsProcessingOutputFile, QgsProcessingOutputString))
+ files = self.dialog.getAvailableValuesOfType(
+ QgsProcessingParameterFile,
+ (
+ QgsProcessingOutputRasterLayer,
+ QgsProcessingOutputVectorLayer,
+ QgsProcessingOutputMapLayer,
+ QgsProcessingOutputFile,
+ QgsProcessingOutputString,
+ ),
+ )
for f in files:
self.combo.addItem(self.dialog.resolveValueDescription(f), f)
- if self.parameterDefinition().flags() & QgsProcessingParameterDefinition.Flag.FlagOptional:
+ if (
+ self.parameterDefinition().flags()
+ & QgsProcessingParameterDefinition.Flag.FlagOptional
+ ):
self.combo.setEditText("")
widget = QWidget()
layout = QHBoxLayout()
@@ -562,7 +661,7 @@ def createWidget(self):
layout.setSpacing(6)
layout.addWidget(self.combo)
btn = QToolButton()
- btn.setText('…')
+ btn.setText("…")
btn.setToolTip(self.tr("Select file"))
btn.clicked.connect(self.selectFile)
layout.addWidget(btn)
@@ -573,21 +672,26 @@ def selectFile(self):
settings = QgsSettings()
if os.path.isdir(os.path.dirname(self.combo.currentText())):
path = os.path.dirname(self.combo.currentText())
- if settings.contains('/Processing/LastInputPath'):
- path = settings.value('/Processing/LastInputPath')
+ if settings.contains("/Processing/LastInputPath"):
+ path = settings.value("/Processing/LastInputPath")
else:
- path = ''
+ path = ""
if self.parameterDefinition().extension():
- filter = self.tr('{} files').format(
- self.parameterDefinition().extension().upper()) + ' (*.' + self.parameterDefinition().extension() + self.tr(
- ');;All files (*.*)')
+ filter = (
+ self.tr("{} files").format(
+ self.parameterDefinition().extension().upper()
+ )
+ + " (*."
+ + self.parameterDefinition().extension()
+ + self.tr(");;All files (*.*)")
+ )
else:
- filter = self.tr('All files (*.*)')
+ filter = self.tr("All files (*.*)")
- filename, selected_filter = QFileDialog.getOpenFileName(self.widget,
- self.tr('Select File'), path,
- filter)
+ filename, selected_filter = QFileDialog.getOpenFileName(
+ self.widget, self.tr("Select File"), path, filter
+ )
if filename:
self.combo.setEditText(filename)
@@ -617,7 +721,11 @@ def __init__(self, *args, **kwargs):
"""
from warnings import warn
- warn("FixedTableWidgetWrapper is deprecated and will be removed in QGIS 4.0", DeprecationWarning)
+
+ warn(
+ "FixedTableWidgetWrapper is deprecated and will be removed in QGIS 4.0",
+ DeprecationWarning,
+ )
def createWidget(self):
if self.dialogType in (DIALOG_STANDARD, DIALOG_BATCH):
@@ -645,116 +753,265 @@ def value(self):
class MultipleLayerWidgetWrapper(WidgetWrapper):
def _getOptions(self):
- if self.parameterDefinition().layerType() == QgsProcessing.SourceType.TypeVectorAnyGeometry:
- options = self.dialog.getAvailableValuesOfType((QgsProcessingParameterFeatureSource,
- QgsProcessingParameterVectorLayer,
- QgsProcessingParameterMultipleLayers),
- [QgsProcessingOutputVectorLayer,
- QgsProcessingOutputMapLayer,
- QgsProcessingOutputMultipleLayers])
- elif self.parameterDefinition().layerType() == QgsProcessing.SourceType.TypeVector:
- options = self.dialog.getAvailableValuesOfType((QgsProcessingParameterFeatureSource,
- QgsProcessingParameterVectorLayer,
- QgsProcessingParameterMultipleLayers),
- [QgsProcessingOutputVectorLayer,
- QgsProcessingOutputMapLayer,
- QgsProcessingOutputMultipleLayers],
- [QgsProcessing.SourceType.TypeVector])
- elif self.parameterDefinition().layerType() == QgsProcessing.SourceType.TypeVectorPoint:
- options = self.dialog.getAvailableValuesOfType((QgsProcessingParameterFeatureSource,
- QgsProcessingParameterVectorLayer,
- QgsProcessingParameterMultipleLayers),
- [QgsProcessingOutputVectorLayer,
- QgsProcessingOutputMapLayer,
- QgsProcessingOutputMultipleLayers],
- [QgsProcessing.SourceType.TypeVectorPoint,
- QgsProcessing.SourceType.TypeVectorAnyGeometry])
- elif self.parameterDefinition().layerType() == QgsProcessing.SourceType.TypeVectorLine:
- options = self.dialog.getAvailableValuesOfType((QgsProcessingParameterFeatureSource,
- QgsProcessingParameterVectorLayer,
- QgsProcessingParameterMultipleLayers),
- [QgsProcessingOutputVectorLayer,
- QgsProcessingOutputMapLayer,
- QgsProcessingOutputMultipleLayers],
- [QgsProcessing.SourceType.TypeVectorLine,
- QgsProcessing.SourceType.TypeVectorAnyGeometry])
- elif self.parameterDefinition().layerType() == QgsProcessing.SourceType.TypeVectorPolygon:
- options = self.dialog.getAvailableValuesOfType((QgsProcessingParameterFeatureSource,
- QgsProcessingParameterVectorLayer,
- QgsProcessingParameterMultipleLayers),
- [QgsProcessingOutputVectorLayer,
- QgsProcessingOutputMapLayer,
- QgsProcessingOutputMultipleLayers],
- [QgsProcessing.SourceType.TypeVectorPolygon,
- QgsProcessing.SourceType.TypeVectorAnyGeometry])
- elif self.parameterDefinition().layerType() == QgsProcessing.SourceType.TypeRaster:
+ if (
+ self.parameterDefinition().layerType()
+ == QgsProcessing.SourceType.TypeVectorAnyGeometry
+ ):
options = self.dialog.getAvailableValuesOfType(
- (QgsProcessingParameterRasterLayer, QgsProcessingParameterMultipleLayers),
- [QgsProcessingOutputRasterLayer,
- QgsProcessingOutputMapLayer,
- QgsProcessingOutputMultipleLayers])
- elif self.parameterDefinition().layerType() == QgsProcessing.SourceType.TypeMesh:
+ (
+ QgsProcessingParameterFeatureSource,
+ QgsProcessingParameterVectorLayer,
+ QgsProcessingParameterMultipleLayers,
+ ),
+ [
+ QgsProcessingOutputVectorLayer,
+ QgsProcessingOutputMapLayer,
+ QgsProcessingOutputMultipleLayers,
+ ],
+ )
+ elif (
+ self.parameterDefinition().layerType()
+ == QgsProcessing.SourceType.TypeVector
+ ):
+ options = self.dialog.getAvailableValuesOfType(
+ (
+ QgsProcessingParameterFeatureSource,
+ QgsProcessingParameterVectorLayer,
+ QgsProcessingParameterMultipleLayers,
+ ),
+ [
+ QgsProcessingOutputVectorLayer,
+ QgsProcessingOutputMapLayer,
+ QgsProcessingOutputMultipleLayers,
+ ],
+ [QgsProcessing.SourceType.TypeVector],
+ )
+ elif (
+ self.parameterDefinition().layerType()
+ == QgsProcessing.SourceType.TypeVectorPoint
+ ):
+ options = self.dialog.getAvailableValuesOfType(
+ (
+ QgsProcessingParameterFeatureSource,
+ QgsProcessingParameterVectorLayer,
+ QgsProcessingParameterMultipleLayers,
+ ),
+ [
+ QgsProcessingOutputVectorLayer,
+ QgsProcessingOutputMapLayer,
+ QgsProcessingOutputMultipleLayers,
+ ],
+ [
+ QgsProcessing.SourceType.TypeVectorPoint,
+ QgsProcessing.SourceType.TypeVectorAnyGeometry,
+ ],
+ )
+ elif (
+ self.parameterDefinition().layerType()
+ == QgsProcessing.SourceType.TypeVectorLine
+ ):
+ options = self.dialog.getAvailableValuesOfType(
+ (
+ QgsProcessingParameterFeatureSource,
+ QgsProcessingParameterVectorLayer,
+ QgsProcessingParameterMultipleLayers,
+ ),
+ [
+ QgsProcessingOutputVectorLayer,
+ QgsProcessingOutputMapLayer,
+ QgsProcessingOutputMultipleLayers,
+ ],
+ [
+ QgsProcessing.SourceType.TypeVectorLine,
+ QgsProcessing.SourceType.TypeVectorAnyGeometry,
+ ],
+ )
+ elif (
+ self.parameterDefinition().layerType()
+ == QgsProcessing.SourceType.TypeVectorPolygon
+ ):
+ options = self.dialog.getAvailableValuesOfType(
+ (
+ QgsProcessingParameterFeatureSource,
+ QgsProcessingParameterVectorLayer,
+ QgsProcessingParameterMultipleLayers,
+ ),
+ [
+ QgsProcessingOutputVectorLayer,
+ QgsProcessingOutputMapLayer,
+ QgsProcessingOutputMultipleLayers,
+ ],
+ [
+ QgsProcessing.SourceType.TypeVectorPolygon,
+ QgsProcessing.SourceType.TypeVectorAnyGeometry,
+ ],
+ )
+ elif (
+ self.parameterDefinition().layerType()
+ == QgsProcessing.SourceType.TypeRaster
+ ):
+ options = self.dialog.getAvailableValuesOfType(
+ (
+ QgsProcessingParameterRasterLayer,
+ QgsProcessingParameterMultipleLayers,
+ ),
+ [
+ QgsProcessingOutputRasterLayer,
+ QgsProcessingOutputMapLayer,
+ QgsProcessingOutputMultipleLayers,
+ ],
+ )
+ elif (
+ self.parameterDefinition().layerType() == QgsProcessing.SourceType.TypeMesh
+ ):
options = self.dialog.getAvailableValuesOfType(
(QgsProcessingParameterMeshLayer, QgsProcessingParameterMultipleLayers),
- [])
- elif self.parameterDefinition().layerType() == QgsProcessing.SourceType.TypeMapLayer:
- options = self.dialog.getAvailableValuesOfType((QgsProcessingParameterRasterLayer,
- QgsProcessingParameterFeatureSource,
- QgsProcessingParameterVectorLayer,
- QgsProcessingParameterMeshLayer,
- QgsProcessingParameterMultipleLayers),
- [QgsProcessingOutputRasterLayer,
- QgsProcessingOutputVectorLayer,
- QgsProcessingOutputMapLayer,
- QgsProcessingOutputMultipleLayers])
+ [],
+ )
+ elif (
+ self.parameterDefinition().layerType()
+ == QgsProcessing.SourceType.TypeMapLayer
+ ):
+ options = self.dialog.getAvailableValuesOfType(
+ (
+ QgsProcessingParameterRasterLayer,
+ QgsProcessingParameterFeatureSource,
+ QgsProcessingParameterVectorLayer,
+ QgsProcessingParameterMeshLayer,
+ QgsProcessingParameterMultipleLayers,
+ ),
+ [
+ QgsProcessingOutputRasterLayer,
+ QgsProcessingOutputVectorLayer,
+ QgsProcessingOutputMapLayer,
+ QgsProcessingOutputMultipleLayers,
+ ],
+ )
else:
- options = self.dialog.getAvailableValuesOfType(QgsProcessingParameterFile, QgsProcessingOutputFile)
- options = sorted(options, key=lambda opt: self.dialog.resolveValueDescription(opt))
+ options = self.dialog.getAvailableValuesOfType(
+ QgsProcessingParameterFile, QgsProcessingOutputFile
+ )
+ options = sorted(
+ options, key=lambda opt: self.dialog.resolveValueDescription(opt)
+ )
return options
def createWidget(self):
if self.dialogType == DIALOG_STANDARD:
- if self.parameterDefinition().layerType() == QgsProcessing.SourceType.TypeFile:
+ if (
+ self.parameterDefinition().layerType()
+ == QgsProcessing.SourceType.TypeFile
+ ):
return MultipleInputPanel(datatype=QgsProcessing.SourceType.TypeFile)
else:
- if self.parameterDefinition().layerType() == QgsProcessing.SourceType.TypeRaster:
- options = QgsProcessingUtils.compatibleRasterLayers(QgsProject.instance(), False)
- elif self.parameterDefinition().layerType() == QgsProcessing.SourceType.TypeMesh:
- options = QgsProcessingUtils.compatibleMeshLayers(QgsProject.instance(), False)
- elif self.parameterDefinition().layerType() in (QgsProcessing.SourceType.TypeVectorAnyGeometry, QgsProcessing.SourceType.TypeVector):
- options = QgsProcessingUtils.compatibleVectorLayers(QgsProject.instance(), [], False)
- elif self.parameterDefinition().layerType() == QgsProcessing.SourceType.TypeMapLayer:
- options = QgsProcessingUtils.compatibleVectorLayers(QgsProject.instance(), [], False)
- options.extend(QgsProcessingUtils.compatibleRasterLayers(QgsProject.instance(), False))
- options.extend(QgsProcessingUtils.compatibleMeshLayers(QgsProject.instance(), False))
+ if (
+ self.parameterDefinition().layerType()
+ == QgsProcessing.SourceType.TypeRaster
+ ):
+ options = QgsProcessingUtils.compatibleRasterLayers(
+ QgsProject.instance(), False
+ )
+ elif (
+ self.parameterDefinition().layerType()
+ == QgsProcessing.SourceType.TypeMesh
+ ):
+ options = QgsProcessingUtils.compatibleMeshLayers(
+ QgsProject.instance(), False
+ )
+ elif self.parameterDefinition().layerType() in (
+ QgsProcessing.SourceType.TypeVectorAnyGeometry,
+ QgsProcessing.SourceType.TypeVector,
+ ):
+ options = QgsProcessingUtils.compatibleVectorLayers(
+ QgsProject.instance(), [], False
+ )
+ elif (
+ self.parameterDefinition().layerType()
+ == QgsProcessing.SourceType.TypeMapLayer
+ ):
+ options = QgsProcessingUtils.compatibleVectorLayers(
+ QgsProject.instance(), [], False
+ )
+ options.extend(
+ QgsProcessingUtils.compatibleRasterLayers(
+ QgsProject.instance(), False
+ )
+ )
+ options.extend(
+ QgsProcessingUtils.compatibleMeshLayers(
+ QgsProject.instance(), False
+ )
+ )
else:
- options = QgsProcessingUtils.compatibleVectorLayers(QgsProject.instance(), [self.parameterDefinition().layerType()],
- False)
+ options = QgsProcessingUtils.compatibleVectorLayers(
+ QgsProject.instance(),
+ [self.parameterDefinition().layerType()],
+ False,
+ )
opts = [getExtendedLayerName(opt) for opt in options]
- return MultipleInputPanel(opts, datatype=self.parameterDefinition().layerType())
+ return MultipleInputPanel(
+ opts, datatype=self.parameterDefinition().layerType()
+ )
elif self.dialogType == DIALOG_BATCH:
- widget = BatchInputSelectionPanel(self.parameterDefinition(), self.row, self.col, self.dialog)
+ widget = BatchInputSelectionPanel(
+ self.parameterDefinition(), self.row, self.col, self.dialog
+ )
widget.valueChanged.connect(lambda: self.widgetValueHasChanged.emit(self))
return widget
else:
- options = [self.dialog.resolveValueDescription(opt) for opt in self._getOptions()]
- return MultipleInputPanel(options, datatype=self.parameterDefinition().layerType())
+ options = [
+ self.dialog.resolveValueDescription(opt) for opt in self._getOptions()
+ ]
+ return MultipleInputPanel(
+ options, datatype=self.parameterDefinition().layerType()
+ )
def refresh(self):
if self.parameterDefinition().layerType() != QgsProcessing.SourceType.TypeFile:
- if self.parameterDefinition().layerType() == QgsProcessing.SourceType.TypeRaster:
- options = QgsProcessingUtils.compatibleRasterLayers(QgsProject.instance(), False)
- elif self.parameterDefinition().layerType() == QgsProcessing.SourceType.TypeMesh:
- options = QgsProcessingUtils.compatibleMeshLayers(QgsProject.instance(), False)
- elif self.parameterDefinition().layerType() in (QgsProcessing.SourceType.TypeVectorAnyGeometry, QgsProcessing.SourceType.TypeVector):
- options = QgsProcessingUtils.compatibleVectorLayers(QgsProject.instance(), [], False)
- elif self.parameterDefinition().layerType() == QgsProcessing.SourceType.TypeMapLayer:
- options = QgsProcessingUtils.compatibleVectorLayers(QgsProject.instance(), [], False)
- options.extend(QgsProcessingUtils.compatibleRasterLayers(QgsProject.instance(), False))
- options.extend(QgsProcessingUtils.compatibleMeshLayers(QgsProject.instance(), False))
+ if (
+ self.parameterDefinition().layerType()
+ == QgsProcessing.SourceType.TypeRaster
+ ):
+ options = QgsProcessingUtils.compatibleRasterLayers(
+ QgsProject.instance(), False
+ )
+ elif (
+ self.parameterDefinition().layerType()
+ == QgsProcessing.SourceType.TypeMesh
+ ):
+ options = QgsProcessingUtils.compatibleMeshLayers(
+ QgsProject.instance(), False
+ )
+ elif self.parameterDefinition().layerType() in (
+ QgsProcessing.SourceType.TypeVectorAnyGeometry,
+ QgsProcessing.SourceType.TypeVector,
+ ):
+ options = QgsProcessingUtils.compatibleVectorLayers(
+ QgsProject.instance(), [], False
+ )
+ elif (
+ self.parameterDefinition().layerType()
+ == QgsProcessing.SourceType.TypeMapLayer
+ ):
+ options = QgsProcessingUtils.compatibleVectorLayers(
+ QgsProject.instance(), [], False
+ )
+ options.extend(
+ QgsProcessingUtils.compatibleRasterLayers(
+ QgsProject.instance(), False
+ )
+ )
+ options.extend(
+ QgsProcessingUtils.compatibleMeshLayers(
+ QgsProject.instance(), False
+ )
+ )
else:
- options = QgsProcessingUtils.compatibleVectorLayers(QgsProject.instance(), [self.parameterDefinition().layerType()],
- False)
+ options = QgsProcessingUtils.compatibleVectorLayers(
+ QgsProject.instance(),
+ [self.parameterDefinition().layerType()],
+ False,
+ )
opts = [getExtendedLayerName(opt) for opt in options]
self.widget.updateForOptions(opts)
@@ -785,30 +1042,77 @@ def setValue(self, value):
def value(self):
if self.dialogType == DIALOG_STANDARD:
- if self.parameterDefinition().layerType() == QgsProcessing.SourceType.TypeFile:
+ if (
+ self.parameterDefinition().layerType()
+ == QgsProcessing.SourceType.TypeFile
+ ):
return self.widget.selectedoptions
else:
- if self.parameterDefinition().layerType() == QgsProcessing.SourceType.TypeRaster:
- options = QgsProcessingUtils.compatibleRasterLayers(QgsProject.instance(), False)
- elif self.parameterDefinition().layerType() == QgsProcessing.SourceType.TypeMesh:
- options = QgsProcessingUtils.compatibleMeshLayers(QgsProject.instance(), False)
- elif self.parameterDefinition().layerType() in (QgsProcessing.SourceType.TypeVectorAnyGeometry, QgsProcessing.SourceType.TypeVector):
- options = QgsProcessingUtils.compatibleVectorLayers(QgsProject.instance(), [], False)
- elif self.parameterDefinition().layerType() == QgsProcessing.SourceType.TypeMapLayer:
- options = QgsProcessingUtils.compatibleVectorLayers(QgsProject.instance(), [], False)
- options.extend(QgsProcessingUtils.compatibleRasterLayers(QgsProject.instance(), False))
- options.extend(QgsProcessingUtils.compatibleMeshLayers(QgsProject.instance(), False))
+ if (
+ self.parameterDefinition().layerType()
+ == QgsProcessing.SourceType.TypeRaster
+ ):
+ options = QgsProcessingUtils.compatibleRasterLayers(
+ QgsProject.instance(), False
+ )
+ elif (
+ self.parameterDefinition().layerType()
+ == QgsProcessing.SourceType.TypeMesh
+ ):
+ options = QgsProcessingUtils.compatibleMeshLayers(
+ QgsProject.instance(), False
+ )
+ elif self.parameterDefinition().layerType() in (
+ QgsProcessing.SourceType.TypeVectorAnyGeometry,
+ QgsProcessing.SourceType.TypeVector,
+ ):
+ options = QgsProcessingUtils.compatibleVectorLayers(
+ QgsProject.instance(), [], False
+ )
+ elif (
+ self.parameterDefinition().layerType()
+ == QgsProcessing.SourceType.TypeMapLayer
+ ):
+ options = QgsProcessingUtils.compatibleVectorLayers(
+ QgsProject.instance(), [], False
+ )
+ options.extend(
+ QgsProcessingUtils.compatibleRasterLayers(
+ QgsProject.instance(), False
+ )
+ )
+ options.extend(
+ QgsProcessingUtils.compatibleMeshLayers(
+ QgsProject.instance(), False
+ )
+ )
else:
- options = QgsProcessingUtils.compatibleVectorLayers(QgsProject.instance(), [self.parameterDefinition().layerType()],
- False)
- return [options[i] if isinstance(i, int) else i for i in self.widget.selectedoptions]
+ options = QgsProcessingUtils.compatibleVectorLayers(
+ QgsProject.instance(),
+ [self.parameterDefinition().layerType()],
+ False,
+ )
+ return [
+ options[i] if isinstance(i, int) else i
+ for i in self.widget.selectedoptions
+ ]
elif self.dialogType == DIALOG_BATCH:
return self.widget.getValue()
else:
options = self._getOptions()
- values = [options[i] if isinstance(i, int) else QgsProcessingModelChildParameterSource.fromStaticValue(i)
- for i in self.widget.selectedoptions]
- if len(values) == 0 and not self.parameterDefinition().flags() & QgsProcessingParameterDefinition.Flag.FlagOptional:
+ values = [
+ (
+ options[i]
+ if isinstance(i, int)
+ else QgsProcessingModelChildParameterSource.fromStaticValue(i)
+ )
+ for i in self.widget.selectedoptions
+ ]
+ if (
+ len(values) == 0
+ and not self.parameterDefinition().flags()
+ & QgsProcessingParameterDefinition.Flag.FlagOptional
+ ):
raise InvalidParameterValue()
return values
@@ -823,7 +1127,11 @@ def __init__(self, *args, **kwargs):
"""
from warnings import warn
- warn("NumberWidgetWrapper is deprecated and will be removed in QGIS 4.0", DeprecationWarning)
+
+ warn(
+ "NumberWidgetWrapper is deprecated and will be removed in QGIS 4.0",
+ DeprecationWarning,
+ )
def createWidget(self):
if self.dialogType in (DIALOG_STANDARD, DIALOG_BATCH):
@@ -843,9 +1151,15 @@ def value(self):
return self.widget.getValue()
def postInitialize(self, wrappers):
- if self.dialogType in (DIALOG_STANDARD, DIALOG_BATCH) and self.parameterDefinition().isDynamic():
+ if (
+ self.dialogType in (DIALOG_STANDARD, DIALOG_BATCH)
+ and self.parameterDefinition().isDynamic()
+ ):
for wrapper in wrappers:
- if wrapper.parameterDefinition().name() == self.parameterDefinition().dynamicLayerParameterName():
+ if (
+ wrapper.parameterDefinition().name()
+ == self.parameterDefinition().dynamicLayerParameterName()
+ ):
self.widget.setDynamicLayer(wrapper.parameterValue())
wrapper.widgetValueHasChanged.connect(self.parentLayerChanged)
break
@@ -864,7 +1178,11 @@ def __init__(self, *args, **kwargs):
"""
from warnings import warn
- warn("DistanceWidgetWrapper is deprecated and will be removed in QGIS 4.0", DeprecationWarning)
+
+ warn(
+ "DistanceWidgetWrapper is deprecated and will be removed in QGIS 4.0",
+ DeprecationWarning,
+ )
def createWidget(self):
if self.dialogType in (DIALOG_STANDARD, DIALOG_BATCH):
@@ -886,10 +1204,16 @@ def value(self):
def postInitialize(self, wrappers):
if self.dialogType in (DIALOG_STANDARD, DIALOG_BATCH):
for wrapper in wrappers:
- if wrapper.parameterDefinition().name() == self.parameterDefinition().dynamicLayerParameterName():
+ if (
+ wrapper.parameterDefinition().name()
+ == self.parameterDefinition().dynamicLayerParameterName()
+ ):
self.widget.setDynamicLayer(wrapper.parameterValue())
wrapper.widgetValueHasChanged.connect(self.dynamicLayerChanged)
- if wrapper.parameterDefinition().name() == self.parameterDefinition().parentParameterName():
+ if (
+ wrapper.parameterDefinition().name()
+ == self.parameterDefinition().parentParameterName()
+ ):
self.widget.setUnitParameterValue(wrapper.parameterValue())
wrapper.widgetValueHasChanged.connect(self.parentParameterChanged)
@@ -910,7 +1234,11 @@ def __init__(self, *args, **kwargs):
"""
from warnings import warn
- warn("RangeWidgetWrapper is deprecated and will be removed in QGIS 4.0", DeprecationWarning)
+
+ warn(
+ "RangeWidgetWrapper is deprecated and will be removed in QGIS 4.0",
+ DeprecationWarning,
+ )
def createWidget(self):
widget = RangePanel(self.parameterDefinition())
@@ -928,7 +1256,7 @@ def value(self):
class MapLayerWidgetWrapper(WidgetWrapper):
- NOT_SELECTED = '[Not selected]'
+ NOT_SELECTED = "[Not selected]"
def __init__(self, param, dialog, row=0, col=0, **kwargs):
"""
@@ -937,7 +1265,11 @@ def __init__(self, param, dialog, row=0, col=0, **kwargs):
"""
from warnings import warn
- warn("MapLayerWidgetWrapper is deprecated and will be removed in QGIS 4.0", DeprecationWarning)
+
+ warn(
+ "MapLayerWidgetWrapper is deprecated and will be removed in QGIS 4.0",
+ DeprecationWarning,
+ )
super().__init__(param, dialog, row, col, **kwargs)
@@ -947,27 +1279,41 @@ def createWidget(self):
self.context = dataobjects.createContext()
try:
- if self.parameterDefinition().flags() & QgsProcessingParameterDefinition.Flag.FlagOptional:
- self.combo.setValue(self.parameterDefinition().defaultValue(), self.context)
+ if (
+ self.parameterDefinition().flags()
+ & QgsProcessingParameterDefinition.Flag.FlagOptional
+ ):
+ self.combo.setValue(
+ self.parameterDefinition().defaultValue(), self.context
+ )
else:
if self.parameterDefinition().defaultValue():
- self.combo.setValue(self.parameterDefinition().defaultValue(), self.context)
+ self.combo.setValue(
+ self.parameterDefinition().defaultValue(), self.context
+ )
else:
self.combo.setLayer(iface.activeLayer())
except:
pass
- self.combo.valueChanged.connect(lambda: self.widgetValueHasChanged.emit(self))
+ self.combo.valueChanged.connect(
+ lambda: self.widgetValueHasChanged.emit(self)
+ )
return self.combo
elif self.dialogType == DIALOG_BATCH:
- widget = BatchInputSelectionPanel(self.parameterDefinition(), self.row, self.col, self.dialog)
+ widget = BatchInputSelectionPanel(
+ self.parameterDefinition(), self.row, self.col, self.dialog
+ )
widget.valueChanged.connect(lambda: self.widgetValueHasChanged.emit(self))
return widget
else:
self.combo = QComboBox()
layers = self.getAvailableLayers()
self.combo.setEditable(True)
- if self.parameterDefinition().flags() & QgsProcessingParameterDefinition.Flag.FlagOptional:
+ if (
+ self.parameterDefinition().flags()
+ & QgsProcessingParameterDefinition.Flag.FlagOptional
+ ):
self.combo.addItem(self.NOT_SELECTED, self.NOT_SET_OPTION)
for layer in layers:
self.combo.addItem(self.dialog.resolveValueDescription(layer), layer)
@@ -979,7 +1325,7 @@ def createWidget(self):
layout.setSpacing(6)
layout.addWidget(self.combo)
btn = QToolButton()
- btn.setText('…')
+ btn.setText("…")
btn.setToolTip(self.tr("Select file"))
btn.clicked.connect(self.selectFile)
layout.addWidget(btn)
@@ -988,8 +1334,21 @@ def createWidget(self):
def getAvailableLayers(self):
return self.dialog.getAvailableValuesOfType(
- [QgsProcessingParameterRasterLayer, QgsProcessingParameterMeshLayer, QgsProcessingParameterVectorLayer, QgsProcessingParameterMapLayer, QgsProcessingParameterString],
- [QgsProcessingOutputRasterLayer, QgsProcessingOutputVectorLayer, QgsProcessingOutputMapLayer, QgsProcessingOutputString, QgsProcessingOutputFile])
+ [
+ QgsProcessingParameterRasterLayer,
+ QgsProcessingParameterMeshLayer,
+ QgsProcessingParameterVectorLayer,
+ QgsProcessingParameterMapLayer,
+ QgsProcessingParameterString,
+ ],
+ [
+ QgsProcessingOutputRasterLayer,
+ QgsProcessingOutputVectorLayer,
+ QgsProcessingOutputMapLayer,
+ QgsProcessingOutputString,
+ QgsProcessingOutputFile,
+ ],
+ )
def selectFile(self):
filename, selected_filter = self.getFileName(self.combo.currentText())
@@ -1027,9 +1386,13 @@ def value(self):
elif self.dialogType == DIALOG_BATCH:
return self.widget.getValue()
else:
+
def validator(v):
if not bool(v):
- return self.parameterDefinition().flags() & QgsProcessingParameterDefinition.Flag.FlagOptional
+ return (
+ self.parameterDefinition().flags()
+ & QgsProcessingParameterDefinition.Flag.FlagOptional
+ )
else:
return os.path.exists(v)
@@ -1045,18 +1408,30 @@ def __init__(self, param, dialog, row=0, col=0, **kwargs):
"""
from warnings import warn
- warn("RasterWidgetWrapper is deprecated and will be removed in QGIS 4.0", DeprecationWarning)
+
+ warn(
+ "RasterWidgetWrapper is deprecated and will be removed in QGIS 4.0",
+ DeprecationWarning,
+ )
super().__init__(param, dialog, row, col, **kwargs)
def getAvailableLayers(self):
- return self.dialog.getAvailableValuesOfType((QgsProcessingParameterRasterLayer, QgsProcessingParameterString),
- (QgsProcessingOutputRasterLayer, QgsProcessingOutputFile, QgsProcessingOutputString))
+ return self.dialog.getAvailableValuesOfType(
+ (QgsProcessingParameterRasterLayer, QgsProcessingParameterString),
+ (
+ QgsProcessingOutputRasterLayer,
+ QgsProcessingOutputFile,
+ QgsProcessingOutputString,
+ ),
+ )
def selectFile(self):
filename, selected_filter = self.getFileName(self.combo.currentText())
if filename:
- filename = dataobjects.getRasterSublayer(filename, self.parameterDefinition())
+ filename = dataobjects.getRasterSublayer(
+ filename, self.parameterDefinition()
+ )
if isinstance(self.combo, QgsProcessingMapLayerComboBox):
self.combo.setValue(filename, self.context)
elif isinstance(self.combo, QgsMapLayerComboBox):
@@ -1078,13 +1453,18 @@ def __init__(self, param, dialog, row=0, col=0, **kwargs):
"""
from warnings import warn
- warn("MeshWidgetWrapper is deprecated and will be removed in QGIS 4.0", DeprecationWarning)
+
+ warn(
+ "MeshWidgetWrapper is deprecated and will be removed in QGIS 4.0",
+ DeprecationWarning,
+ )
super().__init__(param, dialog, row, col, **kwargs)
def getAvailableLayers(self):
- return self.dialog.getAvailableValuesOfType((QgsProcessingParameterMeshLayer, QgsProcessingParameterString),
- ())
+ return self.dialog.getAvailableValuesOfType(
+ (QgsProcessingParameterMeshLayer, QgsProcessingParameterString), ()
+ )
def selectFile(self):
filename, selected_filter = self.getFileName(self.combo.currentText())
@@ -1102,7 +1482,7 @@ def selectFile(self):
class EnumWidgetWrapper(WidgetWrapper):
- NOT_SELECTED = '[Not selected]'
+ NOT_SELECTED = "[Not selected]"
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
@@ -1112,15 +1492,21 @@ def __init__(self, *args, **kwargs):
"""
from warnings import warn
- warn("EnumWidgetWrapper is deprecated and will be removed in QGIS 4.0", DeprecationWarning)
+
+ warn(
+ "EnumWidgetWrapper is deprecated and will be removed in QGIS 4.0",
+ DeprecationWarning,
+ )
def createWidget(self, useCheckBoxes=False, columns=1):
if self.dialogType in (DIALOG_STANDARD, DIALOG_BATCH):
self._useCheckBoxes = useCheckBoxes
if self._useCheckBoxes and not self.dialogType == DIALOG_BATCH:
- return CheckboxesPanel(options=self.parameterDefinition().options(),
- multiple=self.parameterDefinition().allowMultiple(),
- columns=columns)
+ return CheckboxesPanel(
+ options=self.parameterDefinition().options(),
+ multiple=self.parameterDefinition().allowMultiple(),
+ columns=columns,
+ )
if self.parameterDefinition().allowMultiple():
return MultipleInputPanel(options=self.parameterDefinition().options())
else:
@@ -1128,11 +1514,16 @@ def createWidget(self, useCheckBoxes=False, columns=1):
for i, option in enumerate(self.parameterDefinition().options()):
widget.addItem(option, i)
if self.parameterDefinition().defaultValue():
- widget.setCurrentIndex(widget.findData(self.parameterDefinition().defaultValue()))
+ widget.setCurrentIndex(
+ widget.findData(self.parameterDefinition().defaultValue())
+ )
return widget
else:
self.combobox = QComboBox()
- if self.parameterDefinition().flags() & QgsProcessingParameterDefinition.Flag.FlagOptional:
+ if (
+ self.parameterDefinition().flags()
+ & QgsProcessingParameterDefinition.Flag.FlagOptional
+ ):
self.combobox.addItem(self.NOT_SELECTED, self.NOT_SET_OPTION)
for i, option in enumerate(self.parameterDefinition().options()):
self.combobox.addItem(option, i)
@@ -1169,7 +1560,7 @@ def value(self):
class FeatureSourceWidgetWrapper(WidgetWrapper):
- NOT_SELECTED = '[Not selected]'
+ NOT_SELECTED = "[Not selected]"
def __init__(self, *args, **kwargs):
"""
@@ -1178,13 +1569,19 @@ def __init__(self, *args, **kwargs):
"""
from warnings import warn
- warn("FeatureSourceWidgetWrapper is deprecated and will be removed in QGIS 4.0", DeprecationWarning)
+
+ warn(
+ "FeatureSourceWidgetWrapper is deprecated and will be removed in QGIS 4.0",
+ DeprecationWarning,
+ )
self.map_layer_combo = None
super().__init__(*args, **kwargs)
def createWidget(self):
if self.dialogType == DIALOG_STANDARD:
- self.map_layer_combo = QgsProcessingMapLayerComboBox(self.parameterDefinition())
+ self.map_layer_combo = QgsProcessingMapLayerComboBox(
+ self.parameterDefinition()
+ )
self.context = dataobjects.createContext()
try:
@@ -1193,23 +1590,40 @@ def createWidget(self):
except:
pass
- self.map_layer_combo.valueChanged.connect(lambda: self.widgetValueHasChanged.emit(self))
+ self.map_layer_combo.valueChanged.connect(
+ lambda: self.widgetValueHasChanged.emit(self)
+ )
return self.map_layer_combo
elif self.dialogType == DIALOG_BATCH:
- widget = BatchInputSelectionPanel(self.parameterDefinition(), self.row, self.col, self.dialog)
+ widget = BatchInputSelectionPanel(
+ self.parameterDefinition(), self.row, self.col, self.dialog
+ )
widget.valueChanged.connect(lambda: self.widgetValueHasChanged.emit(self))
return widget
else:
self.combo = QComboBox()
layers = self.dialog.getAvailableValuesOfType(
- (QgsProcessingParameterFeatureSource, QgsProcessingParameterVectorLayer),
- (QgsProcessingOutputVectorLayer, QgsProcessingOutputMapLayer, QgsProcessingOutputString, QgsProcessingOutputFile), self.parameterDefinition().dataTypes())
+ (
+ QgsProcessingParameterFeatureSource,
+ QgsProcessingParameterVectorLayer,
+ ),
+ (
+ QgsProcessingOutputVectorLayer,
+ QgsProcessingOutputMapLayer,
+ QgsProcessingOutputString,
+ QgsProcessingOutputFile,
+ ),
+ self.parameterDefinition().dataTypes(),
+ )
self.combo.setEditable(True)
for layer in layers:
self.combo.addItem(self.dialog.resolveValueDescription(layer), layer)
- if self.parameterDefinition().flags() & QgsProcessingParameterDefinition.Flag.FlagOptional:
+ if (
+ self.parameterDefinition().flags()
+ & QgsProcessingParameterDefinition.Flag.FlagOptional
+ ):
self.combo.setEditText("")
widget = QWidget()
@@ -1219,7 +1633,7 @@ def createWidget(self):
layout.setSpacing(2)
layout.addWidget(self.combo)
btn = QToolButton()
- btn.setText('…')
+ btn.setText("…")
btn.setToolTip(self.tr("Select file"))
btn.clicked.connect(self.selectFile)
layout.addWidget(btn)
@@ -1267,9 +1681,13 @@ def value(self):
elif self.dialogType == DIALOG_BATCH:
return self.widget.getValue()
else:
+
def validator(v):
if not bool(v):
- return self.parameterDefinition().flags() & QgsProcessingParameterDefinition.Flag.FlagOptional
+ return (
+ self.parameterDefinition().flags()
+ & QgsProcessingParameterDefinition.Flag.FlagOptional
+ )
else:
return os.path.exists(v)
@@ -1289,7 +1707,11 @@ def __init__(self, *args, **kwargs):
"""
from warnings import warn
- warn("StringWidgetWrapper is deprecated and will be removed in QGIS 4.0", DeprecationWarning)
+
+ warn(
+ "StringWidgetWrapper is deprecated and will be removed in QGIS 4.0",
+ DeprecationWarning,
+ )
def createWidget(self):
if self.dialogType == DIALOG_STANDARD:
@@ -1305,9 +1727,16 @@ def createWidget(self):
else:
# strings, numbers, files and table fields are all allowed input types
strings = self.dialog.getAvailableValuesOfType(
- [QgsProcessingParameterString, QgsProcessingParameterNumber, QgsProcessingParameterDistance, QgsProcessingParameterFile,
- QgsProcessingParameterField, QgsProcessingParameterExpression],
- [QgsProcessingOutputString, QgsProcessingOutputFile])
+ [
+ QgsProcessingParameterString,
+ QgsProcessingParameterNumber,
+ QgsProcessingParameterDistance,
+ QgsProcessingParameterFile,
+ QgsProcessingParameterField,
+ QgsProcessingParameterExpression,
+ ],
+ [QgsProcessingOutputString, QgsProcessingOutputFile],
+ )
options = [(self.dialog.resolveValueDescription(s), s) for s in strings]
if self.parameterDefinition().multiLine():
widget = MultilineTextPanel(options)
@@ -1322,9 +1751,9 @@ def showExpressionsBuilder(self):
context = dataobjects.createExpressionContext()
value = self.value()
if not isinstance(value, str):
- value = ''
- dlg = QgsExpressionBuilderDialog(None, value, self.widget, 'generic', context)
- dlg.setWindowTitle(self.tr('Expression based input'))
+ value = ""
+ dlg = QgsExpressionBuilderDialog(None, value, self.widget, "generic", context)
+ dlg.setWindowTitle(self.tr("Expression based input"))
if dlg.exec() == QDialog.DialogCode.Accepted:
exp = QgsExpression(dlg.expressionText())
if not exp.hasParserError():
@@ -1368,8 +1797,11 @@ def value(self):
value = self.widget.getValue()
option = self.widget.getOption()
if option == MultilineTextPanel.USE_TEXT:
- if value == '':
- if self.parameterDefinition().flags() & QgsProcessingParameterDefinition.Flag.FlagOptional:
+ if value == "":
+ if (
+ self.parameterDefinition().flags()
+ & QgsProcessingParameterDefinition.Flag.FlagOptional
+ ):
return None
else:
raise InvalidParameterValue()
@@ -1378,8 +1810,13 @@ def value(self):
else:
return value
else:
+
def validator(v):
- return bool(v) or self.parameterDefinition().flags() & QgsProcessingParameterDefinition.Flag.FlagOptional
+ return (
+ bool(v)
+ or self.parameterDefinition().flags()
+ & QgsProcessingParameterDefinition.Flag.FlagOptional
+ )
return self.comboValue(validator)
@@ -1393,7 +1830,11 @@ def __init__(self, param, dialog, row=0, col=0, **kwargs):
"""
from warnings import warn
- warn("StringWidgetWrapper is deprecated and will be removed in QGIS 4.0", DeprecationWarning)
+
+ warn(
+ "StringWidgetWrapper is deprecated and will be removed in QGIS 4.0",
+ DeprecationWarning,
+ )
super().__init__(param, dialog, row, col, **kwargs)
self.context = dataobjects.createContext()
@@ -1408,8 +1849,14 @@ def createWidget(self):
widget.setExpression(self.parameterDefinition().defaultValue())
else:
strings = self.dialog.getAvailableValuesOfType(
- [QgsProcessingParameterExpression, QgsProcessingParameterString, QgsProcessingParameterNumber, QgsProcessingParameterDistance],
- (QgsProcessingOutputString, QgsProcessingOutputNumber))
+ [
+ QgsProcessingParameterExpression,
+ QgsProcessingParameterString,
+ QgsProcessingParameterNumber,
+ QgsProcessingParameterDistance,
+ ],
+ (QgsProcessingOutputString, QgsProcessingOutputNumber),
+ )
options = [(self.dialog.resolveValueDescription(s), s) for s in strings]
widget = QComboBox()
widget.setEditable(True)
@@ -1420,7 +1867,10 @@ def createWidget(self):
def postInitialize(self, wrappers):
for wrapper in wrappers:
- if wrapper.parameterDefinition().name() == self.parameterDefinition().parentLayerParameterName():
+ if (
+ wrapper.parameterDefinition().name()
+ == self.parameterDefinition().parentLayerParameterName()
+ ):
if self.dialogType in (DIALOG_STANDARD, DIALOG_BATCH):
self.setLayer(wrapper.parameterValue())
wrapper.widgetValueHasChanged.connect(self.parentLayerChanged)
@@ -1452,14 +1902,19 @@ def value(self):
except:
return self.widget.expression()
else:
+
def validator(v):
- return bool(v) or self.parameterDefinition().flags() & QgsProcessingParameterDefinition.Flag.FlagOptional
+ return (
+ bool(v)
+ or self.parameterDefinition().flags()
+ & QgsProcessingParameterDefinition.Flag.FlagOptional
+ )
return self.comboValue(validator)
class VectorLayerWidgetWrapper(WidgetWrapper):
- NOT_SELECTED = '[Not selected]'
+ NOT_SELECTED = "[Not selected]"
def __init__(self, param, dialog, row=0, col=0, **kwargs):
"""
@@ -1468,7 +1923,11 @@ def __init__(self, param, dialog, row=0, col=0, **kwargs):
"""
from warnings import warn
- warn("VectorLayerWidgetWrapper is deprecated and will be removed in QGIS 4.0", DeprecationWarning)
+
+ warn(
+ "VectorLayerWidgetWrapper is deprecated and will be removed in QGIS 4.0",
+ DeprecationWarning,
+ )
super().__init__(param, dialog, row, col, **kwargs)
@@ -1483,18 +1942,32 @@ def createWidget(self):
except:
pass
- self.combo.valueChanged.connect(lambda: self.widgetValueHasChanged.emit(self))
+ self.combo.valueChanged.connect(
+ lambda: self.widgetValueHasChanged.emit(self)
+ )
return self.combo
elif self.dialogType == DIALOG_BATCH:
- widget = BatchInputSelectionPanel(self.parameterDefinition(), self.row, self.col, self.dialog)
+ widget = BatchInputSelectionPanel(
+ self.parameterDefinition(), self.row, self.col, self.dialog
+ )
widget.valueChanged.connect(lambda: self.widgetValueHasChanged.emit(self))
return widget
else:
self.combo = QComboBox()
self.combo.setEditable(True)
- tables = self.dialog.getAvailableValuesOfType((QgsProcessingParameterVectorLayer, QgsProcessingParameterString),
- (QgsProcessingOutputVectorLayer, QgsProcessingOutputMapLayer, QgsProcessingOutputFile, QgsProcessingOutputString))
- if self.parameterDefinition().flags() & QgsProcessingParameterDefinition.Flag.FlagOptional:
+ tables = self.dialog.getAvailableValuesOfType(
+ (QgsProcessingParameterVectorLayer, QgsProcessingParameterString),
+ (
+ QgsProcessingOutputVectorLayer,
+ QgsProcessingOutputMapLayer,
+ QgsProcessingOutputFile,
+ QgsProcessingOutputString,
+ ),
+ )
+ if (
+ self.parameterDefinition().flags()
+ & QgsProcessingParameterDefinition.Flag.FlagOptional
+ ):
self.combo.addItem(self.NOT_SELECTED, self.NOT_SET_OPTION)
for table in tables:
self.combo.addItem(self.dialog.resolveValueDescription(table), table)
@@ -1506,7 +1979,7 @@ def createWidget(self):
layout.setSpacing(6)
layout.addWidget(self.combo)
btn = QToolButton()
- btn.setText('…')
+ btn.setText("…")
btn.setToolTip(self.tr("Select file"))
btn.clicked.connect(self.selectFile)
layout.addWidget(btn)
@@ -1516,7 +1989,9 @@ def createWidget(self):
def selectFile(self):
filename, selected_filter = self.getFileName(self.combo.currentText())
if filename:
- filename = dataobjects.getRasterSublayer(filename, self.parameterDefinition())
+ filename = dataobjects.getRasterSublayer(
+ filename, self.parameterDefinition()
+ )
if isinstance(self.combo, QgsProcessingMapLayerComboBox):
self.combo.setValue(filename, self.context)
elif isinstance(self.combo, QgsMapLayerComboBox):
@@ -1550,14 +2025,19 @@ def value(self):
elif self.dialogType == DIALOG_BATCH:
return self.widget.getValue()
else:
+
def validator(v):
- return bool(v) or self.parameterDefinition().flags() & QgsProcessingParameterDefinition.Flag.FlagOptional
+ return (
+ bool(v)
+ or self.parameterDefinition().flags()
+ & QgsProcessingParameterDefinition.Flag.FlagOptional
+ )
return self.comboValue(validator, combobox=self.combo)
class TableFieldWidgetWrapper(WidgetWrapper):
- NOT_SET = '[Not set]'
+ NOT_SET = "[Not set]"
def __init__(self, param, dialog, row=0, col=0, **kwargs):
super().__init__(param, dialog, row, col, **kwargs)
@@ -1567,7 +2047,11 @@ def __init__(self, param, dialog, row=0, col=0, **kwargs):
"""
from warnings import warn
- warn("TableFieldWidgetWrapper is deprecated and will be removed in QGIS 4.0", DeprecationWarning)
+
+ warn(
+ "TableFieldWidgetWrapper is deprecated and will be removed in QGIS 4.0",
+ DeprecationWarning,
+ )
self.context = dataobjects.createContext()
@@ -1580,32 +2064,58 @@ def createWidget(self):
return MultipleInputPanel(options=[])
else:
widget = QgsFieldComboBox()
- widget.setAllowEmptyFieldName(self.parameterDefinition().flags() & QgsProcessingParameterDefinition.Flag.FlagOptional)
- widget.fieldChanged.connect(lambda: self.widgetValueHasChanged.emit(self))
- if self.parameterDefinition().dataType() == QgsProcessingParameterField.DataType.Numeric:
+ widget.setAllowEmptyFieldName(
+ self.parameterDefinition().flags()
+ & QgsProcessingParameterDefinition.Flag.FlagOptional
+ )
+ widget.fieldChanged.connect(
+ lambda: self.widgetValueHasChanged.emit(self)
+ )
+ if (
+ self.parameterDefinition().dataType()
+ == QgsProcessingParameterField.DataType.Numeric
+ ):
widget.setFilters(QgsFieldProxyModel.Filter.Numeric)
- elif self.parameterDefinition().dataType() == QgsProcessingParameterField.DataType.String:
+ elif (
+ self.parameterDefinition().dataType()
+ == QgsProcessingParameterField.DataType.String
+ ):
widget.setFilters(QgsFieldProxyModel.Filter.String)
- elif self.parameterDefinition().dataType() == QgsProcessingParameterField.DataType.DateTime:
- widget.setFilters(QgsFieldProxyModel.Filter.Date | QgsFieldProxyModel.Filter.Time)
+ elif (
+ self.parameterDefinition().dataType()
+ == QgsProcessingParameterField.DataType.DateTime
+ ):
+ widget.setFilters(
+ QgsFieldProxyModel.Filter.Date | QgsFieldProxyModel.Filter.Time
+ )
return widget
else:
widget = QComboBox()
widget.setEditable(True)
- fields = self.dialog.getAvailableValuesOfType([QgsProcessingParameterField, QgsProcessingParameterString],
- [QgsProcessingOutputString])
- if self.parameterDefinition().flags() & QgsProcessingParameterDefinition.Flag.FlagOptional:
+ fields = self.dialog.getAvailableValuesOfType(
+ [QgsProcessingParameterField, QgsProcessingParameterString],
+ [QgsProcessingOutputString],
+ )
+ if (
+ self.parameterDefinition().flags()
+ & QgsProcessingParameterDefinition.Flag.FlagOptional
+ ):
widget.addItem(self.NOT_SET, self.NOT_SET_OPTION)
for f in fields:
widget.addItem(self.dialog.resolveValueDescription(f), f)
widget.setToolTip(
self.tr(
- 'Input parameter, or name of field (separate field names with ; for multiple field parameters)'))
+ "Input parameter, or name of field (separate field names with ; for multiple field parameters)"
+ )
+ )
return widget
def postInitialize(self, wrappers):
for wrapper in wrappers:
- if wrapper.parameterDefinition().name() == self.parameterDefinition().parentLayerParameterName():
+ if (
+ wrapper.parameterDefinition().name()
+ == self.parameterDefinition().parentLayerParameterName()
+ ):
if self.dialogType in (DIALOG_STANDARD, DIALOG_BATCH):
self.setLayer(wrapper.parameterValue())
wrapper.widgetValueHasChanged.connect(self.parentValueChanged)
@@ -1630,15 +2140,24 @@ def setLayer(self, layer):
layer = QgsProcessingUtils.mapLayerFromString(layer, self.context)
if not isinstance(layer, QgsVectorLayer) or not layer.isValid():
self.dialog.messageBar().clearWidgets()
- self.dialog.messageBar().pushMessage("", self.tr("Could not load selected layer/table. Dependent field could not be populated"),
- level=Qgis.MessageLevel.Warning, duration=5)
+ self.dialog.messageBar().pushMessage(
+ "",
+ self.tr(
+ "Could not load selected layer/table. Dependent field could not be populated"
+ ),
+ level=Qgis.MessageLevel.Warning,
+ duration=5,
+ )
return
self._layer = layer
self.refreshItems()
- if self.parameterDefinition().allowMultiple() and self.parameterDefinition().defaultToAllFields():
+ if (
+ self.parameterDefinition().allowMultiple()
+ and self.parameterDefinition().defaultToAllFields()
+ ):
self.setValue(self.getFields())
def refreshItems(self):
@@ -1654,12 +2173,26 @@ def getFields(self):
if self._layer is None:
return []
fieldTypes = []
- if self.parameterDefinition().dataType() == QgsProcessingParameterField.DataType.String:
+ if (
+ self.parameterDefinition().dataType()
+ == QgsProcessingParameterField.DataType.String
+ ):
fieldTypes = [QVariant.String]
- elif self.parameterDefinition().dataType() == QgsProcessingParameterField.DataType.Numeric:
- fieldTypes = [QVariant.Int, QVariant.Double, QVariant.LongLong,
- QVariant.UInt, QVariant.ULongLong]
- elif self.parameterDefinition().dataType() == QgsProcessingParameterField.DataType.DateTime:
+ elif (
+ self.parameterDefinition().dataType()
+ == QgsProcessingParameterField.DataType.Numeric
+ ):
+ fieldTypes = [
+ QVariant.Int,
+ QVariant.Double,
+ QVariant.LongLong,
+ QVariant.UInt,
+ QVariant.ULongLong,
+ ]
+ elif (
+ self.parameterDefinition().dataType()
+ == QgsProcessingParameterField.DataType.DateTime
+ ):
fieldTypes = [QVariant.Date, QVariant.Time, QVariant.DateTime]
fieldNames = []
@@ -1677,7 +2210,7 @@ def setValue(self, value):
options = self.widget.options
selected = []
if isinstance(value, str):
- value = value.split(';')
+ value = value.split(";")
for v in value:
for i, opt in enumerate(options):
@@ -1699,18 +2232,27 @@ def value(self):
return [self.widget.options[i] for i in self.widget.selectedoptions]
else:
f = self.widget.currentField()
- if self.parameterDefinition().flags() & QgsProcessingParameterDefinition.Flag.FlagOptional and not f:
+ if (
+ self.parameterDefinition().flags()
+ & QgsProcessingParameterDefinition.Flag.FlagOptional
+ and not f
+ ):
return None
return f
else:
+
def validator(v):
- return bool(v) or self.parameterDefinition().flags() & QgsProcessingParameterDefinition.Flag.FlagOptional
+ return (
+ bool(v)
+ or self.parameterDefinition().flags()
+ & QgsProcessingParameterDefinition.Flag.FlagOptional
+ )
return self.comboValue(validator)
class BandWidgetWrapper(WidgetWrapper):
- NOT_SET = '[Not set]'
+ NOT_SET = "[Not set]"
def __init__(self, param, dialog, row=0, col=0, **kwargs):
"""
@@ -1719,7 +2261,11 @@ def __init__(self, param, dialog, row=0, col=0, **kwargs):
"""
from warnings import warn
- warn("BandWidgetWrapper is deprecated and will be removed in QGIS 4.0", DeprecationWarning)
+
+ warn(
+ "BandWidgetWrapper is deprecated and will be removed in QGIS 4.0",
+ DeprecationWarning,
+ )
super().__init__(param, dialog, row, col, **kwargs)
self.context = dataobjects.createContext()
@@ -1731,15 +2277,27 @@ def createWidget(self):
if self.parameterDefinition().allowMultiple():
return MultipleInputPanel(options=[])
widget = QgsRasterBandComboBox()
- widget.setShowNotSetOption(self.parameterDefinition().flags() & QgsProcessingParameterDefinition.Flag.FlagOptional)
+ widget.setShowNotSetOption(
+ self.parameterDefinition().flags()
+ & QgsProcessingParameterDefinition.Flag.FlagOptional
+ )
widget.bandChanged.connect(lambda: self.widgetValueHasChanged.emit(self))
return widget
else:
widget = QComboBox()
widget.setEditable(True)
- fields = self.dialog.getAvailableValuesOfType([QgsProcessingParameterBand, QgsProcessingParameterDistance, QgsProcessingParameterNumber],
- [QgsProcessingOutputNumber])
- if self.parameterDefinition().flags() & QgsProcessingParameterDefinition.Flag.FlagOptional:
+ fields = self.dialog.getAvailableValuesOfType(
+ [
+ QgsProcessingParameterBand,
+ QgsProcessingParameterDistance,
+ QgsProcessingParameterNumber,
+ ],
+ [QgsProcessingOutputNumber],
+ )
+ if (
+ self.parameterDefinition().flags()
+ & QgsProcessingParameterDefinition.Flag.FlagOptional
+ ):
widget.addItem(self.NOT_SET, self.NOT_SET_OPTION)
for f in fields:
widget.addItem(self.dialog.resolveValueDescription(f), f)
@@ -1747,7 +2305,10 @@ def createWidget(self):
def postInitialize(self, wrappers):
for wrapper in wrappers:
- if wrapper.parameterDefinition().name() == self.parameterDefinition().parentLayerParameterName():
+ if (
+ wrapper.parameterDefinition().name()
+ == self.parameterDefinition().parentLayerParameterName()
+ ):
if self.dialogType in (DIALOG_STANDARD, DIALOG_BATCH):
self.setLayer(wrapper.parameterValue())
wrapper.widgetValueHasChanged.connect(self.parentValueChanged)
@@ -1773,7 +2334,7 @@ def getBands(self):
name = provider.generateBandName(band)
interpretation = provider.colorInterpretationName(band)
if interpretation != "Undefined":
- name = name + f' ({interpretation})'
+ name = name + f" ({interpretation})"
bands.append(name)
return bands
@@ -1794,11 +2355,11 @@ def setValue(self, value):
options = self.widget.options
selected = []
if isinstance(value, str):
- value = value.split(';')
+ value = value.split(";")
for v in value:
for i, opt in enumerate(options):
- match = re.search(f'(?:\\A|[^0-9]){v}(?:\\Z|[^0-9]|)', opt)
+ match = re.search(f"(?:\\A|[^0-9]){v}(?:\\Z|[^0-9]|)", opt)
if match:
selected.append(i)
@@ -1813,18 +2374,29 @@ def value(self):
if self.parameterDefinition().allowMultiple():
bands = []
for i in self.widget.selectedoptions:
- match = re.search('(?:\\A|[^0-9])([0-9]+)(?:\\Z|[^0-9]|)', self.widget.options[i])
+ match = re.search(
+ "(?:\\A|[^0-9])([0-9]+)(?:\\Z|[^0-9]|)", self.widget.options[i]
+ )
if match:
bands.append(match.group(1))
return bands
else:
f = self.widget.currentBand()
- if self.parameterDefinition().flags() & QgsProcessingParameterDefinition.Flag.FlagOptional and not f:
+ if (
+ self.parameterDefinition().flags()
+ & QgsProcessingParameterDefinition.Flag.FlagOptional
+ and not f
+ ):
return None
return f
else:
+
def validator(v):
- return bool(v) or self.parameterDefinition().flags() & QgsProcessingParameterDefinition.Flag.FlagOptional
+ return (
+ bool(v)
+ or self.parameterDefinition().flags()
+ & QgsProcessingParameterDefinition.Flag.FlagOptional
+ )
return self.comboValue(validator)
@@ -1836,43 +2408,52 @@ class WidgetWrapperFactory:
@staticmethod
def create_wrapper(param, dialog, row=0, col=0):
- wrapper_metadata = param.metadata().get('widget_wrapper', None)
+ wrapper_metadata = param.metadata().get("widget_wrapper", None)
# VERY messy logic here to avoid breaking 3.0 API which allowed metadata "widget_wrapper" value to be either
# a string name of a class OR a dict.
# TODO QGIS 4.0 -- require widget_wrapper to be a dict.
- if wrapper_metadata and (not isinstance(wrapper_metadata, dict) or wrapper_metadata.get('class', None) is not None):
- return WidgetWrapperFactory.create_wrapper_from_metadata(param, dialog, row, col)
+ if wrapper_metadata and (
+ not isinstance(wrapper_metadata, dict)
+ or wrapper_metadata.get("class", None) is not None
+ ):
+ return WidgetWrapperFactory.create_wrapper_from_metadata(
+ param, dialog, row, col
+ )
else:
# try from c++ registry first
class_type = dialog.__class__.__name__
- if class_type == 'ModelerParametersDialog':
- wrapper = QgsGui.processingGuiRegistry().createModelerParameterWidget(dialog.model,
- dialog.childId,
- param,
- dialog.context)
+ if class_type == "ModelerParametersDialog":
+ wrapper = QgsGui.processingGuiRegistry().createModelerParameterWidget(
+ dialog.model, dialog.childId, param, dialog.context
+ )
else:
- dialog_type = dialogTypes.get(class_type,
- QgsProcessingGui.WidgetType.Standard)
- wrapper = QgsGui.processingGuiRegistry().createParameterWidgetWrapper(param, dialog_type)
+ dialog_type = dialogTypes.get(
+ class_type, QgsProcessingGui.WidgetType.Standard
+ )
+ wrapper = QgsGui.processingGuiRegistry().createParameterWidgetWrapper(
+ param, dialog_type
+ )
if wrapper is not None:
wrapper.setDialog(dialog)
return wrapper
# fallback to Python registry
- return WidgetWrapperFactory.create_wrapper_from_class(param, dialog, row, col)
+ return WidgetWrapperFactory.create_wrapper_from_class(
+ param, dialog, row, col
+ )
@staticmethod
def create_wrapper_from_metadata(param, dialog, row=0, col=0):
- wrapper = param.metadata().get('widget_wrapper', None)
+ wrapper = param.metadata().get("widget_wrapper", None)
params = {}
# wrapper metadata should be a dict with class key
if isinstance(wrapper, dict):
params = deepcopy(wrapper)
- wrapper = params.pop('class')
+ wrapper = params.pop("class")
# wrapper metadata should be a class path
if isinstance(wrapper, str):
- tokens = wrapper.split('.')
- mod = __import__('.'.join(tokens[:-1]), fromlist=[tokens[-1]])
+ tokens = wrapper.split(".")
+ mod = __import__(".".join(tokens[:-1]), fromlist=[tokens[-1]])
wrapper = getattr(mod, tokens[-1])
# or directly a class object
if isclass(wrapper):
@@ -1883,63 +2464,63 @@ def create_wrapper_from_metadata(param, dialog, row=0, col=0):
@staticmethod
def create_wrapper_from_class(param, dialog, row=0, col=0):
wrapper = None
- if param.type() == 'boolean':
+ if param.type() == "boolean":
# deprecated, moved to c++
wrapper = BooleanWidgetWrapper
- elif param.type() == 'crs':
+ elif param.type() == "crs":
# deprecated, moved to c++
wrapper = CrsWidgetWrapper
- elif param.type() == 'extent':
+ elif param.type() == "extent":
# deprecated, moved to c++
wrapper = ExtentWidgetWrapper
- elif param.type() == 'point':
+ elif param.type() == "point":
# deprecated, moved to c++
wrapper = PointWidgetWrapper
- elif param.type() == 'file':
+ elif param.type() == "file":
# deprecated, moved to c++
wrapper = FileWidgetWrapper
- elif param.type() == 'multilayer':
+ elif param.type() == "multilayer":
wrapper = MultipleLayerWidgetWrapper
- elif param.type() == 'number':
+ elif param.type() == "number":
# deprecated, moved to c++
wrapper = NumberWidgetWrapper
- elif param.type() == 'distance':
+ elif param.type() == "distance":
# deprecated, moved to c++
wrapper = DistanceWidgetWrapper
- elif param.type() == 'raster':
+ elif param.type() == "raster":
# deprecated, moved to c++
wrapper = RasterWidgetWrapper
- elif param.type() == 'enum':
+ elif param.type() == "enum":
# deprecated, moved to c++
wrapper = EnumWidgetWrapper
- elif param.type() == 'string':
+ elif param.type() == "string":
# deprecated, moved to c++
wrapper = StringWidgetWrapper
- elif param.type() == 'expression':
+ elif param.type() == "expression":
# deprecated, moved to c++
wrapper = ExpressionWidgetWrapper
- elif param.type() == 'vector':
+ elif param.type() == "vector":
# deprecated, moved to c++
wrapper = VectorLayerWidgetWrapper
- elif param.type() == 'field':
+ elif param.type() == "field":
# deprecated, moved to c++
wrapper = TableFieldWidgetWrapper
- elif param.type() == 'source':
+ elif param.type() == "source":
# deprecated, moved to c++
wrapper = FeatureSourceWidgetWrapper
- elif param.type() == 'band':
+ elif param.type() == "band":
# deprecated, moved to c++
wrapper = BandWidgetWrapper
- elif param.type() == 'layer':
+ elif param.type() == "layer":
# deprecated, moved to c++
wrapper = MapLayerWidgetWrapper
- elif param.type() == 'range':
+ elif param.type() == "range":
# deprecated, moved to c++
wrapper = RangeWidgetWrapper
- elif param.type() == 'matrix':
+ elif param.type() == "matrix":
# deprecated, moved to c++
wrapper = FixedTableWidgetWrapper
- elif param.type() == 'mesh':
+ elif param.type() == "mesh":
# deprecated, moved to c++
wrapper = MeshWidgetWrapper
else:
diff --git a/python/plugins/processing/modeler/AddModelFromFileAction.py b/python/plugins/processing/modeler/AddModelFromFileAction.py
index c0631b8b8524..69772ff95e24 100644
--- a/python/plugins/processing/modeler/AddModelFromFileAction.py
+++ b/python/plugins/processing/modeler/AddModelFromFileAction.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'April 2014'
-__copyright__ = '(C) 201, Victor Olaya'
+__author__ = "Victor Olaya"
+__date__ = "April 2014"
+__copyright__ = "(C) 201, Victor Olaya"
import os
import shutil
@@ -35,48 +35,75 @@
class AddModelFromFileAction(ToolboxAction):
def __init__(self):
- self.name = QCoreApplication.translate('AddModelFromFileAction', 'Add Model to Toolbox…')
- self.group = self.tr('Tools')
+ self.name = QCoreApplication.translate(
+ "AddModelFromFileAction", "Add Model to Toolbox…"
+ )
+ self.group = self.tr("Tools")
def getIcon(self):
return QgsApplication.getThemeIcon("/processingModel.svg")
def execute(self):
settings = QgsSettings()
- lastDir = settings.value('Processing/lastModelsDir', QDir.homePath())
- filename, selected_filter = QFileDialog.getOpenFileName(self.toolbox,
- self.tr('Open Model', 'AddModelFromFileAction'), lastDir,
- self.tr('Processing models (*.model3 *.MODEL3)', 'AddModelFromFileAction'))
+ lastDir = settings.value("Processing/lastModelsDir", QDir.homePath())
+ filename, selected_filter = QFileDialog.getOpenFileName(
+ self.toolbox,
+ self.tr("Open Model", "AddModelFromFileAction"),
+ lastDir,
+ self.tr("Processing models (*.model3 *.MODEL3)", "AddModelFromFileAction"),
+ )
if filename:
- settings.setValue('Processing/lastModelsDir',
- QFileInfo(filename).absoluteDir().absolutePath())
+ settings.setValue(
+ "Processing/lastModelsDir",
+ QFileInfo(filename).absoluteDir().absolutePath(),
+ )
alg = QgsProcessingModelAlgorithm()
if not alg.fromFile(filename):
QMessageBox.warning(
self.toolbox,
- self.tr('Open Model', 'AddModelFromFileAction'),
- self.tr('The selected file does not contain a valid model', 'AddModelFromFileAction'))
+ self.tr("Open Model", "AddModelFromFileAction"),
+ self.tr(
+ "The selected file does not contain a valid model",
+ "AddModelFromFileAction",
+ ),
+ )
return
- if QgsApplication.instance().processingRegistry().algorithmById(f'model:{alg.id()}'):
+ if (
+ QgsApplication.instance()
+ .processingRegistry()
+ .algorithmById(f"model:{alg.id()}")
+ ):
QMessageBox.warning(
self.toolbox,
- self.tr('Open Model', 'AddModelFromFileAction'),
- self.tr('Model with the same name already exists', 'AddModelFromFileAction'))
+ self.tr("Open Model", "AddModelFromFileAction"),
+ self.tr(
+ "Model with the same name already exists",
+ "AddModelFromFileAction",
+ ),
+ )
return
- destFilename = os.path.join(ModelerUtils.modelsFolders()[0], os.path.basename(filename))
+ destFilename = os.path.join(
+ ModelerUtils.modelsFolders()[0], os.path.basename(filename)
+ )
if os.path.exists(destFilename):
reply = QMessageBox.question(
self.toolbox,
- self.tr('Open Model', 'AddModelFromFileAction'),
- self.tr('There is already a model file with the same name. Overwrite?', 'AddModelFromFileAction'),
+ self.tr("Open Model", "AddModelFromFileAction"),
+ self.tr(
+ "There is already a model file with the same name. Overwrite?",
+ "AddModelFromFileAction",
+ ),
QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No,
- QMessageBox.StandardButton.No)
+ QMessageBox.StandardButton.No,
+ )
if reply == QMessageBox.StandardButton.No:
return
shutil.copyfile(filename, destFilename)
- QgsApplication.processingRegistry().providerById('model').refreshAlgorithms()
+ QgsApplication.processingRegistry().providerById(
+ "model"
+ ).refreshAlgorithms()
diff --git a/python/plugins/processing/modeler/CreateNewModelAction.py b/python/plugins/processing/modeler/CreateNewModelAction.py
index 8ae7b815d466..5e3bcad91d39 100644
--- a/python/plugins/processing/modeler/CreateNewModelAction.py
+++ b/python/plugins/processing/modeler/CreateNewModelAction.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'August 2012'
-__copyright__ = '(C) 2012, Victor Olaya'
+__author__ = "Victor Olaya"
+__date__ = "August 2012"
+__copyright__ = "(C) 2012, Victor Olaya"
import os
@@ -35,8 +35,10 @@
class CreateNewModelAction(ToolboxAction):
def __init__(self):
- self.name = QCoreApplication.translate('CreateNewModelAction', 'Create New Model…')
- self.group = self.tr('Tools')
+ self.name = QCoreApplication.translate(
+ "CreateNewModelAction", "Create New Model…"
+ )
+ self.group = self.tr("Tools")
def getIcon(self):
return QgsApplication.getThemeIcon("/processingModel.svg")
@@ -47,4 +49,4 @@ def execute(self):
dlg.show()
def updateModel(self):
- QgsApplication.processingRegistry().providerById('model').refreshAlgorithms()
+ QgsApplication.processingRegistry().providerById("model").refreshAlgorithms()
diff --git a/python/plugins/processing/modeler/DeleteModelAction.py b/python/plugins/processing/modeler/DeleteModelAction.py
index 9eb472fa2e87..2774708d68a7 100644
--- a/python/plugins/processing/modeler/DeleteModelAction.py
+++ b/python/plugins/processing/modeler/DeleteModelAction.py
@@ -15,14 +15,12 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'August 2012'
-__copyright__ = '(C) 2012, Victor Olaya'
+__author__ = "Victor Olaya"
+__date__ = "August 2012"
+__copyright__ = "(C) 2012, Victor Olaya"
import os
-from qgis.core import (QgsApplication,
- QgsProcessingAlgorithm,
- QgsProject)
+from qgis.core import QgsApplication, QgsProcessingAlgorithm, QgsProject
from qgis.PyQt.QtWidgets import QMessageBox
from qgis.PyQt.QtCore import QCoreApplication
from processing.gui.ContextAction import ContextAction
@@ -33,10 +31,12 @@ class DeleteModelAction(ContextAction):
def __init__(self):
super().__init__()
- self.name = QCoreApplication.translate('DeleteModelAction', 'Delete Model…')
+ self.name = QCoreApplication.translate("DeleteModelAction", "Delete Model…")
def isEnabled(self):
- return isinstance(self.itemData, QgsProcessingAlgorithm) and self.itemData.provider().id() in ("model", "project")
+ return isinstance(
+ self.itemData, QgsProcessingAlgorithm
+ ) and self.itemData.provider().id() in ("model", "project")
def execute(self):
model = self.itemData
@@ -46,22 +46,32 @@ def execute(self):
project_provider = model.provider().id() == PROJECT_PROVIDER_ID
if project_provider:
- msg = self.tr('Are you sure you want to delete this model from the current project?', 'DeleteModelAction')
+ msg = self.tr(
+ "Are you sure you want to delete this model from the current project?",
+ "DeleteModelAction",
+ )
else:
- msg = self.tr('Are you sure you want to delete this model?', 'DeleteModelAction')
+ msg = self.tr(
+ "Are you sure you want to delete this model?", "DeleteModelAction"
+ )
reply = QMessageBox.question(
None,
- self.tr('Delete Model', 'DeleteModelAction'),
+ self.tr("Delete Model", "DeleteModelAction"),
msg,
QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No,
- QMessageBox.StandardButton.No)
+ QMessageBox.StandardButton.No,
+ )
if reply == QMessageBox.StandardButton.Yes:
if project_provider:
- provider = QgsApplication.processingRegistry().providerById(PROJECT_PROVIDER_ID)
+ provider = QgsApplication.processingRegistry().providerById(
+ PROJECT_PROVIDER_ID
+ )
provider.remove_model(model)
QgsProject.instance().setDirty(True)
else:
os.remove(model.sourceFilePath())
- QgsApplication.processingRegistry().providerById('model').refreshAlgorithms()
+ QgsApplication.processingRegistry().providerById(
+ "model"
+ ).refreshAlgorithms()
diff --git a/python/plugins/processing/modeler/EditModelAction.py b/python/plugins/processing/modeler/EditModelAction.py
index 9eb0fc287354..e7bc4e2c8668 100644
--- a/python/plugins/processing/modeler/EditModelAction.py
+++ b/python/plugins/processing/modeler/EditModelAction.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'August 2012'
-__copyright__ = '(C) 2012, Victor Olaya'
+__author__ = "Victor Olaya"
+__date__ = "August 2012"
+__copyright__ = "(C) 2012, Victor Olaya"
from qgis.PyQt.QtCore import QCoreApplication
from qgis.core import QgsApplication, QgsProcessingAlgorithm
@@ -31,10 +31,12 @@ class EditModelAction(ContextAction):
def __init__(self):
super().__init__()
- self.name = QCoreApplication.translate('EditModelAction', 'Edit Model…')
+ self.name = QCoreApplication.translate("EditModelAction", "Edit Model…")
def isEnabled(self):
- return isinstance(self.itemData, QgsProcessingAlgorithm) and self.itemData.provider().id() in ("model", "project")
+ return isinstance(
+ self.itemData, QgsProcessingAlgorithm
+ ) and self.itemData.provider().id() in ("model", "project")
def execute(self):
alg = self.itemData
@@ -44,4 +46,4 @@ def execute(self):
dlg.activate()
def updateModel(self):
- QgsApplication.processingRegistry().providerById('model').refreshAlgorithms()
+ QgsApplication.processingRegistry().providerById("model").refreshAlgorithms()
diff --git a/python/plugins/processing/modeler/ExportModelAsPythonScriptAction.py b/python/plugins/processing/modeler/ExportModelAsPythonScriptAction.py
index 8e84b6eb0838..ecca641352d9 100644
--- a/python/plugins/processing/modeler/ExportModelAsPythonScriptAction.py
+++ b/python/plugins/processing/modeler/ExportModelAsPythonScriptAction.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Nyall Dawson'
-__date__ = 'February 2019'
-__copyright__ = '(C) 2019, Nyall Dawson'
+__author__ = "Nyall Dawson"
+__date__ = "February 2019"
+__copyright__ = "(C) 2019, Nyall Dawson"
from qgis.PyQt.QtCore import QCoreApplication
from qgis.core import QgsProcessingAlgorithm, QgsProcessing, QgsApplication
@@ -31,17 +31,28 @@ class ExportModelAsPythonScriptAction(ContextAction):
def __init__(self):
super().__init__()
- self.name = QCoreApplication.translate('ExportModelAsPythonScriptAction', 'Export Model as Python Algorithm…')
+ self.name = QCoreApplication.translate(
+ "ExportModelAsPythonScriptAction", "Export Model as Python Algorithm…"
+ )
def isEnabled(self):
- return isinstance(self.itemData, QgsProcessingAlgorithm) and self.itemData.provider().id() in ("model", "project")
+ return isinstance(
+ self.itemData, QgsProcessingAlgorithm
+ ) and self.itemData.provider().id() in ("model", "project")
def icon(self):
- return QgsApplication.getThemeIcon('/mActionSaveAsPython.svg')
+ return QgsApplication.getThemeIcon("/mActionSaveAsPython.svg")
def execute(self):
alg = self.itemData
dlg = ScriptEditorDialog(parent=iface.mainWindow())
- dlg.editor.setText('\n'.join(alg.asPythonCode(QgsProcessing.PythonOutputType.PythonQgsProcessingAlgorithmSubclass, 4)))
+ dlg.editor.setText(
+ "\n".join(
+ alg.asPythonCode(
+ QgsProcessing.PythonOutputType.PythonQgsProcessingAlgorithmSubclass,
+ 4,
+ )
+ )
+ )
dlg.show()
diff --git a/python/plugins/processing/modeler/ModelerAlgorithmProvider.py b/python/plugins/processing/modeler/ModelerAlgorithmProvider.py
index 493b72734679..236412c58e34 100644
--- a/python/plugins/processing/modeler/ModelerAlgorithmProvider.py
+++ b/python/plugins/processing/modeler/ModelerAlgorithmProvider.py
@@ -15,30 +15,33 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'August 2012'
-__copyright__ = '(C) 2012, Victor Olaya'
+__author__ = "Victor Olaya"
+__date__ = "August 2012"
+__copyright__ = "(C) 2012, Victor Olaya"
import os
-from qgis.core import (Qgis,
- QgsApplication,
- QgsProcessingProvider,
- QgsMessageLog,
- QgsProcessingModelAlgorithm,
- QgsRuntimeProfiler)
+from qgis.core import (
+ Qgis,
+ QgsApplication,
+ QgsProcessingProvider,
+ QgsMessageLog,
+ QgsProcessingModelAlgorithm,
+ QgsRuntimeProfiler,
+)
from processing.core.ProcessingConfig import ProcessingConfig, Setting
from processing.gui.ContextAction import ContextAction
-from processing.gui.ProviderActions import (ProviderActions,
- ProviderContextMenuActions)
+from processing.gui.ProviderActions import ProviderActions, ProviderContextMenuActions
from processing.modeler.AddModelFromFileAction import AddModelFromFileAction
from processing.modeler.CreateNewModelAction import CreateNewModelAction
from processing.modeler.DeleteModelAction import DeleteModelAction
from processing.modeler.EditModelAction import EditModelAction
-from processing.modeler.ExportModelAsPythonScriptAction import ExportModelAsPythonScriptAction
+from processing.modeler.ExportModelAsPythonScriptAction import (
+ ExportModelAsPythonScriptAction,
+)
from processing.modeler.OpenModelFromFileAction import OpenModelFromFileAction
from processing.modeler.ModelerUtils import ModelerUtils
@@ -49,10 +52,19 @@ class ModelerAlgorithmProvider(QgsProcessingProvider):
def __init__(self):
super().__init__()
- self.actions = [CreateNewModelAction(), OpenModelFromFileAction(), AddModelFromFileAction()]
+ self.actions = [
+ CreateNewModelAction(),
+ OpenModelFromFileAction(),
+ AddModelFromFileAction(),
+ ]
sep_action = ContextAction()
sep_action.is_separator = True
- self.contextMenuActions = [EditModelAction(), DeleteModelAction(), sep_action, ExportModelAsPythonScriptAction()]
+ self.contextMenuActions = [
+ EditModelAction(),
+ DeleteModelAction(),
+ sep_action,
+ ExportModelAsPythonScriptAction(),
+ ]
self.algs = []
self.isLoading = False
@@ -67,13 +79,21 @@ def onProviderAdded(self, provider_id):
self.refreshAlgorithms()
def load(self):
- with QgsRuntimeProfiler.profile('Model Provider'):
+ with QgsRuntimeProfiler.profile("Model Provider"):
ProcessingConfig.settingIcons[self.name()] = self.icon()
- ProcessingConfig.addSetting(Setting(self.name(),
- ModelerUtils.MODELS_FOLDER, self.tr('Models folder', 'ModelerAlgorithmProvider'),
- ModelerUtils.defaultModelsFolder(), valuetype=Setting.MULTIPLE_FOLDERS))
+ ProcessingConfig.addSetting(
+ Setting(
+ self.name(),
+ ModelerUtils.MODELS_FOLDER,
+ self.tr("Models folder", "ModelerAlgorithmProvider"),
+ ModelerUtils.defaultModelsFolder(),
+ valuetype=Setting.MULTIPLE_FOLDERS,
+ )
+ )
ProviderActions.registerProviderActions(self, self.actions)
- ProviderContextMenuActions.registerProviderContextMenuActions(self.contextMenuActions)
+ ProviderContextMenuActions.registerProviderContextMenuActions(
+ self.contextMenuActions
+ )
ProcessingConfig.readSettings()
self.refreshAlgorithms()
@@ -81,16 +101,18 @@ def load(self):
def unload(self):
ProviderActions.deregisterProviderActions(self)
- ProviderContextMenuActions.deregisterProviderContextMenuActions(self.contextMenuActions)
+ ProviderContextMenuActions.deregisterProviderContextMenuActions(
+ self.contextMenuActions
+ )
def modelsFolder(self):
return ModelerUtils.modelsFolders()[0]
def name(self):
- return self.tr('Models', 'ModelerAlgorithmProvider')
+ return self.tr("Models", "ModelerAlgorithmProvider")
def id(self):
- return 'model'
+ return "model"
def icon(self):
return QgsApplication.getThemeIcon("/processingModel.svg")
@@ -102,7 +124,7 @@ def supportsNonFileBasedOutput(self):
return True
def loadAlgorithms(self):
- with QgsRuntimeProfiler.profile('Load model algorithms'):
+ with QgsRuntimeProfiler.profile("Load model algorithms"):
if self.isLoading:
return
self.isLoading = True
@@ -119,7 +141,7 @@ def loadFromFolder(self, folder):
return
for path, subdirs, files in os.walk(folder):
for descriptionFile in files:
- if descriptionFile.endswith('model3'):
+ if descriptionFile.endswith("model3"):
fullpath = os.path.join(path, descriptionFile)
alg = QgsProcessingModelAlgorithm()
@@ -128,5 +150,10 @@ def loadFromFolder(self, folder):
alg.setSourceFilePath(fullpath)
self.algs.append(alg)
else:
- QgsMessageLog.logMessage(self.tr('Could not load model {0}', 'ModelerAlgorithmProvider').format(descriptionFile),
- self.tr('Processing'), Qgis.MessageLevel.Critical)
+ QgsMessageLog.logMessage(
+ self.tr(
+ "Could not load model {0}", "ModelerAlgorithmProvider"
+ ).format(descriptionFile),
+ self.tr("Processing"),
+ Qgis.MessageLevel.Critical,
+ )
diff --git a/python/plugins/processing/modeler/ModelerDialog.py b/python/plugins/processing/modeler/ModelerDialog.py
index bbec5d6b0068..d4d2419c4cf6 100644
--- a/python/plugins/processing/modeler/ModelerDialog.py
+++ b/python/plugins/processing/modeler/ModelerDialog.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'August 2012'
-__copyright__ = '(C) 2012, Victor Olaya'
+__author__ = "Victor Olaya"
+__date__ = "August 2012"
+__copyright__ = "(C) 2012, Victor Olaya"
import os
import re
@@ -32,29 +32,34 @@
QPointF,
pyqtSignal,
QUrl,
- QFileInfo)
-from qgis.PyQt.QtWidgets import (QMessageBox,
- QFileDialog)
-from qgis.core import (Qgis,
- QgsApplication,
- QgsProcessing,
- QgsProject,
- QgsProcessingModelParameter,
- QgsProcessingModelAlgorithm,
- QgsSettings,
- QgsProcessingContext,
- QgsFileUtils
- )
-from qgis.gui import (QgsProcessingParameterDefinitionDialog,
- QgsProcessingParameterWidgetContext,
- QgsModelGraphicsScene,
- QgsModelDesignerDialog,
- QgsProcessingContextGenerator,
- QgsProcessingParametersGenerator)
+ QFileInfo,
+)
+from qgis.PyQt.QtWidgets import QMessageBox, QFileDialog
+from qgis.core import (
+ Qgis,
+ QgsApplication,
+ QgsProcessing,
+ QgsProject,
+ QgsProcessingModelParameter,
+ QgsProcessingModelAlgorithm,
+ QgsSettings,
+ QgsProcessingContext,
+ QgsFileUtils,
+)
+from qgis.gui import (
+ QgsProcessingParameterDefinitionDialog,
+ QgsProcessingParameterWidgetContext,
+ QgsModelGraphicsScene,
+ QgsModelDesignerDialog,
+ QgsProcessingContextGenerator,
+ QgsProcessingParametersGenerator,
+)
from qgis.utils import iface
from processing.gui.AlgorithmDialog import AlgorithmDialog
-from processing.modeler.ModelerParameterDefinitionDialog import ModelerParameterDefinitionDialog
+from processing.modeler.ModelerParameterDefinitionDialog import (
+ ModelerParameterDefinitionDialog,
+)
from processing.modeler.ModelerParametersDialog import ModelerParametersDialog
from processing.modeler.ModelerScene import ModelerScene
from processing.modeler.ModelerUtils import ModelerUtils
@@ -131,12 +136,18 @@ def saveInProject(self):
self.model().setSourceFilePath(None)
- project_provider = QgsApplication.processingRegistry().providerById(PROJECT_PROVIDER_ID)
+ project_provider = QgsApplication.processingRegistry().providerById(
+ PROJECT_PROVIDER_ID
+ )
project_provider.add_model(self.model())
self.update_model.emit()
- self.messageBar().pushMessage("", self.tr("Model was saved inside current project"), level=Qgis.MessageLevel.Success,
- duration=5)
+ self.messageBar().pushMessage(
+ "",
+ self.tr("Model was saved inside current project"),
+ level=Qgis.MessageLevel.Success,
+ duration=5,
+ )
self.setDirty(False)
QgsProject.instance().setDirty(True)
@@ -152,21 +163,25 @@ def saveModel(self, saveAs) -> bool:
if self.model().sourceFilePath():
initial_path = Path(self.model().sourceFilePath())
elif self.model().name():
- initial_path = Path(ModelerUtils.modelsFolders()[0]) / (self.model().name() + '.model3')
+ initial_path = Path(ModelerUtils.modelsFolders()[0]) / (
+ self.model().name() + ".model3"
+ )
else:
initial_path = Path(ModelerUtils.modelsFolders()[0])
- filename, _ = QFileDialog.getSaveFileName(self,
- self.tr('Save Model'),
- initial_path.as_posix(),
- self.tr('Processing models (*.model3 *.MODEL3)'))
+ filename, _ = QFileDialog.getSaveFileName(
+ self,
+ self.tr("Save Model"),
+ initial_path.as_posix(),
+ self.tr("Processing models (*.model3 *.MODEL3)"),
+ )
if not filename:
return False
- filename = QgsFileUtils.ensureFileNameHasExtension(filename, ['model3'])
+ filename = QgsFileUtils.ensureFileNameHasExtension(filename, ["model3"])
self.model().setSourceFilePath(filename)
- if not self.model().name() or self.model().name() == self.tr('model'):
+ if not self.model().name() or self.model().name() == self.tr("model"):
self.setModelName(Path(filename).stem)
elif saveAs and model_name_matched_file_name:
# if saving as, and the model name used to match the filename, then automatically update the
@@ -175,20 +190,35 @@ def saveModel(self, saveAs) -> bool:
if not self.model().toFile(filename):
if saveAs:
- QMessageBox.warning(self, self.tr('I/O error'),
- self.tr('Unable to save edits. Reason:\n {0}').format(str(sys.exc_info()[1])))
+ QMessageBox.warning(
+ self,
+ self.tr("I/O error"),
+ self.tr("Unable to save edits. Reason:\n {0}").format(
+ str(sys.exc_info()[1])
+ ),
+ )
else:
- QMessageBox.warning(self, self.tr("Can't save model"),
- self.tr(
- "This model can't be saved in its original location (probably you do not "
- "have permission to do it). Please, use the 'Save as…' option."))
+ QMessageBox.warning(
+ self,
+ self.tr("Can't save model"),
+ self.tr(
+ "This model can't be saved in its original location (probably you do not "
+ "have permission to do it). Please, use the 'Save as…' option."
+ ),
+ )
return False
self.update_model.emit()
if saveAs:
- self.messageBar().pushMessage("", self.tr("Model was saved to {} ").format(
- QUrl.fromLocalFile(filename).toString(), QDir.toNativeSeparators(filename)), level=Qgis.MessageLevel.Success,
- duration=5)
+ self.messageBar().pushMessage(
+ "",
+ self.tr('Model was saved to {} ').format(
+ QUrl.fromLocalFile(filename).toString(),
+ QDir.toNativeSeparators(filename),
+ ),
+ level=Qgis.MessageLevel.Success,
+ duration=5,
+ )
self.setDirty(False)
return True
@@ -198,25 +228,30 @@ def openModel(self):
return
settings = QgsSettings()
- last_dir = settings.value('Processing/lastModelsDir', QDir.homePath())
- filename, selected_filter = QFileDialog.getOpenFileName(self,
- self.tr('Open Model'),
- last_dir,
- self.tr('Processing models (*.model3 *.MODEL3)'))
+ last_dir = settings.value("Processing/lastModelsDir", QDir.homePath())
+ filename, selected_filter = QFileDialog.getOpenFileName(
+ self,
+ self.tr("Open Model"),
+ last_dir,
+ self.tr("Processing models (*.model3 *.MODEL3)"),
+ )
if filename:
- settings.setValue('Processing/lastModelsDir',
- QFileInfo(filename).absoluteDir().absolutePath())
+ settings.setValue(
+ "Processing/lastModelsDir",
+ QFileInfo(filename).absoluteDir().absolutePath(),
+ )
self.loadModel(filename)
def repaintModel(self, showControls=True):
scene = ModelerScene(self)
- scene.setSceneRect(QRectF(0, 0, self.CANVAS_SIZE,
- self.CANVAS_SIZE))
+ scene.setSceneRect(QRectF(0, 0, self.CANVAS_SIZE, self.CANVAS_SIZE))
if not showControls:
scene.setFlag(QgsModelGraphicsScene.Flag.FlagHideControls)
- showComments = QgsSettings().value("/Processing/Modeler/ShowComments", True, bool)
+ showComments = QgsSettings().value(
+ "/Processing/Modeler/ShowComments", True, bool
+ )
if not showComments:
scene.setFlag(QgsModelGraphicsScene.Flag.FlagHideComments)
@@ -251,7 +286,10 @@ def autogenerate_parameter_name(self, parameter):
parameter.setName(name)
def addInput(self, paramType, pos=None):
- if paramType not in [param.id() for param in QgsApplication.instance().processingRegistry().parameterTypes()]:
+ if paramType not in [
+ param.id()
+ for param in QgsApplication.instance().processingRegistry().parameterTypes()
+ ]:
return
new_param = None
@@ -265,10 +303,12 @@ def addInput(self, paramType, pos=None):
# yay, use new API!
context = createContext()
widget_context = self.create_widget_context()
- dlg = QgsProcessingParameterDefinitionDialog(type=paramType,
- context=context,
- widgetContext=widget_context,
- algorithm=self.model())
+ dlg = QgsProcessingParameterDefinitionDialog(
+ type=paramType,
+ context=context,
+ widgetContext=widget_context,
+ algorithm=self.model(),
+ )
dlg.registerProcessingContextGenerator(self.context_generator)
if dlg.exec():
new_param = dlg.createParameter()
@@ -285,11 +325,12 @@ def addInput(self, paramType, pos=None):
component.setPosition(pos)
component.comment().setDescription(comment)
- component.comment().setPosition(component.position() + QPointF(
- component.size().width(),
- -1.5 * component.size().height()))
+ component.comment().setPosition(
+ component.position()
+ + QPointF(component.size().width(), -1.5 * component.size().height())
+ )
- self.beginUndoCommand(self.tr('Add Model Input'))
+ self.beginUndoCommand(self.tr("Add Model Input"))
self.model().addModelParameter(new_param, component)
self.repaintModel()
# self.view().ensureVisible(self.scene.getLastParameterItem())
@@ -300,7 +341,12 @@ def getPositionForParameterItem(self):
BOX_WIDTH = 200
BOX_HEIGHT = 80
if len(self.model().parameterComponents()) > 0:
- maxX = max([i.position().x() for i in list(self.model().parameterComponents().values())])
+ maxX = max(
+ [
+ i.position().x()
+ for i in list(self.model().parameterComponents().values())
+ ]
+ )
newX = min(MARGIN + BOX_WIDTH + maxX, self.CANVAS_SIZE - BOX_WIDTH)
else:
newX = MARGIN + BOX_WIDTH / 2
@@ -319,17 +365,19 @@ def addAlgorithm(self, alg_id, pos=None):
else:
alg.setPosition(pos)
- alg.comment().setPosition(alg.position() + QPointF(
- alg.size().width(),
- -1.5 * alg.size().height()))
+ alg.comment().setPosition(
+ alg.position() + QPointF(alg.size().width(), -1.5 * alg.size().height())
+ )
output_offset_x = alg.size().width()
output_offset_y = 1.5 * alg.size().height()
for out in alg.modelOutputs():
- alg.modelOutput(out).setPosition(alg.position() + QPointF(output_offset_x, output_offset_y))
+ alg.modelOutput(out).setPosition(
+ alg.position() + QPointF(output_offset_x, output_offset_y)
+ )
output_offset_y += 1.5 * alg.modelOutput(out).size().height()
- self.beginUndoCommand(self.tr('Add Algorithm'))
+ self.beginUndoCommand(self.tr("Add Algorithm"))
id = self.model().addChildAlgorithm(alg)
self.repaintModel()
self.endUndoCommand()
@@ -337,10 +385,15 @@ def addAlgorithm(self, alg_id, pos=None):
res, errors = self.model().validateChildAlgorithm(id)
if not res:
self.view().scene().showWarning(
- QCoreApplication.translate('ModelerDialog', 'Algorithm “{}” is invalid').format(alg.description()),
- self.tr('Algorithm is Invalid'),
- QCoreApplication.translate('ModelerDialog', "The “{}” algorithm is invalid, because:
").format(alg.description(), ''.join(errors)),
- level=Qgis.MessageLevel.Warning
+ QCoreApplication.translate(
+ "ModelerDialog", "Algorithm “{}” is invalid"
+ ).format(alg.description()),
+ self.tr("Algorithm is Invalid"),
+ QCoreApplication.translate(
+ "ModelerDialog",
+ "The “{}” algorithm is invalid, because:
",
+ ).format(alg.description(), " ".join(errors)),
+ level=Qgis.MessageLevel.Warning,
)
else:
self.view().scene().messageBar().clearWidgets()
@@ -350,11 +403,20 @@ def getPositionForAlgorithmItem(self):
BOX_WIDTH = 200
BOX_HEIGHT = 80
if self.model().childAlgorithms():
- maxX = max([alg.position().x() for alg in list(self.model().childAlgorithms().values())])
- maxY = max([alg.position().y() for alg in list(self.model().childAlgorithms().values())])
+ maxX = max(
+ [
+ alg.position().x()
+ for alg in list(self.model().childAlgorithms().values())
+ ]
+ )
+ maxY = max(
+ [
+ alg.position().y()
+ for alg in list(self.model().childAlgorithms().values())
+ ]
+ )
newX = min(MARGIN + BOX_WIDTH + maxX, self.CANVAS_SIZE - BOX_WIDTH)
- newY = min(MARGIN + BOX_HEIGHT + maxY, self.CANVAS_SIZE
- - BOX_HEIGHT)
+ newY = min(MARGIN + BOX_HEIGHT + maxY, self.CANVAS_SIZE - BOX_HEIGHT)
else:
newX = MARGIN + BOX_WIDTH / 2
newY = MARGIN * 2 + BOX_HEIGHT + BOX_HEIGHT / 2
@@ -363,5 +425,12 @@ def getPositionForAlgorithmItem(self):
def exportAsScriptAlgorithm(self):
dlg = ScriptEditorDialog(parent=iface.mainWindow())
- dlg.editor.setText('\n'.join(self.model().asPythonCode(QgsProcessing.PythonOutputType.PythonQgsProcessingAlgorithmSubclass, 4)))
+ dlg.editor.setText(
+ "\n".join(
+ self.model().asPythonCode(
+ QgsProcessing.PythonOutputType.PythonQgsProcessingAlgorithmSubclass,
+ 4,
+ )
+ )
+ )
dlg.show()
diff --git a/python/plugins/processing/modeler/ModelerGraphicItem.py b/python/plugins/processing/modeler/ModelerGraphicItem.py
index 69e6e7dbf356..491779e6f565 100644
--- a/python/plugins/processing/modeler/ModelerGraphicItem.py
+++ b/python/plugins/processing/modeler/ModelerGraphicItem.py
@@ -15,26 +15,30 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'August 2012'
-__copyright__ = '(C) 2012, Victor Olaya'
+__author__ = "Victor Olaya"
+__date__ = "August 2012"
+__copyright__ = "(C) 2012, Victor Olaya"
from qgis.PyQt.QtCore import QCoreApplication
-from qgis.core import (QgsProcessingParameterDefinition,
- QgsProcessingModelOutput,
- QgsProcessingModelAlgorithm,
- QgsProject,
- Qgis)
+from qgis.core import (
+ QgsProcessingParameterDefinition,
+ QgsProcessingModelOutput,
+ QgsProcessingModelAlgorithm,
+ QgsProject,
+ Qgis,
+)
from qgis.gui import (
QgsProcessingParameterDefinitionDialog,
QgsProcessingParameterWidgetContext,
QgsModelParameterGraphicItem,
QgsModelChildAlgorithmGraphicItem,
QgsModelOutputGraphicItem,
- QgsProcessingContextGenerator
+ QgsProcessingContextGenerator,
+)
+from processing.modeler.ModelerParameterDefinitionDialog import (
+ ModelerParameterDefinitionDialog,
)
-from processing.modeler.ModelerParameterDefinitionDialog import ModelerParameterDefinitionDialog
from processing.modeler.ModelerParametersDialog import ModelerParametersDialog
from processing.tools.dataobjects import createContext
from qgis.utils import iface
@@ -78,7 +82,9 @@ def create_widget_context(self):
return widget_context
def edit(self, edit_comment=False):
- existing_param = self.model().parameterDefinition(self.component().parameterName())
+ existing_param = self.model().parameterDefinition(
+ self.component().parameterName()
+ )
old_name = existing_param.name()
old_description = existing_param.description()
@@ -87,8 +93,7 @@ def edit(self, edit_comment=False):
new_param = None
if ModelerParameterDefinitionDialog.use_legacy_dialog(param=existing_param):
# boo, old api
- dlg = ModelerParameterDefinitionDialog(self.model(),
- param=existing_param)
+ dlg = ModelerParameterDefinitionDialog(self.model(), param=existing_param)
dlg.setComments(comment)
dlg.setCommentColor(comment_color)
if edit_comment:
@@ -101,11 +106,13 @@ def edit(self, edit_comment=False):
# yay, use new API!
context = createContext()
widget_context = self.create_widget_context()
- dlg = QgsProcessingParameterDefinitionDialog(type=existing_param.type(),
- context=context,
- widgetContext=widget_context,
- definition=existing_param,
- algorithm=self.model())
+ dlg = QgsProcessingParameterDefinitionDialog(
+ type=existing_param.type(),
+ context=context,
+ widgetContext=widget_context,
+ definition=existing_param,
+ algorithm=self.model(),
+ )
dlg.setComments(comment)
dlg.setCommentColor(comment_color)
dlg.registerProcessingContextGenerator(self.context_generator)
@@ -122,7 +129,7 @@ def edit(self, edit_comment=False):
new_param.setName(safeName.lower())
if new_param is not None:
- self.aboutToChange.emit(self.tr('Edit {}').format(new_param.description()))
+ self.aboutToChange.emit(self.tr("Edit {}").format(new_param.description()))
self.model().removeModelParameter(self.component().parameterName())
if new_param.description() != old_description:
@@ -169,8 +176,12 @@ def __init__(self, element, model):
def edit(self, edit_comment=False):
elemAlg = self.component().algorithm()
- dlg = ModelerParametersDialog(elemAlg, self.model(), self.component().childId(),
- self.component().configuration())
+ dlg = ModelerParametersDialog(
+ elemAlg,
+ self.model(),
+ self.component().childId(),
+ self.component().configuration(),
+ )
dlg.setComments(self.component().comment().description())
dlg.setCommentColor(self.component().comment().color())
if edit_comment:
@@ -179,7 +190,7 @@ def edit(self, edit_comment=False):
alg = dlg.createAlgorithm()
alg.setChildId(self.component().childId())
alg.copyNonDefinitionPropertiesFromModel(self.model())
- self.aboutToChange.emit(self.tr('Edit {}').format(alg.description()))
+ self.aboutToChange.emit(self.tr("Edit {}").format(alg.description()))
self.model().setChildAlgorithm(alg)
self.requestModelRepaint.emit()
self.changed.emit()
@@ -187,10 +198,15 @@ def edit(self, edit_comment=False):
res, errors = self.model().validateChildAlgorithm(alg.childId())
if not res:
self.scene().showWarning(
- QCoreApplication.translate('ModelerGraphicItem', 'Algorithm “{}” is invalid').format(alg.description()),
- self.tr('Algorithm is Invalid'),
- QCoreApplication.translate('ModelerGraphicItem', "The “{}” algorithm is invalid, because:
").format(alg.description(), ' '.join(errors)),
- level=Qgis.MessageLevel.Warning
+ QCoreApplication.translate(
+ "ModelerGraphicItem", "Algorithm “{}” is invalid"
+ ).format(alg.description()),
+ self.tr("Algorithm is Invalid"),
+ QCoreApplication.translate(
+ "ModelerGraphicItem",
+ "The “{}” algorithm is invalid, because:
",
+ ).format(alg.description(), " ".join(errors)),
+ level=Qgis.MessageLevel.Warning,
)
else:
self.scene().messageBar().clearWidgets()
@@ -215,8 +231,12 @@ def __init__(self, element, model):
def edit(self, edit_comment=False):
child_alg = self.model().childAlgorithm(self.component().childId())
- dlg = ModelerParameterDefinitionDialog(self.model(),
- param=self.model().modelParameterFromChildIdAndOutputName(self.component().childId(), self.component().name()))
+ dlg = ModelerParameterDefinitionDialog(
+ self.model(),
+ param=self.model().modelParameterFromChildIdAndOutputName(
+ self.component().childId(), self.component().name()
+ ),
+ )
dlg.setComments(self.component().comment().description())
dlg.setCommentColor(self.component().comment().color())
if edit_comment:
@@ -225,19 +245,28 @@ def edit(self, edit_comment=False):
if dlg.exec():
model_outputs = child_alg.modelOutputs()
- model_output = QgsProcessingModelOutput(model_outputs[self.component().name()])
+ model_output = QgsProcessingModelOutput(
+ model_outputs[self.component().name()]
+ )
del model_outputs[self.component().name()]
model_output.setName(dlg.param.description())
model_output.setDescription(dlg.param.description())
model_output.setDefaultValue(dlg.param.defaultValue())
- model_output.setMandatory(not (dlg.param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional))
+ model_output.setMandatory(
+ not (
+ dlg.param.flags()
+ & QgsProcessingParameterDefinition.Flag.FlagOptional
+ )
+ )
model_output.comment().setDescription(dlg.comments())
model_output.comment().setColor(dlg.commentColor())
model_outputs[model_output.name()] = model_output
child_alg.setModelOutputs(model_outputs)
- self.aboutToChange.emit(self.tr('Edit {}').format(model_output.description()))
+ self.aboutToChange.emit(
+ self.tr("Edit {}").format(model_output.description())
+ )
self.model().updateDestinationParameters()
self.requestModelRepaint.emit()
diff --git a/python/plugins/processing/modeler/ModelerParameterDefinitionDialog.py b/python/plugins/processing/modeler/ModelerParameterDefinitionDialog.py
index f80f665bab3a..4960f1088a77 100644
--- a/python/plugins/processing/modeler/ModelerParameterDefinitionDialog.py
+++ b/python/plugins/processing/modeler/ModelerParameterDefinitionDialog.py
@@ -15,42 +15,43 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'August 2012'
-__copyright__ = '(C) 2012, Victor Olaya'
+__author__ = "Victor Olaya"
+__date__ = "August 2012"
+__copyright__ = "(C) 2012, Victor Olaya"
import math
-from qgis.PyQt.QtCore import (Qt,
- QByteArray,
- QCoreApplication)
-from qgis.PyQt.QtWidgets import (QDialog,
- QVBoxLayout,
- QLabel,
- QLineEdit,
- QComboBox,
- QCheckBox,
- QDialogButtonBox,
- QMessageBox,
- QTabWidget,
- QWidget,
- QTextEdit,
- QHBoxLayout)
+from qgis.PyQt.QtCore import Qt, QByteArray, QCoreApplication
+from qgis.PyQt.QtWidgets import (
+ QDialog,
+ QVBoxLayout,
+ QLabel,
+ QLineEdit,
+ QComboBox,
+ QCheckBox,
+ QDialogButtonBox,
+ QMessageBox,
+ QTabWidget,
+ QWidget,
+ QTextEdit,
+ QHBoxLayout,
+)
from qgis.PyQt.QtGui import QColor
-from qgis.gui import (QgsProcessingLayerOutputDestinationWidget,
- QgsColorButton)
-from qgis.core import (QgsApplication,
- QgsSettings,
- QgsProcessing,
- QgsProcessingParameterDefinition,
- QgsProcessingDestinationParameter,
- QgsProcessingParameterFeatureSink,
- QgsProcessingParameterFileDestination,
- QgsProcessingParameterFolderDestination,
- QgsProcessingParameterRasterDestination,
- QgsProcessingParameterVectorDestination,
- QgsProcessingModelAlgorithm)
+from qgis.gui import QgsProcessingLayerOutputDestinationWidget, QgsColorButton
+from qgis.core import (
+ QgsApplication,
+ QgsSettings,
+ QgsProcessing,
+ QgsProcessingParameterDefinition,
+ QgsProcessingDestinationParameter,
+ QgsProcessingParameterFeatureSink,
+ QgsProcessingParameterFileDestination,
+ QgsProcessingParameterFolderDestination,
+ QgsProcessingParameterRasterDestination,
+ QgsProcessingParameterVectorDestination,
+ QgsProcessingModelAlgorithm,
+)
from processing.core import parameters
from processing.modeler.exceptions import UndefinedParameterException
@@ -74,11 +75,17 @@ def __init__(self, alg, paramType=None, param=None):
self.setModal(True)
self.setupUi()
settings = QgsSettings()
- self.restoreGeometry(settings.value("/Processing/modelParametersDefinitionDialogGeometry", QByteArray()))
+ self.restoreGeometry(
+ settings.value(
+ "/Processing/modelParametersDefinitionDialogGeometry", QByteArray()
+ )
+ )
def closeEvent(self, event):
settings = QgsSettings()
- settings.setValue("/Processing/modelParametersDefinitionDialogGeometry", self.saveGeometry())
+ settings.setValue(
+ "/Processing/modelParametersDefinitionDialogGeometry", self.saveGeometry()
+ )
super().closeEvent(event)
def switchToCommentTab(self):
@@ -87,8 +94,12 @@ def switchToCommentTab(self):
self.commentEdit.selectAll()
def setupUi(self):
- type_metadata = QgsApplication.processingRegistry().parameterType(self.param.type() if self.param else self.paramType)
- self.setWindowTitle(self.tr('{} Parameter Definition').format(type_metadata.name()))
+ type_metadata = QgsApplication.processingRegistry().parameterType(
+ self.param.type() if self.param else self.paramType
+ )
+ self.setWindowTitle(
+ self.tr("{} Parameter Definition").format(type_metadata.name())
+ )
self.mainLayout = QVBoxLayout()
self.tab = QTabWidget()
@@ -98,7 +109,7 @@ def setupUi(self):
self.verticalLayout = QVBoxLayout()
- self.label = QLabel(self.tr('Parameter name'))
+ self.label = QLabel(self.tr("Parameter name"))
self.verticalLayout.addWidget(self.label)
self.nameTextBox = QLineEdit()
self.verticalLayout.addWidget(self.nameTextBox)
@@ -107,31 +118,44 @@ def setupUi(self):
self.nameTextBox.setText(self.param.description())
if isinstance(self.param, QgsProcessingDestinationParameter):
- self.verticalLayout.addWidget(QLabel(self.tr('Default value')))
- self.defaultWidget = QgsProcessingLayerOutputDestinationWidget(self.param, defaultSelection=True)
+ self.verticalLayout.addWidget(QLabel(self.tr("Default value")))
+ self.defaultWidget = QgsProcessingLayerOutputDestinationWidget(
+ self.param, defaultSelection=True
+ )
self.verticalLayout.addWidget(self.defaultWidget)
self.verticalLayout.addSpacing(20)
self.requiredCheck = QCheckBox()
- self.requiredCheck.setText(self.tr('Mandatory'))
+ self.requiredCheck.setText(self.tr("Mandatory"))
self.requiredCheck.setChecked(True)
if self.param is not None:
- self.requiredCheck.setChecked(not self.param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional)
+ self.requiredCheck.setChecked(
+ not self.param.flags()
+ & QgsProcessingParameterDefinition.Flag.FlagOptional
+ )
self.verticalLayout.addWidget(self.requiredCheck)
self.advancedCheck = QCheckBox()
- self.advancedCheck.setText(self.tr('Advanced'))
+ self.advancedCheck.setText(self.tr("Advanced"))
self.advancedCheck.setChecked(False)
if self.param is not None:
- self.advancedCheck.setChecked(self.param.flags() & QgsProcessingParameterDefinition.Flag.FlagAdvanced)
+ self.advancedCheck.setChecked(
+ self.param.flags() & QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
self.verticalLayout.addWidget(self.advancedCheck)
# If child algorithm output is mandatory, disable checkbox
if isinstance(self.param, QgsProcessingDestinationParameter):
- child = self.alg.childAlgorithms()[self.param.metadata()['_modelChildId']]
- model_output = child.modelOutput(self.param.metadata()['_modelChildOutputName'])
- param_def = child.algorithm().parameterDefinition(model_output.childOutputName())
- if not (param_def.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional):
+ child = self.alg.childAlgorithms()[self.param.metadata()["_modelChildId"]]
+ model_output = child.modelOutput(
+ self.param.metadata()["_modelChildOutputName"]
+ )
+ param_def = child.algorithm().parameterDefinition(
+ model_output.childOutputName()
+ )
+ if not (
+ param_def.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional
+ ):
self.requiredCheck.setEnabled(False)
self.requiredCheck.setChecked(True)
@@ -142,7 +166,7 @@ def setupUi(self):
w = QWidget()
w.setLayout(self.verticalLayout)
- self.tab.addTab(w, self.tr('Properties'))
+ self.tab.addTab(w, self.tr("Properties"))
self.commentLayout = QVBoxLayout()
self.commentEdit = QTextEdit()
@@ -151,23 +175,24 @@ def setupUi(self):
hl = QHBoxLayout()
hl.setContentsMargins(0, 0, 0, 0)
- hl.addWidget(QLabel(self.tr('Color')))
+ hl.addWidget(QLabel(self.tr("Color")))
self.comment_color_button = QgsColorButton()
self.comment_color_button.setAllowOpacity(True)
- self.comment_color_button.setWindowTitle(self.tr('Comment Color'))
- self.comment_color_button.setShowNull(True, self.tr('Default'))
+ self.comment_color_button.setWindowTitle(self.tr("Comment Color"))
+ self.comment_color_button.setShowNull(True, self.tr("Default"))
hl.addWidget(self.comment_color_button)
self.commentLayout.addLayout(hl)
w2 = QWidget()
w2.setLayout(self.commentLayout)
- self.tab.addTab(w2, self.tr('Comments'))
+ self.tab.addTab(w2, self.tr("Comments"))
self.buttonBox = QDialogButtonBox(self)
self.buttonBox.setOrientation(Qt.Orientation.Horizontal)
- self.buttonBox.setStandardButtons(QDialogButtonBox.StandardButton.Cancel |
- QDialogButtonBox.StandardButton.Ok)
- self.buttonBox.setObjectName('buttonBox')
+ self.buttonBox.setStandardButtons(
+ QDialogButtonBox.StandardButton.Cancel | QDialogButtonBox.StandardButton.Ok
+ )
+ self.buttonBox.setObjectName("buttonBox")
self.buttonBox.accepted.connect(self.accept)
self.buttonBox.rejected.connect(self.reject)
@@ -188,47 +213,59 @@ def setCommentColor(self, color):
self.comment_color_button.setToNull()
def commentColor(self):
- return self.comment_color_button.color() if not self.comment_color_button.isNull() else QColor()
+ return (
+ self.comment_color_button.color()
+ if not self.comment_color_button.isNull()
+ else QColor()
+ )
def accept(self):
description = self.nameTextBox.text()
- if description.strip() == '':
- QMessageBox.warning(self, self.tr('Unable to define parameter'),
- self.tr('Invalid parameter name'))
+ if description.strip() == "":
+ QMessageBox.warning(
+ self,
+ self.tr("Unable to define parameter"),
+ self.tr("Invalid parameter name"),
+ )
return
safeName = QgsProcessingModelAlgorithm.safeName(description)
name = safeName.lower()
# Destination parameter
- if (isinstance(self.param, QgsProcessingParameterFeatureSink)):
+ if isinstance(self.param, QgsProcessingParameterFeatureSink):
self.param = QgsProcessingParameterFeatureSink(
name=name,
description=description,
type=self.param.dataType(),
- defaultValue=self.defaultWidget.value())
- elif (isinstance(self.param, QgsProcessingParameterFileDestination)):
+ defaultValue=self.defaultWidget.value(),
+ )
+ elif isinstance(self.param, QgsProcessingParameterFileDestination):
self.param = QgsProcessingParameterFileDestination(
name=name,
description=description,
fileFilter=self.param.fileFilter(),
- defaultValue=self.defaultWidget.value())
- elif (isinstance(self.param, QgsProcessingParameterFolderDestination)):
+ defaultValue=self.defaultWidget.value(),
+ )
+ elif isinstance(self.param, QgsProcessingParameterFolderDestination):
self.param = QgsProcessingParameterFolderDestination(
name=name,
description=description,
- defaultValue=self.defaultWidget.value())
- elif (isinstance(self.param, QgsProcessingParameterRasterDestination)):
+ defaultValue=self.defaultWidget.value(),
+ )
+ elif isinstance(self.param, QgsProcessingParameterRasterDestination):
self.param = QgsProcessingParameterRasterDestination(
name=name,
description=description,
- defaultValue=self.defaultWidget.value())
- elif (isinstance(self.param, QgsProcessingParameterVectorDestination)):
+ defaultValue=self.defaultWidget.value(),
+ )
+ elif isinstance(self.param, QgsProcessingParameterVectorDestination):
self.param = QgsProcessingParameterVectorDestination(
name=name,
description=description,
type=self.param.dataType(),
- defaultValue=self.defaultWidget.value())
+ defaultValue=self.defaultWidget.value(),
+ )
else:
if self.paramType:
@@ -236,26 +273,40 @@ def accept(self):
else:
typeId = self.param.type()
- paramTypeDef = QgsApplication.instance().processingRegistry().parameterType(typeId)
+ paramTypeDef = (
+ QgsApplication.instance().processingRegistry().parameterType(typeId)
+ )
if not paramTypeDef:
- msg = self.tr('The parameter `{}` is not registered, are you missing a required plugin?').format(typeId)
+ msg = self.tr(
+ "The parameter `{}` is not registered, are you missing a required plugin?"
+ ).format(typeId)
raise UndefinedParameterException(msg)
self.param = paramTypeDef.create(name)
self.param.setDescription(description)
self.param.setMetadata(paramTypeDef.metadata())
if not self.requiredCheck.isChecked():
- self.param.setFlags(self.param.flags() | QgsProcessingParameterDefinition.Flag.FlagOptional)
+ self.param.setFlags(
+ self.param.flags() | QgsProcessingParameterDefinition.Flag.FlagOptional
+ )
else:
- self.param.setFlags(self.param.flags() & ~QgsProcessingParameterDefinition.Flag.FlagOptional)
+ self.param.setFlags(
+ self.param.flags() & ~QgsProcessingParameterDefinition.Flag.FlagOptional
+ )
if self.advancedCheck.isChecked():
- self.param.setFlags(self.param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
+ self.param.setFlags(
+ self.param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
else:
- self.param.setFlags(self.param.flags() & ~QgsProcessingParameterDefinition.Flag.FlagAdvanced)
+ self.param.setFlags(
+ self.param.flags() & ~QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
settings = QgsSettings()
- settings.setValue("/Processing/modelParametersDefinitionDialogGeometry", self.saveGeometry())
+ settings.setValue(
+ "/Processing/modelParametersDefinitionDialogGeometry", self.saveGeometry()
+ )
QDialog.accept(self)
@@ -263,6 +314,8 @@ def reject(self):
self.param = None
settings = QgsSettings()
- settings.setValue("/Processing/modelParametersDefinitionDialogGeometry", self.saveGeometry())
+ settings.setValue(
+ "/Processing/modelParametersDefinitionDialogGeometry", self.saveGeometry()
+ )
QDialog.reject(self)
diff --git a/python/plugins/processing/modeler/ModelerParametersDialog.py b/python/plugins/processing/modeler/ModelerParametersDialog.py
index eaedee37748b..fa221995a0ac 100644
--- a/python/plugins/processing/modeler/ModelerParametersDialog.py
+++ b/python/plugins/processing/modeler/ModelerParametersDialog.py
@@ -15,38 +15,53 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'August 2012'
-__copyright__ = '(C) 2012, Victor Olaya'
+__author__ = "Victor Olaya"
+__date__ = "August 2012"
+__copyright__ = "(C) 2012, Victor Olaya"
import webbrowser
from qgis.PyQt.QtCore import Qt
-from qgis.PyQt.QtWidgets import (QDialog, QDialogButtonBox, QLabel, QLineEdit,
- QFrame, QPushButton, QSizePolicy, QVBoxLayout,
- QHBoxLayout, QWidget, QTabWidget, QTextEdit)
+from qgis.PyQt.QtWidgets import (
+ QDialog,
+ QDialogButtonBox,
+ QLabel,
+ QLineEdit,
+ QFrame,
+ QPushButton,
+ QSizePolicy,
+ QVBoxLayout,
+ QHBoxLayout,
+ QWidget,
+ QTabWidget,
+ QTextEdit,
+)
from qgis.PyQt.QtGui import QColor
-from qgis.core import (Qgis,
- QgsProject,
- QgsProcessingParameterDefinition,
- QgsProcessingModelOutput,
- QgsProcessingModelChildAlgorithm,
- QgsProcessingModelChildParameterSource,
- QgsProcessingOutputDefinition)
-
-from qgis.gui import (QgsGui,
- QgsMessageBar,
- QgsScrollArea,
- QgsFilterLineEdit,
- QgsHelp,
- QgsProcessingContextGenerator,
- QgsProcessingModelerParameterWidget,
- QgsProcessingParameterWidgetContext,
- QgsPanelWidget,
- QgsPanelWidgetStack,
- QgsColorButton,
- QgsModelChildDependenciesWidget)
+from qgis.core import (
+ Qgis,
+ QgsProject,
+ QgsProcessingParameterDefinition,
+ QgsProcessingModelOutput,
+ QgsProcessingModelChildAlgorithm,
+ QgsProcessingModelChildParameterSource,
+ QgsProcessingOutputDefinition,
+)
+
+from qgis.gui import (
+ QgsGui,
+ QgsMessageBar,
+ QgsScrollArea,
+ QgsFilterLineEdit,
+ QgsHelp,
+ QgsProcessingContextGenerator,
+ QgsProcessingModelerParameterWidget,
+ QgsProcessingParameterWidgetContext,
+ QgsPanelWidget,
+ QgsPanelWidgetStack,
+ QgsColorButton,
+ QgsModelChildDependenciesWidget,
+)
from qgis.utils import iface
from processing.gui.wrappers import WidgetWrapperFactory
@@ -59,7 +74,7 @@ class ModelerParametersDialog(QDialog):
def __init__(self, alg, model, algName=None, configuration=None):
super().__init__()
- self.setObjectName('ModelerParametersDialog')
+ self.setObjectName("ModelerParametersDialog")
self.setModal(True)
if iface is not None:
@@ -72,14 +87,24 @@ def __init__(self, alg, model, algName=None, configuration=None):
self.configuration = configuration
self.context = createContext()
- self.setWindowTitle(' - '.join([self._alg.group(), self._alg.displayName()]) if self._alg.group() else self._alg.displayName())
+ self.setWindowTitle(
+ " - ".join([self._alg.group(), self._alg.displayName()])
+ if self._alg.group()
+ else self._alg.displayName()
+ )
- self.widget = ModelerParametersWidget(alg, model, algName, configuration, context=self.context, dialog=self)
+ self.widget = ModelerParametersWidget(
+ alg, model, algName, configuration, context=self.context, dialog=self
+ )
QgsGui.enableAutoGeometryRestore(self)
self.buttonBox = QDialogButtonBox()
self.buttonBox.setOrientation(Qt.Orientation.Horizontal)
- self.buttonBox.setStandardButtons(QDialogButtonBox.StandardButton.Cancel | QDialogButtonBox.StandardButton.Ok | QDialogButtonBox.StandardButton.Help)
+ self.buttonBox.setStandardButtons(
+ QDialogButtonBox.StandardButton.Cancel
+ | QDialogButtonBox.StandardButton.Ok
+ | QDialogButtonBox.StandardButton.Help
+ )
self.buttonBox.accepted.connect(self.okPressed)
self.buttonBox.rejected.connect(self.reject)
@@ -119,28 +144,47 @@ def getAvailableValuesOfType(self, paramType, outTypes=[], dataTypes=[]):
elif not isinstance(outTypes, (tuple, list)):
outTypes = [outTypes]
- return self.model.availableSourcesForChild(self.childId, [p.typeName() for p in paramType if
- issubclass(p, QgsProcessingParameterDefinition)],
- [o.typeName() for o in outTypes if
- issubclass(o, QgsProcessingOutputDefinition)], dataTypes)
+ return self.model.availableSourcesForChild(
+ self.childId,
+ [
+ p.typeName()
+ for p in paramType
+ if issubclass(p, QgsProcessingParameterDefinition)
+ ],
+ [
+ o.typeName()
+ for o in outTypes
+ if issubclass(o, QgsProcessingOutputDefinition)
+ ],
+ dataTypes,
+ )
def resolveValueDescription(self, value):
if isinstance(value, QgsProcessingModelChildParameterSource):
if value.source() == Qgis.ProcessingModelChildParameterSource.StaticValue:
return value.staticValue()
- elif value.source() == Qgis.ProcessingModelChildParameterSource.ModelParameter:
- return self.model.parameterDefinition(value.parameterName()).description()
+ elif (
+ value.source()
+ == Qgis.ProcessingModelChildParameterSource.ModelParameter
+ ):
+ return self.model.parameterDefinition(
+ value.parameterName()
+ ).description()
elif value.source() == Qgis.ProcessingModelChildParameterSource.ChildOutput:
alg = self.model.childAlgorithm(value.outputChildId())
- output_name = alg.algorithm().outputDefinition(value.outputName()).description()
+ output_name = (
+ alg.algorithm().outputDefinition(value.outputName()).description()
+ )
# see if this output has been named by the model designer -- if so, we use that friendly name
for name, output in alg.modelOutputs().items():
if output.childOutputName() == value.outputName():
output_name = name
break
- return self.tr("'{0}' from algorithm '{1}'").format(output_name, alg.description())
+ return self.tr("'{0}' from algorithm '{1}'").format(
+ output_name, alg.description()
+ )
return value
@@ -157,9 +201,13 @@ def okPressed(self):
def openHelp(self):
algHelp = self.widget.algorithm().helpUrl()
if not algHelp:
- algHelp = QgsHelp.helpUrl("processing_algs/{}/{}.html#{}".format(
- self.widget.algorithm().provider().helpId(), self.algorithm().groupId(),
- f"{self.algorithm().provider().helpId()}{self.algorithm().name()}")).toString()
+ algHelp = QgsHelp.helpUrl(
+ "processing_algs/{}/{}.html#{}".format(
+ self.widget.algorithm().provider().helpId(),
+ self.algorithm().groupId(),
+ f"{self.algorithm().provider().helpId()}{self.algorithm().name()}",
+ )
+ ).toString()
if algHelp not in [None, ""]:
webbrowser.open(algHelp)
@@ -167,7 +215,9 @@ def openHelp(self):
class ModelerParametersPanelWidget(QgsPanelWidget):
- def __init__(self, alg, model, algName=None, configuration=None, dialog=None, context=None):
+ def __init__(
+ self, alg, model, algName=None, configuration=None, dialog=None, context=None
+ ):
super().__init__()
self._alg = alg # The algorithm to define in this dialog. It is an instance of QgsProcessingAlgorithm
self.model = model # The model this algorithm is going to be added to. It is an instance of QgsProcessingModelAlgorithm
@@ -231,10 +281,16 @@ def setupUi(self):
widget_context.setModel(self.model)
widget_context.setModelChildAlgorithmId(self.childId)
- self.algorithmItem = QgsGui.instance().processingGuiRegistry().algorithmConfigurationWidget(self._alg)
+ self.algorithmItem = (
+ QgsGui.instance()
+ .processingGuiRegistry()
+ .algorithmConfigurationWidget(self._alg)
+ )
if self.algorithmItem:
self.algorithmItem.setWidgetContext(widget_context)
- self.algorithmItem.registerProcessingContextGenerator(self.context_generator)
+ self.algorithmItem.registerProcessingContextGenerator(
+ self.context_generator
+ )
if self.configuration:
self.algorithmItem.setConfiguration(self.configuration)
self.verticalLayout.addWidget(self.algorithmItem)
@@ -242,16 +298,18 @@ def setupUi(self):
for param in self._alg.parameterDefinitions():
if param.flags() & QgsProcessingParameterDefinition.Flag.FlagAdvanced:
self.advancedButton = QPushButton()
- self.advancedButton.setText(self.tr('Show advanced parameters'))
- self.advancedButton.clicked.connect(
- self.showAdvancedParametersClicked)
+ self.advancedButton.setText(self.tr("Show advanced parameters"))
+ self.advancedButton.clicked.connect(self.showAdvancedParametersClicked)
advancedButtonHLayout = QHBoxLayout()
advancedButtonHLayout.addWidget(self.advancedButton)
advancedButtonHLayout.addStretch()
self.verticalLayout.addLayout(advancedButtonHLayout)
break
for param in self._alg.parameterDefinitions():
- if param.isDestination() or param.flags() & QgsProcessingParameterDefinition.Flag.FlagHidden:
+ if (
+ param.isDestination()
+ or param.flags() & QgsProcessingParameterDefinition.Flag.FlagHidden
+ ):
continue
wrapper = WidgetWrapperFactory.create_wrapper(param, self.dialog)
@@ -283,10 +341,9 @@ def setupUi(self):
if output.flags() & QgsProcessingParameterDefinition.Flag.FlagHidden:
continue
- widget = QgsGui.processingGuiRegistry().createModelerParameterWidget(self.model,
- self.childId,
- output,
- self.context)
+ widget = QgsGui.processingGuiRegistry().createModelerParameterWidget(
+ self.model, self.childId, output, self.context
+ )
widget.setDialog(self.dialog)
widget.setWidgetContext(widget_context)
widget.registerProcessingContextGenerator(self.context_generator)
@@ -294,8 +351,10 @@ def setupUi(self):
self.wrappers[output.name()] = widget
item = QgsFilterLineEdit()
- if hasattr(item, 'setPlaceholderText'):
- item.setPlaceholderText(self.tr('[Enter name if this is a final result]'))
+ if hasattr(item, "setPlaceholderText"):
+ item.setPlaceholderText(
+ self.tr("[Enter name if this is a final result]")
+ )
label = widget.createLabel()
if label is not None:
@@ -303,10 +362,12 @@ def setupUi(self):
self.verticalLayout.addWidget(widget)
- label = QLabel(' ')
+ label = QLabel(" ")
self.verticalLayout.addWidget(label)
- label = QLabel(self.tr('Dependencies'))
- self.dependencies_panel = QgsModelChildDependenciesWidget(self, self.model, self.childId)
+ label = QLabel(self.tr("Dependencies"))
+ self.dependencies_panel = QgsModelChildDependenciesWidget(
+ self, self.model, self.childId
+ )
self.verticalLayout.addWidget(label)
self.verticalLayout.addWidget(self.dependencies_panel)
self.verticalLayout.addStretch(1000)
@@ -333,9 +394,9 @@ def setupUi(self):
def showAdvancedParametersClicked(self):
self.showAdvanced = not self.showAdvanced
if self.showAdvanced:
- self.advancedButton.setText(self.tr('Hide advanced parameters'))
+ self.advancedButton.setText(self.tr("Hide advanced parameters"))
else:
- self.advancedButton.setText(self.tr('Show advanced parameters'))
+ self.advancedButton.setText(self.tr("Show advanced parameters"))
for param in self._alg.parameterDefinitions():
if param.flags() & QgsProcessingParameterDefinition.Flag.FlagAdvanced:
wrapper = self.wrappers[param.name()]
@@ -352,7 +413,10 @@ def setPreviousValues(self):
self.descriptionBox.setText(alg.description())
for param in alg.algorithm().parameterDefinitions():
- if param.isDestination() or param.flags() & QgsProcessingParameterDefinition.Flag.FlagHidden:
+ if (
+ param.isDestination()
+ or param.flags() & QgsProcessingParameterDefinition.Flag.FlagHidden
+ ):
continue
value = None
if param.name() in alg.parameterSources():
@@ -365,15 +429,20 @@ def setPreviousValues(self):
wrapper = self.wrappers[param.name()]
if issubclass(wrapper.__class__, QgsProcessingModelerParameterWidget):
if value is None:
- value = QgsProcessingModelChildParameterSource.fromStaticValue(param.defaultValue())
+ value = QgsProcessingModelChildParameterSource.fromStaticValue(
+ param.defaultValue()
+ )
wrapper.setWidgetValue(value)
else:
if value is None:
value = param.defaultValue()
- if isinstance(value,
- QgsProcessingModelChildParameterSource) and value.source() == Qgis.ProcessingModelChildParameterSource.StaticValue:
+ if (
+ isinstance(value, QgsProcessingModelChildParameterSource)
+ and value.source()
+ == Qgis.ProcessingModelChildParameterSource.StaticValue
+ ):
value = value.staticValue()
wrapper.setValue(value)
@@ -383,14 +452,20 @@ def setPreviousValues(self):
model_output_name = None
for name, out in alg.modelOutputs().items():
- if out.childId() == self.childId and out.childOutputName() == output.name():
+ if (
+ out.childId() == self.childId
+ and out.childOutputName() == output.name()
+ ):
# this destination parameter is linked to a model output
model_output_name = out.name()
self.previous_output_definitions[output.name()] = out
break
value = None
- if model_output_name is None and output.name() in alg.parameterSources():
+ if (
+ model_output_name is None
+ and output.name() in alg.parameterSources()
+ ):
value = alg.parameterSources()[output.name()]
if isinstance(value, list) and len(value) == 1:
value = value[0]
@@ -403,7 +478,9 @@ def setPreviousValues(self):
wrapper.setToModelOutput(model_output_name)
elif value is not None or output.defaultValue() is not None:
if value is None:
- value = QgsProcessingModelChildParameterSource.fromStaticValue(output.defaultValue())
+ value = QgsProcessingModelChildParameterSource.fromStaticValue(
+ output.defaultValue()
+ )
wrapper.setWidgetValue(value)
@@ -420,7 +497,10 @@ def createAlgorithm(self):
alg.setConfiguration(self.algorithmItem.configuration())
self._alg = alg.algorithm().create(self.algorithmItem.configuration())
for param in self._alg.parameterDefinitions():
- if param.isDestination() or param.flags() & QgsProcessingParameterDefinition.Flag.FlagHidden:
+ if (
+ param.isDestination()
+ or param.flags() & QgsProcessingParameterDefinition.Flag.FlagHidden
+ ):
continue
try:
wrapper = self.wrappers[param.name()]
@@ -435,16 +515,29 @@ def createAlgorithm(self):
if isinstance(val, QgsProcessingModelChildParameterSource):
val = [val]
- elif not (isinstance(val, list) and all(
- [isinstance(subval, QgsProcessingModelChildParameterSource) for subval in val])):
+ elif not (
+ isinstance(val, list)
+ and all(
+ [
+ isinstance(subval, QgsProcessingModelChildParameterSource)
+ for subval in val
+ ]
+ )
+ ):
val = [QgsProcessingModelChildParameterSource.fromStaticValue(val)]
valid = True
for subval in val:
- if (isinstance(subval, QgsProcessingModelChildParameterSource)
- and subval.source() == Qgis.ProcessingModelChildParameterSource.StaticValue
- and not param.checkValueIsAcceptable(subval.staticValue())) \
- or (subval is None and not param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional):
+ if (
+ isinstance(subval, QgsProcessingModelChildParameterSource)
+ and subval.source()
+ == Qgis.ProcessingModelChildParameterSource.StaticValue
+ and not param.checkValueIsAcceptable(subval.staticValue())
+ ) or (
+ subval is None
+ and not param.flags()
+ & QgsProcessingParameterDefinition.Flag.FlagOptional
+ ):
valid = False
break
@@ -461,7 +554,9 @@ def createAlgorithm(self):
if name:
# if there was a previous output definition already for this output, we start with it,
# otherwise we'll lose any existing output comments, coloring, position, etc
- model_output = self.previous_output_definitions.get(output.name(), QgsProcessingModelOutput(name, name))
+ model_output = self.previous_output_definitions.get(
+ output.name(), QgsProcessingModelOutput(name, name)
+ )
model_output.setDescription(name)
model_output.setChildId(alg.childId())
model_output.setChildOutputName(output.name())
@@ -476,7 +571,9 @@ def createAlgorithm(self):
if output.flags() & QgsProcessingParameterDefinition.Flag.FlagIsModelOutput:
if output.name() not in outputs:
- model_output = QgsProcessingModelOutput(output.name(), output.name())
+ model_output = QgsProcessingModelOutput(
+ output.name(), output.name()
+ )
model_output.setChildId(alg.childId())
model_output.setChildOutputName(output.name())
outputs[output.name()] = model_output
@@ -489,7 +586,9 @@ def createAlgorithm(self):
class ModelerParametersWidget(QWidget):
- def __init__(self, alg, model, algName=None, configuration=None, dialog=None, context=None):
+ def __init__(
+ self, alg, model, algName=None, configuration=None, dialog=None, context=None
+ ):
super().__init__()
self._alg = alg # The algorithm to define in this dialog. It is an instance of QgsProcessingAlgorithm
self.model = model # The model this algorithm is going to be added to. It is an instance of QgsProcessingModelAlgorithm
@@ -498,7 +597,9 @@ def __init__(self, alg, model, algName=None, configuration=None, dialog=None, co
self.context = context
self.dialog = dialog
- self.widget = ModelerParametersPanelWidget(alg, model, algName, configuration, dialog, context)
+ self.widget = ModelerParametersPanelWidget(
+ alg, model, algName, configuration, dialog, context
+ )
class ContextGenerator(QgsProcessingContextGenerator):
@@ -532,7 +633,7 @@ def setupUi(self):
self.widget.setDockMode(True)
self.param_widget.setMainPanel(self.widget)
- self.tab.addTab(self.param_widget, self.tr('Properties'))
+ self.tab.addTab(self.param_widget, self.tr("Properties"))
self.commentLayout = QVBoxLayout()
self.commentEdit = QTextEdit()
@@ -541,17 +642,17 @@ def setupUi(self):
hl = QHBoxLayout()
hl.setContentsMargins(0, 0, 0, 0)
- hl.addWidget(QLabel(self.tr('Color')))
+ hl.addWidget(QLabel(self.tr("Color")))
self.comment_color_button = QgsColorButton()
self.comment_color_button.setAllowOpacity(True)
- self.comment_color_button.setWindowTitle(self.tr('Comment Color'))
- self.comment_color_button.setShowNull(True, self.tr('Default'))
+ self.comment_color_button.setWindowTitle(self.tr("Comment Color"))
+ self.comment_color_button.setShowNull(True, self.tr("Default"))
hl.addWidget(self.comment_color_button)
self.commentLayout.addLayout(hl)
w2 = QWidget()
w2.setLayout(self.commentLayout)
- self.tab.addTab(w2, self.tr('Comments'))
+ self.tab.addTab(w2, self.tr("Comments"))
self.setLayout(self.mainLayout)
@@ -568,7 +669,11 @@ def setCommentColor(self, color):
self.comment_color_button.setToNull()
def commentColor(self):
- return self.comment_color_button.color() if not self.comment_color_button.isNull() else QColor()
+ return (
+ self.comment_color_button.color()
+ if not self.comment_color_button.isNull()
+ else QColor()
+ )
def setPreviousValues(self):
self.widget.setPreviousValues()
diff --git a/python/plugins/processing/modeler/ModelerScene.py b/python/plugins/processing/modeler/ModelerScene.py
index b093df0284e0..2ac2b329beec 100644
--- a/python/plugins/processing/modeler/ModelerScene.py
+++ b/python/plugins/processing/modeler/ModelerScene.py
@@ -15,15 +15,15 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'August 2012'
-__copyright__ = '(C) 2012, Victor Olaya'
+__author__ = "Victor Olaya"
+__date__ = "August 2012"
+__copyright__ = "(C) 2012, Victor Olaya"
from qgis.gui import QgsModelGraphicsScene
from processing.modeler.ModelerGraphicItem import (
ModelerInputGraphicItem,
ModelerOutputGraphicItem,
- ModelerChildAlgorithmGraphicItem
+ ModelerChildAlgorithmGraphicItem,
)
diff --git a/python/plugins/processing/modeler/ModelerUtils.py b/python/plugins/processing/modeler/ModelerUtils.py
index d8593ed9b136..1fc539da0778 100644
--- a/python/plugins/processing/modeler/ModelerUtils.py
+++ b/python/plugins/processing/modeler/ModelerUtils.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'August 2012'
-__copyright__ = '(C) 2012, Victor Olaya'
+__author__ = "Victor Olaya"
+__date__ = "August 2012"
+__copyright__ = "(C) 2012, Victor Olaya"
import os
from processing.tools.system import userFolder, mkdir
@@ -25,11 +25,11 @@
class ModelerUtils:
- MODELS_FOLDER = 'MODELS_FOLDER'
+ MODELS_FOLDER = "MODELS_FOLDER"
@staticmethod
def defaultModelsFolder():
- folder = str(os.path.join(userFolder(), 'models'))
+ folder = str(os.path.join(userFolder(), "models"))
mkdir(folder)
return os.path.abspath(folder)
@@ -37,6 +37,6 @@ def defaultModelsFolder():
def modelsFolders():
folder = ProcessingConfig.getSetting(ModelerUtils.MODELS_FOLDER)
if folder is not None:
- return folder.split(';')
+ return folder.split(";")
else:
return [ModelerUtils.defaultModelsFolder()]
diff --git a/python/plugins/processing/modeler/MultilineTextPanel.py b/python/plugins/processing/modeler/MultilineTextPanel.py
index eb5ff36fb115..01745c4ed782 100644
--- a/python/plugins/processing/modeler/MultilineTextPanel.py
+++ b/python/plugins/processing/modeler/MultilineTextPanel.py
@@ -15,11 +15,17 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'January 2013'
-__copyright__ = '(C) 2013, Victor Olaya'
+__author__ = "Victor Olaya"
+__date__ = "January 2013"
+__copyright__ = "(C) 2013, Victor Olaya"
-from qgis.PyQt.QtWidgets import QComboBox, QPlainTextEdit, QSizePolicy, QVBoxLayout, QWidget
+from qgis.PyQt.QtWidgets import (
+ QComboBox,
+ QPlainTextEdit,
+ QSizePolicy,
+ QVBoxLayout,
+ QWidget,
+)
class MultilineTextPanel(QWidget):
@@ -32,11 +38,12 @@ def __init__(self, options, parent=None):
self.verticalLayout.setSpacing(2)
self.verticalLayout.setMargin(0)
self.combo = QComboBox()
- self.combo.addItem(self.tr('[Use text below]'))
+ self.combo.addItem(self.tr("[Use text below]"))
for option in options:
self.combo.addItem(option[0], option[1])
- self.combo.setSizePolicy(QSizePolicy.Policy.Expanding,
- QSizePolicy.Policy.Expanding)
+ self.combo.setSizePolicy(
+ QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding
+ )
self.verticalLayout.addWidget(self.combo)
self.textBox = QPlainTextEdit()
self.verticalLayout.addWidget(self.textBox)
diff --git a/python/plugins/processing/modeler/OpenModelFromFileAction.py b/python/plugins/processing/modeler/OpenModelFromFileAction.py
index 63ad25a6e79c..540713d13ae8 100644
--- a/python/plugins/processing/modeler/OpenModelFromFileAction.py
+++ b/python/plugins/processing/modeler/OpenModelFromFileAction.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Nyall Dawson'
-__date__ = 'February 2018'
-__copyright__ = '(C) 2018, Nyall Dawson'
+__author__ = "Nyall Dawson"
+__date__ = "February 2018"
+__copyright__ = "(C) 2018, Nyall Dawson"
import os
from qgis.PyQt.QtWidgets import QFileDialog
@@ -34,21 +34,28 @@
class OpenModelFromFileAction(ToolboxAction):
def __init__(self):
- self.name = QCoreApplication.translate('OpenModelFromFileAction', 'Open Existing Model…')
- self.group = self.tr('Tools')
+ self.name = QCoreApplication.translate(
+ "OpenModelFromFileAction", "Open Existing Model…"
+ )
+ self.group = self.tr("Tools")
def getIcon(self):
return QgsApplication.getThemeIcon("/processingModel.svg")
def execute(self):
settings = QgsSettings()
- lastDir = settings.value('Processing/lastModelsDir', QDir.homePath())
- filename, selected_filter = QFileDialog.getOpenFileName(self.toolbox,
- self.tr('Open Model', 'AddModelFromFileAction'), lastDir,
- self.tr('Processing models (*.model3 *.MODEL3)', 'AddModelFromFileAction'))
+ lastDir = settings.value("Processing/lastModelsDir", QDir.homePath())
+ filename, selected_filter = QFileDialog.getOpenFileName(
+ self.toolbox,
+ self.tr("Open Model", "AddModelFromFileAction"),
+ lastDir,
+ self.tr("Processing models (*.model3 *.MODEL3)", "AddModelFromFileAction"),
+ )
if filename:
- settings.setValue('Processing/lastModelsDir',
- QFileInfo(filename).absoluteDir().absolutePath())
+ settings.setValue(
+ "Processing/lastModelsDir",
+ QFileInfo(filename).absoluteDir().absolutePath(),
+ )
dlg = ModelerDialog.create()
dlg.loadModel(filename)
diff --git a/python/plugins/processing/modeler/ProjectProvider.py b/python/plugins/processing/modeler/ProjectProvider.py
index 88708f4c6b75..e362000a1eb9 100644
--- a/python/plugins/processing/modeler/ProjectProvider.py
+++ b/python/plugins/processing/modeler/ProjectProvider.py
@@ -15,20 +15,22 @@
***************************************************************************
"""
-__author__ = 'Nyall Dawson'
-__date__ = 'July 2018'
-__copyright__ = '(C) 2018, Nyall Dawson'
+__author__ = "Nyall Dawson"
+__date__ = "July 2018"
+__copyright__ = "(C) 2018, Nyall Dawson"
-from qgis.core import (Qgis,
- QgsApplication,
- QgsProcessingProvider,
- QgsMessageLog,
- QgsProcessingModelAlgorithm,
- QgsProject,
- QgsXmlUtils,
- QgsRuntimeProfiler)
+from qgis.core import (
+ Qgis,
+ QgsApplication,
+ QgsProcessingProvider,
+ QgsMessageLog,
+ QgsProcessingModelAlgorithm,
+ QgsProject,
+ QgsXmlUtils,
+ QgsRuntimeProfiler,
+)
-PROJECT_PROVIDER_ID = 'project'
+PROJECT_PROVIDER_ID = "project"
class ProjectProvider(QgsProcessingProvider):
@@ -45,7 +47,9 @@ def __init__(self, project=None):
# must reload models if providers list is changed - previously unavailable algorithms
# which models depend on may now be available
- QgsApplication.processingRegistry().providerAdded.connect(self.on_provider_added)
+ QgsApplication.processingRegistry().providerAdded.connect(
+ self.on_provider_added
+ )
self.project.readProject.connect(self.read_project)
self.project.writeProject.connect(self.write_project)
@@ -58,7 +62,7 @@ def on_provider_added(self, provider_id):
self.refreshAlgorithms()
def load(self):
- with QgsRuntimeProfiler.profile('Project Provider'):
+ with QgsRuntimeProfiler.profile("Project Provider"):
self.refreshAlgorithms()
return True
@@ -100,7 +104,7 @@ def read_project(self, doc):
:param doc: DOM document
"""
self.model_definitions = {}
- project_models_nodes = doc.elementsByTagName('projectModels')
+ project_models_nodes = doc.elementsByTagName("projectModels")
if project_models_nodes:
project_models_node = project_models_nodes.at(0)
model_nodes = project_models_node.childNodes()
@@ -118,12 +122,12 @@ def write_project(self, doc):
Writes out the project model definitions into the project DOM document
:param doc: DOM document
"""
- qgis_nodes = doc.elementsByTagName('qgis')
+ qgis_nodes = doc.elementsByTagName("qgis")
if not qgis_nodes:
return
qgis_node = qgis_nodes.at(0)
- project_models_node = doc.createElement('projectModels')
+ project_models_node = doc.createElement("projectModels")
for a in self.algorithms():
definition = a.toVariant()
@@ -132,10 +136,10 @@ def write_project(self, doc):
qgis_node.appendChild(project_models_node)
def name(self):
- return self.tr('Project models', 'ProjectProvider')
+ return self.tr("Project models", "ProjectProvider")
def longName(self):
- return self.tr('Models embedded in the current project', 'ProjectProvider')
+ return self.tr("Models embedded in the current project", "ProjectProvider")
def id(self):
return PROJECT_PROVIDER_ID
@@ -160,7 +164,9 @@ def loadAlgorithms(self):
self.addAlgorithm(algorithm)
else:
QgsMessageLog.logMessage(
- self.tr('Could not load model from project', 'ProjectProvider'),
- self.tr('Processing'), Qgis.MessageLevel.Critical)
+ self.tr("Could not load model from project", "ProjectProvider"),
+ self.tr("Processing"),
+ Qgis.MessageLevel.Critical,
+ )
self.is_loading = False
diff --git a/python/plugins/processing/script/AddScriptFromFileAction.py b/python/plugins/processing/script/AddScriptFromFileAction.py
index 74858f5287f1..b4eb2f4e91e3 100644
--- a/python/plugins/processing/script/AddScriptFromFileAction.py
+++ b/python/plugins/processing/script/AddScriptFromFileAction.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'April 2014'
-__copyright__ = '(C) 201, Victor Olaya'
+__author__ = "Victor Olaya"
+__date__ = "April 2014"
+__copyright__ = "(C) 201, Victor Olaya"
import os
import shutil
@@ -35,16 +35,20 @@
class AddScriptFromFileAction(ToolboxAction):
def __init__(self):
- self.name = QCoreApplication.translate("AddScriptFromFileAction", "Add Script to Toolbox…")
+ self.name = QCoreApplication.translate(
+ "AddScriptFromFileAction", "Add Script to Toolbox…"
+ )
self.group = self.tr("Tools")
def execute(self):
settings = QgsSettings()
lastDir = settings.value("processing/lastScriptsDir", "")
- files, _ = QFileDialog.getOpenFileNames(self.toolbox,
- self.tr("Add script(s)"),
- lastDir,
- self.tr("Processing scripts (*.py *.PY)"))
+ files, _ = QFileDialog.getOpenFileNames(
+ self.toolbox,
+ self.tr("Add script(s)"),
+ lastDir,
+ self.tr("Processing scripts (*.py *.PY)"),
+ )
if files:
settings.setValue("processing/lastScriptsDir", os.path.dirname(files[0]))
@@ -54,9 +58,13 @@ def execute(self):
shutil.copy(f, ScriptUtils.scriptsFolders()[0])
valid += 1
except OSError as e:
- QgsMessageLog.logMessage(self.tr("Could not copy script '{}'\n{}").format(f, str(e)),
- "Processing",
- Qgis.MessageLevel.Warning)
+ QgsMessageLog.logMessage(
+ self.tr("Could not copy script '{}'\n{}").format(f, str(e)),
+ "Processing",
+ Qgis.MessageLevel.Warning,
+ )
if valid > 0:
- QgsApplication.processingRegistry().providerById("script").refreshAlgorithms()
+ QgsApplication.processingRegistry().providerById(
+ "script"
+ ).refreshAlgorithms()
diff --git a/python/plugins/processing/script/AddScriptFromTemplateAction.py b/python/plugins/processing/script/AddScriptFromTemplateAction.py
index 29daa568dfb3..f0e59de59b9c 100644
--- a/python/plugins/processing/script/AddScriptFromTemplateAction.py
+++ b/python/plugins/processing/script/AddScriptFromTemplateAction.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Matteo Ghetta'
-__date__ = 'March 2018'
-__copyright__ = '(C) 2018, Matteo Ghetta'
+__author__ = "Matteo Ghetta"
+__date__ = "March 2018"
+__copyright__ = "(C) 2018, Matteo Ghetta"
import os
import codecs
@@ -34,17 +34,18 @@
class AddScriptFromTemplateAction(ToolboxAction):
def __init__(self):
- self.name = QCoreApplication.translate("AddScriptFromTemplate", "Create New Script from Template…")
+ self.name = QCoreApplication.translate(
+ "AddScriptFromTemplate", "Create New Script from Template…"
+ )
self.group = self.tr("Tools")
def execute(self):
dlg = ScriptEditorDialog(parent=iface.mainWindow())
pluginPath = os.path.split(os.path.dirname(__file__))[0]
- templatePath = os.path.join(
- pluginPath, 'script', 'ScriptTemplate.py')
+ templatePath = os.path.join(pluginPath, "script", "ScriptTemplate.py")
- with codecs.open(templatePath, 'r', encoding='utf-8') as f:
+ with codecs.open(templatePath, "r", encoding="utf-8") as f:
templateTxt = f.read()
dlg.editor.setText(templateTxt)
diff --git a/python/plugins/processing/script/CreateNewScriptAction.py b/python/plugins/processing/script/CreateNewScriptAction.py
index 76f3f8c15da0..42a4ad3230c5 100644
--- a/python/plugins/processing/script/CreateNewScriptAction.py
+++ b/python/plugins/processing/script/CreateNewScriptAction.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'August 2012'
-__copyright__ = '(C) 2012, Victor Olaya'
+__author__ = "Victor Olaya"
+__date__ = "August 2012"
+__copyright__ = "(C) 2012, Victor Olaya"
import os
@@ -33,7 +33,9 @@
class CreateNewScriptAction(ToolboxAction):
def __init__(self):
- self.name = QCoreApplication.translate("CreateNewScriptAction", "Create New Script…")
+ self.name = QCoreApplication.translate(
+ "CreateNewScriptAction", "Create New Script…"
+ )
self.group = self.tr("Tools")
def execute(self):
diff --git a/python/plugins/processing/script/DeleteScriptAction.py b/python/plugins/processing/script/DeleteScriptAction.py
index 7a3d901c398a..46535dfa0ebd 100644
--- a/python/plugins/processing/script/DeleteScriptAction.py
+++ b/python/plugins/processing/script/DeleteScriptAction.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'August 2012'
-__copyright__ = '(C) 2012, Victor Olaya'
+__author__ = "Victor Olaya"
+__date__ = "August 2012"
+__copyright__ = "(C) 2012, Victor Olaya"
import os
@@ -38,21 +38,29 @@ def __init__(self):
self.name = QCoreApplication.translate("DeleteScriptAction", "Delete Script…")
def isEnabled(self):
- return isinstance(self.itemData, QgsProcessingAlgorithm) and self.itemData.provider().id() == "script"
+ return (
+ isinstance(self.itemData, QgsProcessingAlgorithm)
+ and self.itemData.provider().id() == "script"
+ )
def execute(self):
- reply = QMessageBox.question(None,
- self.tr("Delete Script"),
- self.tr("Are you sure you want to delete this script?"),
- QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No,
- QMessageBox.StandardButton.No)
+ reply = QMessageBox.question(
+ None,
+ self.tr("Delete Script"),
+ self.tr("Are you sure you want to delete this script?"),
+ QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No,
+ QMessageBox.StandardButton.No,
+ )
if reply == QMessageBox.StandardButton.Yes:
filePath = ScriptUtils.findAlgorithmSource(self.itemData.name())
if filePath is not None:
os.remove(filePath)
- QgsApplication.processingRegistry().providerById("script").refreshAlgorithms()
+ QgsApplication.processingRegistry().providerById(
+ "script"
+ ).refreshAlgorithms()
else:
- QMessageBox.warning(None,
- self.tr("Delete Script"),
- self.tr("Can not find corresponding script file.")
- )
+ QMessageBox.warning(
+ None,
+ self.tr("Delete Script"),
+ self.tr("Can not find corresponding script file."),
+ )
diff --git a/python/plugins/processing/script/EditScriptAction.py b/python/plugins/processing/script/EditScriptAction.py
index 77094e206a7b..3b6e6e8193a4 100644
--- a/python/plugins/processing/script/EditScriptAction.py
+++ b/python/plugins/processing/script/EditScriptAction.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'August 2012'
-__copyright__ = '(C) 2012, Victor Olaya'
+__author__ = "Victor Olaya"
+__date__ = "August 2012"
+__copyright__ = "(C) 2012, Victor Olaya"
import inspect
@@ -39,7 +39,10 @@ def __init__(self):
self.name = QCoreApplication.translate("EditScriptAction", "Edit Script…")
def isEnabled(self):
- return isinstance(self.itemData, QgsProcessingAlgorithm) and self.itemData.provider().id() == "script"
+ return (
+ isinstance(self.itemData, QgsProcessingAlgorithm)
+ and self.itemData.provider().id() == "script"
+ )
def execute(self):
filePath = ScriptUtils.findAlgorithmSource(self.itemData.name())
@@ -47,7 +50,8 @@ def execute(self):
dlg = ScriptEditorDialog(filePath, parent=iface.mainWindow())
dlg.show()
else:
- QMessageBox.warning(None,
- self.tr("Edit Script"),
- self.tr("Can not find corresponding script file.")
- )
+ QMessageBox.warning(
+ None,
+ self.tr("Edit Script"),
+ self.tr("Can not find corresponding script file."),
+ )
diff --git a/python/plugins/processing/script/OpenScriptFromFileAction.py b/python/plugins/processing/script/OpenScriptFromFileAction.py
index 2b1f3d0d8446..1cb3a7d9a103 100644
--- a/python/plugins/processing/script/OpenScriptFromFileAction.py
+++ b/python/plugins/processing/script/OpenScriptFromFileAction.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Nyall Dawson'
-__date__ = 'February 2018'
-__copyright__ = '(C) 2018, Nyall Dawson'
+__author__ = "Nyall Dawson"
+__date__ = "February 2018"
+__copyright__ = "(C) 2018, Nyall Dawson"
import os
from qgis.PyQt.QtWidgets import QFileDialog
@@ -35,21 +35,28 @@
class OpenScriptFromFileAction(ToolboxAction):
def __init__(self):
- self.name = QCoreApplication.translate('OpenScriptFromFileAction', 'Open Existing Script…')
- self.group = self.tr('Tools')
+ self.name = QCoreApplication.translate(
+ "OpenScriptFromFileAction", "Open Existing Script…"
+ )
+ self.group = self.tr("Tools")
def getIcon(self):
return QgsApplication.getThemeIcon("/processingScript.svg")
def execute(self):
settings = QgsSettings()
- lastDir = settings.value('Processing/lastScriptsDir', '')
- filename, selected_filter = QFileDialog.getOpenFileName(self.toolbox,
- self.tr('Open Script', 'AddScriptFromFileAction'), lastDir,
- self.tr('Processing scripts (*.py *.PY)', 'AddScriptFromFileAction'))
+ lastDir = settings.value("Processing/lastScriptsDir", "")
+ filename, selected_filter = QFileDialog.getOpenFileName(
+ self.toolbox,
+ self.tr("Open Script", "AddScriptFromFileAction"),
+ lastDir,
+ self.tr("Processing scripts (*.py *.PY)", "AddScriptFromFileAction"),
+ )
if filename:
- settings.setValue('Processing/lastScriptsDir',
- QFileInfo(filename).absoluteDir().absolutePath())
+ settings.setValue(
+ "Processing/lastScriptsDir",
+ QFileInfo(filename).absoluteDir().absolutePath(),
+ )
dlg = ScriptEditorDialog(filePath=filename, parent=iface.mainWindow())
dlg.show()
diff --git a/python/plugins/processing/script/ScriptAlgorithmProvider.py b/python/plugins/processing/script/ScriptAlgorithmProvider.py
index 0868d7184df3..b87f0fa7220e 100644
--- a/python/plugins/processing/script/ScriptAlgorithmProvider.py
+++ b/python/plugins/processing/script/ScriptAlgorithmProvider.py
@@ -15,22 +15,23 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'August 2012'
-__copyright__ = '(C) 2012, Victor Olaya'
+__author__ = "Victor Olaya"
+__date__ = "August 2012"
+__copyright__ = "(C) 2012, Victor Olaya"
import os
-from qgis.core import (Qgis,
- QgsMessageLog,
- QgsApplication,
- QgsProcessingProvider,
- QgsRuntimeProfiler)
+from qgis.core import (
+ Qgis,
+ QgsMessageLog,
+ QgsApplication,
+ QgsProcessingProvider,
+ QgsRuntimeProfiler,
+)
from processing.core.ProcessingConfig import ProcessingConfig, Setting
-from processing.gui.ProviderActions import (ProviderActions,
- ProviderContextMenuActions)
+from processing.gui.ProviderActions import ProviderActions, ProviderContextMenuActions
from processing.script.AddScriptFromFileAction import AddScriptFromFileAction
from processing.script.CreateNewScriptAction import CreateNewScriptAction
@@ -48,25 +49,31 @@ def __init__(self):
super().__init__()
self.algs = []
self.additional_algorithm_classes = []
- self.actions = [CreateNewScriptAction(),
- AddScriptFromTemplateAction(),
- OpenScriptFromFileAction(),
- AddScriptFromFileAction()
- ]
- self.contextMenuActions = [EditScriptAction(),
- DeleteScriptAction()]
+ self.actions = [
+ CreateNewScriptAction(),
+ AddScriptFromTemplateAction(),
+ OpenScriptFromFileAction(),
+ AddScriptFromFileAction(),
+ ]
+ self.contextMenuActions = [EditScriptAction(), DeleteScriptAction()]
def load(self):
- with QgsRuntimeProfiler.profile('Script Provider'):
+ with QgsRuntimeProfiler.profile("Script Provider"):
ProcessingConfig.settingIcons[self.name()] = self.icon()
- ProcessingConfig.addSetting(Setting(self.name(),
- ScriptUtils.SCRIPTS_FOLDERS,
- self.tr("Scripts folder(s)"),
- ScriptUtils.defaultScriptsFolder(),
- valuetype=Setting.MULTIPLE_FOLDERS))
+ ProcessingConfig.addSetting(
+ Setting(
+ self.name(),
+ ScriptUtils.SCRIPTS_FOLDERS,
+ self.tr("Scripts folder(s)"),
+ ScriptUtils.defaultScriptsFolder(),
+ valuetype=Setting.MULTIPLE_FOLDERS,
+ )
+ )
ProviderActions.registerProviderActions(self, self.actions)
- ProviderContextMenuActions.registerProviderContextMenuActions(self.contextMenuActions)
+ ProviderContextMenuActions.registerProviderContextMenuActions(
+ self.contextMenuActions
+ )
ProcessingConfig.readSettings()
self.refreshAlgorithms()
@@ -77,7 +84,9 @@ def unload(self):
ProcessingConfig.removeSetting(ScriptUtils.SCRIPTS_FOLDERS)
ProviderActions.deregisterProviderActions(self)
- ProviderContextMenuActions.deregisterProviderContextMenuActions(self.contextMenuActions)
+ ProviderContextMenuActions.deregisterProviderContextMenuActions(
+ self.contextMenuActions
+ )
def icon(self):
return QgsApplication.getThemeIcon("/processingScript.svg")
diff --git a/python/plugins/processing/script/ScriptEdit.py b/python/plugins/processing/script/ScriptEdit.py
index dc339a335ea3..09f9e44fa0c0 100644
--- a/python/plugins/processing/script/ScriptEdit.py
+++ b/python/plugins/processing/script/ScriptEdit.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Alexander Bruy'
-__date__ = 'April 2013'
-__copyright__ = '(C) 2013, Alexander Bruy'
+__author__ = "Alexander Bruy"
+__date__ = "April 2013"
+__copyright__ = "(C) 2013, Alexander Bruy"
from qgis.PyQt.QtCore import Qt
@@ -39,17 +39,17 @@ def initShortcuts(self):
(ctrl, shift) = (self.SCMOD_CTRL << 16, self.SCMOD_SHIFT << 16)
# Disable some shortcuts
- self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('D') + ctrl)
- self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('L') + ctrl)
- self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('L') + ctrl
- + shift)
- self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('T') + ctrl)
+ self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord("D") + ctrl)
+ self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord("L") + ctrl)
+ self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord("L") + ctrl + shift)
+ self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord("T") + ctrl)
# self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord("Z") + ctrl)
# self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord("Y") + ctrl)
# Use Ctrl+Space for autocompletion
- self.shortcutAutocomplete = QShortcut(QKeySequence(Qt.Modifier.CTRL
- + Qt.Key.Key_Space), self)
+ self.shortcutAutocomplete = QShortcut(
+ QKeySequence(Qt.Modifier.CTRL + Qt.Key.Key_Space), self
+ )
self.shortcutAutocomplete.setContext(Qt.ShortcutContext.WidgetShortcut)
self.shortcutAutocomplete.activated.connect(self.autoComplete)
diff --git a/python/plugins/processing/script/ScriptEditorDialog.py b/python/plugins/processing/script/ScriptEditorDialog.py
index e9cc13896378..373eb2c964cc 100644
--- a/python/plugins/processing/script/ScriptEditorDialog.py
+++ b/python/plugins/processing/script/ScriptEditorDialog.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Alexander Bruy'
-__date__ = 'December 2012'
-__copyright__ = '(C) 2012, Alexander Bruy'
+__author__ = "Alexander Bruy"
+__date__ = "December 2012"
+__copyright__ = "(C) 2012, Alexander Bruy"
import os
import codecs
@@ -27,24 +27,16 @@
from qgis.PyQt import uic, sip
from qgis.PyQt.QtCore import Qt
-from qgis.PyQt.QtWidgets import (
- QMessageBox,
- QFileDialog,
- QVBoxLayout
-)
+from qgis.PyQt.QtWidgets import QMessageBox, QFileDialog, QVBoxLayout
-from qgis.gui import (
- QgsGui,
- QgsErrorDialog,
- QgsCodeEditorWidget
-)
+from qgis.gui import QgsGui, QgsErrorDialog, QgsCodeEditorWidget
from qgis.core import (
QgsApplication,
QgsFileUtils,
QgsSettings,
QgsError,
QgsProcessingAlgorithm,
- QgsProcessingFeatureBasedAlgorithm
+ QgsProcessingFeatureBasedAlgorithm,
)
from qgis.utils import iface, OverrideCursor
from qgis.processing import alg as algfactory
@@ -58,8 +50,7 @@
with warnings.catch_warnings():
warnings.filterwarnings("ignore", category=DeprecationWarning)
- WIDGET, BASE = uic.loadUiType(
- os.path.join(pluginPath, "ui", "DlgScriptEditor.ui"))
+ WIDGET, BASE = uic.loadUiType(os.path.join(pluginPath, "ui", "DlgScriptEditor.ui"))
class ScriptEditorDialog(BASE, WIDGET):
@@ -77,8 +68,9 @@ def __init__(self, filePath=None, parent=None):
ScriptEditorDialog.DIALOG_STORE.append(self)
def clean_up_store():
- ScriptEditorDialog.DIALOG_STORE =\
- [d for d in ScriptEditorDialog.DIALOG_STORE if d != self]
+ ScriptEditorDialog.DIALOG_STORE = [
+ d for d in ScriptEditorDialog.DIALOG_STORE if d != self
+ ]
self.destroyed.connect(clean_up_store)
@@ -100,31 +92,32 @@ def clean_up_store():
self.setStyleSheet(iface.mainWindow().styleSheet())
self.actionOpenScript.setIcon(
- QgsApplication.getThemeIcon('/mActionScriptOpen.svg'))
+ QgsApplication.getThemeIcon("/mActionScriptOpen.svg")
+ )
self.actionSaveScript.setIcon(
- QgsApplication.getThemeIcon('/mActionFileSave.svg'))
+ QgsApplication.getThemeIcon("/mActionFileSave.svg")
+ )
self.actionSaveScriptAs.setIcon(
- QgsApplication.getThemeIcon('/mActionFileSaveAs.svg'))
- self.actionRunScript.setIcon(
- QgsApplication.getThemeIcon('/mActionStart.svg'))
- self.actionCut.setIcon(
- QgsApplication.getThemeIcon('/mActionEditCut.svg'))
- self.actionCopy.setIcon(
- QgsApplication.getThemeIcon('/mActionEditCopy.svg'))
- self.actionPaste.setIcon(
- QgsApplication.getThemeIcon('/mActionEditPaste.svg'))
- self.actionUndo.setIcon(
- QgsApplication.getThemeIcon('/mActionUndo.svg'))
- self.actionRedo.setIcon(
- QgsApplication.getThemeIcon('/mActionRedo.svg'))
+ QgsApplication.getThemeIcon("/mActionFileSaveAs.svg")
+ )
+ self.actionRunScript.setIcon(QgsApplication.getThemeIcon("/mActionStart.svg"))
+ self.actionCut.setIcon(QgsApplication.getThemeIcon("/mActionEditCut.svg"))
+ self.actionCopy.setIcon(QgsApplication.getThemeIcon("/mActionEditCopy.svg"))
+ self.actionPaste.setIcon(QgsApplication.getThemeIcon("/mActionEditPaste.svg"))
+ self.actionUndo.setIcon(QgsApplication.getThemeIcon("/mActionUndo.svg"))
+ self.actionRedo.setIcon(QgsApplication.getThemeIcon("/mActionRedo.svg"))
self.actionFindReplace.setIcon(
- QgsApplication.getThemeIcon('/mActionFindReplace.svg'))
+ QgsApplication.getThemeIcon("/mActionFindReplace.svg")
+ )
self.actionIncreaseFontSize.setIcon(
- QgsApplication.getThemeIcon('/mActionIncreaseFont.svg'))
+ QgsApplication.getThemeIcon("/mActionIncreaseFont.svg")
+ )
self.actionDecreaseFontSize.setIcon(
- QgsApplication.getThemeIcon('/mActionDecreaseFont.svg'))
+ QgsApplication.getThemeIcon("/mActionDecreaseFont.svg")
+ )
self.actionToggleComment.setIcon(
- QgsApplication.getThemeIcon('console/iconCommentEditorConsole.svg'))
+ QgsApplication.getThemeIcon("console/iconCommentEditorConsole.svg")
+ )
# Connect signals and slots
self.actionOpenScript.triggered.connect(self.openScript)
@@ -160,16 +153,14 @@ def update_dialog_title(self):
Updates the script editor dialog title
"""
if self.code_editor_widget.filePath():
- path, file_name = os.path.split(
- self.code_editor_widget.filePath()
- )
+ path, file_name = os.path.split(self.code_editor_widget.filePath())
else:
- file_name = self.tr('Untitled Script')
+ file_name = self.tr("Untitled Script")
if self.hasChanged:
- file_name = '*' + file_name
+ file_name = "*" + file_name
- self.setWindowTitle(self.tr('{} - Processing Script Editor').format(file_name))
+ self.setWindowTitle(self.tr("{} - Processing Script Editor").format(file_name))
def closeEvent(self, event):
settings = QgsSettings()
@@ -178,9 +169,16 @@ def closeEvent(self, event):
if self.hasChanged:
ret = QMessageBox.question(
- self, self.tr('Save Script?'),
- self.tr('There are unsaved changes in this script. Do you want to keep those?'),
- QMessageBox.StandardButton.Save | QMessageBox.StandardButton.Cancel | QMessageBox.StandardButton.Discard, QMessageBox.StandardButton.Cancel)
+ self,
+ self.tr("Save Script?"),
+ self.tr(
+ "There are unsaved changes in this script. Do you want to keep those?"
+ ),
+ QMessageBox.StandardButton.Save
+ | QMessageBox.StandardButton.Cancel
+ | QMessageBox.StandardButton.Discard,
+ QMessageBox.StandardButton.Cancel,
+ )
if ret == QMessageBox.StandardButton.Save:
self.saveScript(False)
@@ -194,18 +192,23 @@ def closeEvent(self, event):
def openScript(self):
if self.hasChanged:
- ret = QMessageBox.warning(self,
- self.tr("Unsaved changes"),
- self.tr("There are unsaved changes in the script. Continue?"),
- QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No, QMessageBox.StandardButton.No)
+ ret = QMessageBox.warning(
+ self,
+ self.tr("Unsaved changes"),
+ self.tr("There are unsaved changes in the script. Continue?"),
+ QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No,
+ QMessageBox.StandardButton.No,
+ )
if ret == QMessageBox.StandardButton.No:
return
scriptDir = ScriptUtils.scriptsFolders()[0]
- fileName, _ = QFileDialog.getOpenFileName(self,
- self.tr("Open script"),
- scriptDir,
- self.tr("Processing scripts (*.py *.PY)"))
+ fileName, _ = QFileDialog.getOpenFileName(
+ self,
+ self.tr("Open script"),
+ scriptDir,
+ self.tr("Processing scripts (*.py *.PY)"),
+ )
if fileName == "":
return
@@ -223,13 +226,15 @@ def saveScript(self, saveAs):
newPath = None
if not self.code_editor_widget.filePath() or saveAs:
scriptDir = ScriptUtils.scriptsFolders()[0]
- newPath, _ = QFileDialog.getSaveFileName(self,
- self.tr("Save script"),
- scriptDir,
- self.tr("Processing scripts (*.py *.PY)"))
+ newPath, _ = QFileDialog.getSaveFileName(
+ self,
+ self.tr("Save script"),
+ scriptDir,
+ self.tr("Processing scripts (*.py *.PY)"),
+ )
if newPath:
- newPath = QgsFileUtils.ensureFileNameHasExtension(newPath, ['py'])
+ newPath = QgsFileUtils.ensureFileNameHasExtension(newPath, ["py"])
self.code_editor_widget.save(newPath)
elif self.code_editor_widget.filePath():
self.code_editor_widget.save()
@@ -255,9 +260,7 @@ def runAlgorithm(self):
exec(self.editor.text(), _locals)
except Exception as e:
error = QgsError(traceback.format_exc(), "Processing")
- QgsErrorDialog.show(error,
- self.tr("Execution error")
- )
+ QgsErrorDialog.show(error, self.tr("Execution error"))
return
alg = None
@@ -265,15 +268,27 @@ def runAlgorithm(self):
alg = algfactory.instances.pop().createInstance()
except IndexError:
for name, attr in _locals.items():
- if inspect.isclass(attr) and issubclass(attr, (QgsProcessingAlgorithm, QgsProcessingFeatureBasedAlgorithm)) and attr.__name__ not in ("QgsProcessingAlgorithm", "QgsProcessingFeatureBasedAlgorithm"):
+ if (
+ inspect.isclass(attr)
+ and issubclass(
+ attr,
+ (QgsProcessingAlgorithm, QgsProcessingFeatureBasedAlgorithm),
+ )
+ and attr.__name__
+ not in (
+ "QgsProcessingAlgorithm",
+ "QgsProcessingFeatureBasedAlgorithm",
+ )
+ ):
alg = attr()
break
if alg is None:
- QMessageBox.warning(self,
- self.tr("No script found"),
- self.tr("Seems there is no valid script in the file.")
- )
+ QMessageBox.warning(
+ self,
+ self.tr("No script found"),
+ self.tr("Seems there is no valid script in the file."),
+ )
return
alg.setProvider(QgsApplication.processingRegistry().providerById("script"))
diff --git a/python/plugins/processing/script/ScriptTemplate.py b/python/plugins/processing/script/ScriptTemplate.py
index 670cd9053396..2db9a15c142a 100644
--- a/python/plugins/processing/script/ScriptTemplate.py
+++ b/python/plugins/processing/script/ScriptTemplate.py
@@ -10,12 +10,14 @@
"""
from qgis.PyQt.QtCore import QCoreApplication
-from qgis.core import (QgsProcessing,
- QgsFeatureSink,
- QgsProcessingException,
- QgsProcessingAlgorithm,
- QgsProcessingParameterFeatureSource,
- QgsProcessingParameterFeatureSink)
+from qgis.core import (
+ QgsProcessing,
+ QgsFeatureSink,
+ QgsProcessingException,
+ QgsProcessingAlgorithm,
+ QgsProcessingParameterFeatureSource,
+ QgsProcessingParameterFeatureSink,
+)
from qgis import processing
@@ -37,14 +39,14 @@ class ExampleProcessingAlgorithm(QgsProcessingAlgorithm):
# used when calling the algorithm from another algorithm, or when
# calling from the QGIS console.
- INPUT = 'INPUT'
- OUTPUT = 'OUTPUT'
+ INPUT = "INPUT"
+ OUTPUT = "OUTPUT"
def tr(self, string):
"""
Returns a translatable string with the self.tr() function.
"""
- return QCoreApplication.translate('Processing', string)
+ return QCoreApplication.translate("Processing", string)
def createInstance(self):
return ExampleProcessingAlgorithm()
@@ -57,21 +59,21 @@ def name(self):
lowercase alphanumeric characters only and no spaces or other
formatting characters.
"""
- return 'myscript'
+ return "myscript"
def displayName(self):
"""
Returns the translated algorithm name, which should be used for any
user-visible display of the algorithm name.
"""
- return self.tr('My Script')
+ return self.tr("My Script")
def group(self):
"""
Returns the name of the group this algorithm belongs to. This string
should be localised.
"""
- return self.tr('Example scripts')
+ return self.tr("Example scripts")
def groupId(self):
"""
@@ -81,7 +83,7 @@ def groupId(self):
contain lowercase alphanumeric characters only and no spaces or other
formatting characters.
"""
- return 'examplescripts'
+ return "examplescripts"
def shortHelpString(self):
"""
@@ -102,8 +104,8 @@ def initAlgorithm(self, config=None):
self.addParameter(
QgsProcessingParameterFeatureSource(
self.INPUT,
- self.tr('Input layer'),
- [QgsProcessing.SourceType.TypeVectorAnyGeometry]
+ self.tr("Input layer"),
+ [QgsProcessing.SourceType.TypeVectorAnyGeometry],
)
)
@@ -111,10 +113,7 @@ def initAlgorithm(self, config=None):
# usually takes the form of a newly created vector layer when the
# algorithm is run in QGIS).
self.addParameter(
- QgsProcessingParameterFeatureSink(
- self.OUTPUT,
- self.tr('Output layer')
- )
+ QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr("Output layer"))
)
def processAlgorithm(self, parameters, context, feedback):
@@ -125,18 +124,16 @@ def processAlgorithm(self, parameters, context, feedback):
# Retrieve the feature source and sink. The 'dest_id' variable is used
# to uniquely identify the feature sink, and must be included in the
# dictionary returned by the processAlgorithm function.
- source = self.parameterAsSource(
- parameters,
- self.INPUT,
- context
- )
+ source = self.parameterAsSource(parameters, self.INPUT, context)
# If source was not found, throw an exception to indicate that the algorithm
# encountered a fatal error. The exception text can be any string, but in this
# case we use the pre-built invalidSourceError method to return a standard
# helper text for when a source cannot be evaluated
if source is None:
- raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT))
+ raise QgsProcessingException(
+ self.invalidSourceError(parameters, self.INPUT)
+ )
(sink, dest_id) = self.parameterAsSink(
parameters,
@@ -144,11 +141,11 @@ def processAlgorithm(self, parameters, context, feedback):
context,
source.fields(),
source.wkbType(),
- source.sourceCrs()
+ source.sourceCrs(),
)
# Send some information to the user
- feedback.pushInfo(f'CRS is {source.sourceCrs().authid()}')
+ feedback.pushInfo(f"CRS is {source.sourceCrs().authid()}")
# If sink was not created, throw an exception to indicate that the algorithm
# encountered a fatal error. The exception text can be any string, but in this
@@ -179,16 +176,21 @@ def processAlgorithm(self, parameters, context, feedback):
# to the executed algorithm, and that the executed algorithm can send feedback
# reports to the user (and correctly handle cancellation and progress reports!)
if False:
- buffered_layer = processing.run("native:buffer", {
- 'INPUT': dest_id,
- 'DISTANCE': 1.5,
- 'SEGMENTS': 5,
- 'END_CAP_STYLE': 0,
- 'JOIN_STYLE': 0,
- 'MITER_LIMIT': 2,
- 'DISSOLVE': False,
- 'OUTPUT': 'memory:'
- }, context=context, feedback=feedback)['OUTPUT']
+ buffered_layer = processing.run(
+ "native:buffer",
+ {
+ "INPUT": dest_id,
+ "DISTANCE": 1.5,
+ "SEGMENTS": 5,
+ "END_CAP_STYLE": 0,
+ "JOIN_STYLE": 0,
+ "MITER_LIMIT": 2,
+ "DISSOLVE": False,
+ "OUTPUT": "memory:",
+ },
+ context=context,
+ feedback=feedback,
+ )["OUTPUT"]
# Return the results of the algorithm. In this case our only result is
# the feature sink which contains the processed features, but some
diff --git a/python/plugins/processing/script/ScriptUtils.py b/python/plugins/processing/script/ScriptUtils.py
index e9cd4058cd26..793f91ce337e 100644
--- a/python/plugins/processing/script/ScriptUtils.py
+++ b/python/plugins/processing/script/ScriptUtils.py
@@ -15,10 +15,9 @@
***************************************************************************
"""
-
-__author__ = 'Victor Olaya'
-__date__ = 'August 2012'
-__copyright__ = '(C) 2012, Victor Olaya'
+__author__ = "Victor Olaya"
+__date__ = "August 2012"
+__copyright__ = "(C) 2012, Victor Olaya"
from qgis.processing import alg as algfactory
import os
@@ -27,12 +26,13 @@
from qgis.PyQt.QtCore import QCoreApplication, QDir
-from qgis.core import (Qgis,
- QgsApplication,
- QgsProcessingAlgorithm,
- QgsProcessingFeatureBasedAlgorithm,
- QgsMessageLog
- )
+from qgis.core import (
+ Qgis,
+ QgsApplication,
+ QgsProcessingAlgorithm,
+ QgsProcessingFeatureBasedAlgorithm,
+ QgsMessageLog,
+)
from processing.core.ProcessingConfig import ProcessingConfig
from processing.tools.system import mkdir, userFolder
@@ -70,14 +70,29 @@ def loadAlgorithm(moduleName, filePath):
except IndexError:
for x in dir(module):
obj = getattr(module, x)
- if inspect.isclass(obj) and issubclass(obj, (QgsProcessingAlgorithm, QgsProcessingFeatureBasedAlgorithm)) and obj.__name__ not in ("QgsProcessingAlgorithm", "QgsProcessingFeatureBasedAlgorithm"):
+ if (
+ inspect.isclass(obj)
+ and issubclass(
+ obj,
+ (QgsProcessingAlgorithm, QgsProcessingFeatureBasedAlgorithm),
+ )
+ and obj.__name__
+ not in (
+ "QgsProcessingAlgorithm",
+ "QgsProcessingFeatureBasedAlgorithm",
+ )
+ ):
o = obj()
scriptsRegistry[o.name()] = filePath
return o
except (ImportError, AttributeError, TypeError) as e:
- QgsMessageLog.logMessage(QCoreApplication.translate("ScriptUtils", "Could not import script algorithm '{}' from '{}'\n{}").format(moduleName, filePath, str(e)),
- QCoreApplication.translate("ScriptUtils", "Processing"),
- Qgis.MessageLevel.Critical)
+ QgsMessageLog.logMessage(
+ QCoreApplication.translate(
+ "ScriptUtils", "Could not import script algorithm '{}' from '{}'\n{}"
+ ).format(moduleName, filePath, str(e)),
+ QCoreApplication.translate("ScriptUtils", "Processing"),
+ Qgis.MessageLevel.Critical,
+ )
def findAlgorithmSource(name):
@@ -96,9 +111,13 @@ def resetScriptFolder(folder):
if os.path.exists(newFolder):
return newFolder
- QgsMessageLog.logMessage(QgsApplication .translate("loadAlgorithms", "Script folder {} does not exist").format(newFolder),
- QgsApplication.translate("loadAlgorithms", "Processing"),
- Qgis.MessageLevel.Warning)
+ QgsMessageLog.logMessage(
+ QgsApplication.translate(
+ "loadAlgorithms", "Script folder {} does not exist"
+ ).format(newFolder),
+ QgsApplication.translate("loadAlgorithms", "Processing"),
+ Qgis.MessageLevel.Warning,
+ )
if not os.path.isabs(newFolder):
return None
@@ -115,7 +134,7 @@ def resetScriptFolder(folder):
if commonSettingPath in newFolder:
# strip not common folder part. e.g. preserve the profile path
# stripping the heading part that come from another location
- tail = newFolder[newFolder.find(commonSettingPath):]
+ tail = newFolder[newFolder.find(commonSettingPath) :]
# tail folder with the actual userSetting path
header = os.path.join(os.sep, os.path.join(*paths[:appIndex]))
newFolder = os.path.join(header, tail)
@@ -124,8 +143,12 @@ def resetScriptFolder(folder):
if not os.path.exists(newFolder):
return None
- QgsMessageLog.logMessage(QgsApplication .translate("loadAlgorithms", "Script folder changed into {}").format(newFolder),
- QgsApplication.translate("loadAlgorithms", "Processing"),
- Qgis.MessageLevel.Warning)
+ QgsMessageLog.logMessage(
+ QgsApplication.translate(
+ "loadAlgorithms", "Script folder changed into {}"
+ ).format(newFolder),
+ QgsApplication.translate("loadAlgorithms", "Processing"),
+ Qgis.MessageLevel.Warning,
+ )
return newFolder
diff --git a/python/plugins/processing/tests/AlgorithmsTestBase.py b/python/plugins/processing/tests/AlgorithmsTestBase.py
index 3323c5477ac8..e2255a0e32aa 100644
--- a/python/plugins/processing/tests/AlgorithmsTestBase.py
+++ b/python/plugins/processing/tests/AlgorithmsTestBase.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Matthias Kuhn'
-__date__ = 'January 2016'
-__copyright__ = '(C) 2016, Matthias Kuhn'
+__author__ = "Matthias Kuhn"
+__date__ = "January 2016"
+__copyright__ = "(C) 2016, Matthias Kuhn"
import os
@@ -35,21 +35,21 @@
from copy import deepcopy
from qgis.PyQt.QtCore import QT_VERSION
-from qgis.core import (Qgis,
- QgsVectorLayer,
- QgsRasterLayer,
- QgsCoordinateReferenceSystem,
- QgsFeatureRequest,
- QgsMapLayer,
- QgsProject,
- QgsApplication,
- QgsProcessingContext,
- QgsProcessingUtils,
- QgsProcessingFeedback)
-from qgis.analysis import (QgsNativeAlgorithms)
-from qgis.testing import (_UnexpectedSuccess,
- QgisTestCase,
- start_app)
+from qgis.core import (
+ Qgis,
+ QgsVectorLayer,
+ QgsRasterLayer,
+ QgsCoordinateReferenceSystem,
+ QgsFeatureRequest,
+ QgsMapLayer,
+ QgsProject,
+ QgsApplication,
+ QgsProcessingContext,
+ QgsProcessingUtils,
+ QgsProcessingFeedback,
+)
+from qgis.analysis import QgsNativeAlgorithms
+from qgis.testing import _UnexpectedSuccess, QgisTestCase, start_app
from utilities import unitTestDataPath
import processing
@@ -58,11 +58,11 @@
def GDAL_COMPUTE_VERSION(maj, min, rev):
- return ((maj) * 1000000 + (min) * 10000 + (rev) * 100)
+ return (maj) * 1000000 + (min) * 10000 + (rev) * 100
def processingTestDataPath():
- return os.path.join(os.path.dirname(__file__), 'testdata')
+ return os.path.join(os.path.dirname(__file__), "testdata")
class AlgorithmsTest:
@@ -71,51 +71,95 @@ def test_algorithms(self):
"""
This is the main test function. All others will be executed based on the definitions in testdata/algorithm_tests.yaml
"""
- with open(os.path.join(processingTestDataPath(), self.definition_file())) as stream:
+ with open(
+ os.path.join(processingTestDataPath(), self.definition_file())
+ ) as stream:
algorithm_tests = yaml.load(stream, Loader=yaml.SafeLoader)
- if 'tests' in algorithm_tests and algorithm_tests['tests'] is not None:
- for idx, algtest in enumerate(algorithm_tests['tests']):
- condition = algtest.get('condition')
+ if "tests" in algorithm_tests and algorithm_tests["tests"] is not None:
+ for idx, algtest in enumerate(algorithm_tests["tests"]):
+ condition = algtest.get("condition")
if condition:
- geos_condition = condition.get('geos')
+ geos_condition = condition.get("geos")
if geos_condition:
- less_than_condition = geos_condition.get('less_than')
+ less_than_condition = geos_condition.get("less_than")
if less_than_condition:
if Qgis.geosVersionInt() >= less_than_condition:
- print('!!! Skipping {}, requires GEOS < {}, have version {}'.format(algtest['name'], less_than_condition, Qgis.geosVersionInt()))
+ print(
+ "!!! Skipping {}, requires GEOS < {}, have version {}".format(
+ algtest["name"],
+ less_than_condition,
+ Qgis.geosVersionInt(),
+ )
+ )
continue
- at_least_condition = geos_condition.get('at_least')
+ at_least_condition = geos_condition.get("at_least")
if at_least_condition:
if Qgis.geosVersionInt() < at_least_condition:
- print('!!! Skipping {}, requires GEOS >= {}, have version {}'.format(algtest['name'], at_least_condition, Qgis.geosVersionInt()))
+ print(
+ "!!! Skipping {}, requires GEOS >= {}, have version {}".format(
+ algtest["name"],
+ at_least_condition,
+ Qgis.geosVersionInt(),
+ )
+ )
continue
- gdal_condition = condition.get('gdal')
+ gdal_condition = condition.get("gdal")
if gdal_condition:
- less_than_condition = gdal_condition.get('less_than')
+ less_than_condition = gdal_condition.get("less_than")
if less_than_condition:
- if int(gdal.VersionInfo('VERSION_NUM')) >= less_than_condition:
- print('!!! Skipping {}, requires GDAL < {}, have version {}'.format(algtest['name'], less_than_condition, gdal.VersionInfo('VERSION_NUM')))
+ if (
+ int(gdal.VersionInfo("VERSION_NUM"))
+ >= less_than_condition
+ ):
+ print(
+ "!!! Skipping {}, requires GDAL < {}, have version {}".format(
+ algtest["name"],
+ less_than_condition,
+ gdal.VersionInfo("VERSION_NUM"),
+ )
+ )
continue
- at_least_condition = gdal_condition.get('at_least')
+ at_least_condition = gdal_condition.get("at_least")
if at_least_condition:
- if int(gdal.VersionInfo('VERSION_NUM')) < at_least_condition:
- print('!!! Skipping {}, requires GDAL >= {}, have version {}'.format(algtest['name'], at_least_condition, gdal.VersionInfo('VERSION_NUM')))
+ if (
+ int(gdal.VersionInfo("VERSION_NUM"))
+ < at_least_condition
+ ):
+ print(
+ "!!! Skipping {}, requires GDAL >= {}, have version {}".format(
+ algtest["name"],
+ at_least_condition,
+ gdal.VersionInfo("VERSION_NUM"),
+ )
+ )
continue
- qt_condition = condition.get('qt')
+ qt_condition = condition.get("qt")
if qt_condition:
- less_than_condition = qt_condition.get('less_than')
+ less_than_condition = qt_condition.get("less_than")
if less_than_condition:
if QT_VERSION >= less_than_condition:
- print('!!! Skipping {}, requires Qt < {}, have version {}'.format(algtest['name'], less_than_condition, QT_VERSION))
+ print(
+ "!!! Skipping {}, requires Qt < {}, have version {}".format(
+ algtest["name"], less_than_condition, QT_VERSION
+ )
+ )
continue
- at_least_condition = qt_condition.get('at_least')
+ at_least_condition = qt_condition.get("at_least")
if at_least_condition:
if QT_VERSION < at_least_condition:
- print('!!! Skipping {}, requires Qt >= {}, have version {}'.format(algtest['name'], at_least_condition, QT_VERSION))
+ print(
+ "!!! Skipping {}, requires Qt >= {}, have version {}".format(
+ algtest["name"], at_least_condition, QT_VERSION
+ )
+ )
continue
- print('About to start {} of {}: "{}"'.format(idx, len(algorithm_tests['tests']), algtest['name']))
- yield self.check_algorithm, algtest['name'], algtest
+ print(
+ 'About to start {} of {}: "{}"'.format(
+ idx, len(algorithm_tests["tests"]), algtest["name"]
+ )
+ )
+ yield self.check_algorithm, algtest["name"], algtest
def check_algorithm(self, name, defs):
"""
@@ -126,25 +170,29 @@ def check_algorithm(self, name, defs):
self.vector_layer_params = {}
QgsProject.instance().clear()
- if 'project' in defs:
- full_project_path = os.path.join(processingTestDataPath(), defs['project'])
+ if "project" in defs:
+ full_project_path = os.path.join(processingTestDataPath(), defs["project"])
project_read_success = QgsProject.instance().read(full_project_path)
- self.assertTrue(project_read_success, 'Failed to load project file: ' + defs['project'])
-
- if 'project_crs' in defs:
- QgsProject.instance().setCrs(QgsCoordinateReferenceSystem(defs['project_crs']))
+ self.assertTrue(
+ project_read_success, "Failed to load project file: " + defs["project"]
+ )
+
+ if "project_crs" in defs:
+ QgsProject.instance().setCrs(
+ QgsCoordinateReferenceSystem(defs["project_crs"])
+ )
else:
QgsProject.instance().setCrs(QgsCoordinateReferenceSystem())
- if 'ellipsoid' in defs:
- QgsProject.instance().setEllipsoid(defs['ellipsoid'])
+ if "ellipsoid" in defs:
+ QgsProject.instance().setEllipsoid(defs["ellipsoid"])
else:
- QgsProject.instance().setEllipsoid('')
+ QgsProject.instance().setEllipsoid("")
- params = self.load_params(defs['params'])
+ params = self.load_params(defs["params"])
- print('Running alg: "{}"'.format(defs['algorithm']))
- alg = QgsApplication.processingRegistry().createAlgorithmById(defs['algorithm'])
+ print('Running alg: "{}"'.format(defs["algorithm"]))
+ alg = QgsApplication.processingRegistry().createAlgorithmById(defs["algorithm"])
parameters = {}
if isinstance(params, list):
@@ -154,51 +202,53 @@ def check_algorithm(self, name, defs):
for k, p in params.items():
parameters[k] = p
- for r, p in list(defs['results'].items()):
- if 'in_place_result' not in p or not p['in_place_result']:
+ for r, p in list(defs["results"].items()):
+ if "in_place_result" not in p or not p["in_place_result"]:
parameters[r] = self.load_result_param(p)
expectFailure = False
- if 'expectedFailure' in defs:
- exec(('\n'.join(defs['expectedFailure'][:-1])), globals(), locals())
- expectFailure = eval(defs['expectedFailure'][-1])
+ if "expectedFailure" in defs:
+ exec(("\n".join(defs["expectedFailure"][:-1])), globals(), locals())
+ expectFailure = eval(defs["expectedFailure"][-1])
- if 'expectedException' in defs:
+ if "expectedException" in defs:
expectFailure = True
# ignore user setting for invalid geometry handling
context = QgsProcessingContext()
context.setProject(QgsProject.instance())
- if 'ellipsoid' in defs:
+ if "ellipsoid" in defs:
# depending on the project settings, we can't always rely
# on QgsProject.ellipsoid() returning the same ellipsoid as was
# specified in the test definition. So just force ensure that the
# context's ellipsoid is the desired one
- context.setEllipsoid(defs['ellipsoid'])
+ context.setEllipsoid(defs["ellipsoid"])
- if 'skipInvalid' in defs and defs['skipInvalid']:
- context.setInvalidGeometryCheck(QgsFeatureRequest.InvalidGeometryCheck.GeometrySkipInvalid)
+ if "skipInvalid" in defs and defs["skipInvalid"]:
+ context.setInvalidGeometryCheck(
+ QgsFeatureRequest.InvalidGeometryCheck.GeometrySkipInvalid
+ )
feedback = QgsProcessingFeedback()
- print(f'Algorithm parameters are {parameters}')
+ print(f"Algorithm parameters are {parameters}")
# first check that algorithm accepts the parameters we pass...
ok, msg = alg.checkParameterValues(parameters, context)
- self.assertTrue(ok, f'Algorithm failed checkParameterValues with result {msg}')
+ self.assertTrue(ok, f"Algorithm failed checkParameterValues with result {msg}")
if expectFailure:
try:
results, ok = alg.run(parameters, context, feedback)
- self.check_results(results, context, parameters, defs['results'])
+ self.check_results(results, context, parameters, defs["results"])
if ok:
raise _UnexpectedSuccess
except Exception:
pass
else:
results, ok = alg.run(parameters, context, feedback)
- self.assertTrue(ok, f'params: {parameters}, results: {results}')
- self.check_results(results, context, parameters, defs['results'])
+ self.assertTrue(ok, f"params: {parameters}, results: {results}")
+ self.check_results(results, context, parameters, defs["results"])
def load_params(self, params):
"""
@@ -217,68 +267,75 @@ def load_param(self, param, id=None):
parameter based on its key `type` and return the appropriate parameter to pass to the algorithm.
"""
try:
- if param['type'] in ('vector', 'raster', 'table'):
+ if param["type"] in ("vector", "raster", "table"):
return self.load_layer(id, param).id()
- elif param['type'] == 'vrtlayers':
+ elif param["type"] == "vrtlayers":
vals = []
- for p in param['params']:
- p['layer'] = self.load_layer(None, {'type': 'vector', 'name': p['layer']})
+ for p in param["params"]:
+ p["layer"] = self.load_layer(
+ None, {"type": "vector", "name": p["layer"]}
+ )
vals.append(p)
return vals
- elif param['type'] == 'multi':
- return [self.load_param(p) for p in param['params']]
- elif param['type'] == 'file':
+ elif param["type"] == "multi":
+ return [self.load_param(p) for p in param["params"]]
+ elif param["type"] == "file":
return self.filepath_from_param(param)
- elif param['type'] == 'interpolation':
+ elif param["type"] == "interpolation":
prefix = processingTestDataPath()
- tmp = ''
- for r in param['name'].split('::|::'):
- v = r.split('::~::')
- tmp += '{}::~::{}::~::{}::~::{};'.format(os.path.join(prefix, v[0]),
- v[1], v[2], v[3])
+ tmp = ""
+ for r in param["name"].split("::|::"):
+ v = r.split("::~::")
+ tmp += "{}::~::{}::~::{}::~::{};".format(
+ os.path.join(prefix, v[0]), v[1], v[2], v[3]
+ )
return tmp[:-1]
except TypeError:
# No type specified, use whatever is there
return param
- raise KeyError("Unknown type '{}' specified for parameter".format(param['type']))
+ raise KeyError(
+ "Unknown type '{}' specified for parameter".format(param["type"])
+ )
def load_result_param(self, param):
"""
Loads a result parameter. Creates a temporary destination where the result should go to and returns this location
so it can be sent to the algorithm as parameter.
"""
- if param['type'] in ['vector', 'file', 'table', 'regex']:
+ if param["type"] in ["vector", "file", "table", "regex"]:
outdir = tempfile.mkdtemp()
self.cleanup_paths.append(outdir)
- if isinstance(param['name'], str):
- basename = os.path.basename(param['name'])
+ if isinstance(param["name"], str):
+ basename = os.path.basename(param["name"])
else:
- basename = os.path.basename(param['name'][0])
+ basename = os.path.basename(param["name"][0])
filepath = self.uri_path_join(outdir, basename)
return filepath
- elif param['type'] == 'rasterhash':
+ elif param["type"] == "rasterhash":
outdir = tempfile.mkdtemp()
self.cleanup_paths.append(outdir)
- basename = 'raster.tif'
+ basename = "raster.tif"
filepath = os.path.join(outdir, basename)
return filepath
- elif param['type'] == 'directory':
+ elif param["type"] == "directory":
outdir = tempfile.mkdtemp()
return outdir
- raise KeyError("Unknown type '{}' specified for parameter".format(param['type']))
+ raise KeyError(
+ "Unknown type '{}' specified for parameter".format(param["type"])
+ )
def load_layers(self, id, param):
layers = []
- if param['type'] in ('vector', 'table'):
- if isinstance(param['name'], str) or 'uri' in param:
+ if param["type"] in ("vector", "table"):
+ if isinstance(param["name"], str) or "uri" in param:
layers.append(self.load_layer(id, param))
else:
- for n in param['name']:
+ for n in param["name"]:
layer_param = deepcopy(param)
- layer_param['name'] = n
+ layer_param["name"] = n
layers.append(self.load_layer(id, layer_param))
else:
layers.append(self.load_layer(id, param))
@@ -291,37 +348,39 @@ def load_layer(self, id, param):
filepath = self.filepath_from_param(param)
- if 'in_place' in param and param['in_place']:
+ if "in_place" in param and param["in_place"]:
# check if alg modifies layer in place
tmpdir = tempfile.mkdtemp()
self.cleanup_paths.append(tmpdir)
path, file_name = os.path.split(filepath)
base, ext = os.path.splitext(file_name)
- for file in glob.glob(os.path.join(path, f'{base}.*')):
+ for file in glob.glob(os.path.join(path, f"{base}.*")):
shutil.copy(os.path.join(path, file), tmpdir)
filepath = os.path.join(tmpdir, file_name)
self.in_place_layers[id] = filepath
- if param['type'] in ('vector', 'table'):
- gmlrex = r'\.gml\b'
+ if param["type"] in ("vector", "table"):
+ gmlrex = r"\.gml\b"
if re.search(gmlrex, filepath, re.IGNORECASE):
# ewwwww - we have to force SRS detection for GML files, otherwise they'll be loaded
# with no srs
- filepath += '|option:FORCE_SRS_DETECTION=YES'
+ filepath += "|option:FORCE_SRS_DETECTION=YES"
if filepath in self.vector_layer_params:
return self.vector_layer_params[filepath]
options = QgsVectorLayer.LayerOptions()
options.loadDefaultStyle = False
- lyr = QgsVectorLayer(filepath, param['name'], 'ogr', options)
+ lyr = QgsVectorLayer(filepath, param["name"], "ogr", options)
self.vector_layer_params[filepath] = lyr
- elif param['type'] == 'raster':
+ elif param["type"] == "raster":
options = QgsRasterLayer.LayerOptions()
options.loadDefaultStyle = False
- lyr = QgsRasterLayer(filepath, param['name'], 'gdal', options)
+ lyr = QgsRasterLayer(filepath, param["name"], "gdal", options)
- self.assertTrue(lyr.isValid(), f'Could not load layer "{filepath}" from param {param}')
+ self.assertTrue(
+ lyr.isValid(), f'Could not load layer "{filepath}" from param {param}'
+ )
QgsProject.instance().addMapLayer(lyr)
return lyr
@@ -330,13 +389,13 @@ def filepath_from_param(self, param):
Creates a filepath from a param
"""
prefix = processingTestDataPath()
- if 'location' in param and param['location'] == 'qgs':
+ if "location" in param and param["location"] == "qgs":
prefix = unitTestDataPath()
- if 'uri' in param:
- path = param['uri']
+ if "uri" in param:
+ path = param["uri"]
else:
- path = param['name']
+ path = param["name"]
if not path:
return None
@@ -344,7 +403,7 @@ def filepath_from_param(self, param):
return self.uri_path_join(prefix, path)
def uri_path_join(self, prefix, filepath):
- if filepath.startswith('ogr:'):
+ if filepath.startswith("ogr:"):
if not prefix[-1] == os.path.sep:
prefix += os.path.sep
filepath = re.sub(r"dbname='", f"dbname='{prefix}", filepath)
@@ -358,88 +417,105 @@ def check_results(self, results, context, params, expected):
Checks if result produced by an algorithm matches with the expected specification.
"""
for id, expected_result in expected.items():
- if expected_result['type'] in ('vector', 'table'):
- if 'compare' in expected_result and not expected_result['compare']:
+ if expected_result["type"] in ("vector", "table"):
+ if "compare" in expected_result and not expected_result["compare"]:
# skipping the comparison, so just make sure output is valid
if isinstance(results[id], QgsMapLayer):
result_lyr = results[id]
else:
- result_lyr = QgsProcessingUtils.mapLayerFromString(results[id], context)
+ result_lyr = QgsProcessingUtils.mapLayerFromString(
+ results[id], context
+ )
self.assertTrue(result_lyr.isValid())
continue
expected_lyrs = self.load_layers(id, expected_result)
- if 'in_place_result' in expected_result:
- result_lyr = QgsProcessingUtils.mapLayerFromString(self.in_place_layers[id], context)
+ if "in_place_result" in expected_result:
+ result_lyr = QgsProcessingUtils.mapLayerFromString(
+ self.in_place_layers[id], context
+ )
self.assertTrue(result_lyr.isValid(), self.in_place_layers[id])
else:
try:
results[id]
except KeyError as e:
- raise KeyError(f'Expected result {str(e)} does not exist in {list(results.keys())}')
+ raise KeyError(
+ f"Expected result {str(e)} does not exist in {list(results.keys())}"
+ )
if isinstance(results[id], QgsMapLayer):
result_lyr = results[id]
else:
string = results[id]
- gmlrex = r'\.gml\b'
+ gmlrex = r"\.gml\b"
if re.search(gmlrex, string, re.IGNORECASE):
# ewwwww - we have to force SRS detection for GML files, otherwise they'll be loaded
# with no srs
- string += '|option:FORCE_SRS_DETECTION=YES'
+ string += "|option:FORCE_SRS_DETECTION=YES"
- result_lyr = QgsProcessingUtils.mapLayerFromString(string, context)
+ result_lyr = QgsProcessingUtils.mapLayerFromString(
+ string, context
+ )
self.assertTrue(result_lyr, results[id])
- compare = expected_result.get('compare', {})
- pk = expected_result.get('pk', None)
+ compare = expected_result.get("compare", {})
+ pk = expected_result.get("pk", None)
if len(expected_lyrs) == 1:
- self.assertLayersEqual(expected_lyrs[0], result_lyr, compare=compare, pk=pk)
+ self.assertLayersEqual(
+ expected_lyrs[0], result_lyr, compare=compare, pk=pk
+ )
else:
res = False
for l in expected_lyrs:
if self.checkLayersEqual(l, result_lyr, compare=compare, pk=pk):
res = True
break
- self.assertTrue(res, 'Could not find matching layer in expected results')
+ self.assertTrue(
+ res, "Could not find matching layer in expected results"
+ )
- elif 'rasterhash' == expected_result['type']:
+ elif "rasterhash" == expected_result["type"]:
print(f"id:{id} result:{results[id]}")
- self.assertTrue(os.path.exists(results[id]), f'File does not exist: {results[id]}, {params}')
+ self.assertTrue(
+ os.path.exists(results[id]),
+ f"File does not exist: {results[id]}, {params}",
+ )
dataset = gdal.Open(results[id], GA_ReadOnly)
dataArray = nan_to_num(dataset.ReadAsArray(0))
strhash = hashlib.sha224(dataArray.data).hexdigest()
- if not isinstance(expected_result['hash'], str):
- self.assertIn(strhash, expected_result['hash'])
+ if not isinstance(expected_result["hash"], str):
+ self.assertIn(strhash, expected_result["hash"])
else:
- self.assertEqual(strhash, expected_result['hash'])
- elif 'file' == expected_result['type']:
+ self.assertEqual(strhash, expected_result["hash"])
+ elif "file" == expected_result["type"]:
result_filepath = results[id]
- if isinstance(expected_result.get('name'), list):
+ if isinstance(expected_result.get("name"), list):
# test to see if any match expected
- for path in expected_result['name']:
- expected_filepath = self.filepath_from_param({'name': path})
+ for path in expected_result["name"]:
+ expected_filepath = self.filepath_from_param({"name": path})
if self.checkFilesEqual(expected_filepath, result_filepath):
break
else:
- expected_filepath = self.filepath_from_param({'name': expected_result['name'][0]})
+ expected_filepath = self.filepath_from_param(
+ {"name": expected_result["name"][0]}
+ )
else:
expected_filepath = self.filepath_from_param(expected_result)
self.assertFilesEqual(expected_filepath, result_filepath)
- elif 'directory' == expected_result['type']:
+ elif "directory" == expected_result["type"]:
expected_dirpath = self.filepath_from_param(expected_result)
result_dirpath = results[id]
self.assertDirectoriesEqual(expected_dirpath, result_dirpath)
- elif 'regex' == expected_result['type']:
+ elif "regex" == expected_result["type"]:
with open(results[id]) as file:
data = file.read()
- for rule in expected_result.get('rules', []):
+ for rule in expected_result.get("rules", []):
self.assertRegex(data, rule)
@@ -452,21 +528,23 @@ class GenericAlgorithmsTest(QgisTestCase):
def setUpClass(cls):
start_app()
from processing.core.Processing import Processing
+
Processing.initialize()
cls.cleanup_paths = []
@classmethod
def tearDownClass(cls):
from processing.core.Processing import Processing
+
Processing.deinitialize()
for path in cls.cleanup_paths:
shutil.rmtree(path)
def testAlgorithmCompliance(self):
for p in QgsApplication.processingRegistry().providers():
- print(f'testing provider {p.id()}')
+ print(f"testing provider {p.id()}")
for a in p.algorithms():
- print(f'testing algorithm {a.id()}')
+ print(f"testing algorithm {a.id()}")
self.check_algorithm(a)
def check_algorithm(self, alg):
@@ -474,5 +552,5 @@ def check_algorithm(self, alg):
alg.helpUrl()
-if __name__ == '__main__':
+if __name__ == "__main__":
nose2.main()
diff --git a/python/plugins/processing/tests/CheckValidityAlgorithm.py b/python/plugins/processing/tests/CheckValidityAlgorithm.py
index db1e40b21a25..0b6f96863033 100644
--- a/python/plugins/processing/tests/CheckValidityAlgorithm.py
+++ b/python/plugins/processing/tests/CheckValidityAlgorithm.py
@@ -5,9 +5,10 @@
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
"""
-__author__ = 'Alessandro Pasotti'
-__date__ = '2018-09'
-__copyright__ = 'Copyright 2018, The QGIS Project'
+
+__author__ = "Alessandro Pasotti"
+__date__ = "2018-09"
+__copyright__ = "Copyright 2018, The QGIS Project"
from qgis.PyQt.QtCore import QCoreApplication, QVariant
from qgis.core import (
@@ -24,7 +25,7 @@
QgsProject,
QgsProcessingException,
QgsProcessingUtils,
- QgsSettings
+ QgsSettings,
)
from processing.core.Processing import Processing
from processing.gui.AlgorithmExecutor import execute
@@ -51,9 +52,9 @@ def setUpClass(cls):
QCoreApplication.setOrganizationName("QGIS_Test")
QCoreApplication.setOrganizationDomain(
- "QGIS_TestPyQgsProcessingCheckValidity.com")
- QCoreApplication.setApplicationName(
- "QGIS_TestPyQgsProcessingCheckValidity")
+ "QGIS_TestPyQgsProcessingCheckValidity.com"
+ )
+ QCoreApplication.setApplicationName("QGIS_TestPyQgsProcessingCheckValidity")
QgsSettings().clear()
Processing.initialize()
cls.registry = QgsApplication.instance().processingRegistry()
@@ -61,9 +62,13 @@ def setUpClass(cls):
def _make_layer(self, layer_wkb_name):
fields = QgsFields()
wkb_type = getattr(QgsWkbTypes, layer_wkb_name)
- fields.append(QgsField('int_f', QVariant.Int))
+ fields.append(QgsField("int_f", QVariant.Int))
layer = QgsMemoryProviderUtils.createMemoryLayer(
- '%s_layer' % layer_wkb_name, fields, wkb_type, QgsCoordinateReferenceSystem("EPSG:4326"))
+ "%s_layer" % layer_wkb_name,
+ fields,
+ wkb_type,
+ QgsCoordinateReferenceSystem("EPSG:4326"),
+ )
self.assertTrue(layer.isValid())
self.assertEqual(layer.wkbType(), wkb_type)
return layer
@@ -71,18 +76,20 @@ def _make_layer(self, layer_wkb_name):
def test_check_validity(self):
"""Test that the output invalid contains the error reason"""
- polygon_layer = self._make_layer('Polygon')
+ polygon_layer = self._make_layer("Polygon")
self.assertTrue(polygon_layer.startEditing())
f = QgsFeature(polygon_layer.fields())
f.setAttributes([1])
# Flake!
- f.setGeometry(QgsGeometry.fromWkt(
- 'POLYGON ((0 0, 2 2, 0 2, 2 0, 0 0))'))
+ f.setGeometry(QgsGeometry.fromWkt("POLYGON ((0 0, 2 2, 0 2, 2 0, 0 0))"))
self.assertTrue(f.isValid())
f2 = QgsFeature(polygon_layer.fields())
f2.setAttributes([1])
- f2.setGeometry(QgsGeometry.fromWkt(
- 'POLYGON((1.1 1.1, 1.1 2.1, 2.1 2.1, 2.1 1.1, 1.1 1.1))'))
+ f2.setGeometry(
+ QgsGeometry.fromWkt(
+ "POLYGON((1.1 1.1, 1.1 2.1, 2.1 2.1, 2.1 1.1, 1.1 1.1))"
+ )
+ )
self.assertTrue(f2.isValid())
self.assertTrue(polygon_layer.addFeatures([f, f2]))
polygon_layer.commitChanges()
@@ -91,7 +98,7 @@ def test_check_validity(self):
QgsProject.instance().addMapLayers([polygon_layer])
- alg = self.registry.createAlgorithmById('qgis:checkvalidity')
+ alg = self.registry.createAlgorithmById("qgis:checkvalidity")
context = QgsProcessingContext()
context.setProject(QgsProject.instance())
@@ -99,36 +106,37 @@ def test_check_validity(self):
self.assertIsNotNone(alg)
parameters = {}
- parameters['INPUT_LAYER'] = polygon_layer.id()
- parameters['VALID_OUTPUT'] = 'memory:'
- parameters['INVALID_OUTPUT'] = 'memory:'
- parameters['ERROR_OUTPUT'] = 'memory:'
+ parameters["INPUT_LAYER"] = polygon_layer.id()
+ parameters["VALID_OUTPUT"] = "memory:"
+ parameters["INVALID_OUTPUT"] = "memory:"
+ parameters["ERROR_OUTPUT"] = "memory:"
# QGIS method
- parameters['METHOD'] = 1
- ok, results = execute(
- alg, parameters, context=context, feedback=feedback)
+ parameters["METHOD"] = 1
+ ok, results = execute(alg, parameters, context=context, feedback=feedback)
self.assertTrue(ok)
invalid_layer = QgsProcessingUtils.mapLayerFromString(
- results['INVALID_OUTPUT'], context)
- self.assertEqual(invalid_layer.fields().names()[-1], '_errors')
+ results["INVALID_OUTPUT"], context
+ )
+ self.assertEqual(invalid_layer.fields().names()[-1], "_errors")
self.assertEqual(invalid_layer.featureCount(), 1)
f = next(invalid_layer.getFeatures())
- self.assertEqual(f.attributes(), [
- 1, 'segments 0 and 2 of line 0 intersect at 1, 1'])
+ self.assertEqual(
+ f.attributes(), [1, "segments 0 and 2 of line 0 intersect at 1, 1"]
+ )
# GEOS method
- parameters['METHOD'] = 2
- ok, results = execute(
- alg, parameters, context=context, feedback=feedback)
+ parameters["METHOD"] = 2
+ ok, results = execute(alg, parameters, context=context, feedback=feedback)
self.assertTrue(ok)
invalid_layer = QgsProcessingUtils.mapLayerFromString(
- results['INVALID_OUTPUT'], context)
- self.assertEqual(invalid_layer.fields().names()[-1], '_errors')
+ results["INVALID_OUTPUT"], context
+ )
+ self.assertEqual(invalid_layer.fields().names()[-1], "_errors")
self.assertEqual(invalid_layer.featureCount(), 1)
f = next(invalid_layer.getFeatures())
- self.assertEqual(f.attributes(), [1, 'Self-intersection'])
+ self.assertEqual(f.attributes(), [1, "Self-intersection"])
-if __name__ == '__main__':
+if __name__ == "__main__":
unittest.main()
diff --git a/python/plugins/processing/tests/GdalAlgorithmsGeneralTest.py b/python/plugins/processing/tests/GdalAlgorithmsGeneralTest.py
index 40c86a90eed9..17e090601eb6 100644
--- a/python/plugins/processing/tests/GdalAlgorithmsGeneralTest.py
+++ b/python/plugins/processing/tests/GdalAlgorithmsGeneralTest.py
@@ -15,37 +15,38 @@
***************************************************************************
"""
-__author__ = 'Matthias Kuhn'
-__date__ = 'January 2016'
-__copyright__ = '(C) 2016, Matthias Kuhn'
+__author__ = "Matthias Kuhn"
+__date__ = "January 2016"
+__copyright__ = "(C) 2016, Matthias Kuhn"
import nose2
import os
import shutil
import tempfile
-from qgis.core import (QgsProcessingContext,
- QgsProcessingFeedback,
- QgsCoordinateReferenceSystem,
- QgsApplication,
- QgsFeature,
- QgsGeometry,
- QgsPointXY,
- QgsProject,
- QgsVectorLayer,
- QgsRectangle,
- QgsProjUtils,
- QgsProcessingException,
- QgsProcessingFeatureSourceDefinition)
-
-from qgis.testing import (QgisTestCase,
- start_app)
+from qgis.core import (
+ QgsProcessingContext,
+ QgsProcessingFeedback,
+ QgsCoordinateReferenceSystem,
+ QgsApplication,
+ QgsFeature,
+ QgsGeometry,
+ QgsPointXY,
+ QgsProject,
+ QgsVectorLayer,
+ QgsRectangle,
+ QgsProjUtils,
+ QgsProcessingException,
+ QgsProcessingFeatureSourceDefinition,
+)
+
+from qgis.testing import QgisTestCase, start_app
from processing.algs.gdal.GdalUtils import GdalUtils
from processing.algs.gdal.ogr2ogr import ogr2ogr
from processing.algs.gdal.OgrToPostGis import OgrToPostGis
-testDataPath = os.path.join(os.path.dirname(__file__), 'testdata')
+testDataPath = os.path.join(os.path.dirname(__file__), "testdata")
class TestGdalAlgorithms(QgisTestCase):
@@ -54,6 +55,7 @@ class TestGdalAlgorithms(QgisTestCase):
def setUpClass(cls):
start_app()
from processing.core.Processing import Processing
+
Processing.initialize()
cls.cleanup_paths = []
@@ -64,25 +66,28 @@ def tearDownClass(cls):
def testCommandName(self):
# Test that algorithms report a valid commandName
- p = QgsApplication.processingRegistry().providerById('gdal')
+ p = QgsApplication.processingRegistry().providerById("gdal")
for a in p.algorithms():
- if a.id() in ('gdal:buildvirtualvector'):
+ if a.id() in ("gdal:buildvirtualvector"):
# build virtual vector is an exception
continue
- self.assertTrue(a.commandName(), f'Algorithm {a.id()} has no commandName!')
+ self.assertTrue(a.commandName(), f"Algorithm {a.id()} has no commandName!")
def testCommandNameInTags(self):
# Test that algorithms commandName is present in provided tags
- p = QgsApplication.processingRegistry().providerById('gdal')
+ p = QgsApplication.processingRegistry().providerById("gdal")
for a in p.algorithms():
if not a.commandName():
continue
- self.assertTrue(a.commandName() in a.tags(), f'Algorithm {a.id()} commandName not found in tags!')
+ self.assertTrue(
+ a.commandName() in a.tags(),
+ f"Algorithm {a.id()} commandName not found in tags!",
+ )
def testNoParameters(self):
# Test that algorithms throw QgsProcessingException and not base Python
# exceptions when no parameters specified
- p = QgsApplication.processingRegistry().providerById('gdal')
+ p = QgsApplication.processingRegistry().providerById("gdal")
context = QgsProcessingContext()
feedback = QgsProcessingFeedback()
for a in p.algorithms():
@@ -93,8 +98,9 @@ def testNoParameters(self):
def testGetOgrCompatibleSourceFromMemoryLayer(self):
# create a memory layer and add to project and context
- layer = QgsVectorLayer("Point?field=fldtxt:string&field=fldint:integer",
- "testmem", "memory")
+ layer = QgsVectorLayer(
+ "Point?field=fldtxt:string&field=fldint:integer", "testmem", "memory"
+ )
self.assertTrue(layer.isValid())
pr = layer.dataProvider()
f = QgsFeature()
@@ -109,20 +115,23 @@ def testGetOgrCompatibleSourceFromMemoryLayer(self):
context = QgsProcessingContext()
context.setProject(QgsProject.instance())
- alg = QgsApplication.processingRegistry().createAlgorithmById('gdal:buffervectors')
+ alg = QgsApplication.processingRegistry().createAlgorithmById(
+ "gdal:buffervectors"
+ )
self.assertIsNotNone(alg)
- parameters = {'INPUT': 'testmem'}
+ parameters = {"INPUT": "testmem"}
feedback = QgsProcessingFeedback()
# check that memory layer is automatically saved out to geopackage when required by GDAL algorithms
- input_details = alg.getOgrCompatibleSource('INPUT', parameters, context, feedback,
- executing=True)
+ input_details = alg.getOgrCompatibleSource(
+ "INPUT", parameters, context, feedback, executing=True
+ )
self.assertTrue(input_details.connection_string)
- self.assertTrue(input_details.connection_string.endswith('.gpkg'))
+ self.assertTrue(input_details.connection_string.endswith(".gpkg"))
self.assertTrue(os.path.exists(input_details.connection_string))
self.assertTrue(input_details.connection_string)
# make sure that layer has correct features
- res = QgsVectorLayer(input_details.connection_string, 'res')
+ res = QgsVectorLayer(input_details.connection_string, "res")
self.assertTrue(res.isValid())
self.assertEqual(res.featureCount(), 2)
@@ -131,16 +140,17 @@ def testGetOgrCompatibleSourceFromMemoryLayer(self):
# - it has no meaning for the gdal command outside of QGIS, memory layers don't exist!
# - we don't want to force an export of the whole memory layer to a temp file just to show the command preview
# this might be very slow!
- input_details = alg.getOgrCompatibleSource('INPUT', parameters, context, feedback,
- executing=False)
- self.assertEqual(input_details.connection_string, 'path_to_data_file')
- self.assertEqual(input_details.layer_name, 'layer_name')
+ input_details = alg.getOgrCompatibleSource(
+ "INPUT", parameters, context, feedback, executing=False
+ )
+ self.assertEqual(input_details.connection_string, "path_to_data_file")
+ self.assertEqual(input_details.layer_name, "layer_name")
QgsProject.instance().removeMapLayer(layer)
def testGetOgrCompatibleSourceFromOgrLayer(self):
p = QgsProject()
- source = os.path.join(testDataPath, 'points.gml')
+ source = os.path.join(testDataPath, "points.gml")
vl = QgsVectorLayer(source)
self.assertTrue(vl.isValid())
p.addMapLayer(vl)
@@ -151,48 +161,63 @@ def testGetOgrCompatibleSourceFromOgrLayer(self):
alg = ogr2ogr()
alg.initAlgorithm()
- input_details = alg.getOgrCompatibleSource('INPUT', {'INPUT': vl.id()}, context, feedback, True)
+ input_details = alg.getOgrCompatibleSource(
+ "INPUT", {"INPUT": vl.id()}, context, feedback, True
+ )
self.assertEqual(input_details.connection_string, source)
- input_details = alg.getOgrCompatibleSource('INPUT', {'INPUT': vl.id()}, context, feedback, False)
+ input_details = alg.getOgrCompatibleSource(
+ "INPUT", {"INPUT": vl.id()}, context, feedback, False
+ )
self.assertEqual(input_details.connection_string, source)
# with selected features only - if not executing, the 'selected features only' setting
# should be ignored (because it has no meaning for the gdal command outside of QGIS!)
- parameters = {'INPUT': QgsProcessingFeatureSourceDefinition(vl.id(), True)}
- input_details = alg.getOgrCompatibleSource('INPUT', parameters, context, feedback, False)
+ parameters = {"INPUT": QgsProcessingFeatureSourceDefinition(vl.id(), True)}
+ input_details = alg.getOgrCompatibleSource(
+ "INPUT", parameters, context, feedback, False
+ )
self.assertEqual(input_details.connection_string, source)
# with subset string
- vl.setSubsetString('x')
- input_details = alg.getOgrCompatibleSource('INPUT', parameters, context, feedback, False)
+ vl.setSubsetString("x")
+ input_details = alg.getOgrCompatibleSource(
+ "INPUT", parameters, context, feedback, False
+ )
self.assertEqual(input_details.connection_string, source)
# subset of layer must be exported
- input_details = alg.getOgrCompatibleSource('INPUT', parameters, context, feedback, True)
+ input_details = alg.getOgrCompatibleSource(
+ "INPUT", parameters, context, feedback, True
+ )
self.assertNotEqual(input_details.connection_string, source)
self.assertTrue(input_details.connection_string)
- self.assertTrue(input_details.connection_string.endswith('.gpkg'))
+ self.assertTrue(input_details.connection_string.endswith(".gpkg"))
self.assertTrue(os.path.exists(input_details.connection_string))
self.assertTrue(input_details.layer_name)
# geopackage with layer
- source = os.path.join(testDataPath, 'custom', 'circular_strings.gpkg')
- vl2 = QgsVectorLayer(source + '|layername=circular_strings')
+ source = os.path.join(testDataPath, "custom", "circular_strings.gpkg")
+ vl2 = QgsVectorLayer(source + "|layername=circular_strings")
self.assertTrue(vl2.isValid())
p.addMapLayer(vl2)
- input_details = alg.getOgrCompatibleSource('INPUT', {'INPUT': vl2.id()}, context, feedback, True)
+ input_details = alg.getOgrCompatibleSource(
+ "INPUT", {"INPUT": vl2.id()}, context, feedback, True
+ )
self.assertEqual(input_details.connection_string, source)
- self.assertEqual(input_details.layer_name, 'circular_strings')
- vl3 = QgsVectorLayer(source + '|layername=circular_strings_with_line')
+ self.assertEqual(input_details.layer_name, "circular_strings")
+ vl3 = QgsVectorLayer(source + "|layername=circular_strings_with_line")
self.assertTrue(vl3.isValid())
p.addMapLayer(vl3)
- input_details = alg.getOgrCompatibleSource('INPUT', {'INPUT': vl3.id()}, context, feedback, True)
+ input_details = alg.getOgrCompatibleSource(
+ "INPUT", {"INPUT": vl3.id()}, context, feedback, True
+ )
self.assertEqual(input_details.connection_string, source)
- self.assertEqual(input_details.layer_name, 'circular_strings_with_line')
+ self.assertEqual(input_details.layer_name, "circular_strings_with_line")
def testGetOgrCompatibleSourceFromFeatureSource(self):
# create a memory layer and add to project and context
- layer = QgsVectorLayer("Point?field=fldtxt:string&field=fldint:integer",
- "testmem", "memory")
+ layer = QgsVectorLayer(
+ "Point?field=fldtxt:string&field=fldint:integer", "testmem", "memory"
+ )
self.assertTrue(layer.isValid())
pr = layer.dataProvider()
f = QgsFeature()
@@ -210,76 +235,95 @@ def testGetOgrCompatibleSourceFromFeatureSource(self):
context = QgsProcessingContext()
context.setProject(QgsProject.instance())
- alg = QgsApplication.processingRegistry().createAlgorithmById('gdal:buffervectors')
+ alg = QgsApplication.processingRegistry().createAlgorithmById(
+ "gdal:buffervectors"
+ )
self.assertIsNotNone(alg)
- parameters = {'INPUT': QgsProcessingFeatureSourceDefinition('testmem', True)}
+ parameters = {"INPUT": QgsProcessingFeatureSourceDefinition("testmem", True)}
feedback = QgsProcessingFeedback()
# check that memory layer is automatically saved out to geopackage when required by GDAL algorithms
- input_details = alg.getOgrCompatibleSource('INPUT', parameters, context, feedback,
- executing=True)
+ input_details = alg.getOgrCompatibleSource(
+ "INPUT", parameters, context, feedback, executing=True
+ )
self.assertTrue(input_details.connection_string)
- self.assertTrue(input_details.connection_string.endswith('.gpkg'))
+ self.assertTrue(input_details.connection_string.endswith(".gpkg"))
self.assertTrue(os.path.exists(input_details.connection_string))
self.assertTrue(input_details.layer_name)
# make sure that layer has only selected feature
- res = QgsVectorLayer(input_details.connection_string, 'res')
+ res = QgsVectorLayer(input_details.connection_string, "res")
self.assertTrue(res.isValid())
self.assertEqual(res.featureCount(), 1)
QgsProject.instance().removeMapLayer(layer)
def testOgrOutputLayerName(self):
- self.assertEqual(GdalUtils.ogrOutputLayerName('/home/me/out.shp'), 'out')
- self.assertEqual(GdalUtils.ogrOutputLayerName('d:/test/test_out.shp'), 'test_out')
- self.assertEqual(GdalUtils.ogrOutputLayerName('d:/test/TEST_OUT.shp'), 'TEST_OUT')
- self.assertEqual(GdalUtils.ogrOutputLayerName('d:/test/test_out.gpkg'), 'test_out')
+ self.assertEqual(GdalUtils.ogrOutputLayerName("/home/me/out.shp"), "out")
+ self.assertEqual(
+ GdalUtils.ogrOutputLayerName("d:/test/test_out.shp"), "test_out"
+ )
+ self.assertEqual(
+ GdalUtils.ogrOutputLayerName("d:/test/TEST_OUT.shp"), "TEST_OUT"
+ )
+ self.assertEqual(
+ GdalUtils.ogrOutputLayerName("d:/test/test_out.gpkg"), "test_out"
+ )
def testOgrLayerNameExtraction(self):
with tempfile.TemporaryDirectory() as outdir:
+
def _copyFile(dst):
- shutil.copyfile(os.path.join(testDataPath, 'custom', 'weighted.csv'), dst)
+ shutil.copyfile(
+ os.path.join(testDataPath, "custom", "weighted.csv"), dst
+ )
# OGR provider - single layer
- _copyFile(os.path.join(outdir, 'a.csv'))
+ _copyFile(os.path.join(outdir, "a.csv"))
name = GdalUtils.ogrLayerName(outdir)
- self.assertEqual(name, 'a')
+ self.assertEqual(name, "a")
# OGR provider - multiple layers
- _copyFile(os.path.join(outdir, 'b.csv'))
- name1 = GdalUtils.ogrLayerName(outdir + '|layerid=0')
- name2 = GdalUtils.ogrLayerName(outdir + '|layerid=1')
- self.assertEqual(sorted([name1, name2]), ['a', 'b'])
+ _copyFile(os.path.join(outdir, "b.csv"))
+ name1 = GdalUtils.ogrLayerName(outdir + "|layerid=0")
+ name2 = GdalUtils.ogrLayerName(outdir + "|layerid=1")
+ self.assertEqual(sorted([name1, name2]), ["a", "b"])
- name = GdalUtils.ogrLayerName(outdir + '|layerid=2')
+ name = GdalUtils.ogrLayerName(outdir + "|layerid=2")
self.assertIsNone(name)
# OGR provider - layername takes precedence
- name = GdalUtils.ogrLayerName(outdir + '|layername=f')
- self.assertEqual(name, 'f')
+ name = GdalUtils.ogrLayerName(outdir + "|layername=f")
+ self.assertEqual(name, "f")
- name = GdalUtils.ogrLayerName(outdir + '|layerid=0|layername=f')
- self.assertEqual(name, 'f')
+ name = GdalUtils.ogrLayerName(outdir + "|layerid=0|layername=f")
+ self.assertEqual(name, "f")
- name = GdalUtils.ogrLayerName(outdir + '|layername=f|layerid=0')
- self.assertEqual(name, 'f')
+ name = GdalUtils.ogrLayerName(outdir + "|layername=f|layerid=0")
+ self.assertEqual(name, "f")
# SQLite provider
- name = GdalUtils.ogrLayerName('dbname=\'/tmp/x.sqlite\' table="t" (geometry) sql=')
- self.assertEqual(name, 't')
+ name = GdalUtils.ogrLayerName(
+ "dbname='/tmp/x.sqlite' table=\"t\" (geometry) sql="
+ )
+ self.assertEqual(name, "t")
# PostgreSQL provider
name = GdalUtils.ogrLayerName(
- 'port=5493 sslmode=disable key=\'edge_id\' srid=0 type=LineString table="city_data"."edge" (geom) sql=')
- self.assertEqual(name, 'city_data.edge')
+ 'port=5493 sslmode=disable key=\'edge_id\' srid=0 type=LineString table="city_data"."edge" (geom) sql='
+ )
+ self.assertEqual(name, "city_data.edge")
def test_gdal_connection_details_from_uri(self):
context = QgsProcessingContext()
- output_details = GdalUtils.gdal_connection_details_from_uri('d:/test/test.shp', context)
- self.assertEqual(output_details.connection_string, 'd:/test/test.shp')
+ output_details = GdalUtils.gdal_connection_details_from_uri(
+ "d:/test/test.shp", context
+ )
+ self.assertEqual(output_details.connection_string, "d:/test/test.shp")
self.assertEqual(output_details.format, '"ESRI Shapefile"')
- output_details = GdalUtils.gdal_connection_details_from_uri('d:/test/test.mif', context)
- self.assertEqual(output_details.connection_string, 'd:/test/test.mif')
+ output_details = GdalUtils.gdal_connection_details_from_uri(
+ "d:/test/test.mif", context
+ )
+ self.assertEqual(output_details.connection_string, "d:/test/test.mif")
self.assertEqual(output_details.format, '"MapInfo File"')
def testConnectionString(self):
@@ -291,54 +335,91 @@ def testConnectionString(self):
# NOTE: defaults are debatable, see
# https://github.com/qgis/QGIS/pull/3607#issuecomment-253971020
- self.assertEqual(alg.getConnectionString(parameters, context),
- "host=localhost port=5432 active_schema=public")
-
- parameters['HOST'] = 'remote'
- self.assertEqual(alg.getConnectionString(parameters, context),
- "host=remote port=5432 active_schema=public")
-
- parameters['HOST'] = ''
- self.assertEqual(alg.getConnectionString(parameters, context),
- "port=5432 active_schema=public")
-
- parameters['PORT'] = '5555'
- self.assertEqual(alg.getConnectionString(parameters, context),
- "port=5555 active_schema=public")
-
- parameters['PORT'] = ''
- self.assertEqual(alg.getConnectionString(parameters, context),
- "active_schema=public")
-
- parameters['USER'] = 'usr'
- self.assertEqual(alg.getConnectionString(parameters, context),
- "active_schema=public user=usr")
-
- parameters['PASSWORD'] = 'pwd'
- self.assertEqual(alg.getConnectionString(parameters, context),
- "password=pwd active_schema=public user=usr")
+ self.assertEqual(
+ alg.getConnectionString(parameters, context),
+ "host=localhost port=5432 active_schema=public",
+ )
+
+ parameters["HOST"] = "remote"
+ self.assertEqual(
+ alg.getConnectionString(parameters, context),
+ "host=remote port=5432 active_schema=public",
+ )
+
+ parameters["HOST"] = ""
+ self.assertEqual(
+ alg.getConnectionString(parameters, context),
+ "port=5432 active_schema=public",
+ )
+
+ parameters["PORT"] = "5555"
+ self.assertEqual(
+ alg.getConnectionString(parameters, context),
+ "port=5555 active_schema=public",
+ )
+
+ parameters["PORT"] = ""
+ self.assertEqual(
+ alg.getConnectionString(parameters, context), "active_schema=public"
+ )
+
+ parameters["USER"] = "usr"
+ self.assertEqual(
+ alg.getConnectionString(parameters, context),
+ "active_schema=public user=usr",
+ )
+
+ parameters["PASSWORD"] = "pwd"
+ self.assertEqual(
+ alg.getConnectionString(parameters, context),
+ "password=pwd active_schema=public user=usr",
+ )
def testCrsConversion(self):
self.assertFalse(GdalUtils.gdal_crs_string(QgsCoordinateReferenceSystem()))
- self.assertEqual(GdalUtils.gdal_crs_string(QgsCoordinateReferenceSystem('EPSG:3111')), 'EPSG:3111')
- self.assertEqual(GdalUtils.gdal_crs_string(QgsCoordinateReferenceSystem('POSTGIS:3111')), 'EPSG:3111')
- self.assertEqual(GdalUtils.gdal_crs_string(QgsCoordinateReferenceSystem(
- 'proj4: +proj=utm +zone=36 +south +a=6378249.145 +b=6356514.966398753 +towgs84=-143,-90,-294,0,0,0,0 +units=m +no_defs')),
- 'EPSG:20936')
+ self.assertEqual(
+ GdalUtils.gdal_crs_string(QgsCoordinateReferenceSystem("EPSG:3111")),
+ "EPSG:3111",
+ )
+ self.assertEqual(
+ GdalUtils.gdal_crs_string(QgsCoordinateReferenceSystem("POSTGIS:3111")),
+ "EPSG:3111",
+ )
+ self.assertEqual(
+ GdalUtils.gdal_crs_string(
+ QgsCoordinateReferenceSystem(
+ "proj4: +proj=utm +zone=36 +south +a=6378249.145 +b=6356514.966398753 +towgs84=-143,-90,-294,0,0,0,0 +units=m +no_defs"
+ )
+ ),
+ "EPSG:20936",
+ )
crs = QgsCoordinateReferenceSystem()
crs.createFromProj(
- '+proj=utm +zone=36 +south +a=600000 +b=70000 +towgs84=-143,-90,-294,0,0,0,0 +units=m +no_defs')
+ "+proj=utm +zone=36 +south +a=600000 +b=70000 +towgs84=-143,-90,-294,0,0,0,0 +units=m +no_defs"
+ )
self.assertTrue(crs.isValid())
# proj 6, WKT should be used
- self.assertEqual(GdalUtils.gdal_crs_string(crs)[:40], 'BOUNDCRS[SOURCECRS[PROJCRS["unknown",BAS')
+ self.assertEqual(
+ GdalUtils.gdal_crs_string(crs)[:40],
+ 'BOUNDCRS[SOURCECRS[PROJCRS["unknown",BAS',
+ )
- self.assertEqual(GdalUtils.gdal_crs_string(QgsCoordinateReferenceSystem('ESRI:102003')), 'ESRI:102003')
+ self.assertEqual(
+ GdalUtils.gdal_crs_string(QgsCoordinateReferenceSystem("ESRI:102003")),
+ "ESRI:102003",
+ )
def testEscapeAndJoin(self):
- self.assertEqual(GdalUtils.escapeAndJoin([1, "a", "a b", "a&b", "a(b)", ";"]), '1 a "a b" "a&b" "a(b)" ";"')
- self.assertEqual(GdalUtils.escapeAndJoin([1, "-srcnodata", "--srcnodata", "-9999 9999"]), '1 -srcnodata --srcnodata "-9999 9999"')
+ self.assertEqual(
+ GdalUtils.escapeAndJoin([1, "a", "a b", "a&b", "a(b)", ";"]),
+ '1 a "a b" "a&b" "a(b)" ";"',
+ )
+ self.assertEqual(
+ GdalUtils.escapeAndJoin([1, "-srcnodata", "--srcnodata", "-9999 9999"]),
+ '1 -srcnodata --srcnodata "-9999 9999"',
+ )
-if __name__ == '__main__':
+if __name__ == "__main__":
nose2.main()
diff --git a/python/plugins/processing/tests/GdalAlgorithmsRasterTest.py b/python/plugins/processing/tests/GdalAlgorithmsRasterTest.py
index 7971a36179a4..390c37e845b3 100644
--- a/python/plugins/processing/tests/GdalAlgorithmsRasterTest.py
+++ b/python/plugins/processing/tests/GdalAlgorithmsRasterTest.py
@@ -15,29 +15,29 @@
***************************************************************************
"""
-__author__ = 'Matthias Kuhn'
-__date__ = 'January 2016'
-__copyright__ = '(C) 2016, Matthias Kuhn'
+__author__ = "Matthias Kuhn"
+__date__ = "January 2016"
+__copyright__ = "(C) 2016, Matthias Kuhn"
import nose2
import os
import shutil
import tempfile
-from qgis.core import (QgsProcessingContext,
- QgsProcessingException,
- QgsProcessingFeedback,
- QgsRectangle,
- QgsReferencedRectangle,
- QgsRasterLayer,
- QgsProject,
- QgsProjUtils,
- QgsPointXY,
- QgsCoordinateReferenceSystem)
-
-from qgis.testing import (QgisTestCase,
- start_app,
- unittest)
+from qgis.core import (
+ QgsProcessingContext,
+ QgsProcessingException,
+ QgsProcessingFeedback,
+ QgsRectangle,
+ QgsReferencedRectangle,
+ QgsRasterLayer,
+ QgsProject,
+ QgsProjUtils,
+ QgsPointXY,
+ QgsCoordinateReferenceSystem,
+)
+
+from qgis.testing import QgisTestCase, start_app, unittest
import AlgorithmsTestBase
from processing.algs.gdal.GdalUtils import GdalUtils
@@ -48,7 +48,9 @@
from processing.algs.gdal.GridAverage import GridAverage
from processing.algs.gdal.GridDataMetrics import GridDataMetrics
from processing.algs.gdal.GridInverseDistance import GridInverseDistance
-from processing.algs.gdal.GridInverseDistanceNearestNeighbor import GridInverseDistanceNearestNeighbor
+from processing.algs.gdal.GridInverseDistanceNearestNeighbor import (
+ GridInverseDistanceNearestNeighbor,
+)
from processing.algs.gdal.GridLinear import GridLinear
from processing.algs.gdal.GridNearestNeighbor import GridNearestNeighbor
from processing.algs.gdal.gdal2tiles import gdal2tiles
@@ -81,7 +83,7 @@
from processing.algs.gdal.pct2rgb import pct2rgb
from processing.algs.gdal.rgb2pct import rgb2pct
-testDataPath = os.path.join(os.path.dirname(__file__), 'testdata')
+testDataPath = os.path.join(os.path.dirname(__file__), "testdata")
class TestGdalRasterAlgorithms(QgisTestCase, AlgorithmsTestBase.AlgorithmsTest):
@@ -90,6 +92,7 @@ class TestGdalRasterAlgorithms(QgisTestCase, AlgorithmsTestBase.AlgorithmsTest):
def setUpClass(cls):
start_app()
from processing.core.Processing import Processing
+
Processing.initialize()
cls.cleanup_paths = []
@@ -99,247 +102,383 @@ def tearDownClass(cls):
shutil.rmtree(path)
def definition_file(self):
- return 'gdal_algorithm_raster_tests.yaml'
+ return "gdal_algorithm_raster_tests.yaml"
@staticmethod
def get_param_value_and_expected_string_for_custom_crs(proj_def):
crs = QgsCoordinateReferenceSystem.fromProj(proj_def)
- custom_crs = f'proj4: {proj_def}'
- return custom_crs, crs.toWkt(QgsCoordinateReferenceSystem.WktVariant.WKT_PREFERRED_GDAL).replace('"', '"""')
+ custom_crs = f"proj4: {proj_def}"
+ return custom_crs, crs.toWkt(
+ QgsCoordinateReferenceSystem.WktVariant.WKT_PREFERRED_GDAL
+ ).replace('"', '"""')
def testAssignProjection(self):
context = QgsProcessingContext()
feedback = QgsProcessingFeedback()
- source = os.path.join(testDataPath, 'dem.tif')
+ source = os.path.join(testDataPath, "dem.tif")
alg = AssignProjection()
alg.initAlgorithm()
# with target srs
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'CRS': 'EPSG:3111'}, context, feedback),
- ['gdal_edit.py',
- '-a_srs EPSG:3111 ' +
- source])
+ alg.getConsoleCommands(
+ {"INPUT": source, "CRS": "EPSG:3111"}, context, feedback
+ ),
+ ["gdal_edit.py", "-a_srs EPSG:3111 " + source],
+ )
# with target using proj string
- custom_crs = 'proj4: +proj=utm +zone=36 +south +a=6378249.145 +b=6356514.966398753 +towgs84=-143,-90,-294,0,0,0,0 +units=m +no_defs'
+ custom_crs = "proj4: +proj=utm +zone=36 +south +a=6378249.145 +b=6356514.966398753 +towgs84=-143,-90,-294,0,0,0,0 +units=m +no_defs"
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'CRS': custom_crs}, context, feedback),
- ['gdal_edit.py',
- '-a_srs EPSG:20936 ' +
- source])
+ alg.getConsoleCommands(
+ {"INPUT": source, "CRS": custom_crs}, context, feedback
+ ),
+ ["gdal_edit.py", "-a_srs EPSG:20936 " + source],
+ )
# with target using custom projection
- custom_crs, expected_crs_string = self.get_param_value_and_expected_string_for_custom_crs(
- '+proj=utm +zone=36 +south +a=63785 +b=6357 +towgs84=-143,-90,-294,0,0,0,0 +units=m +no_defs')
+ custom_crs, expected_crs_string = (
+ self.get_param_value_and_expected_string_for_custom_crs(
+ "+proj=utm +zone=36 +south +a=63785 +b=6357 +towgs84=-143,-90,-294,0,0,0,0 +units=m +no_defs"
+ )
+ )
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'CRS': custom_crs}, context, feedback),
- ['gdal_edit.py',
- f'-a_srs "{expected_crs_string}" ' +
- source])
+ alg.getConsoleCommands(
+ {"INPUT": source, "CRS": custom_crs}, context, feedback
+ ),
+ ["gdal_edit.py", f'-a_srs "{expected_crs_string}" ' + source],
+ )
# with non-EPSG crs code
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'CRS': 'POSTGIS:3111'}, context, feedback),
- ['gdal_edit.py',
- '-a_srs EPSG:3111 ' +
- source])
+ alg.getConsoleCommands(
+ {"INPUT": source, "CRS": "POSTGIS:3111"}, context, feedback
+ ),
+ ["gdal_edit.py", "-a_srs EPSG:3111 " + source],
+ )
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source + '|option:X_POSSIBLE_NAMES=geom_x|option:Y_POSSIBLE_NAMES=geom_y',
- 'CRS': 'EPSG:3111'}, context, feedback),
- ['gdal_edit.py',
- '-a_srs EPSG:3111 ' +
- source + ' -oo X_POSSIBLE_NAMES=geom_x -oo Y_POSSIBLE_NAMES=geom_y'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source
+ + "|option:X_POSSIBLE_NAMES=geom_x|option:Y_POSSIBLE_NAMES=geom_y",
+ "CRS": "EPSG:3111",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdal_edit.py",
+ "-a_srs EPSG:3111 "
+ + source
+ + " -oo X_POSSIBLE_NAMES=geom_x -oo Y_POSSIBLE_NAMES=geom_y",
+ ],
+ )
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source + '|credential:X=Y|credential:Z=A',
- 'CRS': 'EPSG:3111'}, context, feedback),
- ['gdal_edit.py',
- '-a_srs EPSG:3111 ' +
- source + ' --config X Y --config Z A'])
-
- @unittest.skipIf(os.environ.get('TRAVIS', '') == 'true',
- 'gdal_edit.py: not found')
+ alg.getConsoleCommands(
+ {
+ "INPUT": source + "|credential:X=Y|credential:Z=A",
+ "CRS": "EPSG:3111",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdal_edit.py",
+ "-a_srs EPSG:3111 " + source + " --config X Y --config Z A",
+ ],
+ )
+
+ @unittest.skipIf(os.environ.get("TRAVIS", "") == "true", "gdal_edit.py: not found")
def testRunAssignProjection(self):
# Check that assign projection updates QgsRasterLayer info
# GDAL Assign Projection is based on gdal_edit.py
context = QgsProcessingContext()
feedback = QgsProcessingFeedback()
- source = os.path.join(testDataPath, 'dem.tif')
+ source = os.path.join(testDataPath, "dem.tif")
alg = AssignProjection()
alg.initAlgorithm()
with tempfile.TemporaryDirectory() as outdir:
- fake_dem = os.path.join(outdir, 'dem-fake-crs.tif')
+ fake_dem = os.path.join(outdir, "dem-fake-crs.tif")
shutil.copy(source, fake_dem)
self.assertTrue(os.path.exists(fake_dem))
rlayer = QgsRasterLayer(fake_dem, "Fake dem")
self.assertTrue(rlayer.isValid())
- self.assertEqual(rlayer.crs().authid(), 'EPSG:4326')
+ self.assertEqual(rlayer.crs().authid(), "EPSG:4326")
project = QgsProject()
- project.setFileName(os.path.join(outdir, 'dem-fake-crs.qgs'))
+ project.setFileName(os.path.join(outdir, "dem-fake-crs.qgs"))
project.addMapLayer(rlayer)
self.assertEqual(project.count(), 1)
context.setProject(project)
- alg.run({'INPUT': fake_dem, 'CRS': 'EPSG:3111'},
- context, feedback)
- self.assertEqual(rlayer.crs().authid(), 'EPSG:3111')
+ alg.run({"INPUT": fake_dem, "CRS": "EPSG:3111"}, context, feedback)
+ self.assertEqual(rlayer.crs().authid(), "EPSG:3111")
def testGdalTranslate(self):
context = QgsProcessingContext()
feedback = QgsProcessingFeedback()
- source = os.path.join(testDataPath, 'dem.tif')
+ source = os.path.join(testDataPath, "dem.tif")
translate_alg = translate()
translate_alg.initAlgorithm()
with tempfile.TemporaryDirectory() as outdir:
# without NODATA value
self.assertEqual(
- translate_alg.getConsoleCommands({'INPUT': source,
- 'OUTPUT': outdir + '/check.jpg'}, context, feedback),
- ['gdal_translate',
- '-of JPEG ' +
- source + ' ' +
- outdir + '/check.jpg'])
+ translate_alg.getConsoleCommands(
+ {"INPUT": source, "OUTPUT": outdir + "/check.jpg"},
+ context,
+ feedback,
+ ),
+ ["gdal_translate", "-of JPEG " + source + " " + outdir + "/check.jpg"],
+ )
# with None NODATA value
self.assertEqual(
- translate_alg.getConsoleCommands({'INPUT': source,
- 'NODATA': None,
- 'OUTPUT': outdir + '/check.jpg'}, context, feedback),
- ['gdal_translate',
- '-of JPEG ' +
- source + ' ' +
- outdir + '/check.jpg'])
+ translate_alg.getConsoleCommands(
+ {"INPUT": source, "NODATA": None, "OUTPUT": outdir + "/check.jpg"},
+ context,
+ feedback,
+ ),
+ ["gdal_translate", "-of JPEG " + source + " " + outdir + "/check.jpg"],
+ )
# with NODATA value
self.assertEqual(
- translate_alg.getConsoleCommands({'INPUT': source,
- 'NODATA': 9999,
- 'OUTPUT': outdir + '/check.jpg'}, context, feedback),
- ['gdal_translate',
- '-a_nodata 9999.0 ' +
- '-of JPEG ' +
- source + ' ' +
- outdir + '/check.jpg'])
+ translate_alg.getConsoleCommands(
+ {"INPUT": source, "NODATA": 9999, "OUTPUT": outdir + "/check.jpg"},
+ context,
+ feedback,
+ ),
+ [
+ "gdal_translate",
+ "-a_nodata 9999.0 "
+ + "-of JPEG "
+ + source
+ + " "
+ + outdir
+ + "/check.jpg",
+ ],
+ )
# with "0" NODATA value
self.assertEqual(
- translate_alg.getConsoleCommands({'INPUT': source,
- 'NODATA': 0,
- 'OUTPUT': outdir + '/check.jpg'}, context, feedback),
- ['gdal_translate',
- '-a_nodata 0.0 ' +
- '-of JPEG ' +
- source + ' ' +
- outdir + '/check.jpg'])
+ translate_alg.getConsoleCommands(
+ {"INPUT": source, "NODATA": 0, "OUTPUT": outdir + "/check.jpg"},
+ context,
+ feedback,
+ ),
+ [
+ "gdal_translate",
+ "-a_nodata 0.0 "
+ + "-of JPEG "
+ + source
+ + " "
+ + outdir
+ + "/check.jpg",
+ ],
+ )
# with "0" NODATA value and custom data type
self.assertEqual(
- translate_alg.getConsoleCommands({'INPUT': source,
- 'NODATA': 0,
- 'DATA_TYPE': 6,
- 'OUTPUT': outdir + '/check.jpg'}, context, feedback),
- ['gdal_translate',
- '-a_nodata 0.0 ' +
- '-ot Float32 -of JPEG ' +
- source + ' ' +
- outdir + '/check.jpg'])
+ translate_alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "NODATA": 0,
+ "DATA_TYPE": 6,
+ "OUTPUT": outdir + "/check.jpg",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdal_translate",
+ "-a_nodata 0.0 "
+ + "-ot Float32 -of JPEG "
+ + source
+ + " "
+ + outdir
+ + "/check.jpg",
+ ],
+ )
# with target srs
self.assertEqual(
- translate_alg.getConsoleCommands({'INPUT': source,
- 'TARGET_CRS': 'EPSG:3111',
- 'OUTPUT': outdir + '/check.jpg'}, context, feedback),
- ['gdal_translate',
- '-a_srs EPSG:3111 ' +
- '-of JPEG ' +
- source + ' ' +
- outdir + '/check.jpg'])
+ translate_alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "TARGET_CRS": "EPSG:3111",
+ "OUTPUT": outdir + "/check.jpg",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdal_translate",
+ "-a_srs EPSG:3111 "
+ + "-of JPEG "
+ + source
+ + " "
+ + outdir
+ + "/check.jpg",
+ ],
+ )
# with target using proj string
- custom_crs = 'proj4: +proj=utm +zone=36 +south +a=6378249.145 +b=6356514.966398753 +towgs84=-143,-90,-294,0,0,0,0 +units=m +no_defs'
- self.assertEqual(
- translate_alg.getConsoleCommands({'INPUT': source,
- 'TARGET_CRS': custom_crs,
- 'OUTPUT': outdir + '/check.jpg'}, context, feedback),
- ['gdal_translate',
- '-a_srs EPSG:20936 ' +
- '-of JPEG ' +
- source + ' ' +
- outdir + '/check.jpg'])
+ custom_crs = "proj4: +proj=utm +zone=36 +south +a=6378249.145 +b=6356514.966398753 +towgs84=-143,-90,-294,0,0,0,0 +units=m +no_defs"
+ self.assertEqual(
+ translate_alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "TARGET_CRS": custom_crs,
+ "OUTPUT": outdir + "/check.jpg",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdal_translate",
+ "-a_srs EPSG:20936 "
+ + "-of JPEG "
+ + source
+ + " "
+ + outdir
+ + "/check.jpg",
+ ],
+ )
# with target using custom projection
- custom_crs, expected_crs_string = self.get_param_value_and_expected_string_for_custom_crs('+proj=utm +zone=36 +south +a=63785 +b=6357 +towgs84=-143,-90,-294,0,0,0,0 +units=m +no_defs')
- self.assertEqual(
- translate_alg.getConsoleCommands({'INPUT': source,
- 'TARGET_CRS': custom_crs,
- 'OUTPUT': outdir + '/check.jpg'}, context, feedback),
- ['gdal_translate',
- f'-a_srs "{expected_crs_string}" ' +
- '-of JPEG ' +
- source + ' ' +
- outdir + '/check.jpg'])
+ custom_crs, expected_crs_string = (
+ self.get_param_value_and_expected_string_for_custom_crs(
+ "+proj=utm +zone=36 +south +a=63785 +b=6357 +towgs84=-143,-90,-294,0,0,0,0 +units=m +no_defs"
+ )
+ )
+ self.assertEqual(
+ translate_alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "TARGET_CRS": custom_crs,
+ "OUTPUT": outdir + "/check.jpg",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdal_translate",
+ f'-a_srs "{expected_crs_string}" '
+ + "-of JPEG "
+ + source
+ + " "
+ + outdir
+ + "/check.jpg",
+ ],
+ )
# with non-EPSG crs code
self.assertEqual(
- translate_alg.getConsoleCommands({'INPUT': source,
- 'TARGET_CRS': 'POSTGIS:3111',
- 'OUTPUT': outdir + '/check.jpg'}, context, feedback),
- ['gdal_translate',
- '-a_srs EPSG:3111 ' +
- '-of JPEG ' +
- source + ' ' +
- outdir + '/check.jpg'])
+ translate_alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "TARGET_CRS": "POSTGIS:3111",
+ "OUTPUT": outdir + "/check.jpg",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdal_translate",
+ "-a_srs EPSG:3111 "
+ + "-of JPEG "
+ + source
+ + " "
+ + outdir
+ + "/check.jpg",
+ ],
+ )
# with copy subdatasets
self.assertEqual(
- translate_alg.getConsoleCommands({'INPUT': source,
- 'COPY_SUBDATASETS': True,
- 'OUTPUT': outdir + '/check.tif'}, context, feedback),
- ['gdal_translate',
- '-sds ' +
- '-of GTiff ' +
- source + ' ' +
- outdir + '/check.tif'])
+ translate_alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "COPY_SUBDATASETS": True,
+ "OUTPUT": outdir + "/check.tif",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdal_translate",
+ "-sds " + "-of GTiff " + source + " " + outdir + "/check.tif",
+ ],
+ )
# additional parameters
self.assertEqual(
- translate_alg.getConsoleCommands({'INPUT': source,
- 'EXTRA': '-strict -unscale -epo',
- 'OUTPUT': outdir + '/check.jpg'}, context, feedback),
- ['gdal_translate',
- '-of JPEG -strict -unscale -epo ' +
- source + ' ' +
- outdir + '/check.jpg'])
-
- self.assertEqual(
- translate_alg.getConsoleCommands({'INPUT': source + '|option:X_POSSIBLE_NAMES=geom_x|option:Y_POSSIBLE_NAMES=geom_y',
- 'OUTPUT': outdir + '/check.jpg'}, context, feedback),
- ['gdal_translate',
- '-of JPEG ' +
- source + ' ' +
- outdir + '/check.jpg -oo X_POSSIBLE_NAMES=geom_x -oo Y_POSSIBLE_NAMES=geom_y'])
-
- self.assertEqual(
- translate_alg.getConsoleCommands({'INPUT': source + '|credential:X=Y|credential:Z=A',
- 'OUTPUT': outdir + '/check.jpg'}, context, feedback),
- ['gdal_translate',
- '-of JPEG ' +
- source + ' ' +
- outdir + '/check.jpg --config X Y --config Z A'])
+ translate_alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "EXTRA": "-strict -unscale -epo",
+ "OUTPUT": outdir + "/check.jpg",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdal_translate",
+ "-of JPEG -strict -unscale -epo "
+ + source
+ + " "
+ + outdir
+ + "/check.jpg",
+ ],
+ )
+
+ self.assertEqual(
+ translate_alg.getConsoleCommands(
+ {
+ "INPUT": source
+ + "|option:X_POSSIBLE_NAMES=geom_x|option:Y_POSSIBLE_NAMES=geom_y",
+ "OUTPUT": outdir + "/check.jpg",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdal_translate",
+ "-of JPEG "
+ + source
+ + " "
+ + outdir
+ + "/check.jpg -oo X_POSSIBLE_NAMES=geom_x -oo Y_POSSIBLE_NAMES=geom_y",
+ ],
+ )
+
+ self.assertEqual(
+ translate_alg.getConsoleCommands(
+ {
+ "INPUT": source + "|credential:X=Y|credential:Z=A",
+ "OUTPUT": outdir + "/check.jpg",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdal_translate",
+ "-of JPEG "
+ + source
+ + " "
+ + outdir
+ + "/check.jpg --config X Y --config Z A",
+ ],
+ )
def testClipRasterByExtent(self):
context = QgsProcessingContext()
feedback = QgsProcessingFeedback()
- source = os.path.join(testDataPath, 'dem.tif')
+ source = os.path.join(testDataPath, "dem.tif")
alg = ClipRasterByExtent()
alg.initAlgorithm()
extent = QgsRectangle(1, 2, 3, 4)
@@ -347,1809 +486,3273 @@ def testClipRasterByExtent(self):
with tempfile.TemporaryDirectory() as outdir:
# with no NODATA value
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'EXTENT': extent,
- 'OUTPUT': outdir + '/check.jpg'}, context, feedback),
- ['gdal_translate',
- '-of JPEG ' +
- source + ' ' +
- outdir + '/check.jpg'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "EXTENT": extent,
+ "OUTPUT": outdir + "/check.jpg",
+ },
+ context,
+ feedback,
+ ),
+ ["gdal_translate", "-of JPEG " + source + " " + outdir + "/check.jpg"],
+ )
# with NODATA value
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'EXTENT': extent,
- 'NODATA': 9999,
- 'OUTPUT': outdir + '/check.jpg'}, context, feedback),
- ['gdal_translate',
- '-a_nodata 9999.0 -of JPEG ' +
- source + ' ' +
- outdir + '/check.jpg'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "EXTENT": extent,
+ "NODATA": 9999,
+ "OUTPUT": outdir + "/check.jpg",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdal_translate",
+ "-a_nodata 9999.0 -of JPEG " + source + " " + outdir + "/check.jpg",
+ ],
+ )
# with "0" NODATA value
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'EXTENT': extent,
- 'NODATA': 0,
- 'OUTPUT': outdir + '/check.jpg'}, context, feedback),
- ['gdal_translate',
- '-a_nodata 0.0 -of JPEG ' +
- source + ' ' +
- outdir + '/check.jpg'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "EXTENT": extent,
+ "NODATA": 0,
+ "OUTPUT": outdir + "/check.jpg",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdal_translate",
+ "-a_nodata 0.0 -of JPEG " + source + " " + outdir + "/check.jpg",
+ ],
+ )
# with "0" NODATA value and custom data type
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'EXTENT': extent,
- 'NODATA': 0,
- 'DATA_TYPE': 6,
- 'OUTPUT': outdir + '/check.jpg'}, context, feedback),
- ['gdal_translate',
- '-a_nodata 0.0 -ot Float32 -of JPEG ' +
- source + ' ' +
- outdir + '/check.jpg'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "EXTENT": extent,
+ "NODATA": 0,
+ "DATA_TYPE": 6,
+ "OUTPUT": outdir + "/check.jpg",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdal_translate",
+ "-a_nodata 0.0 -ot Float32 -of JPEG "
+ + source
+ + " "
+ + outdir
+ + "/check.jpg",
+ ],
+ )
# with creation options
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'EXTENT': extent,
- 'OPTIONS': 'COMPRESS=DEFLATE|PREDICTOR=2|ZLEVEL=9',
- 'DATA_TYPE': 0,
- 'OUTPUT': outdir + '/check.jpg'}, context, feedback),
- ['gdal_translate',
- '-of JPEG -co COMPRESS=DEFLATE -co PREDICTOR=2 -co ZLEVEL=9 ' +
- source + ' ' +
- outdir + '/check.jpg'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "EXTENT": extent,
+ "OPTIONS": "COMPRESS=DEFLATE|PREDICTOR=2|ZLEVEL=9",
+ "DATA_TYPE": 0,
+ "OUTPUT": outdir + "/check.jpg",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdal_translate",
+ "-of JPEG -co COMPRESS=DEFLATE -co PREDICTOR=2 -co ZLEVEL=9 "
+ + source
+ + " "
+ + outdir
+ + "/check.jpg",
+ ],
+ )
# with additional parameters
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'EXTENT': extent,
- 'EXTRA': '-s_srs EPSG:4326 -tps -tr 0.1 0.1',
- 'DATA_TYPE': 0,
- 'OUTPUT': outdir + '/check.jpg'}, context, feedback),
- ['gdal_translate',
- '-of JPEG -s_srs EPSG:4326 -tps -tr 0.1 0.1 ' +
- source + ' ' +
- outdir + '/check.jpg'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "EXTENT": extent,
+ "EXTRA": "-s_srs EPSG:4326 -tps -tr 0.1 0.1",
+ "DATA_TYPE": 0,
+ "OUTPUT": outdir + "/check.jpg",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdal_translate",
+ "-of JPEG -s_srs EPSG:4326 -tps -tr 0.1 0.1 "
+ + source
+ + " "
+ + outdir
+ + "/check.jpg",
+ ],
+ )
# override CRS
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'EXTENT': extent,
- 'OVERCRS': True,
- 'OUTPUT': outdir + '/check.jpg'}, context, feedback),
- ['gdal_translate',
- '-a_srs EPSG:4326 -of JPEG ' +
- source + ' ' +
- outdir + '/check.jpg'])
-
- self.assertEqual(
- alg.getConsoleCommands({'INPUT': source + '|option:X_POSSIBLE_NAMES=geom_x|option:Y_POSSIBLE_NAMES=geom_y',
- 'EXTENT': extent,
- 'OUTPUT': outdir + '/check.jpg'}, context, feedback),
- ['gdal_translate',
- '-of JPEG ' +
- source + ' ' +
- outdir + '/check.jpg -oo X_POSSIBLE_NAMES=geom_x -oo Y_POSSIBLE_NAMES=geom_y'])
-
- self.assertEqual(
- alg.getConsoleCommands({'INPUT': source + '|credential:X=Y|credential:Z=A',
- 'EXTENT': extent,
- 'OUTPUT': outdir + '/check.jpg'}, context, feedback),
- ['gdal_translate',
- '-of JPEG ' +
- source + ' ' +
- outdir + '/check.jpg --config X Y --config Z A'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "EXTENT": extent,
+ "OVERCRS": True,
+ "OUTPUT": outdir + "/check.jpg",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdal_translate",
+ "-a_srs EPSG:4326 -of JPEG " + source + " " + outdir + "/check.jpg",
+ ],
+ )
+
+ self.assertEqual(
+ alg.getConsoleCommands(
+ {
+ "INPUT": source
+ + "|option:X_POSSIBLE_NAMES=geom_x|option:Y_POSSIBLE_NAMES=geom_y",
+ "EXTENT": extent,
+ "OUTPUT": outdir + "/check.jpg",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdal_translate",
+ "-of JPEG "
+ + source
+ + " "
+ + outdir
+ + "/check.jpg -oo X_POSSIBLE_NAMES=geom_x -oo Y_POSSIBLE_NAMES=geom_y",
+ ],
+ )
+
+ self.assertEqual(
+ alg.getConsoleCommands(
+ {
+ "INPUT": source + "|credential:X=Y|credential:Z=A",
+ "EXTENT": extent,
+ "OUTPUT": outdir + "/check.jpg",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdal_translate",
+ "-of JPEG "
+ + source
+ + " "
+ + outdir
+ + "/check.jpg --config X Y --config Z A",
+ ],
+ )
def testClipRasterByMask(self):
context = QgsProcessingContext()
feedback = QgsProcessingFeedback()
- source = os.path.join(testDataPath, 'dem.tif')
- mask = os.path.join(testDataPath, 'polys.gml')
- extent = QgsReferencedRectangle(QgsRectangle(1, 2, 3, 4), QgsCoordinateReferenceSystem('EPSG:4236'))
+ source = os.path.join(testDataPath, "dem.tif")
+ mask = os.path.join(testDataPath, "polys.gml")
+ extent = QgsReferencedRectangle(
+ QgsRectangle(1, 2, 3, 4), QgsCoordinateReferenceSystem("EPSG:4236")
+ )
alg = ClipRasterByMask()
alg.initAlgorithm()
with tempfile.TemporaryDirectory() as outdir:
# with no NODATA value
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'MASK': mask,
- 'OUTPUT': outdir + '/check.jpg'}, context, feedback),
- ['gdalwarp',
- '-overwrite -of JPEG -cutline ' +
- mask + ' -cl polys2 -crop_to_cutline ' + source + ' ' +
- outdir + '/check.jpg'])
+ alg.getConsoleCommands(
+ {"INPUT": source, "MASK": mask, "OUTPUT": outdir + "/check.jpg"},
+ context,
+ feedback,
+ ),
+ [
+ "gdalwarp",
+ "-overwrite -of JPEG -cutline "
+ + mask
+ + " -cl polys2 -crop_to_cutline "
+ + source
+ + " "
+ + outdir
+ + "/check.jpg",
+ ],
+ )
# with NODATA value
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'MASK': mask,
- 'NODATA': 9999,
- 'OUTPUT': outdir + '/check.jpg'}, context, feedback),
- ['gdalwarp',
- '-overwrite -of JPEG -cutline ' +
- mask + ' -cl polys2 -crop_to_cutline -dstnodata 9999.0 ' + source + ' ' +
- outdir + '/check.jpg'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "MASK": mask,
+ "NODATA": 9999,
+ "OUTPUT": outdir + "/check.jpg",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdalwarp",
+ "-overwrite -of JPEG -cutline "
+ + mask
+ + " -cl polys2 -crop_to_cutline -dstnodata 9999.0 "
+ + source
+ + " "
+ + outdir
+ + "/check.jpg",
+ ],
+ )
# with "0" NODATA value
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'MASK': mask,
- 'NODATA': 0,
- 'OUTPUT': outdir + '/check.jpg'}, context, feedback),
- ['gdalwarp',
- '-overwrite -of JPEG -cutline ' +
- mask + ' -cl polys2 -crop_to_cutline -dstnodata 0.0 ' + source + ' ' +
- outdir + '/check.jpg'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "MASK": mask,
+ "NODATA": 0,
+ "OUTPUT": outdir + "/check.jpg",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdalwarp",
+ "-overwrite -of JPEG -cutline "
+ + mask
+ + " -cl polys2 -crop_to_cutline -dstnodata 0.0 "
+ + source
+ + " "
+ + outdir
+ + "/check.jpg",
+ ],
+ )
# with "0" NODATA value and custom data type
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'MASK': mask,
- 'NODATA': 0,
- 'DATA_TYPE': 6,
- 'OUTPUT': outdir + '/check.jpg'}, context, feedback),
- ['gdalwarp',
- '-overwrite -ot Float32 -of JPEG -cutline ' +
- mask + ' -cl polys2 -crop_to_cutline -dstnodata 0.0 ' + source + ' ' +
- outdir + '/check.jpg'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "MASK": mask,
+ "NODATA": 0,
+ "DATA_TYPE": 6,
+ "OUTPUT": outdir + "/check.jpg",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdalwarp",
+ "-overwrite -ot Float32 -of JPEG -cutline "
+ + mask
+ + " -cl polys2 -crop_to_cutline -dstnodata 0.0 "
+ + source
+ + " "
+ + outdir
+ + "/check.jpg",
+ ],
+ )
# with creation options
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'MASK': mask,
- 'OPTIONS': 'COMPRESS=DEFLATE|PREDICTOR=2|ZLEVEL=9',
- 'OUTPUT': outdir + '/check.jpg'}, context, feedback),
- ['gdalwarp',
- '-overwrite -of JPEG -cutline ' +
- mask + ' -cl polys2 -crop_to_cutline -co COMPRESS=DEFLATE -co PREDICTOR=2 -co ZLEVEL=9 ' +
- source + ' ' +
- outdir + '/check.jpg'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "MASK": mask,
+ "OPTIONS": "COMPRESS=DEFLATE|PREDICTOR=2|ZLEVEL=9",
+ "OUTPUT": outdir + "/check.jpg",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdalwarp",
+ "-overwrite -of JPEG -cutline "
+ + mask
+ + " -cl polys2 -crop_to_cutline -co COMPRESS=DEFLATE -co PREDICTOR=2 -co ZLEVEL=9 "
+ + source
+ + " "
+ + outdir
+ + "/check.jpg",
+ ],
+ )
# with multothreading and additional parameters
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'MASK': mask,
- 'MULTITHREADING': True,
- 'EXTRA': '-nosrcalpha -wm 2048 -nomd',
- 'OUTPUT': outdir + '/check.jpg'}, context, feedback),
- ['gdalwarp',
- '-overwrite -of JPEG -cutline ' +
- mask + ' -cl polys2 -crop_to_cutline -multi -nosrcalpha -wm 2048 -nomd ' +
- source + ' ' +
- outdir + '/check.jpg'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "MASK": mask,
+ "MULTITHREADING": True,
+ "EXTRA": "-nosrcalpha -wm 2048 -nomd",
+ "OUTPUT": outdir + "/check.jpg",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdalwarp",
+ "-overwrite -of JPEG -cutline "
+ + mask
+ + " -cl polys2 -crop_to_cutline -multi -nosrcalpha -wm 2048 -nomd "
+ + source
+ + " "
+ + outdir
+ + "/check.jpg",
+ ],
+ )
# with target extent value
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'MASK': mask,
- 'TARGET_EXTENT': extent,
- 'OUTPUT': outdir + '/check.jpg'}, context, feedback),
- ['gdalwarp',
- '-overwrite -te 1.0 2.0 3.0 4.0 -te_srs EPSG:4236 -of JPEG -cutline ' +
- mask + ' -cl polys2 -crop_to_cutline ' + source + ' ' +
- outdir + '/check.jpg'])
-
- self.assertEqual(
- alg.getConsoleCommands({'INPUT': source + '|option:X_POSSIBLE_NAMES=geom_x|option:Y_POSSIBLE_NAMES=geom_y',
- 'MASK': mask,
- 'OUTPUT': outdir + '/check.jpg'}, context, feedback),
- ['gdalwarp',
- '-overwrite -of JPEG -cutline ' +
- mask + ' -cl polys2 -crop_to_cutline ' + source + ' ' +
- outdir + '/check.jpg -oo X_POSSIBLE_NAMES=geom_x -oo Y_POSSIBLE_NAMES=geom_y'])
-
- self.assertEqual(
- alg.getConsoleCommands({'INPUT': source + '|credential:X=Y|credential:Z=A',
- 'MASK': mask,
- 'OUTPUT': outdir + '/check.jpg'}, context, feedback),
- ['gdalwarp',
- '-overwrite -of JPEG -cutline ' +
- mask + ' -cl polys2 -crop_to_cutline ' + source + ' ' +
- outdir + '/check.jpg --config X Y --config Z A'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "MASK": mask,
+ "TARGET_EXTENT": extent,
+ "OUTPUT": outdir + "/check.jpg",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdalwarp",
+ "-overwrite -te 1.0 2.0 3.0 4.0 -te_srs EPSG:4236 -of JPEG -cutline "
+ + mask
+ + " -cl polys2 -crop_to_cutline "
+ + source
+ + " "
+ + outdir
+ + "/check.jpg",
+ ],
+ )
+
+ self.assertEqual(
+ alg.getConsoleCommands(
+ {
+ "INPUT": source
+ + "|option:X_POSSIBLE_NAMES=geom_x|option:Y_POSSIBLE_NAMES=geom_y",
+ "MASK": mask,
+ "OUTPUT": outdir + "/check.jpg",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdalwarp",
+ "-overwrite -of JPEG -cutline "
+ + mask
+ + " -cl polys2 -crop_to_cutline "
+ + source
+ + " "
+ + outdir
+ + "/check.jpg -oo X_POSSIBLE_NAMES=geom_x -oo Y_POSSIBLE_NAMES=geom_y",
+ ],
+ )
+
+ self.assertEqual(
+ alg.getConsoleCommands(
+ {
+ "INPUT": source + "|credential:X=Y|credential:Z=A",
+ "MASK": mask,
+ "OUTPUT": outdir + "/check.jpg",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdalwarp",
+ "-overwrite -of JPEG -cutline "
+ + mask
+ + " -cl polys2 -crop_to_cutline "
+ + source
+ + " "
+ + outdir
+ + "/check.jpg --config X Y --config Z A",
+ ],
+ )
def testContourPolygon(self):
context = QgsProcessingContext()
feedback = QgsProcessingFeedback()
- source = os.path.join(testDataPath, 'dem.tif')
+ source = os.path.join(testDataPath, "dem.tif")
alg = contour_polygon()
alg.initAlgorithm()
with tempfile.TemporaryDirectory() as outdir:
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'BAND': 1,
- 'FIELD_NAME_MIN': 'min',
- 'FIELD_NAME_MAX': 'max',
- 'INTERVAL': 5,
- 'OUTPUT': outdir + '/check.shp'}, context, feedback),
- ['gdal_contour',
- '-p -amax max -amin min -b 1 -i 5.0 -f "ESRI Shapefile" ' +
- source + ' ' +
- outdir + '/check.shp'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "BAND": 1,
+ "FIELD_NAME_MIN": "min",
+ "FIELD_NAME_MAX": "max",
+ "INTERVAL": 5,
+ "OUTPUT": outdir + "/check.shp",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdal_contour",
+ '-p -amax max -amin min -b 1 -i 5.0 -f "ESRI Shapefile" '
+ + source
+ + " "
+ + outdir
+ + "/check.shp",
+ ],
+ )
def testContour(self):
context = QgsProcessingContext()
feedback = QgsProcessingFeedback()
- source = os.path.join(testDataPath, 'dem.tif')
+ source = os.path.join(testDataPath, "dem.tif")
alg = contour()
alg.initAlgorithm()
with tempfile.TemporaryDirectory() as outdir:
# with no NODATA value
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'BAND': 1,
- 'FIELD_NAME': 'elev',
- 'INTERVAL': 5,
- 'OUTPUT': outdir + '/check.shp'}, context, feedback),
- ['gdal_contour',
- '-b 1 -a elev -i 5.0 -f "ESRI Shapefile" ' +
- source + ' ' +
- outdir + '/check.shp'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "BAND": 1,
+ "FIELD_NAME": "elev",
+ "INTERVAL": 5,
+ "OUTPUT": outdir + "/check.shp",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdal_contour",
+ '-b 1 -a elev -i 5.0 -f "ESRI Shapefile" '
+ + source
+ + " "
+ + outdir
+ + "/check.shp",
+ ],
+ )
# with NODATA value
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'BAND': 1,
- 'FIELD_NAME': 'elev',
- 'INTERVAL': 5,
- 'NODATA': 9999,
- 'OUTPUT': outdir + '/check.shp'}, context, feedback),
- ['gdal_contour',
- '-b 1 -a elev -i 5.0 -snodata 9999.0 -f "ESRI Shapefile" ' +
- source + ' ' +
- outdir + '/check.shp'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "BAND": 1,
+ "FIELD_NAME": "elev",
+ "INTERVAL": 5,
+ "NODATA": 9999,
+ "OUTPUT": outdir + "/check.shp",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdal_contour",
+ '-b 1 -a elev -i 5.0 -snodata 9999.0 -f "ESRI Shapefile" '
+ + source
+ + " "
+ + outdir
+ + "/check.shp",
+ ],
+ )
# with "0" NODATA value
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'BAND': 1,
- 'FIELD_NAME': 'elev',
- 'INTERVAL': 5,
- 'NODATA': 0,
- 'OUTPUT': outdir + '/check.gpkg'}, context, feedback),
- ['gdal_contour',
- '-b 1 -a elev -i 5.0 -snodata 0.0 -f "GPKG" ' +
- source + ' ' +
- outdir + '/check.gpkg'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "BAND": 1,
+ "FIELD_NAME": "elev",
+ "INTERVAL": 5,
+ "NODATA": 0,
+ "OUTPUT": outdir + "/check.gpkg",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdal_contour",
+ '-b 1 -a elev -i 5.0 -snodata 0.0 -f "GPKG" '
+ + source
+ + " "
+ + outdir
+ + "/check.gpkg",
+ ],
+ )
# with CREATE_3D
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'BAND': 1,
- 'CREATE_3D': True,
- 'OUTPUT': outdir + '/check.shp'}, context, feedback),
- ['gdal_contour',
- '-b 1 -a ELEV -i 10.0 -3d -f "ESRI Shapefile" ' +
- source + ' ' +
- outdir + '/check.shp'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "BAND": 1,
+ "CREATE_3D": True,
+ "OUTPUT": outdir + "/check.shp",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdal_contour",
+ '-b 1 -a ELEV -i 10.0 -3d -f "ESRI Shapefile" '
+ + source
+ + " "
+ + outdir
+ + "/check.shp",
+ ],
+ )
# with IGNORE_NODATA and OFFSET
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'BAND': 1,
- 'IGNORE_NODATA': True,
- 'OFFSET': 100,
- 'OUTPUT': outdir + '/check.shp'}, context, feedback),
- ['gdal_contour',
- '-b 1 -a ELEV -i 10.0 -inodata -off 100.0 -f "ESRI Shapefile" ' +
- source + ' ' +
- outdir + '/check.shp'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "BAND": 1,
+ "IGNORE_NODATA": True,
+ "OFFSET": 100,
+ "OUTPUT": outdir + "/check.shp",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdal_contour",
+ '-b 1 -a ELEV -i 10.0 -inodata -off 100.0 -f "ESRI Shapefile" '
+ + source
+ + " "
+ + outdir
+ + "/check.shp",
+ ],
+ )
# with additional command line parameters
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'BAND': 1,
- 'EXTRA': '-e 3 -amin MIN_H',
- 'OUTPUT': outdir + '/check.shp'}, context, feedback),
- ['gdal_contour',
- '-b 1 -a ELEV -i 10.0 -f "ESRI Shapefile" -e 3 -amin MIN_H ' +
- source + ' ' +
- outdir + '/check.shp'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "BAND": 1,
+ "EXTRA": "-e 3 -amin MIN_H",
+ "OUTPUT": outdir + "/check.shp",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdal_contour",
+ '-b 1 -a ELEV -i 10.0 -f "ESRI Shapefile" -e 3 -amin MIN_H '
+ + source
+ + " "
+ + outdir
+ + "/check.shp",
+ ],
+ )
# obsolete OPTIONS param
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'BAND': 1,
- 'OPTIONS': '-fl 100 125 150 200',
- 'OUTPUT': outdir + '/check.shp'}, context, feedback),
- ['gdal_contour',
- '-b 1 -a ELEV -i 10.0 -f "ESRI Shapefile" -fl 100 125 150 200 ' +
- source + ' ' +
- outdir + '/check.shp'])
-
- self.assertEqual(
- alg.getConsoleCommands({'INPUT': source + '|credential:X=Y|credential:Z=A',
- 'BAND': 1,
- 'FIELD_NAME': 'elev',
- 'INTERVAL': 5,
- 'OUTPUT': outdir + '/check.shp'}, context, feedback),
- ['gdal_contour',
- '-b 1 -a elev -i 5.0 -f "ESRI Shapefile" --config X Y --config Z A ' +
- source + ' ' +
- outdir + '/check.shp'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "BAND": 1,
+ "OPTIONS": "-fl 100 125 150 200",
+ "OUTPUT": outdir + "/check.shp",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdal_contour",
+ '-b 1 -a ELEV -i 10.0 -f "ESRI Shapefile" -fl 100 125 150 200 '
+ + source
+ + " "
+ + outdir
+ + "/check.shp",
+ ],
+ )
+
+ self.assertEqual(
+ alg.getConsoleCommands(
+ {
+ "INPUT": source + "|credential:X=Y|credential:Z=A",
+ "BAND": 1,
+ "FIELD_NAME": "elev",
+ "INTERVAL": 5,
+ "OUTPUT": outdir + "/check.shp",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdal_contour",
+ '-b 1 -a elev -i 5.0 -f "ESRI Shapefile" --config X Y --config Z A '
+ + source
+ + " "
+ + outdir
+ + "/check.shp",
+ ],
+ )
def testGdal2Tiles(self):
context = QgsProcessingContext()
feedback = QgsProcessingFeedback()
- source = os.path.join(testDataPath, 'dem.tif')
+ source = os.path.join(testDataPath, "dem.tif")
alg = gdal2tiles()
alg.initAlgorithm()
with tempfile.TemporaryDirectory() as outdir:
# with no NODATA value
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'OUTPUT': outdir + '/'}, context, feedback),
- ['gdal2tiles.py',
- '-p mercator -w all -r average ' +
- source + ' ' +
- outdir + '/'])
+ alg.getConsoleCommands(
+ {"INPUT": source, "OUTPUT": outdir + "/"}, context, feedback
+ ),
+ [
+ "gdal2tiles.py",
+ "-p mercator -w all -r average " + source + " " + outdir + "/",
+ ],
+ )
# with NODATA value
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'NODATA': -9999,
- 'OUTPUT': outdir + '/'}, context, feedback),
- ['gdal2tiles.py',
- '-p mercator -w all -r average -a -9999.0 ' +
- source + ' ' +
- outdir + '/'])
+ alg.getConsoleCommands(
+ {"INPUT": source, "NODATA": -9999, "OUTPUT": outdir + "/"},
+ context,
+ feedback,
+ ),
+ [
+ "gdal2tiles.py",
+ "-p mercator -w all -r average -a -9999.0 "
+ + source
+ + " "
+ + outdir
+ + "/",
+ ],
+ )
# with "0" NODATA value
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'NODATA': 0,
- 'OUTPUT': outdir + '/'}, context, feedback),
- ['gdal2tiles.py',
- '-p mercator -w all -r average -a 0.0 ' +
- source + ' ' +
- outdir + '/'])
+ alg.getConsoleCommands(
+ {"INPUT": source, "NODATA": 0, "OUTPUT": outdir + "/"},
+ context,
+ feedback,
+ ),
+ [
+ "gdal2tiles.py",
+ "-p mercator -w all -r average -a 0.0 "
+ + source
+ + " "
+ + outdir
+ + "/",
+ ],
+ )
# with input srs
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'SOURCE_CRS': 'EPSG:3111',
- 'OUTPUT': outdir + '/'}, context, feedback),
- ['gdal2tiles.py',
- '-p mercator -w all -r average -s EPSG:3111 ' +
- source + ' ' +
- outdir + '/'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "SOURCE_CRS": "EPSG:3111",
+ "OUTPUT": outdir + "/",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdal2tiles.py",
+ "-p mercator -w all -r average -s EPSG:3111 "
+ + source
+ + " "
+ + outdir
+ + "/",
+ ],
+ )
# with target using proj string
- custom_crs = 'proj4: +proj=utm +zone=36 +south +a=6378249.145 +b=6356514.966398753 +towgs84=-143,-90,-294,0,0,0,0 +units=m +no_defs'
- self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'SOURCE_CRS': custom_crs,
- 'OUTPUT': outdir + '/'}, context, feedback),
- ['gdal2tiles.py',
- '-p mercator -w all -r average -s EPSG:20936 ' +
- source + ' ' +
- outdir + '/'])
+ custom_crs = "proj4: +proj=utm +zone=36 +south +a=6378249.145 +b=6356514.966398753 +towgs84=-143,-90,-294,0,0,0,0 +units=m +no_defs"
+ self.assertEqual(
+ alg.getConsoleCommands(
+ {"INPUT": source, "SOURCE_CRS": custom_crs, "OUTPUT": outdir + "/"},
+ context,
+ feedback,
+ ),
+ [
+ "gdal2tiles.py",
+ "-p mercator -w all -r average -s EPSG:20936 "
+ + source
+ + " "
+ + outdir
+ + "/",
+ ],
+ )
# with target using custom projection
- custom_crs, expected_crs_string = self.get_param_value_and_expected_string_for_custom_crs('+proj=utm +zone=36 +south +a=63785 +b=6357 +towgs84=-143,-90,-294,0,0,0,0 +units=m +no_defs')
- self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'SOURCE_CRS': custom_crs,
- 'OUTPUT': outdir + '/'}, context, feedback),
- ['gdal2tiles.py',
- f'-p mercator -w all -r average -s "{expected_crs_string}" ' +
- source + ' ' +
- outdir + '/'])
+ custom_crs, expected_crs_string = (
+ self.get_param_value_and_expected_string_for_custom_crs(
+ "+proj=utm +zone=36 +south +a=63785 +b=6357 +towgs84=-143,-90,-294,0,0,0,0 +units=m +no_defs"
+ )
+ )
+ self.assertEqual(
+ alg.getConsoleCommands(
+ {"INPUT": source, "SOURCE_CRS": custom_crs, "OUTPUT": outdir + "/"},
+ context,
+ feedback,
+ ),
+ [
+ "gdal2tiles.py",
+ f'-p mercator -w all -r average -s "{expected_crs_string}" '
+ + source
+ + " "
+ + outdir
+ + "/",
+ ],
+ )
# with non-EPSG crs code
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'SOURCE_CRS': 'POSTGIS:3111',
- 'OUTPUT': outdir + '/'}, context, feedback),
- ['gdal2tiles.py',
- '-p mercator -w all -r average -s EPSG:3111 ' +
- source + ' ' +
- outdir + '/'])
-
- self.assertEqual(
- alg.getConsoleCommands({'INPUT': source + '|credential:X=Y|credential:Z=A',
- 'OUTPUT': outdir + '/'}, context, feedback),
- ['gdal2tiles.py',
- '-p mercator -w all -r average ' +
- source + ' ' +
- outdir + '/ --config X Y --config Z A'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "SOURCE_CRS": "POSTGIS:3111",
+ "OUTPUT": outdir + "/",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdal2tiles.py",
+ "-p mercator -w all -r average -s EPSG:3111 "
+ + source
+ + " "
+ + outdir
+ + "/",
+ ],
+ )
+
+ self.assertEqual(
+ alg.getConsoleCommands(
+ {
+ "INPUT": source + "|credential:X=Y|credential:Z=A",
+ "OUTPUT": outdir + "/",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdal2tiles.py",
+ "-p mercator -w all -r average "
+ + source
+ + " "
+ + outdir
+ + "/ --config X Y --config Z A",
+ ],
+ )
def testGdalCalc(self):
context = QgsProcessingContext()
feedback = QgsProcessingFeedback()
- source = os.path.join(testDataPath, 'dem.tif')
- source2 = os.path.join(testDataPath, 'raster.tif')
- source3 = os.path.join(testDataPath, 'raster with spaces.tif')
+ source = os.path.join(testDataPath, "dem.tif")
+ source2 = os.path.join(testDataPath, "raster.tif")
+ source3 = os.path.join(testDataPath, "raster with spaces.tif")
alg = gdalcalc()
alg.initAlgorithm()
with tempfile.TemporaryDirectory() as outdir:
- output = outdir + '/check.jpg'
+ output = outdir + "/check.jpg"
# default execution
- formula = 'A*2' # default formula
- self.assertEqual(
- alg.getConsoleCommands({'INPUT_A': source,
- 'BAND_A': 1,
- 'FORMULA': formula,
- 'OUTPUT': output}, context, feedback),
- ['gdal_calc.py',
- f'--overwrite --calc "{formula}" --format JPEG --type Float32 -A {source} --A_band 1 --outfile {output}'])
+ formula = "A*2" # default formula
+ self.assertEqual(
+ alg.getConsoleCommands(
+ {
+ "INPUT_A": source,
+ "BAND_A": 1,
+ "FORMULA": formula,
+ "OUTPUT": output,
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdal_calc.py",
+ f'--overwrite --calc "{formula}" --format JPEG --type Float32 -A {source} --A_band 1 --outfile {output}',
+ ],
+ )
if GdalUtils.version() >= 3030000:
- extent = QgsReferencedRectangle(QgsRectangle(1, 2, 3, 4), QgsCoordinateReferenceSystem('EPSG:4326'))
+ extent = QgsReferencedRectangle(
+ QgsRectangle(1, 2, 3, 4), QgsCoordinateReferenceSystem("EPSG:4326")
+ )
self.assertEqual(
- alg.getConsoleCommands({'INPUT_A': source,
- 'BAND_A': 1,
- 'FORMULA': formula,
- 'PROJWIN': extent,
- 'OUTPUT': output}, context, feedback),
- ['gdal_calc.py',
- f'--overwrite --calc "{formula}" --format JPEG --type Float32 --projwin 1.0 4.0 3.0 2.0 -A {source} --A_band 1 --outfile {output}'])
+ alg.getConsoleCommands(
+ {
+ "INPUT_A": source,
+ "BAND_A": 1,
+ "FORMULA": formula,
+ "PROJWIN": extent,
+ "OUTPUT": output,
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdal_calc.py",
+ f'--overwrite --calc "{formula}" --format JPEG --type Float32 --projwin 1.0 4.0 3.0 2.0 -A {source} --A_band 1 --outfile {output}',
+ ],
+ )
# Inputs A and B share same pixel size and CRS
self.assertEqual(
- alg.getConsoleCommands({'INPUT_A': source2,
- 'BAND_A': 1,
- 'INPUT_B': source3,
- 'BAND_B': 1,
- 'FORMULA': formula,
- 'EXTENT_OPT': 3,
- 'OUTPUT': output}, context, feedback),
- ['gdal_calc.py',
- f'--overwrite --calc "{formula}" --format JPEG --type Float32 --extent=intersect -A {source2} --A_band 1 -B "{source3}" --B_band 1 --outfile {output}'])
+ alg.getConsoleCommands(
+ {
+ "INPUT_A": source2,
+ "BAND_A": 1,
+ "INPUT_B": source3,
+ "BAND_B": 1,
+ "FORMULA": formula,
+ "EXTENT_OPT": 3,
+ "OUTPUT": output,
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdal_calc.py",
+ f'--overwrite --calc "{formula}" --format JPEG --type Float32 --extent=intersect -A {source2} --A_band 1 -B "{source3}" --B_band 1 --outfile {output}',
+ ],
+ )
# Test mutually exclusive --extent and --projwin. Should raise an exception
self.assertRaises(
QgsProcessingException,
- lambda: alg.getConsoleCommands({'INPUT_A': source,
- 'BAND_A': 1,
- 'FORMULA': formula,
- 'PROJWIN': extent,
- 'EXTENT_OPT': 3,
- 'OUTPUT': output}, context, feedback))
+ lambda: alg.getConsoleCommands(
+ {
+ "INPUT_A": source,
+ "BAND_A": 1,
+ "FORMULA": formula,
+ "PROJWIN": extent,
+ "EXTENT_OPT": 3,
+ "OUTPUT": output,
+ },
+ context,
+ feedback,
+ ),
+ )
# Inputs A and B do not share same pixel size and CRS. Should raise an exception
- source2 = os.path.join(testDataPath, 'raster.tif')
+ source2 = os.path.join(testDataPath, "raster.tif")
self.assertRaises(
QgsProcessingException,
- lambda: alg.getConsoleCommands({'INPUT_A': source,
- 'BAND_A': 1,
- 'INPUT_B': source2,
- 'BAND_B': 1,
- 'FORMULA': formula,
- 'EXTENT_OPT': 3,
- 'OUTPUT': output}, context, feedback))
+ lambda: alg.getConsoleCommands(
+ {
+ "INPUT_A": source,
+ "BAND_A": 1,
+ "INPUT_B": source2,
+ "BAND_B": 1,
+ "FORMULA": formula,
+ "EXTENT_OPT": 3,
+ "OUTPUT": output,
+ },
+ context,
+ feedback,
+ ),
+ )
# check that formula is not escaped and formula is returned as it is
- formula = 'A * 2' # <--- add spaces in the formula
- self.assertEqual(
- alg.getConsoleCommands({'INPUT_A': source,
- 'BAND_A': 1,
- 'FORMULA': formula,
- 'OUTPUT': output}, context, feedback),
- ['gdal_calc.py',
- f'--overwrite --calc "{formula}" --format JPEG --type Float32 -A {source} --A_band 1 --outfile {output}'])
+ formula = "A * 2" # <--- add spaces in the formula
+ self.assertEqual(
+ alg.getConsoleCommands(
+ {
+ "INPUT_A": source,
+ "BAND_A": 1,
+ "FORMULA": formula,
+ "OUTPUT": output,
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdal_calc.py",
+ f'--overwrite --calc "{formula}" --format JPEG --type Float32 -A {source} --A_band 1 --outfile {output}',
+ ],
+ )
# additional creation options
- formula = 'A*2'
- self.assertEqual(
- alg.getConsoleCommands({'INPUT_A': source,
- 'BAND_A': 1,
- 'FORMULA': formula,
- 'OPTIONS': 'COMPRESS=JPEG|JPEG_QUALITY=75',
- 'OUTPUT': output}, context, feedback),
- ['gdal_calc.py',
- f'--overwrite --calc "{formula}" --format JPEG --type Float32 -A {source} --A_band 1 --co COMPRESS=JPEG --co JPEG_QUALITY=75 --outfile {output}'])
+ formula = "A*2"
+ self.assertEqual(
+ alg.getConsoleCommands(
+ {
+ "INPUT_A": source,
+ "BAND_A": 1,
+ "FORMULA": formula,
+ "OPTIONS": "COMPRESS=JPEG|JPEG_QUALITY=75",
+ "OUTPUT": output,
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdal_calc.py",
+ f'--overwrite --calc "{formula}" --format JPEG --type Float32 -A {source} --A_band 1 --co COMPRESS=JPEG --co JPEG_QUALITY=75 --outfile {output}',
+ ],
+ )
# additional parameters
- formula = 'A*2'
- self.assertEqual(
- alg.getConsoleCommands({'INPUT_A': source,
- 'BAND_A': 1,
- 'FORMULA': formula,
- 'EXTRA': '--debug --quiet',
- 'OUTPUT': output}, context, feedback),
- ['gdal_calc.py',
- f'--overwrite --calc "{formula}" --format JPEG --type Float32 -A {source} --A_band 1 --debug --quiet --outfile {output}'])
+ formula = "A*2"
+ self.assertEqual(
+ alg.getConsoleCommands(
+ {
+ "INPUT_A": source,
+ "BAND_A": 1,
+ "FORMULA": formula,
+ "EXTRA": "--debug --quiet",
+ "OUTPUT": output,
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdal_calc.py",
+ f'--overwrite --calc "{formula}" --format JPEG --type Float32 -A {source} --A_band 1 --debug --quiet --outfile {output}',
+ ],
+ )
def testGdalInfo(self):
context = QgsProcessingContext()
feedback = QgsProcessingFeedback()
- source = os.path.join(testDataPath, 'dem.tif')
+ source = os.path.join(testDataPath, "dem.tif")
alg = gdalinfo()
alg.initAlgorithm()
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'MIN_MAX': False,
- 'NOGCP': False,
- 'NO_METADATA': False,
- 'STATS': False}, context, feedback),
- ['gdalinfo',
- source])
-
- source = os.path.join(testDataPath, 'raster with spaces.tif')
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "MIN_MAX": False,
+ "NOGCP": False,
+ "NO_METADATA": False,
+ "STATS": False,
+ },
+ context,
+ feedback,
+ ),
+ ["gdalinfo", source],
+ )
+
+ source = os.path.join(testDataPath, "raster with spaces.tif")
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'MIN_MAX': False,
- 'NOGCP': False,
- 'NO_METADATA': False,
- 'STATS': False}, context, feedback),
- ['gdalinfo',
- '"' + source + '"'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "MIN_MAX": False,
+ "NOGCP": False,
+ "NO_METADATA": False,
+ "STATS": False,
+ },
+ context,
+ feedback,
+ ),
+ ["gdalinfo", '"' + source + '"'],
+ )
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'MIN_MAX': True,
- 'NOGCP': False,
- 'NO_METADATA': False,
- 'STATS': False}, context, feedback),
- ['gdalinfo',
- '-mm "' + source + '"'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "MIN_MAX": True,
+ "NOGCP": False,
+ "NO_METADATA": False,
+ "STATS": False,
+ },
+ context,
+ feedback,
+ ),
+ ["gdalinfo", '-mm "' + source + '"'],
+ )
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'MIN_MAX': False,
- 'NOGCP': True,
- 'NO_METADATA': False,
- 'STATS': False}, context, feedback),
- ['gdalinfo',
- '-nogcp "' + source + '"'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "MIN_MAX": False,
+ "NOGCP": True,
+ "NO_METADATA": False,
+ "STATS": False,
+ },
+ context,
+ feedback,
+ ),
+ ["gdalinfo", '-nogcp "' + source + '"'],
+ )
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'MIN_MAX': False,
- 'NOGCP': False,
- 'NO_METADATA': True,
- 'STATS': False}, context, feedback),
- ['gdalinfo',
- '-nomd "' + source + '"'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "MIN_MAX": False,
+ "NOGCP": False,
+ "NO_METADATA": True,
+ "STATS": False,
+ },
+ context,
+ feedback,
+ ),
+ ["gdalinfo", '-nomd "' + source + '"'],
+ )
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'MIN_MAX': False,
- 'NOGCP': False,
- 'NO_METADATA': False,
- 'STATS': True}, context, feedback),
- ['gdalinfo',
- '-stats "' + source + '"'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "MIN_MAX": False,
+ "NOGCP": False,
+ "NO_METADATA": False,
+ "STATS": True,
+ },
+ context,
+ feedback,
+ ),
+ ["gdalinfo", '-stats "' + source + '"'],
+ )
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'MIN_MAX': False,
- 'NOGCP': False,
- 'NO_METADATA': False,
- 'STATS': False,
- 'EXTRA': '-proj4 -listmdd -checksum'}, context, feedback),
- ['gdalinfo',
- '-proj4 -listmdd -checksum "' + source + '"'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "MIN_MAX": False,
+ "NOGCP": False,
+ "NO_METADATA": False,
+ "STATS": False,
+ "EXTRA": "-proj4 -listmdd -checksum",
+ },
+ context,
+ feedback,
+ ),
+ ["gdalinfo", '-proj4 -listmdd -checksum "' + source + '"'],
+ )
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source + '|option:X_POSSIBLE_NAMES=geom_x|option:Y_POSSIBLE_NAMES=geom_y',
- 'MIN_MAX': False,
- 'NOGCP': False,
- 'NO_METADATA': False,
- 'STATS': False}, context, feedback),
- ['gdalinfo',
- '"' + source + '" -oo X_POSSIBLE_NAMES=geom_x -oo Y_POSSIBLE_NAMES=geom_y'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source
+ + "|option:X_POSSIBLE_NAMES=geom_x|option:Y_POSSIBLE_NAMES=geom_y",
+ "MIN_MAX": False,
+ "NOGCP": False,
+ "NO_METADATA": False,
+ "STATS": False,
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdalinfo",
+ '"'
+ + source
+ + '" -oo X_POSSIBLE_NAMES=geom_x -oo Y_POSSIBLE_NAMES=geom_y',
+ ],
+ )
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source + '|credential:X=Y|credential:Z=A',
- 'MIN_MAX': False,
- 'NOGCP': False,
- 'NO_METADATA': False,
- 'STATS': False}, context, feedback),
- ['gdalinfo',
- '"' + source + '" --config X Y --config Z A'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source + "|credential:X=Y|credential:Z=A",
+ "MIN_MAX": False,
+ "NOGCP": False,
+ "NO_METADATA": False,
+ "STATS": False,
+ },
+ context,
+ feedback,
+ ),
+ ["gdalinfo", '"' + source + '" --config X Y --config Z A'],
+ )
def testGdalTindex(self):
context = QgsProcessingContext()
feedback = QgsProcessingFeedback()
- source = os.path.join(testDataPath, 'dem.tif')
+ source = os.path.join(testDataPath, "dem.tif")
alg = gdaltindex()
alg.initAlgorithm()
with tempfile.TemporaryDirectory() as outdir:
- commands = alg.getConsoleCommands({'LAYERS': [source],
- 'OUTPUT': outdir + '/test.shp'}, context, feedback)
+ commands = alg.getConsoleCommands(
+ {"LAYERS": [source], "OUTPUT": outdir + "/test.shp"}, context, feedback
+ )
self.assertEqual(len(commands), 2)
- self.assertEqual(commands[0], 'gdaltindex')
- self.assertIn('-tileindex location -f "ESRI Shapefile" ' + outdir + '/test.shp', commands[1])
- self.assertIn('--optfile ', commands[1])
+ self.assertEqual(commands[0], "gdaltindex")
+ self.assertIn(
+ '-tileindex location -f "ESRI Shapefile" ' + outdir + "/test.shp",
+ commands[1],
+ )
+ self.assertIn("--optfile ", commands[1])
# with input srs
- commands = alg.getConsoleCommands({'LAYERS': [source],
- 'TARGET_CRS': 'EPSG:3111',
- 'OUTPUT': outdir + '/test.shp'}, context, feedback)
+ commands = alg.getConsoleCommands(
+ {
+ "LAYERS": [source],
+ "TARGET_CRS": "EPSG:3111",
+ "OUTPUT": outdir + "/test.shp",
+ },
+ context,
+ feedback,
+ )
self.assertEqual(len(commands), 2)
- self.assertEqual(commands[0], 'gdaltindex')
- self.assertIn('-tileindex location -t_srs EPSG:3111 -f "ESRI Shapefile" ' + outdir + '/test.shp', commands[1])
- self.assertIn('--optfile ', commands[1])
+ self.assertEqual(commands[0], "gdaltindex")
+ self.assertIn(
+ '-tileindex location -t_srs EPSG:3111 -f "ESRI Shapefile" '
+ + outdir
+ + "/test.shp",
+ commands[1],
+ )
+ self.assertIn("--optfile ", commands[1])
# with target using proj string
- custom_crs = 'proj4: +proj=utm +zone=36 +south +a=6378249.145 +b=6356514.966398753 +towgs84=-143,-90,-294,0,0,0,0 +units=m +no_defs'
- commands = alg.getConsoleCommands({'LAYERS': [source],
- 'TARGET_CRS': custom_crs,
- 'OUTPUT': outdir + '/test.shp'}, context, feedback)
+ custom_crs = "proj4: +proj=utm +zone=36 +south +a=6378249.145 +b=6356514.966398753 +towgs84=-143,-90,-294,0,0,0,0 +units=m +no_defs"
+ commands = alg.getConsoleCommands(
+ {
+ "LAYERS": [source],
+ "TARGET_CRS": custom_crs,
+ "OUTPUT": outdir + "/test.shp",
+ },
+ context,
+ feedback,
+ )
self.assertEqual(len(commands), 2)
- self.assertEqual(commands[0], 'gdaltindex')
- self.assertIn('-tileindex location -t_srs EPSG:20936 -f "ESRI Shapefile" ' + outdir + '/test.shp', commands[1])
- self.assertIn('--optfile ', commands[1])
+ self.assertEqual(commands[0], "gdaltindex")
+ self.assertIn(
+ '-tileindex location -t_srs EPSG:20936 -f "ESRI Shapefile" '
+ + outdir
+ + "/test.shp",
+ commands[1],
+ )
+ self.assertIn("--optfile ", commands[1])
# with target using custom projection
- custom_crs, expected_crs_string = self.get_param_value_and_expected_string_for_custom_crs('+proj=utm +zone=36 +south +a=63785 +b=6357 +towgs84=-143,-90,-294,0,0,0,0 +units=m +no_defs')
- commands = alg.getConsoleCommands({'LAYERS': [source],
- 'TARGET_CRS': custom_crs,
- 'OUTPUT': outdir + '/test.shp'}, context, feedback)
+ custom_crs, expected_crs_string = (
+ self.get_param_value_and_expected_string_for_custom_crs(
+ "+proj=utm +zone=36 +south +a=63785 +b=6357 +towgs84=-143,-90,-294,0,0,0,0 +units=m +no_defs"
+ )
+ )
+ commands = alg.getConsoleCommands(
+ {
+ "LAYERS": [source],
+ "TARGET_CRS": custom_crs,
+ "OUTPUT": outdir + "/test.shp",
+ },
+ context,
+ feedback,
+ )
self.assertEqual(len(commands), 2)
- self.assertEqual(commands[0], 'gdaltindex')
- self.assertIn(f'-tileindex location -t_srs "{expected_crs_string}" -f "ESRI Shapefile" ' + outdir + '/test.shp', commands[1])
- self.assertIn('--optfile ', commands[1])
+ self.assertEqual(commands[0], "gdaltindex")
+ self.assertIn(
+ f'-tileindex location -t_srs "{expected_crs_string}" -f "ESRI Shapefile" '
+ + outdir
+ + "/test.shp",
+ commands[1],
+ )
+ self.assertIn("--optfile ", commands[1])
# with non-EPSG crs code
- commands = alg.getConsoleCommands({'LAYERS': [source],
- 'TARGET_CRS': 'POSTGIS:3111',
- 'OUTPUT': outdir + '/test.shp'}, context, feedback)
+ commands = alg.getConsoleCommands(
+ {
+ "LAYERS": [source],
+ "TARGET_CRS": "POSTGIS:3111",
+ "OUTPUT": outdir + "/test.shp",
+ },
+ context,
+ feedback,
+ )
self.assertEqual(len(commands), 2)
- self.assertEqual(commands[0], 'gdaltindex')
+ self.assertEqual(commands[0], "gdaltindex")
self.assertIn(
- '-tileindex location -t_srs EPSG:3111 -f "ESRI Shapefile" ' + outdir + '/test.shp',
- commands[1])
- self.assertIn('--optfile ', commands[1])
+ '-tileindex location -t_srs EPSG:3111 -f "ESRI Shapefile" '
+ + outdir
+ + "/test.shp",
+ commands[1],
+ )
+ self.assertIn("--optfile ", commands[1])
def testGridAverage(self):
context = QgsProcessingContext()
feedback = QgsProcessingFeedback()
- source = os.path.join(testDataPath, 'points.gml')
+ source = os.path.join(testDataPath, "points.gml")
alg = GridAverage()
alg.initAlgorithm()
with tempfile.TemporaryDirectory() as outdir:
# with no NODATA value
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'OUTPUT': outdir + '/check.jpg'}, context, feedback),
- ['gdal_grid',
- '-l points -a average:radius1=0.0:radius2=0.0:angle=0.0:min_points=0:nodata=0.0 -ot Float32 -of JPEG ' +
- source + ' ' +
- outdir + '/check.jpg'])
+ alg.getConsoleCommands(
+ {"INPUT": source, "OUTPUT": outdir + "/check.jpg"},
+ context,
+ feedback,
+ ),
+ [
+ "gdal_grid",
+ "-l points -a average:radius1=0.0:radius2=0.0:angle=0.0:min_points=0:nodata=0.0 -ot Float32 -of JPEG "
+ + source
+ + " "
+ + outdir
+ + "/check.jpg",
+ ],
+ )
# with NODATA value
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'NODATA': 9999,
- 'OUTPUT': outdir + '/check.jpg'}, context, feedback),
- ['gdal_grid',
- '-l points -a average:radius1=0.0:radius2=0.0:angle=0.0:min_points=0:nodata=9999.0 -ot Float32 -of JPEG ' +
- source + ' ' +
- outdir + '/check.jpg'])
+ alg.getConsoleCommands(
+ {"INPUT": source, "NODATA": 9999, "OUTPUT": outdir + "/check.jpg"},
+ context,
+ feedback,
+ ),
+ [
+ "gdal_grid",
+ "-l points -a average:radius1=0.0:radius2=0.0:angle=0.0:min_points=0:nodata=9999.0 -ot Float32 -of JPEG "
+ + source
+ + " "
+ + outdir
+ + "/check.jpg",
+ ],
+ )
# with "0" NODATA value
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'NODATA': 0,
- 'OUTPUT': outdir + '/check.jpg'}, context, feedback),
- ['gdal_grid',
- '-l points -a average:radius1=0.0:radius2=0.0:angle=0.0:min_points=0:nodata=0.0 -ot Float32 -of JPEG ' +
- source + ' ' +
- outdir + '/check.jpg'])
+ alg.getConsoleCommands(
+ {"INPUT": source, "NODATA": 0, "OUTPUT": outdir + "/check.jpg"},
+ context,
+ feedback,
+ ),
+ [
+ "gdal_grid",
+ "-l points -a average:radius1=0.0:radius2=0.0:angle=0.0:min_points=0:nodata=0.0 -ot Float32 -of JPEG "
+ + source
+ + " "
+ + outdir
+ + "/check.jpg",
+ ],
+ )
# with additional parameters
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'EXTRA': '-z_multiply 1.5 -outsize 1754 1394',
- 'OUTPUT': outdir + '/check.jpg'}, context, feedback),
- ['gdal_grid',
- '-l points -a average:radius1=0.0:radius2=0.0:angle=0.0:min_points=0:nodata=0.0 -ot Float32 -of JPEG -z_multiply 1.5 -outsize 1754 1394 ' +
- source + ' ' +
- outdir + '/check.jpg'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "EXTRA": "-z_multiply 1.5 -outsize 1754 1394",
+ "OUTPUT": outdir + "/check.jpg",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdal_grid",
+ "-l points -a average:radius1=0.0:radius2=0.0:angle=0.0:min_points=0:nodata=0.0 -ot Float32 -of JPEG -z_multiply 1.5 -outsize 1754 1394 "
+ + source
+ + " "
+ + outdir
+ + "/check.jpg",
+ ],
+ )
if GdalUtils.version() >= 3070000:
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source + '|option:X_POSSIBLE_NAMES=geom_x|option:Y_POSSIBLE_NAMES=geom_y',
- 'EXTRA': '-z_multiply 1.5 -outsize 1754 1394',
- 'OUTPUT': outdir + '/check.jpg'}, context, feedback),
- ['gdal_grid',
- '-l points -a average:radius1=0.0:radius2=0.0:angle=0.0:min_points=0:nodata=0.0 -ot Float32 -of JPEG -oo X_POSSIBLE_NAMES=geom_x -oo Y_POSSIBLE_NAMES=geom_y -z_multiply 1.5 -outsize 1754 1394 ' +
- source + ' ' +
- outdir + '/check.jpg'])
-
- self.assertEqual(
- alg.getConsoleCommands({'INPUT': source + '|credential:X=Y|credential:Z=A',
- 'EXTRA': '-z_multiply 1.5 -outsize 1754 1394',
- 'OUTPUT': outdir + '/check.jpg'}, context, feedback),
- ['gdal_grid',
- '-l points -a average:radius1=0.0:radius2=0.0:angle=0.0:min_points=0:nodata=0.0 -ot Float32 -of JPEG -z_multiply 1.5 -outsize 1754 1394 ' +
- source + ' ' +
- outdir + '/check.jpg --config X Y --config Z A'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source
+ + "|option:X_POSSIBLE_NAMES=geom_x|option:Y_POSSIBLE_NAMES=geom_y",
+ "EXTRA": "-z_multiply 1.5 -outsize 1754 1394",
+ "OUTPUT": outdir + "/check.jpg",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdal_grid",
+ "-l points -a average:radius1=0.0:radius2=0.0:angle=0.0:min_points=0:nodata=0.0 -ot Float32 -of JPEG -oo X_POSSIBLE_NAMES=geom_x -oo Y_POSSIBLE_NAMES=geom_y -z_multiply 1.5 -outsize 1754 1394 "
+ + source
+ + " "
+ + outdir
+ + "/check.jpg",
+ ],
+ )
+
+ self.assertEqual(
+ alg.getConsoleCommands(
+ {
+ "INPUT": source + "|credential:X=Y|credential:Z=A",
+ "EXTRA": "-z_multiply 1.5 -outsize 1754 1394",
+ "OUTPUT": outdir + "/check.jpg",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdal_grid",
+ "-l points -a average:radius1=0.0:radius2=0.0:angle=0.0:min_points=0:nodata=0.0 -ot Float32 -of JPEG -z_multiply 1.5 -outsize 1754 1394 "
+ + source
+ + " "
+ + outdir
+ + "/check.jpg --config X Y --config Z A",
+ ],
+ )
def testGridDataMetrics(self):
context = QgsProcessingContext()
feedback = QgsProcessingFeedback()
- source = os.path.join(testDataPath, 'points.gml')
+ source = os.path.join(testDataPath, "points.gml")
alg = GridDataMetrics()
alg.initAlgorithm()
with tempfile.TemporaryDirectory() as outdir:
# without NODATA value
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'OUTPUT': outdir + '/check.jpg'}, context, feedback),
- ['gdal_grid',
- '-l points -a minimum:radius1=0.0:radius2=0.0:angle=0.0:min_points=0:nodata=0.0 -ot Float32 -of JPEG ' +
- source + ' ' +
- outdir + '/check.jpg'])
+ alg.getConsoleCommands(
+ {"INPUT": source, "OUTPUT": outdir + "/check.jpg"},
+ context,
+ feedback,
+ ),
+ [
+ "gdal_grid",
+ "-l points -a minimum:radius1=0.0:radius2=0.0:angle=0.0:min_points=0:nodata=0.0 -ot Float32 -of JPEG "
+ + source
+ + " "
+ + outdir
+ + "/check.jpg",
+ ],
+ )
# with NODATA value
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'NODATA': 9999,
- 'OUTPUT': outdir + '/check.jpg'}, context, feedback),
- ['gdal_grid',
- '-l points -a minimum:radius1=0.0:radius2=0.0:angle=0.0:min_points=0:nodata=9999.0 -ot Float32 -of JPEG ' +
- source + ' ' +
- outdir + '/check.jpg'])
+ alg.getConsoleCommands(
+ {"INPUT": source, "NODATA": 9999, "OUTPUT": outdir + "/check.jpg"},
+ context,
+ feedback,
+ ),
+ [
+ "gdal_grid",
+ "-l points -a minimum:radius1=0.0:radius2=0.0:angle=0.0:min_points=0:nodata=9999.0 -ot Float32 -of JPEG "
+ + source
+ + " "
+ + outdir
+ + "/check.jpg",
+ ],
+ )
# with "0" NODATA value
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'NODATA': 0,
- 'OUTPUT': outdir + '/check.jpg'}, context, feedback),
- ['gdal_grid',
- '-l points -a minimum:radius1=0.0:radius2=0.0:angle=0.0:min_points=0:nodata=0.0 -ot Float32 -of JPEG ' +
- source + ' ' +
- outdir + '/check.jpg'])
+ alg.getConsoleCommands(
+ {"INPUT": source, "NODATA": 0, "OUTPUT": outdir + "/check.jpg"},
+ context,
+ feedback,
+ ),
+ [
+ "gdal_grid",
+ "-l points -a minimum:radius1=0.0:radius2=0.0:angle=0.0:min_points=0:nodata=0.0 -ot Float32 -of JPEG "
+ + source
+ + " "
+ + outdir
+ + "/check.jpg",
+ ],
+ )
# non-default datametrics
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'METRIC': 4,
- 'OUTPUT': outdir + '/check.jpg'}, context, feedback),
- ['gdal_grid',
- '-l points -a average_distance:radius1=0.0:radius2=0.0:angle=0.0:min_points=0:nodata=0.0 -ot Float32 -of JPEG ' +
- source + ' ' +
- outdir + '/check.jpg'])
+ alg.getConsoleCommands(
+ {"INPUT": source, "METRIC": 4, "OUTPUT": outdir + "/check.jpg"},
+ context,
+ feedback,
+ ),
+ [
+ "gdal_grid",
+ "-l points -a average_distance:radius1=0.0:radius2=0.0:angle=0.0:min_points=0:nodata=0.0 -ot Float32 -of JPEG "
+ + source
+ + " "
+ + outdir
+ + "/check.jpg",
+ ],
+ )
# additional parameters
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'EXTRA': '-z_multiply 1.5 -outsize 1754 1394',
- 'OUTPUT': outdir + '/check.tif'}, context, feedback),
- ['gdal_grid',
- '-l points -a minimum:radius1=0.0:radius2=0.0:angle=0.0:min_points=0:nodata=0.0 ' +
- '-ot Float32 -of GTiff -z_multiply 1.5 -outsize 1754 1394 ' +
- source + ' ' +
- outdir + '/check.tif'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "EXTRA": "-z_multiply 1.5 -outsize 1754 1394",
+ "OUTPUT": outdir + "/check.tif",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdal_grid",
+ "-l points -a minimum:radius1=0.0:radius2=0.0:angle=0.0:min_points=0:nodata=0.0 "
+ + "-ot Float32 -of GTiff -z_multiply 1.5 -outsize 1754 1394 "
+ + source
+ + " "
+ + outdir
+ + "/check.tif",
+ ],
+ )
if GdalUtils.version() >= 3070000:
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source + '|option:X_POSSIBLE_NAMES=geom_x|option:Y_POSSIBLE_NAMES=geom_y',
- 'EXTRA': '-z_multiply 1.5 -outsize 1754 1394',
- 'OUTPUT': outdir + '/check.tif'}, context, feedback),
- ['gdal_grid',
- '-l points -a minimum:radius1=0.0:radius2=0.0:angle=0.0:min_points=0:nodata=0.0 ' +
- '-ot Float32 -of GTiff -oo X_POSSIBLE_NAMES=geom_x -oo Y_POSSIBLE_NAMES=geom_y -z_multiply 1.5 -outsize 1754 1394 ' +
- source + ' ' +
- outdir + '/check.tif'])
-
- self.assertEqual(
- alg.getConsoleCommands({'INPUT': source + '|credential:X=Y|credential:Z=A',
- 'EXTRA': '-z_multiply 1.5 -outsize 1754 1394',
- 'OUTPUT': outdir + '/check.tif'}, context, feedback),
- ['gdal_grid',
- '-l points -a minimum:radius1=0.0:radius2=0.0:angle=0.0:min_points=0:nodata=0.0 ' +
- '-ot Float32 -of GTiff -z_multiply 1.5 -outsize 1754 1394 ' +
- source + ' ' +
- outdir + '/check.tif --config X Y --config Z A'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source
+ + "|option:X_POSSIBLE_NAMES=geom_x|option:Y_POSSIBLE_NAMES=geom_y",
+ "EXTRA": "-z_multiply 1.5 -outsize 1754 1394",
+ "OUTPUT": outdir + "/check.tif",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdal_grid",
+ "-l points -a minimum:radius1=0.0:radius2=0.0:angle=0.0:min_points=0:nodata=0.0 "
+ + "-ot Float32 -of GTiff -oo X_POSSIBLE_NAMES=geom_x -oo Y_POSSIBLE_NAMES=geom_y -z_multiply 1.5 -outsize 1754 1394 "
+ + source
+ + " "
+ + outdir
+ + "/check.tif",
+ ],
+ )
+
+ self.assertEqual(
+ alg.getConsoleCommands(
+ {
+ "INPUT": source + "|credential:X=Y|credential:Z=A",
+ "EXTRA": "-z_multiply 1.5 -outsize 1754 1394",
+ "OUTPUT": outdir + "/check.tif",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdal_grid",
+ "-l points -a minimum:radius1=0.0:radius2=0.0:angle=0.0:min_points=0:nodata=0.0 "
+ + "-ot Float32 -of GTiff -z_multiply 1.5 -outsize 1754 1394 "
+ + source
+ + " "
+ + outdir
+ + "/check.tif --config X Y --config Z A",
+ ],
+ )
def testGridInverseDistance(self):
context = QgsProcessingContext()
feedback = QgsProcessingFeedback()
- source = os.path.join(testDataPath, 'points.gml')
+ source = os.path.join(testDataPath, "points.gml")
alg = GridInverseDistance()
alg.initAlgorithm()
with tempfile.TemporaryDirectory() as outdir:
# without NODATA value
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'OUTPUT': outdir + '/check.jpg'}, context, feedback),
- ['gdal_grid',
- '-l points -a invdist:power=2.0:smoothing=0.0:radius1=0.0:radius2=0.0:angle=0.0:max_points=0:min_points=0:nodata=0.0 -ot Float32 -of JPEG ' +
- source + ' ' +
- outdir + '/check.jpg'])
+ alg.getConsoleCommands(
+ {"INPUT": source, "OUTPUT": outdir + "/check.jpg"},
+ context,
+ feedback,
+ ),
+ [
+ "gdal_grid",
+ "-l points -a invdist:power=2.0:smoothing=0.0:radius1=0.0:radius2=0.0:angle=0.0:max_points=0:min_points=0:nodata=0.0 -ot Float32 -of JPEG "
+ + source
+ + " "
+ + outdir
+ + "/check.jpg",
+ ],
+ )
# with NODATA value
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'NODATA': 9999,
- 'OUTPUT': outdir + '/check.jpg'}, context, feedback),
- ['gdal_grid',
- '-l points -a invdist:power=2.0:smoothing=0.0:radius1=0.0:radius2=0.0:angle=0.0:max_points=0:min_points=0:nodata=9999.0 -ot Float32 -of JPEG ' +
- source + ' ' +
- outdir + '/check.jpg'])
+ alg.getConsoleCommands(
+ {"INPUT": source, "NODATA": 9999, "OUTPUT": outdir + "/check.jpg"},
+ context,
+ feedback,
+ ),
+ [
+ "gdal_grid",
+ "-l points -a invdist:power=2.0:smoothing=0.0:radius1=0.0:radius2=0.0:angle=0.0:max_points=0:min_points=0:nodata=9999.0 -ot Float32 -of JPEG "
+ + source
+ + " "
+ + outdir
+ + "/check.jpg",
+ ],
+ )
# with "0" NODATA value
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'NODATA': 0,
- 'OUTPUT': outdir + '/check.jpg'}, context, feedback),
- ['gdal_grid',
- '-l points -a invdist:power=2.0:smoothing=0.0:radius1=0.0:radius2=0.0:angle=0.0:max_points=0:min_points=0:nodata=0.0 -ot Float32 -of JPEG ' +
- source + ' ' +
- outdir + '/check.jpg'])
+ alg.getConsoleCommands(
+ {"INPUT": source, "NODATA": 0, "OUTPUT": outdir + "/check.jpg"},
+ context,
+ feedback,
+ ),
+ [
+ "gdal_grid",
+ "-l points -a invdist:power=2.0:smoothing=0.0:radius1=0.0:radius2=0.0:angle=0.0:max_points=0:min_points=0:nodata=0.0 -ot Float32 -of JPEG "
+ + source
+ + " "
+ + outdir
+ + "/check.jpg",
+ ],
+ )
# additional parameters
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'EXTRA': '-z_multiply 1.5 -outsize 1754 1394',
- 'OUTPUT': outdir + '/check.tif'}, context, feedback),
- ['gdal_grid',
- '-l points -a invdist:power=2.0:smoothing=0.0:radius1=0.0:radius2=0.0:angle=0.0:max_points=0:min_points=0:nodata=0.0 ' +
- '-ot Float32 -of GTiff -z_multiply 1.5 -outsize 1754 1394 ' +
- source + ' ' +
- outdir + '/check.tif'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "EXTRA": "-z_multiply 1.5 -outsize 1754 1394",
+ "OUTPUT": outdir + "/check.tif",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdal_grid",
+ "-l points -a invdist:power=2.0:smoothing=0.0:radius1=0.0:radius2=0.0:angle=0.0:max_points=0:min_points=0:nodata=0.0 "
+ + "-ot Float32 -of GTiff -z_multiply 1.5 -outsize 1754 1394 "
+ + source
+ + " "
+ + outdir
+ + "/check.tif",
+ ],
+ )
if GdalUtils.version() >= 3070000:
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source + '|option:X_POSSIBLE_NAMES=geom_x|option:Y_POSSIBLE_NAMES=geom_y',
- 'EXTRA': '-z_multiply 1.5 -outsize 1754 1394',
- 'OUTPUT': outdir + '/check.tif'}, context, feedback),
- ['gdal_grid',
- '-l points -a invdist:power=2.0:smoothing=0.0:radius1=0.0:radius2=0.0:angle=0.0:max_points=0:min_points=0:nodata=0.0 ' +
- '-ot Float32 -of GTiff -oo X_POSSIBLE_NAMES=geom_x -oo Y_POSSIBLE_NAMES=geom_y -z_multiply 1.5 -outsize 1754 1394 ' +
- source + ' ' +
- outdir + '/check.tif'])
-
- self.assertEqual(
- alg.getConsoleCommands({'INPUT': source + '|credential:X=Y|credential:Z=A',
- 'EXTRA': '-z_multiply 1.5 -outsize 1754 1394',
- 'OUTPUT': outdir + '/check.tif'}, context, feedback),
- ['gdal_grid',
- '-l points -a invdist:power=2.0:smoothing=0.0:radius1=0.0:radius2=0.0:angle=0.0:max_points=0:min_points=0:nodata=0.0 ' +
- '-ot Float32 -of GTiff -z_multiply 1.5 -outsize 1754 1394 ' +
- source + ' ' +
- outdir + '/check.tif --config X Y --config Z A'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source
+ + "|option:X_POSSIBLE_NAMES=geom_x|option:Y_POSSIBLE_NAMES=geom_y",
+ "EXTRA": "-z_multiply 1.5 -outsize 1754 1394",
+ "OUTPUT": outdir + "/check.tif",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdal_grid",
+ "-l points -a invdist:power=2.0:smoothing=0.0:radius1=0.0:radius2=0.0:angle=0.0:max_points=0:min_points=0:nodata=0.0 "
+ + "-ot Float32 -of GTiff -oo X_POSSIBLE_NAMES=geom_x -oo Y_POSSIBLE_NAMES=geom_y -z_multiply 1.5 -outsize 1754 1394 "
+ + source
+ + " "
+ + outdir
+ + "/check.tif",
+ ],
+ )
+
+ self.assertEqual(
+ alg.getConsoleCommands(
+ {
+ "INPUT": source + "|credential:X=Y|credential:Z=A",
+ "EXTRA": "-z_multiply 1.5 -outsize 1754 1394",
+ "OUTPUT": outdir + "/check.tif",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdal_grid",
+ "-l points -a invdist:power=2.0:smoothing=0.0:radius1=0.0:radius2=0.0:angle=0.0:max_points=0:min_points=0:nodata=0.0 "
+ + "-ot Float32 -of GTiff -z_multiply 1.5 -outsize 1754 1394 "
+ + source
+ + " "
+ + outdir
+ + "/check.tif --config X Y --config Z A",
+ ],
+ )
def testGridInverseDistanceNearestNeighbour(self):
context = QgsProcessingContext()
feedback = QgsProcessingFeedback()
- source = os.path.join(testDataPath, 'points.gml')
+ source = os.path.join(testDataPath, "points.gml")
alg = GridInverseDistanceNearestNeighbor()
alg.initAlgorithm()
with tempfile.TemporaryDirectory() as outdir:
# without NODATA value
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'OUTPUT': outdir + '/check.jpg'}, context, feedback),
- ['gdal_grid',
- '-l points -a invdistnn:power=2.0:smoothing=0.0:radius=1.0:max_points=12:min_points=0:nodata=0.0 -ot Float32 -of JPEG ' +
- source + ' ' +
- outdir + '/check.jpg'])
+ alg.getConsoleCommands(
+ {"INPUT": source, "OUTPUT": outdir + "/check.jpg"},
+ context,
+ feedback,
+ ),
+ [
+ "gdal_grid",
+ "-l points -a invdistnn:power=2.0:smoothing=0.0:radius=1.0:max_points=12:min_points=0:nodata=0.0 -ot Float32 -of JPEG "
+ + source
+ + " "
+ + outdir
+ + "/check.jpg",
+ ],
+ )
# with NODATA value
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'NODATA': 9999,
- 'OUTPUT': outdir + '/check.jpg'}, context, feedback),
- ['gdal_grid',
- '-l points -a invdistnn:power=2.0:smoothing=0.0:radius=1.0:max_points=12:min_points=0:nodata=9999.0 -ot Float32 -of JPEG ' +
- source + ' ' +
- outdir + '/check.jpg'])
+ alg.getConsoleCommands(
+ {"INPUT": source, "NODATA": 9999, "OUTPUT": outdir + "/check.jpg"},
+ context,
+ feedback,
+ ),
+ [
+ "gdal_grid",
+ "-l points -a invdistnn:power=2.0:smoothing=0.0:radius=1.0:max_points=12:min_points=0:nodata=9999.0 -ot Float32 -of JPEG "
+ + source
+ + " "
+ + outdir
+ + "/check.jpg",
+ ],
+ )
# with "0" NODATA value
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'NODATA': 0,
- 'OUTPUT': outdir + '/check.jpg'}, context, feedback),
- ['gdal_grid',
- '-l points -a invdistnn:power=2.0:smoothing=0.0:radius=1.0:max_points=12:min_points=0:nodata=0.0 -ot Float32 -of JPEG ' +
- source + ' ' +
- outdir + '/check.jpg'])
+ alg.getConsoleCommands(
+ {"INPUT": source, "NODATA": 0, "OUTPUT": outdir + "/check.jpg"},
+ context,
+ feedback,
+ ),
+ [
+ "gdal_grid",
+ "-l points -a invdistnn:power=2.0:smoothing=0.0:radius=1.0:max_points=12:min_points=0:nodata=0.0 -ot Float32 -of JPEG "
+ + source
+ + " "
+ + outdir
+ + "/check.jpg",
+ ],
+ )
# additional parameters
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'EXTRA': '-z_multiply 1.5 -outsize 1754 1394',
- 'OUTPUT': outdir + '/check.tif'}, context, feedback),
- ['gdal_grid',
- '-l points -a invdistnn:power=2.0:smoothing=0.0:radius=1.0:max_points=12:min_points=0:nodata=0.0 ' +
- '-ot Float32 -of GTiff -z_multiply 1.5 -outsize 1754 1394 ' +
- source + ' ' +
- outdir + '/check.tif'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "EXTRA": "-z_multiply 1.5 -outsize 1754 1394",
+ "OUTPUT": outdir + "/check.tif",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdal_grid",
+ "-l points -a invdistnn:power=2.0:smoothing=0.0:radius=1.0:max_points=12:min_points=0:nodata=0.0 "
+ + "-ot Float32 -of GTiff -z_multiply 1.5 -outsize 1754 1394 "
+ + source
+ + " "
+ + outdir
+ + "/check.tif",
+ ],
+ )
if GdalUtils.version() >= 3070000:
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source + '|option:X_POSSIBLE_NAMES=geom_x|option:Y_POSSIBLE_NAMES=geom_y',
- 'EXTRA': '-z_multiply 1.5 -outsize 1754 1394',
- 'OUTPUT': outdir + '/check.tif'}, context, feedback),
- ['gdal_grid',
- '-l points -a invdistnn:power=2.0:smoothing=0.0:radius=1.0:max_points=12:min_points=0:nodata=0.0 ' +
- '-ot Float32 -of GTiff -oo X_POSSIBLE_NAMES=geom_x -oo Y_POSSIBLE_NAMES=geom_y -z_multiply 1.5 -outsize 1754 1394 ' +
- source + ' ' +
- outdir + '/check.tif'])
-
- self.assertEqual(
- alg.getConsoleCommands({'INPUT': source + '|credential:X=Y|credential:Z=A',
- 'EXTRA': '-z_multiply 1.5 -outsize 1754 1394',
- 'OUTPUT': outdir + '/check.tif'}, context, feedback),
- ['gdal_grid',
- '-l points -a invdistnn:power=2.0:smoothing=0.0:radius=1.0:max_points=12:min_points=0:nodata=0.0 ' +
- '-ot Float32 -of GTiff -z_multiply 1.5 -outsize 1754 1394 ' +
- source + ' ' +
- outdir + '/check.tif --config X Y --config Z A'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source
+ + "|option:X_POSSIBLE_NAMES=geom_x|option:Y_POSSIBLE_NAMES=geom_y",
+ "EXTRA": "-z_multiply 1.5 -outsize 1754 1394",
+ "OUTPUT": outdir + "/check.tif",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdal_grid",
+ "-l points -a invdistnn:power=2.0:smoothing=0.0:radius=1.0:max_points=12:min_points=0:nodata=0.0 "
+ + "-ot Float32 -of GTiff -oo X_POSSIBLE_NAMES=geom_x -oo Y_POSSIBLE_NAMES=geom_y -z_multiply 1.5 -outsize 1754 1394 "
+ + source
+ + " "
+ + outdir
+ + "/check.tif",
+ ],
+ )
+
+ self.assertEqual(
+ alg.getConsoleCommands(
+ {
+ "INPUT": source + "|credential:X=Y|credential:Z=A",
+ "EXTRA": "-z_multiply 1.5 -outsize 1754 1394",
+ "OUTPUT": outdir + "/check.tif",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdal_grid",
+ "-l points -a invdistnn:power=2.0:smoothing=0.0:radius=1.0:max_points=12:min_points=0:nodata=0.0 "
+ + "-ot Float32 -of GTiff -z_multiply 1.5 -outsize 1754 1394 "
+ + source
+ + " "
+ + outdir
+ + "/check.tif --config X Y --config Z A",
+ ],
+ )
def testGridLinear(self):
context = QgsProcessingContext()
feedback = QgsProcessingFeedback()
- source = os.path.join(testDataPath, 'points.gml')
+ source = os.path.join(testDataPath, "points.gml")
alg = GridLinear()
alg.initAlgorithm()
with tempfile.TemporaryDirectory() as outdir:
# without NODATA value
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'OUTPUT': outdir + '/check.jpg'}, context, feedback),
- ['gdal_grid',
- '-l points -a linear:radius=-1.0:nodata=0.0 -ot Float32 -of JPEG ' +
- source + ' ' +
- outdir + '/check.jpg'])
+ alg.getConsoleCommands(
+ {"INPUT": source, "OUTPUT": outdir + "/check.jpg"},
+ context,
+ feedback,
+ ),
+ [
+ "gdal_grid",
+ "-l points -a linear:radius=-1.0:nodata=0.0 -ot Float32 -of JPEG "
+ + source
+ + " "
+ + outdir
+ + "/check.jpg",
+ ],
+ )
# with NODATA value
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'NODATA': 9999,
- 'OUTPUT': outdir + '/check.jpg'}, context, feedback),
- ['gdal_grid',
- '-l points -a linear:radius=-1.0:nodata=9999.0 -ot Float32 -of JPEG ' +
- source + ' ' +
- outdir + '/check.jpg'])
+ alg.getConsoleCommands(
+ {"INPUT": source, "NODATA": 9999, "OUTPUT": outdir + "/check.jpg"},
+ context,
+ feedback,
+ ),
+ [
+ "gdal_grid",
+ "-l points -a linear:radius=-1.0:nodata=9999.0 -ot Float32 -of JPEG "
+ + source
+ + " "
+ + outdir
+ + "/check.jpg",
+ ],
+ )
# with "0" NODATA value
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'NODATA': 0,
- 'OUTPUT': outdir + '/check.jpg'}, context, feedback),
- ['gdal_grid',
- '-l points -a linear:radius=-1.0:nodata=0.0 -ot Float32 -of JPEG ' +
- source + ' ' +
- outdir + '/check.jpg'])
+ alg.getConsoleCommands(
+ {"INPUT": source, "NODATA": 0, "OUTPUT": outdir + "/check.jpg"},
+ context,
+ feedback,
+ ),
+ [
+ "gdal_grid",
+ "-l points -a linear:radius=-1.0:nodata=0.0 -ot Float32 -of JPEG "
+ + source
+ + " "
+ + outdir
+ + "/check.jpg",
+ ],
+ )
# additional parameters
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'EXTRA': '-z_multiply 1.5 -outsize 1754 1394',
- 'OUTPUT': outdir + '/check.tif'}, context, feedback),
- ['gdal_grid',
- '-l points -a linear:radius=-1.0:nodata=0.0 -ot Float32 -of GTiff ' +
- '-z_multiply 1.5 -outsize 1754 1394 ' +
- source + ' ' +
- outdir + '/check.tif'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "EXTRA": "-z_multiply 1.5 -outsize 1754 1394",
+ "OUTPUT": outdir + "/check.tif",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdal_grid",
+ "-l points -a linear:radius=-1.0:nodata=0.0 -ot Float32 -of GTiff "
+ + "-z_multiply 1.5 -outsize 1754 1394 "
+ + source
+ + " "
+ + outdir
+ + "/check.tif",
+ ],
+ )
if GdalUtils.version() >= 3070000:
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source + '|option:X_POSSIBLE_NAMES=geom_x|option:Y_POSSIBLE_NAMES=geom_y',
- 'EXTRA': '-z_multiply 1.5 -outsize 1754 1394',
- 'OUTPUT': outdir + '/check.tif'}, context, feedback),
- ['gdal_grid',
- '-l points -a linear:radius=-1.0:nodata=0.0 -ot Float32 -of GTiff -oo X_POSSIBLE_NAMES=geom_x -oo Y_POSSIBLE_NAMES=geom_y ' +
- '-z_multiply 1.5 -outsize 1754 1394 ' +
- source + ' ' +
- outdir + '/check.tif'])
-
- self.assertEqual(
- alg.getConsoleCommands({'INPUT': source + '|credential:X=Y|credential:Z=A',
- 'EXTRA': '-z_multiply 1.5 -outsize 1754 1394',
- 'OUTPUT': outdir + '/check.tif'}, context, feedback),
- ['gdal_grid',
- '-l points -a linear:radius=-1.0:nodata=0.0 -ot Float32 -of GTiff ' +
- '-z_multiply 1.5 -outsize 1754 1394 ' +
- source + ' ' +
- outdir + '/check.tif --config X Y --config Z A'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source
+ + "|option:X_POSSIBLE_NAMES=geom_x|option:Y_POSSIBLE_NAMES=geom_y",
+ "EXTRA": "-z_multiply 1.5 -outsize 1754 1394",
+ "OUTPUT": outdir + "/check.tif",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdal_grid",
+ "-l points -a linear:radius=-1.0:nodata=0.0 -ot Float32 -of GTiff -oo X_POSSIBLE_NAMES=geom_x -oo Y_POSSIBLE_NAMES=geom_y "
+ + "-z_multiply 1.5 -outsize 1754 1394 "
+ + source
+ + " "
+ + outdir
+ + "/check.tif",
+ ],
+ )
+
+ self.assertEqual(
+ alg.getConsoleCommands(
+ {
+ "INPUT": source + "|credential:X=Y|credential:Z=A",
+ "EXTRA": "-z_multiply 1.5 -outsize 1754 1394",
+ "OUTPUT": outdir + "/check.tif",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdal_grid",
+ "-l points -a linear:radius=-1.0:nodata=0.0 -ot Float32 -of GTiff "
+ + "-z_multiply 1.5 -outsize 1754 1394 "
+ + source
+ + " "
+ + outdir
+ + "/check.tif --config X Y --config Z A",
+ ],
+ )
def testGridNearestNeighbour(self):
context = QgsProcessingContext()
feedback = QgsProcessingFeedback()
- source = os.path.join(testDataPath, 'points.gml')
+ source = os.path.join(testDataPath, "points.gml")
alg = GridNearestNeighbor()
alg.initAlgorithm()
with tempfile.TemporaryDirectory() as outdir:
# without NODATA value
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'OUTPUT': outdir + '/check.jpg'}, context, feedback),
- ['gdal_grid',
- '-l points -a nearest:radius1=0.0:radius2=0.0:angle=0.0:nodata=0.0 -ot Float32 -of JPEG ' +
- source + ' ' +
- outdir + '/check.jpg'])
+ alg.getConsoleCommands(
+ {"INPUT": source, "OUTPUT": outdir + "/check.jpg"},
+ context,
+ feedback,
+ ),
+ [
+ "gdal_grid",
+ "-l points -a nearest:radius1=0.0:radius2=0.0:angle=0.0:nodata=0.0 -ot Float32 -of JPEG "
+ + source
+ + " "
+ + outdir
+ + "/check.jpg",
+ ],
+ )
# with NODATA value
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'NODATA': 9999,
- 'OUTPUT': outdir + '/check.jpg'}, context, feedback),
- ['gdal_grid',
- '-l points -a nearest:radius1=0.0:radius2=0.0:angle=0.0:nodata=9999.0 -ot Float32 -of JPEG ' +
- source + ' ' +
- outdir + '/check.jpg'])
+ alg.getConsoleCommands(
+ {"INPUT": source, "NODATA": 9999, "OUTPUT": outdir + "/check.jpg"},
+ context,
+ feedback,
+ ),
+ [
+ "gdal_grid",
+ "-l points -a nearest:radius1=0.0:radius2=0.0:angle=0.0:nodata=9999.0 -ot Float32 -of JPEG "
+ + source
+ + " "
+ + outdir
+ + "/check.jpg",
+ ],
+ )
# with "0" NODATA value
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'NODATA': 0,
- 'OUTPUT': outdir + '/check.jpg'}, context, feedback),
- ['gdal_grid',
- '-l points -a nearest:radius1=0.0:radius2=0.0:angle=0.0:nodata=0.0 -ot Float32 -of JPEG ' +
- source + ' ' +
- outdir + '/check.jpg'])
+ alg.getConsoleCommands(
+ {"INPUT": source, "NODATA": 0, "OUTPUT": outdir + "/check.jpg"},
+ context,
+ feedback,
+ ),
+ [
+ "gdal_grid",
+ "-l points -a nearest:radius1=0.0:radius2=0.0:angle=0.0:nodata=0.0 -ot Float32 -of JPEG "
+ + source
+ + " "
+ + outdir
+ + "/check.jpg",
+ ],
+ )
# additional parameters
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'EXTRA': '-z_multiply 1.5 -outsize 1754 1394',
- 'OUTPUT': outdir + '/check.tif'}, context, feedback),
- ['gdal_grid',
- '-l points -a nearest:radius1=0.0:radius2=0.0:angle=0.0:nodata=0.0 -ot Float32 -of GTiff ' +
- '-z_multiply 1.5 -outsize 1754 1394 ' +
- source + ' ' +
- outdir + '/check.tif'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "EXTRA": "-z_multiply 1.5 -outsize 1754 1394",
+ "OUTPUT": outdir + "/check.tif",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdal_grid",
+ "-l points -a nearest:radius1=0.0:radius2=0.0:angle=0.0:nodata=0.0 -ot Float32 -of GTiff "
+ + "-z_multiply 1.5 -outsize 1754 1394 "
+ + source
+ + " "
+ + outdir
+ + "/check.tif",
+ ],
+ )
if GdalUtils.version() >= 3070000:
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source + '|option:X_POSSIBLE_NAMES=geom_x|option:Y_POSSIBLE_NAMES=geom_y',
- 'EXTRA': '-z_multiply 1.5 -outsize 1754 1394',
- 'OUTPUT': outdir + '/check.tif'}, context, feedback),
- ['gdal_grid',
- '-l points -a nearest:radius1=0.0:radius2=0.0:angle=0.0:nodata=0.0 -ot Float32 -of GTiff -oo X_POSSIBLE_NAMES=geom_x -oo Y_POSSIBLE_NAMES=geom_y ' +
- '-z_multiply 1.5 -outsize 1754 1394 ' +
- source + ' ' +
- outdir + '/check.tif'])
-
- self.assertEqual(
- alg.getConsoleCommands({'INPUT': source + '|credential:X=Y|credential:Z=A',
- 'EXTRA': '-z_multiply 1.5 -outsize 1754 1394',
- 'OUTPUT': outdir + '/check.tif'}, context, feedback),
- ['gdal_grid',
- '-l points -a nearest:radius1=0.0:radius2=0.0:angle=0.0:nodata=0.0 -ot Float32 -of GTiff ' +
- '-z_multiply 1.5 -outsize 1754 1394 ' +
- source + ' ' +
- outdir + '/check.tif --config X Y --config Z A'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source
+ + "|option:X_POSSIBLE_NAMES=geom_x|option:Y_POSSIBLE_NAMES=geom_y",
+ "EXTRA": "-z_multiply 1.5 -outsize 1754 1394",
+ "OUTPUT": outdir + "/check.tif",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdal_grid",
+ "-l points -a nearest:radius1=0.0:radius2=0.0:angle=0.0:nodata=0.0 -ot Float32 -of GTiff -oo X_POSSIBLE_NAMES=geom_x -oo Y_POSSIBLE_NAMES=geom_y "
+ + "-z_multiply 1.5 -outsize 1754 1394 "
+ + source
+ + " "
+ + outdir
+ + "/check.tif",
+ ],
+ )
+
+ self.assertEqual(
+ alg.getConsoleCommands(
+ {
+ "INPUT": source + "|credential:X=Y|credential:Z=A",
+ "EXTRA": "-z_multiply 1.5 -outsize 1754 1394",
+ "OUTPUT": outdir + "/check.tif",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdal_grid",
+ "-l points -a nearest:radius1=0.0:radius2=0.0:angle=0.0:nodata=0.0 -ot Float32 -of GTiff "
+ + "-z_multiply 1.5 -outsize 1754 1394 "
+ + source
+ + " "
+ + outdir
+ + "/check.tif --config X Y --config Z A",
+ ],
+ )
def testHillshade(self):
context = QgsProcessingContext()
feedback = QgsProcessingFeedback()
- source = os.path.join(testDataPath, 'dem.tif')
+ source = os.path.join(testDataPath, "dem.tif")
alg = hillshade()
alg.initAlgorithm()
with tempfile.TemporaryDirectory() as outdir:
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'BAND': 1,
- 'Z_FACTOR': 5,
- 'SCALE': 2,
- 'AZIMUTH': 90,
- 'ALTITUDE': 20,
- 'OUTPUT': outdir + '/check.tif'}, context, feedback),
- ['gdaldem',
- 'hillshade ' +
- source + ' ' +
- outdir + '/check.tif -of GTiff -b 1 -z 5.0 -s 2.0 -az 90.0 -alt 20.0'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "BAND": 1,
+ "Z_FACTOR": 5,
+ "SCALE": 2,
+ "AZIMUTH": 90,
+ "ALTITUDE": 20,
+ "OUTPUT": outdir + "/check.tif",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdaldem",
+ "hillshade "
+ + source
+ + " "
+ + outdir
+ + "/check.tif -of GTiff -b 1 -z 5.0 -s 2.0 -az 90.0 -alt 20.0",
+ ],
+ )
# paths with space
- source_with_space = os.path.join(testDataPath, 'raster with spaces.tif')
- self.assertEqual(
- alg.getConsoleCommands({'INPUT': source_with_space,
- 'BAND': 1,
- 'Z_FACTOR': 5,
- 'SCALE': 2,
- 'AZIMUTH': 90,
- 'ALTITUDE': 20,
- 'OUTPUT': outdir + '/check out.tif'}, context, feedback),
- ['gdaldem',
- 'hillshade ' +
- '"' + source_with_space + '" ' +
- f'"{outdir}/check out.tif" -of GTiff -b 1 -z 5.0 -s 2.0 -az 90.0 -alt 20.0'])
+ source_with_space = os.path.join(testDataPath, "raster with spaces.tif")
+ self.assertEqual(
+ alg.getConsoleCommands(
+ {
+ "INPUT": source_with_space,
+ "BAND": 1,
+ "Z_FACTOR": 5,
+ "SCALE": 2,
+ "AZIMUTH": 90,
+ "ALTITUDE": 20,
+ "OUTPUT": outdir + "/check out.tif",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdaldem",
+ "hillshade "
+ + '"'
+ + source_with_space
+ + '" '
+ + f'"{outdir}/check out.tif" -of GTiff -b 1 -z 5.0 -s 2.0 -az 90.0 -alt 20.0',
+ ],
+ )
# compute edges
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'BAND': 1,
- 'Z_FACTOR': 5,
- 'SCALE': 2,
- 'AZIMUTH': 90,
- 'ALTITUDE': 20,
- 'COMPUTE_EDGES': True,
- 'OUTPUT': outdir + '/check.tif'}, context, feedback),
- ['gdaldem',
- 'hillshade ' +
- source + ' ' +
- outdir + '/check.tif -of GTiff -b 1 -z 5.0 -s 2.0 -az 90.0 -alt 20.0 -compute_edges'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "BAND": 1,
+ "Z_FACTOR": 5,
+ "SCALE": 2,
+ "AZIMUTH": 90,
+ "ALTITUDE": 20,
+ "COMPUTE_EDGES": True,
+ "OUTPUT": outdir + "/check.tif",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdaldem",
+ "hillshade "
+ + source
+ + " "
+ + outdir
+ + "/check.tif -of GTiff -b 1 -z 5.0 -s 2.0 -az 90.0 -alt 20.0 -compute_edges",
+ ],
+ )
# with ZEVENBERGEN
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'BAND': 1,
- 'Z_FACTOR': 5,
- 'SCALE': 2,
- 'AZIMUTH': 90,
- 'ALTITUDE': 20,
- 'ZEVENBERGEN': True,
- 'OUTPUT': outdir + '/check.tif'}, context, feedback),
- ['gdaldem',
- 'hillshade ' +
- source + ' ' +
- outdir + '/check.tif -of GTiff -b 1 -z 5.0 -s 2.0 -az 90.0 -alt 20.0 -alg ZevenbergenThorne'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "BAND": 1,
+ "Z_FACTOR": 5,
+ "SCALE": 2,
+ "AZIMUTH": 90,
+ "ALTITUDE": 20,
+ "ZEVENBERGEN": True,
+ "OUTPUT": outdir + "/check.tif",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdaldem",
+ "hillshade "
+ + source
+ + " "
+ + outdir
+ + "/check.tif -of GTiff -b 1 -z 5.0 -s 2.0 -az 90.0 -alt 20.0 -alg ZevenbergenThorne",
+ ],
+ )
# with COMBINED
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'BAND': 1,
- 'Z_FACTOR': 5,
- 'SCALE': 2,
- 'AZIMUTH': 90,
- 'ALTITUDE': 20,
- 'COMBINED': True,
- 'OUTPUT': outdir + '/check.tif'}, context, feedback),
- ['gdaldem',
- 'hillshade ' +
- source + ' ' +
- outdir + '/check.tif -of GTiff -b 1 -z 5.0 -s 2.0 -az 90.0 -alt 20.0 -combined'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "BAND": 1,
+ "Z_FACTOR": 5,
+ "SCALE": 2,
+ "AZIMUTH": 90,
+ "ALTITUDE": 20,
+ "COMBINED": True,
+ "OUTPUT": outdir + "/check.tif",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdaldem",
+ "hillshade "
+ + source
+ + " "
+ + outdir
+ + "/check.tif -of GTiff -b 1 -z 5.0 -s 2.0 -az 90.0 -alt 20.0 -combined",
+ ],
+ )
# with multidirectional - "az" argument is not allowed!
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'BAND': 1,
- 'Z_FACTOR': 5,
- 'SCALE': 2,
- 'AZIMUTH': 90,
- 'ALTITUDE': 20,
- 'MULTIDIRECTIONAL': True,
- 'OUTPUT': outdir + '/check.tif'}, context, feedback),
- ['gdaldem',
- 'hillshade ' +
- source + ' ' +
- outdir + '/check.tif -of GTiff -b 1 -z 5.0 -s 2.0 -alt 20.0 -multidirectional'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "BAND": 1,
+ "Z_FACTOR": 5,
+ "SCALE": 2,
+ "AZIMUTH": 90,
+ "ALTITUDE": 20,
+ "MULTIDIRECTIONAL": True,
+ "OUTPUT": outdir + "/check.tif",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdaldem",
+ "hillshade "
+ + source
+ + " "
+ + outdir
+ + "/check.tif -of GTiff -b 1 -z 5.0 -s 2.0 -alt 20.0 -multidirectional",
+ ],
+ )
# defaults with additional parameters
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'BAND': 1,
- 'EXTRA': '-q',
- 'OUTPUT': outdir + '/check.tif'}, context, feedback),
- ['gdaldem',
- 'hillshade ' +
- source + ' ' +
- outdir + '/check.tif -of GTiff -b 1 -z 1.0 -s 1.0 -az 315.0 -alt 45.0 -q'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "BAND": 1,
+ "EXTRA": "-q",
+ "OUTPUT": outdir + "/check.tif",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdaldem",
+ "hillshade "
+ + source
+ + " "
+ + outdir
+ + "/check.tif -of GTiff -b 1 -z 1.0 -s 1.0 -az 315.0 -alt 45.0 -q",
+ ],
+ )
# multidirectional and combined are mutually exclusive
self.assertRaises(
QgsProcessingException,
- lambda: alg.getConsoleCommands({'INPUT': source,
- 'BAND': 1,
- 'Z_FACTOR': 5,
- 'SCALE': 2,
- 'AZIMUTH': 90,
- 'COMBINED': True,
- 'MULTIDIRECTIONAL': True,
- 'OUTPUT': outdir + '/check.tif'}, context, feedback))
- self.assertEqual(
- alg.getConsoleCommands({'INPUT': source + '|credential:X=Y|credential:Z=A',
- 'BAND': 1,
- 'Z_FACTOR': 5,
- 'SCALE': 2,
- 'AZIMUTH': 90,
- 'ALTITUDE': 20,
- 'OUTPUT': outdir + '/check.tif'}, context, feedback),
- ['gdaldem',
- 'hillshade ' +
- source + ' ' +
- outdir + '/check.tif -of GTiff -b 1 -z 5.0 -s 2.0 -az 90.0 -alt 20.0 --config X Y --config Z A'])
+ lambda: alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "BAND": 1,
+ "Z_FACTOR": 5,
+ "SCALE": 2,
+ "AZIMUTH": 90,
+ "COMBINED": True,
+ "MULTIDIRECTIONAL": True,
+ "OUTPUT": outdir + "/check.tif",
+ },
+ context,
+ feedback,
+ ),
+ )
+ self.assertEqual(
+ alg.getConsoleCommands(
+ {
+ "INPUT": source + "|credential:X=Y|credential:Z=A",
+ "BAND": 1,
+ "Z_FACTOR": 5,
+ "SCALE": 2,
+ "AZIMUTH": 90,
+ "ALTITUDE": 20,
+ "OUTPUT": outdir + "/check.tif",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdaldem",
+ "hillshade "
+ + source
+ + " "
+ + outdir
+ + "/check.tif -of GTiff -b 1 -z 5.0 -s 2.0 -az 90.0 -alt 20.0 --config X Y --config Z A",
+ ],
+ )
def testAspect(self):
context = QgsProcessingContext()
feedback = QgsProcessingFeedback()
- source = os.path.join(testDataPath, 'dem.tif')
+ source = os.path.join(testDataPath, "dem.tif")
alg = aspect()
alg.initAlgorithm()
with tempfile.TemporaryDirectory() as outdir:
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'BAND': 1,
- 'TRIG_ANGLE': False,
- 'ZERO_FLAT': False,
- 'COMPUTE_EDGES': False,
- 'ZEVENBERGEN': False,
- 'OUTPUT': outdir + '/check.tif'}, context, feedback),
- ['gdaldem',
- 'aspect ' +
- source + ' ' +
- outdir + '/check.tif -of GTiff -b 1'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "BAND": 1,
+ "TRIG_ANGLE": False,
+ "ZERO_FLAT": False,
+ "COMPUTE_EDGES": False,
+ "ZEVENBERGEN": False,
+ "OUTPUT": outdir + "/check.tif",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdaldem",
+ "aspect " + source + " " + outdir + "/check.tif -of GTiff -b 1",
+ ],
+ )
# paths with space
- source_with_space = os.path.join(testDataPath, 'raster with spaces.tif')
- self.assertEqual(
- alg.getConsoleCommands({'INPUT': source_with_space,
- 'BAND': 1,
- 'TRIG_ANGLE': False,
- 'ZERO_FLAT': False,
- 'COMPUTE_EDGES': False,
- 'ZEVENBERGEN': False,
- 'OUTPUT': outdir + '/check out.tif'}, context, feedback),
- ['gdaldem',
- 'aspect ' +
- '"' + source_with_space + '" ' +
- f'"{outdir}/check out.tif" -of GTiff -b 1'])
+ source_with_space = os.path.join(testDataPath, "raster with spaces.tif")
+ self.assertEqual(
+ alg.getConsoleCommands(
+ {
+ "INPUT": source_with_space,
+ "BAND": 1,
+ "TRIG_ANGLE": False,
+ "ZERO_FLAT": False,
+ "COMPUTE_EDGES": False,
+ "ZEVENBERGEN": False,
+ "OUTPUT": outdir + "/check out.tif",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdaldem",
+ "aspect "
+ + '"'
+ + source_with_space
+ + '" '
+ + f'"{outdir}/check out.tif" -of GTiff -b 1',
+ ],
+ )
# compute edges
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'BAND': 1,
- 'TRIG_ANGLE': False,
- 'ZERO_FLAT': False,
- 'COMPUTE_EDGES': True,
- 'ZEVENBERGEN': False,
- 'OUTPUT': outdir + '/check.tif'}, context, feedback),
- ['gdaldem',
- 'aspect ' +
- source + ' ' +
- outdir + '/check.tif -of GTiff -b 1 -compute_edges'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "BAND": 1,
+ "TRIG_ANGLE": False,
+ "ZERO_FLAT": False,
+ "COMPUTE_EDGES": True,
+ "ZEVENBERGEN": False,
+ "OUTPUT": outdir + "/check.tif",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdaldem",
+ "aspect "
+ + source
+ + " "
+ + outdir
+ + "/check.tif -of GTiff -b 1 -compute_edges",
+ ],
+ )
# with ZEVENBERGEN
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'BAND': 1,
- 'TRIG_ANGLE': False,
- 'ZERO_FLAT': False,
- 'COMPUTE_EDGES': False,
- 'ZEVENBERGEN': True,
- 'OUTPUT': outdir + '/check.tif'}, context, feedback),
- ['gdaldem',
- 'aspect ' +
- source + ' ' +
- outdir + '/check.tif -of GTiff -b 1 -alg ZevenbergenThorne'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "BAND": 1,
+ "TRIG_ANGLE": False,
+ "ZERO_FLAT": False,
+ "COMPUTE_EDGES": False,
+ "ZEVENBERGEN": True,
+ "OUTPUT": outdir + "/check.tif",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdaldem",
+ "aspect "
+ + source
+ + " "
+ + outdir
+ + "/check.tif -of GTiff -b 1 -alg ZevenbergenThorne",
+ ],
+ )
# with ZERO_FLAT
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'BAND': 1,
- 'TRIG_ANGLE': False,
- 'ZERO_FLAT': True,
- 'COMPUTE_EDGES': False,
- 'ZEVENBERGEN': False,
- 'OUTPUT': outdir + '/check.tif'}, context, feedback),
- ['gdaldem',
- 'aspect ' +
- source + ' ' +
- outdir + '/check.tif -of GTiff -b 1 -zero_for_flat'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "BAND": 1,
+ "TRIG_ANGLE": False,
+ "ZERO_FLAT": True,
+ "COMPUTE_EDGES": False,
+ "ZEVENBERGEN": False,
+ "OUTPUT": outdir + "/check.tif",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdaldem",
+ "aspect "
+ + source
+ + " "
+ + outdir
+ + "/check.tif -of GTiff -b 1 -zero_for_flat",
+ ],
+ )
# with TRIG_ANGLE
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'BAND': 1,
- 'TRIG_ANGLE': True,
- 'ZERO_FLAT': False,
- 'COMPUTE_EDGES': False,
- 'ZEVENBERGEN': False,
- 'OUTPUT': outdir + '/check.tif'}, context, feedback),
- ['gdaldem',
- 'aspect ' +
- source + ' ' +
- outdir + '/check.tif -of GTiff -b 1 -trigonometric'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "BAND": 1,
+ "TRIG_ANGLE": True,
+ "ZERO_FLAT": False,
+ "COMPUTE_EDGES": False,
+ "ZEVENBERGEN": False,
+ "OUTPUT": outdir + "/check.tif",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdaldem",
+ "aspect "
+ + source
+ + " "
+ + outdir
+ + "/check.tif -of GTiff -b 1 -trigonometric",
+ ],
+ )
# with creation options
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'BAND': 1,
- 'TRIG_ANGLE': False,
- 'ZERO_FLAT': False,
- 'COMPUTE_EDGES': False,
- 'ZEVENBERGEN': False,
- 'OPTIONS': 'COMPRESS=JPEG|JPEG_QUALITY=75',
- 'OUTPUT': outdir + '/check.tif'}, context, feedback),
- ['gdaldem',
- 'aspect ' +
- source + ' ' +
- outdir + '/check.tif -of GTiff -b 1 -co COMPRESS=JPEG -co JPEG_QUALITY=75'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "BAND": 1,
+ "TRIG_ANGLE": False,
+ "ZERO_FLAT": False,
+ "COMPUTE_EDGES": False,
+ "ZEVENBERGEN": False,
+ "OPTIONS": "COMPRESS=JPEG|JPEG_QUALITY=75",
+ "OUTPUT": outdir + "/check.tif",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdaldem",
+ "aspect "
+ + source
+ + " "
+ + outdir
+ + "/check.tif -of GTiff -b 1 -co COMPRESS=JPEG -co JPEG_QUALITY=75",
+ ],
+ )
# with additional parameter
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'BAND': 1,
- 'TRIG_ANGLE': False,
- 'ZERO_FLAT': False,
- 'COMPUTE_EDGES': False,
- 'ZEVENBERGEN': False,
- 'EXTRA': '-q',
- 'OUTPUT': outdir + '/check.tif'}, context, feedback),
- ['gdaldem',
- 'aspect ' +
- source + ' ' +
- outdir + '/check.tif -of GTiff -b 1 -q'])
-
- self.assertEqual(
- alg.getConsoleCommands({'INPUT': source + '|credential:X=Y|credential:Z=A',
- 'BAND': 1,
- 'TRIG_ANGLE': False,
- 'ZERO_FLAT': False,
- 'COMPUTE_EDGES': False,
- 'ZEVENBERGEN': False,
- 'EXTRA': '-q',
- 'OUTPUT': outdir + '/check.tif'}, context, feedback),
- ['gdaldem',
- 'aspect ' +
- source + ' ' +
- outdir + '/check.tif -of GTiff -b 1 --config X Y --config Z A -q'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "BAND": 1,
+ "TRIG_ANGLE": False,
+ "ZERO_FLAT": False,
+ "COMPUTE_EDGES": False,
+ "ZEVENBERGEN": False,
+ "EXTRA": "-q",
+ "OUTPUT": outdir + "/check.tif",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdaldem",
+ "aspect " + source + " " + outdir + "/check.tif -of GTiff -b 1 -q",
+ ],
+ )
+
+ self.assertEqual(
+ alg.getConsoleCommands(
+ {
+ "INPUT": source + "|credential:X=Y|credential:Z=A",
+ "BAND": 1,
+ "TRIG_ANGLE": False,
+ "ZERO_FLAT": False,
+ "COMPUTE_EDGES": False,
+ "ZEVENBERGEN": False,
+ "EXTRA": "-q",
+ "OUTPUT": outdir + "/check.tif",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdaldem",
+ "aspect "
+ + source
+ + " "
+ + outdir
+ + "/check.tif -of GTiff -b 1 --config X Y --config Z A -q",
+ ],
+ )
def testSlope(self):
context = QgsProcessingContext()
feedback = QgsProcessingFeedback()
- source = os.path.join(testDataPath, 'dem.tif')
+ source = os.path.join(testDataPath, "dem.tif")
alg = slope()
alg.initAlgorithm()
with tempfile.TemporaryDirectory() as outdir:
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'BAND': 1,
- 'OUTPUT': outdir + '/check.tif'}, context, feedback),
- ['gdaldem',
- 'slope ' +
- source + ' ' +
- outdir + '/check.tif -of GTiff -b 1 -s 1.0'])
+ alg.getConsoleCommands(
+ {"INPUT": source, "BAND": 1, "OUTPUT": outdir + "/check.tif"},
+ context,
+ feedback,
+ ),
+ [
+ "gdaldem",
+ "slope "
+ + source
+ + " "
+ + outdir
+ + "/check.tif -of GTiff -b 1 -s 1.0",
+ ],
+ )
# compute edges
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'BAND': 1,
- 'COMPUTE_EDGES': True,
- 'OUTPUT': outdir + '/check.tif'}, context, feedback),
- ['gdaldem',
- 'slope ' +
- source + ' ' +
- outdir + '/check.tif -of GTiff -b 1 -s 1.0 -compute_edges'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "BAND": 1,
+ "COMPUTE_EDGES": True,
+ "OUTPUT": outdir + "/check.tif",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdaldem",
+ "slope "
+ + source
+ + " "
+ + outdir
+ + "/check.tif -of GTiff -b 1 -s 1.0 -compute_edges",
+ ],
+ )
# with ZEVENBERGEN
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'BAND': 1,
- 'ZEVENBERGEN': True,
- 'OUTPUT': outdir + '/check.tif'}, context, feedback),
- ['gdaldem',
- 'slope ' +
- source + ' ' +
- outdir + '/check.tif -of GTiff -b 1 -s 1.0 -alg ZevenbergenThorne'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "BAND": 1,
+ "ZEVENBERGEN": True,
+ "OUTPUT": outdir + "/check.tif",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdaldem",
+ "slope "
+ + source
+ + " "
+ + outdir
+ + "/check.tif -of GTiff -b 1 -s 1.0 -alg ZevenbergenThorne",
+ ],
+ )
# custom ratio
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'BAND': 1,
- 'SCALE': 2.0,
- 'OUTPUT': outdir + '/check.tif'}, context, feedback),
- ['gdaldem',
- 'slope ' +
- source + ' ' +
- outdir + '/check.tif -of GTiff -b 1 -s 2.0'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "BAND": 1,
+ "SCALE": 2.0,
+ "OUTPUT": outdir + "/check.tif",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdaldem",
+ "slope "
+ + source
+ + " "
+ + outdir
+ + "/check.tif -of GTiff -b 1 -s 2.0",
+ ],
+ )
# with creation options
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'BAND': 1,
- 'OPTIONS': 'COMPRESS=JPEG|JPEG_QUALITY=75',
- 'OUTPUT': outdir + '/check.tif'}, context, feedback),
- ['gdaldem',
- 'slope ' +
- source + ' ' +
- outdir + '/check.tif -of GTiff -b 1 -s 1.0 -co COMPRESS=JPEG -co JPEG_QUALITY=75'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "BAND": 1,
+ "OPTIONS": "COMPRESS=JPEG|JPEG_QUALITY=75",
+ "OUTPUT": outdir + "/check.tif",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdaldem",
+ "slope "
+ + source
+ + " "
+ + outdir
+ + "/check.tif -of GTiff -b 1 -s 1.0 -co COMPRESS=JPEG -co JPEG_QUALITY=75",
+ ],
+ )
# with additional parameter
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'BAND': 1,
- 'EXTRA': '-q',
- 'OUTPUT': outdir + '/check.jpg'}, context, feedback),
- ['gdaldem',
- 'slope ' +
- source + ' ' +
- outdir + '/check.jpg -of JPEG -b 1 -s 1.0 -q'])
-
- self.assertEqual(
- alg.getConsoleCommands({'INPUT': source + '|credential:X=Y|credential:Z=A',
- 'BAND': 1,
- 'OUTPUT': outdir + '/check.tif'}, context, feedback),
- ['gdaldem',
- 'slope ' +
- source + ' ' +
- outdir + '/check.tif -of GTiff -b 1 -s 1.0 --config X Y --config Z A'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "BAND": 1,
+ "EXTRA": "-q",
+ "OUTPUT": outdir + "/check.jpg",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdaldem",
+ "slope "
+ + source
+ + " "
+ + outdir
+ + "/check.jpg -of JPEG -b 1 -s 1.0 -q",
+ ],
+ )
+
+ self.assertEqual(
+ alg.getConsoleCommands(
+ {
+ "INPUT": source + "|credential:X=Y|credential:Z=A",
+ "BAND": 1,
+ "OUTPUT": outdir + "/check.tif",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdaldem",
+ "slope "
+ + source
+ + " "
+ + outdir
+ + "/check.tif -of GTiff -b 1 -s 1.0 --config X Y --config Z A",
+ ],
+ )
def testColorRelief(self):
context = QgsProcessingContext()
feedback = QgsProcessingFeedback()
- source = os.path.join(testDataPath, 'dem.tif')
- colorTable = os.path.join(testDataPath, 'colors.txt')
+ source = os.path.join(testDataPath, "dem.tif")
+ colorTable = os.path.join(testDataPath, "colors.txt")
alg = ColorRelief()
alg.initAlgorithm()
with tempfile.TemporaryDirectory() as outdir:
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'BAND': 1,
- 'COLOR_TABLE': colorTable,
- 'OUTPUT': outdir + '/check.tif'}, context, feedback),
- ['gdaldem',
- 'color-relief ' +
- source + ' ' +
- colorTable + ' ' +
- outdir + '/check.tif -of GTiff -b 1'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "BAND": 1,
+ "COLOR_TABLE": colorTable,
+ "OUTPUT": outdir + "/check.tif",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdaldem",
+ "color-relief "
+ + source
+ + " "
+ + colorTable
+ + " "
+ + outdir
+ + "/check.tif -of GTiff -b 1",
+ ],
+ )
# paths with space
- source_with_space = os.path.join(testDataPath, 'raster with spaces.tif')
- self.assertEqual(
- alg.getConsoleCommands({'INPUT': source_with_space,
- 'BAND': 1,
- 'COLOR_TABLE': colorTable,
- 'OUTPUT': outdir + '/check out.tif'}, context, feedback),
- ['gdaldem',
- 'color-relief ' +
- '"' + source_with_space + '" ' +
- colorTable + ' ' +
- f'"{outdir}/check out.tif" -of GTiff -b 1'])
+ source_with_space = os.path.join(testDataPath, "raster with spaces.tif")
+ self.assertEqual(
+ alg.getConsoleCommands(
+ {
+ "INPUT": source_with_space,
+ "BAND": 1,
+ "COLOR_TABLE": colorTable,
+ "OUTPUT": outdir + "/check out.tif",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdaldem",
+ "color-relief "
+ + '"'
+ + source_with_space
+ + '" '
+ + colorTable
+ + " "
+ + f'"{outdir}/check out.tif" -of GTiff -b 1',
+ ],
+ )
# compute edges
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'BAND': 1,
- 'COLOR_TABLE': colorTable,
- 'COMPUTE_EDGES': True,
- 'OUTPUT': outdir + '/check.tif'}, context, feedback),
- ['gdaldem',
- 'color-relief ' +
- source + ' ' +
- colorTable + ' ' +
- outdir + '/check.tif -of GTiff -b 1 -compute_edges'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "BAND": 1,
+ "COLOR_TABLE": colorTable,
+ "COMPUTE_EDGES": True,
+ "OUTPUT": outdir + "/check.tif",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdaldem",
+ "color-relief "
+ + source
+ + " "
+ + colorTable
+ + " "
+ + outdir
+ + "/check.tif -of GTiff -b 1 -compute_edges",
+ ],
+ )
# with custom matching mode
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'BAND': 1,
- 'COLOR_TABLE': colorTable,
- 'MATCH_MODE': 1,
- 'OUTPUT': outdir + '/check.tif'}, context, feedback),
- ['gdaldem',
- 'color-relief ' +
- source + ' ' +
- colorTable + ' ' +
- outdir + '/check.tif -of GTiff -b 1 -nearest_color_entry'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "BAND": 1,
+ "COLOR_TABLE": colorTable,
+ "MATCH_MODE": 1,
+ "OUTPUT": outdir + "/check.tif",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdaldem",
+ "color-relief "
+ + source
+ + " "
+ + colorTable
+ + " "
+ + outdir
+ + "/check.tif -of GTiff -b 1 -nearest_color_entry",
+ ],
+ )
# with creation options
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'BAND': 1,
- 'COLOR_TABLE': colorTable,
- 'MATCH_MODE': 1,
- 'OPTIONS': 'COMPRESS=JPEG|JPEG_QUALITY=75',
- 'OUTPUT': outdir + '/check.tif'}, context, feedback),
- ['gdaldem',
- 'color-relief ' +
- source + ' ' +
- colorTable + ' ' +
- outdir + '/check.tif -of GTiff -b 1 -nearest_color_entry -co COMPRESS=JPEG -co JPEG_QUALITY=75'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "BAND": 1,
+ "COLOR_TABLE": colorTable,
+ "MATCH_MODE": 1,
+ "OPTIONS": "COMPRESS=JPEG|JPEG_QUALITY=75",
+ "OUTPUT": outdir + "/check.tif",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdaldem",
+ "color-relief "
+ + source
+ + " "
+ + colorTable
+ + " "
+ + outdir
+ + "/check.tif -of GTiff -b 1 -nearest_color_entry -co COMPRESS=JPEG -co JPEG_QUALITY=75",
+ ],
+ )
# with additional parameter
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'BAND': 1,
- 'COLOR_TABLE': colorTable,
- 'EXTRA': '-alpha -q',
- 'OUTPUT': outdir + '/check.tif'}, context, feedback),
- ['gdaldem',
- 'color-relief ' +
- source + ' ' +
- colorTable + ' ' +
- outdir + '/check.tif -of GTiff -b 1 -alpha -q'])
-
- self.assertEqual(
- alg.getConsoleCommands({'INPUT': source + '|credential:X=Y|credential:Z=A',
- 'BAND': 1,
- 'COLOR_TABLE': colorTable,
- 'OUTPUT': outdir + '/check.tif'}, context, feedback),
- ['gdaldem',
- 'color-relief ' +
- source + ' ' +
- colorTable + ' ' +
- outdir + '/check.tif -of GTiff -b 1 --config X Y --config Z A'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "BAND": 1,
+ "COLOR_TABLE": colorTable,
+ "EXTRA": "-alpha -q",
+ "OUTPUT": outdir + "/check.tif",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdaldem",
+ "color-relief "
+ + source
+ + " "
+ + colorTable
+ + " "
+ + outdir
+ + "/check.tif -of GTiff -b 1 -alpha -q",
+ ],
+ )
+
+ self.assertEqual(
+ alg.getConsoleCommands(
+ {
+ "INPUT": source + "|credential:X=Y|credential:Z=A",
+ "BAND": 1,
+ "COLOR_TABLE": colorTable,
+ "OUTPUT": outdir + "/check.tif",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdaldem",
+ "color-relief "
+ + source
+ + " "
+ + colorTable
+ + " "
+ + outdir
+ + "/check.tif -of GTiff -b 1 --config X Y --config Z A",
+ ],
+ )
def testProximity(self):
context = QgsProcessingContext()
feedback = QgsProcessingFeedback()
- source = os.path.join(testDataPath, 'dem.tif')
+ source = os.path.join(testDataPath, "dem.tif")
alg = proximity()
alg.initAlgorithm()
with tempfile.TemporaryDirectory() as outdir:
# without NODATA value
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'BAND': 1,
- 'OUTPUT': outdir + '/check.jpg'}, context, feedback),
- ['gdal_proximity.py',
- '-srcband 1 -distunits PIXEL -ot Float32 -of JPEG ' +
- source + ' ' +
- outdir + '/check.jpg'])
+ alg.getConsoleCommands(
+ {"INPUT": source, "BAND": 1, "OUTPUT": outdir + "/check.jpg"},
+ context,
+ feedback,
+ ),
+ [
+ "gdal_proximity.py",
+ "-srcband 1 -distunits PIXEL -ot Float32 -of JPEG "
+ + source
+ + " "
+ + outdir
+ + "/check.jpg",
+ ],
+ )
# with NODATA value
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'NODATA': 9999,
- 'BAND': 2,
- 'OUTPUT': outdir + '/check.jpg'}, context, feedback),
- ['gdal_proximity.py',
- '-srcband 2 -distunits PIXEL -nodata 9999.0 -ot Float32 -of JPEG ' +
- source + ' ' +
- outdir + '/check.jpg'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "NODATA": 9999,
+ "BAND": 2,
+ "OUTPUT": outdir + "/check.jpg",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdal_proximity.py",
+ "-srcband 2 -distunits PIXEL -nodata 9999.0 -ot Float32 -of JPEG "
+ + source
+ + " "
+ + outdir
+ + "/check.jpg",
+ ],
+ )
# with "0" NODATA value
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'NODATA': 0,
- 'BAND': 1,
- 'OUTPUT': outdir + '/check.jpg'}, context, feedback),
- ['gdal_proximity.py',
- '-srcband 1 -distunits PIXEL -nodata 0.0 -ot Float32 -of JPEG ' +
- source + ' ' +
- outdir + '/check.jpg'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "NODATA": 0,
+ "BAND": 1,
+ "OUTPUT": outdir + "/check.jpg",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdal_proximity.py",
+ "-srcband 1 -distunits PIXEL -nodata 0.0 -ot Float32 -of JPEG "
+ + source
+ + " "
+ + outdir
+ + "/check.jpg",
+ ],
+ )
# additional parameters
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'BAND': 1,
- 'EXTRA': '-dstband 2 -values 3,4,12',
- 'OUTPUT': outdir + '/check.jpg'}, context, feedback),
- ['gdal_proximity.py',
- '-srcband 1 -distunits PIXEL -ot Float32 -of JPEG -dstband 2 -values 3,4,12 ' +
- source + ' ' +
- outdir + '/check.jpg'])
-
- self.assertEqual(
- alg.getConsoleCommands({'INPUT': source + '|credential:X=Y|credential:Z=A',
- 'BAND': 1,
- 'OUTPUT': outdir + '/check.jpg'}, context, feedback),
- ['gdal_proximity.py',
- '-srcband 1 -distunits PIXEL -ot Float32 -of JPEG ' +
- source + ' ' +
- outdir + '/check.jpg --config X Y --config Z A'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "BAND": 1,
+ "EXTRA": "-dstband 2 -values 3,4,12",
+ "OUTPUT": outdir + "/check.jpg",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdal_proximity.py",
+ "-srcband 1 -distunits PIXEL -ot Float32 -of JPEG -dstband 2 -values 3,4,12 "
+ + source
+ + " "
+ + outdir
+ + "/check.jpg",
+ ],
+ )
+
+ self.assertEqual(
+ alg.getConsoleCommands(
+ {
+ "INPUT": source + "|credential:X=Y|credential:Z=A",
+ "BAND": 1,
+ "OUTPUT": outdir + "/check.jpg",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdal_proximity.py",
+ "-srcband 1 -distunits PIXEL -ot Float32 -of JPEG "
+ + source
+ + " "
+ + outdir
+ + "/check.jpg --config X Y --config Z A",
+ ],
+ )
def testRasterize(self):
context = QgsProcessingContext()
feedback = QgsProcessingFeedback()
- source = os.path.join(testDataPath, 'polys.gml')
- sourceZ = os.path.join(testDataPath, 'pointsz.gml')
- extent4326 = QgsReferencedRectangle(QgsRectangle(-1, -3, 10, 6), QgsCoordinateReferenceSystem('EPSG:4326'))
- extent3857 = QgsReferencedRectangle(QgsRectangle(-111319.491, -334111.171, 1113194.908, 669141.057), QgsCoordinateReferenceSystem('EPSG:3857'))
+ source = os.path.join(testDataPath, "polys.gml")
+ sourceZ = os.path.join(testDataPath, "pointsz.gml")
+ extent4326 = QgsReferencedRectangle(
+ QgsRectangle(-1, -3, 10, 6), QgsCoordinateReferenceSystem("EPSG:4326")
+ )
+ extent3857 = QgsReferencedRectangle(
+ QgsRectangle(-111319.491, -334111.171, 1113194.908, 669141.057),
+ QgsCoordinateReferenceSystem("EPSG:3857"),
+ )
alg = rasterize()
alg.initAlgorithm()
with tempfile.TemporaryDirectory() as outdir:
# with no NODATA value
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'FIELD': 'id',
- 'OUTPUT': outdir + '/check.jpg'}, context, feedback),
- ['gdal_rasterize',
- '-l polys2 -a id -ts 0.0 0.0 -ot Float32 -of JPEG ' +
- source + ' ' +
- outdir + '/check.jpg'])
+ alg.getConsoleCommands(
+ {"INPUT": source, "FIELD": "id", "OUTPUT": outdir + "/check.jpg"},
+ context,
+ feedback,
+ ),
+ [
+ "gdal_rasterize",
+ "-l polys2 -a id -ts 0.0 0.0 -ot Float32 -of JPEG "
+ + source
+ + " "
+ + outdir
+ + "/check.jpg",
+ ],
+ )
# with NODATA value
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'NODATA': 9999,
- 'FIELD': 'id',
- 'OUTPUT': outdir + '/check.jpg'}, context, feedback),
- ['gdal_rasterize',
- '-l polys2 -a id -ts 0.0 0.0 -a_nodata 9999.0 -ot Float32 -of JPEG ' +
- source + ' ' +
- outdir + '/check.jpg'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "NODATA": 9999,
+ "FIELD": "id",
+ "OUTPUT": outdir + "/check.jpg",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdal_rasterize",
+ "-l polys2 -a id -ts 0.0 0.0 -a_nodata 9999.0 -ot Float32 -of JPEG "
+ + source
+ + " "
+ + outdir
+ + "/check.jpg",
+ ],
+ )
# with "0" INIT value
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'INIT': 0,
- 'FIELD': 'id',
- 'OUTPUT': outdir + '/check.jpg'}, context, feedback),
- ['gdal_rasterize',
- '-l polys2 -a id -ts 0.0 0.0 -init 0.0 -ot Float32 -of JPEG ' +
- source + ' ' +
- outdir + '/check.jpg'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "INIT": 0,
+ "FIELD": "id",
+ "OUTPUT": outdir + "/check.jpg",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdal_rasterize",
+ "-l polys2 -a id -ts 0.0 0.0 -init 0.0 -ot Float32 -of JPEG "
+ + source
+ + " "
+ + outdir
+ + "/check.jpg",
+ ],
+ )
# with "0" NODATA value
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'NODATA': 0,
- 'FIELD': 'id',
- 'OUTPUT': outdir + '/check.jpg'}, context, feedback),
- ['gdal_rasterize',
- '-l polys2 -a id -ts 0.0 0.0 -a_nodata 0.0 -ot Float32 -of JPEG ' +
- source + ' ' +
- outdir + '/check.jpg'])
-
- self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'FIELD': 'id',
- 'EXTRA': '-at -add',
- 'OUTPUT': outdir + '/check.jpg'}, context, feedback),
- ['gdal_rasterize',
- '-l polys2 -a id -ts 0.0 0.0 -ot Float32 -of JPEG -at -add ' +
- source + ' ' +
- outdir + '/check.jpg'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "NODATA": 0,
+ "FIELD": "id",
+ "OUTPUT": outdir + "/check.jpg",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdal_rasterize",
+ "-l polys2 -a id -ts 0.0 0.0 -a_nodata 0.0 -ot Float32 -of JPEG "
+ + source
+ + " "
+ + outdir
+ + "/check.jpg",
+ ],
+ )
+
+ self.assertEqual(
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "FIELD": "id",
+ "EXTRA": "-at -add",
+ "OUTPUT": outdir + "/check.jpg",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdal_rasterize",
+ "-l polys2 -a id -ts 0.0 0.0 -ot Float32 -of JPEG -at -add "
+ + source
+ + " "
+ + outdir
+ + "/check.jpg",
+ ],
+ )
# use_Z selected with no field
self.assertEqual(
- alg.getConsoleCommands({'INPUT': sourceZ,
- 'USE_Z': True,
- 'OUTPUT': outdir + '/check.jpg'}, context, feedback),
- ['gdal_rasterize',
- '-l pointsz -3d -ts 0.0 0.0 -ot Float32 -of JPEG ' +
- sourceZ + ' ' +
- outdir + '/check.jpg'])
+ alg.getConsoleCommands(
+ {"INPUT": sourceZ, "USE_Z": True, "OUTPUT": outdir + "/check.jpg"},
+ context,
+ feedback,
+ ),
+ [
+ "gdal_rasterize",
+ "-l pointsz -3d -ts 0.0 0.0 -ot Float32 -of JPEG "
+ + sourceZ
+ + " "
+ + outdir
+ + "/check.jpg",
+ ],
+ )
# use_Z selected with field indicated (should prefer use_Z)
self.assertEqual(
- alg.getConsoleCommands({'INPUT': sourceZ,
- 'FIELD': 'elev',
- 'USE_Z': True,
- 'OUTPUT': outdir + '/check.jpg'}, context, feedback),
- ['gdal_rasterize',
- '-l pointsz -3d -ts 0.0 0.0 -ot Float32 -of JPEG ' +
- sourceZ + ' ' +
- outdir + '/check.jpg'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": sourceZ,
+ "FIELD": "elev",
+ "USE_Z": True,
+ "OUTPUT": outdir + "/check.jpg",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdal_rasterize",
+ "-l pointsz -3d -ts 0.0 0.0 -ot Float32 -of JPEG "
+ + sourceZ
+ + " "
+ + outdir
+ + "/check.jpg",
+ ],
+ )
# with EXTENT in the same CRS as the input layer source
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'FIELD': 'id',
- 'EXTENT': extent4326,
- 'OUTPUT': outdir + '/check.jpg'}, context, feedback),
- ['gdal_rasterize',
- '-l polys2 -a id -ts 0.0 0.0 -te -1.0 -3.0 10.0 6.0 -ot Float32 -of JPEG ' +
- source + ' ' +
- outdir + '/check.jpg'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "FIELD": "id",
+ "EXTENT": extent4326,
+ "OUTPUT": outdir + "/check.jpg",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdal_rasterize",
+ "-l polys2 -a id -ts 0.0 0.0 -te -1.0 -3.0 10.0 6.0 -ot Float32 -of JPEG "
+ + source
+ + " "
+ + outdir
+ + "/check.jpg",
+ ],
+ )
# with EXTENT in a different CRS than that of the input layer source
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'FIELD': 'id',
- 'EXTENT': extent3857,
- 'OUTPUT': outdir + '/check.jpg'}, context, feedback),
- ['gdal_rasterize',
- '-l polys2 -a id -ts 0.0 0.0 -te -1.000000001857055 -2.9999999963940835 10.000000000604244 5.99999999960471 -ot Float32 -of JPEG ' +
- source + ' ' +
- outdir + '/check.jpg'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "FIELD": "id",
+ "EXTENT": extent3857,
+ "OUTPUT": outdir + "/check.jpg",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdal_rasterize",
+ "-l polys2 -a id -ts 0.0 0.0 -te -1.000000001857055 -2.9999999963940835 10.000000000604244 5.99999999960471 -ot Float32 -of JPEG "
+ + source
+ + " "
+ + outdir
+ + "/check.jpg",
+ ],
+ )
if GdalUtils.version() >= 3070000:
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source + '|option:X_POSSIBLE_NAMES=geom_x|option:Y_POSSIBLE_NAMES=geom_y',
- 'FIELD': 'id',
- 'OUTPUT': outdir + '/check.jpg'}, context, feedback),
- ['gdal_rasterize',
- '-l polys2 -a id -ts 0.0 0.0 -ot Float32 -of JPEG -oo X_POSSIBLE_NAMES=geom_x -oo Y_POSSIBLE_NAMES=geom_y ' +
- source + ' ' +
- outdir + '/check.jpg'])
-
- self.assertEqual(
- alg.getConsoleCommands({'INPUT': source + '|credential:X=Y|credential:Z=A',
- 'FIELD': 'id',
- 'OUTPUT': outdir + '/check.jpg'}, context, feedback),
- ['gdal_rasterize',
- '-l polys2 -a id -ts 0.0 0.0 -ot Float32 -of JPEG --config X Y --config Z A ' +
- source + ' ' +
- outdir + '/check.jpg'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source
+ + "|option:X_POSSIBLE_NAMES=geom_x|option:Y_POSSIBLE_NAMES=geom_y",
+ "FIELD": "id",
+ "OUTPUT": outdir + "/check.jpg",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdal_rasterize",
+ "-l polys2 -a id -ts 0.0 0.0 -ot Float32 -of JPEG -oo X_POSSIBLE_NAMES=geom_x -oo Y_POSSIBLE_NAMES=geom_y "
+ + source
+ + " "
+ + outdir
+ + "/check.jpg",
+ ],
+ )
+
+ self.assertEqual(
+ alg.getConsoleCommands(
+ {
+ "INPUT": source + "|credential:X=Y|credential:Z=A",
+ "FIELD": "id",
+ "OUTPUT": outdir + "/check.jpg",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdal_rasterize",
+ "-l polys2 -a id -ts 0.0 0.0 -ot Float32 -of JPEG --config X Y --config Z A "
+ + source
+ + " "
+ + outdir
+ + "/check.jpg",
+ ],
+ )
def testRasterizeOver(self):
context = QgsProcessingContext()
feedback = QgsProcessingFeedback()
- raster = os.path.join(testDataPath, 'dem.tif')
- vector = os.path.join(testDataPath, 'polys.gml')
+ raster = os.path.join(testDataPath, "dem.tif")
+ vector = os.path.join(testDataPath, "polys.gml")
alg = rasterize_over()
alg.initAlgorithm()
with tempfile.TemporaryDirectory() as outdir:
self.assertEqual(
- alg.getConsoleCommands({'INPUT': vector,
- 'FIELD': 'id',
- 'INPUT_RASTER': raster}, context, feedback),
- ['gdal_rasterize',
- '-l polys2 -a id ' +
- vector + ' ' + raster])
-
- self.assertEqual(
- alg.getConsoleCommands({'INPUT': vector,
- 'FIELD': 'id',
- 'ADD': True,
- 'INPUT_RASTER': raster}, context, feedback),
- ['gdal_rasterize',
- '-l polys2 -a id -add ' +
- vector + ' ' + raster])
-
- self.assertEqual(
- alg.getConsoleCommands({'INPUT': vector,
- 'FIELD': 'id',
- 'EXTRA': '-i',
- 'INPUT_RASTER': raster}, context, feedback),
- ['gdal_rasterize',
- '-l polys2 -a id -i ' +
- vector + ' ' + raster])
+ alg.getConsoleCommands(
+ {"INPUT": vector, "FIELD": "id", "INPUT_RASTER": raster},
+ context,
+ feedback,
+ ),
+ ["gdal_rasterize", "-l polys2 -a id " + vector + " " + raster],
+ )
+
+ self.assertEqual(
+ alg.getConsoleCommands(
+ {
+ "INPUT": vector,
+ "FIELD": "id",
+ "ADD": True,
+ "INPUT_RASTER": raster,
+ },
+ context,
+ feedback,
+ ),
+ ["gdal_rasterize", "-l polys2 -a id -add " + vector + " " + raster],
+ )
+
+ self.assertEqual(
+ alg.getConsoleCommands(
+ {
+ "INPUT": vector,
+ "FIELD": "id",
+ "EXTRA": "-i",
+ "INPUT_RASTER": raster,
+ },
+ context,
+ feedback,
+ ),
+ ["gdal_rasterize", "-l polys2 -a id -i " + vector + " " + raster],
+ )
if GdalUtils.version() >= 3070000:
self.assertEqual(
- alg.getConsoleCommands({'INPUT': vector + '|option:X_POSSIBLE_NAMES=geom_x|option:Y_POSSIBLE_NAMES=geom_y',
- 'FIELD': 'id',
- 'INPUT_RASTER': raster}, context, feedback),
- ['gdal_rasterize',
- '-l polys2 -a id -oo X_POSSIBLE_NAMES=geom_x -oo Y_POSSIBLE_NAMES=geom_y ' +
- vector + ' ' + raster])
-
- self.assertEqual(
- alg.getConsoleCommands({'INPUT': vector + '|credential:X=Y|credential:Z=A',
- 'FIELD': 'id',
- 'INPUT_RASTER': raster}, context, feedback),
- ['gdal_rasterize',
- '-l polys2 -a id --config X Y --config Z A ' +
- vector + ' ' + raster])
+ alg.getConsoleCommands(
+ {
+ "INPUT": vector
+ + "|option:X_POSSIBLE_NAMES=geom_x|option:Y_POSSIBLE_NAMES=geom_y",
+ "FIELD": "id",
+ "INPUT_RASTER": raster,
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdal_rasterize",
+ "-l polys2 -a id -oo X_POSSIBLE_NAMES=geom_x -oo Y_POSSIBLE_NAMES=geom_y "
+ + vector
+ + " "
+ + raster,
+ ],
+ )
+
+ self.assertEqual(
+ alg.getConsoleCommands(
+ {
+ "INPUT": vector + "|credential:X=Y|credential:Z=A",
+ "FIELD": "id",
+ "INPUT_RASTER": raster,
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdal_rasterize",
+ "-l polys2 -a id --config X Y --config Z A "
+ + vector
+ + " "
+ + raster,
+ ],
+ )
def testRasterizeOverFixed(self):
context = QgsProcessingContext()
feedback = QgsProcessingFeedback()
- raster = os.path.join(testDataPath, 'dem.tif')
- vector = os.path.join(testDataPath, 'polys.gml')
+ raster = os.path.join(testDataPath, "dem.tif")
+ vector = os.path.join(testDataPath, "polys.gml")
alg = rasterize_over_fixed_value()
alg.initAlgorithm()
with tempfile.TemporaryDirectory() as outdir:
self.assertEqual(
- alg.getConsoleCommands({'INPUT': vector,
- 'BURN': 100,
- 'INPUT_RASTER': raster}, context, feedback),
- ['gdal_rasterize',
- '-l polys2 -burn 100.0 ' +
- vector + ' ' + raster])
-
- self.assertEqual(
- alg.getConsoleCommands({'INPUT': vector,
- 'BURN': 100,
- 'ADD': True,
- 'INPUT_RASTER': raster}, context, feedback),
- ['gdal_rasterize',
- '-l polys2 -burn 100.0 -add ' +
- vector + ' ' + raster])
-
- self.assertEqual(
- alg.getConsoleCommands({'INPUT': vector,
- 'BURN': 100,
- 'EXTRA': '-i',
- 'INPUT_RASTER': raster}, context, feedback),
- ['gdal_rasterize',
- '-l polys2 -burn 100.0 -i ' +
- vector + ' ' + raster])
+ alg.getConsoleCommands(
+ {"INPUT": vector, "BURN": 100, "INPUT_RASTER": raster},
+ context,
+ feedback,
+ ),
+ ["gdal_rasterize", "-l polys2 -burn 100.0 " + vector + " " + raster],
+ )
+
+ self.assertEqual(
+ alg.getConsoleCommands(
+ {"INPUT": vector, "BURN": 100, "ADD": True, "INPUT_RASTER": raster},
+ context,
+ feedback,
+ ),
+ [
+ "gdal_rasterize",
+ "-l polys2 -burn 100.0 -add " + vector + " " + raster,
+ ],
+ )
+
+ self.assertEqual(
+ alg.getConsoleCommands(
+ {
+ "INPUT": vector,
+ "BURN": 100,
+ "EXTRA": "-i",
+ "INPUT_RASTER": raster,
+ },
+ context,
+ feedback,
+ ),
+ ["gdal_rasterize", "-l polys2 -burn 100.0 -i " + vector + " " + raster],
+ )
if GdalUtils.version() >= 3070000:
self.assertEqual(
- alg.getConsoleCommands({'INPUT': vector + '|option:X_POSSIBLE_NAMES=geom_x|option:Y_POSSIBLE_NAMES=geom_y',
- 'BURN': 100,
- 'INPUT_RASTER': raster}, context, feedback),
- ['gdal_rasterize',
- '-l polys2 -burn 100.0 -oo X_POSSIBLE_NAMES=geom_x -oo Y_POSSIBLE_NAMES=geom_y ' +
- vector + ' ' + raster])
-
- self.assertEqual(
- alg.getConsoleCommands({'INPUT': vector + '|credential:X=Y|credential:Z=A',
- 'BURN': 100,
- 'INPUT_RASTER': raster}, context, feedback),
- ['gdal_rasterize',
- '-l polys2 -burn 100.0 --config X Y --config Z A ' +
- vector + ' ' + raster])
+ alg.getConsoleCommands(
+ {
+ "INPUT": vector
+ + "|option:X_POSSIBLE_NAMES=geom_x|option:Y_POSSIBLE_NAMES=geom_y",
+ "BURN": 100,
+ "INPUT_RASTER": raster,
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdal_rasterize",
+ "-l polys2 -burn 100.0 -oo X_POSSIBLE_NAMES=geom_x -oo Y_POSSIBLE_NAMES=geom_y "
+ + vector
+ + " "
+ + raster,
+ ],
+ )
+
+ self.assertEqual(
+ alg.getConsoleCommands(
+ {
+ "INPUT": vector + "|credential:X=Y|credential:Z=A",
+ "BURN": 100,
+ "INPUT_RASTER": raster,
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdal_rasterize",
+ "-l polys2 -burn 100.0 --config X Y --config Z A "
+ + vector
+ + " "
+ + raster,
+ ],
+ )
def testRasterizeOverRun(self):
# Check that rasterize over tools update QgsRasterLayer
context = QgsProcessingContext()
feedback = QgsProcessingFeedback()
- source_vector = os.path.join(testDataPath, 'rasterize_zones.gml')
- source_raster = os.path.join(testDataPath, 'dem.tif')
+ source_vector = os.path.join(testDataPath, "rasterize_zones.gml")
+ source_raster = os.path.join(testDataPath, "dem.tif")
with tempfile.TemporaryDirectory() as outdir:
# fixed value
alg = rasterize_over_fixed_value()
alg.initAlgorithm()
- test_dem = os.path.join(outdir, 'rasterize-fixed.tif')
+ test_dem = os.path.join(outdir, "rasterize-fixed.tif")
shutil.copy(source_raster, test_dem)
self.assertTrue(os.path.exists(test_dem))
- layer = QgsRasterLayer(test_dem, 'test')
+ layer = QgsRasterLayer(test_dem, "test")
self.assertTrue(layer.isValid())
val, ok = layer.dataProvider().sample(QgsPointXY(18.68704, 45.79568), 1)
self.assertEqual(val, 172.2267303466797)
project = QgsProject()
- project.setFileName(os.path.join(outdir, 'rasterize-fixed.qgs'))
+ project.setFileName(os.path.join(outdir, "rasterize-fixed.qgs"))
project.addMapLayer(layer)
self.assertEqual(project.count(), 1)
context.setProject(project)
- alg.run({'INPUT': source_vector,
- 'INPUT_RASTER': test_dem,
- 'BURN': 200
- }, context, feedback)
+ alg.run(
+ {"INPUT": source_vector, "INPUT_RASTER": test_dem, "BURN": 200},
+ context,
+ feedback,
+ )
val, ok = layer.dataProvider().sample(QgsPointXY(18.68704, 45.79568), 1)
self.assertTrue(ok)
@@ -2159,27 +3762,28 @@ def testRasterizeOverRun(self):
alg = rasterize_over()
alg.initAlgorithm()
- test_dem = os.path.join(outdir, 'rasterize-over.tif')
+ test_dem = os.path.join(outdir, "rasterize-over.tif")
shutil.copy(source_raster, test_dem)
self.assertTrue(os.path.exists(test_dem))
- layer = QgsRasterLayer(test_dem, 'test')
+ layer = QgsRasterLayer(test_dem, "test")
self.assertTrue(layer.isValid())
val, ok = layer.dataProvider().sample(QgsPointXY(18.68704, 45.79568), 1)
self.assertEqual(val, 172.2267303466797)
project = QgsProject()
- project.setFileName(os.path.join(outdir, 'rasterize-over.qgs'))
+ project.setFileName(os.path.join(outdir, "rasterize-over.qgs"))
project.addMapLayer(layer)
self.assertEqual(project.count(), 1)
context.setProject(project)
- alg.run({'INPUT': source_vector,
- 'INPUT_RASTER': test_dem,
- 'FIELD': 'value'
- }, context, feedback)
+ alg.run(
+ {"INPUT": source_vector, "INPUT_RASTER": test_dem, "FIELD": "value"},
+ context,
+ feedback,
+ )
val, ok = layer.dataProvider().sample(QgsPointXY(18.68704, 45.79568), 1)
self.assertTrue(ok)
@@ -2188,553 +3792,1016 @@ def testRasterizeOverRun(self):
def testRetile(self):
context = QgsProcessingContext()
feedback = QgsProcessingFeedback()
- source = os.path.join(testDataPath, 'dem.tif')
+ source = os.path.join(testDataPath, "dem.tif")
alg = retile()
alg.initAlgorithm()
with tempfile.TemporaryDirectory() as outdir:
self.assertEqual(
- alg.getConsoleCommands({'INPUT': [source],
- 'OUTPUT': outdir}, context, feedback),
- ['gdal_retile.py',
- f'-ps 256 256 -overlap 0 -levels 1 -r near -ot Float32 -targetDir {outdir} ' +
- source])
+ alg.getConsoleCommands(
+ {"INPUT": [source], "OUTPUT": outdir}, context, feedback
+ ),
+ [
+ "gdal_retile.py",
+ f"-ps 256 256 -overlap 0 -levels 1 -r near -ot Float32 -targetDir {outdir} "
+ + source,
+ ],
+ )
# with input srs
self.assertEqual(
- alg.getConsoleCommands({'INPUT': [source],
- 'SOURCE_CRS': 'EPSG:3111',
- 'OUTPUT': outdir}, context, feedback),
- ['gdal_retile.py',
- f'-ps 256 256 -overlap 0 -levels 1 -s_srs EPSG:3111 -r near -ot Float32 -targetDir {outdir} {source}'
- ])
+ alg.getConsoleCommands(
+ {"INPUT": [source], "SOURCE_CRS": "EPSG:3111", "OUTPUT": outdir},
+ context,
+ feedback,
+ ),
+ [
+ "gdal_retile.py",
+ f"-ps 256 256 -overlap 0 -levels 1 -s_srs EPSG:3111 -r near -ot Float32 -targetDir {outdir} {source}",
+ ],
+ )
# with target using proj string
- custom_crs = 'proj4: +proj=utm +zone=36 +south +a=6378249.145 +b=6356514.966398753 +towgs84=-143,-90,-294,0,0,0,0 +units=m +no_defs'
- self.assertEqual(
- alg.getConsoleCommands({'INPUT': [source],
- 'SOURCE_CRS': custom_crs,
- 'OUTPUT': outdir}, context, feedback),
- ['gdal_retile.py',
- f'-ps 256 256 -overlap 0 -levels 1 -s_srs EPSG:20936 -r near -ot Float32 -targetDir {outdir} {source}'
- ])
+ custom_crs = "proj4: +proj=utm +zone=36 +south +a=6378249.145 +b=6356514.966398753 +towgs84=-143,-90,-294,0,0,0,0 +units=m +no_defs"
+ self.assertEqual(
+ alg.getConsoleCommands(
+ {"INPUT": [source], "SOURCE_CRS": custom_crs, "OUTPUT": outdir},
+ context,
+ feedback,
+ ),
+ [
+ "gdal_retile.py",
+ f"-ps 256 256 -overlap 0 -levels 1 -s_srs EPSG:20936 -r near -ot Float32 -targetDir {outdir} {source}",
+ ],
+ )
# with target using custom projection
- custom_crs, expected_crs_string = self.get_param_value_and_expected_string_for_custom_crs('+proj=utm +zone=36 +south +a=63785 +b=6357 +towgs84=-143,-90,-294,0,0,0,0 +units=m +no_defs')
- self.assertEqual(
- alg.getConsoleCommands({'INPUT': [source],
- 'SOURCE_CRS': custom_crs,
- 'OUTPUT': outdir}, context, feedback),
- ['gdal_retile.py',
- f'-ps 256 256 -overlap 0 -levels 1 -s_srs "{expected_crs_string}" -r near -ot Float32 -targetDir {outdir} {source}'
- ])
+ custom_crs, expected_crs_string = (
+ self.get_param_value_and_expected_string_for_custom_crs(
+ "+proj=utm +zone=36 +south +a=63785 +b=6357 +towgs84=-143,-90,-294,0,0,0,0 +units=m +no_defs"
+ )
+ )
+ self.assertEqual(
+ alg.getConsoleCommands(
+ {"INPUT": [source], "SOURCE_CRS": custom_crs, "OUTPUT": outdir},
+ context,
+ feedback,
+ ),
+ [
+ "gdal_retile.py",
+ f'-ps 256 256 -overlap 0 -levels 1 -s_srs "{expected_crs_string}" -r near -ot Float32 -targetDir {outdir} {source}',
+ ],
+ )
# with non-EPSG crs code
self.assertEqual(
- alg.getConsoleCommands({'INPUT': [source],
- 'SOURCE_CRS': 'POSTGIS:3111',
- 'OUTPUT': outdir}, context, feedback),
- ['gdal_retile.py',
- f'-ps 256 256 -overlap 0 -levels 1 -s_srs EPSG:3111 -r near -ot Float32 -targetDir {outdir} {source}'
- ])
-
- self.assertEqual(
- alg.getConsoleCommands({'INPUT': [source],
- 'OUTPUT_CSV': 'out.csv',
- 'DELIMITER': '',
- 'OUTPUT': outdir}, context, feedback),
- ['gdal_retile.py',
- f'-ps 256 256 -overlap 0 -levels 1 -r near -ot Float32 -csv out.csv -targetDir {outdir} ' +
- source])
-
- self.assertEqual(
- alg.getConsoleCommands({'INPUT': [source],
- 'OUTPUT_CSV': 'out.csv',
- 'DELIMITER': ';',
- 'OUTPUT': outdir}, context, feedback),
- ['gdal_retile.py',
- f'-ps 256 256 -overlap 0 -levels 1 -r near -ot Float32 -csv out.csv -csvDelim ";" -targetDir {outdir} ' +
- source])
+ alg.getConsoleCommands(
+ {"INPUT": [source], "SOURCE_CRS": "POSTGIS:3111", "OUTPUT": outdir},
+ context,
+ feedback,
+ ),
+ [
+ "gdal_retile.py",
+ f"-ps 256 256 -overlap 0 -levels 1 -s_srs EPSG:3111 -r near -ot Float32 -targetDir {outdir} {source}",
+ ],
+ )
+
+ self.assertEqual(
+ alg.getConsoleCommands(
+ {
+ "INPUT": [source],
+ "OUTPUT_CSV": "out.csv",
+ "DELIMITER": "",
+ "OUTPUT": outdir,
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdal_retile.py",
+ f"-ps 256 256 -overlap 0 -levels 1 -r near -ot Float32 -csv out.csv -targetDir {outdir} "
+ + source,
+ ],
+ )
+
+ self.assertEqual(
+ alg.getConsoleCommands(
+ {
+ "INPUT": [source],
+ "OUTPUT_CSV": "out.csv",
+ "DELIMITER": ";",
+ "OUTPUT": outdir,
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdal_retile.py",
+ f'-ps 256 256 -overlap 0 -levels 1 -r near -ot Float32 -csv out.csv -csvDelim ";" -targetDir {outdir} '
+ + source,
+ ],
+ )
# additional parameters
self.assertEqual(
- alg.getConsoleCommands({'INPUT': [source],
- 'EXTRA': '-v -tileIndex tindex.shp',
- 'OUTPUT': outdir}, context, feedback),
- ['gdal_retile.py',
- f'-ps 256 256 -overlap 0 -levels 1 -r near -ot Float32 -v -tileIndex tindex.shp -targetDir {outdir} ' +
- source])
-
- self.assertEqual(
- alg.getConsoleCommands({'INPUT': [source],
- 'ONLY_PYRAMIDS': True,
- 'OUTPUT': outdir}, context, feedback),
- ['gdal_retile.py',
- f'-ps 256 256 -overlap 0 -levels 1 -r near -ot Float32 -pyramidOnly -targetDir {outdir} ' +
- source])
-
- self.assertEqual(
- alg.getConsoleCommands({'INPUT': [source],
- 'DIR_FOR_ROW': True,
- 'OUTPUT': outdir}, context, feedback),
- ['gdal_retile.py',
- f'-ps 256 256 -overlap 0 -levels 1 -r near -ot Float32 -useDirForEachRow -targetDir {outdir} ' +
- source])
-
- self.assertEqual(
- alg.getConsoleCommands({'INPUT': [source + '|credential:X=Y|credential:Z=A'],
- 'DIR_FOR_ROW': True,
- 'OUTPUT': outdir}, context, feedback),
- ['gdal_retile.py',
- f'-ps 256 256 -overlap 0 -levels 1 -r near -ot Float32 -useDirForEachRow -targetDir {outdir} ' +
- source + ' --config X Y --config Z A'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": [source],
+ "EXTRA": "-v -tileIndex tindex.shp",
+ "OUTPUT": outdir,
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdal_retile.py",
+ f"-ps 256 256 -overlap 0 -levels 1 -r near -ot Float32 -v -tileIndex tindex.shp -targetDir {outdir} "
+ + source,
+ ],
+ )
+
+ self.assertEqual(
+ alg.getConsoleCommands(
+ {"INPUT": [source], "ONLY_PYRAMIDS": True, "OUTPUT": outdir},
+ context,
+ feedback,
+ ),
+ [
+ "gdal_retile.py",
+ f"-ps 256 256 -overlap 0 -levels 1 -r near -ot Float32 -pyramidOnly -targetDir {outdir} "
+ + source,
+ ],
+ )
+
+ self.assertEqual(
+ alg.getConsoleCommands(
+ {"INPUT": [source], "DIR_FOR_ROW": True, "OUTPUT": outdir},
+ context,
+ feedback,
+ ),
+ [
+ "gdal_retile.py",
+ f"-ps 256 256 -overlap 0 -levels 1 -r near -ot Float32 -useDirForEachRow -targetDir {outdir} "
+ + source,
+ ],
+ )
+
+ self.assertEqual(
+ alg.getConsoleCommands(
+ {
+ "INPUT": [source + "|credential:X=Y|credential:Z=A"],
+ "DIR_FOR_ROW": True,
+ "OUTPUT": outdir,
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdal_retile.py",
+ f"-ps 256 256 -overlap 0 -levels 1 -r near -ot Float32 -useDirForEachRow -targetDir {outdir} "
+ + source
+ + " --config X Y --config Z A",
+ ],
+ )
def testWarp(self):
context = QgsProcessingContext()
feedback = QgsProcessingFeedback()
- source = os.path.join(testDataPath, 'dem.tif')
+ source = os.path.join(testDataPath, "dem.tif")
alg = warp()
alg.initAlgorithm()
with tempfile.TemporaryDirectory() as outdir:
# with no NODATA value
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'SOURCE_CRS': 'EPSG:3111',
- 'OUTPUT': outdir + '/check.jpg'}, context, feedback),
- ['gdalwarp',
- '-overwrite -s_srs EPSG:3111 -r near -of JPEG ' +
- source + ' ' +
- outdir + '/check.jpg'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "SOURCE_CRS": "EPSG:3111",
+ "OUTPUT": outdir + "/check.jpg",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdalwarp",
+ "-overwrite -s_srs EPSG:3111 -r near -of JPEG "
+ + source
+ + " "
+ + outdir
+ + "/check.jpg",
+ ],
+ )
# with None NODATA value
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'NODATA': None,
- 'SOURCE_CRS': 'EPSG:3111',
- 'OUTPUT': outdir + '/check.jpg'}, context, feedback),
- ['gdalwarp',
- '-overwrite -s_srs EPSG:3111 -r near -of JPEG ' +
- source + ' ' +
- outdir + '/check.jpg'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "NODATA": None,
+ "SOURCE_CRS": "EPSG:3111",
+ "OUTPUT": outdir + "/check.jpg",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdalwarp",
+ "-overwrite -s_srs EPSG:3111 -r near -of JPEG "
+ + source
+ + " "
+ + outdir
+ + "/check.jpg",
+ ],
+ )
# with NODATA value
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'NODATA': 9999,
- 'SOURCE_CRS': 'EPSG:3111',
- 'OUTPUT': outdir + '/check.jpg'}, context, feedback),
- ['gdalwarp',
- '-overwrite -s_srs EPSG:3111 -dstnodata 9999.0 -r near -of JPEG ' +
- source + ' ' +
- outdir + '/check.jpg'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "NODATA": 9999,
+ "SOURCE_CRS": "EPSG:3111",
+ "OUTPUT": outdir + "/check.jpg",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdalwarp",
+ "-overwrite -s_srs EPSG:3111 -dstnodata 9999.0 -r near -of JPEG "
+ + source
+ + " "
+ + outdir
+ + "/check.jpg",
+ ],
+ )
# with "0" NODATA value
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'NODATA': 0,
- 'SOURCE_CRS': 'EPSG:3111',
- 'OUTPUT': outdir + '/check.jpg'}, context, feedback),
- ['gdalwarp',
- '-overwrite -s_srs EPSG:3111 -dstnodata 0.0 -r near -of JPEG ' +
- source + ' ' +
- outdir + '/check.jpg'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "NODATA": 0,
+ "SOURCE_CRS": "EPSG:3111",
+ "OUTPUT": outdir + "/check.jpg",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdalwarp",
+ "-overwrite -s_srs EPSG:3111 -dstnodata 0.0 -r near -of JPEG "
+ + source
+ + " "
+ + outdir
+ + "/check.jpg",
+ ],
+ )
# with "0" NODATA value and custom data type
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'NODATA': 0,
- 'DATA_TYPE': 6,
- 'SOURCE_CRS': 'EPSG:3111',
- 'OUTPUT': outdir + '/check.jpg'}, context, feedback),
- ['gdalwarp',
- '-overwrite -s_srs EPSG:3111 -dstnodata 0.0 -r near -ot Float32 -of JPEG ' +
- source + ' ' +
- outdir + '/check.jpg'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "NODATA": 0,
+ "DATA_TYPE": 6,
+ "SOURCE_CRS": "EPSG:3111",
+ "OUTPUT": outdir + "/check.jpg",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdalwarp",
+ "-overwrite -s_srs EPSG:3111 -dstnodata 0.0 -r near -ot Float32 -of JPEG "
+ + source
+ + " "
+ + outdir
+ + "/check.jpg",
+ ],
+ )
# with target using EPSG
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'SOURCE_CRS': 'EPSG:3111',
- 'TARGET_CRS': 'EPSG:4326',
- 'OUTPUT': outdir + '/check.jpg'}, context, feedback),
- ['gdalwarp',
- '-overwrite -s_srs EPSG:3111 -t_srs EPSG:4326 -r near -of JPEG ' +
- source + ' ' +
- outdir + '/check.jpg'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "SOURCE_CRS": "EPSG:3111",
+ "TARGET_CRS": "EPSG:4326",
+ "OUTPUT": outdir + "/check.jpg",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdalwarp",
+ "-overwrite -s_srs EPSG:3111 -t_srs EPSG:4326 -r near -of JPEG "
+ + source
+ + " "
+ + outdir
+ + "/check.jpg",
+ ],
+ )
# with target using proj string
- custom_crs = 'proj4: +proj=utm +zone=36 +south +a=6378249.145 +b=6356514.966398753 +towgs84=-143,-90,-294,0,0,0,0 +units=m +no_defs'
- self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'SOURCE_CRS': custom_crs,
- 'TARGET_CRS': custom_crs,
- 'OUTPUT': outdir + '/check.jpg'}, context, feedback),
- ['gdalwarp',
- '-overwrite -s_srs EPSG:20936 -t_srs EPSG:20936 -r near -of JPEG ' +
- source + ' ' +
- outdir + '/check.jpg'])
+ custom_crs = "proj4: +proj=utm +zone=36 +south +a=6378249.145 +b=6356514.966398753 +towgs84=-143,-90,-294,0,0,0,0 +units=m +no_defs"
+ self.assertEqual(
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "SOURCE_CRS": custom_crs,
+ "TARGET_CRS": custom_crs,
+ "OUTPUT": outdir + "/check.jpg",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdalwarp",
+ "-overwrite -s_srs EPSG:20936 -t_srs EPSG:20936 -r near -of JPEG "
+ + source
+ + " "
+ + outdir
+ + "/check.jpg",
+ ],
+ )
# with target using custom projection
- custom_crs, expected_crs_string = self.get_param_value_and_expected_string_for_custom_crs('+proj=utm +zone=36 +south +a=63785 +b=6357 +towgs84=-143,-90,-294,0,0,0,0 +units=m +no_defs')
- self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'SOURCE_CRS': custom_crs,
- 'TARGET_CRS': custom_crs,
- 'OUTPUT': outdir + '/check.jpg'}, context, feedback),
- ['gdalwarp',
- f'-overwrite -s_srs "{expected_crs_string}" -t_srs "{expected_crs_string}" -r near -of JPEG ' +
- source + ' ' +
- outdir + '/check.jpg'])
+ custom_crs, expected_crs_string = (
+ self.get_param_value_and_expected_string_for_custom_crs(
+ "+proj=utm +zone=36 +south +a=63785 +b=6357 +towgs84=-143,-90,-294,0,0,0,0 +units=m +no_defs"
+ )
+ )
+ self.assertEqual(
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "SOURCE_CRS": custom_crs,
+ "TARGET_CRS": custom_crs,
+ "OUTPUT": outdir + "/check.jpg",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdalwarp",
+ f'-overwrite -s_srs "{expected_crs_string}" -t_srs "{expected_crs_string}" -r near -of JPEG '
+ + source
+ + " "
+ + outdir
+ + "/check.jpg",
+ ],
+ )
# with target using custom projection and user-defined extent
- custom_crs2, expected_crs_string2 = self.get_param_value_and_expected_string_for_custom_crs('+proj=longlat +a=6378388 +b=6356912 +no_defs')
- self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'SOURCE_CRS': custom_crs2,
- 'TARGET_CRS': custom_crs2,
- 'TARGET_EXTENT': '18.67,18.70,45.78,45.81',
- 'TARGET_EXTENT_CRS': custom_crs2,
- 'OUTPUT': outdir + '/check.tif'}, context, feedback),
- ['gdalwarp',
- f'-overwrite -s_srs "{expected_crs_string2}" -t_srs "{expected_crs_string2}" -r near -te 18.67 45.78 18.7 45.81 -te_srs "{expected_crs_string2}" -of GTiff ' +
- source + ' ' +
- outdir + '/check.tif'])
+ custom_crs2, expected_crs_string2 = (
+ self.get_param_value_and_expected_string_for_custom_crs(
+ "+proj=longlat +a=6378388 +b=6356912 +no_defs"
+ )
+ )
+ self.assertEqual(
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "SOURCE_CRS": custom_crs2,
+ "TARGET_CRS": custom_crs2,
+ "TARGET_EXTENT": "18.67,18.70,45.78,45.81",
+ "TARGET_EXTENT_CRS": custom_crs2,
+ "OUTPUT": outdir + "/check.tif",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdalwarp",
+ f'-overwrite -s_srs "{expected_crs_string2}" -t_srs "{expected_crs_string2}" -r near -te 18.67 45.78 18.7 45.81 -te_srs "{expected_crs_string2}" -of GTiff '
+ + source
+ + " "
+ + outdir
+ + "/check.tif",
+ ],
+ )
# with non-EPSG crs code
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'SOURCE_CRS': 'POSTGIS:3111',
- 'TARGET_CRS': 'POSTGIS:3111',
- 'OUTPUT': outdir + '/check.jpg'}, context, feedback),
- ['gdalwarp',
- '-overwrite -s_srs EPSG:3111 -t_srs EPSG:3111 -r near -of JPEG ' +
- source + ' ' +
- outdir + '/check.jpg'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "SOURCE_CRS": "POSTGIS:3111",
+ "TARGET_CRS": "POSTGIS:3111",
+ "OUTPUT": outdir + "/check.jpg",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdalwarp",
+ "-overwrite -s_srs EPSG:3111 -t_srs EPSG:3111 -r near -of JPEG "
+ + source
+ + " "
+ + outdir
+ + "/check.jpg",
+ ],
+ )
# with target resolution with None value
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'SOURCE_CRS': 'EPSG:3111',
- 'TARGET_RESOLUTION': None,
- 'OUTPUT': outdir + '/check.jpg'}, context, feedback),
- ['gdalwarp',
- '-overwrite -s_srs EPSG:3111 -r near -of JPEG ' +
- source + ' ' +
- outdir + '/check.jpg'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "SOURCE_CRS": "EPSG:3111",
+ "TARGET_RESOLUTION": None,
+ "OUTPUT": outdir + "/check.jpg",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdalwarp",
+ "-overwrite -s_srs EPSG:3111 -r near -of JPEG "
+ + source
+ + " "
+ + outdir
+ + "/check.jpg",
+ ],
+ )
# test target resolution with a valid value
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'SOURCE_CRS': 'EPSG:3111',
- 'TARGET_RESOLUTION': 10.0,
- 'OUTPUT': outdir + '/check.jpg'}, context, feedback),
- ['gdalwarp',
- '-overwrite -s_srs EPSG:3111 -tr 10.0 10.0 -r near -of JPEG ' +
- source + ' ' +
- outdir + '/check.jpg'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "SOURCE_CRS": "EPSG:3111",
+ "TARGET_RESOLUTION": 10.0,
+ "OUTPUT": outdir + "/check.jpg",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdalwarp",
+ "-overwrite -s_srs EPSG:3111 -tr 10.0 10.0 -r near -of JPEG "
+ + source
+ + " "
+ + outdir
+ + "/check.jpg",
+ ],
+ )
# test target resolution with a value of zero, to be ignored
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'SOURCE_CRS': 'EPSG:3111',
- 'TARGET_RESOLUTION': 0.0,
- 'OUTPUT': outdir + '/check.jpg'}, context, feedback),
- ['gdalwarp',
- '-overwrite -s_srs EPSG:3111 -r near -of JPEG ' +
- source + ' ' +
- outdir + '/check.jpg'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "SOURCE_CRS": "EPSG:3111",
+ "TARGET_RESOLUTION": 0.0,
+ "OUTPUT": outdir + "/check.jpg",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdalwarp",
+ "-overwrite -s_srs EPSG:3111 -r near -of JPEG "
+ + source
+ + " "
+ + outdir
+ + "/check.jpg",
+ ],
+ )
# with additional command-line parameter
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'EXTRA': '-dstalpha',
- 'OUTPUT': outdir + '/check.jpg'}, context, feedback),
- ['gdalwarp',
- '-overwrite -r near -of JPEG -dstalpha ' +
- source + ' ' +
- outdir + '/check.jpg'])
-
- self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'EXTRA': '-dstalpha -srcnodata -9999',
- 'OUTPUT': outdir + '/check.jpg'}, context, feedback),
- ['gdalwarp',
- '-overwrite -r near -of JPEG -dstalpha -srcnodata -9999 ' +
- source + ' ' +
- outdir + '/check.jpg'])
-
- self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'EXTRA': '-dstalpha -srcnodata "-9999 -8888"',
- 'OUTPUT': outdir + '/check.jpg'}, context, feedback),
- ['gdalwarp',
- '-overwrite -r near -of JPEG -dstalpha -srcnodata "-9999 -8888" ' +
- source + ' ' +
- outdir + '/check.jpg'])
-
- self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'EXTRA': '',
- 'OUTPUT': outdir + '/check.jpg'}, context, feedback),
- ['gdalwarp',
- '-overwrite -r near -of JPEG ' +
- source + ' ' +
- outdir + '/check.jpg'])
-
- self.assertEqual(
- alg.getConsoleCommands({'INPUT': source + '|option:X_POSSIBLE_NAMES=geom_x|option:Y_POSSIBLE_NAMES=geom_y',
- 'SOURCE_CRS': 'EPSG:3111',
- 'OUTPUT': outdir + '/check.jpg'}, context, feedback),
- ['gdalwarp',
- '-overwrite -s_srs EPSG:3111 -r near -of JPEG ' +
- source + ' ' +
- outdir + '/check.jpg -oo X_POSSIBLE_NAMES=geom_x -oo Y_POSSIBLE_NAMES=geom_y'])
-
- self.assertEqual(
- alg.getConsoleCommands({'INPUT': source + '|credential:X=Y|credential:Z=A',
- 'SOURCE_CRS': 'EPSG:3111',
- 'OUTPUT': outdir + '/check.jpg'}, context, feedback),
- ['gdalwarp',
- '-overwrite -s_srs EPSG:3111 -r near -of JPEG ' +
- source + ' ' +
- outdir + '/check.jpg --config X Y --config Z A'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "EXTRA": "-dstalpha",
+ "OUTPUT": outdir + "/check.jpg",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdalwarp",
+ "-overwrite -r near -of JPEG -dstalpha "
+ + source
+ + " "
+ + outdir
+ + "/check.jpg",
+ ],
+ )
+
+ self.assertEqual(
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "EXTRA": "-dstalpha -srcnodata -9999",
+ "OUTPUT": outdir + "/check.jpg",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdalwarp",
+ "-overwrite -r near -of JPEG -dstalpha -srcnodata -9999 "
+ + source
+ + " "
+ + outdir
+ + "/check.jpg",
+ ],
+ )
+
+ self.assertEqual(
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "EXTRA": '-dstalpha -srcnodata "-9999 -8888"',
+ "OUTPUT": outdir + "/check.jpg",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdalwarp",
+ '-overwrite -r near -of JPEG -dstalpha -srcnodata "-9999 -8888" '
+ + source
+ + " "
+ + outdir
+ + "/check.jpg",
+ ],
+ )
+
+ self.assertEqual(
+ alg.getConsoleCommands(
+ {"INPUT": source, "EXTRA": "", "OUTPUT": outdir + "/check.jpg"},
+ context,
+ feedback,
+ ),
+ [
+ "gdalwarp",
+ "-overwrite -r near -of JPEG "
+ + source
+ + " "
+ + outdir
+ + "/check.jpg",
+ ],
+ )
+
+ self.assertEqual(
+ alg.getConsoleCommands(
+ {
+ "INPUT": source
+ + "|option:X_POSSIBLE_NAMES=geom_x|option:Y_POSSIBLE_NAMES=geom_y",
+ "SOURCE_CRS": "EPSG:3111",
+ "OUTPUT": outdir + "/check.jpg",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdalwarp",
+ "-overwrite -s_srs EPSG:3111 -r near -of JPEG "
+ + source
+ + " "
+ + outdir
+ + "/check.jpg -oo X_POSSIBLE_NAMES=geom_x -oo Y_POSSIBLE_NAMES=geom_y",
+ ],
+ )
+
+ self.assertEqual(
+ alg.getConsoleCommands(
+ {
+ "INPUT": source + "|credential:X=Y|credential:Z=A",
+ "SOURCE_CRS": "EPSG:3111",
+ "OUTPUT": outdir + "/check.jpg",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdalwarp",
+ "-overwrite -s_srs EPSG:3111 -r near -of JPEG "
+ + source
+ + " "
+ + outdir
+ + "/check.jpg --config X Y --config Z A",
+ ],
+ )
def testMerge(self):
context = QgsProcessingContext()
feedback = QgsProcessingFeedback()
- source = [os.path.join(testDataPath, 'dem1.tif'), os.path.join(testDataPath, 'dem1.tif')]
+ source = [
+ os.path.join(testDataPath, "dem1.tif"),
+ os.path.join(testDataPath, "dem1.tif"),
+ ]
alg = merge()
alg.initAlgorithm()
with tempfile.TemporaryDirectory() as outdir:
# this algorithm creates temporary text file with input layers
# so we strip its path, leaving only filename
- cmd = alg.getConsoleCommands({'INPUT': source,
- 'OUTPUT': outdir + '/check.tif'}, context, feedback)
+ cmd = alg.getConsoleCommands(
+ {"INPUT": source, "OUTPUT": outdir + "/check.tif"}, context, feedback
+ )
t = cmd[1]
- cmd[1] = t[:t.find('--optfile') + 10] + t[t.find('mergeInputFiles.txt'):]
- self.assertEqual(cmd,
- ['gdal_merge.py',
- '-ot Float32 -of GTiff ' +
- '-o ' + outdir + '/check.tif ' +
- '--optfile mergeInputFiles.txt'])
+ cmd[1] = t[: t.find("--optfile") + 10] + t[t.find("mergeInputFiles.txt") :]
+ self.assertEqual(
+ cmd,
+ [
+ "gdal_merge.py",
+ "-ot Float32 -of GTiff "
+ + "-o "
+ + outdir
+ + "/check.tif "
+ + "--optfile mergeInputFiles.txt",
+ ],
+ )
# separate
- cmd = alg.getConsoleCommands({'INPUT': source,
- 'SEPARATE': True,
- 'OUTPUT': outdir + '/check.tif'}, context, feedback)
+ cmd = alg.getConsoleCommands(
+ {"INPUT": source, "SEPARATE": True, "OUTPUT": outdir + "/check.tif"},
+ context,
+ feedback,
+ )
t = cmd[1]
- cmd[1] = t[:t.find('--optfile') + 10] + t[t.find('mergeInputFiles.txt'):]
- self.assertEqual(cmd,
- ['gdal_merge.py',
- '-separate -ot Float32 -of GTiff ' +
- '-o ' + outdir + '/check.tif ' +
- '--optfile mergeInputFiles.txt'])
+ cmd[1] = t[: t.find("--optfile") + 10] + t[t.find("mergeInputFiles.txt") :]
+ self.assertEqual(
+ cmd,
+ [
+ "gdal_merge.py",
+ "-separate -ot Float32 -of GTiff "
+ + "-o "
+ + outdir
+ + "/check.tif "
+ + "--optfile mergeInputFiles.txt",
+ ],
+ )
# assign nodata
- cmd = alg.getConsoleCommands({'INPUT': source,
- 'EXTRA': '-tap -ps 0.1 0.1',
- 'OUTPUT': outdir + '/check.tif'}, context, feedback)
+ cmd = alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "EXTRA": "-tap -ps 0.1 0.1",
+ "OUTPUT": outdir + "/check.tif",
+ },
+ context,
+ feedback,
+ )
t = cmd[1]
- cmd[1] = t[:t.find('--optfile') + 10] + t[t.find('mergeInputFiles.txt'):]
- self.assertEqual(cmd,
- ['gdal_merge.py',
- '-ot Float32 -of GTiff -tap -ps 0.1 0.1 ' +
- '-o ' + outdir + '/check.tif ' +
- '--optfile mergeInputFiles.txt'])
+ cmd[1] = t[: t.find("--optfile") + 10] + t[t.find("mergeInputFiles.txt") :]
+ self.assertEqual(
+ cmd,
+ [
+ "gdal_merge.py",
+ "-ot Float32 -of GTiff -tap -ps 0.1 0.1 "
+ + "-o "
+ + outdir
+ + "/check.tif "
+ + "--optfile mergeInputFiles.txt",
+ ],
+ )
# additional parameters
- cmd = alg.getConsoleCommands({'INPUT': source,
- 'NODATA_OUTPUT': -9999,
- 'OUTPUT': outdir + '/check.tif'}, context, feedback)
+ cmd = alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "NODATA_OUTPUT": -9999,
+ "OUTPUT": outdir + "/check.tif",
+ },
+ context,
+ feedback,
+ )
t = cmd[1]
- cmd[1] = t[:t.find('--optfile') + 10] + t[t.find('mergeInputFiles.txt'):]
- self.assertEqual(cmd,
- ['gdal_merge.py',
- '-a_nodata -9999.0 -ot Float32 -of GTiff ' +
- '-o ' + outdir + '/check.tif ' +
- '--optfile mergeInputFiles.txt'])
+ cmd[1] = t[: t.find("--optfile") + 10] + t[t.find("mergeInputFiles.txt") :]
+ self.assertEqual(
+ cmd,
+ [
+ "gdal_merge.py",
+ "-a_nodata -9999.0 -ot Float32 -of GTiff "
+ + "-o "
+ + outdir
+ + "/check.tif "
+ + "--optfile mergeInputFiles.txt",
+ ],
+ )
def testNearblack(self):
context = QgsProcessingContext()
feedback = QgsProcessingFeedback()
- source = os.path.join(testDataPath, 'dem.tif')
+ source = os.path.join(testDataPath, "dem.tif")
alg = nearblack()
alg.initAlgorithm()
with tempfile.TemporaryDirectory() as outdir:
# defaults
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'OUTPUT': outdir + '/check.tif'}, context, feedback),
- ['nearblack',
- source + ' -of GTiff -o ' + outdir + '/check.tif ' +
- '-near 15'])
+ alg.getConsoleCommands(
+ {"INPUT": source, "OUTPUT": outdir + "/check.tif"},
+ context,
+ feedback,
+ ),
+ [
+ "nearblack",
+ source + " -of GTiff -o " + outdir + "/check.tif " + "-near 15",
+ ],
+ )
# search white pixels
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'WHITE': True,
- 'OUTPUT': outdir + '/check.tif'}, context, feedback),
- ['nearblack',
- source + ' -of GTiff -o ' + outdir + '/check.tif ' +
- '-near 15 -white'])
+ alg.getConsoleCommands(
+ {"INPUT": source, "WHITE": True, "OUTPUT": outdir + "/check.tif"},
+ context,
+ feedback,
+ ),
+ [
+ "nearblack",
+ source
+ + " -of GTiff -o "
+ + outdir
+ + "/check.tif "
+ + "-near 15 -white",
+ ],
+ )
# additional parameters
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'EXTRA': '-nb 5 -setalpha',
- 'OUTPUT': outdir + '/check.tif'}, context, feedback),
- ['nearblack',
- source + ' -of GTiff -o ' + outdir + '/check.tif ' +
- '-near 15 -nb 5 -setalpha'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "EXTRA": "-nb 5 -setalpha",
+ "OUTPUT": outdir + "/check.tif",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "nearblack",
+ source
+ + " -of GTiff -o "
+ + outdir
+ + "/check.tif "
+ + "-near 15 -nb 5 -setalpha",
+ ],
+ )
# additional parameters and creation options
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'OPTIONS': 'COMPRESS=JPEG|JPEG_QUALITY=75',
- 'EXTRA': '-nb 5 -setalpha',
- 'OUTPUT': outdir + '/check.tif'}, context, feedback),
- ['nearblack',
- source + ' -of GTiff -o ' + outdir + '/check.tif ' +
- '-near 15 -co COMPRESS=JPEG -co JPEG_QUALITY=75 -nb 5 -setalpha'])
-
- self.assertEqual(
- alg.getConsoleCommands({'INPUT': source + '|credential:X=Y|credential:Z=A',
- 'OUTPUT': outdir + '/check.tif'}, context, feedback),
- ['nearblack',
- source + ' -of GTiff -o ' + outdir + '/check.tif ' +
- '-near 15 --config X Y --config Z A'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "OPTIONS": "COMPRESS=JPEG|JPEG_QUALITY=75",
+ "EXTRA": "-nb 5 -setalpha",
+ "OUTPUT": outdir + "/check.tif",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "nearblack",
+ source
+ + " -of GTiff -o "
+ + outdir
+ + "/check.tif "
+ + "-near 15 -co COMPRESS=JPEG -co JPEG_QUALITY=75 -nb 5 -setalpha",
+ ],
+ )
+
+ self.assertEqual(
+ alg.getConsoleCommands(
+ {
+ "INPUT": source + "|credential:X=Y|credential:Z=A",
+ "OUTPUT": outdir + "/check.tif",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "nearblack",
+ source
+ + " -of GTiff -o "
+ + outdir
+ + "/check.tif "
+ + "-near 15 --config X Y --config Z A",
+ ],
+ )
def testRearrangeBands(self):
context = QgsProcessingContext()
feedback = QgsProcessingFeedback()
- source = os.path.join(testDataPath, 'dem.tif')
+ source = os.path.join(testDataPath, "dem.tif")
with tempfile.TemporaryDirectory() as outdir:
- outsource = outdir + '/check.tif'
+ outsource = outdir + "/check.tif"
alg = rearrange_bands()
alg.initAlgorithm()
# single band
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'BANDS': 1,
- 'OUTPUT': outsource}, context, feedback),
- ['gdal_translate', '-b 1 ' +
- '-of GTiff ' +
- source + ' ' + outsource])
+ alg.getConsoleCommands(
+ {"INPUT": source, "BANDS": 1, "OUTPUT": outsource},
+ context,
+ feedback,
+ ),
+ ["gdal_translate", "-b 1 " + "-of GTiff " + source + " " + outsource],
+ )
# three bands, re-ordered
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'BANDS': [3, 2, 1],
- 'OUTPUT': outsource}, context, feedback),
- ['gdal_translate', '-b 3 -b 2 -b 1 ' +
- '-of GTiff ' +
- source + ' ' + outsource])
+ alg.getConsoleCommands(
+ {"INPUT": source, "BANDS": [3, 2, 1], "OUTPUT": outsource},
+ context,
+ feedback,
+ ),
+ [
+ "gdal_translate",
+ "-b 3 -b 2 -b 1 " + "-of GTiff " + source + " " + outsource,
+ ],
+ )
# three bands, re-ordered with custom data type
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'BANDS': [3, 2, 1],
- 'DATA_TYPE': 6,
- 'OUTPUT': outsource}, context, feedback),
- ['gdal_translate', '-b 3 -b 2 -b 1 ' +
- '-ot Float32 -of GTiff ' +
- source + ' ' + outsource])
-
- self.assertEqual(
- alg.getConsoleCommands({'INPUT': source + '|option:X_POSSIBLE_NAMES=geom_x|option:Y_POSSIBLE_NAMES=geom_y',
- 'BANDS': 1,
- 'OUTPUT': outsource}, context, feedback),
- ['gdal_translate', '-b 1 ' +
- '-of GTiff ' +
- source + ' ' + outsource + ' -oo X_POSSIBLE_NAMES=geom_x -oo Y_POSSIBLE_NAMES=geom_y'])
-
- self.assertEqual(
- alg.getConsoleCommands({'INPUT': source + '|credential:X=Y|credential:Z=A',
- 'BANDS': 1,
- 'OUTPUT': outsource}, context, feedback),
- ['gdal_translate', '-b 1 ' +
- '-of GTiff ' +
- source + ' ' + outsource + ' --config X Y --config Z A'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "BANDS": [3, 2, 1],
+ "DATA_TYPE": 6,
+ "OUTPUT": outsource,
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdal_translate",
+ "-b 3 -b 2 -b 1 "
+ + "-ot Float32 -of GTiff "
+ + source
+ + " "
+ + outsource,
+ ],
+ )
+
+ self.assertEqual(
+ alg.getConsoleCommands(
+ {
+ "INPUT": source
+ + "|option:X_POSSIBLE_NAMES=geom_x|option:Y_POSSIBLE_NAMES=geom_y",
+ "BANDS": 1,
+ "OUTPUT": outsource,
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdal_translate",
+ "-b 1 "
+ + "-of GTiff "
+ + source
+ + " "
+ + outsource
+ + " -oo X_POSSIBLE_NAMES=geom_x -oo Y_POSSIBLE_NAMES=geom_y",
+ ],
+ )
+
+ self.assertEqual(
+ alg.getConsoleCommands(
+ {
+ "INPUT": source + "|credential:X=Y|credential:Z=A",
+ "BANDS": 1,
+ "OUTPUT": outsource,
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdal_translate",
+ "-b 1 "
+ + "-of GTiff "
+ + source
+ + " "
+ + outsource
+ + " --config X Y --config Z A",
+ ],
+ )
def testFillnodata(self):
context = QgsProcessingContext()
feedback = QgsProcessingFeedback()
- source = os.path.join(testDataPath, 'dem.tif')
- mask = os.path.join(testDataPath, 'raster.tif')
+ source = os.path.join(testDataPath, "dem.tif")
+ mask = os.path.join(testDataPath, "raster.tif")
with tempfile.TemporaryDirectory() as outdir:
- outsource = outdir + '/check.tif'
+ outsource = outdir + "/check.tif"
alg = fillnodata()
alg.initAlgorithm()
# with mask value
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'BAND': 1,
- 'DISTANCE': 10,
- 'ITERATIONS': 0,
- 'MASK_LAYER': mask,
- 'NO_MASK': False,
- 'OUTPUT': outsource}, context, feedback),
- ['gdal_fillnodata.py',
- f'{source} {outsource} -md 10 -b 1 -mask {mask} -of GTiff'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "BAND": 1,
+ "DISTANCE": 10,
+ "ITERATIONS": 0,
+ "MASK_LAYER": mask,
+ "NO_MASK": False,
+ "OUTPUT": outsource,
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdal_fillnodata.py",
+ f"{source} {outsource} -md 10 -b 1 -mask {mask} -of GTiff",
+ ],
+ )
# without mask value
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'BAND': 1,
- 'DISTANCE': 10,
- 'ITERATIONS': 0,
- 'NO_MASK': False,
- 'OUTPUT': outsource}, context, feedback),
- ['gdal_fillnodata.py',
- f'{source} {outsource} -md 10 -b 1 -of GTiff'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "BAND": 1,
+ "DISTANCE": 10,
+ "ITERATIONS": 0,
+ "NO_MASK": False,
+ "OUTPUT": outsource,
+ },
+ context,
+ feedback,
+ ),
+ ["gdal_fillnodata.py", f"{source} {outsource} -md 10 -b 1 -of GTiff"],
+ )
# The -nomask option is no longer supported since GDAL 3.4 and
# it doesn't work as expected even using GDAL < 3.4 https://github.com/OSGeo/gdal/pull/4201
# Silently ignore the NO_MASK parameter
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'BAND': 1,
- 'DISTANCE': 10,
- 'ITERATIONS': 0,
- 'NO_MASK': True,
- 'OUTPUT': outsource}, context, feedback),
- ['gdal_fillnodata.py',
- f'{source} {outsource} -md 10 -b 1 -of GTiff'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "BAND": 1,
+ "DISTANCE": 10,
+ "ITERATIONS": 0,
+ "NO_MASK": True,
+ "OUTPUT": outsource,
+ },
+ context,
+ feedback,
+ ),
+ ["gdal_fillnodata.py", f"{source} {outsource} -md 10 -b 1 -of GTiff"],
+ )
# creation options
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'BAND': 1,
- 'OPTIONS': 'COMPRESS=JPEG|JPEG_QUALITY=75',
- 'OUTPUT': outsource}, context, feedback),
- ['gdal_fillnodata.py',
- f'{source} {outsource} -md 10 -b 1 -of GTiff -co COMPRESS=JPEG -co JPEG_QUALITY=75'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "BAND": 1,
+ "OPTIONS": "COMPRESS=JPEG|JPEG_QUALITY=75",
+ "OUTPUT": outsource,
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdal_fillnodata.py",
+ f"{source} {outsource} -md 10 -b 1 -of GTiff -co COMPRESS=JPEG -co JPEG_QUALITY=75",
+ ],
+ )
# additional parameters
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'BAND': 1,
- 'EXTRA': '-q',
- 'OUTPUT': outsource}, context, feedback),
- ['gdal_fillnodata.py',
- f'{source} {outsource} -md 10 -b 1 -of GTiff -q'])
-
- self.assertEqual(
- alg.getConsoleCommands({'INPUT': source + '|credential:X=Y|credential:Z=A',
- 'BAND': 1,
- 'DISTANCE': 10,
- 'ITERATIONS': 0,
- 'MASK_LAYER': mask,
- 'NO_MASK': False,
- 'OUTPUT': outsource}, context, feedback),
- ['gdal_fillnodata.py',
- f'{source} {outsource} -md 10 -b 1 -mask {mask} -of GTiff --config X Y --config Z A'])
+ alg.getConsoleCommands(
+ {"INPUT": source, "BAND": 1, "EXTRA": "-q", "OUTPUT": outsource},
+ context,
+ feedback,
+ ),
+ [
+ "gdal_fillnodata.py",
+ f"{source} {outsource} -md 10 -b 1 -of GTiff -q",
+ ],
+ )
+
+ self.assertEqual(
+ alg.getConsoleCommands(
+ {
+ "INPUT": source + "|credential:X=Y|credential:Z=A",
+ "BAND": 1,
+ "DISTANCE": 10,
+ "ITERATIONS": 0,
+ "MASK_LAYER": mask,
+ "NO_MASK": False,
+ "OUTPUT": outsource,
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdal_fillnodata.py",
+ f"{source} {outsource} -md 10 -b 1 -mask {mask} -of GTiff --config X Y --config Z A",
+ ],
+ )
def testGdalAddo(self):
context = QgsProcessingContext()
feedback = QgsProcessingFeedback()
- source = os.path.join(testDataPath, 'dem.tif')
+ source = os.path.join(testDataPath, "dem.tif")
with tempfile.TemporaryDirectory() as outdir:
alg = gdaladdo()
@@ -2742,705 +4809,1231 @@ def testGdalAddo(self):
# defaults
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'LEVELS': '2 4 8 16',
- 'CLEAN': False,
- 'RESAMPLING': 0,
- 'FORMAT': 0}, context, feedback),
- ['gdaladdo',
- source + ' ' + '-r nearest 2 4 8 16'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "LEVELS": "2 4 8 16",
+ "CLEAN": False,
+ "RESAMPLING": 0,
+ "FORMAT": 0,
+ },
+ context,
+ feedback,
+ ),
+ ["gdaladdo", source + " " + "-r nearest 2 4 8 16"],
+ )
# with "clean" option
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'LEVELS': '2 4 8 16',
- 'CLEAN': True,
- 'RESAMPLING': 0,
- 'FORMAT': 0}, context, feedback),
- ['gdaladdo',
- source + ' ' + '-r nearest -clean 2 4 8 16'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "LEVELS": "2 4 8 16",
+ "CLEAN": True,
+ "RESAMPLING": 0,
+ "FORMAT": 0,
+ },
+ context,
+ feedback,
+ ),
+ ["gdaladdo", source + " " + "-r nearest -clean 2 4 8 16"],
+ )
# ovr format
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'LEVELS': '2 4 8 16',
- 'CLEAN': False,
- 'RESAMPLING': 0,
- 'FORMAT': 1}, context, feedback),
- ['gdaladdo',
- source + ' ' + '-r nearest -ro 2 4 8 16'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "LEVELS": "2 4 8 16",
+ "CLEAN": False,
+ "RESAMPLING": 0,
+ "FORMAT": 1,
+ },
+ context,
+ feedback,
+ ),
+ ["gdaladdo", source + " " + "-r nearest -ro 2 4 8 16"],
+ )
# Erdas format
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'LEVELS': '2 4 8 16',
- 'CLEAN': False,
- 'RESAMPLING': 0,
- 'FORMAT': 2}, context, feedback),
- ['gdaladdo',
- source + ' ' + '-r nearest --config USE_RRD YES 2 4 8 16'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "LEVELS": "2 4 8 16",
+ "CLEAN": False,
+ "RESAMPLING": 0,
+ "FORMAT": 2,
+ },
+ context,
+ feedback,
+ ),
+ ["gdaladdo", source + " " + "-r nearest --config USE_RRD YES 2 4 8 16"],
+ )
# custom resampling method format
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'LEVELS': '2 4 8 16',
- 'CLEAN': False,
- 'RESAMPLING': 4,
- 'FORMAT': 0}, context, feedback),
- ['gdaladdo',
- source + ' ' + '-r cubicspline 2 4 8 16'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "LEVELS": "2 4 8 16",
+ "CLEAN": False,
+ "RESAMPLING": 4,
+ "FORMAT": 0,
+ },
+ context,
+ feedback,
+ ),
+ ["gdaladdo", source + " " + "-r cubicspline 2 4 8 16"],
+ )
# more levels
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'LEVELS': '2 4 8 16 32 64',
- 'CLEAN': False,
- 'RESAMPLING': 0,
- 'FORMAT': 0}, context, feedback),
- ['gdaladdo',
- source + ' ' + '-r nearest 2 4 8 16 32 64'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "LEVELS": "2 4 8 16 32 64",
+ "CLEAN": False,
+ "RESAMPLING": 0,
+ "FORMAT": 0,
+ },
+ context,
+ feedback,
+ ),
+ ["gdaladdo", source + " " + "-r nearest 2 4 8 16 32 64"],
+ )
# additional parameters
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'LEVELS': '2 4 8 16',
- 'CLEAN': False,
- 'EXTRA': '--config COMPRESS_OVERVIEW JPEG'}, context, feedback),
- ['gdaladdo',
- source + ' ' + '--config COMPRESS_OVERVIEW JPEG 2 4 8 16'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "LEVELS": "2 4 8 16",
+ "CLEAN": False,
+ "EXTRA": "--config COMPRESS_OVERVIEW JPEG",
+ },
+ context,
+ feedback,
+ ),
+ ["gdaladdo", source + " " + "--config COMPRESS_OVERVIEW JPEG 2 4 8 16"],
+ )
if GdalUtils.version() >= 230000:
# without levels
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'CLEAN': False}, context, feedback),
- ['gdaladdo',
- source])
+ alg.getConsoleCommands(
+ {"INPUT": source, "CLEAN": False}, context, feedback
+ ),
+ ["gdaladdo", source],
+ )
# without advanced params
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'LEVELS': '2 4 8 16',
- 'CLEAN': False}, context, feedback),
- ['gdaladdo',
- source + ' ' + '2 4 8 16'])
-
- self.assertEqual(
- alg.getConsoleCommands({'INPUT': source + '|credential:X=Y|credential:Z=A',
- 'LEVELS': '2 4 8 16',
- 'CLEAN': False,
- 'RESAMPLING': 0,
- 'FORMAT': 0}, context, feedback),
- ['gdaladdo',
- source + ' ' + '-r nearest 2 4 8 16 --config X Y --config Z A'])
+ alg.getConsoleCommands(
+ {"INPUT": source, "LEVELS": "2 4 8 16", "CLEAN": False},
+ context,
+ feedback,
+ ),
+ ["gdaladdo", source + " " + "2 4 8 16"],
+ )
+
+ self.assertEqual(
+ alg.getConsoleCommands(
+ {
+ "INPUT": source + "|credential:X=Y|credential:Z=A",
+ "LEVELS": "2 4 8 16",
+ "CLEAN": False,
+ "RESAMPLING": 0,
+ "FORMAT": 0,
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdaladdo",
+ source + " " + "-r nearest 2 4 8 16 --config X Y --config Z A",
+ ],
+ )
def testSieve(self):
context = QgsProcessingContext()
feedback = QgsProcessingFeedback()
- source = os.path.join(testDataPath, 'dem.tif')
- mask = os.path.join(testDataPath, 'raster.tif')
+ source = os.path.join(testDataPath, "dem.tif")
+ mask = os.path.join(testDataPath, "raster.tif")
with tempfile.TemporaryDirectory() as outdir:
- outsource = outdir + '/check.tif'
+ outsource = outdir + "/check.tif"
alg = sieve()
alg.initAlgorithm()
# defaults
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'OUTPUT': outsource}, context, feedback),
- ['gdal_sieve.py',
- '-st 10 -4 -of GTiff ' +
- source + ' ' +
- outsource])
+ alg.getConsoleCommands(
+ {"INPUT": source, "OUTPUT": outsource}, context, feedback
+ ),
+ ["gdal_sieve.py", "-st 10 -4 -of GTiff " + source + " " + outsource],
+ )
# Eight connectedness and custom threshold
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'THRESHOLD': 16,
- 'EIGHT_CONNECTEDNESS': True,
- 'OUTPUT': outsource}, context, feedback),
- ['gdal_sieve.py',
- '-st 16 -8 -of GTiff ' +
- source + ' ' +
- outsource])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "THRESHOLD": 16,
+ "EIGHT_CONNECTEDNESS": True,
+ "OUTPUT": outsource,
+ },
+ context,
+ feedback,
+ ),
+ ["gdal_sieve.py", "-st 16 -8 -of GTiff " + source + " " + outsource],
+ )
# without default mask layer
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'NO_MASK': True,
- 'OUTPUT': outsource}, context, feedback),
- ['gdal_sieve.py',
- '-st 10 -4 -nomask -of GTiff ' +
- source + ' ' +
- outsource])
+ alg.getConsoleCommands(
+ {"INPUT": source, "NO_MASK": True, "OUTPUT": outsource},
+ context,
+ feedback,
+ ),
+ [
+ "gdal_sieve.py",
+ "-st 10 -4 -nomask -of GTiff " + source + " " + outsource,
+ ],
+ )
# defaults with external validity mask
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'MASK_LAYER': mask,
- 'OUTPUT': outsource}, context, feedback),
- ['gdal_sieve.py',
- '-st 10 -4 -mask ' +
- mask +
- ' -of GTiff ' +
- source + ' ' +
- outsource])
+ alg.getConsoleCommands(
+ {"INPUT": source, "MASK_LAYER": mask, "OUTPUT": outsource},
+ context,
+ feedback,
+ ),
+ [
+ "gdal_sieve.py",
+ "-st 10 -4 -mask "
+ + mask
+ + " -of GTiff "
+ + source
+ + " "
+ + outsource,
+ ],
+ )
# additional parameters
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'EXTRA': '-q',
- 'OUTPUT': outsource}, context, feedback),
- ['gdal_sieve.py',
- '-st 10 -4 -of GTiff -q ' +
- source + ' ' +
- outsource])
-
- self.assertEqual(
- alg.getConsoleCommands({'INPUT': source + '|credential:X=Y|credential:Z=A',
- 'OUTPUT': outsource}, context, feedback),
- ['gdal_sieve.py',
- '-st 10 -4 -of GTiff ' +
- source + ' ' +
- outsource + ' --config X Y --config Z A'])
+ alg.getConsoleCommands(
+ {"INPUT": source, "EXTRA": "-q", "OUTPUT": outsource},
+ context,
+ feedback,
+ ),
+ ["gdal_sieve.py", "-st 10 -4 -of GTiff -q " + source + " " + outsource],
+ )
+
+ self.assertEqual(
+ alg.getConsoleCommands(
+ {
+ "INPUT": source + "|credential:X=Y|credential:Z=A",
+ "OUTPUT": outsource,
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdal_sieve.py",
+ "-st 10 -4 -of GTiff "
+ + source
+ + " "
+ + outsource
+ + " --config X Y --config Z A",
+ ],
+ )
def testGdal2Xyz(self):
context = QgsProcessingContext()
feedback = QgsProcessingFeedback()
- source = os.path.join(testDataPath, 'dem.tif')
+ source = os.path.join(testDataPath, "dem.tif")
with tempfile.TemporaryDirectory() as outdir:
- outsource = outdir + '/check.csv'
+ outsource = outdir + "/check.csv"
alg = gdal2xyz()
alg.initAlgorithm()
# defaults
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'BAND': 1,
- 'CSV': False,
- 'OUTPUT': outsource}, context, feedback),
- ['gdal2xyz.py',
- '-band 1 ' +
- source + ' ' +
- outsource])
+ alg.getConsoleCommands(
+ {"INPUT": source, "BAND": 1, "CSV": False, "OUTPUT": outsource},
+ context,
+ feedback,
+ ),
+ ["gdal2xyz.py", "-band 1 " + source + " " + outsource],
+ )
# csv output
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'BAND': 1,
- 'CSV': True,
- 'OUTPUT': outsource}, context, feedback),
- ['gdal2xyz.py',
- '-band 1 -csv ' +
- source + ' ' +
- outsource])
+ alg.getConsoleCommands(
+ {"INPUT": source, "BAND": 1, "CSV": True, "OUTPUT": outsource},
+ context,
+ feedback,
+ ),
+ ["gdal2xyz.py", "-band 1 -csv " + source + " " + outsource],
+ )
if GdalUtils.version() >= 3030000:
# skip nodata output
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'BAND': 1,
- 'CSV': False,
- 'SKIP_NODATA': True,
- 'OUTPUT': outsource}, context, feedback),
- ['gdal2xyz.py',
- '-band 1 -skipnodata ' +
- source + ' ' +
- outsource])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "BAND": 1,
+ "CSV": False,
+ "SKIP_NODATA": True,
+ "OUTPUT": outsource,
+ },
+ context,
+ feedback,
+ ),
+ ["gdal2xyz.py", "-band 1 -skipnodata " + source + " " + outsource],
+ )
if GdalUtils.version() > 3060300:
# srcnodata output
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'BAND': 1,
- 'CSV': False,
- 'NODATA_INPUT': -999,
- 'SKIP_NODATA': False,
- 'OUTPUT': outsource}, context, feedback),
- ['gdal2xyz.py',
- '-band 1 -srcnodata -999.0 ' +
- source + ' ' +
- outsource])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "BAND": 1,
+ "CSV": False,
+ "NODATA_INPUT": -999,
+ "SKIP_NODATA": False,
+ "OUTPUT": outsource,
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdal2xyz.py",
+ "-band 1 -srcnodata -999.0 " + source + " " + outsource,
+ ],
+ )
# dstnodata output
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'BAND': 1,
- 'CSV': False,
- 'NODATA_OUTPUT': -999,
- 'SKIP_NODATA': False,
- 'OUTPUT': outsource}, context, feedback),
- ['gdal2xyz.py',
- '-band 1 -dstnodata -999.0 ' +
- source + ' ' +
- outsource])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "BAND": 1,
+ "CSV": False,
+ "NODATA_OUTPUT": -999,
+ "SKIP_NODATA": False,
+ "OUTPUT": outsource,
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdal2xyz.py",
+ "-band 1 -dstnodata -999.0 " + source + " " + outsource,
+ ],
+ )
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source + '|credential:X=Y|credential:Z=A',
- 'BAND': 1,
- 'CSV': False,
- 'OUTPUT': outsource}, context,
- feedback),
- ['gdal2xyz.py',
- '-band 1 ' +
- source + ' ' +
- outsource + ' --config X Y --config Z A'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source + "|credential:X=Y|credential:Z=A",
+ "BAND": 1,
+ "CSV": False,
+ "OUTPUT": outsource,
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdal2xyz.py",
+ "-band 1 "
+ + source
+ + " "
+ + outsource
+ + " --config X Y --config Z A",
+ ],
+ )
def testGdalPolygonize(self):
context = QgsProcessingContext()
feedback = QgsProcessingFeedback()
- source = os.path.join(testDataPath, 'dem.tif')
+ source = os.path.join(testDataPath, "dem.tif")
with tempfile.TemporaryDirectory() as outdir:
- outsource = outdir + '/check.shp'
+ outsource = outdir + "/check.shp"
alg = polygonize()
alg.initAlgorithm()
# defaults
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'BAND': 1,
- 'FIELD': 'DN',
- 'EIGHT_CONNECTEDNESS': False,
- 'OUTPUT': outsource}, context, feedback),
- ['gdal_polygonize.py',
- source + ' ' +
- '-b 1 -f "ESRI Shapefile"' + ' ' + outsource + ' ' + 'check DN'
- ])
-
- self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'BAND': 1,
- 'FIELD': 'VAL',
- 'EIGHT_CONNECTEDNESS': False,
- 'OUTPUT': outsource}, context, feedback),
- ['gdal_polygonize.py',
- source + ' ' +
- '-b 1 -f "ESRI Shapefile"' + ' ' + outsource + ' ' + 'check VAL'
- ])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "BAND": 1,
+ "FIELD": "DN",
+ "EIGHT_CONNECTEDNESS": False,
+ "OUTPUT": outsource,
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdal_polygonize.py",
+ source
+ + " "
+ + '-b 1 -f "ESRI Shapefile"'
+ + " "
+ + outsource
+ + " "
+ + "check DN",
+ ],
+ )
+
+ self.assertEqual(
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "BAND": 1,
+ "FIELD": "VAL",
+ "EIGHT_CONNECTEDNESS": False,
+ "OUTPUT": outsource,
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdal_polygonize.py",
+ source
+ + " "
+ + '-b 1 -f "ESRI Shapefile"'
+ + " "
+ + outsource
+ + " "
+ + "check VAL",
+ ],
+ )
# 8 connectedness
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'BAND': 1,
- 'FIELD': 'DN',
- 'EIGHT_CONNECTEDNESS': True,
- 'OUTPUT': outsource}, context, feedback),
- ['gdal_polygonize.py',
- '-8' + ' ' + source + ' ' +
- '-b 1 -f "ESRI Shapefile"' + ' ' + outsource + ' ' + 'check DN'
- ])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "BAND": 1,
+ "FIELD": "DN",
+ "EIGHT_CONNECTEDNESS": True,
+ "OUTPUT": outsource,
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdal_polygonize.py",
+ "-8"
+ + " "
+ + source
+ + " "
+ + '-b 1 -f "ESRI Shapefile"'
+ + " "
+ + outsource
+ + " "
+ + "check DN",
+ ],
+ )
# custom output format
- outsource = outdir + '/check.gpkg'
- self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'BAND': 1,
- 'FIELD': 'DN',
- 'EIGHT_CONNECTEDNESS': False,
- 'OUTPUT': outsource}, context, feedback),
- ['gdal_polygonize.py',
- source + ' ' +
- '-b 1 -f "GPKG"' + ' ' + outsource + ' ' + 'check DN'
- ])
+ outsource = outdir + "/check.gpkg"
+ self.assertEqual(
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "BAND": 1,
+ "FIELD": "DN",
+ "EIGHT_CONNECTEDNESS": False,
+ "OUTPUT": outsource,
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdal_polygonize.py",
+ source
+ + " "
+ + '-b 1 -f "GPKG"'
+ + " "
+ + outsource
+ + " "
+ + "check DN",
+ ],
+ )
# additional parameters
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'BAND': 1,
- 'FIELD': 'DN',
- 'EXTRA': '-nomask -q',
- 'OUTPUT': outsource}, context, feedback),
- ['gdal_polygonize.py',
- '-nomask -q' + ' ' + source + ' ' +
- '-b 1 -f "GPKG"' + ' ' + outsource + ' ' + 'check DN'
- ])
-
- self.assertEqual(
- alg.getConsoleCommands({'INPUT': source + '|credential:X=Y|credential:Z=A',
- 'BAND': 1,
- 'FIELD': 'DN',
- 'EIGHT_CONNECTEDNESS': False,
- 'OUTPUT': outsource}, context, feedback),
- ['gdal_polygonize.py',
- source + ' ' +
- '-b 1 -f "GPKG"' + ' ' + outsource + ' ' + 'check DN --config X Y --config Z A'
- ])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "BAND": 1,
+ "FIELD": "DN",
+ "EXTRA": "-nomask -q",
+ "OUTPUT": outsource,
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdal_polygonize.py",
+ "-nomask -q"
+ + " "
+ + source
+ + " "
+ + '-b 1 -f "GPKG"'
+ + " "
+ + outsource
+ + " "
+ + "check DN",
+ ],
+ )
+
+ self.assertEqual(
+ alg.getConsoleCommands(
+ {
+ "INPUT": source + "|credential:X=Y|credential:Z=A",
+ "BAND": 1,
+ "FIELD": "DN",
+ "EIGHT_CONNECTEDNESS": False,
+ "OUTPUT": outsource,
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdal_polygonize.py",
+ source
+ + " "
+ + '-b 1 -f "GPKG"'
+ + " "
+ + outsource
+ + " "
+ + "check DN --config X Y --config Z A",
+ ],
+ )
def testGdalPansharpen(self):
context = QgsProcessingContext()
feedback = QgsProcessingFeedback()
- panchrom = os.path.join(testDataPath, 'dem.tif')
- spectral = os.path.join(testDataPath, 'raster.tif')
+ panchrom = os.path.join(testDataPath, "dem.tif")
+ spectral = os.path.join(testDataPath, "raster.tif")
with tempfile.TemporaryDirectory() as outdir:
- outsource = outdir + '/out.tif'
+ outsource = outdir + "/out.tif"
alg = pansharp()
alg.initAlgorithm()
# defaults
self.assertEqual(
- alg.getConsoleCommands({'SPECTRAL': spectral,
- 'PANCHROMATIC': panchrom,
- 'OUTPUT': outsource}, context, feedback),
- ['gdal_pansharpen.py',
- panchrom + ' ' +
- spectral + ' ' +
- outsource + ' ' +
- '-r cubic -of GTiff'
- ])
+ alg.getConsoleCommands(
+ {
+ "SPECTRAL": spectral,
+ "PANCHROMATIC": panchrom,
+ "OUTPUT": outsource,
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdal_pansharpen.py",
+ panchrom
+ + " "
+ + spectral
+ + " "
+ + outsource
+ + " "
+ + "-r cubic -of GTiff",
+ ],
+ )
# custom resampling
self.assertEqual(
- alg.getConsoleCommands({'SPECTRAL': spectral,
- 'PANCHROMATIC': panchrom,
- 'RESAMPLING': 4,
- 'OUTPUT': outsource}, context, feedback),
- ['gdal_pansharpen.py',
- panchrom + ' ' +
- spectral + ' ' +
- outsource + ' ' +
- '-r lanczos -of GTiff'
- ])
+ alg.getConsoleCommands(
+ {
+ "SPECTRAL": spectral,
+ "PANCHROMATIC": panchrom,
+ "RESAMPLING": 4,
+ "OUTPUT": outsource,
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdal_pansharpen.py",
+ panchrom
+ + " "
+ + spectral
+ + " "
+ + outsource
+ + " "
+ + "-r lanczos -of GTiff",
+ ],
+ )
# additional parameters
self.assertEqual(
- alg.getConsoleCommands({'SPECTRAL': spectral,
- 'PANCHROMATIC': panchrom,
- 'EXTRA': '-bitdepth 12 -threads ALL_CPUS',
- 'OUTPUT': outsource}, context, feedback),
- ['gdal_pansharpen.py',
- panchrom + ' ' +
- spectral + ' ' +
- outsource + ' ' +
- '-r cubic -of GTiff -bitdepth 12 -threads ALL_CPUS'
- ])
-
- self.assertEqual(
- alg.getConsoleCommands({'SPECTRAL': spectral,
- 'PANCHROMATIC': panchrom + '|credential:X=Y|credential:Z=A',
- 'OUTPUT': outsource}, context, feedback),
- ['gdal_pansharpen.py',
- panchrom + ' ' +
- spectral + ' ' +
- outsource + ' ' +
- '-r cubic -of GTiff --config X Y --config Z A'
- ])
+ alg.getConsoleCommands(
+ {
+ "SPECTRAL": spectral,
+ "PANCHROMATIC": panchrom,
+ "EXTRA": "-bitdepth 12 -threads ALL_CPUS",
+ "OUTPUT": outsource,
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdal_pansharpen.py",
+ panchrom
+ + " "
+ + spectral
+ + " "
+ + outsource
+ + " "
+ + "-r cubic -of GTiff -bitdepth 12 -threads ALL_CPUS",
+ ],
+ )
+
+ self.assertEqual(
+ alg.getConsoleCommands(
+ {
+ "SPECTRAL": spectral,
+ "PANCHROMATIC": panchrom + "|credential:X=Y|credential:Z=A",
+ "OUTPUT": outsource,
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdal_pansharpen.py",
+ panchrom
+ + " "
+ + spectral
+ + " "
+ + outsource
+ + " "
+ + "-r cubic -of GTiff --config X Y --config Z A",
+ ],
+ )
def testGdalViewshed(self):
context = QgsProcessingContext()
feedback = QgsProcessingFeedback()
- dem = os.path.join(testDataPath, 'dem.tif')
+ dem = os.path.join(testDataPath, "dem.tif")
with tempfile.TemporaryDirectory() as outdir:
- outsource = outdir + '/out.tif'
+ outsource = outdir + "/out.tif"
alg = viewshed()
alg.initAlgorithm()
# defaults
self.assertEqual(
- alg.getConsoleCommands({'INPUT': dem,
- 'BAND': 1,
- 'OBSERVER': '18.67274,45.80599',
- 'OUTPUT': outsource}, context, feedback),
- ['gdal_viewshed',
- '-b 1 -ox 18.67274 -oy 45.80599 -oz 1.0 -tz 1.0 -md 100.0 -f GTiff ' +
- dem + ' ' + outsource
- ])
-
- self.assertEqual(
- alg.getConsoleCommands({'INPUT': dem,
- 'BAND': 2,
- 'OBSERVER': '18.67274,45.80599',
- 'OBSERVER_HEIGHT': 1.8,
- 'TARGET_HEIGHT': 20,
- 'MAX_DISTANCE': 1000,
- 'OUTPUT': outsource}, context, feedback),
- ['gdal_viewshed',
- '-b 2 -ox 18.67274 -oy 45.80599 -oz 1.8 -tz 20.0 -md 1000.0 -f GTiff ' +
- dem + ' ' + outsource
- ])
-
- self.assertEqual(
- alg.getConsoleCommands({'INPUT': dem,
- 'BAND': 1,
- 'OBSERVER': '18.67274,45.80599',
- 'EXTRA': '-a_nodata=-9999 -cc 0.2',
- 'OUTPUT': outsource}, context, feedback),
- ['gdal_viewshed',
- '-b 1 -ox 18.67274 -oy 45.80599 -oz 1.0 -tz 1.0 -md 100.0 -f GTiff ' +
- '-a_nodata=-9999 -cc 0.2 ' + dem + ' ' + outsource
- ])
-
- self.assertEqual(
- alg.getConsoleCommands({'INPUT': dem,
- 'BAND': 1,
- 'OBSERVER': '18.67274,45.80599',
- 'OPTIONS': 'COMPRESS=DEFLATE|PREDICTOR=2|ZLEVEL=9',
- 'OUTPUT': outsource}, context, feedback),
- ['gdal_viewshed',
- '-b 1 -ox 18.67274 -oy 45.80599 -oz 1.0 -tz 1.0 -md 100.0 -f GTiff ' +
- '-co COMPRESS=DEFLATE -co PREDICTOR=2 -co ZLEVEL=9 ' + dem + ' ' + outsource
- ])
-
- self.assertEqual(
- alg.getConsoleCommands({'INPUT': dem + '|credential:X=Y|credential:Z=A',
- 'BAND': 1,
- 'OBSERVER': '18.67274,45.80599',
- 'OUTPUT': outsource}, context, feedback),
- ['gdal_viewshed',
- '-b 1 -ox 18.67274 -oy 45.80599 -oz 1.0 -tz 1.0 -md 100.0 -f GTiff ' +
- dem + ' ' + outsource + ' --config X Y --config Z A'
- ])
+ alg.getConsoleCommands(
+ {
+ "INPUT": dem,
+ "BAND": 1,
+ "OBSERVER": "18.67274,45.80599",
+ "OUTPUT": outsource,
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdal_viewshed",
+ "-b 1 -ox 18.67274 -oy 45.80599 -oz 1.0 -tz 1.0 -md 100.0 -f GTiff "
+ + dem
+ + " "
+ + outsource,
+ ],
+ )
+
+ self.assertEqual(
+ alg.getConsoleCommands(
+ {
+ "INPUT": dem,
+ "BAND": 2,
+ "OBSERVER": "18.67274,45.80599",
+ "OBSERVER_HEIGHT": 1.8,
+ "TARGET_HEIGHT": 20,
+ "MAX_DISTANCE": 1000,
+ "OUTPUT": outsource,
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdal_viewshed",
+ "-b 2 -ox 18.67274 -oy 45.80599 -oz 1.8 -tz 20.0 -md 1000.0 -f GTiff "
+ + dem
+ + " "
+ + outsource,
+ ],
+ )
+
+ self.assertEqual(
+ alg.getConsoleCommands(
+ {
+ "INPUT": dem,
+ "BAND": 1,
+ "OBSERVER": "18.67274,45.80599",
+ "EXTRA": "-a_nodata=-9999 -cc 0.2",
+ "OUTPUT": outsource,
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdal_viewshed",
+ "-b 1 -ox 18.67274 -oy 45.80599 -oz 1.0 -tz 1.0 -md 100.0 -f GTiff "
+ + "-a_nodata=-9999 -cc 0.2 "
+ + dem
+ + " "
+ + outsource,
+ ],
+ )
+
+ self.assertEqual(
+ alg.getConsoleCommands(
+ {
+ "INPUT": dem,
+ "BAND": 1,
+ "OBSERVER": "18.67274,45.80599",
+ "OPTIONS": "COMPRESS=DEFLATE|PREDICTOR=2|ZLEVEL=9",
+ "OUTPUT": outsource,
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdal_viewshed",
+ "-b 1 -ox 18.67274 -oy 45.80599 -oz 1.0 -tz 1.0 -md 100.0 -f GTiff "
+ + "-co COMPRESS=DEFLATE -co PREDICTOR=2 -co ZLEVEL=9 "
+ + dem
+ + " "
+ + outsource,
+ ],
+ )
+
+ self.assertEqual(
+ alg.getConsoleCommands(
+ {
+ "INPUT": dem + "|credential:X=Y|credential:Z=A",
+ "BAND": 1,
+ "OBSERVER": "18.67274,45.80599",
+ "OUTPUT": outsource,
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdal_viewshed",
+ "-b 1 -ox 18.67274 -oy 45.80599 -oz 1.0 -tz 1.0 -md 100.0 -f GTiff "
+ + dem
+ + " "
+ + outsource
+ + " --config X Y --config Z A",
+ ],
+ )
def testBuildVrt(self):
context = QgsProcessingContext()
feedback = QgsProcessingFeedback()
- source = os.path.join(testDataPath, 'dem.tif')
+ source = os.path.join(testDataPath, "dem.tif")
alg = buildvrt()
alg.initAlgorithm()
with tempfile.TemporaryDirectory() as outdir:
# defaults
- cmd = alg.getConsoleCommands({'INPUT': [source],
- 'OUTPUT': outdir + '/check.vrt'}, context, feedback)
+ cmd = alg.getConsoleCommands(
+ {"INPUT": [source], "OUTPUT": outdir + "/check.vrt"}, context, feedback
+ )
t = cmd[1]
- cmd[1] = t[:t.find('-input_file_list') + 17] + t[t.find('buildvrtInputFiles.txt'):]
- self.assertEqual(cmd,
- ['gdalbuildvrt',
- '-overwrite -resolution average -separate -r nearest ' +
- '-input_file_list buildvrtInputFiles.txt ' +
- outdir + '/check.vrt'])
+ cmd[1] = (
+ t[: t.find("-input_file_list") + 17]
+ + t[t.find("buildvrtInputFiles.txt") :]
+ )
+ self.assertEqual(
+ cmd,
+ [
+ "gdalbuildvrt",
+ "-overwrite -resolution average -separate -r nearest "
+ + "-input_file_list buildvrtInputFiles.txt "
+ + outdir
+ + "/check.vrt",
+ ],
+ )
# custom resolution
- cmd = alg.getConsoleCommands({'INPUT': [source],
- 'RESOLUTION': 2,
- 'OUTPUT': outdir + '/check.vrt'}, context, feedback)
+ cmd = alg.getConsoleCommands(
+ {"INPUT": [source], "RESOLUTION": 2, "OUTPUT": outdir + "/check.vrt"},
+ context,
+ feedback,
+ )
t = cmd[1]
- cmd[1] = t[:t.find('-input_file_list') + 17] + t[t.find('buildvrtInputFiles.txt'):]
- self.assertEqual(cmd,
- ['gdalbuildvrt',
- '-overwrite -resolution lowest -separate -r nearest ' +
- '-input_file_list buildvrtInputFiles.txt ' +
- outdir + '/check.vrt'])
+ cmd[1] = (
+ t[: t.find("-input_file_list") + 17]
+ + t[t.find("buildvrtInputFiles.txt") :]
+ )
+ self.assertEqual(
+ cmd,
+ [
+ "gdalbuildvrt",
+ "-overwrite -resolution lowest -separate -r nearest "
+ + "-input_file_list buildvrtInputFiles.txt "
+ + outdir
+ + "/check.vrt",
+ ],
+ )
# single layer
- cmd = alg.getConsoleCommands({'INPUT': [source],
- 'SEPARATE': False,
- 'OUTPUT': outdir + '/check.vrt'}, context, feedback)
+ cmd = alg.getConsoleCommands(
+ {"INPUT": [source], "SEPARATE": False, "OUTPUT": outdir + "/check.vrt"},
+ context,
+ feedback,
+ )
t = cmd[1]
- cmd[1] = t[:t.find('-input_file_list') + 17] + t[t.find('buildvrtInputFiles.txt'):]
- self.assertEqual(cmd,
- ['gdalbuildvrt',
- '-overwrite -resolution average -r nearest ' +
- '-input_file_list buildvrtInputFiles.txt ' +
- outdir + '/check.vrt'])
+ cmd[1] = (
+ t[: t.find("-input_file_list") + 17]
+ + t[t.find("buildvrtInputFiles.txt") :]
+ )
+ self.assertEqual(
+ cmd,
+ [
+ "gdalbuildvrt",
+ "-overwrite -resolution average -r nearest "
+ + "-input_file_list buildvrtInputFiles.txt "
+ + outdir
+ + "/check.vrt",
+ ],
+ )
# projection difference
- cmd = alg.getConsoleCommands({'INPUT': [source],
- 'PROJ_DIFFERENCE': True,
- 'OUTPUT': outdir + '/check.vrt'}, context, feedback)
+ cmd = alg.getConsoleCommands(
+ {
+ "INPUT": [source],
+ "PROJ_DIFFERENCE": True,
+ "OUTPUT": outdir + "/check.vrt",
+ },
+ context,
+ feedback,
+ )
t = cmd[1]
- cmd[1] = t[:t.find('-input_file_list') + 17] + t[t.find('buildvrtInputFiles.txt'):]
- self.assertEqual(cmd,
- ['gdalbuildvrt',
- '-overwrite -resolution average -separate -allow_projection_difference -r nearest ' +
- '-input_file_list buildvrtInputFiles.txt ' +
- outdir + '/check.vrt'])
+ cmd[1] = (
+ t[: t.find("-input_file_list") + 17]
+ + t[t.find("buildvrtInputFiles.txt") :]
+ )
+ self.assertEqual(
+ cmd,
+ [
+ "gdalbuildvrt",
+ "-overwrite -resolution average -separate -allow_projection_difference -r nearest "
+ + "-input_file_list buildvrtInputFiles.txt "
+ + outdir
+ + "/check.vrt",
+ ],
+ )
# add alpha band
- cmd = alg.getConsoleCommands({'INPUT': [source],
- 'ADD_ALPHA': True,
- 'OUTPUT': outdir + '/check.vrt'}, context, feedback)
+ cmd = alg.getConsoleCommands(
+ {"INPUT": [source], "ADD_ALPHA": True, "OUTPUT": outdir + "/check.vrt"},
+ context,
+ feedback,
+ )
t = cmd[1]
- cmd[1] = t[:t.find('-input_file_list') + 17] + t[t.find('buildvrtInputFiles.txt'):]
- self.assertEqual(cmd,
- ['gdalbuildvrt',
- '-overwrite -resolution average -separate -addalpha -r nearest ' +
- '-input_file_list buildvrtInputFiles.txt ' +
- outdir + '/check.vrt'])
+ cmd[1] = (
+ t[: t.find("-input_file_list") + 17]
+ + t[t.find("buildvrtInputFiles.txt") :]
+ )
+ self.assertEqual(
+ cmd,
+ [
+ "gdalbuildvrt",
+ "-overwrite -resolution average -separate -addalpha -r nearest "
+ + "-input_file_list buildvrtInputFiles.txt "
+ + outdir
+ + "/check.vrt",
+ ],
+ )
# assign CRS
- cmd = alg.getConsoleCommands({'INPUT': [source],
- 'ASSIGN_CRS': 'EPSG:3111',
- 'OUTPUT': outdir + '/check.vrt'}, context, feedback)
+ cmd = alg.getConsoleCommands(
+ {
+ "INPUT": [source],
+ "ASSIGN_CRS": "EPSG:3111",
+ "OUTPUT": outdir + "/check.vrt",
+ },
+ context,
+ feedback,
+ )
t = cmd[1]
- cmd[1] = t[:t.find('-input_file_list') + 17] + t[t.find('buildvrtInputFiles.txt'):]
- self.assertEqual(cmd,
- ['gdalbuildvrt',
- '-overwrite -resolution average -separate -a_srs EPSG:3111 -r nearest ' +
- '-input_file_list buildvrtInputFiles.txt ' +
- outdir + '/check.vrt'])
-
- custom_crs = 'proj4: +proj=utm +zone=36 +south +a=6378249.145 +b=6356514.966398753 +towgs84=-143,-90,-294,0,0,0,0 +units=m +no_defs'
- cmd = alg.getConsoleCommands({'INPUT': [source],
- 'ASSIGN_CRS': custom_crs,
- 'OUTPUT': outdir + '/check.vrt'}, context, feedback)
+ cmd[1] = (
+ t[: t.find("-input_file_list") + 17]
+ + t[t.find("buildvrtInputFiles.txt") :]
+ )
+ self.assertEqual(
+ cmd,
+ [
+ "gdalbuildvrt",
+ "-overwrite -resolution average -separate -a_srs EPSG:3111 -r nearest "
+ + "-input_file_list buildvrtInputFiles.txt "
+ + outdir
+ + "/check.vrt",
+ ],
+ )
+
+ custom_crs = "proj4: +proj=utm +zone=36 +south +a=6378249.145 +b=6356514.966398753 +towgs84=-143,-90,-294,0,0,0,0 +units=m +no_defs"
+ cmd = alg.getConsoleCommands(
+ {
+ "INPUT": [source],
+ "ASSIGN_CRS": custom_crs,
+ "OUTPUT": outdir + "/check.vrt",
+ },
+ context,
+ feedback,
+ )
t = cmd[1]
- cmd[1] = t[:t.find('-input_file_list') + 17] + t[t.find('buildvrtInputFiles.txt'):]
- self.assertEqual(cmd,
- ['gdalbuildvrt',
- '-overwrite -resolution average -separate -a_srs EPSG:20936 -r nearest ' +
- '-input_file_list buildvrtInputFiles.txt ' +
- outdir + '/check.vrt'])
+ cmd[1] = (
+ t[: t.find("-input_file_list") + 17]
+ + t[t.find("buildvrtInputFiles.txt") :]
+ )
+ self.assertEqual(
+ cmd,
+ [
+ "gdalbuildvrt",
+ "-overwrite -resolution average -separate -a_srs EPSG:20936 -r nearest "
+ + "-input_file_list buildvrtInputFiles.txt "
+ + outdir
+ + "/check.vrt",
+ ],
+ )
# source NODATA
- cmd = alg.getConsoleCommands({'INPUT': [source],
- 'SRC_NODATA': '-9999',
- 'OUTPUT': outdir + '/check.vrt'}, context, feedback)
+ cmd = alg.getConsoleCommands(
+ {
+ "INPUT": [source],
+ "SRC_NODATA": "-9999",
+ "OUTPUT": outdir + "/check.vrt",
+ },
+ context,
+ feedback,
+ )
t = cmd[1]
- cmd[1] = t[:t.find('-input_file_list') + 17] + t[t.find('buildvrtInputFiles.txt'):]
- self.assertEqual(cmd,
- ['gdalbuildvrt',
- '-overwrite -resolution average -separate -r nearest -srcnodata -9999 ' +
- '-input_file_list buildvrtInputFiles.txt ' +
- outdir + '/check.vrt'])
-
- cmd = alg.getConsoleCommands({'INPUT': [source],
- 'SRC_NODATA': '-9999 9999',
- 'OUTPUT': outdir + '/check.vrt'}, context, feedback)
+ cmd[1] = (
+ t[: t.find("-input_file_list") + 17]
+ + t[t.find("buildvrtInputFiles.txt") :]
+ )
+ self.assertEqual(
+ cmd,
+ [
+ "gdalbuildvrt",
+ "-overwrite -resolution average -separate -r nearest -srcnodata -9999 "
+ + "-input_file_list buildvrtInputFiles.txt "
+ + outdir
+ + "/check.vrt",
+ ],
+ )
+
+ cmd = alg.getConsoleCommands(
+ {
+ "INPUT": [source],
+ "SRC_NODATA": "-9999 9999",
+ "OUTPUT": outdir + "/check.vrt",
+ },
+ context,
+ feedback,
+ )
t = cmd[1]
- cmd[1] = t[:t.find('-input_file_list') + 17] + t[t.find('buildvrtInputFiles.txt'):]
- self.assertEqual(cmd,
- ['gdalbuildvrt',
- '-overwrite -resolution average -separate -r nearest -srcnodata "-9999 9999" ' +
- '-input_file_list buildvrtInputFiles.txt ' +
- outdir + '/check.vrt'])
-
- cmd = alg.getConsoleCommands({'INPUT': [source],
- 'SRC_NODATA': '',
- 'OUTPUT': outdir + '/check.vrt'}, context, feedback)
+ cmd[1] = (
+ t[: t.find("-input_file_list") + 17]
+ + t[t.find("buildvrtInputFiles.txt") :]
+ )
+ self.assertEqual(
+ cmd,
+ [
+ "gdalbuildvrt",
+ '-overwrite -resolution average -separate -r nearest -srcnodata "-9999 9999" '
+ + "-input_file_list buildvrtInputFiles.txt "
+ + outdir
+ + "/check.vrt",
+ ],
+ )
+
+ cmd = alg.getConsoleCommands(
+ {"INPUT": [source], "SRC_NODATA": "", "OUTPUT": outdir + "/check.vrt"},
+ context,
+ feedback,
+ )
t = cmd[1]
- cmd[1] = t[:t.find('-input_file_list') + 17] + t[t.find('buildvrtInputFiles.txt'):]
- self.assertEqual(cmd,
- ['gdalbuildvrt',
- '-overwrite -resolution average -separate -r nearest ' +
- '-input_file_list buildvrtInputFiles.txt ' +
- outdir + '/check.vrt'])
+ cmd[1] = (
+ t[: t.find("-input_file_list") + 17]
+ + t[t.find("buildvrtInputFiles.txt") :]
+ )
+ self.assertEqual(
+ cmd,
+ [
+ "gdalbuildvrt",
+ "-overwrite -resolution average -separate -r nearest "
+ + "-input_file_list buildvrtInputFiles.txt "
+ + outdir
+ + "/check.vrt",
+ ],
+ )
# additional parameters
- cmd = alg.getConsoleCommands({'INPUT': [source],
- 'EXTRA': '-overwrite -optim RASTER -vrtnodata -9999',
- 'OUTPUT': outdir + '/check.vrt'}, context, feedback)
+ cmd = alg.getConsoleCommands(
+ {
+ "INPUT": [source],
+ "EXTRA": "-overwrite -optim RASTER -vrtnodata -9999",
+ "OUTPUT": outdir + "/check.vrt",
+ },
+ context,
+ feedback,
+ )
t = cmd[1]
- cmd[1] = t[:t.find('-input_file_list') + 17] + t[t.find('buildvrtInputFiles.txt'):]
- self.assertEqual(cmd,
- ['gdalbuildvrt',
- '-overwrite -resolution average -separate -r nearest -overwrite -optim RASTER -vrtnodata -9999 ' +
- '-input_file_list buildvrtInputFiles.txt ' +
- outdir + '/check.vrt'])
+ cmd[1] = (
+ t[: t.find("-input_file_list") + 17]
+ + t[t.find("buildvrtInputFiles.txt") :]
+ )
+ self.assertEqual(
+ cmd,
+ [
+ "gdalbuildvrt",
+ "-overwrite -resolution average -separate -r nearest -overwrite -optim RASTER -vrtnodata -9999 "
+ + "-input_file_list buildvrtInputFiles.txt "
+ + outdir
+ + "/check.vrt",
+ ],
+ )
def testPct2Rgb(self):
context = QgsProcessingContext()
feedback = QgsProcessingFeedback()
- source = os.path.join(testDataPath, 'dem.tif')
+ source = os.path.join(testDataPath, "dem.tif")
alg = pct2rgb()
alg.initAlgorithm()
with tempfile.TemporaryDirectory() as outdir:
# defaults
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'OUTPUT': outdir + '/check.tif'}, context, feedback),
- ['pct2rgb.py',
- source + ' ' + outdir + '/check.tif ' +
- '-of GTiff -b 1'])
+ alg.getConsoleCommands(
+ {"INPUT": source, "OUTPUT": outdir + "/check.tif"},
+ context,
+ feedback,
+ ),
+ [
+ "pct2rgb.py",
+ source + " " + outdir + "/check.tif " + "-of GTiff -b 1",
+ ],
+ )
# set band
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'BAND': 3,
- 'OUTPUT': outdir + '/check.tif'}, context, feedback),
- ['pct2rgb.py',
- source + ' ' + outdir + '/check.tif ' +
- '-of GTiff -b 3'])
+ alg.getConsoleCommands(
+ {"INPUT": source, "BAND": 3, "OUTPUT": outdir + "/check.tif"},
+ context,
+ feedback,
+ ),
+ [
+ "pct2rgb.py",
+ source + " " + outdir + "/check.tif " + "-of GTiff -b 3",
+ ],
+ )
# set RGBA
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'RGBA': True,
- 'OUTPUT': outdir + '/check.tif'}, context, feedback),
- ['pct2rgb.py',
- source + ' ' + outdir + '/check.tif ' +
- '-of GTiff -b 1 -rgba'])
-
- self.assertEqual(
- alg.getConsoleCommands({'INPUT': source + '|credential:X=Y|credential:Z=A',
- 'OUTPUT': outdir + '/check.tif'}, context, feedback),
- ['pct2rgb.py',
- source + ' ' + outdir + '/check.tif ' +
- '-of GTiff -b 1 --config X Y --config Z A'])
+ alg.getConsoleCommands(
+ {"INPUT": source, "RGBA": True, "OUTPUT": outdir + "/check.tif"},
+ context,
+ feedback,
+ ),
+ [
+ "pct2rgb.py",
+ source + " " + outdir + "/check.tif " + "-of GTiff -b 1 -rgba",
+ ],
+ )
+
+ self.assertEqual(
+ alg.getConsoleCommands(
+ {
+ "INPUT": source + "|credential:X=Y|credential:Z=A",
+ "OUTPUT": outdir + "/check.tif",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "pct2rgb.py",
+ source
+ + " "
+ + outdir
+ + "/check.tif "
+ + "-of GTiff -b 1 --config X Y --config Z A",
+ ],
+ )
def testRgb2Pct(self):
context = QgsProcessingContext()
feedback = QgsProcessingFeedback()
- source = os.path.join(testDataPath, 'dem.tif')
+ source = os.path.join(testDataPath, "dem.tif")
alg = rgb2pct()
alg.initAlgorithm()
with tempfile.TemporaryDirectory() as outdir:
# defaults
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'OUTPUT': outdir + '/check.tif'}, context, feedback),
- ['rgb2pct.py',
- '-n 2 -of GTiff ' + source + ' ' + outdir + '/check.tif'])
+ alg.getConsoleCommands(
+ {"INPUT": source, "OUTPUT": outdir + "/check.tif"},
+ context,
+ feedback,
+ ),
+ [
+ "rgb2pct.py",
+ "-n 2 -of GTiff " + source + " " + outdir + "/check.tif",
+ ],
+ )
# set number of colors
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'NCOLORS': 8,
- 'OUTPUT': outdir + '/check.tif'}, context, feedback),
- ['rgb2pct.py',
- '-n 8 -of GTiff ' + source + ' ' + outdir + '/check.tif'])
-
- self.assertEqual(
- alg.getConsoleCommands({'INPUT': source + '|credential:X=Y|credential:Z=A',
- 'OUTPUT': outdir + '/check.tif'}, context, feedback),
- ['rgb2pct.py',
- '-n 2 -of GTiff ' + source + ' ' + outdir + '/check.tif --config X Y --config Z A'])
+ alg.getConsoleCommands(
+ {"INPUT": source, "NCOLORS": 8, "OUTPUT": outdir + "/check.tif"},
+ context,
+ feedback,
+ ),
+ [
+ "rgb2pct.py",
+ "-n 8 -of GTiff " + source + " " + outdir + "/check.tif",
+ ],
+ )
+
+ self.assertEqual(
+ alg.getConsoleCommands(
+ {
+ "INPUT": source + "|credential:X=Y|credential:Z=A",
+ "OUTPUT": outdir + "/check.tif",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "rgb2pct.py",
+ "-n 2 -of GTiff "
+ + source
+ + " "
+ + outdir
+ + "/check.tif --config X Y --config Z A",
+ ],
+ )
def testRoughness(self):
context = QgsProcessingContext()
feedback = QgsProcessingFeedback()
- source = os.path.join(testDataPath, 'dem.tif')
+ source = os.path.join(testDataPath, "dem.tif")
alg = roughness()
alg.initAlgorithm()
with tempfile.TemporaryDirectory() as outdir:
# defaults
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'OUTPUT': outdir + '/check.tif'}, context, feedback),
- ['gdaldem',
- 'roughness ' + source + ' ' + outdir + '/check.tif ' + '-of GTiff -b 1'])
+ alg.getConsoleCommands(
+ {"INPUT": source, "OUTPUT": outdir + "/check.tif"},
+ context,
+ feedback,
+ ),
+ [
+ "gdaldem",
+ "roughness "
+ + source
+ + " "
+ + outdir
+ + "/check.tif "
+ + "-of GTiff -b 1",
+ ],
+ )
# set band
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'BAND': 3,
- 'OUTPUT': outdir + '/check.tif'}, context, feedback),
- ['gdaldem',
- 'roughness ' + source + ' ' + outdir + '/check.tif ' + '-of GTiff -b 3'])
+ alg.getConsoleCommands(
+ {"INPUT": source, "BAND": 3, "OUTPUT": outdir + "/check.tif"},
+ context,
+ feedback,
+ ),
+ [
+ "gdaldem",
+ "roughness "
+ + source
+ + " "
+ + outdir
+ + "/check.tif "
+ + "-of GTiff -b 3",
+ ],
+ )
# compute edges
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'COMPUTE_EDGES': True,
- 'OUTPUT': outdir + '/check.tif'}, context, feedback),
- ['gdaldem',
- 'roughness ' + source + ' ' + outdir + '/check.tif ' + '-of GTiff -b 1 -compute_edges'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "COMPUTE_EDGES": True,
+ "OUTPUT": outdir + "/check.tif",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdaldem",
+ "roughness "
+ + source
+ + " "
+ + outdir
+ + "/check.tif "
+ + "-of GTiff -b 1 -compute_edges",
+ ],
+ )
# creation options
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'OPTIONS': 'COMPRESS=DEFLATE|PREDICTOR=2|ZLEVEL=9',
- 'OUTPUT': outdir + '/check.tif'}, context, feedback),
- ['gdaldem',
- 'roughness ' + source + ' ' + outdir + '/check.tif ' +
- '-of GTiff -b 1 -co COMPRESS=DEFLATE -co PREDICTOR=2 -co ZLEVEL=9'])
-
- self.assertEqual(
- alg.getConsoleCommands({'INPUT': source + '|credential:X=Y|credential:Z=A',
- 'OUTPUT': outdir + '/check.tif'}, context, feedback),
- ['gdaldem',
- 'roughness ' + source + ' ' + outdir + '/check.tif ' + '-of GTiff -b 1 --config X Y --config Z A'])
-
-
-if __name__ == '__main__':
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "OPTIONS": "COMPRESS=DEFLATE|PREDICTOR=2|ZLEVEL=9",
+ "OUTPUT": outdir + "/check.tif",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdaldem",
+ "roughness "
+ + source
+ + " "
+ + outdir
+ + "/check.tif "
+ + "-of GTiff -b 1 -co COMPRESS=DEFLATE -co PREDICTOR=2 -co ZLEVEL=9",
+ ],
+ )
+
+ self.assertEqual(
+ alg.getConsoleCommands(
+ {
+ "INPUT": source + "|credential:X=Y|credential:Z=A",
+ "OUTPUT": outdir + "/check.tif",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "gdaldem",
+ "roughness "
+ + source
+ + " "
+ + outdir
+ + "/check.tif "
+ + "-of GTiff -b 1 --config X Y --config Z A",
+ ],
+ )
+
+
+if __name__ == "__main__":
nose2.main()
diff --git a/python/plugins/processing/tests/GdalAlgorithmsVectorTest.py b/python/plugins/processing/tests/GdalAlgorithmsVectorTest.py
index c2f535a40fd9..d7f0f7659c85 100644
--- a/python/plugins/processing/tests/GdalAlgorithmsVectorTest.py
+++ b/python/plugins/processing/tests/GdalAlgorithmsVectorTest.py
@@ -15,22 +15,23 @@
***************************************************************************
"""
-__author__ = 'Matthias Kuhn'
-__date__ = 'January 2016'
-__copyright__ = '(C) 2016, Matthias Kuhn'
+__author__ = "Matthias Kuhn"
+__date__ = "January 2016"
+__copyright__ = "(C) 2016, Matthias Kuhn"
import nose2
import os
import shutil
import tempfile
-from qgis.core import (QgsProcessingContext,
- QgsProcessingFeedback,
- QgsCoordinateReferenceSystem,
- QgsRectangle)
+from qgis.core import (
+ QgsProcessingContext,
+ QgsProcessingFeedback,
+ QgsCoordinateReferenceSystem,
+ QgsRectangle,
+)
-from qgis.testing import (QgisTestCase,
- start_app)
+from qgis.testing import QgisTestCase, start_app
import AlgorithmsTestBase
from processing.algs.gdal.ogr2ogr import ogr2ogr
@@ -42,7 +43,7 @@
from processing.algs.gdal.OneSideBuffer import OneSideBuffer
from processing.algs.gdal.PointsAlongLines import PointsAlongLines
-testDataPath = os.path.join(os.path.dirname(__file__), 'testdata')
+testDataPath = os.path.join(os.path.dirname(__file__), "testdata")
class TestGdalVectorAlgorithms(QgisTestCase, AlgorithmsTestBase.AlgorithmsTest):
@@ -51,6 +52,7 @@ class TestGdalVectorAlgorithms(QgisTestCase, AlgorithmsTestBase.AlgorithmsTest):
def setUpClass(cls):
start_app()
from processing.core.Processing import Processing
+
Processing.initialize()
cls.cleanup_paths = []
@@ -60,1080 +62,1801 @@ def tearDownClass(cls):
shutil.rmtree(path)
def definition_file(self):
- return 'gdal_algorithm_vector_tests.yaml'
+ return "gdal_algorithm_vector_tests.yaml"
def testOgr2Ogr(self):
context = QgsProcessingContext()
feedback = QgsProcessingFeedback()
- source = os.path.join(testDataPath, 'polys.gml')
- multi_source = os.path.join(testDataPath, 'multi_layers.gml')
+ source = os.path.join(testDataPath, "polys.gml")
+ multi_source = os.path.join(testDataPath, "multi_layers.gml")
alg = ogr2ogr()
alg.initAlgorithm()
with tempfile.TemporaryDirectory() as outdir:
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'OUTPUT': outdir + '/check.shp'}, context, feedback),
- ['ogr2ogr',
- '-f "ESRI Shapefile" ' + outdir + '/check.shp ' +
- source + ' polys2'])
+ alg.getConsoleCommands(
+ {"INPUT": source, "OUTPUT": outdir + "/check.shp"},
+ context,
+ feedback,
+ ),
+ [
+ "ogr2ogr",
+ '-f "ESRI Shapefile" '
+ + outdir
+ + "/check.shp "
+ + source
+ + " polys2",
+ ],
+ )
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'OUTPUT': outdir + '/check.kml'}, context, feedback),
- ['ogr2ogr',
- '-f "LIBKML" ' + outdir + '/check.kml ' +
- source + ' polys2'])
+ alg.getConsoleCommands(
+ {"INPUT": source, "OUTPUT": outdir + "/check.kml"},
+ context,
+ feedback,
+ ),
+ [
+ "ogr2ogr",
+ '-f "LIBKML" ' + outdir + "/check.kml " + source + " polys2",
+ ],
+ )
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'OUTPUT': outdir + '/my out/check.kml'}, context, feedback),
- ['ogr2ogr',
- '-f "LIBKML" "' + outdir + '/my out/check.kml" ' +
- source + ' polys2'])
+ alg.getConsoleCommands(
+ {"INPUT": source, "OUTPUT": outdir + "/my out/check.kml"},
+ context,
+ feedback,
+ ),
+ [
+ "ogr2ogr",
+ '-f "LIBKML" "'
+ + outdir
+ + '/my out/check.kml" '
+ + source
+ + " polys2",
+ ],
+ )
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'OUTPUT': outdir + '/check.gpkg'}, context, feedback),
- ['ogr2ogr',
- '-f "GPKG" ' + outdir + '/check.gpkg ' +
- source + ' polys2'])
+ alg.getConsoleCommands(
+ {"INPUT": source, "OUTPUT": outdir + "/check.gpkg"},
+ context,
+ feedback,
+ ),
+ [
+ "ogr2ogr",
+ '-f "GPKG" ' + outdir + "/check.gpkg " + source + " polys2",
+ ],
+ )
self.assertEqual(
- alg.getConsoleCommands({'INPUT': multi_source + '|layername=lines',
- 'CONVERT_ALL_LAYERS': False,
- 'OUTPUT': outdir + '/check.gpkg'}, context, feedback),
- ['ogr2ogr',
- '-f "GPKG" ' + outdir + '/check.gpkg ' +
- multi_source + ' lines'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": multi_source + "|layername=lines",
+ "CONVERT_ALL_LAYERS": False,
+ "OUTPUT": outdir + "/check.gpkg",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "ogr2ogr",
+ '-f "GPKG" ' + outdir + "/check.gpkg " + multi_source + " lines",
+ ],
+ )
self.assertEqual(
- alg.getConsoleCommands({'INPUT': multi_source + '|layername=lines',
- 'CONVERT_ALL_LAYERS': True,
- 'OUTPUT': outdir + '/check.gpkg'}, context, feedback),
- ['ogr2ogr',
- '-f "GPKG" ' + outdir + '/check.gpkg ' +
- multi_source])
+ alg.getConsoleCommands(
+ {
+ "INPUT": multi_source + "|layername=lines",
+ "CONVERT_ALL_LAYERS": True,
+ "OUTPUT": outdir + "/check.gpkg",
+ },
+ context,
+ feedback,
+ ),
+ ["ogr2ogr", '-f "GPKG" ' + outdir + "/check.gpkg " + multi_source],
+ )
self.assertEqual(
alg.getConsoleCommands(
- {'INPUT': source + '|option:X_POSSIBLE_NAMES=geom_x|option:Y_POSSIBLE_NAMES=geom_y',
- 'CONVERT_ALL_LAYERS': True,
- 'OUTPUT': outdir + '/check.gpkg'}, context, feedback),
- ['ogr2ogr',
- '-f "GPKG" -oo X_POSSIBLE_NAMES=geom_x -oo Y_POSSIBLE_NAMES=geom_y ' + outdir + '/check.gpkg ' +
- source])
+ {
+ "INPUT": source
+ + "|option:X_POSSIBLE_NAMES=geom_x|option:Y_POSSIBLE_NAMES=geom_y",
+ "CONVERT_ALL_LAYERS": True,
+ "OUTPUT": outdir + "/check.gpkg",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "ogr2ogr",
+ '-f "GPKG" -oo X_POSSIBLE_NAMES=geom_x -oo Y_POSSIBLE_NAMES=geom_y '
+ + outdir
+ + "/check.gpkg "
+ + source,
+ ],
+ )
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source + '|credential:X=Y|credential:Z=A',
- 'CONVERT_ALL_LAYERS': True,
- 'OUTPUT': outdir + '/check.gpkg'}, context, feedback),
- ['ogr2ogr',
- '-f "GPKG" --config X Y --config Z A ' + outdir + '/check.gpkg ' +
- source])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source + "|credential:X=Y|credential:Z=A",
+ "CONVERT_ALL_LAYERS": True,
+ "OUTPUT": outdir + "/check.gpkg",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "ogr2ogr",
+ '-f "GPKG" --config X Y --config Z A '
+ + outdir
+ + "/check.gpkg "
+ + source,
+ ],
+ )
def testOgrInfo(self):
context = QgsProcessingContext()
feedback = QgsProcessingFeedback()
- source = os.path.join(testDataPath, 'polys.gml')
+ source = os.path.join(testDataPath, "polys.gml")
alg = ogrinfo()
alg.initAlgorithm()
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'SUMMARY_ONLY': True,
- 'NO_METADATA': False}, context, feedback),
- ['ogrinfo',
- '-al -so ' +
- source + ' polys2'])
-
- source = os.path.join(testDataPath, 'polys.gml')
+ alg.getConsoleCommands(
+ {"INPUT": source, "SUMMARY_ONLY": True, "NO_METADATA": False},
+ context,
+ feedback,
+ ),
+ ["ogrinfo", "-al -so " + source + " polys2"],
+ )
+
+ source = os.path.join(testDataPath, "polys.gml")
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'ALL_LAYERS': True,
- 'SUMMARY_ONLY': True,
- 'NO_METADATA': False}, context, feedback),
- ['ogrinfo',
- '-al -so ' +
- source])
-
- source = os.path.join(testDataPath, 'polys.gml')
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "ALL_LAYERS": True,
+ "SUMMARY_ONLY": True,
+ "NO_METADATA": False,
+ },
+ context,
+ feedback,
+ ),
+ ["ogrinfo", "-al -so " + source],
+ )
+
+ source = os.path.join(testDataPath, "polys.gml")
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'ALL_LAYERS': True,
- 'SUMMARY_ONLY': True,
- 'EXTRA': '-nocount',
- 'NO_METADATA': False}, context, feedback),
- ['ogrinfo',
- '-al -so -nocount ' +
- source])
-
- source = os.path.join(testDataPath, 'filename with spaces.gml')
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "ALL_LAYERS": True,
+ "SUMMARY_ONLY": True,
+ "EXTRA": "-nocount",
+ "NO_METADATA": False,
+ },
+ context,
+ feedback,
+ ),
+ ["ogrinfo", "-al -so -nocount " + source],
+ )
+
+ source = os.path.join(testDataPath, "filename with spaces.gml")
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'SUMMARY_ONLY': True,
- 'NO_METADATA': False}, context, feedback),
- ['ogrinfo',
- '-al -so "' +
- source + '" filename_with_spaces'])
-
- source = os.path.join(testDataPath, 'filename with spaces.gml')
+ alg.getConsoleCommands(
+ {"INPUT": source, "SUMMARY_ONLY": True, "NO_METADATA": False},
+ context,
+ feedback,
+ ),
+ ["ogrinfo", '-al -so "' + source + '" filename_with_spaces'],
+ )
+
+ source = os.path.join(testDataPath, "filename with spaces.gml")
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'SUMMARY_ONLY': False,
- 'NO_METADATA': False}, context, feedback),
- ['ogrinfo',
- '-al "' +
- source + '" filename_with_spaces'])
-
- source = os.path.join(testDataPath, 'filename with spaces.gml')
+ alg.getConsoleCommands(
+ {"INPUT": source, "SUMMARY_ONLY": False, "NO_METADATA": False},
+ context,
+ feedback,
+ ),
+ ["ogrinfo", '-al "' + source + '" filename_with_spaces'],
+ )
+
+ source = os.path.join(testDataPath, "filename with spaces.gml")
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'SUMMARY_ONLY': True,
- 'NO_METADATA': True}, context, feedback),
- ['ogrinfo',
- '-al -so -nomd "' +
- source + '" filename_with_spaces'])
-
- source = os.path.join(testDataPath, 'filename with spaces.gml')
+ alg.getConsoleCommands(
+ {"INPUT": source, "SUMMARY_ONLY": True, "NO_METADATA": True},
+ context,
+ feedback,
+ ),
+ ["ogrinfo", '-al -so -nomd "' + source + '" filename_with_spaces'],
+ )
+
+ source = os.path.join(testDataPath, "filename with spaces.gml")
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source + '|option:X_POSSIBLE_NAMES=geom_x|option:Y_POSSIBLE_NAMES=geom_y',
- 'SUMMARY_ONLY': True,
- 'NO_METADATA': True}, context, feedback),
- ['ogrinfo',
- '-al -so -nomd "' +
- source + '" filename_with_spaces -oo X_POSSIBLE_NAMES=geom_x -oo Y_POSSIBLE_NAMES=geom_y'])
-
- source = os.path.join(testDataPath, 'filename with spaces.gml')
+ alg.getConsoleCommands(
+ {
+ "INPUT": source
+ + "|option:X_POSSIBLE_NAMES=geom_x|option:Y_POSSIBLE_NAMES=geom_y",
+ "SUMMARY_ONLY": True,
+ "NO_METADATA": True,
+ },
+ context,
+ feedback,
+ ),
+ [
+ "ogrinfo",
+ '-al -so -nomd "'
+ + source
+ + '" filename_with_spaces -oo X_POSSIBLE_NAMES=geom_x -oo Y_POSSIBLE_NAMES=geom_y',
+ ],
+ )
+
+ source = os.path.join(testDataPath, "filename with spaces.gml")
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source + '|credential:X=Y|credential:Z=A',
- 'SUMMARY_ONLY': True,
- 'NO_METADATA': True}, context, feedback),
- ['ogrinfo',
- '-al -so -nomd "' +
- source + '" filename_with_spaces --config X Y --config Z A'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source + "|credential:X=Y|credential:Z=A",
+ "SUMMARY_ONLY": True,
+ "NO_METADATA": True,
+ },
+ context,
+ feedback,
+ ),
+ [
+ "ogrinfo",
+ '-al -so -nomd "'
+ + source
+ + '" filename_with_spaces --config X Y --config Z A',
+ ],
+ )
def testOgrInfoJson(self):
context = QgsProcessingContext()
feedback = QgsProcessingFeedback()
- source = os.path.join(testDataPath, 'polys.gml')
+ source = os.path.join(testDataPath, "polys.gml")
alg = ogrinfojson()
alg.initAlgorithm()
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'FEATURES': True,
- 'NO_METADATA': False}, context, feedback),
- ['ogrinfo',
- '-json -features ' +
- source + ' polys2'])
-
- source = os.path.join(testDataPath, 'polys.gml')
+ alg.getConsoleCommands(
+ {"INPUT": source, "FEATURES": True, "NO_METADATA": False},
+ context,
+ feedback,
+ ),
+ ["ogrinfo", "-json -features " + source + " polys2"],
+ )
+
+ source = os.path.join(testDataPath, "polys.gml")
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'ALL_LAYERS': True,
- 'FEATURES': True,
- 'NO_METADATA': False}, context, feedback),
- ['ogrinfo',
- '-json -features ' +
- source])
-
- source = os.path.join(testDataPath, 'polys.gml')
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "ALL_LAYERS": True,
+ "FEATURES": True,
+ "NO_METADATA": False,
+ },
+ context,
+ feedback,
+ ),
+ ["ogrinfo", "-json -features " + source],
+ )
+
+ source = os.path.join(testDataPath, "polys.gml")
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'ALL_LAYERS': True,
- 'FEATURES': True,
- 'EXTRA': '-nocount',
- 'NO_METADATA': False}, context, feedback),
- ['ogrinfo',
- '-json -features -nocount ' +
- source])
-
- source = os.path.join(testDataPath, 'filename with spaces.gml')
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "ALL_LAYERS": True,
+ "FEATURES": True,
+ "EXTRA": "-nocount",
+ "NO_METADATA": False,
+ },
+ context,
+ feedback,
+ ),
+ ["ogrinfo", "-json -features -nocount " + source],
+ )
+
+ source = os.path.join(testDataPath, "filename with spaces.gml")
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'FEATURES': True,
- 'NO_METADATA': False}, context, feedback),
- ['ogrinfo',
- '-json -features "' +
- source + '" filename_with_spaces'])
-
- source = os.path.join(testDataPath, 'filename with spaces.gml')
+ alg.getConsoleCommands(
+ {"INPUT": source, "FEATURES": True, "NO_METADATA": False},
+ context,
+ feedback,
+ ),
+ ["ogrinfo", '-json -features "' + source + '" filename_with_spaces'],
+ )
+
+ source = os.path.join(testDataPath, "filename with spaces.gml")
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'FEATURES': False,
- 'NO_METADATA': False}, context, feedback),
- ['ogrinfo',
- '-json "' +
- source + '" filename_with_spaces'])
-
- source = os.path.join(testDataPath, 'filename with spaces.gml')
+ alg.getConsoleCommands(
+ {"INPUT": source, "FEATURES": False, "NO_METADATA": False},
+ context,
+ feedback,
+ ),
+ ["ogrinfo", '-json "' + source + '" filename_with_spaces'],
+ )
+
+ source = os.path.join(testDataPath, "filename with spaces.gml")
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'FEATURES': True,
- 'NO_METADATA': True}, context, feedback),
- ['ogrinfo',
- '-json -features -nomd "' +
- source + '" filename_with_spaces'])
-
- source = os.path.join(testDataPath, 'filename with spaces.gml')
+ alg.getConsoleCommands(
+ {"INPUT": source, "FEATURES": True, "NO_METADATA": True},
+ context,
+ feedback,
+ ),
+ ["ogrinfo", '-json -features -nomd "' + source + '" filename_with_spaces'],
+ )
+
+ source = os.path.join(testDataPath, "filename with spaces.gml")
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source + '|option:X_POSSIBLE_NAMES=geom_x|option:Y_POSSIBLE_NAMES=geom_y',
- 'FEATURES': True,
- 'NO_METADATA': True}, context, feedback),
- ['ogrinfo',
- '-json -features -nomd "' +
- source + '" filename_with_spaces -oo X_POSSIBLE_NAMES=geom_x -oo Y_POSSIBLE_NAMES=geom_y'])
-
- source = os.path.join(testDataPath, 'filename with spaces.gml')
+ alg.getConsoleCommands(
+ {
+ "INPUT": source
+ + "|option:X_POSSIBLE_NAMES=geom_x|option:Y_POSSIBLE_NAMES=geom_y",
+ "FEATURES": True,
+ "NO_METADATA": True,
+ },
+ context,
+ feedback,
+ ),
+ [
+ "ogrinfo",
+ '-json -features -nomd "'
+ + source
+ + '" filename_with_spaces -oo X_POSSIBLE_NAMES=geom_x -oo Y_POSSIBLE_NAMES=geom_y',
+ ],
+ )
+
+ source = os.path.join(testDataPath, "filename with spaces.gml")
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source + '|credential:X=Y|credential:Z=A',
- 'FEATURES': True,
- 'NO_METADATA': True}, context, feedback),
- ['ogrinfo',
- '-json -features -nomd "' +
- source + '" filename_with_spaces --config X Y --config Z A'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source + "|credential:X=Y|credential:Z=A",
+ "FEATURES": True,
+ "NO_METADATA": True,
+ },
+ context,
+ feedback,
+ ),
+ [
+ "ogrinfo",
+ '-json -features -nomd "'
+ + source
+ + '" filename_with_spaces --config X Y --config Z A',
+ ],
+ )
def testBuffer(self):
context = QgsProcessingContext()
feedback = QgsProcessingFeedback()
- source = os.path.join(testDataPath, 'polys.gml')
- source_with_space = os.path.join(testDataPath, 'filename with spaces.gml')
+ source = os.path.join(testDataPath, "polys.gml")
+ source_with_space = os.path.join(testDataPath, "filename with spaces.gml")
alg = Buffer()
alg.initAlgorithm()
with tempfile.TemporaryDirectory() as outdir:
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'DISTANCE': 5,
- 'OUTPUT': outdir + '/check.shp'}, context, feedback),
- ['ogr2ogr',
- outdir + '/check.shp ' +
- source + ' ' +
- '-dialect sqlite -sql "SELECT ST_Buffer(geometry, 5.0) AS geometry,* FROM """polys2"""" ' +
- '-f "ESRI Shapefile"'])
+ alg.getConsoleCommands(
+ {"INPUT": source, "DISTANCE": 5, "OUTPUT": outdir + "/check.shp"},
+ context,
+ feedback,
+ ),
+ [
+ "ogr2ogr",
+ outdir
+ + "/check.shp "
+ + source
+ + " "
+ + '-dialect sqlite -sql "SELECT ST_Buffer(geometry, 5.0) AS geometry,* FROM """polys2"""" '
+ + '-f "ESRI Shapefile"',
+ ],
+ )
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'DISTANCE': -5,
- 'OUTPUT': outdir + '/check.shp'}, context, feedback),
- ['ogr2ogr',
- outdir + '/check.shp ' +
- source + ' ' +
- '-dialect sqlite -sql "SELECT ST_Buffer(geometry, -5.0) AS geometry,* FROM """polys2"""" ' +
- '-f "ESRI Shapefile"'])
+ alg.getConsoleCommands(
+ {"INPUT": source, "DISTANCE": -5, "OUTPUT": outdir + "/check.shp"},
+ context,
+ feedback,
+ ),
+ [
+ "ogr2ogr",
+ outdir
+ + "/check.shp "
+ + source
+ + " "
+ + '-dialect sqlite -sql "SELECT ST_Buffer(geometry, -5.0) AS geometry,* FROM """polys2"""" '
+ + '-f "ESRI Shapefile"',
+ ],
+ )
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'DISTANCE': 5,
- 'DISSOLVE': True,
- 'OUTPUT': outdir + '/check.shp'}, context, feedback),
- ['ogr2ogr',
- outdir + '/check.shp ' +
- source + ' ' +
- '-dialect sqlite -sql "SELECT ST_Union(ST_Buffer(geometry, 5.0)) AS geometry,* FROM """polys2"""" ' +
- '-f "ESRI Shapefile"'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "DISTANCE": 5,
+ "DISSOLVE": True,
+ "OUTPUT": outdir + "/check.shp",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "ogr2ogr",
+ outdir
+ + "/check.shp "
+ + source
+ + " "
+ + '-dialect sqlite -sql "SELECT ST_Union(ST_Buffer(geometry, 5.0)) AS geometry,* FROM """polys2"""" '
+ + '-f "ESRI Shapefile"',
+ ],
+ )
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'DISTANCE': 1,
- 'DISSOLVE': True,
- 'EXPLODE_COLLECTIONS': False,
- 'GEOMETRY': 'geom',
- 'OUTPUT': outdir + '/check.shp'}, context, feedback),
- ['ogr2ogr',
- outdir + '/check.shp ' +
- source + ' ' +
- '-dialect sqlite -sql "SELECT ST_Union(ST_Buffer(geom, 1.0)) AS geom,* FROM """polys2"""" ' +
- '-f "ESRI Shapefile"'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "DISTANCE": 1,
+ "DISSOLVE": True,
+ "EXPLODE_COLLECTIONS": False,
+ "GEOMETRY": "geom",
+ "OUTPUT": outdir + "/check.shp",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "ogr2ogr",
+ outdir
+ + "/check.shp "
+ + source
+ + " "
+ + '-dialect sqlite -sql "SELECT ST_Union(ST_Buffer(geom, 1.0)) AS geom,* FROM """polys2"""" '
+ + '-f "ESRI Shapefile"',
+ ],
+ )
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'DISTANCE': 5,
- 'EXPLODE_COLLECTIONS': True,
- 'OUTPUT': outdir + '/check.shp'}, context, feedback),
- ['ogr2ogr',
- outdir + '/check.shp ' +
- source + ' ' +
- '-dialect sqlite -sql "SELECT ST_Buffer(geometry, 5.0) AS geometry,* FROM """polys2"""" ' +
- '-explodecollections -f "ESRI Shapefile"'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "DISTANCE": 5,
+ "EXPLODE_COLLECTIONS": True,
+ "OUTPUT": outdir + "/check.shp",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "ogr2ogr",
+ outdir
+ + "/check.shp "
+ + source
+ + " "
+ + '-dialect sqlite -sql "SELECT ST_Buffer(geometry, 5.0) AS geometry,* FROM """polys2"""" '
+ + '-explodecollections -f "ESRI Shapefile"',
+ ],
+ )
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'DISTANCE': 5,
- 'FIELD': 'total population',
- 'EXPLODE_COLLECTIONS': True,
- 'OUTPUT': outdir + '/check.shp'}, context, feedback),
- ['ogr2ogr',
- outdir + '/check.shp ' +
- source + ' ' +
- '-dialect sqlite -sql "SELECT ST_Union(ST_Buffer(geometry, 5.0)) AS geometry,* FROM """polys2""" GROUP BY """total population"""" ' +
- '-explodecollections -f "ESRI Shapefile"'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "DISTANCE": 5,
+ "FIELD": "total population",
+ "EXPLODE_COLLECTIONS": True,
+ "OUTPUT": outdir + "/check.shp",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "ogr2ogr",
+ outdir
+ + "/check.shp "
+ + source
+ + " "
+ + '-dialect sqlite -sql "SELECT ST_Union(ST_Buffer(geometry, 5.0)) AS geometry,* FROM """polys2""" GROUP BY """total population"""" '
+ + '-explodecollections -f "ESRI Shapefile"',
+ ],
+ )
self.assertEqual(
alg.getConsoleCommands(
- {'INPUT': source + '|option:X_POSSIBLE_NAMES=geom_x|option:Y_POSSIBLE_NAMES=geom_y',
- 'DISTANCE': 5,
- 'OUTPUT': outdir + '/check.shp'}, context, feedback),
- ['ogr2ogr',
- outdir + '/check.shp ' +
- source + ' ' +
- '-dialect sqlite -sql "SELECT ST_Buffer(geometry, 5.0) AS geometry,* FROM """polys2"""" ' +
- '-oo X_POSSIBLE_NAMES=geom_x -oo Y_POSSIBLE_NAMES=geom_y -f "ESRI Shapefile"'])
+ {
+ "INPUT": source
+ + "|option:X_POSSIBLE_NAMES=geom_x|option:Y_POSSIBLE_NAMES=geom_y",
+ "DISTANCE": 5,
+ "OUTPUT": outdir + "/check.shp",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "ogr2ogr",
+ outdir
+ + "/check.shp "
+ + source
+ + " "
+ + '-dialect sqlite -sql "SELECT ST_Buffer(geometry, 5.0) AS geometry,* FROM """polys2"""" '
+ + '-oo X_POSSIBLE_NAMES=geom_x -oo Y_POSSIBLE_NAMES=geom_y -f "ESRI Shapefile"',
+ ],
+ )
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source + '|credential:X=Y|credential:Z=A',
- 'DISTANCE': 5,
- 'OUTPUT': outdir + '/check.shp'}, context, feedback),
- ['ogr2ogr',
- outdir + '/check.shp ' +
- source + ' ' +
- '-dialect sqlite -sql "SELECT ST_Buffer(geometry, 5.0) AS geometry,* FROM """polys2"""" ' +
- '--config X Y --config Z A -f "ESRI Shapefile"'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source + "|credential:X=Y|credential:Z=A",
+ "DISTANCE": 5,
+ "OUTPUT": outdir + "/check.shp",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "ogr2ogr",
+ outdir
+ + "/check.shp "
+ + source
+ + " "
+ + '-dialect sqlite -sql "SELECT ST_Buffer(geometry, 5.0) AS geometry,* FROM """polys2"""" '
+ + '--config X Y --config Z A -f "ESRI Shapefile"',
+ ],
+ )
def testDissolve(self):
context = QgsProcessingContext()
feedback = QgsProcessingFeedback()
- source = os.path.join(testDataPath, 'polys.gml')
- source_with_space = os.path.join(testDataPath, 'filename with spaces.gml')
+ source = os.path.join(testDataPath, "polys.gml")
+ source_with_space = os.path.join(testDataPath, "filename with spaces.gml")
alg = Dissolve()
alg.initAlgorithm()
with tempfile.TemporaryDirectory() as outdir:
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'OUTPUT': outdir + '/check.shp'}, context, feedback),
- ['ogr2ogr',
- outdir + '/check.shp ' +
- source + ' ' +
- '-nlt PROMOTE_TO_MULTI -dialect sqlite -sql "SELECT ST_Union(geometry) AS geometry FROM """polys2"""" ' +
- '-f "ESRI Shapefile"'])
+ alg.getConsoleCommands(
+ {"INPUT": source, "OUTPUT": outdir + "/check.shp"},
+ context,
+ feedback,
+ ),
+ [
+ "ogr2ogr",
+ outdir
+ + "/check.shp "
+ + source
+ + " "
+ + '-nlt PROMOTE_TO_MULTI -dialect sqlite -sql "SELECT ST_Union(geometry) AS geometry FROM """polys2"""" '
+ + '-f "ESRI Shapefile"',
+ ],
+ )
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'FIELD': 'my_field',
- 'OUTPUT': outdir + '/check.shp'}, context, feedback),
- ['ogr2ogr',
- outdir + '/check.shp ' +
- source + ' ' +
- '-nlt PROMOTE_TO_MULTI -dialect sqlite -sql "SELECT ST_Union(geometry) AS geometry, """my_field""" FROM """polys2""" ' +
- 'GROUP BY """my_field"""" -f "ESRI Shapefile"'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "FIELD": "my_field",
+ "OUTPUT": outdir + "/check.shp",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "ogr2ogr",
+ outdir
+ + "/check.shp "
+ + source
+ + " "
+ + '-nlt PROMOTE_TO_MULTI -dialect sqlite -sql "SELECT ST_Union(geometry) AS geometry, """my_field""" FROM """polys2""" '
+ + 'GROUP BY """my_field"""" -f "ESRI Shapefile"',
+ ],
+ )
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'FIELD': 'total population',
- 'OUTPUT': outdir + '/check.shp'}, context, feedback),
- ['ogr2ogr',
- outdir + '/check.shp ' +
- source + ' ' +
- '-nlt PROMOTE_TO_MULTI -dialect sqlite -sql "SELECT ST_Union(geometry) AS geometry, """total population""" FROM """polys2""" ' +
- 'GROUP BY """total population"""" -f "ESRI Shapefile"'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "FIELD": "total population",
+ "OUTPUT": outdir + "/check.shp",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "ogr2ogr",
+ outdir
+ + "/check.shp "
+ + source
+ + " "
+ + '-nlt PROMOTE_TO_MULTI -dialect sqlite -sql "SELECT ST_Union(geometry) AS geometry, """total population""" FROM """polys2""" '
+ + 'GROUP BY """total population"""" -f "ESRI Shapefile"',
+ ],
+ )
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source_with_space,
- 'FIELD': 'my_field',
- 'OUTPUT': outdir + '/check.shp'}, context, feedback),
- ['ogr2ogr',
- outdir + '/check.shp ' +
- '"' + source_with_space + '" ' +
- '-nlt PROMOTE_TO_MULTI -dialect sqlite -sql "SELECT ST_Union(geometry) AS geometry, """my_field""" FROM """filename_with_spaces""" ' +
- 'GROUP BY """my_field"""" -f "ESRI Shapefile"'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source_with_space,
+ "FIELD": "my_field",
+ "OUTPUT": outdir + "/check.shp",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "ogr2ogr",
+ outdir
+ + "/check.shp "
+ + '"'
+ + source_with_space
+ + '" '
+ + '-nlt PROMOTE_TO_MULTI -dialect sqlite -sql "SELECT ST_Union(geometry) AS geometry, """my_field""" FROM """filename_with_spaces""" '
+ + 'GROUP BY """my_field"""" -f "ESRI Shapefile"',
+ ],
+ )
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'FIELD': 'my_field',
- 'GEOMETRY': 'the_geom',
- 'OUTPUT': outdir + '/check.shp'}, context, feedback),
- ['ogr2ogr',
- outdir + '/check.shp ' +
- source + ' ' +
- '-nlt PROMOTE_TO_MULTI -dialect sqlite -sql "SELECT ST_Union(the_geom) AS the_geom, """my_field""" FROM """polys2""" ' +
- 'GROUP BY """my_field"""" -f "ESRI Shapefile"'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "FIELD": "my_field",
+ "GEOMETRY": "the_geom",
+ "OUTPUT": outdir + "/check.shp",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "ogr2ogr",
+ outdir
+ + "/check.shp "
+ + source
+ + " "
+ + '-nlt PROMOTE_TO_MULTI -dialect sqlite -sql "SELECT ST_Union(the_geom) AS the_geom, """my_field""" FROM """polys2""" '
+ + 'GROUP BY """my_field"""" -f "ESRI Shapefile"',
+ ],
+ )
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'FIELD': 'my_field',
- 'KEEP_ATTRIBUTES': False,
- 'OUTPUT': outdir + '/check.shp'}, context, feedback),
- ['ogr2ogr',
- outdir + '/check.shp ' +
- source + ' ' +
- '-nlt PROMOTE_TO_MULTI -dialect sqlite -sql "SELECT ST_Union(geometry) AS geometry, """my_field""" FROM """polys2""" ' +
- 'GROUP BY """my_field"""" -f "ESRI Shapefile"'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "FIELD": "my_field",
+ "KEEP_ATTRIBUTES": False,
+ "OUTPUT": outdir + "/check.shp",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "ogr2ogr",
+ outdir
+ + "/check.shp "
+ + source
+ + " "
+ + '-nlt PROMOTE_TO_MULTI -dialect sqlite -sql "SELECT ST_Union(geometry) AS geometry, """my_field""" FROM """polys2""" '
+ + 'GROUP BY """my_field"""" -f "ESRI Shapefile"',
+ ],
+ )
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'KEEP_ATTRIBUTES': False,
- 'OUTPUT': outdir + '/check.shp'}, context, feedback),
- ['ogr2ogr',
- outdir + '/check.shp ' +
- source + ' ' +
- '-nlt PROMOTE_TO_MULTI -dialect sqlite -sql "SELECT ST_Union(geometry) AS geometry FROM """polys2"""" ' +
- '-f "ESRI Shapefile"'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "KEEP_ATTRIBUTES": False,
+ "OUTPUT": outdir + "/check.shp",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "ogr2ogr",
+ outdir
+ + "/check.shp "
+ + source
+ + " "
+ + '-nlt PROMOTE_TO_MULTI -dialect sqlite -sql "SELECT ST_Union(geometry) AS geometry FROM """polys2"""" '
+ + '-f "ESRI Shapefile"',
+ ],
+ )
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'FIELD': 'my_field',
- 'EXPLODE_COLLECTIONS': True,
- 'OUTPUT': outdir + '/check.shp'}, context, feedback),
- ['ogr2ogr',
- outdir + '/check.shp ' +
- source + ' ' +
- '-nlt PROMOTE_TO_MULTI -dialect sqlite -sql "SELECT ST_Union(geometry) AS geometry, """my_field""" FROM """polys2""" ' +
- 'GROUP BY """my_field"""" -explodecollections -f "ESRI Shapefile"'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "FIELD": "my_field",
+ "EXPLODE_COLLECTIONS": True,
+ "OUTPUT": outdir + "/check.shp",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "ogr2ogr",
+ outdir
+ + "/check.shp "
+ + source
+ + " "
+ + '-nlt PROMOTE_TO_MULTI -dialect sqlite -sql "SELECT ST_Union(geometry) AS geometry, """my_field""" FROM """polys2""" '
+ + 'GROUP BY """my_field"""" -explodecollections -f "ESRI Shapefile"',
+ ],
+ )
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'FIELD': 'my_field',
- 'COUNT_FEATURES': True,
- 'OUTPUT': outdir + '/check.shp'}, context, feedback),
- ['ogr2ogr',
- outdir + '/check.shp ' +
- source + ' ' +
- '-nlt PROMOTE_TO_MULTI -dialect sqlite -sql "SELECT ST_Union(geometry) AS geometry, """my_field""", COUNT(geometry) AS count FROM """polys2""" ' +
- 'GROUP BY """my_field"""" -f "ESRI Shapefile"'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "FIELD": "my_field",
+ "COUNT_FEATURES": True,
+ "OUTPUT": outdir + "/check.shp",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "ogr2ogr",
+ outdir
+ + "/check.shp "
+ + source
+ + " "
+ + '-nlt PROMOTE_TO_MULTI -dialect sqlite -sql "SELECT ST_Union(geometry) AS geometry, """my_field""", COUNT(geometry) AS count FROM """polys2""" '
+ + 'GROUP BY """my_field"""" -f "ESRI Shapefile"',
+ ],
+ )
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'FIELD': 'my_field',
- 'COUNT_FEATURES': True,
- 'GEOMETRY': 'the_geom',
- 'OUTPUT': outdir + '/check.shp'}, context, feedback),
- ['ogr2ogr',
- outdir + '/check.shp ' +
- source + ' ' +
- '-nlt PROMOTE_TO_MULTI -dialect sqlite -sql "SELECT ST_Union(the_geom) AS the_geom, """my_field""", COUNT(the_geom) AS count FROM """polys2""" ' +
- 'GROUP BY """my_field"""" -f "ESRI Shapefile"'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "FIELD": "my_field",
+ "COUNT_FEATURES": True,
+ "GEOMETRY": "the_geom",
+ "OUTPUT": outdir + "/check.shp",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "ogr2ogr",
+ outdir
+ + "/check.shp "
+ + source
+ + " "
+ + '-nlt PROMOTE_TO_MULTI -dialect sqlite -sql "SELECT ST_Union(the_geom) AS the_geom, """my_field""", COUNT(the_geom) AS count FROM """polys2""" '
+ + 'GROUP BY """my_field"""" -f "ESRI Shapefile"',
+ ],
+ )
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'FIELD': 'my_field',
- 'COMPUTE_AREA': True,
- 'OUTPUT': outdir + '/check.shp'}, context, feedback),
- ['ogr2ogr',
- outdir + '/check.shp ' +
- source + ' ' +
- '-nlt PROMOTE_TO_MULTI -dialect sqlite -sql "SELECT ST_Union(geometry) AS geometry, """my_field""", SUM(ST_Area(geometry)) AS area, ' +
- 'ST_Perimeter(ST_Union(geometry)) AS perimeter FROM """polys2""" ' +
- 'GROUP BY """my_field"""" -f "ESRI Shapefile"'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "FIELD": "my_field",
+ "COMPUTE_AREA": True,
+ "OUTPUT": outdir + "/check.shp",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "ogr2ogr",
+ outdir
+ + "/check.shp "
+ + source
+ + " "
+ + '-nlt PROMOTE_TO_MULTI -dialect sqlite -sql "SELECT ST_Union(geometry) AS geometry, """my_field""", SUM(ST_Area(geometry)) AS area, '
+ + 'ST_Perimeter(ST_Union(geometry)) AS perimeter FROM """polys2""" '
+ + 'GROUP BY """my_field"""" -f "ESRI Shapefile"',
+ ],
+ )
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'FIELD': 'my_field',
- 'COMPUTE_AREA': True,
- 'GEOMETRY': 'the_geom',
- 'OUTPUT': outdir + '/check.shp'}, context, feedback),
- ['ogr2ogr',
- outdir + '/check.shp ' +
- source + ' ' +
- '-nlt PROMOTE_TO_MULTI -dialect sqlite -sql "SELECT ST_Union(the_geom) AS the_geom, """my_field""", SUM(ST_Area(the_geom)) AS area, ' +
- 'ST_Perimeter(ST_Union(the_geom)) AS perimeter FROM """polys2""" ' +
- 'GROUP BY """my_field"""" -f "ESRI Shapefile"'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "FIELD": "my_field",
+ "COMPUTE_AREA": True,
+ "GEOMETRY": "the_geom",
+ "OUTPUT": outdir + "/check.shp",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "ogr2ogr",
+ outdir
+ + "/check.shp "
+ + source
+ + " "
+ + '-nlt PROMOTE_TO_MULTI -dialect sqlite -sql "SELECT ST_Union(the_geom) AS the_geom, """my_field""", SUM(ST_Area(the_geom)) AS area, '
+ + 'ST_Perimeter(ST_Union(the_geom)) AS perimeter FROM """polys2""" '
+ + 'GROUP BY """my_field"""" -f "ESRI Shapefile"',
+ ],
+ )
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'FIELD': 'my_field',
- 'COMPUTE_STATISTICS': True,
- 'STATISTICS_ATTRIBUTE': 'my_val',
- 'OUTPUT': outdir + '/check.shp'}, context, feedback),
- ['ogr2ogr',
- outdir + '/check.shp ' +
- source + ' ' +
- '-nlt PROMOTE_TO_MULTI -dialect sqlite -sql "SELECT ST_Union(geometry) AS geometry, """my_field""", ' +
- 'SUM("""my_val""") AS sum, MIN("""my_val""") AS min, MAX("""my_val""") AS max, AVG("""my_val""") AS avg FROM """polys2""" ' +
- 'GROUP BY """my_field"""" -f "ESRI Shapefile"'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "FIELD": "my_field",
+ "COMPUTE_STATISTICS": True,
+ "STATISTICS_ATTRIBUTE": "my_val",
+ "OUTPUT": outdir + "/check.shp",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "ogr2ogr",
+ outdir
+ + "/check.shp "
+ + source
+ + " "
+ + '-nlt PROMOTE_TO_MULTI -dialect sqlite -sql "SELECT ST_Union(geometry) AS geometry, """my_field""", '
+ + 'SUM("""my_val""") AS sum, MIN("""my_val""") AS min, MAX("""my_val""") AS max, AVG("""my_val""") AS avg FROM """polys2""" '
+ + 'GROUP BY """my_field"""" -f "ESRI Shapefile"',
+ ],
+ )
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'FIELD': 'test field',
- 'COMPUTE_STATISTICS': True,
- 'STATISTICS_ATTRIBUTE': 'total population',
- 'OUTPUT': outdir + '/check.shp'}, context, feedback),
- ['ogr2ogr',
- outdir + '/check.shp ' +
- source + ' ' +
- '-nlt PROMOTE_TO_MULTI -dialect sqlite -sql "SELECT ST_Union(geometry) AS geometry, """test field""", ' +
- 'SUM("""total population""") AS sum, MIN("""total population""") AS min, MAX("""total population""") AS max, ' +
- 'AVG("""total population""") AS avg FROM """polys2""" ' +
- 'GROUP BY """test field"""" -f "ESRI Shapefile"'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "FIELD": "test field",
+ "COMPUTE_STATISTICS": True,
+ "STATISTICS_ATTRIBUTE": "total population",
+ "OUTPUT": outdir + "/check.shp",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "ogr2ogr",
+ outdir
+ + "/check.shp "
+ + source
+ + " "
+ + '-nlt PROMOTE_TO_MULTI -dialect sqlite -sql "SELECT ST_Union(geometry) AS geometry, """test field""", '
+ + 'SUM("""total population""") AS sum, MIN("""total population""") AS min, MAX("""total population""") AS max, '
+ + 'AVG("""total population""") AS avg FROM """polys2""" '
+ + 'GROUP BY """test field"""" -f "ESRI Shapefile"',
+ ],
+ )
# compute stats without stats attribute, and vice versa (should be ignored)
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'FIELD': 'my_field',
- 'COMPUTE_STATISTICS': True,
- 'OUTPUT': outdir + '/check.shp'}, context, feedback),
- ['ogr2ogr',
- outdir + '/check.shp ' +
- source + ' ' +
- '-nlt PROMOTE_TO_MULTI -dialect sqlite -sql "SELECT ST_Union(geometry) AS geometry, """my_field""" FROM """polys2""" ' +
- 'GROUP BY """my_field"""" -f "ESRI Shapefile"'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "FIELD": "my_field",
+ "COMPUTE_STATISTICS": True,
+ "OUTPUT": outdir + "/check.shp",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "ogr2ogr",
+ outdir
+ + "/check.shp "
+ + source
+ + " "
+ + '-nlt PROMOTE_TO_MULTI -dialect sqlite -sql "SELECT ST_Union(geometry) AS geometry, """my_field""" FROM """polys2""" '
+ + 'GROUP BY """my_field"""" -f "ESRI Shapefile"',
+ ],
+ )
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'FIELD': 'my_field',
- 'STATISTICS_ATTRIBUTE': 'my_val',
- 'OUTPUT': outdir + '/check.shp'}, context, feedback),
- ['ogr2ogr',
- outdir + '/check.shp ' +
- source + ' ' +
- '-nlt PROMOTE_TO_MULTI -dialect sqlite -sql "SELECT ST_Union(geometry) AS geometry, """my_field""" FROM """polys2""" ' +
- 'GROUP BY """my_field"""" -f "ESRI Shapefile"'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "FIELD": "my_field",
+ "STATISTICS_ATTRIBUTE": "my_val",
+ "OUTPUT": outdir + "/check.shp",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "ogr2ogr",
+ outdir
+ + "/check.shp "
+ + source
+ + " "
+ + '-nlt PROMOTE_TO_MULTI -dialect sqlite -sql "SELECT ST_Union(geometry) AS geometry, """my_field""" FROM """polys2""" '
+ + 'GROUP BY """my_field"""" -f "ESRI Shapefile"',
+ ],
+ )
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'FIELD': 'my_field',
- 'OPTIONS': 'my opts',
- 'OUTPUT': outdir + '/check.shp'}, context, feedback),
- ['ogr2ogr',
- outdir + '/check.shp ' +
- source + ' ' +
- '-nlt PROMOTE_TO_MULTI -dialect sqlite -sql "SELECT ST_Union(geometry) AS geometry, """my_field""" FROM """polys2""" ' +
- 'GROUP BY """my_field"""" "my opts" -f "ESRI Shapefile"'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "FIELD": "my_field",
+ "OPTIONS": "my opts",
+ "OUTPUT": outdir + "/check.shp",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "ogr2ogr",
+ outdir
+ + "/check.shp "
+ + source
+ + " "
+ + '-nlt PROMOTE_TO_MULTI -dialect sqlite -sql "SELECT ST_Union(geometry) AS geometry, """my_field""" FROM """polys2""" '
+ + 'GROUP BY """my_field"""" "my opts" -f "ESRI Shapefile"',
+ ],
+ )
self.assertEqual(
alg.getConsoleCommands(
- {'INPUT': source + '|option:X_POSSIBLE_NAMES=geom_x|option:Y_POSSIBLE_NAMES=geom_y',
- 'FIELD': 'my_field',
- 'OPTIONS': 'my opts',
- 'OUTPUT': outdir + '/check.shp'}, context, feedback),
- ['ogr2ogr',
- outdir + '/check.shp ' +
- source + ' ' +
- '-nlt PROMOTE_TO_MULTI -dialect sqlite -sql "SELECT ST_Union(geometry) AS geometry, """my_field""" FROM """polys2""" ' +
- 'GROUP BY """my_field"""" -oo X_POSSIBLE_NAMES=geom_x -oo Y_POSSIBLE_NAMES=geom_y "my opts" -f "ESRI Shapefile"'])
+ {
+ "INPUT": source
+ + "|option:X_POSSIBLE_NAMES=geom_x|option:Y_POSSIBLE_NAMES=geom_y",
+ "FIELD": "my_field",
+ "OPTIONS": "my opts",
+ "OUTPUT": outdir + "/check.shp",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "ogr2ogr",
+ outdir
+ + "/check.shp "
+ + source
+ + " "
+ + '-nlt PROMOTE_TO_MULTI -dialect sqlite -sql "SELECT ST_Union(geometry) AS geometry, """my_field""" FROM """polys2""" '
+ + 'GROUP BY """my_field"""" -oo X_POSSIBLE_NAMES=geom_x -oo Y_POSSIBLE_NAMES=geom_y "my opts" -f "ESRI Shapefile"',
+ ],
+ )
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source + '|credential:X=Y|credential:Z=A',
- 'FIELD': 'my_field',
- 'OPTIONS': 'my opts',
- 'OUTPUT': outdir + '/check.shp'}, context, feedback),
- ['ogr2ogr',
- outdir + '/check.shp ' +
- source + ' ' +
- '-nlt PROMOTE_TO_MULTI -dialect sqlite -sql "SELECT ST_Union(geometry) AS geometry, """my_field""" FROM """polys2""" ' +
- 'GROUP BY """my_field"""" --config X Y --config Z A "my opts" -f "ESRI Shapefile"'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source + "|credential:X=Y|credential:Z=A",
+ "FIELD": "my_field",
+ "OPTIONS": "my opts",
+ "OUTPUT": outdir + "/check.shp",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "ogr2ogr",
+ outdir
+ + "/check.shp "
+ + source
+ + " "
+ + '-nlt PROMOTE_TO_MULTI -dialect sqlite -sql "SELECT ST_Union(geometry) AS geometry, """my_field""" FROM """polys2""" '
+ + 'GROUP BY """my_field"""" --config X Y --config Z A "my opts" -f "ESRI Shapefile"',
+ ],
+ )
def testOgr2PostGis(self):
context = QgsProcessingContext()
feedback = QgsProcessingFeedback()
- source = os.path.join(testDataPath, 'polys.gml')
- source_line = os.path.join(testDataPath, 'multilines.gml')
- source_with_space = os.path.join(testDataPath, 'filename with spaces.gml')
+ source = os.path.join(testDataPath, "polys.gml")
+ source_line = os.path.join(testDataPath, "multilines.gml")
+ source_with_space = os.path.join(testDataPath, "filename with spaces.gml")
alg = OgrToPostGis()
alg.initAlgorithm()
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source}, context, feedback),
- ['ogr2ogr',
- '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
- '-lco DIM=2 ' + source + ' polys2 '
- '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -nlt PROMOTE_TO_MULTI'])
+ alg.getConsoleCommands({"INPUT": source}, context, feedback),
+ [
+ "ogr2ogr",
+ '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
+ "-lco DIM=2 " + source + " polys2 "
+ "-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -nlt PROMOTE_TO_MULTI",
+ ],
+ )
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source_with_space}, context, feedback),
- ['ogr2ogr',
- '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
- '-lco DIM=2 "' + source_with_space + '" filename_with_spaces '
- '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.filename_with_spaces -nlt PROMOTE_TO_MULTI'])
+ alg.getConsoleCommands({"INPUT": source_with_space}, context, feedback),
+ [
+ "ogr2ogr",
+ '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
+ '-lco DIM=2 "' + source_with_space + '" filename_with_spaces '
+ "-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.filename_with_spaces -nlt PROMOTE_TO_MULTI",
+ ],
+ )
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'HOST': 'google.com'}, context, feedback),
- ['ogr2ogr',
- '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=google.com port=5432 active_schema=public" '
- '-lco DIM=2 ' + source + ' polys2 '
- '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -nlt PROMOTE_TO_MULTI'])
+ alg.getConsoleCommands(
+ {"INPUT": source, "HOST": "google.com"}, context, feedback
+ ),
+ [
+ "ogr2ogr",
+ '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=google.com port=5432 active_schema=public" '
+ "-lco DIM=2 " + source + " polys2 "
+ "-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -nlt PROMOTE_TO_MULTI",
+ ],
+ )
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'PORT': 3333}, context, feedback),
- ['ogr2ogr',
- '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=3333 active_schema=public" '
- '-lco DIM=2 ' + source + ' polys2 '
- '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -nlt PROMOTE_TO_MULTI'])
+ alg.getConsoleCommands({"INPUT": source, "PORT": 3333}, context, feedback),
+ [
+ "ogr2ogr",
+ '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=3333 active_schema=public" '
+ "-lco DIM=2 " + source + " polys2 "
+ "-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -nlt PROMOTE_TO_MULTI",
+ ],
+ )
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'USER': 'kevin_bacon'}, context, feedback),
- ['ogr2ogr',
- '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public user=kevin_bacon" '
- '-lco DIM=2 ' + source + ' polys2 '
- '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -nlt PROMOTE_TO_MULTI'])
+ alg.getConsoleCommands(
+ {"INPUT": source, "USER": "kevin_bacon"}, context, feedback
+ ),
+ [
+ "ogr2ogr",
+ '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public user=kevin_bacon" '
+ "-lco DIM=2 " + source + " polys2 "
+ "-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -nlt PROMOTE_TO_MULTI",
+ ],
+ )
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'DBNAME': 'secret_stuff'}, context, feedback),
- ['ogr2ogr',
- '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 dbname=secret_stuff active_schema=public" '
- '-lco DIM=2 ' + source + ' polys2 '
- '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -nlt PROMOTE_TO_MULTI'])
+ alg.getConsoleCommands(
+ {"INPUT": source, "DBNAME": "secret_stuff"}, context, feedback
+ ),
+ [
+ "ogr2ogr",
+ '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 dbname=secret_stuff active_schema=public" '
+ "-lco DIM=2 " + source + " polys2 "
+ "-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -nlt PROMOTE_TO_MULTI",
+ ],
+ )
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'PASSWORD': 'passw0rd'}, context, feedback),
- ['ogr2ogr',
- '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 password=passw0rd active_schema=public" '
- '-lco DIM=2 ' + source + ' polys2 '
- '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -nlt PROMOTE_TO_MULTI'])
+ alg.getConsoleCommands(
+ {"INPUT": source, "PASSWORD": "passw0rd"}, context, feedback
+ ),
+ [
+ "ogr2ogr",
+ '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 password=passw0rd active_schema=public" '
+ "-lco DIM=2 " + source + " polys2 "
+ "-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -nlt PROMOTE_TO_MULTI",
+ ],
+ )
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'SCHEMA': 'desktop'}, context, feedback),
- ['ogr2ogr',
- '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=desktop" '
- '-lco DIM=2 ' + source + ' polys2 '
- '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln desktop.polys2 -nlt PROMOTE_TO_MULTI'])
+ alg.getConsoleCommands(
+ {"INPUT": source, "SCHEMA": "desktop"}, context, feedback
+ ),
+ [
+ "ogr2ogr",
+ '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=desktop" '
+ "-lco DIM=2 " + source + " polys2 "
+ "-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln desktop.polys2 -nlt PROMOTE_TO_MULTI",
+ ],
+ )
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'TABLE': 'out_table'}, context, feedback),
- ['ogr2ogr',
- '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
- '-lco DIM=2 ' + source + ' polys2 '
- '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.out_table -nlt PROMOTE_TO_MULTI'])
+ alg.getConsoleCommands(
+ {"INPUT": source, "TABLE": "out_table"}, context, feedback
+ ),
+ [
+ "ogr2ogr",
+ '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
+ "-lco DIM=2 " + source + " polys2 "
+ "-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.out_table -nlt PROMOTE_TO_MULTI",
+ ],
+ )
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'PK': ''}, context, feedback),
- ['ogr2ogr',
- '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
- '-lco DIM=2 ' + source + ' polys2 '
- '-overwrite -lco GEOMETRY_NAME=geom -nln public.polys2 -nlt PROMOTE_TO_MULTI'])
+ alg.getConsoleCommands({"INPUT": source, "PK": ""}, context, feedback),
+ [
+ "ogr2ogr",
+ '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
+ "-lco DIM=2 " + source + " polys2 "
+ "-overwrite -lco GEOMETRY_NAME=geom -nln public.polys2 -nlt PROMOTE_TO_MULTI",
+ ],
+ )
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'PK': 'new_fid'}, context, feedback),
- ['ogr2ogr',
- '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
- '-lco DIM=2 ' + source + ' polys2 '
- '-overwrite -lco GEOMETRY_NAME=geom -lco FID=new_fid -nln public.polys2 -nlt PROMOTE_TO_MULTI'])
+ alg.getConsoleCommands(
+ {"INPUT": source, "PK": "new_fid"}, context, feedback
+ ),
+ [
+ "ogr2ogr",
+ '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
+ "-lco DIM=2 " + source + " polys2 "
+ "-overwrite -lco GEOMETRY_NAME=geom -lco FID=new_fid -nln public.polys2 -nlt PROMOTE_TO_MULTI",
+ ],
+ )
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'PK': '',
- 'PRIMARY_KEY': 'objectid'}, context, feedback),
- ['ogr2ogr',
- '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
- '-lco DIM=2 ' + source + ' polys2 '
- '-overwrite -lco GEOMETRY_NAME=geom -lco FID=objectid -nln public.polys2 -nlt PROMOTE_TO_MULTI'])
+ alg.getConsoleCommands(
+ {"INPUT": source, "PK": "", "PRIMARY_KEY": "objectid"},
+ context,
+ feedback,
+ ),
+ [
+ "ogr2ogr",
+ '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
+ "-lco DIM=2 " + source + " polys2 "
+ "-overwrite -lco GEOMETRY_NAME=geom -lco FID=objectid -nln public.polys2 -nlt PROMOTE_TO_MULTI",
+ ],
+ )
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'PK': 'new_id',
- 'PRIMARY_KEY': 'objectid'}, context, feedback),
- ['ogr2ogr',
- '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
- '-lco DIM=2 ' + source + ' polys2 '
- '-overwrite -lco GEOMETRY_NAME=geom -lco FID=new_id -nln public.polys2 -nlt PROMOTE_TO_MULTI'])
+ alg.getConsoleCommands(
+ {"INPUT": source, "PK": "new_id", "PRIMARY_KEY": "objectid"},
+ context,
+ feedback,
+ ),
+ [
+ "ogr2ogr",
+ '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
+ "-lco DIM=2 " + source + " polys2 "
+ "-overwrite -lco GEOMETRY_NAME=geom -lco FID=new_id -nln public.polys2 -nlt PROMOTE_TO_MULTI",
+ ],
+ )
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'GEOCOLUMN': 'my_geom'}, context, feedback),
- ['ogr2ogr',
- '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
- '-lco DIM=2 ' + source + ' polys2 '
- '-overwrite -lco GEOMETRY_NAME=my_geom -lco FID=id -nln public.polys2 -nlt PROMOTE_TO_MULTI'])
+ alg.getConsoleCommands(
+ {"INPUT": source, "GEOCOLUMN": "my_geom"}, context, feedback
+ ),
+ [
+ "ogr2ogr",
+ '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
+ "-lco DIM=2 " + source + " polys2 "
+ "-overwrite -lco GEOMETRY_NAME=my_geom -lco FID=id -nln public.polys2 -nlt PROMOTE_TO_MULTI",
+ ],
+ )
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'DIM': 1}, context, feedback),
- ['ogr2ogr',
- '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
- '-lco DIM=3 ' + source + ' polys2 '
- '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -nlt PROMOTE_TO_MULTI'])
+ alg.getConsoleCommands({"INPUT": source, "DIM": 1}, context, feedback),
+ [
+ "ogr2ogr",
+ '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
+ "-lco DIM=3 " + source + " polys2 "
+ "-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -nlt PROMOTE_TO_MULTI",
+ ],
+ )
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'SIMPLIFY': 5}, context, feedback),
- ['ogr2ogr',
- '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
- '-lco DIM=2 ' + source + ' polys2 '
- '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -simplify 5 -nlt PROMOTE_TO_MULTI'])
+ alg.getConsoleCommands({"INPUT": source, "SIMPLIFY": 5}, context, feedback),
+ [
+ "ogr2ogr",
+ '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
+ "-lco DIM=2 " + source + " polys2 "
+ "-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -simplify 5 -nlt PROMOTE_TO_MULTI",
+ ],
+ )
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'SEGMENTIZE': 4}, context, feedback),
- ['ogr2ogr',
- '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
- '-lco DIM=2 ' + source + ' polys2 '
- '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -segmentize 4 -nlt PROMOTE_TO_MULTI'])
+ alg.getConsoleCommands(
+ {"INPUT": source, "SEGMENTIZE": 4}, context, feedback
+ ),
+ [
+ "ogr2ogr",
+ '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
+ "-lco DIM=2 " + source + " polys2 "
+ "-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -segmentize 4 -nlt PROMOTE_TO_MULTI",
+ ],
+ )
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'SPAT': QgsRectangle(1, 2, 3, 4)}, context, feedback),
- ['ogr2ogr',
- '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
- '-lco DIM=2 ' + source + ' polys2 '
- '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -spat 1.0 2.0 3.0 4.0 -nlt PROMOTE_TO_MULTI'])
+ alg.getConsoleCommands(
+ {"INPUT": source, "SPAT": QgsRectangle(1, 2, 3, 4)}, context, feedback
+ ),
+ [
+ "ogr2ogr",
+ '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
+ "-lco DIM=2 " + source + " polys2 "
+ "-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -spat 1.0 2.0 3.0 4.0 -nlt PROMOTE_TO_MULTI",
+ ],
+ )
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'FIELDS': ['f1', 'f2']}, context, feedback),
- ['ogr2ogr',
- '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
- '-lco DIM=2 ' + source + ' polys2 -select "f1,f2" '
- '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -nlt PROMOTE_TO_MULTI'])
+ alg.getConsoleCommands(
+ {"INPUT": source, "FIELDS": ["f1", "f2"]}, context, feedback
+ ),
+ [
+ "ogr2ogr",
+ '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
+ "-lco DIM=2 " + source + ' polys2 -select "f1,f2" '
+ "-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -nlt PROMOTE_TO_MULTI",
+ ],
+ )
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'WHERE': '0=1'}, context, feedback),
- ['ogr2ogr',
- '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
- '-lco DIM=2 ' + source + ' polys2 '
- '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -where "0=1" -nlt PROMOTE_TO_MULTI'])
+ alg.getConsoleCommands(
+ {"INPUT": source, "WHERE": "0=1"}, context, feedback
+ ),
+ [
+ "ogr2ogr",
+ '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
+ "-lco DIM=2 " + source + " polys2 "
+ '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -where "0=1" -nlt PROMOTE_TO_MULTI',
+ ],
+ )
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'GT': 2}, context, feedback),
- ['ogr2ogr',
- '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
- '-lco DIM=2 ' + source + ' polys2 '
- '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -gt 2 -nlt PROMOTE_TO_MULTI'])
+ alg.getConsoleCommands({"INPUT": source, "GT": 2}, context, feedback),
+ [
+ "ogr2ogr",
+ '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
+ "-lco DIM=2 " + source + " polys2 "
+ "-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -gt 2 -nlt PROMOTE_TO_MULTI",
+ ],
+ )
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'OVERWRITE': False}, context, feedback),
- ['ogr2ogr',
- '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
- '-lco DIM=2 ' + source + ' polys2 '
- '-lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -nlt PROMOTE_TO_MULTI'])
+ alg.getConsoleCommands(
+ {"INPUT": source, "OVERWRITE": False}, context, feedback
+ ),
+ [
+ "ogr2ogr",
+ '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
+ "-lco DIM=2 " + source + " polys2 "
+ "-lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -nlt PROMOTE_TO_MULTI",
+ ],
+ )
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'OVERWRITE': False,
- 'APPEND': True}, context, feedback),
- ['ogr2ogr',
- '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
- '-lco DIM=2 ' + source + ' polys2 '
- '-append -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -nlt PROMOTE_TO_MULTI'])
+ alg.getConsoleCommands(
+ {"INPUT": source, "OVERWRITE": False, "APPEND": True}, context, feedback
+ ),
+ [
+ "ogr2ogr",
+ '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
+ "-lco DIM=2 " + source + " polys2 "
+ "-append -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -nlt PROMOTE_TO_MULTI",
+ ],
+ )
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'ADDFIELDS': True}, context, feedback),
- ['ogr2ogr',
- '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
- '-lco DIM=2 ' + source + ' polys2 '
- '-addfields -overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -nlt PROMOTE_TO_MULTI'])
+ alg.getConsoleCommands(
+ {"INPUT": source, "ADDFIELDS": True}, context, feedback
+ ),
+ [
+ "ogr2ogr",
+ '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
+ "-lco DIM=2 " + source + " polys2 "
+ "-addfields -overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -nlt PROMOTE_TO_MULTI",
+ ],
+ )
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'LAUNDER': True}, context, feedback),
- ['ogr2ogr',
- '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
- '-lco DIM=2 ' + source + ' polys2 '
- '-lco LAUNDER=NO -overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -nlt PROMOTE_TO_MULTI'])
+ alg.getConsoleCommands(
+ {"INPUT": source, "LAUNDER": True}, context, feedback
+ ),
+ [
+ "ogr2ogr",
+ '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
+ "-lco DIM=2 " + source + " polys2 "
+ "-lco LAUNDER=NO -overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -nlt PROMOTE_TO_MULTI",
+ ],
+ )
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'INDEX': True}, context, feedback),
- ['ogr2ogr',
- '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
- '-lco DIM=2 ' + source + ' polys2 '
- '-lco SPATIAL_INDEX=OFF -overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -nlt PROMOTE_TO_MULTI'])
+ alg.getConsoleCommands({"INPUT": source, "INDEX": True}, context, feedback),
+ [
+ "ogr2ogr",
+ '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
+ "-lco DIM=2 " + source + " polys2 "
+ "-lco SPATIAL_INDEX=OFF -overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -nlt PROMOTE_TO_MULTI",
+ ],
+ )
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'SKIPFAILURES': True}, context, feedback),
- ['ogr2ogr',
- '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
- '-lco DIM=2 ' + source + ' polys2 '
- '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -skipfailures -nlt PROMOTE_TO_MULTI'])
+ alg.getConsoleCommands(
+ {"INPUT": source, "SKIPFAILURES": True}, context, feedback
+ ),
+ [
+ "ogr2ogr",
+ '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
+ "-lco DIM=2 " + source + " polys2 "
+ "-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -skipfailures -nlt PROMOTE_TO_MULTI",
+ ],
+ )
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'PROMOTETOMULTI': False}, context, feedback),
- ['ogr2ogr',
- '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
- '-lco DIM=2 ' + source + ' polys2 '
- '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2'])
+ alg.getConsoleCommands(
+ {"INPUT": source, "PROMOTETOMULTI": False}, context, feedback
+ ),
+ [
+ "ogr2ogr",
+ '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
+ "-lco DIM=2 " + source + " polys2 "
+ "-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2",
+ ],
+ )
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'PRECISION': False}, context, feedback),
- ['ogr2ogr',
- '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
- '-lco DIM=2 ' + source + ' polys2 '
- '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -nlt PROMOTE_TO_MULTI -lco PRECISION=NO'])
+ alg.getConsoleCommands(
+ {"INPUT": source, "PRECISION": False}, context, feedback
+ ),
+ [
+ "ogr2ogr",
+ '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
+ "-lco DIM=2 " + source + " polys2 "
+ "-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -nlt PROMOTE_TO_MULTI -lco PRECISION=NO",
+ ],
+ )
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'OPTIONS': 'blah'}, context, feedback),
- ['ogr2ogr',
- '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
- '-lco DIM=2 ' + source + ' polys2 '
- '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -nlt PROMOTE_TO_MULTI blah'])
+ alg.getConsoleCommands(
+ {"INPUT": source, "OPTIONS": "blah"}, context, feedback
+ ),
+ [
+ "ogr2ogr",
+ '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
+ "-lco DIM=2 " + source + " polys2 "
+ "-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -nlt PROMOTE_TO_MULTI blah",
+ ],
+ )
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'SHAPE_ENCODING': 'blah'}, context, feedback),
- ['ogr2ogr',
- '-progress --config PG_USE_COPY YES --config SHAPE_ENCODING blah -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
- '-lco DIM=2 ' + source + ' polys2 '
- '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -nlt PROMOTE_TO_MULTI'])
+ alg.getConsoleCommands(
+ {"INPUT": source, "SHAPE_ENCODING": "blah"}, context, feedback
+ ),
+ [
+ "ogr2ogr",
+ '-progress --config PG_USE_COPY YES --config SHAPE_ENCODING blah -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
+ "-lco DIM=2 " + source + " polys2 "
+ "-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -nlt PROMOTE_TO_MULTI",
+ ],
+ )
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'PROMOTETOMULTI': False,
- 'GTYPE': 4}, context, feedback),
- ['ogr2ogr',
- '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
- '-lco DIM=2 ' + source + ' polys2 '
- '-overwrite -nlt LINESTRING -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2'])
+ alg.getConsoleCommands(
+ {"INPUT": source, "PROMOTETOMULTI": False, "GTYPE": 4},
+ context,
+ feedback,
+ ),
+ [
+ "ogr2ogr",
+ '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
+ "-lco DIM=2 " + source + " polys2 "
+ "-overwrite -nlt LINESTRING -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2",
+ ],
+ )
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source_line,
- 'GTYPE': 15}, context, feedback),
- ['ogr2ogr',
- '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
- '-lco DIM=2 ' + source_line + ' multilines '
- '-overwrite -nlt CONVERT_TO_LINEAR -lco GEOMETRY_NAME=geom -lco FID=id -nln public.multilines -nlt PROMOTE_TO_MULTI'])
+ alg.getConsoleCommands(
+ {"INPUT": source_line, "GTYPE": 15}, context, feedback
+ ),
+ [
+ "ogr2ogr",
+ '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
+ "-lco DIM=2 " + source_line + " multilines "
+ "-overwrite -nlt CONVERT_TO_LINEAR -lco GEOMETRY_NAME=geom -lco FID=id -nln public.multilines -nlt PROMOTE_TO_MULTI",
+ ],
+ )
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'A_SRS': 'EPSG:3111'}, context, feedback),
- ['ogr2ogr',
- '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
- '-lco DIM=2 ' + source + ' polys2 '
- '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -a_srs EPSG:3111 -nlt PROMOTE_TO_MULTI'])
+ alg.getConsoleCommands(
+ {"INPUT": source, "A_SRS": "EPSG:3111"}, context, feedback
+ ),
+ [
+ "ogr2ogr",
+ '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
+ "-lco DIM=2 " + source + " polys2 "
+ "-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -a_srs EPSG:3111 -nlt PROMOTE_TO_MULTI",
+ ],
+ )
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'A_SRS': QgsCoordinateReferenceSystem('EPSG:3111')}, context, feedback),
- ['ogr2ogr',
- '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
- '-lco DIM=2 ' + source + ' polys2 '
- '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -a_srs EPSG:3111 -nlt PROMOTE_TO_MULTI'])
-
- custom_crs = 'proj4: +proj=utm +zone=36 +south +a=6378249.145 +b=6356514.966398753 +towgs84=-143,-90,-294,0,0,0,0 +units=m +no_defs'
+ alg.getConsoleCommands(
+ {"INPUT": source, "A_SRS": QgsCoordinateReferenceSystem("EPSG:3111")},
+ context,
+ feedback,
+ ),
+ [
+ "ogr2ogr",
+ '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
+ "-lco DIM=2 " + source + " polys2 "
+ "-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -a_srs EPSG:3111 -nlt PROMOTE_TO_MULTI",
+ ],
+ )
+
+ custom_crs = "proj4: +proj=utm +zone=36 +south +a=6378249.145 +b=6356514.966398753 +towgs84=-143,-90,-294,0,0,0,0 +units=m +no_defs"
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'A_SRS': custom_crs}, context, feedback),
- ['ogr2ogr',
- '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
- '-lco DIM=2 ' + source + ' polys2 '
- '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -a_srs EPSG:20936 -nlt PROMOTE_TO_MULTI'])
+ alg.getConsoleCommands(
+ {"INPUT": source, "A_SRS": custom_crs}, context, feedback
+ ),
+ [
+ "ogr2ogr",
+ '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
+ "-lco DIM=2 " + source + " polys2 "
+ "-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -a_srs EPSG:20936 -nlt PROMOTE_TO_MULTI",
+ ],
+ )
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'T_SRS': 'EPSG:3111'}, context, feedback),
- ['ogr2ogr',
- '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
- '-lco DIM=2 ' + source + ' polys2 '
- '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -t_srs EPSG:3111 -nlt PROMOTE_TO_MULTI'])
+ alg.getConsoleCommands(
+ {"INPUT": source, "T_SRS": "EPSG:3111"}, context, feedback
+ ),
+ [
+ "ogr2ogr",
+ '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
+ "-lco DIM=2 " + source + " polys2 "
+ "-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -t_srs EPSG:3111 -nlt PROMOTE_TO_MULTI",
+ ],
+ )
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'T_SRS': QgsCoordinateReferenceSystem('EPSG:3111')}, context, feedback),
- ['ogr2ogr',
- '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
- '-lco DIM=2 ' + source + ' polys2 '
- '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -t_srs EPSG:3111 -nlt PROMOTE_TO_MULTI'])
-
- custom_crs = 'proj4: +proj=utm +zone=36 +south +a=6378249.145 +b=6356514.966398753 +towgs84=-143,-90,-294,0,0,0,0 +units=m +no_defs'
+ alg.getConsoleCommands(
+ {"INPUT": source, "T_SRS": QgsCoordinateReferenceSystem("EPSG:3111")},
+ context,
+ feedback,
+ ),
+ [
+ "ogr2ogr",
+ '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
+ "-lco DIM=2 " + source + " polys2 "
+ "-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -t_srs EPSG:3111 -nlt PROMOTE_TO_MULTI",
+ ],
+ )
+
+ custom_crs = "proj4: +proj=utm +zone=36 +south +a=6378249.145 +b=6356514.966398753 +towgs84=-143,-90,-294,0,0,0,0 +units=m +no_defs"
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'T_SRS': custom_crs}, context, feedback),
- ['ogr2ogr',
- '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
- '-lco DIM=2 ' + source + ' polys2 '
- '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -t_srs EPSG:20936 -nlt PROMOTE_TO_MULTI'])
+ alg.getConsoleCommands(
+ {"INPUT": source, "T_SRS": custom_crs}, context, feedback
+ ),
+ [
+ "ogr2ogr",
+ '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
+ "-lco DIM=2 " + source + " polys2 "
+ "-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -t_srs EPSG:20936 -nlt PROMOTE_TO_MULTI",
+ ],
+ )
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'S_SRS': 'EPSG:3111'}, context, feedback),
- ['ogr2ogr',
- '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
- '-lco DIM=2 ' + source + ' polys2 '
- '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -s_srs EPSG:3111 -nlt PROMOTE_TO_MULTI'])
+ alg.getConsoleCommands(
+ {"INPUT": source, "S_SRS": "EPSG:3111"}, context, feedback
+ ),
+ [
+ "ogr2ogr",
+ '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
+ "-lco DIM=2 " + source + " polys2 "
+ "-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -s_srs EPSG:3111 -nlt PROMOTE_TO_MULTI",
+ ],
+ )
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'S_SRS': QgsCoordinateReferenceSystem('EPSG:3111')}, context, feedback),
- ['ogr2ogr',
- '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
- '-lco DIM=2 ' + source + ' polys2 '
- '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -s_srs EPSG:3111 -nlt PROMOTE_TO_MULTI'])
-
- custom_crs = 'proj4: +proj=utm +zone=36 +south +a=6378249.145 +b=6356514.966398753 +towgs84=-143,-90,-294,0,0,0,0 +units=m +no_defs'
+ alg.getConsoleCommands(
+ {"INPUT": source, "S_SRS": QgsCoordinateReferenceSystem("EPSG:3111")},
+ context,
+ feedback,
+ ),
+ [
+ "ogr2ogr",
+ '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
+ "-lco DIM=2 " + source + " polys2 "
+ "-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -s_srs EPSG:3111 -nlt PROMOTE_TO_MULTI",
+ ],
+ )
+
+ custom_crs = "proj4: +proj=utm +zone=36 +south +a=6378249.145 +b=6356514.966398753 +towgs84=-143,-90,-294,0,0,0,0 +units=m +no_defs"
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'S_SRS': custom_crs}, context, feedback),
- ['ogr2ogr',
- '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
- '-lco DIM=2 ' + source + ' polys2 '
- '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -s_srs EPSG:20936 -nlt PROMOTE_TO_MULTI'])
+ alg.getConsoleCommands(
+ {"INPUT": source, "S_SRS": custom_crs}, context, feedback
+ ),
+ [
+ "ogr2ogr",
+ '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
+ "-lco DIM=2 " + source + " polys2 "
+ "-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -s_srs EPSG:20936 -nlt PROMOTE_TO_MULTI",
+ ],
+ )
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source + '|option:X_POSSIBLE_NAMES=geom_x|option:Y_POSSIBLE_NAMES=geom_y',
- 'A_SRS': QgsCoordinateReferenceSystem('EPSG:3111')}, context, feedback),
- ['ogr2ogr',
- '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
- '-lco DIM=2 ' + source + ' polys2 '
- '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -a_srs EPSG:3111 -nlt PROMOTE_TO_MULTI -oo X_POSSIBLE_NAMES=geom_x -oo Y_POSSIBLE_NAMES=geom_y'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source
+ + "|option:X_POSSIBLE_NAMES=geom_x|option:Y_POSSIBLE_NAMES=geom_y",
+ "A_SRS": QgsCoordinateReferenceSystem("EPSG:3111"),
+ },
+ context,
+ feedback,
+ ),
+ [
+ "ogr2ogr",
+ '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
+ "-lco DIM=2 " + source + " polys2 "
+ "-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -a_srs EPSG:3111 -nlt PROMOTE_TO_MULTI -oo X_POSSIBLE_NAMES=geom_x -oo Y_POSSIBLE_NAMES=geom_y",
+ ],
+ )
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source + '|credential:X=Y|credential:Z=A',
- 'A_SRS': QgsCoordinateReferenceSystem('EPSG:3111')}, context, feedback),
- ['ogr2ogr',
- '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
- '-lco DIM=2 ' + source + ' polys2 '
- '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -a_srs EPSG:3111 -nlt PROMOTE_TO_MULTI --config X Y --config Z A'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source + "|credential:X=Y|credential:Z=A",
+ "A_SRS": QgsCoordinateReferenceSystem("EPSG:3111"),
+ },
+ context,
+ feedback,
+ ),
+ [
+ "ogr2ogr",
+ '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
+ "-lco DIM=2 " + source + " polys2 "
+ "-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -a_srs EPSG:3111 -nlt PROMOTE_TO_MULTI --config X Y --config Z A",
+ ],
+ )
def testOffsetCurve(self):
context = QgsProcessingContext()
feedback = QgsProcessingFeedback()
- source = os.path.join(testDataPath, 'polys.gml')
- source_with_space = os.path.join(testDataPath, 'filename with spaces.gml')
+ source = os.path.join(testDataPath, "polys.gml")
+ source_with_space = os.path.join(testDataPath, "filename with spaces.gml")
alg = OffsetCurve()
alg.initAlgorithm()
with tempfile.TemporaryDirectory() as outdir:
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'DISTANCE': 5,
- 'OUTPUT': outdir + '/check.shp'}, context, feedback),
- ['ogr2ogr',
- outdir + '/check.shp ' +
- source + ' ' +
- '-dialect sqlite -sql "SELECT ST_OffsetCurve(geometry, 5.0) AS geometry,* FROM """polys2"""" ' +
- '-f "ESRI Shapefile"'])
+ alg.getConsoleCommands(
+ {"INPUT": source, "DISTANCE": 5, "OUTPUT": outdir + "/check.shp"},
+ context,
+ feedback,
+ ),
+ [
+ "ogr2ogr",
+ outdir
+ + "/check.shp "
+ + source
+ + " "
+ + '-dialect sqlite -sql "SELECT ST_OffsetCurve(geometry, 5.0) AS geometry,* FROM """polys2"""" '
+ + '-f "ESRI Shapefile"',
+ ],
+ )
self.assertEqual(
alg.getConsoleCommands(
- {'INPUT': source + '|option:X_POSSIBLE_NAMES=geom_x|option:Y_POSSIBLE_NAMES=geom_y',
- 'DISTANCE': 5,
- 'OUTPUT': outdir + '/check.shp'}, context, feedback),
- ['ogr2ogr',
- outdir + '/check.shp ' +
- source + ' ' +
- '-dialect sqlite -sql "SELECT ST_OffsetCurve(geometry, 5.0) AS geometry,* FROM """polys2"""" -oo X_POSSIBLE_NAMES=geom_x -oo Y_POSSIBLE_NAMES=geom_y ' +
- '-f "ESRI Shapefile"'])
+ {
+ "INPUT": source
+ + "|option:X_POSSIBLE_NAMES=geom_x|option:Y_POSSIBLE_NAMES=geom_y",
+ "DISTANCE": 5,
+ "OUTPUT": outdir + "/check.shp",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "ogr2ogr",
+ outdir
+ + "/check.shp "
+ + source
+ + " "
+ + '-dialect sqlite -sql "SELECT ST_OffsetCurve(geometry, 5.0) AS geometry,* FROM """polys2"""" -oo X_POSSIBLE_NAMES=geom_x -oo Y_POSSIBLE_NAMES=geom_y '
+ + '-f "ESRI Shapefile"',
+ ],
+ )
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source + '|credential:X=Y|credential:Z=A',
- 'DISTANCE': 5,
- 'OUTPUT': outdir + '/check.shp'}, context, feedback),
- ['ogr2ogr',
- outdir + '/check.shp ' +
- source + ' ' +
- '-dialect sqlite -sql "SELECT ST_OffsetCurve(geometry, 5.0) AS geometry,* FROM """polys2"""" --config X Y --config Z A ' +
- '-f "ESRI Shapefile"'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source + "|credential:X=Y|credential:Z=A",
+ "DISTANCE": 5,
+ "OUTPUT": outdir + "/check.shp",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "ogr2ogr",
+ outdir
+ + "/check.shp "
+ + source
+ + " "
+ + '-dialect sqlite -sql "SELECT ST_OffsetCurve(geometry, 5.0) AS geometry,* FROM """polys2"""" --config X Y --config Z A '
+ + '-f "ESRI Shapefile"',
+ ],
+ )
def testOneSidedBuffer(self):
context = QgsProcessingContext()
feedback = QgsProcessingFeedback()
- source = os.path.join(testDataPath, 'polys.gml')
- source_with_space = os.path.join(testDataPath, 'filename with spaces.gml')
+ source = os.path.join(testDataPath, "polys.gml")
+ source_with_space = os.path.join(testDataPath, "filename with spaces.gml")
alg = OneSideBuffer()
alg.initAlgorithm()
with tempfile.TemporaryDirectory() as outdir:
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'DISTANCE': 5,
- 'OUTPUT': outdir + '/check.shp'}, context, feedback),
- ['ogr2ogr',
- outdir + '/check.shp ' +
- source + ' ' +
- '-dialect sqlite -sql "SELECT ST_SingleSidedBuffer(geometry, 5.0, 0) AS geometry,* FROM """polys2"""" ' +
- '-f "ESRI Shapefile"'])
+ alg.getConsoleCommands(
+ {"INPUT": source, "DISTANCE": 5, "OUTPUT": outdir + "/check.shp"},
+ context,
+ feedback,
+ ),
+ [
+ "ogr2ogr",
+ outdir
+ + "/check.shp "
+ + source
+ + " "
+ + '-dialect sqlite -sql "SELECT ST_SingleSidedBuffer(geometry, 5.0, 0) AS geometry,* FROM """polys2"""" '
+ + '-f "ESRI Shapefile"',
+ ],
+ )
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'DISTANCE': 5,
- 'DISSOLVE': True,
- 'OUTPUT': outdir + '/check.shp'}, context, feedback),
- ['ogr2ogr',
- outdir + '/check.shp ' +
- source + ' ' +
- '-dialect sqlite -sql "SELECT ST_Union(ST_SingleSidedBuffer(geometry, 5.0, 0)) AS geometry,* FROM """polys2"""" ' +
- '-f "ESRI Shapefile"'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "DISTANCE": 5,
+ "DISSOLVE": True,
+ "OUTPUT": outdir + "/check.shp",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "ogr2ogr",
+ outdir
+ + "/check.shp "
+ + source
+ + " "
+ + '-dialect sqlite -sql "SELECT ST_Union(ST_SingleSidedBuffer(geometry, 5.0, 0)) AS geometry,* FROM """polys2"""" '
+ + '-f "ESRI Shapefile"',
+ ],
+ )
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'DISTANCE': 5,
- 'EXPLODE_COLLECTIONS': True,
- 'OUTPUT': outdir + '/check.shp'}, context, feedback),
- ['ogr2ogr',
- outdir + '/check.shp ' +
- source + ' ' +
- '-dialect sqlite -sql "SELECT ST_SingleSidedBuffer(geometry, 5.0, 0) AS geometry,* FROM """polys2"""" ' +
- '-explodecollections -f "ESRI Shapefile"'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "DISTANCE": 5,
+ "EXPLODE_COLLECTIONS": True,
+ "OUTPUT": outdir + "/check.shp",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "ogr2ogr",
+ outdir
+ + "/check.shp "
+ + source
+ + " "
+ + '-dialect sqlite -sql "SELECT ST_SingleSidedBuffer(geometry, 5.0, 0) AS geometry,* FROM """polys2"""" '
+ + '-explodecollections -f "ESRI Shapefile"',
+ ],
+ )
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'DISTANCE': 5,
- 'FIELD': 'total population',
- 'OUTPUT': outdir + '/check.shp'}, context, feedback),
- ['ogr2ogr',
- outdir + '/check.shp ' +
- source + ' ' +
- '-dialect sqlite -sql "SELECT ST_Union(ST_SingleSidedBuffer(geometry, 5.0, 0)) AS geometry,* ' +
- 'FROM """polys2""" GROUP BY """total population"""" -f "ESRI Shapefile"'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source,
+ "DISTANCE": 5,
+ "FIELD": "total population",
+ "OUTPUT": outdir + "/check.shp",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "ogr2ogr",
+ outdir
+ + "/check.shp "
+ + source
+ + " "
+ + '-dialect sqlite -sql "SELECT ST_Union(ST_SingleSidedBuffer(geometry, 5.0, 0)) AS geometry,* '
+ + 'FROM """polys2""" GROUP BY """total population"""" -f "ESRI Shapefile"',
+ ],
+ )
self.assertEqual(
alg.getConsoleCommands(
- {'INPUT': source + '|option:X_POSSIBLE_NAMES=geom_x|option:Y_POSSIBLE_NAMES=geom_y',
- 'DISTANCE': 5,
- 'FIELD': 'total population',
- 'OUTPUT': outdir + '/check.shp'}, context, feedback),
- ['ogr2ogr',
- outdir + '/check.shp ' +
- source + ' ' +
- '-dialect sqlite -sql "SELECT ST_Union(ST_SingleSidedBuffer(geometry, 5.0, 0)) AS geometry,* ' +
- 'FROM """polys2""" GROUP BY """total population"""" -oo X_POSSIBLE_NAMES=geom_x -oo Y_POSSIBLE_NAMES=geom_y -f "ESRI Shapefile"'])
+ {
+ "INPUT": source
+ + "|option:X_POSSIBLE_NAMES=geom_x|option:Y_POSSIBLE_NAMES=geom_y",
+ "DISTANCE": 5,
+ "FIELD": "total population",
+ "OUTPUT": outdir + "/check.shp",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "ogr2ogr",
+ outdir
+ + "/check.shp "
+ + source
+ + " "
+ + '-dialect sqlite -sql "SELECT ST_Union(ST_SingleSidedBuffer(geometry, 5.0, 0)) AS geometry,* '
+ + 'FROM """polys2""" GROUP BY """total population"""" -oo X_POSSIBLE_NAMES=geom_x -oo Y_POSSIBLE_NAMES=geom_y -f "ESRI Shapefile"',
+ ],
+ )
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source + '|credential:X=Y|credential:Z=A',
- 'DISTANCE': 5,
- 'FIELD': 'total population',
- 'OUTPUT': outdir + '/check.shp'}, context, feedback),
- ['ogr2ogr',
- outdir + '/check.shp ' +
- source + ' ' +
- '-dialect sqlite -sql "SELECT ST_Union(ST_SingleSidedBuffer(geometry, 5.0, 0)) AS geometry,* ' +
- 'FROM """polys2""" GROUP BY """total population"""" --config X Y --config Z A -f "ESRI Shapefile"'])
+ alg.getConsoleCommands(
+ {
+ "INPUT": source + "|credential:X=Y|credential:Z=A",
+ "DISTANCE": 5,
+ "FIELD": "total population",
+ "OUTPUT": outdir + "/check.shp",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "ogr2ogr",
+ outdir
+ + "/check.shp "
+ + source
+ + " "
+ + '-dialect sqlite -sql "SELECT ST_Union(ST_SingleSidedBuffer(geometry, 5.0, 0)) AS geometry,* '
+ + 'FROM """polys2""" GROUP BY """total population"""" --config X Y --config Z A -f "ESRI Shapefile"',
+ ],
+ )
def testPointsAlongLines(self):
context = QgsProcessingContext()
feedback = QgsProcessingFeedback()
- source = os.path.join(testDataPath, 'polys.gml')
- source_with_space = os.path.join(testDataPath, 'filename with spaces.gml')
+ source = os.path.join(testDataPath, "polys.gml")
+ source_with_space = os.path.join(testDataPath, "filename with spaces.gml")
alg = PointsAlongLines()
alg.initAlgorithm()
with tempfile.TemporaryDirectory() as outdir:
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source,
- 'DISTANCE': 0.2,
- 'OUTPUT': outdir + '/check.shp'}, context, feedback),
- ['ogr2ogr',
- outdir + '/check.shp ' +
- source + ' ' +
- '-dialect sqlite -sql "SELECT ST_Line_Interpolate_Point(geometry, 0.2) AS geometry,* FROM """polys2"""" ' +
- '-f "ESRI Shapefile"'])
+ alg.getConsoleCommands(
+ {"INPUT": source, "DISTANCE": 0.2, "OUTPUT": outdir + "/check.shp"},
+ context,
+ feedback,
+ ),
+ [
+ "ogr2ogr",
+ outdir
+ + "/check.shp "
+ + source
+ + " "
+ + '-dialect sqlite -sql "SELECT ST_Line_Interpolate_Point(geometry, 0.2) AS geometry,* FROM """polys2"""" '
+ + '-f "ESRI Shapefile"',
+ ],
+ )
self.assertEqual(
alg.getConsoleCommands(
- {'INPUT': source + '|option:X_POSSIBLE_NAMES=geom_x|option:Y_POSSIBLE_NAMES=geom_y',
- 'DISTANCE': 0.2,
- 'OUTPUT': outdir + '/check.shp'}, context, feedback),
- ['ogr2ogr',
- outdir + '/check.shp ' +
- source + ' ' +
- '-dialect sqlite -sql "SELECT ST_Line_Interpolate_Point(geometry, 0.2) AS geometry,* FROM """polys2"""" -oo X_POSSIBLE_NAMES=geom_x -oo Y_POSSIBLE_NAMES=geom_y ' +
- '-f "ESRI Shapefile"'])
+ {
+ "INPUT": source
+ + "|option:X_POSSIBLE_NAMES=geom_x|option:Y_POSSIBLE_NAMES=geom_y",
+ "DISTANCE": 0.2,
+ "OUTPUT": outdir + "/check.shp",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "ogr2ogr",
+ outdir
+ + "/check.shp "
+ + source
+ + " "
+ + '-dialect sqlite -sql "SELECT ST_Line_Interpolate_Point(geometry, 0.2) AS geometry,* FROM """polys2"""" -oo X_POSSIBLE_NAMES=geom_x -oo Y_POSSIBLE_NAMES=geom_y '
+ + '-f "ESRI Shapefile"',
+ ],
+ )
self.assertEqual(
- alg.getConsoleCommands({'INPUT': source + '|credential:X=Y|credential:Z=A',
- 'DISTANCE': 0.2,
- 'OUTPUT': outdir + '/check.shp'}, context, feedback),
- ['ogr2ogr',
- outdir + '/check.shp ' +
- source + ' ' +
- '-dialect sqlite -sql "SELECT ST_Line_Interpolate_Point(geometry, 0.2) AS geometry,* FROM """polys2"""" --config X Y --config Z A ' +
- '-f "ESRI Shapefile"'])
-
-
-if __name__ == '__main__':
+ alg.getConsoleCommands(
+ {
+ "INPUT": source + "|credential:X=Y|credential:Z=A",
+ "DISTANCE": 0.2,
+ "OUTPUT": outdir + "/check.shp",
+ },
+ context,
+ feedback,
+ ),
+ [
+ "ogr2ogr",
+ outdir
+ + "/check.shp "
+ + source
+ + " "
+ + '-dialect sqlite -sql "SELECT ST_Line_Interpolate_Point(geometry, 0.2) AS geometry,* FROM """polys2"""" --config X Y --config Z A '
+ + '-f "ESRI Shapefile"',
+ ],
+ )
+
+
+if __name__ == "__main__":
nose2.main()
diff --git a/python/plugins/processing/tests/GuiTest.py b/python/plugins/processing/tests/GuiTest.py
index 57cc1e4dfb07..676393047e8e 100644
--- a/python/plugins/processing/tests/GuiTest.py
+++ b/python/plugins/processing/tests/GuiTest.py
@@ -15,27 +15,29 @@
***************************************************************************
"""
-__author__ = 'Nyall Dawson'
-__date__ = 'August 2017'
-__copyright__ = '(C) 2017, Nyall Dawson'
+__author__ = "Nyall Dawson"
+__date__ = "August 2017"
+__copyright__ = "(C) 2017, Nyall Dawson"
import os
import unittest
from qgis.testing import start_app, QgisTestCase
-from qgis.core import (QgsApplication,
- QgsCoordinateReferenceSystem,
- QgsProcessingParameterMatrix,
- QgsProcessingOutputLayerDefinition,
- QgsProcessingParameterFeatureSink,
- QgsProcessingParameterFileDestination,
- QgsProcessingParameterFolderDestination,
- QgsProcessingParameterVectorDestination,
- QgsProcessingParameterRasterDestination,
- QgsProcessingParameterRange,
- QgsFeature,
- QgsProcessingModelAlgorithm,
- QgsUnitTypes,
- QgsProject)
+from qgis.core import (
+ QgsApplication,
+ QgsCoordinateReferenceSystem,
+ QgsProcessingParameterMatrix,
+ QgsProcessingOutputLayerDefinition,
+ QgsProcessingParameterFeatureSink,
+ QgsProcessingParameterFileDestination,
+ QgsProcessingParameterFolderDestination,
+ QgsProcessingParameterVectorDestination,
+ QgsProcessingParameterRasterDestination,
+ QgsProcessingParameterRange,
+ QgsFeature,
+ QgsProcessingModelAlgorithm,
+ QgsUnitTypes,
+ QgsProject,
+)
from qgis.analysis import QgsNativeAlgorithms
from processing.gui.AlgorithmDialog import AlgorithmDialog
@@ -90,13 +92,15 @@
start_app()
QgsApplication.processingRegistry().addProvider(QgsNativeAlgorithms())
-testDataPath = os.path.join(os.path.dirname(__file__), 'testdata')
+testDataPath = os.path.join(os.path.dirname(__file__), "testdata")
class AlgorithmDialogTest(QgisTestCase):
def testCreation(self):
- alg = QgsApplication.processingRegistry().createAlgorithmById('native:centroids')
+ alg = QgsApplication.processingRegistry().createAlgorithmById(
+ "native:centroids"
+ )
a = AlgorithmDialog(alg)
self.assertEqual(a.mainWidget().algorithm(), alg)
@@ -109,7 +113,9 @@ def setUpClass(cls):
ProcessingConfig.initialize()
def checkConstructWrapper(self, param, expected_wrapper_class):
- alg = QgsApplication.processingRegistry().createAlgorithmById('native:centroids')
+ alg = QgsApplication.processingRegistry().createAlgorithmById(
+ "native:centroids"
+ )
# algorithm dialog
dlg = AlgorithmDialog(alg)
@@ -122,7 +128,9 @@ def checkConstructWrapper(self, param, expected_wrapper_class):
del wrapper.widget
del wrapper
- alg = QgsApplication.processingRegistry().createAlgorithmById('native:centroids')
+ alg = QgsApplication.processingRegistry().createAlgorithmById(
+ "native:centroids"
+ )
# batch dialog
dlg = BatchAlgorithmDialog(alg)
wrapper = WidgetWrapperFactory.create_wrapper_from_class(param, dlg)
@@ -131,7 +139,9 @@ def checkConstructWrapper(self, param, expected_wrapper_class):
self.assertEqual(wrapper.dialog, dlg)
self.assertIsNotNone(wrapper.widget)
- alg = QgsApplication.processingRegistry().createAlgorithmById('native:centroids')
+ alg = QgsApplication.processingRegistry().createAlgorithmById(
+ "native:centroids"
+ )
# modeler dialog
model = QgsProcessingModelAlgorithm()
@@ -146,46 +156,70 @@ def checkConstructWrapper(self, param, expected_wrapper_class):
del wrapper.widget
def testBoolean(self):
- self.checkConstructWrapper(QgsProcessingParameterBoolean('test'), BooleanWidgetWrapper)
+ self.checkConstructWrapper(
+ QgsProcessingParameterBoolean("test"), BooleanWidgetWrapper
+ )
def testCrs(self):
- self.checkConstructWrapper(QgsProcessingParameterCrs('test'), CrsWidgetWrapper)
+ self.checkConstructWrapper(QgsProcessingParameterCrs("test"), CrsWidgetWrapper)
def testExtent(self):
- self.checkConstructWrapper(QgsProcessingParameterExtent('test'), ExtentWidgetWrapper)
+ self.checkConstructWrapper(
+ QgsProcessingParameterExtent("test"), ExtentWidgetWrapper
+ )
def testPoint(self):
- self.checkConstructWrapper(QgsProcessingParameterPoint('test'), PointWidgetWrapper)
+ self.checkConstructWrapper(
+ QgsProcessingParameterPoint("test"), PointWidgetWrapper
+ )
def testFile(self):
- self.checkConstructWrapper(QgsProcessingParameterFile('test'), FileWidgetWrapper)
+ self.checkConstructWrapper(
+ QgsProcessingParameterFile("test"), FileWidgetWrapper
+ )
def testMultiInput(self):
- self.checkConstructWrapper(QgsProcessingParameterMultipleLayers('test'), MultipleLayerWidgetWrapper)
+ self.checkConstructWrapper(
+ QgsProcessingParameterMultipleLayers("test"), MultipleLayerWidgetWrapper
+ )
def testRasterInput(self):
- self.checkConstructWrapper(QgsProcessingParameterRasterLayer('test'), RasterWidgetWrapper)
+ self.checkConstructWrapper(
+ QgsProcessingParameterRasterLayer("test"), RasterWidgetWrapper
+ )
def testEnum(self):
- self.checkConstructWrapper(QgsProcessingParameterEnum('test'), EnumWidgetWrapper)
+ self.checkConstructWrapper(
+ QgsProcessingParameterEnum("test"), EnumWidgetWrapper
+ )
def testString(self):
- self.checkConstructWrapper(QgsProcessingParameterString('test'), StringWidgetWrapper)
+ self.checkConstructWrapper(
+ QgsProcessingParameterString("test"), StringWidgetWrapper
+ )
def testExpression(self):
- self.checkConstructWrapper(QgsProcessingParameterExpression('test'), ExpressionWidgetWrapper)
+ self.checkConstructWrapper(
+ QgsProcessingParameterExpression("test"), ExpressionWidgetWrapper
+ )
def testVector(self):
- self.checkConstructWrapper(QgsProcessingParameterVectorLayer('test'), VectorLayerWidgetWrapper)
+ self.checkConstructWrapper(
+ QgsProcessingParameterVectorLayer("test"), VectorLayerWidgetWrapper
+ )
def testField(self):
- self.checkConstructWrapper(QgsProcessingParameterField('test'), TableFieldWidgetWrapper)
+ self.checkConstructWrapper(
+ QgsProcessingParameterField("test"), TableFieldWidgetWrapper
+ )
def testSource(self):
- self.checkConstructWrapper(QgsProcessingParameterFeatureSource('test'), FeatureSourceWidgetWrapper)
+ self.checkConstructWrapper(
+ QgsProcessingParameterFeatureSource("test"), FeatureSourceWidgetWrapper
+ )
# dummy layer
- layer = QgsVectorLayer('Point', 'test', 'memory')
+ layer = QgsVectorLayer("Point", "test", "memory")
# need at least one feature in order to have a selection
layer.dataProvider().addFeature(QgsFeature())
layer.selectAll()
@@ -193,9 +227,11 @@ def testSource(self):
self.assertTrue(layer.isValid())
QgsProject.instance().addMapLayer(layer)
- alg = QgsApplication.processingRegistry().createAlgorithmById('native:centroids')
+ alg = QgsApplication.processingRegistry().createAlgorithmById(
+ "native:centroids"
+ )
dlg = AlgorithmDialog(alg)
- param = QgsProcessingParameterFeatureSource('test')
+ param = QgsProcessingParameterFeatureSource("test")
wrapper = FeatureSourceWidgetWrapper(param, dlg)
widget = wrapper.createWidget()
@@ -217,24 +253,29 @@ def testSource(self):
self.assertEqual(value, layer.id())
# with non-project layer
- wrapper.setValue('/home/my_layer.shp')
+ wrapper.setValue("/home/my_layer.shp")
value = wrapper.value()
- self.assertEqual(value, '/home/my_layer.shp')
+ self.assertEqual(value, "/home/my_layer.shp")
widget.deleteLater()
del widget
def testRange(self):
# minimal test to check if wrapper generate GUI for each processign context
- self.checkConstructWrapper(QgsProcessingParameterRange('test'), RangeWidgetWrapper)
+ self.checkConstructWrapper(
+ QgsProcessingParameterRange("test"), RangeWidgetWrapper
+ )
- alg = QgsApplication.processingRegistry().createAlgorithmById('native:centroids')
+ alg = QgsApplication.processingRegistry().createAlgorithmById(
+ "native:centroids"
+ )
dlg = AlgorithmDialog(alg)
param = QgsProcessingParameterRange(
- name='test',
- description='test',
+ name="test",
+ description="test",
type=QgsProcessingParameterNumber.Type.Double,
- defaultValue="0.0,100.0")
+ defaultValue="0.0,100.0",
+ )
wrapper = RangeWidgetWrapper(param, dlg)
widget = wrapper.createWidget()
@@ -242,24 +283,25 @@ def testRange(self):
# range values check
# check initial value
- self.assertEqual(widget.getValue(), '0.0,100.0')
+ self.assertEqual(widget.getValue(), "0.0,100.0")
# check set/get
widget.setValue("100.0,200.0")
- self.assertEqual(widget.getValue(), '100.0,200.0')
+ self.assertEqual(widget.getValue(), "100.0,200.0")
# check that min/max are mutually adapted
widget.setValue("200.0,100.0")
- self.assertEqual(widget.getValue(), '100.0,100.0')
+ self.assertEqual(widget.getValue(), "100.0,100.0")
widget.spnMax.setValue(50)
- self.assertEqual(widget.getValue(), '50.0,50.0')
+ self.assertEqual(widget.getValue(), "50.0,50.0")
widget.spnMin.setValue(100)
- self.assertEqual(widget.getValue(), '100.0,100.0')
+ self.assertEqual(widget.getValue(), "100.0,100.0")
# check for integers
param = QgsProcessingParameterRange(
- name='test',
- description='test',
+ name="test",
+ description="test",
type=QgsProcessingParameterNumber.Type.Integer,
- defaultValue="0.1,100.1")
+ defaultValue="0.1,100.1",
+ )
wrapper = RangeWidgetWrapper(param, dlg)
widget = wrapper.createWidget()
@@ -267,35 +309,43 @@ def testRange(self):
# range values check
# check initial value
- self.assertEqual(widget.getValue(), '0.0,100.0')
+ self.assertEqual(widget.getValue(), "0.0,100.0")
# check rounding
widget.setValue("100.1,200.1")
- self.assertEqual(widget.getValue(), '100.0,200.0')
+ self.assertEqual(widget.getValue(), "100.0,200.0")
widget.setValue("100.6,200.6")
- self.assertEqual(widget.getValue(), '101.0,201.0')
+ self.assertEqual(widget.getValue(), "101.0,201.0")
# check set/get
widget.setValue("100.1,200.1")
- self.assertEqual(widget.getValue(), '100.0,200.0')
+ self.assertEqual(widget.getValue(), "100.0,200.0")
# check that min/max are mutually adapted
widget.setValue("200.1,100.1")
- self.assertEqual(widget.getValue(), '100.0,100.0')
+ self.assertEqual(widget.getValue(), "100.0,100.0")
widget.spnMax.setValue(50.1)
- self.assertEqual(widget.getValue(), '50.0,50.0')
+ self.assertEqual(widget.getValue(), "50.0,50.0")
widget.spnMin.setValue(100.1)
- self.assertEqual(widget.getValue(), '100.0,100.0')
+ self.assertEqual(widget.getValue(), "100.0,100.0")
def testMapLayer(self):
- self.checkConstructWrapper(QgsProcessingParameterMapLayer('test'), MapLayerWidgetWrapper)
+ self.checkConstructWrapper(
+ QgsProcessingParameterMapLayer("test"), MapLayerWidgetWrapper
+ )
def testMeshLayer(self):
- self.checkConstructWrapper(QgsProcessingParameterMeshLayer('test'), MeshWidgetWrapper)
+ self.checkConstructWrapper(
+ QgsProcessingParameterMeshLayer("test"), MeshWidgetWrapper
+ )
def testDistance(self):
- self.checkConstructWrapper(QgsProcessingParameterDistance('test'), DistanceWidgetWrapper)
+ self.checkConstructWrapper(
+ QgsProcessingParameterDistance("test"), DistanceWidgetWrapper
+ )
- alg = QgsApplication.processingRegistry().createAlgorithmById('native:centroids')
+ alg = QgsApplication.processingRegistry().createAlgorithmById(
+ "native:centroids"
+ )
dlg = AlgorithmDialog(alg)
- param = QgsProcessingParameterDistance('test')
+ param = QgsProcessingParameterDistance("test")
wrapper = DistanceWidgetWrapper(param, dlg)
widget = wrapper.createWidget()
@@ -303,28 +353,32 @@ def testDistance(self):
widget.show()
# crs values
- widget.setUnitParameterValue('EPSG:3111')
- self.assertEqual(widget.label.text(), 'meters')
+ widget.setUnitParameterValue("EPSG:3111")
+ self.assertEqual(widget.label.text(), "meters")
self.assertFalse(widget.warning_label.isVisible())
self.assertTrue(widget.units_combo.isVisible())
self.assertFalse(widget.label.isVisible())
- self.assertEqual(widget.units_combo.currentData(), QgsUnitTypes.DistanceUnit.DistanceMeters)
+ self.assertEqual(
+ widget.units_combo.currentData(), QgsUnitTypes.DistanceUnit.DistanceMeters
+ )
- widget.setUnitParameterValue('EPSG:4326')
- self.assertEqual(widget.label.text(), 'degrees')
+ widget.setUnitParameterValue("EPSG:4326")
+ self.assertEqual(widget.label.text(), "degrees")
self.assertTrue(widget.warning_label.isVisible())
self.assertFalse(widget.units_combo.isVisible())
self.assertTrue(widget.label.isVisible())
- widget.setUnitParameterValue(QgsCoordinateReferenceSystem('EPSG:3111'))
- self.assertEqual(widget.label.text(), 'meters')
+ widget.setUnitParameterValue(QgsCoordinateReferenceSystem("EPSG:3111"))
+ self.assertEqual(widget.label.text(), "meters")
self.assertFalse(widget.warning_label.isVisible())
self.assertTrue(widget.units_combo.isVisible())
self.assertFalse(widget.label.isVisible())
- self.assertEqual(widget.units_combo.currentData(), QgsUnitTypes.DistanceUnit.DistanceMeters)
+ self.assertEqual(
+ widget.units_combo.currentData(), QgsUnitTypes.DistanceUnit.DistanceMeters
+ )
- widget.setUnitParameterValue(QgsCoordinateReferenceSystem('EPSG:4326'))
- self.assertEqual(widget.label.text(), 'degrees')
+ widget.setUnitParameterValue(QgsCoordinateReferenceSystem("EPSG:4326"))
+ self.assertEqual(widget.label.text(), "degrees")
self.assertTrue(widget.warning_label.isVisible())
self.assertFalse(widget.units_combo.isVisible())
self.assertTrue(widget.label.isVisible())
@@ -332,22 +386,24 @@ def testDistance(self):
# layer values
vl = QgsVectorLayer("Polygon?crs=epsg:3111&field=pk:int", "vl", "memory")
widget.setUnitParameterValue(vl)
- self.assertEqual(widget.label.text(), 'meters')
+ self.assertEqual(widget.label.text(), "meters")
self.assertFalse(widget.warning_label.isVisible())
self.assertTrue(widget.units_combo.isVisible())
self.assertFalse(widget.label.isVisible())
- self.assertEqual(widget.units_combo.currentData(), QgsUnitTypes.DistanceUnit.DistanceMeters)
+ self.assertEqual(
+ widget.units_combo.currentData(), QgsUnitTypes.DistanceUnit.DistanceMeters
+ )
vl2 = QgsVectorLayer("Polygon?crs=epsg:4326&field=pk:int", "vl", "memory")
widget.setUnitParameterValue(vl2)
- self.assertEqual(widget.label.text(), 'degrees')
+ self.assertEqual(widget.label.text(), "degrees")
self.assertTrue(widget.warning_label.isVisible())
self.assertFalse(widget.units_combo.isVisible())
self.assertTrue(widget.label.isVisible())
# unresolvable values
widget.setUnitParameterValue(vl.id())
- self.assertEqual(widget.label.text(), '')
+ self.assertEqual(widget.label.text(), "")
self.assertFalse(widget.warning_label.isVisible())
self.assertFalse(widget.units_combo.isVisible())
self.assertTrue(widget.label.isVisible())
@@ -355,15 +411,19 @@ def testDistance(self):
# resolvable text value
QgsProject.instance().addMapLayer(vl)
widget.setUnitParameterValue(vl.id())
- self.assertEqual(widget.label.text(), 'meters')
+ self.assertEqual(widget.label.text(), "meters")
self.assertFalse(widget.warning_label.isVisible())
self.assertTrue(widget.units_combo.isVisible())
self.assertFalse(widget.label.isVisible())
- self.assertEqual(widget.units_combo.currentData(), QgsUnitTypes.DistanceUnit.DistanceMeters)
+ self.assertEqual(
+ widget.units_combo.currentData(), QgsUnitTypes.DistanceUnit.DistanceMeters
+ )
widget.setValue(5)
self.assertEqual(widget.getValue(), 5)
- widget.units_combo.setCurrentIndex(widget.units_combo.findData(QgsUnitTypes.DistanceUnit.DistanceKilometers))
+ widget.units_combo.setCurrentIndex(
+ widget.units_combo.findData(QgsUnitTypes.DistanceUnit.DistanceKilometers)
+ )
self.assertEqual(widget.getValue(), 5000)
widget.setValue(2)
self.assertEqual(widget.getValue(), 2000)
@@ -376,16 +436,22 @@ def testDistance(self):
widget.deleteLater()
def testMatrix(self):
- self.checkConstructWrapper(QgsProcessingParameterMatrix('test'), FixedTableWidgetWrapper)
+ self.checkConstructWrapper(
+ QgsProcessingParameterMatrix("test"), FixedTableWidgetWrapper
+ )
- alg = QgsApplication.processingRegistry().createAlgorithmById('native:centroids')
+ alg = QgsApplication.processingRegistry().createAlgorithmById(
+ "native:centroids"
+ )
dlg = AlgorithmDialog(alg)
- param = QgsProcessingParameterMatrix('test', 'test', 2, True, ['x', 'y'], [['a', 'b'], ['c', 'd']])
+ param = QgsProcessingParameterMatrix(
+ "test", "test", 2, True, ["x", "y"], [["a", "b"], ["c", "d"]]
+ )
wrapper = FixedTableWidgetWrapper(param, dlg)
widget = wrapper.createWidget()
# check that default value is initially set
- self.assertEqual(wrapper.value(), [['a', 'b'], ['c', 'd']])
+ self.assertEqual(wrapper.value(), [["a", "b"], ["c", "d"]])
# test widget
widget.show()
@@ -395,11 +461,15 @@ def testMatrix(self):
widget.deleteLater()
def testNumber(self):
- self.checkConstructWrapper(QgsProcessingParameterNumber('test'), NumberWidgetWrapper)
+ self.checkConstructWrapper(
+ QgsProcessingParameterNumber("test"), NumberWidgetWrapper
+ )
def testBand(self):
- self.checkConstructWrapper(QgsProcessingParameterBand('test'), BandWidgetWrapper)
+ self.checkConstructWrapper(
+ QgsProcessingParameterBand("test"), BandWidgetWrapper
+ )
-if __name__ == '__main__':
+if __name__ == "__main__":
unittest.main()
diff --git a/python/plugins/processing/tests/ModelerTest.py b/python/plugins/processing/tests/ModelerTest.py
index 0ef46470485f..604b2d3037cb 100644
--- a/python/plugins/processing/tests/ModelerTest.py
+++ b/python/plugins/processing/tests/ModelerTest.py
@@ -15,21 +15,23 @@
***************************************************************************8
"""
-__author__ = 'Nyall Dawson'
-__date__ = 'November 2016'
-__copyright__ = '(C) 2016, Nyall Dawson'
+__author__ = "Nyall Dawson"
+__date__ = "November 2016"
+__copyright__ = "(C) 2016, Nyall Dawson"
import unittest
from qgis.testing import start_app, QgisTestCase
-from qgis.core import (QgsProcessingModelAlgorithm,
- QgsProcessingModelParameter,
- QgsProcessingParameterString,
- QgsProcessingParameterNumber,
- QgsProcessingParameterDistance,
- QgsProcessingParameterField,
- QgsProcessingParameterFile)
-from processing.modeler.ModelerParametersDialog import (ModelerParametersDialog)
+from qgis.core import (
+ QgsProcessingModelAlgorithm,
+ QgsProcessingModelParameter,
+ QgsProcessingParameterString,
+ QgsProcessingParameterNumber,
+ QgsProcessingParameterDistance,
+ QgsProcessingParameterField,
+ QgsProcessingParameterFile,
+)
+from processing.modeler.ModelerParametersDialog import ModelerParametersDialog
start_app()
@@ -41,34 +43,60 @@ def testModelerParametersDialogAvailableValuesOfType(self):
m = QgsProcessingModelAlgorithm()
- string_param_1 = QgsProcessingModelParameter('string')
- m.addModelParameter(QgsProcessingParameterString('string'), string_param_1)
+ string_param_1 = QgsProcessingModelParameter("string")
+ m.addModelParameter(QgsProcessingParameterString("string"), string_param_1)
- string_param_2 = QgsProcessingModelParameter('string2')
- m.addModelParameter(QgsProcessingParameterString('string2'), string_param_2)
+ string_param_2 = QgsProcessingModelParameter("string2")
+ m.addModelParameter(QgsProcessingParameterString("string2"), string_param_2)
- num_param = QgsProcessingModelParameter('number')
- m.addModelParameter(QgsProcessingParameterNumber('number'), num_param)
+ num_param = QgsProcessingModelParameter("number")
+ m.addModelParameter(QgsProcessingParameterNumber("number"), num_param)
- table_field_param = QgsProcessingModelParameter('field')
- m.addModelParameter(QgsProcessingParameterField('field'), table_field_param)
+ table_field_param = QgsProcessingModelParameter("field")
+ m.addModelParameter(QgsProcessingParameterField("field"), table_field_param)
- file_param = QgsProcessingModelParameter('file')
- m.addModelParameter(QgsProcessingParameterFile('file'), file_param)
+ file_param = QgsProcessingModelParameter("file")
+ m.addModelParameter(QgsProcessingParameterFile("file"), file_param)
dlg = ModelerParametersDialog(m, m)
# test single types
- self.assertEqual({p.parameterName() for p in dlg.getAvailableValuesOfType(QgsProcessingParameterNumber)},
- {'number'})
- self.assertEqual({p.parameterName() for p in dlg.getAvailableValuesOfType(QgsProcessingParameterField)},
- {'field'})
- self.assertEqual({p.parameterName() for p in dlg.getAvailableValuesOfType(QgsProcessingParameterFile)},
- {'file'})
+ self.assertEqual(
+ {
+ p.parameterName()
+ for p in dlg.getAvailableValuesOfType(QgsProcessingParameterNumber)
+ },
+ {"number"},
+ )
+ self.assertEqual(
+ {
+ p.parameterName()
+ for p in dlg.getAvailableValuesOfType(QgsProcessingParameterField)
+ },
+ {"field"},
+ )
+ self.assertEqual(
+ {
+ p.parameterName()
+ for p in dlg.getAvailableValuesOfType(QgsProcessingParameterFile)
+ },
+ {"file"},
+ )
# test multiple types
- self.assertEqual({p.parameterName() for p in dlg.getAvailableValuesOfType([QgsProcessingParameterString, QgsProcessingParameterNumber, QgsProcessingParameterFile])},
- {'string', 'string2', 'number', 'file'})
-
-
-if __name__ == '__main__':
+ self.assertEqual(
+ {
+ p.parameterName()
+ for p in dlg.getAvailableValuesOfType(
+ [
+ QgsProcessingParameterString,
+ QgsProcessingParameterNumber,
+ QgsProcessingParameterFile,
+ ]
+ )
+ },
+ {"string", "string2", "number", "file"},
+ )
+
+
+if __name__ == "__main__":
unittest.main()
diff --git a/python/plugins/processing/tests/ParametersTest.py b/python/plugins/processing/tests/ParametersTest.py
index c5c845c0a618..cfcebc154527 100644
--- a/python/plugins/processing/tests/ParametersTest.py
+++ b/python/plugins/processing/tests/ParametersTest.py
@@ -15,23 +15,25 @@
***************************************************************************
"""
-__author__ = 'René-Luc DHONT'
-__date__ = 'May 2021'
-__copyright__ = '(C) 2021, René-Luc DHONT'
+__author__ = "René-Luc DHONT"
+__date__ = "May 2021"
+__copyright__ = "(C) 2021, René-Luc DHONT"
import os
import shutil
-from qgis.core import (QgsProcessingParameterDefinition,
- QgsProcessingParameterNumber,
- QgsProcessingParameterFile,
- QgsProcessing)
+from qgis.core import (
+ QgsProcessingParameterDefinition,
+ QgsProcessingParameterNumber,
+ QgsProcessingParameterFile,
+ QgsProcessing,
+)
import unittest
from qgis.testing import start_app, QgisTestCase
from processing.core.parameters import getParameterFromString
-testDataPath = os.path.join(os.path.dirname(__file__), 'testdata')
+testDataPath = os.path.join(os.path.dirname(__file__), "testdata")
start_app()
@@ -48,695 +50,889 @@ def tearDownClass(cls):
shutil.rmtree(path)
def testParameterStringDesc(self):
- desc = 'QgsProcessingParameterString|in_string|Input String'
+ desc = "QgsProcessingParameterString|in_string|Input String"
param = getParameterFromString(desc)
self.assertIsNotNone(param)
- self.assertEqual(param.type(), 'string')
- self.assertEqual(param.name(), 'in_string')
- self.assertEqual(param.description(), 'Input String')
- self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional)
+ self.assertEqual(param.type(), "string")
+ self.assertEqual(param.name(), "in_string")
+ self.assertEqual(param.description(), "Input String")
+ self.assertFalse(
+ param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional
+ )
- desc = 'QgsProcessingParameterString|in_string|Input String|default value'
+ desc = "QgsProcessingParameterString|in_string|Input String|default value"
param = getParameterFromString(desc)
self.assertIsNotNone(param)
- self.assertEqual(param.type(), 'string')
- self.assertEqual(param.name(), 'in_string')
- self.assertEqual(param.description(), 'Input String')
- self.assertEqual(param.defaultValue(), 'default value')
- self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional)
+ self.assertEqual(param.type(), "string")
+ self.assertEqual(param.name(), "in_string")
+ self.assertEqual(param.description(), "Input String")
+ self.assertEqual(param.defaultValue(), "default value")
+ self.assertFalse(
+ param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional
+ )
- desc = 'QgsProcessingParameterString|in_string|Input String|default value|True'
+ desc = "QgsProcessingParameterString|in_string|Input String|default value|True"
param = getParameterFromString(desc)
self.assertIsNotNone(param)
- self.assertEqual(param.type(), 'string')
- self.assertEqual(param.name(), 'in_string')
- self.assertEqual(param.description(), 'Input String')
- self.assertEqual(param.defaultValue(), 'default value')
+ self.assertEqual(param.type(), "string")
+ self.assertEqual(param.name(), "in_string")
+ self.assertEqual(param.description(), "Input String")
+ self.assertEqual(param.defaultValue(), "default value")
self.assertTrue(param.multiLine())
- self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional)
+ self.assertFalse(
+ param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional
+ )
- desc = 'QgsProcessingParameterString|in_string|Input String||False|True'
+ desc = "QgsProcessingParameterString|in_string|Input String||False|True"
param = getParameterFromString(desc)
self.assertIsNotNone(param)
- self.assertEqual(param.type(), 'string')
- self.assertEqual(param.name(), 'in_string')
- self.assertEqual(param.description(), 'Input String')
- self.assertEqual(param.defaultValue(), '')
+ self.assertEqual(param.type(), "string")
+ self.assertEqual(param.name(), "in_string")
+ self.assertEqual(param.description(), "Input String")
+ self.assertEqual(param.defaultValue(), "")
self.assertFalse(param.multiLine())
- self.assertTrue(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional)
+ self.assertTrue(
+ param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional
+ )
def testParameterNumberDesc(self):
- desc = 'QgsProcessingParameterNumber|in_number|Input Number'
+ desc = "QgsProcessingParameterNumber|in_number|Input Number"
param = getParameterFromString(desc)
self.assertIsNotNone(param)
- self.assertEqual(param.type(), 'number')
- self.assertEqual(param.name(), 'in_number')
- self.assertEqual(param.description(), 'Input Number')
+ self.assertEqual(param.type(), "number")
+ self.assertEqual(param.name(), "in_number")
+ self.assertEqual(param.description(), "Input Number")
self.assertEqual(param.dataType(), QgsProcessingParameterNumber.Type.Integer)
- self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional)
+ self.assertFalse(
+ param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional
+ )
- desc = 'QgsProcessingParameterNumber|in_number|Input Number|QgsProcessingParameterNumber.Double'
+ desc = "QgsProcessingParameterNumber|in_number|Input Number|QgsProcessingParameterNumber.Double"
param = getParameterFromString(desc)
self.assertIsNotNone(param)
- self.assertEqual(param.type(), 'number')
- self.assertEqual(param.name(), 'in_number')
- self.assertEqual(param.description(), 'Input Number')
+ self.assertEqual(param.type(), "number")
+ self.assertEqual(param.name(), "in_number")
+ self.assertEqual(param.description(), "Input Number")
self.assertEqual(param.dataType(), QgsProcessingParameterNumber.Type.Double)
- self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional)
+ self.assertFalse(
+ param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional
+ )
- desc = 'QgsProcessingParameterNumber|in_number|Input Number|QgsProcessingParameterNumber.Integer|10'
+ desc = "QgsProcessingParameterNumber|in_number|Input Number|QgsProcessingParameterNumber.Integer|10"
param = getParameterFromString(desc)
self.assertIsNotNone(param)
- self.assertEqual(param.type(), 'number')
- self.assertEqual(param.name(), 'in_number')
- self.assertEqual(param.description(), 'Input Number')
+ self.assertEqual(param.type(), "number")
+ self.assertEqual(param.name(), "in_number")
+ self.assertEqual(param.description(), "Input Number")
self.assertEqual(param.dataType(), QgsProcessingParameterNumber.Type.Integer)
self.assertEqual(param.defaultValue(), 10)
- self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional)
+ self.assertFalse(
+ param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional
+ )
- desc = 'QgsProcessingParameterNumber|in_number|Input Number|QgsProcessingParameterNumber.Integer|None|True'
+ desc = "QgsProcessingParameterNumber|in_number|Input Number|QgsProcessingParameterNumber.Integer|None|True"
param = getParameterFromString(desc)
self.assertIsNotNone(param)
- self.assertEqual(param.type(), 'number')
- self.assertEqual(param.name(), 'in_number')
- self.assertEqual(param.description(), 'Input Number')
+ self.assertEqual(param.type(), "number")
+ self.assertEqual(param.name(), "in_number")
+ self.assertEqual(param.description(), "Input Number")
self.assertEqual(param.dataType(), QgsProcessingParameterNumber.Type.Integer)
self.assertIsNone(param.defaultValue())
- self.assertTrue(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional)
+ self.assertTrue(
+ param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional
+ )
- desc = 'QgsProcessingParameterNumber|in_number|Input Number|QgsProcessingParameterNumber.Integer|10|False|0'
+ desc = "QgsProcessingParameterNumber|in_number|Input Number|QgsProcessingParameterNumber.Integer|10|False|0"
param = getParameterFromString(desc)
self.assertIsNotNone(param)
- self.assertEqual(param.type(), 'number')
- self.assertEqual(param.name(), 'in_number')
- self.assertEqual(param.description(), 'Input Number')
+ self.assertEqual(param.type(), "number")
+ self.assertEqual(param.name(), "in_number")
+ self.assertEqual(param.description(), "Input Number")
self.assertEqual(param.dataType(), QgsProcessingParameterNumber.Type.Integer)
self.assertEqual(param.defaultValue(), 10)
- self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional)
+ self.assertFalse(
+ param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional
+ )
self.assertEqual(param.minimum(), 0)
- desc = 'QgsProcessingParameterNumber|in_number|Input Number|QgsProcessingParameterNumber.Integer|10|False|0|20'
+ desc = "QgsProcessingParameterNumber|in_number|Input Number|QgsProcessingParameterNumber.Integer|10|False|0|20"
param = getParameterFromString(desc)
self.assertIsNotNone(param)
- self.assertEqual(param.type(), 'number')
- self.assertEqual(param.name(), 'in_number')
- self.assertEqual(param.description(), 'Input Number')
+ self.assertEqual(param.type(), "number")
+ self.assertEqual(param.name(), "in_number")
+ self.assertEqual(param.description(), "Input Number")
self.assertEqual(param.dataType(), QgsProcessingParameterNumber.Type.Integer)
self.assertEqual(param.defaultValue(), 10)
- self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional)
+ self.assertFalse(
+ param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional
+ )
self.assertEqual(param.minimum(), 0)
self.assertEqual(param.maximum(), 20)
def testParameterBooleanDesc(self):
- desc = 'QgsProcessingParameterBoolean|in_bool|Input Boolean'
+ desc = "QgsProcessingParameterBoolean|in_bool|Input Boolean"
param = getParameterFromString(desc)
self.assertIsNotNone(param)
- self.assertEqual(param.type(), 'boolean')
- self.assertEqual(param.name(), 'in_bool')
- self.assertEqual(param.description(), 'Input Boolean')
+ self.assertEqual(param.type(), "boolean")
+ self.assertEqual(param.name(), "in_bool")
+ self.assertEqual(param.description(), "Input Boolean")
self.assertFalse(param.defaultValue())
- self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional)
+ self.assertFalse(
+ param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional
+ )
- desc = 'QgsProcessingParameterBoolean|in_bool|Input Boolean|True'
+ desc = "QgsProcessingParameterBoolean|in_bool|Input Boolean|True"
param = getParameterFromString(desc)
self.assertIsNotNone(param)
- self.assertEqual(param.type(), 'boolean')
- self.assertEqual(param.name(), 'in_bool')
- self.assertEqual(param.description(), 'Input Boolean')
+ self.assertEqual(param.type(), "boolean")
+ self.assertEqual(param.name(), "in_bool")
+ self.assertEqual(param.description(), "Input Boolean")
self.assertTrue(param.defaultValue())
- self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional)
+ self.assertFalse(
+ param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional
+ )
- desc = 'QgsProcessingParameterBoolean|in_bool|Input Boolean|False|True'
+ desc = "QgsProcessingParameterBoolean|in_bool|Input Boolean|False|True"
param = getParameterFromString(desc)
self.assertIsNotNone(param)
- self.assertEqual(param.type(), 'boolean')
- self.assertEqual(param.name(), 'in_bool')
- self.assertEqual(param.description(), 'Input Boolean')
+ self.assertEqual(param.type(), "boolean")
+ self.assertEqual(param.name(), "in_bool")
+ self.assertEqual(param.description(), "Input Boolean")
self.assertFalse(param.defaultValue())
- self.assertTrue(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional)
+ self.assertTrue(
+ param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional
+ )
def testParameterCrsDesc(self):
- desc = 'QgsProcessingParameterCrs|in_crs|Input CRS'
+ desc = "QgsProcessingParameterCrs|in_crs|Input CRS"
param = getParameterFromString(desc)
self.assertIsNotNone(param)
- self.assertEqual(param.type(), 'crs')
- self.assertEqual(param.name(), 'in_crs')
- self.assertEqual(param.description(), 'Input CRS')
+ self.assertEqual(param.type(), "crs")
+ self.assertEqual(param.name(), "in_crs")
+ self.assertEqual(param.description(), "Input CRS")
self.assertIsNone(param.defaultValue())
- self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional)
+ self.assertFalse(
+ param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional
+ )
- desc = 'QgsProcessingParameterCrs|in_crs|Input CRS|EPSG:2154'
+ desc = "QgsProcessingParameterCrs|in_crs|Input CRS|EPSG:2154"
param = getParameterFromString(desc)
self.assertIsNotNone(param)
- self.assertEqual(param.type(), 'crs')
- self.assertEqual(param.name(), 'in_crs')
- self.assertEqual(param.description(), 'Input CRS')
- self.assertEqual(param.defaultValue(), 'EPSG:2154')
- self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional)
+ self.assertEqual(param.type(), "crs")
+ self.assertEqual(param.name(), "in_crs")
+ self.assertEqual(param.description(), "Input CRS")
+ self.assertEqual(param.defaultValue(), "EPSG:2154")
+ self.assertFalse(
+ param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional
+ )
- desc = 'QgsProcessingParameterCrs|in_crs|Input CRS|None|True'
+ desc = "QgsProcessingParameterCrs|in_crs|Input CRS|None|True"
param = getParameterFromString(desc)
self.assertIsNotNone(param)
- self.assertEqual(param.type(), 'crs')
- self.assertEqual(param.name(), 'in_crs')
- self.assertEqual(param.description(), 'Input CRS')
+ self.assertEqual(param.type(), "crs")
+ self.assertEqual(param.name(), "in_crs")
+ self.assertEqual(param.description(), "Input CRS")
self.assertIsNone(param.defaultValue())
- self.assertTrue(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional)
+ self.assertTrue(
+ param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional
+ )
def testParameterExtentDesc(self):
- desc = 'QgsProcessingParameterExtent|in_extent|Input Extent'
+ desc = "QgsProcessingParameterExtent|in_extent|Input Extent"
param = getParameterFromString(desc)
self.assertIsNotNone(param)
- self.assertEqual(param.type(), 'extent')
- self.assertEqual(param.name(), 'in_extent')
- self.assertEqual(param.description(), 'Input Extent')
+ self.assertEqual(param.type(), "extent")
+ self.assertEqual(param.name(), "in_extent")
+ self.assertEqual(param.description(), "Input Extent")
self.assertIsNone(param.defaultValue())
- self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional)
+ self.assertFalse(
+ param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional
+ )
- desc = 'QgsProcessingParameterExtent|in_extent|Input Extent|None|True'
+ desc = "QgsProcessingParameterExtent|in_extent|Input Extent|None|True"
param = getParameterFromString(desc)
self.assertIsNotNone(param)
- self.assertEqual(param.type(), 'extent')
- self.assertEqual(param.name(), 'in_extent')
- self.assertEqual(param.description(), 'Input Extent')
+ self.assertEqual(param.type(), "extent")
+ self.assertEqual(param.name(), "in_extent")
+ self.assertEqual(param.description(), "Input Extent")
self.assertIsNone(param.defaultValue())
- self.assertTrue(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional)
+ self.assertTrue(
+ param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional
+ )
def testParameterFileDesc(self):
- desc = 'QgsProcessingParameterFile|in_file|Input File'
+ desc = "QgsProcessingParameterFile|in_file|Input File"
param = getParameterFromString(desc)
self.assertIsNotNone(param)
- self.assertEqual(param.type(), 'file')
- self.assertEqual(param.name(), 'in_file')
- self.assertEqual(param.description(), 'Input File')
+ self.assertEqual(param.type(), "file")
+ self.assertEqual(param.name(), "in_file")
+ self.assertEqual(param.description(), "Input File")
self.assertEqual(param.behavior(), QgsProcessingParameterFile.Behavior.File)
self.assertIsNone(param.defaultValue())
- self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional)
+ self.assertFalse(
+ param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional
+ )
- desc = 'QgsProcessingParameterFile|in_folder|Input Folder|1'
+ desc = "QgsProcessingParameterFile|in_folder|Input Folder|1"
param = getParameterFromString(desc)
self.assertIsNotNone(param)
- self.assertEqual(param.type(), 'file')
- self.assertEqual(param.name(), 'in_folder')
- self.assertEqual(param.description(), 'Input Folder')
+ self.assertEqual(param.type(), "file")
+ self.assertEqual(param.name(), "in_folder")
+ self.assertEqual(param.description(), "Input Folder")
self.assertEqual(param.behavior(), QgsProcessingParameterFile.Behavior.Folder)
self.assertIsNone(param.defaultValue())
- self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional)
+ self.assertFalse(
+ param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional
+ )
- desc = 'QgsProcessingParameterFile|in_folder|Input Folder|QgsProcessingParameterFile.Folder'
+ desc = "QgsProcessingParameterFile|in_folder|Input Folder|QgsProcessingParameterFile.Folder"
param = getParameterFromString(desc)
self.assertIsNotNone(param)
- self.assertEqual(param.type(), 'file')
- self.assertEqual(param.name(), 'in_folder')
- self.assertEqual(param.description(), 'Input Folder')
+ self.assertEqual(param.type(), "file")
+ self.assertEqual(param.name(), "in_folder")
+ self.assertEqual(param.description(), "Input Folder")
self.assertEqual(param.behavior(), QgsProcessingParameterFile.Behavior.Folder)
self.assertIsNone(param.defaultValue())
- self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional)
+ self.assertFalse(
+ param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional
+ )
- desc = 'QgsProcessingParameterFile|in_file|Input File|0|gpkg'
+ desc = "QgsProcessingParameterFile|in_file|Input File|0|gpkg"
param = getParameterFromString(desc)
self.assertIsNotNone(param)
- self.assertEqual(param.type(), 'file')
- self.assertEqual(param.name(), 'in_file')
- self.assertEqual(param.description(), 'Input File')
+ self.assertEqual(param.type(), "file")
+ self.assertEqual(param.name(), "in_file")
+ self.assertEqual(param.description(), "Input File")
self.assertEqual(param.behavior(), QgsProcessingParameterFile.Behavior.File)
- self.assertEqual(param.extension(), 'gpkg')
+ self.assertEqual(param.extension(), "gpkg")
self.assertIsNone(param.defaultValue())
- self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional)
+ self.assertFalse(
+ param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional
+ )
- desc = 'QgsProcessingParameterFile|in_file|Input File|0|png|None|False|PNG Files (*.png);; JPG Files (*.jpg *.jpeg)'
+ desc = "QgsProcessingParameterFile|in_file|Input File|0|png|None|False|PNG Files (*.png);; JPG Files (*.jpg *.jpeg)"
param = getParameterFromString(desc)
self.assertIsNotNone(param)
- self.assertEqual(param.type(), 'file')
- self.assertEqual(param.name(), 'in_file')
- self.assertEqual(param.description(), 'Input File')
+ self.assertEqual(param.type(), "file")
+ self.assertEqual(param.name(), "in_file")
+ self.assertEqual(param.description(), "Input File")
self.assertEqual(param.behavior(), QgsProcessingParameterFile.Behavior.File)
- self.assertEqual(param.extension(), '')
+ self.assertEqual(param.extension(), "")
self.assertIsNone(param.defaultValue())
- self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional)
- self.assertEqual(param.fileFilter(), 'PNG Files (*.png);; JPG Files (*.jpg *.jpeg)')
+ self.assertFalse(
+ param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional
+ )
+ self.assertEqual(
+ param.fileFilter(), "PNG Files (*.png);; JPG Files (*.jpg *.jpeg)"
+ )
def testParameterVectorDestDesc(self):
- desc = 'QgsProcessingParameterVectorDestination|param_vector_dest|Vector Destination'
+ desc = "QgsProcessingParameterVectorDestination|param_vector_dest|Vector Destination"
param = getParameterFromString(desc)
self.assertIsNotNone(param)
- self.assertEqual(param.type(), 'vectorDestination')
- self.assertEqual(param.name(), 'param_vector_dest')
- self.assertEqual(param.description(), 'Vector Destination')
- self.assertEqual(param.dataType(), QgsProcessing.SourceType.TypeVectorAnyGeometry)
+ self.assertEqual(param.type(), "vectorDestination")
+ self.assertEqual(param.name(), "param_vector_dest")
+ self.assertEqual(param.description(), "Vector Destination")
+ self.assertEqual(
+ param.dataType(), QgsProcessing.SourceType.TypeVectorAnyGeometry
+ )
self.assertIsNone(param.defaultValue())
- self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional)
+ self.assertFalse(
+ param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional
+ )
self.assertTrue(param.createByDefault())
- desc = 'QgsProcessingParameterVectorDestination|param_vector_dest|Vector Destination Point|0'
+ desc = "QgsProcessingParameterVectorDestination|param_vector_dest|Vector Destination Point|0"
param = getParameterFromString(desc)
self.assertIsNotNone(param)
- self.assertEqual(param.type(), 'vectorDestination')
- self.assertEqual(param.name(), 'param_vector_dest')
- self.assertEqual(param.description(), 'Vector Destination Point')
+ self.assertEqual(param.type(), "vectorDestination")
+ self.assertEqual(param.name(), "param_vector_dest")
+ self.assertEqual(param.description(), "Vector Destination Point")
self.assertEqual(param.dataType(), QgsProcessing.SourceType.TypeVectorPoint)
self.assertIsNone(param.defaultValue())
- self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional)
+ self.assertFalse(
+ param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional
+ )
self.assertTrue(param.createByDefault())
- desc = 'QgsProcessingParameterVectorDestination|param_vector_dest|Vector Destination Point|QgsProcessing.TypeVectorPoint'
+ desc = "QgsProcessingParameterVectorDestination|param_vector_dest|Vector Destination Point|QgsProcessing.TypeVectorPoint"
param = getParameterFromString(desc)
self.assertIsNotNone(param)
- self.assertEqual(param.type(), 'vectorDestination')
- self.assertEqual(param.name(), 'param_vector_dest')
- self.assertEqual(param.description(), 'Vector Destination Point')
+ self.assertEqual(param.type(), "vectorDestination")
+ self.assertEqual(param.name(), "param_vector_dest")
+ self.assertEqual(param.description(), "Vector Destination Point")
self.assertEqual(param.dataType(), QgsProcessing.SourceType.TypeVectorPoint)
self.assertIsNone(param.defaultValue())
- self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional)
+ self.assertFalse(
+ param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional
+ )
self.assertTrue(param.createByDefault())
- desc = 'QgsProcessingParameterVectorDestination|param_vector_dest|Vector Destination Line|1'
+ desc = "QgsProcessingParameterVectorDestination|param_vector_dest|Vector Destination Line|1"
param = getParameterFromString(desc)
self.assertIsNotNone(param)
- self.assertEqual(param.type(), 'vectorDestination')
- self.assertEqual(param.name(), 'param_vector_dest')
- self.assertEqual(param.description(), 'Vector Destination Line')
+ self.assertEqual(param.type(), "vectorDestination")
+ self.assertEqual(param.name(), "param_vector_dest")
+ self.assertEqual(param.description(), "Vector Destination Line")
self.assertEqual(param.dataType(), QgsProcessing.SourceType.TypeVectorLine)
self.assertIsNone(param.defaultValue())
- self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional)
+ self.assertFalse(
+ param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional
+ )
self.assertTrue(param.createByDefault())
- desc = 'QgsProcessingParameterVectorDestination|param_vector_dest|Vector Destination Line|QgsProcessing.TypeVectorLine'
+ desc = "QgsProcessingParameterVectorDestination|param_vector_dest|Vector Destination Line|QgsProcessing.TypeVectorLine"
param = getParameterFromString(desc)
self.assertIsNotNone(param)
- self.assertEqual(param.type(), 'vectorDestination')
- self.assertEqual(param.name(), 'param_vector_dest')
- self.assertEqual(param.description(), 'Vector Destination Line')
+ self.assertEqual(param.type(), "vectorDestination")
+ self.assertEqual(param.name(), "param_vector_dest")
+ self.assertEqual(param.description(), "Vector Destination Line")
self.assertEqual(param.dataType(), QgsProcessing.SourceType.TypeVectorLine)
self.assertIsNone(param.defaultValue())
- self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional)
+ self.assertFalse(
+ param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional
+ )
self.assertTrue(param.createByDefault())
- desc = 'QgsProcessingParameterVectorDestination|param_vector_dest|Vector Destination Polygon|2'
+ desc = "QgsProcessingParameterVectorDestination|param_vector_dest|Vector Destination Polygon|2"
param = getParameterFromString(desc)
self.assertIsNotNone(param)
- self.assertEqual(param.type(), 'vectorDestination')
- self.assertEqual(param.name(), 'param_vector_dest')
- self.assertEqual(param.description(), 'Vector Destination Polygon')
+ self.assertEqual(param.type(), "vectorDestination")
+ self.assertEqual(param.name(), "param_vector_dest")
+ self.assertEqual(param.description(), "Vector Destination Polygon")
self.assertEqual(param.dataType(), QgsProcessing.SourceType.TypeVectorPolygon)
self.assertIsNone(param.defaultValue())
- self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional)
+ self.assertFalse(
+ param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional
+ )
self.assertTrue(param.createByDefault())
- desc = 'QgsProcessingParameterVectorDestination|param_vector_dest|Vector Destination Polygon|QgsProcessing.TypeVectorPolygon'
+ desc = "QgsProcessingParameterVectorDestination|param_vector_dest|Vector Destination Polygon|QgsProcessing.TypeVectorPolygon"
param = getParameterFromString(desc)
self.assertIsNotNone(param)
- self.assertEqual(param.type(), 'vectorDestination')
- self.assertEqual(param.name(), 'param_vector_dest')
- self.assertEqual(param.description(), 'Vector Destination Polygon')
+ self.assertEqual(param.type(), "vectorDestination")
+ self.assertEqual(param.name(), "param_vector_dest")
+ self.assertEqual(param.description(), "Vector Destination Polygon")
self.assertEqual(param.dataType(), QgsProcessing.SourceType.TypeVectorPolygon)
self.assertIsNone(param.defaultValue())
- self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional)
+ self.assertFalse(
+ param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional
+ )
self.assertTrue(param.createByDefault())
- desc = 'QgsProcessingParameterVectorDestination|param_vector_dest|Vector Destination Table|5'
+ desc = "QgsProcessingParameterVectorDestination|param_vector_dest|Vector Destination Table|5"
param = getParameterFromString(desc)
self.assertIsNotNone(param)
- self.assertEqual(param.type(), 'vectorDestination')
- self.assertEqual(param.name(), 'param_vector_dest')
- self.assertEqual(param.description(), 'Vector Destination Table')
+ self.assertEqual(param.type(), "vectorDestination")
+ self.assertEqual(param.name(), "param_vector_dest")
+ self.assertEqual(param.description(), "Vector Destination Table")
self.assertEqual(param.dataType(), QgsProcessing.SourceType.TypeVector)
self.assertIsNone(param.defaultValue())
- self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional)
+ self.assertFalse(
+ param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional
+ )
self.assertTrue(param.createByDefault())
- desc = 'QgsProcessingParameterVectorDestination|param_vector_dest|Vector Destination Table|QgsProcessing.TypeVector'
+ desc = "QgsProcessingParameterVectorDestination|param_vector_dest|Vector Destination Table|QgsProcessing.TypeVector"
param = getParameterFromString(desc)
self.assertIsNotNone(param)
- self.assertEqual(param.type(), 'vectorDestination')
- self.assertEqual(param.name(), 'param_vector_dest')
- self.assertEqual(param.description(), 'Vector Destination Table')
+ self.assertEqual(param.type(), "vectorDestination")
+ self.assertEqual(param.name(), "param_vector_dest")
+ self.assertEqual(param.description(), "Vector Destination Table")
self.assertEqual(param.dataType(), QgsProcessing.SourceType.TypeVector)
self.assertIsNone(param.defaultValue())
- self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional)
+ self.assertFalse(
+ param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional
+ )
self.assertTrue(param.createByDefault())
- desc = 'QgsProcessingParameterVectorDestination|param_vector_dest|Vector Destination|-1|None|True|False'
+ desc = "QgsProcessingParameterVectorDestination|param_vector_dest|Vector Destination|-1|None|True|False"
param = getParameterFromString(desc)
self.assertIsNotNone(param)
- self.assertEqual(param.type(), 'vectorDestination')
- self.assertEqual(param.name(), 'param_vector_dest')
- self.assertEqual(param.description(), 'Vector Destination')
- self.assertEqual(param.dataType(), QgsProcessing.SourceType.TypeVectorAnyGeometry)
+ self.assertEqual(param.type(), "vectorDestination")
+ self.assertEqual(param.name(), "param_vector_dest")
+ self.assertEqual(param.description(), "Vector Destination")
+ self.assertEqual(
+ param.dataType(), QgsProcessing.SourceType.TypeVectorAnyGeometry
+ )
self.assertIsNone(param.defaultValue())
- self.assertTrue(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional)
+ self.assertTrue(
+ param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional
+ )
self.assertFalse(param.createByDefault())
def testParameterRasterDestDesc(self):
- desc = 'QgsProcessingParameterRasterDestination|param_raster_dest|Raster Destination'
+ desc = "QgsProcessingParameterRasterDestination|param_raster_dest|Raster Destination"
param = getParameterFromString(desc)
self.assertIsNotNone(param)
- self.assertEqual(param.type(), 'rasterDestination')
- self.assertEqual(param.name(), 'param_raster_dest')
- self.assertEqual(param.description(), 'Raster Destination')
+ self.assertEqual(param.type(), "rasterDestination")
+ self.assertEqual(param.name(), "param_raster_dest")
+ self.assertEqual(param.description(), "Raster Destination")
self.assertIsNone(param.defaultValue())
- self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional)
+ self.assertFalse(
+ param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional
+ )
self.assertTrue(param.createByDefault())
- desc = 'QgsProcessingParameterRasterDestination|param_raster_dest|Raster Destination|None|True|False'
+ desc = "QgsProcessingParameterRasterDestination|param_raster_dest|Raster Destination|None|True|False"
param = getParameterFromString(desc)
self.assertIsNotNone(param)
- self.assertEqual(param.type(), 'rasterDestination')
- self.assertEqual(param.name(), 'param_raster_dest')
- self.assertEqual(param.description(), 'Raster Destination')
+ self.assertEqual(param.type(), "rasterDestination")
+ self.assertEqual(param.name(), "param_raster_dest")
+ self.assertEqual(param.description(), "Raster Destination")
self.assertIsNone(param.defaultValue())
- self.assertTrue(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional)
+ self.assertTrue(
+ param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional
+ )
self.assertFalse(param.createByDefault())
def testParameterFolderDestDesc(self):
- desc = 'QgsProcessingParameterFolderDestination|param_folder_dest|Folder Destination'
+ desc = "QgsProcessingParameterFolderDestination|param_folder_dest|Folder Destination"
param = getParameterFromString(desc)
self.assertIsNotNone(param)
- self.assertEqual(param.type(), 'folderDestination')
- self.assertEqual(param.name(), 'param_folder_dest')
- self.assertEqual(param.description(), 'Folder Destination')
+ self.assertEqual(param.type(), "folderDestination")
+ self.assertEqual(param.name(), "param_folder_dest")
+ self.assertEqual(param.description(), "Folder Destination")
self.assertIsNone(param.defaultValue())
- self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional)
+ self.assertFalse(
+ param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional
+ )
self.assertTrue(param.createByDefault())
- desc = 'QgsProcessingParameterFolderDestination|param_folder_dest|Folder Destination|None|True|False'
+ desc = "QgsProcessingParameterFolderDestination|param_folder_dest|Folder Destination|None|True|False"
param = getParameterFromString(desc)
self.assertIsNotNone(param)
- self.assertEqual(param.type(), 'folderDestination')
- self.assertEqual(param.name(), 'param_folder_dest')
- self.assertEqual(param.description(), 'Folder Destination')
+ self.assertEqual(param.type(), "folderDestination")
+ self.assertEqual(param.name(), "param_folder_dest")
+ self.assertEqual(param.description(), "Folder Destination")
self.assertIsNone(param.defaultValue())
- self.assertTrue(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional)
+ self.assertTrue(
+ param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional
+ )
self.assertFalse(param.createByDefault())
def testParameterFileDestDesc(self):
- desc = 'QgsProcessingParameterFileDestination|param_file_dest|File Destination'
+ desc = "QgsProcessingParameterFileDestination|param_file_dest|File Destination"
param = getParameterFromString(desc)
self.assertIsNotNone(param)
- self.assertEqual(param.type(), 'fileDestination')
- self.assertEqual(param.name(), 'param_file_dest')
- self.assertEqual(param.description(), 'File Destination')
+ self.assertEqual(param.type(), "fileDestination")
+ self.assertEqual(param.name(), "param_file_dest")
+ self.assertEqual(param.description(), "File Destination")
self.assertIsNone(param.defaultValue())
- self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional)
+ self.assertFalse(
+ param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional
+ )
self.assertTrue(param.createByDefault())
- desc = 'QgsProcessingParameterFileDestination|param_html_dest|HTML File Destination|HTML Files (*.html)'
+ desc = "QgsProcessingParameterFileDestination|param_html_dest|HTML File Destination|HTML Files (*.html)"
param = getParameterFromString(desc)
self.assertIsNotNone(param)
- self.assertEqual(param.type(), 'fileDestination')
- self.assertEqual(param.name(), 'param_html_dest')
- self.assertEqual(param.description(), 'HTML File Destination')
- self.assertEqual(param.fileFilter(), 'HTML Files (*.html)')
- self.assertEqual(param.defaultFileExtension(), 'html')
+ self.assertEqual(param.type(), "fileDestination")
+ self.assertEqual(param.name(), "param_html_dest")
+ self.assertEqual(param.description(), "HTML File Destination")
+ self.assertEqual(param.fileFilter(), "HTML Files (*.html)")
+ self.assertEqual(param.defaultFileExtension(), "html")
self.assertIsNone(param.defaultValue())
- self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional)
+ self.assertFalse(
+ param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional
+ )
self.assertTrue(param.createByDefault())
- desc = 'QgsProcessingParameterFileDestination|param_img_dest|Img File Destination|PNG Files (*.png);; JPG Files (*.jpg *.jpeg)'
+ desc = "QgsProcessingParameterFileDestination|param_img_dest|Img File Destination|PNG Files (*.png);; JPG Files (*.jpg *.jpeg)"
param = getParameterFromString(desc)
self.assertIsNotNone(param)
- self.assertEqual(param.type(), 'fileDestination')
- self.assertEqual(param.name(), 'param_img_dest')
- self.assertEqual(param.description(), 'Img File Destination')
- self.assertEqual(param.fileFilter(), 'PNG Files (*.png);; JPG Files (*.jpg *.jpeg)')
- self.assertEqual(param.defaultFileExtension(), 'png')
+ self.assertEqual(param.type(), "fileDestination")
+ self.assertEqual(param.name(), "param_img_dest")
+ self.assertEqual(param.description(), "Img File Destination")
+ self.assertEqual(
+ param.fileFilter(), "PNG Files (*.png);; JPG Files (*.jpg *.jpeg)"
+ )
+ self.assertEqual(param.defaultFileExtension(), "png")
self.assertIsNone(param.defaultValue())
- self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional)
+ self.assertFalse(
+ param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional
+ )
self.assertTrue(param.createByDefault())
- desc = 'QgsProcessingParameterFileDestination|param_csv_dest|CSV File Destination|CSV Files (*.csv)|None|True|False'
+ desc = "QgsProcessingParameterFileDestination|param_csv_dest|CSV File Destination|CSV Files (*.csv)|None|True|False"
param = getParameterFromString(desc)
self.assertIsNotNone(param)
- self.assertEqual(param.type(), 'fileDestination')
- self.assertEqual(param.name(), 'param_csv_dest')
- self.assertEqual(param.description(), 'CSV File Destination')
- self.assertEqual(param.fileFilter(), 'CSV Files (*.csv)')
- self.assertEqual(param.defaultFileExtension(), 'csv')
+ self.assertEqual(param.type(), "fileDestination")
+ self.assertEqual(param.name(), "param_csv_dest")
+ self.assertEqual(param.description(), "CSV File Destination")
+ self.assertEqual(param.fileFilter(), "CSV Files (*.csv)")
+ self.assertEqual(param.defaultFileExtension(), "csv")
self.assertIsNone(param.defaultValue())
- self.assertTrue(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional)
+ self.assertTrue(
+ param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional
+ )
self.assertFalse(param.createByDefault())
def testParameterFeatureSourceDesc(self):
- desc = 'QgsProcessingParameterFeatureSource|in_vector|Input Vector'
+ desc = "QgsProcessingParameterFeatureSource|in_vector|Input Vector"
param = getParameterFromString(desc)
self.assertIsNotNone(param)
- self.assertEqual(param.type(), 'source')
- self.assertEqual(param.name(), 'in_vector')
- self.assertEqual(param.description(), 'Input Vector')
+ self.assertEqual(param.type(), "source")
+ self.assertEqual(param.name(), "in_vector")
+ self.assertEqual(param.description(), "Input Vector")
self.assertListEqual(param.dataTypes(), [])
self.assertIsNone(param.defaultValue())
- self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional)
+ self.assertFalse(
+ param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional
+ )
- desc = 'QgsProcessingParameterFeatureSource|in_vector|Input Vector|0'
+ desc = "QgsProcessingParameterFeatureSource|in_vector|Input Vector|0"
param = getParameterFromString(desc)
self.assertIsNotNone(param)
- self.assertEqual(param.type(), 'source')
- self.assertEqual(param.name(), 'in_vector')
- self.assertEqual(param.description(), 'Input Vector')
- self.assertListEqual(param.dataTypes(), [QgsProcessing.SourceType.TypeVectorPoint])
+ self.assertEqual(param.type(), "source")
+ self.assertEqual(param.name(), "in_vector")
+ self.assertEqual(param.description(), "Input Vector")
+ self.assertListEqual(
+ param.dataTypes(), [QgsProcessing.SourceType.TypeVectorPoint]
+ )
self.assertIsNone(param.defaultValue())
- self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional)
+ self.assertFalse(
+ param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional
+ )
- desc = 'QgsProcessingParameterFeatureSource|in_vector|Input Vector|QgsProcessing.TypeVectorPoint'
+ desc = "QgsProcessingParameterFeatureSource|in_vector|Input Vector|QgsProcessing.TypeVectorPoint"
param = getParameterFromString(desc)
self.assertIsNotNone(param)
- self.assertEqual(param.type(), 'source')
- self.assertEqual(param.name(), 'in_vector')
- self.assertEqual(param.description(), 'Input Vector')
- self.assertListEqual(param.dataTypes(), [QgsProcessing.SourceType.TypeVectorPoint])
+ self.assertEqual(param.type(), "source")
+ self.assertEqual(param.name(), "in_vector")
+ self.assertEqual(param.description(), "Input Vector")
+ self.assertListEqual(
+ param.dataTypes(), [QgsProcessing.SourceType.TypeVectorPoint]
+ )
self.assertIsNone(param.defaultValue())
- self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional)
+ self.assertFalse(
+ param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional
+ )
- desc = 'QgsProcessingParameterFeatureSource|in_vector|Input Vector|1'
+ desc = "QgsProcessingParameterFeatureSource|in_vector|Input Vector|1"
param = getParameterFromString(desc)
self.assertIsNotNone(param)
- self.assertEqual(param.type(), 'source')
- self.assertEqual(param.name(), 'in_vector')
- self.assertEqual(param.description(), 'Input Vector')
- self.assertListEqual(param.dataTypes(), [QgsProcessing.SourceType.TypeVectorLine])
+ self.assertEqual(param.type(), "source")
+ self.assertEqual(param.name(), "in_vector")
+ self.assertEqual(param.description(), "Input Vector")
+ self.assertListEqual(
+ param.dataTypes(), [QgsProcessing.SourceType.TypeVectorLine]
+ )
self.assertIsNone(param.defaultValue())
- self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional)
+ self.assertFalse(
+ param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional
+ )
- desc = 'QgsProcessingParameterFeatureSource|in_vector|Input Vector|QgsProcessing.TypeVectorLine'
+ desc = "QgsProcessingParameterFeatureSource|in_vector|Input Vector|QgsProcessing.TypeVectorLine"
param = getParameterFromString(desc)
self.assertIsNotNone(param)
- self.assertEqual(param.type(), 'source')
- self.assertEqual(param.name(), 'in_vector')
- self.assertEqual(param.description(), 'Input Vector')
- self.assertListEqual(param.dataTypes(), [QgsProcessing.SourceType.TypeVectorLine])
+ self.assertEqual(param.type(), "source")
+ self.assertEqual(param.name(), "in_vector")
+ self.assertEqual(param.description(), "Input Vector")
+ self.assertListEqual(
+ param.dataTypes(), [QgsProcessing.SourceType.TypeVectorLine]
+ )
self.assertIsNone(param.defaultValue())
- self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional)
+ self.assertFalse(
+ param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional
+ )
- desc = 'QgsProcessingParameterFeatureSource|in_vector|Input Vector|2'
+ desc = "QgsProcessingParameterFeatureSource|in_vector|Input Vector|2"
param = getParameterFromString(desc)
self.assertIsNotNone(param)
- self.assertEqual(param.type(), 'source')
- self.assertEqual(param.name(), 'in_vector')
- self.assertEqual(param.description(), 'Input Vector')
- self.assertListEqual(param.dataTypes(), [QgsProcessing.SourceType.TypeVectorPolygon])
+ self.assertEqual(param.type(), "source")
+ self.assertEqual(param.name(), "in_vector")
+ self.assertEqual(param.description(), "Input Vector")
+ self.assertListEqual(
+ param.dataTypes(), [QgsProcessing.SourceType.TypeVectorPolygon]
+ )
self.assertIsNone(param.defaultValue())
- self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional)
+ self.assertFalse(
+ param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional
+ )
- desc = 'QgsProcessingParameterFeatureSource|in_vector|Input Vector|QgsProcessing.TypeVectorPolygon'
+ desc = "QgsProcessingParameterFeatureSource|in_vector|Input Vector|QgsProcessing.TypeVectorPolygon"
param = getParameterFromString(desc)
self.assertIsNotNone(param)
- self.assertEqual(param.type(), 'source')
- self.assertEqual(param.name(), 'in_vector')
- self.assertEqual(param.description(), 'Input Vector')
- self.assertListEqual(param.dataTypes(), [QgsProcessing.SourceType.TypeVectorPolygon])
+ self.assertEqual(param.type(), "source")
+ self.assertEqual(param.name(), "in_vector")
+ self.assertEqual(param.description(), "Input Vector")
+ self.assertListEqual(
+ param.dataTypes(), [QgsProcessing.SourceType.TypeVectorPolygon]
+ )
self.assertIsNone(param.defaultValue())
- self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional)
+ self.assertFalse(
+ param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional
+ )
- desc = 'QgsProcessingParameterFeatureSource|in_vector|Input Vector|5'
+ desc = "QgsProcessingParameterFeatureSource|in_vector|Input Vector|5"
param = getParameterFromString(desc)
self.assertIsNotNone(param)
- self.assertEqual(param.type(), 'source')
- self.assertEqual(param.name(), 'in_vector')
- self.assertEqual(param.description(), 'Input Vector')
+ self.assertEqual(param.type(), "source")
+ self.assertEqual(param.name(), "in_vector")
+ self.assertEqual(param.description(), "Input Vector")
self.assertListEqual(param.dataTypes(), [QgsProcessing.SourceType.TypeVector])
self.assertIsNone(param.defaultValue())
- self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional)
+ self.assertFalse(
+ param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional
+ )
- desc = 'QgsProcessingParameterFeatureSource|in_vector|Input Vector|QgsProcessing.TypeVector'
+ desc = "QgsProcessingParameterFeatureSource|in_vector|Input Vector|QgsProcessing.TypeVector"
param = getParameterFromString(desc)
self.assertIsNotNone(param)
- self.assertEqual(param.type(), 'source')
- self.assertEqual(param.name(), 'in_vector')
- self.assertEqual(param.description(), 'Input Vector')
+ self.assertEqual(param.type(), "source")
+ self.assertEqual(param.name(), "in_vector")
+ self.assertEqual(param.description(), "Input Vector")
self.assertListEqual(param.dataTypes(), [QgsProcessing.SourceType.TypeVector])
self.assertIsNone(param.defaultValue())
- self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional)
+ self.assertFalse(
+ param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional
+ )
- desc = 'QgsProcessingParameterFeatureSource|in_vector|Input Vector|1;2'
+ desc = "QgsProcessingParameterFeatureSource|in_vector|Input Vector|1;2"
param = getParameterFromString(desc)
self.assertIsNotNone(param)
- self.assertEqual(param.type(), 'source')
- self.assertEqual(param.name(), 'in_vector')
- self.assertEqual(param.description(), 'Input Vector')
- self.assertListEqual(param.dataTypes(), [QgsProcessing.SourceType.TypeVectorLine, QgsProcessing.SourceType.TypeVectorPolygon])
+ self.assertEqual(param.type(), "source")
+ self.assertEqual(param.name(), "in_vector")
+ self.assertEqual(param.description(), "Input Vector")
+ self.assertListEqual(
+ param.dataTypes(),
+ [
+ QgsProcessing.SourceType.TypeVectorLine,
+ QgsProcessing.SourceType.TypeVectorPolygon,
+ ],
+ )
self.assertIsNone(param.defaultValue())
- self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional)
+ self.assertFalse(
+ param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional
+ )
- desc = 'QgsProcessingParameterFeatureSource|in_vector|Input Vector|QgsProcessing.TypeVectorLine;QgsProcessing.TypeVectorPolygon'
+ desc = "QgsProcessingParameterFeatureSource|in_vector|Input Vector|QgsProcessing.TypeVectorLine;QgsProcessing.TypeVectorPolygon"
param = getParameterFromString(desc)
self.assertIsNotNone(param)
- self.assertEqual(param.type(), 'source')
- self.assertEqual(param.name(), 'in_vector')
- self.assertEqual(param.description(), 'Input Vector')
- self.assertListEqual(param.dataTypes(), [QgsProcessing.SourceType.TypeVectorLine, QgsProcessing.SourceType.TypeVectorPolygon])
+ self.assertEqual(param.type(), "source")
+ self.assertEqual(param.name(), "in_vector")
+ self.assertEqual(param.description(), "Input Vector")
+ self.assertListEqual(
+ param.dataTypes(),
+ [
+ QgsProcessing.SourceType.TypeVectorLine,
+ QgsProcessing.SourceType.TypeVectorPolygon,
+ ],
+ )
self.assertIsNone(param.defaultValue())
- self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional)
+ self.assertFalse(
+ param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional
+ )
- desc = 'QgsProcessingParameterFeatureSource|in_vector|Input Vector|-1|None|True'
+ desc = "QgsProcessingParameterFeatureSource|in_vector|Input Vector|-1|None|True"
param = getParameterFromString(desc)
self.assertIsNotNone(param)
- self.assertEqual(param.type(), 'source')
- self.assertEqual(param.name(), 'in_vector')
- self.assertEqual(param.description(), 'Input Vector')
- self.assertListEqual(param.dataTypes(), [QgsProcessing.SourceType.TypeVectorAnyGeometry])
+ self.assertEqual(param.type(), "source")
+ self.assertEqual(param.name(), "in_vector")
+ self.assertEqual(param.description(), "Input Vector")
+ self.assertListEqual(
+ param.dataTypes(), [QgsProcessing.SourceType.TypeVectorAnyGeometry]
+ )
self.assertIsNone(param.defaultValue())
- self.assertTrue(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional)
+ self.assertTrue(
+ param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional
+ )
def testParameterVectorLayerDesc(self):
- desc = 'QgsProcessingParameterVectorLayer|in_vector|Input Vector'
+ desc = "QgsProcessingParameterVectorLayer|in_vector|Input Vector"
param = getParameterFromString(desc)
self.assertIsNotNone(param)
- self.assertEqual(param.type(), 'vector')
- self.assertEqual(param.name(), 'in_vector')
- self.assertEqual(param.description(), 'Input Vector')
+ self.assertEqual(param.type(), "vector")
+ self.assertEqual(param.name(), "in_vector")
+ self.assertEqual(param.description(), "Input Vector")
self.assertListEqual(param.dataTypes(), [])
self.assertIsNone(param.defaultValue())
- self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional)
+ self.assertFalse(
+ param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional
+ )
- desc = 'QgsProcessingParameterVectorLayer|in_vector|Input Vector|0'
+ desc = "QgsProcessingParameterVectorLayer|in_vector|Input Vector|0"
param = getParameterFromString(desc)
self.assertIsNotNone(param)
- self.assertEqual(param.type(), 'vector')
- self.assertEqual(param.name(), 'in_vector')
- self.assertEqual(param.description(), 'Input Vector')
- self.assertListEqual(param.dataTypes(), [QgsProcessing.SourceType.TypeVectorPoint])
+ self.assertEqual(param.type(), "vector")
+ self.assertEqual(param.name(), "in_vector")
+ self.assertEqual(param.description(), "Input Vector")
+ self.assertListEqual(
+ param.dataTypes(), [QgsProcessing.SourceType.TypeVectorPoint]
+ )
self.assertIsNone(param.defaultValue())
- self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional)
+ self.assertFalse(
+ param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional
+ )
- desc = 'QgsProcessingParameterVectorLayer|in_vector|Input Vector|QgsProcessing.TypeVectorPoint'
+ desc = "QgsProcessingParameterVectorLayer|in_vector|Input Vector|QgsProcessing.TypeVectorPoint"
param = getParameterFromString(desc)
self.assertIsNotNone(param)
- self.assertEqual(param.type(), 'vector')
- self.assertEqual(param.name(), 'in_vector')
- self.assertEqual(param.description(), 'Input Vector')
- self.assertListEqual(param.dataTypes(), [QgsProcessing.SourceType.TypeVectorPoint])
+ self.assertEqual(param.type(), "vector")
+ self.assertEqual(param.name(), "in_vector")
+ self.assertEqual(param.description(), "Input Vector")
+ self.assertListEqual(
+ param.dataTypes(), [QgsProcessing.SourceType.TypeVectorPoint]
+ )
self.assertIsNone(param.defaultValue())
- self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional)
+ self.assertFalse(
+ param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional
+ )
- desc = 'QgsProcessingParameterVectorLayer|in_vector|Input Vector|1'
+ desc = "QgsProcessingParameterVectorLayer|in_vector|Input Vector|1"
param = getParameterFromString(desc)
self.assertIsNotNone(param)
- self.assertEqual(param.type(), 'vector')
- self.assertEqual(param.name(), 'in_vector')
- self.assertEqual(param.description(), 'Input Vector')
- self.assertListEqual(param.dataTypes(), [QgsProcessing.SourceType.TypeVectorLine])
+ self.assertEqual(param.type(), "vector")
+ self.assertEqual(param.name(), "in_vector")
+ self.assertEqual(param.description(), "Input Vector")
+ self.assertListEqual(
+ param.dataTypes(), [QgsProcessing.SourceType.TypeVectorLine]
+ )
self.assertIsNone(param.defaultValue())
- self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional)
+ self.assertFalse(
+ param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional
+ )
- desc = 'QgsProcessingParameterVectorLayer|in_vector|Input Vector|QgsProcessing.TypeVectorLine'
+ desc = "QgsProcessingParameterVectorLayer|in_vector|Input Vector|QgsProcessing.TypeVectorLine"
param = getParameterFromString(desc)
self.assertIsNotNone(param)
- self.assertEqual(param.type(), 'vector')
- self.assertEqual(param.name(), 'in_vector')
- self.assertEqual(param.description(), 'Input Vector')
- self.assertListEqual(param.dataTypes(), [QgsProcessing.SourceType.TypeVectorLine])
+ self.assertEqual(param.type(), "vector")
+ self.assertEqual(param.name(), "in_vector")
+ self.assertEqual(param.description(), "Input Vector")
+ self.assertListEqual(
+ param.dataTypes(), [QgsProcessing.SourceType.TypeVectorLine]
+ )
self.assertIsNone(param.defaultValue())
- self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional)
+ self.assertFalse(
+ param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional
+ )
- desc = 'QgsProcessingParameterVectorLayer|in_vector|Input Vector|2'
+ desc = "QgsProcessingParameterVectorLayer|in_vector|Input Vector|2"
param = getParameterFromString(desc)
self.assertIsNotNone(param)
- self.assertEqual(param.type(), 'vector')
- self.assertEqual(param.name(), 'in_vector')
- self.assertEqual(param.description(), 'Input Vector')
- self.assertListEqual(param.dataTypes(), [QgsProcessing.SourceType.TypeVectorPolygon])
+ self.assertEqual(param.type(), "vector")
+ self.assertEqual(param.name(), "in_vector")
+ self.assertEqual(param.description(), "Input Vector")
+ self.assertListEqual(
+ param.dataTypes(), [QgsProcessing.SourceType.TypeVectorPolygon]
+ )
self.assertIsNone(param.defaultValue())
- self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional)
+ self.assertFalse(
+ param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional
+ )
- desc = 'QgsProcessingParameterVectorLayer|in_vector|Input Vector|QgsProcessing.TypeVectorPolygon'
+ desc = "QgsProcessingParameterVectorLayer|in_vector|Input Vector|QgsProcessing.TypeVectorPolygon"
param = getParameterFromString(desc)
self.assertIsNotNone(param)
- self.assertEqual(param.type(), 'vector')
- self.assertEqual(param.name(), 'in_vector')
- self.assertEqual(param.description(), 'Input Vector')
- self.assertListEqual(param.dataTypes(), [QgsProcessing.SourceType.TypeVectorPolygon])
+ self.assertEqual(param.type(), "vector")
+ self.assertEqual(param.name(), "in_vector")
+ self.assertEqual(param.description(), "Input Vector")
+ self.assertListEqual(
+ param.dataTypes(), [QgsProcessing.SourceType.TypeVectorPolygon]
+ )
self.assertIsNone(param.defaultValue())
- self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional)
+ self.assertFalse(
+ param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional
+ )
- desc = 'QgsProcessingParameterVectorLayer|in_vector|Input Vector|5'
+ desc = "QgsProcessingParameterVectorLayer|in_vector|Input Vector|5"
param = getParameterFromString(desc)
self.assertIsNotNone(param)
- self.assertEqual(param.type(), 'vector')
- self.assertEqual(param.name(), 'in_vector')
- self.assertEqual(param.description(), 'Input Vector')
+ self.assertEqual(param.type(), "vector")
+ self.assertEqual(param.name(), "in_vector")
+ self.assertEqual(param.description(), "Input Vector")
self.assertListEqual(param.dataTypes(), [QgsProcessing.SourceType.TypeVector])
self.assertIsNone(param.defaultValue())
- self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional)
+ self.assertFalse(
+ param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional
+ )
- desc = 'QgsProcessingParameterVectorLayer|in_vector|Input Vector|QgsProcessing.TypeVector'
+ desc = "QgsProcessingParameterVectorLayer|in_vector|Input Vector|QgsProcessing.TypeVector"
param = getParameterFromString(desc)
self.assertIsNotNone(param)
- self.assertEqual(param.type(), 'vector')
- self.assertEqual(param.name(), 'in_vector')
- self.assertEqual(param.description(), 'Input Vector')
+ self.assertEqual(param.type(), "vector")
+ self.assertEqual(param.name(), "in_vector")
+ self.assertEqual(param.description(), "Input Vector")
self.assertListEqual(param.dataTypes(), [QgsProcessing.SourceType.TypeVector])
self.assertIsNone(param.defaultValue())
- self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional)
+ self.assertFalse(
+ param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional
+ )
- desc = 'QgsProcessingParameterVectorLayer|in_vector|Input Vector|1;2'
+ desc = "QgsProcessingParameterVectorLayer|in_vector|Input Vector|1;2"
param = getParameterFromString(desc)
self.assertIsNotNone(param)
- self.assertEqual(param.type(), 'vector')
- self.assertEqual(param.name(), 'in_vector')
- self.assertEqual(param.description(), 'Input Vector')
- self.assertListEqual(param.dataTypes(), [QgsProcessing.SourceType.TypeVectorLine, QgsProcessing.SourceType.TypeVectorPolygon])
+ self.assertEqual(param.type(), "vector")
+ self.assertEqual(param.name(), "in_vector")
+ self.assertEqual(param.description(), "Input Vector")
+ self.assertListEqual(
+ param.dataTypes(),
+ [
+ QgsProcessing.SourceType.TypeVectorLine,
+ QgsProcessing.SourceType.TypeVectorPolygon,
+ ],
+ )
self.assertIsNone(param.defaultValue())
- self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional)
+ self.assertFalse(
+ param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional
+ )
- desc = 'QgsProcessingParameterVectorLayer|in_vector|Input Vector|QgsProcessing.TypeVectorLine;QgsProcessing.TypeVectorPolygon'
+ desc = "QgsProcessingParameterVectorLayer|in_vector|Input Vector|QgsProcessing.TypeVectorLine;QgsProcessing.TypeVectorPolygon"
param = getParameterFromString(desc)
self.assertIsNotNone(param)
- self.assertEqual(param.type(), 'vector')
- self.assertEqual(param.name(), 'in_vector')
- self.assertEqual(param.description(), 'Input Vector')
- self.assertListEqual(param.dataTypes(), [QgsProcessing.SourceType.TypeVectorLine, QgsProcessing.SourceType.TypeVectorPolygon])
+ self.assertEqual(param.type(), "vector")
+ self.assertEqual(param.name(), "in_vector")
+ self.assertEqual(param.description(), "Input Vector")
+ self.assertListEqual(
+ param.dataTypes(),
+ [
+ QgsProcessing.SourceType.TypeVectorLine,
+ QgsProcessing.SourceType.TypeVectorPolygon,
+ ],
+ )
self.assertIsNone(param.defaultValue())
- self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional)
+ self.assertFalse(
+ param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional
+ )
- desc = 'QgsProcessingParameterVectorLayer|in_vector|Input Vector|-1|None|True'
+ desc = "QgsProcessingParameterVectorLayer|in_vector|Input Vector|-1|None|True"
param = getParameterFromString(desc)
self.assertIsNotNone(param)
- self.assertEqual(param.type(), 'vector')
- self.assertEqual(param.name(), 'in_vector')
- self.assertEqual(param.description(), 'Input Vector')
- self.assertListEqual(param.dataTypes(), [QgsProcessing.SourceType.TypeVectorAnyGeometry])
+ self.assertEqual(param.type(), "vector")
+ self.assertEqual(param.name(), "in_vector")
+ self.assertEqual(param.description(), "Input Vector")
+ self.assertListEqual(
+ param.dataTypes(), [QgsProcessing.SourceType.TypeVectorAnyGeometry]
+ )
self.assertIsNone(param.defaultValue())
- self.assertTrue(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional)
+ self.assertTrue(
+ param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional
+ )
def testParameterRasterLayerDesc(self):
- desc = 'QgsProcessingParameterRasterLayer|in_raster|Input Raster'
+ desc = "QgsProcessingParameterRasterLayer|in_raster|Input Raster"
param = getParameterFromString(desc)
self.assertIsNotNone(param)
- self.assertEqual(param.type(), 'raster')
- self.assertEqual(param.name(), 'in_raster')
- self.assertEqual(param.description(), 'Input Raster')
+ self.assertEqual(param.type(), "raster")
+ self.assertEqual(param.name(), "in_raster")
+ self.assertEqual(param.description(), "Input Raster")
self.assertIsNone(param.defaultValue())
- self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional)
+ self.assertFalse(
+ param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional
+ )
- desc = 'QgsProcessingParameterRasterLayer|in_raster|Input Raster|None|True'
+ desc = "QgsProcessingParameterRasterLayer|in_raster|Input Raster|None|True"
param = getParameterFromString(desc)
self.assertIsNotNone(param)
- self.assertEqual(param.type(), 'raster')
- self.assertEqual(param.name(), 'in_raster')
- self.assertEqual(param.description(), 'Input Raster')
+ self.assertEqual(param.type(), "raster")
+ self.assertEqual(param.name(), "in_raster")
+ self.assertEqual(param.description(), "Input Raster")
self.assertIsNone(param.defaultValue())
- self.assertTrue(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional)
+ self.assertTrue(
+ param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional
+ )
-if __name__ == '__main__':
+if __name__ == "__main__":
unittest.main()
diff --git a/python/plugins/processing/tests/ProcessingGeneralTest.py b/python/plugins/processing/tests/ProcessingGeneralTest.py
index 0eb90ffac73c..a6d7731cc7ee 100644
--- a/python/plugins/processing/tests/ProcessingGeneralTest.py
+++ b/python/plugins/processing/tests/ProcessingGeneralTest.py
@@ -15,21 +15,23 @@
***************************************************************************
"""
-__author__ = 'Nyall Dawson'
-__date__ = 'January 2019'
-__copyright__ = '(C) 2019, Nyall Dawson'
+__author__ = "Nyall Dawson"
+__date__ = "January 2019"
+__copyright__ = "(C) 2019, Nyall Dawson"
import nose2
import shutil
import gc
-from qgis.core import (QgsApplication,
- QgsProcessing,
- QgsProcessingContext,
- QgsVectorLayer,
- QgsProject)
+from qgis.core import (
+ QgsApplication,
+ QgsProcessing,
+ QgsProcessingContext,
+ QgsVectorLayer,
+ QgsProject,
+)
from qgis.PyQt import sip
-from qgis.analysis import (QgsNativeAlgorithms)
+from qgis.analysis import QgsNativeAlgorithms
import unittest
from qgis.testing import start_app, QgisTestCase
import processing
@@ -42,6 +44,7 @@ class TestProcessingGeneral(QgisTestCase):
def setUpClass(cls):
start_app()
from processing.core.Processing import Processing
+
Processing.initialize()
cls.cleanup_paths = []
cls.in_place_layers = {}
@@ -50,6 +53,7 @@ def setUpClass(cls):
@classmethod
def tearDownClass(cls):
from processing.core.Processing import Processing
+
Processing.deinitialize()
for path in cls.cleanup_paths:
shutil.rmtree(path)
@@ -58,27 +62,40 @@ def testRun(self):
context = QgsProcessingContext()
# try running an alg using processing.run - ownership of result layer should be transferred back to the caller
- res = processing.run('qgis:buffer',
- {'DISTANCE': 1, 'INPUT': points(), 'OUTPUT': QgsProcessing.TEMPORARY_OUTPUT},
- context=context)
- self.assertIn('OUTPUT', res)
+ res = processing.run(
+ "qgis:buffer",
+ {
+ "DISTANCE": 1,
+ "INPUT": points(),
+ "OUTPUT": QgsProcessing.TEMPORARY_OUTPUT,
+ },
+ context=context,
+ )
+ self.assertIn("OUTPUT", res)
# output should be the layer instance itself
- self.assertIsInstance(res['OUTPUT'], QgsVectorLayer)
+ self.assertIsInstance(res["OUTPUT"], QgsVectorLayer)
# Python should have ownership
- self.assertTrue(sip.ispyowned(res['OUTPUT']))
+ self.assertTrue(sip.ispyowned(res["OUTPUT"]))
del context
gc.collect()
- self.assertFalse(sip.isdeleted(res['OUTPUT']))
+ self.assertFalse(sip.isdeleted(res["OUTPUT"]))
# now try using processing.run with is_child_algorithm = True. Ownership should remain with the context
context = QgsProcessingContext()
- res = processing.run('qgis:buffer',
- {'DISTANCE': 1, 'INPUT': points(), 'OUTPUT': QgsProcessing.TEMPORARY_OUTPUT},
- context=context, is_child_algorithm=True)
- self.assertIn('OUTPUT', res)
+ res = processing.run(
+ "qgis:buffer",
+ {
+ "DISTANCE": 1,
+ "INPUT": points(),
+ "OUTPUT": QgsProcessing.TEMPORARY_OUTPUT,
+ },
+ context=context,
+ is_child_algorithm=True,
+ )
+ self.assertIn("OUTPUT", res)
# output should be a layer string reference, NOT the layer itself
- self.assertIsInstance(res['OUTPUT'], str)
- layer = context.temporaryLayerStore().mapLayer(res['OUTPUT'])
+ self.assertIsInstance(res["OUTPUT"], str)
+ layer = context.temporaryLayerStore().mapLayer(res["OUTPUT"])
self.assertIsInstance(layer, QgsVectorLayer)
# context should have ownership
self.assertFalse(sip.ispyowned(layer))
@@ -92,15 +109,24 @@ def testRunAndLoadResults(self):
# try running an alg using processing.runAndLoadResults - ownership of result layer should be transferred to
# project, and layer should be present in project
- res = processing.runAndLoadResults('qgis:buffer',
- {'DISTANCE': 1, 'INPUT': points(), 'OUTPUT': QgsProcessing.TEMPORARY_OUTPUT},
- context=context)
- self.assertIn('OUTPUT', res)
+ res = processing.runAndLoadResults(
+ "qgis:buffer",
+ {
+ "DISTANCE": 1,
+ "INPUT": points(),
+ "OUTPUT": QgsProcessing.TEMPORARY_OUTPUT,
+ },
+ context=context,
+ )
+ self.assertIn("OUTPUT", res)
# output should be the layer path
- self.assertIsInstance(res['OUTPUT'], str)
+ self.assertIsInstance(res["OUTPUT"], str)
- self.assertEqual(context.layersToLoadOnCompletion()[res['OUTPUT']].project, QgsProject.instance())
- layer = QgsProject.instance().mapLayer(res['OUTPUT'])
+ self.assertEqual(
+ context.layersToLoadOnCompletion()[res["OUTPUT"]].project,
+ QgsProject.instance(),
+ )
+ layer = QgsProject.instance().mapLayer(res["OUTPUT"])
self.assertIsInstance(layer, QgsVectorLayer)
# Python should NOT have ownership
@@ -111,14 +137,14 @@ def testProviders(self):
When run from a standalone script (like this test), ensure that the providers from separate plugins are available
"""
providers = [p.id() for p in QgsApplication.processingRegistry().providers()]
- self.assertIn('qgis', providers)
- self.assertIn('native', providers)
- self.assertIn('gdal', providers)
- self.assertIn('project', providers)
- self.assertIn('script', providers)
- self.assertIn('model', providers)
- self.assertIn('grass', providers)
+ self.assertIn("qgis", providers)
+ self.assertIn("native", providers)
+ self.assertIn("gdal", providers)
+ self.assertIn("project", providers)
+ self.assertIn("script", providers)
+ self.assertIn("model", providers)
+ self.assertIn("grass", providers)
-if __name__ == '__main__':
+if __name__ == "__main__":
nose2.main()
diff --git a/python/plugins/processing/tests/ProjectProvider.py b/python/plugins/processing/tests/ProjectProvider.py
index 6f0b157b7d0b..5bef743acfdc 100644
--- a/python/plugins/processing/tests/ProjectProvider.py
+++ b/python/plugins/processing/tests/ProjectProvider.py
@@ -15,16 +15,14 @@
***************************************************************************8
"""
-__author__ = 'Nyall Dawson'
-__date__ = 'July 2018'
-__copyright__ = '(C) 2018, Nyall Dawson'
+__author__ = "Nyall Dawson"
+__date__ = "July 2018"
+__copyright__ = "(C) 2018, Nyall Dawson"
import unittest
from qgis.testing import start_app, QgisTestCase
from qgis.PyQt.QtCore import QTemporaryFile
-from qgis.core import (QgsApplication,
- QgsProcessingModelAlgorithm,
- QgsProject)
+from qgis.core import QgsApplication, QgsProcessingModelAlgorithm, QgsProject
from processing.modeler.ProjectProvider import ProjectProvider
from processing.modeler.ModelerDialog import ModelerDialog
@@ -38,9 +36,9 @@ def testSaveRestoreFromProject(self):
provider = ProjectProvider(p)
# add some algorithms
- alg = QgsProcessingModelAlgorithm('test name', 'test group')
+ alg = QgsProcessingModelAlgorithm("test name", "test group")
provider.add_model(alg)
- alg2 = QgsProcessingModelAlgorithm('test name2', 'test group2')
+ alg2 = QgsProcessingModelAlgorithm("test name2", "test group2")
provider.add_model(alg2)
self.assertEqual(len(provider.algorithms()), 2)
@@ -58,10 +56,10 @@ def testSaveRestoreFromProject(self):
self.assertEqual(len(provider2.model_definitions), 2)
self.assertEqual(len(provider2.algorithms()), 2)
- self.assertEqual(provider2.algorithms()[0].name(), 'test name')
- self.assertEqual(provider2.algorithms()[0].group(), 'test group')
- self.assertEqual(provider2.algorithms()[1].name(), 'test name2')
- self.assertEqual(provider2.algorithms()[1].group(), 'test group2')
+ self.assertEqual(provider2.algorithms()[0].name(), "test name")
+ self.assertEqual(provider2.algorithms()[0].group(), "test group")
+ self.assertEqual(provider2.algorithms()[1].name(), "test name2")
+ self.assertEqual(provider2.algorithms()[1].group(), "test group2")
# clear project should remove algorithms
p2.clear()
@@ -75,9 +73,9 @@ def testDelete(self):
provider = ProjectProvider(p)
# add some models
- alg = QgsProcessingModelAlgorithm('test name', 'test group')
+ alg = QgsProcessingModelAlgorithm("test name", "test group")
provider.add_model(alg)
- alg2 = QgsProcessingModelAlgorithm('test name2', 'test group2')
+ alg2 = QgsProcessingModelAlgorithm("test name2", "test group2")
provider.add_model(alg2)
self.assertEqual(len(provider.algorithms()), 2)
@@ -86,21 +84,21 @@ def testDelete(self):
self.assertEqual(len(provider.algorithms()), 2)
# not in provider!
- alg3 = QgsProcessingModelAlgorithm('test name3', 'test group')
+ alg3 = QgsProcessingModelAlgorithm("test name3", "test group")
provider.remove_model(alg3)
self.assertEqual(len(provider.algorithms()), 2)
# delete model actually in project
provider.remove_model(alg)
self.assertEqual(len(provider.algorithms()), 1)
- self.assertEqual(provider.algorithms()[0].name(), 'test name2')
+ self.assertEqual(provider.algorithms()[0].name(), "test name2")
# overwrite model
- alg2b = QgsProcessingModelAlgorithm('test name2', 'test group2')
- alg2b.setHelpContent({'test': 'test'})
+ alg2b = QgsProcessingModelAlgorithm("test name2", "test group2")
+ alg2b.setHelpContent({"test": "test"})
provider.add_model(alg2b)
self.assertEqual(len(provider.algorithms()), 1)
- self.assertEqual(provider.algorithms()[0].helpContent(), {'test': 'test'})
+ self.assertEqual(provider.algorithms()[0].helpContent(), {"test": "test"})
provider.remove_model(alg2)
self.assertEqual(len(provider.algorithms()), 0)
@@ -114,16 +112,16 @@ def testDialog(self):
QgsApplication.processingRegistry().addProvider(provider)
# make an algorithm
- alg = QgsProcessingModelAlgorithm('test name', 'test group')
+ alg = QgsProcessingModelAlgorithm("test name", "test group")
dialog = ModelerDialog(alg)
dialog.saveInProject()
self.assertEqual(len(provider.model_definitions), 1)
self.assertEqual(len(provider.algorithms()), 1)
- self.assertEqual(provider.algorithms()[0].name(), 'test name')
- self.assertEqual(provider.algorithms()[0].group(), 'test group')
+ self.assertEqual(provider.algorithms()[0].name(), "test name")
+ self.assertEqual(provider.algorithms()[0].group(), "test group")
-if __name__ == '__main__':
+if __name__ == "__main__":
unittest.main()
diff --git a/python/plugins/processing/tests/QgisAlgorithmsTest1.py b/python/plugins/processing/tests/QgisAlgorithmsTest1.py
index 802081224250..fbab5d909dd2 100644
--- a/python/plugins/processing/tests/QgisAlgorithmsTest1.py
+++ b/python/plugins/processing/tests/QgisAlgorithmsTest1.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Matthias Kuhn'
-__date__ = 'January 2016'
-__copyright__ = '(C) 2016, Matthias Kuhn'
+__author__ = "Matthias Kuhn"
+__date__ = "January 2016"
+__copyright__ = "(C) 2016, Matthias Kuhn"
import AlgorithmsTestBase
@@ -25,11 +25,13 @@
import shutil
import os
-from qgis.core import (QgsApplication,
- QgsProcessingAlgorithm,
- QgsProcessingFeedback,
- QgsProcessingException)
-from qgis.analysis import (QgsNativeAlgorithms)
+from qgis.core import (
+ QgsApplication,
+ QgsProcessingAlgorithm,
+ QgsProcessingFeedback,
+ QgsProcessingException,
+)
+from qgis.analysis import QgsNativeAlgorithms
import unittest
from qgis.testing import start_app, QgisTestCase
from processing.tools.dataobjects import createContext
@@ -43,10 +45,10 @@ def __init__(self):
super().__init__()
def name(self):
- return 'testalg'
+ return "testalg"
def displayName(self):
- return 'testalg'
+ return "testalg"
def initAlgorithm(self, config=None):
pass
@@ -55,7 +57,7 @@ def createInstance(self):
return TestAlg()
def processAlgorithm(self, parameters, context, feedback):
- raise QgsProcessingException('Exception while processing')
+ raise QgsProcessingException("Exception while processing")
return {}
@@ -65,6 +67,7 @@ class TestQgisAlgorithms(QgisTestCase, AlgorithmsTestBase.AlgorithmsTest):
def setUpClass(cls):
start_app()
from processing.core.Processing import Processing
+
Processing.initialize()
cls.cleanup_paths = []
cls.in_place_layers = {}
@@ -73,12 +76,13 @@ def setUpClass(cls):
@classmethod
def tearDownClass(cls):
from processing.core.Processing import Processing
+
Processing.deinitialize()
for path in cls.cleanup_paths:
shutil.rmtree(path)
def definition_file(self):
- return 'qgis_algorithm_tests1.yaml'
+ return "qgis_algorithm_tests1.yaml"
def testProcessingException(self):
"""
@@ -97,11 +101,13 @@ def testParameterPythonImport(self):
# check that pythonImportString correctly imports
exec(import_string)
# and now we should be able to instantiate an object!
- if t.className() == 'QgsProcessingParameterProviderConnection':
- exec(f'test = {t.className()}(\'id\',\'name\', \'provider\')\nself.assertIsNotNone(test)')
+ if t.className() == "QgsProcessingParameterProviderConnection":
+ exec(
+ f"test = {t.className()}('id','name', 'provider')\nself.assertIsNotNone(test)"
+ )
else:
- exec(f'test = {t.className()}(\'id\',\'name\')\nself.assertIsNotNone(test)')
+ exec(f"test = {t.className()}('id','name')\nself.assertIsNotNone(test)")
-if __name__ == '__main__':
+if __name__ == "__main__":
nose2.main()
diff --git a/python/plugins/processing/tests/QgisAlgorithmsTest2.py b/python/plugins/processing/tests/QgisAlgorithmsTest2.py
index a5a8c34798b7..e8625b3d7a70 100644
--- a/python/plugins/processing/tests/QgisAlgorithmsTest2.py
+++ b/python/plugins/processing/tests/QgisAlgorithmsTest2.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Matthias Kuhn'
-__date__ = 'January 2016'
-__copyright__ = '(C) 2016, Matthias Kuhn'
+__author__ = "Matthias Kuhn"
+__date__ = "January 2016"
+__copyright__ = "(C) 2016, Matthias Kuhn"
import AlgorithmsTestBase
@@ -25,9 +25,8 @@
import shutil
import os
-from qgis.core import (QgsApplication,
- QgsProcessingException)
-from qgis.analysis import (QgsNativeAlgorithms)
+from qgis.core import QgsApplication, QgsProcessingException
+from qgis.analysis import QgsNativeAlgorithms
import unittest
from qgis.testing import start_app, QgisTestCase
from processing.core.ProcessingConfig import ProcessingConfig
@@ -40,6 +39,7 @@ class TestQgisAlgorithms2(QgisTestCase, AlgorithmsTestBase.AlgorithmsTest):
def setUpClass(cls):
start_app()
from processing.core.Processing import Processing
+
Processing.initialize()
cls.cleanup_paths = []
cls.in_place_layers = {}
@@ -48,13 +48,14 @@ def setUpClass(cls):
@classmethod
def tearDownClass(cls):
from processing.core.Processing import Processing
+
Processing.deinitialize()
for path in cls.cleanup_paths:
shutil.rmtree(path)
def definition_file(self):
- return 'qgis_algorithm_tests2.yaml'
+ return "qgis_algorithm_tests2.yaml"
-if __name__ == '__main__':
+if __name__ == "__main__":
nose2.main()
diff --git a/python/plugins/processing/tests/QgisAlgorithmsTest3.py b/python/plugins/processing/tests/QgisAlgorithmsTest3.py
index 2ef1fff5ad61..e041236b215c 100644
--- a/python/plugins/processing/tests/QgisAlgorithmsTest3.py
+++ b/python/plugins/processing/tests/QgisAlgorithmsTest3.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Matthias Kuhn'
-__date__ = 'January 2016'
-__copyright__ = '(C) 2016, Matthias Kuhn'
+__author__ = "Matthias Kuhn"
+__date__ = "January 2016"
+__copyright__ = "(C) 2016, Matthias Kuhn"
import AlgorithmsTestBase
@@ -25,9 +25,8 @@
import shutil
import os
-from qgis.core import (QgsApplication,
- QgsProcessingException)
-from qgis.analysis import (QgsNativeAlgorithms)
+from qgis.core import QgsApplication, QgsProcessingException
+from qgis.analysis import QgsNativeAlgorithms
import unittest
from qgis.testing import start_app, QgisTestCase
from processing.core.ProcessingConfig import ProcessingConfig
@@ -40,6 +39,7 @@ class TestQgisAlgorithms3(QgisTestCase, AlgorithmsTestBase.AlgorithmsTest):
def setUpClass(cls):
start_app()
from processing.core.Processing import Processing
+
Processing.initialize()
cls.cleanup_paths = []
cls.in_place_layers = {}
@@ -48,13 +48,14 @@ def setUpClass(cls):
@classmethod
def tearDownClass(cls):
from processing.core.Processing import Processing
+
Processing.deinitialize()
for path in cls.cleanup_paths:
shutil.rmtree(path)
def definition_file(self):
- return 'qgis_algorithm_tests3.yaml'
+ return "qgis_algorithm_tests3.yaml"
-if __name__ == '__main__':
+if __name__ == "__main__":
nose2.main()
diff --git a/python/plugins/processing/tests/QgisAlgorithmsTest4.py b/python/plugins/processing/tests/QgisAlgorithmsTest4.py
index af6c5da77a38..3d098f653f13 100644
--- a/python/plugins/processing/tests/QgisAlgorithmsTest4.py
+++ b/python/plugins/processing/tests/QgisAlgorithmsTest4.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Matthias Kuhn'
-__date__ = 'January 2016'
-__copyright__ = '(C) 2016, Matthias Kuhn'
+__author__ = "Matthias Kuhn"
+__date__ = "January 2016"
+__copyright__ = "(C) 2016, Matthias Kuhn"
import AlgorithmsTestBase
@@ -25,9 +25,8 @@
import shutil
import os
-from qgis.core import (QgsApplication,
- QgsProcessingException)
-from qgis.analysis import (QgsNativeAlgorithms)
+from qgis.core import QgsApplication, QgsProcessingException
+from qgis.analysis import QgsNativeAlgorithms
import unittest
from qgis.testing import start_app, QgisTestCase
from processing.core.ProcessingConfig import ProcessingConfig
@@ -40,10 +39,14 @@ class TestQgisAlgorithms4(QgisTestCase, AlgorithmsTestBase.AlgorithmsTest):
def setUpClass(cls):
start_app()
from processing.core.Processing import Processing
+
Processing.initialize()
# change the model provider folder so that it looks in the test directory for models
- ProcessingConfig.setSettingValue(ModelerUtils.MODELS_FOLDER, os.path.join(os.path.dirname(__file__), 'models'))
+ ProcessingConfig.setSettingValue(
+ ModelerUtils.MODELS_FOLDER,
+ os.path.join(os.path.dirname(__file__), "models"),
+ )
for p in QgsApplication.processingRegistry().providers():
if p.id() == "model":
p.refreshAlgorithms()
@@ -51,19 +54,24 @@ def setUpClass(cls):
cls.cleanup_paths = []
cls.in_place_layers = {}
cls.vector_layer_params = {}
- cls._original_models_folder = ProcessingConfig.getSetting(ModelerUtils.MODELS_FOLDER)
+ cls._original_models_folder = ProcessingConfig.getSetting(
+ ModelerUtils.MODELS_FOLDER
+ )
@classmethod
def tearDownClass(cls):
from processing.core.Processing import Processing
+
Processing.deinitialize()
for path in cls.cleanup_paths:
shutil.rmtree(path)
- ProcessingConfig.setSettingValue(ModelerUtils.MODELS_FOLDER, cls._original_models_folder)
+ ProcessingConfig.setSettingValue(
+ ModelerUtils.MODELS_FOLDER, cls._original_models_folder
+ )
def definition_file(self):
- return 'qgis_algorithm_tests4.yaml'
+ return "qgis_algorithm_tests4.yaml"
-if __name__ == '__main__':
+if __name__ == "__main__":
nose2.main()
diff --git a/python/plugins/processing/tests/QgisAlgorithmsTest5.py b/python/plugins/processing/tests/QgisAlgorithmsTest5.py
index 3abc91e1817c..5b7e825d203d 100644
--- a/python/plugins/processing/tests/QgisAlgorithmsTest5.py
+++ b/python/plugins/processing/tests/QgisAlgorithmsTest5.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Matthias Kuhn'
-__date__ = 'January 2016'
-__copyright__ = '(C) 2016, Matthias Kuhn'
+__author__ = "Matthias Kuhn"
+__date__ = "January 2016"
+__copyright__ = "(C) 2016, Matthias Kuhn"
import AlgorithmsTestBase
@@ -36,19 +36,21 @@ class TestQgisAlgorithms5(QgisTestCase, AlgorithmsTestBase.AlgorithmsTest):
def setUpClass(cls):
start_app()
from processing.core.Processing import Processing
+
Processing.initialize()
cls.cleanup_paths = []
@classmethod
def tearDownClass(cls):
from processing.core.Processing import Processing
+
Processing.deinitialize()
for path in cls.cleanup_paths:
shutil.rmtree(path)
def definition_file(self):
- return 'qgis_algorithm_tests5.yaml'
+ return "qgis_algorithm_tests5.yaml"
-if __name__ == '__main__':
+if __name__ == "__main__":
nose2.main()
diff --git a/python/plugins/processing/tests/ScriptUtilsTest.py b/python/plugins/processing/tests/ScriptUtilsTest.py
index 61bde4bca504..0c436e9c7908 100644
--- a/python/plugins/processing/tests/ScriptUtilsTest.py
+++ b/python/plugins/processing/tests/ScriptUtilsTest.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Luigi Pirelli'
-__date__ = 'February 2019'
-__copyright__ = '(C) 2019, Luigi Pirelli'
+__author__ = "Luigi Pirelli"
+__date__ = "February 2019"
+__copyright__ = "(C) 2019, Luigi Pirelli"
import os
import shutil
@@ -29,7 +29,7 @@
from processing.script import ScriptUtils
-testDataPath = os.path.join(os.path.dirname(__file__), 'testdata')
+testDataPath = os.path.join(os.path.dirname(__file__), "testdata")
start_app()
@@ -50,13 +50,13 @@ def testResetScriptFolder(self):
defaultScriptFolder = ScriptUtils.defaultScriptsFolder()
folder = ScriptUtils.resetScriptFolder(defaultScriptFolder)
self.assertEqual(folder, defaultScriptFolder)
- folder = ScriptUtils.resetScriptFolder('.')
- self.assertEqual(folder, '.')
+ folder = ScriptUtils.resetScriptFolder(".")
+ self.assertEqual(folder, ".")
# if folder does not exist and not absolute
- folder = ScriptUtils.resetScriptFolder('fake')
+ folder = ScriptUtils.resetScriptFolder("fake")
self.assertEqual(folder, None)
# if absolute but not relative to QgsApplication.qgisSettingsDirPath()
- folder = os.path.join(tempfile.gettempdir(), 'fakePath')
+ folder = os.path.join(tempfile.gettempdir(), "fakePath")
newFolder = ScriptUtils.resetScriptFolder(folder)
self.assertEqual(newFolder, folder)
@@ -66,13 +66,13 @@ def testResetScriptFolder(self):
# modify default profile changing absolute path pointing somewhere
paths = folder.split(os.sep)
- paths[0] = '/'
- paths[1] = 'fakelocation'
+ paths[0] = "/"
+ paths[1] = "fakelocation"
folder = os.path.join(*paths)
folder = ScriptUtils.resetScriptFolder(folder)
self.assertEqual(folder, QgsApplication.qgisSettingsDirPath())
-if __name__ == '__main__':
+if __name__ == "__main__":
unittest.main()
diff --git a/python/plugins/processing/tests/TestData.py b/python/plugins/processing/tests/TestData.py
index fc9024ed73a1..5262e26c00d8 100644
--- a/python/plugins/processing/tests/TestData.py
+++ b/python/plugins/processing/tests/TestData.py
@@ -15,22 +15,22 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'March 2013'
-__copyright__ = '(C) 2013, Victor Olaya'
+__author__ = "Victor Olaya"
+__date__ = "March 2013"
+__copyright__ = "(C) 2013, Victor Olaya"
import os.path
-testDataPath = os.path.join(os.path.dirname(__file__), 'testdata')
+testDataPath = os.path.join(os.path.dirname(__file__), "testdata")
def table():
- return os.path.join(testDataPath, 'table.dbf')
+ return os.path.join(testDataPath, "table.dbf")
def points():
- return os.path.join(testDataPath, 'points.gml')
+ return os.path.join(testDataPath, "points.gml")
def invalid_geometries():
- return os.path.join(testDataPath, 'invalidgeometries.gml')
+ return os.path.join(testDataPath, "invalidgeometries.gml")
diff --git a/python/plugins/processing/tests/ToolsTest.py b/python/plugins/processing/tests/ToolsTest.py
index 0cf6c76b7c6e..f3e7bd7952de 100644
--- a/python/plugins/processing/tests/ToolsTest.py
+++ b/python/plugins/processing/tests/ToolsTest.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Nyall Dawson'
-__date__ = 'July 2016'
-__copyright__ = '(C) 2016, Nyall Dawson'
+__author__ = "Nyall Dawson"
+__date__ = "July 2016"
+__copyright__ = "(C) 2016, Nyall Dawson"
import os
import shutil
@@ -29,7 +29,7 @@
from processing.tests.TestData import points
from processing.tools import vector
-testDataPath = os.path.join(os.path.dirname(__file__), 'testdata')
+testDataPath = os.path.join(os.path.dirname(__file__), "testdata")
start_app()
@@ -47,15 +47,15 @@ def tearDownClass(cls):
def testValues(self):
test_data = points()
- test_layer = QgsVectorLayer(test_data, 'test', 'ogr')
+ test_layer = QgsVectorLayer(test_data, "test", "ogr")
# field by index
res = vector.values(test_layer, 1)
self.assertEqual(res[1], [1, 2, 3, 4, 5, 6, 7, 8, 9])
# field by name
- res = vector.values(test_layer, 'id')
- self.assertEqual(res['id'], [1, 2, 3, 4, 5, 6, 7, 8, 9])
+ res = vector.values(test_layer, "id")
+ self.assertEqual(res["id"], [1, 2, 3, 4, 5, 6, 7, 8, 9])
# two fields
res = vector.values(test_layer, 1, 2)
@@ -63,26 +63,28 @@ def testValues(self):
self.assertEqual(res[2], [2, 1, 0, 2, 1, 0, 0, 0, 0])
# two fields by name
- res = vector.values(test_layer, 'id', 'id2')
- self.assertEqual(res['id'], [1, 2, 3, 4, 5, 6, 7, 8, 9])
- self.assertEqual(res['id2'], [2, 1, 0, 2, 1, 0, 0, 0, 0])
+ res = vector.values(test_layer, "id", "id2")
+ self.assertEqual(res["id"], [1, 2, 3, 4, 5, 6, 7, 8, 9])
+ self.assertEqual(res["id2"], [2, 1, 0, 2, 1, 0, 0, 0, 0])
# two fields by name and index
- res = vector.values(test_layer, 'id', 2)
- self.assertEqual(res['id'], [1, 2, 3, 4, 5, 6, 7, 8, 9])
+ res = vector.values(test_layer, "id", 2)
+ self.assertEqual(res["id"], [1, 2, 3, 4, 5, 6, 7, 8, 9])
self.assertEqual(res[2], [2, 1, 0, 2, 1, 0, 0, 0, 0])
def testConvertNulls(self):
self.assertEqual(vector.convert_nulls([]), [])
- self.assertEqual(vector.convert_nulls([], '_'), [])
+ self.assertEqual(vector.convert_nulls([], "_"), [])
self.assertEqual(vector.convert_nulls([NULL]), [None])
- self.assertEqual(vector.convert_nulls([NULL], '_'), ['_'])
+ self.assertEqual(vector.convert_nulls([NULL], "_"), ["_"])
self.assertEqual(vector.convert_nulls([NULL], -1), [-1])
self.assertEqual(vector.convert_nulls([1, 2, 3]), [1, 2, 3])
self.assertEqual(vector.convert_nulls([1, None, 3]), [1, None, 3])
self.assertEqual(vector.convert_nulls([1, NULL, 3, NULL]), [1, None, 3, None])
- self.assertEqual(vector.convert_nulls([1, NULL, 3, NULL], '_'), [1, '_', 3, '_'])
+ self.assertEqual(
+ vector.convert_nulls([1, NULL, 3, NULL], "_"), [1, "_", 3, "_"]
+ )
-if __name__ == '__main__':
+if __name__ == "__main__":
unittest.main()
diff --git a/python/plugins/processing/tools/__init__.py b/python/plugins/processing/tools/__init__.py
index 9d220581e82e..1d350d9cb43b 100644
--- a/python/plugins/processing/tools/__init__.py
+++ b/python/plugins/processing/tools/__init__.py
@@ -15,6 +15,6 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'February 2013'
-__copyright__ = '(C) 2013, Victor Olaya'
+__author__ = "Victor Olaya"
+__date__ = "February 2013"
+__copyright__ = "(C) 2013, Victor Olaya"
diff --git a/python/plugins/processing/tools/dataobjects.py b/python/plugins/processing/tools/dataobjects.py
index 39929afa06b6..55d9ef9e448d 100644
--- a/python/plugins/processing/tools/dataobjects.py
+++ b/python/plugins/processing/tools/dataobjects.py
@@ -15,25 +15,27 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'August 2012'
-__copyright__ = '(C) 2012, Victor Olaya'
+__author__ = "Victor Olaya"
+__date__ = "August 2012"
+__copyright__ = "(C) 2012, Victor Olaya"
import os
import re
-from qgis.core import (QgsDataProvider,
- QgsRasterLayer,
- QgsWkbTypes,
- QgsVectorLayer,
- QgsProject,
- QgsSettings,
- QgsProcessingContext,
- QgsProcessingUtils,
- QgsFeatureRequest,
- QgsExpressionContext,
- QgsExpressionContextUtils,
- QgsExpressionContextScope)
+from qgis.core import (
+ QgsDataProvider,
+ QgsRasterLayer,
+ QgsWkbTypes,
+ QgsVectorLayer,
+ QgsProject,
+ QgsSettings,
+ QgsProcessingContext,
+ QgsProcessingUtils,
+ QgsFeatureRequest,
+ QgsExpressionContext,
+ QgsExpressionContextUtils,
+ QgsExpressionContextScope,
+)
from qgis.gui import QgsSublayersDialog
from qgis.PyQt.QtCore import QCoreApplication
from qgis.utils import iface
@@ -59,15 +61,25 @@ def createContext(feedback=None):
context.setProject(QgsProject.instance())
context.setFeedback(feedback)
- invalid_features_method = ProcessingConfig.getSetting(ProcessingConfig.FILTER_INVALID_GEOMETRIES)
+ invalid_features_method = ProcessingConfig.getSetting(
+ ProcessingConfig.FILTER_INVALID_GEOMETRIES
+ )
if invalid_features_method is None:
- invalid_features_method = QgsFeatureRequest.InvalidGeometryCheck.GeometryAbortOnInvalid
+ invalid_features_method = (
+ QgsFeatureRequest.InvalidGeometryCheck.GeometryAbortOnInvalid
+ )
else:
- invalid_features_method = QgsFeatureRequest.InvalidGeometryCheck(int(invalid_features_method))
+ invalid_features_method = QgsFeatureRequest.InvalidGeometryCheck(
+ int(invalid_features_method)
+ )
context.setInvalidGeometryCheck(invalid_features_method)
settings = QgsSettings()
- context.setDefaultEncoding(QgsProcessingUtils.resolveDefaultEncoding(settings.value("/Processing/encoding")))
+ context.setDefaultEncoding(
+ QgsProcessingUtils.resolveDefaultEncoding(
+ settings.value("/Processing/encoding")
+ )
+ )
context.setExpressionContext(createExpressionContext())
@@ -83,16 +95,18 @@ def createExpressionContext():
context.appendScope(QgsExpressionContextUtils.projectScope(QgsProject.instance()))
if iface and iface.mapCanvas():
- context.appendScope(QgsExpressionContextUtils.mapSettingsScope(iface.mapCanvas().mapSettings()))
+ context.appendScope(
+ QgsExpressionContextUtils.mapSettingsScope(iface.mapCanvas().mapSettings())
+ )
processingScope = QgsExpressionContextScope()
if iface and iface.mapCanvas():
extent = iface.mapCanvas().fullExtent()
- processingScope.setVariable('fullextent_minx', extent.xMinimum())
- processingScope.setVariable('fullextent_miny', extent.yMinimum())
- processingScope.setVariable('fullextent_maxx', extent.xMaximum())
- processingScope.setVariable('fullextent_maxy', extent.yMaximum())
+ processingScope.setVariable("fullextent_minx", extent.xMinimum())
+ processingScope.setVariable("fullextent_miny", extent.yMinimum())
+ processingScope.setVariable("fullextent_maxx", extent.xMaximum())
+ processingScope.setVariable("fullextent_maxy", extent.yMaximum())
context.appendScope(processingScope)
return context
@@ -107,7 +121,11 @@ def load(fileName, name=None, crs=None, style=None, isRaster=False):
"""
from warnings import warn
- warn("processing.load is deprecated and will be removed in QGIS 4.0", DeprecationWarning)
+
+ warn(
+ "processing.load is deprecated and will be removed in QGIS 4.0",
+ DeprecationWarning,
+ )
if fileName is None:
return
@@ -118,7 +136,7 @@ def load(fileName, name=None, crs=None, style=None, isRaster=False):
if isRaster:
options = QgsRasterLayer.LayerOptions()
options.skipCrsValidation = True
- qgslayer = QgsRasterLayer(fileName, name, 'gdal', options)
+ qgslayer = QgsRasterLayer(fileName, name, "gdal", options)
if qgslayer.isValid():
if crs is not None and qgslayer.crs() is None:
qgslayer.setCrs(crs, False)
@@ -127,23 +145,32 @@ def load(fileName, name=None, crs=None, style=None, isRaster=False):
qgslayer.loadNamedStyle(style)
QgsProject.instance().addMapLayers([qgslayer])
else:
- raise RuntimeError(QCoreApplication.translate('dataobject',
- 'Could not load layer: {0}\nCheck the processing framework log to look for errors.').format(
- fileName))
+ raise RuntimeError(
+ QCoreApplication.translate(
+ "dataobject",
+ "Could not load layer: {0}\nCheck the processing framework log to look for errors.",
+ ).format(fileName)
+ )
else:
options = QgsVectorLayer.LayerOptions()
options.skipCrsValidation = True
- qgslayer = QgsVectorLayer(fileName, name, 'ogr', options)
+ qgslayer = QgsVectorLayer(fileName, name, "ogr", options)
if qgslayer.isValid():
if crs is not None and qgslayer.crs() is None:
qgslayer.setCrs(crs, False)
if style is None:
if qgslayer.geometryType() == QgsWkbTypes.GeometryType.PointGeometry:
- style = ProcessingConfig.getSetting(ProcessingConfig.VECTOR_POINT_STYLE)
+ style = ProcessingConfig.getSetting(
+ ProcessingConfig.VECTOR_POINT_STYLE
+ )
elif qgslayer.geometryType() == QgsWkbTypes.GeometryType.LineGeometry:
- style = ProcessingConfig.getSetting(ProcessingConfig.VECTOR_LINE_STYLE)
+ style = ProcessingConfig.getSetting(
+ ProcessingConfig.VECTOR_LINE_STYLE
+ )
else:
- style = ProcessingConfig.getSetting(ProcessingConfig.VECTOR_POLYGON_STYLE)
+ style = ProcessingConfig.getSetting(
+ ProcessingConfig.VECTOR_POLYGON_STYLE
+ )
qgslayer.loadNamedStyle(style)
QgsProject.instance().addMapLayers([qgslayer])
@@ -156,27 +183,36 @@ def getRasterSublayer(path, param):
try:
# If the layer is a raster layer and has multiple sublayers, let the user chose one.
# Based on QgisApp::askUserForGDALSublayers
- if layer and param.showSublayersDialog and layer.dataProvider().name() == "gdal" and len(layer.subLayers()) > 1:
+ if (
+ layer
+ and param.showSublayersDialog
+ and layer.dataProvider().name() == "gdal"
+ and len(layer.subLayers()) > 1
+ ):
layers = []
subLayerNum = 0
# simplify raster sublayer name
for subLayer in layer.subLayers():
# if netcdf/hdf use all text after filename
- if bool(re.match('netcdf', subLayer, re.I)) or bool(re.match('hdf', subLayer, re.I)):
+ if bool(re.match("netcdf", subLayer, re.I)) or bool(
+ re.match("hdf", subLayer, re.I)
+ ):
subLayer = subLayer.split(path)[1]
subLayer = subLayer[1:]
else:
# remove driver name and file name
- subLayer.replace(subLayer.split(QgsDataProvider.SUBLAYER_SEPARATOR)[0], "")
+ subLayer.replace(
+ subLayer.split(QgsDataProvider.SUBLAYER_SEPARATOR)[0], ""
+ )
subLayer.replace(path, "")
# remove any : or " left over
if subLayer.startswith(":"):
subLayer = subLayer[1:]
- if subLayer.startswith("\""):
+ if subLayer.startswith('"'):
subLayer = subLayer[1:]
if subLayer.endswith(":"):
subLayer = subLayer[:-1]
- if subLayer.endswith("\""):
+ if subLayer.endswith('"'):
subLayer = subLayer[:-1]
ld = QgsSublayersDialog.LayerDefinition()
@@ -187,7 +223,9 @@ def getRasterSublayer(path, param):
# Use QgsSublayersDialog
# Would be good if QgsSublayersDialog had an option to allow only one sublayer to be selected
- chooseSublayersDialog = QgsSublayersDialog(QgsSublayersDialog.ProviderType.Gdal, "gdal")
+ chooseSublayersDialog = QgsSublayersDialog(
+ QgsSublayersDialog.ProviderType.Gdal, "gdal"
+ )
chooseSublayersDialog.populateLayerTable(layers)
if chooseSublayersDialog.exec():
diff --git a/python/plugins/processing/tools/general.py b/python/plugins/processing/tools/general.py
index f6ef2478a11b..3f772555c5e3 100644
--- a/python/plugins/processing/tools/general.py
+++ b/python/plugins/processing/tools/general.py
@@ -15,19 +15,21 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'April 2013'
-__copyright__ = '(C) 2013, Victor Olaya'
-
-from qgis.core import (QgsApplication,
- QgsProcessingAlgorithm,
- QgsProcessingParameterDefinition,
- QgsProcessingParameterEnum,
- QgsProcessingParameterFeatureSink,
- QgsProcessingParameterVectorDestination,
- QgsProcessingParameterRasterDestination,
- QgsProcessingOutputLayerDefinition,
- QgsProject)
+__author__ = "Victor Olaya"
+__date__ = "April 2013"
+__copyright__ = "(C) 2013, Victor Olaya"
+
+from qgis.core import (
+ QgsApplication,
+ QgsProcessingAlgorithm,
+ QgsProcessingParameterDefinition,
+ QgsProcessingParameterEnum,
+ QgsProcessingParameterFeatureSink,
+ QgsProcessingParameterVectorDestination,
+ QgsProcessingParameterRasterDestination,
+ QgsProcessingOutputLayerDefinition,
+ QgsProject,
+)
from processing.core.Processing import Processing
from processing.gui.Postprocessing import handleAlgorithmResults
from processing.gui.AlgorithmDialog import AlgorithmDialog
@@ -40,46 +42,50 @@
def algorithmHelp(id: str) -> None:
alg = QgsApplication.processingRegistry().algorithmById(id)
if alg is not None:
- print(f'{alg.displayName()} ({alg.id()})\n')
+ print(f"{alg.displayName()} ({alg.id()})\n")
if alg.shortDescription():
- print(alg.shortDescription() + '\n')
+ print(alg.shortDescription() + "\n")
if alg.shortHelpString():
- print(alg.shortHelpString() + '\n')
- print('\n----------------')
- print('Input parameters')
- print('----------------')
+ print(alg.shortHelpString() + "\n")
+ print("\n----------------")
+ print("Input parameters")
+ print("----------------")
for p in alg.parameterDefinitions():
if p.flags() & QgsProcessingParameterDefinition.Flag.FlagHidden:
continue
- print(f'\n{p.name()}: {p.description()}')
+ print(f"\n{p.name()}: {p.description()}")
if p.help():
- print(f'\n\t{p.help()}')
+ print(f"\n\t{p.help()}")
- print(f'\n\tParameter type:\t{p.__class__.__name__}')
+ print(f"\n\tParameter type:\t{p.__class__.__name__}")
if isinstance(p, QgsProcessingParameterEnum):
opts = []
for i, o in enumerate(p.options()):
- opts.append(f'\t\t- {i}: {o}')
- print('\n\tAvailable values:\n{}'.format('\n'.join(opts)))
+ opts.append(f"\t\t- {i}: {o}")
+ print("\n\tAvailable values:\n{}".format("\n".join(opts)))
parameter_type = QgsApplication.processingRegistry().parameterType(p.type())
- accepted_types = parameter_type.acceptedPythonTypes() if parameter_type is not None else []
+ accepted_types = (
+ parameter_type.acceptedPythonTypes()
+ if parameter_type is not None
+ else []
+ )
if accepted_types:
opts = []
for t in accepted_types:
- opts.append(f'\t\t- {t}')
- print('\n\tAccepted data types:')
- print('\n'.join(opts))
+ opts.append(f"\t\t- {t}")
+ print("\n\tAccepted data types:")
+ print("\n".join(opts))
- print('\n----------------')
- print('Outputs')
- print('----------------')
+ print("\n----------------")
+ print("Outputs")
+ print("----------------")
for o in alg.outputDefinitions():
- print(f'\n{o.name()}: <{o.__class__.__name__}>')
+ print(f"\n{o.name()}: <{o.__class__.__name__}>")
if o.description():
- print('\t' + o.description())
+ print("\t" + o.description())
else:
print(f'Algorithm "{id}" not found.')
@@ -88,9 +94,18 @@ def algorithmHelp(id: str) -> None:
# changing this signature? make sure you update the signature in
# python/processing/__init__.py too!
# Docstring for this function is in python/processing/__init__.py
-def run(algOrName, parameters, onFinish=None, feedback=None, context=None, is_child_algorithm=False):
+def run(
+ algOrName,
+ parameters,
+ onFinish=None,
+ feedback=None,
+ context=None,
+ is_child_algorithm=False,
+):
if onFinish or not is_child_algorithm:
- return Processing.runAlgorithm(algOrName, parameters, onFinish, feedback, context)
+ return Processing.runAlgorithm(
+ algOrName, parameters, onFinish, feedback, context
+ )
else:
# for child algorithms, we disable to default post-processing step where layer ownership
# is transferred from the context to the caller. In this case, we NEED the ownership to remain
@@ -98,7 +113,13 @@ def run(algOrName, parameters, onFinish=None, feedback=None, context=None, is_ch
def post_process(_alg, _context, _feedback):
return
- return Processing.runAlgorithm(algOrName, parameters, onFinish=post_process, feedback=feedback, context=context)
+ return Processing.runAlgorithm(
+ algOrName,
+ parameters,
+ onFinish=post_process,
+ feedback=feedback,
+ context=context,
+ )
# changing this signature? make sure you update the signature in
@@ -115,17 +136,30 @@ def runAndLoadResults(algOrName, parameters, feedback=None, context=None):
if not param.name() in parameters:
continue
- if isinstance(param, (QgsProcessingParameterFeatureSink, QgsProcessingParameterVectorDestination,
- QgsProcessingParameterRasterDestination)):
+ if isinstance(
+ param,
+ (
+ QgsProcessingParameterFeatureSink,
+ QgsProcessingParameterVectorDestination,
+ QgsProcessingParameterRasterDestination,
+ ),
+ ):
p = parameters[param.name()]
if not isinstance(p, QgsProcessingOutputLayerDefinition):
- parameters[param.name()] = QgsProcessingOutputLayerDefinition(p, QgsProject.instance())
+ parameters[param.name()] = QgsProcessingOutputLayerDefinition(
+ p, QgsProject.instance()
+ )
else:
p.destinationProject = QgsProject.instance()
parameters[param.name()] = p
- return Processing.runAlgorithm(alg, parameters=parameters, onFinish=handleAlgorithmResults, feedback=feedback,
- context=context)
+ return Processing.runAlgorithm(
+ alg,
+ parameters=parameters,
+ onFinish=handleAlgorithmResults,
+ feedback=feedback,
+ context=context,
+ )
# changing this signature? make sure you update the signature in
diff --git a/python/plugins/processing/tools/raster.py b/python/plugins/processing/tools/raster.py
index 73c459cb8c55..bbf83b3847cd 100644
--- a/python/plugins/processing/tools/raster.py
+++ b/python/plugins/processing/tools/raster.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya and Alexander Bruy'
-__date__ = 'February 2013'
-__copyright__ = '(C) 2013, Victor Olaya and Alexander Bruy'
+__author__ = "Victor Olaya and Alexander Bruy"
+__date__ = "February 2013"
+__copyright__ = "(C) 2013, Victor Olaya and Alexander Bruy"
import struct
@@ -36,24 +36,23 @@ def scanraster(layer, feedback, band_number=1):
bandtype = gdal.GetDataTypeName(band.DataType)
for y in range(band.YSize):
feedback.setProgress(y / float(band.YSize) * 100)
- scanline = band.ReadRaster(0, y, band.XSize, 1, band.XSize, 1,
- band.DataType)
- if bandtype == 'Byte':
- values = struct.unpack('B' * band.XSize, scanline)
- elif bandtype == 'Int16':
- values = struct.unpack('h' * band.XSize, scanline)
- elif bandtype == 'UInt16':
- values = struct.unpack('H' * band.XSize, scanline)
- elif bandtype == 'Int32':
- values = struct.unpack('i' * band.XSize, scanline)
- elif bandtype == 'UInt32':
- values = struct.unpack('I' * band.XSize, scanline)
- elif bandtype == 'Float32':
- values = struct.unpack('f' * band.XSize, scanline)
- elif bandtype == 'Float64':
- values = struct.unpack('d' * band.XSize, scanline)
+ scanline = band.ReadRaster(0, y, band.XSize, 1, band.XSize, 1, band.DataType)
+ if bandtype == "Byte":
+ values = struct.unpack("B" * band.XSize, scanline)
+ elif bandtype == "Int16":
+ values = struct.unpack("h" * band.XSize, scanline)
+ elif bandtype == "UInt16":
+ values = struct.unpack("H" * band.XSize, scanline)
+ elif bandtype == "Int32":
+ values = struct.unpack("i" * band.XSize, scanline)
+ elif bandtype == "UInt32":
+ values = struct.unpack("I" * band.XSize, scanline)
+ elif bandtype == "Float32":
+ values = struct.unpack("f" * band.XSize, scanline)
+ elif bandtype == "Float64":
+ values = struct.unpack("d" * band.XSize, scanline)
else:
- raise QgsProcessingException('Raster format not supported')
+ raise QgsProcessingException("Raster format not supported")
for value in values:
if value == nodata:
value = None
@@ -61,8 +60,7 @@ def scanraster(layer, feedback, band_number=1):
def mapToPixel(mX, mY, geoTransform):
- (pX, pY) = gdal.ApplyGeoTransform(
- gdal.InvGeoTransform(geoTransform), mX, mY)
+ (pX, pY) = gdal.ApplyGeoTransform(gdal.InvGeoTransform(geoTransform), mX, mY)
return (int(pX), int(pY))
diff --git a/python/plugins/processing/tools/system.py b/python/plugins/processing/tools/system.py
index 7ef861c56233..266dfaf0f276 100644
--- a/python/plugins/processing/tools/system.py
+++ b/python/plugins/processing/tools/system.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'August 2012'
-__copyright__ = '(C) 2012, Victor Olaya'
+__author__ = "Victor Olaya"
+__date__ = "August 2012"
+__copyright__ = "(C) 2012, Victor Olaya"
from typing import Optional
import os
@@ -27,15 +27,13 @@
import math
from qgis.PyQt.QtCore import QDir
-from qgis.core import (QgsApplication,
- QgsProcessingUtils,
- QgsProcessingContext)
+from qgis.core import QgsApplication, QgsProcessingUtils, QgsProcessingContext
numExported = 1
def userFolder():
- userDir = os.path.join(QgsApplication.qgisSettingsDirPath(), 'processing')
+ userDir = os.path.join(QgsApplication.qgisSettingsDirPath(), "processing")
if not QDir(userDir).exists():
QDir().mkpath(userDir)
@@ -43,7 +41,7 @@ def userFolder():
def defaultOutputFolder():
- folder = os.path.join(userFolder(), 'outputs')
+ folder = os.path.join(userFolder(), "outputs")
if not QDir(folder).exists():
QDir().mkpath(folder)
@@ -51,22 +49,22 @@ def defaultOutputFolder():
def isWindows():
- return os.name == 'nt'
+ return os.name == "nt"
def isMac():
- return sys.platform == 'darwin'
+ return sys.platform == "darwin"
def getTempFilename(ext=None, context: Optional[QgsProcessingContext] = None):
tmpPath = QgsProcessingUtils.tempFolder(context)
t = time.time()
m = math.floor(t)
- uid = f'{m:8x}{int((t - m) * 1000000):05x}'
+ uid = f"{m:8x}{int((t - m) * 1000000):05x}"
if ext is None:
- filename = os.path.join(tmpPath, f'{uid}{getNumExportedLayers()}')
+ filename = os.path.join(tmpPath, f"{uid}{getNumExportedLayers()}")
else:
- filename = os.path.join(tmpPath, f'{uid}{getNumExportedLayers()}.{ext}')
+ filename = os.path.join(tmpPath, f"{uid}{getNumExportedLayers()}.{ext}")
return filename
@@ -77,11 +75,11 @@ def getNumExportedLayers():
def mkdir(newdir):
- os.makedirs(newdir.strip('\n\r '), exist_ok=True)
+ os.makedirs(newdir.strip("\n\r "), exist_ok=True)
def tempHelpFolder():
- tmp = os.path.join(str(QDir.tempPath()), 'processing_help')
+ tmp = os.path.join(str(QDir.tempPath()), "processing_help")
if not QDir(tmp).exists():
QDir().mkpath(tmp)
@@ -95,14 +93,17 @@ def escapeAndJoin(strList):
"""
from warnings import warn
- warn("processing.escapeAndJoin is deprecated and will be removed in QGIS 4.0", DeprecationWarning)
- joined = ''
+ warn(
+ "processing.escapeAndJoin is deprecated and will be removed in QGIS 4.0",
+ DeprecationWarning,
+ )
+
+ joined = ""
for s in strList:
- if s[0] != '-' and ' ' in s:
- escaped = '"' + s.replace('\\', '\\\\').replace('"', '\\"') \
- + '"'
+ if s[0] != "-" and " " in s:
+ escaped = '"' + s.replace("\\", "\\\\").replace('"', '\\"') + '"'
else:
escaped = s
- joined += escaped + ' '
+ joined += escaped + " "
return joined.strip()
diff --git a/python/plugins/processing/tools/vector.py b/python/plugins/processing/tools/vector.py
index b9c644e17ef0..76fc8c463e39 100644
--- a/python/plugins/processing/tools/vector.py
+++ b/python/plugins/processing/tools/vector.py
@@ -15,12 +15,11 @@
***************************************************************************
"""
-__author__ = 'Victor Olaya'
-__date__ = 'February 2013'
-__copyright__ = '(C) 2013, Victor Olaya'
+__author__ = "Victor Olaya"
+__date__ = "February 2013"
+__copyright__ = "(C) 2013, Victor Olaya"
-from qgis.core import (NULL,
- QgsFeatureRequest)
+from qgis.core import NULL, QgsFeatureRequest
def resolveFieldIndex(source, attr):
@@ -39,7 +38,7 @@ def resolveFieldIndex(source, attr):
else:
index = source.fields().lookupField(attr)
if index == -1:
- raise ValueError('Wrong field name')
+ raise ValueError("Wrong field name")
return index
@@ -63,7 +62,11 @@ def values(source, *attributes):
attr_keys[index] = attr
# use an optimised feature request
- request = QgsFeatureRequest().setSubsetOfAttributes(indices).setFlags(QgsFeatureRequest.Flag.NoGeometry)
+ request = (
+ QgsFeatureRequest()
+ .setSubsetOfAttributes(indices)
+ .setFlags(QgsFeatureRequest.Flag.NoGeometry)
+ )
for feature in source.getFeatures(request):
for i in indices:
diff --git a/python/processing/__init__.py b/python/processing/__init__.py
index d2d5a1500f28..d08ff505b183 100644
--- a/python/processing/__init__.py
+++ b/python/processing/__init__.py
@@ -1,5 +1,3 @@
-# -#- coding: utf-8 -#-
-
###########################################################################
# __init__.py
# ---------------------
@@ -22,9 +20,9 @@
to the core QGIS c++ Processing classes.
"""
-__author__ = 'Nathan Woodrow'
-__date__ = 'November 2018'
-__copyright__ = '(C) 2018, Nathan Woodrow'
+__author__ = "Nathan Woodrow"
+__date__ = "November 2018"
+__copyright__ = "(C) 2018, Nathan Woodrow"
import typing as _typing
@@ -39,6 +37,7 @@
# "Forward declare" functions which will be patched in when the Processing plugin loads:
+
def algorithmHelp(id: str) -> None:
"""
Prints algorithm parameters with their types. Also
@@ -50,15 +49,18 @@ def algorithmHelp(id: str) -> None:
:raises: QgsNotSupportedException if the Processing plugin has not been loaded
"""
from qgis.core import QgsNotSupportedException
- raise QgsNotSupportedException('Processing plugin has not been loaded')
+ raise QgsNotSupportedException("Processing plugin has not been loaded")
-def run(algOrName: _typing.Union[str, _QgsProcessingAlgorithm],
- parameters: _typing.Dict[str, object],
- onFinish: _typing.Optional[_typing.Callable] = None,
- feedback: _typing.Optional[_QgsProcessingFeedback] = None,
- context: _typing.Optional[_QgsProcessingContext] = None,
- is_child_algorithm: bool = False) -> _typing.Union[_typing.Dict, None]:
+
+def run(
+ algOrName: _typing.Union[str, _QgsProcessingAlgorithm],
+ parameters: _typing.Dict[str, object],
+ onFinish: _typing.Optional[_typing.Callable] = None,
+ feedback: _typing.Optional[_QgsProcessingFeedback] = None,
+ context: _typing.Optional[_QgsProcessingContext] = None,
+ is_child_algorithm: bool = False,
+) -> _typing.Union[_typing.Dict, None]:
"""
Executes given algorithm and returns its outputs as dictionary object.
@@ -75,13 +77,16 @@ def run(algOrName: _typing.Union[str, _QgsProcessingAlgorithm],
:raises: QgsNotSupportedException if the Processing plugin has not been loaded
"""
from qgis.core import QgsNotSupportedException
- raise QgsNotSupportedException('Processing plugin has not been loaded')
+
+ raise QgsNotSupportedException("Processing plugin has not been loaded")
-def runAndLoadResults(algOrName: _typing.Union[str, _QgsProcessingAlgorithm],
- parameters: _typing.Dict[str, object],
- feedback: _typing.Optional[_QgsProcessingFeedback] = None,
- context: _typing.Optional[_QgsProcessingContext] = None) -> _typing.Union[_typing.Dict, None]:
+def runAndLoadResults(
+ algOrName: _typing.Union[str, _QgsProcessingAlgorithm],
+ parameters: _typing.Dict[str, object],
+ feedback: _typing.Optional[_QgsProcessingFeedback] = None,
+ context: _typing.Optional[_QgsProcessingContext] = None,
+) -> _typing.Union[_typing.Dict, None]:
"""
Executes given algorithm and load its results into the current QGIS project
when possible.
@@ -97,11 +102,14 @@ def runAndLoadResults(algOrName: _typing.Union[str, _QgsProcessingAlgorithm],
:raises: QgsNotSupportedException if the Processing plugin has not been loaded
"""
from qgis.core import QgsNotSupportedException
- raise QgsNotSupportedException('Processing plugin has not been loaded')
+ raise QgsNotSupportedException("Processing plugin has not been loaded")
-def createAlgorithmDialog(algOrName: _typing.Union[str, _QgsProcessingAlgorithm],
- parameters: _typing.Dict[str, object] = {}) -> _typing.Union[str, _QgsProcessingAlgorithm]:
+
+def createAlgorithmDialog(
+ algOrName: _typing.Union[str, _QgsProcessingAlgorithm],
+ parameters: _typing.Dict[str, object] = {},
+) -> _typing.Union[str, _QgsProcessingAlgorithm]:
"""
Creates and returns an algorithm dialog for the specified algorithm, prepopulated
with a given set of parameters. It is the caller's responsibility to execute
@@ -115,11 +123,14 @@ def createAlgorithmDialog(algOrName: _typing.Union[str, _QgsProcessingAlgorithm]
:raises: QgsNotSupportedException if the Processing plugin has not been loaded
"""
from qgis.core import QgsNotSupportedException
- raise QgsNotSupportedException('Processing plugin has not been loaded')
+
+ raise QgsNotSupportedException("Processing plugin has not been loaded")
-def execAlgorithmDialog(algOrName: _typing.Union[str, _QgsProcessingAlgorithm],
- parameters: _typing.Dict[str, object] = {}) -> _typing.Union[_typing.Dict, None]:
+def execAlgorithmDialog(
+ algOrName: _typing.Union[str, _QgsProcessingAlgorithm],
+ parameters: _typing.Dict[str, object] = {},
+) -> _typing.Union[_typing.Dict, None]:
"""
Executes an algorithm dialog for the specified algorithm, prepopulated
with a given set of parameters.
@@ -132,10 +143,13 @@ def execAlgorithmDialog(algOrName: _typing.Union[str, _QgsProcessingAlgorithm],
:raises: QgsNotSupportedException if the Processing plugin has not been loaded
"""
from qgis.core import QgsNotSupportedException
- raise QgsNotSupportedException('Processing plugin has not been loaded')
+ raise QgsNotSupportedException("Processing plugin has not been loaded")
-def createContext(feedback: _typing.Optional[_QgsProcessingFeedback] = None) -> _QgsProcessingContext:
+
+def createContext(
+ feedback: _typing.Optional[_QgsProcessingFeedback] = None,
+) -> _QgsProcessingContext:
"""
Creates a default processing context
@@ -147,4 +161,5 @@ def createContext(feedback: _typing.Optional[_QgsProcessingFeedback] = None) ->
:raises: QgsNotSupportedException if the Processing plugin has not been loaded
"""
from qgis.core import QgsNotSupportedException
- raise QgsNotSupportedException('Processing plugin has not been loaded')
+
+ raise QgsNotSupportedException("Processing plugin has not been loaded")
diff --git a/python/processing/algfactory.py b/python/processing/algfactory.py
index d6a82105059a..d1c4b6d19765 100644
--- a/python/processing/algfactory.py
+++ b/python/processing/algfactory.py
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-
"""
***************************************************************************
algfactory.py
@@ -17,72 +15,74 @@
***************************************************************************
"""
-__author__ = 'Nathan Woodrow'
-__date__ = 'November 2018'
-__copyright__ = '(C) 2018, Nathan Woodrow'
+__author__ = "Nathan Woodrow"
+__date__ = "November 2018"
+__copyright__ = "(C) 2018, Nathan Woodrow"
from collections import OrderedDict
from functools import partial
from qgis.PyQt.QtCore import QCoreApplication
from qgis.PyQt.QtGui import QIcon
-from qgis.core import (QgsProcessingParameterDefinition,
- QgsProcessingAlgorithm,
- QgsProcessingParameterString,
- QgsProcessingParameterAuthConfig,
- QgsProcessingParameterNumber,
- QgsProcessingParameterDistance,
- QgsProcessingParameterDuration,
- QgsProcessingParameterFeatureSource,
- QgsProcessingParameterFeatureSink,
- QgsProcessingParameterFileDestination,
- QgsProcessingParameterFolderDestination,
- QgsProcessingParameterRasterDestination,
- QgsProcessingParameterVectorDestination,
- QgsProcessingParameterPointCloudDestination,
- QgsProcessingParameterBand,
- QgsProcessingParameterBoolean,
- QgsProcessingParameterCrs,
- QgsProcessingParameterEnum,
- QgsProcessingParameterExpression,
- QgsProcessingParameterExtent,
- QgsProcessingParameterField,
- QgsProcessingParameterFile,
- QgsProcessingParameterMapLayer,
- QgsProcessingParameterMatrix,
- QgsProcessingParameterMultipleLayers,
- QgsProcessingParameterPoint,
- QgsProcessingParameterGeometry,
- QgsProcessingParameterRange,
- QgsProcessingParameterRasterLayer,
- QgsProcessingParameterVectorLayer,
- QgsProcessingParameterMeshLayer,
- QgsProcessingParameterColor,
- QgsProcessingParameterScale,
- QgsProcessingParameterLayout,
- QgsProcessingParameterLayoutItem,
- QgsProcessingParameterDateTime,
- QgsProcessingParameterMapTheme,
- QgsProcessingParameterProviderConnection,
- QgsProcessingParameterDatabaseSchema,
- QgsProcessingParameterDatabaseTable,
- QgsProcessingParameterCoordinateOperation,
- QgsProcessingParameterPointCloudLayer,
- QgsProcessingParameterAnnotationLayer,
- QgsProcessingOutputString,
- QgsProcessingOutputBoolean,
- QgsProcessingOutputFile,
- QgsProcessingOutputFolder,
- QgsProcessingOutputHtml,
- QgsProcessingOutputLayerDefinition,
- QgsProcessingOutputMapLayer,
- QgsProcessingOutputMultipleLayers,
- QgsProcessingOutputNumber,
- QgsProcessingOutputRasterLayer,
- QgsProcessingOutputVectorLayer,
- QgsProcessingOutputPointCloudLayer,
- QgsMessageLog,
- QgsApplication)
+from qgis.core import (
+ QgsProcessingParameterDefinition,
+ QgsProcessingAlgorithm,
+ QgsProcessingParameterString,
+ QgsProcessingParameterAuthConfig,
+ QgsProcessingParameterNumber,
+ QgsProcessingParameterDistance,
+ QgsProcessingParameterDuration,
+ QgsProcessingParameterFeatureSource,
+ QgsProcessingParameterFeatureSink,
+ QgsProcessingParameterFileDestination,
+ QgsProcessingParameterFolderDestination,
+ QgsProcessingParameterRasterDestination,
+ QgsProcessingParameterVectorDestination,
+ QgsProcessingParameterPointCloudDestination,
+ QgsProcessingParameterBand,
+ QgsProcessingParameterBoolean,
+ QgsProcessingParameterCrs,
+ QgsProcessingParameterEnum,
+ QgsProcessingParameterExpression,
+ QgsProcessingParameterExtent,
+ QgsProcessingParameterField,
+ QgsProcessingParameterFile,
+ QgsProcessingParameterMapLayer,
+ QgsProcessingParameterMatrix,
+ QgsProcessingParameterMultipleLayers,
+ QgsProcessingParameterPoint,
+ QgsProcessingParameterGeometry,
+ QgsProcessingParameterRange,
+ QgsProcessingParameterRasterLayer,
+ QgsProcessingParameterVectorLayer,
+ QgsProcessingParameterMeshLayer,
+ QgsProcessingParameterColor,
+ QgsProcessingParameterScale,
+ QgsProcessingParameterLayout,
+ QgsProcessingParameterLayoutItem,
+ QgsProcessingParameterDateTime,
+ QgsProcessingParameterMapTheme,
+ QgsProcessingParameterProviderConnection,
+ QgsProcessingParameterDatabaseSchema,
+ QgsProcessingParameterDatabaseTable,
+ QgsProcessingParameterCoordinateOperation,
+ QgsProcessingParameterPointCloudLayer,
+ QgsProcessingParameterAnnotationLayer,
+ QgsProcessingOutputString,
+ QgsProcessingOutputBoolean,
+ QgsProcessingOutputFile,
+ QgsProcessingOutputFolder,
+ QgsProcessingOutputHtml,
+ QgsProcessingOutputLayerDefinition,
+ QgsProcessingOutputMapLayer,
+ QgsProcessingOutputMultipleLayers,
+ QgsProcessingOutputNumber,
+ QgsProcessingOutputRasterLayer,
+ QgsProcessingOutputVectorLayer,
+ QgsProcessingOutputPointCloudLayer,
+ QgsMessageLog,
+ QgsApplication,
+)
def _log(*args, **kw):
@@ -100,11 +100,11 @@ def _make_output(**args):
'description' The description used on the output
:return:
"""
- cls = args['cls']
- del args['cls']
+ cls = args["cls"]
+ del args["cls"]
newargs = {
- "name": args['name'],
- "description": args['description'],
+ "name": args["name"],
+ "description": args["description"],
}
return cls(**newargs)
@@ -115,7 +115,7 @@ class ProcessingAlgFactoryException(Exception):
"""
def __init__(self, message):
- super(ProcessingAlgFactoryException, self).__init__(message)
+ super().__init__(message)
class AlgWrapper(QgsProcessingAlgorithm):
@@ -123,10 +123,19 @@ class AlgWrapper(QgsProcessingAlgorithm):
Wrapper object used to create new processing algorithms from @alg.
"""
- def __init__(self, name=None, display=None,
- group=None, group_id=None, inputs=None,
- outputs=None, func=None, help=None, icon=None):
- super(AlgWrapper, self).__init__()
+ def __init__(
+ self,
+ name=None,
+ display=None,
+ group=None,
+ group_id=None,
+ inputs=None,
+ outputs=None,
+ func=None,
+ help=None,
+ icon=None,
+ ):
+ super().__init__()
self._inputs = OrderedDict(inputs or {})
self._outputs = OrderedDict(outputs or {})
self._icon = icon
@@ -147,7 +156,15 @@ def _get_parent_id(self, parent):
raise NotImplementedError()
# Wrapper logic
- def define(self, name, label, group, group_label, help=None, icon=QgsApplication.iconPath("processingScript.svg")):
+ def define(
+ self,
+ name,
+ label,
+ group,
+ group_label,
+ help=None,
+ icon=QgsApplication.iconPath("processingScript.svg"),
+ ):
self._name = name
self._display = label
self._group = group_label
@@ -160,8 +177,10 @@ def end(self):
Finalize the wrapper logic and check for any invalid config.
"""
if not self.has_outputs:
- raise ProcessingAlgFactoryException("No outputs defined for '{}' alg"
- "At least one must be defined. Use @alg.output")
+ raise ProcessingAlgFactoryException(
+ "No outputs defined for '{}' alg"
+ "At least one must be defined. Use @alg.output"
+ )
def add_output(self, type, **kwargs):
parm = self._create_param(type, output=True, **kwargs)
@@ -183,21 +202,25 @@ def outputs(self):
return self._outputs
def _create_param(self, type, output=False, **kwargs):
- name = kwargs['name']
+ name = kwargs["name"]
if name in self._inputs or name in self._outputs:
- raise ProcessingAlgFactoryException("{} already defined".format(name))
+ raise ProcessingAlgFactoryException(f"{name} already defined")
parent = kwargs.get("parent")
if parent:
parentname = self._get_parent_id(parent)
if parentname == name:
- raise ProcessingAlgFactoryException("{} can't depend on itself. "
- "We know QGIS is smart but it's not that smart".format(name))
+ raise ProcessingAlgFactoryException(
+ "{} can't depend on itself. "
+ "We know QGIS is smart but it's not that smart".format(name)
+ )
if parentname not in self._inputs and parentname not in self._outputs:
- raise ProcessingAlgFactoryException("Can't find parent named {}".format(parentname))
+ raise ProcessingAlgFactoryException(
+ f"Can't find parent named {parentname}"
+ )
- kwargs['description'] = kwargs.pop("label", "")
- kwargs['defaultValue'] = kwargs.pop("default", None)
+ kwargs["description"] = kwargs.pop("label", "")
+ kwargs["defaultValue"] = kwargs.pop("default", None)
advanced = kwargs.pop("advanced", False)
help_str = kwargs.pop("help", "")
try:
@@ -205,20 +228,26 @@ def _create_param(self, type, output=False, **kwargs):
try:
make_func = output_type_mapping[type]
except KeyError:
- raise ProcessingAlgFactoryException("{} is a invalid output type".format(type))
+ raise ProcessingAlgFactoryException(
+ f"{type} is a invalid output type"
+ )
else:
try:
make_func = input_type_mapping[type]
except KeyError:
- raise ProcessingAlgFactoryException("{} is a invalid input type".format(type))
+ raise ProcessingAlgFactoryException(
+ f"{type} is a invalid input type"
+ )
parm = make_func(**kwargs)
if advanced:
- parm.setFlags(parm.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced)
+ parm.setFlags(
+ parm.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced
+ )
if not output:
parm.setHelp(help_str)
return parm
except KeyError as ex:
- raise NotImplementedError("{} not supported".format(str(type)))
+ raise NotImplementedError(f"{str(type)} not supported")
def set_func(self, func):
self._func = func
@@ -245,7 +274,9 @@ def _get_parameter_value(self, parm, parameters, name, context):
"""
Extract the real value from the parameter.
"""
- if isinstance(parm, (QgsProcessingParameterString, QgsProcessingParameterAuthConfig)):
+ if isinstance(
+ parm, (QgsProcessingParameterString, QgsProcessingParameterAuthConfig)
+ ):
value = self.parameterAsString(parameters, name, context)
return value
elif isinstance(parm, QgsProcessingParameterNumber):
@@ -281,13 +312,17 @@ def processAlgorithm(self, parameters, context, feedback):
return output
def createInstance(self):
- return AlgWrapper(self._name, self._display,
- self._group, self._group_id,
- inputs=self._inputs,
- outputs=self._outputs,
- func=self._func,
- help=self._help,
- icon=self._icon)
+ return AlgWrapper(
+ self._name,
+ self._display,
+ self._group,
+ self._group_id,
+ inputs=self._inputs,
+ outputs=self._outputs,
+ func=self._func,
+ help=self._help,
+ icon=self._icon,
+ )
def initAlgorithm(self, configuration=None, p_str=None, Any=None, *args, **kwargs):
for parm in self._inputs.values():
@@ -306,39 +341,39 @@ def icon(self):
return QIcon(self._icon)
-class ProcessingAlgFactory():
- STRING = "STRING",
- INT = "INT",
- NUMBER = "NUMBER",
- DISTANCE = "DISTANCE",
+class ProcessingAlgFactory:
+ STRING = ("STRING",)
+ INT = ("INT",)
+ NUMBER = ("NUMBER",)
+ DISTANCE = ("DISTANCE",)
SINK = "SINK"
SOURCE = "SOURCE"
- FILE = "FILE",
- FOLDER = "FOLDER",
- HTML = "HTML",
- LAYERDEF = "LAYERDEF",
- MAPLAYER = "MAPLAYER",
- MULTILAYER = "MULTILAYER",
- RASTER_LAYER = "RASTER_LAYER",
- VECTOR_LAYER = "VECTOR_LAYER",
- MESH_LAYER = "MESH_LAYER",
- POINT_CLOUD_LAYER = "POINT_CLOUD_LAYER",
- FILE_DEST = "FILE_DEST",
- FOLDER_DEST = "FOLDER_DEST",
- RASTER_LAYER_DEST = "RASTER_LAYER_DEST",
- VECTOR_LAYER_DEST = "VECTOR_LAYER_DEST",
- POINTCLOUD_LAYER_DEST = "POINTCLOUD_LAYER_DEST",
- BAND = "BAND",
- BOOL = "BOOL",
- CRS = "CRS",
- ENUM = "ENUM",
- EXPRESSION = "EXPRESSION",
- EXTENT = "EXTENT",
- FIELD = "FIELD",
- MATRIX = "MATRIX",
- POINT = "POINT",
- GEOMETRY = "GEOMETRY",
- RANGE = "RANGE",
+ FILE = ("FILE",)
+ FOLDER = ("FOLDER",)
+ HTML = ("HTML",)
+ LAYERDEF = ("LAYERDEF",)
+ MAPLAYER = ("MAPLAYER",)
+ MULTILAYER = ("MULTILAYER",)
+ RASTER_LAYER = ("RASTER_LAYER",)
+ VECTOR_LAYER = ("VECTOR_LAYER",)
+ MESH_LAYER = ("MESH_LAYER",)
+ POINT_CLOUD_LAYER = ("POINT_CLOUD_LAYER",)
+ FILE_DEST = ("FILE_DEST",)
+ FOLDER_DEST = ("FOLDER_DEST",)
+ RASTER_LAYER_DEST = ("RASTER_LAYER_DEST",)
+ VECTOR_LAYER_DEST = ("VECTOR_LAYER_DEST",)
+ POINTCLOUD_LAYER_DEST = ("POINTCLOUD_LAYER_DEST",)
+ BAND = ("BAND",)
+ BOOL = ("BOOL",)
+ CRS = ("CRS",)
+ ENUM = ("ENUM",)
+ EXPRESSION = ("EXPRESSION",)
+ EXTENT = ("EXTENT",)
+ FIELD = ("FIELD",)
+ MATRIX = ("MATRIX",)
+ POINT = ("POINT",)
+ GEOMETRY = ("GEOMETRY",)
+ RANGE = ("RANGE",)
AUTH_CFG = "AUTH_CFG"
SCALE = "SCALE"
COLOR = "COLOR"
@@ -363,7 +398,7 @@ def tr(self, string):
"""
Returns a translatable string with the self.tr() function.
"""
- return QCoreApplication.translate('Processing', string)
+ return QCoreApplication.translate("Processing", string)
@property
def current(self):
@@ -516,11 +551,19 @@ def dec(f):
input_type_mapping = {
str: QgsProcessingParameterString,
- int: partial(QgsProcessingParameterNumber, type=QgsProcessingParameterNumber.Type.Integer),
- float: partial(QgsProcessingParameterNumber, type=QgsProcessingParameterNumber.Type.Double),
+ int: partial(
+ QgsProcessingParameterNumber, type=QgsProcessingParameterNumber.Type.Integer
+ ),
+ float: partial(
+ QgsProcessingParameterNumber, type=QgsProcessingParameterNumber.Type.Double
+ ),
bool: QgsProcessingParameterBoolean,
- ProcessingAlgFactory.NUMBER: partial(QgsProcessingParameterNumber, type=QgsProcessingParameterNumber.Type.Double),
- ProcessingAlgFactory.INT: partial(QgsProcessingParameterNumber, type=QgsProcessingParameterNumber.Type.Integer),
+ ProcessingAlgFactory.NUMBER: partial(
+ QgsProcessingParameterNumber, type=QgsProcessingParameterNumber.Type.Double
+ ),
+ ProcessingAlgFactory.INT: partial(
+ QgsProcessingParameterNumber, type=QgsProcessingParameterNumber.Type.Integer
+ ),
ProcessingAlgFactory.STRING: QgsProcessingParameterString,
ProcessingAlgFactory.DISTANCE: QgsProcessingParameterDistance,
ProcessingAlgFactory.SINK: QgsProcessingParameterFeatureSink,
@@ -552,16 +595,23 @@ def dec(f):
ProcessingAlgFactory.LAYOUT: QgsProcessingParameterLayout,
ProcessingAlgFactory.LAYOUT_ITEM: QgsProcessingParameterLayoutItem,
ProcessingAlgFactory.COLOR: QgsProcessingParameterColor,
- ProcessingAlgFactory.DATETIME: partial(QgsProcessingParameterDateTime, type=QgsProcessingParameterDateTime.Type.DateTime),
- ProcessingAlgFactory.DATE: partial(QgsProcessingParameterDateTime, type=QgsProcessingParameterDateTime.Type.Date),
- ProcessingAlgFactory.TIME: partial(QgsProcessingParameterDateTime, type=QgsProcessingParameterDateTime.Type.Time),
+ ProcessingAlgFactory.DATETIME: partial(
+ QgsProcessingParameterDateTime,
+ type=QgsProcessingParameterDateTime.Type.DateTime,
+ ),
+ ProcessingAlgFactory.DATE: partial(
+ QgsProcessingParameterDateTime, type=QgsProcessingParameterDateTime.Type.Date
+ ),
+ ProcessingAlgFactory.TIME: partial(
+ QgsProcessingParameterDateTime, type=QgsProcessingParameterDateTime.Type.Time
+ ),
ProcessingAlgFactory.MAP_THEME: QgsProcessingParameterMapTheme,
ProcessingAlgFactory.PROVIDER_CONNECTION: QgsProcessingParameterProviderConnection,
ProcessingAlgFactory.DATABASE_SCHEMA: QgsProcessingParameterDatabaseSchema,
ProcessingAlgFactory.DATABASE_TABLE: QgsProcessingParameterDatabaseTable,
ProcessingAlgFactory.COORDINATE_OPERATION: QgsProcessingParameterCoordinateOperation,
ProcessingAlgFactory.POINTCLOUD_LAYER: QgsProcessingParameterPointCloudLayer,
- ProcessingAlgFactory.ANNOTATION_LAYER: QgsProcessingParameterAnnotationLayer
+ ProcessingAlgFactory.ANNOTATION_LAYER: QgsProcessingParameterAnnotationLayer,
}
output_type_mapping = {
@@ -575,11 +625,23 @@ def dec(f):
ProcessingAlgFactory.FILE: partial(_make_output, cls=QgsProcessingOutputFile),
ProcessingAlgFactory.FOLDER: partial(_make_output, cls=QgsProcessingOutputFolder),
ProcessingAlgFactory.HTML: partial(_make_output, cls=QgsProcessingOutputHtml),
- ProcessingAlgFactory.LAYERDEF: partial(_make_output, cls=QgsProcessingOutputLayerDefinition),
- ProcessingAlgFactory.MAPLAYER: partial(_make_output, cls=QgsProcessingOutputMapLayer),
- ProcessingAlgFactory.MULTILAYER: partial(_make_output, cls=QgsProcessingOutputMultipleLayers),
- ProcessingAlgFactory.RASTER_LAYER: partial(_make_output, cls=QgsProcessingOutputRasterLayer),
- ProcessingAlgFactory.VECTOR_LAYER: partial(_make_output, cls=QgsProcessingOutputVectorLayer),
- ProcessingAlgFactory.POINTCLOUD_LAYER: partial(_make_output, cls=QgsProcessingOutputPointCloudLayer),
+ ProcessingAlgFactory.LAYERDEF: partial(
+ _make_output, cls=QgsProcessingOutputLayerDefinition
+ ),
+ ProcessingAlgFactory.MAPLAYER: partial(
+ _make_output, cls=QgsProcessingOutputMapLayer
+ ),
+ ProcessingAlgFactory.MULTILAYER: partial(
+ _make_output, cls=QgsProcessingOutputMultipleLayers
+ ),
+ ProcessingAlgFactory.RASTER_LAYER: partial(
+ _make_output, cls=QgsProcessingOutputRasterLayer
+ ),
+ ProcessingAlgFactory.VECTOR_LAYER: partial(
+ _make_output, cls=QgsProcessingOutputVectorLayer
+ ),
+ ProcessingAlgFactory.POINTCLOUD_LAYER: partial(
+ _make_output, cls=QgsProcessingOutputPointCloudLayer
+ ),
ProcessingAlgFactory.BOOL: partial(_make_output, cls=QgsProcessingOutputBoolean),
}
diff --git a/python/pyplugin_installer/__init__.py b/python/pyplugin_installer/__init__.py
index 7399b0baf4bc..b355ca4ee264 100644
--- a/python/pyplugin_installer/__init__.py
+++ b/python/pyplugin_installer/__init__.py
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-
"""
***************************************************************************
__init__.py
@@ -22,9 +20,9 @@
***************************************************************************/
"""
-__author__ = 'Borys Jurgiel'
-__date__ = 'May 2013'
-__copyright__ = '(C) 2013, Borys Jurgiel'
+__author__ = "Borys Jurgiel"
+__date__ = "May 2013"
+__copyright__ = "(C) 2013, Borys Jurgiel"
# import functions for easier access
diff --git a/python/pyplugin_installer/installer.py b/python/pyplugin_installer/installer.py
index c7523b4d8127..e9a64bb2fc57 100644
--- a/python/pyplugin_installer/installer.py
+++ b/python/pyplugin_installer/installer.py
@@ -1,4 +1,3 @@
-# -*- coding:utf-8 -*-
"""
/***************************************************************************
Plugin Installer module
@@ -38,11 +37,19 @@
QMessageBox,
QLabel,
QVBoxLayout,
- QPushButton
+ QPushButton,
)
from qgis.PyQt.QtNetwork import QNetworkRequest
-from qgis.core import Qgis, QgsApplication, QgsMessageLog, QgsNetworkAccessManager, QgsSettings, QgsSettingsTree, QgsNetworkRequestParameters
+from qgis.core import (
+ Qgis,
+ QgsApplication,
+ QgsMessageLog,
+ QgsNetworkAccessManager,
+ QgsSettings,
+ QgsSettingsTree,
+ QgsNetworkRequestParameters,
+)
from qgis.gui import QgsMessageBar, QgsPasswordLineEdit, QgsHelp
from qgis.utils import (
iface,
@@ -53,10 +60,9 @@
updateAvailablePlugins,
plugins_metadata_parser,
isPluginLoaded,
- HOME_PLUGIN_PATH
+ HOME_PLUGIN_PATH,
)
-from .installer_data import (repositories, plugins, officialRepo,
- reposGroup, removeDir)
+from .installer_data import repositories, plugins, officialRepo, reposGroup, removeDir
from .qgsplugininstallerinstallingdialog import QgsPluginInstallerInstallingDialog
from .qgsplugininstallerpluginerrordialog import QgsPluginInstallerPluginErrorDialog
from .qgsplugininstallerfetchingdialog import QgsPluginInstallerFetchingDialog
@@ -77,12 +83,11 @@ def initPluginInstaller():
# -------------------------------------------------------- #
class QgsPluginInstaller(QObject):
-
- """ The main class for managing the plugin installer stuff"""
+ """The main class for managing the plugin installer stuff"""
# ----------------------------------------- #
def __init__(self):
- """ Initialize data objects, starts fetching if appropriate, and warn about/removes obsolete plugins """
+ """Initialize data objects, starts fetching if appropriate, and warn about/removes obsolete plugins"""
QObject.__init__(self) # initialize QObject in order to to use self.tr()
repositories.load()
@@ -90,7 +95,11 @@ def __init__(self):
self.message_bar_widget = None
- if repositories.checkingOnStart() and repositories.timeForChecking() and repositories.allEnabled():
+ if (
+ repositories.checkingOnStart()
+ and repositories.timeForChecking()
+ and repositories.allEnabled()
+ ):
# start fetching repositories
repositories.checkingDone.connect(self.checkingDone)
for key in repositories.allEnabled():
@@ -106,27 +115,43 @@ def __init__(self):
msg = QMessageBox()
msg.setIcon(QMessageBox.Icon.Warning)
msg.setWindowTitle(self.tr("QGIS Python Plugin Installer"))
- msg.addButton(self.tr("Uninstall (recommended)"), QMessageBox.ButtonRole.AcceptRole)
- msg.addButton(self.tr("I will uninstall it later"), QMessageBox.ButtonRole.RejectRole)
- msg.setText("%s %s %s" % (self.tr("Obsolete plugin:"), plugin["name"], self.tr("QGIS has detected an obsolete plugin that masks its more recent version shipped with this copy of QGIS. This is likely due to files associated with a previous installation of QGIS. Do you want to remove the old plugin right now and unmask the more recent version?")))
+ msg.addButton(
+ self.tr("Uninstall (recommended)"), QMessageBox.ButtonRole.AcceptRole
+ )
+ msg.addButton(
+ self.tr("I will uninstall it later"), QMessageBox.ButtonRole.RejectRole
+ )
+ msg.setText(
+ "{} {} {}".format(
+ self.tr("Obsolete plugin:"),
+ plugin["name"],
+ self.tr(
+ "QGIS has detected an obsolete plugin that masks its more recent version shipped with this copy of QGIS. This is likely due to files associated with a previous installation of QGIS. Do you want to remove the old plugin right now and unmask the more recent version?"
+ ),
+ )
+ )
msg.exec()
if not msg.result():
settings = QgsSettings()
- plugin_is_active = settings.value("/PythonPlugins/" + key, False, type=bool)
+ plugin_is_active = settings.value(
+ "/PythonPlugins/" + key, False, type=bool
+ )
# uninstall the update, update utils and reload if enabled
self.uninstallPlugin(key, quiet=True)
updateAvailablePlugins()
if plugin_is_active:
- settings.setValue("/PythonPlugins/watchDogTimestamp/" + key,
- QDateTime.currentDateTime().toSecsSinceEpoch())
+ settings.setValue(
+ "/PythonPlugins/watchDogTimestamp/" + key,
+ QDateTime.currentDateTime().toSecsSinceEpoch(),
+ )
loadPlugin(key)
startPlugin(key)
settings.remove("/PythonPlugins/watchDogTimestamp/" + key)
# ----------------------------------------- #
def fetchAvailablePlugins(self, reloadMode):
- """ Fetch plugins from all enabled repositories."""
+ """Fetch plugins from all enabled repositories."""
""" reloadMode = true: Fully refresh data from QgsSettings to mRepositories """
""" reloadMode = false: Fetch unready repositories only """
if reloadMode:
@@ -135,7 +160,9 @@ def fetchAvailablePlugins(self, reloadMode):
plugins.getAllInstalled()
for key in repositories.allEnabled():
- if reloadMode or repositories.all()[key]["state"] == 3: # if state = 3 (error or not fetched yet), try to fetch once again
+ if (
+ reloadMode or repositories.all()[key]["state"] == 3
+ ): # if state = 3 (error or not fetched yet), try to fetch once again
repositories.requestFetching(key, force_reload=reloadMode)
if repositories.fetchingInProgress():
@@ -146,19 +173,34 @@ def fetchAvailablePlugins(self, reloadMode):
repositories.killConnection(key)
# display error messages for every unavailable repository, unless Shift pressed nor all repositories are unavailable
- keepQuiet = QgsApplication.keyboardModifiers() == Qt.KeyboardModifiers(Qt.KeyboardModifier.ShiftModifier)
- if repositories.allUnavailable() and repositories.allUnavailable() != repositories.allEnabled():
+ keepQuiet = QgsApplication.keyboardModifiers() == Qt.KeyboardModifiers(
+ Qt.KeyboardModifier.ShiftModifier
+ )
+ if (
+ repositories.allUnavailable()
+ and repositories.allUnavailable() != repositories.allEnabled()
+ ):
for key in repositories.allUnavailable():
if not keepQuiet:
- QMessageBox.warning(iface.mainWindow(), self.tr("QGIS Python Plugin Installer"), self.tr("Error reading repository:") + " " + key + "\n\n" + repositories.all()[key]["error"])
- if QgsApplication.keyboardModifiers() == Qt.KeyboardModifiers(Qt.KeyboardModifier.ShiftModifier):
+ QMessageBox.warning(
+ iface.mainWindow(),
+ self.tr("QGIS Python Plugin Installer"),
+ self.tr("Error reading repository:")
+ + " "
+ + key
+ + "\n\n"
+ + repositories.all()[key]["error"],
+ )
+ if QgsApplication.keyboardModifiers() == Qt.KeyboardModifiers(
+ Qt.KeyboardModifier.ShiftModifier
+ ):
keepQuiet = True
# finally, rebuild plugins from the caches
plugins.rebuild()
# ----------------------------------------- #
def checkingDone(self):
- """ Remove the "Looking for new plugins..." label and display a notification instead if any updates available """
+ """Remove the "Looking for new plugins..." label and display a notification instead if any updates available"""
# rebuild plugins cache
plugins.rebuild()
@@ -176,104 +218,120 @@ def checkingDone(self):
if len(updatable_plugin_names) >= 2:
status = self.tr("Multiple plugin updates are available")
else:
- status = self.tr("An update to the {} plugin is available").format(updatable_plugin_names[0])
+ status = self.tr("An update to the {} plugin is available").format(
+ updatable_plugin_names[0]
+ )
QgsMessageLog.logMessage(
- "Plugin update(s) available : {}".format(','.join(updatable_plugin_names)), self.tr("Plugins"))
+ "Plugin update(s) available : {}".format(",".join(updatable_plugin_names)),
+ self.tr("Plugins"),
+ )
bar = iface.messageBar()
- self.message_bar_widget = bar.createMessage('', status)
+ self.message_bar_widget = bar.createMessage("", status)
update_button = QPushButton(self.tr("Install Updates…"))
tab_index = 3 # PLUGMAN_TAB_UPGRADEABLE
- update_button.pressed.connect(partial(self.showPluginManagerWhenReady, tab_index))
+ update_button.pressed.connect(
+ partial(self.showPluginManagerWhenReady, tab_index)
+ )
self.message_bar_widget.layout().addWidget(update_button)
bar.pushWidget(self.message_bar_widget, Qgis.MessageLevel.Info)
# ----------------------------------------- #
def exportRepositoriesToManager(self):
- """ Update manager's repository tree widget with current data """
+ """Update manager's repository tree widget with current data"""
iface.pluginManagerInterface().clearRepositoryList()
for key in repositories.all():
url = repositories.all()[key]["url"] + repositories.urlParams()
if repositories.inspectionFilter():
- enabled = (key == repositories.inspectionFilter())
+ enabled = key == repositories.inspectionFilter()
else:
enabled = repositories.all()[key]["enabled"]
- iface.pluginManagerInterface().addToRepositoryList({
- "name": key,
- "url": url,
- "enabled": enabled and "true" or "false",
- "valid": repositories.all()[key]["valid"] and "true" or "false",
- "state": str(repositories.all()[key]["state"]),
- "error": repositories.all()[key]["error"],
- "inspection_filter": repositories.inspectionFilter() and "true" or "false"
- })
+ iface.pluginManagerInterface().addToRepositoryList(
+ {
+ "name": key,
+ "url": url,
+ "enabled": enabled and "true" or "false",
+ "valid": repositories.all()[key]["valid"] and "true" or "false",
+ "state": str(repositories.all()[key]["state"]),
+ "error": repositories.all()[key]["error"],
+ "inspection_filter": repositories.inspectionFilter()
+ and "true"
+ or "false",
+ }
+ )
# ----------------------------------------- #
def exportPluginsToManager(self):
- """ Insert plugins metadata to QgsMetadataRegistry """
+ """Insert plugins metadata to QgsMetadataRegistry"""
iface.pluginManagerInterface().clearPythonPluginMetadata()
for key in plugins.all():
plugin = plugins.all()[key]
- iface.pluginManagerInterface().addPluginMetadata({
- "id": key,
- "plugin_id": plugin["plugin_id"] or "",
- "name": plugin["name"],
- "description": plugin["description"],
- "about": plugin["about"],
- "category": plugin["category"],
- "tags": plugin["tags"],
- "changelog": plugin["changelog"],
- "author_name": plugin["author_name"],
- "author_email": plugin["author_email"],
- "homepage": plugin["homepage"],
- "tracker": plugin["tracker"],
- "code_repository": plugin["code_repository"],
- "version_installed": plugin["version_installed"],
- "library": plugin["library"],
- "icon": plugin["icon"],
- "readonly": plugin["readonly"] and "true" or "false",
- "installed": plugin["installed"] and "true" or "false",
- "available": plugin["available"] and "true" or "false",
- "status": plugin["status"],
- "status_exp": plugin["status_exp"],
- "error": plugin["error"],
- "error_details": plugin["error_details"],
- "create_date": plugin["create_date"],
- "update_date": plugin["update_date"],
- "create_date_stable": plugin["create_date_stable"],
- "update_date_stable": plugin["update_date_stable"],
- "create_date_experimental": plugin["create_date_experimental"],
- "update_date_experimental": plugin["update_date_experimental"],
- "experimental": plugin["experimental"] and "true" or "false",
- "deprecated": plugin["deprecated"] and "true" or "false",
- "trusted": plugin["trusted"] and "true" or "false",
- "version_available": plugin["version_available"],
- "version_available_stable": plugin["version_available_stable"] or "",
- "version_available_experimental": plugin["version_available_experimental"] or "",
- "zip_repository": plugin["zip_repository"],
- "download_url": plugin["download_url"],
- "download_url_stable": plugin["download_url_stable"],
- "download_url_experimental": plugin["download_url_experimental"],
- "filename": plugin["filename"],
- "downloads": plugin["downloads"],
- "average_vote": plugin["average_vote"],
- "rating_votes": plugin["rating_votes"],
- "plugin_dependencies": plugin.get("plugin_dependencies", None),
- "pythonic": "true"
- })
+ iface.pluginManagerInterface().addPluginMetadata(
+ {
+ "id": key,
+ "plugin_id": plugin["plugin_id"] or "",
+ "name": plugin["name"],
+ "description": plugin["description"],
+ "about": plugin["about"],
+ "category": plugin["category"],
+ "tags": plugin["tags"],
+ "changelog": plugin["changelog"],
+ "author_name": plugin["author_name"],
+ "author_email": plugin["author_email"],
+ "homepage": plugin["homepage"],
+ "tracker": plugin["tracker"],
+ "code_repository": plugin["code_repository"],
+ "version_installed": plugin["version_installed"],
+ "library": plugin["library"],
+ "icon": plugin["icon"],
+ "readonly": plugin["readonly"] and "true" or "false",
+ "installed": plugin["installed"] and "true" or "false",
+ "available": plugin["available"] and "true" or "false",
+ "status": plugin["status"],
+ "status_exp": plugin["status_exp"],
+ "error": plugin["error"],
+ "error_details": plugin["error_details"],
+ "create_date": plugin["create_date"],
+ "update_date": plugin["update_date"],
+ "create_date_stable": plugin["create_date_stable"],
+ "update_date_stable": plugin["update_date_stable"],
+ "create_date_experimental": plugin["create_date_experimental"],
+ "update_date_experimental": plugin["update_date_experimental"],
+ "experimental": plugin["experimental"] and "true" or "false",
+ "deprecated": plugin["deprecated"] and "true" or "false",
+ "trusted": plugin["trusted"] and "true" or "false",
+ "version_available": plugin["version_available"],
+ "version_available_stable": plugin["version_available_stable"]
+ or "",
+ "version_available_experimental": plugin[
+ "version_available_experimental"
+ ]
+ or "",
+ "zip_repository": plugin["zip_repository"],
+ "download_url": plugin["download_url"],
+ "download_url_stable": plugin["download_url_stable"],
+ "download_url_experimental": plugin["download_url_experimental"],
+ "filename": plugin["filename"],
+ "downloads": plugin["downloads"],
+ "average_vote": plugin["average_vote"],
+ "rating_votes": plugin["rating_votes"],
+ "plugin_dependencies": plugin.get("plugin_dependencies", None),
+ "pythonic": "true",
+ }
+ )
iface.pluginManagerInterface().reloadModel()
# ----------------------------------------- #
def reloadAndExportData(self):
- """ Reload All repositories and export data to the Plugin Manager """
+ """Reload All repositories and export data to the Plugin Manager"""
self.fetchAvailablePlugins(reloadMode=True)
self.exportRepositoriesToManager()
self.exportPluginsToManager()
# ----------------------------------------- #
- def showPluginManagerWhenReady(self, * params):
- """ Open the plugin manager window. If fetching is still in progress, it shows the progress window first """
+ def showPluginManagerWhenReady(self, *params):
+ """Open the plugin manager window. If fetching is still in progress, it shows the progress window first"""
""" Optionally pass the index of tab to be opened in params """
if self.message_bar_widget:
if not sip.isdeleted(self.message_bar_widget):
@@ -294,34 +352,47 @@ def showPluginManagerWhenReady(self, * params):
# ----------------------------------------- #
def onManagerClose(self):
- """ Call this method when closing manager window - it resets last-use-dependent values. """
+ """Call this method when closing manager window - it resets last-use-dependent values."""
plugins.updateSeenPluginsList()
repositories.saveCheckingOnStartLastDate()
# ----------------------------------------- #
def exportSettingsGroup(self):
- """ Return QgsSettings settingsGroup value """
+ """Return QgsSettings settingsGroup value"""
# todo QGIS 4 remove
return "plugin-manager"
# ----------------------------------------- #
def upgradeAllUpgradeable(self):
- """ Reinstall all upgradeable plugins """
+ """Reinstall all upgradeable plugins"""
for key in plugins.allUpgradeable():
self.installPlugin(key, quiet=True)
# ----------------------------------------- #
def installPlugin(self, key, quiet=False, stable=True):
- """ Install given plugin """
+ """Install given plugin"""
error = False
- status_key = 'status' if stable else 'status_exp'
- infoString = ('', '')
+ status_key = "status" if stable else "status_exp"
+ infoString = ("", "")
plugin = plugins.all()[key]
previousStatus = plugin[status_key]
if not plugin:
return
- if plugin[status_key] == "newer" and not plugin["error"]: # ask for confirmation if user downgrades an usable plugin
- if QMessageBox.warning(iface.mainWindow(), self.tr("QGIS Python Plugin Installer"), self.tr("Are you sure you want to downgrade the plugin to the latest available version? The installed one is newer!"), QMessageBox.StandardButton.Yes, QMessageBox.StandardButton.No) == QMessageBox.StandardButton.No:
+ if (
+ plugin[status_key] == "newer" and not plugin["error"]
+ ): # ask for confirmation if user downgrades an usable plugin
+ if (
+ QMessageBox.warning(
+ iface.mainWindow(),
+ self.tr("QGIS Python Plugin Installer"),
+ self.tr(
+ "Are you sure you want to downgrade the plugin to the latest available version? The installed one is newer!"
+ ),
+ QMessageBox.StandardButton.Yes,
+ QMessageBox.StandardButton.No,
+ )
+ == QMessageBox.StandardButton.No
+ ):
return
# if plugin is active, unload it before update, see https://github.com/qgis/QGIS/issues/54968
@@ -329,7 +400,9 @@ def installPlugin(self, key, quiet=False, stable=True):
if pluginWasLoaded:
unloadPlugin(plugin["id"])
- dlg = QgsPluginInstallerInstallingDialog(iface.mainWindow(), plugin, stable=stable)
+ dlg = QgsPluginInstallerInstallingDialog(
+ iface.mainWindow(), plugin, stable=stable
+ )
dlg.exec()
plugin_path = HOME_PLUGIN_PATH + "/" + key
@@ -344,11 +417,13 @@ def installPlugin(self, key, quiet=False, stable=True):
infoString = (
self.tr("Plugin has disappeared"),
self.tr(
- "The plugin seems to have been installed but it's not possible to know where. The directory \"{}\" "
+ 'The plugin seems to have been installed but it\'s not possible to know where. The directory "{}" '
"has not been found. Probably the plugin package contained a wrong named directory.\nPlease search "
"the list of installed plugins. You should find the plugin there, but it's not possible to "
"determine which of them it is and it's also not possible to inform you about available updates. "
- "Please contact the plugin author and submit this issue.").format(plugin_path))
+ "Please contact the plugin author and submit this issue."
+ ).format(plugin_path),
+ )
with OverrideCursor(Qt.CursorShape.WaitCursor):
plugins.getAllInstalled()
plugins.rebuild()
@@ -375,7 +450,9 @@ def installPlugin(self, key, quiet=False, stable=True):
loadPlugin(plugin["id"])
startPlugin(plugin["id"])
else:
- unloadPlugin(key) # Just for a case. Will exit quietly if really not loaded
+ unloadPlugin(
+ key
+ ) # Just for a case. Will exit quietly if really not loaded
loadPlugin(key)
if quiet:
infoString = (None, None)
@@ -383,10 +460,14 @@ def installPlugin(self, key, quiet=False, stable=True):
else:
QApplication.restoreOverrideCursor()
if plugin["error"] == "incompatible":
- message = self.tr("The plugin is not compatible with this version of QGIS. It's designed for QGIS versions:")
+ message = self.tr(
+ "The plugin is not compatible with this version of QGIS. It's designed for QGIS versions:"
+ )
message += " " + plugin["error_details"] + " "
elif plugin["error"] == "dependent":
- message = self.tr("The plugin depends on some components missing on your system. You need to install the following Python module in order to enable it:")
+ message = self.tr(
+ "The plugin depends on some components missing on your system. You need to install the following Python module in order to enable it:"
+ )
message += " " + plugin["error_details"] + " "
else:
message = self.tr("The plugin is broken. Python said:")
@@ -425,7 +506,7 @@ def installPlugin(self, key, quiet=False, stable=True):
# ----------------------------------------- #
def uninstallPlugin(self, key, quiet=False):
- """ Uninstall given plugin """
+ """Uninstall given plugin"""
if key in plugins.all():
plugin = plugins.all()[key]
else:
@@ -433,10 +514,30 @@ def uninstallPlugin(self, key, quiet=False):
if not plugin:
return
if not quiet:
- warning = self.tr("Are you sure you want to uninstall the following plugin?") + "\n(" + plugin["name"] + ")"
- if plugin["status"] == "orphan" and plugin["status_exp"] == "orphan" and not plugin["error"]:
- warning += "\n\n" + self.tr("Warning: this plugin isn't available in any accessible repository!")
- if QMessageBox.warning(iface.mainWindow(), self.tr("QGIS Python Plugin Installer"), warning, QMessageBox.StandardButton.Yes, QMessageBox.StandardButton.No) == QMessageBox.StandardButton.No:
+ warning = (
+ self.tr("Are you sure you want to uninstall the following plugin?")
+ + "\n("
+ + plugin["name"]
+ + ")"
+ )
+ if (
+ plugin["status"] == "orphan"
+ and plugin["status_exp"] == "orphan"
+ and not plugin["error"]
+ ):
+ warning += "\n\n" + self.tr(
+ "Warning: this plugin isn't available in any accessible repository!"
+ )
+ if (
+ QMessageBox.warning(
+ iface.mainWindow(),
+ self.tr("QGIS Python Plugin Installer"),
+ warning,
+ QMessageBox.StandardButton.Yes,
+ QMessageBox.StandardButton.No,
+ )
+ == QMessageBox.StandardButton.No
+ ):
return
# unload the plugin
QApplication.setOverrideCursor(Qt.CursorShape.WaitCursor)
@@ -448,7 +549,7 @@ def uninstallPlugin(self, key, quiet=False):
result = removeDir(pluginDir)
if result:
QApplication.restoreOverrideCursor()
- msg = "%s: %s" % (self.tr("Plugin uninstall failed"), result)
+ msg = "{}: {}".format(self.tr("Plugin uninstall failed"), result)
iface.pluginManagerInterface().pushMessage(msg, Qgis.MessageLevel.Critical)
else:
# safe remove
@@ -474,14 +575,16 @@ def uninstallPlugin(self, key, quiet=False):
plugins.rebuild()
self.exportPluginsToManager()
QApplication.restoreOverrideCursor()
- iface.pluginManagerInterface().pushMessage(self.tr("Plugin uninstalled successfully"), Qgis.MessageLevel.Success)
+ iface.pluginManagerInterface().pushMessage(
+ self.tr("Plugin uninstalled successfully"), Qgis.MessageLevel.Success
+ )
settings = QgsSettings()
settings.remove("/PythonPlugins/" + key)
# ----------------------------------------- #
def addRepository(self):
- """ add new repository connection """
+ """add new repository connection"""
dlg = QgsPluginInstallerRepositoryDialog(iface.mainWindow())
dlg.editParams.setText(repositories.urlParams())
dlg.checkBoxEnabled.setCheckState(Qt.CheckState.Checked)
@@ -489,7 +592,10 @@ def addRepository(self):
return
for i in list(repositories.all().values()):
if dlg.editURL.text().strip() == i["url"]:
- iface.pluginManagerInterface().pushMessage(self.tr("Unable to add another repository with the same URL!"), Qgis.MessageLevel.Warning)
+ iface.pluginManagerInterface().pushMessage(
+ self.tr("Unable to add another repository with the same URL!"),
+ Qgis.MessageLevel.Warning,
+ )
return
settings = QgsSettings()
settings.beginGroup(reposGroup)
@@ -500,14 +606,16 @@ def addRepository(self):
# add to settings
settings.setValue(reposName + "/url", reposURL)
settings.setValue(reposName + "/authcfg", dlg.editAuthCfg.text().strip())
- settings.setValue(reposName + "/enabled", bool(dlg.checkBoxEnabled.checkState()))
+ settings.setValue(
+ reposName + "/enabled", bool(dlg.checkBoxEnabled.checkState())
+ )
# refresh lists and populate widgets
plugins.removeRepository(reposName)
self.reloadAndExportData()
# ----------------------------------------- #
def editRepository(self, reposName):
- """ edit repository connection """
+ """edit repository connection"""
if not reposName:
return
checkState = {False: Qt.CheckState.Unchecked, True: Qt.CheckState.Checked}
@@ -516,19 +624,31 @@ def editRepository(self, reposName):
dlg.editURL.setText(repositories.all()[reposName]["url"])
dlg.editAuthCfg.setText(repositories.all()[reposName]["authcfg"])
dlg.editParams.setText(repositories.urlParams())
- dlg.checkBoxEnabled.setCheckState(checkState[repositories.all()[reposName]["enabled"]])
+ dlg.checkBoxEnabled.setCheckState(
+ checkState[repositories.all()[reposName]["enabled"]]
+ )
if repositories.all()[reposName]["valid"]:
dlg.checkBoxEnabled.setEnabled(True)
dlg.labelInfo.setText("")
else:
dlg.checkBoxEnabled.setEnabled(False)
- dlg.labelInfo.setText(self.tr("This repository is blocked due to incompatibility with your QGIS version"))
+ dlg.labelInfo.setText(
+ self.tr(
+ "This repository is blocked due to incompatibility with your QGIS version"
+ )
+ )
dlg.labelInfo.setFrameShape(QFrame.Shape.Box)
if not dlg.exec():
return # nothing to do if canceled
for i in list(repositories.all().values()):
- if dlg.editURL.text().strip() == i["url"] and dlg.editURL.text().strip() != repositories.all()[reposName]["url"]:
- iface.pluginManagerInterface().pushMessage(self.tr("Unable to add another repository with the same URL!"), Qgis.MessageLevel.Warning)
+ if (
+ dlg.editURL.text().strip() == i["url"]
+ and dlg.editURL.text().strip() != repositories.all()[reposName]["url"]
+ ):
+ iface.pluginManagerInterface().pushMessage(
+ self.tr("Unable to add another repository with the same URL!"),
+ Qgis.MessageLevel.Warning,
+ )
return
# delete old repo from QgsSettings and create new one
settings = QgsSettings()
@@ -542,7 +662,11 @@ def editRepository(self, reposName):
settings.setValue(newName + "/enabled", bool(dlg.checkBoxEnabled.checkState()))
if dlg.editAuthCfg.text().strip() != repositories.all()[reposName]["authcfg"]:
repositories.all()[reposName]["authcfg"] = dlg.editAuthCfg.text().strip()
- if dlg.editURL.text().strip() == repositories.all()[reposName]["url"] and dlg.checkBoxEnabled.checkState() == checkState[repositories.all()[reposName]["enabled"]]:
+ if (
+ dlg.editURL.text().strip() == repositories.all()[reposName]["url"]
+ and dlg.checkBoxEnabled.checkState()
+ == checkState[repositories.all()[reposName]["enabled"]]
+ ):
repositories.rename(reposName, newName)
self.exportRepositoriesToManager()
return # nothing else to do if only repository name was changed
@@ -551,16 +675,34 @@ def editRepository(self, reposName):
# ----------------------------------------- #
def deleteRepository(self, reposName: str):
- """ delete repository connection """
+ """delete repository connection"""
if not reposName:
return
settings = QgsSettings()
settings.beginGroup(reposGroup)
if settings.value(reposName + "/url", "", type=str) == officialRepo[1]:
- iface.pluginManagerInterface().pushMessage(self.tr("You can't remove the official QGIS Plugin Repository. You can disable it if needed."), Qgis.MessageLevel.Warning)
+ iface.pluginManagerInterface().pushMessage(
+ self.tr(
+ "You can't remove the official QGIS Plugin Repository. You can disable it if needed."
+ ),
+ Qgis.MessageLevel.Warning,
+ )
return
- warning = self.tr("Are you sure you want to remove the following repository?") + "\n" + reposName
- if QMessageBox.warning(iface.mainWindow(), self.tr("QGIS Python Plugin Installer"), warning, QMessageBox.StandardButton.Yes, QMessageBox.StandardButton.No) == QMessageBox.StandardButton.No:
+ warning = (
+ self.tr("Are you sure you want to remove the following repository?")
+ + "\n"
+ + reposName
+ )
+ if (
+ QMessageBox.warning(
+ iface.mainWindow(),
+ self.tr("QGIS Python Plugin Installer"),
+ warning,
+ QMessageBox.StandardButton.Yes,
+ QMessageBox.StandardButton.No,
+ )
+ == QMessageBox.StandardButton.No
+ ):
return
# delete from the settings, refresh data and repopulate all the widgets
settings.remove(reposName)
@@ -570,23 +712,39 @@ def deleteRepository(self, reposName: str):
# ----------------------------------------- #
def setRepositoryInspectionFilter(self, reposName=None):
- """ temporarily block another repositories to fetch only one for inspection """
+ """temporarily block another repositories to fetch only one for inspection"""
repositories.setInspectionFilter(reposName)
self.reloadAndExportData()
# ----------------------------------------- #
def sendVote(self, plugin_id, vote):
- """ send vote via the RPC """
+ """send vote via the RPC"""
if not plugin_id or not vote:
return False
url = "https://plugins.qgis.org/plugins/RPC2/"
- params = {"id": "djangorpc", "method": "plugin.vote", "params": [str(plugin_id), str(vote)]}
+ params = {
+ "id": "djangorpc",
+ "method": "plugin.vote",
+ "params": [str(plugin_id), str(vote)],
+ }
req = QNetworkRequest(QUrl(url))
- req.setAttribute(QNetworkRequest.Attribute(QgsNetworkRequestParameters.RequestAttributes.AttributeInitiatorClass), "QgsPluginInstaller")
- req.setAttribute(QNetworkRequest.Attribute(QgsNetworkRequestParameters.RequestAttributes.AttributeInitiatorRequestId), "sendVote")
+ req.setAttribute(
+ QNetworkRequest.Attribute(
+ QgsNetworkRequestParameters.RequestAttributes.AttributeInitiatorClass
+ ),
+ "QgsPluginInstaller",
+ )
+ req.setAttribute(
+ QNetworkRequest.Attribute(
+ QgsNetworkRequestParameters.RequestAttributes.AttributeInitiatorRequestId
+ ),
+ "sendVote",
+ )
req.setRawHeader(b"Content-Type", b"application/json")
- reply = QgsNetworkAccessManager.instance().blockingPost(req, bytes(json.dumps(params), "utf-8"))
+ reply = QgsNetworkAccessManager.instance().blockingPost(
+ req, bytes(json.dumps(params), "utf-8")
+ )
if reply.attribute(QNetworkRequest.Attribute.HttpStatusCodeAttribute) == 200:
return True
else:
@@ -596,13 +754,17 @@ def installFromZipFile(self, filePath):
if not os.path.isfile(filePath):
return
- QgsSettingsTree.node("plugin-manager").childSetting("last-zip-directory").setValue(QFileInfo(filePath).absoluteDir().absolutePath())
+ QgsSettingsTree.node("plugin-manager").childSetting(
+ "last-zip-directory"
+ ).setValue(QFileInfo(filePath).absoluteDir().absolutePath())
pluginName = None
- with zipfile.ZipFile(filePath, 'r') as zf:
+ with zipfile.ZipFile(filePath, "r") as zf:
# search for metadata.txt. In case of multiple files, we can assume that
# the shortest path relates /metadata.txt
- metadatafiles = sorted(f for f in zf.namelist() if f.endswith('metadata.txt'))
+ metadatafiles = sorted(
+ f for f in zf.namelist() if f.endswith("metadata.txt")
+ )
if len(metadatafiles) > 0:
pluginName = os.path.split(metadatafiles[0])[0]
@@ -611,10 +773,18 @@ def installFromZipFile(self, filePath):
if not pluginName:
msg_box = QMessageBox()
msg_box.setIcon(QMessageBox.Icon.Warning)
- msg_box.setWindowTitle(self.tr("QGIS Python Install from ZIP Plugin Installer"))
- msg_box.setText(self.tr("The Zip file is not a valid QGIS python plugin. No root folder was found inside."))
+ msg_box.setWindowTitle(
+ self.tr("QGIS Python Install from ZIP Plugin Installer")
+ )
+ msg_box.setText(
+ self.tr(
+ "The Zip file is not a valid QGIS python plugin. No root folder was found inside."
+ )
+ )
msg_box.setStandardButtons(QMessageBox.StandardButton.Ok)
- more_info_btn = msg_box.addButton(self.tr("More Information"), QMessageBox.ButtonRole.HelpRole)
+ more_info_btn = msg_box.addButton(
+ self.tr("More Information"), QMessageBox.ButtonRole.HelpRole
+ )
msg_box.exec()
if msg_box.clickedButton() == more_info_btn:
QgsHelp.openHelp("plugins/plugins.html#the-install-from-zip-tab")
@@ -651,16 +821,24 @@ def installFromZipFile(self, filePath):
success = True
except Exception as e:
success = False
- if 'password' in str(e):
- infoString = self.tr('Aborted by user')
- if 'Bad password' in str(e):
- msg = self.tr('Wrong password. Please enter a correct password to the zip file.')
+ if "password" in str(e):
+ infoString = self.tr("Aborted by user")
+ if "Bad password" in str(e):
+ msg = self.tr(
+ "Wrong password. Please enter a correct password to the zip file."
+ )
else:
- msg = self.tr('The zip file is encrypted. Please enter password.')
+ msg = self.tr(
+ "The zip file is encrypted. Please enter password."
+ )
# Display a password dialog with QgsPasswordLineEdit
dlg = QDialog()
- dlg.setWindowTitle(self.tr('Enter password'))
- buttonBox = QDialogButtonBox(QDialogButtonBox.StandardButton.Ok | QDialogButtonBox.StandardButton.Cancel, Qt.Orientation.Horizontal)
+ dlg.setWindowTitle(self.tr("Enter password"))
+ buttonBox = QDialogButtonBox(
+ QDialogButtonBox.StandardButton.Ok
+ | QDialogButtonBox.StandardButton.Cancel,
+ Qt.Orientation.Horizontal,
+ )
buttonBox.rejected.connect(dlg.reject)
buttonBox.accepted.connect(dlg.accept)
lePass = QgsPasswordLineEdit()
@@ -672,7 +850,9 @@ def installFromZipFile(self, filePath):
keepTrying = dlg.exec()
password = lePass.text()
else:
- infoString = self.tr("Failed to unzip the plugin package\n{}.\nProbably it is broken".format(filePath))
+ infoString = self.tr(
+ f"Failed to unzip the plugin package\n{filePath}.\nProbably it is broken"
+ )
keepTrying = False
if success:
@@ -684,19 +864,25 @@ def installFromZipFile(self, filePath):
plugins.rebuild()
settings = QgsSettings()
- if settings.contains('/PythonPlugins/' + pluginName): # Plugin was available?
+ if settings.contains(
+ "/PythonPlugins/" + pluginName
+ ): # Plugin was available?
unloadPlugin(pluginName)
loadPlugin(pluginName)
- if settings.value('/PythonPlugins/' + pluginName, False, bool): # Plugin was also active?
+ if settings.value(
+ "/PythonPlugins/" + pluginName, False, bool
+ ): # Plugin was also active?
startPlugin(pluginName)
else:
if startPlugin(pluginName):
- settings.setValue('/PythonPlugins/' + pluginName, True)
+ settings.setValue("/PythonPlugins/" + pluginName, True)
self.exportPluginsToManager()
msg = "%s " % self.tr("Plugin installed successfully")
else:
- msg = "%s: %s" % (self.tr("Plugin installation failed"), infoString)
+ msg = "{}: {}".format(
+ self.tr("Plugin installation failed"), infoString
+ )
level = Qgis.MessageLevel.Success if success else Qgis.MessageLevel.Critical
iface.pluginManagerInterface().pushMessage(msg, level)
@@ -710,22 +896,47 @@ def processDependencies(self, plugin_id):
to_install, to_upgrade, not_found = find_dependencies(plugin_id)
if to_install or to_upgrade or not_found:
- dlg = QgsPluginDependenciesDialog(plugin_id, to_install, to_upgrade, not_found)
+ dlg = QgsPluginDependenciesDialog(
+ plugin_id, to_install, to_upgrade, not_found
+ )
if dlg.exec() == QgsPluginDependenciesDialog.Accepted:
actions = dlg.actions()
for dependency_plugin_id, action_data in actions.items():
try:
- self.installPlugin(dependency_plugin_id, stable=action_data['use_stable_version'])
- if action_data['action'] == 'install':
- iface.pluginManagerInterface().pushMessage(self.tr("Plugin dependency %s successfully installed") %
- dependency_plugin_id, Qgis.MessageLevel.Success)
+ self.installPlugin(
+ dependency_plugin_id,
+ stable=action_data["use_stable_version"],
+ )
+ if action_data["action"] == "install":
+ iface.pluginManagerInterface().pushMessage(
+ self.tr(
+ "Plugin dependency %s successfully installed"
+ )
+ % dependency_plugin_id,
+ Qgis.MessageLevel.Success,
+ )
else:
- iface.pluginManagerInterface().pushMessage(self.tr("Plugin dependency %s successfully upgraded") %
- dependency_plugin_id, Qgis.MessageLevel.Success)
+ iface.pluginManagerInterface().pushMessage(
+ self.tr(
+ "Plugin dependency %s successfully upgraded"
+ )
+ % dependency_plugin_id,
+ Qgis.MessageLevel.Success,
+ )
except Exception as ex:
- if action_data['action'] == 'install':
- iface.pluginManagerInterface().pushMessage(self.tr("Error installing plugin dependency %s : %s") %
- (dependency_plugin_id, ex), Qgis.MessageLevel.Warning)
+ if action_data["action"] == "install":
+ iface.pluginManagerInterface().pushMessage(
+ self.tr(
+ "Error installing plugin dependency %s : %s"
+ )
+ % (dependency_plugin_id, ex),
+ Qgis.MessageLevel.Warning,
+ )
else:
- iface.pluginManagerInterface().pushMessage(self.tr("Error upgrading plugin dependency %s : %s") %
- (dependency_plugin_id, ex), Qgis.MessageLevel.Warning)
+ iface.pluginManagerInterface().pushMessage(
+ self.tr(
+ "Error upgrading plugin dependency %s : %s"
+ )
+ % (dependency_plugin_id, ex),
+ Qgis.MessageLevel.Warning,
+ )
diff --git a/python/pyplugin_installer/installer_data.py b/python/pyplugin_installer/installer_data.py
index 089d10a872a5..81a830e554d7 100644
--- a/python/pyplugin_installer/installer_data.py
+++ b/python/pyplugin_installer/installer_data.py
@@ -1,4 +1,3 @@
-# -*- coding:utf-8 -*-
"""
/***************************************************************************
Plugin Installer module
@@ -22,15 +21,23 @@
* *
***************************************************************************/
"""
-from typing import (
- Dict,
- Optional,
- Any
-)
-from qgis.PyQt.QtCore import (pyqtSignal, QObject, QCoreApplication, QFile,
- QDir, QDirIterator, QDate, QUrl, QFileInfo,
- QLocale, QByteArray, QT_VERSION_STR)
+from typing import Dict, Optional, Any
+
+from qgis.PyQt.QtCore import (
+ pyqtSignal,
+ QObject,
+ QCoreApplication,
+ QFile,
+ QDir,
+ QDirIterator,
+ QDate,
+ QUrl,
+ QFileInfo,
+ QLocale,
+ QByteArray,
+ QT_VERSION_STR,
+)
from qgis.PyQt.QtXml import QDomDocument
from qgis.PyQt.QtNetwork import QNetworkRequest, QNetworkReply
from qgis.core import Qgis, QgsSettings, QgsSettingsTree, QgsNetworkRequestParameters
@@ -42,12 +49,13 @@
import qgis.utils
from qgis.core import QgsNetworkAccessManager, QgsApplication
from qgis.gui import QgsGui
-from qgis.utils import (
- iface,
- plugin_paths,
- HOME_PLUGIN_PATH
+from qgis.utils import iface, plugin_paths, HOME_PLUGIN_PATH
+from .version_compare import (
+ pyQgisVersion,
+ compareVersions,
+ normalizeVersion,
+ isCompatible,
)
-from .version_compare import pyQgisVersion, compareVersions, normalizeVersion, isCompatible
"""
@@ -111,14 +119,24 @@
reposGroup = "app/plugin_repositories"
-officialRepo = (QCoreApplication.translate("QgsPluginInstaller", "QGIS Official Plugin Repository"), "https://plugins.qgis.org/plugins/plugins.xml")
+officialRepo = (
+ QCoreApplication.translate("QgsPluginInstaller", "QGIS Official Plugin Repository"),
+ "https://plugins.qgis.org/plugins/plugins.xml",
+)
# --- common functions ------------------------------------------------------------------- #
def removeDir(path):
result = ""
if not QFile(path).exists():
- result = QCoreApplication.translate("QgsPluginInstaller", "Nothing to remove! Plugin directory doesn't exist:") + "\n" + path
+ result = (
+ QCoreApplication.translate(
+ "QgsPluginInstaller",
+ "Nothing to remove! Plugin directory doesn't exist:",
+ )
+ + "\n"
+ + path
+ )
elif QFile(path).remove(): # if it is only link, just remove it without resolving.
pass
else:
@@ -135,7 +153,17 @@ def removeDir(path):
if QDir().rmpath(item):
pass
if QFile(path).exists():
- result = QCoreApplication.translate("QgsPluginInstaller", "Failed to remove the directory:") + "\n" + path + "\n" + QCoreApplication.translate("QgsPluginInstaller", "Check permissions or remove it manually")
+ result = (
+ QCoreApplication.translate(
+ "QgsPluginInstaller", "Failed to remove the directory:"
+ )
+ + "\n"
+ + path
+ + "\n"
+ + QCoreApplication.translate(
+ "QgsPluginInstaller", "Check permissions or remove it manually"
+ )
+ )
# restore plugin directory if removed by QDir().rmpath()
pluginDir = HOME_PLUGIN_PATH
if not QDir(pluginDir).exists():
@@ -147,6 +175,7 @@ class Relay(QObject):
"""
Relay object for transmitting signals from QPHttp with adding the repoName information
"""
+
anythingChanged = pyqtSignal(str, int, int)
def __init__(self, key):
@@ -184,71 +213,97 @@ class Repositories(QObject):
def __init__(self):
QObject.__init__(self)
- self.mRepositories: Dict[str, Dict[str, Any]] = {}
- self.httpId = {} # {httpId : repoName}
+ self.mRepositories: dict[str, dict[str, Any]] = {}
+ self.httpId = {} # {httpId : repoName}
self.mInspectionFilter: Optional[str] = None
- def all(self) -> Dict[str, Dict[str, Any]]:
- """ return dict of all repositories """
+ def all(self) -> dict[str, dict[str, Any]]:
+ """return dict of all repositories"""
return self.mRepositories
- def allEnabled(self) -> Dict[str, Dict[str, Any]]:
- """ return dict of all enabled and valid repositories """
+ def allEnabled(self) -> dict[str, dict[str, Any]]:
+ """return dict of all enabled and valid repositories"""
if self.mInspectionFilter:
return {self.mInspectionFilter: self.mRepositories[self.mInspectionFilter]}
- return {k: v for k, v in self.mRepositories.items() if v['enabled'] and v['valid']}
+ return {
+ k: v for k, v in self.mRepositories.items() if v["enabled"] and v["valid"]
+ }
- def allUnavailable(self) -> Dict[str, Dict[str, Any]]:
- """ return dict of all unavailable repositories """
+ def allUnavailable(self) -> dict[str, dict[str, Any]]:
+ """return dict of all unavailable repositories"""
repos = {}
if self.mInspectionFilter:
# return the inspected repo if unavailable, otherwise empty dict
- if self.mRepositories[self.mInspectionFilter]["state"] == Repositories.STATE_UNAVAILABLE:
- repos[self.mInspectionFilter] = self.mRepositories[self.mInspectionFilter]
+ if (
+ self.mRepositories[self.mInspectionFilter]["state"]
+ == Repositories.STATE_UNAVAILABLE
+ ):
+ repos[self.mInspectionFilter] = self.mRepositories[
+ self.mInspectionFilter
+ ]
return repos
- return {k: v for k, v in self.mRepositories.items() if v['enabled'] and v['valid'] and v['state'] == Repositories.STATE_UNAVAILABLE}
+ return {
+ k: v
+ for k, v in self.mRepositories.items()
+ if v["enabled"]
+ and v["valid"]
+ and v["state"] == Repositories.STATE_UNAVAILABLE
+ }
def urlParams(self) -> str:
- """ return GET parameters to be added to every request """
+ """return GET parameters to be added to every request"""
# Strip down the point release segment from the version string
- return "?qgis={}".format(re.sub(r'\.\d*$', '', pyQgisVersion()))
+ return "?qgis={}".format(re.sub(r"\.\d*$", "", pyQgisVersion()))
def setRepositoryData(self, reposName: str, key: str, value):
- """ write data to the mRepositories dict """
+ """write data to the mRepositories dict"""
self.mRepositories[reposName][key] = value
def remove(self, reposName: str):
- """ remove given item from the mRepositories dict """
+ """remove given item from the mRepositories dict"""
del self.mRepositories[reposName]
def rename(self, oldName: str, newName: str):
- """ rename repository key """
+ """rename repository key"""
if oldName == newName:
return
self.mRepositories[newName] = self.mRepositories[oldName]
del self.mRepositories[oldName]
def checkingOnStart(self) -> bool:
- """ return true if checking for news and updates is enabled """
- return QgsSettingsTree.node("plugin-manager").childSetting('automatically-check-for-updates').value()
+ """return true if checking for news and updates is enabled"""
+ return (
+ QgsSettingsTree.node("plugin-manager")
+ .childSetting("automatically-check-for-updates")
+ .value()
+ )
def setCheckingOnStart(self, state: bool):
- """ set state of checking for news and updates """
- QgsSettingsTree.node("plugin-manager").childSetting('automatically-check-for-updates').setValue(state)
+ """set state of checking for news and updates"""
+ QgsSettingsTree.node("plugin-manager").childSetting(
+ "automatically-check-for-updates"
+ ).setValue(state)
def saveCheckingOnStartLastDate(self):
- """ set today's date as the day of last checking """
- QgsSettingsTree.node("plugin-manager").childSetting('check-on-start-last-date').setValue(QDate.currentDate())
+ """set today's date as the day of last checking"""
+ QgsSettingsTree.node("plugin-manager").childSetting(
+ "check-on-start-last-date"
+ ).setValue(QDate.currentDate())
def timeForChecking(self) -> bool:
- """ determine whether it's the time for checking for news and updates now """
+ """determine whether it's the time for checking for news and updates now"""
settings = QgsSettings()
try:
# QgsSettings may contain ivalid value...
- interval = QgsSettingsTree.node("plugin-manager").childSetting('check-on-start-last-date').valueAs(type=QDate).daysTo(QDate.currentDate())
+ interval = (
+ QgsSettingsTree.node("plugin-manager")
+ .childSetting("check-on-start-last-date")
+ .valueAs(type=QDate)
+ .daysTo(QDate.currentDate())
+ )
except:
interval = 0
if interval >= Repositories.CHECK_ON_START_INTERVAL:
@@ -257,7 +312,7 @@ def timeForChecking(self) -> bool:
return False
def load(self):
- """ populate the mRepositories dict"""
+ """populate the mRepositories dict"""
self.mRepositories = {}
settings = QgsSettings()
settings.beginGroup(reposGroup)
@@ -273,17 +328,29 @@ def load(self):
for key in settings.childGroups():
self.mRepositories[key] = {}
self.mRepositories[key]["url"] = settings.value(key + "/url", "", type=str)
- self.mRepositories[key]["authcfg"] = settings.value(key + "/authcfg", "", type=str)
- self.mRepositories[key]["enabled"] = settings.value(key + "/enabled", True, type=bool)
- self.mRepositories[key]["valid"] = settings.value(key + "/valid", True, type=bool)
+ self.mRepositories[key]["authcfg"] = settings.value(
+ key + "/authcfg", "", type=str
+ )
+ self.mRepositories[key]["enabled"] = settings.value(
+ key + "/enabled", True, type=bool
+ )
+ self.mRepositories[key]["valid"] = settings.value(
+ key + "/valid", True, type=bool
+ )
self.mRepositories[key]["Relay"] = Relay(key)
self.mRepositories[key]["xmlData"] = None
self.mRepositories[key]["state"] = Repositories.STATE_DISABLED
self.mRepositories[key]["error"] = ""
settings.endGroup()
- def requestFetching(self, key: str, url: Optional[QUrl] = None, redirectionCounter=0, force_reload: bool = False):
- """ start fetching the repository given by key """
+ def requestFetching(
+ self,
+ key: str,
+ url: Optional[QUrl] = None,
+ redirectionCounter=0,
+ force_reload: bool = False,
+ ):
+ """start fetching the repository given by key"""
self.mRepositories[key]["state"] = Repositories.STATE_LOADING
if not url:
url = QUrl(self.mRepositories[key]["url"] + self.urlParams())
@@ -291,55 +358,98 @@ def requestFetching(self, key: str, url: Optional[QUrl] = None, redirectionCount
# url.addQueryItem('qgis', '.'.join([str(int(s)) for s in [v[0], v[1:3]]]) ) # don't include the bugfix version!
self.mRepositories[key]["QRequest"] = QNetworkRequest(url)
- self.mRepositories[key]["QRequest"].setAttribute(QNetworkRequest.Attribute(QgsNetworkRequestParameters.RequestAttributes.AttributeInitiatorClass), "Relay")
- self.mRepositories[key]["QRequest"].setAttribute(QNetworkRequest.Attribute.RedirectPolicyAttribute, QNetworkRequest.RedirectPolicy.NoLessSafeRedirectPolicy)
+ self.mRepositories[key]["QRequest"].setAttribute(
+ QNetworkRequest.Attribute(
+ QgsNetworkRequestParameters.RequestAttributes.AttributeInitiatorClass
+ ),
+ "Relay",
+ )
+ self.mRepositories[key]["QRequest"].setAttribute(
+ QNetworkRequest.Attribute.RedirectPolicyAttribute,
+ QNetworkRequest.RedirectPolicy.NoLessSafeRedirectPolicy,
+ )
if force_reload:
- self.mRepositories[key]["QRequest"].setAttribute(QNetworkRequest.Attribute.CacheLoadControlAttribute, QNetworkRequest.CacheLoadControl.AlwaysNetwork)
+ self.mRepositories[key]["QRequest"].setAttribute(
+ QNetworkRequest.Attribute.CacheLoadControlAttribute,
+ QNetworkRequest.CacheLoadControl.AlwaysNetwork,
+ )
authcfg = self.mRepositories[key]["authcfg"]
if authcfg and isinstance(authcfg, str):
if not QgsApplication.authManager().updateNetworkRequest(
- self.mRepositories[key]["QRequest"], authcfg.strip()):
+ self.mRepositories[key]["QRequest"], authcfg.strip()
+ ):
msg = QCoreApplication.translate(
"QgsPluginInstaller",
"Update of network request with authentication "
- "credentials FAILED for configuration '{0}'").format(authcfg)
- iface.pluginManagerInterface().pushMessage(msg, Qgis.MessageLevel.Warning)
+ "credentials FAILED for configuration '{0}'",
+ ).format(authcfg)
+ iface.pluginManagerInterface().pushMessage(
+ msg, Qgis.MessageLevel.Warning
+ )
self.mRepositories[key]["QRequest"] = None
return
- self.mRepositories[key]["QRequest"].setAttribute(QNetworkRequest.Attribute.User, key)
- self.mRepositories[key]["xmlData"] = QgsNetworkAccessManager.instance().get(self.mRepositories[key]["QRequest"])
- self.mRepositories[key]["xmlData"].setProperty('reposName', key)
- self.mRepositories[key]["xmlData"].setProperty('redirectionCounter', redirectionCounter)
- self.mRepositories[key]["xmlData"].downloadProgress.connect(self.mRepositories[key]["Relay"].dataReadProgress)
- self.mRepositories[key]["xmlDataFinished"] = self.mRepositories[key]["xmlData"].finished.connect(self.xmlDownloaded)
+ self.mRepositories[key]["QRequest"].setAttribute(
+ QNetworkRequest.Attribute.User, key
+ )
+ self.mRepositories[key]["xmlData"] = QgsNetworkAccessManager.instance().get(
+ self.mRepositories[key]["QRequest"]
+ )
+ self.mRepositories[key]["xmlData"].setProperty("reposName", key)
+ self.mRepositories[key]["xmlData"].setProperty(
+ "redirectionCounter", redirectionCounter
+ )
+ self.mRepositories[key]["xmlData"].downloadProgress.connect(
+ self.mRepositories[key]["Relay"].dataReadProgress
+ )
+ self.mRepositories[key]["xmlDataFinished"] = self.mRepositories[key][
+ "xmlData"
+ ].finished.connect(self.xmlDownloaded)
def fetchingInProgress(self) -> bool:
- """ return True if fetching repositories is still in progress """
- return any(v['state'] == Repositories.STATE_LOADING for v in self.mRepositories.values())
+ """return True if fetching repositories is still in progress"""
+ return any(
+ v["state"] == Repositories.STATE_LOADING
+ for v in self.mRepositories.values()
+ )
def killConnection(self, key: str):
- """ kill the fetching on demand """
- if self.mRepositories[key]["state"] == Repositories.STATE_LOADING and self.mRepositories[key]["xmlData"] and self.mRepositories[key]["xmlData"].isRunning():
- self.mRepositories[key]["xmlData"].finished.disconnect(self.mRepositories[key]["xmlDataFinished"])
+ """kill the fetching on demand"""
+ if (
+ self.mRepositories[key]["state"] == Repositories.STATE_LOADING
+ and self.mRepositories[key]["xmlData"]
+ and self.mRepositories[key]["xmlData"].isRunning()
+ ):
+ self.mRepositories[key]["xmlData"].finished.disconnect(
+ self.mRepositories[key]["xmlDataFinished"]
+ )
self.mRepositories[key]["xmlData"].abort()
def xmlDownloaded(self):
- """ populate the plugins object with the fetched data """
+ """populate the plugins object with the fetched data"""
reply = self.sender()
- reposName = reply.property('reposName')
+ reposName = reply.property("reposName")
if reply.error() != QNetworkReply.NetworkError.NoError: # fetching failed
self.mRepositories[reposName]["state"] = Repositories.STATE_UNAVAILABLE
self.mRepositories[reposName]["error"] = reply.errorString()
if reply.error() == QNetworkReply.NetworkError.OperationCanceledError:
- self.mRepositories[reposName]["error"] += "\n\n" + QCoreApplication.translate("QgsPluginInstaller", "If you haven't canceled the download manually, it was most likely caused by a timeout. In this case consider increasing the connection timeout value in QGIS options window.")
+ self.mRepositories[reposName][
+ "error"
+ ] += "\n\n" + QCoreApplication.translate(
+ "QgsPluginInstaller",
+ "If you haven't canceled the download manually, it was most likely caused by a timeout. In this case consider increasing the connection timeout value in QGIS options window.",
+ )
elif reply.attribute(QNetworkRequest.Attribute.HttpStatusCodeAttribute) == 301:
- redirectionUrl = reply.attribute(QNetworkRequest.Attribute.RedirectionTargetAttribute)
+ redirectionUrl = reply.attribute(
+ QNetworkRequest.Attribute.RedirectionTargetAttribute
+ )
if redirectionUrl.isRelative():
redirectionUrl = reply.url().resolved(redirectionUrl)
- redirectionCounter = reply.property('redirectionCounter') + 1
+ redirectionCounter = reply.property("redirectionCounter") + 1
if redirectionCounter > 4:
self.mRepositories[reposName]["state"] = Repositories.STATE_UNAVAILABLE
- self.mRepositories[reposName]["error"] = QCoreApplication.translate("QgsPluginInstaller", "Too many redirections")
+ self.mRepositories[reposName]["error"] = QCoreApplication.translate(
+ "QgsPluginInstaller", "Too many redirections"
+ )
else:
# Fire a new request and exit immediately in order to quietly destroy the old one
self.requestFetching(reposName, redirectionUrl, redirectionCounter)
@@ -355,62 +465,165 @@ def xmlDownloaded(self):
if plugins_tag.size():
pluginNodes = reposXML.elementsByTagName("pyqgis_plugin")
for i in range(pluginNodes.size()):
- fileName = pluginNodes.item(i).firstChildElement("file_name").text().strip()
+ fileName = (
+ pluginNodes.item(i)
+ .firstChildElement("file_name")
+ .text()
+ .strip()
+ )
if not fileName:
- fileName = QFileInfo(pluginNodes.item(i).firstChildElement("download_url").text().strip().split("?")[0]).fileName()
+ fileName = QFileInfo(
+ pluginNodes.item(i)
+ .firstChildElement("download_url")
+ .text()
+ .strip()
+ .split("?")[0]
+ ).fileName()
name = fileName.partition(".")[0]
experimental = False
- if pluginNodes.item(i).firstChildElement("experimental").text().strip().upper() in ["TRUE", "YES"]:
+ if pluginNodes.item(i).firstChildElement(
+ "experimental"
+ ).text().strip().upper() in ["TRUE", "YES"]:
experimental = True
deprecated = False
- if pluginNodes.item(i).firstChildElement("deprecated").text().strip().upper() in ["TRUE", "YES"]:
+ if pluginNodes.item(i).firstChildElement(
+ "deprecated"
+ ).text().strip().upper() in ["TRUE", "YES"]:
deprecated = True
trusted = False
- if pluginNodes.item(i).firstChildElement("trusted").text().strip().upper() in ["TRUE", "YES"]:
+ if pluginNodes.item(i).firstChildElement(
+ "trusted"
+ ).text().strip().upper() in ["TRUE", "YES"]:
trusted = True
icon = pluginNodes.item(i).firstChildElement("icon").text().strip()
if icon and not icon.startswith("http"):
url = QUrl(self.mRepositories[reposName]["url"])
- if url.scheme() in ('http', 'https'):
- icon = "{}://{}/{}".format(url.scheme(), url.host(), icon)
+ if url.scheme() in ("http", "https"):
+ icon = f"{url.scheme()}://{url.host()}/{icon}"
if pluginNodes.item(i).toElement().hasAttribute("plugin_id"):
- plugin_id = pluginNodes.item(i).toElement().attribute("plugin_id")
+ plugin_id = (
+ pluginNodes.item(i).toElement().attribute("plugin_id")
+ )
else:
plugin_id = None
version = pluginNodes.item(i).toElement().attribute("version")
- download_url = pluginNodes.item(i).firstChildElement("download_url").text().strip()
+ download_url = (
+ pluginNodes.item(i)
+ .firstChildElement("download_url")
+ .text()
+ .strip()
+ )
plugin = {
"id": name,
"plugin_id": plugin_id,
"name": pluginNodes.item(i).toElement().attribute("name"),
"version_available": version,
- "version_available_stable": normalizeVersion(version) if not experimental else "",
- "version_available_experimental": normalizeVersion(version) if experimental else "",
- "description": pluginNodes.item(i).firstChildElement("description").text().strip(),
- "about": pluginNodes.item(i).firstChildElement("about").text().strip(),
- "author_name": pluginNodes.item(i).firstChildElement("author_name").text().strip(),
- "homepage": pluginNodes.item(i).firstChildElement("homepage").text().strip(),
+ "version_available_stable": (
+ normalizeVersion(version) if not experimental else ""
+ ),
+ "version_available_experimental": (
+ normalizeVersion(version) if experimental else ""
+ ),
+ "description": pluginNodes.item(i)
+ .firstChildElement("description")
+ .text()
+ .strip(),
+ "about": pluginNodes.item(i)
+ .firstChildElement("about")
+ .text()
+ .strip(),
+ "author_name": pluginNodes.item(i)
+ .firstChildElement("author_name")
+ .text()
+ .strip(),
+ "homepage": pluginNodes.item(i)
+ .firstChildElement("homepage")
+ .text()
+ .strip(),
"download_url": download_url,
"download_url_stable": download_url if not experimental else "",
- "download_url_experimental": download_url if experimental else "",
- "category": pluginNodes.item(i).firstChildElement("category").text().strip(),
- "tags": pluginNodes.item(i).firstChildElement("tags").text().strip(),
- "changelog": pluginNodes.item(i).firstChildElement("changelog").text().strip(),
- "author_email": pluginNodes.item(i).firstChildElement("author_email").text().strip(),
- "tracker": pluginNodes.item(i).firstChildElement("tracker").text().strip(),
- "code_repository": pluginNodes.item(i).firstChildElement("repository").text().strip(),
- "downloads": pluginNodes.item(i).firstChildElement("downloads").text().strip(),
- "average_vote": pluginNodes.item(i).firstChildElement("average_vote").text().strip(),
- "rating_votes": pluginNodes.item(i).firstChildElement("rating_votes").text().strip(),
- "create_date": pluginNodes.item(i).firstChildElement("create_date").text().strip(),
- "update_date": pluginNodes.item(i).firstChildElement("update_date").text().strip(),
- "create_date_stable": pluginNodes.item(i).firstChildElement("create_date").text().strip() if not experimental else "",
- "update_date_stable": pluginNodes.item(i).firstChildElement("update_date").text().strip() if not experimental else "",
- "create_date_experimental": pluginNodes.item(i).firstChildElement("create_date").text().strip() if experimental else "",
- "update_date_experimental": pluginNodes.item(i).firstChildElement("update_date").text().strip() if experimental else "",
+ "download_url_experimental": (
+ download_url if experimental else ""
+ ),
+ "category": pluginNodes.item(i)
+ .firstChildElement("category")
+ .text()
+ .strip(),
+ "tags": pluginNodes.item(i)
+ .firstChildElement("tags")
+ .text()
+ .strip(),
+ "changelog": pluginNodes.item(i)
+ .firstChildElement("changelog")
+ .text()
+ .strip(),
+ "author_email": pluginNodes.item(i)
+ .firstChildElement("author_email")
+ .text()
+ .strip(),
+ "tracker": pluginNodes.item(i)
+ .firstChildElement("tracker")
+ .text()
+ .strip(),
+ "code_repository": pluginNodes.item(i)
+ .firstChildElement("repository")
+ .text()
+ .strip(),
+ "downloads": pluginNodes.item(i)
+ .firstChildElement("downloads")
+ .text()
+ .strip(),
+ "average_vote": pluginNodes.item(i)
+ .firstChildElement("average_vote")
+ .text()
+ .strip(),
+ "rating_votes": pluginNodes.item(i)
+ .firstChildElement("rating_votes")
+ .text()
+ .strip(),
+ "create_date": pluginNodes.item(i)
+ .firstChildElement("create_date")
+ .text()
+ .strip(),
+ "update_date": pluginNodes.item(i)
+ .firstChildElement("update_date")
+ .text()
+ .strip(),
+ "create_date_stable": (
+ pluginNodes.item(i)
+ .firstChildElement("create_date")
+ .text()
+ .strip()
+ if not experimental
+ else ""
+ ),
+ "update_date_stable": (
+ pluginNodes.item(i)
+ .firstChildElement("update_date")
+ .text()
+ .strip()
+ if not experimental
+ else ""
+ ),
+ "create_date_experimental": (
+ pluginNodes.item(i)
+ .firstChildElement("create_date")
+ .text()
+ .strip()
+ if experimental
+ else ""
+ ),
+ "update_date_experimental": (
+ pluginNodes.item(i)
+ .firstChildElement("update_date")
+ .text()
+ .strip()
+ if experimental
+ else ""
+ ),
"icon": icon,
"experimental": experimental,
"deprecated": deprecated,
@@ -426,29 +639,58 @@ def xmlDownloaded(self):
"zip_repository": reposName,
"library": "",
"readonly": False,
- "plugin_dependencies": pluginNodes.item(i).firstChildElement("plugin_dependencies").text().strip(),
+ "plugin_dependencies": pluginNodes.item(i)
+ .firstChildElement("plugin_dependencies")
+ .text()
+ .strip(),
}
- qgisMinimumVersion = pluginNodes.item(i).firstChildElement("qgis_minimum_version").text().strip()
+ qgisMinimumVersion = (
+ pluginNodes.item(i)
+ .firstChildElement("qgis_minimum_version")
+ .text()
+ .strip()
+ )
if not qgisMinimumVersion:
qgisMinimumVersion = "2"
- qgisMaximumVersion = pluginNodes.item(i).firstChildElement("qgis_maximum_version").text().strip()
+ qgisMaximumVersion = (
+ pluginNodes.item(i)
+ .firstChildElement("qgis_maximum_version")
+ .text()
+ .strip()
+ )
if not qgisMaximumVersion:
qgisMaximumVersion = qgisMinimumVersion[0] + ".99"
# if compatible, add the plugin to the list
- if not pluginNodes.item(i).firstChildElement("disabled").text().strip().upper() in ["TRUE", "YES"]:
- if isCompatible(pyQgisVersion(), qgisMinimumVersion, qgisMaximumVersion):
+ if not pluginNodes.item(i).firstChildElement(
+ "disabled"
+ ).text().strip().upper() in ["TRUE", "YES"]:
+ if isCompatible(
+ pyQgisVersion(), qgisMinimumVersion, qgisMaximumVersion
+ ):
# add the plugin to the cache
plugins.addFromRepository(plugin)
self.mRepositories[reposName]["state"] = Repositories.STATE_LOADED
else:
# no plugin metadata found
self.mRepositories[reposName]["state"] = Repositories.STATE_UNAVAILABLE
- if reply.attribute(QNetworkRequest.Attribute.HttpStatusCodeAttribute) == 200:
- self.mRepositories[reposName]["error"] = QCoreApplication.translate("QgsPluginInstaller", "Server response is 200 OK, but doesn't contain plugin metadata. This is most likely caused by a proxy or a wrong repository URL. You can configure proxy settings in QGIS options.")
+ if (
+ reply.attribute(QNetworkRequest.Attribute.HttpStatusCodeAttribute)
+ == 200
+ ):
+ self.mRepositories[reposName]["error"] = QCoreApplication.translate(
+ "QgsPluginInstaller",
+ "Server response is 200 OK, but doesn't contain plugin metadata. This is most likely caused by a proxy or a wrong repository URL. You can configure proxy settings in QGIS options.",
+ )
else:
- self.mRepositories[reposName]["error"] = QCoreApplication.translate("QgsPluginInstaller", "Status code:") + " {} {}".format(
- reply.attribute(QNetworkRequest.Attribute.HttpStatusCodeAttribute),
- reply.attribute(QNetworkRequest.Attribute.HttpReasonPhraseAttribute)
+ self.mRepositories[reposName]["error"] = QCoreApplication.translate(
+ "QgsPluginInstaller", "Status code:"
+ ) + " {} {}".format(
+ reply.attribute(
+ QNetworkRequest.Attribute.HttpStatusCodeAttribute
+ ),
+ reply.attribute(
+ QNetworkRequest.Attribute.HttpReasonPhraseAttribute
+ ),
)
self.repositoryFetched.emit(reposName)
@@ -460,35 +702,37 @@ def xmlDownloaded(self):
reply.deleteLater()
def inspectionFilter(self) -> Optional[str]:
- """ return inspection filter (only one repository to be fetched) """
+ """return inspection filter (only one repository to be fetched)"""
return self.mInspectionFilter
def setInspectionFilter(self, key: Optional[str] = None):
- """ temporarily disable all repositories but this for inspection """
+ """temporarily disable all repositories but this for inspection"""
self.mInspectionFilter = key
# --- class Plugins ---------------------------------------------------------------------- #
class Plugins(QObject):
+ """A dict-like class for handling plugins data"""
- """ A dict-like class for handling plugins data """
# ----------------------------------------- #
def __init__(self):
QObject.__init__(self)
- self.mPlugins = {} # the dict of plugins (dicts)
- self.repoCache = {} # the dict of lists of plugins (dicts)
- self.localCache = {} # the dict of plugins (dicts)
- self.obsoletePlugins = [] # the list of outdated 'user' plugins masking newer 'system' ones
+ self.mPlugins = {} # the dict of plugins (dicts)
+ self.repoCache = {} # the dict of lists of plugins (dicts)
+ self.localCache = {} # the dict of plugins (dicts)
+ self.obsoletePlugins = (
+ []
+ ) # the list of outdated 'user' plugins masking newer 'system' ones
# ----------------------------------------- #
def all(self):
- """ return all plugins """
+ """return all plugins"""
return self.mPlugins
# ----------------------------------------- #
def allUpgradeable(self):
- """ return all upgradeable plugins """
+ """return all upgradeable plugins"""
result = {}
for i in self.mPlugins:
if self.mPlugins[i]["status"] == "upgradeable":
@@ -497,7 +741,7 @@ def allUpgradeable(self):
# ----------------------------------------- #
def keyByUrl(self, name):
- """ return plugin key by given url """
+ """return plugin key by given url"""
plugins = [i for i in self.mPlugins if self.mPlugins[i]["download_url"] == name]
if plugins:
return plugins[0]
@@ -505,12 +749,12 @@ def keyByUrl(self, name):
# ----------------------------------------- #
def clearRepoCache(self):
- """ clears the repo cache before re-fetching repositories """
+ """clears the repo cache before re-fetching repositories"""
self.repoCache = {}
# ----------------------------------------- #
def addFromRepository(self, plugin):
- """ add given plugin to the repoCache """
+ """add given plugin to the repoCache"""
repo = plugin["zip_repository"]
try:
self.repoCache[repo] += [plugin]
@@ -519,44 +763,45 @@ def addFromRepository(self, plugin):
# ----------------------------------------- #
def removeInstalledPlugin(self, key):
- """ remove given plugin from the localCache """
+ """remove given plugin from the localCache"""
if key in self.localCache:
del self.localCache[key]
# ----------------------------------------- #
def removeRepository(self, repo: str):
- """ remove whole repository from the repoCache """
+ """remove whole repository from the repoCache"""
if repo in self.repoCache:
del self.repoCache[repo]
# ----------------------------------------- #
def getInstalledPlugin(self, key, path, readOnly):
- """ get the metadata of an installed plugin """
+ """get the metadata of an installed plugin"""
+
def metadataParser(fct):
- """ plugin metadata parser reimplemented from qgis.utils
- for better control of which module is examined
- in case there is an installed plugin masking a core one """
+ """plugin metadata parser reimplemented from qgis.utils
+ for better control of which module is examined
+ in case there is an installed plugin masking a core one"""
global errorDetails
cp = configparser.ConfigParser()
try:
with codecs.open(metadataFile, "r", "utf8") as f:
cp.read_file(f)
- return cp.get('general', fct)
+ return cp.get("general", fct)
except Exception as e:
if not errorDetails:
errorDetails = e.args[0] # set to the first problem
return ""
def pluginMetadata(fct):
- """ calls metadataParser for current l10n.
- If failed, fallbacks to the standard metadata """
- overrideLocale = QgsSettings().value('locale/overrideFlag', False, bool)
+ """calls metadataParser for current l10n.
+ If failed, fallbacks to the standard metadata"""
+ overrideLocale = QgsSettings().value("locale/overrideFlag", False, bool)
if not overrideLocale:
locale = QLocale.system().name()
else:
- locale = QgsSettings().value('locale/userLocale', '')
+ locale = QgsSettings().value("locale/userLocale", "")
if locale and fct in translatableAttributes:
- value = metadataParser("{}[{}]".format(fct, locale))
+ value = metadataParser(f"{fct}[{locale}]")
if value:
return value
value = metadataParser("{}[{}]".format(fct, locale.split("_")[0]))
@@ -573,19 +818,27 @@ def pluginMetadata(fct):
errorDetails = ""
version = None
- if not os.path.exists(os.path.join(path, '__init__.py')):
+ if not os.path.exists(os.path.join(path, "__init__.py")):
error = "broken"
- errorDetails = QCoreApplication.translate("QgsPluginInstaller", "Missing __init__.py")
+ errorDetails = QCoreApplication.translate(
+ "QgsPluginInstaller", "Missing __init__.py"
+ )
- metadataFile = os.path.join(path, 'metadata.txt')
+ metadataFile = os.path.join(path, "metadata.txt")
if os.path.exists(metadataFile):
version = normalizeVersion(pluginMetadata("version"))
- qt_version = int(QT_VERSION_STR.split('.')[0])
+ qt_version = int(QT_VERSION_STR.split(".")[0])
supports_qt6 = pluginMetadata("supportsQt6").strip().upper() in ("TRUE", "YES")
- if qt_version == 6 and not supports_qt6 and "QGIS_DISABLE_SUPPORTS_QT6_CHECK" not in os.environ:
+ if (
+ qt_version == 6
+ and not supports_qt6
+ and "QGIS_DISABLE_SUPPORTS_QT6_CHECK" not in os.environ
+ ):
error = "incompatible"
- errorDetails = QCoreApplication.translate("QgsPluginInstaller", "Plugin does not support Qt6 versions of QGIS")
+ errorDetails = QCoreApplication.translate(
+ "QgsPluginInstaller", "Plugin does not support Qt6 versions of QGIS"
+ )
elif version:
qgisMinimumVersion = pluginMetadata("qgisMinimumVersion").strip()
if not qgisMinimumVersion:
@@ -594,16 +847,22 @@ def pluginMetadata(fct):
if not qgisMaximumVersion:
qgisMaximumVersion = qgisMinimumVersion[0] + ".99"
# if compatible, add the plugin to the list
- if not isCompatible(pyQgisVersion(), qgisMinimumVersion, qgisMaximumVersion):
+ if not isCompatible(
+ pyQgisVersion(), qgisMinimumVersion, qgisMaximumVersion
+ ):
error = "incompatible"
- errorDetails = "{} - {}".format(qgisMinimumVersion, qgisMaximumVersion)
+ errorDetails = f"{qgisMinimumVersion} - {qgisMaximumVersion}"
elif not os.path.exists(metadataFile):
error = "broken"
- errorDetails = QCoreApplication.translate("QgsPluginInstaller", "Missing metadata file")
+ errorDetails = QCoreApplication.translate(
+ "QgsPluginInstaller", "Missing metadata file"
+ )
else:
error = "broken"
e = errorDetails
- errorDetails = QCoreApplication.translate("QgsPluginInstaller", "Error reading metadata")
+ errorDetails = QCoreApplication.translate(
+ "QgsPluginInstaller", "Error reading metadata"
+ )
if e:
errorDetails += ": " + e
@@ -644,14 +903,16 @@ def pluginMetadata(fct):
"version_installed": version,
"library": path,
"pythonic": True,
- "experimental": pluginMetadata("experimental").strip().upper() in ["TRUE", "YES"],
- "deprecated": pluginMetadata("deprecated").strip().upper() in ["TRUE", "YES"],
+ "experimental": pluginMetadata("experimental").strip().upper()
+ in ["TRUE", "YES"],
+ "deprecated": pluginMetadata("deprecated").strip().upper()
+ in ["TRUE", "YES"],
"trusted": False,
"version_available": "",
"version_available_stable": "",
"version_available_experimental": "",
"zip_repository": "",
- "download_url": path, # warning: local path as url!
+ "download_url": path, # warning: local path as url!
"download_url_stable": "",
"download_url_experimental": "",
"filename": "",
@@ -664,7 +925,7 @@ def pluginMetadata(fct):
"update_date_stable": pluginMetadata("update_date_stable"),
"create_date_experimental": pluginMetadata("create_date_experimental"),
"update_date_experimental": pluginMetadata("update_date_experimental"),
- "available": False, # Will be overwritten, if any available version found.
+ "available": False, # Will be overwritten, if any available version found.
"installed": True,
"status": "orphan", # Will be overwritten, if any available version found.
"status_exp": "orphan", # Will be overwritten, if any available version found.
@@ -677,7 +938,7 @@ def pluginMetadata(fct):
# ----------------------------------------- #
def getAllInstalled(self):
- """ Build the localCache """
+ """Build the localCache"""
self.localCache = {}
# reversed list of the plugin paths: first system plugins -> then user plugins -> finally custom path(s)
@@ -685,7 +946,9 @@ def getAllInstalled(self):
pluginPaths.reverse()
for pluginsPath in pluginPaths:
- isTheSystemDir = (pluginPaths.index(pluginsPath) == 0) # The current dir is the system plugins dir
+ isTheSystemDir = (
+ pluginPaths.index(pluginsPath) == 0
+ ) # The current dir is the system plugins dir
if isTheSystemDir:
# temporarily add the system path as the first element to force loading the readonly plugins, even if masked by user ones.
sys.path = [pluginsPath] + sys.path
@@ -696,10 +959,19 @@ def getAllInstalled(self):
if key not in [".", ".."]:
path = QDir.toNativeSeparators(pluginsPath + "/" + key)
# readOnly = not QFileInfo(pluginsPath).isWritable() # On windows testing the writable status isn't reliable.
- readOnly = isTheSystemDir # Assume only the system plugins are not writable.
+ readOnly = isTheSystemDir # Assume only the system plugins are not writable.
# failedToLoad = settings.value("/PythonPlugins/watchDog/" + key) is not None
- plugin = self.getInstalledPlugin(key, path=path, readOnly=readOnly)
- if key in list(self.localCache.keys()) and compareVersions(self.localCache[key]["version_installed"], plugin["version_installed"]) == 1:
+ plugin = self.getInstalledPlugin(
+ key, path=path, readOnly=readOnly
+ )
+ if (
+ key in list(self.localCache.keys())
+ and compareVersions(
+ self.localCache[key]["version_installed"],
+ plugin["version_installed"],
+ )
+ == 1
+ ):
# An obsolete plugin in the "user" location is masking a newer one in the "system" location!
self.obsoletePlugins += [key]
self.localCache[key] = plugin
@@ -713,29 +985,45 @@ def getAllInstalled(self):
# ----------------------------------------- #
def rebuild(self):
- """ build or rebuild the mPlugins from the caches """
+ """build or rebuild the mPlugins from the caches"""
self.mPlugins = {}
for i in list(self.localCache.keys()):
self.mPlugins[i] = self.localCache[i].copy()
- allowExperimental = QgsSettingsTree.node("plugin-manager").childSetting("allow-experimental").value()
- allowDeprecated = QgsSettingsTree.node("plugin-manager").childSetting("allow-deprecated").value()
+ allowExperimental = (
+ QgsSettingsTree.node("plugin-manager")
+ .childSetting("allow-experimental")
+ .value()
+ )
+ allowDeprecated = (
+ QgsSettingsTree.node("plugin-manager")
+ .childSetting("allow-deprecated")
+ .value()
+ )
for i in list(self.repoCache.values()):
for j in i:
plugin = j.copy() # do not update repoCache elements!
key = plugin["id"]
# check if the plugin is allowed and if there isn't any better one added already.
- if (allowExperimental or not plugin["experimental"]) \
- and (allowDeprecated or not plugin["deprecated"]) \
- and not (
- key in self.mPlugins and self.mPlugins[key]["version_available"]
- and compareVersions(self.mPlugins[key]["version_available"], plugin["version_available"]) < 2
- and self.mPlugins[key]["experimental"] and not plugin["experimental"]
+ if (
+ (allowExperimental or not plugin["experimental"])
+ and (allowDeprecated or not plugin["deprecated"])
+ and not (
+ key in self.mPlugins
+ and self.mPlugins[key]["version_available"]
+ and compareVersions(
+ self.mPlugins[key]["version_available"],
+ plugin["version_available"],
+ )
+ < 2
+ and self.mPlugins[key]["experimental"]
+ and not plugin["experimental"]
+ )
):
# The mPlugins dict contains now locally installed plugins.
# Now, add the available one if not present yet or update it if present already.
if key not in self.mPlugins:
- self.mPlugins[key] = plugin # just add a new plugin
+ self.mPlugins[key] = plugin # just add a new plugin
else:
# update local plugin with remote metadata
# description, about, icon: only use remote data if local one not available. Prefer local version because of i18n.
@@ -746,18 +1034,56 @@ def rebuild(self):
if not self.mPlugins[key][attrib] and plugin[attrib]:
self.mPlugins[key][attrib] = plugin[attrib]
# other remote metadata is preferred:
- for attrib in ["name", "plugin_id", "description", "about", "category", "tags", "changelog", "author_name", "author_email", "homepage",
- "tracker", "code_repository", "experimental", "deprecated", "version_available", "zip_repository",
- "download_url", "filename", "downloads", "average_vote", "rating_votes", "trusted", "plugin_dependencies",
- "version_available_stable", "version_available_experimental", "download_url_stable", "download_url_experimental",
- "create_date", "update_date", "create_date_stable", "update_date_stable", "create_date_experimental", "update_date_experimental"]:
- if attrib not in translatableAttributes or attrib == "name": # include name!
+ for attrib in [
+ "name",
+ "plugin_id",
+ "description",
+ "about",
+ "category",
+ "tags",
+ "changelog",
+ "author_name",
+ "author_email",
+ "homepage",
+ "tracker",
+ "code_repository",
+ "experimental",
+ "deprecated",
+ "version_available",
+ "zip_repository",
+ "download_url",
+ "filename",
+ "downloads",
+ "average_vote",
+ "rating_votes",
+ "trusted",
+ "plugin_dependencies",
+ "version_available_stable",
+ "version_available_experimental",
+ "download_url_stable",
+ "download_url_experimental",
+ "create_date",
+ "update_date",
+ "create_date_stable",
+ "update_date_stable",
+ "create_date_experimental",
+ "update_date_experimental",
+ ]:
+ if (
+ attrib not in translatableAttributes or attrib == "name"
+ ): # include name!
if plugin.get(attrib, False):
self.mPlugins[key][attrib] = plugin[attrib]
# If the stable version is higher than the experimental version, we ignore the experimental version
- if compareVersions(self.mPlugins[key]["version_available_stable"], self.mPlugins[key]["version_available_experimental"]) == 1:
- self.mPlugins[key]["version_available_experimental"] = ''
+ if (
+ compareVersions(
+ self.mPlugins[key]["version_available_stable"],
+ self.mPlugins[key]["version_available_experimental"],
+ )
+ == 1
+ ):
+ self.mPlugins[key]["version_available_experimental"] = ""
# set status
#
@@ -769,60 +1095,129 @@ def rebuild(self):
# same same "installed"
# less greater "upgradeable"
# greater less "newer"
- if not self.mPlugins[key]["version_available_stable"] and not self.mPlugins[key]["version_installed"]:
+ if (
+ not self.mPlugins[key]["version_available_stable"]
+ and not self.mPlugins[key]["version_installed"]
+ ):
self.mPlugins[key]["status"] = "none available"
- elif not self.mPlugins[key]["version_available_stable"] and self.mPlugins[key]["version_installed"]:
+ elif (
+ not self.mPlugins[key]["version_available_stable"]
+ and self.mPlugins[key]["version_installed"]
+ ):
self.mPlugins[key]["status"] = "orphan"
elif not self.mPlugins[key]["version_installed"]:
self.mPlugins[key]["status"] = "not installed"
elif self.mPlugins[key]["version_installed"] in ["?", "-1"]:
self.mPlugins[key]["status"] = "installed"
- elif compareVersions(self.mPlugins[key]["version_available_stable"], self.mPlugins[key]["version_installed"]) == 0:
+ elif (
+ compareVersions(
+ self.mPlugins[key]["version_available_stable"],
+ self.mPlugins[key]["version_installed"],
+ )
+ == 0
+ ):
self.mPlugins[key]["status"] = "installed"
- elif compareVersions(self.mPlugins[key]["version_available_stable"], self.mPlugins[key]["version_installed"]) == 1:
+ elif (
+ compareVersions(
+ self.mPlugins[key]["version_available_stable"],
+ self.mPlugins[key]["version_installed"],
+ )
+ == 1
+ ):
self.mPlugins[key]["status"] = "upgradeable"
else:
self.mPlugins[key]["status"] = "newer"
# debug: test if the status match the "installed" tag:
- if self.mPlugins[key]["status"] in ["not installed", "none available"] and self.mPlugins[key]["installed"]:
- raise Exception("Error: plugin status is ambiguous (1) for plugin {}".format(key))
- if self.mPlugins[key]["status"] in ["installed", "orphan", "upgradeable", "newer"] and not self.mPlugins[key]["installed"]:
- raise Exception("Error: plugin status is ambiguous (2) for plugin {}".format(key))
-
- if not self.mPlugins[key]["version_available_experimental"] and not self.mPlugins[key]["version_installed"]:
+ if (
+ self.mPlugins[key]["status"]
+ in ["not installed", "none available"]
+ and self.mPlugins[key]["installed"]
+ ):
+ raise Exception(
+ f"Error: plugin status is ambiguous (1) for plugin {key}"
+ )
+ if (
+ self.mPlugins[key]["status"]
+ in ["installed", "orphan", "upgradeable", "newer"]
+ and not self.mPlugins[key]["installed"]
+ ):
+ raise Exception(
+ f"Error: plugin status is ambiguous (2) for plugin {key}"
+ )
+
+ if (
+ not self.mPlugins[key]["version_available_experimental"]
+ and not self.mPlugins[key]["version_installed"]
+ ):
self.mPlugins[key]["status_exp"] = "none available"
- elif not self.mPlugins[key]["version_available_experimental"] and self.mPlugins[key]["version_installed"]:
+ elif (
+ not self.mPlugins[key]["version_available_experimental"]
+ and self.mPlugins[key]["version_installed"]
+ ):
self.mPlugins[key]["status_exp"] = "orphan"
elif not self.mPlugins[key]["version_installed"]:
self.mPlugins[key]["status_exp"] = "not installed"
elif self.mPlugins[key]["version_installed"] in ["?", "-1"]:
self.mPlugins[key]["status_exp"] = "installed"
- elif compareVersions(self.mPlugins[key]["version_available_experimental"], self.mPlugins[key]["version_installed"]) == 0:
+ elif (
+ compareVersions(
+ self.mPlugins[key]["version_available_experimental"],
+ self.mPlugins[key]["version_installed"],
+ )
+ == 0
+ ):
self.mPlugins[key]["status_exp"] = "installed"
- elif compareVersions(self.mPlugins[key]["version_available_experimental"], self.mPlugins[key]["version_installed"]) == 1:
+ elif (
+ compareVersions(
+ self.mPlugins[key]["version_available_experimental"],
+ self.mPlugins[key]["version_installed"],
+ )
+ == 1
+ ):
self.mPlugins[key]["status_exp"] = "upgradeable"
else:
self.mPlugins[key]["status_exp"] = "newer"
# debug: test if the status_exp match the "installed" tag:
- if self.mPlugins[key]["status_exp"] in ["not installed", "none available"] and self.mPlugins[key]["installed"]:
- raise Exception("Error: plugin status_exp is ambiguous (1) for plugin {}".format(key))
- if self.mPlugins[key]["status_exp"] in ["installed", "orphan", "upgradeable", "newer"] and not self.mPlugins[key]["installed"]:
- raise Exception("Error: plugin status_exp is ambiguous (2) for plugin {} (status_exp={})".format(key, self.mPlugins[key]["status_exp"]))
+ if (
+ self.mPlugins[key]["status_exp"]
+ in ["not installed", "none available"]
+ and self.mPlugins[key]["installed"]
+ ):
+ raise Exception(
+ f"Error: plugin status_exp is ambiguous (1) for plugin {key}"
+ )
+ if (
+ self.mPlugins[key]["status_exp"]
+ in ["installed", "orphan", "upgradeable", "newer"]
+ and not self.mPlugins[key]["installed"]
+ ):
+ raise Exception(
+ "Error: plugin status_exp is ambiguous (2) for plugin {} (status_exp={})".format(
+ key, self.mPlugins[key]["status_exp"]
+ )
+ )
self.markNews()
# ----------------------------------------- #
def markNews(self):
- """ mark all new plugins as new """
- seenPlugins = QgsSettingsTree.node("plugin-manager").childSetting("seen-plugins").valueWithDefaultOverride(list(self.mPlugins.keys()))
+ """mark all new plugins as new"""
+ seenPlugins = (
+ QgsSettingsTree.node("plugin-manager")
+ .childSetting("seen-plugins")
+ .valueWithDefaultOverride(list(self.mPlugins.keys()))
+ )
if len(seenPlugins) > 0:
for plugin in list(self.mPlugins.keys()):
- if seenPlugins.count(plugin) == 0 and self.mPlugins[plugin]["status"] == "not installed":
+ if (
+ seenPlugins.count(plugin) == 0
+ and self.mPlugins[plugin]["status"] == "not installed"
+ ):
self.mPlugins[plugin]["status"] = "new"
# ----------------------------------------- #
def updateSeenPluginsList(self):
- """ update the list of all seen plugins """
+ """update the list of all seen plugins"""
setting = QgsSettingsTree.node("plugin-manager").childSetting("seen-plugins")
seenPlugins = setting.valueWithDefaultOverride(list(self.mPlugins.keys()))
for plugin in list(self.mPlugins.keys()):
@@ -832,7 +1227,7 @@ def updateSeenPluginsList(self):
# ----------------------------------------- #
def isThereAnythingNew(self):
- """ return true if an upgradeable or new plugin detected """
+ """return true if an upgradeable or new plugin detected"""
for i in list(self.mPlugins.values()):
if i["status"] in ["upgradeable", "new"]:
return True
diff --git a/python/pyplugin_installer/plugindependencies.py b/python/pyplugin_installer/plugindependencies.py
index c95e1f49b06d..4c1910208ca2 100644
--- a/python/pyplugin_installer/plugindependencies.py
+++ b/python/pyplugin_installer/plugindependencies.py
@@ -1,4 +1,3 @@
-# coding=utf-8
"""Parse plugin metadata for plugin_dependencies
.. note:: This program is free software; you can redistribute it and/or modify
@@ -8,9 +7,9 @@
"""
-__author__ = 'elpaso@itopen.it'
-__date__ = '2018-05-29'
-__copyright__ = 'Copyright 2018, GISCE-TI S.L.'
+__author__ = "elpaso@itopen.it"
+__date__ = "2018-05-29"
+__copyright__ = "Copyright 2018, GISCE-TI S.L."
from configparser import NoOptionError, NoSectionError
from .version_compare import compareVersions
@@ -19,13 +18,12 @@
def __plugin_name_map(plugin_data_values):
- return {
- plugin['name']: plugin['id']
- for plugin in plugin_data_values
- }
+ return {plugin["name"]: plugin["id"] for plugin in plugin_data_values}
-def find_dependencies(plugin_id, plugin_data=None, plugin_deps=None, installed_plugins=None):
+def find_dependencies(
+ plugin_id, plugin_data=None, plugin_deps=None, installed_plugins=None
+):
"""Finds the plugin dependencies and checks if they can be installed or upgraded
:param plugin_id: plugin id
@@ -52,7 +50,12 @@ def find_dependencies(plugin_id, plugin_data=None, plugin_deps=None, installed_p
if installed_plugins is None:
metadata_parser = metadataParser()
- installed_plugins = {metadata_parser[k].get('general', 'name'): metadata_parser[k].get('general', 'version') for k, v in metadata_parser.items()}
+ installed_plugins = {
+ metadata_parser[k]
+ .get("general", "name"): metadata_parser[k]
+ .get("general", "version")
+ for k, v in metadata_parser.items()
+ }
if plugin_data is None:
plugin_data = plugin_installer.plugins.all()
@@ -64,33 +67,49 @@ def find_dependencies(plugin_id, plugin_data=None, plugin_deps=None, installed_p
try:
p_id = plugins_map[name]
except KeyError:
- not_found.update({name: {
- 'id': None,
- 'version_installed': None,
- 'version_required': None,
- 'version_available': None,
- 'use_stable_version': None,
- 'action': None,
- 'error': 'missing_id'
- }})
+ not_found.update(
+ {
+ name: {
+ "id": None,
+ "version_installed": None,
+ "version_required": None,
+ "version_available": None,
+ "use_stable_version": None,
+ "action": None,
+ "error": "missing_id",
+ }
+ }
+ )
continue
- affected_plugin = dict({
- "id": p_id,
- # "version_installed": installed_plugins.get(p_id, {}).get('installed_plugins', None),
- "version_installed": installed_plugins.get(name, None),
- "version_required": version_required,
- "version_available": plugin_data[p_id].get('version_available', None),
- "use_stable_version": True, # Prefer stable by default
- "action": None,
- })
- version_available_stable = plugin_data[p_id].get('version_available_stable', None)
- version_available_experimental = plugin_data[p_id].get('version_available_experimental', None)
-
- if version_required is not None and version_required == version_available_stable:
+ affected_plugin = dict(
+ {
+ "id": p_id,
+ # "version_installed": installed_plugins.get(p_id, {}).get('installed_plugins', None),
+ "version_installed": installed_plugins.get(name, None),
+ "version_required": version_required,
+ "version_available": plugin_data[p_id].get("version_available", None),
+ "use_stable_version": True, # Prefer stable by default
+ "action": None,
+ }
+ )
+ version_available_stable = plugin_data[p_id].get(
+ "version_available_stable", None
+ )
+ version_available_experimental = plugin_data[p_id].get(
+ "version_available_experimental", None
+ )
+
+ if (
+ version_required is not None
+ and version_required == version_available_stable
+ ):
affected_plugin["version_available"] = version_available_stable
affected_plugin["use_stable_version"] = True
- elif version_required is not None and version_required == version_available_experimental:
+ elif (
+ version_required is not None
+ and version_required == version_available_experimental
+ ):
affected_plugin["version_available"] = version_available_experimental
affected_plugin["use_stable_version"] = False
elif version_required is None:
@@ -104,21 +123,29 @@ def find_dependencies(plugin_id, plugin_data=None, plugin_deps=None, installed_p
# Install is needed
if name not in installed_plugins:
- affected_plugin['action'] = 'install'
+ affected_plugin["action"] = "install"
destination_list = to_install
# Upgrade is needed
- elif version_required is not None and compareVersions(installed_plugins[name], version_required) == 2:
- affected_plugin['action'] = 'upgrade'
+ elif (
+ version_required is not None
+ and compareVersions(installed_plugins[name], version_required) == 2
+ ):
+ affected_plugin["action"] = "upgrade"
destination_list = to_upgrade
# TODO @elpaso: review installed but not activated
# No action is needed
else:
continue
- if version_required == affected_plugin['version_available'] or version_required is None:
+ if (
+ version_required == affected_plugin["version_available"]
+ or version_required is None
+ ):
destination_list.update({name: affected_plugin})
else:
- affected_plugin['error'] = 'unavailable {}'.format(affected_plugin['action'])
+ affected_plugin["error"] = "unavailable {}".format(
+ affected_plugin["action"]
+ )
not_found.update({name: affected_plugin})
return to_install, to_upgrade, not_found
diff --git a/python/pyplugin_installer/qgsplugindependenciesdialog.py b/python/pyplugin_installer/qgsplugindependenciesdialog.py
index ff13fbdeebde..cc8a0f943126 100644
--- a/python/pyplugin_installer/qgsplugindependenciesdialog.py
+++ b/python/pyplugin_installer/qgsplugindependenciesdialog.py
@@ -1,4 +1,3 @@
-# coding=utf-8
"""Plugin dependencies selection dialog
.. note:: This program is free software; you can redistribute it and/or modify
@@ -8,9 +7,9 @@
"""
-__author__ = 'elpaso@itopen.it'
-__date__ = '2018-09-19'
-__copyright__ = 'Copyright 2018, GISCE-TI S.L.'
+__author__ = "elpaso@itopen.it"
+__date__ = "2018-09-19"
+__copyright__ = "Copyright 2018, GISCE-TI S.L."
import os
@@ -20,10 +19,14 @@
from qgis.PyQt import QtWidgets, QtCore
from qgis.utils import iface
-Ui_QgsPluginDependenciesDialogBase, _ = uic.loadUiType(Path(__file__).parent / 'qgsplugindependenciesdialogbase.ui')
+Ui_QgsPluginDependenciesDialogBase, _ = uic.loadUiType(
+ Path(__file__).parent / "qgsplugindependenciesdialogbase.ui"
+)
-class QgsPluginDependenciesDialog(QtWidgets.QDialog, Ui_QgsPluginDependenciesDialogBase):
+class QgsPluginDependenciesDialog(
+ QtWidgets.QDialog, Ui_QgsPluginDependenciesDialogBase
+):
"""A dialog that shows plugin dependencies and offers a way to install or upgrade the
dependencies.
"""
@@ -46,11 +49,21 @@ def __init__(self, plugin_name, to_install, to_upgrade, not_found, parent=None):
super().__init__(parent)
self.setupUi(self)
self.setWindowTitle(self.tr("Plugin Dependencies Manager"))
- self.mPluginDependenciesLabel.setText(self.tr("Plugin dependencies for %s ") % plugin_name)
+ self.mPluginDependenciesLabel.setText(
+ self.tr("Plugin dependencies for %s ") % plugin_name
+ )
self.setStyleSheet("QTableView { padding: 20px;}")
# Name, Version Installed, Version Required, Version Available, Action Checkbox
self.pluginList.setColumnCount(5)
- self.pluginList.setHorizontalHeaderLabels([self.tr('Name'), self.tr('Installed'), self.tr('Required'), self.tr('Available'), self.tr('Action')])
+ self.pluginList.setHorizontalHeaderLabels(
+ [
+ self.tr("Name"),
+ self.tr("Installed"),
+ self.tr("Required"),
+ self.tr("Available"),
+ self.tr("Action"),
+ ]
+ )
self.pluginList.setRowCount(len(not_found) + len(to_install) + len(to_upgrade))
self.__actions = {}
@@ -61,18 +74,18 @@ def _display(txt):
def _make_row(data, i, name):
widget = QtWidgets.QLabel("%s " % name)
- widget.p_id = data['id']
- widget.action = data['action']
- widget.use_stable_version = data['use_stable_version']
+ widget.p_id = data["id"]
+ widget.action = data["action"]
+ widget.use_stable_version = data["use_stable_version"]
self.pluginList.setCellWidget(i, 0, widget)
self.pluginList.resizeColumnToContents(0)
- widget = QtWidgets.QTableWidgetItem(_display(data['version_installed']))
+ widget = QtWidgets.QTableWidgetItem(_display(data["version_installed"]))
widget.setTextAlignment(QtCore.Qt.AlignHCenter | QtCore.Qt.AlignVCenter)
self.pluginList.setItem(i, 1, widget)
- widget = QtWidgets.QTableWidgetItem(_display(data['version_required']))
+ widget = QtWidgets.QTableWidgetItem(_display(data["version_required"]))
widget.setTextAlignment(QtCore.Qt.AlignHCenter | QtCore.Qt.AlignVCenter)
self.pluginList.setItem(i, 2, widget)
- widget = QtWidgets.QTableWidgetItem(_display(data['version_available']))
+ widget = QtWidgets.QTableWidgetItem(_display(data["version_available"]))
widget.setTextAlignment(QtCore.Qt.AlignHCenter | QtCore.Qt.AlignVCenter)
self.pluginList.setItem(i, 3, widget)
@@ -112,8 +125,11 @@ def accept(self):
try:
if self.pluginList.cellWidget(i, 4).isChecked():
self.__actions[self.pluginList.cellWidget(i, 0).p_id] = {
- 'action': self.pluginList.cellWidget(i, 0).action,
- 'use_stable_version': self.pluginList.cellWidget(i, 0).use_stable_version}
+ "action": self.pluginList.cellWidget(i, 0).action,
+ "use_stable_version": self.pluginList.cellWidget(
+ i, 0
+ ).use_stable_version,
+ }
except:
pass
super().accept()
diff --git a/python/pyplugin_installer/qgsplugininstallerfetchingdialog.py b/python/pyplugin_installer/qgsplugininstallerfetchingdialog.py
index c38e15b64cf8..aeee08dbc3c5 100644
--- a/python/pyplugin_installer/qgsplugininstallerfetchingdialog.py
+++ b/python/pyplugin_installer/qgsplugininstallerfetchingdialog.py
@@ -1,4 +1,3 @@
-# -*- coding:utf-8 -*-
"""
/***************************************************************************
qgsplugininstallerfetchingdialog.py
@@ -33,10 +32,15 @@
from .installer_data import repositories
from qgis.gui import QgsGui
-Ui_QgsPluginInstallerFetchingDialogBase, _ = uic.loadUiType(Path(__file__).parent / 'qgsplugininstallerfetchingbase.ui')
+Ui_QgsPluginInstallerFetchingDialogBase, _ = uic.loadUiType(
+ Path(__file__).parent / "qgsplugininstallerfetchingbase.ui"
+)
-class QgsPluginInstallerFetchingDialog(QDialog, Ui_QgsPluginInstallerFetchingDialogBase):
+
+class QgsPluginInstallerFetchingDialog(
+ QDialog, Ui_QgsPluginInstallerFetchingDialogBase
+):
# ----------------------------------------- #
def __init__(self, parent):
@@ -65,13 +69,23 @@ def __init__(self, parent):
def displayState(self, key, state, state2=None):
messages = [
self.tr("Success"),
- QCoreApplication.translate('QgsPluginInstallerFetchingDialog', "Resolving host name…"),
- QCoreApplication.translate('QgsPluginInstallerFetchingDialog', "Connecting…"),
- QCoreApplication.translate('QgsPluginInstallerFetchingDialog', "Host connected. Sending request…"),
- QCoreApplication.translate('QgsPluginInstallerFetchingDialog', "Downloading data…"),
+ QCoreApplication.translate(
+ "QgsPluginInstallerFetchingDialog", "Resolving host name…"
+ ),
+ QCoreApplication.translate(
+ "QgsPluginInstallerFetchingDialog", "Connecting…"
+ ),
+ QCoreApplication.translate(
+ "QgsPluginInstallerFetchingDialog", "Host connected. Sending request…"
+ ),
+ QCoreApplication.translate(
+ "QgsPluginInstallerFetchingDialog", "Downloading data…"
+ ),
self.tr("Idle"),
- QCoreApplication.translate('QgsPluginInstallerFetchingDialog', "Closing connection…"),
- self.tr("Error")
+ QCoreApplication.translate(
+ "QgsPluginInstallerFetchingDialog", "Closing connection…"
+ ),
+ self.tr("Error"),
]
message = messages[state]
if state2:
diff --git a/python/pyplugin_installer/qgsplugininstallerinstallingdialog.py b/python/pyplugin_installer/qgsplugininstallerinstallingdialog.py
index d82c26d29dc3..ebd96422318f 100644
--- a/python/pyplugin_installer/qgsplugininstallerinstallingdialog.py
+++ b/python/pyplugin_installer/qgsplugininstallerinstallingdialog.py
@@ -1,4 +1,3 @@
-# -*- coding:utf-8 -*-
"""
/***************************************************************************
qgsplugininstallerinstallingdialog.py
@@ -23,7 +22,6 @@
* *
***************************************************************************/
"""
-from builtins import str
from pathlib import Path
@@ -32,16 +30,24 @@
from qgis.PyQt.QtWidgets import QDialog
from qgis.PyQt.QtNetwork import QNetworkRequest, QNetworkReply
-from qgis.core import QgsNetworkAccessManager, QgsApplication, QgsNetworkRequestParameters
+from qgis.core import (
+ QgsNetworkAccessManager,
+ QgsApplication,
+ QgsNetworkRequestParameters,
+)
from qgis.utils import HOME_PLUGIN_PATH
from .installer_data import removeDir, repositories
from .unzip import unzip
-Ui_QgsPluginInstallerInstallingDialogBase, _ = uic.loadUiType(Path(__file__).parent / 'qgsplugininstallerinstallingbase.ui')
+Ui_QgsPluginInstallerInstallingDialogBase, _ = uic.loadUiType(
+ Path(__file__).parent / "qgsplugininstallerinstallingbase.ui"
+)
-class QgsPluginInstallerInstallingDialog(QDialog, Ui_QgsPluginInstallerInstallingDialogBase):
+class QgsPluginInstallerInstallingDialog(
+ QDialog, Ui_QgsPluginInstallerInstallingDialogBase
+):
# ----------------------------------------- #
def __init__(self, parent, plugin, stable=True):
@@ -54,7 +60,11 @@ def __init__(self, parent, plugin, stable=True):
self.labelName.setText(plugin["name"])
self.buttonBox.clicked.connect(self.abort)
- self.url = QUrl(plugin["download_url_stable"] if stable else plugin["download_url_experimental"])
+ self.url = QUrl(
+ plugin["download_url_stable"]
+ if stable
+ else plugin["download_url_experimental"]
+ )
self.redirectionCounter = 0
fileName = plugin["filename"]
@@ -66,14 +76,21 @@ def __init__(self, parent, plugin, stable=True):
def requestDownloading(self):
self.request = QNetworkRequest(self.url)
- self.request.setAttribute(QNetworkRequest.Attribute(QgsNetworkRequestParameters.RequestAttributes.AttributeInitiatorClass), "QgsPluginInstallerInstallingDialog")
+ self.request.setAttribute(
+ QNetworkRequest.Attribute(
+ QgsNetworkRequestParameters.RequestAttributes.AttributeInitiatorClass
+ ),
+ "QgsPluginInstallerInstallingDialog",
+ )
authcfg = repositories.all()[self.plugin["zip_repository"]]["authcfg"]
if authcfg and isinstance(authcfg, str):
if not QgsApplication.authManager().updateNetworkRequest(
- self.request, authcfg.strip()):
+ self.request, authcfg.strip()
+ ):
self.mResult = self.tr(
"Update of network request with authentication "
- "credentials FAILED for configuration '{0}'").format(authcfg)
+ "credentials FAILED for configuration '{0}'"
+ ).format(authcfg)
self.request = None
if self.request is not None:
@@ -96,14 +113,26 @@ def result(self):
# ----------------------------------------- #
def stateChanged(self, state):
messages = [
- QCoreApplication.translate('QgsPluginInstallerInstallingDialog', "Installing…"),
- QCoreApplication.translate('QgsPluginInstallerInstallingDialog', "Resolving host name…"),
- QCoreApplication.translate('QgsPluginInstallerInstallingDialog', "Connecting…"),
- QCoreApplication.translate('QgsPluginInstallerInstallingDialog', "Host connected. Sending request…"),
- QCoreApplication.translate('QgsPluginInstallerInstallingDialog', "Downloading data…"),
+ QCoreApplication.translate(
+ "QgsPluginInstallerInstallingDialog", "Installing…"
+ ),
+ QCoreApplication.translate(
+ "QgsPluginInstallerInstallingDialog", "Resolving host name…"
+ ),
+ QCoreApplication.translate(
+ "QgsPluginInstallerInstallingDialog", "Connecting…"
+ ),
+ QCoreApplication.translate(
+ "QgsPluginInstallerInstallingDialog", "Host connected. Sending request…"
+ ),
+ QCoreApplication.translate(
+ "QgsPluginInstallerInstallingDialog", "Downloading data…"
+ ),
self.tr("Idle"),
- QCoreApplication.translate('QgsPluginInstallerInstallingDialog', "Closing connection…"),
- self.tr("Error")
+ QCoreApplication.translate(
+ "QgsPluginInstallerInstallingDialog", "Closing connection…"
+ ),
+ self.tr("Error"),
]
self.labelState.setText(messages[state])
@@ -120,15 +149,25 @@ def requestFinished(self):
if reply.error() != QNetworkReply.NetworkError.NoError:
self.mResult = reply.errorString()
if reply.error() == QNetworkReply.NetworkError.OperationCanceledError:
- self.mResult += " " + QCoreApplication.translate("QgsPluginInstaller", "If you haven't canceled the download manually, it might be caused by a timeout. In this case consider increasing the connection timeout value in QGIS options.")
+ self.mResult += " " + QCoreApplication.translate(
+ "QgsPluginInstaller",
+ "If you haven't canceled the download manually, it might be caused by a timeout. In this case consider increasing the connection timeout value in QGIS options.",
+ )
self.reject()
reply.deleteLater()
return
- elif reply.attribute(QNetworkRequest.Attribute.HttpStatusCodeAttribute) in (301, 302):
- redirectionUrl = reply.attribute(QNetworkRequest.Attribute.RedirectionTargetAttribute)
+ elif reply.attribute(QNetworkRequest.Attribute.HttpStatusCodeAttribute) in (
+ 301,
+ 302,
+ ):
+ redirectionUrl = reply.attribute(
+ QNetworkRequest.Attribute.RedirectionTargetAttribute
+ )
self.redirectionCounter += 1
if self.redirectionCounter > 4:
- self.mResult = QCoreApplication.translate("QgsPluginInstaller", "Too many redirections")
+ self.mResult = QCoreApplication.translate(
+ "QgsPluginInstaller", "Too many redirections"
+ )
self.reject()
reply.deleteLater()
return
@@ -154,12 +193,22 @@ def requestFinished(self):
# if the target directory already exists as a link, remove the link without resolving:
QFile(pluginDir + str(QDir.separator()) + self.plugin["id"]).remove()
try:
- unzip(str(tmpPath), str(pluginDir)) # test extract. If fails, then exception will be raised and no removing occurs
+ unzip(
+ str(tmpPath), str(pluginDir)
+ ) # test extract. If fails, then exception will be raised and no removing occurs
# removing old plugin files if exist
- removeDir(QDir.cleanPath(pluginDir + "/" + self.plugin["id"])) # remove old plugin if exists
+ removeDir(
+ QDir.cleanPath(pluginDir + "/" + self.plugin["id"])
+ ) # remove old plugin if exists
unzip(str(tmpPath), str(pluginDir)) # final extract.
except:
- self.mResult = self.tr("Failed to unzip the plugin package. Probably it's broken or missing from the repository. You may also want to make sure that you have write permission to the plugin directory:") + "\n" + pluginDir
+ self.mResult = (
+ self.tr(
+ "Failed to unzip the plugin package. Probably it's broken or missing from the repository. You may also want to make sure that you have write permission to the plugin directory:"
+ )
+ + "\n"
+ + pluginDir
+ )
self.reject()
return
try:
diff --git a/python/pyplugin_installer/qgsplugininstallerpluginerrordialog.py b/python/pyplugin_installer/qgsplugininstallerpluginerrordialog.py
index 76f635969bab..ad92ef73d930 100644
--- a/python/pyplugin_installer/qgsplugininstallerpluginerrordialog.py
+++ b/python/pyplugin_installer/qgsplugininstallerpluginerrordialog.py
@@ -1,4 +1,3 @@
-# -*- coding:utf-8 -*-
"""
/***************************************************************************
qgsplugininstallerpluginerrordialog.py
@@ -30,10 +29,14 @@
from qgis.PyQt import uic
-Ui_QgsPluginInstallerPluginErrorDialogBase, _ = uic.loadUiType(Path(__file__).parent / 'qgsplugininstallerpluginerrorbase.ui')
+Ui_QgsPluginInstallerPluginErrorDialogBase, _ = uic.loadUiType(
+ Path(__file__).parent / "qgsplugininstallerpluginerrorbase.ui"
+)
-class QgsPluginInstallerPluginErrorDialog(QDialog, Ui_QgsPluginInstallerPluginErrorDialogBase):
+class QgsPluginInstallerPluginErrorDialog(
+ QDialog, Ui_QgsPluginInstallerPluginErrorDialogBase
+):
# ----------------------------------------- #
def __init__(self, parent, errorMessage):
diff --git a/python/pyplugin_installer/qgsplugininstallerrepositorydialog.py b/python/pyplugin_installer/qgsplugininstallerrepositorydialog.py
index 80edeb84bab9..2499d859e4f6 100644
--- a/python/pyplugin_installer/qgsplugininstallerrepositorydialog.py
+++ b/python/pyplugin_installer/qgsplugininstallerrepositorydialog.py
@@ -1,4 +1,3 @@
-# -*- coding:utf-8 -*-
"""
/***************************************************************************
qgsplugininstallerrepositorydialog.py
@@ -31,10 +30,14 @@
from qgis.PyQt.QtWidgets import QDialog, QDialogButtonBox, QVBoxLayout
from qgis.PyQt.QtCore import Qt
-Ui_QgsPluginInstallerRepositoryDetailsDialogBase, _ = uic.loadUiType(Path(__file__).parent / 'qgsplugininstallerrepositorybase.ui')
+Ui_QgsPluginInstallerRepositoryDetailsDialogBase, _ = uic.loadUiType(
+ Path(__file__).parent / "qgsplugininstallerrepositorybase.ui"
+)
-class QgsPluginInstallerRepositoryDialog(QDialog, Ui_QgsPluginInstallerRepositoryDetailsDialogBase):
+class QgsPluginInstallerRepositoryDialog(
+ QDialog, Ui_QgsPluginInstallerRepositoryDetailsDialogBase
+):
# ----------------------------------------- #
def __init__(self, parent=None):
@@ -49,7 +52,7 @@ def __init__(self, parent=None):
# ----------------------------------------- #
def textChanged(self, string):
- enable = (len(self.editName.text()) > 0 and len(self.editURL.text()) > 0)
+ enable = len(self.editName.text()) > 0 and len(self.editURL.text()) > 0
self.buttonBox.button(QDialogButtonBox.StandardButton.Ok).setEnabled(enable)
def editAuthCfgId(self):
@@ -60,7 +63,9 @@ def editAuthCfgId(self):
if self.editAuthCfg.text():
selector.setConfigId(self.editAuthCfg.text())
layout.addWidget(selector)
- buttonBox = QDialogButtonBox(QDialogButtonBox.StandardButton.Ok | QDialogButtonBox.StandardButton.Close)
+ buttonBox = QDialogButtonBox(
+ QDialogButtonBox.StandardButton.Ok | QDialogButtonBox.StandardButton.Close
+ )
buttonBox.accepted.connect(dlg.accept)
buttonBox.rejected.connect(dlg.reject)
layout.addWidget(buttonBox)
diff --git a/python/pyplugin_installer/unzip.py b/python/pyplugin_installer/unzip.py
index 7be620e75092..d4a80f8bcda4 100644
--- a/python/pyplugin_installer/unzip.py
+++ b/python/pyplugin_installer/unzip.py
@@ -1,4 +1,3 @@
-# -*- coding:utf-8 -*-
"""
/***************************************************************************
Plugin Installer module
@@ -25,24 +24,24 @@
def unzip(file, targetDir, password=None):
- """ Creates directory structure and extracts the zip contents to it.
- file (file object) - the zip file to extract
- targetDir (str) - target location
- password (str; optional) - password to decrypt the zip file (if encrypted)
+ """Creates directory structure and extracts the zip contents to it.
+ file (file object) - the zip file to extract
+ targetDir (str) - target location
+ password (str; optional) - password to decrypt the zip file (if encrypted)
"""
# convert password to bytes
if isinstance(password, str):
- password = bytes(password, 'utf8')
+ password = bytes(password, "utf8")
# create destination directory if doesn't exist
- if not targetDir.endswith(':') and not os.path.exists(targetDir):
+ if not targetDir.endswith(":") and not os.path.exists(targetDir):
os.makedirs(targetDir)
zf = zipfile.ZipFile(file)
for name in zf.namelist():
# Skip directories - they will be created when necessary by os.makedirs
- if name.endswith('/'):
+ if name.endswith("/"):
continue
# Read the source file before creating any output,
@@ -56,7 +55,7 @@ def unzip(file, targetDir, password=None):
os.makedirs(fullDir)
# extract file
fullPath = os.path.normpath(os.path.join(targetDir, name))
- outfile = open(fullPath, 'wb')
+ outfile = open(fullPath, "wb")
outfile.write(memberContent)
outfile.flush()
outfile.close()
diff --git a/python/pyplugin_installer/version_compare.py b/python/pyplugin_installer/version_compare.py
index ebcb5c0924a9..2871062e2bc1 100644
--- a/python/pyplugin_installer/version_compare.py
+++ b/python/pyplugin_installer/version_compare.py
@@ -45,8 +45,7 @@
list is usually recognized as higher, except following suffixes:
ALPHA, BETA, RC, PREVIEW and TRUNK which make the version number lower.
"""
-from builtins import str
-from builtins import range
+
from qgis.core import Qgis
import re
@@ -56,21 +55,32 @@
def normalizeVersion(s):
- """ remove possible prefix from given string and convert to uppercase """
- prefixes = ['VERSION', 'VER.', 'VER', 'V.', 'V', 'REVISION', 'REV.', 'REV', 'R.', 'R']
+ """remove possible prefix from given string and convert to uppercase"""
+ prefixes = [
+ "VERSION",
+ "VER.",
+ "VER",
+ "V.",
+ "V",
+ "REVISION",
+ "REV.",
+ "REV",
+ "R.",
+ "R",
+ ]
if not s:
- return str()
+ return ""
s = str(s).upper()
for i in prefixes:
- if s[:len(i)] == i:
- s = s.replace(i, '')
+ if s[: len(i)] == i:
+ s = s.replace(i, "")
s = s.strip()
return s
# ------------------------------------------------------------------------ #
def classifyCharacter(c):
- """ return 0 for delimiter, 1 for digit and 2 for alphabetic character """
+ """return 0 for delimiter, 1 for digit and 2 for alphabetic character"""
if c in [".", "-", "_", " "]:
return 0
if c.isdigit():
@@ -81,7 +91,7 @@ def classifyCharacter(c):
# ------------------------------------------------------------------------ #
def chopString(s):
- """ convert string to list of numbers and words """
+ """convert string to list of numbers and words"""
l = [s[0]]
for i in range(1, len(s)):
if classifyCharacter(s[i]) == 0:
@@ -95,12 +105,19 @@ def chopString(s):
# ------------------------------------------------------------------------ #
def compareElements(s1, s2):
- """ compare two particular elements """
+ """compare two particular elements"""
# check if the matter is easy solvable:
if s1 == s2:
return 0
# try to compare as numeric values (but only if the first character is not 0):
- if s1 and s2 and s1.isnumeric() and s2.isnumeric() and s1[0] != '0' and s2[0] != '0':
+ if (
+ s1
+ and s2
+ and s1.isnumeric()
+ and s2.isnumeric()
+ and s1[0] != "0"
+ and s2[0] != "0"
+ ):
if float(s1) == float(s2):
return 0
elif float(s1) > float(s2):
@@ -109,10 +126,10 @@ def compareElements(s1, s2):
return 2
# if the strings aren't numeric or start from 0, compare them as a strings:
# but first, set ALPHA < BETA < PREVIEW < RC < TRUNK < [NOTHING] < [ANYTHING_ELSE]
- if s1 not in ['ALPHA', 'BETA', 'PREVIEW', 'RC', 'TRUNK']:
- s1 = 'Z' + s1
- if s2 not in ['ALPHA', 'BETA', 'PREVIEW', 'RC', 'TRUNK']:
- s2 = 'Z' + s2
+ if s1 not in ["ALPHA", "BETA", "PREVIEW", "RC", "TRUNK"]:
+ s1 = "Z" + s1
+ if s2 not in ["ALPHA", "BETA", "PREVIEW", "RC", "TRUNK"]:
+ s2 = "Z" + s2
# the final test:
if s1 > s2:
return 1
@@ -122,7 +139,7 @@ def compareElements(s1, s2):
# ------------------------------------------------------------------------ #
def compareVersions(a, b):
- """ Compare two version numbers. Return 0 if a==b or error, 1 if a>b and 2 if b>a """
+ """Compare two version numbers. Return 0 if a==b or error, 1 if a>b and 2 if b>a"""
if not a or not b:
return 0
a = normalizeVersion(a)
@@ -143,9 +160,9 @@ def compareVersions(a, b):
# if the lists are identical till the end of the shorter string, try to compare the odd tail
# with the simple space (because the 'alpha', 'beta', 'preview' and 'rc' are LESS then nothing)
if len(v1) > l:
- return compareElements(v1[l], ' ')
+ return compareElements(v1[l], " ")
if len(v2) > l:
- return compareElements(' ', v2[l])
+ return compareElements(" ", v2[l])
# if everything else fails...
if a > b:
return 1
@@ -160,10 +177,10 @@ def compareVersions(a, b):
def splitVersion(s):
- """ split string into 2 or 3 numerical segments """
+ """split string into 2 or 3 numerical segments"""
if not s or type(s) is not str:
return None
- l = str(s).split('.')
+ l = str(s).split(".")
for c in l:
if not c.isnumeric():
return None
@@ -175,14 +192,14 @@ def splitVersion(s):
def isCompatible(curVer, minVer, maxVer):
- """ Compare current QGIS version with qgisMinVersion and qgisMaxVersion """
+ """Compare current QGIS version with qgisMinVersion and qgisMaxVersion"""
if not minVer or not curVer or not maxVer:
return False
- minVer = splitVersion(re.sub(r'[^0-9.]+', '', minVer))
- maxVer = splitVersion(re.sub(r'[^0-9.]+', '', maxVer))
- curVer = splitVersion(re.sub(r'[^0-9.]+', '', curVer))
+ minVer = splitVersion(re.sub(r"[^0-9.]+", "", minVer))
+ maxVer = splitVersion(re.sub(r"[^0-9.]+", "", maxVer))
+ curVer = splitVersion(re.sub(r"[^0-9.]+", "", curVer))
if not minVer or not curVer or not maxVer:
return False
@@ -196,20 +213,20 @@ def isCompatible(curVer, minVer, maxVer):
if len(maxVer) < 3:
maxVer += ["99"]
- minVer = "{:04n}{:04n}{:04n}".format(int(minVer[0]), int(minVer[1]), int(minVer[2]))
- maxVer = "{:04n}{:04n}{:04n}".format(int(maxVer[0]), int(maxVer[1]), int(maxVer[2]))
- curVer = "{:04n}{:04n}{:04n}".format(int(curVer[0]), int(curVer[1]), int(curVer[2]))
+ minVer = f"{int(minVer[0]):04n}{int(minVer[1]):04n}{int(minVer[2]):04n}"
+ maxVer = f"{int(maxVer[0]):04n}{int(maxVer[1]):04n}{int(maxVer[2]):04n}"
+ curVer = f"{int(curVer[0]):04n}{int(curVer[1]):04n}{int(curVer[2]):04n}"
- return (minVer <= curVer and maxVer >= curVer)
+ return minVer <= curVer and maxVer >= curVer
def pyQgisVersion():
- """ Return current QGIS version number as X.Y.Z for testing plugin compatibility.
- If Y = 99, bump up to (X+1.0.0), so e.g. 2.99 becomes 3.0.0
- This way QGIS X.99 is only compatible with plugins for the upcoming major release.
+ """Return current QGIS version number as X.Y.Z for testing plugin compatibility.
+ If Y = 99, bump up to (X+1.0.0), so e.g. 2.99 becomes 3.0.0
+ This way QGIS X.99 is only compatible with plugins for the upcoming major release.
"""
- x, y, z = re.findall(r'^(\d*).(\d*).(\d*)', Qgis.QGIS_VERSION)[0]
- if y == '99':
+ x, y, z = re.findall(r"^(\d*).(\d*).(\d*)", Qgis.QGIS_VERSION)[0]
+ if y == "99":
x = str(int(x) + 1)
- y = z = '0'
- return '{}.{}.{}'.format(x, y, z)
+ y = z = "0"
+ return f"{x}.{y}.{z}"
diff --git a/python/testing/__init__.py b/python/testing/__init__.py
index f7608a27518f..33087f26de05 100644
--- a/python/testing/__init__.py
+++ b/python/testing/__init__.py
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-
"""
***************************************************************************
__init__.py
@@ -41,13 +39,9 @@
QDir,
QUrl,
QSize,
- QCoreApplication
-)
-from qgis.PyQt.QtGui import (
- QImage,
- QDesktopServices,
- QPainter
+ QCoreApplication,
)
+from qgis.PyQt.QtGui import QImage, QDesktopServices, QPainter
from qgis.core import (
QgsApplication,
QgsFeatureRequest,
@@ -71,12 +65,12 @@ def is_ci_run() -> bool:
"""
Returns True if the test is being run on the CI environment
"""
- return os.environ.get("QGIS_CONTINUOUS_INTEGRATION_RUN") == 'true'
+ return os.environ.get("QGIS_CONTINUOUS_INTEGRATION_RUN") == "true"
@classmethod
def setUpClass(cls):
- cls.report = ''
- cls.markdown_report = ''
+ cls.report = ""
+ cls.markdown_report = ""
@classmethod
def tearDownClass(cls):
@@ -98,32 +92,35 @@ def write_local_html_report(cls, report: str):
if not report_dir.exists():
QDir().mkpath(report_dir.path())
- report_file = report_dir.filePath('index.html')
+ report_file = report_dir.filePath("index.html")
# only append to existing reports if running under CI
file_is_empty = True
- if cls.is_ci_run() or \
- os.environ.get("QGIS_APPEND_TO_TEST_REPORT") == 'true':
- file_mode = 'ta'
+ if cls.is_ci_run() or os.environ.get("QGIS_APPEND_TO_TEST_REPORT") == "true":
+ file_mode = "ta"
try:
- with open(report_file, 'rt', encoding="utf-8") as f:
+ with open(report_file, encoding="utf-8") as f:
file_is_empty = not bool(f.read())
- except IOError:
+ except OSError:
pass
else:
- file_mode = 'wt'
+ file_mode = "wt"
- with open(report_file, file_mode, encoding='utf-8') as f:
+ with open(report_file, file_mode, encoding="utf-8") as f:
if file_is_empty:
from .test_data_dir import TEST_DATA_DIR
# append standard header
- with open(TEST_DATA_DIR + "/../test_report_header.html", 'rt', encoding='utf-8') as header_file:
+ with open(
+ TEST_DATA_DIR + "/../test_report_header.html", encoding="utf-8"
+ ) as header_file:
f.write(header_file.read())
# append embedded scripts
- f.write('\n")
@@ -153,7 +150,7 @@ def write_local_markdown_report(cls, report: str):
@classmethod
def get_test_caller_details(
cls,
- ) -> Tuple[Optional[str], Optional[str], Optional[int]]:
+ ) -> tuple[Optional[str], Optional[str], Optional[int]]:
"""
Retrieves the details of the caller at the earliest position
in the stack, excluding unittest internals.
@@ -186,7 +183,7 @@ def image_check(
size_tolerance: Optional[Union[int, QSize]] = None,
expect_fail: bool = False,
control_path_prefix: Optional[str] = None,
- use_checkerboard_background: bool = False
+ use_checkerboard_background: bool = False,
) -> bool:
if use_checkerboard_background:
output_image = QImage(image.size(), QImage.Format.Format_RGB32)
@@ -217,7 +214,9 @@ def image_check(
if size_tolerance is not None:
if isinstance(size_tolerance, QSize):
if size_tolerance.isValid():
- checker.setSizeTolerance(size_tolerance.width(), size_tolerance.height())
+ checker.setSizeTolerance(
+ size_tolerance.width(), size_tolerance.height()
+ )
else:
checker.setSizeTolerance(size_tolerance, size_tolerance)
@@ -228,7 +227,7 @@ def image_check(
markdown = checker.markdownReport()
if markdown:
- cls.markdown_report += "## {}\n\n".format(name)
+ cls.markdown_report += f"## {name}\n\n"
cls.markdown_report += markdown
return result
@@ -242,7 +241,7 @@ def render_map_settings_check(
control_name=None,
color_tolerance: Optional[int] = None,
allowed_mismatch: Optional[int] = None,
- control_path_prefix: Optional[str] = None
+ control_path_prefix: Optional[str] = None,
) -> bool:
checker = QgsMultiRenderChecker()
checker.setMapSettings(map_settings)
@@ -265,19 +264,20 @@ def render_map_settings_check(
markdown = checker.markdownReport()
if markdown:
- cls.markdown_report += "## {}\n\n".format(name)
+ cls.markdown_report += f"## {name}\n\n"
cls.markdown_report += markdown
return result
@classmethod
def render_layout_check(
- cls, name: str,
+ cls,
+ name: str,
layout: QgsLayout,
size: Optional[QSize] = None,
color_tolerance: Optional[int] = None,
allowed_mismatch: Optional[int] = None,
- page: Optional[int] = 0
+ page: Optional[int] = 0,
) -> bool:
checker = QgsLayoutChecker(name, layout)
@@ -292,15 +292,14 @@ def render_layout_check(
if cls.control_path_prefix():
checker.setControlPathPrefix(cls.control_path_prefix())
- result, message = checker.testLayout(page=page,
- pixelDiff=allowed_mismatch or 0)
+ result, message = checker.testLayout(page=page, pixelDiff=allowed_mismatch or 0)
if not result:
cls.report += f"Render {name} \n"
cls.report += checker.report()
markdown = checker.markdownReport()
if markdown:
- cls.markdown_report += "## {}\n\n".format(name)
+ cls.markdown_report += f"## {name}\n\n"
cls.markdown_report += markdown
return result
@@ -313,9 +312,8 @@ def get_test_data_path(file_path: str) -> Path:
"""
from utilities import unitTestDataPath
- return (
- Path(unitTestDataPath()) /
- (file_path[1:] if file_path.startswith('/') else file_path)
+ return Path(unitTestDataPath()) / (
+ file_path[1:] if file_path.startswith("/") else file_path
)
def assertLayersEqual(self, layer_expected, layer_result, **kwargs):
@@ -335,7 +333,9 @@ def assertLayersEqual(self, layer_expected, layer_result, **kwargs):
"""
self.checkLayersEqual(layer_expected, layer_result, True, **kwargs)
- def checkLayersEqual(self, layer_expected, layer_result, use_asserts=False, **kwargs):
+ def checkLayersEqual(
+ self, layer_expected, layer_result, use_asserts=False, **kwargs
+ ):
"""
:param layer_expected: The first layer to compare
:param layer_result: The second layer to compare
@@ -354,23 +354,36 @@ def checkLayersEqual(self, layer_expected, layer_result, use_asserts=False, **kw
"""
try:
- request = kwargs['request']
+ request = kwargs["request"]
except KeyError:
request = QgsFeatureRequest()
try:
- compare = kwargs['compare']
+ compare = kwargs["compare"]
except KeyError:
compare = {}
# Compare CRS
- if 'ignore_crs_check' not in compare or not compare['ignore_crs_check']:
- expected_wkt = layer_expected.dataProvider().crs().toWkt(QgsCoordinateReferenceSystem.WktVariant.WKT_PREFERRED)
- result_wkt = layer_result.dataProvider().crs().toWkt(QgsCoordinateReferenceSystem.WktVariant.WKT_PREFERRED)
+ if "ignore_crs_check" not in compare or not compare["ignore_crs_check"]:
+ expected_wkt = (
+ layer_expected.dataProvider()
+ .crs()
+ .toWkt(QgsCoordinateReferenceSystem.WktVariant.WKT_PREFERRED)
+ )
+ result_wkt = (
+ layer_result.dataProvider()
+ .crs()
+ .toWkt(QgsCoordinateReferenceSystem.WktVariant.WKT_PREFERRED)
+ )
if use_asserts:
- self.assertEqual(layer_expected.dataProvider().crs(), layer_result.dataProvider().crs())
- elif layer_expected.dataProvider().crs() != layer_result.dataProvider().crs():
+ self.assertEqual(
+ layer_expected.dataProvider().crs(),
+ layer_result.dataProvider().crs(),
+ )
+ elif (
+ layer_expected.dataProvider().crs() != layer_result.dataProvider().crs()
+ ):
return False
# Compare features
@@ -380,42 +393,42 @@ def checkLayersEqual(self, layer_expected, layer_result, use_asserts=False, **kw
return False
try:
- precision = compare['geometry']['precision']
+ precision = compare["geometry"]["precision"]
except KeyError:
precision = 14
try:
- topo_equal_check = compare['geometry']['topo_equal_check']
+ topo_equal_check = compare["geometry"]["topo_equal_check"]
except KeyError:
topo_equal_check = False
try:
- ignore_part_order = compare['geometry']['ignore_part_order']
+ ignore_part_order = compare["geometry"]["ignore_part_order"]
except KeyError:
ignore_part_order = False
try:
- normalize = compare['geometry']['normalize']
+ normalize = compare["geometry"]["normalize"]
except KeyError:
normalize = False
try:
- explode_collections = compare['geometry']['explode_collections']
+ explode_collections = compare["geometry"]["explode_collections"]
except KeyError:
explode_collections = False
try:
- snap_to_grid = compare['geometry']['snap_to_grid']
+ snap_to_grid = compare["geometry"]["snap_to_grid"]
except KeyError:
snap_to_grid = None
try:
- unordered = compare['unordered']
+ unordered = compare["unordered"]
except KeyError:
unordered = False
try:
- equate_null_and_empty = compare['geometry']['equate_null_and_empty']
+ equate_null_and_empty = compare["geometry"]["equate_null_and_empty"]
except KeyError:
equate_null_and_empty = False
@@ -424,13 +437,22 @@ def checkLayersEqual(self, layer_expected, layer_result, use_asserts=False, **kw
for feat in layer_result.getFeatures(request):
feat_expected_equal = None
for feat_expected in features_expected:
- if self.checkGeometriesEqual(feat.geometry(), feat_expected.geometry(),
- feat.id(), feat_expected.id(),
- False, precision, topo_equal_check, ignore_part_order, normalize=normalize,
- explode_collections=explode_collections,
- snap_to_grid=snap_to_grid,
- equate_null_and_empty=equate_null_and_empty) and \
- self.checkAttributesEqual(feat, feat_expected, layer_expected.fields(), False, compare):
+ if self.checkGeometriesEqual(
+ feat.geometry(),
+ feat_expected.geometry(),
+ feat.id(),
+ feat_expected.id(),
+ False,
+ precision,
+ topo_equal_check,
+ ignore_part_order,
+ normalize=normalize,
+ explode_collections=explode_collections,
+ snap_to_grid=snap_to_grid,
+ equate_null_and_empty=equate_null_and_empty,
+ ) and self.checkAttributesEqual(
+ feat, feat_expected, layer_expected.fields(), False, compare
+ ):
feat_expected_equal = feat_expected
break
@@ -440,10 +462,15 @@ def checkLayersEqual(self, layer_expected, layer_result, use_asserts=False, **kw
if use_asserts:
self.assertTrue(
False,
- 'Unexpected result feature: fid {}, geometry: {}, attributes: {}'.format(
+ "Unexpected result feature: fid {}, geometry: {}, attributes: {}".format(
feat.id(),
- feat.geometry().constGet().asWkt(precision) if feat.geometry() else 'NULL',
- feat.attributes())
+ (
+ feat.geometry().constGet().asWkt(precision)
+ if feat.geometry()
+ else "NULL"
+ ),
+ feat.attributes(),
+ ),
)
else:
return False
@@ -452,24 +479,34 @@ def checkLayersEqual(self, layer_expected, layer_result, use_asserts=False, **kw
if use_asserts:
lst_missing = []
for feat in features_expected:
- lst_missing.append('fid {}, geometry: {}, attributes: {}'.format(
- feat.id(),
- feat.geometry().constGet().asWkt(precision) if feat.geometry() else 'NULL',
- feat.attributes())
+ lst_missing.append(
+ "fid {}, geometry: {}, attributes: {}".format(
+ feat.id(),
+ (
+ feat.geometry().constGet().asWkt(precision)
+ if feat.geometry()
+ else "NULL"
+ ),
+ feat.attributes(),
+ )
)
- self.assertTrue(False, 'Some expected features not found in results:\n' + '\n'.join(lst_missing))
+ self.assertTrue(
+ False,
+ "Some expected features not found in results:\n"
+ + "\n".join(lst_missing),
+ )
else:
return False
return True
def get_pk_or_fid(f):
- if 'pk' in kwargs and kwargs['pk'] is not None:
- key = kwargs['pk']
+ if "pk" in kwargs and kwargs["pk"] is not None:
+ key = kwargs["pk"]
if isinstance(key, list) or isinstance(key, tuple):
return [f[k] for k in key]
else:
- return f[kwargs['pk']]
+ return f[kwargs["pk"]]
else:
return f.id()
@@ -481,39 +518,53 @@ def sort_by_pk_or_fid(f):
pk = [(v == NULL, v) for v in pk]
return (pk == NULL, pk)
- expected_features = sorted(layer_expected.getFeatures(request), key=sort_by_pk_or_fid)
- result_features = sorted(layer_result.getFeatures(request), key=sort_by_pk_or_fid)
+ expected_features = sorted(
+ layer_expected.getFeatures(request), key=sort_by_pk_or_fid
+ )
+ result_features = sorted(
+ layer_result.getFeatures(request), key=sort_by_pk_or_fid
+ )
for feats in zip(expected_features, result_features):
- eq = self.checkGeometriesEqual(feats[0].geometry(),
- feats[1].geometry(),
- feats[0].id(),
- feats[1].id(),
- use_asserts, precision, topo_equal_check, ignore_part_order, normalize=normalize, explode_collections=explode_collections,
- snap_to_grid=snap_to_grid, equate_null_and_empty=equate_null_and_empty)
+ eq = self.checkGeometriesEqual(
+ feats[0].geometry(),
+ feats[1].geometry(),
+ feats[0].id(),
+ feats[1].id(),
+ use_asserts,
+ precision,
+ topo_equal_check,
+ ignore_part_order,
+ normalize=normalize,
+ explode_collections=explode_collections,
+ snap_to_grid=snap_to_grid,
+ equate_null_and_empty=equate_null_and_empty,
+ )
if not eq and not use_asserts:
return False
- eq = self.checkAttributesEqual(feats[0], feats[1], layer_expected.fields(), use_asserts, compare)
+ eq = self.checkAttributesEqual(
+ feats[0], feats[1], layer_expected.fields(), use_asserts, compare
+ )
if not eq and not use_asserts:
return False
return True
def checkFilesEqual(self, filepath_expected, filepath_result, use_asserts=False):
- with open(filepath_expected, 'r') as file_expected:
- with open(filepath_result, 'r') as file_result:
+ with open(filepath_expected) as file_expected:
+ with open(filepath_result) as file_result:
diff = difflib.unified_diff(
file_expected.readlines(),
file_result.readlines(),
- fromfile='expected',
- tofile='result',
+ fromfile="expected",
+ tofile="result",
)
diff = list(diff)
eq = not len(diff)
if use_asserts:
- self.assertEqual(0, len(diff), ''.join(diff))
+ self.assertEqual(0, len(diff), "".join(diff))
else:
return eq
@@ -529,8 +580,16 @@ def assertDirectoryEqual(self, dirpath_expected: str, dirpath_result: str):
contents_result = list(path_result.iterdir())
contents_expected = list(path_expected.iterdir())
- contents_expected = [p for p in contents_expected if p.suffix != '.png' or not p.stem.endswith('_mask')]
- self.assertCountEqual([p.name if p.is_file() else p.stem for p in contents_expected], [p.name if p.is_file() else p.stem for p in contents_result], f'Directory contents mismatch in {dirpath_expected} vs {dirpath_result}')
+ contents_expected = [
+ p
+ for p in contents_expected
+ if p.suffix != ".png" or not p.stem.endswith("_mask")
+ ]
+ self.assertCountEqual(
+ [p.name if p.is_file() else p.stem for p in contents_expected],
+ [p.name if p.is_file() else p.stem for p in contents_result],
+ f"Directory contents mismatch in {dirpath_expected} vs {dirpath_result}",
+ )
# compare file contents
for expected_file_path in contents_expected:
@@ -539,23 +598,29 @@ def assertDirectoryEqual(self, dirpath_expected: str, dirpath_result: str):
result_file_path = path_result / expected_file_path.name
- if expected_file_path.suffix == '.pbf':
+ if expected_file_path.suffix == ".pbf":
# vector layer, use assertLayersEqual
- layer_expected = QgsVectorLayer(str(expected_file_path), 'Expected')
+ layer_expected = QgsVectorLayer(str(expected_file_path), "Expected")
self.assertTrue(layer_expected.isValid())
- layer_result = QgsVectorLayer(str(result_file_path), 'Result')
+ layer_result = QgsVectorLayer(str(result_file_path), "Result")
self.assertTrue(layer_result.isValid())
self.assertLayersEqual(layer_expected, layer_result)
- elif expected_file_path.suffix == '.png':
+ elif expected_file_path.suffix == ".png":
# image file, use QgsRenderChecker
checker = QgsRenderChecker()
- res = checker.compareImages(expected_file_path.stem, expected_file_path.as_posix(), result_file_path.as_posix())
+ res = checker.compareImages(
+ expected_file_path.stem,
+ expected_file_path.as_posix(),
+ result_file_path.as_posix(),
+ )
self.assertTrue(res)
else:
- assert False, f"Don't know how to compare {expected_file_path.suffix} files"
+ assert (
+ False
+ ), f"Don't know how to compare {expected_file_path.suffix} files"
def assertDirectoriesEqual(self, dirpath_expected: str, dirpath_result: str):
- """ Checks whether both directories have the same content (recursively) and raises an assertion error if not. """
+ """Checks whether both directories have the same content (recursively) and raises an assertion error if not."""
self.assertDirectoryEqual(dirpath_expected, dirpath_result)
# recurse through subfolders
@@ -565,26 +630,70 @@ def assertDirectoriesEqual(self, dirpath_expected: str, dirpath_result: str):
if p.is_dir():
self.assertDirectoriesEqual(str(p), path_result / p.stem)
- def assertGeometriesEqual(self, geom0, geom1, geom0_id='geometry 1', geom1_id='geometry 2', precision=14, topo_equal_check=False, ignore_part_order=False, normalize=False, explode_collections=False, snap_to_grid=None, equate_null_and_empty=False):
- self.checkGeometriesEqual(geom0, geom1, geom0_id, geom1_id, use_asserts=True, precision=precision, topo_equal_check=topo_equal_check, ignore_part_order=ignore_part_order, normalize=normalize, explode_collections=explode_collections, snap_to_grid=snap_to_grid, equate_null_and_empty=equate_null_and_empty)
+ def assertGeometriesEqual(
+ self,
+ geom0,
+ geom1,
+ geom0_id="geometry 1",
+ geom1_id="geometry 2",
+ precision=14,
+ topo_equal_check=False,
+ ignore_part_order=False,
+ normalize=False,
+ explode_collections=False,
+ snap_to_grid=None,
+ equate_null_and_empty=False,
+ ):
+ self.checkGeometriesEqual(
+ geom0,
+ geom1,
+ geom0_id,
+ geom1_id,
+ use_asserts=True,
+ precision=precision,
+ topo_equal_check=topo_equal_check,
+ ignore_part_order=ignore_part_order,
+ normalize=normalize,
+ explode_collections=explode_collections,
+ snap_to_grid=snap_to_grid,
+ equate_null_and_empty=equate_null_and_empty,
+ )
- def checkGeometriesEqual(self, geom0, geom1, geom0_id, geom1_id, use_asserts=False, precision=14, topo_equal_check=False, ignore_part_order=False, normalize=False, explode_collections=False, snap_to_grid=None, equate_null_and_empty=False):
- """ Checks whether two geometries are the same - using either a strict check of coordinates (up to given precision)
+ def checkGeometriesEqual(
+ self,
+ geom0,
+ geom1,
+ geom0_id,
+ geom1_id,
+ use_asserts=False,
+ precision=14,
+ topo_equal_check=False,
+ ignore_part_order=False,
+ normalize=False,
+ explode_collections=False,
+ snap_to_grid=None,
+ equate_null_and_empty=False,
+ ):
+ """Checks whether two geometries are the same - using either a strict check of coordinates (up to given precision)
or by using topological equality (where e.g. a polygon with clockwise is equal to a polygon with counter-clockwise
order of vertices)
.. versionadded:: 3.2
"""
- geom0_wkt = ''
- geom0_wkt_full = ''
- geom1_wkt = ''
- geom1_wkt_full = ''
+ geom0_wkt = ""
+ geom0_wkt_full = ""
+ geom1_wkt = ""
+ geom1_wkt_full = ""
geom0_is_null = geom0.isNull() or (equate_null_and_empty and geom0.isEmpty())
geom1_is_null = geom1.isNull() or (equate_null_and_empty and geom1.isEmpty())
if not geom0_is_null and not geom1_is_null:
if snap_to_grid is not None:
- geom0 = geom0.snappedToGrid(snap_to_grid, snap_to_grid, snap_to_grid, snap_to_grid)
- geom1 = geom1.snappedToGrid(snap_to_grid, snap_to_grid, snap_to_grid, snap_to_grid)
+ geom0 = geom0.snappedToGrid(
+ snap_to_grid, snap_to_grid, snap_to_grid, snap_to_grid
+ )
+ geom1 = geom1.snappedToGrid(
+ snap_to_grid, snap_to_grid, snap_to_grid, snap_to_grid
+ )
if normalize:
geom0.normalize()
geom1.normalize()
@@ -602,7 +711,9 @@ def checkGeometriesEqual(self, geom0, geom1, geom0_id, geom1_id, use_asserts=Fal
if not equal and topo_equal_check:
equal = geom0.isGeosEqual(geom1)
if not equal and ignore_part_order and geom0.isMultipart():
- equal = sorted([p.asWkt(precision) for p in geom0.constParts()]) == sorted([p.asWkt(precision) for p in geom1.constParts()])
+ equal = sorted(
+ [p.asWkt(precision) for p in geom0.constParts()]
+ ) == sorted([p.asWkt(precision) for p in geom1.constParts()])
elif geom0_is_null and geom1_is_null:
equal = True
else:
@@ -614,90 +725,102 @@ def checkGeometriesEqual(self, geom0, geom1, geom0_id, geom1_id, use_asserts=Fal
if use_asserts:
self.assertTrue(
- equal, ''
- ' Features (Expected fid: {}, Result fid: {}) differ in geometry with method {}: \n\n'
- ' At given precision ({}):\n'
- ' Expected geometry: {}\n'
- ' Result geometry: {}\n\n'
- ' Full precision:\n'
- ' Expected geometry : {}\n'
- ' Result geometry: {}\n\n'.format(
+ equal,
+ ""
+ " Features (Expected fid: {}, Result fid: {}) differ in geometry with method {}: \n\n"
+ " At given precision ({}):\n"
+ " Expected geometry: {}\n"
+ " Result geometry: {}\n\n"
+ " Full precision:\n"
+ " Expected geometry : {}\n"
+ " Result geometry: {}\n\n".format(
geom0_id,
geom1_id,
- 'geos' if topo_equal_check else 'wkt',
+ "geos" if topo_equal_check else "wkt",
precision,
- geom0_wkt if not geom0_is_null else 'NULL',
- geom1_wkt if not geom1_is_null else 'NULL',
- geom0_wkt_full if not geom0_is_null else 'NULL',
- geom1_wkt_full if not geom1_is_null else 'NULL'
- )
+ geom0_wkt if not geom0_is_null else "NULL",
+ geom1_wkt if not geom1_is_null else "NULL",
+ geom0_wkt_full if not geom0_is_null else "NULL",
+ geom1_wkt_full if not geom1_is_null else "NULL",
+ ),
)
else:
return equal
def checkAttributesEqual(self, feat0, feat1, fields_expected, use_asserts, compare):
- """ Checks whether attributes of two features are the same
+ """Checks whether attributes of two features are the same
.. versionadded:: 3.2
"""
- for attr_expected, field_expected in zip(feat0.attributes(), fields_expected.toList()):
+ for attr_expected, field_expected in zip(
+ feat0.attributes(), fields_expected.toList()
+ ):
try:
- cmp = compare['fields'][field_expected.name()]
+ cmp = compare["fields"][field_expected.name()]
except KeyError:
try:
- cmp = compare['fields']['__all__']
+ cmp = compare["fields"]["__all__"]
except KeyError:
cmp = {}
# Skip field
- if 'skip' in cmp:
+ if "skip" in cmp:
continue
if use_asserts:
self.assertIn(
field_expected.name().lower(),
- [name.lower() for name in feat1.fields().names()])
+ [name.lower() for name in feat1.fields().names()],
+ )
attr_result = feat1[field_expected.name()]
- field_result = [fld for fld in fields_expected.toList() if fld.name() == field_expected.name()][0]
+ field_result = [
+ fld
+ for fld in fields_expected.toList()
+ if fld.name() == field_expected.name()
+ ][0]
# Cast field to a given type
isNumber = False
- if 'cast' in cmp:
- if cmp['cast'] == 'int':
+ if "cast" in cmp:
+ if cmp["cast"] == "int":
attr_expected = int(attr_expected) if attr_expected else None
attr_result = int(attr_result) if attr_result else None
isNumber = True
- if cmp['cast'] == 'float':
+ if cmp["cast"] == "float":
attr_expected = float(attr_expected) if attr_expected else None
attr_result = float(attr_result) if attr_result else None
isNumber = True
- if cmp['cast'] == 'str':
+ if cmp["cast"] == "str":
if isinstance(attr_expected, QDateTime):
- attr_expected = attr_expected.toString('yyyy/MM/dd hh:mm:ss')
+ attr_expected = attr_expected.toString("yyyy/MM/dd hh:mm:ss")
elif isinstance(attr_expected, QDate):
- attr_expected = attr_expected.toString('yyyy/MM/dd')
+ attr_expected = attr_expected.toString("yyyy/MM/dd")
else:
attr_expected = str(attr_expected) if attr_expected else None
if isinstance(attr_result, QDateTime):
- attr_result = attr_result.toString('yyyy/MM/dd hh:mm:ss')
+ attr_result = attr_result.toString("yyyy/MM/dd hh:mm:ss")
elif isinstance(attr_result, QDate):
- attr_result = attr_result.toString('yyyy/MM/dd')
+ attr_result = attr_result.toString("yyyy/MM/dd")
else:
attr_result = str(attr_result) if attr_result else None
# Round field (only numeric so it works with __all__)
- if 'precision' in cmp and (field_expected.type() in [QVariant.Int, QVariant.Double, QVariant.LongLong] or isNumber):
+ if "precision" in cmp and (
+ field_expected.type()
+ in [QVariant.Int, QVariant.Double, QVariant.LongLong]
+ or isNumber
+ ):
if not attr_expected == NULL:
- attr_expected = round(attr_expected, cmp['precision'])
+ attr_expected = round(attr_expected, cmp["precision"])
if not attr_result == NULL:
- attr_result = round(attr_result, cmp['precision'])
+ attr_result = round(attr_result, cmp["precision"])
if use_asserts:
self.assertEqual(
attr_expected,
attr_result,
- 'Features {}/{} differ in attributes\n\n * Field expected: {} ({})\n * result : {} ({})\n\n * Expected: {} != Result : {}'.format(
+ "Features {}/{} differ in attributes\n\n * Field expected: {} ({})\n * result : {} ({})\n\n * Expected: {} != Result : {}".format(
feat0.id(),
feat1.id(),
field_expected.name(),
@@ -705,8 +828,8 @@ def checkAttributesEqual(self, feat0, feat1, fields_expected, use_asserts, compa
field_result.name(),
field_result.typeName(),
repr(attr_expected),
- repr(attr_result)
- )
+ repr(attr_result),
+ ),
)
elif attr_expected != attr_result:
return False
@@ -715,10 +838,10 @@ def checkAttributesEqual(self, feat0, feat1, fields_expected, use_asserts, compa
class _UnexpectedSuccess(Exception):
-
"""
The test was supposed to fail, but it didn't!
"""
+
pass
@@ -740,7 +863,7 @@ def my_test(self):
def my_test(self):
self.assertTrue(qgisIsInvented())
"""
- if hasattr(args[0], '__call__'):
+ if hasattr(args[0], "__call__"):
# We got a function as parameter: assume usage like
# @expectedFailure
# def testfunction():
@@ -754,6 +877,7 @@ def wrapper(*args, **kwargs):
pass
else:
raise _UnexpectedSuccess
+
return wrapper
else:
# We got a function as parameter: assume usage like
@@ -773,6 +897,7 @@ def wrapper(*args, **kwargs):
raise _UnexpectedSuccess
else:
func(*args, **kwargs)
+
return wrapper
return realExpectedFailure
@@ -782,64 +907,100 @@ def wrapper(*args, **kwargs):
def _deprecatedAssertLayersEqual(*args, **kwargs):
- warn('unittest.TestCase.assertLayersEqual is deprecated and will be removed in the future. Port your tests to `qgis.testing.TestCase`', DeprecationWarning)
+ warn(
+ "unittest.TestCase.assertLayersEqual is deprecated and will be removed in the future. Port your tests to `qgis.testing.TestCase`",
+ DeprecationWarning,
+ )
return QgisTestCase.assertLayersEqual(*args, **kwargs)
def _deprecatedCheckLayersEqual(*args, **kwargs):
- warn('unittest.TestCase.checkLayersEqual is deprecated and will be removed in the future. Port your tests to `qgis.testing.TestCase`', DeprecationWarning)
+ warn(
+ "unittest.TestCase.checkLayersEqual is deprecated and will be removed in the future. Port your tests to `qgis.testing.TestCase`",
+ DeprecationWarning,
+ )
return QgisTestCase.checkLayersEqual(*args, **kwargs)
def _deprecatedAssertFilesEqual(*args, **kwargs):
- warn('unittest.TestCase.assertFilesEqual is deprecated and will be removed in the future. Port your tests to `qgis.testing.TestCase`', DeprecationWarning)
+ warn(
+ "unittest.TestCase.assertFilesEqual is deprecated and will be removed in the future. Port your tests to `qgis.testing.TestCase`",
+ DeprecationWarning,
+ )
return QgisTestCase.assertFilesEqual(*args, **kwargs)
def _deprecatedCheckFilesEqual(*args, **kwargs):
- warn('unittest.TestCase.checkFilesEqual is deprecated and will be removed in the future. Port your tests to `qgis.testing.TestCase`', DeprecationWarning)
+ warn(
+ "unittest.TestCase.checkFilesEqual is deprecated and will be removed in the future. Port your tests to `qgis.testing.TestCase`",
+ DeprecationWarning,
+ )
return QgisTestCase.checkFilesEqual(*args, **kwargs)
def _deprecatedAssertDirectoryEqual(*args, **kwargs):
- warn('unittest.TestCase.assertDirectoryEqual is deprecated and will be removed in the future. Port your tests to `qgis.testing.TestCase`', DeprecationWarning)
+ warn(
+ "unittest.TestCase.assertDirectoryEqual is deprecated and will be removed in the future. Port your tests to `qgis.testing.TestCase`",
+ DeprecationWarning,
+ )
return QgisTestCase.assertDirectoryEqual(*args, **kwargs)
def _deprecatedAssertDirectoriesEqual(*args, **kwargs):
- warn('unittest.TestCase.assertDirectoriesEqual is deprecated and will be removed in the future. Port your tests to `qgis.testing.TestCase`', DeprecationWarning)
+ warn(
+ "unittest.TestCase.assertDirectoriesEqual is deprecated and will be removed in the future. Port your tests to `qgis.testing.TestCase`",
+ DeprecationWarning,
+ )
return QgisTestCase.assertDirectoriesEqual(*args, **kwargs)
def _deprecatedAssertGeometriesEqual(*args, **kwargs):
- warn('unittest.TestCase.assertGeometriesEqual is deprecated and will be removed in the future. Port your tests to `qgis.testing.TestCase`', DeprecationWarning)
+ warn(
+ "unittest.TestCase.assertGeometriesEqual is deprecated and will be removed in the future. Port your tests to `qgis.testing.TestCase`",
+ DeprecationWarning,
+ )
return QgisTestCase.assertGeometriesEqual(*args, **kwargs)
def _deprecatedCheckGeometriesEqual(*args, **kwargs):
- warn('unittest.TestCase.checkGeometriesEqual is deprecated and will be removed in the future. Port your tests to `qgis.testing.TestCase`', DeprecationWarning)
+ warn(
+ "unittest.TestCase.checkGeometriesEqual is deprecated and will be removed in the future. Port your tests to `qgis.testing.TestCase`",
+ DeprecationWarning,
+ )
return QgisTestCase.checkGeometriesEqual(*args, **kwargs)
def _deprecatedCheckAttributesEqual(*args, **kwargs):
- warn('unittest.TestCase.checkAttributesEqual is deprecated and will be removed in the future. Port your tests to `qgis.testing.TestCase`', DeprecationWarning)
+ warn(
+ "unittest.TestCase.checkAttributesEqual is deprecated and will be removed in the future. Port your tests to `qgis.testing.TestCase`",
+ DeprecationWarning,
+ )
return QgisTestCase.checkAttributesEqual(*args, **kwargs)
def _deprecated_image_check(*args, **kwargs):
- warn('unittest.TestCase.image_check is deprecated and will be removed in the future. Port your tests to `qgis.testing.TestCase`', DeprecationWarning)
+ warn(
+ "unittest.TestCase.image_check is deprecated and will be removed in the future. Port your tests to `qgis.testing.TestCase`",
+ DeprecationWarning,
+ )
# Remove the first args element `self` which we don't need for a @classmethod
return QgisTestCase.image_check(*args[1:], **kwargs)
def _deprecated_render_map_settings_check(*args, **kwargs):
- warn('unittest.TestCase.render_map_settings_check is deprecated and will be removed in the future. Port your tests to `qgis.testing.TestCase`', DeprecationWarning)
+ warn(
+ "unittest.TestCase.render_map_settings_check is deprecated and will be removed in the future. Port your tests to `qgis.testing.TestCase`",
+ DeprecationWarning,
+ )
# Remove the first args element `self` which we don't need for a @classmethod
return QgisTestCase.render_map_settings_check(*args[1:], **kwargs)
def _deprecated_render_layout_check(*args, **kwargs):
- warn('unittest.TestCase.render_layout_check is deprecated and will be removed in the future. Port your tests to `qgis.testing.TestCase`', DeprecationWarning)
+ warn(
+ "unittest.TestCase.render_layout_check is deprecated and will be removed in the future. Port your tests to `qgis.testing.TestCase`",
+ DeprecationWarning,
+ )
# Remove the first args element `self` which we don't need for a @classmethod
return QgisTestCase.render_layout_check(*args[1:], **kwargs)
@@ -890,7 +1051,7 @@ def start_app(cleanup=True):
try:
sys.argv
except AttributeError:
- sys.argv = ['']
+ sys.argv = [""]
# In python3 we need to convert to a bytes object (or should
# QgsApplication accept a QString instead of const char* ?)
@@ -899,22 +1060,26 @@ def start_app(cleanup=True):
except AttributeError:
argvb = sys.argv
- QCoreApplication.setAttribute(Qt.ApplicationAttribute.AA_ShareOpenGLContexts, True)
+ QCoreApplication.setAttribute(
+ Qt.ApplicationAttribute.AA_ShareOpenGLContexts, True
+ )
# Note: QGIS_PREFIX_PATH is evaluated in QgsApplication -
# no need to mess with it here.
QGISAPP = QgsApplication(argvb, myGuiFlag)
- tmpdir = tempfile.mkdtemp('', 'QGIS-PythonTestConfigPath-')
- os.environ['QGIS_CUSTOM_CONFIG_PATH'] = tmpdir
+ tmpdir = tempfile.mkdtemp("", "QGIS-PythonTestConfigPath-")
+ os.environ["QGIS_CUSTOM_CONFIG_PATH"] = tmpdir
QGISAPP.initQgis()
print(QGISAPP.showSettings())
def debug_log_message(message, tag, level):
- print('{}({}): {}'.format(tag, level, message))
+ print(f"{tag}({level}): {message}")
- QgsApplication.instance().messageLog().messageReceived.connect(debug_log_message)
+ QgsApplication.instance().messageLog().messageReceived.connect(
+ debug_log_message
+ )
if cleanup:
import atexit
diff --git a/python/testing/mocked.py b/python/testing/mocked.py
index b871d739f829..e94a0d62ab20 100644
--- a/python/testing/mocked.py
+++ b/python/testing/mocked.py
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-
"""
***************************************************************************
mocked
@@ -17,13 +15,13 @@
***************************************************************************
"""
-__author__ = 'Matthias Kuhn'
-__date__ = 'January 2016'
-__copyright__ = '(C) 2016, Matthias Kuhn'
+__author__ = "Matthias Kuhn"
+__date__ = "January 2016"
+__copyright__ = "(C) 2016, Matthias Kuhn"
import os
import sys
-import mock
+from unittest import mock
from qgis.gui import QgisInterface, QgsMapCanvas
from qgis.core import QgsApplication
diff --git a/python/user.py b/python/user.py
index 49b0718bc832..fafbe530f272 100644
--- a/python/user.py
+++ b/python/user.py
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-
"""
***************************************************************************
user.py
@@ -17,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Nathan Woodrow'
-__date__ = 'January 2015'
-__copyright__ = '(C) 2015, Nathan Woodrow'
+__author__ = "Nathan Woodrow"
+__date__ = "January 2015"
+__copyright__ = "(C) 2015, Nathan Woodrow"
import os
import sys
@@ -43,12 +41,16 @@ def load_user_expressions(path):
# As user expression functions should be registered with qgsfunction
# just importing the file is enough to get it to load the functions into QGIS
try:
- __import__("expressions.{0}".format(name), locals(), globals())
+ __import__(f"expressions.{name}", locals(), globals())
except:
error = traceback.format_exc()
msgtitle = QCoreApplication.translate("UserExpressions", "User expressions")
- msg = QCoreApplication.translate("UserExpressions", "The user expression {0} is not valid").format(name)
- QgsMessageLog.logMessage(msg + "\n" + error, msgtitle, Qgis.MessageLevel.Warning)
+ msg = QCoreApplication.translate(
+ "UserExpressions", "The user expression {0} is not valid"
+ ).format(name)
+ QgsMessageLog.logMessage(
+ msg + "\n" + error, msgtitle, Qgis.MessageLevel.Warning
+ )
def reload_user_expressions(path):
@@ -63,12 +65,12 @@ def reload_user_expressions(path):
if name == "__init__":
continue
- mod = "expressions.{0}".format(name)
+ mod = f"expressions.{name}"
if mod not in sys.modules:
continue
# try removing path
- if hasattr(sys.modules[mod], '__path__'):
+ if hasattr(sys.modules[mod], "__path__"):
for path in sys.modules[mod].__path__:
try:
sys.path.remove(path)
diff --git a/python/utils.py b/python/utils.py
index 0a27f68f0b02..45378ba7456c 100644
--- a/python/utils.py
+++ b/python/utils.py
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-
"""
***************************************************************************
utils.py
@@ -17,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Martin Dobias'
-__date__ = 'November 2009'
-__copyright__ = '(C) 2009, Martin Dobias'
+__author__ = "Martin Dobias"
+__date__ = "November 2009"
+__copyright__ = "(C) 2009, Martin Dobias"
"""
QGIS utilities module
@@ -27,7 +25,14 @@
"""
from typing import List, Dict, Optional
-from qgis.PyQt.QtCore import QT_VERSION_STR, QCoreApplication, QLocale, QThread, qDebug, QUrl
+from qgis.PyQt.QtCore import (
+ QT_VERSION_STR,
+ QCoreApplication,
+ QLocale,
+ QThread,
+ qDebug,
+ QUrl,
+)
from qgis.PyQt.QtGui import QDesktopServices
from qgis.PyQt.QtWidgets import QPushButton, QApplication
from qgis.core import Qgis, QgsMessageLog, qgsfunction, QgsMessageOutput
@@ -45,44 +50,49 @@
import functools
import builtins
-builtins.__dict__['unicode'] = str
-builtins.__dict__['basestring'] = str
-builtins.__dict__['long'] = int
-builtins.__dict__['Set'] = set
+
+builtins.__dict__["unicode"] = str
+builtins.__dict__["basestring"] = str
+builtins.__dict__["long"] = int
+builtins.__dict__["Set"] = set
# ######################
# ERROR HANDLING
-warnings.simplefilter('default')
+warnings.simplefilter("default")
warnings.filterwarnings("ignore", "the sets module is deprecated")
def showWarning(message, category, filename, lineno, file=None, line=None):
stk = ""
for s in traceback.format_stack()[:-2]:
- if hasattr(s, 'decode'):
+ if hasattr(s, "decode"):
stk += s.decode(sys.getfilesystemencoding())
else:
stk += s
- if hasattr(filename, 'decode'):
+ if hasattr(filename, "decode"):
decoded_filename = filename.decode(sys.getfilesystemencoding())
else:
decoded_filename = filename
QgsMessageLog.logMessage(
- "warning:{}\ntraceback:{}".format(warnings.formatwarning(message, category, decoded_filename, lineno), stk),
- QCoreApplication.translate("Python", "Python warning")
+ f"warning:{warnings.formatwarning(message, category, decoded_filename, lineno)}\ntraceback:{stk}",
+ QCoreApplication.translate("Python", "Python warning"),
)
-def showException(type, value, tb, msg, messagebar=False, level=Qgis.MessageLevel.Warning):
+def showException(
+ type, value, tb, msg, messagebar=False, level=Qgis.MessageLevel.Warning
+):
if msg is None:
- msg = QCoreApplication.translate('Python', 'An error has occurred while executing Python code:')
+ msg = QCoreApplication.translate(
+ "Python", "An error has occurred while executing Python code:"
+ )
- logmessage = ''
+ logmessage = ""
for s in traceback.format_exception(type, value, tb):
- logmessage += s.decode('utf-8', 'replace') if hasattr(s, 'decode') else s
+ logmessage += s.decode("utf-8", "replace") if hasattr(s, "decode") else s
- title = QCoreApplication.translate('Python', 'Python error')
+ title = QCoreApplication.translate("Python", "Python error")
QgsMessageLog.logMessage(logmessage, title, level)
try:
@@ -111,10 +121,23 @@ def showException(type, value, tb, msg, messagebar=False, level=Qgis.MessageLeve
# Return of we already have a message with the same error message
return
- widget = bar.createMessage(title, msg + " " + QCoreApplication.translate("Python", "See message log (Python Error) for more details."))
+ widget = bar.createMessage(
+ title,
+ msg
+ + " "
+ + QCoreApplication.translate(
+ "Python", "See message log (Python Error) for more details."
+ ),
+ )
widget.setProperty("Error", msg)
- stackbutton = QPushButton(QCoreApplication.translate("Python", "Stack trace"), pressed=functools.partial(open_stack_dialog, type, value, tb, msg))
- button = QPushButton(QCoreApplication.translate("Python", "View message log"), pressed=show_message_log)
+ stackbutton = QPushButton(
+ QCoreApplication.translate("Python", "Stack trace"),
+ pressed=functools.partial(open_stack_dialog, type, value, tb, msg),
+ )
+ button = QPushButton(
+ QCoreApplication.translate("Python", "View message log"),
+ pressed=show_message_log,
+ )
widget.layout().addWidget(stackbutton)
widget.layout().addWidget(button)
bar.pushWidget(widget, Qgis.MessageLevel.Warning)
@@ -132,10 +155,12 @@ def open_stack_dialog(type, value, tb, msg, pop_error=True):
iface.messageBar().popWidget()
if msg is None:
- msg = QCoreApplication.translate('Python', 'An error has occurred while executing Python code:')
+ msg = QCoreApplication.translate(
+ "Python", "An error has occurred while executing Python code:"
+ )
# TODO Move this to a template HTML file
- txt = '''{msg}
+ txt = """{msg}
{main_error}
@@ -149,32 +174,36 @@ def open_stack_dialog(type, value, tb, msg, pop_error=True):
{pypath_label}
'''
+"""
- error = ''
+ error = ""
lst = traceback.format_exception(type, value, tb)
for s in lst:
- error += s.decode('utf-8', 'replace') if hasattr(s, 'decode') else s
- error = error.replace('\n', ' ')
-
- main_error = lst[-1].decode('utf-8', 'replace') if hasattr(lst[-1], 'decode') else lst[-1]
-
- version_label = QCoreApplication.translate('Python', 'Python version:')
- qgis_label = QCoreApplication.translate('Python', 'QGIS version:')
- pypath_label = QCoreApplication.translate('Python', 'Python Path:')
- txt = txt.format(msg=msg,
- main_error=main_error,
- error=error,
- version_label=version_label,
- num=sys.version,
- qgis_label=qgis_label,
- qversion=Qgis.QGIS_VERSION,
- qgisrelease=Qgis.QGIS_RELEASE_NAME,
- devversion=Qgis.QGIS_DEV_VERSION,
- pypath_label=pypath_label,
- pypath="".join("{} ".format(path) for path in sys.path))
-
- txt = txt.replace(' ', ' ') # preserve whitespaces for nicer output
+ error += s.decode("utf-8", "replace") if hasattr(s, "decode") else s
+ error = error.replace("\n", " ")
+
+ main_error = (
+ lst[-1].decode("utf-8", "replace") if hasattr(lst[-1], "decode") else lst[-1]
+ )
+
+ version_label = QCoreApplication.translate("Python", "Python version:")
+ qgis_label = QCoreApplication.translate("Python", "QGIS version:")
+ pypath_label = QCoreApplication.translate("Python", "Python Path:")
+ txt = txt.format(
+ msg=msg,
+ main_error=main_error,
+ error=error,
+ version_label=version_label,
+ num=sys.version,
+ qgis_label=qgis_label,
+ qversion=Qgis.QGIS_VERSION,
+ qgisrelease=Qgis.QGIS_RELEASE_NAME,
+ devversion=Qgis.QGIS_DEV_VERSION,
+ pypath_label=pypath_label,
+ pypath="".join(f"{path} " for path in sys.path),
+ )
+
+ txt = txt.replace(" ", " ") # preserve whitespaces for nicer output
dlg = QgsMessageOutput.createMessageOutput()
dlg.setTitle(msg)
@@ -184,7 +213,10 @@ def open_stack_dialog(type, value, tb, msg, pop_error=True):
def qgis_excepthook(type, value, tb):
# detect if running in the main thread
- in_main_thread = QCoreApplication.instance() is None or QThread.currentThread() == QCoreApplication.instance().thread()
+ in_main_thread = (
+ QCoreApplication.instance() is None
+ or QThread.currentThread() == QCoreApplication.instance().thread()
+ )
# only use messagebar if running in main thread - otherwise it will crash!
showException(type, value, tb, None, messagebar=in_main_thread)
@@ -245,14 +277,14 @@ def initInterface(pointer):
def findPlugins(path):
- """ for internal use: return list of plugins in given path """
+ """for internal use: return list of plugins in given path"""
for plugin in glob.glob(path + "/*"):
if not os.path.isdir(plugin):
continue
- if not os.path.exists(os.path.join(plugin, '__init__.py')):
+ if not os.path.exists(os.path.join(plugin, "__init__.py")):
continue
- metadataFile = os.path.join(plugin, 'metadata.txt')
+ metadataFile = os.path.join(plugin, "metadata.txt")
if not os.path.exists(metadataFile):
continue
@@ -274,7 +306,7 @@ def metadataParser() -> dict:
def updateAvailablePlugins(sort_by_dependencies=False):
- """ Go through the plugin_paths list and find out what plugins are available. """
+ """Go through the plugin_paths list and find out what plugins are available."""
# merge the lists
plugins = []
metadata_parser = {}
@@ -286,16 +318,22 @@ def updateAvailablePlugins(sort_by_dependencies=False):
if plugin_id not in plugins:
plugins.append(plugin_id)
metadata_parser[plugin_id] = parser
- plugin_name_map[parser.get('general', 'name')] = plugin_id
+ plugin_name_map[parser.get("general", "name")] = plugin_id
global plugins_metadata_parser
plugins_metadata_parser = metadata_parser
global available_plugins
- available_plugins = _sortAvailablePlugins(plugins, plugin_name_map) if sort_by_dependencies else plugins
+ available_plugins = (
+ _sortAvailablePlugins(plugins, plugin_name_map)
+ if sort_by_dependencies
+ else plugins
+ )
-def _sortAvailablePlugins(plugins: List[str], plugin_name_map: Dict[str, str]) -> List[str]:
+def _sortAvailablePlugins(
+ plugins: list[str], plugin_name_map: dict[str, str]
+) -> list[str]:
"""Place dependent plugins after their dependencies
1. Make a copy of plugins list to modify it.
@@ -312,7 +350,7 @@ def _sortAvailablePlugins(plugins: List[str], plugin_name_map: Dict[str, str]) -
deps = {}
for plugin in plugins:
- deps[plugin] = [plugin_name_map.get(dep, '') for dep in get_plugin_deps(plugin)]
+ deps[plugin] = [plugin_name_map.get(dep, "") for dep in get_plugin_deps(plugin)]
for plugin in plugins:
_move_plugin(plugin, deps, visited_plugins, sorted_plugins)
@@ -320,7 +358,12 @@ def _sortAvailablePlugins(plugins: List[str], plugin_name_map: Dict[str, str]) -
return sorted_plugins
-def _move_plugin(plugin: str, deps: Dict[str, List[str]], visited: List[str], sorted_plugins: List[str]):
+def _move_plugin(
+ plugin: str,
+ deps: dict[str, list[str]],
+ visited: list[str],
+ sorted_plugins: list[str],
+):
"""Use recursion to move a plugin after its dependencies in a list of
sorted plugins.
@@ -361,17 +404,17 @@ def _move_plugin(plugin: str, deps: Dict[str, List[str]], visited: List[str], so
sorted_plugins.insert(max_index, plugin)
-def get_plugin_deps(plugin_id: str) -> Dict[str, Optional[str]]:
+def get_plugin_deps(plugin_id: str) -> dict[str, Optional[str]]:
result = {}
try:
parser = plugins_metadata_parser[plugin_id]
- plugin_deps = parser.get('general', 'plugin_dependencies')
+ plugin_deps = parser.get("general", "plugin_dependencies")
except (configparser.NoOptionError, configparser.NoSectionError, KeyError):
return result
- for dep in plugin_deps.split(','):
- if dep.find('==') > 0:
- name, version_required = dep.split('==')
+ for dep in plugin_deps.split(","):
+ if dep.find("==") > 0:
+ name, version_required = dep.split("==")
else:
name = dep
version_required = None
@@ -380,15 +423,15 @@ def get_plugin_deps(plugin_id: str) -> Dict[str, Optional[str]]:
def pluginMetadata(packageName: str, fct: str) -> str:
- """ fetch metadata from a plugin - use values from metadata.txt """
+ """fetch metadata from a plugin - use values from metadata.txt"""
try:
- return plugins_metadata_parser[packageName].get('general', fct)
+ return plugins_metadata_parser[packageName].get("general", fct)
except Exception:
return "__error__"
def loadPlugin(packageName: str) -> bool:
- """ load plugin's package """
+ """load plugin's package"""
try:
__import__(packageName)
@@ -404,13 +447,22 @@ def loadPlugin(packageName: str) -> bool:
__import__(packageName)
return True
except:
- msg = QCoreApplication.translate("Python", "Couldn't load plugin '{0}'").format(packageName)
- showException(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2], msg, messagebar=True, level=Qgis.MessageLevel.Critical)
+ msg = QCoreApplication.translate("Python", "Couldn't load plugin '{0}'").format(
+ packageName
+ )
+ showException(
+ sys.exc_info()[0],
+ sys.exc_info()[1],
+ sys.exc_info()[2],
+ msg,
+ messagebar=True,
+ level=Qgis.MessageLevel.Critical,
+ )
return False
def _startPlugin(packageName: str) -> bool:
- """ initializes a plugin, but does not load GUI """
+ """initializes a plugin, but does not load GUI"""
global plugins, active_plugins, iface, plugin_times
if packageName in active_plugins:
@@ -426,21 +478,32 @@ def _startPlugin(packageName: str) -> bool:
plugins[packageName] = package.classFactory(iface)
except:
_unloadPluginModules(packageName)
- errMsg = QCoreApplication.translate("Python", "Couldn't load plugin '{0}'").format(packageName)
- msg = QCoreApplication.translate("Python", "{0} due to an error when calling its classFactory() method").format(errMsg)
- showException(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2], msg, messagebar=True, level=Qgis.MessageLevel.Critical)
+ errMsg = QCoreApplication.translate(
+ "Python", "Couldn't load plugin '{0}'"
+ ).format(packageName)
+ msg = QCoreApplication.translate(
+ "Python", "{0} due to an error when calling its classFactory() method"
+ ).format(errMsg)
+ showException(
+ sys.exc_info()[0],
+ sys.exc_info()[1],
+ sys.exc_info()[2],
+ msg,
+ messagebar=True,
+ level=Qgis.MessageLevel.Critical,
+ )
return False
return True
def _addToActivePlugins(packageName: str, duration: int):
- """ Adds a plugin to the list of active plugins """
+ """Adds a plugin to the list of active plugins"""
active_plugins.append(packageName)
- plugin_times[packageName] = "{0:02f}s".format(duration)
+ plugin_times[packageName] = f"{duration:02f}s"
def startPlugin(packageName: str) -> bool:
- """ initialize the plugin """
+ """initialize the plugin"""
global plugins, active_plugins, iface, plugin_times
start = time.process_time()
if not _startPlugin(packageName):
@@ -452,9 +515,20 @@ def startPlugin(packageName: str) -> bool:
except:
del plugins[packageName]
_unloadPluginModules(packageName)
- errMsg = QCoreApplication.translate("Python", "Couldn't load plugin '{0}'").format(packageName)
- msg = QCoreApplication.translate("Python", "{0} due to an error when calling its initGui() method").format(errMsg)
- showException(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2], msg, messagebar=True, level=Qgis.MessageLevel.Critical)
+ errMsg = QCoreApplication.translate(
+ "Python", "Couldn't load plugin '{0}'"
+ ).format(packageName)
+ msg = QCoreApplication.translate(
+ "Python", "{0} due to an error when calling its initGui() method"
+ ).format(errMsg)
+ showException(
+ sys.exc_info()[0],
+ sys.exc_info()[1],
+ sys.exc_info()[2],
+ msg,
+ messagebar=True,
+ level=Qgis.MessageLevel.Critical,
+ )
return False
end = time.process_time()
@@ -463,18 +537,29 @@ def startPlugin(packageName: str) -> bool:
def startProcessingPlugin(packageName: str) -> bool:
- """ initialize only the Processing components of a plugin """
+ """initialize only the Processing components of a plugin"""
global plugins, active_plugins, iface, plugin_times
start = time.process_time()
if not _startPlugin(packageName):
return False
- errMsg = QCoreApplication.translate("Python", "Couldn't load plugin '{0}'").format(packageName)
- if not hasattr(plugins[packageName], 'initProcessing'):
+ errMsg = QCoreApplication.translate("Python", "Couldn't load plugin '{0}'").format(
+ packageName
+ )
+ if not hasattr(plugins[packageName], "initProcessing"):
del plugins[packageName]
_unloadPluginModules(packageName)
- msg = QCoreApplication.translate("Python", "{0} - plugin has no initProcessing() method").format(errMsg)
- showException(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2], msg, messagebar=True, level=Qgis.MessageLevel.Critical)
+ msg = QCoreApplication.translate(
+ "Python", "{0} - plugin has no initProcessing() method"
+ ).format(errMsg)
+ showException(
+ sys.exc_info()[0],
+ sys.exc_info()[1],
+ sys.exc_info()[2],
+ msg,
+ messagebar=True,
+ level=Qgis.MessageLevel.Critical,
+ )
return False
# initProcessing
@@ -483,8 +568,16 @@ def startProcessingPlugin(packageName: str) -> bool:
except:
del plugins[packageName]
_unloadPluginModules(packageName)
- msg = QCoreApplication.translate("Python", "{0} due to an error when calling its initProcessing() method").format(errMsg)
- showException(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2], msg, messagebar=True)
+ msg = QCoreApplication.translate(
+ "Python", "{0} due to an error when calling its initProcessing() method"
+ ).format(errMsg)
+ showException(
+ sys.exc_info()[0],
+ sys.exc_info()[1],
+ sys.exc_info()[2],
+ msg,
+ messagebar=True,
+ )
return False
end = time.process_time()
@@ -501,11 +594,11 @@ def finalizeProcessingStartup() -> bool:
for every installed and enabled plugin.
"""
global plugins, active_plugins, iface, plugin_times
- if 'processing' not in plugins:
+ if "processing" not in plugins:
return False
try:
- plugins['processing'].finalizeStartup()
+ plugins["processing"].finalizeStartup()
except:
return False
@@ -513,7 +606,7 @@ def finalizeProcessingStartup() -> bool:
def canUninstallPlugin(packageName: str) -> bool:
- """ confirm that the plugin can be uninstalled """
+ """confirm that the plugin can be uninstalled"""
global plugins, active_plugins
if packageName not in plugins:
@@ -528,12 +621,18 @@ def canUninstallPlugin(packageName: str) -> bool:
return bool(metadata.canBeUninstalled())
except:
msg = "Error calling " + packageName + ".canBeUninstalled"
- showException(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2], msg, messagebar=True)
+ showException(
+ sys.exc_info()[0],
+ sys.exc_info()[1],
+ sys.exc_info()[2],
+ msg,
+ messagebar=True,
+ )
return True
def unloadPlugin(packageName: str) -> bool:
- """ unload and delete plugin! """
+ """unload and delete plugin!"""
global plugins, active_plugins
if packageName not in plugins:
@@ -548,13 +647,21 @@ def unloadPlugin(packageName: str) -> bool:
_unloadPluginModules(packageName)
return True
except Exception as e:
- msg = QCoreApplication.translate("Python", "Error while unloading plugin {0}").format(packageName)
- showException(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2], msg, messagebar=True)
+ msg = QCoreApplication.translate(
+ "Python", "Error while unloading plugin {0}"
+ ).format(packageName)
+ showException(
+ sys.exc_info()[0],
+ sys.exc_info()[1],
+ sys.exc_info()[2],
+ msg,
+ messagebar=True,
+ )
return False
def _unloadPluginModules(packageName: str):
- """ unload plugin package with all its modules (files) """
+ """unload plugin package with all its modules (files)"""
global _plugin_modules
if packageName not in _plugin_modules:
@@ -570,14 +677,14 @@ def _unloadPluginModules(packageName: str):
# otherwise we might experience a segfault next time the plugin is loaded
# because Qt will try to access invalid plugin resource data
try:
- if hasattr(sys.modules[mod], 'qCleanupResources'):
+ if hasattr(sys.modules[mod], "qCleanupResources"):
sys.modules[mod].qCleanupResources()
except:
# Print stack trace for debug
qDebug("qCleanupResources error:\n%s" % traceback.format_exc())
# try removing path
- if hasattr(sys.modules[mod], '__path__'):
+ if hasattr(sys.modules[mod], "__path__"):
for path in sys.modules[mod].__path__:
try:
sys.path.remove(path)
@@ -595,16 +702,16 @@ def _unloadPluginModules(packageName: str):
def isPluginLoaded(packageName: str) -> bool:
- """ find out whether a plugin is active (i.e. has been started) """
+ """find out whether a plugin is active (i.e. has been started)"""
global plugins, active_plugins
if packageName not in plugins:
return False
- return (packageName in active_plugins)
+ return packageName in active_plugins
def reloadPlugin(packageName: str) -> bool:
- """ unload and start again a plugin """
+ """unload and start again a plugin"""
global active_plugins
if packageName not in active_plugins:
return False # it's not active
@@ -651,7 +758,7 @@ def showPluginHelp(packageName: str = None, filename: str = "index", section: st
def pluginDirectory(packageName: str) -> str:
- """ return directory where the plugin resides. Plugin must be loaded already """
+ """return directory where the plugin resides. Plugin must be loaded already"""
return os.path.dirname(sys.modules[packageName].__file__)
@@ -662,12 +769,15 @@ def reloadProjectMacros():
from qgis.core import QgsProject
code, ok = QgsProject.instance().readEntry("Macros", "/pythonCode")
- if not ok or not code or code == '':
+ if not ok or not code or code == "":
return
# create a new empty python module
import importlib
- mod = importlib.util.module_from_spec(importlib.machinery.ModuleSpec("proj_macros_mod", None))
+
+ mod = importlib.util.module_from_spec(
+ importlib.machinery.ModuleSpec("proj_macros_mod", None)
+ )
# set the module code and store it sys.modules
exec(str(code), mod.__dict__)
@@ -690,7 +800,7 @@ def openProjectMacro():
if "proj_macros_mod" not in sys.modules:
return
mod = sys.modules["proj_macros_mod"]
- if hasattr(mod, 'openProject'):
+ if hasattr(mod, "openProject"):
mod.openProject()
@@ -698,7 +808,7 @@ def saveProjectMacro():
if "proj_macros_mod" not in sys.modules:
return
mod = sys.modules["proj_macros_mod"]
- if hasattr(mod, 'saveProject'):
+ if hasattr(mod, "saveProject"):
mod.saveProject()
@@ -706,19 +816,22 @@ def closeProjectMacro():
if "proj_macros_mod" not in sys.modules:
return
mod = sys.modules["proj_macros_mod"]
- if hasattr(mod, 'closeProject'):
+ if hasattr(mod, "closeProject"):
mod.closeProject()
#######################
+
def _list_project_expression_functions():
- """ Get a list of expression functions stored in the current project """
+ """Get a list of expression functions stored in the current project"""
import ast
from qgis.core import QgsProject
functions = []
- project_functions, ok = QgsProject.instance().readEntry("ExpressionFunctions", "/pythonCode")
+ project_functions, ok = QgsProject.instance().readEntry(
+ "ExpressionFunctions", "/pythonCode"
+ )
if ok and project_functions:
code = ast.parse(project_functions)
@@ -741,6 +854,7 @@ def clean_project_expression_functions():
project_functions = _list_project_expression_functions()
if project_functions:
from qgis.core import QgsExpression
+
for function in project_functions:
QgsExpression.unregisterFunction(function)
@@ -775,13 +889,14 @@ def clean_project_expression_functions():
def initServerInterface(pointer):
from qgis.server import QgsServerInterface
from sip import wrapinstance
+
sys.excepthook = sys.__excepthook__
global serverIface
serverIface = wrapinstance(pointer, QgsServerInterface)
def startServerPlugin(packageName: str):
- """ initialize the plugin """
+ """initialize the plugin"""
global server_plugins, server_active_plugins, serverIface
if packageName in server_active_plugins:
@@ -791,15 +906,18 @@ def startServerPlugin(packageName: str):
package = sys.modules[packageName]
- errMsg = QCoreApplication.translate("Python", "Couldn't load server plugin {0}").format(packageName)
+ errMsg = QCoreApplication.translate(
+ "Python", "Couldn't load server plugin {0}"
+ ).format(packageName)
# create an instance of the plugin
try:
server_plugins[packageName] = package.serverClassFactory(serverIface)
except:
_unloadPluginModules(packageName)
- msg = QCoreApplication.translate("Python",
- "{0} due to an error when calling its serverClassFactory() method").format(errMsg)
+ msg = QCoreApplication.translate(
+ "Python", "{0} due to an error when calling its serverClassFactory() method"
+ ).format(errMsg)
showException(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2], msg)
return False
@@ -810,7 +928,7 @@ def startServerPlugin(packageName: str):
def spatialite_connect(*args, **kwargs):
"""returns a dbapi2.Connection to a SpatiaLite db
-using the "mod_spatialite" extension (python3)"""
+ using the "mod_spatialite" extension (python3)"""
import sqlite3
import re
@@ -827,12 +945,12 @@ def fcnRegexp(pattern, string):
# SpatiaLite >= 4.2 and Sqlite < 3.7.17 (Travis)
("mod_spatialite.so", "sqlite3_modspatialite_init"),
# SpatiaLite < 4.2 (linux)
- ("libspatialite.so", "sqlite3_extension_init")
+ ("libspatialite.so", "sqlite3_extension_init"),
]
found = False
for lib, entry_point in libs:
try:
- cur.execute("select load_extension('{}', '{}')".format(lib, entry_point))
+ cur.execute(f"select load_extension('{lib}', '{entry_point}')")
except sqlite3.OperationalError:
continue
else:
@@ -840,12 +958,14 @@ def fcnRegexp(pattern, string):
break
if not found:
raise RuntimeError("Cannot find any suitable spatialite module")
- if any(['.gpkg' in arg for arg in args]):
+ if any([".gpkg" in arg for arg in args]):
try:
cur.execute("SELECT EnableGpkgAmphibiousMode()")
except (sqlite3.Error, sqlite3.DatabaseError, sqlite3.NotSupportedError):
- QgsMessageLog.logMessage("warning:{}".format("Could not enable geopackage amphibious mode"),
- QCoreApplication.translate("Python", "Python warning"))
+ QgsMessageLog.logMessage(
+ "warning:{}".format("Could not enable geopackage amphibious mode"),
+ QCoreApplication.translate("Python", "Python warning"),
+ )
cur.close()
con.enable_load_extension(False)
@@ -853,7 +973,7 @@ def fcnRegexp(pattern, string):
return con
-class OverrideCursor():
+class OverrideCursor:
"""
Executes a code block with a different cursor set and makes sure the cursor
is restored even if exceptions are raised or an intermediate ``return``
@@ -880,15 +1000,15 @@ def __exit__(self, exc_type, exc_val, exc_tb):
#######################
# IMPORT wrapper
-if os.name == 'nt' and sys.version_info < (3, 8):
+if os.name == "nt" and sys.version_info < (3, 8):
import ctypes
from ctypes import windll, wintypes
- kernel32 = ctypes.WinDLL('kernel32', use_last_error=True)
+ kernel32 = ctypes.WinDLL("kernel32", use_last_error=True)
- _hasAddDllDirectory = hasattr(kernel32, 'AddDllDirectory')
+ _hasAddDllDirectory = hasattr(kernel32, "AddDllDirectory")
if _hasAddDllDirectory:
- _import_path = os.environ['PATH']
+ _import_path = os.environ["PATH"]
_import_paths = {}
def _errcheck_zero(result, func, args):
@@ -910,10 +1030,12 @@ def _errcheck_zero(result, func, args):
_uses_builtins = True
try:
import builtins
+
_builtin_import = builtins.__import__
except AttributeError:
_uses_builtins = False
import __builtin__
+
_builtin_import = __builtin__.__import__
_plugin_modules = {}
@@ -927,37 +1049,49 @@ def _import(name, globals={}, locals={}, fromlist=[], level=None):
if level is None:
level = 0
- if 'PyQt4' in name:
- msg = 'PyQt4 classes cannot be imported in QGIS 3.x.\n' \
- 'Use {} or preferably the version independent {} import instead.'.format(name.replace('PyQt4', 'PyQt5'), name.replace('PyQt4', 'qgis.PyQt'))
+ if "PyQt4" in name:
+ msg = (
+ "PyQt4 classes cannot be imported in QGIS 3.x.\n"
+ "Use {} or preferably the version independent {} import instead.".format(
+ name.replace("PyQt4", "PyQt5"), name.replace("PyQt4", "qgis.PyQt")
+ )
+ )
raise ImportError(msg)
- qt_version = int(QT_VERSION_STR.split('.')[0])
- if qt_version == 5 and 'PyQt6' in name:
- msg = 'PyQt6 classes cannot be imported in a QGIS build based on Qt5.\n' \
- 'Use {} or preferably the version independent {} import instead (where available).'.format(name.replace('PyQt6', 'PyQt5'), name.replace('PyQt6', 'qgis.PyQt'))
+ qt_version = int(QT_VERSION_STR.split(".")[0])
+ if qt_version == 5 and "PyQt6" in name:
+ msg = (
+ "PyQt6 classes cannot be imported in a QGIS build based on Qt5.\n"
+ "Use {} or preferably the version independent {} import instead (where available).".format(
+ name.replace("PyQt6", "PyQt5"), name.replace("PyQt6", "qgis.PyQt")
+ )
+ )
raise ImportError(msg)
- elif qt_version == 6 and 'PyQt5' in name:
- msg = 'PyQt5 classes cannot be imported in a QGIS build based on Qt6.\n' \
- 'Use {} or preferably the version independent {} import instead (where available).'.format(name.replace('PyQt5', 'PyQt6'), name.replace('PyQt5', 'qgis.PyQt'))
+ elif qt_version == 6 and "PyQt5" in name:
+ msg = (
+ "PyQt5 classes cannot be imported in a QGIS build based on Qt6.\n"
+ "Use {} or preferably the version independent {} import instead (where available).".format(
+ name.replace("PyQt5", "PyQt6"), name.replace("PyQt5", "qgis.PyQt")
+ )
+ )
raise ImportError(msg)
- if os.name == 'nt' and sys.version_info < (3, 8):
+ if os.name == "nt" and sys.version_info < (3, 8):
global _hasAddDllDirectory
if _hasAddDllDirectory:
global _import_path
global _import_paths
old_path = _import_path
- new_path = os.environ['PATH']
+ new_path = os.environ["PATH"]
if old_path != new_path:
global _AddDllDirectory
global _RemoveDllDirectory
- for p in set(new_path.split(';')) - set(old_path.split(';')):
+ for p in set(new_path.split(";")) - set(old_path.split(";")):
if p is not None and p not in _import_path and os.path.isdir(p):
_import_paths[p] = _AddDllDirectory(p)
- for p in set(old_path.split(';')) - set(new_path.split(';')):
+ for p in set(old_path.split(";")) - set(new_path.split(";")):
if p in _import_paths:
_RemoveDllDirectory(_import_paths.pop(p))
@@ -965,9 +1099,9 @@ def _import(name, globals={}, locals={}, fromlist=[], level=None):
mod = _builtin_import(name, globals, locals, fromlist, level)
- if mod and getattr(mod, '__file__', None):
+ if mod and getattr(mod, "__file__", None):
module_name = mod.__name__ if fromlist else name
- package_name = module_name.split('.')[0]
+ package_name = module_name.split(".")[0]
# check whether the module belongs to one of our plugins
if package_name in available_plugins:
if package_name not in _plugin_modules:
@@ -983,7 +1117,7 @@ def _import(name, globals={}, locals={}, fromlist=[], level=None):
return mod
-if not os.environ.get('QGIS_NO_OVERRIDE_IMPORT'):
+if not os.environ.get("QGIS_NO_OVERRIDE_IMPORT"):
if _uses_builtins:
builtins.__import__ = _import
else:
@@ -1013,20 +1147,34 @@ def processing_algorithm_from_script(filepath: str):
alg_instance = None
try:
- from qgis.core import QgsApplication, QgsProcessingAlgorithm, QgsProcessingFeatureBasedAlgorithm
- _locals = {
- '__file__': filename
- }
+ from qgis.core import (
+ QgsApplication,
+ QgsProcessingAlgorithm,
+ QgsProcessingFeatureBasedAlgorithm,
+ )
+
+ _locals = {"__file__": filename}
with open(filename.encode(sys.getfilesystemencoding())) as input_file:
- code_object = compile(input_file.read(), filename, 'exec')
+ code_object = compile(input_file.read(), filename, "exec")
exec(code_object, _locals)
alg_instance = None
try:
alg_instance = alg.instances.pop().createInstance()
except IndexError:
for name, attr in _locals.items():
- if inspect.isclass(attr) and issubclass(attr, (QgsProcessingAlgorithm, QgsProcessingFeatureBasedAlgorithm)) and attr.__name__ not in ("QgsProcessingAlgorithm", "QgsProcessingFeatureBasedAlgorithm"):
+ if (
+ inspect.isclass(attr)
+ and issubclass(
+ attr,
+ (QgsProcessingAlgorithm, QgsProcessingFeatureBasedAlgorithm),
+ )
+ and attr.__name__
+ not in (
+ "QgsProcessingAlgorithm",
+ "QgsProcessingFeatureBasedAlgorithm",
+ )
+ ):
alg_instance = attr()
break
@@ -1059,6 +1207,7 @@ def import_script_algorithm(filepath: str) -> Optional[str]:
alg_instance = processing_algorithm_from_script(filepath)
if alg_instance:
from qgis.core import QgsApplication
+
script_provider = QgsApplication.processingRegistry().providerById("script")
script_provider.add_algorithm_class(type(alg_instance))
return alg_instance.id()
diff --git a/scripts/2to3 b/scripts/2to3
index 01b6d9c9944e..db82ef2b246b 100755
--- a/scripts/2to3
+++ b/scripts/2to3
@@ -1,7 +1,8 @@
#!/usr/bin/env python3
-import sys, os
+import os
+import sys
from lib2to3.main import main
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__))))
-sys.exit(main('qgis_fixes'))
+sys.exit(main("qgis_fixes"))
diff --git a/scripts/appinfo2ui.py b/scripts/appinfo2ui.py
index c12cffcb7e52..48af6bae35fb 100644
--- a/scripts/appinfo2ui.py
+++ b/scripts/appinfo2ui.py
@@ -19,19 +19,24 @@
"""
import sys
-from xml.etree import ElementTree as et
+
from html import escape
+from xml.etree import ElementTree as et
strings = {}
-d = et.parse('linux/org.qgis.qgis.appdata.xml.in')
+d = et.parse("linux/org.qgis.qgis.appdata.xml.in")
r = d.getroot()
-for elem in ['name', 'summary', 'description']:
+for elem in ["name", "summary", "description"]:
for c in r.iter(elem):
if not c.attrib:
l = list(c)
- t = c.text if not l else "".join([et.tostring(x).decode("utf-8") for x in l])
+ t = (
+ c.text
+ if not l
+ else "".join([et.tostring(x).decode("utf-8") for x in l])
+ )
strings[t] = 1
f = open("linux/org.qgis.qgis.desktop.in")
@@ -45,7 +50,8 @@
f.close()
-print("""\
+print(
+ """\
appinfo ;
-""")
+"""
+)
for k in strings:
print(f"{escape(k)} ")
diff --git a/scripts/doxygen_space.py b/scripts/doxygen_space.py
index 73ec171eda9d..987ef39bca97 100755
--- a/scripts/doxygen_space.py
+++ b/scripts/doxygen_space.py
@@ -15,17 +15,16 @@
# (at your option) any later version. #
# #
###########################################################################
-import sys
import re
+import sys
def exit_with_error(message):
- sys.exit(
- f"! Doxygen formatting error: {message}")
+ sys.exit(f"! Doxygen formatting error: {message}")
def process_file(file_path):
- with open(file_path, 'r') as file:
+ with open(file_path) as file:
input_lines = file.readlines()
output = []
@@ -34,19 +33,19 @@ def process_file(file_path):
previous_was_blankline = False
previous_was_dox_blankline = False
just_finished_a_list = False
- buffered_line = ''
+ buffered_line = ""
i = 0
while i < len(input_lines):
line = input_lines[i].rstrip()
is_blank_line = not line.strip()
- if re.match(r'^\s*(?:#ifdef|#ifndef|#else|#endif)', line):
+ if re.match(r"^\s*(?:#ifdef|#ifndef|#else|#endif)", line):
output.append(line)
i += 1
continue
- if match := re.match(r'^(\s*)/\*[*!]\s*([^\s*].*)\s*$', line):
+ if match := re.match(r"^(\s*)/\*[*!]\s*([^\s*].*)\s*$", line):
# Convert blocks starting with /*! format to /** standard,
# and convert
# /**Some docs
@@ -54,73 +53,89 @@ def process_file(file_path):
# /**
# * Some docs
indent, content = match.groups()
- output.append(f'{indent}/**')
- line = f'{indent} * {content[0].upper()}{content[1:]}'
+ output.append(f"{indent}/**")
+ line = f"{indent} * {content[0].upper()}{content[1:]}"
- if match := re.match(r'^(.*)/\*[!*](?!\*)(<*)[ \t\r\n\f]*(.*?)[ \t\r\n\f]*\*/[ \t\r\n\f]*$', line):
+ if match := re.match(
+ r"^(.*)/\*[!*](?!\*)(<*)[ \t\r\n\f]*(.*?)[ \t\r\n\f]*\*/[ \t\r\n\f]*$", line
+ ):
# Convert single line doxygen blocks:
# /*!< comment */ to //!< comment
# /** comment */ to //! comment
prefix, tag, content = match.groups()
- line = f'{prefix}//!{tag} {content}'
+ line = f"{prefix}//!{tag} {content}"
- if match := re.match(r'^(.*)//!<\s*(.)(.*)$', line):
+ if match := re.match(r"^(.*)//!<\s*(.)(.*)$", line):
# Uppercase initial character in //!< comment
prefix, first, remaining = match.groups()
- line = f'{prefix}//!< {first.upper()}{remaining}'
+ line = f"{prefix}//!< {first.upper()}{remaining}"
- if match := re.match(r'^(.*)\\param ([\w_]+)\s+[:,.-]\s*(.*?)$', line):
+ if match := re.match(r"^(.*)\\param ([\w_]+)\s+[:,.-]\s*(.*?)$", line):
# Standardize \param
prefix, param, suffix = match.groups()
- line = f'{prefix}\\param {param} {suffix}'
+ line = f"{prefix}\\param {param} {suffix}"
- if '//!<' in line and (match := re.match(r'^(.*)\.\s*[Ss]ince (?:QGIS )?(\d+\.\d+(?:\.\d+)?)[.]?$', line)):
+ if "//!<" in line and (
+ match := re.match(
+ r"^(.*)\.\s*[Ss]ince (?:QGIS )?(\d+\.\d+(?:\.\d+)?)[.]?$", line
+ )
+ ):
# Use \since annotation
prefix, version = match.groups()
- line = f'{prefix} \\since QGIS {version}'
+ line = f"{prefix} \\since QGIS {version}"
- if '//!<' in line and (match := re.match(r'^(.*?)\s*\([Ss]ince (?:QGIS )?(\d+\.\d+(?:\.\d+)?)[.)]+$', line)):
+ if "//!<" in line and (
+ match := re.match(
+ r"^(.*?)\s*\([Ss]ince (?:QGIS )?(\d+\.\d+(?:\.\d+)?)[.)]+$", line
+ )
+ ):
# Use \since annotation
prefix, version = match.groups()
- line = f'{prefix} \\since QGIS {version}'
+ line = f"{prefix} \\since QGIS {version}"
- if match := re.match(r'^(.*)\\since (?:QGIS )?(\d+\.\d+(?:\.\d+)?)[.]?$', line):
+ if match := re.match(r"^(.*)\\since (?:QGIS )?(\d+\.\d+(?:\.\d+)?)[.]?$", line):
# Standard since annotation
prefix, version = match.groups()
- line = f'{prefix}\\since QGIS {version}'
+ line = f"{prefix}\\since QGIS {version}"
- if match := re.match(r'^(.*)\\deprecated[,.:]? (?:[dD]eprecated )?(?:[sS]ince )?(?:QGIS )?(\d+\.\d+(?:\.\d+)?)[,\s.\-]*(.*?)$', line):
+ if match := re.match(
+ r"^(.*)\\deprecated[,.:]? (?:[dD]eprecated )?(?:[sS]ince )?(?:QGIS )?(\d+\.\d+(?:\.\d+)?)[,\s.\-]*(.*?)$",
+ line,
+ ):
# Standardize deprecated annotation
prefix, version, suffix = match.groups()
if suffix:
- if suffix.startswith('('):
- if suffix.endswith(')'):
+ if suffix.startswith("("):
+ if suffix.endswith(")"):
suffix = suffix[1:-1]
- elif suffix.endswith(').'):
+ elif suffix.endswith(")."):
suffix = suffix[1:-2]
suffix = suffix[0].upper() + suffix[1:]
- if not suffix.endswith('.'):
+ if not suffix.endswith("."):
suffix += "."
- line = f'{prefix}\\deprecated QGIS {version}. {suffix}'
+ line = f"{prefix}\\deprecated QGIS {version}. {suffix}"
else:
- line = f'{prefix}\\deprecated QGIS {version}'
- elif re.match(r'^(.*)\\deprecated', line):
- exit_with_error("\\deprecated MUST be followed by the correct version number, eg 'QGIS 3.40'")
+ line = f"{prefix}\\deprecated QGIS {version}"
+ elif re.match(r"^(.*)\\deprecated", line):
+ exit_with_error(
+ "\\deprecated MUST be followed by the correct version number, eg 'QGIS 3.40'"
+ )
- if match := re.match(r'^(\s*)//!\s*(.*?)$', line):
+ if match := re.match(r"^(\s*)//!\s*(.*?)$", line):
indentation, comment = match.groups()
# found a //! comment
# check next line to see if it also begins with //!
- if i + 1 < len(input_lines) and re.match(r'^\s*//!\s*(.*?)$',
- input_lines[i + 1]):
+ if i + 1 < len(input_lines) and re.match(
+ r"^\s*//!\s*(.*?)$", input_lines[i + 1]
+ ):
# we are in a multiline //! comment block, convert to /** block
if not previous_was_blankline:
- output.append('')
+ output.append("")
output.append(f"{indentation}/**")
output.append(f"{indentation} * {comment}")
while i + 1 < len(input_lines) and (
- next_match := re.match(r'^\s*//!\s*(.*?)$',
- input_lines[i + 1])):
+ next_match := re.match(r"^\s*//!\s*(.*?)$", input_lines[i + 1])
+ ):
next_comment = next_match.group(1)
if next_comment:
output.append(f"{indentation} * {next_comment}")
@@ -132,9 +147,9 @@ def process_file(file_path):
output.append(line)
elif inside_dox_block:
# replace "* abc" style doxygen lists with correct "- abc" formatting
- line = re.sub(r'^(\s+)\*\s{1,10}\*', r'\1* -', line)
+ line = re.sub(r"^(\s+)\*\s{1,10}\*", r"\1* -", line)
- if re.match(r'^\s*\*\s*$', line):
+ if re.match(r"^\s*\*\s*$", line):
previous_was_dox_blankline = True
if inside_dox_list:
inside_dox_list = False
@@ -143,8 +158,7 @@ def process_file(file_path):
# print("end list")
else:
output.append(line)
- elif match := re.match(r'^(\s*)\*\s*-(?![-\d>]) *(.*)$',
- line):
+ elif match := re.match(r"^(\s*)\*\s*-(?![-\d>]) *(.*)$", line):
indent, content = match.groups()
if not inside_dox_list and not previous_was_dox_blankline:
output.append(f"{indent}*")
@@ -155,34 +169,34 @@ def process_file(file_path):
output.append(f"{indent}* - {content}")
inside_dox_list = True
just_finished_a_list = False
- elif inside_dox_list and (
- match := re.match(r'^(\s*)\*\s{2,}(.*)$', line)):
+ elif inside_dox_list and (match := re.match(r"^(\s*)\*\s{2,}(.*)$", line)):
# print("list continuation")
indent, content = match.groups()
output.append(f"{indent}* {content}")
- elif inside_dox_list and (match := re.match(r'^(\s*)\*(?!/)', line)):
+ elif inside_dox_list and (match := re.match(r"^(\s*)\*(?!/)", line)):
inside_dox_list = False
indent = match.group(1)
# print("end list without line break")
output.append(f"{indent}*")
output.append(line)
just_finished_a_list = True
- elif re.match(r'^(\s*)\*/\s*$', line):
+ elif re.match(r"^(\s*)\*/\s*$", line):
inside_dox_block = False
inside_dox_list = False
just_finished_a_list = False
if buffered_line:
output.append(buffered_line)
- buffered_line = ''
+ buffered_line = ""
output.append(line)
# print("end_block")
else:
if buffered_line:
output.append(buffered_line)
- buffered_line = ''
+ buffered_line = ""
- if not re.match(r'^\s*[#*]', line) and (
- match := re.match(r'^(\s*?)(\s?)(.+?)$', line)):
+ if not re.match(r"^\s*[#*]", line) and (
+ match := re.match(r"^(\s*?)(\s?)(.+?)$", line)
+ ):
indent, space, content = match.groups()
line = f"{indent}* {content}"
@@ -190,11 +204,11 @@ def process_file(file_path):
# print("normal dox")
previous_was_dox_blankline = False
just_finished_a_list = False
- elif (match := re.match(r'^(\s*)/\*\*(?!\*)\s*(.*)$', line)):
+ elif match := re.match(r"^(\s*)/\*\*(?!\*)\s*(.*)$", line):
indent, content = match.groups()
# Space around doxygen start blocks (force blank line before /**)
if not previous_was_blankline:
- output.append('')
+ output.append("")
if content:
# new line after /** begin block
output.append(f"{indent}/**")
@@ -206,14 +220,14 @@ def process_file(file_path):
else:
if buffered_line:
output.append(buffered_line)
- buffered_line = ''
+ buffered_line = ""
output.append(line)
i += 1
previous_was_blankline = is_blank_line
- with open(file_path, 'w') as file:
- file.write('\n'.join(output) + '\n')
+ with open(file_path, "w") as file:
+ file.write("\n".join(output) + "\n")
if __name__ == "__main__":
diff --git a/scripts/dump_babel_formats.py b/scripts/dump_babel_formats.py
index 44e544cfe29c..c3a2762ccf95 100644
--- a/scripts/dump_babel_formats.py
+++ b/scripts/dump_babel_formats.py
@@ -21,12 +21,12 @@
Dumps a list of babel formats for inclusion in QgsBabelFormatRegistry::QgsBabelFormatRegistry()
"""
-__author__ = 'Nyall Dawson'
-__date__ = 'July 2021'
-__copyright__ = '(C) 2021, Nyall Dawson'
+__author__ = "Nyall Dawson"
+__date__ = "July 2021"
+__copyright__ = "(C) 2021, Nyall Dawson"
-import subprocess
import re
+import subprocess
def process_lines(lines):
@@ -38,25 +38,33 @@ def process_lines(lines):
while current_line < len(lines):
line = lines[current_line]
- fields = line.split('\t')
+ fields = line.split("\t")
assert len(fields) >= 5, fields
current_line += 1
html_pages = []
- while lines[current_line].startswith('http'):
+ while lines[current_line].startswith("http"):
html_pages.append(lines[current_line])
current_line += 1
- while current_line < len(lines) and lines[current_line].startswith('option'):
- options = lines[current_line].split('\t')
+ while current_line < len(lines) and lines[current_line].startswith("option"):
+ options = lines[current_line].split("\t")
assert len(options) >= 9, options
- name, description, option_type, option_def, option_min, option_max, option_html = options[:7]
+ (
+ name,
+ description,
+ option_type,
+ option_def,
+ option_min,
+ option_max,
+ option_html,
+ ) = options[:7]
# print(name, description, option_type, option_def, option_min, option_max, option_html)
option_http_pages = []
current_line += 1
- while current_line < len(lines) and lines[current_line].startswith('http'):
+ while current_line < len(lines) and lines[current_line].startswith("http"):
option_http_pages.append(lines[current_line])
current_line += 1
@@ -64,31 +72,42 @@ def process_lines(lines):
description = fields[4]
# remove odd comment from description!
- description = description.replace(' [ Get Jonathon Johnson to describe', '')
-
- read_waypoints = fields[1][0] == 'r'
- read_tracks = fields[1][2] == 'r'
- read_routes = fields[1][4] == 'r'
- write_waypoints = fields[1][1] == 'w'
- write_tracks = fields[1][3] == 'w'
- write_routes = fields[1][5] == 'w'
- is_file_format = fields[0] == 'file'
- is_device_format = fields[0] == 'serial'
- extensions = fields[3].split('/')
+ description = description.replace(" [ Get Jonathon Johnson to describe", "")
+
+ read_waypoints = fields[1][0] == "r"
+ read_tracks = fields[1][2] == "r"
+ read_routes = fields[1][4] == "r"
+ write_waypoints = fields[1][1] == "w"
+ write_tracks = fields[1][3] == "w"
+ write_routes = fields[1][5] == "w"
+ is_file_format = fields[0] == "file"
+ is_device_format = fields[0] == "serial"
+ extensions = fields[3].split("/")
if is_file_format and any([read_routes, read_tracks, read_waypoints]):
capabilities = []
if read_waypoints:
- capabilities.append('Qgis::BabelFormatCapability::Waypoints')
+ capabilities.append("Qgis::BabelFormatCapability::Waypoints")
if read_routes:
- capabilities.append('Qgis::BabelFormatCapability::Routes')
+ capabilities.append("Qgis::BabelFormatCapability::Routes")
if read_tracks:
- capabilities.append('Qgis::BabelFormatCapability::Tracks')
- capabilities_string = ' | '.join(capabilities)
-
- extensions_string = '{' + ', '.join([f'QStringLiteral( "{ext.strip()}" )' for ext in extensions if ext.strip()]) + '}'
- format_out[
- name] = f'mImporters[QStringLiteral( "{name}" )] = new QgsBabelSimpleImportFormat( QStringLiteral( "{name}" ), QStringLiteral( "{description}" ), {capabilities_string}, {extensions_string} );'
+ capabilities.append("Qgis::BabelFormatCapability::Tracks")
+ capabilities_string = " | ".join(capabilities)
+
+ extensions_string = (
+ "{"
+ + ", ".join(
+ [
+ f'QStringLiteral( "{ext.strip()}" )'
+ for ext in extensions
+ if ext.strip()
+ ]
+ )
+ + "}"
+ )
+ format_out[name] = (
+ f'mImporters[QStringLiteral( "{name}" )] = new QgsBabelSimpleImportFormat( QStringLiteral( "{name}" ), QStringLiteral( "{description}" ), {capabilities_string}, {extensions_string} );'
+ )
for format_name in sorted(format_out.keys(), key=lambda x: x.lower()):
print(format_out[format_name])
diff --git a/scripts/generate_test_mask_image.py b/scripts/generate_test_mask_image.py
index 180f156b30a2..968c49d6b4d1 100755
--- a/scripts/generate_test_mask_image.py
+++ b/scripts/generate_test_mask_image.py
@@ -17,24 +17,25 @@
***************************************************************************
"""
-__author__ = 'Nyall Dawson'
-__date__ = 'February 2015'
-__copyright__ = '(C) 2015, Nyall Dawson'
+__author__ = "Nyall Dawson"
+__date__ = "February 2015"
+__copyright__ = "(C) 2015, Nyall Dawson"
# Generates (or updates) a unit test image mask, which is used to specify whether
# a pixel in the control image should be checked (black pixel in mask) or not (white
# pixel in mask). For non black or white pixels, the pixels lightness is used to
# specify a maximum delta for each color component
-import os
-import sys
import argparse
-from PyQt5.QtGui import QImage, QColor, qRed, qBlue, qGreen, qAlpha, qRgb
+import glob
+import os
import struct
-import urllib.request
+import sys
import urllib.error
import urllib.parse
-import glob
+import urllib.request
+
+from PyQt5.QtGui import QColor, QImage, qAlpha, qBlue, qGreen, qRed, qRgb
def error(msg):
@@ -51,7 +52,7 @@ def colorDiff(c1, c2):
def imageFromPath(path):
- if (path[:7] == 'http://' or path[:7] == 'file://' or path[:8] == 'https://'):
+ if path[:7] == "http://" or path[:7] == "file://" or path[:8] == "https://":
# fetch remote image
data = urllib.request.urlopen(path).read()
image = QImage()
@@ -67,42 +68,53 @@ def getControlImagePath(path):
# else try and find matching test image
script_folder = os.path.dirname(os.path.realpath(sys.argv[0]))
- control_images_folder = os.path.join(script_folder, '../tests/testdata/control_images')
+ control_images_folder = os.path.join(
+ script_folder, "../tests/testdata/control_images"
+ )
- matching_control_images = [x[0] for x in os.walk(control_images_folder) if path in x[0]]
+ matching_control_images = [
+ x[0] for x in os.walk(control_images_folder) if path in x[0]
+ ]
if len(matching_control_images) > 1:
- error(f'Found multiple matching control images for {path}')
+ error(f"Found multiple matching control images for {path}")
elif len(matching_control_images) == 0:
- error(f'No matching control images found for {path}')
+ error(f"No matching control images found for {path}")
found_control_image_path = matching_control_images[0]
# check for a single matching expected image
- images = glob.glob(os.path.join(found_control_image_path, '*.png'))
- filtered_images = [i for i in images if not i[-9:] == '_mask.png']
+ images = glob.glob(os.path.join(found_control_image_path, "*.png"))
+ filtered_images = [i for i in images if not i[-9:] == "_mask.png"]
if len(filtered_images) > 1:
- error(f'Found multiple matching control images for {path}')
+ error(f"Found multiple matching control images for {path}")
elif len(filtered_images) == 0:
- error(f'No matching control images found for {path}')
+ error(f"No matching control images found for {path}")
found_image = filtered_images[0]
- print(f'Found matching control image: {found_image}')
+ print(f"Found matching control image: {found_image}")
return found_image
def updateMask(control_image_path, rendered_image_path, mask_image_path):
control_image = imageFromPath(control_image_path)
if not control_image:
- error(f'Could not read control image {control_image_path}')
+ error(f"Could not read control image {control_image_path}")
rendered_image = imageFromPath(rendered_image_path)
if not rendered_image:
- error(f'Could not read rendered image {rendered_image_path}')
- if not rendered_image.width() == control_image.width() or not rendered_image.height() == control_image.height():
- print('Size mismatch - control image is {}x{}, rendered image is {}x{}'.format(control_image.width(),
- control_image.height(),
- rendered_image.width(),
- rendered_image.height()))
+ error(f"Could not read rendered image {rendered_image_path}")
+ if (
+ not rendered_image.width() == control_image.width()
+ or not rendered_image.height() == control_image.height()
+ ):
+ print(
+ "Size mismatch - control image is {}x{}, rendered image is {}x{}".format(
+ control_image.width(),
+ control_image.height(),
+ rendered_image.width(),
+ rendered_image.height(),
+ )
+ )
max_width = min(rendered_image.width(), control_image.width())
max_height = min(rendered_image.height(), control_image.height())
@@ -110,8 +122,10 @@ def updateMask(control_image_path, rendered_image_path, mask_image_path):
# read current mask, if it exist
mask_image = imageFromPath(mask_image_path)
if mask_image.isNull():
- print(f'Mask image does not exist, creating {mask_image_path}')
- mask_image = QImage(control_image.width(), control_image.height(), QImage.Format.Format_ARGB32)
+ print(f"Mask image does not exist, creating {mask_image_path}")
+ mask_image = QImage(
+ control_image.width(), control_image.height(), QImage.Format.Format_ARGB32
+ )
mask_image.fill(QColor(0, 0, 0))
# loop through pixels in rendered image and compare
@@ -123,14 +137,16 @@ def updateMask(control_image_path, rendered_image_path, mask_image_path):
mask_scanline = mask_image.scanLine(y).asstring(linebytes)
for x in range(max_width):
- currentTolerance = qRed(struct.unpack('I', mask_scanline[x * 4:x * 4 + 4])[0])
+ currentTolerance = qRed(
+ struct.unpack("I", mask_scanline[x * 4 : x * 4 + 4])[0]
+ )
if currentTolerance == 255:
# ignore pixel
continue
- expected_rgb = struct.unpack('I', control_scanline[x * 4:x * 4 + 4])[0]
- rendered_rgb = struct.unpack('I', rendered_scanline[x * 4:x * 4 + 4])[0]
+ expected_rgb = struct.unpack("I", control_scanline[x * 4 : x * 4 + 4])[0]
+ rendered_rgb = struct.unpack("I", rendered_scanline[x * 4 : x * 4 + 4])[0]
difference = colorDiff(expected_rgb, rendered_rgb)
if difference > currentTolerance:
@@ -141,20 +157,22 @@ def updateMask(control_image_path, rendered_image_path, mask_image_path):
if mismatch_count:
# update mask
mask_image.save(mask_image_path, "png")
- print(f'Updated {mismatch_count} pixels in {mask_image_path}')
+ print(f"Updated {mismatch_count} pixels in {mask_image_path}")
else:
- print(f'No mismatches in {mask_image_path}')
+ print(f"No mismatches in {mask_image_path}")
-parser = argparse.ArgumentParser() # OptionParser("usage: %prog control_image rendered_image mask_image")
-parser.add_argument('control_image')
-parser.add_argument('rendered_image')
-parser.add_argument('mask_image', nargs='?', default=None)
+parser = (
+ argparse.ArgumentParser()
+) # OptionParser("usage: %prog control_image rendered_image mask_image")
+parser.add_argument("control_image")
+parser.add_argument("rendered_image")
+parser.add_argument("mask_image", nargs="?", default=None)
args = parser.parse_args()
args.control_image = getControlImagePath(args.control_image)
if not args.mask_image:
- args.mask_image = args.control_image[:-4] + '_mask.png'
+ args.mask_image = args.control_image[:-4] + "_mask.png"
updateMask(args.control_image, args.rendered_image, args.mask_image)
diff --git a/scripts/includemocs.py b/scripts/includemocs.py
index a917511ec060..9c35fd5e8622 100644
--- a/scripts/includemocs.py
+++ b/scripts/includemocs.py
@@ -15,9 +15,9 @@
# pylint: disable=redefined-outer-name
+import argparse
import os
import re
-import argparse
import sys
dirty = False
@@ -38,11 +38,11 @@ def shouldExclude(root, path):
return False # No excludes provided
assert root.startswith(args.root)
- root = stripInitialSlash(root[len(args.root):])
+ root = stripInitialSlash(root[len(args.root) :])
if args.headerPrefix:
assert root.startswith(args.headerPrefix)
- root = stripInitialSlash(root[len(args.headerPrefix):])
+ root = stripInitialSlash(root[len(args.headerPrefix) :])
return (path in args.excludes) or (root + "/" + path in args.excludes)
@@ -52,7 +52,7 @@ def shouldExclude(root, path):
def hasMacro(fileName):
- with open(fileName, "r", encoding="ISO-8859-1") as fileHandle:
+ with open(fileName, encoding="ISO-8859-1") as fileHandle:
for line in fileHandle:
if regexp.match(line):
return True
@@ -64,11 +64,11 @@ def hasMacro(fileName):
def matchingCPPFile(root, fileName):
assert root.startswith(args.root)
- root = stripInitialSlash(root[len(args.root):])
+ root = stripInitialSlash(root[len(args.root) :])
if args.headerPrefix:
assert root.startswith(args.headerPrefix)
- root = stripInitialSlash(root[len(args.headerPrefix):])
+ root = stripInitialSlash(root[len(args.headerPrefix) :])
if args.sourcePrefix:
root = args.sourcePrefix + "/" + root
@@ -112,7 +112,7 @@ def trimExistingMocInclude(content, cppFileName):
)
match = mocStrRegex.search(content)
if match:
- return content[: match.start()] + content[match.end():]
+ return content[: match.start()] + content[match.end() :]
return content
@@ -143,7 +143,7 @@ def processFile(root, fileName):
else:
log("Updating %s" % cppFileName)
- with open(cppFileName, "r", encoding="utf8") as f:
+ with open(cppFileName, encoding="utf8") as f:
content = f.read()
if args.replaceExisting:
diff --git a/scripts/mkuidefaults.py b/scripts/mkuidefaults.py
index bbad6eba19cf..f1b67c4be6c5 100755
--- a/scripts/mkuidefaults.py
+++ b/scripts/mkuidefaults.py
@@ -17,19 +17,19 @@
***************************************************************************
"""
-__author__ = 'Juergen E. Fischer'
-__date__ = 'June 2013'
-__copyright__ = '(C) 2013, Juergen E. Fischer'
+__author__ = "Juergen E. Fischer"
+__date__ = "June 2013"
+__copyright__ = "(C) 2013, Juergen E. Fischer"
-import sys
import struct
+import sys
from PyQt5.QtCore import QCoreApplication, QSettings
def chunks(l, n):
for i in range(0, len(l), n):
- yield l[i:i + n]
+ yield l[i : i + n]
QCoreApplication.setOrganizationName("QGIS")
@@ -37,7 +37,7 @@ def chunks(l, n):
QCoreApplication.setApplicationName("QGIS3")
if len(sys.argv) == 1:
- print("Usage: ./scripts/mkuidefaults.py \"location_to_ini\"")
+ print('Usage: ./scripts/mkuidefaults.py "location_to_ini"')
sys.exit(1)
s = QSettings(sys.argv[1], QSettings.Format.IniFormat)
@@ -46,40 +46,57 @@ def chunks(l, n):
with open("src/app/ui_defaults.h", "w") as f:
- f.write("#ifndef UI_DEFAULTS_H\n#define UI_DEFAULTS_H\n" +
- "\nstatic const unsigned char defaultUIgeometry[] =\n{\n")
+ f.write(
+ "#ifndef UI_DEFAULTS_H\n#define UI_DEFAULTS_H\n"
+ + "\nstatic const unsigned char defaultUIgeometry[] =\n{\n"
+ )
for chunk in chunks(ba, 16):
- f.write(' {},\n'.format(
- ', '.join(map(hex, struct.unpack('B' * len(chunk), chunk)))))
+ f.write(
+ " {},\n".format(
+ ", ".join(map(hex, struct.unpack("B" * len(chunk), chunk)))
+ )
+ )
f.write("};\n\nstatic const unsigned char defaultUIstate[] =\n{\n")
ba = bytes(s.value("/UI/state"))
for chunk in chunks(ba, 16):
- f.write(' {},\n'.format(
- ', '.join(map(hex, struct.unpack('B' * len(chunk), chunk)))))
+ f.write(
+ " {},\n".format(
+ ", ".join(map(hex, struct.unpack("B" * len(chunk), chunk)))
+ )
+ )
try:
ba = bytes(s.value("/app/LayoutDesigner/geometry"))
- f.write("};\n\nstatic const unsigned char " +
- "defaultLayerDesignerUIgeometry[] =\n{\n")
+ f.write(
+ "};\n\nstatic const unsigned char "
+ + "defaultLayerDesignerUIgeometry[] =\n{\n"
+ )
for chunk in chunks(ba, 16):
- f.write(' {},\n'.format(
- ', '.join(map(hex, struct.unpack('B' * len(chunk), chunk)))))
+ f.write(
+ " {},\n".format(
+ ", ".join(map(hex, struct.unpack("B" * len(chunk), chunk)))
+ )
+ )
except TypeError as ex:
pass
try:
ba = bytes(s.value("/app/LayoutDesigner/state"))
- f.write("};\n\nstatic const unsigned char " +
- "defaultLayerDesignerUIstate[] =\n{\n")
+ f.write(
+ "};\n\nstatic const unsigned char " + "defaultLayerDesignerUIstate[] =\n{\n"
+ )
for chunk in chunks(ba, 16):
- f.write(' {},\n'.format(
- ', '.join(map(hex, struct.unpack('B' * len(chunk), chunk)))))
+ f.write(
+ " {},\n".format(
+ ", ".join(map(hex, struct.unpack("B" * len(chunk), chunk)))
+ )
+ )
except TypeError as ex:
pass
diff --git a/scripts/parse_dash_results.py b/scripts/parse_dash_results.py
index 4b06578d9f4e..cdd49a3a748c 100755
--- a/scripts/parse_dash_results.py
+++ b/scripts/parse_dash_results.py
@@ -17,43 +17,46 @@
***************************************************************************
"""
-__author__ = 'Nyall Dawson'
-__date__ = 'October 2016'
-__copyright__ = '(C) 2016, Nyall Dawson'
+__author__ = "Nyall Dawson"
+__date__ = "October 2016"
+__copyright__ = "(C) 2016, Nyall Dawson"
+import argparse
+import glob
+import json
import os
+import re
+import struct
import sys
-import argparse
-import urllib.request
-import urllib.parse
import urllib.error
-import re
-import json
-from PyQt5.QtCore import (Qt)
-from PyQt5.QtGui import (
- QImage, QColor, qRed, qBlue, qGreen, qAlpha, qRgb, QPixmap)
-from PyQt5.QtWidgets import (QDialog,
- QApplication,
- QLabel,
- QVBoxLayout,
- QHBoxLayout,
- QGridLayout,
- QPushButton,
- QDoubleSpinBox,
- QWidget,
- QScrollArea,
- QLayout,
- QDialogButtonBox,
- QListWidget)
+import urllib.parse
+import urllib.request
+
import termcolor
-import struct
-import glob
-dash_url = 'https://cdash.orfeo-toolbox.org'
+from PyQt5.QtCore import Qt
+from PyQt5.QtGui import QColor, QImage, QPixmap, qAlpha, qBlue, qGreen, qRed, qRgb
+from PyQt5.QtWidgets import (
+ QApplication,
+ QDialog,
+ QDialogButtonBox,
+ QDoubleSpinBox,
+ QGridLayout,
+ QHBoxLayout,
+ QLabel,
+ QLayout,
+ QListWidget,
+ QPushButton,
+ QScrollArea,
+ QVBoxLayout,
+ QWidget,
+)
+
+dash_url = "https://cdash.orfeo-toolbox.org"
def error(msg):
- print(termcolor.colored(msg, 'red'))
+ print(termcolor.colored(msg, "red"))
sys.exit(1)
@@ -66,14 +69,14 @@ def colorDiff(c1, c2):
def imageFromPath(path):
- if (path[:8] == 'https://' or path[:7] == 'file://'):
+ if path[:8] == "https://" or path[:7] == "file://":
# fetch remote image
- print(f'Fetching remote ({path})')
+ print(f"Fetching remote ({path})")
data = urllib.request.urlopen(path).read()
image = QImage()
image.loadFromData(data)
else:
- print(f'Using local ({path})')
+ print(f"Using local ({path})")
image = QImage(path)
return image
@@ -83,15 +86,19 @@ class SelectReferenceImageDialog(QDialog):
def __init__(self, parent, test_name, images):
super().__init__(parent)
- self.setWindowTitle('Select reference image')
+ self.setWindowTitle("Select reference image")
self.setWindowFlags(Qt.WindowType.Window)
- self.button_box = QDialogButtonBox(QDialogButtonBox.StandardButton.Ok | QDialogButtonBox.StandardButton.Cancel)
+ self.button_box = QDialogButtonBox(
+ QDialogButtonBox.StandardButton.Ok | QDialogButtonBox.StandardButton.Cancel
+ )
self.button_box.accepted.connect(self.accept)
self.button_box.rejected.connect(self.reject)
layout = QVBoxLayout()
- layout.addWidget(QLabel(f'Found multiple matching reference images for {test_name}'))
+ layout.addWidget(
+ QLabel(f"Found multiple matching reference images for {test_name}")
+ )
self.list = QListWidget()
layout.addWidget(self.list, 1)
@@ -110,7 +117,7 @@ class ResultHandler(QDialog):
def __init__(self, parent=None):
super().__init__(parent)
- self.setWindowTitle('Dash results')
+ self.setWindowTitle("Dash results")
self.setWindowFlags(Qt.WindowType.Window)
self.control_label = QLabel()
self.rendered_label = QLabel()
@@ -125,14 +132,14 @@ def __init__(self, parent=None):
self.test_name_label = QLabel()
grid = QGridLayout()
grid.addWidget(self.test_name_label, 0, 0)
- grid.addWidget(QLabel('Control'), 1, 0)
- grid.addWidget(QLabel('Rendered'), 1, 1)
- grid.addWidget(QLabel('Difference'), 1, 2)
+ grid.addWidget(QLabel("Control"), 1, 0)
+ grid.addWidget(QLabel("Rendered"), 1, 1)
+ grid.addWidget(QLabel("Difference"), 1, 2)
grid.addWidget(self.control_label, 2, 0)
grid.addWidget(self.rendered_label, 2, 1)
grid.addWidget(self.diff_label, 2, 2)
- grid.addWidget(QLabel('Current Mask'), 3, 0)
- grid.addWidget(QLabel('New Mask'), 3, 1)
+ grid.addWidget(QLabel("Current Mask"), 3, 0)
+ grid.addWidget(QLabel("New Mask"), 3, 1)
grid.addWidget(self.mask_label, 4, 0)
grid.addWidget(self.new_mask_label, 4, 1)
grid.setSizeConstraint(QLayout.SizeConstraint.SetFixedSize)
@@ -143,31 +150,33 @@ def __init__(self, parent=None):
v_layout.addWidget(self.scrollArea, 1)
next_image_button = QPushButton()
- next_image_button.setText('Skip')
+ next_image_button.setText("Skip")
next_image_button.pressed.connect(self.load_next)
self.overload_spin = QDoubleSpinBox()
self.overload_spin.setMinimum(1)
self.overload_spin.setMaximum(255)
self.overload_spin.setValue(1)
- self.overload_spin.valueChanged.connect(lambda: save_mask_button.setEnabled(False))
+ self.overload_spin.valueChanged.connect(
+ lambda: save_mask_button.setEnabled(False)
+ )
preview_mask_button = QPushButton()
- preview_mask_button.setText('Preview New Mask')
+ preview_mask_button.setText("Preview New Mask")
preview_mask_button.pressed.connect(self.preview_mask)
preview_mask_button.pressed.connect(lambda: save_mask_button.setEnabled(True))
save_mask_button = QPushButton()
- save_mask_button.setText('Save New Mask')
+ save_mask_button.setText("Save New Mask")
save_mask_button.pressed.connect(self.save_mask)
add_ref_image_button = QPushButton()
- add_ref_image_button.setText('Add Reference Image')
+ add_ref_image_button.setText("Add Reference Image")
add_ref_image_button.pressed.connect(self.add_reference_image)
button_layout = QHBoxLayout()
button_layout.addWidget(next_image_button)
- button_layout.addWidget(QLabel('Mask diff multiplier:'))
+ button_layout.addWidget(QLabel("Mask diff multiplier:"))
button_layout.addWidget(self.overload_spin)
button_layout.addWidget(preview_mask_button)
button_layout.addWidget(save_mask_button)
@@ -181,27 +190,39 @@ def closeEvent(self, event):
def parse_url(self, url):
parts = urllib.parse.urlsplit(url)
- apiurl = urllib.parse.urlunsplit((parts.scheme, parts.netloc, '/api/v1/testDetails.php', parts.query, parts.fragment))
- print(f'Fetching dash results from api: {apiurl}')
+ apiurl = urllib.parse.urlunsplit(
+ (
+ parts.scheme,
+ parts.netloc,
+ "/api/v1/testDetails.php",
+ parts.query,
+ parts.fragment,
+ )
+ )
+ print(f"Fetching dash results from api: {apiurl}")
page = urllib.request.urlopen(apiurl)
- content = json.loads(page.read().decode('utf-8'))
+ content = json.loads(page.read().decode("utf-8"))
# build up list of rendered images
- measurement_img = [img for img in content['test']['images'] if img['role'].startswith('Rendered Image')]
+ measurement_img = [
+ img
+ for img in content["test"]["images"]
+ if img["role"].startswith("Rendered Image")
+ ]
images = {}
for img in measurement_img:
- m = re.search(r'Rendered Image (.*?)(\s|$)', img['role'])
+ m = re.search(r"Rendered Image (.*?)(\s|$)", img["role"])
test_name = m.group(1)
- rendered_image = 'displayImage.php?imgid={}'.format(img['imgid'])
- images[test_name] = f'{dash_url}/{rendered_image}'
+ rendered_image = "displayImage.php?imgid={}".format(img["imgid"])
+ images[test_name] = f"{dash_url}/{rendered_image}"
if images:
- print('Found images:\n')
+ print("Found images:\n")
for title, url in images.items():
- print(' ' + termcolor.colored(title, attrs=['bold']) + ' : ' + url)
+ print(" " + termcolor.colored(title, attrs=["bold"]) + " : " + url)
else:
- print(termcolor.colored('No images found\n', 'yellow'))
+ print(termcolor.colored("No images found\n", "yellow"))
self.images = images
self.load_next()
@@ -213,49 +234,53 @@ def load_next(self):
test_name, rendered_image = self.images.popitem()
self.test_name_label.setText(test_name)
- print(termcolor.colored('\n' + test_name, attrs=['bold']))
+ print(termcolor.colored("\n" + test_name, attrs=["bold"]))
control_image = self.get_control_image_path(test_name)
if not control_image:
self.load_next()
return
- self.mask_image_path = control_image[:-4] + '_mask.png'
+ self.mask_image_path = control_image[:-4] + "_mask.png"
self.load_images(control_image, rendered_image, self.mask_image_path)
def load_images(self, control_image_path, rendered_image_path, mask_image_path):
self.control_image = imageFromPath(control_image_path)
if not self.control_image:
- error(f'Could not read control image {control_image_path}')
+ error(f"Could not read control image {control_image_path}")
self.rendered_image = imageFromPath(rendered_image_path)
if not self.rendered_image:
- error(
- f'Could not read rendered image {rendered_image_path}')
- if not self.rendered_image.width() == self.control_image.width() or not self.rendered_image.height() == self.control_image.height():
+ error(f"Could not read rendered image {rendered_image_path}")
+ if (
+ not self.rendered_image.width() == self.control_image.width()
+ or not self.rendered_image.height() == self.control_image.height()
+ ):
print(
- 'Size mismatch - control image is {}x{}, rendered image is {}x{}'.format(self.control_image.width(),
- self.control_image.height(
- ),
- self.rendered_image.width(
- ),
- self.rendered_image.height()))
-
- max_width = min(
- self.rendered_image.width(), self.control_image.width())
- max_height = min(
- self.rendered_image.height(), self.control_image.height())
+ "Size mismatch - control image is {}x{}, rendered image is {}x{}".format(
+ self.control_image.width(),
+ self.control_image.height(),
+ self.rendered_image.width(),
+ self.rendered_image.height(),
+ )
+ )
+
+ max_width = min(self.rendered_image.width(), self.control_image.width())
+ max_height = min(self.rendered_image.height(), self.control_image.height())
# read current mask, if it exist
self.mask_image = imageFromPath(mask_image_path)
if self.mask_image.isNull():
- print(
- f'Mask image does not exist, creating {mask_image_path}')
+ print(f"Mask image does not exist, creating {mask_image_path}")
self.mask_image = QImage(
- self.control_image.width(), self.control_image.height(), QImage.Format.Format_ARGB32)
+ self.control_image.width(),
+ self.control_image.height(),
+ QImage.Format.Format_ARGB32,
+ )
self.mask_image.fill(QColor(0, 0, 0))
self.diff_image = self.create_diff_image(
- self.control_image, self.rendered_image, self.mask_image)
+ self.control_image, self.rendered_image, self.mask_image
+ )
if not self.diff_image:
self.load_next()
return
@@ -272,7 +297,11 @@ def load_images(self, control_image_path, rendered_image_path, mask_image_path):
def preview_mask(self):
self.new_mask_image = self.create_mask(
- self.control_image, self.rendered_image, self.mask_image, self.overload_spin.value())
+ self.control_image,
+ self.rendered_image,
+ self.mask_image,
+ self.overload_spin.value(),
+ )
self.new_mask_label.setPixmap(QPixmap.fromImage(self.new_mask_image))
self.new_mask_label.setFixedSize(self.new_mask_image.size())
@@ -281,20 +310,24 @@ def save_mask(self):
self.load_next()
def add_reference_image(self):
- if os.path.abspath(self.control_images_base_path) == os.path.abspath(self.found_control_image_path):
- images = glob.glob(os.path.join(self.found_control_image_path, '*.png'))
- default_path = os.path.join(self.found_control_image_path, 'set1')
+ if os.path.abspath(self.control_images_base_path) == os.path.abspath(
+ self.found_control_image_path
+ ):
+ images = glob.glob(os.path.join(self.found_control_image_path, "*.png"))
+ default_path = os.path.join(self.found_control_image_path, "set1")
os.makedirs(default_path)
for image in images:
imgname = os.path.basename(image)
os.rename(image, os.path.join(default_path, imgname))
for i in range(2, 100):
- new_path = os.path.join(self.control_images_base_path, 'set' + str(i))
+ new_path = os.path.join(self.control_images_base_path, "set" + str(i))
if not os.path.exists(new_path):
break
else:
- raise RuntimeError('Could not find a suitable directory for another set of reference images')
+ raise RuntimeError(
+ "Could not find a suitable directory for another set of reference images"
+ )
os.makedirs(new_path)
control_image_name = os.path.basename(self.found_image)
@@ -306,44 +339,50 @@ def create_mask(self, control_image, rendered_image, mask_image, overload=1):
max_height = min(rendered_image.height(), control_image.height())
new_mask_image = QImage(
- control_image.width(), control_image.height(), QImage.Format.Format_ARGB32)
+ control_image.width(), control_image.height(), QImage.Format.Format_ARGB32
+ )
new_mask_image.fill(QColor(0, 0, 0))
# loop through pixels in rendered image and compare
mismatch_count = 0
linebytes = max_width * 4
for y in range(max_height):
- control_scanline = control_image.constScanLine(
- y).asstring(linebytes)
- rendered_scanline = rendered_image.constScanLine(
- y).asstring(linebytes)
+ control_scanline = control_image.constScanLine(y).asstring(linebytes)
+ rendered_scanline = rendered_image.constScanLine(y).asstring(linebytes)
mask_scanline = mask_image.scanLine(y).asstring(linebytes)
for x in range(max_width):
currentTolerance = qRed(
- struct.unpack('I', mask_scanline[x * 4:x * 4 + 4])[0])
+ struct.unpack("I", mask_scanline[x * 4 : x * 4 + 4])[0]
+ )
if currentTolerance == 255:
# ignore pixel
new_mask_image.setPixel(
- x, y, qRgb(currentTolerance, currentTolerance, currentTolerance))
+ x, y, qRgb(currentTolerance, currentTolerance, currentTolerance)
+ )
continue
- expected_rgb = struct.unpack(
- 'I', control_scanline[x * 4:x * 4 + 4])[0]
- rendered_rgb = struct.unpack(
- 'I', rendered_scanline[x * 4:x * 4 + 4])[0]
+ expected_rgb = struct.unpack("I", control_scanline[x * 4 : x * 4 + 4])[
+ 0
+ ]
+ rendered_rgb = struct.unpack("I", rendered_scanline[x * 4 : x * 4 + 4])[
+ 0
+ ]
difference = min(
- 255, int(colorDiff(expected_rgb, rendered_rgb) * overload))
+ 255, int(colorDiff(expected_rgb, rendered_rgb) * overload)
+ )
if difference > currentTolerance:
# update mask image
new_mask_image.setPixel(
- x, y, qRgb(difference, difference, difference))
+ x, y, qRgb(difference, difference, difference)
+ )
mismatch_count += 1
else:
new_mask_image.setPixel(
- x, y, qRgb(currentTolerance, currentTolerance, currentTolerance))
+ x, y, qRgb(currentTolerance, currentTolerance, currentTolerance)
+ )
return new_mask_image
def get_control_image_path(self, test_name):
@@ -353,16 +392,20 @@ def get_control_image_path(self, test_name):
# else try and find matching test image
script_folder = os.path.dirname(os.path.realpath(sys.argv[0]))
control_images_folder = os.path.join(
- script_folder, '../tests/testdata/control_images')
+ script_folder, "../tests/testdata/control_images"
+ )
- matching_control_images = [x[0]
- for x in os.walk(control_images_folder) if test_name + '/' in x[0] or x[0].endswith(test_name)]
+ matching_control_images = [
+ x[0]
+ for x in os.walk(control_images_folder)
+ if test_name + "/" in x[0] or x[0].endswith(test_name)
+ ]
self.control_images_base_path = os.path.commonprefix(matching_control_images)
if len(matching_control_images) > 1:
for item in matching_control_images:
- print(' - ' + item)
+ print(" - " + item)
dlg = SelectReferenceImageDialog(self, test_name, matching_control_images)
if not dlg.exec():
@@ -370,22 +413,25 @@ def get_control_image_path(self, test_name):
self.found_control_image_path = dlg.selected_image()
elif len(matching_control_images) == 0:
- print(termcolor.colored(f'No matching control images found for {test_name}', 'yellow'))
+ print(
+ termcolor.colored(
+ f"No matching control images found for {test_name}", "yellow"
+ )
+ )
return None
else:
self.found_control_image_path = matching_control_images[0]
# check for a single matching expected image
- images = glob.glob(os.path.join(self.found_control_image_path, '*.png'))
- filtered_images = [i for i in images if not i[-9:] == '_mask.png']
+ images = glob.glob(os.path.join(self.found_control_image_path, "*.png"))
+ filtered_images = [i for i in images if not i[-9:] == "_mask.png"]
if len(filtered_images) > 1:
- error(
- f'Found multiple matching control images for {test_name}')
+ error(f"Found multiple matching control images for {test_name}")
elif len(filtered_images) == 0:
- error(f'No matching control images found for {test_name}')
+ error(f"No matching control images found for {test_name}")
self.found_image = filtered_images[0]
- print(f'Found matching control image: {self.found_image}')
+ print(f"Found matching control image: {self.found_image}")
return self.found_image
def create_diff_image(self, control_image, rendered_image, mask_image):
@@ -396,28 +442,30 @@ def create_diff_image(self, control_image, rendered_image, mask_image):
linebytes = max_width * 4
diff_image = QImage(
- control_image.width(), control_image.height(), QImage.Format.Format_ARGB32)
+ control_image.width(), control_image.height(), QImage.Format.Format_ARGB32
+ )
diff_image.fill(QColor(152, 219, 249))
for y in range(max_height):
- control_scanline = control_image.constScanLine(
- y).asstring(linebytes)
- rendered_scanline = rendered_image.constScanLine(
- y).asstring(linebytes)
+ control_scanline = control_image.constScanLine(y).asstring(linebytes)
+ rendered_scanline = rendered_image.constScanLine(y).asstring(linebytes)
mask_scanline = mask_image.scanLine(y).asstring(linebytes)
for x in range(max_width):
currentTolerance = qRed(
- struct.unpack('I', mask_scanline[x * 4:x * 4 + 4])[0])
+ struct.unpack("I", mask_scanline[x * 4 : x * 4 + 4])[0]
+ )
if currentTolerance == 255:
# ignore pixel
continue
- expected_rgb = struct.unpack(
- 'I', control_scanline[x * 4:x * 4 + 4])[0]
- rendered_rgb = struct.unpack(
- 'I', rendered_scanline[x * 4:x * 4 + 4])[0]
+ expected_rgb = struct.unpack("I", control_scanline[x * 4 : x * 4 + 4])[
+ 0
+ ]
+ rendered_rgb = struct.unpack("I", rendered_scanline[x * 4 : x * 4 + 4])[
+ 0
+ ]
difference = colorDiff(expected_rgb, rendered_rgb)
if difference > currentTolerance:
@@ -428,7 +476,7 @@ def create_diff_image(self, control_image, rendered_image, mask_image):
if mismatch_count:
return diff_image
else:
- print(termcolor.colored('No mismatches', 'green'))
+ print(termcolor.colored("No mismatches", "green"))
return None
@@ -436,7 +484,7 @@ def main():
app = QApplication(sys.argv)
parser = argparse.ArgumentParser(
- description='''A tool to automatically update test image masks based on results submitted to cdash.
+ description="""A tool to automatically update test image masks based on results submitted to cdash.
It will take local control images from the QGIS source and rendered images from test results
on cdash to create a mask.
@@ -445,9 +493,13 @@ def main():
that the new masks will only mask regions on the image that indeed allow for variation.
If the resulting mask is too tolerant, consider adding a new control image next to the existing one.
- ''')
+ """
+ )
- parser.add_argument('dash_url', help='URL to a dash result with images. E.g. https://cdash.orfeo-toolbox.org/testDetails.php?test=15052561&build=27712')
+ parser.add_argument(
+ "dash_url",
+ help="URL to a dash result with images. E.g. https://cdash.orfeo-toolbox.org/testDetails.php?test=15052561&build=27712",
+ )
args = parser.parse_args()
w = ResultHandler()
@@ -455,5 +507,5 @@ def main():
w.exec()
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/scripts/process_function_template.py b/scripts/process_function_template.py
index 0ce1daef4f6a..f2cb90ad09a8 100644
--- a/scripts/process_function_template.py
+++ b/scripts/process_function_template.py
@@ -1,18 +1,18 @@
-import sys
-import os
-import json
import glob
+import json
+import os
+import sys
+
from copy import deepcopy
sys.path.append(
- os.path.join(
- os.path.dirname(os.path.realpath(__file__)),
- '../python/ext-libs'))
+ os.path.join(os.path.dirname(os.path.realpath(__file__)), "../python/ext-libs")
+)
cpp = open(sys.argv[1], "w", encoding="utf-8")
cpp.write(
- "#include \"qgsexpression.h\"\n"
- "#include \"qgsexpression_p.h\"\n"
+ '#include "qgsexpression.h"\n'
+ '#include "qgsexpression_p.h"\n'
"#include \n"
"\n"
"void QgsExpression::initFunctionHelp()\n"
@@ -32,7 +32,7 @@ def quote(v):
return map(quote, v)
elif isinstance(v, str):
- return v.replace('"', '\\"').replace('\n', '\\n')
+ return v.replace('"', '\\"').replace("\n", "\\n")
elif isinstance(v, bool):
return v
@@ -41,7 +41,7 @@ def quote(v):
raise BaseException("unexpected type " + repr(v))
-for f in sorted(glob.glob('resources/function_help/json/*')):
+for f in sorted(glob.glob("resources/function_help/json/*")):
with open(f, encoding="utf-8") as function_file:
try:
json_params = json.load(function_file)
@@ -51,85 +51,115 @@ def quote(v):
json_params = quote(json_params)
- for field in ['name', 'type']:
+ for field in ["name", "type"]:
if field not in json_params:
raise BaseException(f"{f}: {field} missing")
- if not json_params['type'] in ['function', 'operator', 'value', 'expression', 'group']:
- raise BaseException("{}: invalid type {} ".format(f, json_params['type']))
+ if not json_params["type"] in [
+ "function",
+ "operator",
+ "value",
+ "expression",
+ "group",
+ ]:
+ raise BaseException("{}: invalid type {} ".format(f, json_params["type"]))
- if 'variants' not in json_params:
+ if "variants" not in json_params:
# convert single variant shortcut to a expanded variant
v = {}
for i in json_params:
v[i] = json_params[i]
- v['variant'] = json_params['name']
- v['variant_description'] = json_params['description']
- json_params['variants'] = [v]
+ v["variant"] = json_params["name"]
+ v["variant_description"] = json_params["description"]
+ json_params["variants"] = [v]
- name = "\"{}\"".format(json_params['name'])
+ name = '"{}"'.format(json_params["name"])
- if json_params['type'] == 'operator':
- for v in json_params['variants']:
- if 'arguments' not in v:
+ if json_params["type"] == "operator":
+ for v in json_params["variants"]:
+ if "arguments" not in v:
raise BaseException("%s: arguments expected for operator" % f)
- a_list = list(deepcopy(v['arguments']))
+ a_list = list(deepcopy(v["arguments"]))
if not 1 <= len(a_list) <= 2:
- raise BaseException("%s: 1 or 2 arguments expected for operator found %i" % (f, len(a_list)))
+ raise BaseException(
+ "%s: 1 or 2 arguments expected for operator found %i"
+ % (f, len(a_list))
+ )
- cpp.write("\n\n QgsExpression::functionHelpTexts().insert( QStringLiteral( {0} ),\n Help( QStringLiteral( {0} ), tr( \"{1}\" ), tr( \"{2}\" ),\n QList()".format(
- name, json_params['type'], json_params['description'])
+ cpp.write(
+ '\n\n QgsExpression::functionHelpTexts().insert( QStringLiteral( {0} ),\n Help( QStringLiteral( {0} ), tr( "{1}" ), tr( "{2}" ),\n QList()'.format(
+ name, json_params["type"], json_params["description"]
+ )
)
- for v in json_params['variants']:
+ for v in json_params["variants"]:
cpp.write(
- "\n << HelpVariant( tr( \"{}\" ), tr( \"{}\" ),\n QList()".format(v['variant'], v['variant_description']))
-
- if 'arguments' in v:
- for a in v['arguments']:
- cpp.write("\n << HelpArg( QStringLiteral( \"{}\" ), tr( \"{}\" ), {}, {}, {}, {} )".format(
- a['arg'],
- a.get('description', ''),
- "true" if a.get('descOnly', False) else "false",
- "true" if a.get('syntaxOnly', False) else "false",
- "true" if a.get('optional', False) else "false",
- 'QStringLiteral( "{}" )'.format(a.get('default', '')) if a.get('default', '') else "QString()"
- )
+ '\n << HelpVariant( tr( "{}" ), tr( "{}" ),\n QList()'.format(
+ v["variant"], v["variant_description"]
+ )
+ )
+
+ if "arguments" in v:
+ for a in v["arguments"]:
+ cpp.write(
+ '\n << HelpArg( QStringLiteral( "{}" ), tr( "{}" ), {}, {}, {}, {} )'.format(
+ a["arg"],
+ a.get("description", ""),
+ "true" if a.get("descOnly", False) else "false",
+ "true" if a.get("syntaxOnly", False) else "false",
+ "true" if a.get("optional", False) else "false",
+ (
+ 'QStringLiteral( "{}" )'.format(a.get("default", ""))
+ if a.get("default", "")
+ else "QString()"
+ ),
+ )
)
- cpp.write(",\n /* variableLenArguments */ {}".format(
- "true" if v.get('variableLenArguments', False) else "false"))
+ cpp.write(
+ ",\n /* variableLenArguments */ {}".format(
+ "true" if v.get("variableLenArguments", False) else "false"
+ )
+ )
cpp.write(",\n QList()")
- if 'examples' in v:
- for e in v['examples']:
- cpp.write("\n << HelpExample( tr( \"{}\" ), tr( \"{}\" ), tr( \"{}\" ) )".format(
- e['expression'],
- e['returns'],
- e.get('note', ''))
+ if "examples" in v:
+ for e in v["examples"]:
+ cpp.write(
+ '\n << HelpExample( tr( "{}" ), tr( "{}" ), tr( "{}" ) )'.format(
+ e["expression"], e["returns"], e.get("note", "")
+ )
)
- if 'notes' in v:
- cpp.write(",\n tr( \"{}\" )".format(v['notes']))
+ if "notes" in v:
+ cpp.write(',\n tr( "{}" )'.format(v["notes"]))
else:
cpp.write(",\n QString()")
cpp.write(",\n QStringList()")
- if 'tags' in v:
- cpp.write("\n << tr( \"{}\" )".format(",".join(v['tags'])))
+ if "tags" in v:
+ cpp.write('\n << tr( "{}" )'.format(",".join(v["tags"])))
cpp.write("\n )")
cpp.write("\n )")
cpp.write("\n );")
-for f in sorted(glob.glob('resources/function_help/text/*')):
+for f in sorted(glob.glob("resources/function_help/text/*")):
n = os.path.basename(f)
with open(f) as content:
- cpp.write("\n\n QgsExpression::functionHelpTexts().insert( \"{0}\",\n Help( tr( \"{0}\" ), tr( \"group\" ), tr( \"{1}\" ), QList() ) );\n".format(
- n, content.read().replace("\\", "\").replace('\\', '\\\\').replace('"', '\\"').replace('\n', '\\n')))
+ cpp.write(
+ '\n\n QgsExpression::functionHelpTexts().insert( "{0}",\n Help( tr( "{0}" ), tr( "group" ), tr( "{1}" ), QList() ) );\n'.format(
+ n,
+ content.read()
+ .replace("\\", "\")
+ .replace("\\", "\\\\")
+ .replace('"', '\\"')
+ .replace("\n", "\\n"),
+ )
+ )
cpp.write("\n } );\n}\n")
cpp.close()
diff --git a/scripts/process_google_fonts.py b/scripts/process_google_fonts.py
index d68e888c39c5..7b319c1adffc 100644
--- a/scripts/process_google_fonts.py
+++ b/scripts/process_google_fonts.py
@@ -1,1573 +1,1575 @@
-from pathlib import Path
import re
+from pathlib import Path
+
# path to checked out Google Fonts repo
path = Path("/home/me/google/fonts")
# list of fonts from Google Fonts to include
-fonts = ["ABeeZee",
- "ADLaM Display",
- "Abel",
- "Abhaya Libre",
- "Aboreto",
- "Abril Fatface",
- "Abyssinica SIL",
- "Aclonica",
- "Acme",
- "Actor",
- "Adamina",
- "Advent Pro",
- "Agdasima",
- "Aguafina Script",
- "Akatab",
- "Akaya Kanadaka",
- "Akaya Telivigala",
- "Akronim",
- "Akshar",
- "Aladin",
- "Alata",
- "Alatsi",
- "Albert Sans",
- "Aldrich",
- "Alef",
- "Alegreya",
- "Alegreya SC",
- "Alegreya Sans",
- "Alegreya Sans SC",
- "Aleo",
- "Alex Brush",
- "Alexandria",
- "Alfa Slab One",
- "Alice",
- "Alike",
- "Alike Angular",
- "Alkalami",
- "Alkatra",
- "Allan",
- "Allerta",
- "Allerta Stencil",
- "Allison",
- "Allura",
- "Almarai",
- "Almendra",
- "Almendra Display",
- "Almendra SC",
- "Alumni Sans",
- "Alumni Sans Collegiate One",
- "Alumni Sans Inline One",
- "Alumni Sans Pinstripe",
- "Amarante",
- "Amaranth",
- "Amatic SC",
- "Amethysta",
- "Amiko",
- "Amiri",
- "Amiri Quran",
- "Amita",
- "Anaheim",
- "Andada Pro",
- "Andika",
- "Anek Bangla",
- "Anek Devanagari",
- "Anek Gujarati",
- "Anek Gurmukhi",
- "Anek Kannada",
- "Anek Latin",
- "Anek Malayalam",
- "Anek Odia",
- "Anek Tamil",
- "Anek Telugu",
- "Angkor",
- "Annie Use Your Telescope",
- "Anonymous Pro",
- "Antic",
- "Antic Didone",
- "Antic Slab",
- "Anton",
- "Antonio",
- "Anuphan",
- "Anybody",
- "Aoboshi One",
- "Arapey",
- "Arbutus",
- "Arbutus Slab",
- "Architects Daughter",
- "Archivo",
- "Archivo Black",
- "Archivo Narrow",
- "Are You Serious",
- "Aref Ruqaa",
- "Aref Ruqaa Ink",
- "Arima",
- "Arimo",
- "Arizonia",
- "Armata",
- "Arsenal",
- "Artifika",
- "Arvo",
- "Arya",
- "Asap",
- "Asap Condensed",
- "Asar",
- "Asset",
- "Assistant",
- "Astloch",
- "Asul",
- "Athiti",
- "Atkinson Hyperlegible",
- "Atomic Age",
- "Aubrey",
- "Audiowide",
- "Autour One",
- "Average",
- "Average Sans",
- "Averia Gruesa Libre",
- "Averia Libre",
- "Averia Sans Libre",
- "Averia Serif Libre",
- "Azeret Mono",
- "B612",
- "B612 Mono",
- "BIZ UDGothic",
- "BIZ UDMincho",
- "BIZ UDPGothic",
- "BIZ UDPMincho",
- "Babylonica",
- "Bacasime Antique",
- "Bad Script",
- "Bagel Fat One",
- "Bahiana",
- "Bahianita",
- "Bai Jamjuree",
- "Bakbak One",
- "Ballet",
- "Baloo 2",
- "Baloo Bhai 2",
- "Baloo Bhaijaan 2",
- "Baloo Bhaina 2",
- "Baloo Chettan 2",
- "Baloo Da 2",
- "Baloo Paaji 2",
- "Baloo Tamma 2",
- "Baloo Tammudu 2",
- "Baloo Thambi 2",
- "Balsamiq Sans",
- "Balthazar",
- "Bangers",
- "Barlow",
- "Barlow Condensed",
- "Barlow Semi Condensed",
- "Barriecito",
- "Barrio",
- "Basic",
- "Baskervville",
- "Battambang",
- "Baumans",
- "Bayon",
- "Be Vietnam Pro",
- "Beau Rivage",
- "Bebas Neue",
- "Belanosima",
- "Belgrano",
- "Bellefair",
- "Belleza",
- "Bellota",
- "Bellota Text",
- "BenchNine",
- "Benne",
- "Bentham",
- "Berkshire Swash",
- "Besley",
- "Beth Ellen",
- "Bevan",
- "BhuTuka Expanded One",
- "Big Shoulders Display",
- "Big Shoulders Inline Display",
- "Big Shoulders Inline Text",
- "Big Shoulders Stencil Display",
- "Big Shoulders Stencil Text",
- "Big Shoulders Text",
- "Bigelow Rules",
- "Bigshot One",
- "Bilbo",
- "Bilbo Swash Caps",
- "BioRhyme",
- "BioRhyme Expanded",
- "Birthstone",
- "Birthstone Bounce",
- "Biryani",
- "Bitter",
- "Black And White Picture",
- "Black Han Sans",
- "Black Ops One",
- "Blaka",
- "Blaka Hollow",
- "Blaka Ink",
- "Bodoni Moda",
- "Bokor",
- "Bona Nova",
- "Bonbon",
- "Bonheur Royale",
- "Boogaloo",
- "Borel",
- "Bowlby One",
- "Bowlby One SC",
- "Braah One",
- "Brawler",
- "Bree Serif",
- "Bricolage Grotesque",
- "Bruno Ace",
- "Bruno Ace SC",
- "Brygada 1918",
- "Bubblegum Sans",
- "Bubbler One",
- "Buda",
- "Buenard",
- "Bungee",
- "Bungee Hairline",
- "Bungee Inline",
- "Bungee Outline",
- "Bungee Shade",
- "Bungee Spice",
- "Butcherman",
- "Butterfly Kids",
- "Cabin",
- "Cabin Condensed",
- "Cabin Sketch",
- "Caesar Dressing",
- "Cagliostro",
- "Cairo",
- "Cairo Play",
- "Caladea",
- "Calistoga",
- "Calligraffitti",
- "Cambay",
- "Cambo",
- "Candal",
- "Cantarell",
- "Cantata One",
- "Cantora One",
- "Caprasimo",
- "Capriola",
- "Caramel",
- "Carattere",
- "Cardo",
- "Carlito",
- "Carme",
- "Carrois Gothic",
- "Carrois Gothic SC",
- "Carter One",
- "Castoro",
- "Castoro Titling",
- "Catamaran",
- "Caudex",
- "Caveat",
- "Caveat Brush",
- "Cedarville Cursive",
- "Ceviche One",
- "Chakra Petch",
- "Changa",
- "Changa One",
- "Chango",
- "Charis SIL",
- "Charm",
- "Charmonman",
- "Chau Philomene One",
- "Chela One",
- "Chelsea Market",
- "Chenla",
- "Cherish",
- "Cherry Bomb One",
- "Cherry Cream Soda",
- "Cherry Swash",
- "Chewy",
- "Chicle",
- "Chilanka",
- "Chivo",
- "Chivo Mono",
- "Chokokutai",
- "Chonburi",
- "Cinzel",
- "Cinzel Decorative",
- "Clicker Script",
- "Climate Crisis",
- "Coda",
- "Codystar",
- "Coiny",
- "Combo",
- "Comfortaa",
- "Comforter",
- "Comforter Brush",
- "Comic Neue",
- "Coming Soon",
- "Comme",
- "Commissioner",
- "Concert One",
- "Condiment",
- "Content",
- "Contrail One",
- "Convergence",
- "Cookie",
- "Copse",
- "Corben",
- "Corinthia",
- "Cormorant",
- "Cormorant Garamond",
- "Cormorant Infant",
- "Cormorant SC",
- "Cormorant Unicase",
- "Cormorant Upright",
- "Courgette",
- "Courier Prime",
- "Cousine",
- "Coustard",
- "Covered By Your Grace",
- "Crafty Girls",
- "Creepster",
- "Crete Round",
- "Crimson Pro",
- "Crimson Text",
- "Croissant One",
- "Crushed",
- "Cuprum",
- "Cute Font",
- "Cutive",
- "Cutive Mono",
- "DM Mono",
- "DM Sans",
- "DM Serif Display",
- "DM Serif Text",
- "Dai Banna SIL",
- "Damion",
- "Dancing Script",
- "Dangrek",
- "Darker Grotesque",
- "Darumadrop One",
- "David Libre",
- "Dawning of a New Day",
- "Days One",
- "Dekko",
- "Delicious Handrawn",
- "Delius",
- "Delius Swash Caps",
- "Delius Unicase",
- "Della Respira",
- "Denk One",
- "Devonshire",
- "Dhurjati",
- "Didact Gothic",
- "Diphylleia",
- "Diplomata",
- "Diplomata SC",
- "Do Hyeon",
- "Dokdo",
- "Domine",
- "Donegal One",
- "Dongle",
- "Doppio One",
- "Dorsa",
- "Dosis",
- "DotGothic16",
- "Dr Sugiyama",
- # "Droid Sans",
- # "Droid Sans Mono",
- # "Droid Serif",
- "Duru Sans",
- "DynaPuff",
- "Dynalight",
- "EB Garamond",
- "Eagle Lake",
- "East Sea Dokdo",
- "Eater",
- "Economica",
- "Eczar",
- "Edu NSW ACT Foundation",
- "Edu QLD Beginner",
- "Edu SA Beginner",
- "Edu TAS Beginner",
- "Edu VIC WA NT Beginner",
- "Ek Mukta",
- "El Messiri",
- "Electrolize",
- "Elsie",
- "Elsie Swash Caps",
- "Emblema One",
- "Emilys Candy",
- "Encode Sans",
- "Encode Sans Condensed",
- "Encode Sans Expanded",
- "Encode Sans SC",
- "Encode Sans Semi Condensed",
- "Encode Sans Semi Expanded",
- "Engagement",
- "Englebert",
- "Enriqueta",
- "Ephesis",
- "Epilogue",
- "Erica One",
- "Esteban",
- "Estonia",
- "Euphoria Script",
- "Ewert",
- "Exo",
- "Exo 2",
- "Expletus Sans",
- "Explora",
- "Fahkwang",
- "Familjen Grotesk",
- "Fanwood Text",
- "Farro",
- "Farsan",
- "Fascinate",
- "Fascinate Inline",
- "Faster One",
- "Fasthand",
- "Fauna One",
- "Faustina",
- "Federant",
- "Federo",
- "Felipa",
- "Fenix",
- "Festive",
- "Figtree",
- "Finger Paint",
- "Finlandica",
- "Fira Code",
- "Fira Mono",
- "Fira Sans",
- "Fira Sans Condensed",
- "Fira Sans Extra Condensed",
- "Fira Sans Extra Condensed",
- "Fjalla One",
- "Fjord One",
- "Flamenco",
- "Flavors",
- "Fleur De Leah",
- "Flow Block",
- "Flow Circular",
- "Flow Rounded",
- "Foldit",
- "Fondamento",
- "Fontdiner Swanky",
- "Forum",
- "Fragment Mono",
- "Francois One",
- "Frank Ruhl Libre",
- "Fraunces",
- "Freckle Face",
- "Fredericka the Great",
- "Fredoka",
- "Freehand",
- "Fresca",
- "Frijole",
- "Fruktur",
- "Fugaz One",
- "Fuggles",
- "Fuzzy Bubbles",
- "GFS Didot",
- "GFS Neohellenic",
- "Gabriela",
- "Gaegu",
- "Gafata",
- "Gajraj One",
- "Galada",
- "Galdeano",
- "Galindo",
- "Gamja Flower",
- "Gantari",
- "Gasoek One",
- "Gayathri",
- "Gelasio",
- "Gemunu Libre",
- "Genos",
- "Geo",
- "Geologica",
- "Georama",
- "Geostar",
- "Geostar Fill",
- "Germania One",
- "Gideon Roman",
- "Gidugu",
- "Gilda Display",
- "Girassol",
- "Give You Glory",
- "Glass Antiqua",
- "Glegoo",
- "Gloock",
- "Gloria Hallelujah",
- "Glory",
- "Gluten",
- "Goblin One",
- "Gochi Hand",
- "Goldman",
- "Golos Text",
- "Gorditas",
- "Gothic A1",
- "Gotu",
- "Goudy Bookletter 1911",
- "Gowun Batang",
- "Gowun Dodum",
- "Graduate",
- "Grand Hotel",
- "Grandiflora One",
- "Grandstander",
- "Grape Nuts",
- "Gravitas One",
- "Great Vibes",
- "Grechen Fuemen",
- "Grenze",
- "Grenze Gotisch",
- "Grey Qo",
- "Griffy",
- "Gruppo",
- "Gudea",
- "Gugi",
- "Gulzar",
- "Gupter",
- "Gurajada",
- "Gwendolyn",
- "Habibi",
- "Hachi Maru Pop",
- "Hahmlet",
- "Halant",
- "Hammersmith One",
- "Hanalei",
- "Hanalei Fill",
- "Handjet",
- "Handlee",
- "Hanken Grotesk",
- "Hanuman",
- "Happy Monkey",
- "Harmattan",
- "Headland One",
- "Heebo",
- "Henny Penny",
- "Hepta Slab",
- "Herr Von Muellerhoff",
- "Hi Melody",
- "Hina Mincho",
- "Hind",
- "Hind Guntur",
- "Hind Madurai",
- "Hind Siliguri",
- "Hind Vadodara",
- "Holtwood One SC",
- "Homemade Apple",
- "Homenaje",
- "Hubballi",
- "Hurricane",
- "IBM Plex Mono",
- "IBM Plex Sans",
- "IBM Plex Sans Arabic",
- "IBM Plex Sans Condensed",
- "IBM Plex Sans Devanagari",
- "IBM Plex Sans Hebrew",
- "IBM Plex Sans JP",
- "IBM Plex Sans KR",
- "IBM Plex Sans Thai",
- "IBM Plex Sans Thai Looped",
- "IBM Plex Serif",
- "IM Fell DW Pica",
- "IM Fell DW Pica SC",
- "IM Fell Double Pica",
- "IM Fell Double Pica SC",
- "IM Fell English",
- "IM Fell English SC",
- "IM Fell French Canon",
- "IM Fell French Canon SC",
- "IM Fell Great Primer",
- "IM Fell Great Primer SC",
- "Ibarra Real Nova",
- "Iceberg",
- "Iceland",
- "Imbue",
- "Imperial Script",
- "Imprima",
- "Inconsolata",
- "Inder",
- "Indie Flower",
- "Ingrid Darling",
- "Inika",
- "Inknut Antiqua",
- "Inria Sans",
- "Inria Serif",
- "Inspiration",
- "Instrument Sans",
- "Instrument Serif",
- "Inter",
- "Inter Tight",
- "Irish Grover",
- "Island Moments",
- "Istok Web",
- "Italiana",
- "Italianno",
- "Itim",
- "Jacques Francois",
- "Jacques Francois Shadow",
- "Jaldi",
- "JetBrains Mono",
- "Jim Nightshade",
- "Joan",
- "Jockey One",
- "Jolly Lodger",
- "Jomhuria",
- "Jomolhari",
- "Josefin Sans",
- "Josefin Slab",
- "Jost",
- "Joti One",
- "Jua",
- "Judson",
- "Julee",
- "Julius Sans One",
- "Junge",
- "Jura",
- "Just Another Hand",
- "Just Me Again Down Here",
- "K2D",
- "Kablammo",
- "Kadwa",
- "Kaisei Decol",
- "Kaisei HarunoUmi",
- "Kaisei Opti",
- "Kaisei Tokumin",
- "Kalam",
- "Kameron",
- "Kanit",
- "Kantumruy Pro",
- "Karantina",
- "Karla",
- "Karma",
- "Katibeh",
- "Kaushan Script",
- "Kavivanar",
- "Kavoon",
- "Kdam Thmor Pro",
- "Keania One",
- "Kelly Slab",
- "Kenia",
- "Khand",
- "Khmer",
- "Khula",
- "Kings",
- "Kirang Haerang",
- "Kite One",
- "Kiwi Maru",
- "Klee One",
- "Knewave",
- "KoHo",
- "Kodchasan",
- "Koh Santepheap",
- "Kolker Brush",
- "Konkhmer Sleokchher",
- "Kosugi",
- "Kosugi Maru",
- "Kotta One",
- "Koulen",
- "Kranky",
- "Kreon",
- "Kristi",
- "Krona One",
- "Krub",
- "Kufam",
- "Kumar One",
- "Kumbh Sans",
- "Kurale",
- "La Belle Aurore",
- "Labrada",
- "Lacquer",
- "Laila",
- "Lakki Reddy",
- "Lalezar",
- "Lancelot",
- "Langar",
- "Lateef",
- "Lato",
- "Lavishly Yours",
- "League Gothic",
- "League Script",
- "League Spartan",
- "Leckerli One",
- "Ledger",
- "Lekton",
- "Lemon",
- "Lemonada",
- "Lexend",
- "Lexend Deca",
- "Lexend Exa",
- "Lexend Giga",
- "Lexend Mega",
- "Lexend Peta",
- "Lexend Tera",
- "Lexend Zetta",
- "Libre Barcode 128",
- "Libre Barcode 128 Text",
- "Libre Barcode 39",
- "Libre Barcode 39 Extended",
- "Libre Barcode 39 Extended Text",
- "Libre Barcode 39 Text",
- "Libre Barcode EAN13 Text",
- "Libre Baskerville",
- "Libre Bodoni",
- "Libre Caslon Display",
- "Libre Caslon Text",
- "Libre Franklin",
- "Licorice",
- "Life Savers",
- "Lilita One",
- "Lily Script One",
- "Limelight",
- "Linden Hill",
- "Lisu Bosa",
- "Literata",
- "Liu Jian Mao Cao",
- "Livvic",
- "Lobster",
- "Lobster Two",
- "Londrina Outline",
- "Londrina Shadow",
- "Londrina Sketch",
- "Londrina Solid",
- "Long Cang",
- "Lora",
- "Love Light",
- "Love Ya Like A Sister",
- "Loved by the King",
- "Lovers Quarrel",
- "Luckiest Guy",
- "Lugrasimo",
- "Lumanosimo",
- "Lunasima",
- "Lusitana",
- "Lustria",
- "Luxurious Roman",
- "Luxurious Script",
- "M PLUS 1",
- "M PLUS 1 Code",
- "M PLUS 1p",
- "M PLUS 2",
- "M PLUS Code Latin",
- "Ma Shan Zheng",
- "Macondo",
- "Macondo Swash Caps",
- "Mada",
- "Magra",
- "Maiden Orange",
- "Maitree",
- "Major Mono Display",
- "Mako",
- "Mali",
- "Mallanna",
- "Mandali",
- "Manjari",
- "Manrope",
- "Mansalva",
- "Manuale",
- "Marcellus",
- "Marcellus SC",
- "Marck Script",
- "Margarine",
- "Marhey",
- "Markazi Text",
- "Marko One",
- "Marmelad",
- "Martel",
- "Martel Sans",
- "Martian Mono",
- "Marvel",
- "Mate",
- "Mate SC",
- "Maven Pro",
- "McLaren",
- "Mea Culpa",
- "Meddon",
- "MedievalSharp",
- "Medula One",
- "Meera Inimai",
- "Megrim",
- "Meie Script",
- "Meow Script",
- "Merienda",
- "Merriweather",
- "Merriweather Sans",
- "Metal",
- "Metal Mania",
- "Metamorphous",
- "Metrophobic",
- "Michroma",
- "Milonga",
- "Miltonian",
- "Miltonian Tattoo",
- "Mina",
- "Mingzat",
- "Miniver",
- "Miriam Libre",
- "Miss Fajardose",
- "Mochiy Pop One",
- "Mochiy Pop P One",
- "Modak",
- "Modern Antiqua",
- "Mohave",
- "Moirai One",
- "Molengo",
- "Molle",
- "Monda",
- "Monofett",
- "Monomaniac One",
- "Monoton",
- "Monsieur La Doulaise",
- "Montaga",
- "Montagu Slab",
- "MonteCarlo",
- "Montez",
- "Montserrat",
- "Montserrat Alternates",
- "Montserrat Subrayada",
- "Moo Lah Lah",
- "Moon Dance",
- "Moul",
- "Moulpali",
- "Mountains of Christmas",
- "Mouse Memoirs",
- "Mr Bedfort",
- "Mr Dafoe",
- "Mr De Haviland",
- "Mrs Saint Delafield",
- "Mrs Sheppards",
- "Ms Madi",
- "Mukta",
- "Mukta Mahee",
- "Mukta Malar",
- "Mukta Vaani",
- "Mulish",
- "Murecho",
- "MuseoModerno",
- "My Soul",
- "Mynerve",
- "Mystery Quest",
- "NTR",
- "Nabla",
- "Nanum Brush Script",
- "Nanum Gothic",
- "Nanum Gothic Coding",
- "Nanum Myeongjo",
- "Nanum Pen Script",
- "Narnoor",
- "Neonderthaw",
- "Nerko One",
- "Neucha",
- "Neuton",
- "New Rocker",
- "New Tegomin",
- "News Cycle",
- "Newsreader",
- "Niconne",
- "Niramit",
- "Nixie One",
- "Nobile",
- "Nokora",
- "Norican",
- "Nosifer",
- "Notable",
- "Nothing You Could Do",
- "Noticia Text",
- "Noto Color Emoji",
- "Noto Emoji",
- "Noto Kufi Arabic",
- "Noto Music",
- "Noto Naskh Arabic",
- "Noto Nastaliq Urdu",
- "Noto Rashi Hebrew",
- "Noto Sans",
- "Noto Sans Adlam",
- "Noto Sans Adlam Unjoined",
- "Noto Sans Anatolian Hieroglyphs",
- "Noto Sans Arabic",
- "Noto Sans Armenian",
- "Noto Sans Avestan",
- "Noto Sans Balinese",
- "Noto Sans Bamum",
- "Noto Sans Bassa Vah",
- "Noto Sans Batak",
- "Noto Sans Bengali",
- "Noto Sans Bhaiksuki",
- "Noto Sans Brahmi",
- "Noto Sans Buginese",
- "Noto Sans Buhid",
- "Noto Sans Canadian Aboriginal",
- "Noto Sans Carian",
- "Noto Sans Caucasian Albanian",
- "Noto Sans Chakma",
- "Noto Sans Cham",
- "Noto Sans Cherokee",
- "Noto Sans Chorasmian",
- "Noto Sans Coptic",
- "Noto Sans Cuneiform",
- "Noto Sans Cypriot",
- "Noto Sans Cypro Minoan",
- "Noto Sans Deseret",
- "Noto Sans Devanagari",
- "Noto Sans Display",
- "Noto Sans Duployan",
- "Noto Sans Egyptian Hieroglyphs",
- "Noto Sans Elbasan",
- "Noto Sans Elymaic",
- "Noto Sans Ethiopic",
- "Noto Sans Georgian",
- "Noto Sans Glagolitic",
- "Noto Sans Gothic",
- "Noto Sans Grantha",
- "Noto Sans Gujarati",
- "Noto Sans Gunjala Gondi",
- "Noto Sans Gurmukhi",
- "Noto Sans HK",
- "Noto Sans Hanifi Rohingya",
- "Noto Sans Hanunoo",
- "Noto Sans Hatran",
- "Noto Sans Hebrew",
- "Noto Sans Imperial Aramaic",
- "Noto Sans Indic Siyaq Numbers",
- "Noto Sans Inscriptional Pahlavi",
- "Noto Sans Inscriptional Parthian",
- "Noto Sans JP",
- # "Noto Sans Japanese",
- "Noto Sans Javanese",
- "Noto Sans KR",
- "Noto Sans Kaithi",
- "Noto Sans Kannada",
- "Noto Sans Kayah Li",
- "Noto Sans Kharoshthi",
- "Noto Sans Khmer",
- "Noto Sans Khojki",
- "Noto Sans Khudawadi",
- # "Noto Sans Korean",
- "Noto Sans Lao",
- "Noto Sans Lao Looped",
- "Noto Sans Lepcha",
- "Noto Sans Limbu",
- "Noto Sans Linear A",
- "Noto Sans Linear B",
- "Noto Sans Lisu",
- "Noto Sans Lycian",
- "Noto Sans Lydian",
- "Noto Sans Mahajani",
- "Noto Sans Malayalam",
- "Noto Sans Mandaic",
- "Noto Sans Manichaean",
- "Noto Sans Marchen",
- "Noto Sans Masaram Gondi",
- "Noto Sans Math",
- "Noto Sans Mayan Numerals",
- "Noto Sans Medefaidrin",
- "Noto Sans Meetei Mayek",
- "Noto Sans Mende Kikakui",
- "Noto Sans Meroitic",
- "Noto Sans Miao",
- "Noto Sans Modi",
- "Noto Sans Mongolian",
- "Noto Sans Mono",
- "Noto Sans Mro",
- "Noto Sans Multani",
- "Noto Sans Myanmar",
- "Noto Sans NKo",
- "Noto Sans Nabataean",
- "Noto Sans Nag Mundari",
- "Noto Sans Nandinagari",
- "Noto Sans New Tai Lue",
- "Noto Sans Newa",
- "Noto Sans Nushu",
- "Noto Sans Ogham",
- "Noto Sans Ol Chiki",
- "Noto Sans Old Hungarian",
- "Noto Sans Old Italic",
- "Noto Sans Old North Arabian",
- "Noto Sans Old Permic",
- "Noto Sans Old Persian",
- "Noto Sans Old Sogdian",
- "Noto Sans Old South Arabian",
- "Noto Sans Old Turkic",
- "Noto Sans Oriya",
- "Noto Sans Osage",
- "Noto Sans Osmanya",
- "Noto Sans Pahawh Hmong",
- "Noto Sans Palmyrene",
- "Noto Sans Pau Cin Hau",
- # "Noto Sans Phags Pa",
- "Noto Sans Phoenician",
- "Noto Sans Psalter Pahlavi",
- "Noto Sans Rejang",
- "Noto Sans Runic",
- "Noto Sans SC",
- "Noto Sans Samaritan",
- "Noto Sans Saurashtra",
- "Noto Sans Sharada",
- "Noto Sans Shavian",
- "Noto Sans Siddham",
- "Noto Sans SignWriting",
- "Noto Sans Sinhala",
- "Noto Sans Sogdian",
- "Noto Sans Sora Sompeng",
- "Noto Sans Soyombo",
- "Noto Sans Sundanese",
- "Noto Sans Syloti Nagri",
- "Noto Sans Symbols",
- "Noto Sans Symbols 2",
- "Noto Sans Syriac",
- "Noto Sans Syriac Eastern",
- "Noto Sans TC",
- "Noto Sans Tagalog",
- "Noto Sans Tagbanwa",
- "Noto Sans Tai Le",
- "Noto Sans Tai Tham",
- "Noto Sans Tai Viet",
- "Noto Sans Takri",
- "Noto Sans Tamil",
- "Noto Sans Tamil Supplement",
- "Noto Sans Tangsa",
- "Noto Sans Telugu",
- "Noto Sans Thaana",
- "Noto Sans Thai",
- "Noto Sans Thai Looped",
- "Noto Sans Tifinagh",
- "Noto Sans Tirhuta",
- "Noto Sans Ugaritic",
- "Noto Sans Vai",
- "Noto Sans Vithkuqi",
- "Noto Sans Wancho",
- "Noto Sans Warang Citi",
- "Noto Sans Yi",
- "Noto Sans Zanabazar Square",
- "Noto Serif",
- "Noto Serif Ahom",
- "Noto Serif Armenian",
- "Noto Serif Balinese",
- "Noto Serif Bengali",
- "Noto Serif Devanagari",
- "Noto Serif Display",
- "Noto Serif Dogra",
- "Noto Serif Ethiopic",
- "Noto Serif Georgian",
- "Noto Serif Grantha",
- "Noto Serif Gujarati",
- "Noto Serif Gurmukhi",
- "Noto Serif HK",
- "Noto Serif Hebrew",
- "Noto Serif JP",
- "Noto Serif KR",
- "Noto Serif Kannada",
- "Noto Serif Khitan Small Script",
- "Noto Serif Khmer",
- "Noto Serif Khojki",
- "Noto Serif Lao",
- "Noto Serif Makasar",
- "Noto Serif Malayalam",
- "Noto Serif Myanmar",
- "Noto Serif NP Hmong",
- "Noto Serif Oriya",
- "Noto Serif Ottoman Siyaq",
- "Noto Serif SC",
- "Noto Serif Sinhala",
- "Noto Serif TC",
- "Noto Serif Tamil",
- "Noto Serif Tangut",
- "Noto Serif Telugu",
- "Noto Serif Thai",
- "Noto Serif Tibetan",
- "Noto Serif Toto",
- "Noto Serif Vithkuqi",
- "Noto Serif Yezidi",
- "Noto Traditional Nushu",
- "Nova Cut",
- "Nova Flat",
- "Nova Mono",
- "Nova Oval",
- "Nova Round",
- "Nova Script",
- "Nova Slim",
- "Nova Square",
- "Numans",
- "Nunito",
- "Nunito Sans",
- "Nuosu SIL",
- "Odibee Sans",
- "Odor Mean Chey",
- "Offside",
- "Oi",
- "Old Standard TT",
- "Oldenburg",
- "Ole",
- "Oleo Script",
- "Oleo Script Swash Caps",
- "Oooh Baby",
- "Open Sans",
- # "Open Sans Condensed",
- "Oranienbaum",
- "Orbit",
- "Orbitron",
- "Oregano",
- "Orelega One",
- "Orienta",
- "Original Surfer",
- "Oswald",
- "Outfit",
- "Over the Rainbow",
- "Overlock",
- "Overlock SC",
- "Overpass",
- "Overpass Mono",
- "Ovo",
- "Oxanium",
- "Oxygen",
- "Oxygen Mono",
- "PT Mono",
- "PT Sans",
- "PT Sans Caption",
- "PT Sans Narrow",
- "PT Serif",
- "PT Serif Caption",
- "Pacifico",
- "Padauk",
- "Padyakke Expanded One",
- "Palanquin",
- "Palanquin Dark",
- "Palette Mosaic",
- "Pangolin",
- "Paprika",
- "Parisienne",
- "Passero One",
- "Passion One",
- "Passions Conflict",
- "Pathway Extreme",
- "Pathway Gothic One",
- "Patrick Hand",
- "Patrick Hand SC",
- "Pattaya",
- "Patua One",
- "Pavanam",
- "Paytone One",
- "Peddana",
- "Peralta",
- "Permanent Marker",
- "Petemoss",
- "Petit Formal Script",
- "Petrona",
- "Philosopher",
- "Phudu",
- "Piazzolla",
- "Piedra",
- "Pinyon Script",
- "Pirata One",
- "Plaster",
- "Play",
- "Playball",
- "Playfair",
- "Playfair Display",
- "Playfair Display SC",
- "Plus Jakarta Sans",
- "Podkova",
- "Poiret One",
- "Poller One",
- "Poltawski Nowy",
- "Poly",
- "Pompiere",
- "Pontano Sans",
- "Poor Story",
- "Poppins",
- "Port Lligat Sans",
- "Port Lligat Slab",
- "Potta One",
- "Pragati Narrow",
- "Praise",
- "Preahvihear",
- "Press Start 2P",
- "Pridi",
- "Princess Sofia",
- "Prociono",
- "Prompt",
- "Prosto One",
- "Proza Libre",
- "Public Sans",
- "Puppies Play",
- "Puritan",
- "Purple Purse",
- "Qahiri",
- "Quando",
- "Quantico",
- "Quattrocento",
- "Quattrocento Sans",
- "Questrial",
- "Quicksand",
- "Quintessential",
- "Qwigley",
- "Qwitcher Grypen",
- "REM",
- "Racing Sans One",
- "Radio Canada",
- "Radley",
- "Rajdhani",
- "Rakkas",
- "Raleway",
- "Raleway Dots",
- "Ramabhadra",
- "Ramaraja",
- "Rambla",
- "Rammetto One",
- "Rampart One",
- "Ranchers",
- "Rancho",
- "Ranga",
- "Rasa",
- "Rationale",
- "Ravi Prakash",
- "Readex Pro",
- "Recursive",
- "Red Hat Display",
- "Red Hat Mono",
- "Red Hat Text",
- "Red Rose",
- "Redacted",
- "Redacted Script",
- "Redressed",
- "Reem Kufi",
- "Reem Kufi Fun",
- "Reem Kufi Ink",
- "Reenie Beanie",
- "Reggae One",
- "Revalia",
- "Rhodium Libre",
- "Ribeye",
- "Ribeye Marrow",
- "Righteous",
- "Risque",
- "Road Rage",
- "Roboto",
- "Roboto Condensed",
- "Roboto Flex",
- "Roboto Mono",
- "Roboto Serif",
- "Roboto Slab",
- "Rochester",
- "Rock 3D",
- "Rock Salt",
- "RocknRoll One",
- "Rokkitt",
- "Romanesco",
- "Ropa Sans",
- "Rosario",
- "Rosarivo",
- "Rouge Script",
- "Rowdies",
- "Rozha One",
- "Rubik",
- "Rubik 80s Fade",
- "Rubik Beastly",
- "Rubik Bubbles",
- "Rubik Burned",
- "Rubik Dirt",
- "Rubik Distressed",
- "Rubik Gemstones",
- "Rubik Glitch",
- "Rubik Iso",
- "Rubik Marker Hatch",
- "Rubik Maze",
- "Rubik Microbe",
- "Rubik Mono One",
- "Rubik Moonrocks",
- "Rubik One",
- "Rubik Pixels",
- "Rubik Puddles",
- "Rubik Spray Paint",
- "Rubik Storm",
- "Rubik Vinyl",
- "Rubik Wet Paint",
- "Ruda",
- "Rufina",
- "Ruge Boogie",
- "Ruluko",
- "Rum Raisin",
- "Ruslan Display",
- "Russo One",
- "Ruthie",
- "Ruwudu",
- "Rye",
- "STIX Two Text",
- "Sacramento",
- "Sahitya",
- "Sail",
- "Saira",
- "Saira Condensed",
- "Saira Extra Condensed",
- "Saira Semi Condensed",
- "Saira Stencil One",
- "Salsa",
- "Sanchez",
- "Sancreek",
- "Sansita",
- "Sansita One",
- "Sansita Swashed",
- "Sarabun",
- "Sarala",
- "Sarina",
- "Sarpanch",
- "Sassy Frass",
- "Satisfy",
- "Sawarabi Mincho",
- "Scada",
- "Scheherazade New",
- "Schibsted Grotesk",
- "Schoolbell",
- "Scope One",
- "Seaweed Script",
- "Secular One",
- "Sedgwick Ave",
- "Sedgwick Ave Display",
- "Sen",
- "Send Flowers",
- "Sevillana",
- "Seymour One",
- "Shadows Into Light",
- "Shadows Into Light Two",
- "Shalimar",
- "Shantell Sans",
- "Shanti",
- "Share",
- "Share Tech",
- "Share Tech Mono",
- "Shippori Antique",
- "Shippori Antique B1",
- "Shippori Mincho",
- "Shippori Mincho B1",
- "Shizuru",
- "Shojumaru",
- "Short Stack",
- "Shrikhand",
- "Siemreap",
- "Sigmar",
- "Sigmar One",
- "Signika",
- "Signika Negative",
- "Silkscreen",
- "Simonetta",
- "Single Day",
- "Sintony",
- "Sirin Stencil",
- "Six Caps",
- "Skranji",
- "Slabo 13px",
- "Slabo 27px",
- "Slackey",
- "Slackside One",
- "Smokum",
- "Smooch",
- "Smooch Sans",
- "Smythe",
- "Sniglet",
- "Snippet",
- "Snowburst One",
- "Sofadi One",
- "Sofia",
- "Sofia Sans",
- "Sofia Sans Condensed",
- "Sofia Sans Extra Condensed",
- "Sofia Sans Semi Condensed",
- "Solitreo",
- "Solway",
- "Song Myung",
- "Sono",
- "Sonsie One",
- "Sora",
- "Sorts Mill Goudy",
- "Source Code Pro",
- "Source Sans 3",
- "Space Grotesk",
- "Space Mono",
- "Special Elite",
- "Spectral",
- "Spicy Rice",
- "Spinnaker",
- "Spirax",
- "Splash",
- "Spline Sans",
- "Spline Sans Mono",
- "Squada One",
- "Square Peg",
- "Sree Krushnadevaraya",
- "Sriracha",
- "Srisakdi",
- "Staatliches",
- "Stalemate",
- "Stalinist One",
- "Stardos Stencil",
- "Stick",
- "Stick No Bills",
- "Stint Ultra Condensed",
- "Stint Ultra Expanded",
- "Stoke",
- "Strait",
- "Style Script",
- "Stylish",
- "Sue Ellen Francisco",
- "Suez One",
- "Sulphur Point",
- "Sumana",
- "Sunflower",
- "Sunshiney",
- "Supermercado One",
- "Sura",
- "Suranna",
- "Suravaram",
- "Suwannaphum",
- "Swanky and Moo Moo",
- "Syncopate",
- "Syne",
- "Syne Mono",
- "Syne Tactile",
- "Tai Heritage Pro",
- "Tajawal",
- "Tangerine",
- "Tapestry",
- "Taprom",
- "Tauri",
- "Taviraj",
- "Teko",
- "Tektur",
- "Telex",
- "Tenali Ramakrishna",
- "Tenor Sans",
- "Text Me One",
- "Texturina",
- "Thasadith",
- "The Girl Next Door",
- "The Nautigal",
- "Tienne",
- "Tillana",
- "Tilt Neon",
- "Tilt Prism",
- "Tilt Warp",
- "Timmana",
- "Tinos",
- "Tiro Bangla",
- "Tiro Devanagari Hindi",
- "Tiro Devanagari Marathi",
- "Tiro Devanagari Sanskrit",
- "Tiro Gurmukhi",
- "Tiro Kannada",
- "Tiro Tamil",
- "Tiro Telugu",
- "Titan One",
- "Titillium Web",
- "Tomorrow",
- "Tourney",
- "Trade Winds",
- "Train One",
- "Trirong",
- "Trispace",
- "Trocchi",
- "Trochut",
- "Truculenta",
- "Trykker",
- "Tsukimi Rounded",
- "Tulpen One",
- "Turret Road",
- "Twinkle Star",
- "Ubuntu",
- "Ubuntu Condensed",
- "Ubuntu Mono",
- "Uchen",
- "Ultra",
- "Unbounded",
- "Uncial Antiqua",
- "Underdog",
- "Unica One",
- "UnifrakturCook",
- "UnifrakturMaguntia",
- "Unkempt",
- "Unlock",
- "Unna",
- "Updock",
- "Urbanist",
- "VT323",
- "Vampiro One",
- "Varela",
- "Varela Round",
- "Varta",
- "Vast Shadow",
- "Vazirmatn",
- "Vesper Libre",
- "Viaoda Libre",
- "Vibes",
- "Vibur",
- "Victor Mono",
- "Vidaloka",
- "Viga",
- "Vina Sans",
- "Voces",
- "Volkhov",
- "Vollkorn",
- "Vollkorn SC",
- "Voltaire",
- "Vujahday Script",
- "Waiting for the Sunrise",
- "Wallpoet",
- "Walter Turncoat",
- "Warnes",
- "Water Brush",
- "Waterfall",
- "Wavefont",
- "Wellfleet",
- "Wendy One",
- "Whisper",
- "WindSong",
- "Wire One",
- "Wix Madefor Display",
- "Wix Madefor Text",
- "Work Sans",
- "Xanh Mono",
- "Yaldevi",
- "Yanone Kaffeesatz",
- "Yantramanav",
- "Yatra One",
- "Yellowtail",
- "Yeon Sung",
- "Yeseva One",
- "Yesteryear",
- "Yomogi",
- "Yrsa",
- "Ysabeau",
- "Ysabeau Infant",
- "Ysabeau Office",
- "Ysabeau SC",
- "Yuji Boku",
- "Yuji Hentaigana Akari",
- "Yuji Hentaigana Akebono",
- "Yuji Mai",
- "Yuji Syuku",
- "Yusei Magic",
- "ZCOOL KuaiLe",
- "ZCOOL QingKe HuangYou",
- "ZCOOL XiaoWei",
- "Zen Antique",
- "Zen Antique Soft",
- "Zen Dots",
- "Zen Kaku Gothic Antique",
- "Zen Kaku Gothic New",
- "Zen Kurenaido",
- "Zen Loop",
- "Zen Maru Gothic",
- "Zen Old Mincho",
- "Zen Tokyo Zoo",
- "Zeyada",
- "Zhi Mang Xing",
- "Zilla Slab",
- "Zilla Slab Highlight",
- ]
+fonts = [
+ "ABeeZee",
+ "ADLaM Display",
+ "Abel",
+ "Abhaya Libre",
+ "Aboreto",
+ "Abril Fatface",
+ "Abyssinica SIL",
+ "Aclonica",
+ "Acme",
+ "Actor",
+ "Adamina",
+ "Advent Pro",
+ "Agdasima",
+ "Aguafina Script",
+ "Akatab",
+ "Akaya Kanadaka",
+ "Akaya Telivigala",
+ "Akronim",
+ "Akshar",
+ "Aladin",
+ "Alata",
+ "Alatsi",
+ "Albert Sans",
+ "Aldrich",
+ "Alef",
+ "Alegreya",
+ "Alegreya SC",
+ "Alegreya Sans",
+ "Alegreya Sans SC",
+ "Aleo",
+ "Alex Brush",
+ "Alexandria",
+ "Alfa Slab One",
+ "Alice",
+ "Alike",
+ "Alike Angular",
+ "Alkalami",
+ "Alkatra",
+ "Allan",
+ "Allerta",
+ "Allerta Stencil",
+ "Allison",
+ "Allura",
+ "Almarai",
+ "Almendra",
+ "Almendra Display",
+ "Almendra SC",
+ "Alumni Sans",
+ "Alumni Sans Collegiate One",
+ "Alumni Sans Inline One",
+ "Alumni Sans Pinstripe",
+ "Amarante",
+ "Amaranth",
+ "Amatic SC",
+ "Amethysta",
+ "Amiko",
+ "Amiri",
+ "Amiri Quran",
+ "Amita",
+ "Anaheim",
+ "Andada Pro",
+ "Andika",
+ "Anek Bangla",
+ "Anek Devanagari",
+ "Anek Gujarati",
+ "Anek Gurmukhi",
+ "Anek Kannada",
+ "Anek Latin",
+ "Anek Malayalam",
+ "Anek Odia",
+ "Anek Tamil",
+ "Anek Telugu",
+ "Angkor",
+ "Annie Use Your Telescope",
+ "Anonymous Pro",
+ "Antic",
+ "Antic Didone",
+ "Antic Slab",
+ "Anton",
+ "Antonio",
+ "Anuphan",
+ "Anybody",
+ "Aoboshi One",
+ "Arapey",
+ "Arbutus",
+ "Arbutus Slab",
+ "Architects Daughter",
+ "Archivo",
+ "Archivo Black",
+ "Archivo Narrow",
+ "Are You Serious",
+ "Aref Ruqaa",
+ "Aref Ruqaa Ink",
+ "Arima",
+ "Arimo",
+ "Arizonia",
+ "Armata",
+ "Arsenal",
+ "Artifika",
+ "Arvo",
+ "Arya",
+ "Asap",
+ "Asap Condensed",
+ "Asar",
+ "Asset",
+ "Assistant",
+ "Astloch",
+ "Asul",
+ "Athiti",
+ "Atkinson Hyperlegible",
+ "Atomic Age",
+ "Aubrey",
+ "Audiowide",
+ "Autour One",
+ "Average",
+ "Average Sans",
+ "Averia Gruesa Libre",
+ "Averia Libre",
+ "Averia Sans Libre",
+ "Averia Serif Libre",
+ "Azeret Mono",
+ "B612",
+ "B612 Mono",
+ "BIZ UDGothic",
+ "BIZ UDMincho",
+ "BIZ UDPGothic",
+ "BIZ UDPMincho",
+ "Babylonica",
+ "Bacasime Antique",
+ "Bad Script",
+ "Bagel Fat One",
+ "Bahiana",
+ "Bahianita",
+ "Bai Jamjuree",
+ "Bakbak One",
+ "Ballet",
+ "Baloo 2",
+ "Baloo Bhai 2",
+ "Baloo Bhaijaan 2",
+ "Baloo Bhaina 2",
+ "Baloo Chettan 2",
+ "Baloo Da 2",
+ "Baloo Paaji 2",
+ "Baloo Tamma 2",
+ "Baloo Tammudu 2",
+ "Baloo Thambi 2",
+ "Balsamiq Sans",
+ "Balthazar",
+ "Bangers",
+ "Barlow",
+ "Barlow Condensed",
+ "Barlow Semi Condensed",
+ "Barriecito",
+ "Barrio",
+ "Basic",
+ "Baskervville",
+ "Battambang",
+ "Baumans",
+ "Bayon",
+ "Be Vietnam Pro",
+ "Beau Rivage",
+ "Bebas Neue",
+ "Belanosima",
+ "Belgrano",
+ "Bellefair",
+ "Belleza",
+ "Bellota",
+ "Bellota Text",
+ "BenchNine",
+ "Benne",
+ "Bentham",
+ "Berkshire Swash",
+ "Besley",
+ "Beth Ellen",
+ "Bevan",
+ "BhuTuka Expanded One",
+ "Big Shoulders Display",
+ "Big Shoulders Inline Display",
+ "Big Shoulders Inline Text",
+ "Big Shoulders Stencil Display",
+ "Big Shoulders Stencil Text",
+ "Big Shoulders Text",
+ "Bigelow Rules",
+ "Bigshot One",
+ "Bilbo",
+ "Bilbo Swash Caps",
+ "BioRhyme",
+ "BioRhyme Expanded",
+ "Birthstone",
+ "Birthstone Bounce",
+ "Biryani",
+ "Bitter",
+ "Black And White Picture",
+ "Black Han Sans",
+ "Black Ops One",
+ "Blaka",
+ "Blaka Hollow",
+ "Blaka Ink",
+ "Bodoni Moda",
+ "Bokor",
+ "Bona Nova",
+ "Bonbon",
+ "Bonheur Royale",
+ "Boogaloo",
+ "Borel",
+ "Bowlby One",
+ "Bowlby One SC",
+ "Braah One",
+ "Brawler",
+ "Bree Serif",
+ "Bricolage Grotesque",
+ "Bruno Ace",
+ "Bruno Ace SC",
+ "Brygada 1918",
+ "Bubblegum Sans",
+ "Bubbler One",
+ "Buda",
+ "Buenard",
+ "Bungee",
+ "Bungee Hairline",
+ "Bungee Inline",
+ "Bungee Outline",
+ "Bungee Shade",
+ "Bungee Spice",
+ "Butcherman",
+ "Butterfly Kids",
+ "Cabin",
+ "Cabin Condensed",
+ "Cabin Sketch",
+ "Caesar Dressing",
+ "Cagliostro",
+ "Cairo",
+ "Cairo Play",
+ "Caladea",
+ "Calistoga",
+ "Calligraffitti",
+ "Cambay",
+ "Cambo",
+ "Candal",
+ "Cantarell",
+ "Cantata One",
+ "Cantora One",
+ "Caprasimo",
+ "Capriola",
+ "Caramel",
+ "Carattere",
+ "Cardo",
+ "Carlito",
+ "Carme",
+ "Carrois Gothic",
+ "Carrois Gothic SC",
+ "Carter One",
+ "Castoro",
+ "Castoro Titling",
+ "Catamaran",
+ "Caudex",
+ "Caveat",
+ "Caveat Brush",
+ "Cedarville Cursive",
+ "Ceviche One",
+ "Chakra Petch",
+ "Changa",
+ "Changa One",
+ "Chango",
+ "Charis SIL",
+ "Charm",
+ "Charmonman",
+ "Chau Philomene One",
+ "Chela One",
+ "Chelsea Market",
+ "Chenla",
+ "Cherish",
+ "Cherry Bomb One",
+ "Cherry Cream Soda",
+ "Cherry Swash",
+ "Chewy",
+ "Chicle",
+ "Chilanka",
+ "Chivo",
+ "Chivo Mono",
+ "Chokokutai",
+ "Chonburi",
+ "Cinzel",
+ "Cinzel Decorative",
+ "Clicker Script",
+ "Climate Crisis",
+ "Coda",
+ "Codystar",
+ "Coiny",
+ "Combo",
+ "Comfortaa",
+ "Comforter",
+ "Comforter Brush",
+ "Comic Neue",
+ "Coming Soon",
+ "Comme",
+ "Commissioner",
+ "Concert One",
+ "Condiment",
+ "Content",
+ "Contrail One",
+ "Convergence",
+ "Cookie",
+ "Copse",
+ "Corben",
+ "Corinthia",
+ "Cormorant",
+ "Cormorant Garamond",
+ "Cormorant Infant",
+ "Cormorant SC",
+ "Cormorant Unicase",
+ "Cormorant Upright",
+ "Courgette",
+ "Courier Prime",
+ "Cousine",
+ "Coustard",
+ "Covered By Your Grace",
+ "Crafty Girls",
+ "Creepster",
+ "Crete Round",
+ "Crimson Pro",
+ "Crimson Text",
+ "Croissant One",
+ "Crushed",
+ "Cuprum",
+ "Cute Font",
+ "Cutive",
+ "Cutive Mono",
+ "DM Mono",
+ "DM Sans",
+ "DM Serif Display",
+ "DM Serif Text",
+ "Dai Banna SIL",
+ "Damion",
+ "Dancing Script",
+ "Dangrek",
+ "Darker Grotesque",
+ "Darumadrop One",
+ "David Libre",
+ "Dawning of a New Day",
+ "Days One",
+ "Dekko",
+ "Delicious Handrawn",
+ "Delius",
+ "Delius Swash Caps",
+ "Delius Unicase",
+ "Della Respira",
+ "Denk One",
+ "Devonshire",
+ "Dhurjati",
+ "Didact Gothic",
+ "Diphylleia",
+ "Diplomata",
+ "Diplomata SC",
+ "Do Hyeon",
+ "Dokdo",
+ "Domine",
+ "Donegal One",
+ "Dongle",
+ "Doppio One",
+ "Dorsa",
+ "Dosis",
+ "DotGothic16",
+ "Dr Sugiyama",
+ # "Droid Sans",
+ # "Droid Sans Mono",
+ # "Droid Serif",
+ "Duru Sans",
+ "DynaPuff",
+ "Dynalight",
+ "EB Garamond",
+ "Eagle Lake",
+ "East Sea Dokdo",
+ "Eater",
+ "Economica",
+ "Eczar",
+ "Edu NSW ACT Foundation",
+ "Edu QLD Beginner",
+ "Edu SA Beginner",
+ "Edu TAS Beginner",
+ "Edu VIC WA NT Beginner",
+ "Ek Mukta",
+ "El Messiri",
+ "Electrolize",
+ "Elsie",
+ "Elsie Swash Caps",
+ "Emblema One",
+ "Emilys Candy",
+ "Encode Sans",
+ "Encode Sans Condensed",
+ "Encode Sans Expanded",
+ "Encode Sans SC",
+ "Encode Sans Semi Condensed",
+ "Encode Sans Semi Expanded",
+ "Engagement",
+ "Englebert",
+ "Enriqueta",
+ "Ephesis",
+ "Epilogue",
+ "Erica One",
+ "Esteban",
+ "Estonia",
+ "Euphoria Script",
+ "Ewert",
+ "Exo",
+ "Exo 2",
+ "Expletus Sans",
+ "Explora",
+ "Fahkwang",
+ "Familjen Grotesk",
+ "Fanwood Text",
+ "Farro",
+ "Farsan",
+ "Fascinate",
+ "Fascinate Inline",
+ "Faster One",
+ "Fasthand",
+ "Fauna One",
+ "Faustina",
+ "Federant",
+ "Federo",
+ "Felipa",
+ "Fenix",
+ "Festive",
+ "Figtree",
+ "Finger Paint",
+ "Finlandica",
+ "Fira Code",
+ "Fira Mono",
+ "Fira Sans",
+ "Fira Sans Condensed",
+ "Fira Sans Extra Condensed",
+ "Fira Sans Extra Condensed",
+ "Fjalla One",
+ "Fjord One",
+ "Flamenco",
+ "Flavors",
+ "Fleur De Leah",
+ "Flow Block",
+ "Flow Circular",
+ "Flow Rounded",
+ "Foldit",
+ "Fondamento",
+ "Fontdiner Swanky",
+ "Forum",
+ "Fragment Mono",
+ "Francois One",
+ "Frank Ruhl Libre",
+ "Fraunces",
+ "Freckle Face",
+ "Fredericka the Great",
+ "Fredoka",
+ "Freehand",
+ "Fresca",
+ "Frijole",
+ "Fruktur",
+ "Fugaz One",
+ "Fuggles",
+ "Fuzzy Bubbles",
+ "GFS Didot",
+ "GFS Neohellenic",
+ "Gabriela",
+ "Gaegu",
+ "Gafata",
+ "Gajraj One",
+ "Galada",
+ "Galdeano",
+ "Galindo",
+ "Gamja Flower",
+ "Gantari",
+ "Gasoek One",
+ "Gayathri",
+ "Gelasio",
+ "Gemunu Libre",
+ "Genos",
+ "Geo",
+ "Geologica",
+ "Georama",
+ "Geostar",
+ "Geostar Fill",
+ "Germania One",
+ "Gideon Roman",
+ "Gidugu",
+ "Gilda Display",
+ "Girassol",
+ "Give You Glory",
+ "Glass Antiqua",
+ "Glegoo",
+ "Gloock",
+ "Gloria Hallelujah",
+ "Glory",
+ "Gluten",
+ "Goblin One",
+ "Gochi Hand",
+ "Goldman",
+ "Golos Text",
+ "Gorditas",
+ "Gothic A1",
+ "Gotu",
+ "Goudy Bookletter 1911",
+ "Gowun Batang",
+ "Gowun Dodum",
+ "Graduate",
+ "Grand Hotel",
+ "Grandiflora One",
+ "Grandstander",
+ "Grape Nuts",
+ "Gravitas One",
+ "Great Vibes",
+ "Grechen Fuemen",
+ "Grenze",
+ "Grenze Gotisch",
+ "Grey Qo",
+ "Griffy",
+ "Gruppo",
+ "Gudea",
+ "Gugi",
+ "Gulzar",
+ "Gupter",
+ "Gurajada",
+ "Gwendolyn",
+ "Habibi",
+ "Hachi Maru Pop",
+ "Hahmlet",
+ "Halant",
+ "Hammersmith One",
+ "Hanalei",
+ "Hanalei Fill",
+ "Handjet",
+ "Handlee",
+ "Hanken Grotesk",
+ "Hanuman",
+ "Happy Monkey",
+ "Harmattan",
+ "Headland One",
+ "Heebo",
+ "Henny Penny",
+ "Hepta Slab",
+ "Herr Von Muellerhoff",
+ "Hi Melody",
+ "Hina Mincho",
+ "Hind",
+ "Hind Guntur",
+ "Hind Madurai",
+ "Hind Siliguri",
+ "Hind Vadodara",
+ "Holtwood One SC",
+ "Homemade Apple",
+ "Homenaje",
+ "Hubballi",
+ "Hurricane",
+ "IBM Plex Mono",
+ "IBM Plex Sans",
+ "IBM Plex Sans Arabic",
+ "IBM Plex Sans Condensed",
+ "IBM Plex Sans Devanagari",
+ "IBM Plex Sans Hebrew",
+ "IBM Plex Sans JP",
+ "IBM Plex Sans KR",
+ "IBM Plex Sans Thai",
+ "IBM Plex Sans Thai Looped",
+ "IBM Plex Serif",
+ "IM Fell DW Pica",
+ "IM Fell DW Pica SC",
+ "IM Fell Double Pica",
+ "IM Fell Double Pica SC",
+ "IM Fell English",
+ "IM Fell English SC",
+ "IM Fell French Canon",
+ "IM Fell French Canon SC",
+ "IM Fell Great Primer",
+ "IM Fell Great Primer SC",
+ "Ibarra Real Nova",
+ "Iceberg",
+ "Iceland",
+ "Imbue",
+ "Imperial Script",
+ "Imprima",
+ "Inconsolata",
+ "Inder",
+ "Indie Flower",
+ "Ingrid Darling",
+ "Inika",
+ "Inknut Antiqua",
+ "Inria Sans",
+ "Inria Serif",
+ "Inspiration",
+ "Instrument Sans",
+ "Instrument Serif",
+ "Inter",
+ "Inter Tight",
+ "Irish Grover",
+ "Island Moments",
+ "Istok Web",
+ "Italiana",
+ "Italianno",
+ "Itim",
+ "Jacques Francois",
+ "Jacques Francois Shadow",
+ "Jaldi",
+ "JetBrains Mono",
+ "Jim Nightshade",
+ "Joan",
+ "Jockey One",
+ "Jolly Lodger",
+ "Jomhuria",
+ "Jomolhari",
+ "Josefin Sans",
+ "Josefin Slab",
+ "Jost",
+ "Joti One",
+ "Jua",
+ "Judson",
+ "Julee",
+ "Julius Sans One",
+ "Junge",
+ "Jura",
+ "Just Another Hand",
+ "Just Me Again Down Here",
+ "K2D",
+ "Kablammo",
+ "Kadwa",
+ "Kaisei Decol",
+ "Kaisei HarunoUmi",
+ "Kaisei Opti",
+ "Kaisei Tokumin",
+ "Kalam",
+ "Kameron",
+ "Kanit",
+ "Kantumruy Pro",
+ "Karantina",
+ "Karla",
+ "Karma",
+ "Katibeh",
+ "Kaushan Script",
+ "Kavivanar",
+ "Kavoon",
+ "Kdam Thmor Pro",
+ "Keania One",
+ "Kelly Slab",
+ "Kenia",
+ "Khand",
+ "Khmer",
+ "Khula",
+ "Kings",
+ "Kirang Haerang",
+ "Kite One",
+ "Kiwi Maru",
+ "Klee One",
+ "Knewave",
+ "KoHo",
+ "Kodchasan",
+ "Koh Santepheap",
+ "Kolker Brush",
+ "Konkhmer Sleokchher",
+ "Kosugi",
+ "Kosugi Maru",
+ "Kotta One",
+ "Koulen",
+ "Kranky",
+ "Kreon",
+ "Kristi",
+ "Krona One",
+ "Krub",
+ "Kufam",
+ "Kumar One",
+ "Kumbh Sans",
+ "Kurale",
+ "La Belle Aurore",
+ "Labrada",
+ "Lacquer",
+ "Laila",
+ "Lakki Reddy",
+ "Lalezar",
+ "Lancelot",
+ "Langar",
+ "Lateef",
+ "Lato",
+ "Lavishly Yours",
+ "League Gothic",
+ "League Script",
+ "League Spartan",
+ "Leckerli One",
+ "Ledger",
+ "Lekton",
+ "Lemon",
+ "Lemonada",
+ "Lexend",
+ "Lexend Deca",
+ "Lexend Exa",
+ "Lexend Giga",
+ "Lexend Mega",
+ "Lexend Peta",
+ "Lexend Tera",
+ "Lexend Zetta",
+ "Libre Barcode 128",
+ "Libre Barcode 128 Text",
+ "Libre Barcode 39",
+ "Libre Barcode 39 Extended",
+ "Libre Barcode 39 Extended Text",
+ "Libre Barcode 39 Text",
+ "Libre Barcode EAN13 Text",
+ "Libre Baskerville",
+ "Libre Bodoni",
+ "Libre Caslon Display",
+ "Libre Caslon Text",
+ "Libre Franklin",
+ "Licorice",
+ "Life Savers",
+ "Lilita One",
+ "Lily Script One",
+ "Limelight",
+ "Linden Hill",
+ "Lisu Bosa",
+ "Literata",
+ "Liu Jian Mao Cao",
+ "Livvic",
+ "Lobster",
+ "Lobster Two",
+ "Londrina Outline",
+ "Londrina Shadow",
+ "Londrina Sketch",
+ "Londrina Solid",
+ "Long Cang",
+ "Lora",
+ "Love Light",
+ "Love Ya Like A Sister",
+ "Loved by the King",
+ "Lovers Quarrel",
+ "Luckiest Guy",
+ "Lugrasimo",
+ "Lumanosimo",
+ "Lunasima",
+ "Lusitana",
+ "Lustria",
+ "Luxurious Roman",
+ "Luxurious Script",
+ "M PLUS 1",
+ "M PLUS 1 Code",
+ "M PLUS 1p",
+ "M PLUS 2",
+ "M PLUS Code Latin",
+ "Ma Shan Zheng",
+ "Macondo",
+ "Macondo Swash Caps",
+ "Mada",
+ "Magra",
+ "Maiden Orange",
+ "Maitree",
+ "Major Mono Display",
+ "Mako",
+ "Mali",
+ "Mallanna",
+ "Mandali",
+ "Manjari",
+ "Manrope",
+ "Mansalva",
+ "Manuale",
+ "Marcellus",
+ "Marcellus SC",
+ "Marck Script",
+ "Margarine",
+ "Marhey",
+ "Markazi Text",
+ "Marko One",
+ "Marmelad",
+ "Martel",
+ "Martel Sans",
+ "Martian Mono",
+ "Marvel",
+ "Mate",
+ "Mate SC",
+ "Maven Pro",
+ "McLaren",
+ "Mea Culpa",
+ "Meddon",
+ "MedievalSharp",
+ "Medula One",
+ "Meera Inimai",
+ "Megrim",
+ "Meie Script",
+ "Meow Script",
+ "Merienda",
+ "Merriweather",
+ "Merriweather Sans",
+ "Metal",
+ "Metal Mania",
+ "Metamorphous",
+ "Metrophobic",
+ "Michroma",
+ "Milonga",
+ "Miltonian",
+ "Miltonian Tattoo",
+ "Mina",
+ "Mingzat",
+ "Miniver",
+ "Miriam Libre",
+ "Miss Fajardose",
+ "Mochiy Pop One",
+ "Mochiy Pop P One",
+ "Modak",
+ "Modern Antiqua",
+ "Mohave",
+ "Moirai One",
+ "Molengo",
+ "Molle",
+ "Monda",
+ "Monofett",
+ "Monomaniac One",
+ "Monoton",
+ "Monsieur La Doulaise",
+ "Montaga",
+ "Montagu Slab",
+ "MonteCarlo",
+ "Montez",
+ "Montserrat",
+ "Montserrat Alternates",
+ "Montserrat Subrayada",
+ "Moo Lah Lah",
+ "Moon Dance",
+ "Moul",
+ "Moulpali",
+ "Mountains of Christmas",
+ "Mouse Memoirs",
+ "Mr Bedfort",
+ "Mr Dafoe",
+ "Mr De Haviland",
+ "Mrs Saint Delafield",
+ "Mrs Sheppards",
+ "Ms Madi",
+ "Mukta",
+ "Mukta Mahee",
+ "Mukta Malar",
+ "Mukta Vaani",
+ "Mulish",
+ "Murecho",
+ "MuseoModerno",
+ "My Soul",
+ "Mynerve",
+ "Mystery Quest",
+ "NTR",
+ "Nabla",
+ "Nanum Brush Script",
+ "Nanum Gothic",
+ "Nanum Gothic Coding",
+ "Nanum Myeongjo",
+ "Nanum Pen Script",
+ "Narnoor",
+ "Neonderthaw",
+ "Nerko One",
+ "Neucha",
+ "Neuton",
+ "New Rocker",
+ "New Tegomin",
+ "News Cycle",
+ "Newsreader",
+ "Niconne",
+ "Niramit",
+ "Nixie One",
+ "Nobile",
+ "Nokora",
+ "Norican",
+ "Nosifer",
+ "Notable",
+ "Nothing You Could Do",
+ "Noticia Text",
+ "Noto Color Emoji",
+ "Noto Emoji",
+ "Noto Kufi Arabic",
+ "Noto Music",
+ "Noto Naskh Arabic",
+ "Noto Nastaliq Urdu",
+ "Noto Rashi Hebrew",
+ "Noto Sans",
+ "Noto Sans Adlam",
+ "Noto Sans Adlam Unjoined",
+ "Noto Sans Anatolian Hieroglyphs",
+ "Noto Sans Arabic",
+ "Noto Sans Armenian",
+ "Noto Sans Avestan",
+ "Noto Sans Balinese",
+ "Noto Sans Bamum",
+ "Noto Sans Bassa Vah",
+ "Noto Sans Batak",
+ "Noto Sans Bengali",
+ "Noto Sans Bhaiksuki",
+ "Noto Sans Brahmi",
+ "Noto Sans Buginese",
+ "Noto Sans Buhid",
+ "Noto Sans Canadian Aboriginal",
+ "Noto Sans Carian",
+ "Noto Sans Caucasian Albanian",
+ "Noto Sans Chakma",
+ "Noto Sans Cham",
+ "Noto Sans Cherokee",
+ "Noto Sans Chorasmian",
+ "Noto Sans Coptic",
+ "Noto Sans Cuneiform",
+ "Noto Sans Cypriot",
+ "Noto Sans Cypro Minoan",
+ "Noto Sans Deseret",
+ "Noto Sans Devanagari",
+ "Noto Sans Display",
+ "Noto Sans Duployan",
+ "Noto Sans Egyptian Hieroglyphs",
+ "Noto Sans Elbasan",
+ "Noto Sans Elymaic",
+ "Noto Sans Ethiopic",
+ "Noto Sans Georgian",
+ "Noto Sans Glagolitic",
+ "Noto Sans Gothic",
+ "Noto Sans Grantha",
+ "Noto Sans Gujarati",
+ "Noto Sans Gunjala Gondi",
+ "Noto Sans Gurmukhi",
+ "Noto Sans HK",
+ "Noto Sans Hanifi Rohingya",
+ "Noto Sans Hanunoo",
+ "Noto Sans Hatran",
+ "Noto Sans Hebrew",
+ "Noto Sans Imperial Aramaic",
+ "Noto Sans Indic Siyaq Numbers",
+ "Noto Sans Inscriptional Pahlavi",
+ "Noto Sans Inscriptional Parthian",
+ "Noto Sans JP",
+ # "Noto Sans Japanese",
+ "Noto Sans Javanese",
+ "Noto Sans KR",
+ "Noto Sans Kaithi",
+ "Noto Sans Kannada",
+ "Noto Sans Kayah Li",
+ "Noto Sans Kharoshthi",
+ "Noto Sans Khmer",
+ "Noto Sans Khojki",
+ "Noto Sans Khudawadi",
+ # "Noto Sans Korean",
+ "Noto Sans Lao",
+ "Noto Sans Lao Looped",
+ "Noto Sans Lepcha",
+ "Noto Sans Limbu",
+ "Noto Sans Linear A",
+ "Noto Sans Linear B",
+ "Noto Sans Lisu",
+ "Noto Sans Lycian",
+ "Noto Sans Lydian",
+ "Noto Sans Mahajani",
+ "Noto Sans Malayalam",
+ "Noto Sans Mandaic",
+ "Noto Sans Manichaean",
+ "Noto Sans Marchen",
+ "Noto Sans Masaram Gondi",
+ "Noto Sans Math",
+ "Noto Sans Mayan Numerals",
+ "Noto Sans Medefaidrin",
+ "Noto Sans Meetei Mayek",
+ "Noto Sans Mende Kikakui",
+ "Noto Sans Meroitic",
+ "Noto Sans Miao",
+ "Noto Sans Modi",
+ "Noto Sans Mongolian",
+ "Noto Sans Mono",
+ "Noto Sans Mro",
+ "Noto Sans Multani",
+ "Noto Sans Myanmar",
+ "Noto Sans NKo",
+ "Noto Sans Nabataean",
+ "Noto Sans Nag Mundari",
+ "Noto Sans Nandinagari",
+ "Noto Sans New Tai Lue",
+ "Noto Sans Newa",
+ "Noto Sans Nushu",
+ "Noto Sans Ogham",
+ "Noto Sans Ol Chiki",
+ "Noto Sans Old Hungarian",
+ "Noto Sans Old Italic",
+ "Noto Sans Old North Arabian",
+ "Noto Sans Old Permic",
+ "Noto Sans Old Persian",
+ "Noto Sans Old Sogdian",
+ "Noto Sans Old South Arabian",
+ "Noto Sans Old Turkic",
+ "Noto Sans Oriya",
+ "Noto Sans Osage",
+ "Noto Sans Osmanya",
+ "Noto Sans Pahawh Hmong",
+ "Noto Sans Palmyrene",
+ "Noto Sans Pau Cin Hau",
+ # "Noto Sans Phags Pa",
+ "Noto Sans Phoenician",
+ "Noto Sans Psalter Pahlavi",
+ "Noto Sans Rejang",
+ "Noto Sans Runic",
+ "Noto Sans SC",
+ "Noto Sans Samaritan",
+ "Noto Sans Saurashtra",
+ "Noto Sans Sharada",
+ "Noto Sans Shavian",
+ "Noto Sans Siddham",
+ "Noto Sans SignWriting",
+ "Noto Sans Sinhala",
+ "Noto Sans Sogdian",
+ "Noto Sans Sora Sompeng",
+ "Noto Sans Soyombo",
+ "Noto Sans Sundanese",
+ "Noto Sans Syloti Nagri",
+ "Noto Sans Symbols",
+ "Noto Sans Symbols 2",
+ "Noto Sans Syriac",
+ "Noto Sans Syriac Eastern",
+ "Noto Sans TC",
+ "Noto Sans Tagalog",
+ "Noto Sans Tagbanwa",
+ "Noto Sans Tai Le",
+ "Noto Sans Tai Tham",
+ "Noto Sans Tai Viet",
+ "Noto Sans Takri",
+ "Noto Sans Tamil",
+ "Noto Sans Tamil Supplement",
+ "Noto Sans Tangsa",
+ "Noto Sans Telugu",
+ "Noto Sans Thaana",
+ "Noto Sans Thai",
+ "Noto Sans Thai Looped",
+ "Noto Sans Tifinagh",
+ "Noto Sans Tirhuta",
+ "Noto Sans Ugaritic",
+ "Noto Sans Vai",
+ "Noto Sans Vithkuqi",
+ "Noto Sans Wancho",
+ "Noto Sans Warang Citi",
+ "Noto Sans Yi",
+ "Noto Sans Zanabazar Square",
+ "Noto Serif",
+ "Noto Serif Ahom",
+ "Noto Serif Armenian",
+ "Noto Serif Balinese",
+ "Noto Serif Bengali",
+ "Noto Serif Devanagari",
+ "Noto Serif Display",
+ "Noto Serif Dogra",
+ "Noto Serif Ethiopic",
+ "Noto Serif Georgian",
+ "Noto Serif Grantha",
+ "Noto Serif Gujarati",
+ "Noto Serif Gurmukhi",
+ "Noto Serif HK",
+ "Noto Serif Hebrew",
+ "Noto Serif JP",
+ "Noto Serif KR",
+ "Noto Serif Kannada",
+ "Noto Serif Khitan Small Script",
+ "Noto Serif Khmer",
+ "Noto Serif Khojki",
+ "Noto Serif Lao",
+ "Noto Serif Makasar",
+ "Noto Serif Malayalam",
+ "Noto Serif Myanmar",
+ "Noto Serif NP Hmong",
+ "Noto Serif Oriya",
+ "Noto Serif Ottoman Siyaq",
+ "Noto Serif SC",
+ "Noto Serif Sinhala",
+ "Noto Serif TC",
+ "Noto Serif Tamil",
+ "Noto Serif Tangut",
+ "Noto Serif Telugu",
+ "Noto Serif Thai",
+ "Noto Serif Tibetan",
+ "Noto Serif Toto",
+ "Noto Serif Vithkuqi",
+ "Noto Serif Yezidi",
+ "Noto Traditional Nushu",
+ "Nova Cut",
+ "Nova Flat",
+ "Nova Mono",
+ "Nova Oval",
+ "Nova Round",
+ "Nova Script",
+ "Nova Slim",
+ "Nova Square",
+ "Numans",
+ "Nunito",
+ "Nunito Sans",
+ "Nuosu SIL",
+ "Odibee Sans",
+ "Odor Mean Chey",
+ "Offside",
+ "Oi",
+ "Old Standard TT",
+ "Oldenburg",
+ "Ole",
+ "Oleo Script",
+ "Oleo Script Swash Caps",
+ "Oooh Baby",
+ "Open Sans",
+ # "Open Sans Condensed",
+ "Oranienbaum",
+ "Orbit",
+ "Orbitron",
+ "Oregano",
+ "Orelega One",
+ "Orienta",
+ "Original Surfer",
+ "Oswald",
+ "Outfit",
+ "Over the Rainbow",
+ "Overlock",
+ "Overlock SC",
+ "Overpass",
+ "Overpass Mono",
+ "Ovo",
+ "Oxanium",
+ "Oxygen",
+ "Oxygen Mono",
+ "PT Mono",
+ "PT Sans",
+ "PT Sans Caption",
+ "PT Sans Narrow",
+ "PT Serif",
+ "PT Serif Caption",
+ "Pacifico",
+ "Padauk",
+ "Padyakke Expanded One",
+ "Palanquin",
+ "Palanquin Dark",
+ "Palette Mosaic",
+ "Pangolin",
+ "Paprika",
+ "Parisienne",
+ "Passero One",
+ "Passion One",
+ "Passions Conflict",
+ "Pathway Extreme",
+ "Pathway Gothic One",
+ "Patrick Hand",
+ "Patrick Hand SC",
+ "Pattaya",
+ "Patua One",
+ "Pavanam",
+ "Paytone One",
+ "Peddana",
+ "Peralta",
+ "Permanent Marker",
+ "Petemoss",
+ "Petit Formal Script",
+ "Petrona",
+ "Philosopher",
+ "Phudu",
+ "Piazzolla",
+ "Piedra",
+ "Pinyon Script",
+ "Pirata One",
+ "Plaster",
+ "Play",
+ "Playball",
+ "Playfair",
+ "Playfair Display",
+ "Playfair Display SC",
+ "Plus Jakarta Sans",
+ "Podkova",
+ "Poiret One",
+ "Poller One",
+ "Poltawski Nowy",
+ "Poly",
+ "Pompiere",
+ "Pontano Sans",
+ "Poor Story",
+ "Poppins",
+ "Port Lligat Sans",
+ "Port Lligat Slab",
+ "Potta One",
+ "Pragati Narrow",
+ "Praise",
+ "Preahvihear",
+ "Press Start 2P",
+ "Pridi",
+ "Princess Sofia",
+ "Prociono",
+ "Prompt",
+ "Prosto One",
+ "Proza Libre",
+ "Public Sans",
+ "Puppies Play",
+ "Puritan",
+ "Purple Purse",
+ "Qahiri",
+ "Quando",
+ "Quantico",
+ "Quattrocento",
+ "Quattrocento Sans",
+ "Questrial",
+ "Quicksand",
+ "Quintessential",
+ "Qwigley",
+ "Qwitcher Grypen",
+ "REM",
+ "Racing Sans One",
+ "Radio Canada",
+ "Radley",
+ "Rajdhani",
+ "Rakkas",
+ "Raleway",
+ "Raleway Dots",
+ "Ramabhadra",
+ "Ramaraja",
+ "Rambla",
+ "Rammetto One",
+ "Rampart One",
+ "Ranchers",
+ "Rancho",
+ "Ranga",
+ "Rasa",
+ "Rationale",
+ "Ravi Prakash",
+ "Readex Pro",
+ "Recursive",
+ "Red Hat Display",
+ "Red Hat Mono",
+ "Red Hat Text",
+ "Red Rose",
+ "Redacted",
+ "Redacted Script",
+ "Redressed",
+ "Reem Kufi",
+ "Reem Kufi Fun",
+ "Reem Kufi Ink",
+ "Reenie Beanie",
+ "Reggae One",
+ "Revalia",
+ "Rhodium Libre",
+ "Ribeye",
+ "Ribeye Marrow",
+ "Righteous",
+ "Risque",
+ "Road Rage",
+ "Roboto",
+ "Roboto Condensed",
+ "Roboto Flex",
+ "Roboto Mono",
+ "Roboto Serif",
+ "Roboto Slab",
+ "Rochester",
+ "Rock 3D",
+ "Rock Salt",
+ "RocknRoll One",
+ "Rokkitt",
+ "Romanesco",
+ "Ropa Sans",
+ "Rosario",
+ "Rosarivo",
+ "Rouge Script",
+ "Rowdies",
+ "Rozha One",
+ "Rubik",
+ "Rubik 80s Fade",
+ "Rubik Beastly",
+ "Rubik Bubbles",
+ "Rubik Burned",
+ "Rubik Dirt",
+ "Rubik Distressed",
+ "Rubik Gemstones",
+ "Rubik Glitch",
+ "Rubik Iso",
+ "Rubik Marker Hatch",
+ "Rubik Maze",
+ "Rubik Microbe",
+ "Rubik Mono One",
+ "Rubik Moonrocks",
+ "Rubik One",
+ "Rubik Pixels",
+ "Rubik Puddles",
+ "Rubik Spray Paint",
+ "Rubik Storm",
+ "Rubik Vinyl",
+ "Rubik Wet Paint",
+ "Ruda",
+ "Rufina",
+ "Ruge Boogie",
+ "Ruluko",
+ "Rum Raisin",
+ "Ruslan Display",
+ "Russo One",
+ "Ruthie",
+ "Ruwudu",
+ "Rye",
+ "STIX Two Text",
+ "Sacramento",
+ "Sahitya",
+ "Sail",
+ "Saira",
+ "Saira Condensed",
+ "Saira Extra Condensed",
+ "Saira Semi Condensed",
+ "Saira Stencil One",
+ "Salsa",
+ "Sanchez",
+ "Sancreek",
+ "Sansita",
+ "Sansita One",
+ "Sansita Swashed",
+ "Sarabun",
+ "Sarala",
+ "Sarina",
+ "Sarpanch",
+ "Sassy Frass",
+ "Satisfy",
+ "Sawarabi Mincho",
+ "Scada",
+ "Scheherazade New",
+ "Schibsted Grotesk",
+ "Schoolbell",
+ "Scope One",
+ "Seaweed Script",
+ "Secular One",
+ "Sedgwick Ave",
+ "Sedgwick Ave Display",
+ "Sen",
+ "Send Flowers",
+ "Sevillana",
+ "Seymour One",
+ "Shadows Into Light",
+ "Shadows Into Light Two",
+ "Shalimar",
+ "Shantell Sans",
+ "Shanti",
+ "Share",
+ "Share Tech",
+ "Share Tech Mono",
+ "Shippori Antique",
+ "Shippori Antique B1",
+ "Shippori Mincho",
+ "Shippori Mincho B1",
+ "Shizuru",
+ "Shojumaru",
+ "Short Stack",
+ "Shrikhand",
+ "Siemreap",
+ "Sigmar",
+ "Sigmar One",
+ "Signika",
+ "Signika Negative",
+ "Silkscreen",
+ "Simonetta",
+ "Single Day",
+ "Sintony",
+ "Sirin Stencil",
+ "Six Caps",
+ "Skranji",
+ "Slabo 13px",
+ "Slabo 27px",
+ "Slackey",
+ "Slackside One",
+ "Smokum",
+ "Smooch",
+ "Smooch Sans",
+ "Smythe",
+ "Sniglet",
+ "Snippet",
+ "Snowburst One",
+ "Sofadi One",
+ "Sofia",
+ "Sofia Sans",
+ "Sofia Sans Condensed",
+ "Sofia Sans Extra Condensed",
+ "Sofia Sans Semi Condensed",
+ "Solitreo",
+ "Solway",
+ "Song Myung",
+ "Sono",
+ "Sonsie One",
+ "Sora",
+ "Sorts Mill Goudy",
+ "Source Code Pro",
+ "Source Sans 3",
+ "Space Grotesk",
+ "Space Mono",
+ "Special Elite",
+ "Spectral",
+ "Spicy Rice",
+ "Spinnaker",
+ "Spirax",
+ "Splash",
+ "Spline Sans",
+ "Spline Sans Mono",
+ "Squada One",
+ "Square Peg",
+ "Sree Krushnadevaraya",
+ "Sriracha",
+ "Srisakdi",
+ "Staatliches",
+ "Stalemate",
+ "Stalinist One",
+ "Stardos Stencil",
+ "Stick",
+ "Stick No Bills",
+ "Stint Ultra Condensed",
+ "Stint Ultra Expanded",
+ "Stoke",
+ "Strait",
+ "Style Script",
+ "Stylish",
+ "Sue Ellen Francisco",
+ "Suez One",
+ "Sulphur Point",
+ "Sumana",
+ "Sunflower",
+ "Sunshiney",
+ "Supermercado One",
+ "Sura",
+ "Suranna",
+ "Suravaram",
+ "Suwannaphum",
+ "Swanky and Moo Moo",
+ "Syncopate",
+ "Syne",
+ "Syne Mono",
+ "Syne Tactile",
+ "Tai Heritage Pro",
+ "Tajawal",
+ "Tangerine",
+ "Tapestry",
+ "Taprom",
+ "Tauri",
+ "Taviraj",
+ "Teko",
+ "Tektur",
+ "Telex",
+ "Tenali Ramakrishna",
+ "Tenor Sans",
+ "Text Me One",
+ "Texturina",
+ "Thasadith",
+ "The Girl Next Door",
+ "The Nautigal",
+ "Tienne",
+ "Tillana",
+ "Tilt Neon",
+ "Tilt Prism",
+ "Tilt Warp",
+ "Timmana",
+ "Tinos",
+ "Tiro Bangla",
+ "Tiro Devanagari Hindi",
+ "Tiro Devanagari Marathi",
+ "Tiro Devanagari Sanskrit",
+ "Tiro Gurmukhi",
+ "Tiro Kannada",
+ "Tiro Tamil",
+ "Tiro Telugu",
+ "Titan One",
+ "Titillium Web",
+ "Tomorrow",
+ "Tourney",
+ "Trade Winds",
+ "Train One",
+ "Trirong",
+ "Trispace",
+ "Trocchi",
+ "Trochut",
+ "Truculenta",
+ "Trykker",
+ "Tsukimi Rounded",
+ "Tulpen One",
+ "Turret Road",
+ "Twinkle Star",
+ "Ubuntu",
+ "Ubuntu Condensed",
+ "Ubuntu Mono",
+ "Uchen",
+ "Ultra",
+ "Unbounded",
+ "Uncial Antiqua",
+ "Underdog",
+ "Unica One",
+ "UnifrakturCook",
+ "UnifrakturMaguntia",
+ "Unkempt",
+ "Unlock",
+ "Unna",
+ "Updock",
+ "Urbanist",
+ "VT323",
+ "Vampiro One",
+ "Varela",
+ "Varela Round",
+ "Varta",
+ "Vast Shadow",
+ "Vazirmatn",
+ "Vesper Libre",
+ "Viaoda Libre",
+ "Vibes",
+ "Vibur",
+ "Victor Mono",
+ "Vidaloka",
+ "Viga",
+ "Vina Sans",
+ "Voces",
+ "Volkhov",
+ "Vollkorn",
+ "Vollkorn SC",
+ "Voltaire",
+ "Vujahday Script",
+ "Waiting for the Sunrise",
+ "Wallpoet",
+ "Walter Turncoat",
+ "Warnes",
+ "Water Brush",
+ "Waterfall",
+ "Wavefont",
+ "Wellfleet",
+ "Wendy One",
+ "Whisper",
+ "WindSong",
+ "Wire One",
+ "Wix Madefor Display",
+ "Wix Madefor Text",
+ "Work Sans",
+ "Xanh Mono",
+ "Yaldevi",
+ "Yanone Kaffeesatz",
+ "Yantramanav",
+ "Yatra One",
+ "Yellowtail",
+ "Yeon Sung",
+ "Yeseva One",
+ "Yesteryear",
+ "Yomogi",
+ "Yrsa",
+ "Ysabeau",
+ "Ysabeau Infant",
+ "Ysabeau Office",
+ "Ysabeau SC",
+ "Yuji Boku",
+ "Yuji Hentaigana Akari",
+ "Yuji Hentaigana Akebono",
+ "Yuji Mai",
+ "Yuji Syuku",
+ "Yusei Magic",
+ "ZCOOL KuaiLe",
+ "ZCOOL QingKe HuangYou",
+ "ZCOOL XiaoWei",
+ "Zen Antique",
+ "Zen Antique Soft",
+ "Zen Dots",
+ "Zen Kaku Gothic Antique",
+ "Zen Kaku Gothic New",
+ "Zen Kurenaido",
+ "Zen Loop",
+ "Zen Maru Gothic",
+ "Zen Old Mincho",
+ "Zen Tokyo Zoo",
+ "Zeyada",
+ "Zhi Mang Xing",
+ "Zilla Slab",
+ "Zilla Slab Highlight",
+]
font_details = {}
for p in path.rglob("*METADATA.pb"):
- with open(p, "rt", encoding="utf8") as f_in:
+ with open(p, encoding="utf8") as f_in:
contents = f_in.readlines()
- github_path = str(p.parent)[len(str(path)) + 1:]
+ github_path = str(p.parent)[len(str(path)) + 1 :]
name = None
license = None
@@ -1585,29 +1587,35 @@
match = re.match(r'\s*filename: "(.*)"', line)
if match:
- filenames.append(f'{github_path}/{match.group(1).replace("[", "%5B").replace("]", "%5D")}')
+ filenames.append(
+ f'{github_path}/{match.group(1).replace("[", "%5B").replace("]", "%5D")}'
+ )
license_path = None
- if not (p.parent / f'{license}.txt').exists():
- for license in ['LICENCE.txt', 'LICENSE.txt']:
+ if not (p.parent / f"{license}.txt").exists():
+ for license in ["LICENCE.txt", "LICENSE.txt"]:
if (p.parent / license).exists():
- license_path = f'{github_path}/{license}.txt'
+ license_path = f"{github_path}/{license}.txt"
break
else:
- license_path = f'{github_path}/{license}.txt'
+ license_path = f"{github_path}/{license}.txt"
- font_details[name] = {'filenames': filenames,
- 'license_path': license_path}
+ font_details[name] = {"filenames": filenames, "license_path": license_path}
def process_font(family: str):
assert family in font_details, family
- assert font_details[family]['license_path'], family
+ assert font_details[family]["license_path"], family
- filenames = ', '.join([f'QStringLiteral( "{f}" )' for f in font_details[family]['filenames']])
+ filenames = ", ".join(
+ [f'QStringLiteral( "{f}" )' for f in font_details[family]["filenames"]]
+ )
- print('GoogleFontDetails( QStringLiteral( "{}" ), {{ {} }}, QStringLiteral( "{}" ) ),'.format(
- family, filenames, font_details[family]['license_path']))
+ print(
+ 'GoogleFontDetails( QStringLiteral( "{}" ), {{ {} }}, QStringLiteral( "{}" ) ),'.format(
+ family, filenames, font_details[family]["license_path"]
+ )
+ )
for f in fonts:
diff --git a/scripts/pyqt5_to_pyqt6/pyqt5_to_pyqt6.py b/scripts/pyqt5_to_pyqt6/pyqt5_to_pyqt6.py
index 2edbfed7210d..da4f07c2c7b6 100755
--- a/scripts/pyqt5_to_pyqt6/pyqt5_to_pyqt6.py
+++ b/scripts/pyqt5_to_pyqt6/pyqt5_to_pyqt6.py
@@ -34,71 +34,79 @@
tokenize-rt myfile.py
"""
-__author__ = 'Julien Cabieces'
-__date__ = '2023 December'
-__copyright__ = '(C) 2023, Julien Cabieces'
+__author__ = "Julien Cabieces"
+__date__ = "2023 December"
+__copyright__ = "(C) 2023, Julien Cabieces"
import argparse
import ast
import glob
-import os
import inspect
+import os
import sys
-from enum import Enum
from collections import defaultdict
+from collections.abc import Sequence
+from enum import Enum
-from tokenize_rt import Offset, src_to_tokens, tokens_to_src, reversed_enumerate, Token
-
-from typing import Sequence
-
-from PyQt6 import QtCore, QtGui, QtWidgets, QtTest, QtSql, QtSvg, QtXml, QtNetwork, QtPrintSupport, Qsci
+from PyQt6 import (
+ Qsci,
+ QtCore,
+ QtGui,
+ QtNetwork,
+ QtPrintSupport,
+ QtSql,
+ QtSvg,
+ QtTest,
+ QtWidgets,
+ QtXml,
+)
+from PyQt6.Qsci import * # noqa: F403
from PyQt6.QtCore import * # noqa: F403
from PyQt6.QtGui import * # noqa: F403
-from PyQt6.QtWidgets import * # noqa: F403
-from PyQt6.QtTest import * # noqa: F403
-from PyQt6.QtSql import * # noqa: F403
-from PyQt6.QtXml import * # noqa: F403
from PyQt6.QtNetwork import * # noqa: F403
from PyQt6.QtPrintSupport import * # noqa: F403
-from PyQt6.Qsci import * # noqa: F403
+from PyQt6.QtSql import * # noqa: F403
+from PyQt6.QtTest import * # noqa: F403
+from PyQt6.QtWidgets import * # noqa: F403
+from PyQt6.QtXml import * # noqa: F403
+from tokenize_rt import Offset, Token, reversed_enumerate, src_to_tokens, tokens_to_src
try:
+ import qgis._3d as qgis_3d # noqa: F403
+ import qgis.analysis as qgis_analysis # noqa: F403
import qgis.core as qgis_core # noqa: F403
import qgis.gui as qgis_gui # noqa: F403
- import qgis.analysis as qgis_analysis # noqa: F403
- import qgis._3d as qgis_3d # noqa: F403
+
+ from qgis._3d import * # noqa: F403
+ from qgis.analysis import * # noqa: F403
from qgis.core import * # noqa: F403
from qgis.gui import * # noqa: F403
- from qgis.analysis import * # noqa: F403
- from qgis._3d import * # noqa: F403
except ImportError:
qgis_core = None
qgis_gui = None
qgis_analysis = None
qgis_3d = None
- print('QGIS classes not available for introspection, only a partial upgrade will be performed')
-
-target_modules = [QtCore,
- QtGui,
- QtWidgets,
- QtTest,
- QtSql,
- QtSvg,
- QtXml,
- QtNetwork,
- QtPrintSupport,
- Qsci]
-if qgis_core is not None:
- target_modules.extend([
- qgis_core,
- qgis_gui,
- qgis_analysis,
- qgis_3d
- ]
+ print(
+ "QGIS classes not available for introspection, only a partial upgrade will be performed"
)
+target_modules = [
+ QtCore,
+ QtGui,
+ QtWidgets,
+ QtTest,
+ QtSql,
+ QtSvg,
+ QtXml,
+ QtNetwork,
+ QtPrintSupport,
+ Qsci,
+]
+if qgis_core is not None:
+ target_modules.extend([qgis_core, qgis_gui, qgis_analysis, qgis_3d])
+
# qmetatype which have been renamed
qmetatype_mapping = {
"Invalid": "UnknownType",
@@ -155,22 +163,18 @@
}
deprecated_renamed_enums = {
- ('Qt', 'MidButton'): ('MouseButton', 'MiddleButton'),
- ('Qt', 'TextColorRole'): ('ItemDataRole', 'ForegroundRole'),
- ('Qt', 'BackgroundColorRole'): ('ItemDataRole', 'BackgroundRole'),
- ('QPainter', 'HighQualityAntialiasing'): ('RenderHint', 'Antialiasing'),
+ ("Qt", "MidButton"): ("MouseButton", "MiddleButton"),
+ ("Qt", "TextColorRole"): ("ItemDataRole", "ForegroundRole"),
+ ("Qt", "BackgroundColorRole"): ("ItemDataRole", "BackgroundRole"),
+ ("QPainter", "HighQualityAntialiasing"): ("RenderHint", "Antialiasing"),
}
-rename_function_attributes = {
- 'exec_': 'exec'
-}
+rename_function_attributes = {"exec_": "exec"}
-rename_function_definitions = {
- 'exec_': 'exec'
-}
+rename_function_definitions = {"exec_": "exec"}
import_warnings = {
- 'QRegExp': 'QRegExp is removed in Qt6, please use QRegularExpression for Qt5/Qt6 compatibility'
+ "QRegExp": "QRegExp is removed in Qt6, please use QRegularExpression for Qt5/Qt6 compatibility"
}
# { (class, enum_value) : enum_name }
@@ -180,7 +184,7 @@
def fix_file(filename: str, qgis3_compat: bool) -> int:
- with open(filename, encoding='UTF-8') as f:
+ with open(filename, encoding="UTF-8") as f:
contents = f.read()
fix_qvariant_type = [] # QVariant.Int, QVariant.Double ...
@@ -199,8 +203,11 @@ def fix_file(filename: str, qgis3_compat: bool) -> int:
object_types = {}
def visit_assign(_node: ast.Assign, _parent):
- if isinstance(_node.value, ast.Call) and isinstance(_node.value.func,
- ast.Name) and _node.value.func.id in ('QFontMetrics', 'QFontMetricsF'):
+ if (
+ isinstance(_node.value, ast.Call)
+ and isinstance(_node.value.func, ast.Name)
+ and _node.value.func.id in ("QFontMetrics", "QFontMetricsF")
+ ):
object_types[_node.targets[0].id] = _node.value.func.id
def visit_call(_node: ast.Call, _parent):
@@ -208,161 +215,202 @@ def visit_call(_node: ast.Call, _parent):
if _node.func.attr in rename_function_attributes:
attr_node = _node.func
member_renames[
- Offset(_node.func.lineno, attr_node.end_col_offset - len(
- _node.func.attr) - 1)] = rename_function_attributes[
- _node.func.attr]
- if _node.func.attr == 'addAction':
+ Offset(
+ _node.func.lineno,
+ attr_node.end_col_offset - len(_node.func.attr) - 1,
+ )
+ ] = rename_function_attributes[_node.func.attr]
+ if _node.func.attr == "addAction":
if len(_node.args) >= 4:
sys.stderr.write(
- f'{filename}:{_node.lineno}:{_node.col_offset} WARNING: fragile call to addAction. Use my_action = QAction(...), obj.addAction(my_action) instead.\n')
- if _node.func.attr == 'desktop':
+ f"{filename}:{_node.lineno}:{_node.col_offset} WARNING: fragile call to addAction. Use my_action = QAction(...), obj.addAction(my_action) instead.\n"
+ )
+ if _node.func.attr == "desktop":
if len(_node.args) == 0:
sys.stderr.write(
- f'{filename}:{_node.lineno}:{_node.col_offset} WARNING: QDesktopWidget is deprecated and removed in Qt6. Replace with alternative approach instead.\n')
+ f"{filename}:{_node.lineno}:{_node.col_offset} WARNING: QDesktopWidget is deprecated and removed in Qt6. Replace with alternative approach instead.\n"
+ )
- if isinstance(_node.func, ast.Name) and _node.func.id == 'QVariant':
+ if isinstance(_node.func, ast.Name) and _node.func.id == "QVariant":
if not _node.args:
- extra_imports['qgis.core'].update({'NULL'})
+ extra_imports["qgis.core"].update({"NULL"})
def _invalid_qvariant_to_null(start_index: int, tokens):
- assert tokens[start_index].src == 'QVariant'
- assert tokens[start_index + 1].src == '('
- assert tokens[start_index + 2].src == ')'
+ assert tokens[start_index].src == "QVariant"
+ assert tokens[start_index + 1].src == "("
+ assert tokens[start_index + 2].src == ")"
- tokens[start_index] = tokens[start_index]._replace(src='NULL')
+ tokens[start_index] = tokens[start_index]._replace(src="NULL")
for i in range(start_index + 1, start_index + 3):
- tokens[i] = tokens[i]._replace(src='')
-
- custom_updates[Offset(_node.lineno,
- _node.col_offset)] = _invalid_qvariant_to_null
- elif len(_node.args) == 1 and isinstance(_node.args[0], ast.Attribute) and isinstance(_node.args[0].value, ast.Name) and _node.args[0].value.id == 'QVariant':
- extra_imports['qgis.core'].update({'NULL'})
+ tokens[i] = tokens[i]._replace(src="")
+
+ custom_updates[Offset(_node.lineno, _node.col_offset)] = (
+ _invalid_qvariant_to_null
+ )
+ elif (
+ len(_node.args) == 1
+ and isinstance(_node.args[0], ast.Attribute)
+ and isinstance(_node.args[0].value, ast.Name)
+ and _node.args[0].value.id == "QVariant"
+ ):
+ extra_imports["qgis.core"].update({"NULL"})
def _fix_null_qvariant(start_index: int, tokens):
- assert tokens[start_index].src == 'QVariant'
- assert tokens[start_index + 1].src == '('
- assert tokens[start_index + 2].src == 'QVariant'
- assert tokens[start_index + 3].src == '.'
- assert tokens[start_index + 5].src == ')'
+ assert tokens[start_index].src == "QVariant"
+ assert tokens[start_index + 1].src == "("
+ assert tokens[start_index + 2].src == "QVariant"
+ assert tokens[start_index + 3].src == "."
+ assert tokens[start_index + 5].src == ")"
- tokens[start_index] = tokens[start_index]._replace(src='NULL')
+ tokens[start_index] = tokens[start_index]._replace(src="NULL")
for i in range(start_index + 1, start_index + 6):
- tokens[i] = tokens[i]._replace(src='')
+ tokens[i] = tokens[i]._replace(src="")
- custom_updates[Offset(_node.lineno,
- _node.col_offset)] = _fix_null_qvariant
- elif isinstance(_node.func, ast.Name) and _node.func.id == 'QDateTime':
+ custom_updates[Offset(_node.lineno, _node.col_offset)] = (
+ _fix_null_qvariant
+ )
+ elif isinstance(_node.func, ast.Name) and _node.func.id == "QDateTime":
if len(_node.args) == 8:
# QDateTime(yyyy, mm, dd, hh, MM, ss, ms, ts) doesn't work anymore,
# so port to more reliable QDateTime(QDate, QTime, ts) form
- extra_imports['qgis.PyQt.QtCore'].update({'QDate', 'QTime'})
+ extra_imports["qgis.PyQt.QtCore"].update({"QDate", "QTime"})
def _fix_qdatetime_construct(start_index: int, tokens):
i = start_index + 1
- assert tokens[i].src == '('
- tokens[i] = tokens[i]._replace(src='(QDate(')
- while tokens[i].offset < Offset(_node.args[2].lineno, _node.args[2].col_offset):
+ assert tokens[i].src == "("
+ tokens[i] = tokens[i]._replace(src="(QDate(")
+ while tokens[i].offset < Offset(
+ _node.args[2].lineno, _node.args[2].col_offset
+ ):
i += 1
- assert tokens[i + 1].src == ','
+ assert tokens[i + 1].src == ","
i += 1
- tokens[i] = tokens[i]._replace(src='), QTime(')
+ tokens[i] = tokens[i]._replace(src="), QTime(")
i += 1
while not tokens[i].src.strip():
- tokens[i] = tokens[i]._replace(src='')
+ tokens[i] = tokens[i]._replace(src="")
i += 1
- while tokens[i].offset < Offset(_node.args[6].lineno, _node.args[6].col_offset):
+ while tokens[i].offset < Offset(
+ _node.args[6].lineno, _node.args[6].col_offset
+ ):
i += 1
i += 1
- assert tokens[i].src == ','
- tokens[i] = tokens[i]._replace(src='),')
-
- custom_updates[Offset(_node.lineno, _node.col_offset)] = _fix_qdatetime_construct
- elif len(_node.args) == 1 and isinstance(_node.args[0], ast.Call) and _node.args[0].func.id == 'QDate':
+ assert tokens[i].src == ","
+ tokens[i] = tokens[i]._replace(src="),")
+
+ custom_updates[Offset(_node.lineno, _node.col_offset)] = (
+ _fix_qdatetime_construct
+ )
+ elif (
+ len(_node.args) == 1
+ and isinstance(_node.args[0], ast.Call)
+ and _node.args[0].func.id == "QDate"
+ ):
# QDateTime(QDate(..)) doesn't work anymore,
# so port to more reliable QDateTime(QDate(...), QTime(0,0,0)) form
- extra_imports['qgis.PyQt.QtCore'].update({'QTime'})
+ extra_imports["qgis.PyQt.QtCore"].update({"QTime"})
def _fix_qdatetime_construct(start_index: int, tokens):
- assert tokens[start_index].src == 'QDateTime'
- assert tokens[start_index + 1].src == '('
- assert tokens[start_index + 2].src == 'QDate'
- assert tokens[start_index + 3].src == '('
+ assert tokens[start_index].src == "QDateTime"
+ assert tokens[start_index + 1].src == "("
+ assert tokens[start_index + 2].src == "QDate"
+ assert tokens[start_index + 3].src == "("
i = start_index + 4
- while tokens[i].offset < Offset(_node.args[0].end_lineno,
- _node.args[0].end_col_offset):
+ while tokens[i].offset < Offset(
+ _node.args[0].end_lineno, _node.args[0].end_col_offset
+ ):
i += 1
- assert tokens[i - 1].src == ')'
- tokens[i - 1] = tokens[i - 1]._replace(src='), QTime(0, 0, 0)')
+ assert tokens[i - 1].src == ")"
+ tokens[i - 1] = tokens[i - 1]._replace(src="), QTime(0, 0, 0)")
- custom_updates[Offset(_node.lineno,
- _node.col_offset)] = _fix_qdatetime_construct
+ custom_updates[Offset(_node.lineno, _node.col_offset)] = (
+ _fix_qdatetime_construct
+ )
def visit_attribute(_node: ast.Attribute, _parent):
if isinstance(_node.value, ast.Name):
- if _node.value.id == 'qApp':
- token_renames[Offset(_node.value.lineno, _node.value.col_offset)] = 'QApplication.instance()'
- extra_imports['qgis.PyQt.QtWidgets'].update({'QApplication'})
- removed_imports['qgis.PyQt.QtWidgets'].update({'qApp'})
- if _node.value.id == 'QVariant' and _node.attr == 'Type':
+ if _node.value.id == "qApp":
+ token_renames[Offset(_node.value.lineno, _node.value.col_offset)] = (
+ "QApplication.instance()"
+ )
+ extra_imports["qgis.PyQt.QtWidgets"].update({"QApplication"})
+ removed_imports["qgis.PyQt.QtWidgets"].update({"qApp"})
+ if _node.value.id == "QVariant" and _node.attr == "Type":
+
def _replace_qvariant_type(start_index: int, tokens):
# QVariant.Type.XXX doesn't exist, it should be QVariant.XXX
- assert tokens[start_index].src == 'QVariant'
- assert tokens[start_index + 1].src == '.'
- assert tokens[start_index + 2].src == 'Type'
- assert tokens[start_index + 3].src == '.'
-
- tokens[start_index + 2] = tokens[start_index + 2]._replace(src='')
- tokens[start_index + 3] = tokens[start_index + 3]._replace(
- src='')
-
- custom_updates[Offset(node.lineno, node.col_offset)] = _replace_qvariant_type
- if object_types.get(_node.value.id) in ('QFontMetrics', 'QFontMetricsF'):
- if _node.attr == 'width':
+ assert tokens[start_index].src == "QVariant"
+ assert tokens[start_index + 1].src == "."
+ assert tokens[start_index + 2].src == "Type"
+ assert tokens[start_index + 3].src == "."
+
+ tokens[start_index + 2] = tokens[start_index + 2]._replace(src="")
+ tokens[start_index + 3] = tokens[start_index + 3]._replace(src="")
+
+ custom_updates[Offset(node.lineno, node.col_offset)] = (
+ _replace_qvariant_type
+ )
+ if object_types.get(_node.value.id) in ("QFontMetrics", "QFontMetricsF"):
+ if _node.attr == "width":
sys.stderr.write(
- f'{filename}:{_node.lineno}:{_node.col_offset} WARNING: QFontMetrics.width() '
- 'has been removed in Qt6. Use QFontMetrics.horizontalAdvance() if plugin can '
- 'safely require Qt >= 5.11, or QFontMetrics.boundingRect().width() otherwise.\n')
+ f"{filename}:{_node.lineno}:{_node.col_offset} WARNING: QFontMetrics.width() "
+ "has been removed in Qt6. Use QFontMetrics.horizontalAdvance() if plugin can "
+ "safely require Qt >= 5.11, or QFontMetrics.boundingRect().width() otherwise.\n"
+ )
elif isinstance(_node.value, ast.Call):
- if (_node.attr == 'width' and ((
- isinstance(_node.value.func, ast.Attribute) and
- _node.value.func.attr == 'fontMetrics')
- or (isinstance(_node.value.func, ast.Name) and
- _node.value.func.id == 'QFontMetrics'))):
+ if _node.attr == "width" and (
+ (
+ isinstance(_node.value.func, ast.Attribute)
+ and _node.value.func.attr == "fontMetrics"
+ )
+ or (
+ isinstance(_node.value.func, ast.Name)
+ and _node.value.func.id == "QFontMetrics"
+ )
+ ):
sys.stderr.write(
- f'{filename}:{_node.lineno}:{_node.col_offset} WARNING: QFontMetrics.width() '
- 'has been removed in Qt6. Use QFontMetrics.horizontalAdvance() if plugin can '
- 'safely require Qt >= 5.11, or QFontMetrics.boundingRect().width() otherwise.\n')
+ f"{filename}:{_node.lineno}:{_node.col_offset} WARNING: QFontMetrics.width() "
+ "has been removed in Qt6. Use QFontMetrics.horizontalAdvance() if plugin can "
+ "safely require Qt >= 5.11, or QFontMetrics.boundingRect().width() otherwise.\n"
+ )
def visit_subscript(_node: ast.Subscript, _parent):
if isinstance(_node.value, ast.Attribute):
- if (_node.value.attr == 'activated' and
- isinstance(_node.slice, ast.Name) and
- _node.slice.id == 'str'):
+ if (
+ _node.value.attr == "activated"
+ and isinstance(_node.slice, ast.Name)
+ and _node.slice.id == "str"
+ ):
sys.stderr.write(
- f'{filename}:{_node.lineno}:{_node.col_offset} WARNING: activated[str] '
- 'has been removed in Qt6. Consider using QComboBox.activated instead if the string is not required, '
- 'or QComboBox.textActivated if the plugin can '
- 'safely require Qt >= 5.14. Otherwise conditional Qt version code will need to be introduced.\n')
+ f"{filename}:{_node.lineno}:{_node.col_offset} WARNING: activated[str] "
+ "has been removed in Qt6. Consider using QComboBox.activated instead if the string is not required, "
+ "or QComboBox.textActivated if the plugin can "
+ "safely require Qt >= 5.14. Otherwise conditional Qt version code will need to be introduced.\n"
+ )
def visit_import(_node: ast.ImportFrom, _parent):
import_offsets[Offset(node.lineno, node.col_offset)] = (
- node.module, set(name.name for name in node.names), node.end_lineno,
- node.end_col_offset)
+ node.module,
+ {name.name for name in node.names},
+ node.end_lineno,
+ node.end_col_offset,
+ )
imported_modules.add(node.module)
for name in node.names:
if name.name in import_warnings:
- print(f'{filename}: {import_warnings[name.name]}')
- if name.name == 'resources_rc':
+ print(f"{filename}: {import_warnings[name.name]}")
+ if name.name == "resources_rc":
sys.stderr.write(
- f'{filename}:{_node.lineno}:{_node.col_offset} WARNING: support for compiled resources '
- 'is removed in Qt6. Directly load icon resources by file path and load UI fields using '
- 'uic.loadUiType by file path instead.\n')
- if _node.module == 'qgis.PyQt.Qt':
- extra_imports['qgis.PyQt.QtCore'].update({'Qt'})
- removed_imports['qgis.PyQt.Qt'].update({'Qt'})
+ f"{filename}:{_node.lineno}:{_node.col_offset} WARNING: support for compiled resources "
+ "is removed in Qt6. Directly load icon resources by file path and load UI fields using "
+ "uic.loadUiType by file path instead.\n"
+ )
+ if _node.module == "qgis.PyQt.Qt":
+ extra_imports["qgis.PyQt.QtCore"].update({"Qt"})
+ removed_imports["qgis.PyQt.Qt"].update({"Qt"})
tree = ast.parse(contents, filename=filename)
for parent in ast.walk(tree):
@@ -370,8 +418,12 @@ def visit_import(_node: ast.ImportFrom, _parent):
if isinstance(node, ast.ImportFrom):
visit_import(node, parent)
- if (not qgis3_compat and isinstance(node, ast.Attribute) and isinstance(node.value, ast.Name)
- and node.value.id == "QVariant"):
+ if (
+ not qgis3_compat
+ and isinstance(node, ast.Attribute)
+ and isinstance(node.value, ast.Name)
+ and node.value.id == "QVariant"
+ ):
fix_qvariant_type.append(Offset(node.lineno, node.col_offset))
if isinstance(node, ast.Call):
@@ -383,15 +435,22 @@ def visit_import(_node: ast.ImportFrom, _parent):
elif isinstance(node, ast.Assign):
visit_assign(node, parent)
- if isinstance(node, ast.FunctionDef) and node.name in rename_function_definitions:
- function_def_renames[
- Offset(node.lineno, node.col_offset)] = rename_function_definitions[node.name]
-
- if (isinstance(node, ast.Attribute) and isinstance(node.value, ast.Name)
- and (node.value.id, node.attr) in ambiguous_enums):
+ if (
+ isinstance(node, ast.FunctionDef)
+ and node.name in rename_function_definitions
+ ):
+ function_def_renames[Offset(node.lineno, node.col_offset)] = (
+ rename_function_definitions[node.name]
+ )
+
+ if (
+ isinstance(node, ast.Attribute)
+ and isinstance(node.value, ast.Name)
+ and (node.value.id, node.attr) in ambiguous_enums
+ ):
disambiguated = False
try:
- actual = eval(f'{node.value.id}.{node.attr}')
+ actual = eval(f"{node.value.id}.{node.attr}")
obj = globals()[node.value.id]
if isinstance(obj, type):
for attr_name in dir(obj):
@@ -399,9 +458,10 @@ def visit_import(_node: ast.ImportFrom, _parent):
if attr is actual.__class__:
# print(f'Found alias {node.value.id}.{attr_name}')
disambiguated = True
- fix_qt_enums[
- Offset(node.lineno, node.col_offset)] = (
- node.value.id, attr_name, node.attr
+ fix_qt_enums[Offset(node.lineno, node.col_offset)] = (
+ node.value.id,
+ attr_name,
+ node.attr,
)
break
@@ -409,37 +469,59 @@ def visit_import(_node: ast.ImportFrom, _parent):
pass
if not disambiguated:
- possible_values = [f'{node.value.id}.{e}.{node.attr}' for e
- in ambiguous_enums[
- (node.value.id, node.attr)]]
- sys.stderr.write(f'{filename}:{node.lineno}:{node.col_offset} WARNING: ambiguous enum, cannot fix: {node.value.id}.{node.attr}. Could be: {", ".join(possible_values)}\n')
- elif (isinstance(node, ast.Attribute) and isinstance(node.value, ast.Name) and not isinstance(parent, ast.Attribute)
- and (node.value.id, node.attr) in qt_enums):
- fix_qt_enums[Offset(node.lineno, node.col_offset)] = (node.value.id, qt_enums[(node.value.id, node.attr)], node.attr)
-
- if (isinstance(node, ast.Attribute) and isinstance(node.value, ast.Name)
- and (node.value.id, node.attr) in deprecated_renamed_enums):
+ possible_values = [
+ f"{node.value.id}.{e}.{node.attr}"
+ for e in ambiguous_enums[(node.value.id, node.attr)]
+ ]
+ sys.stderr.write(
+ f'{filename}:{node.lineno}:{node.col_offset} WARNING: ambiguous enum, cannot fix: {node.value.id}.{node.attr}. Could be: {", ".join(possible_values)}\n'
+ )
+ elif (
+ isinstance(node, ast.Attribute)
+ and isinstance(node.value, ast.Name)
+ and not isinstance(parent, ast.Attribute)
+ and (node.value.id, node.attr) in qt_enums
+ ):
+ fix_qt_enums[Offset(node.lineno, node.col_offset)] = (
+ node.value.id,
+ qt_enums[(node.value.id, node.attr)],
+ node.attr,
+ )
+
+ if (
+ isinstance(node, ast.Attribute)
+ and isinstance(node.value, ast.Name)
+ and (node.value.id, node.attr) in deprecated_renamed_enums
+ ):
rename_qt_enums.append(Offset(node.lineno, node.col_offset))
- elif (isinstance(node, ast.ImportFrom) and node.module and node.module.startswith("PyQt5.")):
+ elif (
+ isinstance(node, ast.ImportFrom)
+ and node.module
+ and node.module.startswith("PyQt5.")
+ ):
fix_pyqt_import.append(Offset(node.lineno, node.col_offset))
for module, classes in extra_imports.items():
if module not in imported_modules:
- class_import = ', '.join(classes)
- import_statement = f'from {module} import {class_import}'
- print(f'{filename}: Missing import, manually add \n\t{import_statement}')
-
- if not any([fix_qvariant_type,
- fix_pyqt_import,
- fix_qt_enums,
- rename_qt_enums,
- member_renames,
- function_def_renames,
- custom_updates,
- extra_imports,
- removed_imports,
- token_renames]):
+ class_import = ", ".join(classes)
+ import_statement = f"from {module} import {class_import}"
+ print(f"{filename}: Missing import, manually add \n\t{import_statement}")
+
+ if not any(
+ [
+ fix_qvariant_type,
+ fix_pyqt_import,
+ fix_qt_enums,
+ rename_qt_enums,
+ member_renames,
+ function_def_renames,
+ custom_updates,
+ extra_imports,
+ removed_imports,
+ token_renames,
+ ]
+ ):
return 0
tokens = src_to_tokens(contents)
@@ -447,12 +529,12 @@ def visit_import(_node: ast.ImportFrom, _parent):
if token.offset in import_offsets:
end_import_offset = Offset(*import_offsets[token.offset][-2:])
del import_offsets[token.offset]
- assert tokens[i].src == 'from'
+ assert tokens[i].src == "from"
token_index = i + 1
while not tokens[token_index].src.strip():
token_index += 1
- module = ''
+ module = ""
while tokens[token_index].src.strip():
module += tokens[token_index].src
token_index += 1
@@ -463,17 +545,18 @@ def visit_import(_node: ast.ImportFrom, _parent):
token_index += 1
if tokens[token_index].offset == end_import_offset:
break
- if tokens[token_index].src.strip() in ('', ',', 'import', '(', ')'):
+ if tokens[token_index].src.strip() in ("", ",", "import", "(", ")"):
continue
import_ = tokens[token_index].src
if import_ in removed_imports.get(module, set()):
- tokens[token_index] = tokens[token_index]._replace(src='')
+ tokens[token_index] = tokens[token_index]._replace(src="")
prev_token_index = token_index - 1
while True:
- if tokens[prev_token_index].src.strip() in ('', ','):
+ if tokens[prev_token_index].src.strip() in ("", ","):
tokens[prev_token_index] = tokens[
- prev_token_index]._replace(src='')
+ prev_token_index
+ ]._replace(src="")
prev_token_index -= 1
else:
break
@@ -481,7 +564,7 @@ def visit_import(_node: ast.ImportFrom, _parent):
none_forward = True
current_index = prev_token_index + 1
while True:
- if tokens[current_index].src in ('\n', ')'):
+ if tokens[current_index].src in ("\n", ")"):
break
elif tokens[current_index].src.strip():
none_forward = False
@@ -491,7 +574,7 @@ def visit_import(_node: ast.ImportFrom, _parent):
none_backward = True
current_index = prev_token_index
while True:
- if tokens[current_index].src in ('import',):
+ if tokens[current_index].src in ("import",):
break
elif tokens[current_index].src.strip():
none_backward = False
@@ -500,16 +583,19 @@ def visit_import(_node: ast.ImportFrom, _parent):
if none_backward and none_forward:
# no more imports from this module, remove whole import
while True:
- if tokens[current_index].src in ('from',):
+ if tokens[current_index].src in ("from",):
break
current_index -= 1
while True:
- if tokens[current_index].src in ('\n',):
+ if tokens[current_index].src in ("\n",):
tokens[current_index] = tokens[
- current_index]._replace(src='')
+ current_index
+ ]._replace(src="")
break
- tokens[current_index] = tokens[current_index]._replace(src='')
+ tokens[current_index] = tokens[current_index]._replace(
+ src=""
+ )
current_index += 1
else:
@@ -517,16 +603,19 @@ def visit_import(_node: ast.ImportFrom, _parent):
imports_to_add = extra_imports.get(module, set()) - current_imports
if imports_to_add:
- additional_import_string = ', '.join(imports_to_add)
- if tokens[token_index - 1].src == ')':
+ additional_import_string = ", ".join(imports_to_add)
+ if tokens[token_index - 1].src == ")":
token_index -= 1
- while tokens[token_index].src.strip() in ('', ',', ')'):
- tokens[token_index] = tokens[token_index]._replace(
- src='')
+ while tokens[token_index].src.strip() in ("", ",", ")"):
+ tokens[token_index] = tokens[token_index]._replace(src="")
token_index -= 1
- tokens[token_index + 1] = tokens[token_index + 1]._replace(src=f", {additional_import_string})")
+ tokens[token_index + 1] = tokens[token_index + 1]._replace(
+ src=f", {additional_import_string})"
+ )
else:
- tokens[token_index] = tokens[token_index]._replace(src=f", {additional_import_string}{tokens[token_index].src}")
+ tokens[token_index] = tokens[token_index]._replace(
+ src=f", {additional_import_string}{tokens[token_index].src}"
+ )
if token.offset in fix_qvariant_type:
assert tokens[i].src == "QVariant"
@@ -544,29 +633,34 @@ def visit_import(_node: ast.ImportFrom, _parent):
tokens[i + 2] = tokens[i + 2]._replace(src="qgis.PyQt")
if token.offset in function_def_renames and tokens[i].src == "def":
- tokens[i + 2] = tokens[i + 2]._replace(src=function_def_renames[token.offset])
+ tokens[i + 2] = tokens[i + 2]._replace(
+ src=function_def_renames[token.offset]
+ )
if token.offset in token_renames:
tokens[i] = tokens[i]._replace(src=token_renames[token.offset])
if token.offset in member_renames:
counter = i
- while tokens[counter].src != '.':
+ while tokens[counter].src != ".":
counter += 1
- tokens[counter + 1] = tokens[counter + 1]._replace(src=member_renames[token.offset])
+ tokens[counter + 1] = tokens[counter + 1]._replace(
+ src=member_renames[token.offset]
+ )
if token.offset in fix_qt_enums:
assert tokens[i + 1].src == "."
_class, enum_name, value = fix_qt_enums[token.offset]
# make sure we CAN import enum!
try:
- eval(f'{_class}.{enum_name}.{value}')
+ eval(f"{_class}.{enum_name}.{value}")
tokens[i + 2] = tokens[i + 2]._replace(
- src=f"{enum_name}.{tokens[i + 2].src}")
+ src=f"{enum_name}.{tokens[i + 2].src}"
+ )
except AttributeError:
# let's see if we can find what the replacement should be automatically...
# print(f'Trying to find {_class}.{value}.')
- actual = eval(f'{_class}.{value}')
+ actual = eval(f"{_class}.{value}")
# print(f'Trying to find aliases for {actual.__class__}.')
obj = globals()[_class]
recovered = False
@@ -578,13 +672,15 @@ def visit_import(_node: ast.ImportFrom, _parent):
# print(f'Found alias {_class}.{attr_name}')
recovered = True
tokens[i + 2] = tokens[i + 2]._replace(
- src=f"{attr_name}.{tokens[i + 2].src}")
+ src=f"{attr_name}.{tokens[i + 2].src}"
+ )
except AttributeError:
continue
if not recovered:
sys.stderr.write(
- f'{filename}:{token.line}:{token.utf8_byte_offset} ERROR: wanted to replace with {_class}.{enum_name}.{value}, but does not exist\n')
+ f"{filename}:{token.line}:{token.utf8_byte_offset} ERROR: wanted to replace with {_class}.{enum_name}.{value}, but does not exist\n"
+ )
continue
if token.offset in rename_qt_enums:
@@ -594,7 +690,7 @@ def visit_import(_node: ast.ImportFrom, _parent):
tokens[i + 2] = tokens[i + 2]._replace(src=f"{enum_name[0]}.{enum_name[1]}")
new_contents = tokens_to_src(tokens)
- with open(filename, 'w') as f:
+ with open(filename, "w") as f:
f.write(new_contents)
return new_contents != contents
@@ -609,16 +705,16 @@ def get_class_enums(item):
def all_subclasses(cls):
if cls is object:
return set()
- return {cls}.union(
- s for c in cls.__subclasses__() for s in all_subclasses(c))
+ return {cls}.union(s for c in cls.__subclasses__() for s in all_subclasses(c))
+
matched_classes = {item}.union(all_subclasses(item))
for key, value in item.__dict__.items():
- if key == 'baseClass':
+ if key == "baseClass":
continue
- if inspect.isclass(value) and type(value).__name__ == 'EnumType':
+ if inspect.isclass(value) and type(value).__name__ == "EnumType":
for ekey, evalue in value.__dict__.items():
for matched_class in matched_classes:
if isinstance(evalue, value):
@@ -634,18 +730,28 @@ def all_subclasses(cls):
pass
if (matched_class.__name__, ekey) in ambiguous_enums:
- if value.__name__ not in ambiguous_enums[(matched_class.__name__, ekey)]:
- ambiguous_enums[(matched_class.__name__, ekey)].add(value.__name__)
+ if (
+ value.__name__
+ not in ambiguous_enums[(matched_class.__name__, ekey)]
+ ):
+ ambiguous_enums[(matched_class.__name__, ekey)].add(
+ value.__name__
+ )
continue
existing_entry = qt_enums.get((matched_class.__name__, ekey))
if existing_entry != value.__name__ and existing_entry:
- ambiguous_enums[(matched_class.__name__, ekey)].add(existing_entry)
ambiguous_enums[(matched_class.__name__, ekey)].add(
- value.__name__)
+ existing_entry
+ )
+ ambiguous_enums[(matched_class.__name__, ekey)].add(
+ value.__name__
+ )
del qt_enums[(matched_class.__name__, ekey)]
else:
- qt_enums[(matched_class.__name__, ekey)] = f"{value.__name__}"
+ qt_enums[(matched_class.__name__, ekey)] = (
+ f"{value.__name__}"
+ )
elif inspect.isclass(value):
get_class_enums(value)
@@ -653,9 +759,12 @@ def all_subclasses(cls):
def main(argv: Sequence[str] | None = None) -> int:
parser = argparse.ArgumentParser()
- parser.add_argument('directory')
- parser.add_argument('--qgis3-incompatible-changes', action='store_true',
- help='Apply modifications that would break behavior on QGIS 3, hence code may not work on QGIS 3')
+ parser.add_argument("directory")
+ parser.add_argument(
+ "--qgis3-incompatible-changes",
+ action="store_true",
+ help="Apply modifications that would break behavior on QGIS 3, hence code may not work on QGIS 3",
+ )
args = parser.parse_args(argv)
# get all scope for all qt enum
@@ -666,12 +775,12 @@ def main(argv: Sequence[str] | None = None) -> int:
ret = 0
for filename in glob.glob(os.path.join(args.directory, "**/*.py"), recursive=True):
# print(f'Processing {filename}')
- if 'auto_additions' in filename:
+ if "auto_additions" in filename:
continue
ret |= fix_file(filename, not args.qgis3_incompatible_changes)
return ret
-if __name__ == '__main__':
+if __name__ == "__main__":
raise SystemExit(main())
diff --git a/scripts/pyuic_wrapper.py b/scripts/pyuic_wrapper.py
index d0f9ee92b0a1..d9963570e985 100644
--- a/scripts/pyuic_wrapper.py
+++ b/scripts/pyuic_wrapper.py
@@ -15,8 +15,8 @@
***************************************************************************
"""
-__author__ = 'Juergen E. Fischer'
-__date__ = 'March 2016'
-__copyright__ = '(C) 2016, Juergen E. Fischer'
+__author__ = "Juergen E. Fischer"
+__date__ = "March 2016"
+__copyright__ = "(C) 2016, Juergen E. Fischer"
import qgis.PyQt.uic.pyuic
diff --git a/scripts/qgis_fixes/fix_absolute_import.py b/scripts/qgis_fixes/fix_absolute_import.py
index 86869f5a365e..d7434a808229 100644
--- a/scripts/qgis_fixes/fix_absolute_import.py
+++ b/scripts/qgis_fixes/fix_absolute_import.py
@@ -1,4 +1,6 @@
-from libfuturize.fixes.fix_absolute_import import FixAbsoluteImport as FixAbsoluteImportOrig
+from libfuturize.fixes.fix_absolute_import import (
+ FixAbsoluteImport as FixAbsoluteImportOrig,
+)
class FixAbsoluteImport(FixAbsoluteImportOrig):
diff --git a/scripts/qgis_fixes/fix_future_standard_library_urllib.py b/scripts/qgis_fixes/fix_future_standard_library_urllib.py
index cf3cfdc37938..25fd963f226d 100644
--- a/scripts/qgis_fixes/fix_future_standard_library_urllib.py
+++ b/scripts/qgis_fixes/fix_future_standard_library_urllib.py
@@ -1 +1,3 @@
-from libfuturize.fixes.fix_future_standard_library_urllib import FixFutureStandardLibraryUrllib
+from libfuturize.fixes.fix_future_standard_library_urllib import (
+ FixFutureStandardLibraryUrllib,
+)
diff --git a/scripts/qgis_fixes/fix_print_with_import.py b/scripts/qgis_fixes/fix_print_with_import.py
index 1821829762a2..3e8451431eee 100644
--- a/scripts/qgis_fixes/fix_print_with_import.py
+++ b/scripts/qgis_fixes/fix_print_with_import.py
@@ -1,8 +1,11 @@
-from libfuturize.fixes.fix_print_with_import import FixPrintWithImport as FixPrintWithImportOrig
-from lib2to3.fixer_util import Node, Leaf, syms, find_indentation
-
import re
+from lib2to3.fixer_util import Leaf, Node, find_indentation, syms
+
+from libfuturize.fixes.fix_print_with_import import (
+ FixPrintWithImport as FixPrintWithImportOrig,
+)
+
class FixPrintWithImport(FixPrintWithImportOrig):
@@ -19,6 +22,6 @@ def transform(self, node, results):
indentation = find_indentation(node)
r.prefix = "# fix_print_with_import\n" + indentation
else:
- r.prefix = re.sub('([ \t]*$)', r'\1# fix_print_with_import\n\1', r.prefix)
+ r.prefix = re.sub("([ \t]*$)", r"\1# fix_print_with_import\n\1", r.prefix)
return r
diff --git a/scripts/qgis_fixes/fix_pyqt.py b/scripts/qgis_fixes/fix_pyqt.py
index 54b306ce4e3d..1696c6cbd681 100644
--- a/scripts/qgis_fixes/fix_pyqt.py
+++ b/scripts/qgis_fixes/fix_pyqt.py
@@ -1,391 +1,422 @@
"""Migrate imports of PyQt4 to PyQt wrapper
"""
+
# Author: Juergen E. Fischer
# Adapted from fix_urllib
-# Local imports
-from lib2to3.fixes.fix_imports import alternates, FixImports
from lib2to3 import fixer_base
-from lib2to3.fixer_util import (Name, Comma, FromImport, Newline,
- find_indentation, Node, syms, Leaf)
+from lib2to3.fixer_util import (
+ Comma,
+ FromImport,
+ Leaf,
+ Name,
+ Newline,
+ Node,
+ find_indentation,
+ syms,
+)
+
+# Local imports
+from lib2to3.fixes.fix_imports import FixImports, alternates
MAPPING = {
"PyQt4.QtGui": [
- ("qgis.PyQt.QtGui", [
- "QIcon",
- "QCursor",
- "QColor",
- "QDesktopServices",
- "QFont",
- "QFontMetrics",
- "QKeySequence",
- "QStandardItemModel",
- "QStandardItem",
- "QClipboard",
- "QPixmap",
- "QDoubleValidator",
- "QPainter",
- "QPen",
- "QBrush",
- "QPalette",
- "QPainterPath",
- "QImage",
- "QPolygonF",
- "QFontMetricsF",
- "QGradient",
- "QIntValidator",
- ]),
- ("qgis.PyQt.QtWidgets", [
- "QAbstractButton",
- "QAbstractGraphicsShapeItem",
- "QAbstractItemDelegate",
- "QAbstractItemView",
- "QAbstractScrollArea",
- "QAbstractSlider",
- "QAbstractSpinBox",
- "QAbstractTableModel",
- "QAction",
- "QActionGroup",
- "QApplication",
- "QBoxLayout",
- "QButtonGroup",
- "QCalendarWidget",
- "QCheckBox",
- "QColorDialog",
- "QColumnView",
- "QComboBox",
- "QCommandLinkButton",
- "QCommonStyle",
- "QCompleter",
- "QDataWidgetMapper",
- "QDateEdit",
- "QDateTimeEdit",
- "QDesktopWidget",
- "QDial",
- "QDialog",
- "QDialogButtonBox",
- "QDirModel",
- "QDockWidget",
- "QDoubleSpinBox",
- "QErrorMessage",
- "QFileDialog",
- "QFileIconProvider",
- "QFileSystemModel",
- "QFocusFrame",
- "QFontComboBox",
- "QFontDialog",
- "QFormLayout",
- "QFrame",
- "QGesture",
- "QGestureEvent",
- "QGestureRecognizer",
- "QGraphicsAnchor",
- "QGraphicsAnchorLayout",
- "QGraphicsBlurEffect",
- "QGraphicsColorizeEffect",
- "QGraphicsDropShadowEffect",
- "QGraphicsEffect",
- "QGraphicsEllipseItem",
- "QGraphicsGridLayout",
- "QGraphicsItem",
- "QGraphicsItemGroup",
- "QGraphicsLayout",
- "QGraphicsLayoutItem",
- "QGraphicsLineItem",
- "QGraphicsLinearLayout",
- "QGraphicsObject",
- "QGraphicsOpacityEffect",
- "QGraphicsPathItem",
- "QGraphicsPixmapItem",
- "QGraphicsPolygonItem",
- "QGraphicsProxyWidget",
- "QGraphicsRectItem",
- "QGraphicsRotation",
- "QGraphicsScale",
- "QGraphicsScene",
- "QGraphicsSceneContextMenuEvent",
- "QGraphicsSceneDragDropEvent",
- "QGraphicsSceneEvent",
- "QGraphicsSceneHelpEvent",
- "QGraphicsSceneHoverEvent",
- "QGraphicsSceneMouseEvent",
- "QGraphicsSceneMoveEvent",
- "QGraphicsSceneResizeEvent",
- "QGraphicsSceneWheelEvent",
- "QGraphicsSimpleTextItem",
- "QGraphicsTextItem",
- "QGraphicsTransform",
- "QGraphicsView",
- "QGraphicsWidget",
- "QGridLayout",
- "QGroupBox",
- "QHBoxLayout",
- "QHeaderView",
- "QInputDialog",
- "QItemDelegate",
- "QItemEditorCreatorBase",
- "QItemEditorFactory",
- "QKeyEventTransition",
- "QLCDNumber",
- "QLabel",
- "QLayout",
- "QLayoutItem",
- "QLineEdit",
- "QListView",
- "QListWidget",
- "QListWidgetItem",
- "QMainWindow",
- "QMdiArea",
- "QMdiSubWindow",
- "QMenu",
- "QMenuBar",
- "QMessageBox",
- "QMouseEventTransition",
- "QPanGesture",
- "QPinchGesture",
- "QPlainTextDocumentLayout",
- "QPlainTextEdit",
- "QProgressBar",
- "QProgressDialog",
- "QPushButton",
- "QRadioButton",
- "QRubberBand",
- "QScrollArea",
- "QScrollBar",
- "QShortcut",
- "QSizeGrip",
- "QSizePolicy",
- "QSlider",
- "QSpacerItem",
- "QSpinBox",
- "QSplashScreen",
- "QSplitter",
- "QSplitterHandle",
- "QStackedLayout",
- "QStackedWidget",
- "QStatusBar",
- "QStyle",
- "QStyleFactory",
- "QStyleHintReturn",
- "QStyleHintReturnMask",
- "QStyleHintReturnVariant",
- "QStyleOption",
- "QStyleOptionButton",
- "QStyleOptionComboBox",
- "QStyleOptionComplex",
- "QStyleOptionDockWidget",
- "QStyleOptionFocusRect",
- "QStyleOptionFrame",
- "QStyleOptionGraphicsItem",
- "QStyleOptionGroupBox",
- "QStyleOptionHeader",
- "QStyleOptionMenuItem",
- "QStyleOptionProgressBar",
- "QStyleOptionRubberBand",
- "QStyleOptionSizeGrip",
- "QStyleOptionSlider",
- "QStyleOptionSpinBox",
- "QStyleOptionTab",
- "QStyleOptionTabBarBase",
- "QStyleOptionTabWidgetFrame",
- "QStyleOptionTitleBar",
- "QStyleOptionToolBar",
- "QStyleOptionToolBox",
- "QStyleOptionToolButton",
- "QStyleOptionViewItem",
- "QStylePainter",
- "QStyledItemDelegate",
- "QSwipeGesture",
- "QSystemTrayIcon",
- "QTabBar",
- "QTabWidget",
- "QTableView",
- "QTableWidget",
- "QTableWidgetItem",
- "QTableWidgetSelectionRange",
- "QTapAndHoldGesture",
- "QTapGesture",
- "QTextBrowser",
- "QTextEdit",
- "QTimeEdit",
- "QToolBar",
- "QToolBox",
- "QToolButton",
- "QToolTip",
- "QTreeView",
- "QTreeWidget",
- "QTreeWidgetItem",
- "QTreeWidgetItemIterator",
- "QUndoCommand",
- "QUndoGroup",
- "QUndoStack",
- "QUndoView",
- "QVBoxLayout",
- "QWhatsThis",
- "QWidget",
- "QWidgetAction",
- "QWidgetItem",
- "QWizard",
- "QWizardPage",
- "qApp",
- "qDrawBorderPixmap",
- "qDrawPlainRect",
- "qDrawShadeLine",
- "qDrawShadePanel",
- "qDrawShadeRect",
- "qDrawWinButton",
- "qDrawWinPanel",
- ]),
- ("qgis.PyQt.QtPrintSupport", [
- "QPrinter",
- "QAbstractPrintDialog",
- "QPageSetupDialog",
- "QPrintDialog",
- "QPrintEngine",
- "QPrintPreviewDialog",
- "QPrintPreviewWidget",
- "QPrinterInfo",
- ]),
- ("qgis.PyQt.QtCore", [
- "QItemSelectionModel",
- "QSortFilterProxyModel",
- ]),
+ (
+ "qgis.PyQt.QtGui",
+ [
+ "QIcon",
+ "QCursor",
+ "QColor",
+ "QDesktopServices",
+ "QFont",
+ "QFontMetrics",
+ "QKeySequence",
+ "QStandardItemModel",
+ "QStandardItem",
+ "QClipboard",
+ "QPixmap",
+ "QDoubleValidator",
+ "QPainter",
+ "QPen",
+ "QBrush",
+ "QPalette",
+ "QPainterPath",
+ "QImage",
+ "QPolygonF",
+ "QFontMetricsF",
+ "QGradient",
+ "QIntValidator",
+ ],
+ ),
+ (
+ "qgis.PyQt.QtWidgets",
+ [
+ "QAbstractButton",
+ "QAbstractGraphicsShapeItem",
+ "QAbstractItemDelegate",
+ "QAbstractItemView",
+ "QAbstractScrollArea",
+ "QAbstractSlider",
+ "QAbstractSpinBox",
+ "QAbstractTableModel",
+ "QAction",
+ "QActionGroup",
+ "QApplication",
+ "QBoxLayout",
+ "QButtonGroup",
+ "QCalendarWidget",
+ "QCheckBox",
+ "QColorDialog",
+ "QColumnView",
+ "QComboBox",
+ "QCommandLinkButton",
+ "QCommonStyle",
+ "QCompleter",
+ "QDataWidgetMapper",
+ "QDateEdit",
+ "QDateTimeEdit",
+ "QDesktopWidget",
+ "QDial",
+ "QDialog",
+ "QDialogButtonBox",
+ "QDirModel",
+ "QDockWidget",
+ "QDoubleSpinBox",
+ "QErrorMessage",
+ "QFileDialog",
+ "QFileIconProvider",
+ "QFileSystemModel",
+ "QFocusFrame",
+ "QFontComboBox",
+ "QFontDialog",
+ "QFormLayout",
+ "QFrame",
+ "QGesture",
+ "QGestureEvent",
+ "QGestureRecognizer",
+ "QGraphicsAnchor",
+ "QGraphicsAnchorLayout",
+ "QGraphicsBlurEffect",
+ "QGraphicsColorizeEffect",
+ "QGraphicsDropShadowEffect",
+ "QGraphicsEffect",
+ "QGraphicsEllipseItem",
+ "QGraphicsGridLayout",
+ "QGraphicsItem",
+ "QGraphicsItemGroup",
+ "QGraphicsLayout",
+ "QGraphicsLayoutItem",
+ "QGraphicsLineItem",
+ "QGraphicsLinearLayout",
+ "QGraphicsObject",
+ "QGraphicsOpacityEffect",
+ "QGraphicsPathItem",
+ "QGraphicsPixmapItem",
+ "QGraphicsPolygonItem",
+ "QGraphicsProxyWidget",
+ "QGraphicsRectItem",
+ "QGraphicsRotation",
+ "QGraphicsScale",
+ "QGraphicsScene",
+ "QGraphicsSceneContextMenuEvent",
+ "QGraphicsSceneDragDropEvent",
+ "QGraphicsSceneEvent",
+ "QGraphicsSceneHelpEvent",
+ "QGraphicsSceneHoverEvent",
+ "QGraphicsSceneMouseEvent",
+ "QGraphicsSceneMoveEvent",
+ "QGraphicsSceneResizeEvent",
+ "QGraphicsSceneWheelEvent",
+ "QGraphicsSimpleTextItem",
+ "QGraphicsTextItem",
+ "QGraphicsTransform",
+ "QGraphicsView",
+ "QGraphicsWidget",
+ "QGridLayout",
+ "QGroupBox",
+ "QHBoxLayout",
+ "QHeaderView",
+ "QInputDialog",
+ "QItemDelegate",
+ "QItemEditorCreatorBase",
+ "QItemEditorFactory",
+ "QKeyEventTransition",
+ "QLCDNumber",
+ "QLabel",
+ "QLayout",
+ "QLayoutItem",
+ "QLineEdit",
+ "QListView",
+ "QListWidget",
+ "QListWidgetItem",
+ "QMainWindow",
+ "QMdiArea",
+ "QMdiSubWindow",
+ "QMenu",
+ "QMenuBar",
+ "QMessageBox",
+ "QMouseEventTransition",
+ "QPanGesture",
+ "QPinchGesture",
+ "QPlainTextDocumentLayout",
+ "QPlainTextEdit",
+ "QProgressBar",
+ "QProgressDialog",
+ "QPushButton",
+ "QRadioButton",
+ "QRubberBand",
+ "QScrollArea",
+ "QScrollBar",
+ "QShortcut",
+ "QSizeGrip",
+ "QSizePolicy",
+ "QSlider",
+ "QSpacerItem",
+ "QSpinBox",
+ "QSplashScreen",
+ "QSplitter",
+ "QSplitterHandle",
+ "QStackedLayout",
+ "QStackedWidget",
+ "QStatusBar",
+ "QStyle",
+ "QStyleFactory",
+ "QStyleHintReturn",
+ "QStyleHintReturnMask",
+ "QStyleHintReturnVariant",
+ "QStyleOption",
+ "QStyleOptionButton",
+ "QStyleOptionComboBox",
+ "QStyleOptionComplex",
+ "QStyleOptionDockWidget",
+ "QStyleOptionFocusRect",
+ "QStyleOptionFrame",
+ "QStyleOptionGraphicsItem",
+ "QStyleOptionGroupBox",
+ "QStyleOptionHeader",
+ "QStyleOptionMenuItem",
+ "QStyleOptionProgressBar",
+ "QStyleOptionRubberBand",
+ "QStyleOptionSizeGrip",
+ "QStyleOptionSlider",
+ "QStyleOptionSpinBox",
+ "QStyleOptionTab",
+ "QStyleOptionTabBarBase",
+ "QStyleOptionTabWidgetFrame",
+ "QStyleOptionTitleBar",
+ "QStyleOptionToolBar",
+ "QStyleOptionToolBox",
+ "QStyleOptionToolButton",
+ "QStyleOptionViewItem",
+ "QStylePainter",
+ "QStyledItemDelegate",
+ "QSwipeGesture",
+ "QSystemTrayIcon",
+ "QTabBar",
+ "QTabWidget",
+ "QTableView",
+ "QTableWidget",
+ "QTableWidgetItem",
+ "QTableWidgetSelectionRange",
+ "QTapAndHoldGesture",
+ "QTapGesture",
+ "QTextBrowser",
+ "QTextEdit",
+ "QTimeEdit",
+ "QToolBar",
+ "QToolBox",
+ "QToolButton",
+ "QToolTip",
+ "QTreeView",
+ "QTreeWidget",
+ "QTreeWidgetItem",
+ "QTreeWidgetItemIterator",
+ "QUndoCommand",
+ "QUndoGroup",
+ "QUndoStack",
+ "QUndoView",
+ "QVBoxLayout",
+ "QWhatsThis",
+ "QWidget",
+ "QWidgetAction",
+ "QWidgetItem",
+ "QWizard",
+ "QWizardPage",
+ "qApp",
+ "qDrawBorderPixmap",
+ "qDrawPlainRect",
+ "qDrawShadeLine",
+ "qDrawShadePanel",
+ "qDrawShadeRect",
+ "qDrawWinButton",
+ "qDrawWinPanel",
+ ],
+ ),
+ (
+ "qgis.PyQt.QtPrintSupport",
+ [
+ "QPrinter",
+ "QAbstractPrintDialog",
+ "QPageSetupDialog",
+ "QPrintDialog",
+ "QPrintEngine",
+ "QPrintPreviewDialog",
+ "QPrintPreviewWidget",
+ "QPrinterInfo",
+ ],
+ ),
+ (
+ "qgis.PyQt.QtCore",
+ [
+ "QItemSelectionModel",
+ "QSortFilterProxyModel",
+ ],
+ ),
],
"PyQt4.QtCore": [
- ("qgis.PyQt.QtCore", [
- "QAbstractItemModel",
- "QAbstractTableModel",
- "QByteArray",
- "QCoreApplication",
- "QDataStream",
- "QDir",
- "QEvent",
- "QFile",
- "QFileInfo",
- "QIODevice",
- "QLocale",
- "QMimeData",
- "QModelIndex",
- "QMutex",
- "QObject",
- "QProcess",
- "QSettings",
- "QSize",
- "QSizeF",
- "QTextCodec",
- "QThread",
- "QThreadPool",
- "QTimer",
- "QTranslator",
- "QUrl",
- "Qt",
- "pyqtProperty",
- "pyqtWrapperType",
- "pyqtSignal",
- "pyqtSlot",
- "qDebug",
- "qWarning",
- "qVersion",
- "QDate",
- "QTime",
- "QDateTime",
- "QRegExp",
- "QTemporaryFile",
- "QTextStream",
- "QVariant",
- "QPyNullVariant",
- "QRect",
- "QRectF",
- "QMetaObject",
- "QPoint",
- "QPointF",
- "QDirIterator",
- "QEventLoop",
- "NULL",
- ]),
- (None, [
- "SIGNAL",
- "SLOT",
- ]),
+ (
+ "qgis.PyQt.QtCore",
+ [
+ "QAbstractItemModel",
+ "QAbstractTableModel",
+ "QByteArray",
+ "QCoreApplication",
+ "QDataStream",
+ "QDir",
+ "QEvent",
+ "QFile",
+ "QFileInfo",
+ "QIODevice",
+ "QLocale",
+ "QMimeData",
+ "QModelIndex",
+ "QMutex",
+ "QObject",
+ "QProcess",
+ "QSettings",
+ "QSize",
+ "QSizeF",
+ "QTextCodec",
+ "QThread",
+ "QThreadPool",
+ "QTimer",
+ "QTranslator",
+ "QUrl",
+ "Qt",
+ "pyqtProperty",
+ "pyqtWrapperType",
+ "pyqtSignal",
+ "pyqtSlot",
+ "qDebug",
+ "qWarning",
+ "qVersion",
+ "QDate",
+ "QTime",
+ "QDateTime",
+ "QRegExp",
+ "QTemporaryFile",
+ "QTextStream",
+ "QVariant",
+ "QPyNullVariant",
+ "QRect",
+ "QRectF",
+ "QMetaObject",
+ "QPoint",
+ "QPointF",
+ "QDirIterator",
+ "QEventLoop",
+ "NULL",
+ ],
+ ),
+ (
+ None,
+ [
+ "SIGNAL",
+ "SLOT",
+ ],
+ ),
],
"PyQt4.QtNetwork": [
- ("qgis.PyQt.QtNetwork", [
- "QNetworkReply",
- "QNetworkRequest",
- "QSslCertificate",
- "QSslKey",
- "QSsl"
- ])
+ (
+ "qgis.PyQt.QtNetwork",
+ ["QNetworkReply", "QNetworkRequest", "QSslCertificate", "QSslKey", "QSsl"],
+ )
],
"PyQt4.QtXml": [
- ("qgis.PyQt.QtXml", [
- "QDomDocument"
- ]),
+ ("qgis.PyQt.QtXml", ["QDomDocument"]),
],
"PyQt4.Qsci": [
- ("qgis.PyQt.Qsci", [
- "QsciAPIs",
- "QsciLexerCustom",
- "QsciLexerPython",
- "QsciScintilla",
- "QsciLexerSQL",
- "QsciStyle",
- ]),
+ (
+ "qgis.PyQt.Qsci",
+ [
+ "QsciAPIs",
+ "QsciLexerCustom",
+ "QsciLexerPython",
+ "QsciScintilla",
+ "QsciLexerSQL",
+ "QsciStyle",
+ ],
+ ),
],
"PyQt4.QtWebKit": [
- ("qgis.PyQt.QtWebKitWidgets", [
- "QGraphicsWebView",
- "QWebFrame",
- "QWebHitTestResult",
- "QWebInspector",
- "QWebPage",
- "QWebView",
- ]),
+ (
+ "qgis.PyQt.QtWebKitWidgets",
+ [
+ "QGraphicsWebView",
+ "QWebFrame",
+ "QWebHitTestResult",
+ "QWebInspector",
+ "QWebPage",
+ "QWebView",
+ ],
+ ),
],
"PyQt4.QtTest": [
- ("qgis.PyQt.QtTest", [
- "QTest",
- ]),
+ (
+ "qgis.PyQt.QtTest",
+ [
+ "QTest",
+ ],
+ ),
],
"PyQt4.QtSvg": [
- ("qgis.PyQt.QtSvg", [
- "QSvgRenderer",
- "QSvgGenerator"
- ]),
+ ("qgis.PyQt.QtSvg", ["QSvgRenderer", "QSvgGenerator"]),
],
"PyQt4.QtSql": [
- ("qgis.PyQt.QtSql", [
- "QSqlDatabase",
- "QSqlQuery",
- "QSqlField"
- ]),
+ ("qgis.PyQt.QtSql", ["QSqlDatabase", "QSqlQuery", "QSqlField"]),
],
"PyQt4.uic": [
- ("qgis.PyQt.uic", [
- "loadUiType",
- "loadUi",
- ]),
+ (
+ "qgis.PyQt.uic",
+ [
+ "loadUiType",
+ "loadUi",
+ ],
+ ),
],
"PyQt4": [
- ("qgis.PyQt", [
- "QtCore",
- "QtGui",
- "QtNetwork",
- "QtXml",
- "QtWebkit",
- "QtSql",
- "QtSvg",
- "Qsci",
- "uic",
- ])
+ (
+ "qgis.PyQt",
+ [
+ "QtCore",
+ "QtGui",
+ "QtNetwork",
+ "QtXml",
+ "QtWebkit",
+ "QtSql",
+ "QtSvg",
+ "Qsci",
+ "uic",
+ ],
+ )
],
}
new_mappings = {}
for key, value in MAPPING.items():
- match_str = key.replace('PyQt4', '')
- match_str = '{}{}'.format('qgis.PyQt', match_str)
+ match_str = key.replace("PyQt4", "")
+ match_str = "{}{}".format("qgis.PyQt", match_str)
new_mappings[match_str] = value
MAPPING.update(new_mappings)
@@ -398,11 +429,11 @@ def build_pattern():
new_module, members = change
members = alternates(members)
- if '.' not in old_module:
+ if "." not in old_module:
from_name = "%r" % old_module
else:
- dotted = old_module.split('.')
+ dotted = old_module.split(".")
if len(dotted) == 3:
from_name = f"dotted_name<{dotted[0]!r} '.' {dotted[1]!r} '.' {dotted[2]!r}>"
else:
@@ -411,15 +442,21 @@ def build_pattern():
yield """import_name< 'import' (module={}
| dotted_as_names< any* module={} any* >) >
- """.format(from_name, from_name)
+ """.format(
+ from_name, from_name
+ )
yield """import_from< 'from' mod_member={} 'import'
( member={} | import_as_name< member={} 'as' any > |
import_as_names< members=any* >) >
- """.format(from_name, members, members)
+ """.format(
+ from_name, members, members
+ )
yield """import_from< 'from' mod_member={} 'import' '('
( member={} | import_as_name< member={} 'as' any > |
import_as_names< members=any* >) ')' >
- """.format(from_name, members, members)
+ """.format(
+ from_name, members, members
+ )
yield """import_from< 'from' module_star=%s 'import' star='*' >
""" % from_name
yield """import_name< 'import'
@@ -427,7 +464,9 @@ def build_pattern():
""" % from_name
# bare_with_attr has a special significance for FixImports.match().
yield """power< bare_with_attr={} trailer< '.' member={} > any* >
- """.format(from_name, members)
+ """.format(
+ from_name, members
+ )
class FixPyqt(FixImports):
@@ -435,15 +474,15 @@ class FixPyqt(FixImports):
def build_pattern(self):
return "|".join(build_pattern())
-# def match(self, node):
-# res = super(FixImports, self).match( node )
-# print repr(node)
-# return res
+ # def match(self, node):
+ # res = super(FixImports, self).match( node )
+ # print repr(node)
+ # return res
def transform_import(self, node, results):
"""Transform for the basic import case. Replaces the old
- import name with a comma separated list of its
- replacements.
+ import name with a comma separated list of its
+ replacements.
"""
import_mod = results.get("module")
pref = import_mod.prefix
@@ -457,12 +496,15 @@ def transform_import(self, node, results):
names.append(Name(MAPPING[import_mod.value][-1][0], prefix=pref))
import_mod.replace(names)
else:
- self.cannot_convert(node, "imports like PyQt4.QtGui or import qgis.PyQt.QtGui are not supported")
+ self.cannot_convert(
+ node,
+ "imports like PyQt4.QtGui or import qgis.PyQt.QtGui are not supported",
+ )
def transform_member(self, node, results):
"""Transform for imports of specific module elements. Replaces
- the module to be imported from with the appropriate new
- module.
+ the module to be imported from with the appropriate new
+ module.
"""
mod_member = results.get("mod_member")
if isinstance(mod_member, Node):
@@ -480,14 +522,14 @@ def transform_member(self, node, results):
# this may be a list of length one, or just a node
if isinstance(member, list):
member = member[0]
- new_name = ''
+ new_name = ""
for change in MAPPING[mod_member.value]:
if member.value in change[1]:
new_name = change[0]
break
if new_name:
mod_member.replace(Name(new_name, prefix=pref))
- elif new_name == '':
+ elif new_name == "":
self.cannot_convert(node, "This is an invalid module element")
else:
node.remove()
@@ -517,7 +559,9 @@ def transform_member(self, node, results):
found = True
if not found:
f = open("/tmp/missing", "a+")
- f.write(f"member {member_name} of {mod_member.value} not found\n")
+ f.write(
+ f"member {member_name} of {mod_member.value} not found\n"
+ )
f.close()
missing = True
@@ -527,9 +571,11 @@ def transform_member(self, node, results):
def handle_name(name, prefix):
if name.type == syms.import_as_name:
- kids = [Name(name.children[0].value, prefix=prefix),
- name.children[1].clone(),
- name.children[2].clone()]
+ kids = [
+ Name(name.children[0].value, prefix=prefix),
+ name.children[1].clone(),
+ name.children[2].clone(),
+ ]
return [Node(syms.import_as_name, kids)]
return [Name(name.value, prefix=prefix)]
@@ -573,8 +619,7 @@ def transform_dot(self, node, results):
new_name = change[0]
break
if new_name:
- module_dot.replace(Name(new_name,
- prefix=module_dot.prefix))
+ module_dot.replace(Name(new_name, prefix=module_dot.prefix))
else:
self.cannot_convert(node, "This is an invalid module element")
diff --git a/scripts/qgis_fixes/fix_qfiledialog.py b/scripts/qgis_fixes/fix_qfiledialog.py
index 762bc79f0cce..c111e694cf5d 100644
--- a/scripts/qgis_fixes/fix_qfiledialog.py
+++ b/scripts/qgis_fixes/fix_qfiledialog.py
@@ -1,6 +1,7 @@
"""
Migrate QFileDialog methods from PyQt4 to PyQt5
"""
+
# Author: Médéric Ribreux
# Adapted from fix_pyqt
# and http://python3porting.com/fixers.html
@@ -23,8 +24,8 @@ def transform(self, node, results):
# First case: getOpen/SaveFileName
# We need to add __ variable because in PyQt5
# getOpen/SaveFileName returns a tuple
- if 'filename' in results:
- node = results['filename']
+ if "filename" in results:
+ node = results["filename"]
# count number of leaves (result variables)
nbLeaves = sum(1 for i in node.leaves())
@@ -33,11 +34,11 @@ def transform(self, node, results):
# we add __ special variable
if nbLeaves < 3:
fileName = node.value
- node.value = f'{fileName}, __'
+ node.value = f"{fileName}, __"
node.changed()
# Rename *AndFilter methods
- if 'filter' in results:
- method = results['filter'][0]
- method.value = method.value.replace('AndFilter', '')
+ if "filter" in results:
+ method = results["filter"][0]
+ method.value = method.value.replace("AndFilter", "")
method.changed()
diff --git a/scripts/qgis_fixes/fix_signals.py b/scripts/qgis_fixes/fix_signals.py
index e232299defa4..56d4488b8514 100644
--- a/scripts/qgis_fixes/fix_signals.py
+++ b/scripts/qgis_fixes/fix_signals.py
@@ -1,14 +1,15 @@
"""Migrate signals from old style to new style
"""
+
# Author: Juergen E. Fischer
# .connect( sender, signal, receiver, slot )
+import re
+
# Local imports
from lib2to3 import fixer_base, pytree
-from lib2to3.fixer_util import Call, Name, Attr, ArgList, Node, syms
-
-import re
+from lib2to3.fixer_util import ArgList, Attr, Call, Name, Node, syms
class FixSignals(fixer_base.BaseFix):
@@ -50,25 +51,29 @@ class FixSignals(fixer_base.BaseFix):
)
"""
-# def match(self, node):
-# res = super(FixSignals, self).match( node )
-# r = repr(node)
-# if "emit" in r:
-# print "yes" if res else "no", ": ", r
-# return res
+ # def match(self, node):
+ # res = super(FixSignals, self).match( node )
+ # r = repr(node)
+ # if "emit" in r:
+ # print "yes" if res else "no", ": ", r
+ # return res
def transform(self, node, results):
signal = results.get("signal").value
- signal = re.sub('^["\']([^(]+)(?:\\(.*\\))?["\']$', '\\1', signal)
+ signal = re.sub("^[\"']([^(]+)(?:\\(.*\\))?[\"']$", "\\1", signal)
- if 'emitter' in results:
+ if "emitter" in results:
emitter = results.get("emitter").clone()
emitter.prefix = node.prefix
args = results.get("args").clone()
args.children = args.children[2:]
if args.children:
- args.children[0].prefix = ''
- res = Node(syms.power, [emitter, Name('.'), Name(signal), Name('.'), Name('emit')] + [ArgList([args])])
+ args.children[0].prefix = ""
+ res = Node(
+ syms.power,
+ [emitter, Name("."), Name(signal), Name("."), Name("emit")]
+ + [ArgList([args])],
+ )
else:
sender = results.get("sender").clone()
method = results.get("method")
@@ -78,5 +83,9 @@ def transform(self, node, results):
sender.prefix = node.prefix
slot = results.get("slot").clone()
slot.prefix = ""
- res = Node(syms.power, [sender, Name('.'), Name(signal), Name('.'), method] + [ArgList([slot])])
+ res = Node(
+ syms.power,
+ [sender, Name("."), Name(signal), Name("."), method]
+ + [ArgList([slot])],
+ )
return res
diff --git a/scripts/qgis_fixes/fix_uiimport.py b/scripts/qgis_fixes/fix_uiimport.py
index 296c166327de..fb2026e2603b 100644
--- a/scripts/qgis_fixes/fix_uiimport.py
+++ b/scripts/qgis_fixes/fix_uiimport.py
@@ -3,8 +3,8 @@
# Local imports
from lib2to3 import fixer_base
+from lib2to3.fixer_util import FromImport, Leaf, Node, syms
from lib2to3.fixes.fix_import import FixImport
-from lib2to3.fixer_util import FromImport, Node, Leaf, syms
class FixUiimport(fixer_base.BaseFix):
@@ -17,14 +17,14 @@ class FixUiimport(fixer_base.BaseFix):
"""
def transform(self, node, results):
- imp = results.get('imp')
+ imp = results.get("imp")
if node.type == syms.import_from:
# Some imps are top-level (e.g., 'import ham')
# some are first level (e.g., 'import ham.eggs')
# some are third level (e.g., 'import ham.eggs as spam')
# Hence, the loop
- while not hasattr(imp, 'value'):
+ while not hasattr(imp, "value"):
imp = imp.children[0]
if imp.value.startswith("ui_"):
imp.value = "." + imp.value
diff --git a/scripts/qstringfixup.py b/scripts/qstringfixup.py
index 4ca86ff78752..fff0d0446adc 100644
--- a/scripts/qstringfixup.py
+++ b/scripts/qstringfixup.py
@@ -38,7 +38,7 @@
import re
import sys
-lines = [l[0:-1] if l[-1] == '\n' else l for l in open(sys.argv[1]).readlines()]
+lines = [l[0:-1] if l[-1] == "\n" else l for l in open(sys.argv[1]).readlines()]
# Double quoted strings that only include ASCII characters
string_literal = r"""(R?"(?:(?:\\['"\\nrt])|[\x00-\x21\x23-\x5B\x5D-\x7F])+?")"""
@@ -47,25 +47,31 @@
char_literal = r"""('(?:\\['"\\nrt]|[\x00-\x26\x28-\x5B\x5D-\x7F])')"""
# Simple expression like foo or foo.bar() or foo.bar(baz, baw)
-simple_expr = r"""([a-zA-Z0-9_:<>]+(?:\.(?:[a-zA-Z0-9_]+\([^\(\)]*\)|[a-zA-Z0-9_]+))?)"""
+simple_expr = (
+ r"""([a-zA-Z0-9_:<>]+(?:\.(?:[a-zA-Z0-9_]+\([^\(\)]*\)|[a-zA-Z0-9_]+))?)"""
+)
-qsl = fr"""QStringLiteral\( {string_literal} \)"""
+qsl = rf"""QStringLiteral\( {string_literal} \)"""
# Find lines like " foo += QStringLiteral( "bla" ); // optional comment"
-pattern_plus_equal = re.compile(fr'^([ ]*)([^ ]+) \+= {qsl};([ ]*//.*)?$')
+pattern_plus_equal = re.compile(rf"^([ ]*)([^ ]+) \+= {qsl};([ ]*//.*)?$")
# Find patterns like "...QString( tr( "foo" ) )..."
-pattern_qstring_tr = re.compile(fr"""(.*)QString\( tr\( {string_literal} \) \)(.*)""")
+pattern_qstring_tr = re.compile(rf"""(.*)QString\( tr\( {string_literal} \) \)(.*)""")
# Find patterns like "...== QStringLiteral( "foo" ) something that is not like .arg()"
-pattern_equalequal_qsl = re.compile(r'(.*)(==|!=) ' + qsl + r'( \)| \|\|| &&| }|;| \?| ,)(.*)')
+pattern_equalequal_qsl = re.compile(
+ r"(.*)(==|!=) " + qsl + r"( \)| \|\|| &&| }|;| \?| ,)(.*)"
+)
# Find patterns like "...startsWith( QStringLiteral( "foo" ) )..."
-pattern_startswith_qsl = re.compile(fr'(.*)\.(startsWith|endsWith|indexOf|lastIndexOf|compare)\( {qsl} \)(.*)')
+pattern_startswith_qsl = re.compile(
+ rf"(.*)\.(startsWith|endsWith|indexOf|lastIndexOf|compare)\( {qsl} \)(.*)"
+)
# .replace( 'a' or simple_expr or qsl, QStringLiteral( "foo" ) )
-replace_char_qsl = re.compile(fr"""(.*)\.replace\( {char_literal}, {qsl} \)(.*)""")
-replace_str_qsl = re.compile(fr"""(.*)\.replace\( {string_literal}, {qsl} \)(.*)""")
+replace_char_qsl = re.compile(rf"""(.*)\.replace\( {char_literal}, {qsl} \)(.*)""")
+replace_str_qsl = re.compile(rf"""(.*)\.replace\( {string_literal}, {qsl} \)(.*)""")
# Do not use that: if simple_expr is a QRegExp, there is no QString::replace(QRegExp, QLatin1String)
# replace_simple_expr_qsl = re.compile(r"""(.*)\.replace\( {simple_expr}, {qsl} \)(.*)""".format(simple_expr=simple_expr, qsl=qsl))
@@ -73,21 +79,23 @@
replace_qsl_qsl = re.compile(r"""(.*)\.replace\( {qsl}, {qsl} \)(.*)""".format(qsl=qsl))
# .replace( QStringLiteral( "foo" ), something
-replace_qsl_something = re.compile(fr"""(.*)\.replace\( {qsl}, (.+)""")
+replace_qsl_something = re.compile(rf"""(.*)\.replace\( {qsl}, (.+)""")
# .arg( QStringLiteral( "foo" ) )
# note: QString QString::arg(QLatin1String a) added in QT 5.10, but using QLatin1String() will work with older too
-arg_qsl = re.compile(fr"""(.*)\.arg\( {qsl} \)(.*)""")
+arg_qsl = re.compile(rf"""(.*)\.arg\( {qsl} \)(.*)""")
# .join( QStringLiteral( "foo" ) )
-join = re.compile(fr"""(.*)\.join\( {qsl} \)(.*)""")
+join = re.compile(rf"""(.*)\.join\( {qsl} \)(.*)""")
# if QT >= 5.14 .compare would be ok
-qlatin1str_single_char = re.compile(r"""(.*)(.startsWith\(|.endsWith\(|.indexOf\(|.lastIndexOf\(|\+=) QLatin1String\( ("[^"]") \)(.*)""")
+qlatin1str_single_char = re.compile(
+ r"""(.*)(.startsWith\(|.endsWith\(|.indexOf\(|.lastIndexOf\(|\+=) QLatin1String\( ("[^"]") \)(.*)"""
+)
def qlatin1char_or_string(x):
- """ x is a double quoted string """
+ """x is a double quoted string"""
if len(x) == 3 and x[1] == "'":
return "QLatin1Char( '\\'' )"
elif len(x) == 3:
@@ -106,8 +114,8 @@ def qlatin1char_or_string(x):
m = pattern_plus_equal.match(line)
if m:
g = m.groups()
- newline = g[0] + g[1] + ' += '
- newline += 'QLatin1String( ' + g[2] + ' );'
+ newline = g[0] + g[1] + " += "
+ newline += "QLatin1String( " + g[2] + " );"
if g[3]:
newline += g[3]
line = newline
@@ -115,16 +123,16 @@ def qlatin1char_or_string(x):
m = pattern_qstring_tr.match(line)
if m:
g = m.groups()
- newline = g[0] + 'tr( ' + g[1] + ' )'
+ newline = g[0] + "tr( " + g[1] + " )"
if g[2]:
newline += g[2]
line = newline
while True:
m = pattern_equalequal_qsl.match(line)
- if m and 'qgetenv' not in line and 'h.first' not in line:
+ if m and "qgetenv" not in line and "h.first" not in line:
g = m.groups()
- newline = g[0] + g[1] + ' QLatin1String( ' + g[2] + ' )' + g[3]
+ newline = g[0] + g[1] + " QLatin1String( " + g[2] + " )" + g[3]
if g[4]:
newline += g[4]
line = newline
@@ -135,7 +143,7 @@ def qlatin1char_or_string(x):
m = pattern_startswith_qsl.match(line)
if m:
g = m.groups()
- newline = g[0] + '.' + g[1] + '( QLatin1String( ' + g[2] + ' ) )'
+ newline = g[0] + "." + g[1] + "( QLatin1String( " + g[2] + " ) )"
if g[3]:
newline += g[3]
line = newline
@@ -150,7 +158,7 @@ def qlatin1char_or_string(x):
# m = replace_simple_expr_qsl.match(line)
if m:
g = m.groups()
- newline = g[0] + '.replace( ' + g[1] + ', QLatin1String( ' + g[2] + ' ) )'
+ newline = g[0] + ".replace( " + g[1] + ", QLatin1String( " + g[2] + " ) )"
if g[3]:
newline += g[3]
line = newline
@@ -161,7 +169,14 @@ def qlatin1char_or_string(x):
m = replace_qsl_qsl.match(line)
if m:
g = m.groups()
- newline = g[0] + '.replace( QLatin1String( ' + g[1] + ' ), QLatin1String( ' + g[2] + ' ) )'
+ newline = (
+ g[0]
+ + ".replace( QLatin1String( "
+ + g[1]
+ + " ), QLatin1String( "
+ + g[2]
+ + " ) )"
+ )
if g[3]:
newline += g[3]
line = newline
@@ -172,7 +187,7 @@ def qlatin1char_or_string(x):
m = replace_qsl_something.match(line)
if m:
g = m.groups()
- newline = g[0] + '.replace( QLatin1String( ' + g[1] + ' ), ' + g[2]
+ newline = g[0] + ".replace( QLatin1String( " + g[1] + " ), " + g[2]
line = newline
else:
break
@@ -181,7 +196,7 @@ def qlatin1char_or_string(x):
m = arg_qsl.match(line)
if m:
g = m.groups()
- newline = g[0] + '.arg( QLatin1String( ' + g[1] + ') )'
+ newline = g[0] + ".arg( QLatin1String( " + g[1] + ") )"
if g[2]:
newline += g[2]
line = newline
@@ -192,7 +207,7 @@ def qlatin1char_or_string(x):
m = join.match(line)
if m:
g = m.groups()
- newline = g[0] + '.join( ' + qlatin1char_or_string(g[1]) + ' )'
+ newline = g[0] + ".join( " + qlatin1char_or_string(g[1]) + " )"
if g[2]:
newline += g[2]
line = newline
@@ -203,7 +218,7 @@ def qlatin1char_or_string(x):
m = qlatin1str_single_char.match(line)
if m:
g = m.groups()
- newline = g[0] + g[1] + ' ' + qlatin1char_or_string(g[2])
+ newline = g[0] + g[1] + " " + qlatin1char_or_string(g[2])
if g[3]:
newline += g[3]
line = newline
diff --git a/scripts/random_vector.py b/scripts/random_vector.py
index f0a3e459cb57..aed6860366c8 100755
--- a/scripts/random_vector.py
+++ b/scripts/random_vector.py
@@ -2,14 +2,16 @@
# Generates random shapefile which may be used for benchmarks
+import math
import os
-import sys
import random
import string
-import math
-from osgeo import ogr
+import sys
+
from optparse import OptionParser
+from osgeo import ogr
+
def error(msg):
print(msg)
@@ -17,11 +19,47 @@ def error(msg):
parser = OptionParser("usage: %prog [options] output")
-parser.add_option("-t", "--type", dest="type", type="choice", choices=("point", "line", "polygon"), default="point", help="Geometry type")
-parser.add_option("-f", "--features", dest="features", type="int", default=1000, help="Number of features")
-parser.add_option("-c", "--coordinates", dest="coordinates", type="int", default=10, help="Number of coordinates per feature (lines and polygons)")
-parser.add_option("-a", "--attributes", dest="attributes", type="int", default=10, help="Number of attributes")
-parser.add_option("-e", "--extent", dest="extent", type="string", default="-180,-90,180,90", help="Extent")
+parser.add_option(
+ "-t",
+ "--type",
+ dest="type",
+ type="choice",
+ choices=("point", "line", "polygon"),
+ default="point",
+ help="Geometry type",
+)
+parser.add_option(
+ "-f",
+ "--features",
+ dest="features",
+ type="int",
+ default=1000,
+ help="Number of features",
+)
+parser.add_option(
+ "-c",
+ "--coordinates",
+ dest="coordinates",
+ type="int",
+ default=10,
+ help="Number of coordinates per feature (lines and polygons)",
+)
+parser.add_option(
+ "-a",
+ "--attributes",
+ dest="attributes",
+ type="int",
+ default=10,
+ help="Number of attributes",
+)
+parser.add_option(
+ "-e",
+ "--extent",
+ dest="extent",
+ type="string",
+ default="-180,-90,180,90",
+ help="Extent",
+)
(options, args) = parser.parse_args()
if len(args) != 1:
@@ -107,7 +145,10 @@ def error(msg):
limit = 10000000
if field_defn.GetType() == ogr.OFTString:
nChars = random.randint(0, stringWidth)
- val = ''.join(random.choice(string.ascii_letters + string.digits) for x in range(nChars))
+ val = "".join(
+ random.choice(string.ascii_letters + string.digits)
+ for x in range(nChars)
+ )
elif field_defn.GetType() == ogr.OFTInteger:
val = random.randint(-limit, limit)
elif field_defn.GetType() == ogr.OFTReal:
diff --git a/scripts/sipify.py b/scripts/sipify.py
index 71c6aebc8e62..2f816a58ad66 100755
--- a/scripts/sipify.py
+++ b/scripts/sipify.py
@@ -5,9 +5,10 @@
import os
import re
import sys
+
from collections import defaultdict
from enum import Enum, auto
-from typing import List, Dict, Any, Tuple, Optional
+from typing import Any, Dict, List, Optional, Tuple
import yaml
@@ -38,8 +39,7 @@ class MultiLineType(Enum):
# Parse command-line arguments
-parser = argparse.ArgumentParser(
- description="Convert header file to SIP and Python")
+parser = argparse.ArgumentParser(description="Convert header file to SIP and Python")
parser.add_argument("-debug", action="store_true", help="Enable debug mode")
parser.add_argument("-qt6", action="store_true", help="Enable Qt6 mode")
parser.add_argument("-sip_output", help="SIP output file")
@@ -50,21 +50,23 @@ class MultiLineType(Enum):
# Read the input file
try:
- with open(args.headerfile, "r") as f:
+ with open(args.headerfile) as f:
input_lines = f.read().splitlines()
-except IOError as e:
- print(f"Couldn't open '{args.headerfile}' for reading because: {e}",
- file=sys.stderr)
+except OSError as e:
+ print(
+ f"Couldn't open '{args.headerfile}' for reading because: {e}", file=sys.stderr
+ )
sys.exit(1)
# Read configuration
-cfg_file = os.path.join(os.path.dirname(__file__), '../python/sipify.yaml')
+cfg_file = os.path.join(os.path.dirname(__file__), "../python/sipify.yaml")
try:
- with open(cfg_file, 'r') as f:
+ with open(cfg_file) as f:
sip_config = yaml.safe_load(f)
-except IOError as e:
- print(f"Couldn't open configuration file '{cfg_file}' because: {e}",
- file=sys.stderr)
+except OSError as e:
+ print(
+ f"Couldn't open configuration file '{cfg_file}' because: {e}", file=sys.stderr
+ )
sys.exit(1)
@@ -76,63 +78,68 @@ class Context:
def __init__(self):
self.debug: bool = False
self.is_qt6: bool = False
- self.header_file: str = ''
+ self.header_file: str = ""
- self.current_line: str = ''
+ self.current_line: str = ""
self.sip_run: bool = False
self.header_code: bool = False
- self.access: List[Visibility] = [Visibility.Public]
+ self.access: list[Visibility] = [Visibility.Public]
self.multiline_definition: MultiLineType = MultiLineType.NotMultiline
- self.classname: List[str] = []
- self.class_and_struct: List[str] = []
- self.declared_classes: List[str] = []
- self.all_fully_qualified_class_names: List[str] = []
- self.exported: List[int] = [0]
- self.actual_class: str = ''
- self.python_signature: str = ''
- self.enum_int_types: List[str] = []
- self.enum_intflag_types: List[str] = []
- self.enum_class_non_int_types: List[str] = []
- self.enum_monkey_patched_types: List = []
- self.indent: str = ''
- self.prev_indent: str = ''
- self.comment: str = ''
+ self.classname: list[str] = []
+ self.class_and_struct: list[str] = []
+ self.declared_classes: list[str] = []
+ self.all_fully_qualified_class_names: list[str] = []
+ self.exported: list[int] = [0]
+ self.actual_class: str = ""
+ self.python_signature: str = ""
+ self.enum_int_types: list[str] = []
+ self.enum_intflag_types: list[str] = []
+ self.enum_class_non_int_types: list[str] = []
+ self.enum_monkey_patched_types: list = []
+ self.indent: str = ""
+ self.prev_indent: str = ""
+ self.comment: str = ""
self.comment_param_list: bool = False
self.comment_last_line_note_warning: bool = False
self.comment_code_snippet: CodeSnippetType = CodeSnippetType.NotCodeSnippet
self.comment_template_docstring: bool = False
- self.skipped_params_out: List[str] = []
- self.skipped_params_remove: List[str] = []
+ self.skipped_params_out: list[str] = []
+ self.skipped_params_remove: list[str] = []
self.ifdef_nesting_idx: int = 0
- self.bracket_nesting_idx: List[int] = [0]
- self.private_section_line: str = ''
- self.last_access_section_line: str = ''
- self.return_type: str = ''
+ self.bracket_nesting_idx: list[int] = [0]
+ self.private_section_line: str = ""
+ self.last_access_section_line: str = ""
+ self.return_type: str = ""
self.is_override_or_make_private: PrependType = PrependType.NoPrepend
- self.if_feature_condition: str = ''
+ self.if_feature_condition: str = ""
self.found_since: bool = False
- self.qflag_hash: Dict[str, Any] = {}
- self.input_lines: List[str] = []
+ self.qflag_hash: dict[str, Any] = {}
+ self.input_lines: list[str] = []
self.line_count: int = len(input_lines)
self.line_idx: int = 0
- self.output: List[str] = []
- self.output_python: List[str] = []
+ self.output: list[str] = []
+ self.output_python: list[str] = []
self.doxy_inside_sip_run: int = 0
self.has_pushed_force_int: bool = False
self.attribute_docstrings = defaultdict(dict)
self.struct_docstrings = defaultdict(dict)
- self.current_method_name: str = ''
+ self.current_method_name: str = ""
self.static_methods = defaultdict(dict)
self.current_signal_args = []
self.signal_arguments = defaultdict(dict)
def current_fully_qualified_class_name(self) -> str:
- return '.'.join(
- _c for _c in ([c for c in self.classname if c != self.actual_class] + [
- self.actual_class]) if _c)
+ return ".".join(
+ _c
+ for _c in (
+ [c for c in self.classname if c != self.actual_class]
+ + [self.actual_class]
+ )
+ if _c
+ )
def current_fully_qualified_struct_name(self) -> str:
- return '.'.join(self.class_and_struct)
+ return ".".join(self.class_and_struct)
CONTEXT = Context()
@@ -559,21 +566,22 @@ def current_fully_qualified_struct_name(self) -> str:
"SymbolTable",
"TagTable",
"TagmapTable",
- "TextFormatTable"
+ "TextFormatTable",
]
def replace_macros(line):
global CONTEXT
- line = re.sub(r'\bTRUE\b', '``True``', line)
- line = re.sub(r'\bFALSE\b', '``False``', line)
- line = re.sub(r'\bNULLPTR\b', '``None``', line)
+ line = re.sub(r"\bTRUE\b", "``True``", line)
+ line = re.sub(r"\bFALSE\b", "``False``", line)
+ line = re.sub(r"\bNULLPTR\b", "``None``", line)
if CONTEXT.is_qt6:
# sip for Qt6 chokes on QList/QVector, but is happy if you expand out the map explicitly
- line = re.sub(r'(QList<\s*|QVector<\s*)QVariantMap',
- r'\1QMap', line)
+ line = re.sub(
+ r"(QList<\s*|QVector<\s*)QVariantMap", r"\1QMap", line
+ )
return line
@@ -586,9 +594,10 @@ def read_line():
if CONTEXT.debug:
print(
- f'LIN:{CONTEXT.line_idx} DEPTH:{len(CONTEXT.access)} ACC:{CONTEXT.access[-1]} '
- f'BRCK:{CONTEXT.bracket_nesting_idx[-1]} SIP:{CONTEXT.sip_run} MLT:{CONTEXT.multiline_definition} '
- f'OVR: {CONTEXT.is_override_or_make_private} CLSS: {CONTEXT.actual_class}/{len(CONTEXT.classname)} :: {new_line}')
+ f"LIN:{CONTEXT.line_idx} DEPTH:{len(CONTEXT.access)} ACC:{CONTEXT.access[-1]} "
+ f"BRCK:{CONTEXT.bracket_nesting_idx[-1]} SIP:{CONTEXT.sip_run} MLT:{CONTEXT.multiline_definition} "
+ f"OVR: {CONTEXT.is_override_or_make_private} CLSS: {CONTEXT.actual_class}/{len(CONTEXT.classname)} :: {new_line}"
+ )
new_line = replace_macros(new_line)
return new_line
@@ -600,18 +609,18 @@ def write_output(dbg_code, out, prepend="no"):
if CONTEXT.debug:
dbg_code = f"{CONTEXT.line_idx} {dbg_code:<4} :: "
else:
- dbg_code = ''
+ dbg_code = ""
if prepend == "prepend":
CONTEXT.output.insert(0, dbg_code + out)
else:
- if CONTEXT.if_feature_condition != '':
+ if CONTEXT.if_feature_condition != "":
CONTEXT.output.append(f"%If ({CONTEXT.if_feature_condition})\n")
CONTEXT.output.append(dbg_code + out)
- if CONTEXT.if_feature_condition != '':
+ if CONTEXT.if_feature_condition != "":
CONTEXT.output.append("%End\n")
- CONTEXT.if_feature_condition = ''
+ CONTEXT.if_feature_condition = ""
def dbg_info(info):
@@ -620,13 +629,15 @@ def dbg_info(info):
if CONTEXT.debug:
CONTEXT.output.append(f"{info}\n")
print(
- f"{CONTEXT.line_idx} {len(CONTEXT.access)} {CONTEXT.sip_run} {CONTEXT.multiline_definition} {info}")
+ f"{CONTEXT.line_idx} {len(CONTEXT.access)} {CONTEXT.sip_run} {CONTEXT.multiline_definition} {info}"
+ )
def exit_with_error(message):
global CONTEXT
sys.exit(
- f"! Sipify error in {CONTEXT.header_file} at line :: {CONTEXT.line_idx}\n! {message}")
+ f"! Sipify error in {CONTEXT.header_file} at line :: {CONTEXT.line_idx}\n! {message}"
+ )
def sip_header_footer():
@@ -636,29 +647,33 @@ def sip_header_footer():
# otherwise "sip up to date" test fails. This is because the test uses %Include entries
# and over there we have to use ./3d/X.h entries because SIP parser does not allow a number
# as the first letter of a relative path
- headerfile_x = re.sub(r'src/core/3d', r'src/core/./3d',
- CONTEXT.header_file)
+ headerfile_x = re.sub(r"src/core/3d", r"src/core/./3d", CONTEXT.header_file)
header_footer.append(
- "/************************************************************************\n")
+ "/************************************************************************\n"
+ )
header_footer.append(
- " * This file has been generated automatically from *\n")
+ " * This file has been generated automatically from *\n"
+ )
header_footer.append(
- " * *\n")
+ " * *\n"
+ )
header_footer.append(f" * {headerfile_x:<68} *\n")
header_footer.append(
- " * *\n")
+ " * *\n"
+ )
header_footer.append(
- " * Do not edit manually ! Edit header and run scripts/sipify.py again *\n")
+ " * Do not edit manually ! Edit header and run scripts/sipify.py again *\n"
+ )
header_footer.append(
- " ************************************************************************/\n")
+ " ************************************************************************/\n"
+ )
return header_footer
def python_header():
global CONTEXT
header = []
- headerfile_x = re.sub(r'src/core/3d', r'src/core/./3d',
- CONTEXT.header_file)
+ headerfile_x = re.sub(r"src/core/3d", r"src/core/./3d", CONTEXT.header_file)
header.append("# The following has been generated automatically from ")
header.append(f"{headerfile_x}\n")
return header
@@ -668,30 +683,34 @@ def create_class_links(line):
global CONTEXT
# Replace Qgs classes (but not the current class) with :py:class: links
- class_link_match = re.search(r'\b(Qgs[A-Z]\w+|Qgis)\b(\.?$|\W{2})', line)
+ class_link_match = re.search(r"\b(Qgs[A-Z]\w+|Qgis)\b(\.?$|\W{2})", line)
if class_link_match:
if CONTEXT.actual_class and class_link_match.group(1) != CONTEXT.actual_class:
- line = re.sub(r'\b(Qgs[A-Z]\w+)\b(\.?$|\W{2})',
- r':py:class:`\1`\2', line)
+ line = re.sub(r"\b(Qgs[A-Z]\w+)\b(\.?$|\W{2})", r":py:class:`\1`\2", line)
# Replace Qgs class methods with :py:func: links
- line = re.sub(r'\b((Qgs[A-Z]\w+|Qgis)\.[a-z]\w+\(\))(?!\w)',
- r':py:func:`\1`', line)
+ line = re.sub(r"\b((Qgs[A-Z]\w+|Qgis)\.[a-z]\w+\(\))(?!\w)", r":py:func:`\1`", line)
# Replace other methods with :py:func: links
if CONTEXT.actual_class:
- line = re.sub(r'(? str:
global CONTEXT
# Handle SIP_RUN preprocessor directives
- if re.search(r'\s*#ifdef SIP_RUN', line):
+ if re.search(r"\s*#ifdef SIP_RUN", line):
CONTEXT.doxy_inside_sip_run = 1
return ""
- elif re.search(r'\s*#ifndef SIP_RUN', line):
+ elif re.search(r"\s*#ifndef SIP_RUN", line):
CONTEXT.doxy_inside_sip_run = 2
return ""
- elif CONTEXT.doxy_inside_sip_run != 0 and re.search(r'\s*#else', line):
+ elif CONTEXT.doxy_inside_sip_run != 0 and re.search(r"\s*#else", line):
CONTEXT.doxy_inside_sip_run = 2 if CONTEXT.doxy_inside_sip_run == 1 else 1
return ""
- elif CONTEXT.doxy_inside_sip_run != 0 and re.search(r'\s*#endif', line):
+ elif CONTEXT.doxy_inside_sip_run != 0 and re.search(r"\s*#endif", line):
CONTEXT.doxy_inside_sip_run = 0
return ""
if CONTEXT.doxy_inside_sip_run == 2:
return ""
- if r'\copydoc' in line:
+ if r"\copydoc" in line:
exit_with_error(
- '\\copydoc doxygen command cannot be used for methods exposed to Python')
+ "\\copydoc doxygen command cannot be used for methods exposed to Python"
+ )
- if re.search(r'<(?:dl|dt|dd>)', line):
+ if re.search(r"<(?:dl|dt|dd>)", line):
exit_with_error(
"Don't use raw html , or tags in documentation. "
- "Use markdown headings instead")
- if re.search(r'', line):
+ "Use markdown headings instead"
+ )
+ if re.search(r"", line):
exit_with_error(
"Don't use raw html heading tags in documentation. "
- "Use markdown headings instead")
- if re.search(r'', line):
+ "Use markdown headings instead"
+ )
+ if re.search(r" ", line):
exit_with_error(
- "Don't use raw html lists in documentation. "
- "Use markdown lists instead")
- if re.search(r'<[ib]>', line):
+ "Don't use raw html lists in documentation. " "Use markdown lists instead"
+ )
+ if re.search(r"<[ib]>", line):
exit_with_error(
- "Don't use raw or tags in documentation. "
- "Use markdown instead")
+ "Don't use raw or tags in documentation. " "Use markdown instead"
+ )
# Detect code snippet
- code_match = re.search(r'\\code(\{\.?(\w+)})?', line)
+ code_match = re.search(r"\\code(\{\.?(\w+)})?", line)
if code_match:
codelang = f" {code_match.group(2)}" if code_match.group(2) else ""
- if not re.search(r'(cpp|py|unparsed)', codelang):
+ if not re.search(r"(cpp|py|unparsed)", codelang):
exit_with_error(f"invalid code snippet format: {codelang}")
CONTEXT.comment_code_snippet = CodeSnippetType.NotSpecified
- if re.search(r'cpp', codelang):
+ if re.search(r"cpp", codelang):
CONTEXT.comment_code_snippet = CodeSnippetType.Cpp
- codelang = codelang.replace('py', 'python').replace('unparsed', 'text')
- return "\n" if CONTEXT.comment_code_snippet == CodeSnippetType.Cpp else f"\n.. code-block::{codelang}\n\n"
-
- if re.search(r'\\endcode', line):
+ codelang = codelang.replace("py", "python").replace("unparsed", "text")
+ return (
+ "\n"
+ if CONTEXT.comment_code_snippet == CodeSnippetType.Cpp
+ else f"\n.. code-block::{codelang}\n\n"
+ )
+
+ if re.search(r"\\endcode", line):
CONTEXT.comment_code_snippet = CodeSnippetType.NotCodeSnippet
return "\n"
@@ -757,127 +783,145 @@ def process_doxygen_line(line: str) -> str:
if CONTEXT.comment_code_snippet == CodeSnippetType.Cpp:
return ""
else:
- return f" {line}\n" if line != '' else "\n"
+ return f" {line}\n" if line != "" else "\n"
# Remove prepending spaces and apply various replacements
- line = re.sub(r'^\s+', '', line)
- line = re.sub(r'\\a (.+?)\b', r'``\1``', line)
- line = line.replace('::', '.')
- line = re.sub(r'\bnullptr\b', 'None', line)
+ line = re.sub(r"^\s+", "", line)
+ line = re.sub(r"\\a (.+?)\b", r"``\1``", line)
+ line = line.replace("::", ".")
+ line = re.sub(r"\bnullptr\b", "None", line)
# Handle section and subsection
- section_match = re.match(r'^\\(?Psub)?section', line)
+ section_match = re.match(r"^\\(?Psub)?section", line)
if section_match:
- sep = "^" if section_match.group('SUB') else "-"
- line = re.sub(r'^\\(sub)?section \w+ ', '', line)
- sep_line = re.sub(r'[\w ()]', sep, line)
+ sep = "^" if section_match.group("SUB") else "-"
+ line = re.sub(r"^\\(sub)?section \w+ ", "", line)
+ sep_line = re.sub(r"[\w ()]", sep, line)
line += f"\n{sep_line}"
# Convert ### style headings
- heading_match = re.match(r'^###\s+(.*)$', line)
+ heading_match = re.match(r"^###\s+(.*)$", line)
if heading_match:
line = f"{heading_match.group(1)}\n{'-' * (len(heading_match.group(1)) + 30)}"
- heading_match = re.match(r'^##\s+(.*)$', line)
+ heading_match = re.match(r"^##\s+(.*)$", line)
if heading_match:
line = f"{heading_match.group(1)}\n{'=' * (len(heading_match.group(1)) + 30)}"
- if line == '*':
- line = ''
+ if line == "*":
+ line = ""
# Handle multi-line parameters/returns/lists
- if line != '':
- if re.match(r'^\s*[\-#]', line):
+ if line != "":
+ if re.match(r"^\s*[\-#]", line):
line = f"{CONTEXT.prev_indent}{line}"
CONTEXT.indent = f"{CONTEXT.prev_indent} "
elif not re.match(
- r'^\s*[\\:]+(param|note|since|return|deprecated|warning|throws)',
- line):
+ r"^\s*[\\:]+(param|note|since|return|deprecated|warning|throws)", line
+ ):
line = f"{CONTEXT.indent}{line}"
else:
CONTEXT.prev_indent = CONTEXT.indent
- CONTEXT.indent = ''
+ CONTEXT.indent = ""
# Replace \returns with :return:
- if re.search(r'\\return(s)?', line):
- line = re.sub(r'\s*\\return(s)?\s*', '\n:return: ', line)
- line = re.sub(r'\s*$', '', line)
- CONTEXT.indent = ' ' * (line.index(':', 4) + 1)
+ if re.search(r"\\return(s)?", line):
+ line = re.sub(r"\s*\\return(s)?\s*", "\n:return: ", line)
+ line = re.sub(r"\s*$", "", line)
+ CONTEXT.indent = " " * (line.index(":", 4) + 1)
# Handle params
- if re.search(r'\\param(?:\[(?:out|in|,)+])? ', line):
- line = re.sub(r'\s*\\param(?:\[(?:out|in|,)+])?\s+(\w+)\b\s*', r':param \1: ', line)
- line = re.sub(r'\s*$', '', line)
- CONTEXT.indent = ' ' * (line.index(':', 2) + 2)
- if line.startswith(':param'):
+ if re.search(r"\\param(?:\[(?:out|in|,)+])? ", line):
+ line = re.sub(
+ r"\s*\\param(?:\[(?:out|in|,)+])?\s+(\w+)\b\s*", r":param \1: ", line
+ )
+ line = re.sub(r"\s*$", "", line)
+ CONTEXT.indent = " " * (line.index(":", 2) + 2)
+ if line.startswith(":param"):
if not CONTEXT.comment_param_list:
line = f"\n{line}"
CONTEXT.comment_param_list = True
CONTEXT.comment_last_line_note_warning = False
# Handle brief
- if re.match(r'^\s*[\\@]brief', line):
- line = re.sub(r'[\\@]brief\s*', '', line)
+ if re.match(r"^\s*[\\@]brief", line):
+ line = re.sub(r"[\\@]brief\s*", "", line)
if CONTEXT.found_since:
exit_with_error(
- f"{CONTEXT.header_file}::{CONTEXT.line_idx} Since annotation must come after brief")
+ f"{CONTEXT.header_file}::{CONTEXT.line_idx} Since annotation must come after brief"
+ )
CONTEXT.found_since = False
- if re.match(r'^\s*$', line):
+ if re.match(r"^\s*$", line):
return ""
# Handle ingroup and class
- if re.search(r'[\\@](ingroup|class)', line):
+ if re.search(r"[\\@](ingroup|class)", line):
CONTEXT.prev_indent = CONTEXT.indent
- CONTEXT.indent = ''
+ CONTEXT.indent = ""
return ""
# Handle since
- since_match = re.search(r'\\since .*?([\d.]+)', line, re.IGNORECASE)
+ since_match = re.search(r"\\since .*?([\d.]+)", line, re.IGNORECASE)
if since_match:
CONTEXT.prev_indent = CONTEXT.indent
- CONTEXT.indent = ''
+ CONTEXT.indent = ""
CONTEXT.found_since = True
return f"\n.. versionadded:: {since_match.group(1)}\n"
# Handle deprecated
if deprecated_match := re.search(
- r'\\deprecated QGIS (?P[0-9.]+)\s*(?P.*)?',
+ r"\\deprecated QGIS (?P[0-9.]+)\s*(?P.*)?",
line,
- re.IGNORECASE):
+ re.IGNORECASE,
+ ):
CONTEXT.prev_indent = CONTEXT.indent
- CONTEXT.indent = ''
- version = deprecated_match.group('DEPR_VERSION')
- if version.endswith('.'):
+ CONTEXT.indent = ""
+ version = deprecated_match.group("DEPR_VERSION")
+ if version.endswith("."):
version = version[:-1]
depr_line = f"\n.. deprecated:: {version}"
- message = deprecated_match.group('DEPR_MESSAGE')
+ message = deprecated_match.group("DEPR_MESSAGE")
if message:
depr_line += "\n"
- depr_line += "\n".join(f"\n {_m}" for _m in message.split('\n'))
+ depr_line += "\n".join(f"\n {_m}" for _m in message.split("\n"))
return create_class_links(depr_line)
# Handle see also
- see_matches = list(re.finditer(r'\\see +([\w:/.#-]+(\.\w+)*)(\([^()]*\))?(\.?)', line))
+ see_matches = list(
+ re.finditer(r"\\see +([\w:/.#-]+(\.\w+)*)(\([^()]*\))?(\.?)", line)
+ )
if see_matches:
for see_match in reversed(see_matches):
seealso = see_match.group(1)
seealso_suffix = see_match.group(4)
- seeline = ''
+ seeline = ""
dbg_info(f"see also: `{seealso}`")
- if re.match(r'^http', seealso):
+ if re.match(r"^http", seealso):
seeline = f"{seealso}"
- elif seealso_match := re.match(r'^(Qgs[A-Z]\w+(\([^()]*\))?)(\.)?$', seealso):
+ elif seealso_match := re.match(
+ r"^(Qgs[A-Z]\w+(\([^()]*\))?)(\.)?$", seealso
+ ):
dbg_info(f"\\see :py:class:`{seealso_match.group(1)}`")
seeline = f":py:class:`{seealso_match.group(1)}`{seealso_match.group(3) or ''}"
- elif seealso_match := re.match(r'^((Qgs[A-Z]\w+)\.(\w+)(\([^()]*\))?)(\.)?$', seealso):
- dbg_info(f"\\see py:func with param: :py:func:`{seealso_match.group(1)}`")
- seeline = f":py:func:`{seealso_match.group(1)}`{seealso_match.group(5) or ''}"
- elif seealso_match := re.match(r'^([a-z]\w+(\([^()]*\))?)(\.)?$', seealso):
+ elif seealso_match := re.match(
+ r"^((Qgs[A-Z]\w+)\.(\w+)(\([^()]*\))?)(\.)?$", seealso
+ ):
+ dbg_info(
+ f"\\see py:func with param: :py:func:`{seealso_match.group(1)}`"
+ )
+ seeline = (
+ f":py:func:`{seealso_match.group(1)}`{seealso_match.group(5) or ''}"
+ )
+ elif seealso_match := re.match(r"^([a-z]\w+(\([^()]*\))?)(\.)?$", seealso):
dbg_info(f"\\see :py:func:`{seealso_match.group(1)}`")
- seeline = f":py:func:`{seealso_match.group(1)}`{seealso_match.group(3) or ''}"
-
- if full_line_match := re.match(r'^\s*\\see +(\w+(?:\.\w+)*)(?:\([^()]*\))?[\s,.:-]*(.*?)$', line):
- if seeline.startswith('http'):
+ seeline = (
+ f":py:func:`{seealso_match.group(1)}`{seealso_match.group(3) or ''}"
+ )
+
+ if full_line_match := re.match(
+ r"^\s*\\see +(\w+(?:\.\w+)*)(?:\([^()]*\))?[\s,.:-]*(.*?)$", line
+ ):
+ if seeline.startswith("http"):
return f"\n.. seealso:: {seeline}\n"
suffix = full_line_match.group(2)
if suffix:
@@ -886,32 +930,36 @@ def process_doxygen_line(line: str) -> str:
return f"\n.. seealso:: {seeline or seealso}\n"
else:
if seeline:
- line = line[:see_match.start()] + seeline + seealso_suffix + line[
- see_match.end():] # re.sub(r'\\see +(\w+(\.\w+)*(\(\))?)', seeline, line)
+ line = (
+ line[: see_match.start()]
+ + seeline
+ + seealso_suffix
+ + line[see_match.end() :]
+ ) # re.sub(r'\\see +(\w+(\.\w+)*(\(\))?)', seeline, line)
else:
- line = line.replace('\\see', 'see')
- elif not re.search(r'\\throws.*', line):
+ line = line.replace("\\see", "see")
+ elif not re.search(r"\\throws.*", line):
line = create_class_links(line)
# Handle note, warning, and throws
- note_match = re.search(r'[\\@]note (.*)', line)
+ note_match = re.search(r"[\\@]note (.*)", line)
if note_match:
CONTEXT.comment_last_line_note_warning = True
CONTEXT.prev_indent = CONTEXT.indent
- CONTEXT.indent = ''
+ CONTEXT.indent = ""
return f"\n.. note::\n\n {note_match.group(1)}\n"
- warning_match = re.search(r'[\\@]warning (.*)', line)
+ warning_match = re.search(r"[\\@]warning (.*)", line)
if warning_match:
CONTEXT.prev_indent = CONTEXT.indent
- CONTEXT.indent = ''
+ CONTEXT.indent = ""
CONTEXT.comment_last_line_note_warning = True
return f"\n.. warning::\n\n {warning_match.group(1)}\n"
- throws_match = re.search(r'[\\@]throws (.+?)\b\s*(.*)', line)
+ throws_match = re.search(r"[\\@]throws (.+?)\b\s*(.*)", line)
if throws_match:
CONTEXT.prev_indent = CONTEXT.indent
- CONTEXT.indent = ''
+ CONTEXT.indent = ""
CONTEXT.comment_last_line_note_warning = True
return f"\n:raises {throws_match.group(1)}: {throws_match.group(2)}\n"
@@ -928,19 +976,22 @@ def process_doxygen_line(line: str) -> str:
def detect_and_remove_following_body_or_initializerlist():
global CONTEXT
- signature = ''
+ signature = ""
# Complex regex pattern to match various C++ function declarations and definitions
pattern1 = r'^(\s*)?((?:(?:explicit|static|const|unsigned|virtual)\s+)*)(([(?:long )\w:]+(<.*?>)?\s+[*&]?)?(~?\w+|(\w+::)?operator.{1,2})\s*\(([\w=()\/ ,&*<>."-]|::)*\)( +(?:const|SIP_[\w_]+?))*)\s*((\s*[:,]\s+\w+\(.*\))*\s*\{.*\}\s*(?:SIP_[\w_]+)?;?|(?!;))(\s*\/\/.*)?$'
- pattern2 = r'SIP_SKIP\s*(?!;)\s*(\/\/.*)?$'
- pattern3 = r'^\s*class.*SIP_SKIP'
+ pattern2 = r"SIP_SKIP\s*(?!;)\s*(\/\/.*)?$"
+ pattern3 = r"^\s*class.*SIP_SKIP"
- if (re.match(pattern1, CONTEXT.current_line) or
- re.search(pattern2, CONTEXT.current_line) or
- re.match(pattern3, CONTEXT.current_line)):
+ if (
+ re.match(pattern1, CONTEXT.current_line)
+ or re.search(pattern2, CONTEXT.current_line)
+ or re.match(pattern3, CONTEXT.current_line)
+ ):
dbg_info(
- "remove constructor definition, function bodies, member initializing list (1)")
+ "remove constructor definition, function bodies, member initializing list (1)"
+ )
# Extract the parts we want to keep
initializer_match = re.match(pattern1, CONTEXT.current_line)
@@ -950,8 +1001,7 @@ def detect_and_remove_following_body_or_initializerlist():
newline = CONTEXT.current_line
# Call remove_following_body_or_initializerlist() if necessary
- if not re.search(r'{.*}(\s*SIP_\w+)*\s*(//.*)?$',
- CONTEXT.current_line):
+ if not re.search(r"{.*}(\s*SIP_\w+)*\s*(//.*)?$", CONTEXT.current_line):
signature = remove_following_body_or_initializerlist()
CONTEXT.current_line = newline
@@ -962,21 +1012,22 @@ def detect_and_remove_following_body_or_initializerlist():
def remove_following_body_or_initializerlist():
global CONTEXT
- signature = ''
+ signature = ""
dbg_info(
- "remove constructor definition, function bodies, member initializing list (2)")
+ "remove constructor definition, function bodies, member initializing list (2)"
+ )
line = read_line()
# Python signature
- if re.match(r'^\s*\[\s*(\w+\s*)?\(', line):
+ if re.match(r"^\s*\[\s*(\w+\s*)?\(", line):
dbg_info("python signature detected")
_nesting_index = 0
while CONTEXT.line_idx < CONTEXT.line_count:
- _nesting_index += line.count('[')
- _nesting_index -= line.count(']')
+ _nesting_index += line.count("[")
+ _nesting_index -= line.count("]")
if _nesting_index == 0:
- line_match = re.match(r'^(.*);\s*(//.*)?$', line)
+ line_match = re.match(r"^(.*);\s*(//.*)?$", line)
if line_match:
line = line_match.group(1) # remove semicolon (added later)
signature += f"\n{line}"
@@ -986,17 +1037,17 @@ def remove_following_body_or_initializerlist():
line = read_line()
# Member initializing list
- while re.match(r'^\s*[:,]\s+([\w<>]|::)+\(.*?\)', line):
+ while re.match(r"^\s*[:,]\s+([\w<>]|::)+\(.*?\)", line):
dbg_info("member initializing list")
line = read_line()
# Body
- if re.match(r'^\s*\{', line):
+ if re.match(r"^\s*\{", line):
_nesting_index = 0
while CONTEXT.line_idx < CONTEXT.line_count:
dbg_info(" remove body")
- _nesting_index += line.count('{')
- _nesting_index -= line.count('}')
+ _nesting_index += line.count("{")
+ _nesting_index -= line.count("}")
if _nesting_index == 0:
break
line = read_line()
@@ -1010,37 +1061,37 @@ def replace_alternative_types(text):
"""
# Original perl regex was:
# s/(\w+)(\<(?>[^<>]|(?2))*\>)?\s+SIP_PYALTERNATIVETYPE\(\s*\'?([^()']+)(\(\s*(?:[^()]++|(?2))*\s*\))?\'?\s*\)/$3/g;
- _pattern = r'(\w+)(<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>)?\s+SIP_PYALTERNATIVETYPE\(\s*\'?([^()\']+)(\(\s*(?:[^()]|\([^()]*\))*\s*\))?\'?\s*\)'
+ _pattern = r"(\w+)(<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>)?\s+SIP_PYALTERNATIVETYPE\(\s*\'?([^()\']+)(\(\s*(?:[^()]|\([^()]*\))*\s*\))?\'?\s*\)"
while True:
- new_text = re.sub(_pattern, r'\3', text, flags=re.S)
+ new_text = re.sub(_pattern, r"\3", text, flags=re.S)
if new_text == text:
return text
text = new_text
-def split_args(args_string: str) -> List[str]:
+def split_args(args_string: str) -> list[str]:
"""
Tries to split a line of arguments into separate parts
"""
res = []
- current_arg = ''
+ current_arg = ""
paren_level = 0
angle_level = 0
for char in args_string:
- if char == ',' and paren_level == 0 and angle_level == 0:
+ if char == "," and paren_level == 0 and angle_level == 0:
res.append(current_arg.strip())
- current_arg = ''
+ current_arg = ""
else:
current_arg += char
- if char == '(':
+ if char == "(":
paren_level += 1
- elif char == ')':
+ elif char == ")":
paren_level -= 1
- elif char == '<':
+ elif char == "<":
angle_level += 1
- elif char == '>':
+ elif char == ">":
angle_level -= 1
if current_arg:
@@ -1055,37 +1106,38 @@ def remove_sip_pyargremove(input_string: str) -> str:
"""
global CONTEXT
# Split the string into function signature and body
- signature_split = re.match(r'(.*?)\((.*)\)(.*)', input_string)
- if signature_split and 'SIP_PYARGREMOVE' not in signature_split.group(1):
+ signature_split = re.match(r"(.*?)\((.*)\)(.*)", input_string)
+ if signature_split and "SIP_PYARGREMOVE" not in signature_split.group(1):
prefix, arguments, suffix = signature_split.groups()
- prefix += '('
- suffix = ')' + suffix
+ prefix += "("
+ suffix = ")" + suffix
else:
- signature_split = re.match(r'(\s*)(.*)\)(.*)', input_string)
+ signature_split = re.match(r"(\s*)(.*)\)(.*)", input_string)
if signature_split:
prefix, arguments, suffix = signature_split.groups()
- suffix = ')' + suffix
+ suffix = ")" + suffix
else:
- prefix = ''
+ prefix = ""
arguments = input_string
- suffix = ''
+ suffix = ""
arguments_list = split_args(arguments)
if CONTEXT.is_qt6:
- filtered_args = [arg for arg in arguments_list if
- 'SIP_PYARGREMOVE' not in arg]
+ filtered_args = [arg for arg in arguments_list if "SIP_PYARGREMOVE" not in arg]
else:
- filtered_args = [re.sub(r'\s*SIP_PYARGREMOVE6\s*', ' ', arg)
- for arg in arguments_list if
- not ('SIP_PYARGREMOVE' in arg and 'SIP_PYARGREMOVE6' not in arg)]
+ filtered_args = [
+ re.sub(r"\s*SIP_PYARGREMOVE6\s*", " ", arg)
+ for arg in arguments_list
+ if not ("SIP_PYARGREMOVE" in arg and "SIP_PYARGREMOVE6" not in arg)
+ ]
# Reassemble the function signature
- remaining_args = ', '.join(filtered_args)
+ remaining_args = ", ".join(filtered_args)
if remaining_args and prefix.strip():
- prefix += ' '
+ prefix += " "
if remaining_args and suffix.strip():
- suffix = ' ' + suffix
+ suffix = " " + suffix
return f"{prefix}{remaining_args}{suffix}"
@@ -1093,50 +1145,50 @@ def fix_annotations(line):
global CONTEXT
# Get removed params to be able to drop them out of the API doc
- removed_params = re.findall(r'(\w+)\s+SIP_PYARGREMOVE', line)
+ removed_params = re.findall(r"(\w+)\s+SIP_PYARGREMOVE", line)
if CONTEXT.is_qt6:
- removed_params = re.findall(r'(\w+)\s+SIP_PYARGREMOVE6?', line)
+ removed_params = re.findall(r"(\w+)\s+SIP_PYARGREMOVE6?", line)
for param in removed_params:
CONTEXT.skipped_params_remove.append(param)
dbg_info(f"caught removed param: {CONTEXT.skipped_params_remove[-1]}")
- _out_params = re.findall(r'(\w+)\s+SIP_OUT', line)
+ _out_params = re.findall(r"(\w+)\s+SIP_OUT", line)
for param in _out_params:
CONTEXT.skipped_params_out.append(param)
dbg_info(f"caught removed param: {CONTEXT.skipped_params_out[-1]}")
# Printed annotations
replacements = {
- r'//\s*SIP_ABSTRACT\b': '/Abstract/',
- r'\bSIP_ABSTRACT\b': '/Abstract/',
- r'\bSIP_ALLOWNONE\b': '/AllowNone/',
- r'\bSIP_ARRAY\b': '/Array/',
- r'\bSIP_ARRAYSIZE\b': '/ArraySize/',
- r'\bSIP_DEPRECATED\b': '/Deprecated/',
- r'\bSIP_CONSTRAINED\b': '/Constrained/',
- r'\bSIP_EXTERNAL\b': '/External/',
- r'\bSIP_FACTORY\b': '/Factory/',
- r'\bSIP_IN\b': '/In/',
- r'\bSIP_INOUT\b': '/In,Out/',
- r'\bSIP_KEEPREFERENCE\b': '/KeepReference/',
- r'\bSIP_NODEFAULTCTORS\b': '/NoDefaultCtors/',
- r'\bSIP_OUT\b': '/Out/',
- r'\bSIP_RELEASEGIL\b': '/ReleaseGIL/',
- r'\bSIP_HOLDGIL\b': '/HoldGIL/',
- r'\bSIP_TRANSFER\b': '/Transfer/',
- r'\bSIP_TRANSFERBACK\b': '/TransferBack/',
- r'\bSIP_TRANSFERTHIS\b': '/TransferThis/',
- r'\bSIP_GETWRAPPER\b': '/GetWrapper/',
- r'SIP_PYNAME\(\s*(\w+)\s*\)': r'/PyName=\1/',
- r'SIP_TYPEHINT\(\s*([\w\.\s,\[\]]+?)\s*\)': r'/TypeHint="\1"/',
- r'SIP_VIRTUALERRORHANDLER\(\s*(\w+)\s*\)': r'/VirtualErrorHandler=\1/',
+ r"//\s*SIP_ABSTRACT\b": "/Abstract/",
+ r"\bSIP_ABSTRACT\b": "/Abstract/",
+ r"\bSIP_ALLOWNONE\b": "/AllowNone/",
+ r"\bSIP_ARRAY\b": "/Array/",
+ r"\bSIP_ARRAYSIZE\b": "/ArraySize/",
+ r"\bSIP_DEPRECATED\b": "/Deprecated/",
+ r"\bSIP_CONSTRAINED\b": "/Constrained/",
+ r"\bSIP_EXTERNAL\b": "/External/",
+ r"\bSIP_FACTORY\b": "/Factory/",
+ r"\bSIP_IN\b": "/In/",
+ r"\bSIP_INOUT\b": "/In,Out/",
+ r"\bSIP_KEEPREFERENCE\b": "/KeepReference/",
+ r"\bSIP_NODEFAULTCTORS\b": "/NoDefaultCtors/",
+ r"\bSIP_OUT\b": "/Out/",
+ r"\bSIP_RELEASEGIL\b": "/ReleaseGIL/",
+ r"\bSIP_HOLDGIL\b": "/HoldGIL/",
+ r"\bSIP_TRANSFER\b": "/Transfer/",
+ r"\bSIP_TRANSFERBACK\b": "/TransferBack/",
+ r"\bSIP_TRANSFERTHIS\b": "/TransferThis/",
+ r"\bSIP_GETWRAPPER\b": "/GetWrapper/",
+ r"SIP_PYNAME\(\s*(\w+)\s*\)": r"/PyName=\1/",
+ r"SIP_TYPEHINT\(\s*([\w\.\s,\[\]]+?)\s*\)": r'/TypeHint="\1"/',
+ r"SIP_VIRTUALERRORHANDLER\(\s*(\w+)\s*\)": r"/VirtualErrorHandler=\1/",
}
if not CONTEXT.is_qt6:
- replacements[r'SIP_THROW\(\s*([\w\s,]+?)\s*\)'] = r'throw( \1 )'
+ replacements[r"SIP_THROW\(\s*([\w\s,]+?)\s*\)"] = r"throw( \1 )"
else:
# these have no effect (and aren't required) on sip >= 6
- replacements[r'SIP_THROW\(\s*([\w\s,]+?)\s*\)'] = ''
+ replacements[r"SIP_THROW\(\s*([\w\s,]+?)\s*\)"] = ""
for _pattern, replacement in replacements.items():
line = re.sub(_pattern, replacement, line)
@@ -1145,7 +1197,9 @@ def fix_annotations(line):
while True:
new_line = re.sub(
r'/([\w,]+(="?[\w, \[\]]+"?)?)/\s*/([\w,]+(="?[\w, \[\]]+"?)?]?)/',
- r'/\1,\3/', line)
+ r"/\1,\3/",
+ line,
+ )
if new_line == line:
break
line = new_line
@@ -1153,22 +1207,23 @@ def fix_annotations(line):
# Unprinted annotations
line = replace_alternative_types(line)
- line = re.sub(r'(\w+)\s+SIP_PYARGRENAME\(\s*(\w+)\s*\)', r'\2', line)
+ line = re.sub(r"(\w+)\s+SIP_PYARGRENAME\(\s*(\w+)\s*\)", r"\2", line)
# Note: this was the original perl regex, which isn't compatible with Python:
# line = re.sub(r"""=\s+[^=]*?\s+SIP_PYARGDEFAULT\(\s*\'?([^()']+)(\(\s*(?:[^()]++|(?2))*\s*\))?\'?\s*\)""", r'= \1', line)
line = re.sub(
r"""=\s+[^=]*?\s+SIP_PYARGDEFAULT\(\s*\'?([^()\']+)(\((?:[^()]|\([^()]*\))*\))?\'?\s*\)""",
- r'= \1',
- line)
+ r"= \1",
+ line,
+ )
# Remove argument
- if 'SIP_PYARGREMOVE' in line:
+ if "SIP_PYARGREMOVE" in line:
dbg_info("remove arg")
if CONTEXT.multiline_definition != MultiLineType.NotMultiline:
prev_line = CONTEXT.output.pop().rstrip()
# Update multi line status
- parenthesis_balance = prev_line.count('(') - prev_line.count(')')
+ parenthesis_balance = prev_line.count("(") - prev_line.count(")")
if parenthesis_balance == 1:
CONTEXT.multiline_definition = MultiLineType.NotMultiline
# Concatenate with above line to bring previous commas
@@ -1176,30 +1231,26 @@ def fix_annotations(line):
# original perl regex was:
# (?, +)?(const )?(\w+)(\<(?>[^<>]|(?4))*\>)?\s+[\w&*]+\s+SIP_PYARGREMOVE( = [^()]*(\(\s*(?:[^()]++|(?6))*\s*\))?)?(?()|,?)//
- if 'SIP_PYARGREMOVE' in line:
+ if "SIP_PYARGREMOVE" in line:
line = remove_sip_pyargremove(line)
- line = re.sub(r'\(\s+\)', '()', line)
+ line = re.sub(r"\(\s+\)", "()", line)
- line = re.sub(r'SIP_FORCE', '', line)
- line = re.sub(r'SIP_DOC_TEMPLATE', '', line)
- line = re.sub(r'\s+;$', ';', line)
+ line = re.sub(r"SIP_FORCE", "", line)
+ line = re.sub(r"SIP_DOC_TEMPLATE", "", line)
+ line = re.sub(r"\s+;$", ";", line)
return line
def fix_constants(line):
- line = re.sub(r'\bstd::numeric_limits::max\(\)', 'DBL_MAX', line)
- line = re.sub(r'\bstd::numeric_limits::lowest\(\)', '-DBL_MAX',
- line)
- line = re.sub(r'\bstd::numeric_limits::epsilon\(\)', 'DBL_EPSILON',
- line)
- line = re.sub(r'\bstd::numeric_limits::min\(\)', 'LLONG_MIN',
- line)
- line = re.sub(r'\bstd::numeric_limits::max\(\)', 'LLONG_MAX',
- line)
- line = re.sub(r'\bstd::numeric_limits::max\(\)', 'INT_MAX', line)
- line = re.sub(r'\bstd::numeric_limits::min\(\)', 'INT_MIN', line)
+ line = re.sub(r"\bstd::numeric_limits::max\(\)", "DBL_MAX", line)
+ line = re.sub(r"\bstd::numeric_limits::lowest\(\)", "-DBL_MAX", line)
+ line = re.sub(r"\bstd::numeric_limits::epsilon\(\)", "DBL_EPSILON", line)
+ line = re.sub(r"\bstd::numeric_limits::min\(\)", "LLONG_MIN", line)
+ line = re.sub(r"\bstd::numeric_limits::max\(\)", "LLONG_MAX", line)
+ line = re.sub(r"\bstd::numeric_limits::max\(\)", "INT_MAX", line)
+ line = re.sub(r"\bstd::numeric_limits::min\(\)", "INT_MIN", line)
return line
@@ -1208,8 +1259,8 @@ def detect_comment_block(strict_mode=True):
global CONTEXT
CONTEXT.comment_param_list = False
- CONTEXT.indent = ''
- CONTEXT.prev_indent = ''
+ CONTEXT.indent = ""
+ CONTEXT.prev_indent = ""
CONTEXT.comment_code_snippet = CodeSnippetType.NotCodeSnippet
CONTEXT.comment_last_line_note_warning = False
CONTEXT.found_since = False
@@ -1217,21 +1268,24 @@ def detect_comment_block(strict_mode=True):
CONTEXT.skipped_params_out = []
CONTEXT.skipped_params_remove = []
- if re.match(r'^\s*/\*', CONTEXT.current_line) or (
- not strict_mode and '/*' in CONTEXT.current_line):
+ if re.match(r"^\s*/\*", CONTEXT.current_line) or (
+ not strict_mode and "/*" in CONTEXT.current_line
+ ):
dbg_info("found comment block")
CONTEXT.comment = process_doxygen_line(
- re.sub(r'^\s*/\*(\*)?(.*?)\n?$', r'\2', CONTEXT.current_line))
- CONTEXT.comment = re.sub(r'^\s*$', '', CONTEXT.comment)
+ re.sub(r"^\s*/\*(\*)?(.*?)\n?$", r"\2", CONTEXT.current_line)
+ )
+ CONTEXT.comment = re.sub(r"^\s*$", "", CONTEXT.comment)
- while not re.search(r'\*/\s*(//.*?)?$', CONTEXT.current_line):
+ while not re.search(r"\*/\s*(//.*?)?$", CONTEXT.current_line):
CONTEXT.current_line = read_line()
CONTEXT.comment += process_doxygen_line(
- re.sub(r'\s*\*?(.*?)(/)?\n?$', r'\1', CONTEXT.current_line))
+ re.sub(r"\s*\*?(.*?)(/)?\n?$", r"\1", CONTEXT.current_line)
+ )
- CONTEXT.comment = re.sub(r'\n\s+\n', '\n\n', CONTEXT.comment)
- CONTEXT.comment = re.sub(r'\n{3,}', '\n\n', CONTEXT.comment)
- CONTEXT.comment = re.sub(r'\n+$', '', CONTEXT.comment)
+ CONTEXT.comment = re.sub(r"\n\s+\n", "\n\n", CONTEXT.comment)
+ CONTEXT.comment = re.sub(r"\n{3,}", "\n\n", CONTEXT.comment)
+ CONTEXT.comment = re.sub(r"\n+$", "", CONTEXT.comment)
return True
@@ -1239,7 +1293,7 @@ def detect_comment_block(strict_mode=True):
def detect_non_method_member(line):
- _pattern = r'''^\s*(?:template\s*<\w+>\s+)?(?:(const|mutable|static|friend|unsigned)\s+)*\w+(::\w+)?(<([\w<> *&,()]|::)+>)?(,?\s+\*?\w+( = (-?\d+(\.\d+)?|((QMap|QList)<[^()]+>\(\))|(\w+::)*\w+(\([^()]?\))?)|\[\d+\])?)+;'''
+ _pattern = r"""^\s*(?:template\s*<\w+>\s+)?(?:(const|mutable|static|friend|unsigned)\s+)*\w+(::\w+)?(<([\w<> *&,()]|::)+>)?(,?\s+\*?\w+( = (-?\d+(\.\d+)?|((QMap|QList)<[^()]+>\(\))|(\w+::)*\w+(\([^()]?\))?)|\[\d+\])?)+;"""
return re.match(_pattern, line)
@@ -1248,41 +1302,41 @@ def convert_type(cpp_type: str) -> str:
Converts C++ types to Python types
"""
type_mapping = {
- 'int': 'int',
- 'float': 'float',
- 'double': 'float',
- 'bool': 'bool',
- 'char': 'str',
- 'QString': 'str',
- 'void': 'None',
- 'qint64': 'int',
- 'unsigned long long': 'int',
- 'long long': 'int',
- 'qlonglong': 'int',
- 'long': 'int',
- 'QStringList': 'List[str]',
- 'QVariantList': 'List[object]',
- 'QVariantMap': 'Dict[str, object]',
- 'QVariant': 'object'
+ "int": "int",
+ "float": "float",
+ "double": "float",
+ "bool": "bool",
+ "char": "str",
+ "QString": "str",
+ "void": "None",
+ "qint64": "int",
+ "unsigned long long": "int",
+ "long long": "int",
+ "qlonglong": "int",
+ "long": "int",
+ "QStringList": "List[str]",
+ "QVariantList": "List[object]",
+ "QVariantMap": "Dict[str, object]",
+ "QVariant": "object",
}
# Handle templates
- template_match = re.match(r'(\w+)\s*<\s*(.+)\s*>', cpp_type)
+ template_match = re.match(r"(\w+)\s*<\s*(.+)\s*>", cpp_type)
if template_match:
container, inner_type = template_match.groups()
- if container in ('QVector', 'QList'):
+ if container in ("QVector", "QList"):
return f"List[{convert_type(inner_type.strip())}]"
- elif container in ('QSet',):
+ elif container in ("QSet",):
return f"Set[{convert_type(inner_type.strip())}]"
- elif container in ('QHash', 'QMap'):
- key_type, value_type = [t.strip() for t in inner_type.split(',')]
+ elif container in ("QHash", "QMap"):
+ key_type, value_type = (t.strip() for t in inner_type.split(","))
return f"Dict[{convert_type(key_type)}, {convert_type(value_type)}]"
else:
return f"{container}[{convert_type(inner_type.strip())}]"
if cpp_type not in type_mapping:
- if cpp_type.startswith('Q'):
- cpp_type = cpp_type.replace('::', '.')
+ if cpp_type.startswith("Q"):
+ cpp_type = cpp_type.replace("::", ".")
return cpp_type
assert False, cpp_type
@@ -1290,27 +1344,27 @@ def convert_type(cpp_type: str) -> str:
return type_mapping[cpp_type]
-def parse_argument(arg: str) -> Tuple[str, str, Optional[str]]:
+def parse_argument(arg: str) -> tuple[str, str, Optional[str]]:
# Remove leading/trailing whitespace and 'const'
- arg = re.sub(r'^\s*const\s+', '', arg.strip())
+ arg = re.sub(r"^\s*const\s+", "", arg.strip())
# Extract default value if present
- default_match = re.search(r'=\s*(.+)$', arg)
+ default_match = re.search(r"=\s*(.+)$", arg)
default_value = default_match.group(1).strip() if default_match else None
- arg = re.sub(r'\s*=\s*.+$', '', arg)
+ arg = re.sub(r"\s*=\s*.+$", "", arg)
# Handle pointers and references
- is_pointer = '*' in arg
- arg = arg.replace('*', '').replace('&', '').strip()
+ is_pointer = "*" in arg
+ arg = arg.replace("*", "").replace("&", "").strip()
# Split type and variable name
parts = arg.split()
if len(parts) > 1:
- cpp_type = ' '.join(parts[:-1])
+ cpp_type = " ".join(parts[:-1])
var_name = parts[-1]
else:
cpp_type = arg
- var_name = ''
+ var_name = ""
python_type = convert_type(cpp_type)
if is_pointer and default_value:
@@ -1318,27 +1372,25 @@ def parse_argument(arg: str) -> Tuple[str, str, Optional[str]]:
# Convert default value
if default_value:
- default_value_map = {
- 'QVariantList()': '[]'
- }
+ default_value_map = {"QVariantList()": "[]"}
if default_value in default_value_map:
default_value = default_value_map[default_value]
elif default_value == "nullptr":
default_value = "None"
- elif python_type == 'int':
+ elif python_type == "int":
pass
- elif cpp_type in ("QString", ):
- if default_value == 'QString()':
- default_value = 'None'
- python_type = f'Optional[{python_type}]'
- elif default_value.startswith('Q'):
- default_value = default_value.replace('::', '.')
+ elif cpp_type in ("QString",):
+ if default_value == "QString()":
+ default_value = "None"
+ python_type = f"Optional[{python_type}]"
+ elif default_value.startswith("Q"):
+ default_value = default_value.replace("::", ".")
else:
default_value = f'"{default_value}"'
elif cpp_type in ("bool",):
default_value = f'{"False" if default_value == "false" else "True"}'
- elif cpp_type.startswith('Q'):
- default_value = default_value.replace('::', '.')
+ elif cpp_type.startswith("Q"):
+ default_value = default_value.replace("::", ".")
else:
assert False, (default_value, cpp_type)
@@ -1348,12 +1400,14 @@ def parse_argument(arg: str) -> Tuple[str, str, Optional[str]]:
def cpp_to_python_signature(cpp_function: str) -> str:
# Extract function name and arguments
- match = re.match(r'(\w+)\s*\((.*)\)\s*(?:const)?\s*(?:->)?\s*([\w:]+)?', cpp_function)
+ match = re.match(
+ r"(\w+)\s*\((.*)\)\s*(?:const)?\s*(?:->)?\s*([\w:]+)?", cpp_function
+ )
if not match:
raise ValueError("Invalid C++ function signature")
func_name, args_str, return_type = match.groups()
- args = [arg.strip() for arg in args_str.split(',') if arg.strip()]
+ args = [arg.strip() for arg in args_str.split(",") if arg.strip()]
# Parse arguments
python_args = []
@@ -1374,197 +1428,203 @@ def cpp_to_python_signature(cpp_function: str) -> str:
while CONTEXT.line_idx < CONTEXT.line_count:
- CONTEXT.python_signature = ''
+ CONTEXT.python_signature = ""
CONTEXT.actual_class = CONTEXT.classname[-1] if CONTEXT.classname else None
CONTEXT.current_line = read_line()
- if re.match(r'^\s*(#define\s+)?SIP_IF_MODULE\(.*\)$',
- CONTEXT.current_line):
- dbg_info('skipping SIP include condition macro')
+ if re.match(r"^\s*(#define\s+)?SIP_IF_MODULE\(.*\)$", CONTEXT.current_line):
+ dbg_info("skipping SIP include condition macro")
continue
- match = re.match(r'^(.*?)\s*//\s*cppcheck-suppress.*$',
- CONTEXT.current_line)
+ match = re.match(r"^(.*?)\s*//\s*cppcheck-suppress.*$", CONTEXT.current_line)
if match:
CONTEXT.current_line = match.group(1)
- match = re.match(r'^\s*SIP_FEATURE\(\s*(\w+)\s*\)(.*)$',
- CONTEXT.current_line)
+ match = re.match(r"^\s*SIP_FEATURE\(\s*(\w+)\s*\)(.*)$", CONTEXT.current_line)
if match:
write_output("SF1", f"%Feature {match.group(1)}{match.group(2)}\n")
continue
- match = re.match(r'^\s*SIP_PROPERTY\((.*)\)$', CONTEXT.current_line)
+ match = re.match(r"^\s*SIP_PROPERTY\((.*)\)$", CONTEXT.current_line)
if match:
write_output("SF1", f"%Property({match.group(1)})\n")
continue
- match = re.match(r'^\s*SIP_IF_FEATURE\(\s*(!?\w+)\s*\)(.*)$',
- CONTEXT.current_line)
+ match = re.match(r"^\s*SIP_IF_FEATURE\(\s*(!?\w+)\s*\)(.*)$", CONTEXT.current_line)
if match:
write_output("SF2", f"%If ({match.group(1)}){match.group(2)}\n")
continue
- match = re.match(r'^\s*SIP_CONVERT_TO_SUBCLASS_CODE(.*)$',
- CONTEXT.current_line)
+ match = re.match(r"^\s*SIP_CONVERT_TO_SUBCLASS_CODE(.*)$", CONTEXT.current_line)
if match:
CONTEXT.current_line = f"%ConvertToSubClassCode{match.group(1)}"
# Do not continue here, let the code process the next steps
- match = re.match(r'^\s*SIP_VIRTUAL_CATCHER_CODE(.*)$',
- CONTEXT.current_line)
+ match = re.match(r"^\s*SIP_VIRTUAL_CATCHER_CODE(.*)$", CONTEXT.current_line)
if match:
CONTEXT.current_line = f"%VirtualCatcherCode{match.group(1)}"
# Do not continue here, let the code process the next steps
- match = re.match(r'^\s*SIP_END(.*)$', CONTEXT.current_line)
+ match = re.match(r"^\s*SIP_END(.*)$", CONTEXT.current_line)
if match:
write_output("SEN", f"%End{match.group(1)}\n")
continue
- match = re.search(r'SIP_WHEN_FEATURE\(\s*(.*?)\s*\)', CONTEXT.current_line)
+ match = re.search(r"SIP_WHEN_FEATURE\(\s*(.*?)\s*\)", CONTEXT.current_line)
if match:
- dbg_info('found SIP_WHEN_FEATURE')
+ dbg_info("found SIP_WHEN_FEATURE")
CONTEXT.if_feature_condition = match.group(1)
if CONTEXT.is_qt6:
- CONTEXT.current_line = re.sub(r'int\s*__len__\s*\(\s*\)',
- 'Py_ssize_t __len__()',
- CONTEXT.current_line)
- CONTEXT.current_line = re.sub(r'long\s*__hash__\s*\(\s*\)',
- 'Py_hash_t __hash__()',
- CONTEXT.current_line)
-
- if CONTEXT.is_qt6 and re.match(r'^\s*#ifdef SIP_PYQT5_RUN',
- CONTEXT.current_line):
+ CONTEXT.current_line = re.sub(
+ r"int\s*__len__\s*\(\s*\)", "Py_ssize_t __len__()", CONTEXT.current_line
+ )
+ CONTEXT.current_line = re.sub(
+ r"long\s*__hash__\s*\(\s*\)", "Py_hash_t __hash__()", CONTEXT.current_line
+ )
+
+ if CONTEXT.is_qt6 and re.match(r"^\s*#ifdef SIP_PYQT5_RUN", CONTEXT.current_line):
dbg_info("do not process PYQT5 code")
- while not re.match(r'^#endif', CONTEXT.current_line):
+ while not re.match(r"^#endif", CONTEXT.current_line):
CONTEXT.current_line = read_line()
- if not CONTEXT.is_qt6 and re.match(r'^\s*#ifdef SIP_PYQT6_RUN',
- CONTEXT.current_line):
+ if not CONTEXT.is_qt6 and re.match(
+ r"^\s*#ifdef SIP_PYQT6_RUN", CONTEXT.current_line
+ ):
dbg_info("do not process PYQT6 code")
- while not re.match(r'^#endif', CONTEXT.current_line):
+ while not re.match(r"^#endif", CONTEXT.current_line):
CONTEXT.current_line = read_line()
# Do not process SIP code %XXXCode
if CONTEXT.sip_run and re.match(
- r'^ *% *(VirtualErrorHandler|MappedType|Type(?:Header)?Code|Module(?:Header)?Code|Convert(?:From|To)(?:Type|SubClass)Code|MethodCode|Docstring)(.*)?$',
- CONTEXT.current_line):
- CONTEXT.current_line = f"%{re.match(r'^ *% *(.*)$', CONTEXT.current_line).group(1)}"
- CONTEXT.comment = ''
+ r"^ *% *(VirtualErrorHandler|MappedType|Type(?:Header)?Code|Module(?:Header)?Code|Convert(?:From|To)(?:Type|SubClass)Code|MethodCode|Docstring)(.*)?$",
+ CONTEXT.current_line,
+ ):
+ CONTEXT.current_line = (
+ f"%{re.match(r'^ *% *(.*)$', CONTEXT.current_line).group(1)}"
+ )
+ CONTEXT.comment = ""
dbg_info("do not process SIP code")
- while not re.match(r'^ *% *End', CONTEXT.current_line):
+ while not re.match(r"^ *% *End", CONTEXT.current_line):
write_output("COD", CONTEXT.current_line + "\n")
CONTEXT.current_line = read_line()
if CONTEXT.is_qt6:
- CONTEXT.current_line = re.sub(r'SIP_SSIZE_T', 'Py_ssize_t',
- CONTEXT.current_line)
- CONTEXT.current_line = re.sub(r'SIPLong_AsLong',
- 'PyLong_AsLong',
- CONTEXT.current_line)
+ CONTEXT.current_line = re.sub(
+ r"SIP_SSIZE_T", "Py_ssize_t", CONTEXT.current_line
+ )
+ CONTEXT.current_line = re.sub(
+ r"SIPLong_AsLong", "PyLong_AsLong", CONTEXT.current_line
+ )
+ CONTEXT.current_line = re.sub(
+ r"^ *% *(VirtualErrorHandler|MappedType|Type(?:Header)?Code|Module(?:Header)?Code|Convert(?:From|To)(?:Type|SubClass)Code|MethodCode|Docstring)(.*)?$",
+ r"%\1\2",
+ CONTEXT.current_line,
+ )
CONTEXT.current_line = re.sub(
- r'^ *% *(VirtualErrorHandler|MappedType|Type(?:Header)?Code|Module(?:Header)?Code|Convert(?:From|To)(?:Type|SubClass)Code|MethodCode|Docstring)(.*)?$',
- r'%\1\2', CONTEXT.current_line)
- CONTEXT.current_line = re.sub(r'^\s*SIP_END(.*)$', r'%End\1',
- CONTEXT.current_line)
+ r"^\s*SIP_END(.*)$", r"%End\1", CONTEXT.current_line
+ )
- CONTEXT.current_line = re.sub(r'^\s*% End', '%End',
- CONTEXT.current_line)
+ CONTEXT.current_line = re.sub(r"^\s*% End", "%End", CONTEXT.current_line)
write_output("COD", CONTEXT.current_line + "\n")
continue
# Do not process SIP code %Property
- if CONTEXT.sip_run and re.match(r'^ *% *(Property)(.*)?$',
- CONTEXT.current_line):
- CONTEXT.current_line = f"%{re.match(r'^ *% *(.*)$', CONTEXT.current_line).group(1)}"
- CONTEXT.comment = ''
+ if CONTEXT.sip_run and re.match(r"^ *% *(Property)(.*)?$", CONTEXT.current_line):
+ CONTEXT.current_line = (
+ f"%{re.match(r'^ *% *(.*)$', CONTEXT.current_line).group(1)}"
+ )
+ CONTEXT.comment = ""
write_output("COD", CONTEXT.current_line + "\n")
continue
# Do not process SIP code %If %End
- if CONTEXT.sip_run and re.match(r'^ *% (If|End)(.*)?$',
- CONTEXT.current_line):
- CONTEXT.current_line = f"%{re.match(r'^ *% (.*)$', CONTEXT.current_line).group(1)}"
- CONTEXT.comment = ''
+ if CONTEXT.sip_run and re.match(r"^ *% (If|End)(.*)?$", CONTEXT.current_line):
+ CONTEXT.current_line = (
+ f"%{re.match(r'^ *% (.*)$', CONTEXT.current_line).group(1)}"
+ )
+ CONTEXT.comment = ""
write_output("COD", CONTEXT.current_line)
continue
# Skip preprocessor directives
- if re.match(r'^\s*#', CONTEXT.current_line):
+ if re.match(r"^\s*#", CONTEXT.current_line):
# Skip #if 0 or #if defined(Q_OS_WIN) blocks
- match = re.match(r'^\s*#if (0|defined\(Q_OS_WIN\))',
- CONTEXT.current_line)
+ match = re.match(r"^\s*#if (0|defined\(Q_OS_WIN\))", CONTEXT.current_line)
if match:
dbg_info(f"skipping #if {match.group(1)} block")
nesting_index = 0
while CONTEXT.line_idx < CONTEXT.line_count:
CONTEXT.current_line = read_line()
- if re.match(r'^\s*#if(def)?\s+', CONTEXT.current_line):
+ if re.match(r"^\s*#if(def)?\s+", CONTEXT.current_line):
nesting_index += 1
- elif nesting_index == 0 and re.match(r'^\s*#(endif|else)',
- CONTEXT.current_line):
- CONTEXT.comment = ''
+ elif nesting_index == 0 and re.match(
+ r"^\s*#(endif|else)", CONTEXT.current_line
+ ):
+ CONTEXT.comment = ""
break
- elif nesting_index != 0 and re.match(r'^\s*#endif',
- CONTEXT.current_line):
+ elif nesting_index != 0 and re.match(
+ r"^\s*#endif", CONTEXT.current_line
+ ):
nesting_index -= 1
continue
- if re.match(r'^\s*#ifdef SIP_RUN', CONTEXT.current_line):
+ if re.match(r"^\s*#ifdef SIP_RUN", CONTEXT.current_line):
CONTEXT.sip_run = True
if CONTEXT.access[-1] == Visibility.Private:
dbg_info("writing private content (1)")
if CONTEXT.private_section_line:
write_output("PRV1", CONTEXT.private_section_line + "\n")
- CONTEXT.private_section_line = ''
+ CONTEXT.private_section_line = ""
continue
if CONTEXT.sip_run:
- if re.match(r'^\s*#endif', CONTEXT.current_line):
+ if re.match(r"^\s*#endif", CONTEXT.current_line):
if CONTEXT.ifdef_nesting_idx == 0:
CONTEXT.sip_run = False
continue
else:
CONTEXT.ifdef_nesting_idx -= 1
- if re.match(r'^\s*#if(def)?\s+', CONTEXT.current_line):
+ if re.match(r"^\s*#if(def)?\s+", CONTEXT.current_line):
CONTEXT.ifdef_nesting_idx += 1
# If there is an else at this level, code will be ignored (i.e., not SIP_RUN)
- if re.match(r'^\s*#else',
- CONTEXT.current_line) and CONTEXT.ifdef_nesting_idx == 0:
+ if (
+ re.match(r"^\s*#else", CONTEXT.current_line)
+ and CONTEXT.ifdef_nesting_idx == 0
+ ):
while CONTEXT.line_idx < CONTEXT.line_count:
CONTEXT.current_line = read_line()
- if re.match(r'^\s*#if(def)?\s+', CONTEXT.current_line):
+ if re.match(r"^\s*#if(def)?\s+", CONTEXT.current_line):
CONTEXT.ifdef_nesting_idx += 1
- elif re.match(r'^\s*#endif', CONTEXT.current_line):
+ elif re.match(r"^\s*#endif", CONTEXT.current_line):
if CONTEXT.ifdef_nesting_idx == 0:
- CONTEXT.comment = ''
+ CONTEXT.comment = ""
CONTEXT.sip_run = False
break
else:
CONTEXT.ifdef_nesting_idx -= 1
continue
- elif re.match(r'^\s*#ifndef SIP_RUN', CONTEXT.current_line):
+ elif re.match(r"^\s*#ifndef SIP_RUN", CONTEXT.current_line):
# Code is ignored here
while CONTEXT.line_idx < CONTEXT.line_count:
CONTEXT.current_line = read_line()
- if re.match(r'^\s*#if(def)?\s+', CONTEXT.current_line):
+ if re.match(r"^\s*#if(def)?\s+", CONTEXT.current_line):
CONTEXT.ifdef_nesting_idx += 1
- elif re.match(r'^\s*#else',
- CONTEXT.current_line) and CONTEXT.ifdef_nesting_idx == 0:
+ elif (
+ re.match(r"^\s*#else", CONTEXT.current_line)
+ and CONTEXT.ifdef_nesting_idx == 0
+ ):
# Code here will be printed out
if CONTEXT.access[-1] == Visibility.Private:
dbg_info("writing private content (2)")
- if CONTEXT.private_section_line != '':
- write_output("PRV2",
- CONTEXT.private_section_line + "\n")
- CONTEXT.private_section_line = ''
+ if CONTEXT.private_section_line != "":
+ write_output("PRV2", CONTEXT.private_section_line + "\n")
+ CONTEXT.private_section_line = ""
CONTEXT.sip_run = True
break
- elif re.match(r'^\s*#endif', CONTEXT.current_line):
+ elif re.match(r"^\s*#endif", CONTEXT.current_line):
if CONTEXT.ifdef_nesting_idx == 0:
CONTEXT.sip_run = 0
break
@@ -1582,80 +1642,88 @@ def cpp_to_python_signature(cpp_function: str) -> str:
# Skip forward declarations
match = re.match(
- r'^\s*(template ? |enum\s+)?(class|struct) \w+(?P *SIP_EXTERNAL)?;\s*(//.*)?$',
- CONTEXT.current_line)
+ r"^\s*(template ? |enum\s+)?(class|struct) \w+(?P *SIP_EXTERNAL)?;\s*(//.*)?$",
+ CONTEXT.current_line,
+ )
if match:
- if match.group('external'):
- dbg_info('do not skip external forward declaration')
- CONTEXT.comment = ''
+ if match.group("external"):
+ dbg_info("do not skip external forward declaration")
+ CONTEXT.comment = ""
else:
- dbg_info('skipping forward declaration')
+ dbg_info("skipping forward declaration")
continue
# Skip friend declarations
- if re.match(r'^\s*friend class \w+', CONTEXT.current_line):
+ if re.match(r"^\s*friend class \w+", CONTEXT.current_line):
continue
# Insert metaobject for Q_GADGET
- if re.match(r'^\s*Q_GADGET\b.*?$', CONTEXT.current_line):
- if not re.search(r'SIP_SKIP', CONTEXT.current_line):
- dbg_info('Q_GADGET')
+ if re.match(r"^\s*Q_GADGET\b.*?$", CONTEXT.current_line):
+ if not re.search(r"SIP_SKIP", CONTEXT.current_line):
+ dbg_info("Q_GADGET")
write_output("HCE", " public:\n")
- write_output("HCE",
- " static const QMetaObject staticMetaObject;\n\n")
+ write_output("HCE", " static const QMetaObject staticMetaObject;\n\n")
continue
# Insert in Python output (python/module/__init__.py)
- match = re.search(r'Q_(ENUM|FLAG)\(\s*(\w+)\s*\)', CONTEXT.current_line)
+ match = re.search(r"Q_(ENUM|FLAG)\(\s*(\w+)\s*\)", CONTEXT.current_line)
if match:
- if not re.search(r'SIP_SKIP', CONTEXT.current_line):
- is_flag = 1 if match.group(1) == 'FLAG' else 0
+ if not re.search(r"SIP_SKIP", CONTEXT.current_line):
+ is_flag = 1 if match.group(1) == "FLAG" else 0
enum_helper = f"{CONTEXT.actual_class}.{match.group(2)}.baseClass = {CONTEXT.actual_class}"
dbg_info(f"Q_ENUM/Q_FLAG {enum_helper}")
if args.python_output:
- if enum_helper != '':
+ if enum_helper != "":
CONTEXT.output_python.append(f"{enum_helper}\n")
if is_flag == 1:
# SIP seems to introduce the flags in the module rather than in the class itself
# as a dirty hack, inject directly in module, hopefully we don't have flags with the same name...
CONTEXT.output_python.append(
- f"{match.group(2)} = {CONTEXT.actual_class} # dirty hack since SIP seems to introduce the flags in module\n")
+ f"{match.group(2)} = {CONTEXT.actual_class} # dirty hack since SIP seems to introduce the flags in module\n"
+ )
continue
# Skip Q_OBJECT, Q_PROPERTY, Q_ENUM, etc.
if re.match(
- r'^\s*Q_(OBJECT|ENUMS|ENUM|FLAG|PROPERTY|DECLARE_METATYPE|DECLARE_TYPEINFO|NOWARN_DEPRECATED_(PUSH|POP))\b.*?$',
- CONTEXT.current_line):
+ r"^\s*Q_(OBJECT|ENUMS|ENUM|FLAG|PROPERTY|DECLARE_METATYPE|DECLARE_TYPEINFO|NOWARN_DEPRECATED_(PUSH|POP))\b.*?$",
+ CONTEXT.current_line,
+ ):
continue
- if re.match(r'^\s*QHASH_FOR_CLASS_ENUM', CONTEXT.current_line):
+ if re.match(r"^\s*QHASH_FOR_CLASS_ENUM", CONTEXT.current_line):
continue
- if re.search(r'SIP_SKIP|SIP_PYTHON_SPECIAL_', CONTEXT.current_line):
- dbg_info('SIP SKIP!')
+ if re.search(r"SIP_SKIP|SIP_PYTHON_SPECIAL_", CONTEXT.current_line):
+ dbg_info("SIP SKIP!")
# if multiline definition, remove previous lines
if CONTEXT.multiline_definition != MultiLineType.NotMultiline:
- dbg_info('SIP_SKIP with MultiLine')
- opening_line = ''
- while not re.match(r'^[^()]*\(([^()]*\([^()]*\)[^()]*)*[^()]*$',
- opening_line):
+ dbg_info("SIP_SKIP with MultiLine")
+ opening_line = ""
+ while not re.match(
+ r"^[^()]*\(([^()]*\([^()]*\)[^()]*)*[^()]*$", opening_line
+ ):
opening_line = CONTEXT.output.pop()
if len(CONTEXT.output) < 1:
- exit_with_error('could not reach opening definition')
+ exit_with_error("could not reach opening definition")
dbg_info("removed multiline definition of SIP_SKIP method")
CONTEXT.multiline_definition = MultiLineType.NotMultiline
- del CONTEXT.static_methods[CONTEXT.current_fully_qualified_class_name()][CONTEXT.current_method_name]
+ del CONTEXT.static_methods[CONTEXT.current_fully_qualified_class_name()][
+ CONTEXT.current_method_name
+ ]
# also skip method body if there is one
detect_and_remove_following_body_or_initializerlist()
# line skipped, go to next iteration
- match = re.search(r'SIP_PYTHON_SPECIAL_(\w+)\(\s*(".*"|\w+)\s*\)',
- CONTEXT.current_line)
+ match = re.search(
+ r'SIP_PYTHON_SPECIAL_(\w+)\(\s*(".*"|\w+)\s*\)', CONTEXT.current_line
+ )
if match:
method_or_code = match.group(2)
dbg_info(f"PYTHON SPECIAL method or code: {method_or_code}")
- pyop = f"{CONTEXT.actual_class}.__{match.group(1).lower()}__ = lambda self: "
+ pyop = (
+ f"{CONTEXT.actual_class}.__{match.group(1).lower()}__ = lambda self: "
+ )
if re.match(r'^".*"$', method_or_code):
pyop += method_or_code.strip('"')
else:
@@ -1664,7 +1732,7 @@ def cpp_to_python_signature(cpp_function: str) -> str:
if args.python_output:
CONTEXT.output_python.append(f"{pyop}\n")
- CONTEXT.comment = ''
+ CONTEXT.comment = ""
continue
# Detect comment block
@@ -1672,16 +1740,20 @@ def cpp_to_python_signature(cpp_function: str) -> str:
continue
struct_match = re.match(
- r'^\s*struct(\s+\w+_EXPORT)?\s+(?P\w+)$',
- CONTEXT.current_line)
+ r"^\s*struct(\s+\w+_EXPORT)?\s+(?P\w+)$", CONTEXT.current_line
+ )
if struct_match:
dbg_info(" going to struct => public")
- CONTEXT.class_and_struct.append(struct_match.group('structname'))
+ CONTEXT.class_and_struct.append(struct_match.group("structname"))
CONTEXT.classname.append(
- CONTEXT.classname[-1] if CONTEXT.classname else struct_match.group(
- 'structname')) # fake new class since struct has considered similarly
+ CONTEXT.classname[-1]
+ if CONTEXT.classname
+ else struct_match.group("structname")
+ ) # fake new class since struct has considered similarly
if CONTEXT.access[-1] != Visibility.Private:
- CONTEXT.all_fully_qualified_class_names.append(CONTEXT.current_fully_qualified_struct_name())
+ CONTEXT.all_fully_qualified_class_names.append(
+ CONTEXT.current_fully_qualified_struct_name()
+ )
CONTEXT.access.append(Visibility.Public)
CONTEXT.exported.append(CONTEXT.exported[-1])
CONTEXT.bracket_nesting_idx.append(0)
@@ -1702,10 +1774,12 @@ def cpp_to_python_signature(cpp_function: str) -> str:
template_inheritance_class2 = []
template_inheritance_class3 = []
- CONTEXT.classname.append(class_pattern_match.group('classname'))
- CONTEXT.class_and_struct.append(class_pattern_match.group('classname'))
+ CONTEXT.classname.append(class_pattern_match.group("classname"))
+ CONTEXT.class_and_struct.append(class_pattern_match.group("classname"))
if CONTEXT.access[-1] != Visibility.Private:
- CONTEXT.all_fully_qualified_class_names.append(CONTEXT.current_fully_qualified_struct_name())
+ CONTEXT.all_fully_qualified_class_names.append(
+ CONTEXT.current_fully_qualified_struct_name()
+ )
CONTEXT.access.append(Visibility.Public)
if len(CONTEXT.classname) == 1:
@@ -1714,63 +1788,70 @@ def cpp_to_python_signature(cpp_function: str) -> str:
dbg_info(f"class: {CONTEXT.classname[-1]}")
if (
- re.search(r'\b[A-Z0-9_]+_EXPORT\b', CONTEXT.current_line)
+ re.search(r"\b[A-Z0-9_]+_EXPORT\b", CONTEXT.current_line)
or len(CONTEXT.classname) != 1
- or re.search(r'^\s*template\s*<',
- CONTEXT.input_lines[CONTEXT.line_idx - 2])
+ or re.search(r"^\s*template\s*<", CONTEXT.input_lines[CONTEXT.line_idx - 2])
):
CONTEXT.exported[-1] += 1
- CONTEXT.current_line = f"{class_pattern_match.group(1)} {class_pattern_match.group('classname')}"
+ CONTEXT.current_line = (
+ f"{class_pattern_match.group(1)} {class_pattern_match.group('classname')}"
+ )
# append to class map file
if args.class_map:
- with open(args.class_map, 'a') as fh3:
+ with open(args.class_map, "a") as fh3:
fh3.write(
- f"{'.'.join(CONTEXT.classname)}: {CONTEXT.header_file}#L{CONTEXT.line_idx}\n")
+ f"{'.'.join(CONTEXT.classname)}: {CONTEXT.header_file}#L{CONTEXT.line_idx}\n"
+ )
# Inheritance
- if class_pattern_match.group('domain'):
- m = class_pattern_match.group('domain')
- m = re.sub(r'public +(\w+, *)*(Ui::\w+,? *)+', '', m)
- m = re.sub(r'public +', '', m)
- m = re.sub(r'[,:]?\s*private +\w+(::\w+)?', '', m)
+ if class_pattern_match.group("domain"):
+ m = class_pattern_match.group("domain")
+ m = re.sub(r"public +(\w+, *)*(Ui::\w+,? *)+", "", m)
+ m = re.sub(r"public +", "", m)
+ m = re.sub(r"[,:]?\s*private +\w+(::\w+)?", "", m)
# detect template based inheritance
# https://regex101.com/r/9LGhyy/1
tpl_pattern = re.compile(
- r'[,:]\s+(?P(?!QList)\w+)< *(?P(\w|::)+) *(, *(?P(\w|::)+)? *(, *(?P(\w|::)+)? *)?)? *>'
+ r"[,:]\s+(?P(?!QList)\w+)< *(?P(\w|::)+) *(, *(?P(\w|::)+)? *(, *(?P(\w|::)+)? *)?)? *>"
)
for match in tpl_pattern.finditer(m):
dbg_info("template class")
- template_inheritance_template.append(match.group('tpl'))
- template_inheritance_class1.append(match.group('cls1'))
- template_inheritance_class2.append(match.group('cls2') or "")
- template_inheritance_class3.append(match.group('cls3') or "")
+ template_inheritance_template.append(match.group("tpl"))
+ template_inheritance_class1.append(match.group("cls1"))
+ template_inheritance_class2.append(match.group("cls2") or "")
+ template_inheritance_class3.append(match.group("cls3") or "")
dbg_info(f"domain: {m}")
tpl_replace_pattern = re.compile(
- r'\b(?P(?!QList)\w+)< *(?P(\w|::)+) *(, *(?P(\w|::)+)? *(, *(?P(\w|::)+)? *)?)? *>'
+ r"\b(?P(?!QList)\w+)< *(?P(\w|::)+) *(, *(?P(\w|::)+)? *(, *(?P(\w|::)+)? *)?)? *>"
+ )
+ m = tpl_replace_pattern.sub(
+ lambda tpl_match: f"{tpl_match.group('tpl') or ''}{tpl_match.group('cls1') or ''}{tpl_match.group('cls2') or ''}{tpl_match.group('cls3') or ''}Base",
+ m,
)
- m = tpl_replace_pattern.sub(lambda
- tpl_match: f"{tpl_match.group('tpl') or ''}{tpl_match.group('cls1') or ''}{tpl_match.group('cls2') or ''}{tpl_match.group('cls3') or ''}Base",
- m)
- m = re.sub(r'(\w+)< *(?:\w|::)+ *>', '', m)
- m = re.sub(r'([:,])\s*,', r'\1', m)
- m = re.sub(r'(\s*[:,])?\s*$', '', m)
+ m = re.sub(r"(\w+)< *(?:\w|::)+ *>", "", m)
+ m = re.sub(r"([:,])\s*,", r"\1", m)
+ m = re.sub(r"(\s*[:,])?\s*$", "", m)
CONTEXT.current_line += m
- if class_pattern_match.group('annot'):
- CONTEXT.current_line += class_pattern_match.group('annot')
+ if class_pattern_match.group("annot"):
+ CONTEXT.current_line += class_pattern_match.group("annot")
CONTEXT.current_line = fix_annotations(CONTEXT.current_line)
CONTEXT.current_line += "\n{\n"
if CONTEXT.comment.strip():
- CONTEXT.current_line += "%Docstring(signature=\"appended\")\n" + CONTEXT.comment + "\n%End\n"
+ CONTEXT.current_line += (
+ '%Docstring(signature="appended")\n' + CONTEXT.comment + "\n%End\n"
+ )
- CONTEXT.current_line += f"\n%TypeHeaderCode\n#include \"{os.path.basename(CONTEXT.header_file)}\""
+ CONTEXT.current_line += (
+ f'\n%TypeHeaderCode\n#include "{os.path.basename(CONTEXT.header_file)}"'
+ )
# for template based inheritance, add a typedef to define the base type
while template_inheritance_template:
@@ -1788,19 +1869,23 @@ def cpp_to_python_signature(cpp_function: str) -> str:
if tpl not in CONTEXT.declared_classes:
tpl_header = f"{tpl.lower()}.h"
- if tpl in sip_config['class_headerfile']:
- tpl_header = sip_config['class_headerfile'][tpl]
- CONTEXT.current_line += f"\n#include \"{tpl_header}\""
+ if tpl in sip_config["class_headerfile"]:
+ tpl_header = sip_config["class_headerfile"][tpl]
+ CONTEXT.current_line += f'\n#include "{tpl_header}"'
if cls2 == "":
CONTEXT.current_line += f"\ntypedef {tpl}<{cls1}> {tpl}{cls1}Base;"
elif cls3 == "":
- CONTEXT.current_line += f"\ntypedef {tpl}<{cls1},{cls2}> {tpl}{cls1}{cls2}Base;"
+ CONTEXT.current_line += (
+ f"\ntypedef {tpl}<{cls1},{cls2}> {tpl}{cls1}{cls2}Base;"
+ )
else:
CONTEXT.current_line += f"\ntypedef {tpl}<{cls1},{cls2},{cls3}> {tpl}{cls1}{cls2}{cls3}Base;"
- if any(x == Visibility.Private for x in CONTEXT.access) and len(
- CONTEXT.access) != 1:
+ if (
+ any(x == Visibility.Private for x in CONTEXT.access)
+ and len(CONTEXT.access) != 1
+ ):
dbg_info("skipping class in private context")
continue
@@ -1809,11 +1894,11 @@ def cpp_to_python_signature(cpp_function: str) -> str:
# Skip opening curly bracket, incrementing hereunder
skip = read_line()
- if not re.match(r'^\s*{\s*$', skip):
+ if not re.match(r"^\s*{\s*$", skip):
exit_with_error("expecting { after class definition")
CONTEXT.bracket_nesting_idx[-1] += 1
- CONTEXT.comment = ''
+ CONTEXT.comment = ""
CONTEXT.header_code = True
CONTEXT.access[-1] = Visibility.Private
continue
@@ -1821,8 +1906,8 @@ def cpp_to_python_signature(cpp_function: str) -> str:
# Bracket balance in class/struct tree
if not CONTEXT.sip_run:
bracket_balance = 0
- bracket_balance += CONTEXT.current_line.count('{')
- bracket_balance -= CONTEXT.current_line.count('}')
+ bracket_balance += CONTEXT.current_line.count("{")
+ bracket_balance -= CONTEXT.current_line.count("}")
if bracket_balance != 0:
CONTEXT.bracket_nesting_idx[-1] += bracket_balance
@@ -1835,8 +1920,8 @@ def cpp_to_python_signature(cpp_function: str) -> str:
CONTEXT.access.pop()
if CONTEXT.exported[-1] == 0 and CONTEXT.classname[
- -1] != sip_config.get(
- 'no_export_macro'):
+ -1
+ ] != sip_config.get("no_export_macro"):
exit_with_error(
f"Class {CONTEXT.classname[-1]} should be exported with appropriate [LIB]_EXPORT macro. "
f"If this should not be available in python, wrap it in a `#ifndef SIP_RUN` block."
@@ -1849,152 +1934,168 @@ def cpp_to_python_signature(cpp_function: str) -> str:
if len(CONTEXT.access) == 1:
dbg_info("reached top level")
- CONTEXT.access[
- -1] = Visibility.Public # Top level should stay public
+ CONTEXT.access[-1] = (
+ Visibility.Public
+ ) # Top level should stay public
- CONTEXT.comment = ''
- CONTEXT.return_type = ''
- CONTEXT.private_section_line = ''
+ CONTEXT.comment = ""
+ CONTEXT.return_type = ""
+ CONTEXT.private_section_line = ""
dbg_info(f"new bracket balance: {CONTEXT.bracket_nesting_idx}")
# Private members (exclude SIP_RUN)
- if re.match(r'^\s*private( slots)?:', CONTEXT.current_line):
+ if re.match(r"^\s*private( slots)?:", CONTEXT.current_line):
CONTEXT.access[-1] = Visibility.Private
CONTEXT.last_access_section_line = CONTEXT.current_line
CONTEXT.private_section_line = CONTEXT.current_line
- CONTEXT.comment = ''
+ CONTEXT.comment = ""
dbg_info("going private")
continue
- elif re.match(r'^\s*(public( slots)?):.*$', CONTEXT.current_line):
+ elif re.match(r"^\s*(public( slots)?):.*$", CONTEXT.current_line):
dbg_info("going public")
CONTEXT.last_access_section_line = CONTEXT.current_line
CONTEXT.access[-1] = Visibility.Public
- CONTEXT.comment = ''
+ CONTEXT.comment = ""
- elif re.match(r'^\s*signals:.*$', CONTEXT.current_line):
+ elif re.match(r"^\s*signals:.*$", CONTEXT.current_line):
dbg_info("going public for signals")
CONTEXT.last_access_section_line = CONTEXT.current_line
CONTEXT.access[-1] = Visibility.Signals
- CONTEXT.comment = ''
+ CONTEXT.comment = ""
- elif re.match(r'^\s*(protected)( slots)?:.*$', CONTEXT.current_line):
+ elif re.match(r"^\s*(protected)( slots)?:.*$", CONTEXT.current_line):
dbg_info("going protected")
CONTEXT.last_access_section_line = CONTEXT.current_line
CONTEXT.access[-1] = Visibility.Protected
- CONTEXT.comment = ''
+ CONTEXT.comment = ""
- elif CONTEXT.access[
- -1] == Visibility.Private and 'SIP_FORCE' in CONTEXT.current_line:
+ elif (
+ CONTEXT.access[-1] == Visibility.Private and "SIP_FORCE" in CONTEXT.current_line
+ ):
dbg_info("private with SIP_FORCE")
if CONTEXT.private_section_line:
write_output("PRV3", CONTEXT.private_section_line + "\n")
- CONTEXT.private_section_line = ''
+ CONTEXT.private_section_line = ""
- elif any(x == Visibility.Private for x in
- CONTEXT.access) and not CONTEXT.sip_run:
- CONTEXT.comment = ''
+ elif any(x == Visibility.Private for x in CONTEXT.access) and not CONTEXT.sip_run:
+ CONTEXT.comment = ""
continue
# Skip operators
if CONTEXT.access[-1] != Visibility.Private and re.search(
- r'operator(=|<<|>>|->)\s*\(', CONTEXT.current_line):
+ r"operator(=|<<|>>|->)\s*\(", CONTEXT.current_line
+ ):
dbg_info("skip operator")
detect_and_remove_following_body_or_initializerlist()
continue
# Save comments and do not print them, except in SIP_RUN
if not CONTEXT.sip_run:
- if re.match(r'^\s*//', CONTEXT.current_line):
- match = re.match(r'^\s*//!\s*(.*?)\n?$', CONTEXT.current_line)
+ if re.match(r"^\s*//", CONTEXT.current_line):
+ match = re.match(r"^\s*//!\s*(.*?)\n?$", CONTEXT.current_line)
if match:
CONTEXT.comment_param_list = False
CONTEXT.prev_indent = CONTEXT.indent
- CONTEXT.indent = ''
+ CONTEXT.indent = ""
CONTEXT.comment_last_line_note_warning = False
CONTEXT.comment = process_doxygen_line(match.group(1))
CONTEXT.comment = CONTEXT.comment.rstrip()
- elif not re.search(r'\*/',
- CONTEXT.input_lines[CONTEXT.line_idx - 1]):
- CONTEXT.comment = ''
+ elif not re.search(r"\*/", CONTEXT.input_lines[CONTEXT.line_idx - 1]):
+ CONTEXT.comment = ""
continue
# Handle Q_DECLARE_FLAGS in Qt6
if CONTEXT.is_qt6 and re.match(
- r'^\s*Q_DECLARE_FLAGS\s*\(\s*(\w+)\s*,\s*(\w+)\s*\)',
- CONTEXT.current_line):
- flags_name = re.search(r'\(\s*(\w+)\s*,\s*(\w+)\s*\)',
- CONTEXT.current_line).group(1)
- flag_name = re.search(r'\(\s*(\w+)\s*,\s*(\w+)\s*\)',
- CONTEXT.current_line).group(2)
+ r"^\s*Q_DECLARE_FLAGS\s*\(\s*(\w+)\s*,\s*(\w+)\s*\)", CONTEXT.current_line
+ ):
+ flags_name = re.search(
+ r"\(\s*(\w+)\s*,\s*(\w+)\s*\)", CONTEXT.current_line
+ ).group(1)
+ flag_name = re.search(
+ r"\(\s*(\w+)\s*,\s*(\w+)\s*\)", CONTEXT.current_line
+ ).group(2)
CONTEXT.output_python.append(
- f"{CONTEXT.actual_class}.{flags_name} = lambda flags=0: {CONTEXT.actual_class}.{flag_name}(flags)\n")
+ f"{CONTEXT.actual_class}.{flags_name} = lambda flags=0: {CONTEXT.actual_class}.{flag_name}(flags)\n"
+ )
# Enum declaration
# For scoped and type-based enum, the type has to be removed
if re.match(
- r'^\s*Q_DECLARE_FLAGS\s*\(\s*(\w+)\s*,\s*(\w+)\s*\)\s*SIP_MONKEYPATCH_FLAGS_UNNEST\s*\(\s*(\w+)\s*,\s*(\w+)\s*\)\s*$',
- CONTEXT.current_line):
- flags_name = re.search(r'\(\s*(\w+)\s*,\s*(\w+)\s*\)',
- CONTEXT.current_line).group(1)
- flag_name = re.search(r'\(\s*(\w+)\s*,\s*(\w+)\s*\)',
- CONTEXT.current_line).group(2)
+ r"^\s*Q_DECLARE_FLAGS\s*\(\s*(\w+)\s*,\s*(\w+)\s*\)\s*SIP_MONKEYPATCH_FLAGS_UNNEST\s*\(\s*(\w+)\s*,\s*(\w+)\s*\)\s*$",
+ CONTEXT.current_line,
+ ):
+ flags_name = re.search(
+ r"\(\s*(\w+)\s*,\s*(\w+)\s*\)", CONTEXT.current_line
+ ).group(1)
+ flag_name = re.search(
+ r"\(\s*(\w+)\s*,\s*(\w+)\s*\)", CONTEXT.current_line
+ ).group(2)
emkb = re.search(
- r'SIP_MONKEYPATCH_FLAGS_UNNEST\s*\(\s*(\w+)\s*,\s*(\w+)\s*\)',
- CONTEXT.current_line).group(1)
+ r"SIP_MONKEYPATCH_FLAGS_UNNEST\s*\(\s*(\w+)\s*,\s*(\w+)\s*\)",
+ CONTEXT.current_line,
+ ).group(1)
emkf = re.search(
- r'SIP_MONKEYPATCH_FLAGS_UNNEST\s*\(\s*(\w+)\s*,\s*(\w+)\s*\)',
- CONTEXT.current_line).group(2)
+ r"SIP_MONKEYPATCH_FLAGS_UNNEST\s*\(\s*(\w+)\s*,\s*(\w+)\s*\)",
+ CONTEXT.current_line,
+ ).group(2)
if f"{emkb}.{emkf}" != f"{CONTEXT.actual_class}.{flags_name}":
CONTEXT.output_python.append(
- f"{emkb}.{emkf} = {CONTEXT.actual_class}.{flags_name}\n")
+ f"{emkb}.{emkf} = {CONTEXT.actual_class}.{flags_name}\n"
+ )
CONTEXT.enum_monkey_patched_types.append(
- [CONTEXT.actual_class, flags_name, emkb, emkf])
+ [CONTEXT.actual_class, flags_name, emkb, emkf]
+ )
CONTEXT.current_line = re.sub(
- r'\s*SIP_MONKEYPATCH_FLAGS_UNNEST\(.*?\)', '',
- CONTEXT.current_line)
+ r"\s*SIP_MONKEYPATCH_FLAGS_UNNEST\(.*?\)", "", CONTEXT.current_line
+ )
enum_match = re.match(
- r'^(\s*enum(\s+Q_DECL_DEPRECATED)?\s+(?Pclass\s+)?(?P\w+))(:?\s+SIP_[^:]*)?(\s*:\s*(?P\w+))?(?:\s*SIP_ENUM_BASETYPE\s*\(\s*(?P\w+)\s*\))?(?P.*)$',
- CONTEXT.current_line)
+ r"^(\s*enum(\s+Q_DECL_DEPRECATED)?\s+(?Pclass\s+)?(?P\w+))(:?\s+SIP_[^:]*)?(\s*:\s*(?P\w+))?(?:\s*SIP_ENUM_BASETYPE\s*\(\s*(?P\w+)\s*\))?(?P.*)$",
+ CONTEXT.current_line,
+ )
if enum_match:
enum_decl = enum_match.group(1)
- enum_qualname = enum_match.group('enum_qualname')
- enum_type = enum_match.group('enum_type')
- isclass = enum_match.group('isclass')
- enum_cpp_name = f"{CONTEXT.actual_class}::{enum_qualname}" if CONTEXT.actual_class else enum_qualname
+ enum_qualname = enum_match.group("enum_qualname")
+ enum_type = enum_match.group("enum_type")
+ isclass = enum_match.group("isclass")
+ enum_cpp_name = (
+ f"{CONTEXT.actual_class}::{enum_qualname}"
+ if CONTEXT.actual_class
+ else enum_qualname
+ )
if not isclass and enum_cpp_name not in ALLOWED_NON_CLASS_ENUMS:
exit_with_error(
- f"Non class enum exposed to Python -- must be a enum class: {enum_cpp_name}")
+ f"Non class enum exposed to Python -- must be a enum class: {enum_cpp_name}"
+ )
- oneliner = enum_match.group('oneliner')
+ oneliner = enum_match.group("oneliner")
is_scope_based = bool(isclass)
- enum_decl = re.sub(r'\s*\bQ_DECL_DEPRECATED\b', '', enum_decl)
+ enum_decl = re.sub(r"\s*\bQ_DECL_DEPRECATED\b", "", enum_decl)
- py_enum_type_match = re.search(r'SIP_ENUM_BASETYPE\(\s*(.*?)\s*\)',
- CONTEXT.current_line)
- py_enum_type = py_enum_type_match.group(
- 1) if py_enum_type_match else None
+ py_enum_type_match = re.search(
+ r"SIP_ENUM_BASETYPE\(\s*(.*?)\s*\)", CONTEXT.current_line
+ )
+ py_enum_type = py_enum_type_match.group(1) if py_enum_type_match else None
if py_enum_type == "IntFlag":
CONTEXT.enum_intflag_types.append(enum_cpp_name)
if enum_type in ["int", "quint32"]:
- CONTEXT.enum_int_types.append(
- f"{CONTEXT.actual_class}.{enum_qualname}")
+ CONTEXT.enum_int_types.append(f"{CONTEXT.actual_class}.{enum_qualname}")
if CONTEXT.is_qt6:
enum_decl += f" /BaseType={py_enum_type or 'IntEnum'}/"
elif enum_type:
- exit_with_error(
- f"Unhandled enum type {enum_type} for {enum_cpp_name}")
+ exit_with_error(f"Unhandled enum type {enum_type} for {enum_cpp_name}")
elif isclass:
CONTEXT.enum_class_non_int_types.append(
- f"{CONTEXT.actual_class}.{enum_qualname}")
+ f"{CONTEXT.actual_class}.{enum_qualname}"
+ )
elif CONTEXT.is_qt6:
enum_decl += " /BaseType=IntEnum/"
@@ -2006,38 +2107,44 @@ def cpp_to_python_signature(cpp_function: str) -> str:
_match = None
if is_scope_based:
_match = re.search(
- r'SIP_MONKEYPATCH_SCOPEENUM(_UNNEST)?(:?\(\s*(?P\w+)\s*,\s*(?P\w+)\s*\))?',
- CONTEXT.current_line)
+ r"SIP_MONKEYPATCH_SCOPEENUM(_UNNEST)?(:?\(\s*(?P\w+)\s*,\s*(?P\w+)\s*\))?",
+ CONTEXT.current_line,
+ )
monkeypatch = is_scope_based and _match
- enum_mk_base = _match.group('emkb') if _match else ''
+ enum_mk_base = _match.group("emkb") if _match else ""
- enum_old_name = ''
- if _match and _match.group('emkf') and monkeypatch:
- enum_old_name = _match.group('emkf')
+ enum_old_name = ""
+ if _match and _match.group("emkf") and monkeypatch:
+ enum_old_name = _match.group("emkf")
if CONTEXT.actual_class:
- if f"{enum_mk_base}.{enum_old_name}" != f"{CONTEXT.actual_class}.{enum_qualname}":
+ if (
+ f"{enum_mk_base}.{enum_old_name}"
+ != f"{CONTEXT.actual_class}.{enum_qualname}"
+ ):
CONTEXT.output_python.append(
- f"{enum_mk_base}.{enum_old_name} = {CONTEXT.actual_class}.{enum_qualname}\n")
+ f"{enum_mk_base}.{enum_old_name} = {CONTEXT.actual_class}.{enum_qualname}\n"
+ )
else:
CONTEXT.output_python.append(
- f"{enum_mk_base}.{enum_old_name} = {enum_qualname}\n")
+ f"{enum_mk_base}.{enum_old_name} = {enum_qualname}\n"
+ )
- if re.search(r'\{((\s*\w+)(\s*=\s*[\w\s<|]+.*?)?(,?))+\s*}',
- CONTEXT.current_line):
- if '=' in CONTEXT.current_line:
+ if re.search(
+ r"\{((\s*\w+)(\s*=\s*[\w\s<|]+.*?)?(,?))+\s*}", CONTEXT.current_line
+ ):
+ if "=" in CONTEXT.current_line:
exit_with_error(
- "Sipify does not handle enum one liners with value assignment. Use multiple lines instead. Or just write a new parser.")
+ "Sipify does not handle enum one liners with value assignment. Use multiple lines instead. Or just write a new parser."
+ )
continue
else:
CONTEXT.current_line = read_line()
- if not re.match(r'^\s*\{\s*$', CONTEXT.current_line):
- exit_with_error(
- 'Unexpected content: enum should be followed by {')
+ if not re.match(r"^\s*\{\s*$", CONTEXT.current_line):
+ exit_with_error("Unexpected content: enum should be followed by {")
write_output("ENU2", f"{CONTEXT.current_line}\n")
if is_scope_based:
- CONTEXT.output_python.append(
- "# monkey patching scoped based enum\n")
+ CONTEXT.output_python.append("# monkey patching scoped based enum\n")
enum_members_doc = []
@@ -2045,117 +2152,150 @@ def cpp_to_python_signature(cpp_function: str) -> str:
CONTEXT.current_line = read_line()
if detect_comment_block():
continue
- if re.search(r'};', CONTEXT.current_line):
+ if re.search(r"};", CONTEXT.current_line):
break
- if re.match(r'^\s*\w+\s*\|',
- CONTEXT.current_line): # multi line declaration as sum of enums
+ if re.match(
+ r"^\s*\w+\s*\|", CONTEXT.current_line
+ ): # multi line declaration as sum of enums
continue
enum_match = re.match(
- r'^(\s*(?P\w+))(\s+SIP_PYNAME(?:\(\s*(?P[^() ]+)\s*\)\s*)?)?(\s+SIP_MONKEY\w+(?:\(\s*(?P[^() ]+)\s*\)\s*)?)?(?:\s*=\s*(?P(:?[\w\s|+-]|::|<<)+))?(?P,?)(:?\s*//!<\s*(?P.*)|.*)$',
- CONTEXT.current_line)
-
- enum_decl = f"{enum_match.group(1) or ''}{enum_match.group(3) or ''}{enum_match.group('optional_comma') or ''}" if enum_match else CONTEXT.current_line
- enum_member = enum_match.group(
- 'em') or '' if enum_match else ''
- value_comment = enum_match.group(
- 'co') or '' if enum_match else ''
- compat_name = enum_match.group(
- 'compat') or enum_member if enum_match else ''
- enum_value = enum_match.group(
- 'enum_value') or '' if enum_match else ''
-
- value_comment = value_comment.replace('::', '.').replace('"',
- '\\"')
- value_comment = re.sub(r'\\since .*?([\d.]+)',
- r'\\n.. versionadded:: \1\\n',
- value_comment, flags=re.I)
- value_comment = re.sub(r'\\deprecated (?:QGIS )?(.*)',
- r'\\n.. deprecated:: \1\\n',
- value_comment, flags=re.I)
- value_comment = re.sub(r'^\\n+', '', value_comment)
- value_comment = re.sub(r'\\n+$', '', value_comment)
+ r"^(\s*(?P\w+))(\s+SIP_PYNAME(?:\(\s*(?P[^() ]+)\s*\)\s*)?)?(\s+SIP_MONKEY\w+(?:\(\s*(?P[^() ]+)\s*\)\s*)?)?(?:\s*=\s*(?P(:?[\w\s|+-]|::|<<)+))?(?P,?)(:?\s*//!<\s*(?P.*)|.*)$",
+ CONTEXT.current_line,
+ )
+
+ enum_decl = (
+ f"{enum_match.group(1) or ''}{enum_match.group(3) or ''}{enum_match.group('optional_comma') or ''}"
+ if enum_match
+ else CONTEXT.current_line
+ )
+ enum_member = enum_match.group("em") or "" if enum_match else ""
+ value_comment = enum_match.group("co") or "" if enum_match else ""
+ compat_name = (
+ enum_match.group("compat") or enum_member if enum_match else ""
+ )
+ enum_value = enum_match.group("enum_value") or "" if enum_match else ""
+
+ value_comment = value_comment.replace("::", ".").replace('"', '\\"')
+ value_comment = re.sub(
+ r"\\since .*?([\d.]+)",
+ r"\\n.. versionadded:: \1\\n",
+ value_comment,
+ flags=re.I,
+ )
+ value_comment = re.sub(
+ r"\\deprecated (?:QGIS )?(.*)",
+ r"\\n.. deprecated:: \1\\n",
+ value_comment,
+ flags=re.I,
+ )
+ value_comment = re.sub(r"^\\n+", "", value_comment)
+ value_comment = re.sub(r"\\n+$", "", value_comment)
dbg_info(
- f"is_scope_based:{is_scope_based} enum_mk_base:{enum_mk_base} monkeypatch:{monkeypatch}")
+ f"is_scope_based:{is_scope_based} enum_mk_base:{enum_mk_base} monkeypatch:{monkeypatch}"
+ )
if enum_value and (
- re.search(r'.*<<.*', enum_value) or re.search(r'.*0x0.*',
- enum_value)):
- if f"{CONTEXT.actual_class}::{enum_qualname}" not in CONTEXT.enum_intflag_types:
+ re.search(r".*<<.*", enum_value)
+ or re.search(r".*0x0.*", enum_value)
+ ):
+ if (
+ f"{CONTEXT.actual_class}::{enum_qualname}"
+ not in CONTEXT.enum_intflag_types
+ ):
exit_with_error(
- f"{CONTEXT.actual_class}::{enum_qualname} is a flags type, but was not declared with IntFlag type. Add 'SIP_ENUM_BASETYPE(IntFlag)' to the enum class declaration line")
+ f"{CONTEXT.actual_class}::{enum_qualname} is a flags type, but was not declared with IntFlag type. Add 'SIP_ENUM_BASETYPE(IntFlag)' to the enum class declaration line"
+ )
if is_scope_based and enum_member:
- value_comment_parts = value_comment.replace('\\n', '\n').split('\n')
- value_comment_indented = ''
+ value_comment_parts = value_comment.replace("\\n", "\n").split("\n")
+ value_comment_indented = ""
for part_idx, part in enumerate(value_comment_parts):
if part_idx == 0:
- if part.strip().startswith('..'):
- exit_with_error(f'Enum member description missing for {CONTEXT.actual_class}::{enum_qualname}')
+ if part.strip().startswith(".."):
+ exit_with_error(
+ f"Enum member description missing for {CONTEXT.actual_class}::{enum_qualname}"
+ )
value_comment_indented += part.rstrip()
else:
if part.startswith(".."):
value_comment_indented += "\n"
- value_comment_indented += ' ' + part.rstrip()
+ value_comment_indented += " " + part.rstrip()
if part.startswith(".."):
value_comment_indented += "\n"
if part_idx < len(value_comment_parts) - 1:
- value_comment_indented += '\n'
+ value_comment_indented += "\n"
- complete_class_path = '.'.join(CONTEXT.classname)
+ complete_class_path = ".".join(CONTEXT.classname)
if monkeypatch and enum_mk_base:
if compat_name != enum_member:
- value_comment_indented += f'\n\n Available as ``{enum_mk_base}.{compat_name}`` in older QGIS releases.\n'
+ value_comment_indented += f"\n\n Available as ``{enum_mk_base}.{compat_name}`` in older QGIS releases.\n"
if CONTEXT.actual_class:
CONTEXT.output_python.append(
- f"{enum_mk_base}.{compat_name} = {complete_class_path}.{enum_qualname}.{enum_member}\n")
+ f"{enum_mk_base}.{compat_name} = {complete_class_path}.{enum_qualname}.{enum_member}\n"
+ )
if enum_old_name and compat_name != enum_member:
CONTEXT.output_python.append(
- f"{enum_mk_base}.{enum_old_name}.{compat_name} = {complete_class_path}.{enum_qualname}.{enum_member}\n")
+ f"{enum_mk_base}.{enum_old_name}.{compat_name} = {complete_class_path}.{enum_qualname}.{enum_member}\n"
+ )
CONTEXT.output_python.append(
- f"{enum_mk_base}.{compat_name}.is_monkey_patched = True\n")
+ f"{enum_mk_base}.{compat_name}.is_monkey_patched = True\n"
+ )
CONTEXT.output_python.append(
- f"{enum_mk_base}.{compat_name}.__doc__ = \"{value_comment}\"\n")
+ f'{enum_mk_base}.{compat_name}.__doc__ = "{value_comment}"\n'
+ )
enum_members_doc.append(
- f"* ``{enum_member}``: {value_comment_indented}")
+ f"* ``{enum_member}``: {value_comment_indented}"
+ )
else:
CONTEXT.output_python.append(
- f"{enum_mk_base}.{compat_name} = {enum_qualname}.{enum_member}\n")
+ f"{enum_mk_base}.{compat_name} = {enum_qualname}.{enum_member}\n"
+ )
CONTEXT.output_python.append(
- f"{enum_mk_base}.{compat_name}.is_monkey_patched = True\n")
+ f"{enum_mk_base}.{compat_name}.is_monkey_patched = True\n"
+ )
CONTEXT.output_python.append(
- f"{enum_mk_base}.{compat_name}.__doc__ = \"{value_comment}\"\n")
+ f'{enum_mk_base}.{compat_name}.__doc__ = "{value_comment}"\n'
+ )
enum_members_doc.append(
- f"* ``{enum_member}``: {value_comment_indented}")
+ f"* ``{enum_member}``: {value_comment_indented}"
+ )
else:
if compat_name != enum_member:
- value_comment_indented += f'\n\n Available as ``{CONTEXT.actual_class}.{compat_name}`` in older QGIS releases.\n'
+ value_comment_indented += f"\n\n Available as ``{CONTEXT.actual_class}.{compat_name}`` in older QGIS releases.\n"
if monkeypatch:
CONTEXT.output_python.append(
- f"{complete_class_path}.{compat_name} = {complete_class_path}.{enum_qualname}.{enum_member}\n")
+ f"{complete_class_path}.{compat_name} = {complete_class_path}.{enum_qualname}.{enum_member}\n"
+ )
CONTEXT.output_python.append(
- f"{complete_class_path}.{compat_name}.is_monkey_patched = True\n")
+ f"{complete_class_path}.{compat_name}.is_monkey_patched = True\n"
+ )
if CONTEXT.actual_class:
CONTEXT.output_python.append(
- f"{complete_class_path}.{enum_qualname}.{compat_name}.__doc__ = \"{value_comment}\"\n")
+ f'{complete_class_path}.{enum_qualname}.{compat_name}.__doc__ = "{value_comment}"\n'
+ )
enum_members_doc.append(
- f"* ``{enum_member}``: {value_comment_indented}")
+ f"* ``{enum_member}``: {value_comment_indented}"
+ )
else:
CONTEXT.output_python.append(
- f"{enum_qualname}.{compat_name}.__doc__ = \"{value_comment}\"\n")
+ f'{enum_qualname}.{compat_name}.__doc__ = "{value_comment}"\n'
+ )
enum_members_doc.append(
- f"* ``{enum_member}``: {value_comment_indented}")
+ f"* ``{enum_member}``: {value_comment_indented}"
+ )
if not is_scope_based and CONTEXT.is_qt6 and enum_member:
- basename = '.'.join(CONTEXT.class_and_struct)
+ basename = ".".join(CONTEXT.class_and_struct)
if basename:
- enum_member = 'None_' if enum_member == 'None' else enum_member
+ enum_member = "None_" if enum_member == "None" else enum_member
CONTEXT.output_python.append(
- f"{basename}.{enum_member} = {basename}.{enum_qualname}.{enum_member}\n")
+ f"{basename}.{enum_member} = {basename}.{enum_qualname}.{enum_member}\n"
+ )
enum_decl = fix_annotations(enum_decl)
write_output("ENU3", f"{enum_decl}\n")
@@ -2168,98 +2308,103 @@ def cpp_to_python_signature(cpp_function: str) -> str:
enum_member_doc_string = "\n".join(enum_members_doc)
if CONTEXT.actual_class:
CONTEXT.output_python.append(
- f'{".".join(CONTEXT.classname)}.{enum_qualname}.__doc__ = """{CONTEXT.comment}\n\n{enum_member_doc_string}\n\n"""\n# --\n')
+ f'{".".join(CONTEXT.classname)}.{enum_qualname}.__doc__ = """{CONTEXT.comment}\n\n{enum_member_doc_string}\n\n"""\n# --\n'
+ )
else:
CONTEXT.output_python.append(
- f'{enum_qualname}.__doc__ = """{CONTEXT.comment}\n\n{enum_member_doc_string}\n\n"""\n# --\n')
+ f'{enum_qualname}.__doc__ = """{CONTEXT.comment}\n\n{enum_member_doc_string}\n\n"""\n# --\n'
+ )
# enums don't have Docstring apparently
- CONTEXT.comment = ''
+ CONTEXT.comment = ""
continue
# Check for invalid use of doxygen command
- if re.search(r'.*//!<', CONTEXT.current_line):
+ if re.search(r".*//!<", CONTEXT.current_line):
exit_with_error(
- '"\\!<" doxygen command must only be used for enum documentation')
+ '"\\!<" doxygen command must only be used for enum documentation'
+ )
# Handle override, final, and make private keywords
- if re.search(r'\boverride\b', CONTEXT.current_line):
+ if re.search(r"\boverride\b", CONTEXT.current_line):
CONTEXT.is_override_or_make_private = PrependType.Virtual
- if re.search(r'\bFINAL\b', CONTEXT.current_line):
+ if re.search(r"\bFINAL\b", CONTEXT.current_line):
CONTEXT.is_override_or_make_private = PrependType.Virtual
- if re.search(r'\bSIP_MAKE_PRIVATE\b', CONTEXT.current_line):
+ if re.search(r"\bSIP_MAKE_PRIVATE\b", CONTEXT.current_line):
CONTEXT.is_override_or_make_private = PrependType.MakePrivate
# Remove Q_INVOKABLE
- CONTEXT.current_line = re.sub(r'^(\s*)Q_INVOKABLE ', r'\1',
- CONTEXT.current_line)
+ CONTEXT.current_line = re.sub(r"^(\s*)Q_INVOKABLE ", r"\1", CONTEXT.current_line)
# Keyword fixes
CONTEXT.current_line = re.sub(
- r'^(\s*template\s*<)(?:class|typename) (\w+>)(.*)$',
- r'\1\2\3', CONTEXT.current_line)
+ r"^(\s*template\s*<)(?:class|typename) (\w+>)(.*)$",
+ r"\1\2\3",
+ CONTEXT.current_line,
+ )
+ CONTEXT.current_line = re.sub(
+ r"^(\s*template\s*<)(?:class|typename) (\w+) *, *(?:class|typename) (\w+>)(.*)$",
+ r"\1\2,\3\4",
+ CONTEXT.current_line,
+ )
CONTEXT.current_line = re.sub(
- r'^(\s*template\s*<)(?:class|typename) (\w+) *, *(?:class|typename) (\w+>)(.*)$',
- r'\1\2,\3\4',
- CONTEXT.current_line)
+ r"^(\s*template\s*<)(?:class|typename) (\w+) *, *(?:class|typename) (\w+) *, *(?:class|typename) (\w+>)(.*)$",
+ r"\1\2,\3,\4\5",
+ CONTEXT.current_line,
+ )
+ CONTEXT.current_line = re.sub(r"\s*\boverride\b", "", CONTEXT.current_line)
+ CONTEXT.current_line = re.sub(r"\s*\bSIP_MAKE_PRIVATE\b", "", CONTEXT.current_line)
CONTEXT.current_line = re.sub(
- r'^(\s*template\s*<)(?:class|typename) (\w+) *, *(?:class|typename) (\w+) *, *(?:class|typename) (\w+>)(.*)$',
- r'\1\2,\3,\4\5', CONTEXT.current_line)
- CONTEXT.current_line = re.sub(r'\s*\boverride\b', '', CONTEXT.current_line)
- CONTEXT.current_line = re.sub(r'\s*\bSIP_MAKE_PRIVATE\b', '',
- CONTEXT.current_line)
- CONTEXT.current_line = re.sub(r'\s*\bFINAL\b', ' ${SIP_FINAL}',
- CONTEXT.current_line)
- CONTEXT.current_line = re.sub(r'\s*\bextern \b', '', CONTEXT.current_line)
- CONTEXT.current_line = re.sub(r'\s*\bMAYBE_UNUSED \b', '',
- CONTEXT.current_line)
- CONTEXT.current_line = re.sub(r'\s*\bNODISCARD \b', '',
- CONTEXT.current_line)
- CONTEXT.current_line = re.sub(r'\s*\bQ_DECL_DEPRECATED\b', '',
- CONTEXT.current_line)
- CONTEXT.current_line = re.sub(r'^(\s*)?(const |virtual |static )*inline ',
- r'\1\2', CONTEXT.current_line)
- CONTEXT.current_line = re.sub(r'\bconstexpr\b', 'const',
- CONTEXT.current_line)
- CONTEXT.current_line = re.sub(r'\bnullptr\b', '0', CONTEXT.current_line)
- CONTEXT.current_line = re.sub(r'\s*=\s*default\b', '',
- CONTEXT.current_line)
+ r"\s*\bFINAL\b", " ${SIP_FINAL}", CONTEXT.current_line
+ )
+ CONTEXT.current_line = re.sub(r"\s*\bextern \b", "", CONTEXT.current_line)
+ CONTEXT.current_line = re.sub(r"\s*\bMAYBE_UNUSED \b", "", CONTEXT.current_line)
+ CONTEXT.current_line = re.sub(r"\s*\bNODISCARD \b", "", CONTEXT.current_line)
+ CONTEXT.current_line = re.sub(r"\s*\bQ_DECL_DEPRECATED\b", "", CONTEXT.current_line)
+ CONTEXT.current_line = re.sub(
+ r"^(\s*)?(const |virtual |static )*inline ", r"\1\2", CONTEXT.current_line
+ )
+ CONTEXT.current_line = re.sub(r"\bconstexpr\b", "const", CONTEXT.current_line)
+ CONTEXT.current_line = re.sub(r"\bnullptr\b", "0", CONTEXT.current_line)
+ CONTEXT.current_line = re.sub(r"\s*=\s*default\b", "", CONTEXT.current_line)
# Handle export macros
- if re.search(r'\b\w+_EXPORT\b', CONTEXT.current_line):
+ if re.search(r"\b\w+_EXPORT\b", CONTEXT.current_line):
CONTEXT.exported[-1] += 1
- CONTEXT.current_line = re.sub(r'\b\w+_EXPORT\s+', '',
- CONTEXT.current_line)
+ CONTEXT.current_line = re.sub(r"\b\w+_EXPORT\s+", "", CONTEXT.current_line)
# Skip non-method member declaration in non-public sections
- if not CONTEXT.sip_run and CONTEXT.access[
- -1] != Visibility.Public and detect_non_method_member(
- CONTEXT.current_line):
+ if (
+ not CONTEXT.sip_run
+ and CONTEXT.access[-1] != Visibility.Public
+ and detect_non_method_member(CONTEXT.current_line)
+ ):
dbg_info("skip non-method member declaration in non-public sections")
continue
# Remove static const value assignment
# https://regex101.com/r/DyWkgn/6
- if re.search(r'^\s*const static \w+', CONTEXT.current_line):
+ if re.search(r"^\s*const static \w+", CONTEXT.current_line):
exit_with_error(
- f"const static should be written static const in {CONTEXT.classname[-1]}")
+ f"const static should be written static const in {CONTEXT.classname[-1]}"
+ )
# TODO needs fixing!!
# original perl regex was:
# ^(? *(?static )?const (\w+::)*\w+(?:<(?:[\w<>, ]|::)+>)? \w+)(?: = [^()]+?(\((?:[^()]++|(?3))*\))?[^()]*?)?(?[|;]) *(\/\/.*?)?$
match = re.search(
- r'^(?P *(?Pstatic )?const (\w+::)*\w+(?:<(?:[\w<>, ]|::)+>)? \w+)(?: = [^()]+?(\((?:[^()]|\([^()]*\))*\))?[^()]*?)?(?P[|;]) *(//.*)?$',
- CONTEXT.current_line
+ r"^(?P *(?Pstatic )?const (\w+::)*\w+(?:<(?:[\w<>, ]|::)+>)? \w+)(?: = [^()]+?(\((?:[^()]|\([^()]*\))*\))?[^()]*?)?(?P[|;]) *(//.*)?$",
+ CONTEXT.current_line,
)
if match:
CONTEXT.current_line = f"{match.group('staticconst')};"
- if match.group('static') is None:
- CONTEXT.comment = ''
+ if match.group("static") is None:
+ CONTEXT.comment = ""
- if match.group('endingchar') == '|':
+ if match.group("endingchar") == "|":
dbg_info("multiline const static assignment")
- skip = ''
- while not re.search(r';\s*(//.*?)?$', skip):
+ skip = ""
+ while not re.search(r";\s*(//.*?)?$", skip):
skip = read_line()
# Remove struct member assignment
@@ -2268,7 +2413,7 @@ def cpp_to_python_signature(cpp_function: str) -> str:
# original perl regex: ^(\s*\w+[\w<> *&:,]* \*?\w+) = ([\-\w\:\.]+(< *\w+( \*)? *>)?)+(\([^()]*\))?\s*;
# dbg_info(f"attempt struct member assignment '{CONTEXT.current_line}'")
- python_regex_verbose = r'''
+ python_regex_verbose = r"""
^ # Start of the line
( # Start of capturing group for the left-hand side
\s* # Optional leading whitespace
@@ -2309,58 +2454,69 @@ def cpp_to_python_signature(cpp_function: str) -> str:
\s* # Optional whitespace after semicolon
(?:\/\/.*)? # Optional single-line comment
$ # End of the line
- '''
- regex_verbose = re.compile(python_regex_verbose,
- re.VERBOSE | re.MULTILINE)
+ """
+ regex_verbose = re.compile(python_regex_verbose, re.VERBOSE | re.MULTILINE)
match = regex_verbose.match(CONTEXT.current_line)
if match:
dbg_info(f"remove struct member assignment '={match.group(2)}'")
CONTEXT.current_line = f"{match.group(1)};"
# Catch Q_DECLARE_FLAGS
- match = re.search(r'^(\s*)Q_DECLARE_FLAGS\(\s*(.*?)\s*,\s*(.*?)\s*\)\s*$',
- CONTEXT.current_line)
+ match = re.search(
+ r"^(\s*)Q_DECLARE_FLAGS\(\s*(.*?)\s*,\s*(.*?)\s*\)\s*$", CONTEXT.current_line
+ )
if match:
- CONTEXT.actual_class = f"{CONTEXT.classname[-1]}::" if len(
- CONTEXT.classname) >= 0 else ''
+ CONTEXT.actual_class = (
+ f"{CONTEXT.classname[-1]}::" if len(CONTEXT.classname) >= 0 else ""
+ )
dbg_info(f"Declare flags: {CONTEXT.actual_class}")
CONTEXT.current_line = f"{match.group(1)}typedef QFlags<{CONTEXT.actual_class}{match.group(3)}> {match.group(2)};\n"
- CONTEXT.qflag_hash[
- f"{CONTEXT.actual_class}{match.group(2)}"] = f"{CONTEXT.actual_class}{match.group(3)}"
+ CONTEXT.qflag_hash[f"{CONTEXT.actual_class}{match.group(2)}"] = (
+ f"{CONTEXT.actual_class}{match.group(3)}"
+ )
if f"{CONTEXT.actual_class}{match.group(3)}" not in CONTEXT.enum_intflag_types:
exit_with_error(
- f"{CONTEXT.actual_class}{match.group(3)} is a flags type, but was not declared with IntFlag type. Add 'SIP_ENUM_BASETYPE(IntFlag)' to the enum class declaration line")
+ f"{CONTEXT.actual_class}{match.group(3)} is a flags type, but was not declared with IntFlag type. Add 'SIP_ENUM_BASETYPE(IntFlag)' to the enum class declaration line"
+ )
# Catch Q_DECLARE_OPERATORS_FOR_FLAGS
match = re.search(
- r'^(\s*)Q_DECLARE_OPERATORS_FOR_FLAGS\(\s*(.*?)\s*\)\s*$',
- CONTEXT.current_line)
+ r"^(\s*)Q_DECLARE_OPERATORS_FOR_FLAGS\(\s*(.*?)\s*\)\s*$", CONTEXT.current_line
+ )
if match:
flags = match.group(2)
flag = CONTEXT.qflag_hash.get(flags)
- CONTEXT.current_line = f"{match.group(1)}QFlags<{flag}> operator|({flag} f1, QFlags<{flag}> f2);\n"
+ CONTEXT.current_line = (
+ f"{match.group(1)}QFlags<{flag}> operator|({flag} f1, QFlags<{flag}> f2);\n"
+ )
py_flag = flag.replace("::", ".")
if py_flag in CONTEXT.enum_class_non_int_types:
exit_with_error(
- f"{flag} is a flags type, but was not declared with int type. Add ': int' to the enum class declaration line")
+ f"{flag} is a flags type, but was not declared with int type. Add ': int' to the enum class declaration line"
+ )
elif py_flag not in CONTEXT.enum_int_types:
if CONTEXT.is_qt6:
dbg_info("monkey patching operators for non-class enum")
if not CONTEXT.has_pushed_force_int:
CONTEXT.output_python.append(
- "from enum import Enum\n\n\ndef _force_int(v): return int(v.value) if isinstance(v, Enum) else v\n\n\n")
+ "from enum import Enum\n\n\ndef _force_int(v): return int(v.value) if isinstance(v, Enum) else v\n\n\n"
+ )
CONTEXT.has_pushed_force_int = True
CONTEXT.output_python.append(
- f"{py_flag}.__bool__ = lambda flag: bool(_force_int(flag))\n")
+ f"{py_flag}.__bool__ = lambda flag: bool(_force_int(flag))\n"
+ )
CONTEXT.output_python.append(
- f"{py_flag}.__eq__ = lambda flag1, flag2: _force_int(flag1) == _force_int(flag2)\n")
+ f"{py_flag}.__eq__ = lambda flag1, flag2: _force_int(flag1) == _force_int(flag2)\n"
+ )
CONTEXT.output_python.append(
- f"{py_flag}.__and__ = lambda flag1, flag2: _force_int(flag1) & _force_int(flag2)\n")
+ f"{py_flag}.__and__ = lambda flag1, flag2: _force_int(flag1) & _force_int(flag2)\n"
+ )
CONTEXT.output_python.append(
- f"{py_flag}.__or__ = lambda flag1, flag2: {py_flag}(_force_int(flag1) | _force_int(flag2))\n")
+ f"{py_flag}.__or__ = lambda flag1, flag2: {py_flag}(_force_int(flag1) | _force_int(flag2))\n"
+ )
if not CONTEXT.is_qt6:
for patched_type in CONTEXT.enum_monkey_patched_types:
@@ -2368,10 +2524,12 @@ def cpp_to_python_signature(cpp_function: str) -> str:
dbg_info("monkey patching flags")
if not CONTEXT.has_pushed_force_int:
CONTEXT.output_python.append(
- "from enum import Enum\n\n\ndef _force_int(v): return int(v.value) if isinstance(v, Enum) else v\n\n\n")
+ "from enum import Enum\n\n\ndef _force_int(v): return int(v.value) if isinstance(v, Enum) else v\n\n\n"
+ )
CONTEXT.has_pushed_force_int = True
CONTEXT.output_python.append(
- f"{py_flag}.__or__ = lambda flag1, flag2: {patched_type[0]}.{patched_type[1]}(_force_int(flag1) | _force_int(flag2))\n")
+ f"{py_flag}.__or__ = lambda flag1, flag2: {patched_type[0]}.{patched_type[1]}(_force_int(flag1) | _force_int(flag2))\n"
+ )
# Remove keywords
if CONTEXT.is_override_or_make_private != PrependType.NoPrepend:
@@ -2380,180 +2538,233 @@ def cpp_to_python_signature(cpp_function: str) -> str:
rolling_line = CONTEXT.current_line
rolling_line_idx = CONTEXT.line_idx
dbg_info(
- "handle multiline definition to add virtual keyword or making private on opening line")
- while not re.match(r'^[^()]*\(([^()]*\([^()]*\)[^()]*)*[^()]*$',
- rolling_line):
+ "handle multiline definition to add virtual keyword or making private on opening line"
+ )
+ while not re.match(
+ r"^[^()]*\(([^()]*\([^()]*\)[^()]*)*[^()]*$", rolling_line
+ ):
rolling_line_idx -= 1
rolling_line = CONTEXT.input_lines[rolling_line_idx]
if rolling_line_idx < 0:
- exit_with_error('could not reach opening definition')
- dbg_info(f'rolled back to {rolling_line_idx}: {rolling_line}')
+ exit_with_error("could not reach opening definition")
+ dbg_info(f"rolled back to {rolling_line_idx}: {rolling_line}")
- if CONTEXT.is_override_or_make_private == PrependType.Virtual and not re.match(
- r'^(\s*)virtual\b(.*)$',
- rolling_line):
+ if (
+ CONTEXT.is_override_or_make_private == PrependType.Virtual
+ and not re.match(r"^(\s*)virtual\b(.*)$", rolling_line)
+ ):
idx = rolling_line_idx - CONTEXT.line_idx + 1
CONTEXT.output[idx] = fix_annotations(
- re.sub(r'^(\s*?)\b(.*)$', r'\1 virtual \2\n',
- rolling_line))
+ re.sub(r"^(\s*?)\b(.*)$", r"\1 virtual \2\n", rolling_line)
+ )
elif CONTEXT.is_override_or_make_private == PrependType.MakePrivate:
dbg_info("prepending private access")
idx = rolling_line_idx - CONTEXT.line_idx
- private_access = re.sub(r'(protected|public)', 'private',
- CONTEXT.last_access_section_line)
+ private_access = re.sub(
+ r"(protected|public)", "private", CONTEXT.last_access_section_line
+ )
CONTEXT.output.insert(idx + 1, private_access + "\n")
CONTEXT.output[idx + 1] = fix_annotations(rolling_line) + "\n"
elif CONTEXT.is_override_or_make_private == PrependType.MakePrivate:
dbg_info("prepending private access")
- CONTEXT.current_line = re.sub(r'(protected|public)', 'private',
- CONTEXT.last_access_section_line) + "\n" + CONTEXT.current_line + "\n"
- elif CONTEXT.is_override_or_make_private == PrependType.Virtual and not re.match(
- r'^(\s*)virtual\b(.*)$', CONTEXT.current_line):
+ CONTEXT.current_line = (
+ re.sub(
+ r"(protected|public)", "private", CONTEXT.last_access_section_line
+ )
+ + "\n"
+ + CONTEXT.current_line
+ + "\n"
+ )
+ elif (
+ CONTEXT.is_override_or_make_private == PrependType.Virtual
+ and not re.match(r"^(\s*)virtual\b(.*)$", CONTEXT.current_line)
+ ):
# SIP often requires the virtual keyword to be present, or it chokes on covariant return types
# in overridden methods
- dbg_info('adding virtual keyword for overridden method')
- CONTEXT.current_line = re.sub(r'^(\s*?)\b(.*)$', r'\1virtual \2\n',
- CONTEXT.current_line)
+ dbg_info("adding virtual keyword for overridden method")
+ CONTEXT.current_line = re.sub(
+ r"^(\s*?)\b(.*)$", r"\1virtual \2\n", CONTEXT.current_line
+ )
# remove constructor definition, function bodies, member initializing list
CONTEXT.python_signature = detect_and_remove_following_body_or_initializerlist()
# remove inline declarations
match = re.search(
- r'^(\s*)?(static |const )*(([(?:long )\w]+(<.*?>)?\s+([*&])?)?(\w+)( const*?)*)\s*(\{.*});(\s*//.*)?$',
- CONTEXT.current_line)
+ r"^(\s*)?(static |const )*(([(?:long )\w]+(<.*?>)?\s+([*&])?)?(\w+)( const*?)*)\s*(\{.*});(\s*//.*)?$",
+ CONTEXT.current_line,
+ )
if match:
CONTEXT.current_line = f"{match.group(1)}{match.group(3)};"
- pattern = r'^\s*((?:const |virtual |static |inline ))*(?!explicit)([(?:long )\w:]+(?:<.*?>)?)\s+(?:\*|&)?(\w+|operator.{1,2})(\(.*)$'
+ pattern = r"^\s*((?:const |virtual |static |inline ))*(?!explicit)([(?:long )\w:]+(?:<.*?>)?)\s+(?:\*|&)?(\w+|operator.{1,2})(\(.*)$"
match = re.match(pattern, CONTEXT.current_line)
if match:
CONTEXT.current_method_name = match.group(3)
return_type_candidate = match.group(2)
- is_static = bool(match.group(1) and 'static' in match.group(1))
+ is_static = bool(match.group(1) and "static" in match.group(1))
class_name = CONTEXT.current_fully_qualified_class_name()
if CONTEXT.current_method_name in CONTEXT.static_methods[class_name]:
- if CONTEXT.static_methods[class_name][CONTEXT.current_method_name] != is_static:
- CONTEXT.static_methods[class_name][
- CONTEXT.current_method_name] = False
+ if (
+ CONTEXT.static_methods[class_name][CONTEXT.current_method_name]
+ != is_static
+ ):
+ CONTEXT.static_methods[class_name][CONTEXT.current_method_name] = False
else:
CONTEXT.static_methods[class_name][CONTEXT.current_method_name] = is_static
if CONTEXT.access[-1] == Visibility.Signals:
CONTEXT.current_signal_args = []
signal_args = match.group(4).strip()
- if signal_args.startswith('('):
+ if signal_args.startswith("("):
signal_args = signal_args[1:]
- if signal_args.endswith(');'):
+ if signal_args.endswith(");"):
signal_args = signal_args[:-2]
if signal_args.strip():
CONTEXT.current_signal_args = split_args(signal_args)
- dbg_info('SIGARG ' + CONTEXT.current_method_name + " " + str(CONTEXT.current_signal_args))
- if ');' in match.group(4):
- CONTEXT.signal_arguments[class_name][
- CONTEXT.current_method_name] = CONTEXT.current_signal_args[:]
- dbg_info('SIGARG finalizing' + CONTEXT.current_method_name + " " + str(CONTEXT.current_signal_args))
-
- if not re.search(r'(void|SIP_PYOBJECT|operator|return|QFlag)',
- return_type_candidate):
+ dbg_info(
+ "SIGARG "
+ + CONTEXT.current_method_name
+ + " "
+ + str(CONTEXT.current_signal_args)
+ )
+ if ");" in match.group(4):
+ CONTEXT.signal_arguments[class_name][CONTEXT.current_method_name] = (
+ CONTEXT.current_signal_args[:]
+ )
+ dbg_info(
+ "SIGARG finalizing"
+ + CONTEXT.current_method_name
+ + " "
+ + str(CONTEXT.current_signal_args)
+ )
+
+ if not re.search(
+ r"(void|SIP_PYOBJECT|operator|return|QFlag)", return_type_candidate
+ ):
# replace :: with . (changes c++ style namespace/class directives to Python style)
- CONTEXT.return_type = return_type_candidate.replace('::', '.')
+ CONTEXT.return_type = return_type_candidate.replace("::", ".")
# replace with builtin Python types
- CONTEXT.return_type = re.sub(r'\bdouble\b', 'float',
- CONTEXT.return_type)
- CONTEXT.return_type = re.sub(r'\bQString\b', 'str',
- CONTEXT.return_type)
- CONTEXT.return_type = re.sub(r'\bQStringList\b', 'list of str',
- CONTEXT.return_type)
-
- list_match = re.match(r'^(?:QList|QVector)<\s*(.*?)[\s*]*>$',
- CONTEXT.return_type)
+ CONTEXT.return_type = re.sub(r"\bdouble\b", "float", CONTEXT.return_type)
+ CONTEXT.return_type = re.sub(r"\bQString\b", "str", CONTEXT.return_type)
+ CONTEXT.return_type = re.sub(
+ r"\bQStringList\b", "list of str", CONTEXT.return_type
+ )
+
+ list_match = re.match(
+ r"^(?:QList|QVector)<\s*(.*?)[\s*]*>$", CONTEXT.return_type
+ )
if list_match:
CONTEXT.return_type = f"list of {list_match.group(1)}"
- set_match = re.match(r'^QSet<\s*(.*?)[\s*]*>$',
- CONTEXT.return_type)
+ set_match = re.match(r"^QSet<\s*(.*?)[\s*]*>$", CONTEXT.return_type)
if set_match:
CONTEXT.return_type = f"set of {set_match.group(1)}"
- elif CONTEXT.access[-1] == Visibility.Signals and CONTEXT.current_line.strip() not in ('', 'signals:'):
- dbg_info('SIGARG4 ' + CONTEXT.current_method_name + " " + CONTEXT.current_line)
+ elif CONTEXT.access[
+ -1
+ ] == Visibility.Signals and CONTEXT.current_line.strip() not in ("", "signals:"):
+ dbg_info("SIGARG4 " + CONTEXT.current_method_name + " " + CONTEXT.current_line)
signal_args = CONTEXT.current_line.strip()
- if signal_args.endswith(');'):
+ if signal_args.endswith(");"):
signal_args = signal_args[:-2]
if signal_args.strip():
CONTEXT.current_signal_args.extend(split_args(signal_args))
- dbg_info('SIGARG5 ' + CONTEXT.current_method_name + " " + str(CONTEXT.current_signal_args))
- if ');' in CONTEXT.current_line:
+ dbg_info(
+ "SIGARG5 "
+ + CONTEXT.current_method_name
+ + " "
+ + str(CONTEXT.current_signal_args)
+ )
+ if ");" in CONTEXT.current_line:
class_name = CONTEXT.current_fully_qualified_class_name()
- CONTEXT.signal_arguments[class_name][
- CONTEXT.current_method_name] = CONTEXT.current_signal_args[:]
- dbg_info('SIGARG finalizing' + CONTEXT.current_method_name + " " + str(CONTEXT.current_signal_args))
+ CONTEXT.signal_arguments[class_name][CONTEXT.current_method_name] = (
+ CONTEXT.current_signal_args[:]
+ )
+ dbg_info(
+ "SIGARG finalizing"
+ + CONTEXT.current_method_name
+ + " "
+ + str(CONTEXT.current_signal_args)
+ )
# deleted functions
if re.match(
- r'^(\s*)?(const )?(virtual |static )?((\w+(<.*?>)?\s+([*&])?)?(\w+|operator.{1,2})\(.*?(\(.*\))*.*\)( const)?)\s*= delete;(\s*//.*)?$',
- CONTEXT.current_line):
- CONTEXT.comment = ''
+ r"^(\s*)?(const )?(virtual |static )?((\w+(<.*?>)?\s+([*&])?)?(\w+|operator.{1,2})\(.*?(\(.*\))*.*\)( const)?)\s*= delete;(\s*//.*)?$",
+ CONTEXT.current_line,
+ ):
+ CONTEXT.comment = ""
continue
# remove export macro from struct definition
- CONTEXT.current_line = re.sub(r'^(\s*struct )\w+_EXPORT (.+)$', r'\1\2',
- CONTEXT.current_line)
+ CONTEXT.current_line = re.sub(
+ r"^(\s*struct )\w+_EXPORT (.+)$", r"\1\2", CONTEXT.current_line
+ )
# Skip comments
- if re.match(r'^\s*typedef\s+\w+\s*<\s*\w+\s*>\s+\w+\s+.*SIP_DOC_TEMPLATE',
- CONTEXT.current_line):
+ if re.match(
+ r"^\s*typedef\s+\w+\s*<\s*\w+\s*>\s+\w+\s+.*SIP_DOC_TEMPLATE",
+ CONTEXT.current_line,
+ ):
# support Docstring for template based classes in SIP 4.19.7+
CONTEXT.comment_template_docstring = True
- elif (CONTEXT.multiline_definition == MultiLineType.NotMultiline and
- (re.search(r'//', CONTEXT.current_line) or
- re.match(r'^\s*typedef ', CONTEXT.current_line) or
- re.search(r'\s*struct ', CONTEXT.current_line) or
- re.search(r'operator\[]\(', CONTEXT.current_line) or
- re.match(r'^\s*operator\b', CONTEXT.current_line) or
- re.search(r'operator\s?[!+-=*/\[\]<>]{1,2}',
- CONTEXT.current_line) or
- re.match(r'^\s*%\w+(.*)?$', CONTEXT.current_line) or
- re.match(r'^\s*namespace\s+\w+', CONTEXT.current_line) or
- re.match(r'^\s*(virtual\s*)?~', CONTEXT.current_line) or
- detect_non_method_member(CONTEXT.current_line)
- )):
- dbg_info(f'skipping comment for {CONTEXT.current_line}')
- if re.search(r'\s*typedef.*?(?!SIP_DOC_TEMPLATE)',
- CONTEXT.current_line):
- dbg_info('because typedef')
- elif CONTEXT.actual_class and detect_non_method_member(
- CONTEXT.current_line) and CONTEXT.comment:
- attribute_name_match = re.match(r'^.*?\s[*&]*(\w+);.*$',
- CONTEXT.current_line)
+ elif CONTEXT.multiline_definition == MultiLineType.NotMultiline and (
+ re.search(r"//", CONTEXT.current_line)
+ or re.match(r"^\s*typedef ", CONTEXT.current_line)
+ or re.search(r"\s*struct ", CONTEXT.current_line)
+ or re.search(r"operator\[]\(", CONTEXT.current_line)
+ or re.match(r"^\s*operator\b", CONTEXT.current_line)
+ or re.search(r"operator\s?[!+-=*/\[\]<>]{1,2}", CONTEXT.current_line)
+ or re.match(r"^\s*%\w+(.*)?$", CONTEXT.current_line)
+ or re.match(r"^\s*namespace\s+\w+", CONTEXT.current_line)
+ or re.match(r"^\s*(virtual\s*)?~", CONTEXT.current_line)
+ or detect_non_method_member(CONTEXT.current_line)
+ ):
+ dbg_info(f"skipping comment for {CONTEXT.current_line}")
+ if re.search(r"\s*typedef.*?(?!SIP_DOC_TEMPLATE)", CONTEXT.current_line):
+ dbg_info("because typedef")
+ elif (
+ CONTEXT.actual_class
+ and detect_non_method_member(CONTEXT.current_line)
+ and CONTEXT.comment
+ ):
+ attribute_name_match = re.match(
+ r"^.*?\s[*&]*(\w+);.*$", CONTEXT.current_line
+ )
class_name = CONTEXT.current_fully_qualified_struct_name()
dbg_info(
- f'storing attribute docstring for {class_name} : {attribute_name_match.group(1)}')
+ f"storing attribute docstring for {class_name} : {attribute_name_match.group(1)}"
+ )
CONTEXT.attribute_docstrings[class_name][
- attribute_name_match.group(1)] = CONTEXT.comment
- elif CONTEXT.current_fully_qualified_struct_name() and re.search(r'\s*struct ', CONTEXT.current_line) and CONTEXT.comment:
+ attribute_name_match.group(1)
+ ] = CONTEXT.comment
+ elif (
+ CONTEXT.current_fully_qualified_struct_name()
+ and re.search(r"\s*struct ", CONTEXT.current_line)
+ and CONTEXT.comment
+ ):
class_name = CONTEXT.current_fully_qualified_struct_name()
- dbg_info(
- f'storing struct docstring for {class_name}')
+ dbg_info(f"storing struct docstring for {class_name}")
CONTEXT.struct_docstrings[class_name] = CONTEXT.comment
- CONTEXT.comment = ''
- CONTEXT.return_type = ''
+ CONTEXT.comment = ""
+ CONTEXT.return_type = ""
CONTEXT.is_override_or_make_private = PrependType.NoPrepend
CONTEXT.current_line = fix_constants(CONTEXT.current_line)
CONTEXT.current_line = fix_annotations(CONTEXT.current_line)
# fix astyle placing space after % character
- CONTEXT.current_line = re.sub(r'/\s+GetWrapper\s+/', '/GetWrapper/',
- CONTEXT.current_line)
+ CONTEXT.current_line = re.sub(
+ r"/\s+GetWrapper\s+/", "/GetWrapper/", CONTEXT.current_line
+ )
# MISSING
# handle enum/flags QgsSettingsEntryEnumFlag
- match = re.match(r'^(\s*)const QgsSettingsEntryEnumFlag<(.*)> (.+);$',
- CONTEXT.current_line)
+ match = re.match(
+ r"^(\s*)const QgsSettingsEntryEnumFlag<(.*)> (.+);$", CONTEXT.current_line
+ )
if match:
CONTEXT.indent, enum_type, var_name = match.groups()
@@ -2570,8 +2781,10 @@ def cpp_to_python_signature(cpp_function: str) -> str:
{enum_type} value( const QString &dynamicKeyPart = QString(), bool useDefaultValueOverride = false, const {enum_type} &defaultValueOverride = {enum_type}() ) const;
}};"""
- CONTEXT.current_line = f"{CONTEXT.indent}const QgsSettingsEntryEnumFlag_{var_name} {var_name};"
- CONTEXT.comment = ''
+ CONTEXT.current_line = (
+ f"{CONTEXT.indent}const QgsSettingsEntryEnumFlag_{var_name} {var_name};"
+ )
+ CONTEXT.comment = ""
write_output("ENF", f"{prep_line}\n", "prepend")
write_output("NOR", f"{CONTEXT.current_line}\n")
@@ -2579,12 +2792,14 @@ def cpp_to_python_signature(cpp_function: str) -> str:
# append to class map file
if args.class_map and CONTEXT.actual_class:
match = re.match(
- r'^ *(const |virtual |static )* *[\w:]+ +\*?(?P\w+)\(.*$',
- CONTEXT.current_line)
+ r"^ *(const |virtual |static )* *[\w:]+ +\*?(?P\w+)\(.*$",
+ CONTEXT.current_line,
+ )
if match:
- with open(args.class_map, 'a') as f:
+ with open(args.class_map, "a") as f:
f.write(
- f"{'.'.join(CONTEXT.classname)}.{match.group('method')}: {CONTEXT.header_file}#L{CONTEXT.line_idx}\n")
+ f"{'.'.join(CONTEXT.classname)}.{match.group('method')}: {CONTEXT.header_file}#L{CONTEXT.line_idx}\n"
+ )
if CONTEXT.python_signature:
write_output("PSI", f"{CONTEXT.python_signature}\n")
@@ -2596,13 +2811,15 @@ def cpp_to_python_signature(cpp_function: str) -> str:
# TODO - original regex is incompatible with python -- it was:
# ^([^()]+(\((?:[^()]++|(?1))*\)))*[^()]*\)([^()](throw\([^()]+\))?)*$:
if re.match(
- r'^([^()]+(\((?:[^()]|\([^()]*\))*\)))*[^()]*\)([^()](throw\([^()]+\))?)*',
- CONTEXT.current_line):
+ r"^([^()]+(\((?:[^()]|\([^()]*\))*\)))*[^()]*\)([^()](throw\([^()]+\))?)*",
+ CONTEXT.current_line,
+ ):
dbg_info("ending multiline")
# remove potential following body
- if CONTEXT.multiline_definition != MultiLineType.ConditionalStatement and not re.search(
- r'(\{.*}|;)\s*(//.*)?$',
- CONTEXT.current_line):
+ if (
+ CONTEXT.multiline_definition != MultiLineType.ConditionalStatement
+ and not re.search(r"(\{.*}|;)\s*(//.*)?$", CONTEXT.current_line)
+ ):
dbg_info("remove following body of multiline def")
last_line = CONTEXT.current_line
last_line += remove_following_body_or_initializerlist()
@@ -2612,39 +2829,43 @@ def cpp_to_python_signature(cpp_function: str) -> str:
CONTEXT.multiline_definition = MultiLineType.NotMultiline
else:
continue
- elif re.match(r'^[^()]+\([^()]*(?:\([^()]*\)[^()]*)*[^)]*$',
- CONTEXT.current_line):
+ elif re.match(r"^[^()]+\([^()]*(?:\([^()]*\)[^()]*)*[^)]*$", CONTEXT.current_line):
dbg_info(f"Multiline detected:: {CONTEXT.current_line}")
- if re.match(r'^\s*((else )?if|while|for) *\(', CONTEXT.current_line):
+ if re.match(r"^\s*((else )?if|while|for) *\(", CONTEXT.current_line):
CONTEXT.multiline_definition = MultiLineType.ConditionalStatement
else:
CONTEXT.multiline_definition = MultiLineType.Method
continue
# write comment
- if re.match(r'^\s*$', CONTEXT.current_line):
+ if re.match(r"^\s*$", CONTEXT.current_line):
dbg_info("no more override / private")
CONTEXT.is_override_or_make_private = PrependType.NoPrepend
continue
- if re.match(r'^\s*template\s*<.*>', CONTEXT.current_line):
+ if re.match(r"^\s*template\s*<.*>", CONTEXT.current_line):
# do not comment now for templates, wait for class definition
continue
if CONTEXT.comment.strip() or CONTEXT.return_type:
- if CONTEXT.is_override_or_make_private != PrependType.Virtual and not CONTEXT.comment.strip():
+ if (
+ CONTEXT.is_override_or_make_private != PrependType.Virtual
+ and not CONTEXT.comment.strip()
+ ):
# overridden method with no new docs - so don't create a Docstring and use
# parent class Docstring
pass
else:
- dbg_info('writing comment')
+ dbg_info("writing comment")
if CONTEXT.comment.strip():
- dbg_info('comment non-empty')
- doc_prepend = "@DOCSTRINGSTEMPLATE@" if CONTEXT.comment_template_docstring else ""
+ dbg_info("comment non-empty")
+ doc_prepend = (
+ "@DOCSTRINGSTEMPLATE@" if CONTEXT.comment_template_docstring else ""
+ )
write_output("CM1", f"{doc_prepend}%Docstring\n")
- doc_string = ''
- comment_lines = CONTEXT.comment.split('\n')
+ doc_string = ""
+ comment_lines = CONTEXT.comment.split("\n")
skipping_param = 0
out_params = []
waiting_for_return_to_end = False
@@ -2654,8 +2875,9 @@ def cpp_to_python_signature(cpp_function: str) -> str:
comment_line = comment_lines[comment_line_idx]
comment_line_idx += 1
if (
- 'versionadded:' in comment_line or 'deprecated:' in comment_line) and out_params:
- dbg_info('out style parameters remain to flush!')
+ "versionadded:" in comment_line or "deprecated:" in comment_line
+ ) and out_params:
+ dbg_info("out style parameters remain to flush!")
# member has /Out/ parameters, but no return type, so flush out out_params docs now
first_out_param = out_params.pop(0)
doc_string += f"{doc_prepend}:return: - {first_out_param}\n"
@@ -2666,21 +2888,29 @@ def cpp_to_python_signature(cpp_function: str) -> str:
doc_string += f"{doc_prepend}\n"
out_params = []
- param_match = re.match(r'^:param\s+(\w+)', comment_line)
+ param_match = re.match(r"^:param\s+(\w+)", comment_line)
if param_match:
param_name = param_match.group(1)
- dbg_info(f'found parameter: {param_name}')
- if param_name in CONTEXT.skipped_params_out or param_name in CONTEXT.skipped_params_remove:
+ dbg_info(f"found parameter: {param_name}")
+ if (
+ param_name in CONTEXT.skipped_params_out
+ or param_name in CONTEXT.skipped_params_remove
+ ):
dbg_info(str(CONTEXT.skipped_params_out))
if param_name in CONTEXT.skipped_params_out:
- dbg_info(f'deferring docs for parameter {param_name} marked as SIP_OUT')
+ dbg_info(
+ f"deferring docs for parameter {param_name} marked as SIP_OUT"
+ )
comment_line = re.sub(
- r'^:param\s+(\w+):\s*(.*?)$', r'\1: \2',
- comment_line)
+ r"^:param\s+(\w+):\s*(.*?)$",
+ r"\1: \2",
+ comment_line,
+ )
comment_line = re.sub(
- r'(?:optional|if specified|if given|storage for|will be set to),?\s*',
- '',
- comment_line)
+ r"(?:optional|if specified|if given|storage for|will be set to),?\s*",
+ "",
+ comment_line,
+ )
out_params.append(comment_line)
skipping_param = 2
else:
@@ -2688,19 +2918,18 @@ def cpp_to_python_signature(cpp_function: str) -> str:
continue
if skipping_param > 0:
- if re.match(r'^(:.*|\.\..*|\s*)$', comment_line):
+ if re.match(r"^(:.*|\.\..*|\s*)$", comment_line):
skipping_param = 0
elif skipping_param == 2:
- comment_line = re.sub(r'^\s+', ' ', comment_line)
+ comment_line = re.sub(r"^\s+", " ", comment_line)
out_params[-1] += comment_line
continue
else:
continue
- if ':return:' in comment_line and out_params:
+ if ":return:" in comment_line and out_params:
waiting_for_return_to_end = True
- comment_line = comment_line.replace(':return:',
- ':return: -')
+ comment_line = comment_line.replace(":return:", ":return: -")
doc_string += f"{doc_prepend}{comment_line}\n"
# scan forward to find end of return description
@@ -2709,15 +2938,23 @@ def cpp_to_python_signature(cpp_function: str) -> str:
while scan_forward_idx < len(comment_lines):
scan_forward_line = comment_lines[scan_forward_idx]
scan_forward_idx += 1
- if not scan_forward_line.strip() and scan_forward_idx < len(comment_lines) - 1:
+ if (
+ not scan_forward_line.strip()
+ and scan_forward_idx < len(comment_lines) - 1
+ ):
# check if following line is start of list
- if re.match(r'^\s*-(?!-)', comment_lines[scan_forward_idx + 1]):
+ if re.match(
+ r"^\s*-(?!-)", comment_lines[scan_forward_idx + 1]
+ ):
doc_string += "\n"
comment_line_idx += 1
needs_blank_line_after_return = True
continue
- if re.match(r'^(:.*|\.\..*|\s*)$', scan_forward_line) or not scan_forward_line.strip():
+ if (
+ re.match(r"^(:.*|\.\..*|\s*)$", scan_forward_line)
+ or not scan_forward_line.strip()
+ ):
break
doc_string += f"{doc_prepend} {scan_forward_line}\n"
@@ -2733,7 +2970,7 @@ def cpp_to_python_signature(cpp_function: str) -> str:
doc_string += f"{doc_prepend}{comment_line}\n"
if waiting_for_return_to_end:
- if re.match(r'^(:.*|\.\..*|\s*)$', comment_line):
+ if re.match(r"^(:.*|\.\..*|\s*)$", comment_line):
waiting_for_return_to_end = False
else:
pass # Return docstring should be single line with SIP_OUT params
@@ -2741,7 +2978,8 @@ def cpp_to_python_signature(cpp_function: str) -> str:
if out_params:
if CONTEXT.return_type:
exit_with_error(
- f"A method with output parameters must contain a return directive ({CONTEXT.current_method_name} method returns {CONTEXT.return_type})")
+ f"A method with output parameters must contain a return directive ({CONTEXT.current_method_name} method returns {CONTEXT.return_type})"
+ )
else:
doc_string += "\n"
@@ -2750,22 +2988,27 @@ def cpp_to_python_signature(cpp_function: str) -> str:
if len(out_params) > 1:
doc_string += f":return: - {out_param}\n"
else:
- arg_name_match = re.match(r'^(.*?):\s*(.*?)$', out_param)
- doc_string += f":return: {arg_name_match.group(2)}\n"
+ arg_name_match = re.match(
+ r"^(.*?):\s*(.*?)$", out_param
+ )
+ doc_string += (
+ f":return: {arg_name_match.group(2)}\n"
+ )
else:
doc_string += f"{doc_prepend} - {out_param}\n"
- dbg_info(f'doc_string is {doc_string}')
+ dbg_info(f"doc_string is {doc_string}")
write_output("DS", doc_string)
if CONTEXT.access[-1] == Visibility.Signals and doc_string:
- dbg_info('storing signal docstring')
- class_name = '.'.join(CONTEXT.classname)
+ dbg_info("storing signal docstring")
+ class_name = ".".join(CONTEXT.classname)
CONTEXT.attribute_docstrings[class_name][
- CONTEXT.current_method_name] = doc_string
+ CONTEXT.current_method_name
+ ] = doc_string
write_output("CM4", f"{doc_prepend}%End\n")
- CONTEXT.comment = ''
- CONTEXT.return_type = ''
+ CONTEXT.comment = ""
+ CONTEXT.return_type = ""
if CONTEXT.is_override_or_make_private == PrependType.MakePrivate:
write_output("MKP", CONTEXT.last_access_section_line)
CONTEXT.is_override_or_make_private = PrependType.NoPrepend
@@ -2776,19 +3019,23 @@ def cpp_to_python_signature(cpp_function: str) -> str:
# Output results
if args.sip_output:
- with open(args.sip_output, 'w') as f:
- f.write(''.join(sip_header_footer()))
- f.write(''.join(CONTEXT.output))
- f.write(''.join(sip_header_footer()))
+ with open(args.sip_output, "w") as f:
+ f.write("".join(sip_header_footer()))
+ f.write("".join(CONTEXT.output))
+ f.write("".join(sip_header_footer()))
else:
- print(''.join(sip_header_footer()) +
- ''.join(CONTEXT.output) +
- ''.join(sip_header_footer()).rstrip())
+ print(
+ "".join(sip_header_footer())
+ + "".join(CONTEXT.output)
+ + "".join(sip_header_footer()).rstrip()
+ )
class_additions = defaultdict(list)
for class_name, attribute_docstrings in CONTEXT.attribute_docstrings.items():
- class_additions[class_name].append(f'{class_name}.__attribute_docs__ = {str(attribute_docstrings)}')
+ class_additions[class_name].append(
+ f"{class_name}.__attribute_docs__ = {str(attribute_docstrings)}"
+ )
for class_name, static_methods in CONTEXT.static_methods.items():
for method_name, is_static in static_methods.items():
@@ -2796,19 +3043,32 @@ def cpp_to_python_signature(cpp_function: str) -> str:
continue
# TODO -- fix
- if class_name == 'QgsProcessingUtils' and method_name == 'createFeatureSinkPython':
- method_name = 'createFeatureSink'
- elif class_name == 'QgsRasterAttributeTable' and method_name == 'usageInformationInt':
- method_name = 'usageInformation'
- elif class_name == 'QgsSymbolLayerUtils' and method_name == 'wellKnownMarkerFromSld':
- method_name = 'wellKnownMarkerFromSld2'
- elif class_name == 'QgsZonalStatistics' and method_name in ('calculateStatisticsInt', 'calculateStatistics'):
+ if (
+ class_name == "QgsProcessingUtils"
+ and method_name == "createFeatureSinkPython"
+ ):
+ method_name = "createFeatureSink"
+ elif (
+ class_name == "QgsRasterAttributeTable"
+ and method_name == "usageInformationInt"
+ ):
+ method_name = "usageInformation"
+ elif (
+ class_name == "QgsSymbolLayerUtils"
+ and method_name == "wellKnownMarkerFromSld"
+ ):
+ method_name = "wellKnownMarkerFromSld2"
+ elif class_name == "QgsZonalStatistics" and method_name in (
+ "calculateStatisticsInt",
+ "calculateStatistics",
+ ):
continue
- elif class_name == 'QgsServerApiUtils' and method_name == 'temporalExtentList':
- method_name = 'temporalExtent'
+ elif class_name == "QgsServerApiUtils" and method_name == "temporalExtentList":
+ method_name = "temporalExtent"
class_additions[class_name].append(
- f'{class_name}.{method_name} = staticmethod({class_name}.{method_name})')
+ f"{class_name}.{method_name} = staticmethod({class_name}.{method_name})"
+ )
for class_name, signal_arguments in CONTEXT.signal_arguments.items():
python_signatures = {}
@@ -2826,28 +3086,31 @@ def cpp_to_python_signature(cpp_function: str) -> str:
if python_signatures:
class_additions[class_name].append(
- f'{class_name}.__signal_arguments__ = {str(python_signatures)}')
+ f"{class_name}.__signal_arguments__ = {str(python_signatures)}"
+ )
for class_name, doc_string in CONTEXT.struct_docstrings.items():
class_additions[class_name].append(f'{class_name}.__doc__ = """{doc_string}"""')
-group_match = re.match('^.*src/[a-z0-9_]+/(.*?)/[^/]+$', CONTEXT.header_file)
+group_match = re.match("^.*src/[a-z0-9_]+/(.*?)/[^/]+$", CONTEXT.header_file)
if group_match:
- groups = list(group for group in group_match.group(1).split('/') if group and group != '.')
+ groups = list(
+ group for group in group_match.group(1).split("/") if group and group != "."
+ )
if groups:
for class_name in CONTEXT.all_fully_qualified_class_names:
- class_additions[class_name].append(
- f'{class_name}.__group__ = {groups}')
+ class_additions[class_name].append(f"{class_name}.__group__ = {groups}")
for _class, additions in class_additions.items():
if additions:
this_class_additions = "\n".join(" " + c for c in additions)
CONTEXT.output_python.append(
- f'try:\n{this_class_additions}\nexcept NameError:\n pass\n')
+ f"try:\n{this_class_additions}\nexcept NameError:\n pass\n"
+ )
if args.python_output and CONTEXT.output_python:
- with open(args.python_output, 'w') as f:
- f.write(''.join(python_header()))
- f.write(''.join(CONTEXT.output_python))
+ with open(args.python_output, "w") as f:
+ f.write("".join(python_header()))
+ f.write("".join(CONTEXT.output_python))
diff --git a/scripts/symbol_xml2db.py b/scripts/symbol_xml2db.py
index 1a5591350f22..d876a1ba80ed 100644
--- a/scripts/symbol_xml2db.py
+++ b/scripts/symbol_xml2db.py
@@ -28,34 +28,31 @@
xmlfile = "../resources/symbology-style.xml"
dbfile = "../resources/symbology-style.db"
-_symbol = "CREATE TABLE symbol("\
- "id INTEGER PRIMARY KEY,"\
- "name TEXT UNIQUE,"\
- "xml TEXT,"\
- "favorite INTEGER)"
-
-_colorramp = "CREATE TABLE colorramp("\
- "id INTEGER PRIMARY KEY,"\
- "name TEXT UNIQUE,"\
- "xml TEXT,"\
- "favorite INTEGER)"
-
-_tag = "CREATE TABLE tag("\
- "id INTEGER PRIMARY KEY,"\
- "name TEXT)"
-
-_tagmap = "CREATE TABLE tagmap("\
- "tag_id INTEGER NOT NULL,"\
- "symbol_id INTEGER)"
-
-_ctagmap = "CREATE TABLE ctagmap("\
- "tag_id INTEGER NOT NULL,"\
- "colorramp_id INTEGER)"
-
-_smartgroup = "CREATE TABLE smartgroup("\
- "id INTEGER PRIMARY KEY,"\
- "name TEXT,"\
- "xml TEXT)"
+_symbol = (
+ "CREATE TABLE symbol("
+ "id INTEGER PRIMARY KEY,"
+ "name TEXT UNIQUE,"
+ "xml TEXT,"
+ "favorite INTEGER)"
+)
+
+_colorramp = (
+ "CREATE TABLE colorramp("
+ "id INTEGER PRIMARY KEY,"
+ "name TEXT UNIQUE,"
+ "xml TEXT,"
+ "favorite INTEGER)"
+)
+
+_tag = "CREATE TABLE tag(" "id INTEGER PRIMARY KEY," "name TEXT)"
+
+_tagmap = "CREATE TABLE tagmap(" "tag_id INTEGER NOT NULL," "symbol_id INTEGER)"
+
+_ctagmap = "CREATE TABLE ctagmap(" "tag_id INTEGER NOT NULL," "colorramp_id INTEGER)"
+
+_smartgroup = (
+ "CREATE TABLE smartgroup(" "id INTEGER PRIMARY KEY," "name TEXT," "xml TEXT)"
+)
create_tables = [_symbol, _colorramp, _tag, _tagmap, _ctagmap, _smartgroup]
@@ -80,16 +77,19 @@
if not symbol_favorite:
symbol_favorite = 0
- if '@' in symbol_name:
- parts = symbol_name.split('@')
+ if "@" in symbol_name:
+ parts = symbol_name.split("@")
parent_name = parts[1]
layerno = int(parts[2])
c.execute("SELECT xml FROM symbol WHERE name=(?)", (parent_name,))
- symdom = parseString(c.fetchone()[0]).getElementsByTagName('symbol')[0]
+ symdom = parseString(c.fetchone()[0]).getElementsByTagName("symbol")[0]
symdom.getElementsByTagName("layer")[layerno].appendChild(symbol)
c.execute("UPDATE symbol SET xml=? WHERE name=?", (symdom.toxml(), parent_name))
else:
- c.execute("INSERT INTO symbol VALUES (?,?,?,?)", (None, symbol_name, symbol.toxml(), symbol_favorite))
+ c.execute(
+ "INSERT INTO symbol VALUES (?,?,?,?)",
+ (None, symbol_name, symbol.toxml(), symbol_favorite),
+ )
conn.commit()
@@ -101,7 +101,10 @@
if not symbol_favorite:
symbol_favorite = 0
- c.execute("INSERT INTO colorramp VALUES (?,?,?,?)", (None, ramp_name, ramp.toxml(), symbol_favorite))
+ c.execute(
+ "INSERT INTO colorramp VALUES (?,?,?,?)",
+ (None, ramp_name, ramp.toxml(), symbol_favorite),
+ )
conn.commit()
# Finally close the sqlite cursor
diff --git a/scripts/widgets_tree.py b/scripts/widgets_tree.py
index 380d358dbbff..10a2b4efe024 100644
--- a/scripts/widgets_tree.py
+++ b/scripts/widgets_tree.py
@@ -17,9 +17,9 @@
***************************************************************************
"""
-__author__ = 'Martin Dobias'
-__date__ = 'May 2011'
-__copyright__ = '(C) 2011, Martin Dobias'
+__author__ = "Martin Dobias"
+__date__ = "May 2011"
+__copyright__ = "(C) 2011, Martin Dobias"
"""
Reads .ui files from ../src/ui/ directory and write to stdout an XML describing
@@ -33,17 +33,44 @@
"""
-import sys
-import os
import glob
-from qgis.PyQt.QtWidgets import QWidget, QDialog, QCheckBox, QComboBox, QDial, QPushButton, QLabel, QLCDNumber, QLineEdit, QRadioButton, QScrollBar, QSlider, QSpinBox, QTextEdit, QDateEdit, QTimeEdit, QDateTimeEdit, QListView, QProgressBar, QTableView, QTabWidget, QTextBrowser, QDialogButtonBox, QScrollArea, QGroupBox, QStackedWidget
-from qgis.PyQt.uic import loadUi
-from qgis.PyQt.QtXml import QDomDocument
+import os
+import sys
# qwt_plot is missing somehow but it may depend on installed packages
from qgis.PyQt import Qwt5 as qwt_plot
+from qgis.PyQt.QtWidgets import (
+ QCheckBox,
+ QComboBox,
+ QDateEdit,
+ QDateTimeEdit,
+ QDial,
+ QDialog,
+ QDialogButtonBox,
+ QGroupBox,
+ QLabel,
+ QLCDNumber,
+ QLineEdit,
+ QListView,
+ QProgressBar,
+ QPushButton,
+ QRadioButton,
+ QScrollArea,
+ QScrollBar,
+ QSlider,
+ QSpinBox,
+ QStackedWidget,
+ QTableView,
+ QTabWidget,
+ QTextBrowser,
+ QTextEdit,
+ QTimeEdit,
+ QWidget,
+)
+from qgis.PyQt.QtXml import QDomDocument
+from qgis.PyQt.uic import loadUi
-sys.modules['qwt_plot'] = qwt_plot
+sys.modules["qwt_plot"] = qwt_plot
# loadUi is looking for custom widget in module which is lowercase version of
# the class, which do not exist (AFAIK) -> preload them, problems anyway:
@@ -51,21 +78,60 @@
# QgsRendererRulesTreeWidget
# and QgsProjectionSelector cannot open db file
from qgis import gui
-for m in ['qgscolorbutton', 'qgscolorrampcombobox', 'qgsprojectionselector', 'qgslabelpreview', 'qgsrulebasedrendererwidget', 'qgscollapsiblegroupbox', 'qgsblendmodecombobox', 'qgsexpressionbuilderwidget', 'qgsrasterformatsaveoptionswidget', 'qgsrasterpyramidsoptionswidget', 'qgsscalecombobox', 'qgsfilterlineedit', 'qgsdualview']:
+
+for m in [
+ "qgscolorbutton",
+ "qgscolorrampcombobox",
+ "qgsprojectionselector",
+ "qgslabelpreview",
+ "qgsrulebasedrendererwidget",
+ "qgscollapsiblegroupbox",
+ "qgsblendmodecombobox",
+ "qgsexpressionbuilderwidget",
+ "qgsrasterformatsaveoptionswidget",
+ "qgsrasterpyramidsoptionswidget",
+ "qgsscalecombobox",
+ "qgsfilterlineedit",
+ "qgsdualview",
+]:
sys.modules[m] = gui
class UiInspector:
def __init__(self):
- self.ui_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), '../src/ui/*.ui'))
+ self.ui_dir = os.path.abspath(
+ os.path.join(os.path.dirname(__file__), "../src/ui/*.ui")
+ )
self.printMsg("Loading UI files " + self.ui_dir)
# list of widget classes we want to follow
self.follow = [
- QWidget, QDialog,
- QCheckBox, QComboBox, QDial, QPushButton, QLabel, QLCDNumber, QLineEdit, QRadioButton, QScrollBar, QSlider, QSpinBox, QTextEdit,
- QDateEdit, QTimeEdit, QDateTimeEdit, QListView, QProgressBar, QTableView, QTabWidget, QTextBrowser, QDialogButtonBox,
- QScrollArea, QGroupBox, QStackedWidget,
+ QWidget,
+ QDialog,
+ QCheckBox,
+ QComboBox,
+ QDial,
+ QPushButton,
+ QLabel,
+ QLCDNumber,
+ QLineEdit,
+ QRadioButton,
+ QScrollBar,
+ QSlider,
+ QSpinBox,
+ QTextEdit,
+ QDateEdit,
+ QTimeEdit,
+ QDateTimeEdit,
+ QListView,
+ QProgressBar,
+ QTableView,
+ QTabWidget,
+ QTextBrowser,
+ QDialogButtonBox,
+ QScrollArea,
+ QGroupBox,
+ QStackedWidget,
]
def printMsg(self, msg):
@@ -81,29 +147,32 @@ def widgetXml(self, element, widget, level=0, label=None):
return
lab = label
- if hasattr(widget, 'text'):
+ if hasattr(widget, "text"):
lab = widget.text()
if widget.windowTitle():
label = widget.windowTitle()
if not lab:
- lab = ''
+ lab = ""
- subElement = self.doc.createElement('widget')
- subElement.setAttribute('class', widget.__class__.__name__)
- subElement.setAttribute('objectName', widget.objectName())
- subElement.setAttribute('label', lab)
+ subElement = self.doc.createElement("widget")
+ subElement.setAttribute("class", widget.__class__.__name__)
+ subElement.setAttribute("objectName", widget.objectName())
+ subElement.setAttribute("label", lab)
element.appendChild(subElement)
# print str ( widget.children () )
# tab widget label is stored in QTabWidget->QTabBarPrivate->tabList->QTab ..
if type(widget) in [QTabWidget]:
- children = list({'widget': widget.widget(i), 'label': widget.tabText(i)} for i in range(0, widget.count()))
+ children = list(
+ {"widget": widget.widget(i), "label": widget.tabText(i)}
+ for i in range(0, widget.count())
+ )
else:
- children = list({'widget': c, 'label': None} for c in widget.children())
+ children = list({"widget": c, "label": None} for c in widget.children())
for child in children:
- w = child['widget']
+ w = child["widget"]
if w.isWidgetType() and (type(w) in self.follow):
- self.widgetXml(subElement, w, level + 1, child['label'])
+ self.widgetXml(subElement, w, level + 1, child["label"])
def xml(self):
self.doc = QDomDocument()
@@ -122,7 +191,7 @@ def xml(self):
return self.doc.toString(2)
-if __name__ == '__main__':
+if __name__ == "__main__":
from qgis.PyQt.QtCore import QApplication
app = QApplication(sys.argv) # required by loadUi
diff --git a/src/plugins/grass/qgis_grass_test.py b/src/plugins/grass/qgis_grass_test.py
index 3e5b79d8f725..2c406f8225c1 100755
--- a/src/plugins/grass/qgis_grass_test.py
+++ b/src/plugins/grass/qgis_grass_test.py
@@ -1,5 +1,4 @@
#!/usr/bin/env python3
-# -*- coding: utf-8 -*-
# -----------------------------------------------------------
#
# Copyright (C) 2012 Radim Blazek
@@ -35,15 +34,15 @@
- writes out report
***************************************************************************
"""
-__author__ = 'Radim Blazek'
-__date__ = 'December 2012'
-__copyright__ = '(C) 2012, Radim Blazek'
+__author__ = "Radim Blazek"
+__date__ = "December 2012"
+__copyright__ = "(C) 2012, Radim Blazek"
import os
-import sys
+import re
import subprocess
+import sys
import time
-import re
class Test:
@@ -71,7 +70,7 @@ def writeReport(self):
def test(self):
print("GRASS Direct test")
- tmp_dir = os.path.abspath("qgis-grass-test-%s" % time.strftime('%y%m%d-%H%M%S'))
+ tmp_dir = os.path.abspath("qgis-grass-test-%s" % time.strftime("%y%m%d-%H%M%S"))
tmp_dir = os.path.abspath("qgis-grass-test-debug") # debug
print("Output will be written to %s" % tmp_dir)
@@ -82,14 +81,21 @@ def test(self):
print("Getting list of rasters ...")
rasters = self.srun(["g.mlist", "type=rast"]).splitlines()
max_rasters = 1
- print("%s rasters found, using first %s" % (len(rasters), max_rasters))
+ print(f"{len(rasters)} rasters found, using first {max_rasters}")
rasters = rasters[0:1]
print("Exporting rasters")
for raster in rasters:
print(raster)
- output = "%s/%s.tif" % (files_dir, raster)
- self.srun(["g.region", "rast=%s" % raster, "cols=%s" % self.size, "rows=%s" % self.size])
+ output = f"{files_dir}/{raster}.tif"
+ self.srun(
+ [
+ "g.region",
+ "rast=%s" % raster,
+ "cols=%s" % self.size,
+ "rows=%s" % self.size,
+ ]
+ )
self.srun(["r.out.gdal", "input=%s" % raster, "output=%s" % output])
# run modules
@@ -98,26 +104,49 @@ def test(self):
module = re.sub(" *", " ", module)
module_name = module.split(" ")[0]
# --- native ---
- self.srun(["g.region", "rast=%s" % raster, "cols=%s" % self.size, "rows=%s" % self.size])
+ self.srun(
+ [
+ "g.region",
+ "rast=%s" % raster,
+ "cols=%s" % self.size,
+ "rows=%s" % self.size,
+ ]
+ )
output = "qgistest1"
# clean old
self.srun(["g.remove", "-f", "rast=%s" % output])
# substitute rasters
- native_args = module.replace("R1", raster).replace("RO1", output).split(" ")
+ native_args = (
+ module.replace("R1", raster).replace("RO1", output).split(" ")
+ )
(code, out, err) = self.run(native_args)
if code != 0:
self.report("Native failed: %s" % " ".join(native_args))
# export
- native_output_file = "%s/%s-%s-native.tif" % (files_dir, module_name, raster)
- self.srun(["r.out.gdal", "input=%s" % output, "output=%s" % native_output_file])
+ native_output_file = "{}/{}-{}-native.tif".format(
+ files_dir, module_name, raster
+ )
+ self.srun(
+ [
+ "r.out.gdal",
+ "input=%s" % output,
+ "output=%s" % native_output_file,
+ ]
+ )
self.srun(["g.remove", "-f", "rast=%s" % output])
# --- direct ---
- direct_input_file = "%s/%s.tif" % (files_dir, raster)
- direct_output_file = "%s/%s-%s-direct.tif" % (files_dir, module_name, raster)
+ direct_input_file = f"{files_dir}/{raster}.tif"
+ direct_output_file = "{}/{}-{}-direct.tif".format(
+ files_dir, module_name, raster
+ )
# substitute rasters
- direct_args = module.replace("R1", direct_input_file).replace("RO1", direct_output_file).split(" ")
+ direct_args = (
+ module.replace("R1", direct_input_file)
+ .replace("RO1", direct_output_file)
+ .split(" ")
+ )
env = os.environ
# CRS
@@ -126,38 +155,57 @@ def test(self):
proj = proj.splitlines()
proj = " ".join(proj)
print(proj)
- env['QGIS_GRASS_CRS'] = proj
+ env["QGIS_GRASS_CRS"] = proj
# set GRASS region as environment variable
reg = self.srun(["g.region", "-g"])
reg_dict = dict(item.split("=") for item in reg.splitlines())
- reg_var = {'n': 'north', 's': 'south', 'e': 'east', 'w': 'west', 'nsres': 'n-s resol', 'ewres': 'e-w resol'}
+ reg_var = {
+ "n": "north",
+ "s": "south",
+ "e": "east",
+ "w": "west",
+ "nsres": "n-s resol",
+ "ewres": "e-w resol",
+ }
if longlat:
region = "proj:3;zone:-1" # longlat
else:
region = "proj:99;zone:-1" # other projection
for k, v in reg_dict.iteritems():
- if k == 'cells':
+ if k == "cells":
continue
kn = k
if k in reg_var:
kn = reg_var[k]
- region += ";%s:%s" % (kn, v)
+ region += f";{kn}:{v}"
print(region)
- env['GRASS_REGION'] = region
+ env["GRASS_REGION"] = region
# add path to fake GRASS gis library
- env['LD_LIBRARY_PATH'] = "%s/lib/qgis/plugins/:%s" % (env['QGIS_PREFIX_PATH'], env['LD_LIBRARY_PATH'])
+ env["LD_LIBRARY_PATH"] = "{}/lib/qgis/plugins/:{}".format(
+ env["QGIS_PREFIX_PATH"], env["LD_LIBRARY_PATH"]
+ )
(code, out, err) = self.run(direct_args, env)
print("code = %s" % code)
if code != 0:
- self.report("Direct failed: %s\n%s\n%s" % (" ".join(direct_args), out, err))
+ self.report(
+ "Direct failed: {}\n{}\n{}".format(
+ " ".join(direct_args), out, err
+ )
+ )
# TODO: compare native x direct output
def run(self, args, env=None, input=None, exit_on_error=False):
cmd = " ".join(args)
print(cmd)
- p = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE, env=env)
+ p = subprocess.Popen(
+ args,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ stdin=subprocess.PIPE,
+ env=env,
+ )
com = p.communicate(input)
p.wait()
@@ -174,13 +222,11 @@ def srun(self, args):
def modules(self):
# R1 - input raster 1
# RO1 - output raster 1
- modules = [
- "r.slope.aspect elevation=R1 aspect=RO1"
- ]
+ modules = ["r.slope.aspect elevation=R1 aspect=RO1"]
return modules
-if __name__ == '__main__':
+if __name__ == "__main__":
test = Test()
test.test()
test.writeReport()
diff --git a/src/plugins/grass/scripts/db.connect-login.pg.py b/src/plugins/grass/scripts/db.connect-login.pg.py
index 75bdf6e0a212..4375d45d00f3 100644
--- a/src/plugins/grass/scripts/db.connect-login.pg.py
+++ b/src/plugins/grass/scripts/db.connect-login.pg.py
@@ -1,5 +1,4 @@
#!/usr/bin/env python3
-# -*- coding: utf-8 -*-
"""
***************************************************************************
@@ -18,82 +17,85 @@
***************************************************************************
"""
-__author__ = 'Radim Blazek'
-__date__ = 'July 2009'
-__copyright__ = '(C) 2009, Radim Blazek'
-
-
-#%Module
-#% description: Make connection to PostgreSQL database and login.
-#% keywords: database
-#%End
-
-#%option
-#% key: host
-#% type: string
-#% label: Host
-#% description: Host name of the machine on which the server is running.
-#% required : no
-#%end
-
-#%option
-#% key: port
-#% type: integer
-#% label: Port
-#% description: TCP port on which the server is listening, usually 5432.
-#% required : no
-#%end
-
-#%option
-#% key: database
-#% type: string
-#% key_desc : name
-#% gisprompt: old_dbname,dbname,dbname
-#% label: Database
-#% description: Database name
-#% required : yes
-#%end
-
-#%option
-#% key: schema
-#% type: string
-#% label: Schema
-#% description: Database schema.
-#% required : no
-#%end
-
-#%option
-#% key: user
-#% type: string
-#% label: User
-#% description: Connect to the database as the user username instead of the default.
-#% required : no
-#%end
-
-#%option
-#% key: password
-#% type: string
-#% label: Password
-#% description: Password will be stored in file!
-#% required : no
-#%end
+__author__ = "Radim Blazek"
+__date__ = "July 2009"
+__copyright__ = "(C) 2009, Radim Blazek"
+
+
+# %Module
+# % description: Make connection to PostgreSQL database and login.
+# % keywords: database
+# %End
+
+# %option
+# % key: host
+# % type: string
+# % label: Host
+# % description: Host name of the machine on which the server is running.
+# % required : no
+# %end
+
+# %option
+# % key: port
+# % type: integer
+# % label: Port
+# % description: TCP port on which the server is listening, usually 5432.
+# % required : no
+# %end
+
+# %option
+# % key: database
+# % type: string
+# % key_desc : name
+# % gisprompt: old_dbname,dbname,dbname
+# % label: Database
+# % description: Database name
+# % required : yes
+# %end
+
+# %option
+# % key: schema
+# % type: string
+# % label: Schema
+# % description: Database schema.
+# % required : no
+# %end
+
+# %option
+# % key: user
+# % type: string
+# % label: User
+# % description: Connect to the database as the user username instead of the default.
+# % required : no
+# %end
+
+# %option
+# % key: password
+# % type: string
+# % label: Password
+# % description: Password will be stored in file!
+# % required : no
+# %end
import sys
+
try:
from grass.script import core as grass
except ImportError:
import grass
except:
- raise Exception("Cannot find 'grass' Python module. Python is supported by GRASS from version >= 6.4")
+ raise Exception(
+ "Cannot find 'grass' Python module. Python is supported by GRASS from version >= 6.4"
+ )
def main():
- host = options['host']
- port = options['port']
- database = options['database']
- schema = options['schema']
- user = options['user']
- password = options['password']
+ host = options["host"]
+ port = options["port"]
+ database = options["database"]
+ schema = options["schema"]
+ user = options["user"]
+ password = options["password"]
# Test connection
conn = "dbname=" + database
@@ -106,22 +108,47 @@ def main():
if user or password:
print("Setting login (db.login) ... ")
sys.stdout.flush()
- if grass.run_command('db.login', driver="pg", database=conn, user=user, password=password) != 0:
+ if (
+ grass.run_command(
+ "db.login", driver="pg", database=conn, user=user, password=password
+ )
+ != 0
+ ):
grass.fatal("Cannot login")
# Try to connect
print("Testing connection ...")
sys.stdout.flush()
- if grass.run_command('db.select', quiet=True, flags='c', driver="pg", database=conn, sql="select version()") != 0:
+ if (
+ grass.run_command(
+ "db.select",
+ quiet=True,
+ flags="c",
+ driver="pg",
+ database=conn,
+ sql="select version()",
+ )
+ != 0
+ ):
if user or password:
print("Deleting login (db.login) ...")
sys.stdout.flush()
- if grass.run_command('db.login', quiet=True, driver="pg", database=conn, user="", password="") != 0:
+ if (
+ grass.run_command(
+ "db.login",
+ quiet=True,
+ driver="pg",
+ database=conn,
+ user="",
+ password="",
+ )
+ != 0
+ ):
print("Cannot delete login.")
sys.stdout.flush()
grass.fatal("Cannot connect to database.")
- if grass.run_command('db.connect', driver="pg", database=conn, schema=schema) != 0:
+ if grass.run_command("db.connect", driver="pg", database=conn, schema=schema) != 0:
grass.fatal("Cannot connect to database.")
diff --git a/src/plugins/grass/scripts/qgis.v.kernel.rast.py b/src/plugins/grass/scripts/qgis.v.kernel.rast.py
index 579e9cdc0759..60c84a219d24 100644
--- a/src/plugins/grass/scripts/qgis.v.kernel.rast.py
+++ b/src/plugins/grass/scripts/qgis.v.kernel.rast.py
@@ -1,5 +1,4 @@
#!/usr/bin/env python3
-# -*- coding: utf-8 -*-
"""
***************************************************************************
@@ -18,9 +17,9 @@
***************************************************************************
"""
-__author__ = 'Radim Blazek'
-__date__ = 'February 2010'
-__copyright__ = '(C) 2010, Radim Blazek'
+__author__ = "Radim Blazek"
+__date__ = "February 2010"
+__copyright__ = "(C) 2010, Radim Blazek"
############################################################################
@@ -30,50 +29,57 @@
#
#############################################################################
-#%Module
-#% description: Generates a raster density map from vector points data using a moving 2D isotropic Gaussian kernel.
-#% keywords: vector, export, database
-#%End
+# %Module
+# % description: Generates a raster density map from vector points data using a moving 2D isotropic Gaussian kernel.
+# % keywords: vector, export, database
+# %End
-#%option
-#% key: input
-#% type: string
-#% gisprompt: old,vector,vector
-#% key_desc : name
-#% description: Input vector with training points
-#% required : yes
-#%end
+# %option
+# % key: input
+# % type: string
+# % gisprompt: old,vector,vector
+# % key_desc : name
+# % description: Input vector with training points
+# % required : yes
+# %end
-#%option
-#% key: stddeviation
-#% type: double
-#% description: Standard deviation in map units
-#% required : yes
-#%end
+# %option
+# % key: stddeviation
+# % type: double
+# % description: Standard deviation in map units
+# % required : yes
+# %end
-#%option
-#% key: output
-#% type: string
-#% gisprompt: new,cell,raster
-#% key_desc : name
-#% description: Output raster map
-#% required : yes
-#%end
+# %option
+# % key: output
+# % type: string
+# % gisprompt: new,cell,raster
+# % key_desc : name
+# % description: Output raster map
+# % required : yes
+# %end
try:
from grass.script import core as grass
except ImportError:
import grass
except:
- raise Exception("Cannot find 'grass' Python module. Python is supported by GRASS from version >= 6.4")
+ raise Exception(
+ "Cannot find 'grass' Python module. Python is supported by GRASS from version >= 6.4"
+ )
def main():
- input = options['input']
- output = options['output']
- stddeviation = options['stddeviation']
+ input = options["input"]
+ output = options["output"]
+ stddeviation = options["stddeviation"]
- if grass.run_command('v.kernel', input=input, stddeviation=stddeviation, output=output) != 0:
+ if (
+ grass.run_command(
+ "v.kernel", input=input, stddeviation=stddeviation, output=output
+ )
+ != 0
+ ):
grass.fatal("Cannot run v.kernel.")
diff --git a/src/plugins/grass/scripts/qgis.v.upgrade.py b/src/plugins/grass/scripts/qgis.v.upgrade.py
index 2b8aa23b1f0a..78d154d6bcbf 100644
--- a/src/plugins/grass/scripts/qgis.v.upgrade.py
+++ b/src/plugins/grass/scripts/qgis.v.upgrade.py
@@ -1,5 +1,4 @@
#!/usr/bin/env python3
-# -*- coding: utf-8 -*-
"""
***************************************************************************
@@ -18,9 +17,9 @@
***************************************************************************
"""
-__author__ = 'Radim Blazek'
-__date__ = 'October 2015'
-__copyright__ = '(C) 2015 by Radim Blazek'
+__author__ = "Radim Blazek"
+__date__ = "October 2015"
+__copyright__ = "(C) 2015 by Radim Blazek"
############################################################################
@@ -38,33 +37,35 @@
#
#############################################################################
-#%Module
-#% description: Upgrade all vectors from GRASS 6 to GRASS 7
-#% keywords: vector, upgrade
-#%End
+# %Module
+# % description: Upgrade all vectors from GRASS 6 to GRASS 7
+# % keywords: vector, upgrade
+# %End
try:
from grass.script import core as grass
except ImportError:
import grass
except:
- raise Exception("Cannot find 'grass' Python module. Python is supported by GRASS from version >= 6.4")
+ raise Exception(
+ "Cannot find 'grass' Python module. Python is supported by GRASS from version >= 6.4"
+ )
def main():
# see https://grasswiki.osgeo.org/wiki/Convert_all_GRASS_6_vector_maps_to_GRASS_7
- grass.message('Building topology')
- if grass.run_command('v.build.all') != 0:
- grass.warning('Cannot build topology')
+ grass.message("Building topology")
+ if grass.run_command("v.build.all") != 0:
+ grass.warning("Cannot build topology")
- grass.message('Creating new DB connection')
- if grass.run_command('db.connect', flags='d') != 0:
- grass.warning('Cannot create new DB connection')
+ grass.message("Creating new DB connection")
+ if grass.run_command("db.connect", flags="d") != 0:
+ grass.warning("Cannot create new DB connection")
return
- grass.message('Transferring tables to the new DB')
- if grass.run_command('v.db.reconnect.all', flags='cd') != 0:
- grass.warning('Cannot transfer tables')
+ grass.message("Transferring tables to the new DB")
+ if grass.run_command("v.db.reconnect.all", flags="cd") != 0:
+ grass.warning("Cannot transfer tables")
if __name__ == "__main__":
diff --git a/src/plugins/grass/scripts/r.external.all.py b/src/plugins/grass/scripts/r.external.all.py
index 7b5487824ccf..b06f0103c2c7 100644
--- a/src/plugins/grass/scripts/r.external.all.py
+++ b/src/plugins/grass/scripts/r.external.all.py
@@ -1,5 +1,4 @@
#!/usr/bin/env python3
-# -*- coding: utf-8 -*-
"""
***************************************************************************
@@ -18,9 +17,9 @@
***************************************************************************
"""
-__author__ = 'Lorenzo Masini'
-__date__ = 'July 2009'
-__copyright__ = '(C) 2009, Lorenzo Masini'
+__author__ = "Lorenzo Masini"
+__date__ = "July 2009"
+__copyright__ = "(C) 2009, Lorenzo Masini"
############################################################################
@@ -38,56 +37,69 @@
#
#############################################################################
-#%Module
-#% description: Link all GDAL supported raster files into a directory to binary raster map layers.
-#% keywords: raster, import
-#%End
-
-#%option
-#% key: input
-#% type: string
-#% gisprompt: input
-#% key_desc : name
-#% description: Directory containing raster files
-#% required : yes
-#%end
-
-#%option
-#% key: band
-#% type: integer
-#% description: Band to select
-#% answer: 1
-#% required : no
-#%end
-
-#%flag
-#% key: o
-#% description: Override projection (use location's projection)
-#%end
-
-#%flag
-#% key: e
-#% description: Extend location extents based on new dataset
-#%end
-
-#%flag
-#% key: r
-#% description: Recursively scan subdirectories
+# %Module
+# % description: Link all GDAL supported raster files into a directory to binary raster map layers.
+# % keywords: raster, import
+# %End
+
+# %option
+# % key: input
+# % type: string
+# % gisprompt: input
+# % key_desc : name
+# % description: Directory containing raster files
+# % required : yes
+# %end
+
+# %option
+# % key: band
+# % type: integer
+# % description: Band to select
+# % answer: 1
+# % required : no
+# %end
+
+# %flag
+# % key: o
+# % description: Override projection (use location's projection)
+# %end
+
+# %flag
+# % key: e
+# % description: Extend location extents based on new dataset
+# %end
+
+# %flag
+# % key: r
+# % description: Recursively scan subdirectories
import os
+
try:
from grass.script import core as grass
except ImportError:
import grass
except:
- raise Exception("Cannot find 'grass' Python module. Python is supported by GRASS from version >= 6.4")
+ raise Exception(
+ "Cannot find 'grass' Python module. Python is supported by GRASS from version >= 6.4"
+ )
def import_directory_of_rasters(directory, recursive):
for dir, dirnames, filenames in os.walk(directory):
for filename in filenames:
- if grass.run_command('r.external', flags=flags_string, input=os.path.join(dir, filename), band=options['band'], output=filename[:-4], title=filename[:-4]) != 0:
- grass.warning('Cannot import file' + filename)
+ if (
+ grass.run_command(
+ "r.external",
+ flags=flags_string,
+ input=os.path.join(dir, filename),
+ band=options["band"],
+ output=filename[:-4],
+ title=filename[:-4],
+ )
+ != 0
+ ):
+ grass.warning("Cannot import file" + filename)
if not recursive:
break
for dirname in dirnames:
@@ -95,13 +107,13 @@ def import_directory_of_rasters(directory, recursive):
def main():
- input = options['input']
- recursive = flags['r']
+ input = options["input"]
+ recursive = flags["r"]
import_directory_of_rasters(input, recursive)
if __name__ == "__main__":
options, flags = grass.parser()
- flags_string = "".join([k for k in flags.keys() if flags[k] and k != 'r'])
+ flags_string = "".join([k for k in flags.keys() if flags[k] and k != "r"])
main()
diff --git a/src/plugins/grass/scripts/t.rast.what.qgis.py b/src/plugins/grass/scripts/t.rast.what.qgis.py
index 1b0beba20cc6..91e054c42537 100644
--- a/src/plugins/grass/scripts/t.rast.what.qgis.py
+++ b/src/plugins/grass/scripts/t.rast.what.qgis.py
@@ -1,5 +1,4 @@
#!/usr/bin/env python3
-# -*- coding: utf-8 -*-
############################################################################
#
# MODULE: t.rast.what
@@ -17,81 +16,81 @@
#
#############################################################################
-#%module
-#% description: Sample a space time raster dataset at specific vector point coordinates and write the output to stdout using different layouts
-#% keyword: temporal
-#% keyword: sampling
-#% keyword: raster
-#% keyword: time
-#%end
-
-#%option G_OPT_V_INPUT
-#% key: points
-#% required: no
-#%end
-
-#%option G_OPT_M_COORDS
-#% required: no
-#% description: Comma separated list of coordinates
-#%end
-
-#%option G_OPT_STRDS_INPUT
-#% key: strds
-#%end
-
-#%option G_OPT_F_OUTPUT
-#% required: no
-#% description: Name for the output file or "-" in case stdout should be used
-#% answer: -
-#%end
-
-#%option G_OPT_T_WHERE
-#%end
-
-#%option G_OPT_M_NULL_VALUE
-#%end
-
-#%option G_OPT_F_SEP
-#%end
-
-#%option
-#% key: order
-#% type: string
-#% description: Sort the maps by category
-#% required: no
-#% multiple: yes
-#% options: id, name, creator, mapset, creation_time, modification_time, start_time, end_time, north, south, west, east, min, max
-#% answer: start_time
-#%end
-
-#%option
-#% key: layout
-#% type: string
-#% description: The layout of the output. One point per row (row), one point per column (col), all timsteps in one row (timerow)
-#% required: no
-#% multiple: no
-#% options: row, col, timerow
-#% answer: row
-#%end
-
-#%option
-#% key: nprocs
-#% type: integer
-#% description: Number of r.what processes to run in parallel
-#% required: no
-#% multiple: no
-#% answer: 1
-#%end
-
-#%flag
-#% key: n
-#% description: Output header row
-#%end
-
-#%flag
-#% key: i
-#% description: Use stdin as input and ignore coordinates and point option
-#%end
+# %module
+# % description: Sample a space time raster dataset at specific vector point coordinates and write the output to stdout using different layouts
+# % keyword: temporal
+# % keyword: sampling
+# % keyword: raster
+# % keyword: time
+# %end
+
+# %option G_OPT_V_INPUT
+# % key: points
+# % required: no
+# %end
+
+# %option G_OPT_M_COORDS
+# % required: no
+# % description: Comma separated list of coordinates
+# %end
+
+# %option G_OPT_STRDS_INPUT
+# % key: strds
+# %end
+
+# %option G_OPT_F_OUTPUT
+# % required: no
+# % description: Name for the output file or "-" in case stdout should be used
+# % answer: -
+# %end
+
+# %option G_OPT_T_WHERE
+# %end
+
+# %option G_OPT_M_NULL_VALUE
+# %end
+
+# %option G_OPT_F_SEP
+# %end
+
+# %option
+# % key: order
+# % type: string
+# % description: Sort the maps by category
+# % required: no
+# % multiple: yes
+# % options: id, name, creator, mapset, creation_time, modification_time, start_time, end_time, north, south, west, east, min, max
+# % answer: start_time
+# %end
+
+# %option
+# % key: layout
+# % type: string
+# % description: The layout of the output. One point per row (row), one point per column (col), all timsteps in one row (timerow)
+# % required: no
+# % multiple: no
+# % options: row, col, timerow
+# % answer: row
+# %end
+
+# %option
+# % key: nprocs
+# % type: integer
+# % description: Number of r.what processes to run in parallel
+# % required: no
+# % multiple: no
+# % answer: 1
+# %end
+
+# %flag
+# % key: n
+# % description: Output header row
+# %end
+
+# %flag
+# % key: i
+# % description: Use stdin as input and ignore coordinates and point option
+# %end
## Temporary disabled the r.what flags due to test issues
##%flag
@@ -109,15 +108,16 @@
##% description: Output integer category values, not cell values
##%end
-import sys
import copy
+import sys
+
+import grass.pygrass.modules as pymod
import grass.script as gscript
import grass.temporal as tgis
-import grass.pygrass.modules as pymod
-
############################################################################
+
def main(options, flags):
# Get the options
@@ -145,12 +145,16 @@ def main(options, flags):
gscript.fatal(_("Options coordinates and points are mutually exclusive"))
if not coordinates and not points and not use_stdin:
- gscript.fatal(_("Please specify the coordinates, the points option or use the 's' option to pipe coordinate positions to t.rast.what from stdin, to provide the sampling coordinates"))
+ gscript.fatal(
+ _(
+ "Please specify the coordinates, the points option or use the 's' option to pipe coordinate positions to t.rast.what from stdin, to provide the sampling coordinates"
+ )
+ )
if use_stdin:
coordinates_stdin = str(sys.__stdin__.read())
# Check if coordinates are given with site names or IDs
- stdin_length = len(coordinates_stdin.split('\n')[0].split())
+ stdin_length = len(coordinates_stdin.split("\n")[0].split())
if stdin_length <= 2:
site_input = False
elif stdin_length >= 3:
@@ -165,8 +169,7 @@ def main(options, flags):
dbif.connect()
sp = tgis.open_old_stds(strds, "strds", dbif)
- maps = sp.get_registered_maps_as_objects(where=where, order=order,
- dbif=dbif)
+ maps = sp.get_registered_maps_as_objects(where=where, order=order, dbif=dbif)
dbif.close()
if not maps:
@@ -195,27 +198,43 @@ def main(options, flags):
# Configure the r.what module
if points:
- r_what = pymod.Module("r.what", map="dummy",
- output="dummy", run_=False,
- separator=separator, points=points,
- overwrite=overwrite, flags=flags,
- quiet=True)
+ r_what = pymod.Module(
+ "r.what",
+ map="dummy",
+ output="dummy",
+ run_=False,
+ separator=separator,
+ points=points,
+ overwrite=overwrite,
+ flags=flags,
+ quiet=True,
+ )
elif coordinates:
# Create a list of values
coord_list = coordinates.split(",")
- r_what = pymod.Module("r.what", map="dummy",
- output="dummy", run_=False,
- separator=separator,
- coordinates=coord_list,
- overwrite=overwrite, flags=flags,
- quiet=True)
+ r_what = pymod.Module(
+ "r.what",
+ map="dummy",
+ output="dummy",
+ run_=False,
+ separator=separator,
+ coordinates=coord_list,
+ overwrite=overwrite,
+ flags=flags,
+ quiet=True,
+ )
elif use_stdin:
- r_what = pymod.Module("r.what", map="dummy",
- output="dummy", run_=False,
- separator=separator,
- stdin_=coordinates_stdin,
- overwrite=overwrite, flags=flags,
- quiet=True)
+ r_what = pymod.Module(
+ "r.what",
+ map="dummy",
+ output="dummy",
+ run_=False,
+ separator=separator,
+ stdin_=coordinates_stdin,
+ overwrite=overwrite,
+ flags=flags,
+ quiet=True,
+ )
else:
grass.error(_("Please specify points or coordinates"))
@@ -252,13 +271,24 @@ def main(options, flags):
count = 0
for loop in range(num_loops):
file_name = gscript.tempfile() + "_%i" % (loop)
- count = process_loop(nprocs, maps, file_name, count, maps_per_process,
- remaining_maps_per_loop, output_files,
- output_time_list, r_what, process_queue)
+ count = process_loop(
+ nprocs,
+ maps,
+ file_name,
+ count,
+ maps_per_process,
+ remaining_maps_per_loop,
+ output_files,
+ output_time_list,
+ r_what,
+ process_queue,
+ )
process_queue.wait()
- gscript.verbose("Number of raster map layers remaining for sampling %i" % (remaining_maps))
+ gscript.verbose(
+ "Number of raster map layers remaining for sampling %i" % (remaining_maps)
+ )
if remaining_maps > 0:
# Use a single process if less then 100 maps
if remaining_maps <= 100:
@@ -270,48 +300,65 @@ def main(options, flags):
remaining_maps_per_loop = remaining_maps % nprocs
file_name = "out_remain"
- process_loop(nprocs, maps, file_name, count, maps_per_process,
- remaining_maps_per_loop, output_files,
- output_time_list, r_what, process_queue)
+ process_loop(
+ nprocs,
+ maps,
+ file_name,
+ count,
+ maps_per_process,
+ remaining_maps_per_loop,
+ output_files,
+ output_time_list,
+ r_what,
+ process_queue,
+ )
# Wait for unfinished processes
process_queue.wait()
# Out the output files in the correct order together
if layout == "row":
- one_point_per_row_output(separator, output_files, output_time_list,
- output, write_header, site_input)
+ one_point_per_row_output(
+ separator, output_files, output_time_list, output, write_header, site_input
+ )
elif layout == "col":
- one_point_per_col_output(separator, output_files, output_time_list,
- output, write_header, site_input)
+ one_point_per_col_output(
+ separator, output_files, output_time_list, output, write_header, site_input
+ )
else:
- one_point_per_timerow_output(separator, output_files, output_time_list,
- output, write_header, site_input)
+ one_point_per_timerow_output(
+ separator, output_files, output_time_list, output, write_header, site_input
+ )
+
############################################################################
-def one_point_per_row_output(separator, output_files, output_time_list,
- output, write_header, site_input):
+def one_point_per_row_output(
+ separator, output_files, output_time_list, output, write_header, site_input
+):
"""Write one point per row
- output is of type: x,y,start,end,value
+ output is of type: x,y,start,end,value
"""
# open the output file for writing
- out_file = open(output, 'w') if output != "-" else sys.stdout
+ out_file = open(output, "w") if output != "-" else sys.stdout
if write_header is True:
if site_input:
- out_file.write("x%(sep)sy%(sep)ssite%(sep)sstart%(sep)send%(sep)svalue\n"
- % ({"sep": separator}))
+ out_file.write(
+ "x%(sep)sy%(sep)ssite%(sep)sstart%(sep)send%(sep)svalue\n"
+ % ({"sep": separator})
+ )
else:
- out_file.write("x%(sep)sy%(sep)sstart%(sep)send%(sep)svalue\n"
- % ({"sep": separator}))
+ out_file.write(
+ "x%(sep)sy%(sep)sstart%(sep)send%(sep)svalue\n" % ({"sep": separator})
+ )
for count in range(len(output_files)):
file_name = output_files[count]
gscript.verbose(_("Transforming r.what output file %s" % (file_name)))
map_list = output_time_list[count]
- in_file = open(file_name, "r")
+ in_file = open(file_name)
for line in in_file:
line = line.split(separator)
x = line[0]
@@ -324,14 +371,29 @@ def one_point_per_row_output(separator, output_files, output_time_list,
for i in range(len(values)):
start, end = map_list[i].get_temporal_extent_as_tuple()
if site_input:
- coor_string = "%(x)10.10f%(sep)s%(y)10.10f%(sep)s%(site_name)s%(sep)s"\
- % ({"x": float(x), "y": float(y), "site_name": str(site), "sep": separator})
+ coor_string = (
+ "%(x)10.10f%(sep)s%(y)10.10f%(sep)s%(site_name)s%(sep)s"
+ % (
+ {
+ "x": float(x),
+ "y": float(y),
+ "site_name": str(site),
+ "sep": separator,
+ }
+ )
+ )
else:
- coor_string = "%(x)10.10f%(sep)s%(y)10.10f%(sep)s"\
- % ({"x": float(x), "y": float(y), "sep": separator})
- time_string = "%(start)s%(sep)s%(end)s%(sep)s%(val)s\n"\
- % ({"start": str(start), "end": str(end),
- "val": (values[i].strip()), "sep": separator})
+ coor_string = "%(x)10.10f%(sep)s%(y)10.10f%(sep)s" % (
+ {"x": float(x), "y": float(y), "sep": separator}
+ )
+ time_string = "%(start)s%(sep)s%(end)s%(sep)s%(val)s\n" % (
+ {
+ "start": str(start),
+ "end": str(end),
+ "val": (values[i].strip()),
+ "sep": separator,
+ }
+ )
out_file.write(coor_string + time_string)
@@ -340,26 +402,28 @@ def one_point_per_row_output(separator, output_files, output_time_list,
if out_file is not sys.stdout:
out_file.close()
+
############################################################################
-def one_point_per_col_output(separator, output_files, output_time_list,
- output, write_header, site_input):
+def one_point_per_col_output(
+ separator, output_files, output_time_list, output, write_header, site_input
+):
"""Write one point per col
- output is of type:
- start,end,point_1 value,point_2 value,...,point_n value
+ output is of type:
+ start,end,point_1 value,point_2 value,...,point_n value
- Each row represents a single raster map, hence a single time stamp
+ Each row represents a single raster map, hence a single time stamp
"""
# open the output file for writing
- out_file = open(output, 'w') if output != "-" else sys.stdout
+ out_file = open(output, "w") if output != "-" else sys.stdout
first = True
for count in range(len(output_files)):
file_name = output_files[count]
gscript.verbose(_("Transforming r.what output file %s" % (file_name)))
map_list = output_time_list[count]
- in_file = open(file_name, "r")
+ in_file = open(file_name)
lines = in_file.readlines()
matrix = []
@@ -376,19 +440,25 @@ def one_point_per_col_output(separator, output_files, output_time_list,
x = row[0]
y = row[1]
site = row[2]
- out_file.write("%(sep)s%(x)10.10f;%(y)10.10f;%(site_name)s"
- % ({"sep": separator,
- "x": float(x),
- "y": float(y),
- "site_name": str(site)}))
+ out_file.write(
+ "%(sep)s%(x)10.10f;%(y)10.10f;%(site_name)s"
+ % (
+ {
+ "sep": separator,
+ "x": float(x),
+ "y": float(y),
+ "site_name": str(site),
+ }
+ )
+ )
else:
for row in matrix:
x = row[0]
y = row[1]
- out_file.write("%(sep)s%(x)10.10f;%(y)10.10f"
- % ({"sep": separator,
- "x": float(x),
- "y": float(y)}))
+ out_file.write(
+ "%(sep)s%(x)10.10f;%(y)10.10f"
+ % ({"sep": separator, "x": float(x), "y": float(y)})
+ )
out_file.write("\n")
@@ -396,35 +466,37 @@ def one_point_per_col_output(separator, output_files, output_time_list,
for col in xrange(num_cols - 3):
start, end = output_time_list[count][col].get_temporal_extent_as_tuple()
- time_string = "%(start)s%(sep)s%(end)s"\
- % ({"start": str(start), "end": str(end),
- "sep": separator})
+ time_string = "%(start)s%(sep)s%(end)s" % (
+ {"start": str(start), "end": str(end), "sep": separator}
+ )
out_file.write(time_string)
for row in xrange(len(matrix)):
value = matrix[row][col + 3]
- out_file.write("%(sep)s%(value)s"
- % ({"sep": separator,
- "value": value.strip()}))
+ out_file.write(
+ "%(sep)s%(value)s" % ({"sep": separator, "value": value.strip()})
+ )
out_file.write("\n")
in_file.close()
if out_file is not sys.stdout:
out_file.close()
+
############################################################################
-def one_point_per_timerow_output(separator, output_files, output_time_list,
- output, write_header, site_input):
+def one_point_per_timerow_output(
+ separator, output_files, output_time_list, output, write_header, site_input
+):
"""Use the original layout of the r.what output and print instead of
- the raster names, the time stamps as header
+ the raster names, the time stamps as header
- One point per line for all time stamps:
- x|y|1991-01-01 00:00:00;1991-01-02 00:00:00|1991-01-02 00:00:00;1991-01-03 00:00:00|1991-01-03 00:00:00;1991-01-04 00:00:00|1991-01-04 00:00:00;1991-01-05 00:00:00
- 3730731.49590371|5642483.51236521|6|8|7|7
- 3581249.04638104|5634411.97526282|5|8|7|7
+ One point per line for all time stamps:
+ x|y|1991-01-01 00:00:00;1991-01-02 00:00:00|1991-01-02 00:00:00;1991-01-03 00:00:00|1991-01-03 00:00:00;1991-01-04 00:00:00|1991-01-04 00:00:00;1991-01-05 00:00:00
+ 3730731.49590371|5642483.51236521|6|8|7|7
+ 3581249.04638104|5634411.97526282|5|8|7|7
"""
- out_file = open(output, 'w') if output != "-" else sys.stdout
+ out_file = open(output, "w") if output != "-" else sys.stdout
matrix = []
header = ""
@@ -434,7 +506,7 @@ def one_point_per_timerow_output(separator, output_files, output_time_list,
file_name = output_files[count]
gscript.verbose("Transforming r.what output file %s" % (file_name))
map_list = output_time_list[count]
- in_file = open(file_name, "r")
+ in_file = open(file_name)
if write_header:
if first is True:
@@ -444,9 +516,9 @@ def one_point_per_timerow_output(separator, output_files, output_time_list,
header = "x%(sep)sy" % ({"sep": separator})
for map in map_list:
start, end = map.get_temporal_extent_as_tuple()
- time_string = "%(sep)s%(start)s;%(end)s"\
- % ({"start": str(start), "end": str(end),
- "sep": separator})
+ time_string = "%(sep)s%(start)s;%(end)s" % (
+ {"start": str(start), "end": str(end), "sep": separator}
+ )
header += time_string
lines = in_file.readlines()
@@ -484,12 +556,22 @@ def one_point_per_timerow_output(separator, output_files, output_time_list,
if out_file is not sys.stdout:
out_file.close()
+
############################################################################
-def process_loop(nprocs, maps, file_name, count, maps_per_process,
- remaining_maps_per_loop, output_files,
- output_time_list, r_what, process_queue):
+def process_loop(
+ nprocs,
+ maps,
+ file_name,
+ count,
+ maps_per_process,
+ remaining_maps_per_loop,
+ output_files,
+ output_time_list,
+ r_what,
+ process_queue,
+):
"""Call r.what in parallel subprocesses"""
first = True
for process in range(nprocs):
@@ -513,9 +595,16 @@ def process_loop(nprocs, maps, file_name, count, maps_per_process,
output_time_list.append(map_list)
- gscript.verbose(("Process maps %(samp_start)i to %(samp_end)i (of %(total)i)" %
- ({"samp_start": count - len(map_names) + 1,
- "samp_end": count, "total": len(maps)})))
+ gscript.verbose(
+ "Process maps %(samp_start)i to %(samp_end)i (of %(total)i)"
+ % (
+ {
+ "samp_start": count - len(map_names) + 1,
+ "samp_end": count,
+ "total": len(maps),
+ }
+ )
+ )
mod = copy.deepcopy(r_what)
mod(map=map_names, output=final_file_name)
# print(mod.get_bash())
diff --git a/src/plugins/grass/scripts/v.class.mlpy.qgis.py b/src/plugins/grass/scripts/v.class.mlpy.qgis.py
index dff9493e8e85..f762d5a57155 100644
--- a/src/plugins/grass/scripts/v.class.mlpy.qgis.py
+++ b/src/plugins/grass/scripts/v.class.mlpy.qgis.py
@@ -1,5 +1,4 @@
#!/usr/bin/env python3
-# -*- coding: utf-8 -*-
############################################################################
#
# MODULE: v.class.mlpy
@@ -19,41 +18,41 @@
#
############################################################################
-#%module
-#% description: Vector supervised classification tool which uses attributes as classification parameters (order of columns matters, names not), cat column identifies feature, class_column is excluded from classification parameters.
-#% keyword: vector
-#% keyword: classification
-#% keyword: supervised
-#%end
-#%option G_OPT_V_MAP
-#% key: input
-#% description: Input vector map (attribute table required)
-#% required: yes
-#% multiple: no
-#%end
-#%option G_OPT_V_MAP
-#% key: training
-#% description: Training vector map (attribute table required)
-#% required: yes
-#% multiple: no
-#%end
-#%option G_OPT_V_FIELD
-#% key: class_column
-#% type: string
-#% label: Name of column containing class
-#% description: Used for both input/output and training dataset. If column does not exists in input map attribute table, it will be created.
-#% required: no
-#% multiple: no
-#% answer: class
-#%end
-#%option
-#% key: columns
-#% type: string
-#% label: Columns to be used in classification
-#% description: Columns to be used in classification. If left empty, all columns will be used for classification except for class_column and cat column.
-#% required: no
-#% multiple: yes
-#%end
+# %module
+# % description: Vector supervised classification tool which uses attributes as classification parameters (order of columns matters, names not), cat column identifies feature, class_column is excluded from classification parameters.
+# % keyword: vector
+# % keyword: classification
+# % keyword: supervised
+# %end
+# %option G_OPT_V_MAP
+# % key: input
+# % description: Input vector map (attribute table required)
+# % required: yes
+# % multiple: no
+# %end
+# %option G_OPT_V_MAP
+# % key: training
+# % description: Training vector map (attribute table required)
+# % required: yes
+# % multiple: no
+# %end
+# %option G_OPT_V_FIELD
+# % key: class_column
+# % type: string
+# % label: Name of column containing class
+# % description: Used for both input/output and training dataset. If column does not exists in input map attribute table, it will be created.
+# % required: no
+# % multiple: no
+# % answer: class
+# %end
+# %option
+# % key: columns
+# % type: string
+# % label: Columns to be used in classification
+# % description: Columns to be used in classification. If left empty, all columns will be used for classification except for class_column and cat column.
+# % required: no
+# % multiple: yes
+# %end
# TODO: add other classifiers
@@ -64,15 +63,13 @@
import grass.script as grass
-
import numpy as np
def addColumn(mapName, columnName, columnType):
"""Adds column to the map's table."""
- columnDefinition = columnName + ' ' + columnType
- grass.run_command('v.db.addcolumn', map=mapName,
- columns=columnDefinition)
+ columnDefinition = columnName + " " + columnType
+ grass.run_command("v.db.addcolumn", map=mapName, columns=columnDefinition)
def hasColumn(tableDescription, column):
@@ -80,20 +77,20 @@ def hasColumn(tableDescription, column):
\todo This should be part of some object in the lib.
"""
- for col in tableDescription['cols']:
+ for col in tableDescription["cols"]:
if col[0] == column:
return True
return False
def updateColumn(mapName, column, cats, values=None):
- """!Updates column values for rows with a given categories.
+ r"""!Updates column values for rows with a given categories.
\param cats categories to be updated
or a list of tuples (cat, value) if \p values is None
\param values to be set for column (same length as cats) or \c None
"""
- statements = ''
+ statements = ""
for i in range(len(cats)):
if values is None:
cat = str(cats[i][0])
@@ -101,16 +98,15 @@ def updateColumn(mapName, column, cats, values=None):
else:
cat = str(cats[i])
val = str(values[i])
- statement = 'UPDATE ' + mapName + ' SET '
- statement += column + ' = ' + val
- statement += ' WHERE cat = ' + cat
- statements += statement + ';\n'
+ statement = "UPDATE " + mapName + " SET "
+ statement += column + " = " + val
+ statement += " WHERE cat = " + cat
+ statements += statement + ";\n"
- grass.write_command('db.execute', input='-', stdin=statements)
+ grass.write_command("db.execute", input="-", stdin=statements)
class Classifier:
-
"""!Interface class between mlpy and other code
It does not uses numpy in the interface bu this may be wrong.
@@ -120,10 +116,14 @@ def __init__(self):
try:
import mlpy
except ImportError:
- grass.fatal(_("Cannot import mlpy (http://mlpy.sourceforge.net)"
- " library."
- " Please install it or ensure that it is on path"
- " (use PYTHONPATH variable)."))
+ grass.fatal(
+ _(
+ "Cannot import mlpy (http://mlpy.sourceforge.net)"
+ " library."
+ " Please install it or ensure that it is on path"
+ " (use PYTHONPATH variable)."
+ )
+ )
# Pytlit has a problem with this mlpy and v.class.mlpy.py
# thus, warnings for objects from mlpy has to be disabled
self.mlclassifier = mlpy.DLDA(delta=0.01) # pylint: disable=E1101
@@ -144,7 +144,7 @@ def fromDbTableToSimpleTable(dbTable, columnsDescription, columnWithClass):
sRow = []
for i, col in enumerate(row):
columnName = columnsDescription[i][0]
- if columnName != columnWithClass and columnName != 'cat':
+ if columnName != columnWithClass and columnName != "cat":
sRow.append(float(col))
sTable.append(sRow)
@@ -177,7 +177,7 @@ def extractColumnWithCats(dbTable, columnsDescription):
for row in dbTable:
for i, col in enumerate(row):
columnName = columnsDescription[i][0]
- if columnName == 'cat':
+ if columnName == "cat":
column.append(float(col))
return column
@@ -185,35 +185,38 @@ def extractColumnWithCats(dbTable, columnsDescription):
# unused
def fatal_noAttributeTable(mapName):
- grass.fatal(_("Vector map <%s> has no or empty attribute table")
- % mapName)
+ grass.fatal(_("Vector map <%s> has no or empty attribute table") % mapName)
def fatal_noEnoughColumns(mapName, ncols, required):
- grass.fatal(_("Not enough columns in vector map <%(map)s>"
- " (found %(ncols)s, expected at least %(r)s")
- % {'map': mapName, 'ncols': ncols, 'r': required})
+ grass.fatal(
+ _(
+ "Not enough columns in vector map <%(map)s>"
+ " (found %(ncols)s, expected at least %(r)s"
+ )
+ % {"map": mapName, "ncols": ncols, "r": required}
+ )
def fatal_noClassColumn(mapName, columnName):
- grass.fatal(_("Vector map <%(map)s> does not have"
- " the column <%(col)s> containing class")
- % {'map': mapName, 'col': columnName})
+ grass.fatal(
+ _("Vector map <%(map)s> does not have" " the column <%(col)s> containing class")
+ % {"map": mapName, "col": columnName}
+ )
def fatal_noRows(mapName):
- grass.fatal(_("Empty attribute table for map vector <%(map)s>")
- % {'map': mapName})
+ grass.fatal(_("Empty attribute table for map vector <%(map)s>") % {"map": mapName})
def checkNcols(mapName, tableDescription, requiredNcols):
- ncols = tableDescription['ncols']
+ ncols = tableDescription["ncols"]
if ncols < requiredNcols:
fatal_noEnoughColumns(mapName, ncols, requiredNcols)
def checkNrows(mapName, tableDescription):
- if not tableDescription['nrows'] > 0:
+ if not tableDescription["nrows"] > 0:
fatal_noRows(mapName)
@@ -230,15 +233,15 @@ def checkDbConnection(mapName):
def main():
options, unused = grass.parser()
- mapName = options['input']
- trainingMapName = options['training']
+ mapName = options["input"]
+ trainingMapName = options["training"]
- columnWithClass = options['class_column']
+ columnWithClass = options["class_column"]
useAllColumns = True
- if options['columns']:
+ if options["columns"]:
# columns as string
- columns = options['columns'].strip()
+ columns = options["columns"].strip()
useAllColumns = False
# TODO: allow same input and output map only if --overwrite was specified
@@ -286,17 +289,21 @@ def main():
dbTable = grass.db_select(table=trainingMapName)
else:
# assuming that columns concatenated by comma
- sql = 'SELECT %s,%s FROM %s' % (columnWithClass, columns, trainingMapName)
+ sql = f"SELECT {columnWithClass},{columns} FROM {trainingMapName}"
dbTable = grass.db_select(sql=sql)
- trainingParameters = fromDbTableToSimpleTable(dbTable,
- columnsDescription=trainingTableDescription['cols'],
- columnWithClass=columnWithClass)
+ trainingParameters = fromDbTableToSimpleTable(
+ dbTable,
+ columnsDescription=trainingTableDescription["cols"],
+ columnWithClass=columnWithClass,
+ )
if useAllColumns:
- trainingClasses = extractColumnWithClass(dbTable,
- columnsDescription=trainingTableDescription['cols'],
- columnWithClass=columnWithClass)
+ trainingClasses = extractColumnWithClass(
+ dbTable,
+ columnsDescription=trainingTableDescription["cols"],
+ columnWithClass=columnWithClass,
+ )
else:
# FIXME: magic num?
trainingClasses = extractNthColumn(dbTable, 0)
@@ -306,14 +313,18 @@ def main():
dbTable = grass.db_select(table=mapName)
else:
# assuming that columns concatenated by comma
- sql = 'SELECT %s,%s FROM %s' % ('cat', columns, mapName)
+ sql = "SELECT {},{} FROM {}".format("cat", columns, mapName)
dbTable = grass.db_select(sql=sql)
- parameters = fromDbTableToSimpleTable(dbTable,
- columnsDescription=tableDescription['cols'],
- columnWithClass=columnWithClass)
+ parameters = fromDbTableToSimpleTable(
+ dbTable,
+ columnsDescription=tableDescription["cols"],
+ columnWithClass=columnWithClass,
+ )
if useAllColumns:
- cats = extractColumnWithCats(dbTable, columnsDescription=tableDescription['cols'])
+ cats = extractColumnWithCats(
+ dbTable, columnsDescription=tableDescription["cols"]
+ )
else:
cats = extractNthColumn(dbTable, 0)
@@ -327,7 +338,7 @@ def main():
# add column only if not exists and the classification was successful
if not hasColumn(tableDescription, columnWithClass):
- addColumn(mapName, columnWithClass, 'int')
+ addColumn(mapName, columnWithClass, "int")
updateColumn(mapName, columnWithClass, cats, classes)
diff --git a/src/plugins/grass/scripts/v.out.ogr.pg.py b/src/plugins/grass/scripts/v.out.ogr.pg.py
index 69da2bcd0cd0..47340cc1b517 100644
--- a/src/plugins/grass/scripts/v.out.ogr.pg.py
+++ b/src/plugins/grass/scripts/v.out.ogr.pg.py
@@ -1,5 +1,4 @@
#!/usr/bin/env python3
-# -*- coding: utf-8 -*-
"""
***************************************************************************
@@ -18,9 +17,9 @@
***************************************************************************
"""
-__author__ = 'Radim Blazek'
-__date__ = 'July 2009'
-__copyright__ = '(C) 2009, Radim Blazek'
+__author__ = "Radim Blazek"
+__date__ = "July 2009"
+__copyright__ = "(C) 2009, Radim Blazek"
############################################################################
@@ -30,69 +29,69 @@
#
#############################################################################
-#%Module
-#% description: Export vector to PostGIS (PostgreSQL) database table.
-#% keywords: vector, export, database
-#%End
-
-#%option
-#% key: input
-#% type: string
-#% gisprompt: old,vector,vector
-#% key_desc : name
-#% description: Name of input vector map
-#% required : yes
-#%end
-
-#%option
-#% key: layer
-#% type: integer
-#% description: Number of input layer
-#% answer: 1
-#% required : yes
-#%end
-
-#%option
-#% key: type
-#% type: string
-#% description: Feature type(s)
-#% options: point,kernel,centroid,line,boundary,area,face
-#% multiple: yes
-#% required : yes
-#%end
-
-#%option
-#% key: olayer
-#% type: string
-#% description: Name of output database table
-#% required : yes
-#%end
-
-#%option
-#% key: host
-#% type: string
-#% label: Host
-#% description: Host name of the machine on which the server is running.
-#% required : no
-#%end
-
-#%option
-#% key: port
-#% type: integer
-#% label: Port
-#% description: TCP port on which the server is listening, usually 5432.
-#% required : no
-#%end
-
-#%option
-#% key: database
-#% type: string
-#% key_desc : name
-#% gisprompt: old_dbname,dbname,dbname
-#% label: Database
-#% description: Database name
-#% required : yes
-#%end
+# %Module
+# % description: Export vector to PostGIS (PostgreSQL) database table.
+# % keywords: vector, export, database
+# %End
+
+# %option
+# % key: input
+# % type: string
+# % gisprompt: old,vector,vector
+# % key_desc : name
+# % description: Name of input vector map
+# % required : yes
+# %end
+
+# %option
+# % key: layer
+# % type: integer
+# % description: Number of input layer
+# % answer: 1
+# % required : yes
+# %end
+
+# %option
+# % key: type
+# % type: string
+# % description: Feature type(s)
+# % options: point,kernel,centroid,line,boundary,area,face
+# % multiple: yes
+# % required : yes
+# %end
+
+# %option
+# % key: olayer
+# % type: string
+# % description: Name of output database table
+# % required : yes
+# %end
+
+# %option
+# % key: host
+# % type: string
+# % label: Host
+# % description: Host name of the machine on which the server is running.
+# % required : no
+# %end
+
+# %option
+# % key: port
+# % type: integer
+# % label: Port
+# % description: TCP port on which the server is listening, usually 5432.
+# % required : no
+# %end
+
+# %option
+# % key: database
+# % type: string
+# % key_desc : name
+# % gisprompt: old_dbname,dbname,dbname
+# % label: Database
+# % description: Database name
+# % required : yes
+# %end
# AFAIK scheme is not supported well by OGR
##%option
@@ -103,46 +102,48 @@
##% required : no
##%end
-#%option
-#% key: user
-#% type: string
-#% label: User
-#% description: Connect to the database as the user username instead of the default.
-#% required : no
-#%end
-
-#%option
-#% key: password
-#% type: string
-#% label: Password
-#% description: Password will be stored in file!
-#% required : no
-#%end
-
-#%flag
-#% key: c
-#% description: to export features with category (labeled) only. Otherwise all features are exported
-#%end
+# %option
+# % key: user
+# % type: string
+# % label: User
+# % description: Connect to the database as the user username instead of the default.
+# % required : no
+# %end
+
+# %option
+# % key: password
+# % type: string
+# % label: Password
+# % description: Password will be stored in file!
+# % required : no
+# %end
+
+# %flag
+# % key: c
+# % description: to export features with category (labeled) only. Otherwise all features are exported
+# %end
try:
from grass.script import core as grass
except ImportError:
import grass
except:
- raise Exception("Cannot find 'grass' Python module. Python is supported by GRASS from version >= 6.4")
+ raise Exception(
+ "Cannot find 'grass' Python module. Python is supported by GRASS from version >= 6.4"
+ )
def main():
- input = options['input']
- layer = options['layer']
- type = options['type']
- olayer = options['olayer']
- host = options['host']
- port = options['port']
- database = options['database']
+ input = options["input"]
+ layer = options["layer"]
+ type = options["type"]
+ olayer = options["olayer"]
+ host = options["host"]
+ port = options["port"]
+ database = options["database"]
# schema = options['schema']
- user = options['user']
- password = options['password']
+ user = options["user"]
+ password = options["password"]
# Construct dsn string
dsn = "PG:dbname=" + database
@@ -155,11 +156,23 @@ def main():
if password:
dsn += " password=" + password
- if grass.run_command('v.out.ogr', flags=flags_string, input=input, layer=layer, type=type, format="PostgreSQL", dsn=dsn, olayer=olayer) != 0:
+ if (
+ grass.run_command(
+ "v.out.ogr",
+ flags=flags_string,
+ input=input,
+ layer=layer,
+ type=type,
+ format="PostgreSQL",
+ dsn=dsn,
+ olayer=olayer,
+ )
+ != 0
+ ):
grass.fatal("Cannot export vector to database.")
if __name__ == "__main__":
options, flags = grass.parser()
- flags_string = "".join([k for k in flags.keys() if flags[k] and k != 'r'])
+ flags_string = "".join([k for k in flags.keys() if flags[k] and k != "r"])
main()
diff --git a/tests/code_layout/acceptable_missing_doc.py b/tests/code_layout/acceptable_missing_doc.py
index c4c96cdae63d..58537a4c59bb 100644
--- a/tests/code_layout/acceptable_missing_doc.py
+++ b/tests/code_layout/acceptable_missing_doc.py
@@ -15,407 +15,2125 @@
***************************************************************************
"""
-__author__ = 'Stéphane Brunner'
-__date__ = 'March 2016'
-__copyright__ = '(C) 2016, Stéphane Brunner'
+__author__ = "Stéphane Brunner"
+__date__ = "March 2016"
+__copyright__ = "(C) 2016, Stéphane Brunner"
# -*- coding: utf-8 -*-
"""
The list of acceptable documentation missing
"""
-__author__ = 'Stéphane Brunner'
-__date__ = '18/03/2016'
-__copyright__ = 'Copyright 2016, The QGIS Project'
+__author__ = "Stéphane Brunner"
+__date__ = "18/03/2016"
+__copyright__ = "Copyright 2016, The QGIS Project"
ACCEPTABLE_MISSING_DOCS = {
- "QgsGeometryLineIntersectionCheck": ["QgsGeometryLineIntersectionCheck(QgsGeometryCheckContext *context, const QVariantMap &configuration)", "factoryDescription()", "ResolutionMethod", "factoryCompatibleGeometryTypes()", "factoryCheckType()", "factoryIsCompatible(QgsVectorLayer *layer)", "factoryId()"],
- "QgsRangeConfigDlg": ["rangeWidgetChanged(int index)", "QgsRangeConfigDlg(QgsVectorLayer *vl, int fieldIdx, QWidget *parent)"],
- "QgsFeatureListViewDelegate": ["setEditSelectionModel(QItemSelectionModel *editSelectionModel)", "positionToElement(QPoint pos)", "editButtonClicked(QModelIndex &index)", "setFeatureSelectionModel(QgsFeatureSelectionModel *featureSelectionModel)", "Element", "QgsFeatureListViewDelegate(QgsFeatureListModel *listModel, QObject *parent=nullptr)", "setCurrentFeatureEdited(bool state)"],
- "QgsPenStyleComboBox": ["iconForPen(Qt::PenStyle style)", "QgsPenStyleComboBox(QWidget *parent=nullptr)", "penStyle() const", "setPenStyle(Qt::PenStyle style)"],
- "QgsRelationReferenceFactory": ["QgsRelationReferenceFactory(const QString &name, QgsMapCanvas *canvas, QgsMessageBar *messageBar)"],
- "QgsVectorLayerSelectionManager": ["QgsVectorLayerSelectionManager(QgsVectorLayer *layer, QObject *parent=nullptr)"],
- "QgsAuthMethodConfig": ["setMethod(const QString &method)", "setUri(const QString &uri)"],
+ "QgsGeometryLineIntersectionCheck": [
+ "QgsGeometryLineIntersectionCheck(QgsGeometryCheckContext *context, const QVariantMap &configuration)",
+ "factoryDescription()",
+ "ResolutionMethod",
+ "factoryCompatibleGeometryTypes()",
+ "factoryCheckType()",
+ "factoryIsCompatible(QgsVectorLayer *layer)",
+ "factoryId()",
+ ],
+ "QgsRangeConfigDlg": [
+ "rangeWidgetChanged(int index)",
+ "QgsRangeConfigDlg(QgsVectorLayer *vl, int fieldIdx, QWidget *parent)",
+ ],
+ "QgsFeatureListViewDelegate": [
+ "setEditSelectionModel(QItemSelectionModel *editSelectionModel)",
+ "positionToElement(QPoint pos)",
+ "editButtonClicked(QModelIndex &index)",
+ "setFeatureSelectionModel(QgsFeatureSelectionModel *featureSelectionModel)",
+ "Element",
+ "QgsFeatureListViewDelegate(QgsFeatureListModel *listModel, QObject *parent=nullptr)",
+ "setCurrentFeatureEdited(bool state)",
+ ],
+ "QgsPenStyleComboBox": [
+ "iconForPen(Qt::PenStyle style)",
+ "QgsPenStyleComboBox(QWidget *parent=nullptr)",
+ "penStyle() const",
+ "setPenStyle(Qt::PenStyle style)",
+ ],
+ "QgsRelationReferenceFactory": [
+ "QgsRelationReferenceFactory(const QString &name, QgsMapCanvas *canvas, QgsMessageBar *messageBar)"
+ ],
+ "QgsVectorLayerSelectionManager": [
+ "QgsVectorLayerSelectionManager(QgsVectorLayer *layer, QObject *parent=nullptr)"
+ ],
+ "QgsAuthMethodConfig": [
+ "setMethod(const QString &method)",
+ "setUri(const QString &uri)",
+ ],
"QgsRuleBasedLabeling": ["rootRule()", "rootRule() const"],
"QgsDrawSourceWidget": ["QgsDrawSourceWidget(QWidget *parent=nullptr)", "create()"],
"QgsLegendSymbolItem": ["QgsLegendSymbolItem(const QgsLegendSymbolItem &other)"],
- "QgsMeshDatasetGroupProxyModel": ["QgsMeshDatasetGroupProxyModel(QAbstractItemModel *sourceModel)"],
- "QgsStyleManagerDialog": ["editColorRamp()", "currentItemType()", "editSymbol()", "currentItemName()"],
+ "QgsMeshDatasetGroupProxyModel": [
+ "QgsMeshDatasetGroupProxyModel(QAbstractItemModel *sourceModel)"
+ ],
+ "QgsStyleManagerDialog": [
+ "editColorRamp()",
+ "currentItemType()",
+ "editSymbol()",
+ "currentItemName()",
+ ],
"QgsDirectoryItem": ["directoryChanged()"],
- "QgsSymbolLayer": ["drawPreviewIcon(QgsSymbolRenderContext &context, QSize size)=0", "setMapUnitScale(const QgsMapUnitScale &scale)", "type() const", "mapUnitScale() const", "ogrFeatureStyle(double mmScaleFactor, double mapUnitScaleFactor) const"],
- "QgsGraduatedSymbolRenderer": ["sortByLabel(Qt::SortOrder order=Qt::AscendingOrder)", "deleteAllClasses()", "updateRangeLabel(int rangeIndex, const QString &label)", "updateRangeLowerValue(int rangeIndex, double value)", "updateRangeSymbol(int rangeIndex, QgsSymbol *symbol)", "updateRangeUpperValue(int rangeIndex, double value)", "sortByValue(Qt::SortOrder order=Qt::AscendingOrder)", "addClass(QgsSymbol *symbol)", "updateRangeRenderState(int rangeIndex, bool render)", "QgsGraduatedSymbolRenderer(const QString &attrName=QString(), const QgsRangeList &ranges=QgsRangeList())", "deleteClass(int idx)"],
- "QgsGeometryAngleCheck": ["factoryDescription()", "ResolutionMethod", "factoryCompatibleGeometryTypes()", "factoryCheckType()", "factoryIsCompatible(QgsVectorLayer *layer)", "factoryId()", "QgsGeometryAngleCheck(QgsGeometryCheckContext *context, const QVariantMap &configuration)"],
- "QgsMapRendererSequentialJob": ["internalFinished()", "QgsMapRendererSequentialJob(const QgsMapSettings &settings)"],
- "QgsLayerTreeRegistryBridge": ["groupWillRemoveChildren(QgsLayerTreeNode *node, int indexFrom, int indexTo)", "layersWillBeRemoved(const QStringList &layerIds)", "layersAdded(const QList< QgsMapLayer * > &layers)", "groupRemovedChildren()", "setNewLayersVisible(bool enabled)", "isEnabled() const", "removeLayersFromRegistry(const QStringList &layerIds)", "setEnabled(bool enabled)", "newLayersVisible() const"],
- "QgsDirectoryParamWidget": ["showHideColumn()", "QgsDirectoryParamWidget(const QString &path, QWidget *parent=nullptr)"],
- "QgsDiagramRenderer": ["diagram() const", "QgsDiagramRenderer(const QgsDiagramRenderer &other)", "rendererName() const =0", "setDiagram(QgsDiagram *d)"],
- "QgsVectorLayer": ["vectorJoins() const", "setDiagramLayerSettings(const QgsDiagramLayerSettings &s)", "diagramLayerSettings() const", "diagramRenderer() const"],
- "QgsRelationReferenceConfigDlg": ["QgsRelationReferenceConfigDlg(QgsVectorLayer *vl, int fieldIdx, QWidget *parent)"],
- "QgsDial": ["setMaximum(const QVariant &max)", "setSingleStep(const QVariant &step)", "setValue(const QVariant &value)", "variantValue() const", "valueChanged(const QVariant &)", "setMinimum(const QVariant &min)"],
- "QgsHillshadeFilter": ["lightAzimuth() const", "setLightAngle(float angle)", "QgsHillshadeFilter(const QString &inputFile, const QString &outputFile, const QString &outputFormat, double lightAzimuth=300, double lightAngle=40)", "lightAngle() const", "setLightAzimuth(float azimuth)"],
- "QgsClipToMinMaxEnhancement": ["QgsClipToMinMaxEnhancement(Qgis::DataType, double, double)"],
- "QgsRenderChecker": ["setElapsedTimeTarget(int target)", "setControlPathSuffix(const QString &name)", "setMapSettings(const QgsMapSettings &mapSettings)"],
- "QgsDateTimeEditConfig": ["QgsDateTimeEditConfig(QgsVectorLayer *vl, int fieldIdx, QWidget *parent=nullptr)"],
- "QgsGeometryDuplicateCheck": ["factoryDescription()", "ResolutionMethod", "factoryCompatibleGeometryTypes()", "factoryCheckType()", "factoryIsCompatible(QgsVectorLayer *layer)", "factoryId()", "QgsGeometryDuplicateCheck(QgsGeometryCheckContext *context, const QVariantMap &configuration)"],
- "QgsVectorLayerRenderer": ["QgsVectorLayerRenderer(QgsVectorLayer *layer, QgsRenderContext &context)"],
- "QgsGeometrySliverPolygonCheck": ["QgsGeometrySliverPolygonCheck(QgsGeometryCheckContext *context, const QVariantMap &configuration)", "factoryId()", "factoryDescription()"],
- "QgsRendererRange": ["QgsRendererRange(const QgsRendererRange &range)", "operator<(const QgsRendererRange &other) const", "swap(QgsRendererRange &other)"],
+ "QgsSymbolLayer": [
+ "drawPreviewIcon(QgsSymbolRenderContext &context, QSize size)=0",
+ "setMapUnitScale(const QgsMapUnitScale &scale)",
+ "type() const",
+ "mapUnitScale() const",
+ "ogrFeatureStyle(double mmScaleFactor, double mapUnitScaleFactor) const",
+ ],
+ "QgsGraduatedSymbolRenderer": [
+ "sortByLabel(Qt::SortOrder order=Qt::AscendingOrder)",
+ "deleteAllClasses()",
+ "updateRangeLabel(int rangeIndex, const QString &label)",
+ "updateRangeLowerValue(int rangeIndex, double value)",
+ "updateRangeSymbol(int rangeIndex, QgsSymbol *symbol)",
+ "updateRangeUpperValue(int rangeIndex, double value)",
+ "sortByValue(Qt::SortOrder order=Qt::AscendingOrder)",
+ "addClass(QgsSymbol *symbol)",
+ "updateRangeRenderState(int rangeIndex, bool render)",
+ "QgsGraduatedSymbolRenderer(const QString &attrName=QString(), const QgsRangeList &ranges=QgsRangeList())",
+ "deleteClass(int idx)",
+ ],
+ "QgsGeometryAngleCheck": [
+ "factoryDescription()",
+ "ResolutionMethod",
+ "factoryCompatibleGeometryTypes()",
+ "factoryCheckType()",
+ "factoryIsCompatible(QgsVectorLayer *layer)",
+ "factoryId()",
+ "QgsGeometryAngleCheck(QgsGeometryCheckContext *context, const QVariantMap &configuration)",
+ ],
+ "QgsMapRendererSequentialJob": [
+ "internalFinished()",
+ "QgsMapRendererSequentialJob(const QgsMapSettings &settings)",
+ ],
+ "QgsLayerTreeRegistryBridge": [
+ "groupWillRemoveChildren(QgsLayerTreeNode *node, int indexFrom, int indexTo)",
+ "layersWillBeRemoved(const QStringList &layerIds)",
+ "layersAdded(const QList< QgsMapLayer * > &layers)",
+ "groupRemovedChildren()",
+ "setNewLayersVisible(bool enabled)",
+ "isEnabled() const",
+ "removeLayersFromRegistry(const QStringList &layerIds)",
+ "setEnabled(bool enabled)",
+ "newLayersVisible() const",
+ ],
+ "QgsDirectoryParamWidget": [
+ "showHideColumn()",
+ "QgsDirectoryParamWidget(const QString &path, QWidget *parent=nullptr)",
+ ],
+ "QgsDiagramRenderer": [
+ "diagram() const",
+ "QgsDiagramRenderer(const QgsDiagramRenderer &other)",
+ "rendererName() const =0",
+ "setDiagram(QgsDiagram *d)",
+ ],
+ "QgsVectorLayer": [
+ "vectorJoins() const",
+ "setDiagramLayerSettings(const QgsDiagramLayerSettings &s)",
+ "diagramLayerSettings() const",
+ "diagramRenderer() const",
+ ],
+ "QgsRelationReferenceConfigDlg": [
+ "QgsRelationReferenceConfigDlg(QgsVectorLayer *vl, int fieldIdx, QWidget *parent)"
+ ],
+ "QgsDial": [
+ "setMaximum(const QVariant &max)",
+ "setSingleStep(const QVariant &step)",
+ "setValue(const QVariant &value)",
+ "variantValue() const",
+ "valueChanged(const QVariant &)",
+ "setMinimum(const QVariant &min)",
+ ],
+ "QgsHillshadeFilter": [
+ "lightAzimuth() const",
+ "setLightAngle(float angle)",
+ "QgsHillshadeFilter(const QString &inputFile, const QString &outputFile, const QString &outputFormat, double lightAzimuth=300, double lightAngle=40)",
+ "lightAngle() const",
+ "setLightAzimuth(float azimuth)",
+ ],
+ "QgsClipToMinMaxEnhancement": [
+ "QgsClipToMinMaxEnhancement(Qgis::DataType, double, double)"
+ ],
+ "QgsRenderChecker": [
+ "setElapsedTimeTarget(int target)",
+ "setControlPathSuffix(const QString &name)",
+ "setMapSettings(const QgsMapSettings &mapSettings)",
+ ],
+ "QgsDateTimeEditConfig": [
+ "QgsDateTimeEditConfig(QgsVectorLayer *vl, int fieldIdx, QWidget *parent=nullptr)"
+ ],
+ "QgsGeometryDuplicateCheck": [
+ "factoryDescription()",
+ "ResolutionMethod",
+ "factoryCompatibleGeometryTypes()",
+ "factoryCheckType()",
+ "factoryIsCompatible(QgsVectorLayer *layer)",
+ "factoryId()",
+ "QgsGeometryDuplicateCheck(QgsGeometryCheckContext *context, const QVariantMap &configuration)",
+ ],
+ "QgsVectorLayerRenderer": [
+ "QgsVectorLayerRenderer(QgsVectorLayer *layer, QgsRenderContext &context)"
+ ],
+ "QgsGeometrySliverPolygonCheck": [
+ "QgsGeometrySliverPolygonCheck(QgsGeometryCheckContext *context, const QVariantMap &configuration)",
+ "factoryId()",
+ "factoryDescription()",
+ ],
+ "QgsRendererRange": [
+ "QgsRendererRange(const QgsRendererRange &range)",
+ "operator<(const QgsRendererRange &other) const",
+ "swap(QgsRendererRange &other)",
+ ],
"QgsRasterMinMaxWidget": ["setBands(const QList< int > &bands)"],
- "QgsDataDefinedWidthDialog": ["QgsDataDefinedWidthDialog(const QList< QgsSymbol * > &symbolList, QgsVectorLayer *layer)"],
- "QgsVectorLayerEditBuffer": ["attributeDeleted(int idx)", "committedFeaturesRemoved(const QString &layerId, const QgsFeatureIds &deletedFeatureIds)", "updateLayerFields()", "committedAttributesAdded(const QString &layerId, const QList< QgsField > &addedAttributes)", "QgsVectorLayerEditBuffer(QgsVectorLayer *layer)", "attributeValueChanged(QgsFeatureId fid, int idx, const QVariant &)", "undoIndexChanged(int index)", "committedGeometriesChanges(const QString &layerId, const QgsGeometryMap &changedGeometries)", "committedFeaturesAdded(const QString &layerId, const QgsFeatureList &addedFeatures)", "featureAdded(QgsFeatureId fid)", "committedAttributeValuesChanges(const QString &layerId, const QgsChangedAttributesMap &changedAttributesValues)", "attributeAdded(int idx)", "featureDeleted(QgsFeatureId fid)"],
- "QgsLinearMinMaxEnhancement": ["QgsLinearMinMaxEnhancement(Qgis::DataType, double, double)"],
+ "QgsDataDefinedWidthDialog": [
+ "QgsDataDefinedWidthDialog(const QList< QgsSymbol * > &symbolList, QgsVectorLayer *layer)"
+ ],
+ "QgsVectorLayerEditBuffer": [
+ "attributeDeleted(int idx)",
+ "committedFeaturesRemoved(const QString &layerId, const QgsFeatureIds &deletedFeatureIds)",
+ "updateLayerFields()",
+ "committedAttributesAdded(const QString &layerId, const QList< QgsField > &addedAttributes)",
+ "QgsVectorLayerEditBuffer(QgsVectorLayer *layer)",
+ "attributeValueChanged(QgsFeatureId fid, int idx, const QVariant &)",
+ "undoIndexChanged(int index)",
+ "committedGeometriesChanges(const QString &layerId, const QgsGeometryMap &changedGeometries)",
+ "committedFeaturesAdded(const QString &layerId, const QgsFeatureList &addedFeatures)",
+ "featureAdded(QgsFeatureId fid)",
+ "committedAttributeValuesChanges(const QString &layerId, const QgsChangedAttributesMap &changedAttributesValues)",
+ "attributeAdded(int idx)",
+ "featureDeleted(QgsFeatureId fid)",
+ ],
+ "QgsLinearMinMaxEnhancement": [
+ "QgsLinearMinMaxEnhancement(Qgis::DataType, double, double)"
+ ],
"QgsVectorLayerEditUtils": ["QgsVectorLayerEditUtils(QgsVectorLayer *layer)"],
- "QgsPointLocator_VisitorNearestEdge": ["QgsPointLocator_VisitorNearestEdge(QgsPointLocator *pl, QgsPointLocator::Match &m, const QgsPointXY &srcPoint, QgsPointLocator::MatchFilter *filter=nullptr)"],
- "QgsFieldCalculator": ["QgsFieldCalculator(QgsVectorLayer *vl, QWidget *parent=nullptr)"],
- "QgsLayerTreeGroup": ["QgsLayerTreeGroup(const QgsLayerTreeGroup &other)", "nodeVisibilityChanged(QgsLayerTreeNode *node)"],
- "QgsLongLongValidator": ["QgsLongLongValidator(qint64 bottom, qint64 top, QObject *parent)", "setRange(qint64 bottom, qint64 top)", "setBottom(qint64 bottom)", "setTop(qint64 top)", "QgsLongLongValidator(QObject *parent)", "bottom() const", "top() const"],
+ "QgsPointLocator_VisitorNearestEdge": [
+ "QgsPointLocator_VisitorNearestEdge(QgsPointLocator *pl, QgsPointLocator::Match &m, const QgsPointXY &srcPoint, QgsPointLocator::MatchFilter *filter=nullptr)"
+ ],
+ "QgsFieldCalculator": [
+ "QgsFieldCalculator(QgsVectorLayer *vl, QWidget *parent=nullptr)"
+ ],
+ "QgsLayerTreeGroup": [
+ "QgsLayerTreeGroup(const QgsLayerTreeGroup &other)",
+ "nodeVisibilityChanged(QgsLayerTreeNode *node)",
+ ],
+ "QgsLongLongValidator": [
+ "QgsLongLongValidator(qint64 bottom, qint64 top, QObject *parent)",
+ "setRange(qint64 bottom, qint64 top)",
+ "setBottom(qint64 bottom)",
+ "setTop(qint64 top)",
+ "QgsLongLongValidator(QObject *parent)",
+ "bottom() const",
+ "top() const",
+ ],
"QgsScopeLogger": ["QgsScopeLogger(const char *file, const char *func, int line)"],
- "QgsPythonRunner": ["evalCommand(QString command, QString &result)=0", "runCommand(QString command, QString messageOnError=QString())=0"],
- "QgsAttributeActionDialog": ["init(const QgsActionManager &action, const QgsAttributeTableConfig &attributeTableConfig)", "QgsAttributeActionDialog(const QgsActionManager &actions, QWidget *parent=nullptr)", "attributeTableWidgetStyle() const", "actions() const", "showWidgetInAttributeTable() const"],
- "QgsRasterRendererWidget": ["setStdDev(const QString &value)", "setMin(const QString &value, int index=0)", "max(int index=0)", "stdDev()", "selectedBand(int index=0)", "QgsRasterRendererWidget(QgsRasterLayer *layer, const QgsRectangle &extent)", "min(int index=0)", "setMax(const QString &value, int index=0)"],
- "QgsRasterDataProvider": ["colorTable(int bandNo) const", "setUserNoDataValue(int bandNo, const QgsRasterRangeList &noData)"],
- "QgsHueSaturationFilter": ["colorizeStrength() const", "setColorizeStrength(int colorizeStrength)", "QgsHueSaturationFilter(QgsRasterInterface *input=nullptr)", "colorizeColor() const", "setColorizeOn(bool colorizeOn)", "setSaturation(int saturation)", "GrayscaleMode", "grayscaleMode() const", "setGrayscaleMode(QgsHueSaturationFilter::GrayscaleMode grayscaleMode)", "setColorizeColor(const QColor &colorizeColor)", "colorizeOn() const", "saturation() const"],
+ "QgsPythonRunner": [
+ "evalCommand(QString command, QString &result)=0",
+ "runCommand(QString command, QString messageOnError=QString())=0",
+ ],
+ "QgsAttributeActionDialog": [
+ "init(const QgsActionManager &action, const QgsAttributeTableConfig &attributeTableConfig)",
+ "QgsAttributeActionDialog(const QgsActionManager &actions, QWidget *parent=nullptr)",
+ "attributeTableWidgetStyle() const",
+ "actions() const",
+ "showWidgetInAttributeTable() const",
+ ],
+ "QgsRasterRendererWidget": [
+ "setStdDev(const QString &value)",
+ "setMin(const QString &value, int index=0)",
+ "max(int index=0)",
+ "stdDev()",
+ "selectedBand(int index=0)",
+ "QgsRasterRendererWidget(QgsRasterLayer *layer, const QgsRectangle &extent)",
+ "min(int index=0)",
+ "setMax(const QString &value, int index=0)",
+ ],
+ "QgsRasterDataProvider": [
+ "colorTable(int bandNo) const",
+ "setUserNoDataValue(int bandNo, const QgsRasterRangeList &noData)",
+ ],
+ "QgsHueSaturationFilter": [
+ "colorizeStrength() const",
+ "setColorizeStrength(int colorizeStrength)",
+ "QgsHueSaturationFilter(QgsRasterInterface *input=nullptr)",
+ "colorizeColor() const",
+ "setColorizeOn(bool colorizeOn)",
+ "setSaturation(int saturation)",
+ "GrayscaleMode",
+ "grayscaleMode() const",
+ "setGrayscaleMode(QgsHueSaturationFilter::GrayscaleMode grayscaleMode)",
+ "setColorizeColor(const QColor &colorizeColor)",
+ "colorizeOn() const",
+ "saturation() const",
+ ],
"QgsSymbolLevelItem": ["QgsSymbolLevelItem(QgsSymbol *symbol, int layer)"],
"QgsCredentials": ["getMasterPassword(QString &password, bool stored=false)"],
- "QgsDataDefinedRotationDialog": ["QgsDataDefinedRotationDialog(const QList< QgsSymbol * > &symbolList, QgsVectorLayer *layer)"],
- "QgsCptCityColorRamp": ["loadFile()", "setSchemeName(const QString &schemeName)", "variantName() const", "copyingInfo() const", "setName(const QString &schemeName, const QString &variantName=QString(), const QStringList &variantList=QStringList())", "setVariantName(const QString &variantName)", "variantList() const", "setVariantList(const QStringList &variantList)", "cloneGradientRamp() const", "loadPalette()", "hasMultiStops() const", "schemeName() const", "fileName() const", "copyingFileName() const", "fileLoaded() const", "descFileName() const", "copy(const QgsCptCityColorRamp *other)"],
- "QgsMapToolIdentifyFeature": ["featureIdentified(QgsFeatureId)", "featureIdentified(const QgsFeature &)"],
- "QgsGroupBoxCollapseButton": ["QgsGroupBoxCollapseButton(QWidget *parent=nullptr)", "setAltDown(bool updown)", "setShiftDown(bool shiftdown)", "shiftDown() const", "altDown() const"],
+ "QgsDataDefinedRotationDialog": [
+ "QgsDataDefinedRotationDialog(const QList< QgsSymbol * > &symbolList, QgsVectorLayer *layer)"
+ ],
+ "QgsCptCityColorRamp": [
+ "loadFile()",
+ "setSchemeName(const QString &schemeName)",
+ "variantName() const",
+ "copyingInfo() const",
+ "setName(const QString &schemeName, const QString &variantName=QString(), const QStringList &variantList=QStringList())",
+ "setVariantName(const QString &variantName)",
+ "variantList() const",
+ "setVariantList(const QStringList &variantList)",
+ "cloneGradientRamp() const",
+ "loadPalette()",
+ "hasMultiStops() const",
+ "schemeName() const",
+ "fileName() const",
+ "copyingFileName() const",
+ "fileLoaded() const",
+ "descFileName() const",
+ "copy(const QgsCptCityColorRamp *other)",
+ ],
+ "QgsMapToolIdentifyFeature": [
+ "featureIdentified(QgsFeatureId)",
+ "featureIdentified(const QgsFeature &)",
+ ],
+ "QgsGroupBoxCollapseButton": [
+ "QgsGroupBoxCollapseButton(QWidget *parent=nullptr)",
+ "setAltDown(bool updown)",
+ "setShiftDown(bool shiftdown)",
+ "shiftDown() const",
+ "altDown() const",
+ ],
"QgsGlowWidget": ["QgsGlowWidget(QWidget *parent=nullptr)", "create()"],
- "QgsRuggednessFilter": ["QgsRuggednessFilter(const QString &inputFile, const QString &outputFile, const QString &outputFormat)"],
+ "QgsRuggednessFilter": [
+ "QgsRuggednessFilter(const QString &inputFile, const QString &outputFile, const QString &outputFormat)"
+ ],
"QgsIFeatureSelectionManager": ["QgsIFeatureSelectionManager(QObject *parent)"],
- "QgsGraduatedSymbolRendererWidget": ["classifyGraduated()", "updateUiFromRenderer(bool updateCount=true)", "QgsGraduatedSymbolRendererWidget(QgsVectorLayer *layer, QgsStyle *style, QgsFeatureRenderer *renderer)", "connectUpdateHandlers()", "create(QgsVectorLayer *layer, QgsStyle *style, QgsFeatureRenderer *renderer)", "reapplySizes()", "rangesDoubleClicked(const QModelIndex &idx)", "changeRange(int rangeIdx)", "changeCurrentValue(QStandardItem *item)", "showSymbolLevels()", "changeSelectedSymbols()", "selectedRanges()", "reapplyColorRamp()", "disconnectUpdateHandlers()", "rowsOrdered()", "modelDataChanged()", "graduatedColumnChanged(const QString &field)", "rowsMoved()", "findSymbolForRange(double lowerBound, double upperBound, const QgsRangeList &ranges) const", "labelFormatChanged()", "changeRangeSymbol(int rangeIdx)", "rangesClicked(const QModelIndex &idx)"],
+ "QgsGraduatedSymbolRendererWidget": [
+ "classifyGraduated()",
+ "updateUiFromRenderer(bool updateCount=true)",
+ "QgsGraduatedSymbolRendererWidget(QgsVectorLayer *layer, QgsStyle *style, QgsFeatureRenderer *renderer)",
+ "connectUpdateHandlers()",
+ "create(QgsVectorLayer *layer, QgsStyle *style, QgsFeatureRenderer *renderer)",
+ "reapplySizes()",
+ "rangesDoubleClicked(const QModelIndex &idx)",
+ "changeRange(int rangeIdx)",
+ "changeCurrentValue(QStandardItem *item)",
+ "showSymbolLevels()",
+ "changeSelectedSymbols()",
+ "selectedRanges()",
+ "reapplyColorRamp()",
+ "disconnectUpdateHandlers()",
+ "rowsOrdered()",
+ "modelDataChanged()",
+ "graduatedColumnChanged(const QString &field)",
+ "rowsMoved()",
+ "findSymbolForRange(double lowerBound, double upperBound, const QgsRangeList &ranges) const",
+ "labelFormatChanged()",
+ "changeRangeSymbol(int rangeIdx)",
+ "rangesClicked(const QModelIndex &idx)",
+ ],
"QgsPointLocator": ["destroyIndex()", "rebuildIndex(int maxFeaturesToIndex=-1)"],
"QgsRuleBasedRenderer": ["FeatureFlags", "rootRule()"],
- "QgsSimpleFillSymbolLayerWidget": ["setColor(const QColor &color)", "setStrokeColor(const QColor &color)"],
+ "QgsSimpleFillSymbolLayerWidget": [
+ "setColor(const QColor &color)",
+ "setStrokeColor(const QColor &color)",
+ ],
"pal::Pal": ["FnIsCanceled)(void *ctx)"],
"QgsColorSwatchDelegate": ["QgsColorSwatchDelegate(QWidget *parent=nullptr)"],
- "QgsMeshDatasetGroupTreeItemDelegate": ["QgsMeshDatasetGroupTreeItemDelegate(QObject *parent=nullptr)"],
- "QgsAspectFilter": ["QgsAspectFilter(const QString &inputFile, const QString &outputFile, const QString &outputFormat)"],
- "QgsRasterMatrix": ["asinus()", "setData(int cols, int rows, double *data, double nodataValue)", "power(const QgsRasterMatrix &other)", "number() const", "multiply(const QgsRasterMatrix &other)", "greaterThan(const QgsRasterMatrix &other)", "equal(const QgsRasterMatrix &other)", "greaterEqual(const QgsRasterMatrix &other)", "lesserEqual(const QgsRasterMatrix &other)", "nColumns() const", "logicalOr(const QgsRasterMatrix &other)", "QgsRasterMatrix(const QgsRasterMatrix &m)", "log10()", "tangens()", "divide(const QgsRasterMatrix &other)", "logicalAnd(const QgsRasterMatrix &other)", "sinus()", "squareRoot()", "changeSign()", "nRows() const", "cosinus()", "atangens()", "acosinus()", "lesserThan(const QgsRasterMatrix &other)", "OneArgOperator", "TwoArgOperator", "setNodataValue(double d)", "notEqual(const QgsRasterMatrix &other)", "nodataValue() const", "log()"],
- "QgsVectorFileWriter::Option": ["Option(const QString &docString, QgsVectorFileWriter::OptionType type)"],
- "QgsErrorMessage": ["file() const", "message() const", "function() const", "line() const", "tag() const"],
- "QgsTextEditConfigDlg": ["QgsTextEditConfigDlg(QgsVectorLayer *vl, int fieldIdx, QWidget *parent=nullptr)"],
- "QgsMarkerLineSymbolLayerWidget": ["setInterval(double val)", "setOffsetAlongLine(double val)"],
- "QgsNineCellFilter": ["setCellSizeY(double size)", "setZFactor(double factor)", "outputNodataValue() const", "setCellSizeX(double size)", "setInputNodataValue(double value)", "cellSizeY() const", "cellSizeX() const", "setOutputNodataValue(double value)", "inputNodataValue() const", "zFactor() const"],
- "QgsIdentifyMenu": ["showFeatureActions()", "maxFeatureDisplay()", "execWithSingleResult()", "allowMultipleReturn()", "maxLayerDisplay()", "resultsIfExternalAction()", "MenuLevel"],
- "QgsRuleBasedRendererModel": ["finishedAddingRules()", "updateRule(const QModelIndex &index)", "willAddRules(const QModelIndex &parent, int count)", "clearFeatureCounts()", "insertRule(const QModelIndex &parent, int before, QgsRuleBasedRenderer::Rule *newrule)", "removeRule(const QModelIndex &index)", "updateRule(const QModelIndex &parent, int row)", "ruleForIndex(const QModelIndex &index) const"],
+ "QgsMeshDatasetGroupTreeItemDelegate": [
+ "QgsMeshDatasetGroupTreeItemDelegate(QObject *parent=nullptr)"
+ ],
+ "QgsAspectFilter": [
+ "QgsAspectFilter(const QString &inputFile, const QString &outputFile, const QString &outputFormat)"
+ ],
+ "QgsRasterMatrix": [
+ "asinus()",
+ "setData(int cols, int rows, double *data, double nodataValue)",
+ "power(const QgsRasterMatrix &other)",
+ "number() const",
+ "multiply(const QgsRasterMatrix &other)",
+ "greaterThan(const QgsRasterMatrix &other)",
+ "equal(const QgsRasterMatrix &other)",
+ "greaterEqual(const QgsRasterMatrix &other)",
+ "lesserEqual(const QgsRasterMatrix &other)",
+ "nColumns() const",
+ "logicalOr(const QgsRasterMatrix &other)",
+ "QgsRasterMatrix(const QgsRasterMatrix &m)",
+ "log10()",
+ "tangens()",
+ "divide(const QgsRasterMatrix &other)",
+ "logicalAnd(const QgsRasterMatrix &other)",
+ "sinus()",
+ "squareRoot()",
+ "changeSign()",
+ "nRows() const",
+ "cosinus()",
+ "atangens()",
+ "acosinus()",
+ "lesserThan(const QgsRasterMatrix &other)",
+ "OneArgOperator",
+ "TwoArgOperator",
+ "setNodataValue(double d)",
+ "notEqual(const QgsRasterMatrix &other)",
+ "nodataValue() const",
+ "log()",
+ ],
+ "QgsVectorFileWriter::Option": [
+ "Option(const QString &docString, QgsVectorFileWriter::OptionType type)"
+ ],
+ "QgsErrorMessage": [
+ "file() const",
+ "message() const",
+ "function() const",
+ "line() const",
+ "tag() const",
+ ],
+ "QgsTextEditConfigDlg": [
+ "QgsTextEditConfigDlg(QgsVectorLayer *vl, int fieldIdx, QWidget *parent=nullptr)"
+ ],
+ "QgsMarkerLineSymbolLayerWidget": [
+ "setInterval(double val)",
+ "setOffsetAlongLine(double val)",
+ ],
+ "QgsNineCellFilter": [
+ "setCellSizeY(double size)",
+ "setZFactor(double factor)",
+ "outputNodataValue() const",
+ "setCellSizeX(double size)",
+ "setInputNodataValue(double value)",
+ "cellSizeY() const",
+ "cellSizeX() const",
+ "setOutputNodataValue(double value)",
+ "inputNodataValue() const",
+ "zFactor() const",
+ ],
+ "QgsIdentifyMenu": [
+ "showFeatureActions()",
+ "maxFeatureDisplay()",
+ "execWithSingleResult()",
+ "allowMultipleReturn()",
+ "maxLayerDisplay()",
+ "resultsIfExternalAction()",
+ "MenuLevel",
+ ],
+ "QgsRuleBasedRendererModel": [
+ "finishedAddingRules()",
+ "updateRule(const QModelIndex &index)",
+ "willAddRules(const QModelIndex &parent, int count)",
+ "clearFeatureCounts()",
+ "insertRule(const QModelIndex &parent, int before, QgsRuleBasedRenderer::Rule *newrule)",
+ "removeRule(const QModelIndex &index)",
+ "updateRule(const QModelIndex &parent, int row)",
+ "ruleForIndex(const QModelIndex &index) const",
+ ],
"QgsSymbolLevelsDialog": ["setForceOrderingEnabled(bool enabled)"],
- "QgsSimpleMarkerSymbolLayerWidget": ["setColorStroke(const QColor &color)", "setColorFill(const QColor &color)"],
+ "QgsSimpleMarkerSymbolLayerWidget": [
+ "setColorStroke(const QColor &color)",
+ "setColorFill(const QColor &color)",
+ ],
"QgsActionMenu": ["reinit()"],
"QgsFieldComboBox": ["indexChanged(int i)"],
"QgsPaintEffect": ["QgsPaintEffect(const QgsPaintEffect &other)"],
- "QgsMeshDatasetGroupTreeModel": ["Roles", "QgsMeshDatasetGroupTreeModel(QObject *parent=nullptr)"],
+ "QgsMeshDatasetGroupTreeModel": [
+ "Roles",
+ "QgsMeshDatasetGroupTreeModel(QObject *parent=nullptr)",
+ ],
"QgsPaintEngineHack": ["fixFlags()", "fixEngineFlags(QPaintEngine *engine)"],
"QgsHeatmapRenderer": ["convertFromRenderer(const QgsFeatureRenderer *renderer)"],
- "QgsShadowEffectWidget": ["QgsShadowEffectWidget(QWidget *parent=nullptr)", "create()"],
- "QgsCentroidFillSymbolLayer": ["createFromSld(QDomElement &element)", "setPointOnSurface(bool pointOnSurface)", "pointOnSurface() const"],
+ "QgsShadowEffectWidget": [
+ "QgsShadowEffectWidget(QWidget *parent=nullptr)",
+ "create()",
+ ],
+ "QgsCentroidFillSymbolLayer": [
+ "createFromSld(QDomElement &element)",
+ "setPointOnSurface(bool pointOnSurface)",
+ "pointOnSurface() const",
+ ],
"QgsPluginLayerType": ["QgsPluginLayerType(const QString &name)", "name() const"],
- "QgsConditionalStyle": ["QgsConditionalStyle(const QString &rule)", "QgsConditionalStyle(const QgsConditionalStyle &other)"],
- "QgsContrastEnhancement": ["contrastEnhancementAlgorithm() const", "readXml(const QDomElement &elem)", "writeXml(QDomDocument &doc, QDomElement &parentElem) const", "QgsContrastEnhancement(const QgsContrastEnhancement &ce)"],
- "QgsFontMarkerSymbolLayerWidget": ["setFontFamily(const QFont &font)", "setColor(const QColor &color)", "setAngle(double angle)", "setSize(double size)"],
- "QgsBrushStyleComboBox": ["iconForBrush(Qt::BrushStyle style)", "QgsBrushStyleComboBox(QWidget *parent=nullptr)", "setBrushStyle(Qt::BrushStyle style)", "brushStyle() const"],
+ "QgsConditionalStyle": [
+ "QgsConditionalStyle(const QString &rule)",
+ "QgsConditionalStyle(const QgsConditionalStyle &other)",
+ ],
+ "QgsContrastEnhancement": [
+ "contrastEnhancementAlgorithm() const",
+ "readXml(const QDomElement &elem)",
+ "writeXml(QDomDocument &doc, QDomElement &parentElem) const",
+ "QgsContrastEnhancement(const QgsContrastEnhancement &ce)",
+ ],
+ "QgsFontMarkerSymbolLayerWidget": [
+ "setFontFamily(const QFont &font)",
+ "setColor(const QColor &color)",
+ "setAngle(double angle)",
+ "setSize(double size)",
+ ],
+ "QgsBrushStyleComboBox": [
+ "iconForBrush(Qt::BrushStyle style)",
+ "QgsBrushStyleComboBox(QWidget *parent=nullptr)",
+ "setBrushStyle(Qt::BrushStyle style)",
+ "brushStyle() const",
+ ],
"QgsGlowEffect": ["QgsGlowEffect(const QgsGlowEffect &other)"],
"QgsLabelCandidate": ["QgsLabelCandidate(const QRectF &r, double c)"],
- "pal::LabelPosition": ["getReversed() const", "resetNumOverlaps()", "getPartId() const", "getProblemFeatureId() const", "getWidth() const", "getNumOverlaps() const", "getHeight() const", "getQuadrant() const", "setPartId(int id)", "getUpsideDown() const"],
- "QgsAttributesFormProperties": ["initSuppressCombo()", "QgsAttributesFormProperties(QgsVectorLayer *layer, QWidget *parent=nullptr)", "initLayoutConfig()", "initFormLayoutTree()", "updateButtons()", "FieldPropertiesRoles", "loadRelations()", "initAvailableWidgetsTree()", "init()", "initInitPython()"],
+ "pal::LabelPosition": [
+ "getReversed() const",
+ "resetNumOverlaps()",
+ "getPartId() const",
+ "getProblemFeatureId() const",
+ "getWidth() const",
+ "getNumOverlaps() const",
+ "getHeight() const",
+ "getQuadrant() const",
+ "setPartId(int id)",
+ "getUpsideDown() const",
+ ],
+ "QgsAttributesFormProperties": [
+ "initSuppressCombo()",
+ "QgsAttributesFormProperties(QgsVectorLayer *layer, QWidget *parent=nullptr)",
+ "initLayoutConfig()",
+ "initFormLayoutTree()",
+ "updateButtons()",
+ "FieldPropertiesRoles",
+ "loadRelations()",
+ "initAvailableWidgetsTree()",
+ "init()",
+ "initInitPython()",
+ ],
"QgsWkbException": ["QgsWkbException(QString const &what)"],
- "QgsVectorFileWriter": ["driverMetadata(const QString &driverName, MetaData &driverMetadata)", "OptionType", "WriterError"],
+ "QgsVectorFileWriter": [
+ "driverMetadata(const QString &driverName, MetaData &driverMetadata)",
+ "OptionType",
+ "WriterError",
+ ],
"QgsBlurWidget": ["QgsBlurWidget(QWidget *parent=nullptr)", "create()"],
- "QgsDataItem": ["icon()", "setIconName(const QString &iconName)", "populate(bool foreground=false)", "deleteLater(QVector< QgsDataItem * > &items)", "children() const", "hasChildren()", "beginInsertItems(QgsDataItem *parent, int first, int last)", "rowCount()", "dataChanged(QgsDataItem *item)", "type() const", "beginRemoveItems(QgsDataItem *parent, int first, int last)", "endRemoveItems()", "path() const", "endInsertItems()", "refresh()", "setIcon(const QIcon &icon)", "findItem(QVector< QgsDataItem * > items, QgsDataItem *item)", "childrenCreated()", "setPath(const QString &path)", "setToolTip(const QString &msg)", "state() const", "populate(const QVector< QgsDataItem * > &children)", "toolTip() const"],
+ "QgsDataItem": [
+ "icon()",
+ "setIconName(const QString &iconName)",
+ "populate(bool foreground=false)",
+ "deleteLater(QVector< QgsDataItem * > &items)",
+ "children() const",
+ "hasChildren()",
+ "beginInsertItems(QgsDataItem *parent, int first, int last)",
+ "rowCount()",
+ "dataChanged(QgsDataItem *item)",
+ "type() const",
+ "beginRemoveItems(QgsDataItem *parent, int first, int last)",
+ "endRemoveItems()",
+ "path() const",
+ "endInsertItems()",
+ "refresh()",
+ "setIcon(const QIcon &icon)",
+ "findItem(QVector< QgsDataItem * > items, QgsDataItem *item)",
+ "childrenCreated()",
+ "setPath(const QString &path)",
+ "setToolTip(const QString &msg)",
+ "state() const",
+ "populate(const QVector< QgsDataItem * > &children)",
+ "toolTip() const",
+ ],
"QgsMapCanvas": ["setCurrentLayer(QgsMapLayer *layer)"],
- "QgsLayerTreeViewDefaultActions": ["actionRenameGroupOrLayer(QObject *parent=nullptr)", "actionShowInOverview(QObject *parent=nullptr)", "addGroup()", "showInOverview()", "QgsLayerTreeViewDefaultActions(QgsLayerTreeView *view)", "actionShowFeatureCount(QObject *parent=nullptr)", "uniqueGroupName(QgsLayerTreeGroup *parentGroup)", "actionGroupSelected(QObject *parent=nullptr)", "groupSelected()", "removeGroupOrLayer()", "zoomToGroup(QgsMapCanvas *canvas)", "renameGroupOrLayer()", "showFeatureCount()", "zoomToGroup()", "actionAddGroup(QObject *parent=nullptr)", "actionZoomToGroup(QgsMapCanvas *canvas, QObject *parent=nullptr)", "actionRemoveGroupOrLayer(QObject *parent=nullptr)", "zoomToLayers(QgsMapCanvas *canvas, const QList< QgsMapLayer * > &layers)"],
- "QgsGeometryPointInPolygonCheck": ["factoryDescription()", "factoryIsCompatible(QgsVectorLayer *layer)", "ResolutionMethod", "factoryCompatibleGeometryTypes()", "factoryCheckType()", "QgsGeometryPointInPolygonCheck(QgsGeometryCheckContext *context, const QVariantMap &configuration)", "factoryId()"],
+ "QgsLayerTreeViewDefaultActions": [
+ "actionRenameGroupOrLayer(QObject *parent=nullptr)",
+ "actionShowInOverview(QObject *parent=nullptr)",
+ "addGroup()",
+ "showInOverview()",
+ "QgsLayerTreeViewDefaultActions(QgsLayerTreeView *view)",
+ "actionShowFeatureCount(QObject *parent=nullptr)",
+ "uniqueGroupName(QgsLayerTreeGroup *parentGroup)",
+ "actionGroupSelected(QObject *parent=nullptr)",
+ "groupSelected()",
+ "removeGroupOrLayer()",
+ "zoomToGroup(QgsMapCanvas *canvas)",
+ "renameGroupOrLayer()",
+ "showFeatureCount()",
+ "zoomToGroup()",
+ "actionAddGroup(QObject *parent=nullptr)",
+ "actionZoomToGroup(QgsMapCanvas *canvas, QObject *parent=nullptr)",
+ "actionRemoveGroupOrLayer(QObject *parent=nullptr)",
+ "zoomToLayers(QgsMapCanvas *canvas, const QList< QgsMapLayer * > &layers)",
+ ],
+ "QgsGeometryPointInPolygonCheck": [
+ "factoryDescription()",
+ "factoryIsCompatible(QgsVectorLayer *layer)",
+ "ResolutionMethod",
+ "factoryCompatibleGeometryTypes()",
+ "factoryCheckType()",
+ "QgsGeometryPointInPolygonCheck(QgsGeometryCheckContext *context, const QVariantMap &configuration)",
+ "factoryId()",
+ ],
"QgsMeshRendererMeshSettingsWidget": ["MeshType"],
- "QgsDummyConfigDlg": ["QgsDummyConfigDlg(QgsVectorLayer *vl, int fieldIdx, QWidget *parent, const QString &description)"],
- "QgsRasterLayerSaveAsDialog": ["mode() const", "xResolution() const", "tileMode() const", "yResolution() const", "noData() const", "outputCrs()", "pyramidsConfigOptions() const", "nColumns() const", "hideFormat()", "ResolutionState", "pyramidsResamplingMethod() const", "nRows() const", "outputFormat() const", "Mode", "hideOutput()", "outputRectangle() const", "maximumTileSizeX() const", "maximumTileSizeY() const", "outputFileName() const", "createOptions() const", "CrsState", "pyramidsList() const"],
- "QgsSlider": ["setMaximum(const QVariant &max)", "setSingleStep(const QVariant &step)", "setValue(const QVariant &value)", "variantValue() const", "valueChanged(const QVariant &)", "setMinimum(const QVariant &min)"],
+ "QgsDummyConfigDlg": [
+ "QgsDummyConfigDlg(QgsVectorLayer *vl, int fieldIdx, QWidget *parent, const QString &description)"
+ ],
+ "QgsRasterLayerSaveAsDialog": [
+ "mode() const",
+ "xResolution() const",
+ "tileMode() const",
+ "yResolution() const",
+ "noData() const",
+ "outputCrs()",
+ "pyramidsConfigOptions() const",
+ "nColumns() const",
+ "hideFormat()",
+ "ResolutionState",
+ "pyramidsResamplingMethod() const",
+ "nRows() const",
+ "outputFormat() const",
+ "Mode",
+ "hideOutput()",
+ "outputRectangle() const",
+ "maximumTileSizeX() const",
+ "maximumTileSizeY() const",
+ "outputFileName() const",
+ "createOptions() const",
+ "CrsState",
+ "pyramidsList() const",
+ ],
+ "QgsSlider": [
+ "setMaximum(const QVariant &max)",
+ "setSingleStep(const QVariant &step)",
+ "setValue(const QVariant &value)",
+ "variantValue() const",
+ "valueChanged(const QVariant &)",
+ "setMinimum(const QVariant &min)",
+ ],
"QgsSearchQueryBuilder": ["loadQuery()", "saveQuery()"],
- "QgsGpsdConnection": ["QgsGpsdConnection(const QString &host, qint16 port, const QString &device)"],
- "QgsSpatialIndexCopyVisitor": ["QgsSpatialIndexCopyVisitor(SpatialIndex::ISpatialIndex *newIndex)"],
- "pal::PointSet": ["getCentroid(double &px, double &py, bool forceInside=false) const", "PointSet(double x, double y)", "invalidateGeos() const", "getGeosType() const", "PointSet(int nbPoints, double *x, double *y)", "getNumPoints() const", "deleteCoords()", "preparedGeom() const", "PointSet(const PointSet &ps)", "createGeosGeom() const"],
- "QgsSimpleFillSymbolLayer": ["createFromSld(QDomElement &element)", "setBrushStyle(Qt::BrushStyle style)", "setStrokeWidth(double strokeWidth)", "strokeWidth() const", "brushStyle() const", "strokeWidthMapUnitScale() const", "strokeStyle() const", "setPenJoinStyle(Qt::PenJoinStyle style)", "QgsSimpleFillSymbolLayer(const QColor &color=DEFAULT_SIMPLEFILL_COLOR, Qt::BrushStyle style=DEFAULT_SIMPLEFILL_STYLE, const QColor &strokeColor=DEFAULT_SIMPLEFILL_BORDERCOLOR, Qt::PenStyle strokeStyle=DEFAULT_SIMPLEFILL_BORDERSTYLE, double strokeWidth=DEFAULT_SIMPLEFILL_BORDERWIDTH, Qt::PenJoinStyle penJoinStyle=DEFAULT_SIMPLEFILL_JOINSTYLE)", "setStrokeWidthMapUnitScale(const QgsMapUnitScale &scale)", "penJoinStyle() const", "setStrokeStyle(Qt::PenStyle strokeStyle)"],
- "QgsSingleCategoryDiagramRenderer": ["setDiagramSettings(const QgsDiagramSettings &s)"],
+ "QgsGpsdConnection": [
+ "QgsGpsdConnection(const QString &host, qint16 port, const QString &device)"
+ ],
+ "QgsSpatialIndexCopyVisitor": [
+ "QgsSpatialIndexCopyVisitor(SpatialIndex::ISpatialIndex *newIndex)"
+ ],
+ "pal::PointSet": [
+ "getCentroid(double &px, double &py, bool forceInside=false) const",
+ "PointSet(double x, double y)",
+ "invalidateGeos() const",
+ "getGeosType() const",
+ "PointSet(int nbPoints, double *x, double *y)",
+ "getNumPoints() const",
+ "deleteCoords()",
+ "preparedGeom() const",
+ "PointSet(const PointSet &ps)",
+ "createGeosGeom() const",
+ ],
+ "QgsSimpleFillSymbolLayer": [
+ "createFromSld(QDomElement &element)",
+ "setBrushStyle(Qt::BrushStyle style)",
+ "setStrokeWidth(double strokeWidth)",
+ "strokeWidth() const",
+ "brushStyle() const",
+ "strokeWidthMapUnitScale() const",
+ "strokeStyle() const",
+ "setPenJoinStyle(Qt::PenJoinStyle style)",
+ "QgsSimpleFillSymbolLayer(const QColor &color=DEFAULT_SIMPLEFILL_COLOR, Qt::BrushStyle style=DEFAULT_SIMPLEFILL_STYLE, const QColor &strokeColor=DEFAULT_SIMPLEFILL_BORDERCOLOR, Qt::PenStyle strokeStyle=DEFAULT_SIMPLEFILL_BORDERSTYLE, double strokeWidth=DEFAULT_SIMPLEFILL_BORDERWIDTH, Qt::PenJoinStyle penJoinStyle=DEFAULT_SIMPLEFILL_JOINSTYLE)",
+ "setStrokeWidthMapUnitScale(const QgsMapUnitScale &scale)",
+ "penJoinStyle() const",
+ "setStrokeStyle(Qt::PenStyle strokeStyle)",
+ ],
+ "QgsSingleCategoryDiagramRenderer": [
+ "setDiagramSettings(const QgsDiagramSettings &s)"
+ ],
"QgsStackedDiagramRenderer": ["setDiagramSettings(const QgsDiagramSettings &s)"],
- "QgsPointDisplacementRendererWidget": ["QgsPointDisplacementRendererWidget(QgsVectorLayer *layer, QgsStyle *style, QgsFeatureRenderer *renderer)", "create(QgsVectorLayer *layer, QgsStyle *style, QgsFeatureRenderer *renderer)"],
- "QgsSingleBandGrayRendererWidget": ["create(QgsRasterLayer *layer, const QgsRectangle &extent)", "QgsSingleBandGrayRendererWidget(QgsRasterLayer *layer, const QgsRectangle &extent=QgsRectangle())"],
- "QgsLayerTreeModel": ["nodeWillRemoveChildren(QgsLayerTreeNode *node, int indexFrom, int indexTo)", "disconnectFromLayers(QgsLayerTreeGroup *parentGroup)", "connectToLayers(QgsLayerTreeGroup *parentGroup)", "nodeLayerWillBeUnloaded()", "legendInvalidateMapBasedData()", "nodeCustomPropertyChanged(QgsLayerTreeNode *node, const QString &key)", "legendNodeData(QgsLayerTreeModelLegendNode *node, int role) const", "legendCleanup()", "Flag", "iconGroup()", "disconnectFromRootNode()", "layerNeedsUpdate()", "addLegendToLayer(QgsLayerTreeLayer *nodeL)", "nodeVisibilityChanged(QgsLayerTreeNode *node)", "layerLegendChanged()", "legendRootRowCount(QgsLayerTreeLayer *nL) const", "removeLegendFromLayer(QgsLayerTreeLayer *nodeLayer)", "legendNodeRowCount(QgsLayerTreeModelLegendNode *node) const", "legendNodeDataChanged()", "connectToRootNode()", "legendNodeFlags(QgsLayerTreeModelLegendNode *node) const", "indexOfParentLayerTreeNode(QgsLayerTreeNode *parentNode) const", "nodeLayerLoaded()", "nodeWillAddChildren(QgsLayerTreeNode *node, int indexFrom, int indexTo)", "nodeRemovedChildren()", "legendRootIndex(int row, int column, QgsLayerTreeLayer *nL) const", "connectToLayer(QgsLayerTreeLayer *nodeLayer)", "legendIconEmbeddedInParent(QgsLayerTreeLayer *nodeLayer) const", "nodeAddedChildren(QgsLayerTreeNode *node, int indexFrom, int indexTo)", "legendNodeIndex(int row, int column, QgsLayerTreeModelLegendNode *node) const", "invalidateLegendMapBasedData()", "disconnectFromLayer(QgsLayerTreeLayer *nodeLayer)", "legendEmbeddedInParent(QgsLayerTreeLayer *nodeLayer) const", "legendParent(QgsLayerTreeModelLegendNode *legendNode) const"],
- "QgsEditorWidgetRegistry": ["createSearchWidget(const QString &widgetId, QgsVectorLayer *vl, int fieldIdx, const QVariantMap &config, QWidget *parent, const QgsAttributeEditorContext &context=QgsAttributeEditorContext())"],
- "QgsGeometryCheckerUtils": ["lineIntersections(const QgsLineString *line1, const QgsLineString *line2, double tol)", "polygonRings(const QgsPolygon *polygon)", "getGeomPart(const QgsAbstractGeometry *geom, int partIdx)", "canDeleteVertex(const QgsAbstractGeometry *geom, int iPart, int iRing)", "sharedEdgeLength(const QgsAbstractGeometry *geom1, const QgsAbstractGeometry *geom2, double tol)", "createGeomEngine(const QgsAbstractGeometry *geometry, double tolerance)", "pointOnLine(const QgsPoint &p, const QgsLineString *line, double tol, bool excludeExtremities=false)", "getGeomPart(QgsAbstractGeometry *geom, int partIdx)", "filter1DTypes(QgsAbstractGeometry *geom)"],
- "QgsLayerTreeLayer": ["QgsLayerTreeLayer(const QgsLayerTreeLayer &other)", "QgsLayerTreeLayer(QgsMapLayer *layer)", "attachToLayer()"],
- "QgsMasterPasswordResetDialog": ["requestMasterPasswordReset(QString *newpass, QString *oldpass, bool *keepbackup)", "QgsMasterPasswordResetDialog(QWidget *parent=nullptr)"],
+ "QgsPointDisplacementRendererWidget": [
+ "QgsPointDisplacementRendererWidget(QgsVectorLayer *layer, QgsStyle *style, QgsFeatureRenderer *renderer)",
+ "create(QgsVectorLayer *layer, QgsStyle *style, QgsFeatureRenderer *renderer)",
+ ],
+ "QgsSingleBandGrayRendererWidget": [
+ "create(QgsRasterLayer *layer, const QgsRectangle &extent)",
+ "QgsSingleBandGrayRendererWidget(QgsRasterLayer *layer, const QgsRectangle &extent=QgsRectangle())",
+ ],
+ "QgsLayerTreeModel": [
+ "nodeWillRemoveChildren(QgsLayerTreeNode *node, int indexFrom, int indexTo)",
+ "disconnectFromLayers(QgsLayerTreeGroup *parentGroup)",
+ "connectToLayers(QgsLayerTreeGroup *parentGroup)",
+ "nodeLayerWillBeUnloaded()",
+ "legendInvalidateMapBasedData()",
+ "nodeCustomPropertyChanged(QgsLayerTreeNode *node, const QString &key)",
+ "legendNodeData(QgsLayerTreeModelLegendNode *node, int role) const",
+ "legendCleanup()",
+ "Flag",
+ "iconGroup()",
+ "disconnectFromRootNode()",
+ "layerNeedsUpdate()",
+ "addLegendToLayer(QgsLayerTreeLayer *nodeL)",
+ "nodeVisibilityChanged(QgsLayerTreeNode *node)",
+ "layerLegendChanged()",
+ "legendRootRowCount(QgsLayerTreeLayer *nL) const",
+ "removeLegendFromLayer(QgsLayerTreeLayer *nodeLayer)",
+ "legendNodeRowCount(QgsLayerTreeModelLegendNode *node) const",
+ "legendNodeDataChanged()",
+ "connectToRootNode()",
+ "legendNodeFlags(QgsLayerTreeModelLegendNode *node) const",
+ "indexOfParentLayerTreeNode(QgsLayerTreeNode *parentNode) const",
+ "nodeLayerLoaded()",
+ "nodeWillAddChildren(QgsLayerTreeNode *node, int indexFrom, int indexTo)",
+ "nodeRemovedChildren()",
+ "legendRootIndex(int row, int column, QgsLayerTreeLayer *nL) const",
+ "connectToLayer(QgsLayerTreeLayer *nodeLayer)",
+ "legendIconEmbeddedInParent(QgsLayerTreeLayer *nodeLayer) const",
+ "nodeAddedChildren(QgsLayerTreeNode *node, int indexFrom, int indexTo)",
+ "legendNodeIndex(int row, int column, QgsLayerTreeModelLegendNode *node) const",
+ "invalidateLegendMapBasedData()",
+ "disconnectFromLayer(QgsLayerTreeLayer *nodeLayer)",
+ "legendEmbeddedInParent(QgsLayerTreeLayer *nodeLayer) const",
+ "legendParent(QgsLayerTreeModelLegendNode *legendNode) const",
+ ],
+ "QgsEditorWidgetRegistry": [
+ "createSearchWidget(const QString &widgetId, QgsVectorLayer *vl, int fieldIdx, const QVariantMap &config, QWidget *parent, const QgsAttributeEditorContext &context=QgsAttributeEditorContext())"
+ ],
+ "QgsGeometryCheckerUtils": [
+ "lineIntersections(const QgsLineString *line1, const QgsLineString *line2, double tol)",
+ "polygonRings(const QgsPolygon *polygon)",
+ "getGeomPart(const QgsAbstractGeometry *geom, int partIdx)",
+ "canDeleteVertex(const QgsAbstractGeometry *geom, int iPart, int iRing)",
+ "sharedEdgeLength(const QgsAbstractGeometry *geom1, const QgsAbstractGeometry *geom2, double tol)",
+ "createGeomEngine(const QgsAbstractGeometry *geometry, double tolerance)",
+ "pointOnLine(const QgsPoint &p, const QgsLineString *line, double tol, bool excludeExtremities=false)",
+ "getGeomPart(QgsAbstractGeometry *geom, int partIdx)",
+ "filter1DTypes(QgsAbstractGeometry *geom)",
+ ],
+ "QgsLayerTreeLayer": [
+ "QgsLayerTreeLayer(const QgsLayerTreeLayer &other)",
+ "QgsLayerTreeLayer(QgsMapLayer *layer)",
+ "attachToLayer()",
+ ],
+ "QgsMasterPasswordResetDialog": [
+ "requestMasterPasswordReset(QString *newpass, QString *oldpass, bool *keepbackup)",
+ "QgsMasterPasswordResetDialog(QWidget *parent=nullptr)",
+ ],
"pal::FeaturePart": ["FeaturePart(const FeaturePart &other)"],
- "QgsEffectDrawModeComboBox": ["QgsEffectDrawModeComboBox(QWidget *parent SIP_TRANSFERTHIS=nullptr)"],
- "QgsSingleBandColorDataRenderer": ["create(const QDomElement &elem, QgsRasterInterface *input)", "QgsSingleBandColorDataRenderer(QgsRasterInterface *input, int band)"],
- "QgsLayerTreeMapCanvasBridge": ["mapCanvas() const", "rootGroup() const", "autoSetupOnFirstLayer() const"],
- "QgsGeometrySegmentLengthCheck": ["QgsGeometrySegmentLengthCheck(QgsGeometryCheckContext *context, const QVariantMap &configuration)", "factoryDescription()", "ResolutionMethod", "factoryCompatibleGeometryTypes()", "factoryCheckType()", "factoryIsCompatible(QgsVectorLayer *layer)", "factoryId()"],
+ "QgsEffectDrawModeComboBox": [
+ "QgsEffectDrawModeComboBox(QWidget *parent SIP_TRANSFERTHIS=nullptr)"
+ ],
+ "QgsSingleBandColorDataRenderer": [
+ "create(const QDomElement &elem, QgsRasterInterface *input)",
+ "QgsSingleBandColorDataRenderer(QgsRasterInterface *input, int band)",
+ ],
+ "QgsLayerTreeMapCanvasBridge": [
+ "mapCanvas() const",
+ "rootGroup() const",
+ "autoSetupOnFirstLayer() const",
+ ],
+ "QgsGeometrySegmentLengthCheck": [
+ "QgsGeometrySegmentLengthCheck(QgsGeometryCheckContext *context, const QVariantMap &configuration)",
+ "factoryDescription()",
+ "ResolutionMethod",
+ "factoryCompatibleGeometryTypes()",
+ "factoryCheckType()",
+ "factoryIsCompatible(QgsVectorLayer *layer)",
+ "factoryId()",
+ ],
"QgsAttributeDialog": ["attributeForm()", "feature()"],
"QgsDiagramSettings": ["LabelPlacementMethod"],
"QgsPalLayerSettings": ["QgsPalLayerSettings(const QgsPalLayerSettings &s)"],
- "ParametricLine": ["calcSecDer(float t, Vector3D *v)=0", "setParent(ParametricLine *paral)=0", "add(ParametricLine *pl)=0", "calcFirstDer(float t, Vector3D *v)=0", "getParent() const =0", "getControlPoly() const =0", "calcPoint(float t, QgsPoint *p)=0", "getDegree() const =0", "setControlPoly(QVector< QgsPoint * > *cp)=0", "changeDirection()=0", "remove(int i)=0", "getControlPoint(int number) const =0"],
- "QgsPalettedRasterRenderer": ["create(const QDomElement &elem, QgsRasterInterface *input)"],
+ "ParametricLine": [
+ "calcSecDer(float t, Vector3D *v)=0",
+ "setParent(ParametricLine *paral)=0",
+ "add(ParametricLine *pl)=0",
+ "calcFirstDer(float t, Vector3D *v)=0",
+ "getParent() const =0",
+ "getControlPoly() const =0",
+ "calcPoint(float t, QgsPoint *p)=0",
+ "getDegree() const =0",
+ "setControlPoly(QVector< QgsPoint * > *cp)=0",
+ "changeDirection()=0",
+ "remove(int i)=0",
+ "getControlPoint(int number) const =0",
+ ],
+ "QgsPalettedRasterRenderer": [
+ "create(const QDomElement &elem, QgsRasterInterface *input)"
+ ],
"QgsDataCollectionItem": ["addChild(QgsDataItem *item)"],
- "QgsMapLayerModel": ["addLayers(const QList< QgsMapLayer * > &layers)", "removeLayers(const QStringList &layerIds)"],
- "QgsLinePatternFillSymbolLayer": ["ogrFeatureStyleWidth(double widthScaleFactor) const"],
- "QgsMeshAvailableDatasetGroupTreeModel": ["QgsMeshAvailableDatasetGroupTreeModel(QObject *parent=nullptr)"],
- "QgsSymbolLayerUtils": ["drawStippledBackground(QPainter *painter, QRect rect)", "createLineLayerFromSld(QDomElement &element)", "createDisplacementElement(QDomDocument &doc, QDomElement &element, QPointF offset)", "decodeMapUnitScale(const QString &str)", "createFillLayerFromSld(QDomElement &element)", "decodeBlendMode(const QString &s)", "decodePenJoinStyle(const QString &str)", "encodeSldAlpha(int alpha)", "encodeSldFontWeight(int weight)", "fillToSld(QDomDocument &doc, QDomElement &element, Qt::BrushStyle brushStyle, const QColor &color=QColor())", "createOnlineResourceElement(QDomDocument &doc, QDomElement &element, const QString &path, const QString &format)", "geometryFromSldElement(QDomElement &element, QString &geomFunc)", "needLinePatternFill(QDomElement &element)", "needSvgFill(QDomElement &element)", "hasWellKnownMark(QDomElement &element)", "decodePenStyle(const QString &str)", "clearSymbolMap(QgsSymbolMap &symbols)", "fillFromSld(QDomElement &element, Qt::BrushStyle &brushStyle, QColor &color)", "decodeSldFontWeight(const QString &str)", "needPointPatternFill(QDomElement &element)", "decodeSldFontStyle(const QString &str)", "encodeSldFontStyle(QFont::Style style)", "externalMarkerFromSld(QDomElement &element, QString &path, QString &format, int &markIndex, QColor &color, double &size)", "getVendorOptionList(QDomElement &element)", "needSvgMarker(QDomElement &element)", "lineFromSld(QDomElement &element, Qt::PenStyle &penStyle, QColor &color, double &width, Qt::PenJoinStyle *penJoinStyle=nullptr, Qt::PenCapStyle *penCapStyle=nullptr, QVector< qreal > *customDashPattern=nullptr, double *dashOffset=nullptr)", "decodeSldAlpha(const QString &str)", "needFontMarker(QDomElement &element)", "decodeSldLineCapStyle(const QString &str)", "encodePenCapStyle(Qt::PenCapStyle style)", "decodeBrushStyle(const QString &str)", "onlineResourceFromSldElement(QDomElement &element, QString &path, QString &format)", "createFunctionElement(QDomDocument &doc, QDomElement &element, const QString &function)", "createMarkerLayerFromSld(QDomElement &element)", "encodeSldBrushStyle(Qt::BrushStyle style)", "encodeSldLineJoinStyle(Qt::PenJoinStyle style)", "externalGraphicToSld(QDomDocument &doc, QDomElement &element, const QString &path, const QString &mime, const QColor &color, double size=-1)", "encodeRealVector(const QVector< qreal > &v)", "encodeBrushStyle(Qt::BrushStyle style)", "encodeMapUnitScale(const QgsMapUnitScale &mapUnitScale)", "encodePenStyle(Qt::PenStyle style)", "decodePenCapStyle(const QString &str)", "opacityFromSldElement(QDomElement &element, QString &alphaFunc)", "rotationFromSldElement(QDomElement &element, QString &rotationFunc)", "wellKnownMarkerToSld(QDomDocument &doc, QDomElement &element, const QString &name, const QColor &color, const QColor &strokeColor, Qt::PenStyle strokeStyle, double strokeWidth=-1, double size=-1)", "needMarkerLine(QDomElement &element)", "createOpacityElement(QDomDocument &doc, QDomElement &element, const QString &alphaFunc)", "decodeSldLineJoinStyle(const QString &str)", "decodeSldRealVector(const QString &s)", "encodeColor(const QColor &color)", "displacementFromSldElement(QDomElement &element, QPointF &offset)", "encodePenJoinStyle(Qt::PenJoinStyle style)", "decodeSldBrushStyle(const QString &str)", "externalGraphicFromSld(QDomElement &element, QString &path, QString &mime, QColor &color, double &size)", "encodeSldRealVector(const QVector< qreal > &v)", "externalMarkerToSld(QDomDocument &doc, QDomElement &element, const QString &path, const QString &format, int *markIndex=nullptr, const QColor &color=QColor(), double size=-1)", "createRotationElement(QDomDocument &doc, QDomElement &element, const QString &rotationFunc)", "createGeometryElement(QDomDocument &doc, QDomElement &element, const QString &geomFunc)", "labelTextToSld(QDomDocument &doc, QDomElement &element, const QString &label, const QFont &font, const QColor &color=QColor(), double size=-1)", "decodeRealVector(const QString &s)", "functionFromSldElement(QDomElement &element, QString &function)", "getSvgParameterList(QDomElement &element)", "encodeSldLineCapStyle(Qt::PenCapStyle style)", "decodeColor(const QString &str)", "createSvgParameterElement(QDomDocument &doc, const QString &name, const QString &value)", "needEllipseMarker(QDomElement &element)", "createVendorOptionElement(QDomDocument &doc, const QString &name, const QString &value)"],
- "QgsMapRendererQImageJob": ["QgsMapRendererQImageJob(const QgsMapSettings &settings)"],
- "QgsSvgSelectorWidget": ["currentSvgPath() const", "svgSelected(const QString &path)", "populateList()"],
- "QgsMeshDatasetGroupListModel": ["QgsMeshDatasetGroupListModel(QObject *parent)", "variableNames() const", "setDisplayProviderName(bool displayProviderName)"],
- "QgsSmartGroupEditorDialog": ["QgsSmartGroupEditorDialog(QgsStyle *style, QWidget *parent=nullptr)"],
- "QgsSvgMarkerSymbolLayer": ["createFromSld(QDomElement &element)", "strokeWidth() const", "setStrokeWidth(double w)", "setStrokeWidthMapUnitScale(const QgsMapUnitScale &scale)", "strokeWidthMapUnitScale() const"],
- "QgsLUDialog": ["lowerValue() const", "QgsLUDialog(QWidget *parent=nullptr, Qt::WindowFlags fl=QgsGuiUtils::ModalDialogFlags)", "setLowerValue(const QString &val)", "setUpperValue(const QString &val)", "upperValue() const"],
- "QgsMapRendererCustomPainterJob": ["QgsMapRendererCustomPainterJob(const QgsMapSettings &settings, QPainter *painter)"],
- "QgsFeatureRenderer": ["type() const", "QgsFeatureRenderer(const QString &type)", "setUsingSymbolLevels(bool usingSymbolLevels)", "usingSymbolLevels() const"],
+ "QgsMapLayerModel": [
+ "addLayers(const QList< QgsMapLayer * > &layers)",
+ "removeLayers(const QStringList &layerIds)",
+ ],
+ "QgsLinePatternFillSymbolLayer": [
+ "ogrFeatureStyleWidth(double widthScaleFactor) const"
+ ],
+ "QgsMeshAvailableDatasetGroupTreeModel": [
+ "QgsMeshAvailableDatasetGroupTreeModel(QObject *parent=nullptr)"
+ ],
+ "QgsSymbolLayerUtils": [
+ "drawStippledBackground(QPainter *painter, QRect rect)",
+ "createLineLayerFromSld(QDomElement &element)",
+ "createDisplacementElement(QDomDocument &doc, QDomElement &element, QPointF offset)",
+ "decodeMapUnitScale(const QString &str)",
+ "createFillLayerFromSld(QDomElement &element)",
+ "decodeBlendMode(const QString &s)",
+ "decodePenJoinStyle(const QString &str)",
+ "encodeSldAlpha(int alpha)",
+ "encodeSldFontWeight(int weight)",
+ "fillToSld(QDomDocument &doc, QDomElement &element, Qt::BrushStyle brushStyle, const QColor &color=QColor())",
+ "createOnlineResourceElement(QDomDocument &doc, QDomElement &element, const QString &path, const QString &format)",
+ "geometryFromSldElement(QDomElement &element, QString &geomFunc)",
+ "needLinePatternFill(QDomElement &element)",
+ "needSvgFill(QDomElement &element)",
+ "hasWellKnownMark(QDomElement &element)",
+ "decodePenStyle(const QString &str)",
+ "clearSymbolMap(QgsSymbolMap &symbols)",
+ "fillFromSld(QDomElement &element, Qt::BrushStyle &brushStyle, QColor &color)",
+ "decodeSldFontWeight(const QString &str)",
+ "needPointPatternFill(QDomElement &element)",
+ "decodeSldFontStyle(const QString &str)",
+ "encodeSldFontStyle(QFont::Style style)",
+ "externalMarkerFromSld(QDomElement &element, QString &path, QString &format, int &markIndex, QColor &color, double &size)",
+ "getVendorOptionList(QDomElement &element)",
+ "needSvgMarker(QDomElement &element)",
+ "lineFromSld(QDomElement &element, Qt::PenStyle &penStyle, QColor &color, double &width, Qt::PenJoinStyle *penJoinStyle=nullptr, Qt::PenCapStyle *penCapStyle=nullptr, QVector< qreal > *customDashPattern=nullptr, double *dashOffset=nullptr)",
+ "decodeSldAlpha(const QString &str)",
+ "needFontMarker(QDomElement &element)",
+ "decodeSldLineCapStyle(const QString &str)",
+ "encodePenCapStyle(Qt::PenCapStyle style)",
+ "decodeBrushStyle(const QString &str)",
+ "onlineResourceFromSldElement(QDomElement &element, QString &path, QString &format)",
+ "createFunctionElement(QDomDocument &doc, QDomElement &element, const QString &function)",
+ "createMarkerLayerFromSld(QDomElement &element)",
+ "encodeSldBrushStyle(Qt::BrushStyle style)",
+ "encodeSldLineJoinStyle(Qt::PenJoinStyle style)",
+ "externalGraphicToSld(QDomDocument &doc, QDomElement &element, const QString &path, const QString &mime, const QColor &color, double size=-1)",
+ "encodeRealVector(const QVector< qreal > &v)",
+ "encodeBrushStyle(Qt::BrushStyle style)",
+ "encodeMapUnitScale(const QgsMapUnitScale &mapUnitScale)",
+ "encodePenStyle(Qt::PenStyle style)",
+ "decodePenCapStyle(const QString &str)",
+ "opacityFromSldElement(QDomElement &element, QString &alphaFunc)",
+ "rotationFromSldElement(QDomElement &element, QString &rotationFunc)",
+ "wellKnownMarkerToSld(QDomDocument &doc, QDomElement &element, const QString &name, const QColor &color, const QColor &strokeColor, Qt::PenStyle strokeStyle, double strokeWidth=-1, double size=-1)",
+ "needMarkerLine(QDomElement &element)",
+ "createOpacityElement(QDomDocument &doc, QDomElement &element, const QString &alphaFunc)",
+ "decodeSldLineJoinStyle(const QString &str)",
+ "decodeSldRealVector(const QString &s)",
+ "encodeColor(const QColor &color)",
+ "displacementFromSldElement(QDomElement &element, QPointF &offset)",
+ "encodePenJoinStyle(Qt::PenJoinStyle style)",
+ "decodeSldBrushStyle(const QString &str)",
+ "externalGraphicFromSld(QDomElement &element, QString &path, QString &mime, QColor &color, double &size)",
+ "encodeSldRealVector(const QVector< qreal > &v)",
+ "externalMarkerToSld(QDomDocument &doc, QDomElement &element, const QString &path, const QString &format, int *markIndex=nullptr, const QColor &color=QColor(), double size=-1)",
+ "createRotationElement(QDomDocument &doc, QDomElement &element, const QString &rotationFunc)",
+ "createGeometryElement(QDomDocument &doc, QDomElement &element, const QString &geomFunc)",
+ "labelTextToSld(QDomDocument &doc, QDomElement &element, const QString &label, const QFont &font, const QColor &color=QColor(), double size=-1)",
+ "decodeRealVector(const QString &s)",
+ "functionFromSldElement(QDomElement &element, QString &function)",
+ "getSvgParameterList(QDomElement &element)",
+ "encodeSldLineCapStyle(Qt::PenCapStyle style)",
+ "decodeColor(const QString &str)",
+ "createSvgParameterElement(QDomDocument &doc, const QString &name, const QString &value)",
+ "needEllipseMarker(QDomElement &element)",
+ "createVendorOptionElement(QDomDocument &doc, const QString &name, const QString &value)",
+ ],
+ "QgsMapRendererQImageJob": [
+ "QgsMapRendererQImageJob(const QgsMapSettings &settings)"
+ ],
+ "QgsSvgSelectorWidget": [
+ "currentSvgPath() const",
+ "svgSelected(const QString &path)",
+ "populateList()",
+ ],
+ "QgsMeshDatasetGroupListModel": [
+ "QgsMeshDatasetGroupListModel(QObject *parent)",
+ "variableNames() const",
+ "setDisplayProviderName(bool displayProviderName)",
+ ],
+ "QgsSmartGroupEditorDialog": [
+ "QgsSmartGroupEditorDialog(QgsStyle *style, QWidget *parent=nullptr)"
+ ],
+ "QgsSvgMarkerSymbolLayer": [
+ "createFromSld(QDomElement &element)",
+ "strokeWidth() const",
+ "setStrokeWidth(double w)",
+ "setStrokeWidthMapUnitScale(const QgsMapUnitScale &scale)",
+ "strokeWidthMapUnitScale() const",
+ ],
+ "QgsLUDialog": [
+ "lowerValue() const",
+ "QgsLUDialog(QWidget *parent=nullptr, Qt::WindowFlags fl=QgsGuiUtils::ModalDialogFlags)",
+ "setLowerValue(const QString &val)",
+ "setUpperValue(const QString &val)",
+ "upperValue() const",
+ ],
+ "QgsMapRendererCustomPainterJob": [
+ "QgsMapRendererCustomPainterJob(const QgsMapSettings &settings, QPainter *painter)"
+ ],
+ "QgsFeatureRenderer": [
+ "type() const",
+ "QgsFeatureRenderer(const QString &type)",
+ "setUsingSymbolLevels(bool usingSymbolLevels)",
+ "usingSymbolLevels() const",
+ ],
"QgsExpressionFieldBuffer": ["expressions() const"],
- "QgsValueRelationConfigDlg": ["QgsValueRelationConfigDlg(QgsVectorLayer *vl, int fieldIdx, QWidget *parent=nullptr)", "editExpression()"],
- "QgsRasterPyramidsOptionsWidget": ["checkAllLevels(bool checked)", "overviewList() const", "overviewListChanged()", "apply()", "configOptions() const", "someValueChanged()", "createOptionsWidget()", "setRasterFileName(const QString &file)", "setRasterLayer(QgsRasterLayer *rasterLayer)", "resamplingMethod() const"],
- "QgsBrowserModel": ["endInsertItems()", "itemDataChanged(QgsDataItem *item)", "updateProjectHome()", "beginRemoveItems(QgsDataItem *parent, int first, int last)", "ItemDataRole", "beginInsertItems(QgsDataItem *parent, int first, int last)", "removeRootItems()", "endRemoveItems()"],
- "QgsRasterFileWriter": ["pyramidsResampling() const", "setPyramidsResampling(const QString &str)"],
- "QgsExternalResourceWidget": ["setDocumentPath(const QVariant &documentPath)", "DocumentViewerContent"],
+ "QgsValueRelationConfigDlg": [
+ "QgsValueRelationConfigDlg(QgsVectorLayer *vl, int fieldIdx, QWidget *parent=nullptr)",
+ "editExpression()",
+ ],
+ "QgsRasterPyramidsOptionsWidget": [
+ "checkAllLevels(bool checked)",
+ "overviewList() const",
+ "overviewListChanged()",
+ "apply()",
+ "configOptions() const",
+ "someValueChanged()",
+ "createOptionsWidget()",
+ "setRasterFileName(const QString &file)",
+ "setRasterLayer(QgsRasterLayer *rasterLayer)",
+ "resamplingMethod() const",
+ ],
+ "QgsBrowserModel": [
+ "endInsertItems()",
+ "itemDataChanged(QgsDataItem *item)",
+ "updateProjectHome()",
+ "beginRemoveItems(QgsDataItem *parent, int first, int last)",
+ "ItemDataRole",
+ "beginInsertItems(QgsDataItem *parent, int first, int last)",
+ "removeRootItems()",
+ "endRemoveItems()",
+ ],
+ "QgsRasterFileWriter": [
+ "pyramidsResampling() const",
+ "setPyramidsResampling(const QString &str)",
+ ],
+ "QgsExternalResourceWidget": [
+ "setDocumentPath(const QVariant &documentPath)",
+ "DocumentViewerContent",
+ ],
"QgsStyleExportImportDialog": ["doExportImport()", "importTypeChanged(int)"],
"pal::Util": ["unmulti(const GEOSGeometry *the_geom)"],
- "QgsProjectFileTransform": ["updateRevision(const QgsProjectVersion &version)", "convertRasterProperties(QDomDocument &doc, QDomNode &parentNode, QDomElement &rasterPropertiesElem, QgsRasterLayer *rlayer)"],
- "QgsGeometryDegeneratePolygonCheck": ["factoryDescription()", "QgsGeometryDegeneratePolygonCheck(QgsGeometryCheckContext *context, const QVariantMap &configuration)", "ResolutionMethod", "factoryCompatibleGeometryTypes()", "factoryCheckType()", "factoryIsCompatible(QgsVectorLayer *layer)", "factoryId()"],
- "QgsRelief": ["setZFactor(double factor)", "setReliefColors(const QList< QgsRelief::ReliefColor > &c)", "QgsRelief(const QString &inputFile, const QString &outputFile, const QString &outputFormat)", "addReliefColorClass(const QgsRelief::ReliefColor &color)", "reliefColors() const", "clearReliefColors()", "zFactor() const"],
- "QgsValueMapConfigDlg": ["QgsValueMapConfigDlg(QgsVectorLayer *vl, int fieldIdx, QWidget *parent)"],
+ "QgsProjectFileTransform": [
+ "updateRevision(const QgsProjectVersion &version)",
+ "convertRasterProperties(QDomDocument &doc, QDomNode &parentNode, QDomElement &rasterPropertiesElem, QgsRasterLayer *rlayer)",
+ ],
+ "QgsGeometryDegeneratePolygonCheck": [
+ "factoryDescription()",
+ "QgsGeometryDegeneratePolygonCheck(QgsGeometryCheckContext *context, const QVariantMap &configuration)",
+ "ResolutionMethod",
+ "factoryCompatibleGeometryTypes()",
+ "factoryCheckType()",
+ "factoryIsCompatible(QgsVectorLayer *layer)",
+ "factoryId()",
+ ],
+ "QgsRelief": [
+ "setZFactor(double factor)",
+ "setReliefColors(const QList< QgsRelief::ReliefColor > &c)",
+ "QgsRelief(const QString &inputFile, const QString &outputFile, const QString &outputFormat)",
+ "addReliefColorClass(const QgsRelief::ReliefColor &color)",
+ "reliefColors() const",
+ "clearReliefColors()",
+ "zFactor() const",
+ ],
+ "QgsValueMapConfigDlg": [
+ "QgsValueMapConfigDlg(QgsVectorLayer *vl, int fieldIdx, QWidget *parent)"
+ ],
"QgsSnappingUtils": ["mapSettings() const", "IndexingStrategy"],
- "QgsVectorFileWriter::BoolOption": ["BoolOption(const QString &docString, bool defaultValue)"],
- "QgsNewNameDialog": ["nameChanged()", "fullNames(const QString &name, const QStringList &extensions)", "matching(const QStringList &newNames, const QStringList &existingNames, Qt::CaseSensitivity cs=Qt::CaseSensitive)", "highlightText(const QString &text)"],
- "QgsMeshActiveDatasetGroupTreeView": ["QgsMeshActiveDatasetGroupTreeView(QWidget *parent=nullptr)"],
- "pal::PriorityQueue": ["print()", "decreaseKey(int key)", "getSize() const", "remove(int key)", "downheap(int id)", "getSizeByPos() const", "getId(int key) const", "isIn(int key) const", "setPriority(int key, double new_p)", "upheap(int key)", "getBest()", "insert(int key, double p)", "sort()"],
+ "QgsVectorFileWriter::BoolOption": [
+ "BoolOption(const QString &docString, bool defaultValue)"
+ ],
+ "QgsNewNameDialog": [
+ "nameChanged()",
+ "fullNames(const QString &name, const QStringList &extensions)",
+ "matching(const QStringList &newNames, const QStringList &existingNames, Qt::CaseSensitivity cs=Qt::CaseSensitive)",
+ "highlightText(const QString &text)",
+ ],
+ "QgsMeshActiveDatasetGroupTreeView": [
+ "QgsMeshActiveDatasetGroupTreeView(QWidget *parent=nullptr)"
+ ],
+ "pal::PriorityQueue": [
+ "print()",
+ "decreaseKey(int key)",
+ "getSize() const",
+ "remove(int key)",
+ "downheap(int id)",
+ "getSizeByPos() const",
+ "getId(int key) const",
+ "isIn(int key) const",
+ "setPriority(int key, double new_p)",
+ "upheap(int key)",
+ "getBest()",
+ "insert(int key, double p)",
+ "sort()",
+ ],
"QgsSvgSelectorGroupsModel": ["QgsSvgSelectorGroupsModel(QObject *parent)"],
"QgsEncodingFileDialog": ["pbnCancelAll_clicked()", "saveUsedEncoding()"],
"QgsDefaultRasterLayerLegend": ["QgsDefaultRasterLayerLegend(QgsRasterLayer *rl)"],
- "QgsDetailedItemDelegate": ["verticalSpacing() const", "horizontalSpacing() const", "setVerticalSpacing(int value)", "setHorizontalSpacing(int value)"],
- "QgsStyleGroupSelectionDialog": ["QgsStyleGroupSelectionDialog(QgsStyle *style, QWidget *parent=nullptr)"],
+ "QgsDetailedItemDelegate": [
+ "verticalSpacing() const",
+ "horizontalSpacing() const",
+ "setVerticalSpacing(int value)",
+ "setHorizontalSpacing(int value)",
+ ],
+ "QgsStyleGroupSelectionDialog": [
+ "QgsStyleGroupSelectionDialog(QgsStyle *style, QWidget *parent=nullptr)"
+ ],
"QgsFeatureModel": ["fidToIndex(QgsFeatureId fid)=0"],
- "QgsMimeDataUtils": ["decodeUriList(const QMimeData *data)", "isUriList(const QMimeData *data)"],
+ "QgsMimeDataUtils": [
+ "decodeUriList(const QMimeData *data)",
+ "isUriList(const QMimeData *data)",
+ ],
"QgsVectorFileWriter::HiddenOption": ["HiddenOption(const QString &value)"],
- "QgsAttributeTableDelegate": ["setFeatureSelectionModel(QgsFeatureSelectionModel *featureSelectionModel)"],
- "QgisInterface": ["actionAddPgLayer()=0", "actionShowPythonDialog()=0", "actionSaveAllEdits()=0", "actionPluginListSeparator()=0", "actionAddRasterLayer()=0", "actionCancelAllEdits()=0", "actionOpenFieldCalculator()=0", "pluginManagerInterface()=0", "actionHideSelectedLayers()=0", "actionShowAllLayers()=0", "actionLayerProperties()=0", "actionLayerSaveAs()=0", "actionAddToOverview()=0", "actionAddOgrLayer()=0", "actionOptions()=0", "actionAddAllToOverview()=0", "layerTreeView()=0", "actionDuplicateLayer()=0", "actionRollbackEdits()=0", "actionCheckQgisVersion()=0", "actionAddWmsLayer()=0", "actionCustomProjection()=0", "actionQgisHomePage()=0", "actionPasteLayerStyle()=0", "actionShowSelectedLayers()=0", "actionNewVectorLayer()=0", "actionRollbackAllEdits()=0", "actionManagePlugins()=0", "actionCopyLayerStyle()=0", "actionToggleEditing()=0", "actionSaveActiveLayerEdits()=0", "actionCancelEdits()=0", "actionRemoveAllFromOverview()=0", "actionToggleFullScreen()=0", "actionHelpContents()=0", "actionSaveEdits()=0", "actionAllEdits()=0", "actionHideAllLayers()=0", "actionOpenTable()=0", "actionAbout()=0"],
- "QgsConnectionPoolGroup": ["initTimer(QObject *parent)", "QgsConnectionPoolGroup(const QString &ci)", "onConnectionExpired()", "release(T conn)", "invalidateConnections()"],
- "QgsLinearMinMaxEnhancementWithClip": ["QgsLinearMinMaxEnhancementWithClip(Qgis::DataType, double, double)"],
- "QgsFeatureSelectionModel": ["QgsFeatureSelectionModel(QAbstractItemModel *model, QgsFeatureModel *featureModel, QgsIFeatureSelectionManager *featureSelectionHandler, QObject *parent)", "setFeatureSelectionManager(QgsIFeatureSelectionManager *featureSelectionManager)"],
- "QgsRasterResampleFilter": ["zoomedOutResampler() const", "setMaxOversampling(double os)", "maxOversampling() const", "QgsRasterResampleFilter(QgsRasterInterface *input=nullptr)", "zoomedInResampler() const"],
+ "QgsAttributeTableDelegate": [
+ "setFeatureSelectionModel(QgsFeatureSelectionModel *featureSelectionModel)"
+ ],
+ "QgisInterface": [
+ "actionAddPgLayer()=0",
+ "actionShowPythonDialog()=0",
+ "actionSaveAllEdits()=0",
+ "actionPluginListSeparator()=0",
+ "actionAddRasterLayer()=0",
+ "actionCancelAllEdits()=0",
+ "actionOpenFieldCalculator()=0",
+ "pluginManagerInterface()=0",
+ "actionHideSelectedLayers()=0",
+ "actionShowAllLayers()=0",
+ "actionLayerProperties()=0",
+ "actionLayerSaveAs()=0",
+ "actionAddToOverview()=0",
+ "actionAddOgrLayer()=0",
+ "actionOptions()=0",
+ "actionAddAllToOverview()=0",
+ "layerTreeView()=0",
+ "actionDuplicateLayer()=0",
+ "actionRollbackEdits()=0",
+ "actionCheckQgisVersion()=0",
+ "actionAddWmsLayer()=0",
+ "actionCustomProjection()=0",
+ "actionQgisHomePage()=0",
+ "actionPasteLayerStyle()=0",
+ "actionShowSelectedLayers()=0",
+ "actionNewVectorLayer()=0",
+ "actionRollbackAllEdits()=0",
+ "actionManagePlugins()=0",
+ "actionCopyLayerStyle()=0",
+ "actionToggleEditing()=0",
+ "actionSaveActiveLayerEdits()=0",
+ "actionCancelEdits()=0",
+ "actionRemoveAllFromOverview()=0",
+ "actionToggleFullScreen()=0",
+ "actionHelpContents()=0",
+ "actionSaveEdits()=0",
+ "actionAllEdits()=0",
+ "actionHideAllLayers()=0",
+ "actionOpenTable()=0",
+ "actionAbout()=0",
+ ],
+ "QgsConnectionPoolGroup": [
+ "initTimer(QObject *parent)",
+ "QgsConnectionPoolGroup(const QString &ci)",
+ "onConnectionExpired()",
+ "release(T conn)",
+ "invalidateConnections()",
+ ],
+ "QgsLinearMinMaxEnhancementWithClip": [
+ "QgsLinearMinMaxEnhancementWithClip(Qgis::DataType, double, double)"
+ ],
+ "QgsFeatureSelectionModel": [
+ "QgsFeatureSelectionModel(QAbstractItemModel *model, QgsFeatureModel *featureModel, QgsIFeatureSelectionManager *featureSelectionHandler, QObject *parent)",
+ "setFeatureSelectionManager(QgsIFeatureSelectionManager *featureSelectionManager)",
+ ],
+ "QgsRasterResampleFilter": [
+ "zoomedOutResampler() const",
+ "setMaxOversampling(double os)",
+ "maxOversampling() const",
+ "QgsRasterResampleFilter(QgsRasterInterface *input=nullptr)",
+ "zoomedInResampler() const",
+ ],
"QgsAlignRaster": ["setGridOffset(QPointF offset)", "gridOffset() const"],
- "QgsLinearlyInterpolatedDiagramRenderer": ["classificationAttributeIsExpression() const", "lowerValue() const", "upperSize() const", "setUpperValue(double val)", "lowerSize() const", "classificationAttributeExpression() const", "setClassificationAttributeIsExpression(bool isExpression)", "setUpperSize(QSizeF s)", "upperValue() const", "setLowerValue(double val)", "setDiagramSettings(const QgsDiagramSettings &s)", "setLowerSize(QSizeF s)", "setClassificationAttributeExpression(const QString &expression)"],
- "QgsRasterBlock": ["toString() const", "applyNoDataValues(const QgsRasterRangeList &rangeList)"],
- "QgsRasterLayer": ["showStatusMessage(const QString &message)", "isValidRasterFileName(const QString &fileNameQString)"],
+ "QgsLinearlyInterpolatedDiagramRenderer": [
+ "classificationAttributeIsExpression() const",
+ "lowerValue() const",
+ "upperSize() const",
+ "setUpperValue(double val)",
+ "lowerSize() const",
+ "classificationAttributeExpression() const",
+ "setClassificationAttributeIsExpression(bool isExpression)",
+ "setUpperSize(QSizeF s)",
+ "upperValue() const",
+ "setLowerValue(double val)",
+ "setDiagramSettings(const QgsDiagramSettings &s)",
+ "setLowerSize(QSizeF s)",
+ "setClassificationAttributeExpression(const QString &expression)",
+ ],
+ "QgsRasterBlock": [
+ "toString() const",
+ "applyNoDataValues(const QgsRasterRangeList &rangeList)",
+ ],
+ "QgsRasterLayer": [
+ "showStatusMessage(const QString &message)",
+ "isValidRasterFileName(const QString &fileNameQString)",
+ ],
"QgsZipItem": ["iconZip()", "getZipFileList()"],
- "QgsVectorDataProvider": ["convertValue(QVariant::Type type, const QString &value)"],
+ "QgsVectorDataProvider": [
+ "convertValue(QVariant::Type type, const QString &value)"
+ ],
"QgsQueryBuilder": ["setDatasourceDescription(const QString &uri)", "clear()"],
"QgsFillSymbolLayer": ["QgsFillSymbolLayer(bool locked=false)"],
"QgsGeometryCollection": ["QgsGeometryCollection(const QgsGeometryCollection &c)"],
- "QgsMultiBandColorRendererWidget": ["create(QgsRasterLayer *layer, const QgsRectangle &extent)", "QgsMultiBandColorRendererWidget(QgsRasterLayer *layer, const QgsRectangle &extent=QgsRectangle())"],
+ "QgsMultiBandColorRendererWidget": [
+ "create(QgsRasterLayer *layer, const QgsRectangle &extent)",
+ "QgsMultiBandColorRendererWidget(QgsRasterLayer *layer, const QgsRectangle &extent=QgsRectangle())",
+ ],
"QgsTransaction": ["QgsTransaction(const QString &connString)"],
- "QgsExpressionHighlighter": ["QgsExpressionHighlighter(QTextDocument *parent=nullptr)", "addFields(const QStringList &fieldList)"],
- "QgsPenCapStyleComboBox": ["setPenCapStyle(Qt::PenCapStyle style)", "QgsPenCapStyleComboBox(QWidget *parent=nullptr)", "penCapStyle() const"],
- "QgsRuleBasedRendererWidget": ["refineRuleScalesGui(const QModelIndexList &index)", "refineRuleScales()", "create(QgsVectorLayer *layer, QgsStyle *style, QgsFeatureRenderer *renderer)", "saveSectionWidth(int section, int oldSize, int newSize)", "currentRule()", "QgsRuleBasedRendererWidget(QgsVectorLayer *layer, QgsStyle *style, QgsFeatureRenderer *renderer)", "selectedRules()", "currentRuleChanged(const QModelIndex ¤t=QModelIndex(), const QModelIndex &previous=QModelIndex())", "selectedRulesChanged()", "clearFeatureCounts()", "editRule()", "refineRuleCategories()", "restoreSectionWidths()", "setRenderingOrder()", "countFeatures()", "refineRule(int type)", "editRule(const QModelIndex &index)", "removeRule()", "addRule()", "refineRuleRanges()"],
- "QgsPointLocator_Stream": ["QgsPointLocator_Stream(const QLinkedList< RTree::Data * > &dataList)"],
- "QgsCheckBoxConfigDlg": ["QgsCheckBoxConfigDlg(QgsVectorLayer *vl, int fieldIdx, QWidget *parent=nullptr)"],
- "QgsAttributeTableView": ["repaintRequested()", "setModel(QgsAttributeTableFilterModel *filterModel)", "_q_selectRow(int row)", "selectRow(int row)", "repaintRequested(const QModelIndexList &indexes)", "finished()"],
- "QgsAttributesDnDTree": ["setType(QgsAttributesDnDTree::Type value)", "QgsAttributesDnDTree(QgsVectorLayer *layer, QWidget *parent=nullptr)", "type() const", "selectFirstMatchingItem(const QgsAttributesFormProperties::DnDTreeItemData &data)", "Type"],
- "QgsAbstractFeatureIteratorFromSource": ["QgsAbstractFeatureIteratorFromSource(T *source, bool ownSource, const QgsFeatureRequest &request)"],
+ "QgsExpressionHighlighter": [
+ "QgsExpressionHighlighter(QTextDocument *parent=nullptr)",
+ "addFields(const QStringList &fieldList)",
+ ],
+ "QgsPenCapStyleComboBox": [
+ "setPenCapStyle(Qt::PenCapStyle style)",
+ "QgsPenCapStyleComboBox(QWidget *parent=nullptr)",
+ "penCapStyle() const",
+ ],
+ "QgsRuleBasedRendererWidget": [
+ "refineRuleScalesGui(const QModelIndexList &index)",
+ "refineRuleScales()",
+ "create(QgsVectorLayer *layer, QgsStyle *style, QgsFeatureRenderer *renderer)",
+ "saveSectionWidth(int section, int oldSize, int newSize)",
+ "currentRule()",
+ "QgsRuleBasedRendererWidget(QgsVectorLayer *layer, QgsStyle *style, QgsFeatureRenderer *renderer)",
+ "selectedRules()",
+ "currentRuleChanged(const QModelIndex ¤t=QModelIndex(), const QModelIndex &previous=QModelIndex())",
+ "selectedRulesChanged()",
+ "clearFeatureCounts()",
+ "editRule()",
+ "refineRuleCategories()",
+ "restoreSectionWidths()",
+ "setRenderingOrder()",
+ "countFeatures()",
+ "refineRule(int type)",
+ "editRule(const QModelIndex &index)",
+ "removeRule()",
+ "addRule()",
+ "refineRuleRanges()",
+ ],
+ "QgsPointLocator_Stream": [
+ "QgsPointLocator_Stream(const QLinkedList< RTree::Data * > &dataList)"
+ ],
+ "QgsCheckBoxConfigDlg": [
+ "QgsCheckBoxConfigDlg(QgsVectorLayer *vl, int fieldIdx, QWidget *parent=nullptr)"
+ ],
+ "QgsAttributeTableView": [
+ "repaintRequested()",
+ "setModel(QgsAttributeTableFilterModel *filterModel)",
+ "_q_selectRow(int row)",
+ "selectRow(int row)",
+ "repaintRequested(const QModelIndexList &indexes)",
+ "finished()",
+ ],
+ "QgsAttributesDnDTree": [
+ "setType(QgsAttributesDnDTree::Type value)",
+ "QgsAttributesDnDTree(QgsVectorLayer *layer, QWidget *parent=nullptr)",
+ "type() const",
+ "selectFirstMatchingItem(const QgsAttributesFormProperties::DnDTreeItemData &data)",
+ "Type",
+ ],
+ "QgsAbstractFeatureIteratorFromSource": [
+ "QgsAbstractFeatureIteratorFromSource(T *source, bool ownSource, const QgsFeatureRequest &request)"
+ ],
"QgsPointPatternFillSymbolLayer": ["createFromSld(QDomElement &element)"],
- "QgsRasterProjector": ["precisionLabel(Precision precision)", "setPrecision(Precision precision)", "precision() const"],
- "QgsColorBrewerPalette": ["listSchemeVariants(const QString &schemeName)", "listSchemes()", "listSchemeColors(const QString &schemeName, int colors)"],
- "QgsDerivativeFilter": ["QgsDerivativeFilter(const QString &inputFile, const QString &outputFile, const QString &outputFormat)"],
- "QgsVertexMarker": ["setPenWidth(int width)", "QgsVertexMarker(QgsMapCanvas *mapCanvas)", "setIconType(int iconType)", "setIconSize(int iconSize)"],
- "QgsAttributeFormLegacyInterface": ["QgsAttributeFormLegacyInterface(const QString &function, const QString &pyFormName, QgsAttributeForm *form)"],
- "QgsGpsDetector": ["detectionFailed()", "connDestroyed(QObject *)", "advance()", "detected(const QgsGpsInformation &)", "QgsGpsDetector(const QString &portName)", "availablePorts()"],
+ "QgsRasterProjector": [
+ "precisionLabel(Precision precision)",
+ "setPrecision(Precision precision)",
+ "precision() const",
+ ],
+ "QgsColorBrewerPalette": [
+ "listSchemeVariants(const QString &schemeName)",
+ "listSchemes()",
+ "listSchemeColors(const QString &schemeName, int colors)",
+ ],
+ "QgsDerivativeFilter": [
+ "QgsDerivativeFilter(const QString &inputFile, const QString &outputFile, const QString &outputFormat)"
+ ],
+ "QgsVertexMarker": [
+ "setPenWidth(int width)",
+ "QgsVertexMarker(QgsMapCanvas *mapCanvas)",
+ "setIconType(int iconType)",
+ "setIconSize(int iconSize)",
+ ],
+ "QgsAttributeFormLegacyInterface": [
+ "QgsAttributeFormLegacyInterface(const QString &function, const QString &pyFormName, QgsAttributeForm *form)"
+ ],
+ "QgsGpsDetector": [
+ "detectionFailed()",
+ "connDestroyed(QObject *)",
+ "advance()",
+ "detected(const QgsGpsInformation &)",
+ "QgsGpsDetector(const QString &portName)",
+ "availablePorts()",
+ ],
"QgsSimpleLineSymbolLayerWidget": ["updatePatternIcon()"],
"QgsMeshVariableStrokeWidthButton": ["widgetChanged()"],
"QgsRunProcess": ["create(const QString &action, bool capture)"],
- "pal::GeomFunction": ["findLineCircleIntersection(double cx, double cy, double radius, double x1, double y1, double x2, double y2, double &xRes, double &yRes)", "cross_product(double x1, double y1, double x2, double y2, double x3, double y3)"],
- "QgsLayerTreeModelLegendNode": ["isEmbeddedInParent() const", "setUserLabel(const QString &userLabel)", "isScaleOK(double scale) const", "userLabel() const", "setEmbeddedInParent(bool embedded)"],
- "QgsCollapsibleGroupBox": ["saveCollapsedState()", "saveCheckedState()", "saveKey() const", "QgsCollapsibleGroupBox(QWidget *parent=nullptr, QgsSettings *settings=nullptr)", "setSettings(QgsSettings *settings)", "QgsCollapsibleGroupBox(const QString &title, QWidget *parent=nullptr, QgsSettings *settings=nullptr)", "init()"],
- "QgsFieldValidator": ["dateFormat() const", "QgsFieldValidator(QObject *parent, const QgsField &field, const QString &defaultValue, const QString &dateFormat=\"yyyy-MM-dd\")"],
+ "pal::GeomFunction": [
+ "findLineCircleIntersection(double cx, double cy, double radius, double x1, double y1, double x2, double y2, double &xRes, double &yRes)",
+ "cross_product(double x1, double y1, double x2, double y2, double x3, double y3)",
+ ],
+ "QgsLayerTreeModelLegendNode": [
+ "isEmbeddedInParent() const",
+ "setUserLabel(const QString &userLabel)",
+ "isScaleOK(double scale) const",
+ "userLabel() const",
+ "setEmbeddedInParent(bool embedded)",
+ ],
+ "QgsCollapsibleGroupBox": [
+ "saveCollapsedState()",
+ "saveCheckedState()",
+ "saveKey() const",
+ "QgsCollapsibleGroupBox(QWidget *parent=nullptr, QgsSettings *settings=nullptr)",
+ "setSettings(QgsSettings *settings)",
+ "QgsCollapsibleGroupBox(const QString &title, QWidget *parent=nullptr, QgsSettings *settings=nullptr)",
+ "init()",
+ ],
+ "QgsFieldValidator": [
+ "dateFormat() const",
+ 'QgsFieldValidator(QObject *parent, const QgsField &field, const QString &defaultValue, const QString &dateFormat="yyyy-MM-dd")',
+ ],
"QgsDiagram": ["QgsDiagram(const QgsDiagram &other)", "clearCache()"],
- "QgsSourceFieldsProperties": ["setRow(int row, int idx, const QgsField &field)", "QgsSourceFieldsProperties(QgsVectorLayer *layer, QWidget *parent=nullptr)", "apply()", "AttrColumns", "updateButtons()", "toggleEditing()", "loadRows()", "init()"],
- "QgsCptCityAllRampsItem": ["QgsCptCityAllRampsItem(QgsCptCityDataItem *parent, const QString &name, const QVector< QgsCptCityDataItem * > &items)"],
- "QgsExpressionBuilderDialog": ["setExpressionText(const QString &text)", "QgsExpressionBuilderDialog(QgsVectorLayer *layer, const QString &startText=QString(), QWidget *parent SIP_TRANSFERTHIS=nullptr, const QString &key=\"generic\", const QgsExpressionContext &context=QgsExpressionContext())", "expressionText()"],
- "QgsUniqueValuesConfigDlg": ["QgsUniqueValuesConfigDlg(QgsVectorLayer *vl, int fieldIdx, QWidget *parent=nullptr)"],
+ "QgsSourceFieldsProperties": [
+ "setRow(int row, int idx, const QgsField &field)",
+ "QgsSourceFieldsProperties(QgsVectorLayer *layer, QWidget *parent=nullptr)",
+ "apply()",
+ "AttrColumns",
+ "updateButtons()",
+ "toggleEditing()",
+ "loadRows()",
+ "init()",
+ ],
+ "QgsCptCityAllRampsItem": [
+ "QgsCptCityAllRampsItem(QgsCptCityDataItem *parent, const QString &name, const QVector< QgsCptCityDataItem * > &items)"
+ ],
+ "QgsExpressionBuilderDialog": [
+ "setExpressionText(const QString &text)",
+ 'QgsExpressionBuilderDialog(QgsVectorLayer *layer, const QString &startText=QString(), QWidget *parent SIP_TRANSFERTHIS=nullptr, const QString &key="generic", const QgsExpressionContext &context=QgsExpressionContext())',
+ "expressionText()",
+ ],
+ "QgsUniqueValuesConfigDlg": [
+ "QgsUniqueValuesConfigDlg(QgsVectorLayer *vl, int fieldIdx, QWidget *parent=nullptr)"
+ ],
"QgsUnitSelectionWidget": ["changed()"],
- "QgsRendererRangeLabelFormat": ["setPrecision(int precision)", "setTrimTrailingZeroes(bool trimTrailingZeroes)", "formatNumber(double value) const", "setFormat(const QString &format)", "setFromDomElement(QDomElement &element)", "trimTrailingZeroes() const", "QgsRendererRangeLabelFormat(const QString &format, int precision=4, bool trimTrailingZeroes=false)", "format() const", "precision() const", "saveToDomElement(QDomElement &element)", "labelForRange(const QgsRendererRange &range) const"],
+ "QgsRendererRangeLabelFormat": [
+ "setPrecision(int precision)",
+ "setTrimTrailingZeroes(bool trimTrailingZeroes)",
+ "formatNumber(double value) const",
+ "setFormat(const QString &format)",
+ "setFromDomElement(QDomElement &element)",
+ "trimTrailingZeroes() const",
+ "QgsRendererRangeLabelFormat(const QString &format, int precision=4, bool trimTrailingZeroes=false)",
+ "format() const",
+ "precision() const",
+ "saveToDomElement(QDomElement &element)",
+ "labelForRange(const QgsRendererRange &range) const",
+ ],
"QgsAbstractLabelProvider": ["Flag"],
- "QgsGmlFeatureClass": ["fields()", "geometryAttributes()", "fieldIndex(const QString &name)", "QgsGmlFeatureClass(const QString &name, const QString &path)", "path() const"],
- "QgsCategorizedSymbolRendererWidget": ["changeCategorySymbol()", "QgsCategorizedSymbolRendererWidget(QgsVectorLayer *layer, QgsStyle *style, QgsFeatureRenderer *renderer)", "addCategories()", "changeCategorizedSymbol()", "deleteCategories()", "updateUiFromRenderer()", "categoriesDoubleClicked(const QModelIndex &idx)", "deleteAllCategories()", "rowsMoved()", "showSymbolLevels()", "categoryColumnChanged(const QString &field)", "addCategory()", "create(QgsVectorLayer *layer, QgsStyle *style, QgsFeatureRenderer *renderer)", "selectedCategoryList()", "populateCategories()"],
- "QgsMessageViewer": ["setCheckBoxText(const QString &text)", "setCheckBoxState(Qt::CheckState state)", "checkBoxState()", "setCheckBoxVisible(bool visible)", "setCheckBoxQgsSettingsLabel(const QString &label)", "QgsMessageViewer(QWidget *parent=nullptr, Qt::WindowFlags fl=QgsGuiUtils::ModalDialogFlags, bool deleteOnClose=true)", "setMessageAsPlainText(const QString &msg)", "setMessageAsHtml(const QString &msg)"],
+ "QgsGmlFeatureClass": [
+ "fields()",
+ "geometryAttributes()",
+ "fieldIndex(const QString &name)",
+ "QgsGmlFeatureClass(const QString &name, const QString &path)",
+ "path() const",
+ ],
+ "QgsCategorizedSymbolRendererWidget": [
+ "changeCategorySymbol()",
+ "QgsCategorizedSymbolRendererWidget(QgsVectorLayer *layer, QgsStyle *style, QgsFeatureRenderer *renderer)",
+ "addCategories()",
+ "changeCategorizedSymbol()",
+ "deleteCategories()",
+ "updateUiFromRenderer()",
+ "categoriesDoubleClicked(const QModelIndex &idx)",
+ "deleteAllCategories()",
+ "rowsMoved()",
+ "showSymbolLevels()",
+ "categoryColumnChanged(const QString &field)",
+ "addCategory()",
+ "create(QgsVectorLayer *layer, QgsStyle *style, QgsFeatureRenderer *renderer)",
+ "selectedCategoryList()",
+ "populateCategories()",
+ ],
+ "QgsMessageViewer": [
+ "setCheckBoxText(const QString &text)",
+ "setCheckBoxState(Qt::CheckState state)",
+ "checkBoxState()",
+ "setCheckBoxVisible(bool visible)",
+ "setCheckBoxQgsSettingsLabel(const QString &label)",
+ "QgsMessageViewer(QWidget *parent=nullptr, Qt::WindowFlags fl=QgsGuiUtils::ModalDialogFlags, bool deleteOnClose=true)",
+ "setMessageAsPlainText(const QString &msg)",
+ "setMessageAsHtml(const QString &msg)",
+ ],
"QgsCurvePolygon": ["QgsCurvePolygon(const QgsCurvePolygon &p)"],
- "QgsRuleBasedRenderer::Rule": ["setLabel(const QString &label)", "legendSymbolItems(int currentLevel=-1) const", "label() const", "save(QDomDocument &doc, QgsSymbolMap &symbolMap) const", "initFilter()", "dependsOnScale() const", "symbol()"],
+ "QgsRuleBasedRenderer::Rule": [
+ "setLabel(const QString &label)",
+ "legendSymbolItems(int currentLevel=-1) const",
+ "label() const",
+ "save(QDomDocument &doc, QgsSymbolMap &symbolMap) const",
+ "initFilter()",
+ "dependsOnScale() const",
+ "symbol()",
+ ],
"QgsValueRelationSearchWidgetWrapper": ["value() const"],
- "QgsGml": ["dataReadProgress(int progress)", "totalStepsUpdate(int totalSteps)", "QgsGml(const QString &typeName, const QString &geometryAttribute, const QgsFields &fields)"],
- "QgsCptCitySelectionItem": ["QgsCptCitySelectionItem(QgsCptCityDataItem *parent, const QString &name, const QString &path)", "parseXml()", "selectionsList() const"],
- "QgsRasterFormatSaveOptionsWidget": ["apply()", "optionsChanged()", "QgsRasterFormatSaveOptionsWidget(QWidget *parent SIP_TRANSFERTHIS=nullptr, const QString &format=\"GTiff\", QgsRasterFormatSaveOptionsWidget::Type type=Default, const QString &provider=\"gdal\")", "Type"],
- "QgsSymbolLayerAbstractMetadata": ["visibleName() const", "type() const", "name() const"],
- "QgsMultiBandColorRenderer": ["setRedBand(int band)", "greenBand() const", "redBand() const", "create(const QDomElement &elem, QgsRasterInterface *input)", "blueBand() const", "setBlueBand(int band)", "QgsMultiBandColorRenderer(QgsRasterInterface *input, int redBand, int greenBand, int blueBand, QgsContrastEnhancement *redEnhancement=nullptr, QgsContrastEnhancement *greenEnhancement=nullptr, QgsContrastEnhancement *blueEnhancement=nullptr)", "setGreenBand(int band)"],
+ "QgsGml": [
+ "dataReadProgress(int progress)",
+ "totalStepsUpdate(int totalSteps)",
+ "QgsGml(const QString &typeName, const QString &geometryAttribute, const QgsFields &fields)",
+ ],
+ "QgsCptCitySelectionItem": [
+ "QgsCptCitySelectionItem(QgsCptCityDataItem *parent, const QString &name, const QString &path)",
+ "parseXml()",
+ "selectionsList() const",
+ ],
+ "QgsRasterFormatSaveOptionsWidget": [
+ "apply()",
+ "optionsChanged()",
+ 'QgsRasterFormatSaveOptionsWidget(QWidget *parent SIP_TRANSFERTHIS=nullptr, const QString &format="GTiff", QgsRasterFormatSaveOptionsWidget::Type type=Default, const QString &provider="gdal")',
+ "Type",
+ ],
+ "QgsSymbolLayerAbstractMetadata": [
+ "visibleName() const",
+ "type() const",
+ "name() const",
+ ],
+ "QgsMultiBandColorRenderer": [
+ "setRedBand(int band)",
+ "greenBand() const",
+ "redBand() const",
+ "create(const QDomElement &elem, QgsRasterInterface *input)",
+ "blueBand() const",
+ "setBlueBand(int band)",
+ "QgsMultiBandColorRenderer(QgsRasterInterface *input, int redBand, int greenBand, int blueBand, QgsContrastEnhancement *redEnhancement=nullptr, QgsContrastEnhancement *greenEnhancement=nullptr, QgsContrastEnhancement *blueEnhancement=nullptr)",
+ "setGreenBand(int band)",
+ ],
"QgsPreviewEffect": ["PreviewMode", "QgsPreviewEffect(QObject *parent)"],
"QgsPixmapLabel": ["setPixmap(const QPixmap &)"],
"QgsCapabilitiesCache": ["QgsCapabilitiesCache(int size)"],
"QgsCompoundCurve": ["QgsCompoundCurve(const QgsCompoundCurve &curve)"],
- "QgsVectorFileWriter::SetOption": ["SetOption(const QString &docString, const QStringList &values, const QString &defaultValue, bool allowNone=false)"],
- "QgsVectorFileWriter::StringOption": ["StringOption(const QString &docString, const QString &defaultValue=QString())"],
+ "QgsVectorFileWriter::SetOption": [
+ "SetOption(const QString &docString, const QStringList &values, const QString &defaultValue, bool allowNone=false)"
+ ],
+ "QgsVectorFileWriter::StringOption": [
+ "StringOption(const QString &docString, const QString &defaultValue=QString())"
+ ],
"QgsOWSSourceSelect": ["enableLayersForCrs(QTreeWidgetItem *item)"],
- "QgsGeometry::Error": ["Error(const QString &m, const QgsPointXY &p)", "Error(const QString &m)"],
+ "QgsGeometry::Error": [
+ "Error(const QString &m, const QgsPointXY &p)",
+ "Error(const QString &m)",
+ ],
"QgisPlugin": ["name()"],
"QgsXmlUtils": ["readRectangle(const QDomElement &element)"],
- "QgsAttributeTableFilterModel": ["fidToIndexList(QgsFeatureId fid)", "mapFromMaster(const QModelIndex &sourceIndex) const", "mapToMaster(const QModelIndex &proxyIndex) const"],
- "QgsVectorLayerLegendWidget": ["QgsVectorLayerLegendWidget(QWidget *parent=nullptr)"],
+ "QgsAttributeTableFilterModel": [
+ "fidToIndexList(QgsFeatureId fid)",
+ "mapFromMaster(const QModelIndex &sourceIndex) const",
+ "mapToMaster(const QModelIndex &proxyIndex) const",
+ ],
+ "QgsVectorLayerLegendWidget": [
+ "QgsVectorLayerLegendWidget(QWidget *parent=nullptr)"
+ ],
"QgsSymbolRenderContext": ["setFeature(const QgsFeature *f)"],
- "QgsDartMeasurement": ["send() const", "QgsDartMeasurement(const QString &name, Type type, const QString &value)", "Type", "toString() const"],
- "QgsShapeburstFillSymbolLayer": ["setOffsetMapUnitScale(const QgsMapUnitScale &scale)", "setDistanceMapUnitScale(const QgsMapUnitScale &scale)", "offsetMapUnitScale() const", "distanceMapUnitScale() const"],
- "QgsJoinDialog": ["QgsJoinDialog(QgsVectorLayer *layer, QList< QgsMapLayer * > alreadyJoinedLayers, QWidget *parent=nullptr, Qt::WindowFlags f=Qt::WindowFlags())"],
- "QgsGeometryLineLayerIntersectionCheck": ["factoryDescription()", "QgsGeometryLineLayerIntersectionCheck(QgsGeometryCheckContext *context, const QVariantMap &configuration)", "ResolutionMethod", "factoryCompatibleGeometryTypes()", "factoryCheckType()", "factoryIsCompatible(QgsVectorLayer *layer)", "factoryId()"],
- "QgsVectorFileWriter::IntOption": ["IntOption(const QString &docString, int defaultValue)"],
- "QgsAttributeTableModel": ["Role", "idToIndex(QgsFeatureId id) const", "idToIndexList(QgsFeatureId id) const", "finished()"],
- "QgsFeatureListModel": ["Role", "featureByIndex(const QModelIndex &index, QgsFeature &feat)", "mapSelectionFromMaster(const QItemSelection &selection) const", "mapToMaster(const QModelIndex &proxyIndex) const", "setSourceModel(QgsAttributeTableFilterModel *sourceModel)", "mapFromMaster(const QModelIndex &sourceIndex) const", "mapSelectionToMaster(const QItemSelection &selection) const", "fidToIndexList(QgsFeatureId fid)", "masterModel()", "displayExpression() const"],
- "QgsColorEffectWidget": ["QgsColorEffectWidget(QWidget *parent=nullptr)", "create()"],
- "QgsDetailedItemWidget": ["setChecked(bool flag)", "setData(const QgsDetailedItemData &data)"],
- "QgsGeos": ["getGEOSHandler()", "coordSeqPoint(const GEOSCoordSequence *cs, int i, bool hasZ, bool hasM)", "fromGeosPolygon(const GEOSGeometry *geos)"],
- "QgsRasterShaderFunction": ["QgsRasterShaderFunction(double minimumValue=0.0, double maximumValue=255.0)", "minimumMaximumRange() const"],
- "QgsGeometryChecker": ["execute(int *totalSteps=nullptr)", "getContext() const", "getMessages() const", "setMergeAttributeIndices(const QMap< QString, int > &mergeAttributeIndices)", "QgsGeometryChecker(const QList< QgsGeometryCheck * > &checks, QgsGeometryCheckContext *context, const QMap< QString, QgsFeaturePool * > &featurePools)", "errorAdded(QgsGeometryCheckError *error)", "fixError(QgsGeometryCheckError *error, int method, bool triggerRepaint=false)", "featurePools() const", "errorUpdated(QgsGeometryCheckError *error, bool statusChanged)", "progressValue(int value)", "getChecks() const"],
+ "QgsDartMeasurement": [
+ "send() const",
+ "QgsDartMeasurement(const QString &name, Type type, const QString &value)",
+ "Type",
+ "toString() const",
+ ],
+ "QgsShapeburstFillSymbolLayer": [
+ "setOffsetMapUnitScale(const QgsMapUnitScale &scale)",
+ "setDistanceMapUnitScale(const QgsMapUnitScale &scale)",
+ "offsetMapUnitScale() const",
+ "distanceMapUnitScale() const",
+ ],
+ "QgsJoinDialog": [
+ "QgsJoinDialog(QgsVectorLayer *layer, QList< QgsMapLayer * > alreadyJoinedLayers, QWidget *parent=nullptr, Qt::WindowFlags f=Qt::WindowFlags())"
+ ],
+ "QgsGeometryLineLayerIntersectionCheck": [
+ "factoryDescription()",
+ "QgsGeometryLineLayerIntersectionCheck(QgsGeometryCheckContext *context, const QVariantMap &configuration)",
+ "ResolutionMethod",
+ "factoryCompatibleGeometryTypes()",
+ "factoryCheckType()",
+ "factoryIsCompatible(QgsVectorLayer *layer)",
+ "factoryId()",
+ ],
+ "QgsVectorFileWriter::IntOption": [
+ "IntOption(const QString &docString, int defaultValue)"
+ ],
+ "QgsAttributeTableModel": [
+ "Role",
+ "idToIndex(QgsFeatureId id) const",
+ "idToIndexList(QgsFeatureId id) const",
+ "finished()",
+ ],
+ "QgsFeatureListModel": [
+ "Role",
+ "featureByIndex(const QModelIndex &index, QgsFeature &feat)",
+ "mapSelectionFromMaster(const QItemSelection &selection) const",
+ "mapToMaster(const QModelIndex &proxyIndex) const",
+ "setSourceModel(QgsAttributeTableFilterModel *sourceModel)",
+ "mapFromMaster(const QModelIndex &sourceIndex) const",
+ "mapSelectionToMaster(const QItemSelection &selection) const",
+ "fidToIndexList(QgsFeatureId fid)",
+ "masterModel()",
+ "displayExpression() const",
+ ],
+ "QgsColorEffectWidget": [
+ "QgsColorEffectWidget(QWidget *parent=nullptr)",
+ "create()",
+ ],
+ "QgsDetailedItemWidget": [
+ "setChecked(bool flag)",
+ "setData(const QgsDetailedItemData &data)",
+ ],
+ "QgsGeos": [
+ "getGEOSHandler()",
+ "coordSeqPoint(const GEOSCoordSequence *cs, int i, bool hasZ, bool hasM)",
+ "fromGeosPolygon(const GEOSGeometry *geos)",
+ ],
+ "QgsRasterShaderFunction": [
+ "QgsRasterShaderFunction(double minimumValue=0.0, double maximumValue=255.0)",
+ "minimumMaximumRange() const",
+ ],
+ "QgsGeometryChecker": [
+ "execute(int *totalSteps=nullptr)",
+ "getContext() const",
+ "getMessages() const",
+ "setMergeAttributeIndices(const QMap< QString, int > &mergeAttributeIndices)",
+ "QgsGeometryChecker(const QList< QgsGeometryCheck * > &checks, QgsGeometryCheckContext *context, const QMap< QString, QgsFeaturePool * > &featurePools)",
+ "errorAdded(QgsGeometryCheckError *error)",
+ "fixError(QgsGeometryCheckError *error, int method, bool triggerRepaint=false)",
+ "featurePools() const",
+ "errorUpdated(QgsGeometryCheckError *error, bool statusChanged)",
+ "progressValue(int value)",
+ "getChecks() const",
+ ],
"QgsRendererRulePropsDialog": ["buildExpression()", "testFilter()", "rule()"],
- "QgsCptCityArchive": ["initArchives(bool loadAll=false)", "defaultArchive()", "archiveRegistry()", "initDefaultArchive()", "copyingInfo(const QString &fileName)", "isEmpty()", "baseDir(QString archiveName)", "archiveName() const", "findFileName(const QString &target, const QString &startDir, const QString &baseDir)", "defaultBaseDir()", "rootItems() const", "descFileName(const QString &dirName) const", "setBaseDir(const QString &dirName)", "copyingFileName(const QString &dirName) const", "QgsCptCityArchive(const QString &archiveName=DEFAULT_CPTCITY_ARCHIVE, const QString &baseDir=QString())", "baseDir() const", "clearArchives()", "description(const QString &fileName)", "initArchive(const QString &archiveName, const QString &archiveBaseDir)", "selectionItems() const"],
- "QgsSingleBandGrayRenderer": ["gradient() const", "grayBand() const", "setGradient(Gradient gradient)", "create(const QDomElement &elem, QgsRasterInterface *input)", "Gradient", "QgsSingleBandGrayRenderer(QgsRasterInterface *input, int grayBand)", "setGrayBand(int band)", "contrastEnhancement() const"],
- "QgsGeometryContainedCheck": ["factoryDescription()", "ResolutionMethod", "QgsGeometryContainedCheck(QgsGeometryCheckContext *context, const QVariantMap &configuration)", "factoryCompatibleGeometryTypes()", "factoryCheckType()", "factoryIsCompatible(QgsVectorLayer *layer)", "factoryId()"],
- "QgsVectorLayerJoinBuffer": ["vectorJoins() const", "QgsVectorLayerJoinBuffer(QgsVectorLayer *layer=nullptr)"],
- "QgsAbstractFeatureSource": ["iteratorClosed(QgsAbstractFeatureIterator *it)", "iteratorOpened(QgsAbstractFeatureIterator *it)"],
- "QgsRasterCalcNode": ["parseRasterCalcString(const QString &str, QString &parserErrorMsg)", "setRight(QgsRasterCalcNode *right)", "QgsRasterCalcNode(Operator op, QgsRasterCalcNode *left, QgsRasterCalcNode *right)", "QgsRasterCalcNode(QgsRasterMatrix *matrix)", "QgsRasterCalcNode(double number)", "type() const", "setLeft(QgsRasterCalcNode *left)", "QgsRasterCalcNode(const QString &rasterName)"],
+ "QgsCptCityArchive": [
+ "initArchives(bool loadAll=false)",
+ "defaultArchive()",
+ "archiveRegistry()",
+ "initDefaultArchive()",
+ "copyingInfo(const QString &fileName)",
+ "isEmpty()",
+ "baseDir(QString archiveName)",
+ "archiveName() const",
+ "findFileName(const QString &target, const QString &startDir, const QString &baseDir)",
+ "defaultBaseDir()",
+ "rootItems() const",
+ "descFileName(const QString &dirName) const",
+ "setBaseDir(const QString &dirName)",
+ "copyingFileName(const QString &dirName) const",
+ "QgsCptCityArchive(const QString &archiveName=DEFAULT_CPTCITY_ARCHIVE, const QString &baseDir=QString())",
+ "baseDir() const",
+ "clearArchives()",
+ "description(const QString &fileName)",
+ "initArchive(const QString &archiveName, const QString &archiveBaseDir)",
+ "selectionItems() const",
+ ],
+ "QgsSingleBandGrayRenderer": [
+ "gradient() const",
+ "grayBand() const",
+ "setGradient(Gradient gradient)",
+ "create(const QDomElement &elem, QgsRasterInterface *input)",
+ "Gradient",
+ "QgsSingleBandGrayRenderer(QgsRasterInterface *input, int grayBand)",
+ "setGrayBand(int band)",
+ "contrastEnhancement() const",
+ ],
+ "QgsGeometryContainedCheck": [
+ "factoryDescription()",
+ "ResolutionMethod",
+ "QgsGeometryContainedCheck(QgsGeometryCheckContext *context, const QVariantMap &configuration)",
+ "factoryCompatibleGeometryTypes()",
+ "factoryCheckType()",
+ "factoryIsCompatible(QgsVectorLayer *layer)",
+ "factoryId()",
+ ],
+ "QgsVectorLayerJoinBuffer": [
+ "vectorJoins() const",
+ "QgsVectorLayerJoinBuffer(QgsVectorLayer *layer=nullptr)",
+ ],
+ "QgsAbstractFeatureSource": [
+ "iteratorClosed(QgsAbstractFeatureIterator *it)",
+ "iteratorOpened(QgsAbstractFeatureIterator *it)",
+ ],
+ "QgsRasterCalcNode": [
+ "parseRasterCalcString(const QString &str, QString &parserErrorMsg)",
+ "setRight(QgsRasterCalcNode *right)",
+ "QgsRasterCalcNode(Operator op, QgsRasterCalcNode *left, QgsRasterCalcNode *right)",
+ "QgsRasterCalcNode(QgsRasterMatrix *matrix)",
+ "QgsRasterCalcNode(double number)",
+ "type() const",
+ "setLeft(QgsRasterCalcNode *left)",
+ "QgsRasterCalcNode(const QString &rasterName)",
+ ],
"QgsFields": ["FieldOrigin"],
- "QgsSymbolSelectorDialog": ["lockLayer()", "removeLayer()", "updatePreview()", "addLayer()", "symbolModified()", "layerChanged()", "moveLayerUp()", "updateLayerPreview()", "moveLayerDown()"],
+ "QgsSymbolSelectorDialog": [
+ "lockLayer()",
+ "removeLayer()",
+ "updatePreview()",
+ "addLayer()",
+ "symbolModified()",
+ "layerChanged()",
+ "moveLayerUp()",
+ "updateLayerPreview()",
+ "moveLayerDown()",
+ ],
"QgsEffectStack": ["QgsEffectStack(const QgsEffectStack &other)"],
- "QgsRelationReferenceWidget": ["setRelation(const QgsRelation &relation, bool allowNullValue)", "CanvasExtent", "setOpenFormButtonVisible(bool openFormButtonVisible)", "QgsRelationReferenceWidget(QWidget *parent)", "setReadOnlySelector(bool readOnly)", "setRelationEditable(bool editable)", "init()", "setAllowMapIdentification(bool allowMapIdentification)", "setEmbedForm(bool display)"],
- "QgsDiagramProperties": ["mAttributesTreeWidget_itemDoubleClicked(QTreeWidgetItem *item, int column)", "scalingTypeChanged()", "mAddCategoryPushButton_clicked()", "mEngineSettingsButton_clicked()", "apply()", "mRemoveCategoryPushButton_clicked()", "showSizeLegendDialog()", "QgsDiagramProperties(QgsVectorLayer *layer, QWidget *parent, QgsMapCanvas *canvas)", "mDiagramAttributesTreeWidget_itemDoubleClicked(QTreeWidgetItem *item, int column)", "mDiagramStackedWidget_currentChanged(int index)", "mDiagramTypeComboBox_currentIndexChanged(int index)", "mFindMaximumValueButton_clicked()", "showAddAttributeExpressionDialog()", "auxiliaryFieldCreated()", "updatePlacementWidgets()"],
- "QgsStackedDiagramProperties": ["apply()", "auxiliaryFieldCreated()", "QgsStackedDiagramProperties(QgsVectorLayer *layer, QWidget *parent, QgsMapCanvas *canvas)"],
- "QgsDiagramWidget": ["mDiagramTypeComboBox_currentIndexChanged(int index)", "showEngineConfigDialog()"],
- "QgsFeatureListView": ["repaintRequested()", "repaintRequested(const QModelIndexList &indexes)"],
- "QgsGradientFillSymbolLayerWidget": ["setGradientSpread(int index)", "setColor(const QColor &color)", "setCoordinateMode(int index)", "setColor2(const QColor &color)", "setGradientType(int index)"],
+ "QgsRelationReferenceWidget": [
+ "setRelation(const QgsRelation &relation, bool allowNullValue)",
+ "CanvasExtent",
+ "setOpenFormButtonVisible(bool openFormButtonVisible)",
+ "QgsRelationReferenceWidget(QWidget *parent)",
+ "setReadOnlySelector(bool readOnly)",
+ "setRelationEditable(bool editable)",
+ "init()",
+ "setAllowMapIdentification(bool allowMapIdentification)",
+ "setEmbedForm(bool display)",
+ ],
+ "QgsDiagramProperties": [
+ "mAttributesTreeWidget_itemDoubleClicked(QTreeWidgetItem *item, int column)",
+ "scalingTypeChanged()",
+ "mAddCategoryPushButton_clicked()",
+ "mEngineSettingsButton_clicked()",
+ "apply()",
+ "mRemoveCategoryPushButton_clicked()",
+ "showSizeLegendDialog()",
+ "QgsDiagramProperties(QgsVectorLayer *layer, QWidget *parent, QgsMapCanvas *canvas)",
+ "mDiagramAttributesTreeWidget_itemDoubleClicked(QTreeWidgetItem *item, int column)",
+ "mDiagramStackedWidget_currentChanged(int index)",
+ "mDiagramTypeComboBox_currentIndexChanged(int index)",
+ "mFindMaximumValueButton_clicked()",
+ "showAddAttributeExpressionDialog()",
+ "auxiliaryFieldCreated()",
+ "updatePlacementWidgets()",
+ ],
+ "QgsStackedDiagramProperties": [
+ "apply()",
+ "auxiliaryFieldCreated()",
+ "QgsStackedDiagramProperties(QgsVectorLayer *layer, QWidget *parent, QgsMapCanvas *canvas)",
+ ],
+ "QgsDiagramWidget": [
+ "mDiagramTypeComboBox_currentIndexChanged(int index)",
+ "showEngineConfigDialog()",
+ ],
+ "QgsFeatureListView": [
+ "repaintRequested()",
+ "repaintRequested(const QModelIndexList &indexes)",
+ ],
+ "QgsGradientFillSymbolLayerWidget": [
+ "setGradientSpread(int index)",
+ "setColor(const QColor &color)",
+ "setCoordinateMode(int index)",
+ "setColor2(const QColor &color)",
+ "setGradientType(int index)",
+ ],
"QgsFillSymbol": ["setAngle(double angle) const"],
- "QgsSmartGroupCondition": ["QgsSmartGroupCondition(int id, QWidget *parent=nullptr)", "removed(int)", "destruct()"],
- "QgsRasterRendererRegistry": ["insert(const QgsRasterRendererRegistryEntry &entry)", "entries() const", "renderersList() const", "insertWidgetFunction(const QString &rendererName, QgsRasterRendererWidgetCreateFunc func)", "rendererData(const QString &rendererName, QgsRasterRendererRegistryEntry &data) const"],
- "QgsAdvancedDigitizingCanvasItem": ["QgsAdvancedDigitizingCanvasItem(QgsMapCanvas *canvas, QgsAdvancedDigitizingDockWidget *cadDockWidget)"],
+ "QgsSmartGroupCondition": [
+ "QgsSmartGroupCondition(int id, QWidget *parent=nullptr)",
+ "removed(int)",
+ "destruct()",
+ ],
+ "QgsRasterRendererRegistry": [
+ "insert(const QgsRasterRendererRegistryEntry &entry)",
+ "entries() const",
+ "renderersList() const",
+ "insertWidgetFunction(const QString &rendererName, QgsRasterRendererWidgetCreateFunc func)",
+ "rendererData(const QString &rendererName, QgsRasterRendererRegistryEntry &data) const",
+ ],
+ "QgsAdvancedDigitizingCanvasItem": [
+ "QgsAdvancedDigitizingCanvasItem(QgsMapCanvas *canvas, QgsAdvancedDigitizingDockWidget *cadDockWidget)"
+ ],
"QgsSimplifyMethod": ["MethodType"],
- "QgsExpressionItem": ["QgsExpressionItem(const QString &label, const QString &expressionText, QgsExpressionItem::ItemType itemType=ExpressionNode)", "ItemType", "QgsExpressionItem(const QString &label, const QString &expressionText, const QString &helpText, QgsExpressionItem::ItemType itemType=ExpressionNode)", "getExpressionText() const"],
- "QgsCptCityBrowserModel": ["endInsertItems()", "connectItem(QgsCptCityDataItem *item)", "QgsCptCityBrowserModel(QObject *parent=nullptr, QgsCptCityArchive *archive=QgsCptCityArchive::defaultArchive(), ViewType Type=Authors)", "refresh(const QString &path)", "reload()", "findItem(QgsCptCityDataItem *item, QgsCptCityDataItem *parent=nullptr) const", "refresh(const QModelIndex &index=QModelIndex())", "addRootItems()", "beginRemoveItems(QgsCptCityDataItem *parent, int first, int last)", "removeRootItems()", "endRemoveItems()", "ViewType", "beginInsertItems(QgsCptCityDataItem *parent, int first, int last)"],
- "QgsDxfPaintEngine": ["setLayer(const QString &layer)", "layer() const", "setShift(QPointF shift)", "QgsDxfPaintEngine(const QgsDxfPaintDevice *dxfDevice, QgsDxfExport *dxf)"],
+ "QgsExpressionItem": [
+ "QgsExpressionItem(const QString &label, const QString &expressionText, QgsExpressionItem::ItemType itemType=ExpressionNode)",
+ "ItemType",
+ "QgsExpressionItem(const QString &label, const QString &expressionText, const QString &helpText, QgsExpressionItem::ItemType itemType=ExpressionNode)",
+ "getExpressionText() const",
+ ],
+ "QgsCptCityBrowserModel": [
+ "endInsertItems()",
+ "connectItem(QgsCptCityDataItem *item)",
+ "QgsCptCityBrowserModel(QObject *parent=nullptr, QgsCptCityArchive *archive=QgsCptCityArchive::defaultArchive(), ViewType Type=Authors)",
+ "refresh(const QString &path)",
+ "reload()",
+ "findItem(QgsCptCityDataItem *item, QgsCptCityDataItem *parent=nullptr) const",
+ "refresh(const QModelIndex &index=QModelIndex())",
+ "addRootItems()",
+ "beginRemoveItems(QgsCptCityDataItem *parent, int first, int last)",
+ "removeRootItems()",
+ "endRemoveItems()",
+ "ViewType",
+ "beginInsertItems(QgsCptCityDataItem *parent, int first, int last)",
+ ],
+ "QgsDxfPaintEngine": [
+ "setLayer(const QString &layer)",
+ "layer() const",
+ "setShift(QPointF shift)",
+ "QgsDxfPaintEngine(const QgsDxfPaintDevice *dxfDevice, QgsDxfExport *dxf)",
+ ],
"QgsGeometryRubberBand": ["IconType"],
"QgsProject": ["relationManager() const"],
- "QgsMapLayerLegendUtils": ["hasLegendNodeOrder(QgsLayerTreeLayer *nodeLayer)", "legendNodeOrder(QgsLayerTreeLayer *nodeLayer)", "hasLegendNodeUserLabel(QgsLayerTreeLayer *nodeLayer, int originalIndex)", "legendNodeUserLabel(QgsLayerTreeLayer *nodeLayer, int originalIndex)", "setLegendNodeOrder(QgsLayerTreeLayer *nodeLayer, const QList< int > &order)", "setLegendNodeUserLabel(QgsLayerTreeLayer *nodeLayer, int originalIndex, const QString &newLabel)"],
+ "QgsMapLayerLegendUtils": [
+ "hasLegendNodeOrder(QgsLayerTreeLayer *nodeLayer)",
+ "legendNodeOrder(QgsLayerTreeLayer *nodeLayer)",
+ "hasLegendNodeUserLabel(QgsLayerTreeLayer *nodeLayer, int originalIndex)",
+ "legendNodeUserLabel(QgsLayerTreeLayer *nodeLayer, int originalIndex)",
+ "setLegendNodeOrder(QgsLayerTreeLayer *nodeLayer, const QList< int > &order)",
+ "setLegendNodeUserLabel(QgsLayerTreeLayer *nodeLayer, int originalIndex, const QString &newLabel)",
+ ],
"QgsTransformWidget": ["create()", "QgsTransformWidget(QWidget *parent=nullptr)"],
"QgsBusyIndicatorDialog": ["message() const", "setMessage(const QString &message)"],
- "QgsSingleBandPseudoColorRenderer": ["classificationMax() const", "setClassificationMax(double max)", "create(const QDomElement &elem, QgsRasterInterface *input)", "setClassificationMin(double min)", "classificationMin() const"],
- "QgsShapeburstFillSymbolLayerWidget": ["setColor2(const QColor &color)", "setColor(const QColor &color)"],
+ "QgsSingleBandPseudoColorRenderer": [
+ "classificationMax() const",
+ "setClassificationMax(double max)",
+ "create(const QDomElement &elem, QgsRasterInterface *input)",
+ "setClassificationMin(double min)",
+ "classificationMin() const",
+ ],
+ "QgsShapeburstFillSymbolLayerWidget": [
+ "setColor2(const QColor &color)",
+ "setColor(const QColor &color)",
+ ],
"QgsExpression": ["SpatialOperator", "BuiltinFunctions()", "Functions()"],
"EditBlockerDelegate": ["EditBlockerDelegate(QObject *parent=nullptr)"],
- "QgsGeometryMultipartCheck": ["factoryDescription()", "QgsGeometryMultipartCheck(QgsGeometryCheckContext *context, const QVariantMap &configuration)", "ResolutionMethod", "factoryCompatibleGeometryTypes()", "factoryCheckType()", "factoryIsCompatible(QgsVectorLayer *layer)", "factoryId()"],
- "QgsGenericFeatureSelectionManager": ["QgsGenericFeatureSelectionManager(QObject *parent=nullptr)", "QgsGenericFeatureSelectionManager(const QgsFeatureIds &initialSelection, QObject *parent=nullptr)"],
+ "QgsGeometryMultipartCheck": [
+ "factoryDescription()",
+ "QgsGeometryMultipartCheck(QgsGeometryCheckContext *context, const QVariantMap &configuration)",
+ "ResolutionMethod",
+ "factoryCompatibleGeometryTypes()",
+ "factoryCheckType()",
+ "factoryIsCompatible(QgsVectorLayer *layer)",
+ "factoryId()",
+ ],
+ "QgsGenericFeatureSelectionManager": [
+ "QgsGenericFeatureSelectionManager(QObject *parent=nullptr)",
+ "QgsGenericFeatureSelectionManager(const QgsFeatureIds &initialSelection, QObject *parent=nullptr)",
+ ],
"QgsAbstractGeometry": ["QgsAbstractGeometry(const QgsAbstractGeometry &geom)"],
- "QgsMeshDatasetGroupSaveMenu": ["createSaveMenu(int groupIndex, QMenu *parentMenu=nullptr)", "setMeshLayer(QgsMeshLayer *meshLayer)", "QgsMeshDatasetGroupSaveMenu(QObject *parent=nullptr)", "datasetGroupSaved(const QString &uri)"],
- "QgsBrightnessContrastFilter": ["QgsBrightnessContrastFilter(QgsRasterInterface *input=nullptr)"],
- "QgsRasterRenderer": ["rasterTransparency() const", "usesTransparency() const", "setAlphaBand(int band)", "alphaBand() const", "setRasterTransparency(QgsRasterTransparency *t)"],
+ "QgsMeshDatasetGroupSaveMenu": [
+ "createSaveMenu(int groupIndex, QMenu *parentMenu=nullptr)",
+ "setMeshLayer(QgsMeshLayer *meshLayer)",
+ "QgsMeshDatasetGroupSaveMenu(QObject *parent=nullptr)",
+ "datasetGroupSaved(const QString &uri)",
+ ],
+ "QgsBrightnessContrastFilter": [
+ "QgsBrightnessContrastFilter(QgsRasterInterface *input=nullptr)"
+ ],
+ "QgsRasterRenderer": [
+ "rasterTransparency() const",
+ "usesTransparency() const",
+ "setAlphaBand(int band)",
+ "alphaBand() const",
+ "setRasterTransparency(QgsRasterTransparency *t)",
+ ],
"QgsDiagramLayerSettings": ["Placement"],
- "QgsPalettedRendererWidget": ["create(QgsRasterLayer *layer, const QgsRectangle &extent)", "QgsPalettedRendererWidget(QgsRasterLayer *layer, const QgsRectangle &extent=QgsRectangle())"],
+ "QgsPalettedRendererWidget": [
+ "create(QgsRasterLayer *layer, const QgsRectangle &extent)",
+ "QgsPalettedRendererWidget(QgsRasterLayer *layer, const QgsRectangle &extent=QgsRectangle())",
+ ],
"CharacterWidget": ["updateFontMerging(bool enable)"],
"QgsDataDefinedValueDialog": ["dataDefinedChanged()"],
- "QgsSlopeFilter": ["QgsSlopeFilter(const QString &inputFile, const QString &outputFile, const QString &outputFormat)"],
- "QgsLayerPropertiesWidget": ["populateLayerTypes()", "changed()", "changeLayer(QgsSymbolLayer *)", "emitSignalChanged()", "layerTypeChanged()", "updateSymbolLayerWidget(QgsSymbolLayer *layer)"],
- "QgsVectorLayerCache": ["QgsVectorLayerCache(QgsVectorLayer *layer, int cacheSize, QObject *parent=nullptr)"],
+ "QgsSlopeFilter": [
+ "QgsSlopeFilter(const QString &inputFile, const QString &outputFile, const QString &outputFormat)"
+ ],
+ "QgsLayerPropertiesWidget": [
+ "populateLayerTypes()",
+ "changed()",
+ "changeLayer(QgsSymbolLayer *)",
+ "emitSignalChanged()",
+ "layerTypeChanged()",
+ "updateSymbolLayerWidget(QgsSymbolLayer *layer)",
+ ],
+ "QgsVectorLayerCache": [
+ "QgsVectorLayerCache(QgsVectorLayer *layer, int cacheSize, QObject *parent=nullptr)"
+ ],
"QgsAttributeTableAction": ["execute()", "featureForm()"],
- "QgsAttributesFormProperties::DnDTreeItemData": ["visibilityExpression() const", "setQmlElementEditorConfiguration(QmlElementEditorConfiguration qmlElementEditorConfiguration)", "operator QVariant()", "setType(Type type)", "setShowLabel(bool showLabel)", "setDisplayName(const QString &displayName)", "DnDTreeItemData(Type type, const QString &name, const QString &displayName, const QColor &backgroundColor=QColor())", "setColumnCount(int count)", "displayName() const", "backgroundColor() const", "columnCount() const", "htmlElementEditorConfiguration() const", "type() const", "setHtmlElementEditorConfiguration(HtmlElementEditorConfiguration htmlElementEditorConfiguration)", "Type", "name() const", "relationEditorConfiguration() const", "qmlElementEditorConfiguration() const", "showLabel() const", "DnDTreeItemData()=default", "setRelationEditorConfiguration(RelationEditorConfiguration relationEditorConfiguration)", "setName(const QString &name)", "setBackgroundColor(const QColor &backgroundColor)"],
- "QgsVectorFieldSymbolLayer": ["angleUnits() const", "vectorFieldType() const", "createFromSld(QDomElement &element)", "xAttribute() const", "setAngleOrientation(AngleOrientation orientation)", "setScale(double s)", "AngleUnits", "setVectorFieldType(VectorFieldType type)", "yAttribute() const", "scale() const", "setXAttribute(const QString &attribute)", "AngleOrientation", "setAngleUnits(AngleUnits units)", "setDistanceMapUnitScale(const QgsMapUnitScale &scale)", "angleOrientation() const", "setYAttribute(const QString &attribute)", "distanceMapUnitScale() const", "VectorFieldType"],
- "QgsGeometryEngine": ["simplify(double tolerance, QString *errorMsg=nullptr) const =0", "interpolate(double distance, QString *errorMsg=nullptr) const =0", "envelope(QString *errorMsg=nullptr) const =0", "QgsGeometryEngine(const QgsAbstractGeometry *geometry)", "isEmpty(QString *errorMsg) const =0", "buffer(double distance, int segments, QString *errorMsg=nullptr) const =0", "area(QString *errorMsg=nullptr) const =0", "length(QString *errorMsg=nullptr) const =0"],
+ "QgsAttributesFormProperties::DnDTreeItemData": [
+ "visibilityExpression() const",
+ "setQmlElementEditorConfiguration(QmlElementEditorConfiguration qmlElementEditorConfiguration)",
+ "operator QVariant()",
+ "setType(Type type)",
+ "setShowLabel(bool showLabel)",
+ "setDisplayName(const QString &displayName)",
+ "DnDTreeItemData(Type type, const QString &name, const QString &displayName, const QColor &backgroundColor=QColor())",
+ "setColumnCount(int count)",
+ "displayName() const",
+ "backgroundColor() const",
+ "columnCount() const",
+ "htmlElementEditorConfiguration() const",
+ "type() const",
+ "setHtmlElementEditorConfiguration(HtmlElementEditorConfiguration htmlElementEditorConfiguration)",
+ "Type",
+ "name() const",
+ "relationEditorConfiguration() const",
+ "qmlElementEditorConfiguration() const",
+ "showLabel() const",
+ "DnDTreeItemData()=default",
+ "setRelationEditorConfiguration(RelationEditorConfiguration relationEditorConfiguration)",
+ "setName(const QString &name)",
+ "setBackgroundColor(const QColor &backgroundColor)",
+ ],
+ "QgsVectorFieldSymbolLayer": [
+ "angleUnits() const",
+ "vectorFieldType() const",
+ "createFromSld(QDomElement &element)",
+ "xAttribute() const",
+ "setAngleOrientation(AngleOrientation orientation)",
+ "setScale(double s)",
+ "AngleUnits",
+ "setVectorFieldType(VectorFieldType type)",
+ "yAttribute() const",
+ "scale() const",
+ "setXAttribute(const QString &attribute)",
+ "AngleOrientation",
+ "setAngleUnits(AngleUnits units)",
+ "setDistanceMapUnitScale(const QgsMapUnitScale &scale)",
+ "angleOrientation() const",
+ "setYAttribute(const QString &attribute)",
+ "distanceMapUnitScale() const",
+ "VectorFieldType",
+ ],
+ "QgsGeometryEngine": [
+ "simplify(double tolerance, QString *errorMsg=nullptr) const =0",
+ "interpolate(double distance, QString *errorMsg=nullptr) const =0",
+ "envelope(QString *errorMsg=nullptr) const =0",
+ "QgsGeometryEngine(const QgsAbstractGeometry *geometry)",
+ "isEmpty(QString *errorMsg) const =0",
+ "buffer(double distance, int segments, QString *errorMsg=nullptr) const =0",
+ "area(QString *errorMsg=nullptr) const =0",
+ "length(QString *errorMsg=nullptr) const =0",
+ ],
"QgsRenderContext": ["QgsRenderContext(const QgsRenderContext &rh)"],
- "QgsCptCityDirectoryItem": ["dataItem(QgsCptCityDataItem *parent, const QString &name, const QString &path)", "QgsCptCityDirectoryItem(QgsCptCityDataItem *parent, const QString &name, const QString &path)", "dirEntries() const", "rampsMap()"],
+ "QgsCptCityDirectoryItem": [
+ "dataItem(QgsCptCityDataItem *parent, const QString &name, const QString &path)",
+ "QgsCptCityDirectoryItem(QgsCptCityDataItem *parent, const QString &name, const QString &path)",
+ "dirEntries() const",
+ "rampsMap()",
+ ],
"QgsGeometryValidator": ["addError(const QgsGeometry::Error &)", "stop()"],
"QgsWms::QgsWmsParameters": ["PdfFormatOption"],
- "QgsConstWkbPtr": ["operator>>(float &r) const", "operator const unsigned char *() const", "operator-=(int n) const", "operator+=(int n) const", "QgsConstWkbPtr(const unsigned char *p, int size)", "operator>>(double &v) const", "operator>>(int &v) const", "operator>>(unsigned int &v) const", "operator>>(char &v) const"],
- "QgsLineSymbolLayer": ["widthMapUnitScale() const", "setWidthMapUnitScale(const QgsMapUnitScale &scale)", "QgsLineSymbolLayer(bool locked=false)"],
- "QgsMapOverviewCanvas": ["updateFullExtent()", "mapRenderingFinished()", "enableAntiAliasing(bool flag)", "QgsMapOverviewCanvas(QWidget *parent=nullptr, QgsMapCanvas *mapCanvas=nullptr)"],
- "QgsDxfPaintDevice": ["setLayer(const QString &layer)", "QgsDxfPaintDevice(QgsDxfExport *dxf)", "setOutputSize(const QRectF &r)", "setDrawingSize(QSizeF size)", "setShift(QPointF shift)"],
- "QgsVectorLayerEditPassthrough": ["QgsVectorLayerEditPassthrough(QgsVectorLayer *layer)"],
- "QgsGeometrySelfContactCheck": ["QgsGeometrySelfContactCheck(QgsGeometryCheckContext *context, const QVariantMap &configuration)", "factoryDescription()", "ResolutionMethod", "factoryCompatibleGeometryTypes()", "factoryCheckType()", "factoryIsCompatible(QgsVectorLayer *layer)", "factoryId()"],
- "QgsCollapsibleGroupBoxBasic": ["clearModifiers()", "titleRect() const", "QgsCollapsibleGroupBoxBasic(QWidget *parent=nullptr)", "QgsCollapsibleGroupBoxBasic(const QString &title, QWidget *parent=nullptr)", "checkToggled(bool ckd)", "checkClicked(bool ckd)", "toggleCollapsed()", "updateStyle()", "init()"],
- "QgsPenJoinStyleComboBox": ["setPenJoinStyle(Qt::PenJoinStyle style)", "QgsPenJoinStyleComboBox(QWidget *parent=nullptr)", "penJoinStyle() const"],
- "QgsAttributeActionPropertiesDialog": ["QgsAttributeActionPropertiesDialog(QgsVectorLayer *layer, QWidget *parent=nullptr)", "shortTitle() const", "notificationMessage() const", "type() const", "description() const", "actionText() const", "isEnabledOnlyWhenEditable() const", "capture() const", "iconPath() const", "actionScopes() const"],
- "QgsInterpolator": ["QgsInterpolator(const QList< QgsInterpolator::LayerData > &layerData)"],
- "QgsCptCityCollectionItem": ["setPopulated()", "childrenRamps(bool recursive)", "addChild(QgsCptCityDataItem *item)", "QgsCptCityCollectionItem(QgsCptCityDataItem *parent, const QString &name, const QString &path)"],
+ "QgsConstWkbPtr": [
+ "operator>>(float &r) const",
+ "operator const unsigned char *() const",
+ "operator-=(int n) const",
+ "operator+=(int n) const",
+ "QgsConstWkbPtr(const unsigned char *p, int size)",
+ "operator>>(double &v) const",
+ "operator>>(int &v) const",
+ "operator>>(unsigned int &v) const",
+ "operator>>(char &v) const",
+ ],
+ "QgsLineSymbolLayer": [
+ "widthMapUnitScale() const",
+ "setWidthMapUnitScale(const QgsMapUnitScale &scale)",
+ "QgsLineSymbolLayer(bool locked=false)",
+ ],
+ "QgsMapOverviewCanvas": [
+ "updateFullExtent()",
+ "mapRenderingFinished()",
+ "enableAntiAliasing(bool flag)",
+ "QgsMapOverviewCanvas(QWidget *parent=nullptr, QgsMapCanvas *mapCanvas=nullptr)",
+ ],
+ "QgsDxfPaintDevice": [
+ "setLayer(const QString &layer)",
+ "QgsDxfPaintDevice(QgsDxfExport *dxf)",
+ "setOutputSize(const QRectF &r)",
+ "setDrawingSize(QSizeF size)",
+ "setShift(QPointF shift)",
+ ],
+ "QgsVectorLayerEditPassthrough": [
+ "QgsVectorLayerEditPassthrough(QgsVectorLayer *layer)"
+ ],
+ "QgsGeometrySelfContactCheck": [
+ "QgsGeometrySelfContactCheck(QgsGeometryCheckContext *context, const QVariantMap &configuration)",
+ "factoryDescription()",
+ "ResolutionMethod",
+ "factoryCompatibleGeometryTypes()",
+ "factoryCheckType()",
+ "factoryIsCompatible(QgsVectorLayer *layer)",
+ "factoryId()",
+ ],
+ "QgsCollapsibleGroupBoxBasic": [
+ "clearModifiers()",
+ "titleRect() const",
+ "QgsCollapsibleGroupBoxBasic(QWidget *parent=nullptr)",
+ "QgsCollapsibleGroupBoxBasic(const QString &title, QWidget *parent=nullptr)",
+ "checkToggled(bool ckd)",
+ "checkClicked(bool ckd)",
+ "toggleCollapsed()",
+ "updateStyle()",
+ "init()",
+ ],
+ "QgsPenJoinStyleComboBox": [
+ "setPenJoinStyle(Qt::PenJoinStyle style)",
+ "QgsPenJoinStyleComboBox(QWidget *parent=nullptr)",
+ "penJoinStyle() const",
+ ],
+ "QgsAttributeActionPropertiesDialog": [
+ "QgsAttributeActionPropertiesDialog(QgsVectorLayer *layer, QWidget *parent=nullptr)",
+ "shortTitle() const",
+ "notificationMessage() const",
+ "type() const",
+ "description() const",
+ "actionText() const",
+ "isEnabledOnlyWhenEditable() const",
+ "capture() const",
+ "iconPath() const",
+ "actionScopes() const",
+ ],
+ "QgsInterpolator": [
+ "QgsInterpolator(const QList< QgsInterpolator::LayerData > &layerData)"
+ ],
+ "QgsCptCityCollectionItem": [
+ "setPopulated()",
+ "childrenRamps(bool recursive)",
+ "addChild(QgsCptCityDataItem *item)",
+ "QgsCptCityCollectionItem(QgsCptCityDataItem *parent, const QString &name, const QString &path)",
+ ],
"QgsRasterChecker": ["report() const"],
- "QgsRasterInterface": ["yBlockSize() const", "ySize() const", "QgsRasterInterface(QgsRasterInterface *input=nullptr)"],
+ "QgsRasterInterface": [
+ "yBlockSize() const",
+ "ySize() const",
+ "QgsRasterInterface(QgsRasterInterface *input=nullptr)",
+ ],
"HalfEdge": ["HalfEdge(int dual, int next, int point, bool mbreak, bool forced)"],
- "QgsRasterLayerRenderer": ["QgsRasterLayerRenderer(QgsRasterLayer *layer, QgsRenderContext &rendererContext)"],
- "QgsGeometrySelfIntersectionCheck": ["QgsGeometrySelfIntersectionCheck(const QgsGeometryCheckContext *context, const QVariantMap &configuration=QVariantMap())", "ResolutionMethod"],
+ "QgsRasterLayerRenderer": [
+ "QgsRasterLayerRenderer(QgsRasterLayer *layer, QgsRenderContext &rendererContext)"
+ ],
+ "QgsGeometrySelfIntersectionCheck": [
+ "QgsGeometrySelfIntersectionCheck(const QgsGeometryCheckContext *context, const QVariantMap &configuration=QVariantMap())",
+ "ResolutionMethod",
+ ],
"QgsOfflineEditing": ["ProgressMode"],
- "QgsMeshDatasetGroupTreeView": ["resetDefault(QgsMeshLayer *meshLayer)", "apply()", "selectAllGroups()", "QgsMeshDatasetGroupTreeView(QWidget *parent=nullptr)", "syncToLayer(QgsMeshLayer *layer)", "deselectAllGroups()", "datasetGroupTreeRootItem()"],
+ "QgsMeshDatasetGroupTreeView": [
+ "resetDefault(QgsMeshLayer *meshLayer)",
+ "apply()",
+ "selectAllGroups()",
+ "QgsMeshDatasetGroupTreeView(QWidget *parent=nullptr)",
+ "syncToLayer(QgsMeshLayer *layer)",
+ "deselectAllGroups()",
+ "datasetGroupTreeRootItem()",
+ ],
"QgsMapLayerComboBox": ["indexChanged(int i)", "rowsChanged()"],
- "QgsGeometryTypeCheck": ["factoryDescription()", "QgsGeometryTypeCheck(QgsGeometryCheckContext *context, const QVariantMap &configuration, int allowedTypes)", "factoryCompatibleGeometryTypes()", "factoryCheckType()", "factoryIsCompatible(QgsVectorLayer *layer)", "factoryId()"],
- "QgsRendererWidget": ["QgsRendererWidget(QgsVectorLayer *layer, QgsStyle *style)", "copy()", "contextMenuViewCategories(QPoint p)", "paste()", "refreshSymbolView()"],
- "QgsVectorLayerProperties": ["toggleEditing(QgsMapLayer *)", "exportAuxiliaryLayer(QgsAuxiliaryLayer *layer)", "QgsVectorLayerProperties(QgsMapCanvas *canvas, QgsMessageBar *messageBar, QgsVectorLayer *lyr=nullptr, QWidget *parent=nullptr, Qt::WindowFlags fl=QgsGuiUtils::ModalDialogFlags)"],
- "QgsGeometrySelfIntersectionCheckError": ["QgsGeometrySelfIntersectionCheckError(const QgsSingleGeometryCheck *check, const QgsGeometry &geometry, const QgsGeometry &errorLocation, QgsVertexId vertexId, const QgsGeometryUtils::SelfIntersection &intersection)", "intersection() const"],
- "QgsSingleSymbolRendererWidget": ["QgsSingleSymbolRendererWidget(QgsVectorLayer *layer, QgsStyle *style, QgsFeatureRenderer *renderer)", "create(QgsVectorLayer *layer, QgsStyle *style, QgsFeatureRenderer *renderer)"],
+ "QgsGeometryTypeCheck": [
+ "factoryDescription()",
+ "QgsGeometryTypeCheck(QgsGeometryCheckContext *context, const QVariantMap &configuration, int allowedTypes)",
+ "factoryCompatibleGeometryTypes()",
+ "factoryCheckType()",
+ "factoryIsCompatible(QgsVectorLayer *layer)",
+ "factoryId()",
+ ],
+ "QgsRendererWidget": [
+ "QgsRendererWidget(QgsVectorLayer *layer, QgsStyle *style)",
+ "copy()",
+ "contextMenuViewCategories(QPoint p)",
+ "paste()",
+ "refreshSymbolView()",
+ ],
+ "QgsVectorLayerProperties": [
+ "toggleEditing(QgsMapLayer *)",
+ "exportAuxiliaryLayer(QgsAuxiliaryLayer *layer)",
+ "QgsVectorLayerProperties(QgsMapCanvas *canvas, QgsMessageBar *messageBar, QgsVectorLayer *lyr=nullptr, QWidget *parent=nullptr, Qt::WindowFlags fl=QgsGuiUtils::ModalDialogFlags)",
+ ],
+ "QgsGeometrySelfIntersectionCheckError": [
+ "QgsGeometrySelfIntersectionCheckError(const QgsSingleGeometryCheck *check, const QgsGeometry &geometry, const QgsGeometry &errorLocation, QgsVertexId vertexId, const QgsGeometryUtils::SelfIntersection &intersection)",
+ "intersection() const",
+ ],
+ "QgsSingleSymbolRendererWidget": [
+ "QgsSingleSymbolRendererWidget(QgsVectorLayer *layer, QgsStyle *style, QgsFeatureRenderer *renderer)",
+ "create(QgsVectorLayer *layer, QgsStyle *style, QgsFeatureRenderer *renderer)",
+ ],
"QgsCategorizedSymbolRenderer": ["rebuildHash()"],
"QgsDualView": ["openConditionalStyles()"],
- "QgsRuleBasedLabelProvider": ["QgsRuleBasedLabelProvider(const QgsRuleBasedLabeling &rules, QgsVectorLayer *layer, bool withFeatureLoop=true)"],
+ "QgsRuleBasedLabelProvider": [
+ "QgsRuleBasedLabelProvider(const QgsRuleBasedLabeling &rules, QgsVectorLayer *layer, bool withFeatureLoop=true)"
+ ],
"QgsMapToolAdvancedDigitizing": ["cadDockWidget() const"],
- "QgsOptionsDialogBase": ["warnAboutMissingObjects()", "updateWindowTitle()", "setSettings(QgsSettings *settings)"],
- "QgsSymbolsListWidget": ["updateDataDefinedMarkerAngle()", "setMarkerSize(double size)", "changed()", "setLineWidth(double width)", "updateDataDefinedMarkerSize()", "setMarkerAngle(double angle)", "clipFeaturesToggled(bool checked)", "updateDataDefinedLineWidth()", "setSymbolColor(const QColor &color)"],
- "QgsRasterShader": ["rasterShaderFunction() const", "QgsRasterShader(double minimumValue=0.0, double maximumValue=255.0)", "rasterShaderFunction()"],
- "QgsGeometryAreaCheck": ["factoryDescription()", "QgsGeometryAreaCheck(QgsGeometryCheckContext *context, const QVariantMap &configuration)", "ResolutionMethod", "factoryCompatibleGeometryTypes()", "factoryCheckType()", "factoryIsCompatible(QgsVectorLayer *layer)", "factoryId()"],
- "QgsWkbPtr": ["operator>>(float &r) const", "QgsWkbPtr(unsigned char *p, int size)", "operator+=(int n) const", "operator>>(double &v) const", "operator unsigned char *() const"],
+ "QgsOptionsDialogBase": [
+ "warnAboutMissingObjects()",
+ "updateWindowTitle()",
+ "setSettings(QgsSettings *settings)",
+ ],
+ "QgsSymbolsListWidget": [
+ "updateDataDefinedMarkerAngle()",
+ "setMarkerSize(double size)",
+ "changed()",
+ "setLineWidth(double width)",
+ "updateDataDefinedMarkerSize()",
+ "setMarkerAngle(double angle)",
+ "clipFeaturesToggled(bool checked)",
+ "updateDataDefinedLineWidth()",
+ "setSymbolColor(const QColor &color)",
+ ],
+ "QgsRasterShader": [
+ "rasterShaderFunction() const",
+ "QgsRasterShader(double minimumValue=0.0, double maximumValue=255.0)",
+ "rasterShaderFunction()",
+ ],
+ "QgsGeometryAreaCheck": [
+ "factoryDescription()",
+ "QgsGeometryAreaCheck(QgsGeometryCheckContext *context, const QVariantMap &configuration)",
+ "ResolutionMethod",
+ "factoryCompatibleGeometryTypes()",
+ "factoryCheckType()",
+ "factoryIsCompatible(QgsVectorLayer *layer)",
+ "factoryId()",
+ ],
+ "QgsWkbPtr": [
+ "operator>>(float &r) const",
+ "QgsWkbPtr(unsigned char *p, int size)",
+ "operator+=(int n) const",
+ "operator>>(double &v) const",
+ "operator unsigned char *() const",
+ ],
"QgsMapToolEdit": ["QgsMapToolEdit(QgsMapCanvas *canvas)"],
"QgsSymbolLegendNode": ["iconSize() const"],
- "QgsDataDefinedSizeDialog": ["QgsDataDefinedSizeDialog(const QList< QgsSymbol * > &symbolList, QgsVectorLayer *layer)"],
- "QgsGeometryDuplicateNodesCheck": ["QgsGeometryDuplicateNodesCheck(QgsGeometryCheckContext *context, const QVariantMap &configuration)", "factoryDescription()", "ResolutionMethod", "factoryCompatibleGeometryTypes()", "factoryCheckType()", "factoryIsCompatible(QgsVectorLayer *layer)", "factoryId()"],
- "QgsTotalCurvatureFilter": ["QgsTotalCurvatureFilter(const QString &inputFile, const QString &outputFile, const QString &outputFormat)"],
- "QgsAttributeFormInterface": ["featureChanged()", "form()", "feature()", "QgsAttributeFormInterface(QgsAttributeForm *form)", "acceptChanges(const QgsFeature &feature)", "initForm()"],
- "QgsGeometryPointCoveredByLineCheck": ["factoryDescription()", "ResolutionMethod", "factoryCompatibleGeometryTypes()", "QgsGeometryPointCoveredByLineCheck(QgsGeometryCheckContext *context, const QVariantMap &configuration)", "factoryCheckType()", "factoryIsCompatible(QgsVectorLayer *layer)", "factoryId()"],
- "QgsGeometryContainedCheckError": ["QgsGeometryContainedCheckError(const QgsGeometryCheck *check, const QgsGeometryCheckerUtils::LayerFeature &layerFeature, const QgsPointXY &errorLocation, const QgsGeometryCheckerUtils::LayerFeature &containingFeature)", "containingFeature() const"],
+ "QgsDataDefinedSizeDialog": [
+ "QgsDataDefinedSizeDialog(const QList< QgsSymbol * > &symbolList, QgsVectorLayer *layer)"
+ ],
+ "QgsGeometryDuplicateNodesCheck": [
+ "QgsGeometryDuplicateNodesCheck(QgsGeometryCheckContext *context, const QVariantMap &configuration)",
+ "factoryDescription()",
+ "ResolutionMethod",
+ "factoryCompatibleGeometryTypes()",
+ "factoryCheckType()",
+ "factoryIsCompatible(QgsVectorLayer *layer)",
+ "factoryId()",
+ ],
+ "QgsTotalCurvatureFilter": [
+ "QgsTotalCurvatureFilter(const QString &inputFile, const QString &outputFile, const QString &outputFormat)"
+ ],
+ "QgsAttributeFormInterface": [
+ "featureChanged()",
+ "form()",
+ "feature()",
+ "QgsAttributeFormInterface(QgsAttributeForm *form)",
+ "acceptChanges(const QgsFeature &feature)",
+ "initForm()",
+ ],
+ "QgsGeometryPointCoveredByLineCheck": [
+ "factoryDescription()",
+ "ResolutionMethod",
+ "factoryCompatibleGeometryTypes()",
+ "QgsGeometryPointCoveredByLineCheck(QgsGeometryCheckContext *context, const QVariantMap &configuration)",
+ "factoryCheckType()",
+ "factoryIsCompatible(QgsVectorLayer *layer)",
+ "factoryId()",
+ ],
+ "QgsGeometryContainedCheckError": [
+ "QgsGeometryContainedCheckError(const QgsGeometryCheck *check, const QgsGeometryCheckerUtils::LayerFeature &layerFeature, const QgsPointXY &errorLocation, const QgsGeometryCheckerUtils::LayerFeature &containingFeature)",
+ "containingFeature() const",
+ ],
"QgsAuthCertInfo": ["trustCacheRebuilt()"],
- "QgsGeometryHoleCheck": ["factoryDescription()", "factoryIsCompatible(QgsVectorLayer *layer)", "ResolutionMethod", "factoryCompatibleGeometryTypes()", "factoryCheckType()", "QgsGeometryHoleCheck(QgsGeometryCheckContext *context, const QVariantMap &configuration)", "factoryId()"],
+ "QgsGeometryHoleCheck": [
+ "factoryDescription()",
+ "factoryIsCompatible(QgsVectorLayer *layer)",
+ "ResolutionMethod",
+ "factoryCompatibleGeometryTypes()",
+ "factoryCheckType()",
+ "QgsGeometryHoleCheck(QgsGeometryCheckContext *context, const QVariantMap &configuration)",
+ "factoryId()",
+ ],
"QgsMapRendererJob": ["QgsMapRendererJob(const QgsMapSettings &settings)"],
"QgsRendererCategory": ["swap(QgsRendererCategory &other)"],
"pal::Problem": ["init_sol_falp()", "reduce()"],
"QgsPaintEffectWidget": ["QgsPaintEffectWidget(QWidget *parent=nullptr)"],
- "QgsBrowserTreeView": ["setSettingsSection(const QString §ion)", "hasExpandedDescendant(const QModelIndex &index) const"],
+ "QgsBrowserTreeView": [
+ "setSettingsSection(const QString §ion)",
+ "hasExpandedDescendant(const QModelIndex &index) const",
+ ],
"QgsAttributeTypeLoadDialog": ["QgsAttributeTypeLoadDialog(QgsVectorLayer *vl)"],
- "QgsMapSettings": ["updateDerived()", "readXml(QDomNode &node)", "writeXml(QDomNode &node, QDomDocument &doc)", "mapToPixel() const"],
- "QgsManageConnectionsDialog": ["selectionChanged()", "clearSelection()", "doExportImport()", "Mode", "selectAll()", "Type"],
+ "QgsMapSettings": [
+ "updateDerived()",
+ "readXml(QDomNode &node)",
+ "writeXml(QDomNode &node, QDomDocument &doc)",
+ "mapToPixel() const",
+ ],
+ "QgsManageConnectionsDialog": [
+ "selectionChanged()",
+ "clearSelection()",
+ "doExportImport()",
+ "Mode",
+ "selectAll()",
+ "Type",
+ ],
"QgsLayerTreeNode": ["QgsLayerTreeNode(const QgsLayerTreeNode &other)"],
- "QgsPointLocator_VisitorNearestVertex": ["QgsPointLocator_VisitorNearestVertex(QgsPointLocator *pl, QgsPointLocator::Match &m, const QgsPointXY &srcPoint, QgsPointLocator::MatchFilter *filter=nullptr)"],
- "QgsErrorItem": ["QgsErrorItem(QgsDataItem *parent, const QString &error, const QString &path)"],
- "QgsAttributeForm": ["QgsAttributeForm(QgsVectorLayer *vl, const QgsFeature &feature=QgsFeature(), const QgsAttributeEditorContext &context=QgsAttributeEditorContext(), QWidget *parent=nullptr)", "feature()"],
+ "QgsPointLocator_VisitorNearestVertex": [
+ "QgsPointLocator_VisitorNearestVertex(QgsPointLocator *pl, QgsPointLocator::Match &m, const QgsPointXY &srcPoint, QgsPointLocator::MatchFilter *filter=nullptr)"
+ ],
+ "QgsErrorItem": [
+ "QgsErrorItem(QgsDataItem *parent, const QString &error, const QString &path)"
+ ],
+ "QgsAttributeForm": [
+ "QgsAttributeForm(QgsVectorLayer *vl, const QgsFeature &feature=QgsFeature(), const QgsAttributeEditorContext &context=QgsAttributeEditorContext(), QWidget *parent=nullptr)",
+ "feature()",
+ ],
"QgsSocketMonitoringThread": ["run()"],
"QgsMeshDatasetGroupTreeWidget": ["datasetGroupAdded()"],
- "QgsWmsDimensionDialog": ["setInfo(const QgsMapLayerServerProperties::WmsDimensionInfo &info)", "QgsWmsDimensionDialog(QgsVectorLayer *layer, QStringList alreadyDefinedDimensions, QWidget *parent=nullptr, Qt::WindowFlags f=Qt::WindowFlags())", "info() const"],
- "QgsMapToolIdentify": ["formatChanged(QgsRasterLayer *layer)", "identifyMessage(const QString &)", "IdentifyMode", "identifyProgress(int, int)", "Type", "changedRasterResults(QList< QgsMapToolIdentify::IdentifyResult > &)"],
- "QgsEllipseSymbolLayer": ["createFromSld(QDomElement &element)", "strokeWidth() const", "strokeWidthMapUnitScale() const", "symbolWidth() const", "setStrokeWidth(double w)", "strokeStyle() const", "symbolHeight() const", "setSymbolHeightMapUnitScale(const QgsMapUnitScale &scale)", "setSymbolWidth(double w)", "symbolWidthMapUnitScale() const", "setStrokeWidthMapUnitScale(const QgsMapUnitScale &scale)", "setSymbolWidthMapUnitScale(const QgsMapUnitScale &scale)", "setStrokeStyle(Qt::PenStyle strokeStyle)", "setSymbolHeight(double h)", "symbolHeightMapUnitScale() const"],
- "QgsPluginLayer": ["QgsPluginLayer(const QString &layerType, const QString &layerName=QString())"],
- "QgsMapRendererParallelJob": ["QgsMapRendererParallelJob(const QgsMapSettings &settings)"],
- "QgsVectorLayerFeatureIterator": ["QgsVectorLayerFeatureIterator(QgsVectorLayerFeatureSource *source, bool ownSource, const QgsFeatureRequest &request)"],
+ "QgsWmsDimensionDialog": [
+ "setInfo(const QgsMapLayerServerProperties::WmsDimensionInfo &info)",
+ "QgsWmsDimensionDialog(QgsVectorLayer *layer, QStringList alreadyDefinedDimensions, QWidget *parent=nullptr, Qt::WindowFlags f=Qt::WindowFlags())",
+ "info() const",
+ ],
+ "QgsMapToolIdentify": [
+ "formatChanged(QgsRasterLayer *layer)",
+ "identifyMessage(const QString &)",
+ "IdentifyMode",
+ "identifyProgress(int, int)",
+ "Type",
+ "changedRasterResults(QList< QgsMapToolIdentify::IdentifyResult > &)",
+ ],
+ "QgsEllipseSymbolLayer": [
+ "createFromSld(QDomElement &element)",
+ "strokeWidth() const",
+ "strokeWidthMapUnitScale() const",
+ "symbolWidth() const",
+ "setStrokeWidth(double w)",
+ "strokeStyle() const",
+ "symbolHeight() const",
+ "setSymbolHeightMapUnitScale(const QgsMapUnitScale &scale)",
+ "setSymbolWidth(double w)",
+ "symbolWidthMapUnitScale() const",
+ "setStrokeWidthMapUnitScale(const QgsMapUnitScale &scale)",
+ "setSymbolWidthMapUnitScale(const QgsMapUnitScale &scale)",
+ "setStrokeStyle(Qt::PenStyle strokeStyle)",
+ "setSymbolHeight(double h)",
+ "symbolHeightMapUnitScale() const",
+ ],
+ "QgsPluginLayer": [
+ "QgsPluginLayer(const QString &layerType, const QString &layerName=QString())"
+ ],
+ "QgsMapRendererParallelJob": [
+ "QgsMapRendererParallelJob(const QgsMapSettings &settings)"
+ ],
+ "QgsVectorLayerFeatureIterator": [
+ "QgsVectorLayerFeatureIterator(QgsVectorLayerFeatureSource *source, bool ownSource, const QgsFeatureRequest &request)"
+ ],
"QgsMapLayer": ["readSld(const QDomNode &node, QString &errorMessage)"],
- "QgsFieldExpressionWidget": ["setLeftHandButtonStyle(bool isLeft)", "currentFieldChanged()", "isExpressionValid(const QString &expressionStr)"],
- "QgsContrastEnhancementFunction": ["QgsContrastEnhancementFunction(const QgsContrastEnhancementFunction &f)", "QgsContrastEnhancementFunction(Qgis::DataType, double, double)"],
- "QgsAttributeTableMapLayerAction": ["execute()", "QgsAttributeTableMapLayerAction(const QString &name, QgsDualView *dualView, QgsMapLayerAction *action, const QModelIndex &fieldIdx)"],
- "QgsSymbolLayerWidget": ["symbolLayer()=0", "setSymbolLayer(QgsSymbolLayer *layer)=0", "updateDataDefinedProperty()"],
- "QgsGeometryFollowBoundariesCheck": ["factoryDescription()", "QgsGeometryFollowBoundariesCheck(QgsGeometryCheckContext *context, const QVariantMap &configuration, QgsVectorLayer *checkLayer)", "factoryCompatibleGeometryTypes()", "factoryCheckType()", "factoryIsCompatible(QgsVectorLayer *layer)", "factoryId()"],
- "QgsLayerTreeView": ["onCurrentChanged()", "onExpandedChanged(QgsLayerTreeNode *node, bool expanded)", "updateExpandedStateToNode(const QModelIndex &index)", "modelRowsRemoved()", "updateExpandedStateFromNode(QgsLayerTreeNode *node)", "onModelReset()", "modelRowsInserted(const QModelIndex &index, int start, int end)", "layerForIndex(const QModelIndex &index) const"],
+ "QgsFieldExpressionWidget": [
+ "setLeftHandButtonStyle(bool isLeft)",
+ "currentFieldChanged()",
+ "isExpressionValid(const QString &expressionStr)",
+ ],
+ "QgsContrastEnhancementFunction": [
+ "QgsContrastEnhancementFunction(const QgsContrastEnhancementFunction &f)",
+ "QgsContrastEnhancementFunction(Qgis::DataType, double, double)",
+ ],
+ "QgsAttributeTableMapLayerAction": [
+ "execute()",
+ "QgsAttributeTableMapLayerAction(const QString &name, QgsDualView *dualView, QgsMapLayerAction *action, const QModelIndex &fieldIdx)",
+ ],
+ "QgsSymbolLayerWidget": [
+ "symbolLayer()=0",
+ "setSymbolLayer(QgsSymbolLayer *layer)=0",
+ "updateDataDefinedProperty()",
+ ],
+ "QgsGeometryFollowBoundariesCheck": [
+ "factoryDescription()",
+ "QgsGeometryFollowBoundariesCheck(QgsGeometryCheckContext *context, const QVariantMap &configuration, QgsVectorLayer *checkLayer)",
+ "factoryCompatibleGeometryTypes()",
+ "factoryCheckType()",
+ "factoryIsCompatible(QgsVectorLayer *layer)",
+ "factoryId()",
+ ],
+ "QgsLayerTreeView": [
+ "onCurrentChanged()",
+ "onExpandedChanged(QgsLayerTreeNode *node, bool expanded)",
+ "updateExpandedStateToNode(const QModelIndex &index)",
+ "modelRowsRemoved()",
+ "updateExpandedStateFromNode(QgsLayerTreeNode *node)",
+ "onModelReset()",
+ "modelRowsInserted(const QModelIndex &index, int start, int end)",
+ "layerForIndex(const QModelIndex &index) const",
+ ],
"CloughTocherInterpolator": ["setTriangulation(NormVecDecorator *tin)"],
"QgsDefaultVectorLayerLegend": ["QgsDefaultVectorLayerLegend(QgsVectorLayer *vl)"],
- "QgsAttributeEditorContext": ["QgsAttributeEditorContext(const QgsAttributeEditorContext &parentContext, FormMode formMode)", "FormMode", "QgsAttributeEditorContext(const QgsAttributeEditorContext &parentContext, const QgsRelation &relation, RelationMode relationMode, FormMode widgetMode)", "parentContext() const"],
+ "QgsAttributeEditorContext": [
+ "QgsAttributeEditorContext(const QgsAttributeEditorContext &parentContext, FormMode formMode)",
+ "FormMode",
+ "QgsAttributeEditorContext(const QgsAttributeEditorContext &parentContext, const QgsRelation &relation, RelationMode relationMode, FormMode widgetMode)",
+ "parentContext() const",
+ ],
"QgsGpsConnectionRegistry": ["connectionList() const"],
- "QgsGeometryDangleCheck": ["factoryDescription()", "QgsGeometryDangleCheck(QgsGeometryCheckContext *context, const QVariantMap &configuration)", "ResolutionMethod", "factoryCompatibleGeometryTypes()", "factoryCheckType()", "factoryIsCompatible(QgsVectorLayer *layer)", "factoryId()"],
- "QgsCptCityDataItem": ["icon()", "toolTip() const", "parent() const", "children() const", "hasChildren()", "populate()", "icon(QSize size)", "rowCount()", "paramWidget()", "handleDrop(const QMimeData *, Qt::DropAction)", "type() const", "beginRemoveItems(QgsCptCityDataItem *parent, int first, int last)", "endRemoveItems()", "path() const", "Type", "isPopulated()", "endInsertItems()", "name() const", "refresh()", "setIcon(const QIcon &icon)", "deleteChildItem(QgsCptCityDataItem *child)", "leafCount() const", "isValid()", "setToolTip(const QString &msg)", "createChildren()", "QgsCptCityDataItem(QgsCptCityDataItem::Type type, QgsCptCityDataItem *parent, const QString &name, const QString &path)", "setParent(QgsCptCityDataItem *parent)", "addChildItem(QgsCptCityDataItem *child, bool refresh=false)", "beginInsertItems(QgsCptCityDataItem *parent, int first, int last)", "shortInfo() const", "acceptDrop()", "info() const", "findItem(QVector< QgsCptCityDataItem * > items, QgsCptCityDataItem *item)", "removeChildItem(QgsCptCityDataItem *child)", "equal(const QgsCptCityDataItem *other)"],
- "QgsRasterNuller": ["setNoData(int bandNo, const QgsRasterRangeList &noData)", "noData(int bandNo) const", "QgsRasterNuller(QgsRasterInterface *input=nullptr)"],
+ "QgsGeometryDangleCheck": [
+ "factoryDescription()",
+ "QgsGeometryDangleCheck(QgsGeometryCheckContext *context, const QVariantMap &configuration)",
+ "ResolutionMethod",
+ "factoryCompatibleGeometryTypes()",
+ "factoryCheckType()",
+ "factoryIsCompatible(QgsVectorLayer *layer)",
+ "factoryId()",
+ ],
+ "QgsCptCityDataItem": [
+ "icon()",
+ "toolTip() const",
+ "parent() const",
+ "children() const",
+ "hasChildren()",
+ "populate()",
+ "icon(QSize size)",
+ "rowCount()",
+ "paramWidget()",
+ "handleDrop(const QMimeData *, Qt::DropAction)",
+ "type() const",
+ "beginRemoveItems(QgsCptCityDataItem *parent, int first, int last)",
+ "endRemoveItems()",
+ "path() const",
+ "Type",
+ "isPopulated()",
+ "endInsertItems()",
+ "name() const",
+ "refresh()",
+ "setIcon(const QIcon &icon)",
+ "deleteChildItem(QgsCptCityDataItem *child)",
+ "leafCount() const",
+ "isValid()",
+ "setToolTip(const QString &msg)",
+ "createChildren()",
+ "QgsCptCityDataItem(QgsCptCityDataItem::Type type, QgsCptCityDataItem *parent, const QString &name, const QString &path)",
+ "setParent(QgsCptCityDataItem *parent)",
+ "addChildItem(QgsCptCityDataItem *child, bool refresh=false)",
+ "beginInsertItems(QgsCptCityDataItem *parent, int first, int last)",
+ "shortInfo() const",
+ "acceptDrop()",
+ "info() const",
+ "findItem(QVector< QgsCptCityDataItem * > items, QgsCptCityDataItem *item)",
+ "removeChildItem(QgsCptCityDataItem *child)",
+ "equal(const QgsCptCityDataItem *other)",
+ ],
+ "QgsRasterNuller": [
+ "setNoData(int bandNo, const QgsRasterRangeList &noData)",
+ "noData(int bandNo) const",
+ "QgsRasterNuller(QgsRasterInterface *input=nullptr)",
+ ],
"QgsMapThemeCollection": ["setProject(QgsProject *project)"],
- "QgsLayerItem": ["iconDefault()", "iconRaster()", "iconPoint()", "iconPolygon()", "iconTable()", "iconLine()"],
+ "QgsLayerItem": [
+ "iconDefault()",
+ "iconRaster()",
+ "iconPoint()",
+ "iconPolygon()",
+ "iconTable()",
+ "iconLine()",
+ ],
"QgsCacheIndexFeatureId": ["QgsCacheIndexFeatureId(QgsVectorLayerCache *)"],
- "QgsPointLocator_VisitorEdgesInRect": ["QgsPointLocator_VisitorEdgesInRect(QgsPointLocator *pl, QgsPointLocator::MatchList &lst, const QgsRectangle &srcRect, QgsPointLocator::MatchFilter *filter=nullptr)"],
- "QgsCptCityColorRampItem": ["ramp() const", "QgsCptCityColorRampItem(QgsCptCityDataItem *parent, const QString &name, const QString &path, const QStringList &variantList, bool initialize=false)", "init()", "QgsCptCityColorRampItem(QgsCptCityDataItem *parent, const QString &name, const QString &path, const QString &variantName=QString(), bool initialize=false)"],
+ "QgsPointLocator_VisitorEdgesInRect": [
+ "QgsPointLocator_VisitorEdgesInRect(QgsPointLocator *pl, QgsPointLocator::MatchList &lst, const QgsRectangle &srcRect, QgsPointLocator::MatchFilter *filter=nullptr)"
+ ],
+ "QgsCptCityColorRampItem": [
+ "ramp() const",
+ "QgsCptCityColorRampItem(QgsCptCityDataItem *parent, const QString &name, const QString &path, const QStringList &variantList, bool initialize=false)",
+ "init()",
+ "QgsCptCityColorRampItem(QgsCptCityDataItem *parent, const QString &name, const QString &path, const QString &variantName=QString(), bool initialize=false)",
+ ],
"QgsTextDiagram": ["Shape", "Orientation"],
"QgsSublayersDialog": ["ProviderType"],
- "QgsCharacterSelectorDialog": ["QgsCharacterSelectorDialog(QWidget *parent=nullptr, Qt::WindowFlags fl=QgsGuiUtils::ModalDialogFlags)"],
+ "QgsCharacterSelectorDialog": [
+ "QgsCharacterSelectorDialog(QWidget *parent=nullptr, Qt::WindowFlags fl=QgsGuiUtils::ModalDialogFlags)"
+ ],
"QgisVisitor": ["QgisVisitor(QList< QgsFeatureId > &list)"],
- "QgsLabelingEngine": ["processProvider(QgsAbstractLabelProvider *provider, QgsRenderContext &context, pal::Pal &p)"],
- "QgsNetworkAccessManager": ["requestTimedOut(QNetworkReply *)", "QgsNetworkAccessManager(QObject *parent=nullptr)"],
+ "QgsLabelingEngine": [
+ "processProvider(QgsAbstractLabelProvider *provider, QgsRenderContext &context, pal::Pal &p)"
+ ],
+ "QgsNetworkAccessManager": [
+ "requestTimedOut(QNetworkReply *)",
+ "QgsNetworkAccessManager(QObject *parent=nullptr)",
+ ],
"QgsGpsConnection": ["Status"],
}
@@ -1112,7 +2830,6 @@
"QgsMapLayerLegend",
"QgsLayoutRenderContext",
"QgsLabelingEngine",
-
"QgsOgcUtilsExprToFilter",
"QgsGeometryLineIntersectionCheck",
"QgsRangeConfigDlg",
@@ -1815,247 +3532,247 @@
]
ACCEPTABLE_MISSING_BRIEF = [
- 'QgsDial',
- 'QgsPluginManagerInterface',
- 'QgsRangeWidgetFactory',
- 'QgsLinearlyInterpolatedDiagramRenderer',
- 'QgsTextDiagram',
- 'QgsShapeburstFillSymbolLayer',
- 'QgsCptCityArchive',
- 'QgsValueRelationConfigDlg',
- 'QgsGeometryMultipartCheck',
- 'QgsArrowSymbolLayerWidget',
- 'QgsCheckboxWidgetFactory',
- 'QgsLabelCandidate',
- 'QgsGeometrySliverPolygonCheck',
- 'QgsMarkerLineSymbolLayerWidget',
- 'QgsRelationReferenceFactory',
- 'QgsGradientFillSymbolLayer',
- 'QgsPointPatternFillSymbolLayer',
- 'QgsSymbolLayer',
- 'QgsLUDialog',
- 'QgsFeatureModel',
- 'QgsSimpleMarkerSymbolLayerWidget',
- 'QgsMimeDataUtils',
- 'QgsRuleBasedLabelProvider',
- 'QgsRuntimeProfiler',
- 'QgsRelation',
- 'QgsGeometryPointCoveredByLineCheck',
- 'QgsFontMarkerSymbolLayerWidget',
- 'QgsDataDefinedWidthDialog',
- 'QgsHistogramDiagram',
- 'QgsSymbolLayerWidget',
- 'QgsSpatialIndexCopyVisitor',
- 'pal::CostCalculator',
- 'QgsRendererRangeLabelFormat',
- 'QgsGeometrySelfContactCheck',
- 'QgsExpressionHighlighter',
- 'QgsFillSymbolLayer',
- 'QgsRendererRange',
- 'QgsVectorFileWriter::HiddenOption',
- 'QgsDrawSourceWidget',
- 'QgsSvgSelectorDialog',
- 'QgsFontMarkerSymbolLayer',
- 'QgsStyleGroupSelectionDialog',
- 'QgsGeometryLineLayerIntersectionCheck',
- 'QgsFeatureRenderer',
- 'QgsGeometryDangleCheck',
- 'QgsRelationEditorWidget',
- 'QgsGeometryPointInPolygonCheck',
- 'QgsSymbolLayerUtils',
- 'QgsCategorizedSymbolRenderer',
- 'QgsRasterRendererWidget',
- 'QgsValueMapConfigDlg',
- 'QgsSublayersDialog',
- 'QgsLabelPosition',
- 'QgsSimpleLineSymbolLayerWidget',
- 'QgsGeometrySelfIntersectionCheckError',
- 'QgsRelationReferenceConfigDlg',
- 'QgsFeatureListModel',
- 'QgsMessageBarItem',
- 'QgsCptCityBrowserModel',
- 'QgsQtLocationConnection',
- 'HalfEdge',
- 'QgsBrushStyleComboBox',
- 'QgsDartMeasurement',
- 'QgsDateTimeEditFactory',
- 'QgsPieDiagram',
- 'QgsVectorLayerFeatureIterator',
- 'QgsGeometryValidator',
- 'QgsGeometrySelfIntersectionCheck',
- 'QgsRangeConfigDlg',
- 'QgsSymbolsListWidget',
- 'QgsDummyConfigDlg',
- 'QgsEnumerationWidgetFactory',
- 'QgsGeometryDuplicateNodesCheck',
- 'QgsVectorLayerEditPassthrough',
- 'QgsGeometryTypeCheck',
- 'QgsSVGFillSymbolLayerWidget',
- 'QgsSingleSymbolRenderer',
- 'QgsGeometryAreaCheck',
- 'QgsHillshadeFilter',
- 'QgsColorWidgetFactory',
- 'QgsRendererPropertiesDialog',
- 'QgsBrowserWatcher',
- 'QgsDxfExport',
- 'QgsTransactionGroup',
- 'QgsStyle',
- 'QgsSingleSymbolRendererWidget',
- 'QgsGeometryDuplicateCheckError',
- 'QgsSvgMarkerSymbolLayer',
- 'QgsGeometry::Error',
- 'QgsLayerPropertiesWidget',
- 'QgsSymbolSelectorDialog',
- 'QgsConstWkbPtr',
- 'QgsErrorDialog',
- 'QgsPalLayerSettings',
- 'QgsRendererRulePropsWidget',
- 'QgsTextEditConfigDlg',
- 'QgsDateTimeEditConfig',
- 'QgsGroupBoxCollapseButton',
- 'QgsGeometryFollowBoundariesCheck',
- 'QgsLongLongValidator',
- 'QgsTextEditWidgetFactory',
- 'QgsCentroidFillSymbolLayerWidget',
- 'QgsGmlSchema',
- 'QgsSingleBandGrayRendererWidget',
- 'Qgs25DRenderer',
- 'QgsVectorFileWriter::BoolOption',
- 'QgsSimpleFillSymbolLayer',
- 'QgsDxfPaintEngine',
- 'QgsGlowWidget',
- 'QgsGroupWmsDataDialog',
- 'QgsMapToolCapture',
- 'QgsRendererRasterPropertiesWidget',
- 'QgsCptCityColorRamp',
- 'QgsVectorLayerEditUtils',
- 'QgsVectorLayerSelectionManager',
- 'QgsTrackedVectorLayerTools',
- 'QgsSmartGroupCondition',
- 'pal::Sol',
- 'QgsAttributeTypeLoadDialog',
- 'QgsCentroidFillSymbolLayer',
- 'QgsWkbPtr',
- 'QgsFeatureSelectionModel',
- 'QgsDataDefinedRotationDialog',
- 'QgsGraduatedSymbolRendererWidget',
- 'QgsTransformWidget',
- 'QgsShapeburstFillSymbolLayerWidget',
- 'QgsUniqueValuesConfigDlg',
- 'QgsHeatmapRendererWidget',
- 'QgsScaleUtils',
- 'pal::PointSet',
- 'QgsEllipseSymbolLayerWidget',
- 'QgsFontUtils',
- 'QgsRuleBasedLabeling',
- 'QgsRasterCalcNode',
- 'QgsPointPatternFillSymbolLayerWidget',
- 'QgsVectorFileWriter::StringOption',
- 'QgsUuidWidgetFactory',
- 'QgsHiddenWidgetFactory',
- 'QgsGeometryGeneratorSymbolLayer',
- 'QgsGeometryAngleCheck',
- 'QgsAttributeTableAction',
- 'QgsAttributeForm',
- 'QgsDatumTransformDialog',
- 'pal::PriorityQueue',
- 'Qgs25DRendererWidget',
- 'QgsShadowEffectWidget',
- 'QgsGeometryHoleCheck',
- 'QgsVectorFileWriter::Option',
- 'QgsRuleBasedRendererWidget',
- 'QgsPenCapStyleComboBox',
- 'QgsScopeLogger',
- 'QgsGeometrySegmentLengthCheck',
- 'QgsGeometryContainedCheckError',
- 'QgsClassificationWidgetWrapper',
- 'QgsMultiBandColorRendererWidget',
- 'QgsFeatureListViewDelegate',
- 'QgsManageConnectionsDialog',
- 'QgsFieldValidator',
- 'QgsPalLabeling',
- 'QgsLocaleNumC',
- 'QgsColorBrewerPalette',
- 'pal::Util',
- 'QgsVectorFileWriter::IntOption',
- 'QgsGeometryLineIntersectionCheck',
- 'QgsSymbolRenderContext',
- 'QgsCategorizedSymbolRendererWidget',
- 'pal::GeomFunction',
- 'QgsRendererRulePropsDialog',
- 'QgsSvgMarkerSymbolLayerWidget',
- 'QgsExternalResourceConfigDlg',
- 'QgsClassificationWidgetWrapperFactory',
- 'QgsGeometryTypeCheckError',
- 'QgsNewVectorLayerDialog',
- 'QgsRuleBasedLabeling::Rule',
- 'QgsVectorFieldSymbolLayerWidget',
- 'QgsSmartGroupEditorDialog',
- 'QgsSlider',
- 'QgsAttributeDialog',
- 'QgsVectorFileWriter::SetOption',
- 'QgsNewMemoryLayerDialog',
- 'QgsCheckBoxConfigDlg',
- 'QgsEnumerationWidgetWrapper',
- 'QgsRelationReferenceWidget',
- 'QgsRasterLayerSaveAsDialog',
- 'QgsValueRelationWidgetFactory',
- 'QgsGraduatedSymbolRenderer',
- 'QgsGeometryGeneratorSymbolLayerWidget',
- 'QgsBlurWidget',
- 'QgsLineSymbolLayer',
- 'QgsRelationWidgetWrapper',
- 'QgsOfflineEditing',
- 'QgsValueMapWidgetFactory',
- 'QgsGeometryDegeneratePolygonCheck',
- 'QgsExternalResourceWidgetFactory',
- 'QgsEditFormConfig',
- 'QgsAttributeFormInterface',
- 'QgsProjectFileTransform',
- 'QgsColorEffectWidget',
- 'QgsAttributeTableMapLayerAction',
- 'QgsGeometryDuplicateCheck',
- 'QgsPalettedRendererWidget',
- 'QgsSimpleFillSymbolLayerWidget',
- 'QgsSurface',
- 'QgsAttributeTableFilterModel',
- 'QgsLinePatternFillSymbolLayerWidget',
- 'QgsCacheIndexFeatureId',
- 'QgsGeometryContainedCheck',
- 'QgsPenJoinStyleComboBox',
- 'QgsDataDefinedSizeDialog',
- 'QgsUniqueValueWidgetFactory',
- 'QgsStyleExportImportDialog',
- 'QgsRasterMatrix',
- 'QgsPointDisplacementRendererWidget',
- 'QgsVectorLayerEditBuffer',
- 'QgsGradientFillSymbolLayerWidget',
- 'QgsRasterFillSymbolLayerWidget',
- 'QgsRasterMinMaxWidget',
- 'QgsSymbolLevelItem',
- 'QgsSvgSelectorWidget',
- 'QgsPenStyleComboBox',
- 'QgsFeatureSelectionDlg',
- 'QgsAttributeActionDialog',
- 'QgsDiagramProperties',
- 'QgsSourceFieldsProperties',
- 'QgsJoinDialog',
- 'QgsAttributesFormProperties::DnDTreeItemData',
- 'QgsMeshDatasetGroupListModel',
- 'QgsMeshDatasetGroupSaveMenu',
- 'QgsMeshDatasetGroupProxyModel',
- 'QgsAttributeActionPropertiesDialog',
- 'QgsAttributesFormProperties',
- 'QgsMeshAvailableDatasetGroupTreeModel',
- 'QgsVectorLayerProperties',
- 'QgsSettingsEntryBase',
- 'QgsMeshDatasetGroupTreeWidget',
- 'QgsAttributesFormInitCode',
- 'QgsMeshRendererScalarSettingsWidget',
- 'QgsCPLErrorHandler',
- 'EditBlockerDelegate'
+ "QgsDial",
+ "QgsPluginManagerInterface",
+ "QgsRangeWidgetFactory",
+ "QgsLinearlyInterpolatedDiagramRenderer",
+ "QgsTextDiagram",
+ "QgsShapeburstFillSymbolLayer",
+ "QgsCptCityArchive",
+ "QgsValueRelationConfigDlg",
+ "QgsGeometryMultipartCheck",
+ "QgsArrowSymbolLayerWidget",
+ "QgsCheckboxWidgetFactory",
+ "QgsLabelCandidate",
+ "QgsGeometrySliverPolygonCheck",
+ "QgsMarkerLineSymbolLayerWidget",
+ "QgsRelationReferenceFactory",
+ "QgsGradientFillSymbolLayer",
+ "QgsPointPatternFillSymbolLayer",
+ "QgsSymbolLayer",
+ "QgsLUDialog",
+ "QgsFeatureModel",
+ "QgsSimpleMarkerSymbolLayerWidget",
+ "QgsMimeDataUtils",
+ "QgsRuleBasedLabelProvider",
+ "QgsRuntimeProfiler",
+ "QgsRelation",
+ "QgsGeometryPointCoveredByLineCheck",
+ "QgsFontMarkerSymbolLayerWidget",
+ "QgsDataDefinedWidthDialog",
+ "QgsHistogramDiagram",
+ "QgsSymbolLayerWidget",
+ "QgsSpatialIndexCopyVisitor",
+ "pal::CostCalculator",
+ "QgsRendererRangeLabelFormat",
+ "QgsGeometrySelfContactCheck",
+ "QgsExpressionHighlighter",
+ "QgsFillSymbolLayer",
+ "QgsRendererRange",
+ "QgsVectorFileWriter::HiddenOption",
+ "QgsDrawSourceWidget",
+ "QgsSvgSelectorDialog",
+ "QgsFontMarkerSymbolLayer",
+ "QgsStyleGroupSelectionDialog",
+ "QgsGeometryLineLayerIntersectionCheck",
+ "QgsFeatureRenderer",
+ "QgsGeometryDangleCheck",
+ "QgsRelationEditorWidget",
+ "QgsGeometryPointInPolygonCheck",
+ "QgsSymbolLayerUtils",
+ "QgsCategorizedSymbolRenderer",
+ "QgsRasterRendererWidget",
+ "QgsValueMapConfigDlg",
+ "QgsSublayersDialog",
+ "QgsLabelPosition",
+ "QgsSimpleLineSymbolLayerWidget",
+ "QgsGeometrySelfIntersectionCheckError",
+ "QgsRelationReferenceConfigDlg",
+ "QgsFeatureListModel",
+ "QgsMessageBarItem",
+ "QgsCptCityBrowserModel",
+ "QgsQtLocationConnection",
+ "HalfEdge",
+ "QgsBrushStyleComboBox",
+ "QgsDartMeasurement",
+ "QgsDateTimeEditFactory",
+ "QgsPieDiagram",
+ "QgsVectorLayerFeatureIterator",
+ "QgsGeometryValidator",
+ "QgsGeometrySelfIntersectionCheck",
+ "QgsRangeConfigDlg",
+ "QgsSymbolsListWidget",
+ "QgsDummyConfigDlg",
+ "QgsEnumerationWidgetFactory",
+ "QgsGeometryDuplicateNodesCheck",
+ "QgsVectorLayerEditPassthrough",
+ "QgsGeometryTypeCheck",
+ "QgsSVGFillSymbolLayerWidget",
+ "QgsSingleSymbolRenderer",
+ "QgsGeometryAreaCheck",
+ "QgsHillshadeFilter",
+ "QgsColorWidgetFactory",
+ "QgsRendererPropertiesDialog",
+ "QgsBrowserWatcher",
+ "QgsDxfExport",
+ "QgsTransactionGroup",
+ "QgsStyle",
+ "QgsSingleSymbolRendererWidget",
+ "QgsGeometryDuplicateCheckError",
+ "QgsSvgMarkerSymbolLayer",
+ "QgsGeometry::Error",
+ "QgsLayerPropertiesWidget",
+ "QgsSymbolSelectorDialog",
+ "QgsConstWkbPtr",
+ "QgsErrorDialog",
+ "QgsPalLayerSettings",
+ "QgsRendererRulePropsWidget",
+ "QgsTextEditConfigDlg",
+ "QgsDateTimeEditConfig",
+ "QgsGroupBoxCollapseButton",
+ "QgsGeometryFollowBoundariesCheck",
+ "QgsLongLongValidator",
+ "QgsTextEditWidgetFactory",
+ "QgsCentroidFillSymbolLayerWidget",
+ "QgsGmlSchema",
+ "QgsSingleBandGrayRendererWidget",
+ "Qgs25DRenderer",
+ "QgsVectorFileWriter::BoolOption",
+ "QgsSimpleFillSymbolLayer",
+ "QgsDxfPaintEngine",
+ "QgsGlowWidget",
+ "QgsGroupWmsDataDialog",
+ "QgsMapToolCapture",
+ "QgsRendererRasterPropertiesWidget",
+ "QgsCptCityColorRamp",
+ "QgsVectorLayerEditUtils",
+ "QgsVectorLayerSelectionManager",
+ "QgsTrackedVectorLayerTools",
+ "QgsSmartGroupCondition",
+ "pal::Sol",
+ "QgsAttributeTypeLoadDialog",
+ "QgsCentroidFillSymbolLayer",
+ "QgsWkbPtr",
+ "QgsFeatureSelectionModel",
+ "QgsDataDefinedRotationDialog",
+ "QgsGraduatedSymbolRendererWidget",
+ "QgsTransformWidget",
+ "QgsShapeburstFillSymbolLayerWidget",
+ "QgsUniqueValuesConfigDlg",
+ "QgsHeatmapRendererWidget",
+ "QgsScaleUtils",
+ "pal::PointSet",
+ "QgsEllipseSymbolLayerWidget",
+ "QgsFontUtils",
+ "QgsRuleBasedLabeling",
+ "QgsRasterCalcNode",
+ "QgsPointPatternFillSymbolLayerWidget",
+ "QgsVectorFileWriter::StringOption",
+ "QgsUuidWidgetFactory",
+ "QgsHiddenWidgetFactory",
+ "QgsGeometryGeneratorSymbolLayer",
+ "QgsGeometryAngleCheck",
+ "QgsAttributeTableAction",
+ "QgsAttributeForm",
+ "QgsDatumTransformDialog",
+ "pal::PriorityQueue",
+ "Qgs25DRendererWidget",
+ "QgsShadowEffectWidget",
+ "QgsGeometryHoleCheck",
+ "QgsVectorFileWriter::Option",
+ "QgsRuleBasedRendererWidget",
+ "QgsPenCapStyleComboBox",
+ "QgsScopeLogger",
+ "QgsGeometrySegmentLengthCheck",
+ "QgsGeometryContainedCheckError",
+ "QgsClassificationWidgetWrapper",
+ "QgsMultiBandColorRendererWidget",
+ "QgsFeatureListViewDelegate",
+ "QgsManageConnectionsDialog",
+ "QgsFieldValidator",
+ "QgsPalLabeling",
+ "QgsLocaleNumC",
+ "QgsColorBrewerPalette",
+ "pal::Util",
+ "QgsVectorFileWriter::IntOption",
+ "QgsGeometryLineIntersectionCheck",
+ "QgsSymbolRenderContext",
+ "QgsCategorizedSymbolRendererWidget",
+ "pal::GeomFunction",
+ "QgsRendererRulePropsDialog",
+ "QgsSvgMarkerSymbolLayerWidget",
+ "QgsExternalResourceConfigDlg",
+ "QgsClassificationWidgetWrapperFactory",
+ "QgsGeometryTypeCheckError",
+ "QgsNewVectorLayerDialog",
+ "QgsRuleBasedLabeling::Rule",
+ "QgsVectorFieldSymbolLayerWidget",
+ "QgsSmartGroupEditorDialog",
+ "QgsSlider",
+ "QgsAttributeDialog",
+ "QgsVectorFileWriter::SetOption",
+ "QgsNewMemoryLayerDialog",
+ "QgsCheckBoxConfigDlg",
+ "QgsEnumerationWidgetWrapper",
+ "QgsRelationReferenceWidget",
+ "QgsRasterLayerSaveAsDialog",
+ "QgsValueRelationWidgetFactory",
+ "QgsGraduatedSymbolRenderer",
+ "QgsGeometryGeneratorSymbolLayerWidget",
+ "QgsBlurWidget",
+ "QgsLineSymbolLayer",
+ "QgsRelationWidgetWrapper",
+ "QgsOfflineEditing",
+ "QgsValueMapWidgetFactory",
+ "QgsGeometryDegeneratePolygonCheck",
+ "QgsExternalResourceWidgetFactory",
+ "QgsEditFormConfig",
+ "QgsAttributeFormInterface",
+ "QgsProjectFileTransform",
+ "QgsColorEffectWidget",
+ "QgsAttributeTableMapLayerAction",
+ "QgsGeometryDuplicateCheck",
+ "QgsPalettedRendererWidget",
+ "QgsSimpleFillSymbolLayerWidget",
+ "QgsSurface",
+ "QgsAttributeTableFilterModel",
+ "QgsLinePatternFillSymbolLayerWidget",
+ "QgsCacheIndexFeatureId",
+ "QgsGeometryContainedCheck",
+ "QgsPenJoinStyleComboBox",
+ "QgsDataDefinedSizeDialog",
+ "QgsUniqueValueWidgetFactory",
+ "QgsStyleExportImportDialog",
+ "QgsRasterMatrix",
+ "QgsPointDisplacementRendererWidget",
+ "QgsVectorLayerEditBuffer",
+ "QgsGradientFillSymbolLayerWidget",
+ "QgsRasterFillSymbolLayerWidget",
+ "QgsRasterMinMaxWidget",
+ "QgsSymbolLevelItem",
+ "QgsSvgSelectorWidget",
+ "QgsPenStyleComboBox",
+ "QgsFeatureSelectionDlg",
+ "QgsAttributeActionDialog",
+ "QgsDiagramProperties",
+ "QgsSourceFieldsProperties",
+ "QgsJoinDialog",
+ "QgsAttributesFormProperties::DnDTreeItemData",
+ "QgsMeshDatasetGroupListModel",
+ "QgsMeshDatasetGroupSaveMenu",
+ "QgsMeshDatasetGroupProxyModel",
+ "QgsAttributeActionPropertiesDialog",
+ "QgsAttributesFormProperties",
+ "QgsMeshAvailableDatasetGroupTreeModel",
+ "QgsVectorLayerProperties",
+ "QgsSettingsEntryBase",
+ "QgsMeshDatasetGroupTreeWidget",
+ "QgsAttributesFormInitCode",
+ "QgsMeshRendererScalarSettingsWidget",
+ "QgsCPLErrorHandler",
+ "EditBlockerDelegate",
]
-if __name__ == '__main__':
+if __name__ == "__main__":
for k in sorted(list(ACCEPTABLE_MISSING_DOCS.keys())):
print(f' "{k}": {sorted(ACCEPTABLE_MISSING_DOCS[k])},')
diff --git a/tests/code_layout/doxygen_parser.py b/tests/code_layout/doxygen_parser.py
index 70f59fa84c4d..f558e98dc934 100644
--- a/tests/code_layout/doxygen_parser.py
+++ b/tests/code_layout/doxygen_parser.py
@@ -15,9 +15,9 @@
***************************************************************************
"""
-__author__ = 'Denis Rouzaud'
-__date__ = 'May 2017'
-__copyright__ = '(C) 2017, Denis Rouzaud'
+__author__ = "Denis Rouzaud"
+__date__ = "May 2017"
+__copyright__ = "(C) 2017, Denis Rouzaud"
import glob
import os
@@ -29,12 +29,18 @@
import xml.etree.ElementTree as ET
-class DoxygenParser():
+class DoxygenParser:
"""
Parses the XML files generated by Doxygen which describe the API docs
"""
- def __init__(self, path, acceptable_missing={}, acceptable_missing_added_note=[], acceptable_missing_brief=[]):
+ def __init__(
+ self,
+ path,
+ acceptable_missing={},
+ acceptable_missing_added_note=[],
+ acceptable_missing_brief=[],
+ ):
"""
Initializes the parser.
:param path: Path to Doxygen XML output
@@ -53,28 +59,32 @@ def __init__(self, path, acceptable_missing={}, acceptable_missing_added_note=[]
self.classes_missing_brief = []
self.classes_missing_version_added = []
# for some reason the Doxygen generation on Travis refuses to assign these classes to groups
- self.acceptable_missing_group = ['QgsOgcUtils::LayerProperties',
- 'QgsSQLStatement::Node',
- 'QgsSQLStatement::NodeBinaryOperator',
- 'QgsSQLStatement::NodeColumnRef',
- 'QgsSQLStatement::NodeFunction',
- 'QgsSQLStatement::NodeInOperator',
- 'QgsSQLStatement::NodeList',
- 'QgsSQLStatement::NodeLiteral',
- 'QgsSQLStatement::NodeUnaryOperator',
- 'QgsRuleBasedLabeling::Rule',
- 'QgsSQLStatement::Visitor']
- self.version_regex = re.compile(r'.*QGIS\s+(?:)?[\d\.]+.*', re.MULTILINE)
+ self.acceptable_missing_group = [
+ "QgsOgcUtils::LayerProperties",
+ "QgsSQLStatement::Node",
+ "QgsSQLStatement::NodeBinaryOperator",
+ "QgsSQLStatement::NodeColumnRef",
+ "QgsSQLStatement::NodeFunction",
+ "QgsSQLStatement::NodeInOperator",
+ "QgsSQLStatement::NodeList",
+ "QgsSQLStatement::NodeLiteral",
+ "QgsSQLStatement::NodeUnaryOperator",
+ "QgsRuleBasedLabeling::Rule",
+ "QgsSQLStatement::Visitor",
+ ]
+ self.version_regex = re.compile(
+ r".*QGIS\s+(?:)?[\d\.]+.*", re.MULTILINE
+ )
self.parseFiles(path)
def parseFiles(self, path):
- """ Parses all the Doxygen XML files in a folder
- :param path: Path to Doxygen XML output
+ """Parses all the Doxygen XML files in a folder
+ :param path: Path to Doxygen XML output
"""
found = False
# find groups
- for f in glob.glob(os.path.join(path, 'group__*.xml')):
+ for f in glob.glob(os.path.join(path, "group__*.xml")):
found = True
group, members = self.parseGroup(f)
self.groups[group] = members
@@ -82,14 +92,14 @@ def parseFiles(self, path):
assert found, "Could not find doxygen groups xml"
found = False
# parse docs
- for f in glob.glob(os.path.join(path, '*.xml')):
+ for f in glob.glob(os.path.join(path, "*.xml")):
found = True
self.parseFile(f)
assert found, "Could not find doxygen files xml"
def parseGroup(self, f):
- """ Parses a single Doxygen Group XML file
- :param f: XML file path
+ """Parses a single Doxygen Group XML file
+ :param f: XML file path
"""
name = None
members = []
@@ -97,9 +107,9 @@ def parseGroup(self, f):
# Wrap everything in a try, as sometimes Doxygen XML is malformed
try:
for event, elem in ET.iterparse(f):
- if event == 'end' and elem.tag == 'compoundname':
+ if event == "end" and elem.tag == "compoundname":
name = elem.text
- if event == 'end' and elem.tag == 'innerclass':
+ if event == "end" and elem.tag == "innerclass":
members.append(elem.text)
except:
pass
@@ -107,8 +117,8 @@ def parseGroup(self, f):
return name, members
def hasGroup(self, class_name):
- """ Returns true if a class has been assigned to a group
- :param class_name class name to test
+ """Returns true if a class has been assigned to a group
+ :param class_name class name to test
"""
for g in self.groups:
if class_name in self.groups[g]:
@@ -120,11 +130,11 @@ def standardize_signature(signature):
"""
Standardizes a method's signature for comparison
"""
- return signature.lower().replace('* >', '*>').replace('< ', '<')
+ return signature.lower().replace("* >", "*>").replace("< ", "<")
def parseFile(self, f):
- """ Parses a single Doxygen XML file
- :param f: XML file path
+ """Parses a single Doxygen XML file
+ :param f: XML file path
"""
documentable_members = 0
documented_members = 0
@@ -132,39 +142,65 @@ def parseFile(self, f):
# Wrap everything in a try, as sometimes Doxygen XML is malformed
try:
for event, elem in ET.iterparse(f):
- if event == 'end' and elem.tag == 'compounddef':
+ if event == "end" and elem.tag == "compounddef":
if self.elemIsPublicClass(elem):
# store documentation status
- members, documented, undocumented, noncompliant, bindable, has_brief_description, found_version_added, broken_links = self.parseClassElem(
- elem)
+ (
+ members,
+ documented,
+ undocumented,
+ noncompliant,
+ bindable,
+ has_brief_description,
+ found_version_added,
+ broken_links,
+ ) = self.parseClassElem(elem)
documentable_members += members
documented_members += documented
- class_name = elem.find('compoundname').text
+ class_name = elem.find("compoundname").text
acceptable_missing = self.acceptable_missing.get(class_name, [])
- if not self.hasGroup(class_name) and class_name not in self.acceptable_missing_group:
+ if (
+ not self.hasGroup(class_name)
+ and class_name not in self.acceptable_missing_group
+ ):
self.classes_missing_group.append(class_name)
- if class_name not in self.acceptable_missing_brief and not has_brief_description:
+ if (
+ class_name not in self.acceptable_missing_brief
+ and not has_brief_description
+ ):
self.classes_missing_brief.append(class_name)
- if class_name not in self.acceptable_missing_added_note and not found_version_added:
+ if (
+ class_name not in self.acceptable_missing_added_note
+ and not found_version_added
+ ):
self.classes_missing_version_added.append(class_name)
# GEN LIST
# if len(undocumented) > 0:
# print('"%s": [%s],' % (class_name, ", ".join(['"%s"' % e.replace('"', '\\"') for e in undocumented])))
- unacceptable_undocumented = undocumented - set(acceptable_missing)
+ unacceptable_undocumented = undocumented - set(
+ acceptable_missing
+ )
# do a case insensitive check too
unacceptable_undocumented_insensitive = {
- DoxygenParser.standardize_signature(u) for u in undocumented} - {
- DoxygenParser.standardize_signature(u) for u in acceptable_missing}
+ DoxygenParser.standardize_signature(u) for u in undocumented
+ } - {
+ DoxygenParser.standardize_signature(u)
+ for u in acceptable_missing
+ }
if len(unacceptable_undocumented_insensitive) > 0:
self.undocumented_members[class_name] = {}
- self.undocumented_members[class_name]['documented'] = documented
- self.undocumented_members[class_name]['members'] = members
- self.undocumented_members[class_name]['missing_members'] = unacceptable_undocumented
+ self.undocumented_members[class_name][
+ "documented"
+ ] = documented
+ self.undocumented_members[class_name]["members"] = members
+ self.undocumented_members[class_name][
+ "missing_members"
+ ] = unacceptable_undocumented
if len(noncompliant) > 0:
self.noncompliant_members[class_name] = noncompliant
@@ -186,44 +222,44 @@ def parseFile(self, f):
if i == line_num - 1:
line = l
break
- caret = '{:=>{}}'.format('^', col)
- print(f'ParseError in {f}\n{e}\n{line}\n{caret}')
+ caret = "{:=>{}}".format("^", col)
+ print(f"ParseError in {f}\n{e}\n{line}\n{caret}")
self.documentable_members += documentable_members
self.documented_members += documented_members
def elemIsPublicClass(self, elem):
- """ Tests whether an XML element corresponds to a public (or protected) class
- :param elem: XML element
+ """Tests whether an XML element corresponds to a public (or protected) class
+ :param elem: XML element
"""
# only looking for classes
- if not elem.get('kind') == 'class':
+ if not elem.get("kind") == "class":
return False
# only looking for public or protected classes
- return elem.get('prot') in ('public', 'protected')
+ return elem.get("prot") in ("public", "protected")
def classElemIsBindable(self, elem):
- """ Tests whether a class should have SIP bindings
- :param elem: XML element corresponding to a class
+ """Tests whether a class should have SIP bindings
+ :param elem: XML element corresponding to a class
"""
try:
# check for classes with special python doc notes (probably 'not available' or renamed classes, either way
# they should be safe to ignore as obviously some consideration has been given to Python bindings)
- detailed_sec = elem.find('detaileddescription')
- for p in detailed_sec.iter('para'):
- for s in p.iter('simplesect'):
- for ps in s.iter('para'):
- if ps.text and 'python' in ps.text.lower():
+ detailed_sec = elem.find("detaileddescription")
+ for p in detailed_sec.iter("para"):
+ for s in p.iter("simplesect"):
+ for ps in s.iter("para"):
+ if ps.text and "python" in ps.text.lower():
return False
return True
except:
return True
def parseClassElem(self, e):
- """ Parses an XML element corresponding to a Doxygen class
- :param e: XML element
+ """Parses an XML element corresponding to a Doxygen class
+ :param e: XML element
"""
documentable_members = 0
documented_members = 0
@@ -232,12 +268,12 @@ def parseClassElem(self, e):
bindable_members = []
broken_links = {}
# loop through all members
- for m in e.iter('memberdef'):
+ for m in e.iter("memberdef"):
signature = self.memberSignature(m)
if signature is None:
continue
if self.elemIsBindableMember(m):
- bindable_member = [e.find('compoundname').text, m.find('name').text]
+ bindable_member = [e.find("compoundname").text, m.find("name").text]
if bindable_member not in bindable_members:
bindable_members.append(bindable_member)
if self.elemIsDocumentableMember(m):
@@ -246,69 +282,88 @@ def parseClassElem(self, e):
documented_members += 1
error = self.memberDocIsNonCompliant(m)
if error:
- noncompliant_members.append({m.find('name').text: error})
+ noncompliant_members.append({m.find("name").text: error})
else:
undocumented_members.add(signature)
broken_see_also_links = self.checkForBrokenSeeAlsoLinks(m)
if broken_see_also_links:
- broken_links[m.find('name').text] = broken_see_also_links
+ broken_links[m.find("name").text] = broken_see_also_links
# test for brief description
- d = e.find('briefdescription')
+ d = e.find("briefdescription")
has_brief_description = False
if d is not None:
has_brief_description = True
- for para in d.iter('para'):
- if para.text and re.search(r'\btodo\b', para.text.lower()) is not None:
- noncompliant_members.append({'Brief description': 'Don\'t add TODO comments to public doxygen documentation. Leave these as c++ code comments only.'})
+ for para in d.iter("para"):
+ if para.text and re.search(r"\btodo\b", para.text.lower()) is not None:
+ noncompliant_members.append(
+ {
+ "Brief description": "Don't add TODO comments to public doxygen documentation. Leave these as c++ code comments only."
+ }
+ )
break
# test for "added in QGIS xxx" string
- d = e.find('detaileddescription')
+ d = e.find("detaileddescription")
found_version_added = False
- for para in d.iter('para'):
- for s in para.iter('simplesect'):
- if s.get('kind') == 'since':
- for p in s.iter('para'):
+ for para in d.iter("para"):
+ for s in para.iter("simplesect"):
+ if s.get("kind") == "since":
+ for p in s.iter("para"):
if self.version_regex.match(ET.tostring(p).decode()):
found_version_added = True
break
- for s in para.iter('xrefsect'):
- if s.find('xreftitle') is not None and 'Deprecated' in s.find('xreftitle').text:
+ for s in para.iter("xrefsect"):
+ if (
+ s.find("xreftitle") is not None
+ and "Deprecated" in s.find("xreftitle").text
+ ):
# can't have both deprecated and since, so if we've found deprecated then treat it as having satisfied the "since" requirement too
found_version_added = True
break
- if para.text and re.search(r'\btodo\b', para.text.lower()) is not None:
- noncompliant_members.append({
- 'Detailed description': 'Don\'t add TODO comments to public doxygen documentation. Leave these as c++ code comments only.'})
-
- return documentable_members, documented_members, undocumented_members, noncompliant_members, bindable_members, has_brief_description, found_version_added, broken_links
+ if para.text and re.search(r"\btodo\b", para.text.lower()) is not None:
+ noncompliant_members.append(
+ {
+ "Detailed description": "Don't add TODO comments to public doxygen documentation. Leave these as c++ code comments only."
+ }
+ )
+
+ return (
+ documentable_members,
+ documented_members,
+ undocumented_members,
+ noncompliant_members,
+ bindable_members,
+ has_brief_description,
+ found_version_added,
+ broken_links,
+ )
def memberSignature(self, elem):
- """ Returns the signature for a member
- :param elem: XML element for a class member
+ """Returns the signature for a member
+ :param elem: XML element for a class member
"""
- a = elem.find('argsstring')
+ a = elem.find("argsstring")
try:
if a is not None:
- signature = elem.find('name').text + a.text
+ signature = elem.find("name").text + a.text
else:
- signature = elem.find('name').text
- if signature.endswith('= default'):
- signature = signature[:-len('= default')]
+ signature = elem.find("name").text
+ if signature.endswith("= default"):
+ signature = signature[: -len("= default")]
return signature.strip()
except:
return None
def elemIsBindableMember(self, elem):
- """ Tests whether an member should be included in SIP bindings
- :param elem: XML element for a class member
+ """Tests whether an member should be included in SIP bindings
+ :param elem: XML element for a class member
"""
# only public or protected members are bindable
- if not self.visibility(elem) in ('public', 'protected'):
+ if not self.visibility(elem) in ("public", "protected"):
return False
# property themselves are not bound, only getters and setters
@@ -323,18 +378,18 @@ def elemIsBindableMember(self, elem):
if self.isTypeDef(elem):
return False
- if self.isVariable(elem) and self.visibility(elem) == 'protected':
+ if self.isVariable(elem) and self.visibility(elem) == "protected":
# protected variables can't be bound in SIP
return False
# check for members with special python doc notes (probably 'not available' or renamed methods, either way
# they should be safe to ignore as obviously some consideration has been given to Python bindings)
try:
- detailed_sec = elem.find('detaileddescription')
- for p in detailed_sec.iter('para'):
- for s in p.iter('simplesect'):
- for ps in s.iter('para'):
- if ps.text and 'python' in ps.text.lower():
+ detailed_sec = elem.find("detaileddescription")
+ for p in detailed_sec.iter("para"):
+ for s in p.iter("simplesect"):
+ for ps in s.iter("para"):
+ if ps.text and "python" in ps.text.lower():
return False
except:
pass
@@ -354,8 +409,8 @@ def elemIsBindableMember(self, elem):
return True
def elemIsDocumentableMember(self, elem):
- """ Tests whether an member should be included in Doxygen docs
- :param elem: XML element for a class member
+ """Tests whether an member should be included in Doxygen docs
+ :param elem: XML element for a class member
"""
# ignore variables (for now, eventually public/protected variables should be documented)
@@ -363,7 +418,7 @@ def elemIsDocumentableMember(self, elem):
return False
# only public or protected members should be documented
- if not self.visibility(elem) in ('public', 'protected'):
+ if not self.visibility(elem) in ("public", "protected"):
return False
# ignore reimplemented methods
@@ -381,26 +436,43 @@ def elemIsDocumentableMember(self, elem):
if self.isConstructor(elem):
# ignore constructors with no arguments
try:
- if re.match(r'^\s*\(\s*\)\s*(?:=\s*(?:default|delete)\s*)?$', elem.find('argsstring').text):
+ if re.match(
+ r"^\s*\(\s*\)\s*(?:=\s*(?:default|delete)\s*)?$",
+ elem.find("argsstring").text,
+ ):
return False
except:
pass
# ignore copy, move constructors
- name = elem.find('name').text
- match = re.match(r'^\s*\(\s*(?:const)?\s*' + name + r'\s*&{0,2}\s*(?:[a-zA-Z0-9_]+)?\s*\)\s*(?:=\s*(?:default|delete)\s*)?$', elem.find('argsstring').text)
+ name = elem.find("name").text
+ match = re.match(
+ r"^\s*\(\s*(?:const)?\s*"
+ + name
+ + r"\s*&{0,2}\s*(?:[a-zA-Z0-9_]+)?\s*\)\s*(?:=\s*(?:default|delete)\s*)?$",
+ elem.find("argsstring").text,
+ )
if match:
return False
- name = elem.find('name')
+ name = elem.find("name")
# ignore certain obvious operators
- if name.text in ('operator=', 'operator==', 'operator!=', 'operator>=', 'operator>', 'operator<=', 'operator<', 'Q_ENUM'):
+ if name.text in (
+ "operator=",
+ "operator==",
+ "operator!=",
+ "operator>=",
+ "operator>",
+ "operator<=",
+ "operator<",
+ "Q_ENUM",
+ ):
return False
# ignore on_* slots
try:
- if name.text.startswith('on_'):
+ if name.text.startswith("on_"):
return False
except:
pass
@@ -412,20 +484,20 @@ def elemIsDocumentableMember(self, elem):
return True
def visibility(self, elem):
- """ Returns the visibility of a class or member
- :param elem: XML element for a class or member
+ """Returns the visibility of a class or member
+ :param elem: XML element for a class or member
"""
try:
- return elem.get('prot')
+ return elem.get("prot")
except:
- return ''
+ return ""
def isVariable(self, member_elem):
- """ Tests whether an member is a variable
- :param member_elem: XML element for a class member
+ """Tests whether an member is a variable
+ :param member_elem: XML element for a class member
"""
try:
- if member_elem.get('kind') == 'variable':
+ if member_elem.get("kind") == "variable":
return True
except:
pass
@@ -433,11 +505,11 @@ def isVariable(self, member_elem):
return False
def isProperty(self, member_elem):
- """ Tests whether an member is a property
- :param member_elem: XML element for a class member
+ """Tests whether an member is a property
+ :param member_elem: XML element for a class member
"""
try:
- if member_elem.get('kind') == 'property':
+ if member_elem.get("kind") == "property":
return True
except:
pass
@@ -445,12 +517,12 @@ def isProperty(self, member_elem):
return False
def isDestructor(self, member_elem):
- """ Tests whether an member is a destructor
- :param member_elem: XML element for a class member
+ """Tests whether an member is a destructor
+ :param member_elem: XML element for a class member
"""
try:
- name = member_elem.find('name').text
- if name.startswith('~'):
+ name = member_elem.find("name").text
+ if name.startswith("~"):
# destructor
return True
except:
@@ -458,15 +530,15 @@ def isDestructor(self, member_elem):
return False
def isConstructor(self, member_elem):
- """ Tests whether an member is a constructor
- :param member_elem: XML element for a class member
+ """Tests whether an member is a constructor
+ :param member_elem: XML element for a class member
"""
try:
- definition = member_elem.find('definition').text
- name = member_elem.find('name').text
- if f'{name}::{name}' in definition:
+ definition = member_elem.find("definition").text
+ name = member_elem.find("name").text
+ if f"{name}::{name}" in definition:
return True
- if re.match(rf'{name}\s*\<\s*[a-zA-Z0-9_]+\s*\>\s*::{name}', definition):
+ if re.match(rf"{name}\s*\<\s*[a-zA-Z0-9_]+\s*\>\s*::{name}", definition):
return True
except (AttributeError, re.error):
pass
@@ -474,12 +546,12 @@ def isConstructor(self, member_elem):
return False
def isOperator(self, member_elem):
- """ Tests whether an member is an operator
- :param member_elem: XML element for a class member
+ """Tests whether an member is an operator
+ :param member_elem: XML element for a class member
"""
try:
- name = member_elem.find('name').text
- if re.match(r'^operator\W.*', name):
+ name = member_elem.find("name").text
+ if re.match(r"^operator\W.*", name):
return True
except:
pass
@@ -487,39 +559,39 @@ def isOperator(self, member_elem):
return False
def isFriendClass(self, member_elem):
- """ Tests whether an member is a friend class
- :param member_elem: XML element for a class member
+ """Tests whether an member is a friend class
+ :param member_elem: XML element for a class member
"""
try:
- if member_elem.get('kind') == 'friend':
+ if member_elem.get("kind") == "friend":
return True
except:
pass
return False
def isTypeDef(self, member_elem):
- """ Tests whether an member is a type def
- :param member_elem: XML element for a class member
+ """Tests whether an member is a type def
+ :param member_elem: XML element for a class member
"""
try:
- if member_elem.get('kind') == 'typedef':
+ if member_elem.get("kind") == "typedef":
return True
except:
pass
return False
def isReimplementation(self, member_elem):
- """ Tests whether an member is a reimplementation
- :param member_elem: XML element for a class member
+ """Tests whether an member is a reimplementation
+ :param member_elem: XML element for a class member
"""
# use two different tests, as Doxygen will not detect reimplemented Qt methods
try:
- if member_elem.find('reimplements') is not None:
+ if member_elem.find("reimplements") is not None:
return True
- if ' override' in member_elem.find('argsstring').text:
+ if " override" in member_elem.find("argsstring").text:
return True
- if ' final' in member_elem.find('argsstring').text.lower():
+ if " final" in member_elem.find("argsstring").text.lower():
return True
except:
pass
@@ -527,91 +599,108 @@ def isReimplementation(self, member_elem):
return False
def isDeprecated(self, member_elem):
- """ Tests whether an member is deprecated
- :param member_elem: XML element for a class member
+ """Tests whether an member is deprecated
+ :param member_elem: XML element for a class member
"""
# look for both Q_DECL_DEPRECATED and Doxygen deprecated tag
decl_deprecated = False
- type_elem = member_elem.find('type')
+ type_elem = member_elem.find("type")
try:
- if 'Q_DECL_DEPRECATED' in type_elem.text:
+ if "Q_DECL_DEPRECATED" in type_elem.text:
decl_deprecated = True
except:
pass
- if b'Q_DECL_DEPRECATED' in ET.tostring(type_elem):
+ if b"Q_DECL_DEPRECATED" in ET.tostring(type_elem):
decl_deprecated = True
doxy_deprecated = False
has_description = True
try:
- for p in member_elem.find('detaileddescription').iter('para'):
- for s in p.iter('xrefsect'):
- if s.find('xreftitle') is not None and 'Deprecated' in s.find('xreftitle').text:
+ for p in member_elem.find("detaileddescription").iter("para"):
+ for s in p.iter("xrefsect"):
+ if (
+ s.find("xreftitle") is not None
+ and "Deprecated" in s.find("xreftitle").text
+ ):
doxy_deprecated = True
- if s.find('xrefdescription') is None or s.find('xrefdescription').find('para') is None:
+ if (
+ s.find("xrefdescription") is None
+ or s.find("xrefdescription").find("para") is None
+ ):
has_description = False
break
except:
- assert 0, member_elem.find('definition').text
+ assert 0, member_elem.find("definition").text
if not decl_deprecated and not doxy_deprecated:
return False
if doxy_deprecated and not has_description:
- assert has_description, 'Error: Missing description for deprecated method {}'.format(
- member_elem.find('definition').text)
+ assert (
+ has_description
+ ), "Error: Missing description for deprecated method {}".format(
+ member_elem.find("definition").text
+ )
# only functions for now, but in future this should also apply for enums and variables
- if member_elem.get('kind') in ('function', 'variable'):
- assert decl_deprecated, 'Error: Missing Q_DECL_DEPRECATED for {}'.format(
- member_elem.find('definition').text)
- assert doxy_deprecated, 'Error: Missing Doxygen deprecated tag for {}'.format(
- member_elem.find('definition').text)
+ if member_elem.get("kind") in ("function", "variable"):
+ assert decl_deprecated, "Error: Missing Q_DECL_DEPRECATED for {}".format(
+ member_elem.find("definition").text
+ )
+ assert (
+ doxy_deprecated
+ ), "Error: Missing Doxygen deprecated tag for {}".format(
+ member_elem.find("definition").text
+ )
return True
def memberIsDocumented(self, member_elem):
- """ Tests whether an member has documentation
- :param member_elem: XML element for a class member
+ """Tests whether an member has documentation
+ :param member_elem: XML element for a class member
"""
- for doc_type in ('inbodydescription', 'briefdescription', 'detaileddescription'):
+ for doc_type in (
+ "inbodydescription",
+ "briefdescription",
+ "detaileddescription",
+ ):
doc = member_elem.find(doc_type)
if doc is not None and list(doc):
return True
return False
def memberDocIsNonCompliant(self, member_elem):
- """ Tests whether an member's documentation is non-compliant
- :param member_elem: XML element for a class member
+ """Tests whether an member's documentation is non-compliant
+ :param member_elem: XML element for a class member
"""
def _check_compliance(elem):
- for para in elem.iter('para'):
- for sect in para.iter('simplesect'):
+ for para in elem.iter("para"):
+ for sect in para.iter("simplesect"):
res = _check_compliance(sect)
if res:
return res
for t in para.itertext():
- if doc_type == 'briefdescription':
- if t.strip().lower().startswith('getter'):
+ if doc_type == "briefdescription":
+ if t.strip().lower().startswith("getter"):
return 'Use "Returns the..." instead of "getter"'
- if t.strip().lower().startswith('get '):
+ if t.strip().lower().startswith("get "):
return 'Use "Gets..." (or better, "Returns ...") instead of "get ..."'
- elif t.strip().lower().startswith('setter'):
+ elif t.strip().lower().startswith("setter"):
return 'Use "Sets the..." instead of "setter"'
- elif t.strip().lower().startswith('mutator'):
+ elif t.strip().lower().startswith("mutator"):
return 'Use "Sets the..." instead of "mutator for..."'
- elif t.strip().lower().startswith('accessor'):
+ elif t.strip().lower().startswith("accessor"):
return 'Use "Returns the..." instead of "accessor for..."'
- elif t.strip().lower().startswith('return '):
+ elif t.strip().lower().startswith("return "):
return 'Use "Returns the..." instead of "return ..."'
- if re.search(r'\btodo\b', t.lower()) is not None:
- return 'Don\'t add TODO comments to public doxygen documentation. Leave these as c++ code comments only.'
+ if re.search(r"\btodo\b", t.lower()) is not None:
+ return "Don't add TODO comments to public doxygen documentation. Leave these as c++ code comments only."
- for doc_type in ['briefdescription', 'detaileddescription']:
+ for doc_type in ["briefdescription", "detaileddescription"]:
doc = member_elem.find(doc_type)
if doc is not None:
res = _check_compliance(doc)
@@ -625,15 +714,18 @@ def checkForBrokenSeeAlsoLinks(self, elem):
Checks for any broken 'see also' links
"""
broken = []
- detailed_sec = elem.find('detaileddescription')
- for p in detailed_sec.iter('para'):
- for s in p.iter('simplesect'):
- if s.get('kind') != 'see':
+ detailed_sec = elem.find("detaileddescription")
+ for p in detailed_sec.iter("para"):
+ for s in p.iter("simplesect"):
+ if s.get("kind") != "see":
continue
para = list(s.iter())[1]
- if para.find('ref') is None and para.text and (
- not para.text.startswith('Q') or para.text.startswith('Qgs')):
+ if (
+ para.find("ref") is None
+ and para.text
+ and (not para.text.startswith("Q") or para.text.startswith("Qgs"))
+ ):
broken.append(para.text)
return broken
diff --git a/tests/code_layout/test_qgsdoccoverage.py b/tests/code_layout/test_qgsdoccoverage.py
index b0bb071c9767..1e26fb81a6d7 100644
--- a/tests/code_layout/test_qgsdoccoverage.py
+++ b/tests/code_layout/test_qgsdoccoverage.py
@@ -5,9 +5,10 @@
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
"""
-__author__ = 'Nyall Dawson'
-__date__ = '01/02/2015'
-__copyright__ = 'Copyright 2016, The QGIS Project'
+
+__author__ = "Nyall Dawson"
+__date__ = "01/02/2015"
+__copyright__ = "Copyright 2016, The QGIS Project"
import os
import sys
@@ -38,10 +39,15 @@
class TestQgsDocCoverage(unittest.TestCase):
def testCoverage(self):
- print('CTEST_FULL_OUTPUT')
- prefixPath = os.environ['QGIS_PREFIX_PATH']
- docPath = os.path.join(prefixPath, '..', 'doc', 'api', 'xml')
- parser = DoxygenParser(docPath, ACCEPTABLE_MISSING_DOCS, ACCEPTABLE_MISSING_ADDED_NOTE, ACCEPTABLE_MISSING_BRIEF)
+ print("CTEST_FULL_OUTPUT")
+ prefixPath = os.environ["QGIS_PREFIX_PATH"]
+ docPath = os.path.join(prefixPath, "..", "doc", "api", "xml")
+ parser = DoxygenParser(
+ docPath,
+ ACCEPTABLE_MISSING_DOCS,
+ ACCEPTABLE_MISSING_ADDED_NOTE,
+ ACCEPTABLE_MISSING_BRIEF,
+ )
coverage = 100.0 * parser.documented_members / parser.documentable_members
missing = parser.documentable_members - parser.documented_members
@@ -57,54 +63,117 @@ def testCoverage(self):
if parser.undocumented_members:
for cls, props in list(parser.undocumented_members.items()):
- print('\n\nClass {}, {}/{} members documented\n'.format(colored(cls, 'yellow'), props['documented'], props['members']))
- for mem in props['missing_members']:
- print(colored(' "' + mem + '"', 'yellow', attrs=['bold']))
+ print(
+ "\n\nClass {}, {}/{} members documented\n".format(
+ colored(cls, "yellow"), props["documented"], props["members"]
+ )
+ )
+ for mem in props["missing_members"]:
+ print(colored(' "' + mem + '"', "yellow", attrs=["bold"]))
if parser.noncompliant_members:
for cls, props in list(parser.noncompliant_members.items()):
- print('\n\nClass {}, non-compliant members found\n'.format(colored(cls, 'yellow')))
+ print(
+ "\n\nClass {}, non-compliant members found\n".format(
+ colored(cls, "yellow")
+ )
+ )
for p in props:
for mem, error in p.items():
- print(colored(' ' + mem + ': ' + error, 'yellow', attrs=['bold']))
+ print(
+ colored(" " + mem + ": " + error, "yellow", attrs=["bold"])
+ )
if parser.broken_links:
for cls, props in list(parser.broken_links.items()):
- print('\n\nClass {}, broken see also links found\n'.format(colored(cls, 'yellow')))
+ print(
+ "\n\nClass {}, broken see also links found\n".format(
+ colored(cls, "yellow")
+ )
+ )
for member, links in props.items():
for l in links:
- print(colored(' ' + member + ': ' + l, 'yellow', attrs=['bold']))
+ print(
+ colored(" " + member + ": " + l, "yellow", attrs=["bold"])
+ )
# self.assertEquals(len(parser.undocumented_string), 0, 'FAIL: new undocumented members have been introduced, please add documentation for these members')
if parser.classes_missing_group:
print("---------------------------------")
- print('\n')
- print(colored(f'{len(parser.classes_missing_group)} classes have been added without Doxygen group tag ("\\ingroup"):', 'yellow'))
- print('')
- print(' ' + '\n '.join([colored(cls, 'yellow', attrs=['bold']) for cls in parser.classes_missing_group]))
+ print("\n")
+ print(
+ colored(
+ f'{len(parser.classes_missing_group)} classes have been added without Doxygen group tag ("\\ingroup"):',
+ "yellow",
+ )
+ )
+ print("")
+ print(
+ " "
+ + "\n ".join(
+ [
+ colored(cls, "yellow", attrs=["bold"])
+ for cls in parser.classes_missing_group
+ ]
+ )
+ )
if parser.classes_missing_version_added:
print("---------------------------------")
- print('\n')
- print(colored(f'{len(parser.classes_missing_version_added)} classes have been added without a version added doxygen note ("\\since QGIS x.xx"):', 'yellow'))
- print('')
- print(' ' + '\n '.join([colored(cls, 'yellow', attrs=['bold']) for cls in parser.classes_missing_version_added]))
+ print("\n")
+ print(
+ colored(
+ f'{len(parser.classes_missing_version_added)} classes have been added without a version added doxygen note ("\\since QGIS x.xx"):',
+ "yellow",
+ )
+ )
+ print("")
+ print(
+ " "
+ + "\n ".join(
+ [
+ colored(cls, "yellow", attrs=["bold"])
+ for cls in parser.classes_missing_version_added
+ ]
+ )
+ )
if parser.classes_missing_brief:
print("---------------------------------")
- print('\n')
- print(colored(f'{len(parser.classes_missing_brief)} classes have been added without at least a brief description:', 'yellow'))
- print('')
- print(' ' + '\n '.join([colored(cls, 'yellow', attrs=['bold']) for cls in parser.classes_missing_brief]))
+ print("\n")
+ print(
+ colored(
+ f"{len(parser.classes_missing_brief)} classes have been added without at least a brief description:",
+ "yellow",
+ )
+ )
+ print("")
+ print(
+ " "
+ + "\n ".join(
+ [
+ colored(cls, "yellow", attrs=["bold"])
+ for cls in parser.classes_missing_brief
+ ]
+ )
+ )
sys.stdout.flush()
- self.assertTrue(not parser.undocumented_members, 'Undocumented members found')
- self.assertTrue(not parser.classes_missing_group, 'Classes without \\group tag found')
- self.assertTrue(not parser.classes_missing_version_added, 'Classes without \\since version tag found')
- self.assertTrue(not parser.classes_missing_brief, 'Classes without \\brief description found')
- self.assertTrue(not parser.noncompliant_members, 'Non compliant members found')
- self.assertTrue(not parser.broken_links, 'Broken links found')
-
-
-if __name__ == '__main__':
+ self.assertTrue(not parser.undocumented_members, "Undocumented members found")
+ self.assertTrue(
+ not parser.classes_missing_group, "Classes without \\group tag found"
+ )
+ self.assertTrue(
+ not parser.classes_missing_version_added,
+ "Classes without \\since version tag found",
+ )
+ self.assertTrue(
+ not parser.classes_missing_brief,
+ "Classes without \\brief description found",
+ )
+ self.assertTrue(not parser.noncompliant_members, "Non compliant members found")
+ self.assertTrue(not parser.broken_links, "Broken links found")
+
+
+if __name__ == "__main__":
unittest.main()
diff --git a/tests/code_layout/test_qgssipcoverage.py b/tests/code_layout/test_qgssipcoverage.py
index bc8a87586f1e..afb12c778e77 100644
--- a/tests/code_layout/test_qgssipcoverage.py
+++ b/tests/code_layout/test_qgssipcoverage.py
@@ -5,12 +5,15 @@
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
"""
-__author__ = 'Nyall Dawson'
-__date__ = '15/10/2015'
-__copyright__ = 'Copyright 2015, The QGIS Project'
+
+__author__ = "Nyall Dawson"
+__date__ = "15/10/2015"
+__copyright__ = "Copyright 2015, The QGIS Project"
import os
+from doxygen_parser import DoxygenParser
+
# Import all the things!
from qgis.analysis import * # NOQA
from qgis.core import * # NOQA
@@ -19,8 +22,6 @@
from termcolor import colored
from utilities import printImportant
-from doxygen_parser import DoxygenParser
-
try:
from qgis.server import * # NOQA
except:
@@ -30,9 +31,9 @@
class TestQgsSipCoverage(unittest.TestCase):
def testCoverage(self):
- print('CTEST_FULL_OUTPUT')
- prefixPath = os.environ['QGIS_PREFIX_PATH']
- docPath = os.path.join(prefixPath, '..', 'doc', 'api', 'xml')
+ print("CTEST_FULL_OUTPUT")
+ prefixPath = os.environ["QGIS_PREFIX_PATH"]
+ docPath = os.path.join(prefixPath, "..", "doc", "api", "xml")
parser = DoxygenParser(docPath)
# first look for objects without any bindings
@@ -41,8 +42,10 @@ def testCoverage(self):
bound_objects = {}
for o in objects:
try:
- if '::' in o:
- bound_objects[o] = getattr(globals()[o.split('::')[0]], o.split('::')[1])
+ if "::" in o:
+ bound_objects[o] = getattr(
+ globals()[o.split("::")[0]], o.split("::")[1]
+ )
else:
bound_objects[o] = globals()[o]
except:
@@ -71,20 +74,32 @@ def testCoverage(self):
if m[1] in dir(obj):
continue
except:
- printImportant(f"SIP coverage test: something strange happened in {m[0]}.{m[1]}, obj={obj}")
+ printImportant(
+ f"SIP coverage test: something strange happened in {m[0]}.{m[1]}, obj={obj}"
+ )
- missing_members.append(f'{m[0]}.{m[1]}')
+ missing_members.append(f"{m[0]}.{m[1]}")
missing_members.sort()
if missing_objects:
print("---------------------------------")
- print(colored('Missing classes:', 'yellow'))
- print(' ' + '\n '.join([colored(obj, 'yellow', attrs=['bold']) for obj in missing_objects]))
+ print(colored("Missing classes:", "yellow"))
+ print(
+ " "
+ + "\n ".join(
+ [colored(obj, "yellow", attrs=["bold"]) for obj in missing_objects]
+ )
+ )
if missing_members:
print("---------------------------------")
- print(colored('Missing members:', 'yellow'))
- print(' ' + '\n '.join([colored(mem, 'yellow', attrs=['bold']) for mem in missing_members]))
+ print(colored("Missing members:", "yellow"))
+ print(
+ " "
+ + "\n ".join(
+ [colored(mem, "yellow", attrs=["bold"]) for mem in missing_members]
+ )
+ )
# print summaries
missing_class_count = len(missing_objects)
@@ -110,14 +125,22 @@ def testCoverage(self):
printImportant("---------------------------------")
printImportant(f"{missing_member_count} members missing bindings")
- self.assertEqual(missing_class_count, 0, """\n\nFAIL: new unbound classes have been introduced, please add SIP bindings for these classes
+ self.assertEqual(
+ missing_class_count,
+ 0,
+ """\n\nFAIL: new unbound classes have been introduced, please add SIP bindings for these classes
If these classes are not suitable for the Python bindings, please add the Doxygen tag
-"\\note not available in Python bindings" to the CLASS Doxygen comments""")
+"\\note not available in Python bindings" to the CLASS Doxygen comments""",
+ )
- self.assertEqual(missing_member_count, 0, """\n\nFAIL: new unbound members have been introduced, please add SIP bindings for these members
+ self.assertEqual(
+ missing_member_count,
+ 0,
+ """\n\nFAIL: new unbound members have been introduced, please add SIP bindings for these members
If these members are not suitable for the Python bindings, please add the Doxygen tag
-"\\note not available in Python bindings" to the MEMBER Doxygen comments""")
+"\\note not available in Python bindings" to the MEMBER Doxygen comments""",
+ )
-if __name__ == '__main__':
+if __name__ == "__main__":
unittest.main()
diff --git a/tests/src/python/featuresourcetestbase.py b/tests/src/python/featuresourcetestbase.py
index c492be10e1b1..a17bd06d908b 100644
--- a/tests/src/python/featuresourcetestbase.py
+++ b/tests/src/python/featuresourcetestbase.py
@@ -6,10 +6,9 @@
(at your option) any later version.
"""
-
-__author__ = 'Nyall Dawson'
-__date__ = '2017-05-25'
-__copyright__ = 'Copyright 2017, The QGIS Project'
+__author__ = "Nyall Dawson"
+__date__ = "2017-05-25"
+__copyright__ = "Copyright 2017, The QGIS Project"
from qgis.PyQt.QtCore import QDate, QDateTime, Qt, QTime
from qgis.core import (
@@ -51,7 +50,7 @@ def treat_datetime_tz_as_utc(self):
return False
def testCrs(self):
- self.assertEqual(self.source.sourceCrs().authid(), 'EPSG:4326')
+ self.assertEqual(self.source.sourceCrs().authid(), "EPSG:4326")
def testWkbType(self):
self.assertEqual(self.source.wkbType(), QgsWkbTypes.Type.Point)
@@ -62,12 +61,18 @@ def testFeatureCount(self):
def testFields(self):
fields = self.source.fields()
- for f in ('pk', 'cnt', 'name', 'name2', 'num_char'):
+ for f in ("pk", "cnt", "name", "name2", "num_char"):
self.assertGreaterEqual(fields.lookupField(f), 0)
- def testGetFeatures(self, source=None, extra_features=[], skip_features=[], changed_attributes={},
- changed_geometries={}):
- """ Test that expected results are returned when fetching all features """
+ def testGetFeatures(
+ self,
+ source=None,
+ extra_features=[],
+ skip_features=[],
+ changed_attributes={},
+ changed_geometries={},
+ ):
+ """Test that expected results are returned when fetching all features"""
# IMPORTANT - we do not use `for f in source.getFeatures()` as we are also
# testing that existing attributes & geometry in f are overwritten correctly
@@ -85,26 +90,131 @@ def testGetFeatures(self, source=None, extra_features=[], skip_features=[], chan
self.assertTrue(f.isValid())
# some source test datasets will include additional attributes which we ignore,
# so cherry pick desired attributes
- attrs = [f['pk'], f['cnt'], f['name'], f['name2'], f['num_char'], f['dt'], f['date'], f['time']]
+ attrs = [
+ f["pk"],
+ f["cnt"],
+ f["name"],
+ f["name2"],
+ f["num_char"],
+ f["dt"],
+ f["date"],
+ f["time"],
+ ]
# force the num_char attribute to be text - some sources (e.g., delimited text) will
# automatically detect that this attribute contains numbers and set it as a numeric
# field
- attrs[4] = 'NULL' if attrs[4] is None else str(attrs[4])
- attributes[f['pk']] = attrs
- geometries[f['pk']] = f.hasGeometry() and f.geometry().asWkt()
-
- tz = Qt.TimeSpec.UTC if self.treat_datetime_tz_as_utc() else Qt.TimeSpec.LocalTime
- expected_attributes = {5: [5, -200, NULL, 'NuLl', '5', QDateTime(QDate(2020, 5, 4), QTime(12, 13, 14), tz) if not self.treat_datetime_as_string() else '2020-05-04 12:13:14', QDate(2020, 5, 2) if not self.treat_date_as_datetime() and not self.treat_date_as_string() else QDateTime(2020, 5, 2, 0, 0, 0) if not self.treat_date_as_string() else '2020-05-02', QTime(12, 13, 1) if not self.treat_time_as_string() else '12:13:01'],
- 3: [3, 300, 'Pear', 'PEaR', '3', NULL, NULL, NULL],
- 1: [1, 100, 'Orange', 'oranGe', '1', QDateTime(QDate(2020, 5, 3), QTime(12, 13, 14), tz) if not self.treat_datetime_as_string() else '2020-05-03 12:13:14', QDate(2020, 5, 3) if not self.treat_date_as_datetime() and not self.treat_date_as_string() else QDateTime(2020, 5, 3, 0, 0, 0) if not self.treat_date_as_string() else '2020-05-03', QTime(12, 13, 14) if not self.treat_time_as_string() else '12:13:14'],
- 2: [2, 200, 'Apple', 'Apple', '2', QDateTime(QDate(2020, 5, 4), QTime(12, 14, 14), tz) if not self.treat_datetime_as_string() else '2020-05-04 12:14:14', QDate(2020, 5, 4) if not self.treat_date_as_datetime() and not self.treat_date_as_string() else QDateTime(2020, 5, 4, 0, 0, 0) if not self.treat_date_as_string() else '2020-05-04', QTime(12, 14, 14) if not self.treat_time_as_string() else '12:14:14'],
- 4: [4, 400, 'Honey', 'Honey', '4', QDateTime(QDate(2021, 5, 4), QTime(13, 13, 14), tz) if not self.treat_datetime_as_string() else '2021-05-04 13:13:14', QDate(2021, 5, 4) if not self.treat_date_as_datetime() and not self.treat_date_as_string() else QDateTime(2021, 5, 4, 0, 0, 0) if not self.treat_date_as_string() else '2021-05-04', QTime(13, 13, 14) if not self.treat_time_as_string() else '13:13:14']}
-
- expected_geometries = {1: 'Point (-70.332 66.33)',
- 2: 'Point (-68.2 70.8)',
- 3: None,
- 4: 'Point(-65.32 78.3)',
- 5: 'Point(-71.123 78.23)'}
+ attrs[4] = "NULL" if attrs[4] is None else str(attrs[4])
+ attributes[f["pk"]] = attrs
+ geometries[f["pk"]] = f.hasGeometry() and f.geometry().asWkt()
+
+ tz = (
+ Qt.TimeSpec.UTC
+ if self.treat_datetime_tz_as_utc()
+ else Qt.TimeSpec.LocalTime
+ )
+ expected_attributes = {
+ 5: [
+ 5,
+ -200,
+ NULL,
+ "NuLl",
+ "5",
+ (
+ QDateTime(QDate(2020, 5, 4), QTime(12, 13, 14), tz)
+ if not self.treat_datetime_as_string()
+ else "2020-05-04 12:13:14"
+ ),
+ (
+ QDate(2020, 5, 2)
+ if not self.treat_date_as_datetime()
+ and not self.treat_date_as_string()
+ else (
+ QDateTime(2020, 5, 2, 0, 0, 0)
+ if not self.treat_date_as_string()
+ else "2020-05-02"
+ )
+ ),
+ QTime(12, 13, 1) if not self.treat_time_as_string() else "12:13:01",
+ ],
+ 3: [3, 300, "Pear", "PEaR", "3", NULL, NULL, NULL],
+ 1: [
+ 1,
+ 100,
+ "Orange",
+ "oranGe",
+ "1",
+ (
+ QDateTime(QDate(2020, 5, 3), QTime(12, 13, 14), tz)
+ if not self.treat_datetime_as_string()
+ else "2020-05-03 12:13:14"
+ ),
+ (
+ QDate(2020, 5, 3)
+ if not self.treat_date_as_datetime()
+ and not self.treat_date_as_string()
+ else (
+ QDateTime(2020, 5, 3, 0, 0, 0)
+ if not self.treat_date_as_string()
+ else "2020-05-03"
+ )
+ ),
+ QTime(12, 13, 14) if not self.treat_time_as_string() else "12:13:14",
+ ],
+ 2: [
+ 2,
+ 200,
+ "Apple",
+ "Apple",
+ "2",
+ (
+ QDateTime(QDate(2020, 5, 4), QTime(12, 14, 14), tz)
+ if not self.treat_datetime_as_string()
+ else "2020-05-04 12:14:14"
+ ),
+ (
+ QDate(2020, 5, 4)
+ if not self.treat_date_as_datetime()
+ and not self.treat_date_as_string()
+ else (
+ QDateTime(2020, 5, 4, 0, 0, 0)
+ if not self.treat_date_as_string()
+ else "2020-05-04"
+ )
+ ),
+ QTime(12, 14, 14) if not self.treat_time_as_string() else "12:14:14",
+ ],
+ 4: [
+ 4,
+ 400,
+ "Honey",
+ "Honey",
+ "4",
+ (
+ QDateTime(QDate(2021, 5, 4), QTime(13, 13, 14), tz)
+ if not self.treat_datetime_as_string()
+ else "2021-05-04 13:13:14"
+ ),
+ (
+ QDate(2021, 5, 4)
+ if not self.treat_date_as_datetime()
+ and not self.treat_date_as_string()
+ else (
+ QDateTime(2021, 5, 4, 0, 0, 0)
+ if not self.treat_date_as_string()
+ else "2021-05-04"
+ )
+ ),
+ QTime(13, 13, 14) if not self.treat_time_as_string() else "13:13:14",
+ ],
+ }
+
+ expected_geometries = {
+ 1: "Point (-70.332 66.33)",
+ 2: "Point (-68.2 70.8)",
+ 3: None,
+ 4: "Point(-65.32 78.3)",
+ 5: "Point(-71.123 78.23)",
+ }
for f in extra_features:
expected_attributes[f[0]] = f.attributes()
if f.hasGeometry():
@@ -118,226 +228,321 @@ def testGetFeatures(self, source=None, extra_features=[], skip_features=[], chan
for i, a in changed_attributes.items():
for attr_idx, v in a.items():
expected_attributes[i][attr_idx] = v
- for i, g, in changed_geometries.items():
+ for (
+ i,
+ g,
+ ) in changed_geometries.items():
if g:
expected_geometries[i] = g.asWkt()
else:
expected_geometries[i] = None
- self.assertEqual(attributes, expected_attributes, f'Expected {expected_attributes}, got {attributes}')
+ self.assertEqual(
+ attributes,
+ expected_attributes,
+ f"Expected {expected_attributes}, got {attributes}",
+ )
self.assertEqual(len(expected_geometries), len(geometries))
for pk, geom in list(expected_geometries.items()):
if geom:
- assert compareWkt(geom, geometries[pk]), "Geometry {} mismatch Expected:\n{}\nGot:\n{}\n".format(pk,
- geom,
- geometries[
- pk])
+ assert compareWkt(
+ geom, geometries[pk]
+ ), "Geometry {} mismatch Expected:\n{}\nGot:\n{}\n".format(
+ pk, geom, geometries[pk]
+ )
else:
- self.assertFalse(geometries[pk], f'Expected null geometry for {pk}')
+ self.assertFalse(geometries[pk], f"Expected null geometry for {pk}")
def assert_query(self, source, expression, expected):
- request = QgsFeatureRequest().setFilterExpression(expression).setFlags(QgsFeatureRequest.Flag.NoGeometry | QgsFeatureRequest.Flag.IgnoreStaticNodesDuringExpressionCompilation)
- result = {f['pk'] for f in source.getFeatures(request)}
- assert set(expected) == result, 'Expected {} and got {} when testing expression "{}"'.format(set(expected),
- result, expression)
+ request = (
+ QgsFeatureRequest()
+ .setFilterExpression(expression)
+ .setFlags(
+ QgsFeatureRequest.Flag.NoGeometry
+ | QgsFeatureRequest.Flag.IgnoreStaticNodesDuringExpressionCompilation
+ )
+ )
+ result = {f["pk"] for f in source.getFeatures(request)}
+ assert (
+ set(expected) == result
+ ), 'Expected {} and got {} when testing expression "{}"'.format(
+ set(expected), result, expression
+ )
self.assertTrue(all(f.isValid() for f in source.getFeatures(request)))
# Also check that filter works when referenced fields are not being retrieved by request
- result = {f['pk'] for f in source.getFeatures(
- QgsFeatureRequest().setFilterExpression(expression).setSubsetOfAttributes(['pk'], self.source.fields()).setFlags(QgsFeatureRequest.Flag.IgnoreStaticNodesDuringExpressionCompilation))}
- assert set(
- expected) == result, 'Expected {} and got {} when testing expression "{}" using empty attribute subset'.format(
- set(expected), result, expression)
+ result = {
+ f["pk"]
+ for f in source.getFeatures(
+ QgsFeatureRequest()
+ .setFilterExpression(expression)
+ .setSubsetOfAttributes(["pk"], self.source.fields())
+ .setFlags(
+ QgsFeatureRequest.Flag.IgnoreStaticNodesDuringExpressionCompilation
+ )
+ )
+ }
+ assert (
+ set(expected) == result
+ ), 'Expected {} and got {} when testing expression "{}" using empty attribute subset'.format(
+ set(expected), result, expression
+ )
# test that results match QgsFeatureRequest.acceptFeature
- request = QgsFeatureRequest().setFilterExpression(expression).setFlags(QgsFeatureRequest.Flag.IgnoreStaticNodesDuringExpressionCompilation)
+ request = (
+ QgsFeatureRequest()
+ .setFilterExpression(expression)
+ .setFlags(
+ QgsFeatureRequest.Flag.IgnoreStaticNodesDuringExpressionCompilation
+ )
+ )
for f in source.getFeatures():
- self.assertEqual(request.acceptFeature(f), f['pk'] in expected)
+ self.assertEqual(request.acceptFeature(f), f["pk"] in expected)
def runGetFeatureTests(self, source):
self.assertEqual(len([f for f in source.getFeatures()]), 5)
- self.assert_query(source, 'name ILIKE \'QGIS\'', [])
+ self.assert_query(source, "name ILIKE 'QGIS'", [])
self.assert_query(source, '"name" IS NULL', [5])
self.assert_query(source, '"name" IS NOT NULL', [1, 2, 3, 4])
- self.assert_query(source, '"name" NOT LIKE \'Ap%\'', [1, 3, 4])
- self.assert_query(source, '"name" NOT ILIKE \'QGIS\'', [1, 2, 3, 4])
- self.assert_query(source, '"name" NOT ILIKE \'pEAR\'', [1, 2, 4])
- self.assert_query(source, 'name = \'Apple\'', [2])
+ self.assert_query(source, "\"name\" NOT LIKE 'Ap%'", [1, 3, 4])
+ self.assert_query(source, "\"name\" NOT ILIKE 'QGIS'", [1, 2, 3, 4])
+ self.assert_query(source, "\"name\" NOT ILIKE 'pEAR'", [1, 2, 4])
+ self.assert_query(source, "name = 'Apple'", [2])
# field names themselves are NOT case sensitive -- QGIS expressions don't care about this
- self.assert_query(source, '\"NaMe\" = \'Apple\'', [2])
- self.assert_query(source, 'name <> \'Apple\'', [1, 3, 4])
- self.assert_query(source, 'name = \'apple\'', [])
- self.assert_query(source, '"name" <> \'apple\'', [1, 2, 3, 4])
- self.assert_query(source, '(name = \'Apple\') is not null', [1, 2, 3, 4])
- self.assert_query(source, 'name LIKE \'Apple\'', [2])
- self.assert_query(source, 'name LIKE \'aPple\'', [])
- self.assert_query(source, 'name LIKE \'Ap_le\'', [2])
- self.assert_query(source, 'name LIKE \'Ap\\_le\'', [])
- self.assert_query(source, 'name ILIKE \'aPple\'', [2])
- self.assert_query(source, 'name ILIKE \'%pp%\'', [2])
- self.assert_query(source, 'cnt > 0', [1, 2, 3, 4])
- self.assert_query(source, '-cnt > 0', [5])
- self.assert_query(source, 'cnt < 0', [5])
- self.assert_query(source, '-cnt < 0', [1, 2, 3, 4])
- self.assert_query(source, 'cnt >= 100', [1, 2, 3, 4])
- self.assert_query(source, 'cnt <= 100', [1, 5])
- self.assert_query(source, 'pk IN (1, 2, 4, 8)', [1, 2, 4])
- self.assert_query(source, 'cnt = 50 * 2', [1])
- self.assert_query(source, 'cnt = 150 / 1.5', [1])
- self.assert_query(source, 'cnt = 1000 / 10', [1])
- self.assert_query(source, 'cnt = 1000/11+10', []) # checks that source isn't rounding int/int
- self.assert_query(source, 'pk = 9 // 4', [2]) # int division
- self.assert_query(source, 'cnt = 99 + 1', [1])
- self.assert_query(source, 'cnt = 101 - 1', [1])
- self.assert_query(source, 'cnt - 1 = 99', [1])
- self.assert_query(source, '-cnt - 1 = -101', [1])
- self.assert_query(source, '-(-cnt) = 100', [1])
- self.assert_query(source, '-(cnt) = -(100)', [1])
- self.assert_query(source, 'cnt + 1 = 101', [1])
- self.assert_query(source, 'cnt = 1100 % 1000', [1])
- self.assert_query(source, '"name" || \' \' || "name" = \'Orange Orange\'', [1])
- self.assert_query(source, '"name" || \' \' || "cnt" = \'Orange 100\'', [1])
- self.assert_query(source, '\'x\' || "name" IS NOT NULL', [1, 2, 3, 4])
- self.assert_query(source, '\'x\' || "name" IS NULL', [5])
- self.assert_query(source, 'cnt = 10 ^ 2', [1])
- self.assert_query(source, '"name" ~ \'[OP]ra[gne]+\'', [1])
- self.assert_query(source, '"name"="name2"', [2, 4]) # mix of matched and non-matched case sensitive names
- self.assert_query(source, 'true', [1, 2, 3, 4, 5])
- self.assert_query(source, 'false', [])
+ self.assert_query(source, "\"NaMe\" = 'Apple'", [2])
+ self.assert_query(source, "name <> 'Apple'", [1, 3, 4])
+ self.assert_query(source, "name = 'apple'", [])
+ self.assert_query(source, "\"name\" <> 'apple'", [1, 2, 3, 4])
+ self.assert_query(source, "(name = 'Apple') is not null", [1, 2, 3, 4])
+ self.assert_query(source, "name LIKE 'Apple'", [2])
+ self.assert_query(source, "name LIKE 'aPple'", [])
+ self.assert_query(source, "name LIKE 'Ap_le'", [2])
+ self.assert_query(source, "name LIKE 'Ap\\_le'", [])
+ self.assert_query(source, "name ILIKE 'aPple'", [2])
+ self.assert_query(source, "name ILIKE '%pp%'", [2])
+ self.assert_query(source, "cnt > 0", [1, 2, 3, 4])
+ self.assert_query(source, "-cnt > 0", [5])
+ self.assert_query(source, "cnt < 0", [5])
+ self.assert_query(source, "-cnt < 0", [1, 2, 3, 4])
+ self.assert_query(source, "cnt >= 100", [1, 2, 3, 4])
+ self.assert_query(source, "cnt <= 100", [1, 5])
+ self.assert_query(source, "pk IN (1, 2, 4, 8)", [1, 2, 4])
+ self.assert_query(source, "cnt = 50 * 2", [1])
+ self.assert_query(source, "cnt = 150 / 1.5", [1])
+ self.assert_query(source, "cnt = 1000 / 10", [1])
+ self.assert_query(
+ source, "cnt = 1000/11+10", []
+ ) # checks that source isn't rounding int/int
+ self.assert_query(source, "pk = 9 // 4", [2]) # int division
+ self.assert_query(source, "cnt = 99 + 1", [1])
+ self.assert_query(source, "cnt = 101 - 1", [1])
+ self.assert_query(source, "cnt - 1 = 99", [1])
+ self.assert_query(source, "-cnt - 1 = -101", [1])
+ self.assert_query(source, "-(-cnt) = 100", [1])
+ self.assert_query(source, "-(cnt) = -(100)", [1])
+ self.assert_query(source, "cnt + 1 = 101", [1])
+ self.assert_query(source, "cnt = 1100 % 1000", [1])
+ self.assert_query(source, "\"name\" || ' ' || \"name\" = 'Orange Orange'", [1])
+ self.assert_query(source, "\"name\" || ' ' || \"cnt\" = 'Orange 100'", [1])
+ self.assert_query(source, "'x' || \"name\" IS NOT NULL", [1, 2, 3, 4])
+ self.assert_query(source, "'x' || \"name\" IS NULL", [5])
+ self.assert_query(source, "cnt = 10 ^ 2", [1])
+ self.assert_query(source, "\"name\" ~ '[OP]ra[gne]+'", [1])
+ self.assert_query(
+ source, '"name"="name2"', [2, 4]
+ ) # mix of matched and non-matched case sensitive names
+ self.assert_query(source, "true", [1, 2, 3, 4, 5])
+ self.assert_query(source, "false", [])
# Three value logic
- self.assert_query(source, 'false and false', [])
- self.assert_query(source, 'false and true', [])
- self.assert_query(source, 'false and NULL', [])
- self.assert_query(source, 'true and false', [])
- self.assert_query(source, 'true and true', [1, 2, 3, 4, 5])
- self.assert_query(source, 'true and NULL', [])
- self.assert_query(source, 'NULL and false', [])
- self.assert_query(source, 'NULL and true', [])
- self.assert_query(source, 'NULL and NULL', [])
- self.assert_query(source, 'false or false', [])
- self.assert_query(source, 'false or true', [1, 2, 3, 4, 5])
- self.assert_query(source, 'false or NULL', [])
- self.assert_query(source, 'true or false', [1, 2, 3, 4, 5])
- self.assert_query(source, 'true or true', [1, 2, 3, 4, 5])
- self.assert_query(source, 'true or NULL', [1, 2, 3, 4, 5])
- self.assert_query(source, 'NULL or false', [])
- self.assert_query(source, 'NULL or true', [1, 2, 3, 4, 5])
- self.assert_query(source, 'NULL or NULL', [])
- self.assert_query(source, 'not true', [])
- self.assert_query(source, 'not false', [1, 2, 3, 4, 5])
- self.assert_query(source, 'not null', [])
+ self.assert_query(source, "false and false", [])
+ self.assert_query(source, "false and true", [])
+ self.assert_query(source, "false and NULL", [])
+ self.assert_query(source, "true and false", [])
+ self.assert_query(source, "true and true", [1, 2, 3, 4, 5])
+ self.assert_query(source, "true and NULL", [])
+ self.assert_query(source, "NULL and false", [])
+ self.assert_query(source, "NULL and true", [])
+ self.assert_query(source, "NULL and NULL", [])
+ self.assert_query(source, "false or false", [])
+ self.assert_query(source, "false or true", [1, 2, 3, 4, 5])
+ self.assert_query(source, "false or NULL", [])
+ self.assert_query(source, "true or false", [1, 2, 3, 4, 5])
+ self.assert_query(source, "true or true", [1, 2, 3, 4, 5])
+ self.assert_query(source, "true or NULL", [1, 2, 3, 4, 5])
+ self.assert_query(source, "NULL or false", [])
+ self.assert_query(source, "NULL or true", [1, 2, 3, 4, 5])
+ self.assert_query(source, "NULL or NULL", [])
+ self.assert_query(source, "not true", [])
+ self.assert_query(source, "not false", [1, 2, 3, 4, 5])
+ self.assert_query(source, "not null", [])
# not
- self.assert_query(source, 'not name = \'Apple\'', [1, 3, 4])
- self.assert_query(source, 'not name IS NULL', [1, 2, 3, 4])
- self.assert_query(source, 'not name = \'Apple\' or name = \'Apple\'', [1, 2, 3, 4])
- self.assert_query(source, 'not name = \'Apple\' or not name = \'Apple\'', [1, 3, 4])
- self.assert_query(source, 'not name = \'Apple\' and pk = 4', [4])
- self.assert_query(source, 'not name = \'Apple\' and not pk = 4', [1, 3])
- self.assert_query(source, 'not pk IN (1, 2, 4, 8)', [3, 5])
+ self.assert_query(source, "not name = 'Apple'", [1, 3, 4])
+ self.assert_query(source, "not name IS NULL", [1, 2, 3, 4])
+ self.assert_query(source, "not name = 'Apple' or name = 'Apple'", [1, 2, 3, 4])
+ self.assert_query(source, "not name = 'Apple' or not name = 'Apple'", [1, 3, 4])
+ self.assert_query(source, "not name = 'Apple' and pk = 4", [4])
+ self.assert_query(source, "not name = 'Apple' and not pk = 4", [1, 3])
+ self.assert_query(source, "not pk IN (1, 2, 4, 8)", [3, 5])
# type conversion - QGIS expressions do not mind that we are comparing a string
# against numeric literals
- self.assert_query(source, 'num_char IN (2, 4, 5)', [2, 4, 5])
+ self.assert_query(source, "num_char IN (2, 4, 5)", [2, 4, 5])
# function
- self.assert_query(source, 'sqrt(pk) >= 2', [4, 5])
- self.assert_query(source, 'radians(cnt) < 2', [1, 5])
- self.assert_query(source, 'degrees(pk) <= 200', [1, 2, 3])
- self.assert_query(source, 'abs(cnt) <= 200', [1, 2, 5])
- self.assert_query(source, 'cos(pk) < 0', [2, 3, 4])
- self.assert_query(source, 'sin(pk) < 0', [4, 5])
- self.assert_query(source, 'tan(pk) < 0', [2, 3, 5])
- self.assert_query(source, 'acos(-1) < pk', [4, 5])
- self.assert_query(source, 'asin(1) < pk', [2, 3, 4, 5])
- self.assert_query(source, 'atan(3.14) < pk', [2, 3, 4, 5])
- self.assert_query(source, 'atan2(3.14, pk) < 1', [3, 4, 5])
- self.assert_query(source, 'exp(pk) < 10', [1, 2])
- self.assert_query(source, 'ln(pk) <= 1', [1, 2])
- self.assert_query(source, 'log(3, pk) <= 1', [1, 2, 3])
- self.assert_query(source, 'log10(pk) < 0.5', [1, 2, 3])
- self.assert_query(source, 'round(3.14) <= pk', [3, 4, 5])
- self.assert_query(source, 'round(0.314,1) * 10 = pk', [3])
- self.assert_query(source, 'floor(3.14) <= pk', [3, 4, 5])
- self.assert_query(source, 'ceil(3.14) <= pk', [4, 5])
- self.assert_query(source, 'pk < pi()', [1, 2, 3])
-
- self.assert_query(source, 'round(cnt / 66.67) <= 2', [1, 5])
- self.assert_query(source, 'floor(cnt / 66.67) <= 2', [1, 2, 5])
- self.assert_query(source, 'ceil(cnt / 66.67) <= 2', [1, 5])
- self.assert_query(source, 'pk < pi() / 2', [1])
- self.assert_query(source, 'pk = char(51)', [3])
- self.assert_query(source, 'pk = coalesce(NULL,3,4)', [3])
- self.assert_query(source, 'lower(name) = \'apple\'', [2])
- self.assert_query(source, 'upper(name) = \'APPLE\'', [2])
- self.assert_query(source, 'name = trim(\' Apple \')', [2])
+ self.assert_query(source, "sqrt(pk) >= 2", [4, 5])
+ self.assert_query(source, "radians(cnt) < 2", [1, 5])
+ self.assert_query(source, "degrees(pk) <= 200", [1, 2, 3])
+ self.assert_query(source, "abs(cnt) <= 200", [1, 2, 5])
+ self.assert_query(source, "cos(pk) < 0", [2, 3, 4])
+ self.assert_query(source, "sin(pk) < 0", [4, 5])
+ self.assert_query(source, "tan(pk) < 0", [2, 3, 5])
+ self.assert_query(source, "acos(-1) < pk", [4, 5])
+ self.assert_query(source, "asin(1) < pk", [2, 3, 4, 5])
+ self.assert_query(source, "atan(3.14) < pk", [2, 3, 4, 5])
+ self.assert_query(source, "atan2(3.14, pk) < 1", [3, 4, 5])
+ self.assert_query(source, "exp(pk) < 10", [1, 2])
+ self.assert_query(source, "ln(pk) <= 1", [1, 2])
+ self.assert_query(source, "log(3, pk) <= 1", [1, 2, 3])
+ self.assert_query(source, "log10(pk) < 0.5", [1, 2, 3])
+ self.assert_query(source, "round(3.14) <= pk", [3, 4, 5])
+ self.assert_query(source, "round(0.314,1) * 10 = pk", [3])
+ self.assert_query(source, "floor(3.14) <= pk", [3, 4, 5])
+ self.assert_query(source, "ceil(3.14) <= pk", [4, 5])
+ self.assert_query(source, "pk < pi()", [1, 2, 3])
+
+ self.assert_query(source, "round(cnt / 66.67) <= 2", [1, 5])
+ self.assert_query(source, "floor(cnt / 66.67) <= 2", [1, 2, 5])
+ self.assert_query(source, "ceil(cnt / 66.67) <= 2", [1, 5])
+ self.assert_query(source, "pk < pi() / 2", [1])
+ self.assert_query(source, "pk = char(51)", [3])
+ self.assert_query(source, "pk = coalesce(NULL,3,4)", [3])
+ self.assert_query(source, "lower(name) = 'apple'", [2])
+ self.assert_query(source, "upper(name) = 'APPLE'", [2])
+ self.assert_query(source, "name = trim(' Apple ')", [2])
# geometry
# azimuth and touches tests are deactivated because they do not pass for WFS source
# self.assert_query(source, 'azimuth($geometry,geom_from_wkt( \'Point (-70 70)\')) < pi()', [1, 5])
- self.assert_query(source, 'x($geometry) < -70', [1, 5])
- self.assert_query(source, 'y($geometry) > 70', [2, 4, 5])
- self.assert_query(source, 'xmin($geometry) < -70', [1, 5])
- self.assert_query(source, 'ymin($geometry) > 70', [2, 4, 5])
- self.assert_query(source, 'xmax($geometry) < -70', [1, 5])
- self.assert_query(source, 'ymax($geometry) > 70', [2, 4, 5])
- self.assert_query(source,
- 'disjoint($geometry,geom_from_wkt( \'Polygon ((-72.2 66.1, -65.2 66.1, -65.2 72.0, -72.2 72.0, -72.2 66.1))\'))',
- [4, 5])
- self.assert_query(source,
- 'intersects($geometry,geom_from_wkt( \'Polygon ((-72.2 66.1, -65.2 66.1, -65.2 72.0, -72.2 72.0, -72.2 66.1))\'))',
- [1, 2])
+ self.assert_query(source, "x($geometry) < -70", [1, 5])
+ self.assert_query(source, "y($geometry) > 70", [2, 4, 5])
+ self.assert_query(source, "xmin($geometry) < -70", [1, 5])
+ self.assert_query(source, "ymin($geometry) > 70", [2, 4, 5])
+ self.assert_query(source, "xmax($geometry) < -70", [1, 5])
+ self.assert_query(source, "ymax($geometry) > 70", [2, 4, 5])
+ self.assert_query(
+ source,
+ "disjoint($geometry,geom_from_wkt( 'Polygon ((-72.2 66.1, -65.2 66.1, -65.2 72.0, -72.2 72.0, -72.2 66.1))'))",
+ [4, 5],
+ )
+ self.assert_query(
+ source,
+ "intersects($geometry,geom_from_wkt( 'Polygon ((-72.2 66.1, -65.2 66.1, -65.2 72.0, -72.2 72.0, -72.2 66.1))'))",
+ [1, 2],
+ )
# self.assert_query(source, 'touches($geometry,geom_from_wkt( \'Polygon ((-70.332 66.33, -65.32 66.33, -65.32 78.3, -70.332 78.3, -70.332 66.33))\'))', [1, 4])
- self.assert_query(source,
- 'contains(geom_from_wkt( \'Polygon ((-72.2 66.1, -65.2 66.1, -65.2 72.0, -72.2 72.0, -72.2 66.1))\'),$geometry)',
- [1, 2])
- self.assert_query(source, 'distance($geometry,geom_from_wkt( \'Point (-70 70)\')) > 7', [4, 5])
- self.assert_query(source,
- 'intersects($geometry,geom_from_gml( \'-72.2,66.1 -65.2,66.1 -65.2,72.0 -72.2,72.0 -72.2,66.1 \'))',
- [1, 2])
+ self.assert_query(
+ source,
+ "contains(geom_from_wkt( 'Polygon ((-72.2 66.1, -65.2 66.1, -65.2 72.0, -72.2 72.0, -72.2 66.1))'),$geometry)",
+ [1, 2],
+ )
+ self.assert_query(
+ source, "distance($geometry,geom_from_wkt( 'Point (-70 70)')) > 7", [4, 5]
+ )
+ self.assert_query(
+ source,
+ "intersects($geometry,geom_from_gml( '-72.2,66.1 -65.2,66.1 -65.2,72.0 -72.2,72.0 -72.2,66.1 '))",
+ [1, 2],
+ )
# between/not between
- self.assert_query(source, 'cnt BETWEEN -200 AND 200', [1, 2, 5])
- self.assert_query(source, 'cnt NOT BETWEEN 100 AND 200', [3, 4, 5])
+ self.assert_query(source, "cnt BETWEEN -200 AND 200", [1, 2, 5])
+ self.assert_query(source, "cnt NOT BETWEEN 100 AND 200", [3, 4, 5])
if self.treat_datetime_as_string():
- self.assert_query(source, """dt BETWEEN format_date(make_datetime(2020, 5, 3, 12, 13, 14), 'yyyy-MM-dd hh:mm:ss') AND format_date(make_datetime(2020, 5, 4, 12, 14, 14), 'yyyy-MM-dd hh:mm:ss')""", [1, 2, 5])
- self.assert_query(source, """dt NOT BETWEEN format_date(make_datetime(2020, 5, 3, 12, 13, 14), 'yyyy-MM-dd hh:mm:ss') AND format_date(make_datetime(2020, 5, 4, 12, 14, 14), 'yyyy-MM-dd hh:mm:ss')""", [4])
+ self.assert_query(
+ source,
+ """dt BETWEEN format_date(make_datetime(2020, 5, 3, 12, 13, 14), 'yyyy-MM-dd hh:mm:ss') AND format_date(make_datetime(2020, 5, 4, 12, 14, 14), 'yyyy-MM-dd hh:mm:ss')""",
+ [1, 2, 5],
+ )
+ self.assert_query(
+ source,
+ """dt NOT BETWEEN format_date(make_datetime(2020, 5, 3, 12, 13, 14), 'yyyy-MM-dd hh:mm:ss') AND format_date(make_datetime(2020, 5, 4, 12, 14, 14), 'yyyy-MM-dd hh:mm:ss')""",
+ [4],
+ )
else:
- self.assert_query(source, 'dt BETWEEN make_datetime(2020, 5, 3, 12, 13, 14) AND make_datetime(2020, 5, 4, 12, 14, 14)', [1, 2, 5])
- self.assert_query(source, 'dt NOT BETWEEN make_datetime(2020, 5, 3, 12, 13, 14) AND make_datetime(2020, 5, 4, 12, 14, 14)', [4])
+ self.assert_query(
+ source,
+ "dt BETWEEN make_datetime(2020, 5, 3, 12, 13, 14) AND make_datetime(2020, 5, 4, 12, 14, 14)",
+ [1, 2, 5],
+ )
+ self.assert_query(
+ source,
+ "dt NOT BETWEEN make_datetime(2020, 5, 3, 12, 13, 14) AND make_datetime(2020, 5, 4, 12, 14, 14)",
+ [4],
+ )
# datetime
if self.treat_datetime_as_string():
- self.assert_query(source, '"dt" <= format_date(make_datetime(2020, 5, 4, 12, 13, 14), \'yyyy-MM-dd hh:mm:ss\')', [1, 5])
- self.assert_query(source, '"dt" < format_date(make_date(2020, 5, 4), \'yyyy-MM-dd hh:mm:ss\')', [1])
- self.assert_query(source, '"dt" = format_date(to_datetime(\'000www14ww13ww12www4ww5ww2020\',\'zzzwwwsswwmmwwhhwwwdwwMwwyyyy\'),\'yyyy-MM-dd hh:mm:ss\')', [5])
+ self.assert_query(
+ source,
+ "\"dt\" <= format_date(make_datetime(2020, 5, 4, 12, 13, 14), 'yyyy-MM-dd hh:mm:ss')",
+ [1, 5],
+ )
+ self.assert_query(
+ source,
+ "\"dt\" < format_date(make_date(2020, 5, 4), 'yyyy-MM-dd hh:mm:ss')",
+ [1],
+ )
+ self.assert_query(
+ source,
+ "\"dt\" = format_date(to_datetime('000www14ww13ww12www4ww5ww2020','zzzwwwsswwmmwwhhwwwdwwMwwyyyy'),'yyyy-MM-dd hh:mm:ss')",
+ [5],
+ )
else:
- self.assert_query(source, '"dt" <= make_datetime(2020, 5, 4, 12, 13, 14)', [1, 5])
+ self.assert_query(
+ source, '"dt" <= make_datetime(2020, 5, 4, 12, 13, 14)', [1, 5]
+ )
self.assert_query(source, '"dt" < make_date(2020, 5, 4)', [1])
- self.assert_query(source, '"dt" = to_datetime(\'000www14ww13ww12www4ww5ww2020\',\'zzzwwwsswwmmwwhhwwwdwwMwwyyyy\')', [5])
-
- self.assert_query(source, '"date" <= make_datetime(2020, 5, 4, 12, 13, 14)', [1, 2, 5])
+ self.assert_query(
+ source,
+ "\"dt\" = to_datetime('000www14ww13ww12www4ww5ww2020','zzzwwwsswwmmwwhhwwwdwwMwwyyyy')",
+ [5],
+ )
+
+ self.assert_query(
+ source, '"date" <= make_datetime(2020, 5, 4, 12, 13, 14)', [1, 2, 5]
+ )
self.assert_query(source, '"date" >= make_date(2020, 5, 4)', [2, 4])
if not self.treat_date_as_datetime():
- self.assert_query(source,
- '"date" = to_date(\'www4ww5ww2020\',\'wwwdwwMwwyyyy\')',
- [2])
+ self.assert_query(
+ source, "\"date\" = to_date('www4ww5ww2020','wwwdwwMwwyyyy')", [2]
+ )
else:
# TODO - we don't have any expression functions which can upgrade a date value to a datetime value!
pass
if not self.treat_time_as_string():
self.assert_query(source, '"time" >= make_time(12, 14, 14)', [2, 4])
- self.assert_query(source, '"time" = to_time(\'000www14ww13ww12www\',\'zzzwwwsswwmmwwhhwww\')', [1])
+ self.assert_query(
+ source,
+ "\"time\" = to_time('000www14ww13ww12www','zzzwwwsswwmmwwhhwww')",
+ [1],
+ )
else:
- self.assert_query(source, 'to_time("time") >= make_time(12, 14, 14)', [2, 4])
- self.assert_query(source, 'to_time("time") = to_time(\'000www14ww13ww12www\',\'zzzwwwsswwmmwwhhwww\')', [1])
+ self.assert_query(
+ source, 'to_time("time") >= make_time(12, 14, 14)', [2, 4]
+ )
+ self.assert_query(
+ source,
+ "to_time(\"time\") = to_time('000www14ww13ww12www','zzzwwwsswwmmwwhhwww')",
+ [1],
+ )
# TODO - enable, but needs fixing on Travis due to timezone handling issues
# if self.treat_datetime_as_string():
@@ -372,94 +577,108 @@ def testGetFeaturesExp(self):
self.runGetFeatureTests(self.source)
def runOrderByTests(self):
- request = QgsFeatureRequest().addOrderBy('cnt')
- values = [f['cnt'] for f in self.source.getFeatures(request)]
+ request = QgsFeatureRequest().addOrderBy("cnt")
+ values = [f["cnt"] for f in self.source.getFeatures(request)]
self.assertEqual(values, [-200, 100, 200, 300, 400])
- request = QgsFeatureRequest().addOrderBy('cnt', False)
- values = [f['cnt'] for f in self.source.getFeatures(request)]
+ request = QgsFeatureRequest().addOrderBy("cnt", False)
+ values = [f["cnt"] for f in self.source.getFeatures(request)]
self.assertEqual(values, [400, 300, 200, 100, -200])
- request = QgsFeatureRequest().addOrderBy('name')
- values = [f['name'] for f in self.source.getFeatures(request)]
- self.assertEqual(values, ['Apple', 'Honey', 'Orange', 'Pear', NULL])
+ request = QgsFeatureRequest().addOrderBy("name")
+ values = [f["name"] for f in self.source.getFeatures(request)]
+ self.assertEqual(values, ["Apple", "Honey", "Orange", "Pear", NULL])
- request = QgsFeatureRequest().addOrderBy('name', True, True)
- values = [f['name'] for f in self.source.getFeatures(request)]
- self.assertEqual(values, [NULL, 'Apple', 'Honey', 'Orange', 'Pear'])
+ request = QgsFeatureRequest().addOrderBy("name", True, True)
+ values = [f["name"] for f in self.source.getFeatures(request)]
+ self.assertEqual(values, [NULL, "Apple", "Honey", "Orange", "Pear"])
- request = QgsFeatureRequest().addOrderBy('name', False)
- values = [f['name'] for f in self.source.getFeatures(request)]
- self.assertEqual(values, [NULL, 'Pear', 'Orange', 'Honey', 'Apple'])
+ request = QgsFeatureRequest().addOrderBy("name", False)
+ values = [f["name"] for f in self.source.getFeatures(request)]
+ self.assertEqual(values, [NULL, "Pear", "Orange", "Honey", "Apple"])
- request = QgsFeatureRequest().addOrderBy('name', False, False)
- values = [f['name'] for f in self.source.getFeatures(request)]
- self.assertEqual(values, ['Pear', 'Orange', 'Honey', 'Apple', NULL])
+ request = QgsFeatureRequest().addOrderBy("name", False, False)
+ values = [f["name"] for f in self.source.getFeatures(request)]
+ self.assertEqual(values, ["Pear", "Orange", "Honey", "Apple", NULL])
- request = QgsFeatureRequest().addOrderBy('num_char', False)
- values = [f['pk'] for f in self.source.getFeatures(request)]
+ request = QgsFeatureRequest().addOrderBy("num_char", False)
+ values = [f["pk"] for f in self.source.getFeatures(request)]
self.assertEqual(values, [5, 4, 3, 2, 1])
- request = QgsFeatureRequest().addOrderBy('dt', False)
- values = [f['pk'] for f in self.source.getFeatures(request)]
+ request = QgsFeatureRequest().addOrderBy("dt", False)
+ values = [f["pk"] for f in self.source.getFeatures(request)]
self.assertEqual(values, [3, 4, 2, 5, 1])
- request = QgsFeatureRequest().addOrderBy('date', False)
- values = [f['pk'] for f in self.source.getFeatures(request)]
+ request = QgsFeatureRequest().addOrderBy("date", False)
+ values = [f["pk"] for f in self.source.getFeatures(request)]
self.assertEqual(values, [3, 4, 2, 1, 5])
- request = QgsFeatureRequest().addOrderBy('time', False)
- values = [f['pk'] for f in self.source.getFeatures(request)]
+ request = QgsFeatureRequest().addOrderBy("time", False)
+ values = [f["pk"] for f in self.source.getFeatures(request)]
self.assertEqual(values, [3, 4, 2, 1, 5])
# Case sensitivity
- request = QgsFeatureRequest().addOrderBy('name2')
- values = [f['name2'] for f in self.source.getFeatures(request)]
- self.assertEqual(values, ['Apple', 'Honey', 'NuLl', 'oranGe', 'PEaR'])
+ request = QgsFeatureRequest().addOrderBy("name2")
+ values = [f["name2"] for f in self.source.getFeatures(request)]
+ self.assertEqual(values, ["Apple", "Honey", "NuLl", "oranGe", "PEaR"])
# Combination with LIMIT
- request = QgsFeatureRequest().addOrderBy('pk', False).setLimit(2)
- values = [f['pk'] for f in self.source.getFeatures(request)]
+ request = QgsFeatureRequest().addOrderBy("pk", False).setLimit(2)
+ values = [f["pk"] for f in self.source.getFeatures(request)]
self.assertEqual(values, [5, 4])
# A slightly more complex expression
- request = QgsFeatureRequest().addOrderBy('pk*2', False)
- values = [f['pk'] for f in self.source.getFeatures(request)]
+ request = QgsFeatureRequest().addOrderBy("pk*2", False)
+ values = [f["pk"] for f in self.source.getFeatures(request)]
self.assertEqual(values, [5, 4, 3, 2, 1])
# Order reversing expression
- request = QgsFeatureRequest().addOrderBy('pk*-1', False)
- values = [f['pk'] for f in self.source.getFeatures(request)]
+ request = QgsFeatureRequest().addOrderBy("pk*-1", False)
+ values = [f["pk"] for f in self.source.getFeatures(request)]
self.assertEqual(values, [1, 2, 3, 4, 5])
# Type dependent expression
- request = QgsFeatureRequest().addOrderBy('num_char*2', False)
- values = [f['pk'] for f in self.source.getFeatures(request)]
+ request = QgsFeatureRequest().addOrderBy("num_char*2", False)
+ values = [f["pk"] for f in self.source.getFeatures(request)]
self.assertEqual(values, [5, 4, 3, 2, 1])
# Order by guaranteed to fail
- request = QgsFeatureRequest().addOrderBy('not a valid expression*', False)
- values = [f['pk'] for f in self.source.getFeatures(request)]
+ request = QgsFeatureRequest().addOrderBy("not a valid expression*", False)
+ values = [f["pk"] for f in self.source.getFeatures(request)]
self.assertEqual(set(values), {5, 4, 3, 2, 1})
# Multiple order bys and boolean
- request = QgsFeatureRequest().addOrderBy('pk > 2').addOrderBy('pk', False)
- values = [f['pk'] for f in self.source.getFeatures(request)]
+ request = QgsFeatureRequest().addOrderBy("pk > 2").addOrderBy("pk", False)
+ values = [f["pk"] for f in self.source.getFeatures(request)]
self.assertEqual(values, [2, 1, 5, 4, 3])
# Multiple order bys, one bad, and a limit
- request = QgsFeatureRequest().addOrderBy('pk', False).addOrderBy('not a valid expression*', False).setLimit(2)
- values = [f['pk'] for f in self.source.getFeatures(request)]
+ request = (
+ QgsFeatureRequest()
+ .addOrderBy("pk", False)
+ .addOrderBy("not a valid expression*", False)
+ .setLimit(2)
+ )
+ values = [f["pk"] for f in self.source.getFeatures(request)]
self.assertEqual(values, [5, 4])
# Bad expression first
- request = QgsFeatureRequest().addOrderBy('not a valid expression*', False).addOrderBy('pk', False).setLimit(2)
- values = [f['pk'] for f in self.source.getFeatures(request)]
+ request = (
+ QgsFeatureRequest()
+ .addOrderBy("not a valid expression*", False)
+ .addOrderBy("pk", False)
+ .setLimit(2)
+ )
+ values = [f["pk"] for f in self.source.getFeatures(request)]
self.assertEqual(values, [5, 4])
# Combination with subset of attributes
- request = QgsFeatureRequest().addOrderBy('num_char', False).setSubsetOfAttributes(['pk'], self.source.fields())
- values = [f['pk'] for f in self.source.getFeatures(request)]
+ request = (
+ QgsFeatureRequest()
+ .addOrderBy("num_char", False)
+ .setSubsetOfAttributes(["pk"], self.source.fields())
+ )
+ values = [f["pk"] for f in self.source.getFeatures(request)]
self.assertEqual(values, [5, 4, 3, 2, 1])
def testOrderBy(self):
@@ -471,7 +690,7 @@ def testOpenIteratorAfterSourceRemoval(self):
information should be captured in the iterator's source and there MUST be no
links between the iterators and the sources's data source
"""
- if not getattr(self, 'getSource', None):
+ if not getattr(self, "getSource", None):
return
source = self.getSource()
@@ -481,22 +700,27 @@ def testOpenIteratorAfterSourceRemoval(self):
# get the features
pks = []
for f in it:
- pks.append(f['pk'])
+ pks.append(f["pk"])
self.assertEqual(set(pks), {1, 2, 3, 4, 5})
def testGetFeaturesFidTests(self):
fids = [f.id() for f in self.source.getFeatures()]
- assert len(fids) == 5, f'Expected 5 features, got {len(fids)} instead'
+ assert len(fids) == 5, f"Expected 5 features, got {len(fids)} instead"
for id in fids:
- features = [f for f in self.source.getFeatures(QgsFeatureRequest().setFilterFid(id))]
+ features = [
+ f for f in self.source.getFeatures(QgsFeatureRequest().setFilterFid(id))
+ ]
self.assertEqual(len(features), 1)
feature = features[0]
self.assertTrue(feature.isValid())
result = [feature.id()]
expected = [id]
- assert result == expected, 'Expected {} and got {} when testing for feature ID filter'.format(expected,
- result)
+ assert (
+ result == expected
+ ), "Expected {} and got {} when testing for feature ID filter".format(
+ expected, result
+ )
# test that results match QgsFeatureRequest.acceptFeature
request = QgsFeatureRequest().setFilterFid(id)
@@ -521,9 +745,11 @@ def testGetFeaturesFidsTests(self):
request = QgsFeatureRequest().setFilterFids([fids[0], fids[2]])
result = {f.id() for f in self.source.getFeatures(request)}
- all_valid = (all(f.isValid() for f in self.source.getFeatures(request)))
+ all_valid = all(f.isValid() for f in self.source.getFeatures(request))
expected = {fids[0], fids[2]}
- assert result == expected, f'Expected {expected} and got {result} when testing for feature IDs filter'
+ assert (
+ result == expected
+ ), f"Expected {expected} and got {result} when testing for feature IDs filter"
self.assertTrue(all_valid)
# test that results match QgsFeatureRequest.acceptFeature
@@ -531,19 +757,38 @@ def testGetFeaturesFidsTests(self):
self.assertEqual(request.acceptFeature(f), f.id() in expected)
result = {
- f.id() for f in self.source.getFeatures(QgsFeatureRequest().setFilterFids([fids[1], fids[3], fids[4]]))}
+ f.id()
+ for f in self.source.getFeatures(
+ QgsFeatureRequest().setFilterFids([fids[1], fids[3], fids[4]])
+ )
+ }
expected = {fids[1], fids[3], fids[4]}
- assert result == expected, f'Expected {expected} and got {result} when testing for feature IDs filter'
+ assert (
+ result == expected
+ ), f"Expected {expected} and got {result} when testing for feature IDs filter"
# sources should ignore non-existent fids
- result = {f.id() for f in self.source.getFeatures(
- QgsFeatureRequest().setFilterFids([-101, fids[1], -102, fids[3], -103, fids[4], -104]))}
+ result = {
+ f.id()
+ for f in self.source.getFeatures(
+ QgsFeatureRequest().setFilterFids(
+ [-101, fids[1], -102, fids[3], -103, fids[4], -104]
+ )
+ )
+ }
expected = {fids[1], fids[3], fids[4]}
- assert result == expected, f'Expected {expected} and got {result} when testing for feature IDs filter'
+ assert (
+ result == expected
+ ), f"Expected {expected} and got {result} when testing for feature IDs filter"
- result = {f.id() for f in self.source.getFeatures(QgsFeatureRequest().setFilterFids([]))}
+ result = {
+ f.id()
+ for f in self.source.getFeatures(QgsFeatureRequest().setFilterFids([]))
+ }
expected = set()
- assert result == expected, f'Expected {expected} and got {result} when testing for feature IDs filter'
+ assert (
+ result == expected
+ ), f"Expected {expected} and got {result} when testing for feature IDs filter"
# Rewind mid-way
request = QgsFeatureRequest().setFilterFids([fids[1], fids[3], fids[4]])
@@ -569,29 +814,29 @@ def testGetFeaturesFidsTests(self):
def testGetFeaturesFilterRectTests(self):
extent = QgsRectangle(-70, 67, -60, 80)
request = QgsFeatureRequest().setFilterRect(extent)
- features = [f['pk'] for f in self.source.getFeatures(request)]
- all_valid = (all(f.isValid() for f in self.source.getFeatures(request)))
- assert set(features) == {2, 4}, f'Got {features} instead'
+ features = [f["pk"] for f in self.source.getFeatures(request)]
+ all_valid = all(f.isValid() for f in self.source.getFeatures(request))
+ assert set(features) == {2, 4}, f"Got {features} instead"
self.assertTrue(all_valid)
# test that results match QgsFeatureRequest.acceptFeature
for f in self.source.getFeatures():
- self.assertEqual(request.acceptFeature(f), f['pk'] in {2, 4})
+ self.assertEqual(request.acceptFeature(f), f["pk"] in {2, 4})
# test with an empty rectangle
extent = QgsRectangle()
request = QgsFeatureRequest().setFilterRect(extent)
- features = [f['pk'] for f in self.source.getFeatures(request)]
- all_valid = (all(f.isValid() for f in self.source.getFeatures(request)))
- assert set(features) == {1, 2, 3, 4, 5}, f'Got {features} instead'
+ features = [f["pk"] for f in self.source.getFeatures(request)]
+ all_valid = all(f.isValid() for f in self.source.getFeatures(request))
+ assert set(features) == {1, 2, 3, 4, 5}, f"Got {features} instead"
self.assertTrue(all_valid)
# ExactIntersection flag set, but no filter rect set. Should be ignored.
request = QgsFeatureRequest()
request.setFlags(QgsFeatureRequest.Flag.ExactIntersect)
- features = [f['pk'] for f in self.source.getFeatures(request)]
- all_valid = (all(f.isValid() for f in self.source.getFeatures(request)))
- assert set(features) == {1, 2, 3, 4, 5}, f'Got {features} instead'
+ features = [f["pk"] for f in self.source.getFeatures(request)]
+ all_valid = all(f.isValid() for f in self.source.getFeatures(request))
+ assert set(features) == {1, 2, 3, 4, 5}, f"Got {features} instead"
self.assertTrue(all_valid)
def testGetFeaturesFilterRectTestsNoGeomFlag(self):
@@ -604,165 +849,241 @@ def testGetFeaturesFilterRectTestsNoGeomFlag(self):
request.setFilterRect(extent)
request.setFlags(QgsFeatureRequest.Flag.NoGeometry)
- features = [f['pk'] for f in self.source.getFeatures(request)]
- all_valid = (all(f.isValid() for f in self.source.getFeatures(request)))
- assert set(features) == {2, 4}, f'Got {features} instead'
+ features = [f["pk"] for f in self.source.getFeatures(request)]
+ all_valid = all(f.isValid() for f in self.source.getFeatures(request))
+ assert set(features) == {2, 4}, f"Got {features} instead"
self.assertTrue(all_valid)
# test that results match QgsFeatureRequest.acceptFeature
for f in self.source.getFeatures():
- self.assertEqual(request.acceptFeature(f), f['pk'] in {2, 4})
+ self.assertEqual(request.acceptFeature(f), f["pk"] in {2, 4})
# test with an empty rectangle
extent = QgsRectangle()
- request = QgsFeatureRequest().setFilterRect(extent).setFlags(QgsFeatureRequest.Flag.NoGeometry)
- features = [f['pk'] for f in self.source.getFeatures(request)]
- all_valid = (all(f.isValid() for f in self.source.getFeatures(request)))
- assert set(features) == {1, 2, 3, 4, 5}, f'Got {features} instead'
+ request = (
+ QgsFeatureRequest()
+ .setFilterRect(extent)
+ .setFlags(QgsFeatureRequest.Flag.NoGeometry)
+ )
+ features = [f["pk"] for f in self.source.getFeatures(request)]
+ all_valid = all(f.isValid() for f in self.source.getFeatures(request))
+ assert set(features) == {1, 2, 3, 4, 5}, f"Got {features} instead"
self.assertTrue(all_valid)
# ExactIntersection flag set, but no filter rect set. Should be ignored.
request = QgsFeatureRequest()
- request.setFlags(QgsFeatureRequest.Flag.ExactIntersect | QgsFeatureRequest.Flag.NoGeometry)
- features = [f['pk'] for f in self.source.getFeatures(request)]
- all_valid = (all(f.isValid() for f in self.source.getFeatures(request)))
- assert set(features) == {1, 2, 3, 4, 5}, f'Got {features} instead'
+ request.setFlags(
+ QgsFeatureRequest.Flag.ExactIntersect | QgsFeatureRequest.Flag.NoGeometry
+ )
+ features = [f["pk"] for f in self.source.getFeatures(request)]
+ all_valid = all(f.isValid() for f in self.source.getFeatures(request))
+ assert set(features) == {1, 2, 3, 4, 5}, f"Got {features} instead"
self.assertTrue(all_valid)
def testRectAndExpression(self):
extent = QgsRectangle(-70, 67, -60, 80)
- request = QgsFeatureRequest().setFilterExpression('"cnt">200').setFilterRect(extent)
- result = {f['pk'] for f in self.source.getFeatures(request)}
- all_valid = (all(f.isValid() for f in self.source.getFeatures(request)))
+ request = (
+ QgsFeatureRequest().setFilterExpression('"cnt">200').setFilterRect(extent)
+ )
+ result = {f["pk"] for f in self.source.getFeatures(request)}
+ all_valid = all(f.isValid() for f in self.source.getFeatures(request))
expected = [4]
- assert set(
- expected) == result, 'Expected {} and got {} when testing for combination of filterRect and expression'.format(
- set(expected), result)
+ assert (
+ set(expected) == result
+ ), "Expected {} and got {} when testing for combination of filterRect and expression".format(
+ set(expected), result
+ )
self.assertTrue(all_valid)
# shouldn't matter what order this is done in
- request = QgsFeatureRequest().setFilterRect(extent).setFilterExpression('"cnt">200')
- result = {f['pk'] for f in self.source.getFeatures(request)}
- all_valid = (all(f.isValid() for f in self.source.getFeatures(request)))
+ request = (
+ QgsFeatureRequest().setFilterRect(extent).setFilterExpression('"cnt">200')
+ )
+ result = {f["pk"] for f in self.source.getFeatures(request)}
+ all_valid = all(f.isValid() for f in self.source.getFeatures(request))
expected = [4]
- assert set(
- expected) == result, 'Expected {} and got {} when testing for combination of filterRect and expression'.format(
- set(expected), result)
+ assert (
+ set(expected) == result
+ ), "Expected {} and got {} when testing for combination of filterRect and expression".format(
+ set(expected), result
+ )
self.assertTrue(all_valid)
# test that results match QgsFeatureRequest.acceptFeature
for f in self.source.getFeatures():
- self.assertEqual(request.acceptFeature(f), f['pk'] in expected)
+ self.assertEqual(request.acceptFeature(f), f["pk"] in expected)
def testGetFeaturesDistanceWithinTests(self):
- request = QgsFeatureRequest().setDistanceWithin(QgsGeometry.fromWkt('LineString (-63.2 69.9, -68.47 69.86, -69.74 79.28)'), 1.7)
- features = [f['pk'] for f in self.source.getFeatures(request)]
- all_valid = (all(f.isValid() for f in self.source.getFeatures(request)))
- assert set(features) == {2, 5}, f'Got {features} instead'
+ request = QgsFeatureRequest().setDistanceWithin(
+ QgsGeometry.fromWkt("LineString (-63.2 69.9, -68.47 69.86, -69.74 79.28)"),
+ 1.7,
+ )
+ features = [f["pk"] for f in self.source.getFeatures(request)]
+ all_valid = all(f.isValid() for f in self.source.getFeatures(request))
+ assert set(features) == {2, 5}, f"Got {features} instead"
self.assertTrue(all_valid)
# test that results match QgsFeatureRequest.acceptFeature
for f in self.source.getFeatures():
- self.assertEqual(request.acceptFeature(f), f['pk'] in {2, 5})
+ self.assertEqual(request.acceptFeature(f), f["pk"] in {2, 5})
- request = QgsFeatureRequest().setDistanceWithin(QgsGeometry.fromWkt('LineString (-63.2 69.9, -68.47 69.86, -69.74 79.28)'), 0.6)
- features = [f['pk'] for f in self.source.getFeatures(request)]
- all_valid = (all(f.isValid() for f in self.source.getFeatures(request)))
- assert set(features) == {2}, f'Got {features} instead'
+ request = QgsFeatureRequest().setDistanceWithin(
+ QgsGeometry.fromWkt("LineString (-63.2 69.9, -68.47 69.86, -69.74 79.28)"),
+ 0.6,
+ )
+ features = [f["pk"] for f in self.source.getFeatures(request)]
+ all_valid = all(f.isValid() for f in self.source.getFeatures(request))
+ assert set(features) == {2}, f"Got {features} instead"
self.assertTrue(all_valid)
# test that results match QgsFeatureRequest.acceptFeature
for f in self.source.getFeatures():
- self.assertEqual(request.acceptFeature(f), f['pk'] in {2})
+ self.assertEqual(request.acceptFeature(f), f["pk"] in {2})
# in different crs
- request = QgsFeatureRequest().setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:3857'), QgsProject.instance().transformContext()).setDistanceWithin(QgsGeometry.fromWkt('LineString (-7035391 11036245, -7622045 11023301, -7763421 15092839)'), 250000)
- features = [f['pk'] for f in self.source.getFeatures(request)]
- all_valid = (all(f.isValid() for f in self.source.getFeatures(request)))
+ request = (
+ QgsFeatureRequest()
+ .setDestinationCrs(
+ QgsCoordinateReferenceSystem("EPSG:3857"),
+ QgsProject.instance().transformContext(),
+ )
+ .setDistanceWithin(
+ QgsGeometry.fromWkt(
+ "LineString (-7035391 11036245, -7622045 11023301, -7763421 15092839)"
+ ),
+ 250000,
+ )
+ )
+ features = [f["pk"] for f in self.source.getFeatures(request)]
+ all_valid = all(f.isValid() for f in self.source.getFeatures(request))
self.assertEqual(set(features), {2, 5})
self.assertTrue(all_valid)
# using coordinate transform
- request = QgsFeatureRequest().setCoordinateTransform(
- QgsCoordinateTransform(
- self.source.sourceCrs(),
- QgsCoordinateReferenceSystem('EPSG:3857'), QgsProject.instance().transformContext()
- )).setDistanceWithin(QgsGeometry.fromWkt('LineString (-7035391 11036245, -7622045 11023301, -7763421 15092839)'), 250000)
- features = [f['pk'] for f in self.source.getFeatures(request)]
- all_valid = (all(f.isValid() for f in self.source.getFeatures(request)))
+ request = (
+ QgsFeatureRequest()
+ .setCoordinateTransform(
+ QgsCoordinateTransform(
+ self.source.sourceCrs(),
+ QgsCoordinateReferenceSystem("EPSG:3857"),
+ QgsProject.instance().transformContext(),
+ )
+ )
+ .setDistanceWithin(
+ QgsGeometry.fromWkt(
+ "LineString (-7035391 11036245, -7622045 11023301, -7763421 15092839)"
+ ),
+ 250000,
+ )
+ )
+ features = [f["pk"] for f in self.source.getFeatures(request)]
+ all_valid = all(f.isValid() for f in self.source.getFeatures(request))
self.assertEqual(set(features), {2, 5})
self.assertTrue(all_valid)
# point geometry
request = QgsFeatureRequest().setDistanceWithin(
- QgsGeometry.fromWkt('Point (-68.1 78.1)'), 3.6)
- features = [f['pk'] for f in self.source.getFeatures(request)]
- all_valid = (all(f.isValid() for f in self.source.getFeatures(request)))
- assert set(features) == {4, 5}, f'Got {features} instead'
+ QgsGeometry.fromWkt("Point (-68.1 78.1)"), 3.6
+ )
+ features = [f["pk"] for f in self.source.getFeatures(request)]
+ all_valid = all(f.isValid() for f in self.source.getFeatures(request))
+ assert set(features) == {4, 5}, f"Got {features} instead"
self.assertTrue(all_valid)
# test that results match QgsFeatureRequest.acceptFeature
for f in self.source.getFeatures():
- self.assertEqual(request.acceptFeature(f), f['pk'] in {4, 5})
+ self.assertEqual(request.acceptFeature(f), f["pk"] in {4, 5})
request = QgsFeatureRequest().setDistanceWithin(
- QgsGeometry.fromWkt('Polygon ((-64.47 79.59, -64.37 73.59, -72.69 73.61, -72.73 68.07, -62.51 68.01, -62.71 79.55, -64.47 79.59))'), 0)
- features = [f['pk'] for f in self.source.getFeatures(request)]
- all_valid = (all(f.isValid() for f in self.source.getFeatures(request)))
- assert set(features) == {2}, f'Got {features} instead'
+ QgsGeometry.fromWkt(
+ "Polygon ((-64.47 79.59, -64.37 73.59, -72.69 73.61, -72.73 68.07, -62.51 68.01, -62.71 79.55, -64.47 79.59))"
+ ),
+ 0,
+ )
+ features = [f["pk"] for f in self.source.getFeatures(request)]
+ all_valid = all(f.isValid() for f in self.source.getFeatures(request))
+ assert set(features) == {2}, f"Got {features} instead"
self.assertTrue(all_valid)
# test that results match QgsFeatureRequest.acceptFeature
for f in self.source.getFeatures():
- self.assertEqual(request.acceptFeature(f), f['pk'] in {2})
+ self.assertEqual(request.acceptFeature(f), f["pk"] in {2})
request = QgsFeatureRequest().setDistanceWithin(
- QgsGeometry.fromWkt('Polygon ((-64.47 79.59, -64.37 73.59, -72.69 73.61, -72.73 68.07, -62.51 68.01, -62.71 79.55, -64.47 79.59))'), 1.3)
- features = [f['pk'] for f in self.source.getFeatures(request)]
- all_valid = (all(f.isValid() for f in self.source.getFeatures(request)))
- assert set(features) == {2, 4}, f'Got {features} instead'
+ QgsGeometry.fromWkt(
+ "Polygon ((-64.47 79.59, -64.37 73.59, -72.69 73.61, -72.73 68.07, -62.51 68.01, -62.71 79.55, -64.47 79.59))"
+ ),
+ 1.3,
+ )
+ features = [f["pk"] for f in self.source.getFeatures(request)]
+ all_valid = all(f.isValid() for f in self.source.getFeatures(request))
+ assert set(features) == {2, 4}, f"Got {features} instead"
self.assertTrue(all_valid)
# test that results match QgsFeatureRequest.acceptFeature
for f in self.source.getFeatures():
- self.assertEqual(request.acceptFeature(f), f['pk'] in {2, 4})
+ self.assertEqual(request.acceptFeature(f), f["pk"] in {2, 4})
request = QgsFeatureRequest().setDistanceWithin(
- QgsGeometry.fromWkt('Polygon ((-64.47 79.59, -64.37 73.59, -72.69 73.61, -72.73 68.07, -62.51 68.01, -62.71 79.55, -64.47 79.59))'), 2.3)
- features = [f['pk'] for f in self.source.getFeatures(request)]
- all_valid = (all(f.isValid() for f in self.source.getFeatures(request)))
- assert set(features) == {1, 2, 4}, f'Got {features} instead'
+ QgsGeometry.fromWkt(
+ "Polygon ((-64.47 79.59, -64.37 73.59, -72.69 73.61, -72.73 68.07, -62.51 68.01, -62.71 79.55, -64.47 79.59))"
+ ),
+ 2.3,
+ )
+ features = [f["pk"] for f in self.source.getFeatures(request)]
+ all_valid = all(f.isValid() for f in self.source.getFeatures(request))
+ assert set(features) == {1, 2, 4}, f"Got {features} instead"
self.assertTrue(all_valid)
# test that results match QgsFeatureRequest.acceptFeature
for f in self.source.getFeatures():
- self.assertEqual(request.acceptFeature(f), f['pk'] in {1, 2, 4})
+ self.assertEqual(request.acceptFeature(f), f["pk"] in {1, 2, 4})
# test with linestring whose bounding box overlaps all query
# points but being only within one of them, which we hope will
# be returned NOT as the first one.
# This is a test for https://github.com/qgis/QGIS/issues/45352
request = QgsFeatureRequest().setDistanceWithin(
- QgsGeometry.fromWkt('LINESTRING(-100 80, -100 66, -30 66, -30 80)'), 0.5)
- features = {f['pk'] for f in self.source.getFeatures(request)}
- self.assertEqual(features, {1}, "Unexpected return from QgsFeatureRequest with DistanceWithin filter")
+ QgsGeometry.fromWkt("LINESTRING(-100 80, -100 66, -30 66, -30 80)"), 0.5
+ )
+ features = {f["pk"] for f in self.source.getFeatures(request)}
+ self.assertEqual(
+ features,
+ {1},
+ "Unexpected return from QgsFeatureRequest with DistanceWithin filter",
+ )
def testGeomAndAllAttributes(self):
"""
Test combination of a filter which requires geometry and all attributes
"""
- request = QgsFeatureRequest().setFilterExpression(
- 'attribute($currentfeature,\'cnt\')>200 and $x>=-70 and $x<=-60').setSubsetOfAttributes([]).setFlags(
- QgsFeatureRequest.Flag.NoGeometry | QgsFeatureRequest.Flag.IgnoreStaticNodesDuringExpressionCompilation)
- result = {f['pk'] for f in self.source.getFeatures(request)}
- all_valid = (all(f.isValid() for f in self.source.getFeatures(request)))
+ request = (
+ QgsFeatureRequest()
+ .setFilterExpression(
+ "attribute($currentfeature,'cnt')>200 and $x>=-70 and $x<=-60"
+ )
+ .setSubsetOfAttributes([])
+ .setFlags(
+ QgsFeatureRequest.Flag.NoGeometry
+ | QgsFeatureRequest.Flag.IgnoreStaticNodesDuringExpressionCompilation
+ )
+ )
+ result = {f["pk"] for f in self.source.getFeatures(request)}
+ all_valid = all(f.isValid() for f in self.source.getFeatures(request))
self.assertEqual(result, {4})
self.assertTrue(all_valid)
- request = QgsFeatureRequest().setFilterExpression(
- 'attribute($currentfeature,\'cnt\')>200 and $x>=-70 and $x<=-60').setFlags(QgsFeatureRequest.Flag.IgnoreStaticNodesDuringExpressionCompilation)
- result = {f['pk'] for f in self.source.getFeatures(request)}
- all_valid = (all(f.isValid() for f in self.source.getFeatures(request)))
+ request = (
+ QgsFeatureRequest()
+ .setFilterExpression(
+ "attribute($currentfeature,'cnt')>200 and $x>=-70 and $x<=-60"
+ )
+ .setFlags(
+ QgsFeatureRequest.Flag.IgnoreStaticNodesDuringExpressionCompilation
+ )
+ )
+ result = {f["pk"] for f in self.source.getFeatures(request)}
+ all_valid = all(f.isValid() for f in self.source.getFeatures(request))
self.assertEqual(result, {4})
self.assertTrue(all_valid)
@@ -772,36 +1093,46 @@ def testRectAndFids(self):
"""
# first get feature ids
- ids = {f['pk']: f.id() for f in self.source.getFeatures()}
+ ids = {f["pk"]: f.id() for f in self.source.getFeatures()}
extent = QgsRectangle(-70, 67, -60, 80)
- request = QgsFeatureRequest().setFilterFids([ids[3], ids[4]]).setFilterRect(extent)
- result = {f['pk'] for f in self.source.getFeatures(request)}
- all_valid = (all(f.isValid() for f in self.source.getFeatures(request)))
+ request = (
+ QgsFeatureRequest().setFilterFids([ids[3], ids[4]]).setFilterRect(extent)
+ )
+ result = {f["pk"] for f in self.source.getFeatures(request)}
+ all_valid = all(f.isValid() for f in self.source.getFeatures(request))
expected = [4]
- assert set(
- expected) == result, 'Expected {} and got {} when testing for combination of filterRect and expression'.format(
- set(expected), result)
+ assert (
+ set(expected) == result
+ ), "Expected {} and got {} when testing for combination of filterRect and expression".format(
+ set(expected), result
+ )
self.assertTrue(all_valid)
# shouldn't matter what order this is done in
- request = QgsFeatureRequest().setFilterRect(extent).setFilterFids([ids[3], ids[4]])
- result = {f['pk'] for f in self.source.getFeatures(request)}
- all_valid = (all(f.isValid() for f in self.source.getFeatures(request)))
+ request = (
+ QgsFeatureRequest().setFilterRect(extent).setFilterFids([ids[3], ids[4]])
+ )
+ result = {f["pk"] for f in self.source.getFeatures(request)}
+ all_valid = all(f.isValid() for f in self.source.getFeatures(request))
expected = [4]
- assert set(
- expected) == result, 'Expected {} and got {} when testing for combination of filterRect and expression'.format(
- set(expected), result)
+ assert (
+ set(expected) == result
+ ), "Expected {} and got {} when testing for combination of filterRect and expression".format(
+ set(expected), result
+ )
self.assertTrue(all_valid)
# test that results match QgsFeatureRequest.acceptFeature
for f in self.source.getFeatures():
- self.assertEqual(request.acceptFeature(f), f['pk'] in expected)
+ self.assertEqual(request.acceptFeature(f), f["pk"] in expected)
def testGetFeaturesDestinationCrs(self):
- request = QgsFeatureRequest().setDestinationCrs(QgsCoordinateReferenceSystem('epsg:3857'),
- QgsProject.instance().transformContext())
- features = {f['pk']: f for f in self.source.getFeatures(request)}
+ request = QgsFeatureRequest().setDestinationCrs(
+ QgsCoordinateReferenceSystem("epsg:3857"),
+ QgsProject.instance().transformContext(),
+ )
+ features = {f["pk"]: f for f in self.source.getFeatures(request)}
# test that features have been reprojected
self.assertAlmostEqual(features[1].geometry().constGet().x(), -7829322, -5)
self.assertAlmostEqual(features[1].geometry().constGet().y(), 9967753, -5)
@@ -815,9 +1146,15 @@ def testGetFeaturesDestinationCrs(self):
# when destination crs is set, filter rect should be in destination crs
rect = QgsRectangle(-7650000, 10500000, -7200000, 15000000)
- request = QgsFeatureRequest().setDestinationCrs(QgsCoordinateReferenceSystem('epsg:3857'),
- QgsProject.instance().transformContext()).setFilterRect(rect)
- features = {f['pk']: f for f in self.source.getFeatures(request)}
+ request = (
+ QgsFeatureRequest()
+ .setDestinationCrs(
+ QgsCoordinateReferenceSystem("epsg:3857"),
+ QgsProject.instance().transformContext(),
+ )
+ .setFilterRect(rect)
+ )
+ features = {f["pk"]: f for f in self.source.getFeatures(request)}
self.assertEqual(set(features.keys()), {2, 4})
# test that features have been reprojected
self.assertAlmostEqual(features[2].geometry().constGet().x(), -7591989, -5)
@@ -827,8 +1164,14 @@ def testGetFeaturesDestinationCrs(self):
# bad rect for transform
rect = QgsRectangle(-99999999999, 99999999999, -99999999998, 99999999998)
- request = QgsFeatureRequest().setDestinationCrs(QgsCoordinateReferenceSystem('epsg:28356'),
- QgsProject.instance().transformContext()).setFilterRect(rect)
+ request = (
+ QgsFeatureRequest()
+ .setDestinationCrs(
+ QgsCoordinateReferenceSystem("epsg:28356"),
+ QgsProject.instance().transformContext(),
+ )
+ .setFilterRect(rect)
+ )
features = [f for f in self.source.getFeatures(request)]
self.assertFalse(features)
@@ -836,10 +1179,11 @@ def testGetFeaturesCoordinateTransform(self):
request = QgsFeatureRequest().setCoordinateTransform(
QgsCoordinateTransform(
self.source.sourceCrs(),
- QgsCoordinateReferenceSystem('epsg:3857'),
- QgsProject.instance().transformContext())
+ QgsCoordinateReferenceSystem("epsg:3857"),
+ QgsProject.instance().transformContext(),
+ )
)
- features = {f['pk']: f for f in self.source.getFeatures(request)}
+ features = {f["pk"]: f for f in self.source.getFeatures(request)}
# test that features have been reprojected
self.assertAlmostEqual(features[1].geometry().constGet().x(), -7829322, -5)
self.assertAlmostEqual(features[1].geometry().constGet().y(), 9967753, -5)
@@ -853,13 +1197,18 @@ def testGetFeaturesCoordinateTransform(self):
# when destination crs is set, filter rect should be in destination crs
rect = QgsRectangle(-7650000, 10500000, -7200000, 15000000)
- request = QgsFeatureRequest().setCoordinateTransform(
- QgsCoordinateTransform(
- self.source.sourceCrs(),
- QgsCoordinateReferenceSystem('epsg:3857'),
- QgsProject.instance().transformContext())
- ).setFilterRect(rect)
- features = {f['pk']: f for f in self.source.getFeatures(request)}
+ request = (
+ QgsFeatureRequest()
+ .setCoordinateTransform(
+ QgsCoordinateTransform(
+ self.source.sourceCrs(),
+ QgsCoordinateReferenceSystem("epsg:3857"),
+ QgsProject.instance().transformContext(),
+ )
+ )
+ .setFilterRect(rect)
+ )
+ features = {f["pk"]: f for f in self.source.getFeatures(request)}
self.assertEqual(set(features.keys()), {2, 4})
# test that features have been reprojected
self.assertAlmostEqual(features[2].geometry().constGet().x(), -7591989, -5)
@@ -869,218 +1218,466 @@ def testGetFeaturesCoordinateTransform(self):
# bad rect for transform
rect = QgsRectangle(-99999999999, 99999999999, -99999999998, 99999999998)
- request = QgsFeatureRequest().setCoordinateTransform(
- QgsCoordinateTransform(
- self.source.sourceCrs(),
- QgsCoordinateReferenceSystem('epsg:28356'),
- QgsProject.instance().transformContext())
- ).setFilterRect(rect)
+ request = (
+ QgsFeatureRequest()
+ .setCoordinateTransform(
+ QgsCoordinateTransform(
+ self.source.sourceCrs(),
+ QgsCoordinateReferenceSystem("epsg:28356"),
+ QgsProject.instance().transformContext(),
+ )
+ )
+ .setFilterRect(rect)
+ )
features = [f for f in self.source.getFeatures(request)]
self.assertFalse(features)
def testGetFeaturesLimit(self):
it = self.source.getFeatures(QgsFeatureRequest().setLimit(2))
- features = [f['pk'] for f in it]
- assert len(features) == 2, f'Expected two features, got {len(features)} instead'
+ features = [f["pk"] for f in it]
+ assert len(features) == 2, f"Expected two features, got {len(features)} instead"
# fetch one feature
feature = QgsFeature()
- assert not it.nextFeature(feature), 'Expected no feature after limit, got one'
+ assert not it.nextFeature(feature), "Expected no feature after limit, got one"
it.rewind()
- features = [f['pk'] for f in it]
- assert len(features) == 2, f'Expected two features after rewind, got {len(features)} instead'
+ features = [f["pk"] for f in it]
+ assert (
+ len(features) == 2
+ ), f"Expected two features after rewind, got {len(features)} instead"
it.rewind()
- assert it.nextFeature(feature), 'Expected feature after rewind, got none'
+ assert it.nextFeature(feature), "Expected feature after rewind, got none"
it.rewind()
- features = [f['pk'] for f in it]
- assert len(features) == 2, f'Expected two features after rewind, got {len(features)} instead'
+ features = [f["pk"] for f in it]
+ assert (
+ len(features) == 2
+ ), f"Expected two features after rewind, got {len(features)} instead"
# test with expression, both with and without compilation
try:
self.disableCompiler()
except AttributeError:
pass
- it = self.source.getFeatures(QgsFeatureRequest().setLimit(2).setFilterExpression('cnt <= 100'))
- features = [f['pk'] for f in it]
- assert set(features) == {1, 5}, 'Expected [1,5] for expression and feature limit, Got {} instead'.format(
- features)
+ it = self.source.getFeatures(
+ QgsFeatureRequest().setLimit(2).setFilterExpression("cnt <= 100")
+ )
+ features = [f["pk"] for f in it]
+ assert set(features) == {
+ 1,
+ 5,
+ }, "Expected [1,5] for expression and feature limit, Got {} instead".format(
+ features
+ )
try:
self.enableCompiler()
except AttributeError:
pass
- it = self.source.getFeatures(QgsFeatureRequest().setLimit(2).setFilterExpression('cnt <= 100'))
- features = [f['pk'] for f in it]
- assert set(features) == {1, 5}, 'Expected [1,5] for expression and feature limit, Got {} instead'.format(
- features)
+ it = self.source.getFeatures(
+ QgsFeatureRequest().setLimit(2).setFilterExpression("cnt <= 100")
+ )
+ features = [f["pk"] for f in it]
+ assert set(features) == {
+ 1,
+ 5,
+ }, "Expected [1,5] for expression and feature limit, Got {} instead".format(
+ features
+ )
# limit to more features than exist
- it = self.source.getFeatures(QgsFeatureRequest().setLimit(3).setFilterExpression('cnt <= 100'))
- features = [f['pk'] for f in it]
- assert set(features) == {1, 5}, 'Expected [1,5] for expression and feature limit, Got {} instead'.format(
- features)
+ it = self.source.getFeatures(
+ QgsFeatureRequest().setLimit(3).setFilterExpression("cnt <= 100")
+ )
+ features = [f["pk"] for f in it]
+ assert set(features) == {
+ 1,
+ 5,
+ }, "Expected [1,5] for expression and feature limit, Got {} instead".format(
+ features
+ )
# limit to less features than possible
- it = self.source.getFeatures(QgsFeatureRequest().setLimit(1).setFilterExpression('cnt <= 100'))
- features = [f['pk'] for f in it]
- assert 1 in features or 5 in features, 'Expected either 1 or 5 for expression and feature limit, Got {} instead'.format(
- features)
+ it = self.source.getFeatures(
+ QgsFeatureRequest().setLimit(1).setFilterExpression("cnt <= 100")
+ )
+ features = [f["pk"] for f in it]
+ assert (
+ 1 in features or 5 in features
+ ), "Expected either 1 or 5 for expression and feature limit, Got {} instead".format(
+ features
+ )
def testClosedIterators(self):
- """ Test behavior of closed iterators """
+ """Test behavior of closed iterators"""
# Test retrieving feature after closing iterator
f_it = self.source.getFeatures(QgsFeatureRequest())
fet = QgsFeature()
- assert f_it.nextFeature(fet), 'Could not fetch feature'
- assert fet.isValid(), 'Feature is not valid'
- assert f_it.close(), 'Could not close iterator'
- self.assertFalse(f_it.nextFeature(fet),
- 'Fetched feature after iterator closed, expected nextFeature() to return False')
- self.assertFalse(fet.isValid(), 'Valid feature fetched from closed iterator, should be invalid')
+ assert f_it.nextFeature(fet), "Could not fetch feature"
+ assert fet.isValid(), "Feature is not valid"
+ assert f_it.close(), "Could not close iterator"
+ self.assertFalse(
+ f_it.nextFeature(fet),
+ "Fetched feature after iterator closed, expected nextFeature() to return False",
+ )
+ self.assertFalse(
+ fet.isValid(),
+ "Valid feature fetched from closed iterator, should be invalid",
+ )
# Test rewinding closed iterator
- self.assertFalse(f_it.rewind(), 'Rewinding closed iterator successful, should not be allowed')
+ self.assertFalse(
+ f_it.rewind(), "Rewinding closed iterator successful, should not be allowed"
+ )
def testGetFeaturesSubsetAttributes(self):
- """ Test that expected results are returned when using subsets of attributes """
-
- tz = Qt.TimeSpec.UTC if self.treat_datetime_tz_as_utc() else Qt.TimeSpec.LocalTime
- tests = {'pk': {1, 2, 3, 4, 5},
- 'cnt': {-200, 300, 100, 200, 400},
- 'name': {'Pear', 'Orange', 'Apple', 'Honey', NULL},
- 'name2': {'NuLl', 'PEaR', 'oranGe', 'Apple', 'Honey'},
- 'dt': {NULL, '2021-05-04 13:13:14' if self.treat_datetime_as_string() else QDateTime(QDate(2021, 5, 4), QTime(13, 13, 14, 0), tz) if not self.treat_datetime_as_string() else '2021-05-04 13:13:14',
- '2020-05-04 12:14:14' if self.treat_datetime_as_string() else QDateTime(QDate(2020, 5, 4), QTime(12, 14, 14, 0), tz) if not self.treat_datetime_as_string() else '2020-05-04 12:14:14',
- '2020-05-04 12:13:14' if self.treat_datetime_as_string() else QDateTime(QDate(2020, 5, 4), QTime(12, 13, 14, 0), tz) if not self.treat_datetime_as_string() else '2020-05-04 12:13:14',
- '2020-05-03 12:13:14' if self.treat_datetime_as_string() else QDateTime(QDate(2020, 5, 3), QTime(12, 13, 14, 0), tz) if not self.treat_datetime_as_string() else '2020-05-03 12:13:14'},
- 'date': {NULL,
- '2020-05-02' if self.treat_date_as_string() else QDate(2020, 5, 2) if not self.treat_date_as_datetime() else QDateTime(2020, 5, 2, 0, 0, 0),
- '2020-05-03' if self.treat_date_as_string() else QDate(2020, 5, 3) if not self.treat_date_as_datetime() else QDateTime(2020, 5, 3, 0, 0, 0),
- '2020-05-04' if self.treat_date_as_string() else QDate(2020, 5, 4) if not self.treat_date_as_datetime() else QDateTime(2020, 5, 4, 0, 0, 0),
- '2021-05-04' if self.treat_date_as_string() else QDate(2021, 5, 4) if not self.treat_date_as_datetime() else QDateTime(2021, 5, 4, 0, 0, 0)},
- 'time': {QTime(12, 13, 1) if not self.treat_time_as_string() else '12:13:01',
- QTime(12, 14, 14) if not self.treat_time_as_string() else '12:14:14',
- QTime(12, 13, 14) if not self.treat_time_as_string() else '12:13:14',
- QTime(13, 13, 14) if not self.treat_time_as_string() else '13:13:14', NULL}}
+ """Test that expected results are returned when using subsets of attributes"""
+
+ tz = (
+ Qt.TimeSpec.UTC
+ if self.treat_datetime_tz_as_utc()
+ else Qt.TimeSpec.LocalTime
+ )
+ tests = {
+ "pk": {1, 2, 3, 4, 5},
+ "cnt": {-200, 300, 100, 200, 400},
+ "name": {"Pear", "Orange", "Apple", "Honey", NULL},
+ "name2": {"NuLl", "PEaR", "oranGe", "Apple", "Honey"},
+ "dt": {
+ NULL,
+ (
+ "2021-05-04 13:13:14"
+ if self.treat_datetime_as_string()
+ else (
+ QDateTime(QDate(2021, 5, 4), QTime(13, 13, 14, 0), tz)
+ if not self.treat_datetime_as_string()
+ else "2021-05-04 13:13:14"
+ )
+ ),
+ (
+ "2020-05-04 12:14:14"
+ if self.treat_datetime_as_string()
+ else (
+ QDateTime(QDate(2020, 5, 4), QTime(12, 14, 14, 0), tz)
+ if not self.treat_datetime_as_string()
+ else "2020-05-04 12:14:14"
+ )
+ ),
+ (
+ "2020-05-04 12:13:14"
+ if self.treat_datetime_as_string()
+ else (
+ QDateTime(QDate(2020, 5, 4), QTime(12, 13, 14, 0), tz)
+ if not self.treat_datetime_as_string()
+ else "2020-05-04 12:13:14"
+ )
+ ),
+ (
+ "2020-05-03 12:13:14"
+ if self.treat_datetime_as_string()
+ else (
+ QDateTime(QDate(2020, 5, 3), QTime(12, 13, 14, 0), tz)
+ if not self.treat_datetime_as_string()
+ else "2020-05-03 12:13:14"
+ )
+ ),
+ },
+ "date": {
+ NULL,
+ (
+ "2020-05-02"
+ if self.treat_date_as_string()
+ else (
+ QDate(2020, 5, 2)
+ if not self.treat_date_as_datetime()
+ else QDateTime(2020, 5, 2, 0, 0, 0)
+ )
+ ),
+ (
+ "2020-05-03"
+ if self.treat_date_as_string()
+ else (
+ QDate(2020, 5, 3)
+ if not self.treat_date_as_datetime()
+ else QDateTime(2020, 5, 3, 0, 0, 0)
+ )
+ ),
+ (
+ "2020-05-04"
+ if self.treat_date_as_string()
+ else (
+ QDate(2020, 5, 4)
+ if not self.treat_date_as_datetime()
+ else QDateTime(2020, 5, 4, 0, 0, 0)
+ )
+ ),
+ (
+ "2021-05-04"
+ if self.treat_date_as_string()
+ else (
+ QDate(2021, 5, 4)
+ if not self.treat_date_as_datetime()
+ else QDateTime(2021, 5, 4, 0, 0, 0)
+ )
+ ),
+ },
+ "time": {
+ QTime(12, 13, 1) if not self.treat_time_as_string() else "12:13:01",
+ QTime(12, 14, 14) if not self.treat_time_as_string() else "12:14:14",
+ QTime(12, 13, 14) if not self.treat_time_as_string() else "12:13:14",
+ QTime(13, 13, 14) if not self.treat_time_as_string() else "13:13:14",
+ NULL,
+ },
+ }
for field, expected in list(tests.items()):
- request = QgsFeatureRequest().setSubsetOfAttributes([field], self.source.fields())
+ request = QgsFeatureRequest().setSubsetOfAttributes(
+ [field], self.source.fields()
+ )
result = {f[field] for f in self.source.getFeatures(request)}
- all_valid = (all(f.isValid() for f in self.source.getFeatures(request)))
- self.assertEqual(result, expected, f'Expected {expected}, got {result}')
+ all_valid = all(f.isValid() for f in self.source.getFeatures(request))
+ self.assertEqual(result, expected, f"Expected {expected}, got {result}")
self.assertTrue(all_valid)
def testGetFeaturesSubsetAttributes2(self):
- """ Test that other fields are NULL when fetching subsets of attributes """
+ """Test that other fields are NULL when fetching subsets of attributes"""
- for field_to_fetch in ['pk', 'cnt', 'name', 'name2', 'dt', 'date', 'time']:
+ for field_to_fetch in ["pk", "cnt", "name", "name2", "dt", "date", "time"]:
for f in self.source.getFeatures(
- QgsFeatureRequest().setSubsetOfAttributes([field_to_fetch], self.source.fields())):
+ QgsFeatureRequest().setSubsetOfAttributes(
+ [field_to_fetch], self.source.fields()
+ )
+ ):
# Check that all other fields are NULL and force name to lower-case
- for other_field in [field.name() for field in self.source.fields() if
- field.name().lower() != field_to_fetch]:
- if other_field == 'pk' or other_field == 'PK':
+ for other_field in [
+ field.name()
+ for field in self.source.fields()
+ if field.name().lower() != field_to_fetch
+ ]:
+ if other_field == "pk" or other_field == "PK":
# skip checking the primary key field, as it may be validly fetched by providers to use as feature id
continue
- self.assertEqual(f[other_field], NULL,
- 'Value for field "{}" was present when it should not have been fetched by request'.format(
- other_field))
+ self.assertEqual(
+ f[other_field],
+ NULL,
+ 'Value for field "{}" was present when it should not have been fetched by request'.format(
+ other_field
+ ),
+ )
def testGetFeaturesNoGeometry(self):
- """ Test that no geometry is present when fetching features without geometry"""
+ """Test that no geometry is present when fetching features without geometry"""
- for f in self.source.getFeatures(QgsFeatureRequest().setFlags(QgsFeatureRequest.Flag.NoGeometry)):
- self.assertFalse(f.hasGeometry(), 'Expected no geometry, got one')
+ for f in self.source.getFeatures(
+ QgsFeatureRequest().setFlags(QgsFeatureRequest.Flag.NoGeometry)
+ ):
+ self.assertFalse(f.hasGeometry(), "Expected no geometry, got one")
self.assertTrue(f.isValid())
def testGetFeaturesWithGeometry(self):
- """ Test that geometry is present when fetching features without setting NoGeometry flag"""
+ """Test that geometry is present when fetching features without setting NoGeometry flag"""
for f in self.source.getFeatures(QgsFeatureRequest()):
- if f['pk'] == 3:
+ if f["pk"] == 3:
# no geometry for this feature
continue
- assert f.hasGeometry(), 'Expected geometry, got none'
+ assert f.hasGeometry(), "Expected geometry, got none"
self.assertTrue(f.isValid())
def testUniqueValues(self):
- self.assertEqual(set(self.source.uniqueValues(self.source.fields().lookupField('cnt'))),
- {-200, 100, 200, 300, 400})
- assert {'Apple', 'Honey', 'Orange', 'Pear', NULL} == set(
- self.source.uniqueValues(self.source.fields().lookupField('name'))), 'Got {}'.format(
- set(self.source.uniqueValues(self.source.fields().lookupField('name'))))
+ self.assertEqual(
+ set(self.source.uniqueValues(self.source.fields().lookupField("cnt"))),
+ {-200, 100, 200, 300, 400},
+ )
+ assert {"Apple", "Honey", "Orange", "Pear", NULL} == set(
+ self.source.uniqueValues(self.source.fields().lookupField("name"))
+ ), "Got {}".format(
+ set(self.source.uniqueValues(self.source.fields().lookupField("name")))
+ )
if self.treat_datetime_as_string():
- self.assertEqual(set(self.source.uniqueValues(self.source.fields().lookupField('dt'))),
- {'2021-05-04 13:13:14', '2020-05-04 12:14:14', '2020-05-04 12:13:14', '2020-05-03 12:13:14', NULL})
+ self.assertEqual(
+ set(self.source.uniqueValues(self.source.fields().lookupField("dt"))),
+ {
+ "2021-05-04 13:13:14",
+ "2020-05-04 12:14:14",
+ "2020-05-04 12:13:14",
+ "2020-05-03 12:13:14",
+ NULL,
+ },
+ )
else:
if self.treat_datetime_tz_as_utc():
- self.assertEqual(set(self.source.uniqueValues(self.source.fields().lookupField('dt'))),
- {QDateTime(QDate(2021, 5, 4), QTime(13, 13, 14, 0), Qt.TimeSpec.UTC), QDateTime(QDate(2020, 5, 4), QTime(12, 14, 14, 0), Qt.TimeSpec.UTC),
- QDateTime(QDate(2020, 5, 4), QTime(12, 13, 14, 0), Qt.TimeSpec.UTC), QDateTime(QDate(2020, 5, 3), QTime(12, 13, 14, 0), Qt.TimeSpec.UTC), NULL})
+ self.assertEqual(
+ set(
+ self.source.uniqueValues(self.source.fields().lookupField("dt"))
+ ),
+ {
+ QDateTime(
+ QDate(2021, 5, 4), QTime(13, 13, 14, 0), Qt.TimeSpec.UTC
+ ),
+ QDateTime(
+ QDate(2020, 5, 4), QTime(12, 14, 14, 0), Qt.TimeSpec.UTC
+ ),
+ QDateTime(
+ QDate(2020, 5, 4), QTime(12, 13, 14, 0), Qt.TimeSpec.UTC
+ ),
+ QDateTime(
+ QDate(2020, 5, 3), QTime(12, 13, 14, 0), Qt.TimeSpec.UTC
+ ),
+ NULL,
+ },
+ )
else:
- self.assertEqual(set(self.source.uniqueValues(self.source.fields().lookupField('dt'))),
- {QDateTime(2021, 5, 4, 13, 13, 14), QDateTime(2020, 5, 4, 12, 14, 14), QDateTime(2020, 5, 4, 12, 13, 14), QDateTime(2020, 5, 3, 12, 13, 14), NULL})
+ self.assertEqual(
+ set(
+ self.source.uniqueValues(self.source.fields().lookupField("dt"))
+ ),
+ {
+ QDateTime(2021, 5, 4, 13, 13, 14),
+ QDateTime(2020, 5, 4, 12, 14, 14),
+ QDateTime(2020, 5, 4, 12, 13, 14),
+ QDateTime(2020, 5, 3, 12, 13, 14),
+ NULL,
+ },
+ )
if self.treat_date_as_string():
- self.assertEqual(set(self.source.uniqueValues(self.source.fields().lookupField('date'))),
- {'2020-05-03', '2020-05-04', '2021-05-04', '2020-05-02', NULL})
+ self.assertEqual(
+ set(self.source.uniqueValues(self.source.fields().lookupField("date"))),
+ {"2020-05-03", "2020-05-04", "2021-05-04", "2020-05-02", NULL},
+ )
elif self.treat_date_as_datetime():
- self.assertEqual(set(self.source.uniqueValues(self.source.fields().lookupField('date'))),
- {QDateTime(2020, 5, 3, 0, 0, 0), QDateTime(2020, 5, 4, 0, 0, 0), QDateTime(2021, 5, 4, 0, 0, 0), QDateTime(2020, 5, 2, 0, 0, 0), NULL})
+ self.assertEqual(
+ set(self.source.uniqueValues(self.source.fields().lookupField("date"))),
+ {
+ QDateTime(2020, 5, 3, 0, 0, 0),
+ QDateTime(2020, 5, 4, 0, 0, 0),
+ QDateTime(2021, 5, 4, 0, 0, 0),
+ QDateTime(2020, 5, 2, 0, 0, 0),
+ NULL,
+ },
+ )
else:
- self.assertEqual(set(self.source.uniqueValues(self.source.fields().lookupField('date'))),
- {QDate(2020, 5, 3), QDate(2020, 5, 4), QDate(2021, 5, 4), QDate(2020, 5, 2), NULL})
+ self.assertEqual(
+ set(self.source.uniqueValues(self.source.fields().lookupField("date"))),
+ {
+ QDate(2020, 5, 3),
+ QDate(2020, 5, 4),
+ QDate(2021, 5, 4),
+ QDate(2020, 5, 2),
+ NULL,
+ },
+ )
if self.treat_time_as_string():
- self.assertEqual(set(self.source.uniqueValues(self.source.fields().lookupField('time'))),
- {'12:14:14', '13:13:14', '12:13:14', '12:13:01', NULL})
+ self.assertEqual(
+ set(self.source.uniqueValues(self.source.fields().lookupField("time"))),
+ {"12:14:14", "13:13:14", "12:13:14", "12:13:01", NULL},
+ )
else:
- self.assertEqual(set(self.source.uniqueValues(self.source.fields().lookupField('time'))),
- {QTime(12, 14, 14), QTime(13, 13, 14), QTime(12, 13, 14), QTime(12, 13, 1), NULL})
+ self.assertEqual(
+ set(self.source.uniqueValues(self.source.fields().lookupField("time"))),
+ {
+ QTime(12, 14, 14),
+ QTime(13, 13, 14),
+ QTime(12, 13, 14),
+ QTime(12, 13, 1),
+ NULL,
+ },
+ )
def testMinimumValue(self):
- self.assertEqual(self.source.minimumValue(self.source.fields().lookupField('cnt')), -200)
- self.assertEqual(self.source.minimumValue(self.source.fields().lookupField('name')), 'Apple')
+ self.assertEqual(
+ self.source.minimumValue(self.source.fields().lookupField("cnt")), -200
+ )
+ self.assertEqual(
+ self.source.minimumValue(self.source.fields().lookupField("name")), "Apple"
+ )
if self.treat_datetime_as_string():
- self.assertEqual(self.source.minimumValue(self.source.fields().lookupField('dt')), '2020-05-03 12:13:14')
+ self.assertEqual(
+ self.source.minimumValue(self.source.fields().lookupField("dt")),
+ "2020-05-03 12:13:14",
+ )
else:
- self.assertEqual(self.source.minimumValue(self.source.fields().lookupField('dt')), QDateTime(QDate(2020, 5, 3), QTime(12, 13, 14)))
+ self.assertEqual(
+ self.source.minimumValue(self.source.fields().lookupField("dt")),
+ QDateTime(QDate(2020, 5, 3), QTime(12, 13, 14)),
+ )
if self.treat_date_as_string():
- self.assertEqual(self.source.minimumValue(self.source.fields().lookupField('date')), '2020-05-02')
+ self.assertEqual(
+ self.source.minimumValue(self.source.fields().lookupField("date")),
+ "2020-05-02",
+ )
elif not self.treat_date_as_datetime():
- self.assertEqual(self.source.minimumValue(self.source.fields().lookupField('date')), QDate(2020, 5, 2))
+ self.assertEqual(
+ self.source.minimumValue(self.source.fields().lookupField("date")),
+ QDate(2020, 5, 2),
+ )
else:
- self.assertEqual(self.source.minimumValue(self.source.fields().lookupField('date')), QDateTime(2020, 5, 2, 0, 0, 0))
+ self.assertEqual(
+ self.source.minimumValue(self.source.fields().lookupField("date")),
+ QDateTime(2020, 5, 2, 0, 0, 0),
+ )
if not self.treat_time_as_string():
- self.assertEqual(self.source.minimumValue(self.source.fields().lookupField('time')), QTime(12, 13, 1))
+ self.assertEqual(
+ self.source.minimumValue(self.source.fields().lookupField("time")),
+ QTime(12, 13, 1),
+ )
else:
- self.assertEqual(self.source.minimumValue(self.source.fields().lookupField('time')), '12:13:01')
+ self.assertEqual(
+ self.source.minimumValue(self.source.fields().lookupField("time")),
+ "12:13:01",
+ )
def testMaximumValue(self):
- self.assertEqual(self.source.maximumValue(self.source.fields().lookupField('cnt')), 400)
- self.assertEqual(self.source.maximumValue(self.source.fields().lookupField('name')), 'Pear')
+ self.assertEqual(
+ self.source.maximumValue(self.source.fields().lookupField("cnt")), 400
+ )
+ self.assertEqual(
+ self.source.maximumValue(self.source.fields().lookupField("name")), "Pear"
+ )
if not self.treat_datetime_as_string():
- self.assertEqual(self.source.maximumValue(self.source.fields().lookupField('dt')), QDateTime(QDate(2021, 5, 4), QTime(13, 13, 14)))
+ self.assertEqual(
+ self.source.maximumValue(self.source.fields().lookupField("dt")),
+ QDateTime(QDate(2021, 5, 4), QTime(13, 13, 14)),
+ )
else:
- self.assertEqual(self.source.maximumValue(self.source.fields().lookupField('dt')), '2021-05-04 13:13:14')
+ self.assertEqual(
+ self.source.maximumValue(self.source.fields().lookupField("dt")),
+ "2021-05-04 13:13:14",
+ )
if self.treat_date_as_string():
- self.assertEqual(self.source.maximumValue(self.source.fields().lookupField('date')), '2021-05-04')
+ self.assertEqual(
+ self.source.maximumValue(self.source.fields().lookupField("date")),
+ "2021-05-04",
+ )
elif not self.treat_date_as_datetime():
- self.assertEqual(self.source.maximumValue(self.source.fields().lookupField('date')), QDate(2021, 5, 4))
+ self.assertEqual(
+ self.source.maximumValue(self.source.fields().lookupField("date")),
+ QDate(2021, 5, 4),
+ )
else:
- self.assertEqual(self.source.maximumValue(self.source.fields().lookupField('date')), QDateTime(2021, 5, 4, 0, 0, 0))
+ self.assertEqual(
+ self.source.maximumValue(self.source.fields().lookupField("date")),
+ QDateTime(2021, 5, 4, 0, 0, 0),
+ )
if not self.treat_time_as_string():
- self.assertEqual(self.source.maximumValue(self.source.fields().lookupField('time')), QTime(13, 13, 14))
+ self.assertEqual(
+ self.source.maximumValue(self.source.fields().lookupField("time")),
+ QTime(13, 13, 14),
+ )
else:
- self.assertEqual(self.source.maximumValue(self.source.fields().lookupField('time')), '13:13:14')
+ self.assertEqual(
+ self.source.maximumValue(self.source.fields().lookupField("time")),
+ "13:13:14",
+ )
def testAllFeatureIds(self):
ids = {f.id() for f in self.source.getFeatures()}
self.assertEqual(set(self.source.allFeatureIds()), ids)
def testSubsetOfAttributesWithFilterExprWithNonExistingColumn(self):
- """ Test fix for https://github.com/qgis/QGIS/issues/33878 """
+ """Test fix for https://github.com/qgis/QGIS/issues/33878"""
request = QgsFeatureRequest().setSubsetOfAttributes([0])
request.setFilterExpression("non_existing = 1")
features = [f for f in self.source.getFeatures(request)]
diff --git a/tests/src/python/mockedwebserver.py b/tests/src/python/mockedwebserver.py
index 7c73b868ea31..eb114897f0ce 100644
--- a/tests/src/python/mockedwebserver.py
+++ b/tests/src/python/mockedwebserver.py
@@ -52,7 +52,19 @@ def install_http_handler(handler_instance):
class RequestResponse:
- def __init__(self, method, path, code, headers=None, body=None, custom_method=None, expected_headers=None, expected_body=None, add_content_length_header=True, unexpected_headers=[]):
+ def __init__(
+ self,
+ method,
+ path,
+ code,
+ headers=None,
+ body=None,
+ custom_method=None,
+ expected_headers=None,
+ expected_body=None,
+ add_content_length_header=True,
+ unexpected_headers=[],
+ ):
self.method = method
self.path = path
self.code = code
@@ -73,12 +85,38 @@ def __init__(self):
def final_check(self):
assert not self.unexpected
- assert self.req_count == len(self.req_resp), (self.req_count, len(self.req_resp))
-
- def add(self, method, path, code=None, headers=None, body=None, custom_method=None, expected_headers=None, expected_body=None, add_content_length_header=True, unexpected_headers=[]):
+ assert self.req_count == len(self.req_resp), (
+ self.req_count,
+ len(self.req_resp),
+ )
+
+ def add(
+ self,
+ method,
+ path,
+ code=None,
+ headers=None,
+ body=None,
+ custom_method=None,
+ expected_headers=None,
+ expected_body=None,
+ add_content_length_header=True,
+ unexpected_headers=[],
+ ):
hdrs = {} if headers is None else headers
expected_hdrs = {} if expected_headers is None else expected_headers
- req = RequestResponse(method, path, code, hdrs, body, custom_method, expected_hdrs, expected_body, add_content_length_header, unexpected_headers)
+ req = RequestResponse(
+ method,
+ path,
+ code,
+ hdrs,
+ body,
+ custom_method,
+ expected_hdrs,
+ expected_body,
+ add_content_length_header,
+ unexpected_headers,
+ )
self.req_resp.append(req)
return req
@@ -89,29 +127,34 @@ def _process_req_resp(self, req_resp, request):
if req_resp.expected_headers:
for k in req_resp.expected_headers:
- if k not in request.headers or request.headers[k] != req_resp.expected_headers[k]:
- sys.stderr.write('Did not get expected headers: %s\n' % str(request.headers))
+ if (
+ k not in request.headers
+ or request.headers[k] != req_resp.expected_headers[k]
+ ):
+ sys.stderr.write(
+ "Did not get expected headers: %s\n" % str(request.headers)
+ )
request.send_response(400)
- request.send_header('Content-Length', 0)
+ request.send_header("Content-Length", 0)
request.end_headers()
self.unexpected = True
return
for k in req_resp.unexpected_headers:
if k in request.headers:
- sys.stderr.write('Did not expect header: %s\n' % k)
+ sys.stderr.write("Did not expect header: %s\n" % k)
request.send_response(400)
- request.send_header('Content-Length', 0)
+ request.send_header("Content-Length", 0)
request.end_headers()
self.unexpected = True
return
if req_resp.expected_body:
- content = request.rfile.read(int(request.headers['Content-Length']))
+ content = request.rfile.read(int(request.headers["Content-Length"]))
if content != req_resp.expected_body:
- sys.stderr.write('Did not get expected content: %s\n' % content)
+ sys.stderr.write("Did not get expected content: %s\n" % content)
request.send_response(400)
- request.send_header('Content-Length', 0)
+ request.send_header("Content-Length", 0)
request.end_headers()
self.unexpected = True
return
@@ -121,15 +164,15 @@ def _process_req_resp(self, req_resp, request):
request.send_header(k, req_resp.headers[k])
if req_resp.add_content_length_header:
if req_resp.body:
- request.send_header('Content-Length', len(req_resp.body))
- elif 'Content-Length' not in req_resp.headers:
- request.send_header('Content-Length', '0')
+ request.send_header("Content-Length", len(req_resp.body))
+ elif "Content-Length" not in req_resp.headers:
+ request.send_header("Content-Length", "0")
request.end_headers()
if req_resp.body:
try:
request.wfile.write(req_resp.body)
except:
- request.wfile.write(req_resp.body.encode('ascii'))
+ request.wfile.write(req_resp.body.encode("ascii"))
def process(self, method, request):
if self.req_count < len(self.req_resp):
@@ -139,38 +182,42 @@ def process(self, method, request):
self._process_req_resp(req_resp, request)
return
- request.send_error(500, 'Unexpected %s request for %s, req_count = %d' % (method, request.path, self.req_count))
+ request.send_error(
+ 500,
+ "Unexpected %s request for %s, req_count = %d"
+ % (method, request.path, self.req_count),
+ )
self.unexpected = True
def do_HEAD(self, request):
- self.process('HEAD', request)
+ self.process("HEAD", request)
def do_GET(self, request):
- self.process('GET', request)
+ self.process("GET", request)
def do_POST(self, request):
- self.process('POST', request)
+ self.process("POST", request)
def do_PUT(self, request):
- self.process('PUT', request)
+ self.process("PUT", request)
def do_DELETE(self, request):
- self.process('DELETE', request)
+ self.process("DELETE", request)
class DispatcherHttpHandler(BaseHTTPRequestHandler):
# protocol_version = 'HTTP/1.1'
- def log_request(self, code='-', size='-'):
+ def log_request(self, code="-", size="-"):
# pylint: disable=unused-argument
pass
def do_HEAD(self):
if do_log:
- f = open(tempfile.gettempdir() + '/log.txt', 'a')
- f.write('HEAD %s\n' % self.path)
+ f = open(tempfile.gettempdir() + "/log.txt", "a")
+ f.write("HEAD %s\n" % self.path)
f.close()
custom_handler.do_HEAD(self)
@@ -178,8 +225,8 @@ def do_HEAD(self):
def do_DELETE(self):
if do_log:
- f = open(tempfile.gettempdir() + '/log.txt', 'a')
- f.write('DELETE %s\n' % self.path)
+ f = open(tempfile.gettempdir() + "/log.txt", "a")
+ f.write("DELETE %s\n" % self.path)
f.close()
custom_handler.do_DELETE(self)
@@ -187,8 +234,8 @@ def do_DELETE(self):
def do_POST(self):
if do_log:
- f = open(tempfile.gettempdir() + '/log.txt', 'a')
- f.write('POST %s\n' % self.path)
+ f = open(tempfile.gettempdir() + "/log.txt", "a")
+ f.write("POST %s\n" % self.path)
f.close()
custom_handler.do_POST(self)
@@ -196,8 +243,8 @@ def do_POST(self):
def do_PUT(self):
if do_log:
- f = open(tempfile.gettempdir() + '/log.txt', 'a')
- f.write('PUT %s\n' % self.path)
+ f = open(tempfile.gettempdir() + "/log.txt", "a")
+ f.write("PUT %s\n" % self.path)
f.close()
custom_handler.do_PUT(self)
@@ -205,8 +252,8 @@ def do_PUT(self):
def do_GET(self):
if do_log:
- f = open(tempfile.gettempdir() + '/log.txt', 'a')
- f.write('GET %s\n' % self.path)
+ f = open(tempfile.gettempdir() + "/log.txt", "a")
+ f.write("GET %s\n" % self.path)
f.close()
custom_handler.do_GET(self)
@@ -216,7 +263,7 @@ class ThreadedHttpServer(Thread):
def __init__(self, handlerClass):
Thread.__init__(self)
- self.server = HTTPServer(('', 0), handlerClass)
+ self.server = HTTPServer(("", 0), handlerClass)
self.running = False
def getPort(self):
@@ -227,7 +274,7 @@ def run(self):
self.running = True
self.server.serve_forever()
except KeyboardInterrupt:
- print('^C received, shutting down server')
+ print("^C received, shutting down server")
self.stop()
def start_and_wait_ready(self):
diff --git a/tests/src/python/offlineditingtestbase.py b/tests/src/python/offlineditingtestbase.py
index 559e0d49c8f1..20782377fc09 100644
--- a/tests/src/python/offlineditingtestbase.py
+++ b/tests/src/python/offlineditingtestbase.py
@@ -18,10 +18,9 @@
(at your option) any later version.
"""
-
-__author__ = 'Alessandro Pasotti'
-__date__ = '2016-06-30'
-__copyright__ = 'Copyright 2016, The QGIS Project'
+__author__ = "Alessandro Pasotti"
+__date__ = "2016-06-30"
+__copyright__ = "Copyright 2016, The QGIS Project"
from time import sleep
@@ -38,16 +37,16 @@
# Tet features, fields: [id, name, geometry]
# "id" is used as a pk to retrieve features by attribute
TEST_FEATURES = [
- (1, 'name 1', QgsPointXY(9, 45)),
- (2, 'name 2', QgsPointXY(9.5, 45.5)),
- (3, 'name 3', QgsPointXY(9.5, 46)),
- (4, 'name 4', QgsPointXY(10, 46.5)),
+ (1, "name 1", QgsPointXY(9, 45)),
+ (2, "name 2", QgsPointXY(9.5, 45.5)),
+ (3, "name 3", QgsPointXY(9.5, 46)),
+ (4, "name 4", QgsPointXY(10, 46.5)),
]
# Additional features for insert test
TEST_FEATURES_INSERT = [
- (5, 'name 5', QgsPointXY(9.7, 45.7)),
- (6, 'name 6', QgsPointXY(10.6, 46.6)),
+ (5, "name 5", QgsPointXY(9.7, 45.7)),
+ (6, "name 6", QgsPointXY(10.6, 46.6)),
]
@@ -58,12 +57,12 @@ def _setUp(self):
"""Called by setUp: run before each test."""
# Setup: create some features for the test layer
features = []
- layer = self._getLayer('test_point')
+ layer = self._getLayer("test_point")
assert layer.startEditing()
for id, name, geom in TEST_FEATURES:
f = QgsFeature(layer.fields())
- f['id'] = id
- f['name'] = name
+ f["id"] = id
+ f["name"] = name
f.setGeometry(QgsGeometry.fromPointXY(geom))
features.append(f)
layer.addFeatures(features)
@@ -71,7 +70,7 @@ def _setUp(self):
# Add the online layer
self.registry = QgsProject.instance()
self.registry.removeAllMapLayers()
- assert self.registry.addMapLayer(self._getOnlineLayer('test_point')) is not None
+ assert self.registry.addMapLayer(self._getOnlineLayer("test_point")) is not None
def _tearDown(self):
"""Called by tearDown: run after each test."""
@@ -82,8 +81,11 @@ def _tearDown(self):
@classmethod
def _compareFeature(cls, layer, attributes):
"""Compare id, name and geometry"""
- f = cls._getFeatureByAttribute(layer, 'id', attributes[0])
- return f['name'] == attributes[1] and f.geometry().asPoint().toString() == attributes[2].toString()
+ f = cls._getFeatureByAttribute(layer, "id", attributes[0])
+ return (
+ f["name"] == attributes[1]
+ and f.geometry().asPoint().toString() == attributes[2].toString()
+ )
@classmethod
def _clearLayer(cls, layer):
@@ -114,13 +116,11 @@ def _getFeatureByAttribute(cls, layer, attr_name, attr_value):
"""
Find the feature and return it, raise exception if not found
"""
- request = QgsFeatureRequest(QgsExpression("{}={}".format(attr_name,
- attr_value)))
+ request = QgsFeatureRequest(QgsExpression(f"{attr_name}={attr_value}"))
try:
return next(layer.dataProvider().getFeatures(request))
except StopIteration:
- raise Exception("Wrong attributes in WFS layer %s" %
- layer.name())
+ raise Exception("Wrong attributes in WFS layer %s" % layer.name())
def _testInit(self):
"""
@@ -131,24 +131,40 @@ def _testInit(self):
online_layer = list(self.registry.mapLayers().values())[0]
self.assertTrue(online_layer.isSpatial())
# Check we have features
- self.assertEqual(len([f for f in online_layer.getFeatures()]), len(TEST_FEATURES))
- self.assertTrue(ol.convertToOfflineProject(self.temp_path, 'offlineDbFile.sqlite', [online_layer.id()]))
+ self.assertEqual(
+ len([f for f in online_layer.getFeatures()]), len(TEST_FEATURES)
+ )
+ self.assertTrue(
+ ol.convertToOfflineProject(
+ self.temp_path, "offlineDbFile.sqlite", [online_layer.id()]
+ )
+ )
offline_layer = list(self.registry.mapLayers().values())[0]
self.assertTrue(offline_layer.isSpatial())
self.assertTrue(offline_layer.isValid())
- self.assertGreater(offline_layer.name().find('(offline)'), -1)
- self.assertEqual(len([f for f in offline_layer.getFeatures()]), len(TEST_FEATURES))
+ self.assertGreater(offline_layer.name().find("(offline)"), -1)
+ self.assertEqual(
+ len([f for f in offline_layer.getFeatures()]), len(TEST_FEATURES)
+ )
return ol, offline_layer
def test_updateFeatures(self):
ol, offline_layer = self._testInit()
# Edit feature 2
- feat2 = self._getFeatureByAttribute(offline_layer, 'name', "'name 2'")
+ feat2 = self._getFeatureByAttribute(offline_layer, "name", "'name 2'")
self.assertTrue(offline_layer.startEditing())
- self.assertTrue(offline_layer.changeAttributeValue(feat2.id(), offline_layer.fields().lookupField('name'), 'name 2 edited'))
- self.assertTrue(offline_layer.changeGeometry(feat2.id(), QgsGeometry.fromPointXY(QgsPointXY(33.0, 60.0))))
+ self.assertTrue(
+ offline_layer.changeAttributeValue(
+ feat2.id(), offline_layer.fields().lookupField("name"), "name 2 edited"
+ )
+ )
+ self.assertTrue(
+ offline_layer.changeGeometry(
+ feat2.id(), QgsGeometry.fromPointXY(QgsPointXY(33.0, 60.0))
+ )
+ )
self.assertTrue(offline_layer.commitChanges())
- feat2 = self._getFeatureByAttribute(offline_layer, 'name', "'name 2 edited'")
+ feat2 = self._getFeatureByAttribute(offline_layer, "name", "'name 2 edited'")
self.assertTrue(ol.isOfflineProject())
# Sync
ol.synchronize()
@@ -156,14 +172,20 @@ def test_updateFeatures(self):
# Does anybody know why the sleep is needed? Is that a threaded WFS consequence?
online_layer = list(self.registry.mapLayers().values())[0]
self.assertTrue(online_layer.isValid())
- self.assertFalse(online_layer.name().find('(offline)') > -1)
- self.assertEqual(len([f for f in online_layer.getFeatures()]), len(TEST_FEATURES))
+ self.assertFalse(online_layer.name().find("(offline)") > -1)
+ self.assertEqual(
+ len([f for f in online_layer.getFeatures()]), len(TEST_FEATURES)
+ )
# Check that data have changed in the backend (raise exception if not found)
- feat2 = self._getFeatureByAttribute(self._getLayer('test_point'), 'name', "'name 2 edited'")
- feat2 = self._getFeatureByAttribute(online_layer, 'name', "'name 2 edited'")
- self.assertEqual(feat2.geometry().asPoint().toString(), QgsPointXY(33.0, 60.0).toString())
+ feat2 = self._getFeatureByAttribute(
+ self._getLayer("test_point"), "name", "'name 2 edited'"
+ )
+ feat2 = self._getFeatureByAttribute(online_layer, "name", "'name 2 edited'")
+ self.assertEqual(
+ feat2.geometry().asPoint().toString(), QgsPointXY(33.0, 60.0).toString()
+ )
# Check that all other features have not changed
- layer = self._getLayer('test_point')
+ layer = self._getLayer("test_point")
self.assertTrue(self._compareFeature(layer, TEST_FEATURES[1 - 1]))
self.assertTrue(self._compareFeature(layer, TEST_FEATURES[3 - 1]))
self.assertTrue(self._compareFeature(layer, TEST_FEATURES[4 - 1]))
@@ -173,27 +195,39 @@ def test_updateFeatures(self):
ol = QgsOfflineEditing()
offline_layer = list(self.registry.mapLayers().values())[0]
# Edit feature 2
- feat2 = self._getFeatureByAttribute(offline_layer, 'name', "'name 2 edited'")
+ feat2 = self._getFeatureByAttribute(offline_layer, "name", "'name 2 edited'")
self.assertTrue(offline_layer.startEditing())
- self.assertTrue(offline_layer.changeAttributeValue(feat2.id(), offline_layer.fields().lookupField('name'), 'name 2'))
- self.assertTrue(offline_layer.changeGeometry(feat2.id(), QgsGeometry.fromPointXY(TEST_FEATURES[1][2])))
+ self.assertTrue(
+ offline_layer.changeAttributeValue(
+ feat2.id(), offline_layer.fields().lookupField("name"), "name 2"
+ )
+ )
+ self.assertTrue(
+ offline_layer.changeGeometry(
+ feat2.id(), QgsGeometry.fromPointXY(TEST_FEATURES[1][2])
+ )
+ )
# Edit feat 4
- feat4 = self._getFeatureByAttribute(offline_layer, 'name', "'name 4'")
- self.assertTrue(offline_layer.changeAttributeValue(feat4.id(), offline_layer.fields().lookupField('name'), 'name 4 edited'))
+ feat4 = self._getFeatureByAttribute(offline_layer, "name", "'name 4'")
+ self.assertTrue(
+ offline_layer.changeAttributeValue(
+ feat4.id(), offline_layer.fields().lookupField("name"), "name 4 edited"
+ )
+ )
self.assertTrue(offline_layer.commitChanges())
# Sync
ol.synchronize()
# Does anybody knows why the sleep is needed? Is that a threaded WFS consequence?
sleep(1)
online_layer = list(self.registry.mapLayers().values())[0]
- layer = self._getLayer('test_point')
+ layer = self._getLayer("test_point")
# Check that data have changed in the backend (raise exception if not found)
- feat4 = self._getFeatureByAttribute(layer, 'name', "'name 4 edited'")
- feat4 = self._getFeatureByAttribute(online_layer, 'name', "'name 4 edited'")
- feat2 = self._getFeatureByAttribute(layer, 'name', "'name 2'")
- feat2 = self._getFeatureByAttribute(online_layer, 'name', "'name 2'")
+ feat4 = self._getFeatureByAttribute(layer, "name", "'name 4 edited'")
+ feat4 = self._getFeatureByAttribute(online_layer, "name", "'name 4 edited'")
+ feat2 = self._getFeatureByAttribute(layer, "name", "'name 2'")
+ feat2 = self._getFeatureByAttribute(online_layer, "name", "'name 2'")
# Check that all other features have not changed
- layer = self._getLayer('test_point')
+ layer = self._getLayer("test_point")
self.assertTrue(self._compareFeature(layer, TEST_FEATURES[1 - 1]))
self.assertTrue(self._compareFeature(layer, TEST_FEATURES[2 - 1]))
self.assertTrue(self._compareFeature(layer, TEST_FEATURES[3 - 1]))
@@ -204,11 +238,14 @@ def test_deleteOneFeature(self):
"""
ol, offline_layer = self._testInit()
# Delete feature 3
- feat3 = self._getFeatureByAttribute(offline_layer, 'name', "'name 3'")
+ feat3 = self._getFeatureByAttribute(offline_layer, "name", "'name 3'")
self.assertTrue(offline_layer.startEditing())
self.assertTrue(offline_layer.deleteFeatures([feat3.id()]))
self.assertTrue(offline_layer.commitChanges())
- self.assertRaises(Exception, lambda: self._getFeatureByAttribute(offline_layer, 'name', "'name 3'"))
+ self.assertRaises(
+ Exception,
+ lambda: self._getFeatureByAttribute(offline_layer, "name", "'name 3'"),
+ )
self.assertTrue(ol.isOfflineProject())
# Sync
ol.synchronize()
@@ -216,12 +253,17 @@ def test_deleteOneFeature(self):
sleep(1)
online_layer = list(self.registry.mapLayers().values())[0]
self.assertTrue(online_layer.isValid())
- self.assertFalse(online_layer.name().find('(offline)') > -1)
- self.assertEqual(len([f for f in online_layer.getFeatures()]), len(TEST_FEATURES) - 1)
+ self.assertFalse(online_layer.name().find("(offline)") > -1)
+ self.assertEqual(
+ len([f for f in online_layer.getFeatures()]), len(TEST_FEATURES) - 1
+ )
# Check that data have changed in the backend (raise exception if not found)
- self.assertRaises(Exception, lambda: self._getFeatureByAttribute(online_layer, 'name', "'name 3'"))
+ self.assertRaises(
+ Exception,
+ lambda: self._getFeatureByAttribute(online_layer, "name", "'name 3'"),
+ )
# Check that all other features have not changed
- layer = self._getLayer('test_point')
+ layer = self._getLayer("test_point")
self.assertTrue(self._compareFeature(layer, TEST_FEATURES[1 - 1]))
self.assertTrue(self._compareFeature(layer, TEST_FEATURES[2 - 1]))
self.assertTrue(self._compareFeature(layer, TEST_FEATURES[4 - 1]))
@@ -232,13 +274,19 @@ def test_deleteMultipleFeatures(self):
"""
ol, offline_layer = self._testInit()
# Delete feature 1 and 3
- feat1 = self._getFeatureByAttribute(offline_layer, 'name', "'name 1'")
- feat3 = self._getFeatureByAttribute(offline_layer, 'name', "'name 3'")
+ feat1 = self._getFeatureByAttribute(offline_layer, "name", "'name 1'")
+ feat3 = self._getFeatureByAttribute(offline_layer, "name", "'name 3'")
self.assertTrue(offline_layer.startEditing())
self.assertTrue(offline_layer.deleteFeatures([feat3.id(), feat1.id()]))
self.assertTrue(offline_layer.commitChanges())
- self.assertRaises(Exception, lambda: self._getFeatureByAttribute(offline_layer, 'name', "'name 3'"))
- self.assertRaises(Exception, lambda: self._getFeatureByAttribute(offline_layer, 'name', "'name 1'"))
+ self.assertRaises(
+ Exception,
+ lambda: self._getFeatureByAttribute(offline_layer, "name", "'name 3'"),
+ )
+ self.assertRaises(
+ Exception,
+ lambda: self._getFeatureByAttribute(offline_layer, "name", "'name 1'"),
+ )
self.assertTrue(ol.isOfflineProject())
# Sync
ol.synchronize()
@@ -246,13 +294,21 @@ def test_deleteMultipleFeatures(self):
sleep(1)
online_layer = list(self.registry.mapLayers().values())[0]
self.assertTrue(online_layer.isValid())
- self.assertFalse(online_layer.name().find('(offline)') > -1)
- self.assertEqual(len([f for f in online_layer.getFeatures()]), len(TEST_FEATURES) - 2)
+ self.assertFalse(online_layer.name().find("(offline)") > -1)
+ self.assertEqual(
+ len([f for f in online_layer.getFeatures()]), len(TEST_FEATURES) - 2
+ )
# Check that data have changed in the backend (raise exception if not found)
- self.assertRaises(Exception, lambda: self._getFeatureByAttribute(online_layer, 'name', "'name 3'"))
- self.assertRaises(Exception, lambda: self._getFeatureByAttribute(online_layer, 'name', "'name 1'"))
+ self.assertRaises(
+ Exception,
+ lambda: self._getFeatureByAttribute(online_layer, "name", "'name 3'"),
+ )
+ self.assertRaises(
+ Exception,
+ lambda: self._getFeatureByAttribute(online_layer, "name", "'name 1'"),
+ )
# Check that all other features have not changed
- layer = self._getLayer('test_point')
+ layer = self._getLayer("test_point")
self.assertTrue(self._compareFeature(layer, TEST_FEATURES[2 - 1]))
self.assertTrue(self._compareFeature(layer, TEST_FEATURES[4 - 1]))
@@ -266,14 +322,14 @@ def test_InsertFeatures(self):
features = []
for id, name, geom in TEST_FEATURES_INSERT:
f = QgsFeature(offline_layer.fields())
- f['id'] = id
- f['name'] = name
+ f["id"] = id
+ f["name"] = name
f.setGeometry(QgsGeometry.fromPointXY(geom))
features.append(f)
offline_layer.addFeatures(features)
self.assertTrue(offline_layer.commitChanges())
- self._getFeatureByAttribute(offline_layer, 'name', "'name 5'")
- self._getFeatureByAttribute(offline_layer, 'name', "'name 6'")
+ self._getFeatureByAttribute(offline_layer, "name", "'name 5'")
+ self._getFeatureByAttribute(offline_layer, "name", "'name 6'")
self.assertTrue(ol.isOfflineProject())
# Sync
ol.synchronize()
@@ -281,13 +337,15 @@ def test_InsertFeatures(self):
sleep(1)
online_layer = list(self.registry.mapLayers().values())[0]
self.assertTrue(online_layer.isValid())
- self.assertFalse(online_layer.name().find('(offline)') > -1)
- self.assertEqual(len([f for f in online_layer.getFeatures()]), len(TEST_FEATURES) + 2)
+ self.assertFalse(online_layer.name().find("(offline)") > -1)
+ self.assertEqual(
+ len([f for f in online_layer.getFeatures()]), len(TEST_FEATURES) + 2
+ )
# Check that data have changed in the backend (raise exception if not found)
- self._getFeatureByAttribute(online_layer, 'name', "'name 5'")
- self._getFeatureByAttribute(online_layer, 'name', "'name 6'")
+ self._getFeatureByAttribute(online_layer, "name", "'name 5'")
+ self._getFeatureByAttribute(online_layer, "name", "'name 6'")
# Check that all other features have not changed
- layer = self._getLayer('test_point')
+ layer = self._getLayer("test_point")
self.assertTrue(self._compareFeature(layer, TEST_FEATURES[1 - 1]))
self.assertTrue(self._compareFeature(layer, TEST_FEATURES[2 - 1]))
self.assertTrue(self._compareFeature(layer, TEST_FEATURES[3 - 1]))
diff --git a/tests/src/python/provider_python.py b/tests/src/python/provider_python.py
index 2b99e20e1a44..ad6ab99e0f2a 100644
--- a/tests/src/python/provider_python.py
+++ b/tests/src/python/provider_python.py
@@ -8,9 +8,10 @@
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
"""
-__author__ = 'Alessandro Pasotti'
-__date__ = '2018-03-18'
-__copyright__ = 'Copyright 2018, The QGIS Project'
+
+__author__ = "Alessandro Pasotti"
+__date__ = "2018-03-18"
+__copyright__ = "Copyright 2018, The QGIS Project"
from qgis.PyQt.QtCore import QVariant
from qgis.core import (
@@ -52,27 +53,50 @@ def __init__(self, source, request):
self._filter_rect = self.filterRectToSourceCrs(self._transform)
if not self._filter_rect.isNull():
self._select_rect_geom = QgsGeometry.fromRect(self._filter_rect)
- self._select_rect_engine = QgsGeometry.createGeometryEngine(self._select_rect_geom.constGet())
+ self._select_rect_engine = QgsGeometry.createGeometryEngine(
+ self._select_rect_geom.constGet()
+ )
self._select_rect_engine.prepareGeometry()
else:
self._select_rect_engine = None
self._select_rect_geom = None
- if self._request.spatialFilterType() == Qgis.SpatialFilterType.DistanceWithin and not self._request.referenceGeometry().isEmpty():
+ if (
+ self._request.spatialFilterType() == Qgis.SpatialFilterType.DistanceWithin
+ and not self._request.referenceGeometry().isEmpty()
+ ):
self._select_distance_within_geom = self._request.referenceGeometry()
- self._select_distance_within_engine = QgsGeometry.createGeometryEngine(self._select_distance_within_geom.constGet())
+ self._select_distance_within_engine = QgsGeometry.createGeometryEngine(
+ self._select_distance_within_geom.constGet()
+ )
self._select_distance_within_engine.prepareGeometry()
else:
self._select_distance_within_geom = None
self._select_distance_within_engine = None
self._feature_id_list = None
- if self._filter_rect is not None and self._source._provider._spatialindex is not None:
- self._feature_id_list = self._source._provider._spatialindex.intersects(self._filter_rect)
-
- if self._request.filterType() == QgsFeatureRequest.FilterType.FilterFid or self._request.filterType() == QgsFeatureRequest.FilterType.FilterFids:
- fids = [self._request.filterFid()] if self._request.filterType() == QgsFeatureRequest.FilterType.FilterFid else self._request.filterFids()
- self._feature_id_list = list(set(self._feature_id_list).intersection(set(fids))) if self._feature_id_list else fids
+ if (
+ self._filter_rect is not None
+ and self._source._provider._spatialindex is not None
+ ):
+ self._feature_id_list = self._source._provider._spatialindex.intersects(
+ self._filter_rect
+ )
+
+ if (
+ self._request.filterType() == QgsFeatureRequest.FilterType.FilterFid
+ or self._request.filterType() == QgsFeatureRequest.FilterType.FilterFids
+ ):
+ fids = (
+ [self._request.filterFid()]
+ if self._request.filterType() == QgsFeatureRequest.FilterType.FilterFid
+ else self._request.filterFids()
+ )
+ self._feature_id_list = (
+ list(set(self._feature_id_list).intersection(set(fids)))
+ if self._feature_id_list
+ else fids
+ )
def fetchFeature(self, f):
"""fetch next feature, return true on success"""
@@ -83,10 +107,15 @@ def fetchFeature(self, f):
try:
found = False
while not found:
- _f = self._source._features[list(self._source._features.keys())[self._index]]
+ _f = self._source._features[
+ list(self._source._features.keys())[self._index]
+ ]
self._index += 1
- if self._feature_id_list is not None and _f.id() not in self._feature_id_list:
+ if (
+ self._feature_id_list is not None
+ and _f.id() not in self._feature_id_list
+ ):
continue
if not self._filter_rect.isNull():
@@ -94,29 +123,53 @@ def fetchFeature(self, f):
continue
if self._request.flags() & QgsFeatureRequest.Flag.ExactIntersect:
# do exact check in case we're doing intersection
- if not self._select_rect_engine.intersects(_f.geometry().constGet()):
+ if not self._select_rect_engine.intersects(
+ _f.geometry().constGet()
+ ):
continue
else:
- if not _f.geometry().boundingBox().intersects(self._filter_rect):
+ if (
+ not _f.geometry()
+ .boundingBox()
+ .intersects(self._filter_rect)
+ ):
continue
self._source._expression_context.setFeature(_f)
- if self._request.filterType() == QgsFeatureRequest.FilterType.FilterExpression:
- if not self._request.filterExpression().evaluate(self._source._expression_context):
+ if (
+ self._request.filterType()
+ == QgsFeatureRequest.FilterType.FilterExpression
+ ):
+ if not self._request.filterExpression().evaluate(
+ self._source._expression_context
+ ):
continue
if self._source._subset_expression:
- if not self._source._subset_expression.evaluate(self._source._expression_context):
+ if not self._source._subset_expression.evaluate(
+ self._source._expression_context
+ ):
continue
- elif self._request.filterType() == QgsFeatureRequest.FilterType.FilterFids:
+ elif (
+ self._request.filterType()
+ == QgsFeatureRequest.FilterType.FilterFids
+ ):
if not _f.id() in self._request.filterFids():
continue
- elif self._request.filterType() == QgsFeatureRequest.FilterType.FilterFid:
+ elif (
+ self._request.filterType() == QgsFeatureRequest.FilterType.FilterFid
+ ):
if _f.id() != self._request.filterFid():
continue
f.setGeometry(_f.geometry())
self.geometryToDestinationCrs(f, self._transform)
- if self._select_distance_within_engine and self._select_distance_within_engine.distance(f.geometry().constGet()) > self._request.distanceWithin():
+ if (
+ self._select_distance_within_engine
+ and self._select_distance_within_engine.distance(
+ f.geometry().constGet()
+ )
+ > self._request.distanceWithin()
+ ):
continue
f.setFields(_f.fields())
@@ -165,7 +218,9 @@ def __init__(self, provider):
self._expression_context = QgsExpressionContext()
self._expression_context.appendScope(QgsExpressionContextUtils.globalScope())
- self._expression_context.appendScope(QgsExpressionContextUtils.projectScope(QgsProject.instance()))
+ self._expression_context.appendScope(
+ QgsExpressionContextUtils.projectScope(QgsProject.instance())
+ )
self._expression_context.setFields(self._provider.fields())
if self._provider.subsetString():
self._subset_expression = QgsExpression(self._provider.subsetString())
@@ -184,12 +239,12 @@ class PyProvider(QgsVectorDataProvider):
@classmethod
def providerKey(cls):
"""Returns the memory provider key"""
- return 'pythonprovider'
+ return "pythonprovider"
@classmethod
def description(cls):
"""Returns the memory provider description"""
- return 'Python Test Provider'
+ return "Python Test Provider"
@classmethod
def createProvider(cls, uri, providerOptions, flags=QgsDataProvider.ReadFlags()):
@@ -197,10 +252,15 @@ def createProvider(cls, uri, providerOptions, flags=QgsDataProvider.ReadFlags())
# Implementation of functions from QgsVectorDataProvider
- def __init__(self, uri='', providerOptions=QgsDataProvider.ProviderOptions(), flags=QgsDataProvider.ReadFlags()):
+ def __init__(
+ self,
+ uri="",
+ providerOptions=QgsDataProvider.ProviderOptions(),
+ flags=QgsDataProvider.ReadFlags(),
+ ):
super().__init__(uri)
# Use the memory layer to parse the uri
- mlayer = QgsVectorLayer(uri, 'ml', 'memory')
+ mlayer = QgsVectorLayer(uri, "ml", "memory")
self.setNativeTypes(mlayer.dataProvider().nativeTypes())
self._uri = uri
self._fields = mlayer.fields()
@@ -208,12 +268,12 @@ def __init__(self, uri='', providerOptions=QgsDataProvider.ProviderOptions(), fl
self._features = {}
self._extent = QgsRectangle()
self._extent.setNull()
- self._subset_string = ''
+ self._subset_string = ""
self._crs = mlayer.crs()
self._spatialindex = None
self._provider_options = providerOptions
self._flags = flags
- if 'index=yes' in self._uri:
+ if "index=yes" in self._uri:
self.createSpatialIndex()
def featureSource(self):
@@ -300,7 +360,17 @@ def deleteFeatures(self, ids):
def addAttributes(self, attrs):
try:
for new_f in attrs:
- if new_f.type() not in (QVariant.Int, QVariant.Double, QVariant.String, QVariant.Date, QVariant.Time, QVariant.DateTime, QVariant.LongLong, QVariant.StringList, QVariant.List):
+ if new_f.type() not in (
+ QVariant.Int,
+ QVariant.Double,
+ QVariant.String,
+ QVariant.Date,
+ QVariant.Time,
+ QVariant.DateTime,
+ QVariant.LongLong,
+ QVariant.StringList,
+ QVariant.List,
+ ):
continue
self._fields.append(new_f)
for f in self._features.values():
@@ -339,7 +409,7 @@ def deleteAttributes(self, attributes):
self._fields.remove(idx)
for f in self._features.values():
attr = f.attributes()
- del (attr[idx])
+ del attr[idx]
f.setAttributes(attr)
self.clearMinMaxCache()
return True
@@ -391,7 +461,18 @@ def createSpatialIndex(self):
return True
def capabilities(self):
- return QgsVectorDataProvider.Capability.AddFeatures | QgsVectorDataProvider.Capability.DeleteFeatures | QgsVectorDataProvider.Capability.CreateSpatialIndex | QgsVectorDataProvider.Capability.ChangeGeometries | QgsVectorDataProvider.Capability.ChangeAttributeValues | QgsVectorDataProvider.Capability.AddAttributes | QgsVectorDataProvider.Capability.DeleteAttributes | QgsVectorDataProvider.Capability.RenameAttributes | QgsVectorDataProvider.Capability.SelectAtId | QgsVectorDataProvider.Capability. CircularGeometries
+ return (
+ QgsVectorDataProvider.Capability.AddFeatures
+ | QgsVectorDataProvider.Capability.DeleteFeatures
+ | QgsVectorDataProvider.Capability.CreateSpatialIndex
+ | QgsVectorDataProvider.Capability.ChangeGeometries
+ | QgsVectorDataProvider.Capability.ChangeAttributeValues
+ | QgsVectorDataProvider.Capability.AddAttributes
+ | QgsVectorDataProvider.Capability.DeleteAttributes
+ | QgsVectorDataProvider.Capability.RenameAttributes
+ | QgsVectorDataProvider.Capability.SelectAtId
+ | QgsVectorDataProvider.Capability.CircularGeometries
+ )
# /* Implementation of functions from QgsDataProvider */
@@ -407,7 +488,9 @@ def extent(self):
if feat.hasGeometry():
self._extent.combineExtentWith(feat.geometry().boundingBox())
else:
- for f in self.getFeatures(QgsFeatureRequest().setSubsetOfAttributes([])):
+ for f in self.getFeatures(
+ QgsFeatureRequest().setSubsetOfAttributes([])
+ ):
if f.hasGeometry():
self._extent.combineExtentWith(f.geometry().boundingBox())
diff --git a/tests/src/python/providertestbase.py b/tests/src/python/providertestbase.py
index c2533b6c8009..073ada0f14f9 100644
--- a/tests/src/python/providertestbase.py
+++ b/tests/src/python/providertestbase.py
@@ -6,10 +6,9 @@
(at your option) any later version.
"""
-
-__author__ = 'Matthias Kuhn'
-__date__ = '2015-04-27'
-__copyright__ = 'Copyright 2015, The QGIS Project'
+__author__ = "Matthias Kuhn"
+__date__ = "2015-04-27"
+__copyright__ = "Copyright 2015, The QGIS Project"
from qgis.PyQt.QtCore import QDate, QDateTime, Qt, QTime, QVariant
from qgis.PyQt.QtTest import QSignalSpy
@@ -38,69 +37,87 @@
class ProviderTestCase(FeatureSourceTestCase):
- '''
- This is a collection of tests for vector data providers and kept generic.
- To make use of it, subclass it and set self.source to a provider you want to test.
- Make sure that your provider uses the default dataset by converting one of the provided datasets from the folder
- tests/testdata/provider to a dataset your provider is able to handle.
+ """
+ This is a collection of tests for vector data providers and kept generic.
+ To make use of it, subclass it and set self.source to a provider you want to test.
+ Make sure that your provider uses the default dataset by converting one of the provided datasets from the folder
+ tests/testdata/provider to a dataset your provider is able to handle.
- To test expression compilation, add the methods `enableCompiler()` and `disableCompiler()` to your subclass.
- If these methods are present, the tests will ensure that the result of server side and client side expression
- evaluation are equal.
+ To test expression compilation, add the methods `enableCompiler()` and `disableCompiler()` to your subclass.
+ If these methods are present, the tests will ensure that the result of server side and client side expression
+ evaluation are equal.
- To enable constraints checks for a data provider, please see the comment to the specific tests:
- - testChangeAttributesConstraintViolation
- - testUniqueNotNullConstraints
+ To enable constraints checks for a data provider, please see the comment to the specific tests:
+ - testChangeAttributesConstraintViolation
+ - testUniqueNotNullConstraints
- '''
+ """
def uncompiledFilters(self):
- """ Individual derived provider tests should override this to return a list of expressions which
- cannot be compiled """
+ """Individual derived provider tests should override this to return a list of expressions which
+ cannot be compiled"""
return set()
def enableCompiler(self):
"""By default there is no expression compiling available, needs to be overridden in subclass"""
- print('Provider does not support compiling')
+ print("Provider does not support compiling")
return False
def partiallyCompiledFilters(self):
- """ Individual derived provider tests should override this to return a list of expressions which
- should be partially compiled """
+ """Individual derived provider tests should override this to return a list of expressions which
+ should be partially compiled"""
return set()
@property
def pk_name(self):
"""Return the primary key name, override if different than the default 'pk'"""
- return 'pk'
+ return "pk"
def assert_query(self, source, expression, expected):
FeatureSourceTestCase.assert_query(self, source, expression, expected)
if self.compiled:
# Check compilation status
- it = source.getFeatures(QgsFeatureRequest().setFilterExpression(expression).setFlags(QgsFeatureRequest.Flag.IgnoreStaticNodesDuringExpressionCompilation))
+ it = source.getFeatures(
+ QgsFeatureRequest()
+ .setFilterExpression(expression)
+ .setFlags(
+ QgsFeatureRequest.Flag.IgnoreStaticNodesDuringExpressionCompilation
+ )
+ )
if expression in self.uncompiledFilters():
- self.assertEqual(it.compileStatus(), QgsAbstractFeatureIterator.CompileStatus.NoCompilation)
+ self.assertEqual(
+ it.compileStatus(),
+ QgsAbstractFeatureIterator.CompileStatus.NoCompilation,
+ )
elif expression in self.partiallyCompiledFilters():
- self.assertEqual(it.compileStatus(), QgsAbstractFeatureIterator.CompileStatus.PartiallyCompiled)
+ self.assertEqual(
+ it.compileStatus(),
+ QgsAbstractFeatureIterator.CompileStatus.PartiallyCompiled,
+ )
else:
- self.assertEqual(it.compileStatus(), QgsAbstractFeatureIterator.CompileStatus.Compiled, expression)
+ self.assertEqual(
+ it.compileStatus(),
+ QgsAbstractFeatureIterator.CompileStatus.Compiled,
+ expression,
+ )
def runGetFeatureTests(self, source):
FeatureSourceTestCase.runGetFeatureTests(self, source)
# combination of an uncompilable expression and limit
- feature = next(self.vl.getFeatures('pk=4'))
+ feature = next(self.vl.getFeatures("pk=4"))
context = QgsExpressionContext()
scope = QgsExpressionContextScope()
- scope.setVariable('parent', feature)
+ scope.setVariable("parent", feature)
context.appendScope(scope)
request = QgsFeatureRequest()
request.setExpressionContext(context)
- request.setFilterExpression('"pk" = attribute(@parent, \'pk\')').setFlags(QgsFeatureRequest.Flag.IgnoreStaticNodesDuringExpressionCompilation)
+ request.setFilterExpression("\"pk\" = attribute(@parent, 'pk')").setFlags(
+ QgsFeatureRequest.Flag.IgnoreStaticNodesDuringExpressionCompilation
+ )
request.setLimit(1)
values = [f[self.pk_name] for f in self.vl.getFeatures(request)]
@@ -110,42 +127,62 @@ def runPolyGetFeatureTests(self, provider):
assert len([f for f in provider.getFeatures()]) == 4
# geometry
- self.assert_query(provider, 'x($geometry) < -70', [1])
- self.assert_query(provider, 'y($geometry) > 79', [1, 2])
- self.assert_query(provider, 'xmin($geometry) < -70', [1, 3])
- self.assert_query(provider, 'ymin($geometry) < 76', [3])
- self.assert_query(provider, 'xmax($geometry) > -68', [2, 3])
- self.assert_query(provider, 'ymax($geometry) > 80', [1, 2])
- self.assert_query(provider, 'area($geometry) > 10', [1])
- self.assert_query(provider, 'perimeter($geometry) < 12', [2, 3])
- self.assert_query(provider,
- 'relate($geometry,geom_from_wkt( \'Polygon ((-68.2 82.1, -66.95 82.1, -66.95 79.05, -68.2 79.05, -68.2 82.1))\')) = \'FF2FF1212\'',
- [1, 3])
- self.assert_query(provider,
- 'relate($geometry,geom_from_wkt( \'Polygon ((-68.2 82.1, -66.95 82.1, -66.95 79.05, -68.2 79.05, -68.2 82.1))\'), \'****F****\')',
- [1, 3])
- self.assert_query(provider,
- 'crosses($geometry,geom_from_wkt( \'Linestring (-68.2 82.1, -66.95 82.1, -66.95 79.05)\'))',
- [2])
- self.assert_query(provider,
- 'overlaps($geometry,geom_from_wkt( \'Polygon ((-68.2 82.1, -66.95 82.1, -66.95 79.05, -68.2 79.05, -68.2 82.1))\'))',
- [2])
- self.assert_query(provider,
- 'within($geometry,geom_from_wkt( \'Polygon ((-75.1 76.1, -75.1 81.6, -68.8 81.6, -68.8 76.1, -75.1 76.1))\'))',
- [1])
- self.assert_query(provider,
- 'overlaps(translate($geometry,-1,-1),geom_from_wkt( \'Polygon ((-75.1 76.1, -75.1 81.6, -68.8 81.6, -68.8 76.1, -75.1 76.1))\'))',
- [1])
- self.assert_query(provider,
- 'overlaps(buffer($geometry,1),geom_from_wkt( \'Polygon ((-75.1 76.1, -75.1 81.6, -68.8 81.6, -68.8 76.1, -75.1 76.1))\'))',
- [1, 3])
- self.assert_query(provider,
- 'intersects(centroid($geometry),geom_from_wkt( \'Polygon ((-74.4 78.2, -74.4 79.1, -66.8 79.1, -66.8 78.2, -74.4 78.2))\'))',
- [2])
- self.assert_query(provider,
- 'intersects(point_on_surface($geometry),geom_from_wkt( \'Polygon ((-74.4 78.2, -74.4 79.1, -66.8 79.1, -66.8 78.2, -74.4 78.2))\'))',
- [1, 2])
- self.assert_query(provider, 'distance($geometry,geom_from_wkt( \'Point (-70 70)\')) > 7', [1, 2])
+ self.assert_query(provider, "x($geometry) < -70", [1])
+ self.assert_query(provider, "y($geometry) > 79", [1, 2])
+ self.assert_query(provider, "xmin($geometry) < -70", [1, 3])
+ self.assert_query(provider, "ymin($geometry) < 76", [3])
+ self.assert_query(provider, "xmax($geometry) > -68", [2, 3])
+ self.assert_query(provider, "ymax($geometry) > 80", [1, 2])
+ self.assert_query(provider, "area($geometry) > 10", [1])
+ self.assert_query(provider, "perimeter($geometry) < 12", [2, 3])
+ self.assert_query(
+ provider,
+ "relate($geometry,geom_from_wkt( 'Polygon ((-68.2 82.1, -66.95 82.1, -66.95 79.05, -68.2 79.05, -68.2 82.1))')) = 'FF2FF1212'",
+ [1, 3],
+ )
+ self.assert_query(
+ provider,
+ "relate($geometry,geom_from_wkt( 'Polygon ((-68.2 82.1, -66.95 82.1, -66.95 79.05, -68.2 79.05, -68.2 82.1))'), '****F****')",
+ [1, 3],
+ )
+ self.assert_query(
+ provider,
+ "crosses($geometry,geom_from_wkt( 'Linestring (-68.2 82.1, -66.95 82.1, -66.95 79.05)'))",
+ [2],
+ )
+ self.assert_query(
+ provider,
+ "overlaps($geometry,geom_from_wkt( 'Polygon ((-68.2 82.1, -66.95 82.1, -66.95 79.05, -68.2 79.05, -68.2 82.1))'))",
+ [2],
+ )
+ self.assert_query(
+ provider,
+ "within($geometry,geom_from_wkt( 'Polygon ((-75.1 76.1, -75.1 81.6, -68.8 81.6, -68.8 76.1, -75.1 76.1))'))",
+ [1],
+ )
+ self.assert_query(
+ provider,
+ "overlaps(translate($geometry,-1,-1),geom_from_wkt( 'Polygon ((-75.1 76.1, -75.1 81.6, -68.8 81.6, -68.8 76.1, -75.1 76.1))'))",
+ [1],
+ )
+ self.assert_query(
+ provider,
+ "overlaps(buffer($geometry,1),geom_from_wkt( 'Polygon ((-75.1 76.1, -75.1 81.6, -68.8 81.6, -68.8 76.1, -75.1 76.1))'))",
+ [1, 3],
+ )
+ self.assert_query(
+ provider,
+ "intersects(centroid($geometry),geom_from_wkt( 'Polygon ((-74.4 78.2, -74.4 79.1, -66.8 79.1, -66.8 78.2, -74.4 78.2))'))",
+ [2],
+ )
+ self.assert_query(
+ provider,
+ "intersects(point_on_surface($geometry),geom_from_wkt( 'Polygon ((-74.4 78.2, -74.4 79.1, -66.8 79.1, -66.8 78.2, -74.4 78.2))'))",
+ [1, 2],
+ )
+ self.assert_query(
+ provider, "distance($geometry,geom_from_wkt( 'Point (-70 70)')) > 7", [1, 2]
+ )
def testGetFeaturesUncompiled(self):
self.compiled = False
@@ -154,19 +191,19 @@ def testGetFeaturesUncompiled(self):
except AttributeError:
pass
self.runGetFeatureTests(self.source)
- if hasattr(self, 'poly_provider'):
+ if hasattr(self, "poly_provider"):
self.runPolyGetFeatureTests(self.poly_provider)
def testGetFeaturesExp(self):
if self.enableCompiler():
self.compiled = True
self.runGetFeatureTests(self.source)
- if hasattr(self, 'poly_provider'):
+ if hasattr(self, "poly_provider"):
self.runPolyGetFeatureTests(self.poly_provider)
def testSubsetString(self):
if not self.source.supportsSubsetString():
- print('Provider does not support subset strings')
+ print("Provider does not support subset strings")
return
changed_spy = QSignalSpy(self.source.dataChanged)
@@ -180,12 +217,15 @@ def testSubsetString(self):
self.assertEqual(len(changed_spy), 1)
result = {f[self.pk_name] for f in self.source.getFeatures()}
- all_valid = (all(f.isValid() for f in self.source.getFeatures()))
+ all_valid = all(f.isValid() for f in self.source.getFeatures())
self.source.setSubsetString(None)
expected = {2, 3, 4}
- assert set(expected) == result, 'Expected {} and got {} when testing subset string {}'.format(set(expected),
- result, subset)
+ assert (
+ set(expected) == result
+ ), "Expected {} and got {} when testing subset string {}".format(
+ set(expected), result, subset
+ )
self.assertTrue(all_valid)
# Subset string AND filter rect
@@ -193,31 +233,43 @@ def testSubsetString(self):
extent = QgsRectangle(-70, 70, -60, 75)
request = QgsFeatureRequest().setFilterRect(extent)
result = {f[self.pk_name] for f in self.source.getFeatures(request)}
- all_valid = (all(f.isValid() for f in self.source.getFeatures(request)))
+ all_valid = all(f.isValid() for f in self.source.getFeatures(request))
self.source.setSubsetString(None)
expected = {2}
- assert set(expected) == result, 'Expected {} and got {} when testing subset string {}'.format(set(expected),
- result, subset)
+ assert (
+ set(expected) == result
+ ), "Expected {} and got {} when testing subset string {}".format(
+ set(expected), result, subset
+ )
self.assertTrue(all_valid)
# Subset string AND filter rect, version 2
self.source.setSubsetString(subset)
extent = QgsRectangle(-71, 65, -60, 80)
- result = {f[self.pk_name] for f in self.source.getFeatures(QgsFeatureRequest().setFilterRect(extent))}
+ result = {
+ f[self.pk_name]
+ for f in self.source.getFeatures(QgsFeatureRequest().setFilterRect(extent))
+ }
self.source.setSubsetString(None)
expected = {2, 4}
- assert set(expected) == result, 'Expected {} and got {} when testing subset string {}'.format(set(expected),
- result, subset)
+ assert (
+ set(expected) == result
+ ), "Expected {} and got {} when testing subset string {}".format(
+ set(expected), result, subset
+ )
# Subset string AND expression
self.source.setSubsetString(subset)
request = QgsFeatureRequest().setFilterExpression('length("name")=5')
result = {f[self.pk_name] for f in self.source.getFeatures(request)}
- all_valid = (all(f.isValid() for f in self.source.getFeatures(request)))
+ all_valid = all(f.isValid() for f in self.source.getFeatures(request))
self.source.setSubsetString(None)
expected = {2, 4}
- assert set(expected) == result, 'Expected {} and got {} when testing subset string {}'.format(set(expected),
- result, subset)
+ assert (
+ set(expected) == result
+ ), "Expected {} and got {} when testing subset string {}".format(
+ set(expected), result, subset
+ )
self.assertTrue(all_valid)
if self.providerCompatibleOfSubsetStringWithStableFID():
@@ -226,31 +278,37 @@ def testSubsetString(self):
self.source.setSubsetString(subset)
request = QgsFeatureRequest().setFilterFid(ids[4])
result = {f.id() for f in self.source.getFeatures(request)}
- all_valid = (all(f.isValid() for f in self.source.getFeatures(request)))
+ all_valid = all(f.isValid() for f in self.source.getFeatures(request))
self.source.setSubsetString(None)
expected = {ids[4]}
- assert set(expected) == result, 'Expected {} and got {} when testing subset string {}'.format(set(expected),
- result, subset)
+ assert (
+ set(expected) == result
+ ), "Expected {} and got {} when testing subset string {}".format(
+ set(expected), result, subset
+ )
self.assertTrue(all_valid)
# Subset string AND filter fids
self.source.setSubsetString(subset)
request = QgsFeatureRequest().setFilterFids([ids[2], ids[4]])
result = {f.id() for f in self.source.getFeatures(request)}
- all_valid = (all(f.isValid() for f in self.source.getFeatures(request)))
+ all_valid = all(f.isValid() for f in self.source.getFeatures(request))
self.source.setSubsetString(None)
expected = {ids[2], ids[4]}
- assert set(expected) == result, 'Expected {} and got {} when testing subset string {}'.format(set(expected),
- result, subset)
+ assert (
+ set(expected) == result
+ ), "Expected {} and got {} when testing subset string {}".format(
+ set(expected), result, subset
+ )
self.assertTrue(all_valid)
def providerCompatibleOfSubsetStringWithStableFID(self):
- """ Return whether the provider is expected to have stable FID when changing subsetString.
- The WFS provider might not always be able to have that guarantee. """
+ """Return whether the provider is expected to have stable FID when changing subsetString.
+ The WFS provider might not always be able to have that guarantee."""
return True
def referenceExtent(self):
- """ Extent of the reference dataset """
+ """Extent of the reference dataset"""
return QgsRectangle(-71.123, 66.33, -65.32, 78.3)
def getSubsetString(self):
@@ -262,16 +320,16 @@ def getSubsetString2(self):
return '"cnt" > 100 and "cnt" < 400'
def referenceSubsetString3Extent(self):
- """ Extent of the data selected by subset string 3 """
+ """Extent of the data selected by subset string 3"""
return QgsRectangle(-68.2, 70.8, -68.2, 70.8)
def getSubsetString3(self):
"""Individual providers may need to override this depending on their subset string formats"""
- return '"name"=\'Apple\''
+ return "\"name\"='Apple'"
def getSubsetStringNoMatching(self):
"""Individual providers may need to override this depending on their subset string formats"""
- return '"name"=\'AppleBearOrangePear\''
+ return "\"name\"='AppleBearOrangePear'"
def testGetFeaturesThreadSafety(self):
# no request
@@ -280,7 +338,9 @@ def testGetFeaturesThreadSafety(self):
# filter rect request
extent = QgsRectangle(-73, 70, -63, 80)
request = QgsFeatureRequest().setFilterRect(extent)
- self.assertTrue(QgsTestUtils.testProviderIteratorThreadSafety(self.source, request))
+ self.assertTrue(
+ QgsTestUtils.testProviderIteratorThreadSafety(self.source, request)
+ )
def testOrderBy(self):
try:
@@ -297,7 +357,11 @@ def runOrderByTests(self):
FeatureSourceTestCase.runOrderByTests(self)
# Combination with subset of attributes
- request = QgsFeatureRequest().addOrderBy('num_char', False).setSubsetOfAttributes([self.pk_name], self.vl.fields())
+ request = (
+ QgsFeatureRequest()
+ .addOrderBy("num_char", False)
+ .setSubsetOfAttributes([self.pk_name], self.vl.fields())
+ )
values = [f[self.pk_name] for f in self.vl.getFeatures(request)]
self.assertEqual(values, [5, 4, 3, 2, 1])
@@ -307,7 +371,7 @@ def testOpenIteratorAfterLayerRemoval(self):
information should be captured in the iterator's source and there MUST be no
links between the iterators and the layer's data provider
"""
- if not getattr(self, 'getEditableLayer', None):
+ if not getattr(self, "getEditableLayer", None):
return
l = self.getEditableLayer()
@@ -337,7 +401,7 @@ def testCloneLayer(self):
self.assertEqual(set(pks), {1, 2, 3, 4, 5})
def testGetFeaturesPolyFilterRectTests(self):
- """ Test fetching features from a polygon layer with filter rect"""
+ """Test fetching features from a polygon layer with filter rect"""
try:
if not self.poly_provider:
return
@@ -347,85 +411,146 @@ def testGetFeaturesPolyFilterRectTests(self):
extent = QgsRectangle(-73, 70, -63, 80)
request = QgsFeatureRequest().setFilterRect(extent)
features = [f[self.pk_name] for f in self.poly_provider.getFeatures(request)]
- all_valid = (all(f.isValid() for f in self.source.getFeatures(request)))
+ all_valid = all(f.isValid() for f in self.source.getFeatures(request))
# Some providers may return the exact intersection matches (2, 3) even without the ExactIntersect flag, so we accept that too
- assert set(features) == {2, 3} or set(features) == {1, 2, 3}, f'Got {features} instead'
+ assert set(features) == {2, 3} or set(features) == {
+ 1,
+ 2,
+ 3,
+ }, f"Got {features} instead"
self.assertTrue(all_valid)
# Test with exact intersection
- request = QgsFeatureRequest().setFilterRect(extent).setFlags(QgsFeatureRequest.Flag.ExactIntersect)
+ request = (
+ QgsFeatureRequest()
+ .setFilterRect(extent)
+ .setFlags(QgsFeatureRequest.Flag.ExactIntersect)
+ )
features = [f[self.pk_name] for f in self.poly_provider.getFeatures(request)]
- all_valid = (all(f.isValid() for f in self.source.getFeatures(request)))
- assert set(features) == {2, 3}, f'Got {features} instead'
+ all_valid = all(f.isValid() for f in self.source.getFeatures(request))
+ assert set(features) == {2, 3}, f"Got {features} instead"
self.assertTrue(all_valid)
# test with an empty rectangle
extent = QgsRectangle()
- features = [f[self.pk_name] for f in self.source.getFeatures(QgsFeatureRequest().setFilterRect(extent))]
- assert set(features) == {1, 2, 3, 4, 5}, f'Got {features} instead'
+ features = [
+ f[self.pk_name]
+ for f in self.source.getFeatures(QgsFeatureRequest().setFilterRect(extent))
+ ]
+ assert set(features) == {1, 2, 3, 4, 5}, f"Got {features} instead"
def testMinValue(self):
self.assertFalse(self.source.minimumValue(-1))
self.assertFalse(self.source.minimumValue(1000))
- self.assertEqual(self.source.minimumValue(self.source.fields().lookupField('cnt')), -200)
- self.assertEqual(self.source.minimumValue(self.source.fields().lookupField('name')), 'Apple')
+ self.assertEqual(
+ self.source.minimumValue(self.source.fields().lookupField("cnt")), -200
+ )
+ self.assertEqual(
+ self.source.minimumValue(self.source.fields().lookupField("name")), "Apple"
+ )
if self.treat_datetime_as_string():
- self.assertEqual(self.source.minimumValue(self.source.fields().lookupField('dt')), '2020-05-03 12:13:14')
+ self.assertEqual(
+ self.source.minimumValue(self.source.fields().lookupField("dt")),
+ "2020-05-03 12:13:14",
+ )
else:
- self.assertEqual(self.source.minimumValue(self.source.fields().lookupField('dt')),
- QDateTime(QDate(2020, 5, 3), QTime(12, 13, 14)))
+ self.assertEqual(
+ self.source.minimumValue(self.source.fields().lookupField("dt")),
+ QDateTime(QDate(2020, 5, 3), QTime(12, 13, 14)),
+ )
if self.treat_date_as_string():
- self.assertEqual(self.source.minimumValue(self.source.fields().lookupField('date')), '2020-05-02')
+ self.assertEqual(
+ self.source.minimumValue(self.source.fields().lookupField("date")),
+ "2020-05-02",
+ )
elif not self.treat_date_as_datetime():
- self.assertEqual(self.source.minimumValue(self.source.fields().lookupField('date')), QDate(2020, 5, 2))
+ self.assertEqual(
+ self.source.minimumValue(self.source.fields().lookupField("date")),
+ QDate(2020, 5, 2),
+ )
else:
- self.assertEqual(self.source.minimumValue(self.source.fields().lookupField('date')),
- QDateTime(2020, 5, 2, 0, 0, 0))
+ self.assertEqual(
+ self.source.minimumValue(self.source.fields().lookupField("date")),
+ QDateTime(2020, 5, 2, 0, 0, 0),
+ )
if not self.treat_time_as_string():
- self.assertEqual(self.source.minimumValue(self.source.fields().lookupField('time')), QTime(12, 13, 1))
+ self.assertEqual(
+ self.source.minimumValue(self.source.fields().lookupField("time")),
+ QTime(12, 13, 1),
+ )
else:
- self.assertEqual(self.source.minimumValue(self.source.fields().lookupField('time')), '12:13:01')
+ self.assertEqual(
+ self.source.minimumValue(self.source.fields().lookupField("time")),
+ "12:13:01",
+ )
if self.source.supportsSubsetString():
subset = self.getSubsetString()
self.source.setSubsetString(subset)
- min_value = self.source.minimumValue(self.source.fields().lookupField('cnt'))
+ min_value = self.source.minimumValue(
+ self.source.fields().lookupField("cnt")
+ )
self.source.setSubsetString(None)
self.assertEqual(min_value, 200)
def testMaxValue(self):
self.assertFalse(self.source.maximumValue(-1))
self.assertFalse(self.source.maximumValue(1000))
- self.assertEqual(self.source.maximumValue(self.source.fields().lookupField('cnt')), 400)
- self.assertEqual(self.source.maximumValue(self.source.fields().lookupField('name')), 'Pear')
+ self.assertEqual(
+ self.source.maximumValue(self.source.fields().lookupField("cnt")), 400
+ )
+ self.assertEqual(
+ self.source.maximumValue(self.source.fields().lookupField("name")), "Pear"
+ )
if not self.treat_datetime_as_string():
- self.assertEqual(self.source.maximumValue(self.source.fields().lookupField('dt')),
- QDateTime(QDate(2021, 5, 4), QTime(13, 13, 14)))
+ self.assertEqual(
+ self.source.maximumValue(self.source.fields().lookupField("dt")),
+ QDateTime(QDate(2021, 5, 4), QTime(13, 13, 14)),
+ )
else:
- self.assertEqual(self.source.maximumValue(self.source.fields().lookupField('dt')), '2021-05-04 13:13:14')
+ self.assertEqual(
+ self.source.maximumValue(self.source.fields().lookupField("dt")),
+ "2021-05-04 13:13:14",
+ )
if self.treat_date_as_string():
- self.assertEqual(self.source.maximumValue(self.source.fields().lookupField('date')), '2021-05-04')
+ self.assertEqual(
+ self.source.maximumValue(self.source.fields().lookupField("date")),
+ "2021-05-04",
+ )
elif not self.treat_date_as_datetime():
- self.assertEqual(self.source.maximumValue(self.source.fields().lookupField('date')), QDate(2021, 5, 4))
+ self.assertEqual(
+ self.source.maximumValue(self.source.fields().lookupField("date")),
+ QDate(2021, 5, 4),
+ )
else:
- self.assertEqual(self.source.maximumValue(self.source.fields().lookupField('date')),
- QDateTime(2021, 5, 4, 0, 0, 0))
+ self.assertEqual(
+ self.source.maximumValue(self.source.fields().lookupField("date")),
+ QDateTime(2021, 5, 4, 0, 0, 0),
+ )
if not self.treat_time_as_string():
- self.assertEqual(self.source.maximumValue(self.source.fields().lookupField('time')), QTime(13, 13, 14))
+ self.assertEqual(
+ self.source.maximumValue(self.source.fields().lookupField("time")),
+ QTime(13, 13, 14),
+ )
else:
- self.assertEqual(self.source.maximumValue(self.source.fields().lookupField('time')), '13:13:14')
+ self.assertEqual(
+ self.source.maximumValue(self.source.fields().lookupField("time")),
+ "13:13:14",
+ )
if self.source.supportsSubsetString():
subset = self.getSubsetString2()
self.source.setSubsetString(subset)
- max_value = self.source.maximumValue(self.source.fields().lookupField('cnt'))
+ max_value = self.source.maximumValue(
+ self.source.fields().lookupField("cnt")
+ )
self.source.setSubsetString(None)
self.assertEqual(max_value, 300)
@@ -447,10 +572,18 @@ def testExtentSubsetString(self):
subset_extent = self.referenceSubsetString3Extent()
self.source.setSubsetString(None)
self.assertEqual(count, 1)
- self.assertAlmostEqual(provider_extent.xMinimum(), subset_extent.xMinimum(), 3)
- self.assertAlmostEqual(provider_extent.xMaximum(), subset_extent.xMaximum(), 3)
- self.assertAlmostEqual(provider_extent.yMinimum(), subset_extent.yMinimum(), 3)
- self.assertAlmostEqual(provider_extent.yMaximum(), subset_extent.yMaximum(), 3)
+ self.assertAlmostEqual(
+ provider_extent.xMinimum(), subset_extent.xMinimum(), 3
+ )
+ self.assertAlmostEqual(
+ provider_extent.xMaximum(), subset_extent.xMaximum(), 3
+ )
+ self.assertAlmostEqual(
+ provider_extent.yMinimum(), subset_extent.yMinimum(), 3
+ )
+ self.assertAlmostEqual(
+ provider_extent.yMaximum(), subset_extent.yMaximum(), 3
+ )
# with no points
subset = self.getSubsetStringNoMatching()
@@ -466,74 +599,147 @@ def testUnique(self):
self.assertEqual(self.source.uniqueValues(-1), set())
self.assertEqual(self.source.uniqueValues(1000), set())
- self.assertEqual(set(self.source.uniqueValues(self.source.fields().lookupField('cnt'))),
- {-200, 100, 200, 300, 400})
- assert {'Apple', 'Honey', 'Orange', 'Pear', NULL} == set(
- self.source.uniqueValues(self.source.fields().lookupField('name'))), 'Got {}'.format(
- set(self.source.uniqueValues(self.source.fields().lookupField('name'))))
+ self.assertEqual(
+ set(self.source.uniqueValues(self.source.fields().lookupField("cnt"))),
+ {-200, 100, 200, 300, 400},
+ )
+ assert {"Apple", "Honey", "Orange", "Pear", NULL} == set(
+ self.source.uniqueValues(self.source.fields().lookupField("name"))
+ ), "Got {}".format(
+ set(self.source.uniqueValues(self.source.fields().lookupField("name")))
+ )
if self.treat_datetime_as_string():
- self.assertEqual(set(self.source.uniqueValues(self.source.fields().lookupField('dt'))),
- {'2021-05-04 13:13:14', '2020-05-04 12:14:14', '2020-05-04 12:13:14',
- '2020-05-03 12:13:14', NULL})
+ self.assertEqual(
+ set(self.source.uniqueValues(self.source.fields().lookupField("dt"))),
+ {
+ "2021-05-04 13:13:14",
+ "2020-05-04 12:14:14",
+ "2020-05-04 12:13:14",
+ "2020-05-03 12:13:14",
+ NULL,
+ },
+ )
else:
if self.treat_datetime_tz_as_utc():
- self.assertEqual(set(self.source.uniqueValues(self.source.fields().lookupField('dt'))),
- {QDateTime(QDate(2021, 5, 4), QTime(13, 13, 14, 0), Qt.TimeSpec.UTC), QDateTime(QDate(2020, 5, 4), QTime(12, 14, 14, 0), Qt.TimeSpec.UTC),
- QDateTime(QDate(2020, 5, 4), QTime(12, 13, 14, 0), Qt.TimeSpec.UTC), QDateTime(QDate(2020, 5, 3), QTime(12, 13, 14, 0), Qt.TimeSpec.UTC), NULL})
+ self.assertEqual(
+ set(
+ self.source.uniqueValues(self.source.fields().lookupField("dt"))
+ ),
+ {
+ QDateTime(
+ QDate(2021, 5, 4), QTime(13, 13, 14, 0), Qt.TimeSpec.UTC
+ ),
+ QDateTime(
+ QDate(2020, 5, 4), QTime(12, 14, 14, 0), Qt.TimeSpec.UTC
+ ),
+ QDateTime(
+ QDate(2020, 5, 4), QTime(12, 13, 14, 0), Qt.TimeSpec.UTC
+ ),
+ QDateTime(
+ QDate(2020, 5, 3), QTime(12, 13, 14, 0), Qt.TimeSpec.UTC
+ ),
+ NULL,
+ },
+ )
else:
- self.assertEqual(set(self.source.uniqueValues(self.source.fields().lookupField('dt'))),
- {QDateTime(2021, 5, 4, 13, 13, 14), QDateTime(2020, 5, 4, 12, 14, 14),
- QDateTime(2020, 5, 4, 12, 13, 14), QDateTime(2020, 5, 3, 12, 13, 14), NULL})
+ self.assertEqual(
+ set(
+ self.source.uniqueValues(self.source.fields().lookupField("dt"))
+ ),
+ {
+ QDateTime(2021, 5, 4, 13, 13, 14),
+ QDateTime(2020, 5, 4, 12, 14, 14),
+ QDateTime(2020, 5, 4, 12, 13, 14),
+ QDateTime(2020, 5, 3, 12, 13, 14),
+ NULL,
+ },
+ )
if self.treat_date_as_string():
- self.assertEqual(set(self.source.uniqueValues(self.source.fields().lookupField('date'))),
- {'2020-05-03', '2020-05-04', '2021-05-04', '2020-05-02', NULL})
+ self.assertEqual(
+ set(self.source.uniqueValues(self.source.fields().lookupField("date"))),
+ {"2020-05-03", "2020-05-04", "2021-05-04", "2020-05-02", NULL},
+ )
elif self.treat_date_as_datetime():
- self.assertEqual(set(self.source.uniqueValues(self.source.fields().lookupField('date'))),
- {QDateTime(2020, 5, 3, 0, 0, 0), QDateTime(2020, 5, 4, 0, 0, 0),
- QDateTime(2021, 5, 4, 0, 0, 0), QDateTime(2020, 5, 2, 0, 0, 0), NULL})
+ self.assertEqual(
+ set(self.source.uniqueValues(self.source.fields().lookupField("date"))),
+ {
+ QDateTime(2020, 5, 3, 0, 0, 0),
+ QDateTime(2020, 5, 4, 0, 0, 0),
+ QDateTime(2021, 5, 4, 0, 0, 0),
+ QDateTime(2020, 5, 2, 0, 0, 0),
+ NULL,
+ },
+ )
else:
- self.assertEqual(set(self.source.uniqueValues(self.source.fields().lookupField('date'))),
- {QDate(2020, 5, 3), QDate(2020, 5, 4), QDate(2021, 5, 4), QDate(2020, 5, 2), NULL})
+ self.assertEqual(
+ set(self.source.uniqueValues(self.source.fields().lookupField("date"))),
+ {
+ QDate(2020, 5, 3),
+ QDate(2020, 5, 4),
+ QDate(2021, 5, 4),
+ QDate(2020, 5, 2),
+ NULL,
+ },
+ )
if self.treat_time_as_string():
- self.assertEqual(set(self.source.uniqueValues(self.source.fields().lookupField('time'))),
- {'12:14:14', '13:13:14', '12:13:14', '12:13:01', NULL})
+ self.assertEqual(
+ set(self.source.uniqueValues(self.source.fields().lookupField("time"))),
+ {"12:14:14", "13:13:14", "12:13:14", "12:13:01", NULL},
+ )
else:
- self.assertEqual(set(self.source.uniqueValues(self.source.fields().lookupField('time'))),
- {QTime(12, 14, 14), QTime(13, 13, 14), QTime(12, 13, 14), QTime(12, 13, 1), NULL})
+ self.assertEqual(
+ set(self.source.uniqueValues(self.source.fields().lookupField("time"))),
+ {
+ QTime(12, 14, 14),
+ QTime(13, 13, 14),
+ QTime(12, 13, 14),
+ QTime(12, 13, 1),
+ NULL,
+ },
+ )
if self.source.supportsSubsetString():
subset = self.getSubsetString2()
self.source.setSubsetString(subset)
- values = self.source.uniqueValues(self.source.fields().lookupField('cnt'))
+ values = self.source.uniqueValues(self.source.fields().lookupField("cnt"))
self.source.setSubsetString(None)
self.assertEqual(set(values), {200, 300})
def testUniqueStringsMatching(self):
- self.assertEqual(self.source.uniqueStringsMatching(-1, 'a'), [])
- self.assertEqual(self.source.uniqueStringsMatching(100001, 'a'), [])
-
- field_index = self.source.fields().lookupField('name')
- self.assertEqual(set(self.source.uniqueStringsMatching(field_index, 'a')), {'Pear', 'Orange', 'Apple'})
+ self.assertEqual(self.source.uniqueStringsMatching(-1, "a"), [])
+ self.assertEqual(self.source.uniqueStringsMatching(100001, "a"), [])
+
+ field_index = self.source.fields().lookupField("name")
+ self.assertEqual(
+ set(self.source.uniqueStringsMatching(field_index, "a")),
+ {"Pear", "Orange", "Apple"},
+ )
# test case insensitive
- self.assertEqual(set(self.source.uniqueStringsMatching(field_index, 'A')), {'Pear', 'Orange', 'Apple'})
+ self.assertEqual(
+ set(self.source.uniqueStringsMatching(field_index, "A")),
+ {"Pear", "Orange", "Apple"},
+ )
# test string ending in substring
- self.assertEqual(set(self.source.uniqueStringsMatching(field_index, 'ney')), {'Honey'})
+ self.assertEqual(
+ set(self.source.uniqueStringsMatching(field_index, "ney")), {"Honey"}
+ )
# test limit
- result = set(self.source.uniqueStringsMatching(field_index, 'a', 2))
+ result = set(self.source.uniqueStringsMatching(field_index, "a", 2))
self.assertEqual(len(result), 2)
- self.assertTrue(result.issubset({'Pear', 'Orange', 'Apple'}))
+ self.assertTrue(result.issubset({"Pear", "Orange", "Apple"}))
- assert {'Apple', 'Honey', 'Orange', 'Pear', NULL} == set(
- self.source.uniqueValues(field_index)), f'Got {set(self.source.uniqueValues(field_index))}'
+ assert {"Apple", "Honey", "Orange", "Pear", NULL} == set(
+ self.source.uniqueValues(field_index)
+ ), f"Got {set(self.source.uniqueValues(field_index))}"
if self.source.supportsSubsetString():
subset = self.getSubsetString2()
self.source.setSubsetString(subset)
- values = self.source.uniqueStringsMatching(field_index, 'a')
+ values = self.source.uniqueStringsMatching(field_index, "a")
self.source.setSubsetString(None)
- self.assertEqual(set(values), {'Pear', 'Apple'})
+ self.assertEqual(set(values), {"Pear", "Apple"})
def testFeatureCount(self):
self.assertEqual(self.source.featureCount(), 5)
@@ -565,7 +771,10 @@ def testFeatureCount(self):
def testEmpty(self):
self.assertFalse(self.source.empty())
- self.assertEqual(self.source.hasFeatures(), QgsFeatureSource.FeatureAvailability.FeaturesAvailable)
+ self.assertEqual(
+ self.source.hasFeatures(),
+ QgsFeatureSource.FeatureAvailability.FeaturesAvailable,
+ )
if self.source.supportsSubsetString():
try:
@@ -574,70 +783,128 @@ def testEmpty(self):
subset = self.getSubsetString()
self.source.setSubsetString(subset)
self.assertFalse(self.source.empty())
- self.assertEqual(self.source.hasFeatures(), QgsFeatureSource.FeatureAvailability.FeaturesAvailable)
+ self.assertEqual(
+ self.source.hasFeatures(),
+ QgsFeatureSource.FeatureAvailability.FeaturesAvailable,
+ )
subsetNoMatching = self.getSubsetStringNoMatching()
self.source.setSubsetString(subsetNoMatching)
self.assertTrue(self.source.empty())
- self.assertEqual(self.source.hasFeatures(), QgsFeatureSource.FeatureAvailability.NoFeaturesAvailable)
+ self.assertEqual(
+ self.source.hasFeatures(),
+ QgsFeatureSource.FeatureAvailability.NoFeaturesAvailable,
+ )
finally:
self.source.setSubsetString(None)
self.assertFalse(self.source.empty())
# If the provider supports tests on editable layers
- if getattr(self, 'getEditableLayer', None):
+ if getattr(self, "getEditableLayer", None):
l = self.getEditableLayer()
self.assertTrue(l.isValid())
- self.assertEqual(l.hasFeatures(), QgsFeatureSource.FeatureAvailability.FeaturesAvailable)
+ self.assertEqual(
+ l.hasFeatures(), QgsFeatureSource.FeatureAvailability.FeaturesAvailable
+ )
# Test that deleting some features in the edit buffer does not
# return empty, we accept FeaturesAvailable as well as
# MaybeAvailable
l.startEditing()
l.deleteFeature(next(l.getFeatures()).id())
- self.assertNotEqual(l.hasFeatures(), QgsFeatureSource.FeatureAvailability.NoFeaturesAvailable)
+ self.assertNotEqual(
+ l.hasFeatures(),
+ QgsFeatureSource.FeatureAvailability.NoFeaturesAvailable,
+ )
l.rollBack()
# Call truncate(), we need an empty set now
l.dataProvider().truncate()
self.assertTrue(l.dataProvider().empty())
- self.assertEqual(l.dataProvider().hasFeatures(), QgsFeatureSource.FeatureAvailability.NoFeaturesAvailable)
+ self.assertEqual(
+ l.dataProvider().hasFeatures(),
+ QgsFeatureSource.FeatureAvailability.NoFeaturesAvailable,
+ )
def testGetFeaturesNoGeometry(self):
- """ Test that no geometry is present when fetching features without geometry"""
+ """Test that no geometry is present when fetching features without geometry"""
- for f in self.source.getFeatures(QgsFeatureRequest().setFlags(QgsFeatureRequest.Flag.NoGeometry)):
- self.assertFalse(f.hasGeometry(), 'Expected no geometry, got one')
+ for f in self.source.getFeatures(
+ QgsFeatureRequest().setFlags(QgsFeatureRequest.Flag.NoGeometry)
+ ):
+ self.assertFalse(f.hasGeometry(), "Expected no geometry, got one")
self.assertTrue(f.isValid())
def testAddFeature(self):
- if not getattr(self, 'getEditableLayer', None):
+ if not getattr(self, "getEditableLayer", None):
return
l = self.getEditableLayer()
self.assertTrue(l.isValid())
f1 = QgsFeature()
- f1.setAttributes([6, -220, NULL, 'String', '15',
- '2019-01-02 03:04:05' if self.treat_datetime_as_string() else QDateTime(2019, 1, 2, 3, 4, 5),
- '2019-01-02' if self.treat_date_as_string() else QDateTime(2019, 1, 2, 0, 0,
- 0) if self.treat_date_as_datetime() else QDate(
- 2019, 1, 2),
- '03:04:05' if self.treat_time_as_string() else QTime(3, 4, 5)])
- f1.setGeometry(QgsGeometry.fromWkt('Point (-72.345 71.987)'))
+ f1.setAttributes(
+ [
+ 6,
+ -220,
+ NULL,
+ "String",
+ "15",
+ (
+ "2019-01-02 03:04:05"
+ if self.treat_datetime_as_string()
+ else QDateTime(2019, 1, 2, 3, 4, 5)
+ ),
+ (
+ "2019-01-02"
+ if self.treat_date_as_string()
+ else (
+ QDateTime(2019, 1, 2, 0, 0, 0)
+ if self.treat_date_as_datetime()
+ else QDate(2019, 1, 2)
+ )
+ ),
+ "03:04:05" if self.treat_time_as_string() else QTime(3, 4, 5),
+ ]
+ )
+ f1.setGeometry(QgsGeometry.fromWkt("Point (-72.345 71.987)"))
f2 = QgsFeature()
- f2.setAttributes([7, 330, 'Coconut', 'CoCoNut', '13',
- '2018-05-06 07:08:09' if self.treat_datetime_as_string() else QDateTime(2018, 5, 6, 7, 8, 9),
- '2018-05-06' if self.treat_date_as_string() else QDateTime(2018, 5, 6, 0, 0,
- 0) if self.treat_date_as_datetime() else QDate(
- 2018, 5, 6),
- '07:08:09' if self.treat_time_as_string() else QTime(7, 8, 9)])
-
- if l.dataProvider().capabilities() & QgsVectorDataProvider.Capability.AddFeatures:
+ f2.setAttributes(
+ [
+ 7,
+ 330,
+ "Coconut",
+ "CoCoNut",
+ "13",
+ (
+ "2018-05-06 07:08:09"
+ if self.treat_datetime_as_string()
+ else QDateTime(2018, 5, 6, 7, 8, 9)
+ ),
+ (
+ "2018-05-06"
+ if self.treat_date_as_string()
+ else (
+ QDateTime(2018, 5, 6, 0, 0, 0)
+ if self.treat_date_as_datetime()
+ else QDate(2018, 5, 6)
+ )
+ ),
+ "07:08:09" if self.treat_time_as_string() else QTime(7, 8, 9),
+ ]
+ )
+
+ if (
+ l.dataProvider().capabilities()
+ & QgsVectorDataProvider.Capability.AddFeatures
+ ):
# expect success
result, added = l.dataProvider().addFeatures([f1, f2])
- self.assertTrue(result, 'Provider reported AddFeatures capability, but returned False to addFeatures')
+ self.assertTrue(
+ result,
+ "Provider reported AddFeatures capability, but returned False to addFeatures",
+ )
f1.setId(added[0].id())
f2.setId(added[1].id())
@@ -650,18 +917,20 @@ def testAddFeature(self):
# ensure that returned features have been given the correct id
f = next(l.getFeatures(QgsFeatureRequest().setFilterFid(added[0].id())))
self.assertTrue(f.isValid())
- self.assertEqual(f['cnt'], -220)
+ self.assertEqual(f["cnt"], -220)
f = next(l.getFeatures(QgsFeatureRequest().setFilterFid(added[1].id())))
self.assertTrue(f.isValid())
- self.assertEqual(f['cnt'], 330)
+ self.assertEqual(f["cnt"], 330)
else:
# expect fail
- self.assertFalse(l.dataProvider().addFeatures([f1, f2]),
- 'Provider reported no AddFeatures capability, but returned true to addFeatures')
+ self.assertFalse(
+ l.dataProvider().addFeatures([f1, f2]),
+ "Provider reported no AddFeatures capability, but returned true to addFeatures",
+ )
def testAddFeatureFastInsert(self):
- if not getattr(self, 'getEditableLayer', None):
+ if not getattr(self, "getEditableLayer", None):
return
l = self.getEditableLayer()
@@ -669,109 +938,234 @@ def testAddFeatureFastInsert(self):
f1 = QgsFeature()
f1.setAttributes(
- [6, -220, NULL, 'String', '15',
- '2019-01-02 03:04:05' if self.treat_datetime_as_string() else QDateTime(2019, 1, 2, 3, 4, 5),
- '2019-01-02' if self.treat_date_as_string() else QDateTime(2019, 1, 2, 0, 0, 0) if self.treat_date_as_datetime() else QDate(2019, 1, 2),
- '03:04:05' if self.treat_time_as_string() else QTime(3, 4, 5)])
- f1.setGeometry(QgsGeometry.fromWkt('Point (-72.345 71.987)'))
+ [
+ 6,
+ -220,
+ NULL,
+ "String",
+ "15",
+ (
+ "2019-01-02 03:04:05"
+ if self.treat_datetime_as_string()
+ else QDateTime(2019, 1, 2, 3, 4, 5)
+ ),
+ (
+ "2019-01-02"
+ if self.treat_date_as_string()
+ else (
+ QDateTime(2019, 1, 2, 0, 0, 0)
+ if self.treat_date_as_datetime()
+ else QDate(2019, 1, 2)
+ )
+ ),
+ "03:04:05" if self.treat_time_as_string() else QTime(3, 4, 5),
+ ]
+ )
+ f1.setGeometry(QgsGeometry.fromWkt("Point (-72.345 71.987)"))
f2 = QgsFeature()
- f2.setAttributes([7, 330, 'Coconut', 'CoCoNut', '13',
- '2019-01-02 03:04:05' if self.treat_datetime_as_string() else QDateTime(2019, 1, 2, 3, 4, 5),
- '2019-01-02' if self.treat_date_as_string() else QDateTime(2019, 1, 2, 0, 0, 0) if self.treat_date_as_datetime() else QDate(2019, 1, 2),
- '03:04:05' if self.treat_time_as_string() else QTime(3, 4, 5)])
-
- if l.dataProvider().capabilities() & QgsVectorDataProvider.Capability.AddFeatures:
+ f2.setAttributes(
+ [
+ 7,
+ 330,
+ "Coconut",
+ "CoCoNut",
+ "13",
+ (
+ "2019-01-02 03:04:05"
+ if self.treat_datetime_as_string()
+ else QDateTime(2019, 1, 2, 3, 4, 5)
+ ),
+ (
+ "2019-01-02"
+ if self.treat_date_as_string()
+ else (
+ QDateTime(2019, 1, 2, 0, 0, 0)
+ if self.treat_date_as_datetime()
+ else QDate(2019, 1, 2)
+ )
+ ),
+ "03:04:05" if self.treat_time_as_string() else QTime(3, 4, 5),
+ ]
+ )
+
+ if (
+ l.dataProvider().capabilities()
+ & QgsVectorDataProvider.Capability.AddFeatures
+ ):
# expect success
- result, added = l.dataProvider().addFeatures([f1, f2], QgsFeatureSink.Flag.FastInsert)
- self.assertTrue(result, 'Provider reported AddFeatures capability, but returned False to addFeatures')
+ result, added = l.dataProvider().addFeatures(
+ [f1, f2], QgsFeatureSink.Flag.FastInsert
+ )
+ self.assertTrue(
+ result,
+ "Provider reported AddFeatures capability, but returned False to addFeatures",
+ )
self.assertEqual(l.dataProvider().featureCount(), 7)
def testAddFeatureMissingAttributes(self):
- if not getattr(self, 'getEditableLayer', None):
+ if not getattr(self, "getEditableLayer", None):
return
l = self.getEditableLayer()
self.assertTrue(l.isValid())
- if not l.dataProvider().capabilities() & QgsVectorDataProvider.Capability.AddFeatures:
+ if (
+ not l.dataProvider().capabilities()
+ & QgsVectorDataProvider.Capability.AddFeatures
+ ):
return
# test that adding features with missing attributes pads out these
# attributes with NULL values to the correct length
f1 = QgsFeature()
- f1.setAttributes([6, -220, NULL, 'String'])
+ f1.setAttributes([6, -220, NULL, "String"])
f2 = QgsFeature()
f2.setAttributes([7, 330])
result, added = l.dataProvider().addFeatures([f1, f2])
- self.assertTrue(result,
- 'Provider returned False to addFeatures with missing attributes. Providers should accept these features but add NULL attributes to the end of the existing attributes to the required field length.')
+ self.assertTrue(
+ result,
+ "Provider returned False to addFeatures with missing attributes. Providers should accept these features but add NULL attributes to the end of the existing attributes to the required field length.",
+ )
f1.setId(added[0].id())
f2.setId(added[1].id())
# check result - feature attributes MUST be padded out to required number of fields
- f1.setAttributes([6, -220, NULL, 'String', 'NULL', NULL, NULL, NULL])
- f2.setAttributes([7, 330, NULL, NULL, 'NULL', NULL, NULL, NULL])
+ f1.setAttributes([6, -220, NULL, "String", "NULL", NULL, NULL, NULL])
+ f2.setAttributes([7, 330, NULL, NULL, "NULL", NULL, NULL, NULL])
self.testGetFeatures(l.dataProvider(), [f1, f2])
def testAddFeatureExtraAttributes(self):
- if not getattr(self, 'getEditableLayer', None):
+ if not getattr(self, "getEditableLayer", None):
return
l = self.getEditableLayer()
self.assertTrue(l.isValid())
- if not l.dataProvider().capabilities() & QgsVectorDataProvider.Capability.AddFeatures:
+ if (
+ not l.dataProvider().capabilities()
+ & QgsVectorDataProvider.Capability.AddFeatures
+ ):
return
# test that adding features with too many attributes drops these attributes
# we be more tricky and also add a valid feature to stress test the provider
f1 = QgsFeature()
- f1.setAttributes([6, -220, NULL, 'String', '15',
- '2019-01-02 03:04:05' if self.treat_datetime_as_string() else QDateTime(2019, 1, 2, 3, 4, 5),
- '2019-01-02' if self.treat_date_as_string() else QDateTime(2019, 1, 2, 0, 0, 0) if self.treat_date_as_datetime() else QDate(2019, 1, 2),
- '03:04:05' if self.treat_time_as_string() else QTime(3, 4, 5)])
+ f1.setAttributes(
+ [
+ 6,
+ -220,
+ NULL,
+ "String",
+ "15",
+ (
+ "2019-01-02 03:04:05"
+ if self.treat_datetime_as_string()
+ else QDateTime(2019, 1, 2, 3, 4, 5)
+ ),
+ (
+ "2019-01-02"
+ if self.treat_date_as_string()
+ else (
+ QDateTime(2019, 1, 2, 0, 0, 0)
+ if self.treat_date_as_datetime()
+ else QDate(2019, 1, 2)
+ )
+ ),
+ "03:04:05" if self.treat_time_as_string() else QTime(3, 4, 5),
+ ]
+ )
f2 = QgsFeature()
- f2.setAttributes([7, -230, NULL, 'String', '15',
- '2019-01-02 03:04:05' if self.treat_datetime_as_string() else QDateTime(2019, 1, 2, 3, 4, 5),
- '2019-01-02' if self.treat_date_as_string() else QDateTime(2019, 1, 2, 0, 0, 0) if self.treat_date_as_datetime() else QDate(2019, 1, 2),
- '03:04:05' if self.treat_time_as_string() else QTime(3, 4, 5), 15, 16, 17])
+ f2.setAttributes(
+ [
+ 7,
+ -230,
+ NULL,
+ "String",
+ "15",
+ (
+ "2019-01-02 03:04:05"
+ if self.treat_datetime_as_string()
+ else QDateTime(2019, 1, 2, 3, 4, 5)
+ ),
+ (
+ "2019-01-02"
+ if self.treat_date_as_string()
+ else (
+ QDateTime(2019, 1, 2, 0, 0, 0)
+ if self.treat_date_as_datetime()
+ else QDate(2019, 1, 2)
+ )
+ ),
+ "03:04:05" if self.treat_time_as_string() else QTime(3, 4, 5),
+ 15,
+ 16,
+ 17,
+ ]
+ )
result, added = l.dataProvider().addFeatures([f1, f2])
- self.assertTrue(result,
- 'Provider returned False to addFeatures with extra attributes. Providers should accept these features but truncate the extra attributes.')
+ self.assertTrue(
+ result,
+ "Provider returned False to addFeatures with extra attributes. Providers should accept these features but truncate the extra attributes.",
+ )
# make sure feature was added correctly
added = [f for f in l.dataProvider().getFeatures() if f[self.pk_name] == 7][0]
- self.assertEqual(added.attributes(), [7, -230, NULL, 'String', '15',
- '2019-01-02 03:04:05' if self.treat_datetime_as_string() else QDateTime(
- 2019, 1, 2, 3, 4, 5),
- '2019-01-02' if self.treat_date_as_string() else QDateTime(2019, 1, 2, 0, 0, 0) if self.treat_date_as_datetime() else QDate(2019, 1, 2),
- '03:04:05' if self.treat_time_as_string() else QTime(3, 4, 5)])
+ self.assertEqual(
+ added.attributes(),
+ [
+ 7,
+ -230,
+ NULL,
+ "String",
+ "15",
+ (
+ "2019-01-02 03:04:05"
+ if self.treat_datetime_as_string()
+ else QDateTime(2019, 1, 2, 3, 4, 5)
+ ),
+ (
+ "2019-01-02"
+ if self.treat_date_as_string()
+ else (
+ QDateTime(2019, 1, 2, 0, 0, 0)
+ if self.treat_date_as_datetime()
+ else QDate(2019, 1, 2)
+ )
+ ),
+ "03:04:05" if self.treat_time_as_string() else QTime(3, 4, 5),
+ ],
+ )
def testAddFeatureWrongGeomType(self):
- if not getattr(self, 'getEditableLayer', None):
+ if not getattr(self, "getEditableLayer", None):
return
l = self.getEditableLayer()
self.assertTrue(l.isValid())
- if not l.dataProvider().capabilities() & QgsVectorDataProvider.Capability.AddFeatures:
+ if (
+ not l.dataProvider().capabilities()
+ & QgsVectorDataProvider.Capability.AddFeatures
+ ):
return
# test that adding features with incorrect geometry type rejects the feature
# we be more tricky and also add a valid feature to stress test the provider
f1 = QgsFeature()
- f1.setGeometry(QgsGeometry.fromWkt('LineString (-72.345 71.987, -80 80)'))
+ f1.setGeometry(QgsGeometry.fromWkt("LineString (-72.345 71.987, -80 80)"))
f1.setAttributes([7])
f2 = QgsFeature()
- f2.setGeometry(QgsGeometry.fromWkt('Point (-72.345 71.987)'))
+ f2.setGeometry(QgsGeometry.fromWkt("Point (-72.345 71.987)"))
f2.setAttributes([8])
result, added = l.dataProvider().addFeatures([f1, f2])
- self.assertFalse(result,
- 'Provider returned True to addFeatures with incorrect geometry type. Providers should reject these features.')
+ self.assertFalse(
+ result,
+ "Provider returned True to addFeatures with incorrect geometry type. Providers should reject these features.",
+ )
# make sure feature was not added
added = [f for f in l.dataProvider().getFeatures() if f[self.pk_name] == 7]
@@ -781,33 +1175,42 @@ def testAddFeatureWrongGeomType(self):
f3 = QgsFeature()
f3.setAttributes([9])
result, added = l.dataProvider().addFeatures([f3])
- self.assertTrue(result,
- 'Provider returned False to addFeatures with null geometry. Providers should always accept these features.')
+ self.assertTrue(
+ result,
+ "Provider returned False to addFeatures with null geometry. Providers should always accept these features.",
+ )
# make sure feature was added correctly
added = [f for f in l.dataProvider().getFeatures() if f[self.pk_name] == 9][0]
self.assertFalse(added.hasGeometry())
def testAddFeaturesUpdateExtent(self):
- if not getattr(self, 'getEditableLayer', None):
+ if not getattr(self, "getEditableLayer", None):
return
l = self.getEditableLayer()
self.assertTrue(l.isValid())
- self.assertEqual(l.dataProvider().extent().toString(1), '-71.1,66.3 : -65.3,78.3')
+ self.assertEqual(
+ l.dataProvider().extent().toString(1), "-71.1,66.3 : -65.3,78.3"
+ )
- if l.dataProvider().capabilities() & QgsVectorDataProvider.Capability.AddFeatures:
+ if (
+ l.dataProvider().capabilities()
+ & QgsVectorDataProvider.Capability.AddFeatures
+ ):
f1 = QgsFeature()
- f1.setAttributes([6, -220, NULL, 'String', '15'])
- f1.setGeometry(QgsGeometry.fromWkt('Point (-50 90)'))
+ f1.setAttributes([6, -220, NULL, "String", "15"])
+ f1.setGeometry(QgsGeometry.fromWkt("Point (-50 90)"))
l.dataProvider().addFeatures([f1])
l.dataProvider().updateExtents()
- self.assertEqual(l.dataProvider().extent().toString(1), '-71.1,66.3 : -50.0,90.0')
+ self.assertEqual(
+ l.dataProvider().extent().toString(1), "-71.1,66.3 : -50.0,90.0"
+ )
def testDeleteFeatures(self):
- if not getattr(self, 'getEditableLayer', None):
+ if not getattr(self, "getEditableLayer", None):
return
l = self.getEditableLayer()
@@ -817,10 +1220,16 @@ def testDeleteFeatures(self):
features = [f for f in l.dataProvider().getFeatures()]
to_delete = [f.id() for f in features if f.attributes()[0] in [1, 3]]
- if l.dataProvider().capabilities() & QgsVectorDataProvider.Capability.DeleteFeatures:
+ if (
+ l.dataProvider().capabilities()
+ & QgsVectorDataProvider.Capability.DeleteFeatures
+ ):
# expect success
result = l.dataProvider().deleteFeatures(to_delete)
- self.assertTrue(result, 'Provider reported DeleteFeatures capability, but returned False to deleteFeatures')
+ self.assertTrue(
+ result,
+ "Provider reported DeleteFeatures capability, but returned False to deleteFeatures",
+ )
# check result
self.testGetFeatures(l.dataProvider(), skip_features=[1, 3])
@@ -830,28 +1239,41 @@ def testDeleteFeatures(self):
else:
# expect fail
- self.assertFalse(l.dataProvider().deleteFeatures(to_delete),
- 'Provider reported no DeleteFeatures capability, but returned true to deleteFeatures')
+ self.assertFalse(
+ l.dataProvider().deleteFeatures(to_delete),
+ "Provider reported no DeleteFeatures capability, but returned true to deleteFeatures",
+ )
def testDeleteFeaturesUpdateExtent(self):
- if not getattr(self, 'getEditableLayer', None):
+ if not getattr(self, "getEditableLayer", None):
return
l = self.getEditableLayer()
self.assertTrue(l.isValid())
- self.assertEqual(l.dataProvider().extent().toString(1), '-71.1,66.3 : -65.3,78.3')
+ self.assertEqual(
+ l.dataProvider().extent().toString(1), "-71.1,66.3 : -65.3,78.3"
+ )
- to_delete = [f.id() for f in l.dataProvider().getFeatures() if f.attributes()[0] in [5, 4]]
+ to_delete = [
+ f.id()
+ for f in l.dataProvider().getFeatures()
+ if f.attributes()[0] in [5, 4]
+ ]
- if l.dataProvider().capabilities() & QgsVectorDataProvider.Capability.DeleteFeatures:
+ if (
+ l.dataProvider().capabilities()
+ & QgsVectorDataProvider.Capability.DeleteFeatures
+ ):
l.dataProvider().deleteFeatures(to_delete)
l.dataProvider().updateExtents()
- self.assertEqual(l.dataProvider().extent().toString(1), '-70.3,66.3 : -68.2,70.8')
+ self.assertEqual(
+ l.dataProvider().extent().toString(1), "-70.3,66.3 : -68.2,70.8"
+ )
def testTruncate(self):
- if not getattr(self, 'getEditableLayer', None):
+ if not getattr(self, "getEditableLayer", None):
return
l = self.getEditableLayer()
@@ -859,22 +1281,31 @@ def testTruncate(self):
features = [f[self.pk_name] for f in l.dataProvider().getFeatures()]
- if l.dataProvider().capabilities() & QgsVectorDataProvider.Capability.FastTruncate or l.dataProvider().capabilities() & QgsVectorDataProvider.Capability.DeleteFeatures:
+ if (
+ l.dataProvider().capabilities()
+ & QgsVectorDataProvider.Capability.FastTruncate
+ or l.dataProvider().capabilities()
+ & QgsVectorDataProvider.Capability.DeleteFeatures
+ ):
# expect success
result = l.dataProvider().truncate()
- self.assertTrue(result,
- 'Provider reported FastTruncate or DeleteFeatures capability, but returned False to truncate()')
+ self.assertTrue(
+ result,
+ "Provider reported FastTruncate or DeleteFeatures capability, but returned False to truncate()",
+ )
# check result
features = [f[self.pk_name] for f in l.dataProvider().getFeatures()]
self.assertEqual(len(features), 0)
else:
# expect fail
- self.assertFalse(l.dataProvider().truncate(),
- 'Provider reported no FastTruncate or DeleteFeatures capability, but returned true to truncate()')
+ self.assertFalse(
+ l.dataProvider().truncate(),
+ "Provider reported no FastTruncate or DeleteFeatures capability, but returned true to truncate()",
+ )
def testChangeAttributes(self):
- if not getattr(self, 'getEditableLayer', None):
+ if not getattr(self, "getEditableLayer", None):
return
l = self.getEditableLayer()
@@ -886,15 +1317,23 @@ def testChangeAttributes(self):
to_change = [f for f in features if f.attributes()[0] == 1]
to_change.extend([f for f in features if f.attributes()[0] == 3])
# changes by feature id, for changeAttributeValues call
- changes = {to_change[0].id(): {1: 501, 3: 'new string'}, to_change[1].id(): {1: 502, 4: 'NEW'}}
+ changes = {
+ to_change[0].id(): {1: 501, 3: "new string"},
+ to_change[1].id(): {1: 502, 4: "NEW"},
+ }
# changes by pk, for testing after retrieving changed features
- new_attr_map = {1: {1: 501, 3: 'new string'}, 3: {1: 502, 4: 'NEW'}}
+ new_attr_map = {1: {1: 501, 3: "new string"}, 3: {1: 502, 4: "NEW"}}
- if l.dataProvider().capabilities() & QgsVectorDataProvider.Capability.ChangeAttributeValues:
+ if (
+ l.dataProvider().capabilities()
+ & QgsVectorDataProvider.Capability.ChangeAttributeValues
+ ):
# expect success
result = l.dataProvider().changeAttributeValues(changes)
- self.assertTrue(result,
- 'Provider reported ChangeAttributeValues capability, but returned False to changeAttributeValues')
+ self.assertTrue(
+ result,
+ "Provider reported ChangeAttributeValues capability, but returned False to changeAttributeValues",
+ )
# check result
self.testGetFeatures(l.dataProvider(), changed_attributes=new_attr_map)
@@ -904,8 +1343,10 @@ def testChangeAttributes(self):
else:
# expect fail
- self.assertFalse(l.dataProvider().changeAttributeValues(changes),
- 'Provider reported no ChangeAttributeValues capability, but returned true to changeAttributeValues')
+ self.assertFalse(
+ l.dataProvider().changeAttributeValues(changes),
+ "Provider reported no ChangeAttributeValues capability, but returned true to changeAttributeValues",
+ )
def testChangeAttributesConstraintViolation(self):
"""Checks that changing attributes violating a DB-level CHECK constraint returns false
@@ -914,30 +1355,35 @@ def testChangeAttributesConstraintViolation(self):
The layer must contain at least 2 features, that will be used to test the attribute change.
"""
- if not getattr(self, 'getEditableLayerWithCheckConstraint', None):
+ if not getattr(self, "getEditableLayerWithCheckConstraint", None):
return
l = self.getEditableLayerWithCheckConstraint()
self.assertTrue(l.isValid())
- assert l.dataProvider().capabilities() & QgsVectorDataProvider.Capability.ChangeAttributeValues
+ assert (
+ l.dataProvider().capabilities()
+ & QgsVectorDataProvider.Capability.ChangeAttributeValues
+ )
# find the featurea to change
feature0 = [f for f in l.dataProvider().getFeatures()][0]
feature1 = [f for f in l.dataProvider().getFeatures()][1]
- field_idx = l.fields().indexFromName('i_will_fail_on_no_name')
+ field_idx = l.fields().indexFromName("i_will_fail_on_no_name")
self.assertGreaterEqual(field_idx, 0)
# changes by feature id, for changeAttributeValues call
changes = {
- feature0.id(): {field_idx: 'no name'},
- feature1.id(): {field_idx: 'I have a valid name'}
+ feature0.id(): {field_idx: "no name"},
+ feature1.id(): {field_idx: "I have a valid name"},
}
# expect failure
result = l.dataProvider().changeAttributeValues(changes)
self.assertFalse(
- result, 'Provider reported success when changing an attribute value that violates a DB level CHECK constraint')
+ result,
+ "Provider reported success when changing an attribute value that violates a DB level CHECK constraint",
+ )
- if getattr(self, 'stopEditableLayerWithCheckConstraint', None):
+ if getattr(self, "stopEditableLayerWithCheckConstraint", None):
self.stopEditableLayerWithCheckConstraint()
def testUniqueNotNullConstraints(self):
@@ -950,25 +1396,45 @@ def testUniqueNotNullConstraints(self):
"""
- if not getattr(self, 'getEditableLayerWithUniqueNotNullConstraints', None):
+ if not getattr(self, "getEditableLayerWithUniqueNotNullConstraints", None):
return
vl = self.getEditableLayerWithUniqueNotNullConstraints()
self.assertTrue(vl.isValid())
- unique_field_idx = vl.fields().indexFromName('unique')
- not_null_field_idx = vl.fields().indexFromName('not_null')
+ unique_field_idx = vl.fields().indexFromName("unique")
+ not_null_field_idx = vl.fields().indexFromName("not_null")
self.assertGreater(unique_field_idx, 0)
self.assertGreater(not_null_field_idx, 0)
# Not null
- self.assertFalse(bool(vl.fieldConstraints(unique_field_idx) & QgsFieldConstraints.Constraint.ConstraintNotNull))
- self.assertTrue(bool(vl.fieldConstraints(not_null_field_idx) & QgsFieldConstraints.Constraint.ConstraintNotNull))
+ self.assertFalse(
+ bool(
+ vl.fieldConstraints(unique_field_idx)
+ & QgsFieldConstraints.Constraint.ConstraintNotNull
+ )
+ )
+ self.assertTrue(
+ bool(
+ vl.fieldConstraints(not_null_field_idx)
+ & QgsFieldConstraints.Constraint.ConstraintNotNull
+ )
+ )
# Unique
- self.assertTrue(bool(vl.fieldConstraints(unique_field_idx) & QgsFieldConstraints.Constraint.ConstraintUnique))
- self.assertFalse(bool(vl.fieldConstraints(not_null_field_idx) & QgsFieldConstraints.Constraint.ConstraintUnique))
+ self.assertTrue(
+ bool(
+ vl.fieldConstraints(unique_field_idx)
+ & QgsFieldConstraints.Constraint.ConstraintUnique
+ )
+ )
+ self.assertFalse(
+ bool(
+ vl.fieldConstraints(not_null_field_idx)
+ & QgsFieldConstraints.Constraint.ConstraintUnique
+ )
+ )
def testChangeGeometries(self):
- if not getattr(self, 'getEditableLayer', None):
+ if not getattr(self, "getEditableLayer", None):
return
l = self.getEditableLayer()
@@ -979,15 +1445,23 @@ def testChangeGeometries(self):
to_change = [f for f in features if f.attributes()[0] == 1]
to_change.extend([f for f in features if f.attributes()[0] == 3])
# changes by feature id, for changeGeometryValues call
- changes = {to_change[0].id(): QgsGeometry.fromWkt('Point (10 20)'), to_change[1].id(): QgsGeometry()}
+ changes = {
+ to_change[0].id(): QgsGeometry.fromWkt("Point (10 20)"),
+ to_change[1].id(): QgsGeometry(),
+ }
# changes by pk, for testing after retrieving changed features
- new_geom_map = {1: QgsGeometry.fromWkt('Point ( 10 20 )'), 3: QgsGeometry()}
+ new_geom_map = {1: QgsGeometry.fromWkt("Point ( 10 20 )"), 3: QgsGeometry()}
- if l.dataProvider().capabilities() & QgsVectorDataProvider.Capability.ChangeGeometries:
+ if (
+ l.dataProvider().capabilities()
+ & QgsVectorDataProvider.Capability.ChangeGeometries
+ ):
# expect success
result = l.dataProvider().changeGeometryValues(changes)
- self.assertTrue(result,
- 'Provider reported ChangeGeometries capability, but returned False to changeGeometryValues')
+ self.assertTrue(
+ result,
+ "Provider reported ChangeGeometries capability, but returned False to changeGeometryValues",
+ )
# check result
self.testGetFeatures(l.dataProvider(), changed_geometries=new_geom_map)
@@ -997,11 +1471,13 @@ def testChangeGeometries(self):
else:
# expect fail
- self.assertFalse(l.dataProvider().changeGeometryValues(changes),
- 'Provider reported no ChangeGeometries capability, but returned true to changeGeometryValues')
+ self.assertFalse(
+ l.dataProvider().changeGeometryValues(changes),
+ "Provider reported no ChangeGeometries capability, but returned true to changeGeometryValues",
+ )
def testChangeFeatures(self):
- if not getattr(self, 'getEditableLayer', None):
+ if not getattr(self, "getEditableLayer", None):
return
l = self.getEditableLayer()
@@ -1015,44 +1491,73 @@ def testChangeFeatures(self):
to_change = [f for f in features if f.attributes()[0] == 1]
to_change.extend([f for f in features if f.attributes()[0] == 2])
# changes by feature id, for changeAttributeValues call
- attribute_changes = {to_change[0].id(): {1: 501, 3: 'new string'}, to_change[1].id(): {1: 502, 4: 'NEW'}}
+ attribute_changes = {
+ to_change[0].id(): {1: 501, 3: "new string"},
+ to_change[1].id(): {1: 502, 4: "NEW"},
+ }
# changes by pk, for testing after retrieving changed features
- new_attr_map = {1: {1: 501, 3: 'new string'}, 2: {1: 502, 4: 'NEW'}}
+ new_attr_map = {1: {1: 501, 3: "new string"}, 2: {1: 502, 4: "NEW"}}
# find 2 features to change geometries for
to_change = [f for f in features if f.attributes()[0] == 1]
to_change.extend([f for f in features if f.attributes()[0] == 3])
# changes by feature id, for changeGeometryValues call
- geometry_changes = {to_change[0].id(): QgsGeometry.fromWkt('Point (10 20)'), to_change[1].id(): QgsGeometry()}
+ geometry_changes = {
+ to_change[0].id(): QgsGeometry.fromWkt("Point (10 20)"),
+ to_change[1].id(): QgsGeometry(),
+ }
# changes by pk, for testing after retrieving changed features
- new_geom_map = {1: QgsGeometry.fromWkt('Point ( 10 20 )'), 3: QgsGeometry()}
-
- if l.dataProvider().capabilities() & QgsVectorDataProvider.Capability.ChangeGeometries and l.dataProvider().capabilities() & QgsVectorDataProvider.Capability.ChangeAttributeValues:
+ new_geom_map = {1: QgsGeometry.fromWkt("Point ( 10 20 )"), 3: QgsGeometry()}
+
+ if (
+ l.dataProvider().capabilities()
+ & QgsVectorDataProvider.Capability.ChangeGeometries
+ and l.dataProvider().capabilities()
+ & QgsVectorDataProvider.Capability.ChangeAttributeValues
+ ):
# expect success
- result = l.dataProvider().changeFeatures(attribute_changes, geometry_changes)
- self.assertTrue(result,
- 'Provider reported ChangeGeometries and ChangeAttributeValues capability, but returned False to changeFeatures')
+ result = l.dataProvider().changeFeatures(
+ attribute_changes, geometry_changes
+ )
+ self.assertTrue(
+ result,
+ "Provider reported ChangeGeometries and ChangeAttributeValues capability, but returned False to changeFeatures",
+ )
# check result
- self.testGetFeatures(l.dataProvider(), changed_attributes=new_attr_map, changed_geometries=new_geom_map)
+ self.testGetFeatures(
+ l.dataProvider(),
+ changed_attributes=new_attr_map,
+ changed_geometries=new_geom_map,
+ )
# change empty list, should return true for consistency
self.assertTrue(l.dataProvider().changeFeatures({}, {}))
- elif not l.dataProvider().capabilities() & QgsVectorDataProvider.Capability.ChangeGeometries:
+ elif (
+ not l.dataProvider().capabilities()
+ & QgsVectorDataProvider.Capability.ChangeGeometries
+ ):
# expect fail
- self.assertFalse(l.dataProvider().changeFeatures(attribute_changes, geometry_changes),
- 'Provider reported no ChangeGeometries capability, but returned true to changeFeatures')
- elif not l.dataProvider().capabilities() & QgsVectorDataProvider.Capability.ChangeAttributeValues:
+ self.assertFalse(
+ l.dataProvider().changeFeatures(attribute_changes, geometry_changes),
+ "Provider reported no ChangeGeometries capability, but returned true to changeFeatures",
+ )
+ elif (
+ not l.dataProvider().capabilities()
+ & QgsVectorDataProvider.Capability.ChangeAttributeValues
+ ):
# expect fail
- self.assertFalse(l.dataProvider().changeFeatures(attribute_changes, geometry_changes),
- 'Provider reported no ChangeAttributeValues capability, but returned true to changeFeatures')
+ self.assertFalse(
+ l.dataProvider().changeFeatures(attribute_changes, geometry_changes),
+ "Provider reported no ChangeAttributeValues capability, but returned true to changeFeatures",
+ )
def testMinMaxAfterChanges(self):
"""
Tests retrieving field min and max value after making changes to the provider's features
"""
- if not getattr(self, 'getEditableLayer', None):
+ if not getattr(self, "getEditableLayer", None):
return
vl = self.getEditableLayer()
@@ -1082,7 +1587,11 @@ def testMinMaxAfterChanges(self):
self.assertEqual(vl.dataProvider().maximumValue(1), 1400)
# change attribute values
- self.assertTrue(vl.dataProvider().changeAttributeValues({f6.id(): {1: 150}, f7.id(): {1: -100}}))
+ self.assertTrue(
+ vl.dataProvider().changeAttributeValues(
+ {f6.id(): {1: 150}, f7.id(): {1: -100}}
+ )
+ )
self.assertEqual(vl.dataProvider().minimumValue(1), -200)
self.assertEqual(vl.dataProvider().maximumValue(1), 400)
@@ -1095,7 +1604,10 @@ def testMinMaxAfterChanges(self):
self.assertEqual(vl.dataProvider().maximumValue(0), 5)
self.assertEqual(vl.dataProvider().maximumValue(1), 400)
- if vl.dataProvider().capabilities() & QgsVectorDataProvider.Capability.DeleteAttributes:
+ if (
+ vl.dataProvider().capabilities()
+ & QgsVectorDataProvider.Capability.DeleteAttributes
+ ):
# delete attributes
if vl.dataProvider().deleteAttributes([0]):
# may not be possible, e.g. if it's a primary key
@@ -1108,17 +1620,30 @@ def testStringComparison(self):
compiler (or work fine without doing anything :P)
"""
for expression in (
- '5 LIKE \'5\'',
- '5 ILIKE \'5\'',
- '15 NOT LIKE \'5\'',
- '15 NOT ILIKE \'5\'',
- '5 ~ \'5\''):
- iterator = self.source.getFeatures(QgsFeatureRequest().setFilterExpression('5 LIKE \'5\'').setFlags(QgsFeatureRequest.Flag.IgnoreStaticNodesDuringExpressionCompilation))
+ "5 LIKE '5'",
+ "5 ILIKE '5'",
+ "15 NOT LIKE '5'",
+ "15 NOT ILIKE '5'",
+ "5 ~ '5'",
+ ):
+ iterator = self.source.getFeatures(
+ QgsFeatureRequest()
+ .setFilterExpression("5 LIKE '5'")
+ .setFlags(
+ QgsFeatureRequest.Flag.IgnoreStaticNodesDuringExpressionCompilation
+ )
+ )
count = len([f for f in iterator])
self.assertEqual(count, 5)
self.assertFalse(iterator.compileFailed())
if self.enableCompiler():
- iterator = self.source.getFeatures(QgsFeatureRequest().setFilterExpression('5 LIKE \'5\'').setFlags(QgsFeatureRequest.Flag.IgnoreStaticNodesDuringExpressionCompilation))
+ iterator = self.source.getFeatures(
+ QgsFeatureRequest()
+ .setFilterExpression("5 LIKE '5'")
+ .setFlags(
+ QgsFeatureRequest.Flag.IgnoreStaticNodesDuringExpressionCompilation
+ )
+ )
self.assertEqual(count, 5)
self.assertFalse(iterator.compileFailed())
self.disableCompiler()
@@ -1142,7 +1667,7 @@ def testConcurrency(self):
feat = next(iterators[0])
context = QgsExpressionContext()
context.setFeature(feat)
- exp = QgsExpression(f'get_feature(\'{self.vl.id()}\', \'pk\', 5)')
+ exp = QgsExpression(f"get_feature('{self.vl.id()}', 'pk', 5)")
exp.evaluate(context)
def testEmptySubsetOfAttributesWithSubsetString(self):
@@ -1173,7 +1698,7 @@ def testEmptySubsetOfAttributesWithSubsetString(self):
def testGeneratedColumns(self):
- if not getattr(self, 'getGeneratedColumnsData', None):
+ if not getattr(self, "getGeneratedColumnsData", None):
return
vl, generated_value = self.getGeneratedColumnsData()
@@ -1236,7 +1761,9 @@ def testGeneratedColumns(self):
# Test insertion with default value evaluation on provider side to be sure
# it doesn't fail generated columns
- vl.dataProvider().setProviderProperty(QgsDataProvider.ProviderProperty.EvaluateDefaultValues, True)
+ vl.dataProvider().setProviderProperty(
+ QgsDataProvider.ProviderProperty.EvaluateDefaultValues, True
+ )
vl.startEditing()
feature = QgsVectorLayerUtils.createFeature(vl, QgsGeometry(), {0: 8})
diff --git a/tests/src/python/qgis_interface.py b/tests/src/python/qgis_interface.py
index 7faf63c873c8..f2127789fae1 100644
--- a/tests/src/python/qgis_interface.py
+++ b/tests/src/python/qgis_interface.py
@@ -16,12 +16,14 @@
"""
-__author__ = 'tim@linfiniti.com'
-__version__ = '0.5.0'
-__date__ = '10/01/2011'
-__copyright__ = ('Copyright (c) 2010 by Ivan Mincik, ivan.mincik@gista.sk and '
- 'Copyright (c) 2011 German Carrillo, '
- 'geotux_tuxman@linuxmail.org')
+__author__ = "tim@linfiniti.com"
+__version__ = "0.5.0"
+__date__ = "10/01/2011"
+__copyright__ = (
+ "Copyright (c) 2010 by Ivan Mincik, ivan.mincik@gista.sk and "
+ "Copyright (c) 2011 German Carrillo, "
+ "geotux_tuxman@linuxmail.org"
+)
from qgis.PyQt.QtCore import QObject
from qgis.core import QgsProject
@@ -93,5 +95,5 @@ def mainWindow(self):
pass
def addDockWidget(self, area, dockwidget):
- """ Add a dock widget to the main window """
+ """Add a dock widget to the main window"""
pass
diff --git a/tests/src/python/qgis_wrapped_server.py b/tests/src/python/qgis_wrapped_server.py
index 8cd0c2ecab21..7483d815348c 100644
--- a/tests/src/python/qgis_wrapped_server.py
+++ b/tests/src/python/qgis_wrapped_server.py
@@ -116,13 +116,13 @@
import os
-__author__ = 'Alessandro Pasotti'
-__date__ = '05/15/2016'
-__copyright__ = 'Copyright 2016, The QGIS Project'
+__author__ = "Alessandro Pasotti"
+__date__ = "05/15/2016"
+__copyright__ = "Copyright 2016, The QGIS Project"
# Needed on Qt 5 so that the serialization of XML is consistent among all
# executions
-os.environ['QT_HASH_SEED'] = '1'
+os.environ["QT_HASH_SEED"] = "1"
import copy
import math
@@ -143,52 +143,52 @@
QgsServerRequest,
)
-QGIS_SERVER_PORT = int(os.environ.get('QGIS_SERVER_PORT', '8081'))
-QGIS_SERVER_HOST = os.environ.get('QGIS_SERVER_HOST', '127.0.0.1')
+QGIS_SERVER_PORT = int(os.environ.get("QGIS_SERVER_PORT", "8081"))
+QGIS_SERVER_HOST = os.environ.get("QGIS_SERVER_HOST", "127.0.0.1")
# HTTP Basic
-QGIS_SERVER_HTTP_BASIC_AUTH = os.environ.get(
- 'QGIS_SERVER_HTTP_BASIC_AUTH', False)
-QGIS_SERVER_USERNAME = os.environ.get('QGIS_SERVER_USERNAME', 'username')
-QGIS_SERVER_PASSWORD = os.environ.get('QGIS_SERVER_PASSWORD', 'password')
+QGIS_SERVER_HTTP_BASIC_AUTH = os.environ.get("QGIS_SERVER_HTTP_BASIC_AUTH", False)
+QGIS_SERVER_USERNAME = os.environ.get("QGIS_SERVER_USERNAME", "username")
+QGIS_SERVER_PASSWORD = os.environ.get("QGIS_SERVER_PASSWORD", "password")
# PKI authentication
-QGIS_SERVER_PKI_CERTIFICATE = os.environ.get('QGIS_SERVER_PKI_CERTIFICATE')
-QGIS_SERVER_PKI_KEY = os.environ.get('QGIS_SERVER_PKI_KEY')
-QGIS_SERVER_PKI_AUTHORITY = os.environ.get('QGIS_SERVER_PKI_AUTHORITY')
-QGIS_SERVER_PKI_USERNAME = os.environ.get('QGIS_SERVER_PKI_USERNAME')
+QGIS_SERVER_PKI_CERTIFICATE = os.environ.get("QGIS_SERVER_PKI_CERTIFICATE")
+QGIS_SERVER_PKI_KEY = os.environ.get("QGIS_SERVER_PKI_KEY")
+QGIS_SERVER_PKI_AUTHORITY = os.environ.get("QGIS_SERVER_PKI_AUTHORITY")
+QGIS_SERVER_PKI_USERNAME = os.environ.get("QGIS_SERVER_PKI_USERNAME")
# OAuth2 authentication
-QGIS_SERVER_OAUTH2_CERTIFICATE = os.environ.get(
- 'QGIS_SERVER_OAUTH2_CERTIFICATE')
-QGIS_SERVER_OAUTH2_KEY = os.environ.get('QGIS_SERVER_OAUTH2_KEY')
-QGIS_SERVER_OAUTH2_AUTHORITY = os.environ.get('QGIS_SERVER_OAUTH2_AUTHORITY')
-QGIS_SERVER_OAUTH2_USERNAME = os.environ.get(
- 'QGIS_SERVER_OAUTH2_USERNAME', 'username')
-QGIS_SERVER_OAUTH2_PASSWORD = os.environ.get(
- 'QGIS_SERVER_OAUTH2_PASSWORD', 'password')
+QGIS_SERVER_OAUTH2_CERTIFICATE = os.environ.get("QGIS_SERVER_OAUTH2_CERTIFICATE")
+QGIS_SERVER_OAUTH2_KEY = os.environ.get("QGIS_SERVER_OAUTH2_KEY")
+QGIS_SERVER_OAUTH2_AUTHORITY = os.environ.get("QGIS_SERVER_OAUTH2_AUTHORITY")
+QGIS_SERVER_OAUTH2_USERNAME = os.environ.get("QGIS_SERVER_OAUTH2_USERNAME", "username")
+QGIS_SERVER_OAUTH2_PASSWORD = os.environ.get("QGIS_SERVER_OAUTH2_PASSWORD", "password")
QGIS_SERVER_OAUTH2_TOKEN_EXPIRES_IN = os.environ.get(
- 'QGIS_SERVER_OAUTH2_TOKEN_EXPIRES_IN', 3600)
+ "QGIS_SERVER_OAUTH2_TOKEN_EXPIRES_IN", 3600
+)
# Check if PKI is enabled
QGIS_SERVER_PKI_AUTH = (
- QGIS_SERVER_PKI_CERTIFICATE is not None and
- os.path.isfile(QGIS_SERVER_PKI_CERTIFICATE) and
- QGIS_SERVER_PKI_KEY is not None and
- os.path.isfile(QGIS_SERVER_PKI_KEY) and
- QGIS_SERVER_PKI_AUTHORITY is not None and
- os.path.isfile(QGIS_SERVER_PKI_AUTHORITY) and
- QGIS_SERVER_PKI_USERNAME)
+ QGIS_SERVER_PKI_CERTIFICATE is not None
+ and os.path.isfile(QGIS_SERVER_PKI_CERTIFICATE)
+ and QGIS_SERVER_PKI_KEY is not None
+ and os.path.isfile(QGIS_SERVER_PKI_KEY)
+ and QGIS_SERVER_PKI_AUTHORITY is not None
+ and os.path.isfile(QGIS_SERVER_PKI_AUTHORITY)
+ and QGIS_SERVER_PKI_USERNAME
+)
# Check if OAuth2 is enabled
QGIS_SERVER_OAUTH2_AUTH = (
- QGIS_SERVER_OAUTH2_CERTIFICATE is not None and
- os.path.isfile(QGIS_SERVER_OAUTH2_CERTIFICATE) and
- QGIS_SERVER_OAUTH2_KEY is not None and
- os.path.isfile(QGIS_SERVER_OAUTH2_KEY) and
- QGIS_SERVER_OAUTH2_AUTHORITY is not None and
- os.path.isfile(QGIS_SERVER_OAUTH2_AUTHORITY) and
- QGIS_SERVER_OAUTH2_USERNAME and QGIS_SERVER_OAUTH2_PASSWORD)
+ QGIS_SERVER_OAUTH2_CERTIFICATE is not None
+ and os.path.isfile(QGIS_SERVER_OAUTH2_CERTIFICATE)
+ and QGIS_SERVER_OAUTH2_KEY is not None
+ and os.path.isfile(QGIS_SERVER_OAUTH2_KEY)
+ and QGIS_SERVER_OAUTH2_AUTHORITY is not None
+ and os.path.isfile(QGIS_SERVER_OAUTH2_AUTHORITY)
+ and QGIS_SERVER_OAUTH2_USERNAME
+ and QGIS_SERVER_OAUTH2_PASSWORD
+)
HTTPS_ENABLED = QGIS_SERVER_PKI_AUTH or QGIS_SERVER_OAUTH2_AUTH
@@ -202,28 +202,37 @@ class HTTPBasicFilter(QgsServerFilter):
def requestReady(self):
handler = self.serverInterface().requestHandler()
- auth = self.serverInterface().requestHandler().requestHeader('HTTP_AUTHORIZATION')
+ auth = (
+ self.serverInterface()
+ .requestHandler()
+ .requestHeader("HTTP_AUTHORIZATION")
+ )
if auth:
- username, password = base64.b64decode(auth[6:]).split(b':')
- if (username.decode('utf-8') == os.environ.get('QGIS_SERVER_USERNAME', 'username') and
- password.decode('utf-8') == os.environ.get('QGIS_SERVER_PASSWORD', 'password')):
+ username, password = base64.b64decode(auth[6:]).split(b":")
+ if username.decode("utf-8") == os.environ.get(
+ "QGIS_SERVER_USERNAME", "username"
+ ) and password.decode("utf-8") == os.environ.get(
+ "QGIS_SERVER_PASSWORD", "password"
+ ):
return
- handler.setParameter('SERVICE', 'ACCESS_DENIED')
+ handler.setParameter("SERVICE", "ACCESS_DENIED")
def responseComplete(self):
handler = self.serverInterface().requestHandler()
- auth = handler.requestHeader('HTTP_AUTHORIZATION')
+ auth = handler.requestHeader("HTTP_AUTHORIZATION")
if auth:
- username, password = base64.b64decode(auth[6:]).split(b':')
- if (username.decode('utf-8') == os.environ.get('QGIS_SERVER_USERNAME', 'username') and
- password.decode('utf-8') == os.environ.get('QGIS_SERVER_PASSWORD', 'password')):
+ username, password = base64.b64decode(auth[6:]).split(b":")
+ if username.decode("utf-8") == os.environ.get(
+ "QGIS_SERVER_USERNAME", "username"
+ ) and password.decode("utf-8") == os.environ.get(
+ "QGIS_SERVER_PASSWORD", "password"
+ ):
return
# No auth ...
handler.clear()
- handler.setResponseHeader('Status', '401 Authorization required')
- handler.setResponseHeader(
- 'WWW-Authenticate', 'Basic realm="QGIS Server"')
- handler.appendBody(b'Authorization required ')
+ handler.setResponseHeader("Status", "401 Authorization required")
+ handler.setResponseHeader("WWW-Authenticate", 'Basic realm="QGIS Server"')
+ handler.appendBody(b"Authorization required ")
filter = HTTPBasicFilter(qgs_server.serverInterface())
qgs_server.serverInterface().registerFilter(filter)
@@ -231,8 +240,9 @@ def responseComplete(self):
def num2deg(xtile, ytile, zoom):
"""This returns the NW-corner of the square. Use the function with xtile+1 and/or ytile+1
- to get the other corners. With xtile+0.5 & ytile+0.5 it will return the center of the tile."""
- n = 2.0 ** zoom
+ to get the other corners. With xtile+0.5 & ytile+0.5 it will return the center of the tile.
+ """
+ n = 2.0**zoom
lon_deg = xtile / n * 360.0 - 180.0
lat_rad = math.atan(math.sinh(math.pi * (1 - 2 * ytile / n)))
lat_deg = math.degrees(lat_rad)
@@ -244,21 +254,21 @@ class XYZFilter(QgsServerFilter):
def requestReady(self):
handler = self.serverInterface().requestHandler()
- if handler.parameter('SERVICE') == 'XYZ':
- x = int(handler.parameter('X'))
- y = int(handler.parameter('Y'))
- z = int(handler.parameter('Z'))
+ if handler.parameter("SERVICE") == "XYZ":
+ x = int(handler.parameter("X"))
+ y = int(handler.parameter("Y"))
+ z = int(handler.parameter("Z"))
# NW corner
lat_deg, lon_deg = num2deg(x, y, z)
# SE corner
lat_deg2, lon_deg2 = num2deg(x + 1, y + 1, z)
- handler.setParameter('SERVICE', 'WMS')
- handler.setParameter('REQUEST', 'GetMap')
- handler.setParameter('VERSION', '1.3.0')
- handler.setParameter('SRS', 'EPSG:4326')
- handler.setParameter('HEIGHT', '256')
- handler.setParameter('WIDTH', '256')
- handler.setParameter('BBOX', f"{lat_deg2},{lon_deg},{lat_deg},{lon_deg2}")
+ handler.setParameter("SERVICE", "WMS")
+ handler.setParameter("REQUEST", "GetMap")
+ handler.setParameter("VERSION", "1.3.0")
+ handler.setParameter("SRS", "EPSG:4326")
+ handler.setParameter("HEIGHT", "256")
+ handler.setParameter("WIDTH", "256")
+ handler.setParameter("BBOX", f"{lat_deg2},{lon_deg},{lat_deg},{lon_deg2}")
xyzfilter = XYZFilter(qgs_server.serverInterface())
@@ -282,22 +292,27 @@ def validate_client_id(self, client_id, request):
def authenticate_client(self, request, *args, **kwargs):
"""Wide open"""
- request.client = type("Client", (), {'client_id': 'my_id'})
+ request.client = type("Client", (), {"client_id": "my_id"})
return True
def validate_user(self, username, password, client, request, *args, **kwargs):
- if username == QGIS_SERVER_OAUTH2_USERNAME and password == QGIS_SERVER_OAUTH2_PASSWORD:
+ if (
+ username == QGIS_SERVER_OAUTH2_USERNAME
+ and password == QGIS_SERVER_OAUTH2_PASSWORD
+ ):
return True
return False
- def validate_grant_type(self, client_id, grant_type, client, request, *args, **kwargs):
+ def validate_grant_type(
+ self, client_id, grant_type, client, request, *args, **kwargs
+ ):
# Clients should only be allowed to use one type of grant.
- return grant_type in ('password', 'refresh_token')
+ return grant_type in ("password", "refresh_token")
def get_default_scopes(self, client_id, request, *args, **kwargs):
# Scopes a client will authorize for if none are supplied in the
# authorization request.
- return ('my_scope',)
+ return ("my_scope",)
def validate_scopes(self, client_id, scopes, client, request, *args, **kwargs):
"""Wide open"""
@@ -309,18 +324,24 @@ def save_bearer_token(self, token, request, *args, **kwargs):
# the authorization code. Don't forget to save both the
# access_token and the refresh_token and set expiration for the
# access_token to now + expires_in seconds.
- _tokens[token['access_token']] = copy.copy(token)
- _tokens[token['access_token']]['expiration'] = datetime.now(
- ).timestamp() + int(token['expires_in'])
+ _tokens[token["access_token"]] = copy.copy(token)
+ _tokens[token["access_token"]][
+ "expiration"
+ ] = datetime.now().timestamp() + int(token["expires_in"])
def validate_bearer_token(self, token, scopes, request):
"""Check the token"""
- return token in _tokens and _tokens[token]['expiration'] > datetime.now().timestamp()
+ return (
+ token in _tokens
+ and _tokens[token]["expiration"] > datetime.now().timestamp()
+ )
- def validate_refresh_token(self, refresh_token, client, request, *args, **kwargs):
+ def validate_refresh_token(
+ self, refresh_token, client, request, *args, **kwargs
+ ):
"""Ensure the Bearer token is valid and authorized access to scopes."""
for t in _tokens.values():
- if t['refresh_token'] == refresh_token:
+ if t["refresh_token"] == refresh_token:
return True
return False
@@ -330,7 +351,8 @@ def get_original_scopes(self, refresh_token, request, *args, **kwargs):
validator = SimpleValidator()
oauth_server = LegacyApplicationServer(
- validator, token_expires_in=QGIS_SERVER_OAUTH2_TOKEN_EXPIRES_IN)
+ validator, token_expires_in=QGIS_SERVER_OAUTH2_TOKEN_EXPIRES_IN
+ )
class OAuth2Filter(QgsServerFilter):
"""This filter provides testing endpoint for OAuth2 Resource Owner Grant Flow
@@ -350,41 +372,46 @@ def responseComplete(self):
def _token(ttl):
"""Common code for new and refresh token"""
handler.clear()
- body = bytes(handler.data()).decode('utf8')
+ body = bytes(handler.data()).decode("utf8")
old_expires_in = oauth_server.default_token_type.expires_in
# Hacky way to dynamically set token expiration time
oauth_server.default_token_type.expires_in = ttl
headers, payload, code = oauth_server.create_token_response(
- '/token', 'post', body, {})
+ "/token", "post", body, {}
+ )
oauth_server.default_token_type.expires_in = old_expires_in
for k, v in headers.items():
handler.setResponseHeader(k, v)
handler.setStatusCode(code)
- handler.appendBody(payload.encode('utf-8'))
+ handler.appendBody(payload.encode("utf-8"))
# Token expiration
- ttl = handler.parameterMap().get('TTL', QGIS_SERVER_OAUTH2_TOKEN_EXPIRES_IN)
+ ttl = handler.parameterMap().get("TTL", QGIS_SERVER_OAUTH2_TOKEN_EXPIRES_IN)
# Issue a new token
- if handler.url().find('/token') != -1:
+ if handler.url().find("/token") != -1:
_token(ttl)
return
# Refresh token
- if handler.url().find('/refresh') != -1:
+ if handler.url().find("/refresh") != -1:
_token(ttl)
return
# Check for valid token
- auth = handler.requestHeader('HTTP_AUTHORIZATION')
+ auth = handler.requestHeader("HTTP_AUTHORIZATION")
if auth:
result, response = oauth_server.verify_request(
- urllib.parse.quote_plus(handler.url(), safe='/:?=&'), 'post', '', {'Authorization': auth})
+ urllib.parse.quote_plus(handler.url(), safe="/:?=&"),
+ "post",
+ "",
+ {"Authorization": auth},
+ )
if result:
# This is a test endpoint for OAuth2, it requires a valid
# token
- if handler.url().find('/result') != -1:
+ if handler.url().find("/result") != -1:
handler.clear()
- handler.appendBody(b'Valid Token: enjoy OAuth2')
+ handler.appendBody(b"Valid Token: enjoy OAuth2")
# Standard flow
return
else:
@@ -394,10 +421,9 @@ def _token(ttl):
# No auth ...
handler.clear()
handler.setStatusCode(401)
- handler.setResponseHeader('Status', '401 Unauthorized')
- handler.setResponseHeader(
- 'WWW-Authenticate', 'Bearer realm="QGIS Server"')
- handler.appendBody(b'Invalid Token: Authorization required.')
+ handler.setResponseHeader("Status", "401 Unauthorized")
+ handler.setResponseHeader("WWW-Authenticate", 'Bearer realm="QGIS Server"')
+ handler.appendBody(b"Invalid Token: Authorization required.")
filter = OAuth2Filter(qgs_server.serverInterface())
qgs_server.serverInterface().registerFilter(filter)
@@ -409,17 +435,33 @@ def do_GET(self, post_body=None):
# CGI vars:
headers = {}
for k, v in self.headers.items():
- headers['HTTP_%s' % k.replace(' ', '-').replace('-', '_').replace(' ', '-').upper()] = v
- if not self.path.startswith('http'):
- self.path = "{}://{}:{}{}".format('https' if HTTPS_ENABLED else 'http', QGIS_SERVER_HOST, self.server.server_port, self.path)
+ headers[
+ "HTTP_%s"
+ % k.replace(" ", "-").replace("-", "_").replace(" ", "-").upper()
+ ] = v
+ if not self.path.startswith("http"):
+ self.path = "{}://{}:{}{}".format(
+ "https" if HTTPS_ENABLED else "http",
+ QGIS_SERVER_HOST,
+ self.server.server_port,
+ self.path,
+ )
request = QgsBufferServerRequest(
- self.path, (QgsServerRequest.PostMethod if post_body is not None else QgsServerRequest.GetMethod), headers, post_body)
+ self.path,
+ (
+ QgsServerRequest.PostMethod
+ if post_body is not None
+ else QgsServerRequest.GetMethod
+ ),
+ headers,
+ post_body,
+ )
response = QgsBufferServerResponse()
qgs_server.handleRequest(request, response)
headers_dict = response.headers()
try:
- self.send_response(int(headers_dict['Status'].split(' ')[0]))
+ self.send_response(int(headers_dict["Status"].split(" ")[0]))
except:
self.send_response(200)
for k, v in headers_dict.items():
@@ -429,18 +471,19 @@ def do_GET(self, post_body=None):
return
def do_POST(self):
- content_len = int(self.headers.get('content-length', 0))
+ content_len = int(self.headers.get("content-length", 0))
post_body = self.rfile.read(content_len)
return self.do_GET(post_body)
class ThreadedHTTPServer(ThreadingMixIn, HTTPServer):
"""Handle requests in a separate thread."""
+
pass
-if __name__ == '__main__':
- if os.environ.get('MULTITHREADING') == '1':
+if __name__ == "__main__":
+ if os.environ.get("MULTITHREADING") == "1":
server = ThreadedHTTPServer((QGIS_SERVER_HOST, QGIS_SERVER_PORT), Handler)
else:
server = HTTPServer((QGIS_SERVER_HOST, QGIS_SERVER_PORT), Handler)
@@ -450,29 +493,28 @@ class ThreadedHTTPServer(ThreadingMixIn, HTTPServer):
ssl_version = ssl.PROTOCOL_TLS
context = ssl.SSLContext(ssl_version)
context.verify_mode = ssl.CERT_NONE # No certs for OAuth2
- context.load_cert_chain(certfile=QGIS_SERVER_OAUTH2_CERTIFICATE,
- keyfile=QGIS_SERVER_OAUTH2_KEY)
+ context.load_cert_chain(
+ certfile=QGIS_SERVER_OAUTH2_CERTIFICATE, keyfile=QGIS_SERVER_OAUTH2_KEY
+ )
context.load_verify_locations(cafile=QGIS_SERVER_OAUTH2_AUTHORITY)
- server.socket = context.wrap_socket(
- server.socket,
- server_side=True
- )
+ server.socket = context.wrap_socket(server.socket, server_side=True)
else:
ssl_version = ssl.PROTOCOL_TLS
context = ssl.SSLContext(ssl_version)
context.verify_mode = ssl.CERT_REQUIRED
- context.load_cert_chain(certfile=QGIS_SERVER_PKI_CERTIFICATE,
- keyfile=QGIS_SERVER_PKI_KEY)
+ context.load_cert_chain(
+ certfile=QGIS_SERVER_PKI_CERTIFICATE, keyfile=QGIS_SERVER_PKI_KEY
+ )
context.load_verify_locations(cafile=QGIS_SERVER_PKI_AUTHORITY)
- server.socket = context.wrap_socket(
- server.socket,
- server_side=True
- )
+ server.socket = context.wrap_socket(server.socket, server_side=True)
- print('Starting server on %s://%s:%s, use to stop' %
- ('https' if HTTPS_ENABLED else 'http', QGIS_SERVER_HOST, server.server_port), flush=True)
+ print(
+ "Starting server on %s://%s:%s, use to stop"
+ % ("https" if HTTPS_ENABLED else "http", QGIS_SERVER_HOST, server.server_port),
+ flush=True,
+ )
def signal_handler(signal, frame):
global qgs_app
diff --git a/tests/src/python/qgsauthconfigurationcustomstorage.py b/tests/src/python/qgsauthconfigurationcustomstorage.py
index 529d00738b66..1a44d49c2bf6 100644
--- a/tests/src/python/qgsauthconfigurationcustomstorage.py
+++ b/tests/src/python/qgsauthconfigurationcustomstorage.py
@@ -21,7 +21,7 @@
class QgsAuthConfigurationCustomStorage(QgsAuthConfigurationStorage):
"""Only for testing purposes: supports authentication
- configuration storage in memory"""
+ configuration storage in memory"""
def __init__(self, params: dict = {}):
super().__init__(params)
@@ -29,33 +29,46 @@ def __init__(self, params: dict = {}):
self.payloads = {}
self._initialized = False
self._id = str(uuid.uuid4())
- self.is_encrypted = params.get('is_encrypted', 'true') in ['true', 'True', '1', 'TRUE', 'on', 'ON', 'YES', 'yes']
+ self.is_encrypted = params.get("is_encrypted", "true") in [
+ "true",
+ "True",
+ "1",
+ "TRUE",
+ "on",
+ "ON",
+ "YES",
+ "yes",
+ ]
def settingsParams(self):
- param = QgsAuthConfigurationStorage.SettingParam('is_encrypted', 'Whether the storage is encrypted or not', QVariant.Bool)
+ param = QgsAuthConfigurationStorage.SettingParam(
+ "is_encrypted", "Whether the storage is encrypted or not", QVariant.Bool
+ )
return [param]
def isEncrypted(self):
return self.is_encrypted
def name(self):
- return 'Custom'
+ return "Custom"
def description(self):
- return 'Custom storage'
+ return "Custom storage"
def type(self):
- return 'custom'
+ return "custom"
def id(self):
return self._id
def capabilities(self):
- return (Qgis.AuthConfigurationStorageCapability.ReadConfiguration |
- Qgis.AuthConfigurationStorageCapability.DeleteConfiguration |
- Qgis.AuthConfigurationStorageCapability.CreateConfiguration |
- Qgis.AuthConfigurationStorageCapability.UpdateConfiguration |
- Qgis.AuthConfigurationStorageCapability.ClearStorage)
+ return (
+ Qgis.AuthConfigurationStorageCapability.ReadConfiguration
+ | Qgis.AuthConfigurationStorageCapability.DeleteConfiguration
+ | Qgis.AuthConfigurationStorageCapability.CreateConfiguration
+ | Qgis.AuthConfigurationStorageCapability.UpdateConfiguration
+ | Qgis.AuthConfigurationStorageCapability.ClearStorage
+ )
def isReady(self):
return self._initialized
@@ -98,11 +111,11 @@ def loadMethodConfig(self, id: str, full=False):
else:
config = self.configs.get(id, QgsAuthMethodConfig())
config.clearConfigMap()
- return self.configs.get(id, QgsAuthMethodConfig()), ''
+ return self.configs.get(id, QgsAuthMethodConfig()), ""
def authMethodConfigsWithPayload(self) -> str:
configs = {}
for id, config in self.configs.items():
configs[id] = config
- configs[id].setConfig('encrypted_payload', self.payloads[id])
+ configs[id].setConfig("encrypted_payload", self.payloads[id])
return configs
diff --git a/tests/src/python/qgslayermetadataprovidertestbase.py b/tests/src/python/qgslayermetadataprovidertestbase.py
index 25ba1e518506..a765ddb83f05 100644
--- a/tests/src/python/qgslayermetadataprovidertestbase.py
+++ b/tests/src/python/qgslayermetadataprovidertestbase.py
@@ -7,9 +7,9 @@
"""
-__author__ = 'elpaso@itopen.it'
-__date__ = '2022-08-19'
-__copyright__ = 'Copyright 2022, ItOpen'
+__author__ = "elpaso@itopen.it"
+__date__ = "2022-08-19"
+__copyright__ = "Copyright 2022, ItOpen"
from qgis.PyQt.QtCore import QCoreApplication
from qgis.core import (
@@ -32,7 +32,7 @@
TEST_DATA_DIR = unitTestDataPath()
-class LayerMetadataProviderTestBase():
+class LayerMetadataProviderTestBase:
"""Base test for layer metadata providers
Provider tests must implement:
@@ -57,11 +57,11 @@ def testMetadataWriteRead(self):
data_provider_name = self.test_layer.dataProvider().name()
m = self.test_layer.metadata()
- m.setAbstract('QGIS Some Data')
- m.setIdentifier('MD012345')
- m.setTitle('QGIS Test Title')
- m.setKeywords({'dtd1': ['Kw1', 'Kw2']})
- m.setCategories(['Cat1', 'Cat2'])
+ m.setAbstract("QGIS Some Data")
+ m.setIdentifier("MD012345")
+ m.setTitle("QGIS Test Title")
+ m.setKeywords({"dtd1": ["Kw1", "Kw2"]})
+ m.setCategories(["Cat1", "Cat2"])
ext = QgsLayerMetadata.Extent()
spatial_ext = QgsLayerMetadata.SpatialExtent()
spatial_ext.bounds = QgsBox3d(self.test_layer.extent())
@@ -72,66 +72,87 @@ def testMetadataWriteRead(self):
md = QgsProviderRegistry.instance().providerMetadata(data_provider_name)
self.assertIsNotNone(md)
- self.assertTrue(bool(md.providerCapabilities() & QgsProviderMetadata.ProviderCapability.SaveLayerMetadata))
+ self.assertTrue(
+ bool(
+ md.providerCapabilities()
+ & QgsProviderMetadata.ProviderCapability.SaveLayerMetadata
+ )
+ )
layer_uri = self.test_layer.publicSource()
self.assertTrue(md.saveLayerMetadata(layer_uri, m)[0])
self.test_layer = self.getLayer()
m = self.test_layer.metadata()
- self.assertEqual(m.title(), 'QGIS Test Title')
- self.assertEqual(m.identifier(), 'MD012345')
- self.assertEqual(m.abstract(), 'QGIS Some Data')
+ self.assertEqual(m.title(), "QGIS Test Title")
+ self.assertEqual(m.identifier(), "MD012345")
+ self.assertEqual(m.abstract(), "QGIS Some Data")
self.assertEqual(m.crs().authid(), layer_authid)
del self.test_layer
reg = QGIS_APP.layerMetadataProviderRegistry()
md_provider = reg.layerMetadataProviderFromId(self.getMetadataProviderId())
- results = md_provider.search(QgsMetadataSearchContext(), 'QgIs SoMe DaTa')
+ results = md_provider.search(QgsMetadataSearchContext(), "QgIs SoMe DaTa")
self.assertEqual(len(results.metadata()), 1)
result = results.metadata()[0]
- self.assertEqual(result.abstract(), 'QGIS Some Data')
- self.assertEqual(result.identifier(), 'MD012345')
- self.assertEqual(result.title(), 'QGIS Test Title')
+ self.assertEqual(result.abstract(), "QGIS Some Data")
+ self.assertEqual(result.identifier(), "MD012345")
+ self.assertEqual(result.title(), "QGIS Test Title")
self.assertEqual(result.layerType(), layer_type)
self.assertEqual(result.authid(), layer_authid)
# For raster is unknown
if layer_type != QgsMapLayerType.VectorLayer:
- self.assertEqual(result.geometryType(), QgsWkbTypes.GeometryType.UnknownGeometry)
+ self.assertEqual(
+ result.geometryType(), QgsWkbTypes.GeometryType.UnknownGeometry
+ )
else:
- self.assertEqual(result.geometryType(), QgsWkbTypes.GeometryType.PointGeometry)
+ self.assertEqual(
+ result.geometryType(), QgsWkbTypes.GeometryType.PointGeometry
+ )
self.assertEqual(result.dataProviderName(), data_provider_name)
- self.assertEqual(result.standardUri(), 'http://mrcc.com/qgis.dtd')
+ self.assertEqual(result.standardUri(), "http://mrcc.com/qgis.dtd")
self.assertTrue(compareWkt(result.geographicExtent().asWkt(), extent_as_wkt))
# Check layer load
if layer_type == QgsMapLayerType.VectorLayer:
- test_layer = QgsVectorLayer(result.uri(), 'PG MD Layer', result.dataProviderName())
+ test_layer = QgsVectorLayer(
+ result.uri(), "PG MD Layer", result.dataProviderName()
+ )
else:
- test_layer = QgsRasterLayer(result.uri(), 'PG MD Layer', result.dataProviderName())
+ test_layer = QgsRasterLayer(
+ result.uri(), "PG MD Layer", result.dataProviderName()
+ )
self.assertTrue(test_layer.isValid())
# Test search filters
- results = md_provider.search(QgsMetadataSearchContext(), '', QgsRectangle(0, 0, 1, 1))
+ results = md_provider.search(
+ QgsMetadataSearchContext(), "", QgsRectangle(0, 0, 1, 1)
+ )
self.assertEqual(len(results.metadata()), 0)
- results = md_provider.search(QgsMetadataSearchContext(), '', test_layer.extent())
+ results = md_provider.search(
+ QgsMetadataSearchContext(), "", test_layer.extent()
+ )
self.assertEqual(len(results.metadata()), 1)
- results = md_provider.search(QgsMetadataSearchContext(), 'NOT HERE!', test_layer.extent())
+ results = md_provider.search(
+ QgsMetadataSearchContext(), "NOT HERE!", test_layer.extent()
+ )
self.assertEqual(len(results.metadata()), 0)
- results = md_provider.search(QgsMetadataSearchContext(), 'QGIS', test_layer.extent())
+ results = md_provider.search(
+ QgsMetadataSearchContext(), "QGIS", test_layer.extent()
+ )
self.assertEqual(len(results.metadata()), 1)
# Test keywords
- results = md_provider.search(QgsMetadataSearchContext(), 'kw')
+ results = md_provider.search(QgsMetadataSearchContext(), "kw")
self.assertEqual(len(results.metadata()), 1)
- results = md_provider.search(QgsMetadataSearchContext(), 'kw2')
+ results = md_provider.search(QgsMetadataSearchContext(), "kw2")
self.assertEqual(len(results.metadata()), 1)
# Test categories
- results = md_provider.search(QgsMetadataSearchContext(), 'cat')
+ results = md_provider.search(QgsMetadataSearchContext(), "cat")
self.assertEqual(len(results.metadata()), 1)
- results = md_provider.search(QgsMetadataSearchContext(), 'cat2')
+ results = md_provider.search(QgsMetadataSearchContext(), "cat2")
self.assertEqual(len(results.metadata()), 1)
diff --git a/tests/src/python/stylestoragebase.py b/tests/src/python/stylestoragebase.py
index 907e9043dff8..bb7cbc96db57 100644
--- a/tests/src/python/stylestoragebase.py
+++ b/tests/src/python/stylestoragebase.py
@@ -7,9 +7,9 @@
"""
-__author__ = 'elpaso@itopen.it'
-__date__ = '2022-11-07'
-__copyright__ = 'Copyright 2022, ItOpen'
+__author__ = "elpaso@itopen.it"
+__date__ = "2022-11-07"
+__copyright__ = "Copyright 2022, ItOpen"
from qgis.PyQt.QtCore import QCoreApplication, QVariant
from qgis.PyQt.QtGui import QColor
@@ -41,7 +41,7 @@ def setUpClass(cls):
start_app()
-class StyleStorageTestBase():
+class StyleStorageTestBase:
def layerUri(self, conn, schema_name, table_name):
"""Providers may override if they need more complex URI generation than
@@ -52,26 +52,29 @@ def layerUri(self, conn, schema_name, table_name):
def schemaName(self):
"""Providers may override (Oracle?)"""
- return 'test_styles_schema'
+ return "test_styles_schema"
def tableName(self):
"""Providers may override (Oracle?)"""
- return 'test_styles_table'
+ return "test_styles_table"
def testMultipleStyles(self):
md = QgsProviderRegistry.instance().providerMetadata(self.providerKey)
conn = md.createConnection(self.uri, {})
- md.saveConnection(conn, 'qgis_test1')
+ md.saveConnection(conn, "qgis_test1")
schema = None
capabilities = conn.capabilities()
- if (capabilities & QgsAbstractDatabaseProviderConnection.Capability.CreateSchema
+ if (
+ capabilities & QgsAbstractDatabaseProviderConnection.Capability.CreateSchema
and capabilities & QgsAbstractDatabaseProviderConnection.Capability.Schemas
- and capabilities & QgsAbstractDatabaseProviderConnection.Capability.DropSchema):
+ and capabilities
+ & QgsAbstractDatabaseProviderConnection.Capability.DropSchema
+ ):
schema = self.schemaName()
# Start clean
@@ -83,7 +86,7 @@ def testMultipleStyles(self):
schemas = conn.schemas()
self.assertIn(schema, schemas)
- elif (capabilities & QgsAbstractDatabaseProviderConnection.Capability.Schemas):
+ elif capabilities & QgsAbstractDatabaseProviderConnection.Capability.Schemas:
schema = self.schemaName()
try:
@@ -106,52 +109,54 @@ def testMultipleStyles(self):
typ = QgsWkbTypes.Type.Point
# Create table
- conn.createVectorTable(schema, self.tableName(), fields, typ, crs, True, options)
+ conn.createVectorTable(
+ schema, self.tableName(), fields, typ, crs, True, options
+ )
uri = self.layerUri(conn, schema, self.tableName())
- vl = QgsVectorLayer(uri, 'vl', self.providerKey)
+ vl = QgsVectorLayer(uri, "vl", self.providerKey)
self.assertTrue(vl.isValid())
renderer = vl.renderer()
symbol = renderer.symbol().clone()
- symbol.setColor(QColor('#ff0000'))
+ symbol.setColor(QColor("#ff0000"))
renderer.setSymbol(symbol)
- vl.saveStyleToDatabase('style1', 'style1', False, None)
+ vl.saveStyleToDatabase("style1", "style1", False, None)
symbol = renderer.symbol().clone()
- symbol.setColor(QColor('#00ff00'))
+ symbol.setColor(QColor("#00ff00"))
renderer.setSymbol(symbol)
- vl.saveStyleToDatabase('style2', 'style2', True, None)
+ vl.saveStyleToDatabase("style2", "style2", True, None)
symbol = renderer.symbol().clone()
- symbol.setColor(QColor('#0000ff'))
+ symbol.setColor(QColor("#0000ff"))
renderer.setSymbol(symbol)
- vl.saveStyleToDatabase('style3', 'style3', False, None)
+ vl.saveStyleToDatabase("style3", "style3", False, None)
num, ids, names, desc, err = vl.listStylesInDatabase()
- self.assertTrue({'style2', 'style3', 'style1'}.issubset(set(names)))
+ self.assertTrue({"style2", "style3", "style1"}.issubset(set(names)))
del vl
- vl = QgsVectorLayer(uri, 'vl', self.providerKey)
+ vl = QgsVectorLayer(uri, "vl", self.providerKey)
self.assertTrue(vl.isValid())
renderer = vl.renderer()
symbol = renderer.symbol()
- self.assertEqual(symbol.color().name(), '#00ff00')
+ self.assertEqual(symbol.color().name(), "#00ff00")
mgr = vl.styleManager()
- self.assertEqual(mgr.styles(), ['style2'])
+ self.assertEqual(mgr.styles(), ["style2"])
del vl
options = QgsVectorLayer.LayerOptions()
options.loadAllStoredStyles = True
- vl = QgsVectorLayer(uri, 'vl', self.providerKey, options)
+ vl = QgsVectorLayer(uri, "vl", self.providerKey, options)
self.assertTrue(vl.isValid())
renderer = vl.renderer()
symbol = renderer.symbol()
- self.assertEqual(symbol.color().name(), '#00ff00')
+ self.assertEqual(symbol.color().name(), "#00ff00")
mgr = vl.styleManager()
- self.assertTrue({'style2', 'style3', 'style1'}.issubset(set(names)))
+ self.assertTrue({"style2", "style3", "style1"}.issubset(set(names)))
diff --git a/tests/src/python/test_authmanager_oauth2_ows.py b/tests/src/python/test_authmanager_oauth2_ows.py
index 1a320211d264..fea9213cb9db 100644
--- a/tests/src/python/test_authmanager_oauth2_ows.py
+++ b/tests/src/python/test_authmanager_oauth2_ows.py
@@ -14,6 +14,7 @@
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
"""
+
import json
import os
import random
@@ -24,9 +25,9 @@
import tempfile
import urllib
-__author__ = 'Alessandro Pasotti'
-__date__ = '20/04/2017'
-__copyright__ = 'Copyright 2017, The QGIS Project'
+__author__ = "Alessandro Pasotti"
+__date__ = "20/04/2017"
+__copyright__ = "Copyright 2017, The QGIS Project"
from shutil import rmtree
@@ -42,18 +43,25 @@
from utilities import unitTestDataPath, waitServer
try:
- QGIS_SERVER_ENDPOINT_PORT = os.environ['QGIS_SERVER_ENDPOINT_PORT']
+ QGIS_SERVER_ENDPOINT_PORT = os.environ["QGIS_SERVER_ENDPOINT_PORT"]
except:
- QGIS_SERVER_ENDPOINT_PORT = '0' # Auto
+ QGIS_SERVER_ENDPOINT_PORT = "0" # Auto
QGIS_AUTH_DB_DIR_PATH = tempfile.mkdtemp()
-os.environ['QGIS_AUTH_DB_DIR_PATH'] = QGIS_AUTH_DB_DIR_PATH
+os.environ["QGIS_AUTH_DB_DIR_PATH"] = QGIS_AUTH_DB_DIR_PATH
qgis_app = start_app()
-def setup_oauth(username, password, token_uri, refresh_token_uri='', authcfg_id='oauth-2', authcfg_name='OAuth2 test configuration'):
+def setup_oauth(
+ username,
+ password,
+ token_uri,
+ refresh_token_uri="",
+ authcfg_id="oauth-2",
+ authcfg_name="OAuth2 test configuration",
+):
"""Setup oauth configuration to access OAuth API,
return authcfg_id on success, None on failure
"""
@@ -66,29 +74,31 @@ def setup_oauth(username, password, token_uri, refresh_token_uri='', authcfg_id=
"grantFlow": 2,
"password": password,
"persistToken": False,
- "redirectPort": '7070',
+ "redirectPort": "7070",
"redirectUrl": "",
"refreshTokenUrl": refresh_token_uri,
- "requestTimeout": '30',
+ "requestTimeout": "30",
"requestUrl": "",
"scope": "",
"tokenUrl": token_uri,
"username": username,
- "version": 1
+ "version": 1,
}
if authcfg_id not in QgsApplication.authManager().availableAuthMethodConfigs():
- authConfig = QgsAuthMethodConfig('OAuth2')
+ authConfig = QgsAuthMethodConfig("OAuth2")
authConfig.setId(authcfg_id)
authConfig.setName(authcfg_name)
- authConfig.setConfig('oauth2config', json.dumps(cfgjson))
+ authConfig.setConfig("oauth2config", json.dumps(cfgjson))
if QgsApplication.authManager().storeAuthenticationConfig(authConfig):
return authcfg_id
else:
authConfig = QgsAuthMethodConfig()
- QgsApplication.authManager().loadAuthenticationConfig(authcfg_id, authConfig, True)
+ QgsApplication.authManager().loadAuthenticationConfig(
+ authcfg_id, authConfig, True
+ )
authConfig.setName(authcfg_name)
- authConfig.setConfig('oauth2config', json.dumps(cfgjson))
+ authConfig.setConfig("oauth2config", json.dumps(cfgjson))
if QgsApplication.authManager().updateAuthenticationConfig(authConfig):
return authcfg_id
return None
@@ -100,8 +110,8 @@ class TestAuthManager(QgisTestCase):
def setUpAuth(cls):
"""Run before all tests and set up authentication"""
authm = QgsApplication.authManager()
- assert (authm.setMasterPassword('masterpassword', True))
- cls.sslrootcert_path = os.path.join(cls.certsdata_path, 'qgis_ca.crt')
+ assert authm.setMasterPassword("masterpassword", True)
+ cls.sslrootcert_path = os.path.join(cls.certsdata_path, "qgis_ca.crt")
assert os.path.isfile(cls.sslrootcert_path)
os.chmod(cls.sslrootcert_path, stat.S_IRUSR)
@@ -111,24 +121,24 @@ def setUpAuth(cls):
authm.rebuildCaCertsCache()
authm.rebuildTrustedCaCertsCache()
- cls.server_cert = os.path.join(cls.certsdata_path, '127_0_0_1.crt')
- cls.server_key = os.path.join(cls.certsdata_path, '127_0_0_1.key')
+ cls.server_cert = os.path.join(cls.certsdata_path, "127_0_0_1.crt")
+ cls.server_key = os.path.join(cls.certsdata_path, "127_0_0_1.key")
cls.server_rootcert = cls.sslrootcert_path
os.chmod(cls.server_cert, stat.S_IRUSR)
os.chmod(cls.server_key, stat.S_IRUSR)
os.chmod(cls.server_rootcert, stat.S_IRUSR)
- os.environ['QGIS_SERVER_HOST'] = cls.hostname
- os.environ['QGIS_SERVER_PORT'] = str(cls.port)
- os.environ['QGIS_SERVER_OAUTH2_KEY'] = cls.server_key
- os.environ['QGIS_SERVER_OAUTH2_CERTIFICATE'] = cls.server_cert
- os.environ['QGIS_SERVER_OAUTH2_USERNAME'] = cls.username
- os.environ['QGIS_SERVER_OAUTH2_PASSWORD'] = cls.password
- os.environ['QGIS_SERVER_OAUTH2_AUTHORITY'] = cls.server_rootcert
+ os.environ["QGIS_SERVER_HOST"] = cls.hostname
+ os.environ["QGIS_SERVER_PORT"] = str(cls.port)
+ os.environ["QGIS_SERVER_OAUTH2_KEY"] = cls.server_key
+ os.environ["QGIS_SERVER_OAUTH2_CERTIFICATE"] = cls.server_cert
+ os.environ["QGIS_SERVER_OAUTH2_USERNAME"] = cls.username
+ os.environ["QGIS_SERVER_OAUTH2_PASSWORD"] = cls.password
+ os.environ["QGIS_SERVER_OAUTH2_AUTHORITY"] = cls.server_rootcert
# Set default token expiration to 2 seconds, note that this can be
# also controlled when issuing token requests by adding ttl=
# to the query string
- os.environ['QGIS_SERVER_OAUTH2_TOKEN_EXPIRES_IN'] = '2'
+ os.environ["QGIS_SERVER_OAUTH2_TOKEN_EXPIRES_IN"] = "2"
@classmethod
def setUpClass(cls):
@@ -137,43 +147,63 @@ def setUpClass(cls):
Creates an auth configuration"""
cls.port = QGIS_SERVER_ENDPOINT_PORT
# Clean env just to be sure
- env_vars = ['QUERY_STRING', 'QGIS_PROJECT_FILE']
+ env_vars = ["QUERY_STRING", "QGIS_PROJECT_FILE"]
for ev in env_vars:
try:
del os.environ[ev]
except KeyError:
pass
- cls.testdata_path = unitTestDataPath('qgis_server')
- cls.certsdata_path = os.path.join(unitTestDataPath('auth_system'), 'certs_keys_2048')
+ cls.testdata_path = unitTestDataPath("qgis_server")
+ cls.certsdata_path = os.path.join(
+ unitTestDataPath("auth_system"), "certs_keys_2048"
+ )
cls.project_path = os.path.join(cls.testdata_path, "test_project.qgs")
# cls.hostname = 'localhost'
- cls.protocol = 'https'
- cls.hostname = '127.0.0.1'
- cls.username = 'username'
- cls.password = 'password'
+ cls.protocol = "https"
+ cls.hostname = "127.0.0.1"
+ cls.username = "username"
+ cls.password = "password"
cls.setUpAuth()
- server_path = os.path.join(os.path.dirname(os.path.realpath(__file__)),
- 'qgis_wrapped_server.py')
- cls.server = subprocess.Popen([sys.executable, server_path],
- env=os.environ, stdout=subprocess.PIPE)
+ server_path = os.path.join(
+ os.path.dirname(os.path.realpath(__file__)), "qgis_wrapped_server.py"
+ )
+ cls.server = subprocess.Popen(
+ [sys.executable, server_path], env=os.environ, stdout=subprocess.PIPE
+ )
line = cls.server.stdout.readline()
- cls.port = int(re.findall(br':(\d+)', line)[0])
+ cls.port = int(re.findall(rb":(\d+)", line)[0])
assert cls.port != 0
# We need a valid port before we setup the oauth configuration
- cls.token_uri = f'{cls.protocol}://{cls.hostname}:{cls.port}/token'
- cls.refresh_token_uri = f'{cls.protocol}://{cls.hostname}:{cls.port}/refresh'
+ cls.token_uri = f"{cls.protocol}://{cls.hostname}:{cls.port}/token"
+ cls.refresh_token_uri = f"{cls.protocol}://{cls.hostname}:{cls.port}/refresh"
# Need a random authcfg or the cache will bites us back!
- cls.authcfg_id = setup_oauth(cls.username, cls.password, cls.token_uri, cls.refresh_token_uri, str(random.randint(0, 10000000)))
+ cls.authcfg_id = setup_oauth(
+ cls.username,
+ cls.password,
+ cls.token_uri,
+ cls.refresh_token_uri,
+ str(random.randint(0, 10000000)),
+ )
# This is to test wrong credentials
- cls.wrong_authcfg_id = setup_oauth('wrong', 'wrong', cls.token_uri, cls.refresh_token_uri, str(random.randint(0, 10000000)))
+ cls.wrong_authcfg_id = setup_oauth(
+ "wrong",
+ "wrong",
+ cls.token_uri,
+ cls.refresh_token_uri,
+ str(random.randint(0, 10000000)),
+ )
# Get the authentication configuration instance:
- cls.auth_config = QgsApplication.authManager().availableAuthMethodConfigs()[cls.authcfg_id]
+ cls.auth_config = QgsApplication.authManager().availableAuthMethodConfigs()[
+ cls.authcfg_id
+ ]
assert cls.auth_config.isValid()
# Wait for the server process to start
- assert waitServer(f'{cls.protocol}://{cls.hostname}:{cls.port}'), f"Server is not responding! {cls.protocol}://{cls.hostname}:{cls.port}"
+ assert waitServer(
+ f"{cls.protocol}://{cls.hostname}:{cls.port}"
+ ), f"Server is not responding! {cls.protocol}://{cls.hostname}:{cls.port}"
@classmethod
def tearDownClass(cls):
@@ -197,18 +227,18 @@ def _getWFSLayer(cls, type_name, layer_name=None, authcfg=None):
WFS layer factory
"""
if layer_name is None:
- layer_name = 'wfs_' + type_name
+ layer_name = "wfs_" + type_name
parms = {
- 'srsname': 'EPSG:4326',
- 'typename': type_name,
- 'url': f'{cls.protocol}://{cls.hostname}:{cls.port}/?map={cls.project_path}',
- 'version': 'auto',
- 'table': '',
+ "srsname": "EPSG:4326",
+ "typename": type_name,
+ "url": f"{cls.protocol}://{cls.hostname}:{cls.port}/?map={cls.project_path}",
+ "version": "auto",
+ "table": "",
}
if authcfg is not None:
- parms.update({'authcfg': authcfg})
- uri = ' '.join([(f"{k}='{v}'") for k, v in list(parms.items())])
- wfs_layer = QgsVectorLayer(uri, layer_name, 'WFS')
+ parms.update({"authcfg": authcfg})
+ uri = " ".join([(f"{k}='{v}'") for k, v in list(parms.items())])
+ wfs_layer = QgsVectorLayer(uri, layer_name, "WFS")
return wfs_layer
@classmethod
@@ -217,36 +247,36 @@ def _getWMSLayer(cls, layers, layer_name=None, authcfg=None):
WMS layer factory
"""
if layer_name is None:
- layer_name = 'wms_' + layers.replace(',', '')
+ layer_name = "wms_" + layers.replace(",", "")
parms = {
- 'crs': 'EPSG:4326',
- 'url': f'{cls.protocol}://{cls.hostname}:{cls.port}/?map={cls.project_path}',
- 'format': 'image/png',
+ "crs": "EPSG:4326",
+ "url": f"{cls.protocol}://{cls.hostname}:{cls.port}/?map={cls.project_path}",
+ "format": "image/png",
# This is needed because of a really weird implementation in QGIS Server, that
# replaces _ in the the real layer name with spaces
- 'layers': urllib.parse.quote(layers.replace('_', ' ')),
- 'styles': '',
- 'version': 'auto',
+ "layers": urllib.parse.quote(layers.replace("_", " ")),
+ "styles": "",
+ "version": "auto",
# 'sql': '',
}
if authcfg is not None:
- parms.update({'authcfg': authcfg})
- uri = '&'.join([f"{k}={v.replace('=', '%3D')}" for k, v in list(parms.items())])
- wms_layer = QgsRasterLayer(uri, layer_name, 'wms')
+ parms.update({"authcfg": authcfg})
+ uri = "&".join([f"{k}={v.replace('=', '%3D')}" for k, v in list(parms.items())])
+ wms_layer = QgsRasterLayer(uri, layer_name, "wms")
return wms_layer
def testNoAuthAccess(self):
"""
Access the protected layer with no credentials
"""
- wms_layer = self._getWMSLayer('testlayer_èé')
+ wms_layer = self._getWMSLayer("testlayer_èé")
self.assertFalse(wms_layer.isValid())
def testInvalidAuthAccess(self):
"""
Access the protected layer with wrong credentials
"""
- wms_layer = self._getWMSLayer('testlayer_èé', authcfg=self.wrong_authcfg_id)
+ wms_layer = self._getWMSLayer("testlayer_èé", authcfg=self.wrong_authcfg_id)
self.assertFalse(wms_layer.isValid())
def testValidAuthAccess(self):
@@ -255,11 +285,11 @@ def testValidAuthAccess(self):
Note: cannot test invalid access WFS in a separate test because
it would fail the subsequent (valid) calls due to cached connections
"""
- wfs_layer = self._getWFSLayer('testlayer_èé', authcfg=self.auth_config.id())
+ wfs_layer = self._getWFSLayer("testlayer_èé", authcfg=self.auth_config.id())
self.assertTrue(wfs_layer.isValid())
- wms_layer = self._getWMSLayer('testlayer_èé', authcfg=self.auth_config.id())
+ wms_layer = self._getWMSLayer("testlayer_èé", authcfg=self.auth_config.id())
self.assertTrue(wms_layer.isValid())
-if __name__ == '__main__':
+if __name__ == "__main__":
unittest.main()
diff --git a/tests/src/python/test_authmanager_ogr.py b/tests/src/python/test_authmanager_ogr.py
index d2a51a4d468b..1f578dfb496c 100644
--- a/tests/src/python/test_authmanager_ogr.py
+++ b/tests/src/python/test_authmanager_ogr.py
@@ -17,9 +17,9 @@
import unittest
from qgis.testing import start_app, QgisTestCase
-__author__ = 'Alessandro Pasotti'
-__date__ = '14/11/2017'
-__copyright__ = 'Copyright 2017, The QGIS Project'
+__author__ = "Alessandro Pasotti"
+__date__ = "14/11/2017"
+__copyright__ = "Copyright 2017, The QGIS Project"
qgis_app = start_app()
@@ -28,18 +28,18 @@
TEST_URIS = {
"http://mysite.com/geojson authcfg='%s'": "http://username:password@mysite.com/geojson",
"PG:\"dbname='databasename' host='addr' port='5432' authcfg='%s'\"": "PG:\"dbname='databasename' host='addr' port='5432' user='username' password='password'",
- 'SDE:127.0.0.1,12345,dbname, authcfg=\'%s\'': 'SDE:127.0.0.1,12345,dbname,username,password',
- 'IDB:"server=demo_on user=informix dbname=frames authcfg=\'%s\'"': 'IDB:"server=demo_on user=informix dbname=frames user=username pass=password"',
- '@driver=ingres,dbname=test,tables=usa/canada authcfg=\'%s\'': '@driver=ingres,dbname=test,tables=usa/canada,userid=username,password=password',
- 'MySQL:westholland,port=3306,tables=bedrijven authcfg=\'%s\'': 'MySQL:westholland,port=3306,tables=bedrijven,user=username,password=password',
- 'MSSQL:server=.\\MSSQLSERVER2008;database=dbname;trusted_connection=yes authcfg=\'%s\'': 'MSSQL:server=.\\MSSQLSERVER2008;database=dbname;uid=username;pwd=password',
- 'OCI:/@database_instance:table,table authcfg=\'%s\'': 'OCI:username/password@database_instance:table,table',
- 'ODBC:database_instance authcfg=\'%s\'': 'ODBC:username/password@database_instance',
- 'couchdb://myconnection authcfg=\'%s\'': 'couchdb://username:password@myconnection',
- 'http://www.myconnection.com/geojson authcfg=\'%s\'': 'http://username:password@www.myconnection.com/geojson',
- 'https://www.myconnection.com/geojson authcfg=\'%s\'': 'https://username:password@www.myconnection.com/geojson',
- 'ftp://www.myconnection.com/geojson authcfg=\'%s\'': 'ftp://username:password@www.myconnection.com/geojson',
- 'DODS://www.myconnection.com/geojson authcfg=\'%s\'': 'DODS://username:password@www.myconnection.com/geojson',
+ "SDE:127.0.0.1,12345,dbname, authcfg='%s'": "SDE:127.0.0.1,12345,dbname,username,password",
+ "IDB:\"server=demo_on user=informix dbname=frames authcfg='%s'\"": 'IDB:"server=demo_on user=informix dbname=frames user=username pass=password"',
+ "@driver=ingres,dbname=test,tables=usa/canada authcfg='%s'": "@driver=ingres,dbname=test,tables=usa/canada,userid=username,password=password",
+ "MySQL:westholland,port=3306,tables=bedrijven authcfg='%s'": "MySQL:westholland,port=3306,tables=bedrijven,user=username,password=password",
+ "MSSQL:server=.\\MSSQLSERVER2008;database=dbname;trusted_connection=yes authcfg='%s'": "MSSQL:server=.\\MSSQLSERVER2008;database=dbname;uid=username;pwd=password",
+ "OCI:/@database_instance:table,table authcfg='%s'": "OCI:username/password@database_instance:table,table",
+ "ODBC:database_instance authcfg='%s'": "ODBC:username/password@database_instance",
+ "couchdb://myconnection authcfg='%s'": "couchdb://username:password@myconnection",
+ "http://www.myconnection.com/geojson authcfg='%s'": "http://username:password@www.myconnection.com/geojson",
+ "https://www.myconnection.com/geojson authcfg='%s'": "https://username:password@www.myconnection.com/geojson",
+ "ftp://www.myconnection.com/geojson authcfg='%s'": "ftp://username:password@www.myconnection.com/geojson",
+ "DODS://www.myconnection.com/geojson authcfg='%s'": "DODS://username:password@www.myconnection.com/geojson",
}
@@ -49,13 +49,13 @@ class TestAuthManager(QgisTestCase):
def setUpAuth(cls):
"""Run before all tests and set up authentication"""
authm = QgsApplication.authManager()
- assert (authm.setMasterPassword('masterpassword', True))
+ assert authm.setMasterPassword("masterpassword", True)
# Client side
cls.auth_config = QgsAuthMethodConfig("Basic")
- cls.auth_config.setConfig('username', cls.username)
- cls.auth_config.setConfig('password', cls.password)
- cls.auth_config.setName('test_basic_auth_config')
- assert (authm.storeAuthenticationConfig(cls.auth_config)[0])
+ cls.auth_config.setConfig("username", cls.username)
+ cls.auth_config.setConfig("password", cls.password)
+ cls.auth_config.setName("test_basic_auth_config")
+ assert authm.storeAuthenticationConfig(cls.auth_config)[0]
assert cls.auth_config.isValid()
cls.authcfg = cls.auth_config.id()
@@ -64,10 +64,10 @@ def setUpClass(cls):
super().setUpClass()
"""Run before all tests:
Creates an auth configuration"""
- cls.username = 'username'
- cls.password = 'password'
- cls.dbname = 'test_basic'
- cls.hostname = 'localhost'
+ cls.username = "username"
+ cls.password = "password"
+ cls.dbname = "test_basic"
+ cls.hostname = "localhost"
cls.setUpAuth()
def setUp(self):
@@ -82,15 +82,19 @@ def testConnections(self):
"""
Test credentials injection
"""
- pr = QgsProviderRegistry.instance().createProvider('ogr', '')
+ pr = QgsProviderRegistry.instance().createProvider("ogr", "")
for uri, expanded in TEST_URIS.items():
pr.setDataSourceUri(uri % self.authcfg)
self.assertIn(expanded, pr.dataSourceUri(True))
# Test sublayers
for uri, expanded in TEST_URIS.items():
- pr.setDataSourceUri((uri + '|sublayer1') % self.authcfg)
- self.assertEqual(pr.dataSourceUri(True).split('|')[1], "sublayer1", pr.dataSourceUri(True))
+ pr.setDataSourceUri((uri + "|sublayer1") % self.authcfg)
+ self.assertEqual(
+ pr.dataSourceUri(True).split("|")[1],
+ "sublayer1",
+ pr.dataSourceUri(True),
+ )
def testQuotesAndComma(self):
"""
@@ -98,18 +102,20 @@ def testQuotesAndComma(self):
"""
authm = QgsApplication.authManager()
auth_config = QgsAuthMethodConfig("Basic")
- auth_config.setConfig('username', 'qgis,\"rocks\"')
- auth_config.setConfig('password', '\"quoted\"')
- auth_config.setName('test_basic_auth_config_quoted')
+ auth_config.setConfig("username", 'qgis,"rocks"')
+ auth_config.setConfig("password", '"quoted"')
+ auth_config.setName("test_basic_auth_config_quoted")
self.assertTrue(authm.storeAuthenticationConfig(auth_config)[0])
self.assertTrue(auth_config.isValid())
authcfg = auth_config.id()
- pr = QgsProviderRegistry.instance().createProvider('ogr', '')
- uri = 'MySQL:hostname authcfg=\'%s\''
+ pr = QgsProviderRegistry.instance().createProvider("ogr", "")
+ uri = "MySQL:hostname authcfg='%s'"
pr.setDataSourceUri(uri % authcfg)
expanded = pr.dataSourceUri(True)
- self.assertEqual(expanded, r'MySQL:hostname,user="qgis,\"rocks\"",password="\"quoted\""')
+ self.assertEqual(
+ expanded, r'MySQL:hostname,user="qgis,\"rocks\"",password="\"quoted\""'
+ )
-if __name__ == '__main__':
+if __name__ == "__main__":
unittest.main()
diff --git a/tests/src/python/test_authmanager_ogr_postgres.py b/tests/src/python/test_authmanager_ogr_postgres.py
index 7ca8fe5412a4..4299789b605f 100644
--- a/tests/src/python/test_authmanager_ogr_postgres.py
+++ b/tests/src/python/test_authmanager_ogr_postgres.py
@@ -23,6 +23,7 @@
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
"""
+
import os
import signal
import stat
@@ -42,12 +43,14 @@
from utilities import unitTestDataPath
-__author__ = 'Alessandro Pasotti'
-__date__ = '03/11/2017'
-__copyright__ = 'Copyright 2017, The QGIS Project'
+__author__ = "Alessandro Pasotti"
+__date__ = "03/11/2017"
+__copyright__ = "Copyright 2017, The QGIS Project"
-QGIS_POSTGRES_SERVER_PORT = os.environ.get('QGIS_POSTGRES_SERVER_PORT', '55432')
-QGIS_POSTGRES_EXECUTABLE_PATH = os.environ.get('QGIS_POSTGRES_EXECUTABLE_PATH', '/usr/lib/postgresql/9.4/bin')
+QGIS_POSTGRES_SERVER_PORT = os.environ.get("QGIS_POSTGRES_SERVER_PORT", "55432")
+QGIS_POSTGRES_EXECUTABLE_PATH = os.environ.get(
+ "QGIS_POSTGRES_EXECUTABLE_PATH", "/usr/lib/postgresql/9.4/bin"
+)
assert os.path.exists(QGIS_POSTGRES_EXECUTABLE_PATH)
@@ -56,7 +59,7 @@
# Postgres test path
QGIS_PG_TEST_PATH = tempfile.mkdtemp()
-os.environ['QGIS_AUTH_DB_DIR_PATH'] = QGIS_AUTH_DB_DIR_PATH
+os.environ["QGIS_AUTH_DB_DIR_PATH"] = QGIS_AUTH_DB_DIR_PATH
qgis_app = start_app()
@@ -91,46 +94,51 @@ class TestAuthManager(QgisTestCase):
def setUpAuth(cls):
"""Run before all tests and set up authentication"""
authm = QgsApplication.authManager()
- assert (authm.setMasterPassword('masterpassword', True))
- cls.pg_conf = os.path.join(cls.tempfolder, 'postgresql.conf')
- cls.pg_hba = os.path.join(cls.tempfolder, 'pg_hba.conf')
+ assert authm.setMasterPassword("masterpassword", True)
+ cls.pg_conf = os.path.join(cls.tempfolder, "postgresql.conf")
+ cls.pg_hba = os.path.join(cls.tempfolder, "pg_hba.conf")
# Client side
- cls.sslrootcert_path = os.path.join(cls.certsdata_path, 'chains_subissuer-issuer-root_issuer2-root2.pem')
+ cls.sslrootcert_path = os.path.join(
+ cls.certsdata_path, "chains_subissuer-issuer-root_issuer2-root2.pem"
+ )
assert os.path.isfile(cls.sslrootcert_path)
os.chmod(cls.sslrootcert_path, stat.S_IRUSR)
cls.auth_config = QgsAuthMethodConfig("Basic")
- cls.auth_config.setConfig('username', cls.username)
- cls.auth_config.setConfig('password', cls.password)
- cls.auth_config.setName('test_basic_auth_config')
+ cls.auth_config.setConfig("username", cls.username)
+ cls.auth_config.setConfig("password", cls.password)
+ cls.auth_config.setName("test_basic_auth_config")
cls.sslrootcert = QSslCertificate.fromPath(cls.sslrootcert_path)
assert cls.sslrootcert is not None
authm.storeCertAuthorities(cls.sslrootcert)
authm.rebuildCaCertsCache()
authm.rebuildTrustedCaCertsCache()
authm.rebuildCertTrustCache()
- assert (authm.storeAuthenticationConfig(cls.auth_config)[0])
+ assert authm.storeAuthenticationConfig(cls.auth_config)[0]
assert cls.auth_config.isValid()
cls.authcfg = cls.auth_config.id()
# Server side
- cls.server_cert = os.path.join(cls.certsdata_path, 'localhost_ssl_cert.pem')
- cls.server_key = os.path.join(cls.certsdata_path, 'localhost_ssl_key.pem')
+ cls.server_cert = os.path.join(cls.certsdata_path, "localhost_ssl_cert.pem")
+ cls.server_key = os.path.join(cls.certsdata_path, "localhost_ssl_key.pem")
cls.server_rootcert = cls.sslrootcert_path
os.chmod(cls.server_cert, stat.S_IRUSR)
os.chmod(cls.server_key, stat.S_IRUSR)
os.chmod(cls.server_rootcert, stat.S_IRUSR)
# Place conf in the data folder
- with open(cls.pg_conf, 'w+') as f:
- f.write(QGIS_POSTGRES_CONF_TEMPLATE % {
- 'port': cls.port,
- 'tempfolder': cls.tempfolder,
- 'server_cert': cls.server_cert,
- 'server_key': cls.server_key,
- 'sslrootcert_path': cls.sslrootcert_path,
- })
-
- with open(cls.pg_hba, 'w+') as f:
+ with open(cls.pg_conf, "w+") as f:
+ f.write(
+ QGIS_POSTGRES_CONF_TEMPLATE
+ % {
+ "port": cls.port,
+ "tempfolder": cls.tempfolder,
+ "server_cert": cls.server_cert,
+ "server_key": cls.server_key,
+ "sslrootcert_path": cls.sslrootcert_path,
+ }
+ )
+
+ with open(cls.pg_hba, "w+") as f:
f.write(QGIS_POSTGRES_HBA_TEMPLATE)
@classmethod
@@ -139,28 +147,36 @@ def setUpClass(cls):
Creates an auth configuration"""
super().setUpClass()
cls.port = QGIS_POSTGRES_SERVER_PORT
- cls.username = 'username'
- cls.password = 'password'
- cls.dbname = 'test_basic'
+ cls.username = "username"
+ cls.password = "password"
+ cls.dbname = "test_basic"
cls.tempfolder = QGIS_PG_TEST_PATH
- cls.certsdata_path = os.path.join(unitTestDataPath('auth_system'), 'certs_keys')
- cls.hostname = 'localhost'
- cls.data_path = os.path.join(cls.tempfolder, 'data')
+ cls.certsdata_path = os.path.join(unitTestDataPath("auth_system"), "certs_keys")
+ cls.hostname = "localhost"
+ cls.data_path = os.path.join(cls.tempfolder, "data")
os.mkdir(cls.data_path)
cls.setUpAuth()
- subprocess.check_call([os.path.join(QGIS_POSTGRES_EXECUTABLE_PATH, 'initdb'), '-D', cls.data_path])
+ subprocess.check_call(
+ [os.path.join(QGIS_POSTGRES_EXECUTABLE_PATH, "initdb"), "-D", cls.data_path]
+ )
# Disable SSL verification for setup operations
env = dict(os.environ)
- env['PGSSLMODE'] = 'disable'
-
- cls.server = subprocess.Popen([os.path.join(QGIS_POSTGRES_EXECUTABLE_PATH, 'postgres'), '-D',
- cls.data_path, '-c',
- f"config_file={cls.pg_conf}"],
- env=env,
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE)
+ env["PGSSLMODE"] = "disable"
+
+ cls.server = subprocess.Popen(
+ [
+ os.path.join(QGIS_POSTGRES_EXECUTABLE_PATH, "postgres"),
+ "-D",
+ cls.data_path,
+ "-c",
+ f"config_file={cls.pg_conf}",
+ ],
+ env=env,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ )
# Wait max 10 secs for the server to start
end = time.time() + 10
while True:
@@ -171,12 +187,46 @@ def setUpClass(cls):
if time.time() > end:
raise Exception("Timeout connecting to PostgreSQL")
# Create a DB
- subprocess.check_call([os.path.join(QGIS_POSTGRES_EXECUTABLE_PATH, 'createdb'), '-h', 'localhost', '-p', cls.port, 'test_basic'], env=env)
+ subprocess.check_call(
+ [
+ os.path.join(QGIS_POSTGRES_EXECUTABLE_PATH, "createdb"),
+ "-h",
+ "localhost",
+ "-p",
+ cls.port,
+ "test_basic",
+ ],
+ env=env,
+ )
# Inject test SQL from test path
- test_sql = os.path.join(unitTestDataPath('provider'), 'testdata_pg.sql')
- subprocess.check_call([os.path.join(QGIS_POSTGRES_EXECUTABLE_PATH, 'psql'), '-h', 'localhost', '-p', cls.port, '-f', test_sql, cls.dbname], env=env)
+ test_sql = os.path.join(unitTestDataPath("provider"), "testdata_pg.sql")
+ subprocess.check_call(
+ [
+ os.path.join(QGIS_POSTGRES_EXECUTABLE_PATH, "psql"),
+ "-h",
+ "localhost",
+ "-p",
+ cls.port,
+ "-f",
+ test_sql,
+ cls.dbname,
+ ],
+ env=env,
+ )
# Create a role
- subprocess.check_call([os.path.join(QGIS_POSTGRES_EXECUTABLE_PATH, 'psql'), '-h', 'localhost', '-p', cls.port, '-c', f'CREATE ROLE "{cls.username}" WITH SUPERUSER LOGIN PASSWORD \'{cls.password}\'', cls.dbname], env=env)
+ subprocess.check_call(
+ [
+ os.path.join(QGIS_POSTGRES_EXECUTABLE_PATH, "psql"),
+ "-h",
+ "localhost",
+ "-p",
+ cls.port,
+ "-c",
+ f"CREATE ROLE \"{cls.username}\" WITH SUPERUSER LOGIN PASSWORD '{cls.password}'",
+ cls.dbname,
+ ],
+ env=env,
+ )
@classmethod
def tearDownClass(cls):
@@ -198,40 +248,43 @@ def tearDown(self):
pass
@classmethod
- def _getPostGISLayer(cls, type_name, layer_name=None, authcfg=''):
+ def _getPostGISLayer(cls, type_name, layer_name=None, authcfg=""):
"""
PG layer factory
"""
if layer_name is None:
- layer_name = 'pg_' + type_name
+ layer_name = "pg_" + type_name
# Warning: OGR needs the schema if it's not the default, so qgis_test.someData
- connstring = "PG:dbname='%(dbname)s' host='%(hostname)s' port='%(port)s' sslmode='verify-full' sslrootcert='%(sslrootcert)s'%(authcfg)s|layername=qgis_test.someData" % (
- {
- 'dbname': cls.dbname,
- 'hostname': cls.hostname,
- 'port': cls.port,
- 'authcfg': ' authcfg=\'%s\'' % authcfg if authcfg else '',
- 'sslrootcert': cls.sslrootcert_path,
- }
+ connstring = (
+ "PG:dbname='%(dbname)s' host='%(hostname)s' port='%(port)s' sslmode='verify-full' sslrootcert='%(sslrootcert)s'%(authcfg)s|layername=qgis_test.someData"
+ % (
+ {
+ "dbname": cls.dbname,
+ "hostname": cls.hostname,
+ "port": cls.port,
+ "authcfg": " authcfg='%s'" % authcfg if authcfg else "",
+ "sslrootcert": cls.sslrootcert_path,
+ }
+ )
)
- layer = QgsVectorLayer(connstring, layer_name, 'ogr')
+ layer = QgsVectorLayer(connstring, layer_name, "ogr")
return layer
def testValidAuthAccess(self):
"""
Access the protected layer with valid credentials
"""
- pg_layer = self._getPostGISLayer('testlayer_èé', authcfg=self.auth_config.id())
+ pg_layer = self._getPostGISLayer("testlayer_èé", authcfg=self.auth_config.id())
self.assertTrue(pg_layer.isValid())
def testInvalidAuthAccess(self):
"""
Access the protected layer with not valid credentials
"""
- pg_layer = self._getPostGISLayer('testlayer_èé')
+ pg_layer = self._getPostGISLayer("testlayer_èé")
self.assertFalse(pg_layer.isValid())
-if __name__ == '__main__':
+if __name__ == "__main__":
unittest.main()
diff --git a/tests/src/python/test_authmanager_password_ows.py b/tests/src/python/test_authmanager_password_ows.py
index 697527e3daa2..7d32740d56d3 100644
--- a/tests/src/python/test_authmanager_password_ows.py
+++ b/tests/src/python/test_authmanager_password_ows.py
@@ -15,6 +15,7 @@
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
"""
+
import os
import random
import re
@@ -26,9 +27,9 @@
from functools import partial
-__author__ = 'Alessandro Pasotti'
-__date__ = '18/09/2016'
-__copyright__ = 'Copyright 2016, The QGIS Project'
+__author__ = "Alessandro Pasotti"
+__date__ = "18/09/2016"
+__copyright__ = "Copyright 2016, The QGIS Project"
from shutil import rmtree
@@ -45,13 +46,13 @@
from utilities import unitTestDataPath, waitServer
try:
- QGIS_SERVER_ENDPOINT_PORT = os.environ['QGIS_SERVER_ENDPOINT_PORT']
+ QGIS_SERVER_ENDPOINT_PORT = os.environ["QGIS_SERVER_ENDPOINT_PORT"]
except:
- QGIS_SERVER_ENDPOINT_PORT = '0' # Auto
+ QGIS_SERVER_ENDPOINT_PORT = "0" # Auto
QGIS_AUTH_DB_DIR_PATH = tempfile.mkdtemp()
-os.environ['QGIS_AUTH_DB_DIR_PATH'] = QGIS_AUTH_DB_DIR_PATH
+os.environ["QGIS_AUTH_DB_DIR_PATH"] = QGIS_AUTH_DB_DIR_PATH
qgis_app = start_app()
@@ -65,44 +66,53 @@ def setUpClass(cls):
super().setUpClass()
cls.port = QGIS_SERVER_ENDPOINT_PORT
# Clean env just to be sure
- env_vars = ['QUERY_STRING', 'QGIS_PROJECT_FILE']
+ env_vars = ["QUERY_STRING", "QGIS_PROJECT_FILE"]
for ev in env_vars:
try:
del os.environ[ev]
except KeyError:
pass
- cls.testdata_path = unitTestDataPath('qgis_server') + '/'
+ cls.testdata_path = unitTestDataPath("qgis_server") + "/"
cls.project_path = cls.testdata_path + "test_project.qgs"
# Enable auth
# os.environ['QGIS_AUTH_PASSWORD_FILE'] = QGIS_AUTH_PASSWORD_FILE
authm = QgsApplication.authManager()
- assert (authm.setMasterPassword('masterpassword', True))
- cls.auth_config = QgsAuthMethodConfig('Basic')
- cls.auth_config.setName('test_auth_config')
- cls.username = ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(6))
+ assert authm.setMasterPassword("masterpassword", True)
+ cls.auth_config = QgsAuthMethodConfig("Basic")
+ cls.auth_config.setName("test_auth_config")
+ cls.username = "".join(
+ random.choice(string.ascii_uppercase + string.digits) for _ in range(6)
+ )
cls.password = cls.username[::-1] # reversed
- cls.auth_config.setConfig('username', cls.username)
- cls.auth_config.setConfig('password', cls.password)
- assert (authm.storeAuthenticationConfig(cls.auth_config)[0])
- cls.hostname = '127.0.0.1'
- cls.protocol = 'http'
-
- os.environ['QGIS_SERVER_HTTP_BASIC_AUTH'] = '1'
- os.environ['QGIS_SERVER_USERNAME'] = cls.username
- os.environ['QGIS_SERVER_PASSWORD'] = cls.password
- os.environ['QGIS_SERVER_PORT'] = str(cls.port)
- os.environ['QGIS_SERVER_HOST'] = cls.hostname
-
- server_path = os.path.dirname(os.path.realpath(__file__)) + \
- '/qgis_wrapped_server.py'
- cls.server = subprocess.Popen([sys.executable, server_path],
- env=os.environ, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ cls.auth_config.setConfig("username", cls.username)
+ cls.auth_config.setConfig("password", cls.password)
+ assert authm.storeAuthenticationConfig(cls.auth_config)[0]
+ cls.hostname = "127.0.0.1"
+ cls.protocol = "http"
+
+ os.environ["QGIS_SERVER_HTTP_BASIC_AUTH"] = "1"
+ os.environ["QGIS_SERVER_USERNAME"] = cls.username
+ os.environ["QGIS_SERVER_PASSWORD"] = cls.password
+ os.environ["QGIS_SERVER_PORT"] = str(cls.port)
+ os.environ["QGIS_SERVER_HOST"] = cls.hostname
+
+ server_path = (
+ os.path.dirname(os.path.realpath(__file__)) + "/qgis_wrapped_server.py"
+ )
+ cls.server = subprocess.Popen(
+ [sys.executable, server_path],
+ env=os.environ,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ )
line = cls.server.stdout.readline()
- cls.port = int(re.findall(br':(\d+)', line)[0])
+ cls.port = int(re.findall(rb":(\d+)", line)[0])
assert cls.port != 0
# Wait for the server process to start
- assert waitServer(f'{cls.protocol}://{cls.hostname}:{cls.port}'), f"Server is not responding! {cls.protocol}://{cls.hostname}:{cls.port}"
+ assert waitServer(
+ f"{cls.protocol}://{cls.hostname}:{cls.port}"
+ ), f"Server is not responding! {cls.protocol}://{cls.hostname}:{cls.port}"
@classmethod
def tearDownClass(cls):
@@ -126,18 +136,18 @@ def _getWFSLayer(cls, type_name, layer_name=None, authcfg=None):
WFS layer factory
"""
if layer_name is None:
- layer_name = 'wfs_' + type_name
+ layer_name = "wfs_" + type_name
parms = {
- 'srsname': 'EPSG:4326',
- 'typename': type_name,
- 'url': f'{cls.protocol}://{cls.hostname}:{cls.port}/?map={cls.project_path}',
- 'version': 'auto',
- 'table': '',
+ "srsname": "EPSG:4326",
+ "typename": type_name,
+ "url": f"{cls.protocol}://{cls.hostname}:{cls.port}/?map={cls.project_path}",
+ "version": "auto",
+ "table": "",
}
if authcfg is not None:
- parms.update({'authcfg': authcfg})
- uri = ' '.join([(f"{k}='{v}'") for k, v in list(parms.items())])
- wfs_layer = QgsVectorLayer(uri, layer_name, 'WFS')
+ parms.update({"authcfg": authcfg})
+ uri = " ".join([(f"{k}='{v}'") for k, v in list(parms.items())])
+ wfs_layer = QgsVectorLayer(uri, layer_name, "WFS")
return wfs_layer
@classmethod
@@ -146,21 +156,21 @@ def _getWMSLayer(cls, layers, layer_name=None, authcfg=None):
WMS layer factory
"""
if layer_name is None:
- layer_name = 'wms_' + layers.replace(',', '')
+ layer_name = "wms_" + layers.replace(",", "")
parms = {
- 'crs': 'EPSG:4326',
- 'url': f'{cls.protocol}://{cls.hostname}:{cls.port}/?map={cls.project_path}',
+ "crs": "EPSG:4326",
+ "url": f"{cls.protocol}://{cls.hostname}:{cls.port}/?map={cls.project_path}",
# This is needed because of a really weird implementation in QGIS Server, that
# replaces _ in the the real layer name with spaces
- 'layers': urllib.parse.quote(layers.replace('_', ' ')),
- 'styles': '',
- 'version': 'auto',
+ "layers": urllib.parse.quote(layers.replace("_", " ")),
+ "styles": "",
+ "version": "auto",
# 'sql': '',
}
if authcfg is not None:
- parms.update({'authcfg': authcfg})
- uri = '&'.join([f"{k}={v.replace('=', '%3D')}" for k, v in list(parms.items())])
- wms_layer = QgsRasterLayer(uri, layer_name, 'wms')
+ parms.update({"authcfg": authcfg})
+ uri = "&".join([f"{k}={v.replace('=', '%3D')}" for k, v in list(parms.items())])
+ wms_layer = QgsRasterLayer(uri, layer_name, "wms")
return wms_layer
@classmethod
@@ -169,99 +179,119 @@ def _getGeoJsonLayer(cls, type_name, layer_name=None, authcfg=None):
OGR layer factory
"""
if layer_name is None:
- layer_name = 'geojson_' + type_name
- uri = f'{cls.protocol}://{cls.hostname}:{cls.port}/?MAP={cls.project_path}&SERVICE=WFS&REQUEST=GetFeature&TYPENAME={urllib.parse.quote(type_name)}&VERSION=2.0.0&OUTPUTFORMAT=geojson'
+ layer_name = "geojson_" + type_name
+ uri = f"{cls.protocol}://{cls.hostname}:{cls.port}/?MAP={cls.project_path}&SERVICE=WFS&REQUEST=GetFeature&TYPENAME={urllib.parse.quote(type_name)}&VERSION=2.0.0&OUTPUTFORMAT=geojson"
if authcfg is not None:
uri += f" authcfg='{authcfg}'"
- geojson_layer = QgsVectorLayer(uri, layer_name, 'ogr')
+ geojson_layer = QgsVectorLayer(uri, layer_name, "ogr")
return geojson_layer
def testValidAuthAccess(self):
"""
Access the HTTP Basic protected layer with valid credentials
"""
- wfs_layer = self._getWFSLayer('testlayer_èé', authcfg=self.auth_config.id())
+ wfs_layer = self._getWFSLayer("testlayer_èé", authcfg=self.auth_config.id())
self.assertTrue(wfs_layer.isValid())
- wms_layer = self._getWMSLayer('testlayer_èé', authcfg=self.auth_config.id())
+ wms_layer = self._getWMSLayer("testlayer_èé", authcfg=self.auth_config.id())
self.assertTrue(wms_layer.isValid())
- geojson_layer = self._getGeoJsonLayer('testlayer_èé', authcfg=self.auth_config.id())
+ geojson_layer = self._getGeoJsonLayer(
+ "testlayer_èé", authcfg=self.auth_config.id()
+ )
self.assertTrue(geojson_layer.isValid())
def testInvalidAuthAccess(self):
"""
Access the HTTP Basic protected layer with no credentials
"""
- wfs_layer = self._getWFSLayer('testlayer èé')
+ wfs_layer = self._getWFSLayer("testlayer èé")
self.assertFalse(wfs_layer.isValid())
- wms_layer = self._getWMSLayer('testlayer_èé')
+ wms_layer = self._getWMSLayer("testlayer_èé")
self.assertFalse(wms_layer.isValid())
- geojson_layer = self._getGeoJsonLayer('testlayer_èé')
+ geojson_layer = self._getGeoJsonLayer("testlayer_èé")
self.assertFalse(geojson_layer.isValid())
def testInvalidAuthFileDownload(self):
"""
Download a protected map tile without authcfg
"""
- qs = "?" + "&".join(["%s=%s" % i for i in list({
- "MAP": urllib.parse.quote(self.project_path),
- "SERVICE": "WMS",
- "VERSION": "1.1.1",
- "REQUEST": "GetMap",
- "LAYERS": "testlayer_èé".replace('_', '%20'),
- "STYLES": "",
- "FORMAT": "image/png",
- "BBOX": "-16817707,-4710778,5696513,14587125",
- "HEIGHT": "500",
- "WIDTH": "500",
- "CRS": "EPSG:3857"
- }.items())])
- url = f'{self.protocol}://{self.hostname}:{self.port}/{qs}'
+ qs = "?" + "&".join(
+ [
+ "%s=%s" % i
+ for i in list(
+ {
+ "MAP": urllib.parse.quote(self.project_path),
+ "SERVICE": "WMS",
+ "VERSION": "1.1.1",
+ "REQUEST": "GetMap",
+ "LAYERS": "testlayer_èé".replace("_", "%20"),
+ "STYLES": "",
+ "FORMAT": "image/png",
+ "BBOX": "-16817707,-4710778,5696513,14587125",
+ "HEIGHT": "500",
+ "WIDTH": "500",
+ "CRS": "EPSG:3857",
+ }.items()
+ )
+ ]
+ )
+ url = f"{self.protocol}://{self.hostname}:{self.port}/{qs}"
destination = tempfile.mktemp()
loop = QEventLoop()
downloader = QgsFileDownloader(QUrl(url), destination, None, False)
- downloader.downloadCompleted.connect(partial(self._set_slot, 'completed'))
- downloader.downloadExited.connect(partial(self._set_slot, 'exited'))
- downloader.downloadCanceled.connect(partial(self._set_slot, 'canceled'))
- downloader.downloadError.connect(partial(self._set_slot, 'error'))
- downloader.downloadProgress.connect(partial(self._set_slot, 'progress'))
+ downloader.downloadCompleted.connect(partial(self._set_slot, "completed"))
+ downloader.downloadExited.connect(partial(self._set_slot, "exited"))
+ downloader.downloadCanceled.connect(partial(self._set_slot, "canceled"))
+ downloader.downloadError.connect(partial(self._set_slot, "error"))
+ downloader.downloadProgress.connect(partial(self._set_slot, "progress"))
downloader.downloadExited.connect(loop.quit)
loop.exec()
self.assertTrue(self.error_was_called)
- self.assertIn("Download failed: Host requires authentication", str(self.error_args))
+ self.assertIn(
+ "Download failed: Host requires authentication", str(self.error_args)
+ )
def testValidAuthFileDownload(self):
"""
Download a map tile with valid authcfg
"""
- qs = "?" + "&".join(["%s=%s" % i for i in list({
- "MAP": urllib.parse.quote(self.project_path),
- "SERVICE": "WMS",
- "VERSION": "1.1.1",
- "REQUEST": "GetMap",
- "LAYERS": "testlayer_èé".replace('_', '%20'),
- "STYLES": "",
- "FORMAT": "image/png",
- "BBOX": "-16817707,-4710778,5696513,14587125",
- "HEIGHT": "500",
- "WIDTH": "500",
- "CRS": "EPSG:3857"
- }.items())])
- url = f'{self.protocol}://{self.hostname}:{self.port}/{qs}'
+ qs = "?" + "&".join(
+ [
+ "%s=%s" % i
+ for i in list(
+ {
+ "MAP": urllib.parse.quote(self.project_path),
+ "SERVICE": "WMS",
+ "VERSION": "1.1.1",
+ "REQUEST": "GetMap",
+ "LAYERS": "testlayer_èé".replace("_", "%20"),
+ "STYLES": "",
+ "FORMAT": "image/png",
+ "BBOX": "-16817707,-4710778,5696513,14587125",
+ "HEIGHT": "500",
+ "WIDTH": "500",
+ "CRS": "EPSG:3857",
+ }.items()
+ )
+ ]
+ )
+ url = f"{self.protocol}://{self.hostname}:{self.port}/{qs}"
destination = tempfile.mktemp()
loop = QEventLoop()
- downloader = QgsFileDownloader(QUrl(url), destination, self.auth_config.id(), False)
- downloader.downloadCompleted.connect(partial(self._set_slot, 'completed'))
- downloader.downloadExited.connect(partial(self._set_slot, 'exited'))
- downloader.downloadCanceled.connect(partial(self._set_slot, 'canceled'))
- downloader.downloadError.connect(partial(self._set_slot, 'error'))
- downloader.downloadProgress.connect(partial(self._set_slot, 'progress'))
+ downloader = QgsFileDownloader(
+ QUrl(url), destination, self.auth_config.id(), False
+ )
+ downloader.downloadCompleted.connect(partial(self._set_slot, "completed"))
+ downloader.downloadExited.connect(partial(self._set_slot, "exited"))
+ downloader.downloadCanceled.connect(partial(self._set_slot, "canceled"))
+ downloader.downloadError.connect(partial(self._set_slot, "error"))
+ downloader.downloadProgress.connect(partial(self._set_slot, "progress"))
downloader.downloadExited.connect(loop.quit)
@@ -270,14 +300,14 @@ def testValidAuthFileDownload(self):
# Check the we've got a likely PNG image
self.assertTrue(self.completed_was_called)
self.assertGreater(os.path.getsize(destination), 2000) # > 1MB
- with open(destination, 'rb') as f:
- self.assertTrue(b'PNG' in f.read()) # is a PNG
+ with open(destination, "rb") as f:
+ self.assertTrue(b"PNG" in f.read()) # is a PNG
def _set_slot(self, *args, **kwargs):
# print('_set_slot(%s) called' % args[0])
- setattr(self, args[0] + '_was_called', True)
- setattr(self, args[0] + '_args', args)
+ setattr(self, args[0] + "_was_called", True)
+ setattr(self, args[0] + "_args", args)
-if __name__ == '__main__':
+if __name__ == "__main__":
unittest.main()
diff --git a/tests/src/python/test_authmanager_password_postgres.py b/tests/src/python/test_authmanager_password_postgres.py
index ab27daae3104..7911b6eea333 100644
--- a/tests/src/python/test_authmanager_password_postgres.py
+++ b/tests/src/python/test_authmanager_password_postgres.py
@@ -20,6 +20,7 @@
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
"""
+
import os
from contextlib import contextmanager
@@ -36,9 +37,9 @@
from utilities import unitTestDataPath
-__author__ = 'Alessandro Pasotti'
-__date__ = '25/10/2016'
-__copyright__ = 'Copyright 2016, The QGIS Project'
+__author__ = "Alessandro Pasotti"
+__date__ = "25/10/2016"
+__copyright__ = "Copyright 2016, The QGIS Project"
qgis_app = start_app()
@@ -51,9 +52,9 @@ def ScopedCertAuthority(username, password, sslrootcert_path=None):
"""
authm = QgsApplication.authManager()
auth_config = QgsAuthMethodConfig("Basic")
- auth_config.setConfig('username', username)
- auth_config.setConfig('password', password)
- auth_config.setName('test_password_auth_config')
+ auth_config.setConfig("username", username)
+ auth_config.setConfig("password", password)
+ auth_config.setName("test_password_auth_config")
if sslrootcert_path:
sslrootcert = QSslCertificate.fromPath(sslrootcert_path)
assert sslrootcert is not None
@@ -61,7 +62,7 @@ def ScopedCertAuthority(username, password, sslrootcert_path=None):
authm.rebuildCaCertsCache()
authm.rebuildTrustedCaCertsCache()
authm.rebuildCertTrustCache()
- assert (authm.storeAuthenticationConfig(auth_config)[0])
+ assert authm.storeAuthenticationConfig(auth_config)[0]
assert auth_config.isValid()
yield auth_config
if sslrootcert_path:
@@ -79,16 +80,18 @@ def setUpClass(cls):
"""Run before all tests:
Creates an auth configuration"""
super().setUpClass()
- cls.username = 'docker'
- cls.password = 'docker'
- cls.dbname = 'qgis_test'
- cls.hostname = 'postgres'
- cls.port = '5432'
+ cls.username = "docker"
+ cls.password = "docker"
+ cls.dbname = "qgis_test"
+ cls.hostname = "postgres"
+ cls.port = "5432"
authm = QgsApplication.authManager()
- assert (authm.setMasterPassword('masterpassword', True))
- cls.certsdata_path = os.path.join(unitTestDataPath('auth_system'), 'certs_keys_2048')
- cls.sslrootcert_path = os.path.join(cls.certsdata_path, 'qgis_ca.crt')
+ assert authm.setMasterPassword("masterpassword", True)
+ cls.certsdata_path = os.path.join(
+ unitTestDataPath("auth_system"), "certs_keys_2048"
+ )
+ cls.sslrootcert_path = os.path.join(cls.certsdata_path, "qgis_ca.crt")
def setUp(self):
"""Run before each test."""
@@ -99,36 +102,46 @@ def tearDown(self):
pass
@classmethod
- def _getPostGISLayer(cls, type_name, layer_name=None, authcfg=None, sslmode=QgsDataSourceUri.SslMode.SslVerifyFull):
+ def _getPostGISLayer(
+ cls,
+ type_name,
+ layer_name=None,
+ authcfg=None,
+ sslmode=QgsDataSourceUri.SslMode.SslVerifyFull,
+ ):
"""
PG layer factory
"""
if layer_name is None:
- layer_name = 'pg_' + type_name
+ layer_name = "pg_" + type_name
uri = QgsDataSourceUri()
uri.setWkbType(QgsWkbTypes.Type.Point)
uri.setConnection(cls.hostname, cls.port, cls.dbname, "", "", sslmode, authcfg)
- uri.setKeyColumn('pk')
- uri.setSrid('EPSG:4326')
- uri.setDataSource('qgis_test', 'someData', "geom", "", "pk")
+ uri.setKeyColumn("pk")
+ uri.setSrid("EPSG:4326")
+ uri.setDataSource("qgis_test", "someData", "geom", "", "pk")
# Note: do not expand here!
- layer = QgsVectorLayer(uri.uri(False), layer_name, 'postgres')
+ layer = QgsVectorLayer(uri.uri(False), layer_name, "postgres")
return layer
def testValidAuthAccess(self):
"""
Access the protected layer with valid credentials
"""
- with ScopedCertAuthority(self.username, self.password, self.sslrootcert_path) as auth_config:
- pg_layer = self._getPostGISLayer('testlayer_èé', authcfg=auth_config.id())
+ with ScopedCertAuthority(
+ self.username, self.password, self.sslrootcert_path
+ ) as auth_config:
+ pg_layer = self._getPostGISLayer("testlayer_èé", authcfg=auth_config.id())
self.assertTrue(pg_layer.isValid())
def testInvalidAuthAccess(self):
"""
Access the protected layer with invalid credentials
"""
- with ScopedCertAuthority(self.username, self.password, self.sslrootcert_path) as auth_config:
- pg_layer = self._getPostGISLayer('testlayer_èé')
+ with ScopedCertAuthority(
+ self.username, self.password, self.sslrootcert_path
+ ) as auth_config:
+ pg_layer = self._getPostGISLayer("testlayer_èé")
self.assertFalse(pg_layer.isValid())
def testSslRequireNoCaCheck(self):
@@ -137,7 +150,11 @@ def testSslRequireNoCaCheck(self):
This should work.
"""
with ScopedCertAuthority(self.username, self.password) as auth_config:
- pg_layer = self._getPostGISLayer('testlayer_èé', authcfg=auth_config.id(), sslmode=QgsDataSourceUri.SslMode.SslRequire)
+ pg_layer = self._getPostGISLayer(
+ "testlayer_èé",
+ authcfg=auth_config.id(),
+ sslmode=QgsDataSourceUri.SslMode.SslRequire,
+ )
self.assertTrue(pg_layer.isValid())
def testSslVerifyFullCaCheck(self):
@@ -146,9 +163,9 @@ def testSslVerifyFullCaCheck(self):
This should not work.
"""
with ScopedCertAuthority(self.username, self.password) as auth_config:
- pg_layer = self._getPostGISLayer('testlayer_èé', authcfg=auth_config.id())
+ pg_layer = self._getPostGISLayer("testlayer_èé", authcfg=auth_config.id())
self.assertFalse(pg_layer.isValid())
-if __name__ == '__main__':
+if __name__ == "__main__":
unittest.main()
diff --git a/tests/src/python/test_authmanager_pki_ows.py b/tests/src/python/test_authmanager_pki_ows.py
index b2378313918e..1ec1e012fab4 100644
--- a/tests/src/python/test_authmanager_pki_ows.py
+++ b/tests/src/python/test_authmanager_pki_ows.py
@@ -14,6 +14,7 @@
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
"""
+
import os
import re
import stat
@@ -22,9 +23,9 @@
import tempfile
import urllib
-__author__ = 'Alessandro Pasotti'
-__date__ = '25/10/2016'
-__copyright__ = 'Copyright 2016, The QGIS Project'
+__author__ = "Alessandro Pasotti"
+__date__ = "25/10/2016"
+__copyright__ = "Copyright 2016, The QGIS Project"
from shutil import rmtree
@@ -40,13 +41,13 @@
from utilities import unitTestDataPath, waitServer
try:
- QGIS_SERVER_ENDPOINT_PORT = os.environ['QGIS_SERVER_ENDPOINT_PORT']
+ QGIS_SERVER_ENDPOINT_PORT = os.environ["QGIS_SERVER_ENDPOINT_PORT"]
except:
- QGIS_SERVER_ENDPOINT_PORT = '0' # Auto
+ QGIS_SERVER_ENDPOINT_PORT = "0" # Auto
QGIS_AUTH_DB_DIR_PATH = tempfile.mkdtemp()
-os.environ['QGIS_AUTH_DB_DIR_PATH'] = QGIS_AUTH_DB_DIR_PATH
+os.environ["QGIS_AUTH_DB_DIR_PATH"] = QGIS_AUTH_DB_DIR_PATH
qgis_app = start_app()
@@ -57,10 +58,10 @@ class TestAuthManager(QgisTestCase):
def setUpAuth(cls):
"""Run before all tests and set up authentication"""
authm = QgsApplication.authManager()
- assert (authm.setMasterPassword('masterpassword', True))
- cls.sslrootcert_path = os.path.join(cls.certsdata_path, 'qgis_ca.crt')
- cls.sslcert = os.path.join(cls.certsdata_path, 'Gerardus.crt')
- cls.sslkey = os.path.join(cls.certsdata_path, 'Gerardus.key')
+ assert authm.setMasterPassword("masterpassword", True)
+ cls.sslrootcert_path = os.path.join(cls.certsdata_path, "qgis_ca.crt")
+ cls.sslcert = os.path.join(cls.certsdata_path, "Gerardus.crt")
+ cls.sslkey = os.path.join(cls.certsdata_path, "Gerardus.key")
assert os.path.isfile(cls.sslcert)
assert os.path.isfile(cls.sslkey)
assert os.path.isfile(cls.sslrootcert_path)
@@ -68,31 +69,31 @@ def setUpAuth(cls):
os.chmod(cls.sslkey, stat.S_IRUSR)
os.chmod(cls.sslrootcert_path, stat.S_IRUSR)
cls.auth_config = QgsAuthMethodConfig("PKI-Paths")
- cls.auth_config.setConfig('certpath', cls.sslcert)
- cls.auth_config.setConfig('keypath', cls.sslkey)
- cls.auth_config.setName('test_pki_auth_config')
- cls.username = 'Gerardus'
+ cls.auth_config.setConfig("certpath", cls.sslcert)
+ cls.auth_config.setConfig("keypath", cls.sslkey)
+ cls.auth_config.setName("test_pki_auth_config")
+ cls.username = "Gerardus"
cls.sslrootcert = QSslCertificate.fromPath(cls.sslrootcert_path)
assert cls.sslrootcert is not None
authm.storeCertAuthorities(cls.sslrootcert)
authm.rebuildCaCertsCache()
authm.rebuildTrustedCaCertsCache()
- assert (authm.storeAuthenticationConfig(cls.auth_config)[0])
+ assert authm.storeAuthenticationConfig(cls.auth_config)[0]
assert cls.auth_config.isValid()
- cls.server_cert = os.path.join(cls.certsdata_path, '127_0_0_1.crt')
- cls.server_key = os.path.join(cls.certsdata_path, '127_0_0_1.key')
+ cls.server_cert = os.path.join(cls.certsdata_path, "127_0_0_1.crt")
+ cls.server_key = os.path.join(cls.certsdata_path, "127_0_0_1.key")
cls.server_rootcert = cls.sslrootcert_path
os.chmod(cls.server_cert, stat.S_IRUSR)
os.chmod(cls.server_key, stat.S_IRUSR)
os.chmod(cls.server_rootcert, stat.S_IRUSR)
- os.environ['QGIS_SERVER_HOST'] = cls.hostname
- os.environ['QGIS_SERVER_PORT'] = str(cls.port)
- os.environ['QGIS_SERVER_PKI_KEY'] = cls.server_key
- os.environ['QGIS_SERVER_PKI_CERTIFICATE'] = cls.server_cert
- os.environ['QGIS_SERVER_PKI_USERNAME'] = cls.username
- os.environ['QGIS_SERVER_PKI_AUTHORITY'] = cls.server_rootcert
+ os.environ["QGIS_SERVER_HOST"] = cls.hostname
+ os.environ["QGIS_SERVER_PORT"] = str(cls.port)
+ os.environ["QGIS_SERVER_PKI_KEY"] = cls.server_key
+ os.environ["QGIS_SERVER_PKI_CERTIFICATE"] = cls.server_cert
+ os.environ["QGIS_SERVER_PKI_USERNAME"] = cls.username
+ os.environ["QGIS_SERVER_PKI_AUTHORITY"] = cls.server_rootcert
@classmethod
def setUpClass(cls):
@@ -101,30 +102,36 @@ def setUpClass(cls):
super().setUpClass()
cls.port = QGIS_SERVER_ENDPOINT_PORT
# Clean env just to be sure
- env_vars = ['QUERY_STRING', 'QGIS_PROJECT_FILE']
+ env_vars = ["QUERY_STRING", "QGIS_PROJECT_FILE"]
for ev in env_vars:
try:
del os.environ[ev]
except KeyError:
pass
- cls.testdata_path = unitTestDataPath('qgis_server')
- cls.certsdata_path = os.path.join(unitTestDataPath('auth_system'), 'certs_keys_2048')
+ cls.testdata_path = unitTestDataPath("qgis_server")
+ cls.certsdata_path = os.path.join(
+ unitTestDataPath("auth_system"), "certs_keys_2048"
+ )
cls.project_path = os.path.join(cls.testdata_path, "test_project.qgs")
# cls.hostname = 'localhost'
- cls.protocol = 'https'
- cls.hostname = '127.0.0.1'
+ cls.protocol = "https"
+ cls.hostname = "127.0.0.1"
cls.setUpAuth()
- server_path = os.path.join(os.path.dirname(os.path.realpath(__file__)),
- 'qgis_wrapped_server.py')
- cls.server = subprocess.Popen([sys.executable, server_path],
- env=os.environ, stdout=subprocess.PIPE)
+ server_path = os.path.join(
+ os.path.dirname(os.path.realpath(__file__)), "qgis_wrapped_server.py"
+ )
+ cls.server = subprocess.Popen(
+ [sys.executable, server_path], env=os.environ, stdout=subprocess.PIPE
+ )
line = cls.server.stdout.readline()
- cls.port = int(re.findall(br':(\d+)', line)[0])
+ cls.port = int(re.findall(rb":(\d+)", line)[0])
assert cls.port != 0
# Wait for the server process to start
- assert waitServer(f'{cls.protocol}://{cls.hostname}:{cls.port}'), f"Server is not responding! {cls.protocol}://{cls.hostname}:{cls.port}"
+ assert waitServer(
+ f"{cls.protocol}://{cls.hostname}:{cls.port}"
+ ), f"Server is not responding! {cls.protocol}://{cls.hostname}:{cls.port}"
@classmethod
def tearDownClass(cls):
@@ -148,18 +155,18 @@ def _getWFSLayer(cls, type_name, layer_name=None, authcfg=None):
WFS layer factory
"""
if layer_name is None:
- layer_name = 'wfs_' + type_name
+ layer_name = "wfs_" + type_name
parms = {
- 'srsname': 'EPSG:4326',
- 'typename': type_name,
- 'url': f'{cls.protocol}://{cls.hostname}:{cls.port}/?map={cls.project_path}',
- 'version': 'auto',
- 'table': '',
+ "srsname": "EPSG:4326",
+ "typename": type_name,
+ "url": f"{cls.protocol}://{cls.hostname}:{cls.port}/?map={cls.project_path}",
+ "version": "auto",
+ "table": "",
}
if authcfg is not None:
- parms.update({'authcfg': authcfg})
- uri = ' '.join([(f"{k}='{v}'") for k, v in list(parms.items())])
- wfs_layer = QgsVectorLayer(uri, layer_name, 'WFS')
+ parms.update({"authcfg": authcfg})
+ uri = " ".join([(f"{k}='{v}'") for k, v in list(parms.items())])
+ wfs_layer = QgsVectorLayer(uri, layer_name, "WFS")
return wfs_layer
@classmethod
@@ -168,22 +175,22 @@ def _getWMSLayer(cls, layers, layer_name=None, authcfg=None):
WMS layer factory
"""
if layer_name is None:
- layer_name = 'wms_' + layers.replace(',', '')
+ layer_name = "wms_" + layers.replace(",", "")
parms = {
- 'crs': 'EPSG:4326',
- 'url': f'{cls.protocol}://{cls.hostname}:{cls.port}/?map={cls.project_path}',
- 'format': 'image/png',
+ "crs": "EPSG:4326",
+ "url": f"{cls.protocol}://{cls.hostname}:{cls.port}/?map={cls.project_path}",
+ "format": "image/png",
# This is needed because of a really weird implementation in QGIS Server, that
# replaces _ in the the real layer name with spaces
- 'layers': urllib.parse.quote(layers.replace('_', ' ')),
- 'styles': '',
- 'version': 'auto',
+ "layers": urllib.parse.quote(layers.replace("_", " ")),
+ "styles": "",
+ "version": "auto",
# 'sql': '',
}
if authcfg is not None:
- parms.update({'authcfg': authcfg})
- uri = '&'.join([f"{k}={v.replace('=', '%3D')}" for k, v in list(parms.items())])
- wms_layer = QgsRasterLayer(uri, layer_name, 'wms')
+ parms.update({"authcfg": authcfg})
+ uri = "&".join([f"{k}={v.replace('=', '%3D')}" for k, v in list(parms.items())])
+ wms_layer = QgsRasterLayer(uri, layer_name, "wms")
return wms_layer
def testValidAuthAccess(self):
@@ -192,11 +199,11 @@ def testValidAuthAccess(self):
Note: cannot test invalid access in a separate test because
it would fail the subsequent (valid) calls due to cached connections
"""
- wfs_layer = self._getWFSLayer('testlayer_èé', authcfg=self.auth_config.id())
+ wfs_layer = self._getWFSLayer("testlayer_èé", authcfg=self.auth_config.id())
self.assertTrue(wfs_layer.isValid())
- wms_layer = self._getWMSLayer('testlayer_èé', authcfg=self.auth_config.id())
+ wms_layer = self._getWMSLayer("testlayer_èé", authcfg=self.auth_config.id())
self.assertTrue(wms_layer.isValid())
-if __name__ == '__main__':
+if __name__ == "__main__":
unittest.main()
diff --git a/tests/src/python/test_authmanager_pki_postgres.py b/tests/src/python/test_authmanager_pki_postgres.py
index 3ab2b6a47b01..2928a9206482 100644
--- a/tests/src/python/test_authmanager_pki_postgres.py
+++ b/tests/src/python/test_authmanager_pki_postgres.py
@@ -20,6 +20,7 @@
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
"""
+
import glob
import os
import stat
@@ -39,9 +40,9 @@
from utilities import unitTestDataPath
-__author__ = 'Alessandro Pasotti'
-__date__ = '25/10/2016'
-__copyright__ = 'Copyright 2016, The QGIS Project'
+__author__ = "Alessandro Pasotti"
+__date__ = "25/10/2016"
+__copyright__ = "Copyright 2016, The QGIS Project"
qgis_app = start_app()
@@ -52,11 +53,11 @@ class TestAuthManager(QgisTestCase):
def setUpAuth(cls):
"""Run before all tests and set up authentication"""
authm = QgsApplication.authManager()
- assert (authm.setMasterPassword('masterpassword', True))
+ assert authm.setMasterPassword("masterpassword", True)
# Client side
- cls.sslrootcert_path = os.path.join(cls.certsdata_path, 'qgis_ca.crt')
- cls.sslcert = os.path.join(cls.certsdata_path, 'docker.crt')
- cls.sslkey = os.path.join(cls.certsdata_path, 'docker.key')
+ cls.sslrootcert_path = os.path.join(cls.certsdata_path, "qgis_ca.crt")
+ cls.sslcert = os.path.join(cls.certsdata_path, "docker.crt")
+ cls.sslkey = os.path.join(cls.certsdata_path, "docker.key")
assert os.path.isfile(cls.sslcert)
assert os.path.isfile(cls.sslkey)
assert os.path.isfile(cls.sslrootcert_path)
@@ -64,21 +65,21 @@ def setUpAuth(cls):
os.chmod(cls.sslkey, stat.S_IRUSR)
os.chmod(cls.sslrootcert_path, stat.S_IRUSR)
cls.auth_config = QgsAuthMethodConfig("PKI-Paths")
- cls.auth_config.setConfig('certpath', cls.sslcert)
- cls.auth_config.setConfig('keypath', cls.sslkey)
- cls.auth_config.setName('test_pki_auth_config')
- cls.pg_user = 'docker'
- cls.pg_pass = 'docker'
- cls.pg_host = 'postgres'
- cls.pg_port = '5432'
- cls.pg_dbname = 'qgis_test'
+ cls.auth_config.setConfig("certpath", cls.sslcert)
+ cls.auth_config.setConfig("keypath", cls.sslkey)
+ cls.auth_config.setName("test_pki_auth_config")
+ cls.pg_user = "docker"
+ cls.pg_pass = "docker"
+ cls.pg_host = "postgres"
+ cls.pg_port = "5432"
+ cls.pg_dbname = "qgis_test"
cls.sslrootcert = QSslCertificate.fromPath(cls.sslrootcert_path)
assert cls.sslrootcert is not None
authm.storeCertAuthorities(cls.sslrootcert)
authm.rebuildCaCertsCache()
authm.rebuildTrustedCaCertsCache()
authm.rebuildCertTrustCache()
- assert (authm.storeAuthenticationConfig(cls.auth_config)[0])
+ assert authm.storeAuthenticationConfig(cls.auth_config)[0]
assert cls.auth_config.isValid()
@classmethod
@@ -87,7 +88,9 @@ def setUpClass(cls):
Creates an auth configuration"""
super().setUpClass()
- cls.certsdata_path = os.path.join(unitTestDataPath('auth_system'), 'certs_keys_2048')
+ cls.certsdata_path = os.path.join(
+ unitTestDataPath("auth_system"), "certs_keys_2048"
+ )
cls.setUpAuth()
def setUp(self):
@@ -104,29 +107,37 @@ def _getPostGISLayer(cls, type_name, layer_name=None, authcfg=None):
PG layer factory
"""
if layer_name is None:
- layer_name = 'pg_' + type_name
+ layer_name = "pg_" + type_name
uri = QgsDataSourceUri()
uri.setWkbType(QgsWkbTypes.Type.Point)
- uri.setConnection(cls.pg_host, cls.pg_port, cls.pg_dbname, cls.pg_user, cls.pg_pass, QgsDataSourceUri.SslMode.SslVerifyFull, authcfg)
- uri.setKeyColumn('pk')
- uri.setSrid('EPSG:4326')
- uri.setDataSource('qgis_test', 'someData', "geom", "", "pk")
+ uri.setConnection(
+ cls.pg_host,
+ cls.pg_port,
+ cls.pg_dbname,
+ cls.pg_user,
+ cls.pg_pass,
+ QgsDataSourceUri.SslMode.SslVerifyFull,
+ authcfg,
+ )
+ uri.setKeyColumn("pk")
+ uri.setSrid("EPSG:4326")
+ uri.setDataSource("qgis_test", "someData", "geom", "", "pk")
# Note: do not expand here!
- layer = QgsVectorLayer(uri.uri(False), layer_name, 'postgres')
+ layer = QgsVectorLayer(uri.uri(False), layer_name, "postgres")
return layer
def testValidAuthAccess(self):
"""
Access the protected layer with valid credentials
"""
- pg_layer = self._getPostGISLayer('testlayer_èé', authcfg=self.auth_config.id())
+ pg_layer = self._getPostGISLayer("testlayer_èé", authcfg=self.auth_config.id())
self.assertTrue(pg_layer.isValid())
def testInvalidAuthAccess(self):
"""
Access the protected layer with not valid credentials
"""
- pg_layer = self._getPostGISLayer('testlayer_èé')
+ pg_layer = self._getPostGISLayer("testlayer_èé")
self.assertFalse(pg_layer.isValid())
def testRemoveTemporaryCerts(self):
@@ -136,7 +147,7 @@ def testRemoveTemporaryCerts(self):
"""
def cleanTempPki():
- pkies = glob.glob(os.path.join(tempfile.gettempdir(), 'tmp*_{*}.pem'))
+ pkies = glob.glob(os.path.join(tempfile.gettempdir(), "tmp*_{*}.pem"))
for fn in pkies:
f = QFile(fn)
f.setPermissions(QFile.Permission.WriteOwner)
@@ -146,12 +157,12 @@ def cleanTempPki():
# other pki remain after connection
cleanTempPki()
# connect using postgres provider
- pg_layer = self._getPostGISLayer('testlayer_èé', authcfg=self.auth_config.id())
+ pg_layer = self._getPostGISLayer("testlayer_èé", authcfg=self.auth_config.id())
self.assertTrue(pg_layer.isValid())
# do test no certs remained
- pkies = glob.glob(os.path.join(tempfile.gettempdir(), 'tmp*_{*}.pem'))
+ pkies = glob.glob(os.path.join(tempfile.gettempdir(), "tmp*_{*}.pem"))
self.assertEqual(len(pkies), 0)
-if __name__ == '__main__':
+if __name__ == "__main__":
unittest.main()
diff --git a/tests/src/python/test_authmanager_proxy.py b/tests/src/python/test_authmanager_proxy.py
index ee87283ab12c..90efff340c13 100644
--- a/tests/src/python/test_authmanager_proxy.py
+++ b/tests/src/python/test_authmanager_proxy.py
@@ -9,6 +9,7 @@
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
"""
+
import os
import random
import string
@@ -24,13 +25,13 @@
import unittest
from qgis.testing import start_app, QgisTestCase
-__author__ = 'Alessandro Pasotti'
-__date__ = '27/09/2017'
-__copyright__ = 'Copyright 2017, The QGIS Project'
+__author__ = "Alessandro Pasotti"
+__date__ = "27/09/2017"
+__copyright__ = "Copyright 2017, The QGIS Project"
QGIS_AUTH_DB_DIR_PATH = tempfile.mkdtemp()
-os.environ['QGIS_AUTH_DB_DIR_PATH'] = QGIS_AUTH_DB_DIR_PATH
+os.environ["QGIS_AUTH_DB_DIR_PATH"] = QGIS_AUTH_DB_DIR_PATH
qgis_app = start_app()
@@ -45,14 +46,16 @@ def setUpClass(cls):
# Enable auth
# os.environ['QGIS_AUTH_PASSWORD_FILE'] = QGIS_AUTH_PASSWORD_FILE
authm = QgsApplication.authManager()
- assert (authm.setMasterPassword('masterpassword', True))
- cls.auth_config = QgsAuthMethodConfig('Basic')
- cls.auth_config.setName('test_auth_config')
- cls.username = ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(6))
+ assert authm.setMasterPassword("masterpassword", True)
+ cls.auth_config = QgsAuthMethodConfig("Basic")
+ cls.auth_config.setName("test_auth_config")
+ cls.username = "".join(
+ random.choice(string.ascii_uppercase + string.digits) for _ in range(6)
+ )
cls.password = cls.username[::-1] # reversed
- cls.auth_config.setConfig('username', cls.username)
- cls.auth_config.setConfig('password', cls.password)
- assert (authm.storeAuthenticationConfig(cls.auth_config)[0])
+ cls.auth_config.setConfig("username", cls.username)
+ cls.auth_config.setConfig("password", cls.password)
+ assert authm.storeAuthenticationConfig(cls.auth_config)[0]
@classmethod
def tearDownClass(cls):
@@ -75,8 +78,8 @@ def testProxyIsUpdated(self):
authm = QgsApplication.authManager()
nam = QgsNetworkAccessManager.instance()
proxy = nam.proxy()
- self.assertEqual(proxy.password(), '')
- self.assertEqual(proxy.user(), '')
+ self.assertEqual(proxy.password(), "")
+ self.assertEqual(proxy.user(), "")
self.assertTrue(authm.updateNetworkProxy(proxy, self.auth_config.id()))
self.assertEqual(proxy.user(), self.username)
self.assertEqual(proxy.password(), self.password)
@@ -88,17 +91,17 @@ def testProxyIsUpdatedByUserSettings(self):
nam = QgsNetworkAccessManager.instance()
nam.setupDefaultProxyAndCache()
proxy = nam.proxy()
- self.assertEqual(proxy.password(), '')
- self.assertEqual(proxy.user(), '')
+ self.assertEqual(proxy.password(), "")
+ self.assertEqual(proxy.user(), "")
settings = QgsSettings()
settings.setValue("proxy/authcfg", self.auth_config.id())
settings.setValue("proxy/proxyEnabled", True)
- del (settings)
+ del settings
nam.setupDefaultProxyAndCache()
proxy = nam.fallbackProxy()
self.assertEqual(proxy.password(), self.password)
self.assertEqual(proxy.user(), self.username)
-if __name__ == '__main__':
+if __name__ == "__main__":
unittest.main()
diff --git a/tests/src/python/test_authmanager_storage_base.py b/tests/src/python/test_authmanager_storage_base.py
index fdf3aae4e718..94cb07a09cc6 100644
--- a/tests/src/python/test_authmanager_storage_base.py
+++ b/tests/src/python/test_authmanager_storage_base.py
@@ -26,9 +26,9 @@
from qgis.testing import start_app, QgisTestCase
from utilities import unitTestDataPath
-__author__ = 'Alessandro Pasotti'
-__date__ = '2024-06-24'
-__copyright__ = 'Copyright 2024, The QGIS Project'
+__author__ = "Alessandro Pasotti"
+__date__ = "2024-06-24"
+__copyright__ = "Copyright 2024, The QGIS Project"
class AuthManagerStorageBaseTestCase(QgisTestCase):
@@ -44,7 +44,7 @@ def setUpClass(cls):
super().setUpClass()
if cls.storage_uri is not None:
- os.environ['QGIS_AUTH_DB_URI'] = cls.storage_uri
+ os.environ["QGIS_AUTH_DB_URI"] = cls.storage_uri
QCoreApplication.setOrganizationName("QGIS_Test")
QCoreApplication.setOrganizationDomain("%s.com" % __name__)
@@ -52,23 +52,32 @@ def setUpClass(cls):
QgsSettings().clear()
start_app()
- cls.certdata_path = os.path.join(unitTestDataPath('auth_system'), 'certs_keys_2048')
+ cls.certdata_path = os.path.join(
+ unitTestDataPath("auth_system"), "certs_keys_2048"
+ )
-class TestAuthManagerStorageBase():
+class TestAuthManagerStorageBase:
def testInitialized(self):
assert self.storage is not None
self.assertTrue(self.storage.initialize())
if issubclass(type(self.storage), QgsAuthConfigurationStorageDb):
- for table in ['auth_authorities', 'auth_identities', 'auth_servers', 'auth_settings', 'auth_trust', 'auth_configs']:
+ for table in [
+ "auth_authorities",
+ "auth_identities",
+ "auth_servers",
+ "auth_settings",
+ "auth_trust",
+ "auth_configs",
+ ]:
self.assertTrue(self.storage.tableExists(table))
def testDefaultStorage(self):
if self.storage_uri is None:
- raise unittest.SkipTest('No storage URI defined')
+ raise unittest.SkipTest("No storage URI defined")
auth_manager = QgsApplication.authManager()
auth_manager.ensureInitialized()
@@ -79,75 +88,289 @@ def testDefaultStorage(self):
# Verify that the registry has the storage
registry = QgsApplication.authConfigurationStorageRegistry()
storage = registry.readyStorages()[0]
- self.assertEqual(storage.settings()['database'], self.storage.settings()['database'])
- self.assertEqual(storage.settings()['driver'], self.storage.settings()['driver'])
+ self.assertEqual(
+ storage.settings()["database"], self.storage.settings()["database"]
+ )
+ self.assertEqual(
+ storage.settings()["driver"], self.storage.settings()["driver"]
+ )
def _assert_readonly(self, storage):
self.assertTrue(storage.isReadOnly())
- self.assertTrue(bool(storage.capabilities() & Qgis.AuthConfigurationStorageCapability.ReadConfiguration))
- self.assertFalse(bool(storage.capabilities() & Qgis.AuthConfigurationStorageCapability.DeleteConfiguration))
- self.assertFalse(bool(storage.capabilities() & Qgis.AuthConfigurationStorageCapability.UpdateConfiguration))
- self.assertFalse(bool(storage.capabilities() & Qgis.AuthConfigurationStorageCapability.CreateConfiguration))
-
- self.assertTrue(bool(storage.capabilities() & Qgis.AuthConfigurationStorageCapability.ReadSetting))
- self.assertFalse(bool(storage.capabilities() & Qgis.AuthConfigurationStorageCapability.DeleteSetting))
- self.assertFalse(bool(storage.capabilities() & Qgis.AuthConfigurationStorageCapability.UpdateSetting))
- self.assertFalse(bool(storage.capabilities() & Qgis.AuthConfigurationStorageCapability.CreateSetting))
-
- self.assertTrue(bool(storage.capabilities() & Qgis.AuthConfigurationStorageCapability.ReadCertificateIdentity))
- self.assertFalse(bool(storage.capabilities() & Qgis.AuthConfigurationStorageCapability.DeleteCertificateIdentity))
- self.assertFalse(bool(storage.capabilities() & Qgis.AuthConfigurationStorageCapability.UpdateCertificateIdentity))
- self.assertFalse(bool(storage.capabilities() & Qgis.AuthConfigurationStorageCapability.CreateCertificateIdentity))
-
- self.assertTrue(bool(storage.capabilities() & Qgis.AuthConfigurationStorageCapability.ReadSslCertificateCustomConfig))
- self.assertFalse(bool(storage.capabilities() & Qgis.AuthConfigurationStorageCapability.DeleteSslCertificateCustomConfig))
- self.assertFalse(bool(storage.capabilities() & Qgis.AuthConfigurationStorageCapability.UpdateSslCertificateCustomConfig))
- self.assertFalse(bool(storage.capabilities() & Qgis.AuthConfigurationStorageCapability.CreateSslCertificateCustomConfig))
-
- self.assertTrue(bool(storage.capabilities() & Qgis.AuthConfigurationStorageCapability.ReadCertificateTrustPolicy))
- self.assertFalse(bool(storage.capabilities() & Qgis.AuthConfigurationStorageCapability.DeleteCertificateTrustPolicy))
- self.assertFalse(bool(storage.capabilities() & Qgis.AuthConfigurationStorageCapability.UpdateCertificateTrustPolicy))
- self.assertFalse(bool(storage.capabilities() & Qgis.AuthConfigurationStorageCapability.CreateCertificateTrustPolicy))
-
- self.assertFalse(bool(storage.capabilities() & Qgis.AuthConfigurationStorageCapability.ClearStorage))
+ self.assertTrue(
+ bool(
+ storage.capabilities()
+ & Qgis.AuthConfigurationStorageCapability.ReadConfiguration
+ )
+ )
+ self.assertFalse(
+ bool(
+ storage.capabilities()
+ & Qgis.AuthConfigurationStorageCapability.DeleteConfiguration
+ )
+ )
+ self.assertFalse(
+ bool(
+ storage.capabilities()
+ & Qgis.AuthConfigurationStorageCapability.UpdateConfiguration
+ )
+ )
+ self.assertFalse(
+ bool(
+ storage.capabilities()
+ & Qgis.AuthConfigurationStorageCapability.CreateConfiguration
+ )
+ )
+
+ self.assertTrue(
+ bool(
+ storage.capabilities()
+ & Qgis.AuthConfigurationStorageCapability.ReadSetting
+ )
+ )
+ self.assertFalse(
+ bool(
+ storage.capabilities()
+ & Qgis.AuthConfigurationStorageCapability.DeleteSetting
+ )
+ )
+ self.assertFalse(
+ bool(
+ storage.capabilities()
+ & Qgis.AuthConfigurationStorageCapability.UpdateSetting
+ )
+ )
+ self.assertFalse(
+ bool(
+ storage.capabilities()
+ & Qgis.AuthConfigurationStorageCapability.CreateSetting
+ )
+ )
+
+ self.assertTrue(
+ bool(
+ storage.capabilities()
+ & Qgis.AuthConfigurationStorageCapability.ReadCertificateIdentity
+ )
+ )
+ self.assertFalse(
+ bool(
+ storage.capabilities()
+ & Qgis.AuthConfigurationStorageCapability.DeleteCertificateIdentity
+ )
+ )
+ self.assertFalse(
+ bool(
+ storage.capabilities()
+ & Qgis.AuthConfigurationStorageCapability.UpdateCertificateIdentity
+ )
+ )
+ self.assertFalse(
+ bool(
+ storage.capabilities()
+ & Qgis.AuthConfigurationStorageCapability.CreateCertificateIdentity
+ )
+ )
+
+ self.assertTrue(
+ bool(
+ storage.capabilities()
+ & Qgis.AuthConfigurationStorageCapability.ReadSslCertificateCustomConfig
+ )
+ )
+ self.assertFalse(
+ bool(
+ storage.capabilities()
+ & Qgis.AuthConfigurationStorageCapability.DeleteSslCertificateCustomConfig
+ )
+ )
+ self.assertFalse(
+ bool(
+ storage.capabilities()
+ & Qgis.AuthConfigurationStorageCapability.UpdateSslCertificateCustomConfig
+ )
+ )
+ self.assertFalse(
+ bool(
+ storage.capabilities()
+ & Qgis.AuthConfigurationStorageCapability.CreateSslCertificateCustomConfig
+ )
+ )
+
+ self.assertTrue(
+ bool(
+ storage.capabilities()
+ & Qgis.AuthConfigurationStorageCapability.ReadCertificateTrustPolicy
+ )
+ )
+ self.assertFalse(
+ bool(
+ storage.capabilities()
+ & Qgis.AuthConfigurationStorageCapability.DeleteCertificateTrustPolicy
+ )
+ )
+ self.assertFalse(
+ bool(
+ storage.capabilities()
+ & Qgis.AuthConfigurationStorageCapability.UpdateCertificateTrustPolicy
+ )
+ )
+ self.assertFalse(
+ bool(
+ storage.capabilities()
+ & Qgis.AuthConfigurationStorageCapability.CreateCertificateTrustPolicy
+ )
+ )
+
+ self.assertFalse(
+ bool(
+ storage.capabilities()
+ & Qgis.AuthConfigurationStorageCapability.ClearStorage
+ )
+ )
# Checks that calling a RO method raises an QgsNotSupportedException
with self.assertRaises(QgsNotSupportedException):
config = QgsAuthMethodConfig()
- storage.storeMethodConfig(config, 'test')
+ storage.storeMethodConfig(config, "test")
def _assert_readwrite(self, storage):
self.assertFalse(storage.isReadOnly())
- self.assertTrue(bool(storage.capabilities() & Qgis.AuthConfigurationStorageCapability.ReadConfiguration))
- self.assertTrue(bool(storage.capabilities() & Qgis.AuthConfigurationStorageCapability.DeleteConfiguration))
- self.assertTrue(bool(storage.capabilities() & Qgis.AuthConfigurationStorageCapability.UpdateConfiguration))
- self.assertTrue(bool(storage.capabilities() & Qgis.AuthConfigurationStorageCapability.CreateConfiguration))
-
- self.assertTrue(bool(storage.capabilities() & Qgis.AuthConfigurationStorageCapability.ReadSetting))
- self.assertTrue(bool(storage.capabilities() & Qgis.AuthConfigurationStorageCapability.DeleteSetting))
- self.assertTrue(bool(storage.capabilities() & Qgis.AuthConfigurationStorageCapability.UpdateSetting))
- self.assertTrue(bool(storage.capabilities() & Qgis.AuthConfigurationStorageCapability.CreateSetting))
-
- self.assertTrue(bool(storage.capabilities() & Qgis.AuthConfigurationStorageCapability.ReadCertificateIdentity))
- self.assertTrue(bool(storage.capabilities() & Qgis.AuthConfigurationStorageCapability.DeleteCertificateIdentity))
- self.assertTrue(bool(storage.capabilities() & Qgis.AuthConfigurationStorageCapability.UpdateCertificateIdentity))
- self.assertTrue(bool(storage.capabilities() & Qgis.AuthConfigurationStorageCapability.CreateCertificateIdentity))
-
- self.assertTrue(bool(storage.capabilities() & Qgis.AuthConfigurationStorageCapability.ReadSslCertificateCustomConfig))
- self.assertTrue(bool(storage.capabilities() & Qgis.AuthConfigurationStorageCapability.DeleteSslCertificateCustomConfig))
- self.assertTrue(bool(storage.capabilities() & Qgis.AuthConfigurationStorageCapability.UpdateSslCertificateCustomConfig))
- self.assertTrue(bool(storage.capabilities() & Qgis.AuthConfigurationStorageCapability.CreateSslCertificateCustomConfig))
-
- self.assertTrue(bool(storage.capabilities() & Qgis.AuthConfigurationStorageCapability.ReadCertificateTrustPolicy))
- self.assertTrue(bool(storage.capabilities() & Qgis.AuthConfigurationStorageCapability.DeleteCertificateTrustPolicy))
- self.assertTrue(bool(storage.capabilities() & Qgis.AuthConfigurationStorageCapability.UpdateCertificateTrustPolicy))
- self.assertTrue(bool(storage.capabilities() & Qgis.AuthConfigurationStorageCapability.CreateCertificateTrustPolicy))
-
- self.assertTrue(bool(storage.capabilities() & Qgis.AuthConfigurationStorageCapability.ClearStorage))
+ self.assertTrue(
+ bool(
+ storage.capabilities()
+ & Qgis.AuthConfigurationStorageCapability.ReadConfiguration
+ )
+ )
+ self.assertTrue(
+ bool(
+ storage.capabilities()
+ & Qgis.AuthConfigurationStorageCapability.DeleteConfiguration
+ )
+ )
+ self.assertTrue(
+ bool(
+ storage.capabilities()
+ & Qgis.AuthConfigurationStorageCapability.UpdateConfiguration
+ )
+ )
+ self.assertTrue(
+ bool(
+ storage.capabilities()
+ & Qgis.AuthConfigurationStorageCapability.CreateConfiguration
+ )
+ )
+
+ self.assertTrue(
+ bool(
+ storage.capabilities()
+ & Qgis.AuthConfigurationStorageCapability.ReadSetting
+ )
+ )
+ self.assertTrue(
+ bool(
+ storage.capabilities()
+ & Qgis.AuthConfigurationStorageCapability.DeleteSetting
+ )
+ )
+ self.assertTrue(
+ bool(
+ storage.capabilities()
+ & Qgis.AuthConfigurationStorageCapability.UpdateSetting
+ )
+ )
+ self.assertTrue(
+ bool(
+ storage.capabilities()
+ & Qgis.AuthConfigurationStorageCapability.CreateSetting
+ )
+ )
+
+ self.assertTrue(
+ bool(
+ storage.capabilities()
+ & Qgis.AuthConfigurationStorageCapability.ReadCertificateIdentity
+ )
+ )
+ self.assertTrue(
+ bool(
+ storage.capabilities()
+ & Qgis.AuthConfigurationStorageCapability.DeleteCertificateIdentity
+ )
+ )
+ self.assertTrue(
+ bool(
+ storage.capabilities()
+ & Qgis.AuthConfigurationStorageCapability.UpdateCertificateIdentity
+ )
+ )
+ self.assertTrue(
+ bool(
+ storage.capabilities()
+ & Qgis.AuthConfigurationStorageCapability.CreateCertificateIdentity
+ )
+ )
+
+ self.assertTrue(
+ bool(
+ storage.capabilities()
+ & Qgis.AuthConfigurationStorageCapability.ReadSslCertificateCustomConfig
+ )
+ )
+ self.assertTrue(
+ bool(
+ storage.capabilities()
+ & Qgis.AuthConfigurationStorageCapability.DeleteSslCertificateCustomConfig
+ )
+ )
+ self.assertTrue(
+ bool(
+ storage.capabilities()
+ & Qgis.AuthConfigurationStorageCapability.UpdateSslCertificateCustomConfig
+ )
+ )
+ self.assertTrue(
+ bool(
+ storage.capabilities()
+ & Qgis.AuthConfigurationStorageCapability.CreateSslCertificateCustomConfig
+ )
+ )
+
+ self.assertTrue(
+ bool(
+ storage.capabilities()
+ & Qgis.AuthConfigurationStorageCapability.ReadCertificateTrustPolicy
+ )
+ )
+ self.assertTrue(
+ bool(
+ storage.capabilities()
+ & Qgis.AuthConfigurationStorageCapability.DeleteCertificateTrustPolicy
+ )
+ )
+ self.assertTrue(
+ bool(
+ storage.capabilities()
+ & Qgis.AuthConfigurationStorageCapability.UpdateCertificateTrustPolicy
+ )
+ )
+ self.assertTrue(
+ bool(
+ storage.capabilities()
+ & Qgis.AuthConfigurationStorageCapability.CreateCertificateTrustPolicy
+ )
+ )
+
+ self.assertTrue(
+ bool(
+ storage.capabilities()
+ & Qgis.AuthConfigurationStorageCapability.ClearStorage
+ )
+ )
def testAuthStoragePermissions(self):
"""Checks that the auth manager default DB storage permissions are set correctly"""
@@ -172,82 +395,110 @@ def testAuthConfigs(self):
self.assertTrue(self.storage.initialize(), self.storage.lastError())
- if not bool(self.storage.capabilities() & Qgis.AuthConfigurationStorageCapability.ReadConfiguration):
- raise unittest.SkipTest('Storage does not support reading configurations')
-
- self.assertTrue(bool(self.storage.capabilities() & Qgis.AuthConfigurationStorageCapability.ReadConfiguration))
- self.assertTrue(bool(self.storage.capabilities() & Qgis.AuthConfigurationStorageCapability.DeleteConfiguration))
- self.assertTrue(bool(self.storage.capabilities() & Qgis.AuthConfigurationStorageCapability.UpdateConfiguration))
- self.assertTrue(bool(self.storage.capabilities() & Qgis.AuthConfigurationStorageCapability.CreateConfiguration))
- self.assertTrue(bool(self.storage.capabilities() & Qgis.AuthConfigurationStorageCapability.ClearStorage))
+ if not bool(
+ self.storage.capabilities()
+ & Qgis.AuthConfigurationStorageCapability.ReadConfiguration
+ ):
+ raise unittest.SkipTest("Storage does not support reading configurations")
+
+ self.assertTrue(
+ bool(
+ self.storage.capabilities()
+ & Qgis.AuthConfigurationStorageCapability.ReadConfiguration
+ )
+ )
+ self.assertTrue(
+ bool(
+ self.storage.capabilities()
+ & Qgis.AuthConfigurationStorageCapability.DeleteConfiguration
+ )
+ )
+ self.assertTrue(
+ bool(
+ self.storage.capabilities()
+ & Qgis.AuthConfigurationStorageCapability.UpdateConfiguration
+ )
+ )
+ self.assertTrue(
+ bool(
+ self.storage.capabilities()
+ & Qgis.AuthConfigurationStorageCapability.CreateConfiguration
+ )
+ )
+ self.assertTrue(
+ bool(
+ self.storage.capabilities()
+ & Qgis.AuthConfigurationStorageCapability.ClearStorage
+ )
+ )
# Create a configuration
config = QgsAuthMethodConfig()
- config.setId('test')
- config.setName('test name')
- config.setMethod('basic')
- config.setConfig('username', 'test user')
- config.setConfig('password', 'test pass')
- config.setConfig('realm', 'test realm')
+ config.setId("test")
+ config.setName("test name")
+ config.setMethod("basic")
+ config.setConfig("username", "test user")
+ config.setConfig("password", "test pass")
+ config.setConfig("realm", "test realm")
payload = config.configString()
self.assertTrue(self.storage.storeMethodConfig(config, payload))
# Create another configuration
config2 = QgsAuthMethodConfig()
- config2.setId('test2')
- config2.setName('test name 2')
- config2.setMethod('basic')
- config2.setConfig('username', 'test user 2')
- config2.setConfig('password', 'test pass 2')
- config2.setConfig('realm', 'test realm 2')
+ config2.setId("test2")
+ config2.setName("test name 2")
+ config2.setMethod("basic")
+ config2.setConfig("username", "test user 2")
+ config2.setConfig("password", "test pass 2")
+ config2.setConfig("realm", "test realm 2")
payload2 = config2.configString()
self.assertTrue(self.storage.storeMethodConfig(config2, payload2))
# Test exists
- self.assertTrue(self.storage.methodConfigExists('test'))
- self.assertFalse(self.storage.methodConfigExists('xxxx'))
+ self.assertTrue(self.storage.methodConfigExists("test"))
+ self.assertFalse(self.storage.methodConfigExists("xxxx"))
# Read it back
- configback, payloadback = self.storage.loadMethodConfig('test', True)
+ configback, payloadback = self.storage.loadMethodConfig("test", True)
configback.loadConfigString(payloadback)
- self.assertEqual(configback.id(), 'test')
- self.assertEqual(configback.name(), 'test name')
- self.assertEqual(configback.method(), 'basic')
- self.assertEqual(configback.config('username'), 'test user')
- self.assertEqual(configback.config('password'), 'test pass')
- self.assertEqual(configback.config('realm'), 'test realm')
+ self.assertEqual(configback.id(), "test")
+ self.assertEqual(configback.name(), "test name")
+ self.assertEqual(configback.method(), "basic")
+ self.assertEqual(configback.config("username"), "test user")
+ self.assertEqual(configback.config("password"), "test pass")
+ self.assertEqual(configback.config("realm"), "test realm")
self.assertEqual(payloadback, payload)
- configback, payloadback = self.storage.loadMethodConfig('test', False)
- self.assertEqual(payloadback, '')
- self.assertEqual(configback.id(), 'test')
- self.assertEqual(configback.name(), 'test name')
- self.assertEqual(configback.method(), 'basic')
- self.assertEqual(configback.config('username'), '')
- self.assertEqual(configback.config('password'), '')
- self.assertEqual(configback.config('realm'), '')
+ configback, payloadback = self.storage.loadMethodConfig("test", False)
+ self.assertEqual(payloadback, "")
+ self.assertEqual(configback.id(), "test")
+ self.assertEqual(configback.name(), "test name")
+ self.assertEqual(configback.method(), "basic")
+ self.assertEqual(configback.config("username"), "")
+ self.assertEqual(configback.config("password"), "")
+ self.assertEqual(configback.config("realm"), "")
- configs = self.storage.authMethodConfigs(['xxxx'])
+ configs = self.storage.authMethodConfigs(["xxxx"])
self.assertEqual(len(configs), 0)
- configs = self.storage.authMethodConfigs(['basic'])
+ configs = self.storage.authMethodConfigs(["basic"])
self.assertEqual(len(configs), 2)
configs = self.storage.authMethodConfigsWithPayload()
- configback = configs['test']
- payloadback = configback.config('encrypted_payload')
+ configback = configs["test"]
+ payloadback = configback.config("encrypted_payload")
configback.loadConfigString(payloadback)
- self.assertEqual(configback.id(), 'test')
- self.assertEqual(configback.name(), 'test name')
- self.assertEqual(configback.method(), 'basic')
- self.assertEqual(configback.config('username'), 'test user')
- self.assertEqual(configback.config('password'), 'test pass')
- self.assertEqual(configback.config('realm'), 'test realm')
+ self.assertEqual(configback.id(), "test")
+ self.assertEqual(configback.name(), "test name")
+ self.assertEqual(configback.method(), "basic")
+ self.assertEqual(configback.config("username"), "test user")
+ self.assertEqual(configback.config("password"), "test pass")
+ self.assertEqual(configback.config("realm"), "test realm")
self.assertEqual(payloadback, payload)
# Remove method config
- self.assertTrue(self.storage.removeMethodConfig('test2'))
- configs = self.storage.authMethodConfigs(['basic'])
+ self.assertTrue(self.storage.removeMethodConfig("test2"))
+ configs = self.storage.authMethodConfigs(["basic"])
self.assertEqual(len(configs), 1)
# Clear the storage
@@ -263,36 +514,64 @@ def testAuthSettings(self):
self.assertTrue(self.storage.initialize(), self.storage.lastError())
- if not bool(self.storage.capabilities() & Qgis.AuthConfigurationStorageCapability.ReadSetting):
- raise unittest.SkipTest('Storage does not support reading settings')
-
- self.assertTrue(bool(self.storage.capabilities() & Qgis.AuthConfigurationStorageCapability.ReadSetting))
- self.assertTrue(bool(self.storage.capabilities() & Qgis.AuthConfigurationStorageCapability.DeleteSetting))
- self.assertTrue(bool(self.storage.capabilities() & Qgis.AuthConfigurationStorageCapability.UpdateSetting))
- self.assertTrue(bool(self.storage.capabilities() & Qgis.AuthConfigurationStorageCapability.CreateSetting))
- self.assertTrue(bool(self.storage.capabilities() & Qgis.AuthConfigurationStorageCapability.ClearStorage))
+ if not bool(
+ self.storage.capabilities()
+ & Qgis.AuthConfigurationStorageCapability.ReadSetting
+ ):
+ raise unittest.SkipTest("Storage does not support reading settings")
+
+ self.assertTrue(
+ bool(
+ self.storage.capabilities()
+ & Qgis.AuthConfigurationStorageCapability.ReadSetting
+ )
+ )
+ self.assertTrue(
+ bool(
+ self.storage.capabilities()
+ & Qgis.AuthConfigurationStorageCapability.DeleteSetting
+ )
+ )
+ self.assertTrue(
+ bool(
+ self.storage.capabilities()
+ & Qgis.AuthConfigurationStorageCapability.UpdateSetting
+ )
+ )
+ self.assertTrue(
+ bool(
+ self.storage.capabilities()
+ & Qgis.AuthConfigurationStorageCapability.CreateSetting
+ )
+ )
+ self.assertTrue(
+ bool(
+ self.storage.capabilities()
+ & Qgis.AuthConfigurationStorageCapability.ClearStorage
+ )
+ )
# Create a setting
- self.assertTrue(self.storage.storeAuthSetting('test', 'test value'))
+ self.assertTrue(self.storage.storeAuthSetting("test", "test value"))
# Create another setting
- self.assertTrue(self.storage.storeAuthSetting('test2', 'test value 2'))
+ self.assertTrue(self.storage.storeAuthSetting("test2", "test value 2"))
- self.assertTrue(self.storage.authSettingExists('test'))
- self.assertTrue(self.storage.authSettingExists('test2'))
- self.assertFalse(self.storage.authSettingExists('xxxx'))
+ self.assertTrue(self.storage.authSettingExists("test"))
+ self.assertTrue(self.storage.authSettingExists("test2"))
+ self.assertFalse(self.storage.authSettingExists("xxxx"))
# Read it back
- value = self.storage.loadAuthSetting('test')
- self.assertEqual(value, 'test value')
+ value = self.storage.loadAuthSetting("test")
+ self.assertEqual(value, "test value")
# Remove setting
- self.assertTrue(self.storage.removeAuthSetting('test'))
- self.assertTrue(self.storage.removeAuthSetting('test2'))
+ self.assertTrue(self.storage.removeAuthSetting("test"))
+ self.assertTrue(self.storage.removeAuthSetting("test2"))
# Check it's empty
- self.assertFalse(self.storage.authSettingExists('test'))
- self.assertFalse(self.storage.authSettingExists('test2'))
+ self.assertFalse(self.storage.authSettingExists("test"))
+ self.assertFalse(self.storage.authSettingExists("test2"))
def testCertIdentity(self):
@@ -300,23 +579,53 @@ def testCertIdentity(self):
self.assertTrue(self.storage.initialize(), self.storage.lastError())
- if not bool(self.storage.capabilities() & Qgis.AuthConfigurationStorageCapability.ReadCertificateIdentity):
- raise unittest.SkipTest('Storage does not support reading certificate identities')
-
- sslrootcert_path = os.path.join(self.certdata_path, 'qgis_ca.crt')
- sslcert = os.path.join(self.certdata_path, 'Gerardus.crt')
- sslkey_path = os.path.join(self.certdata_path, 'Gerardus.key')
+ if not bool(
+ self.storage.capabilities()
+ & Qgis.AuthConfigurationStorageCapability.ReadCertificateIdentity
+ ):
+ raise unittest.SkipTest(
+ "Storage does not support reading certificate identities"
+ )
+
+ sslrootcert_path = os.path.join(self.certdata_path, "qgis_ca.crt")
+ sslcert = os.path.join(self.certdata_path, "Gerardus.crt")
+ sslkey_path = os.path.join(self.certdata_path, "Gerardus.key")
# In real life, key should be encrypted (the auth manager does that)
- with open(sslkey_path, 'r') as f:
+ with open(sslkey_path) as f:
sslkey = f.read()
cert = QSslCertificate.fromPath(sslcert)[0]
- self.assertTrue(bool(self.storage.capabilities() & Qgis.AuthConfigurationStorageCapability.ReadCertificateIdentity))
- self.assertTrue(bool(self.storage.capabilities() & Qgis.AuthConfigurationStorageCapability.DeleteCertificateIdentity))
- self.assertTrue(bool(self.storage.capabilities() & Qgis.AuthConfigurationStorageCapability.UpdateCertificateIdentity))
- self.assertTrue(bool(self.storage.capabilities() & Qgis.AuthConfigurationStorageCapability.CreateCertificateIdentity))
- self.assertTrue(bool(self.storage.capabilities() & Qgis.AuthConfigurationStorageCapability.ClearStorage))
+ self.assertTrue(
+ bool(
+ self.storage.capabilities()
+ & Qgis.AuthConfigurationStorageCapability.ReadCertificateIdentity
+ )
+ )
+ self.assertTrue(
+ bool(
+ self.storage.capabilities()
+ & Qgis.AuthConfigurationStorageCapability.DeleteCertificateIdentity
+ )
+ )
+ self.assertTrue(
+ bool(
+ self.storage.capabilities()
+ & Qgis.AuthConfigurationStorageCapability.UpdateCertificateIdentity
+ )
+ )
+ self.assertTrue(
+ bool(
+ self.storage.capabilities()
+ & Qgis.AuthConfigurationStorageCapability.CreateCertificateIdentity
+ )
+ )
+ self.assertTrue(
+ bool(
+ self.storage.capabilities()
+ & Qgis.AuthConfigurationStorageCapability.ClearStorage
+ )
+ )
# Create an identity
self.assertTrue(self.storage.storeCertIdentity(cert, sslkey))
@@ -352,47 +661,85 @@ def testSslCertificateCustomConfig(self):
self.assertTrue(self.storage.initialize(), self.storage.lastError())
- if not bool(self.storage.capabilities() & Qgis.AuthConfigurationStorageCapability.ReadSslCertificateCustomConfig):
- raise unittest.SkipTest('Storage does not support reading ssl certificate custom configs')
-
- sslrootcert_path = os.path.join(self.certdata_path, 'qgis_ca.crt')
- sslcert = os.path.join(self.certdata_path, 'Gerardus.crt')
- sslkey_path = os.path.join(self.certdata_path, 'Gerardus.key')
+ if not bool(
+ self.storage.capabilities()
+ & Qgis.AuthConfigurationStorageCapability.ReadSslCertificateCustomConfig
+ ):
+ raise unittest.SkipTest(
+ "Storage does not support reading ssl certificate custom configs"
+ )
+
+ sslrootcert_path = os.path.join(self.certdata_path, "qgis_ca.crt")
+ sslcert = os.path.join(self.certdata_path, "Gerardus.crt")
+ sslkey_path = os.path.join(self.certdata_path, "Gerardus.key")
# In real life, key should be encrypted (the auth manager does that)
- with open(sslkey_path, 'r') as f:
+ with open(sslkey_path) as f:
sslkey = f.read()
cert = QSslCertificate.fromPath(sslcert)[0]
- self.assertTrue(bool(self.storage.capabilities() & Qgis.AuthConfigurationStorageCapability.ReadSslCertificateCustomConfig))
- self.assertTrue(bool(self.storage.capabilities() & Qgis.AuthConfigurationStorageCapability.DeleteSslCertificateCustomConfig))
- self.assertTrue(bool(self.storage.capabilities() & Qgis.AuthConfigurationStorageCapability.UpdateSslCertificateCustomConfig))
- self.assertTrue(bool(self.storage.capabilities() & Qgis.AuthConfigurationStorageCapability.CreateSslCertificateCustomConfig))
- self.assertTrue(bool(self.storage.capabilities() & Qgis.AuthConfigurationStorageCapability.ClearStorage))
+ self.assertTrue(
+ bool(
+ self.storage.capabilities()
+ & Qgis.AuthConfigurationStorageCapability.ReadSslCertificateCustomConfig
+ )
+ )
+ self.assertTrue(
+ bool(
+ self.storage.capabilities()
+ & Qgis.AuthConfigurationStorageCapability.DeleteSslCertificateCustomConfig
+ )
+ )
+ self.assertTrue(
+ bool(
+ self.storage.capabilities()
+ & Qgis.AuthConfigurationStorageCapability.UpdateSslCertificateCustomConfig
+ )
+ )
+ self.assertTrue(
+ bool(
+ self.storage.capabilities()
+ & Qgis.AuthConfigurationStorageCapability.CreateSslCertificateCustomConfig
+ )
+ )
+ self.assertTrue(
+ bool(
+ self.storage.capabilities()
+ & Qgis.AuthConfigurationStorageCapability.ClearStorage
+ )
+ )
# Create a custom config
config = QgsAuthConfigSslServer()
config.setSslCertificate(cert)
- config.setSslHostPort('localhost:5432')
+ config.setSslHostPort("localhost:5432")
self.assertTrue(self.storage.storeSslCertCustomConfig(config))
ids = self.storage.sslCertCustomConfigIds()
cert_id = ids[0]
- self.assertTrue(self.storage.sslCertCustomConfigExists(cert_id, config.sslHostPort()))
+ self.assertTrue(
+ self.storage.sslCertCustomConfigExists(cert_id, config.sslHostPort())
+ )
# Read it back
configback = self.storage.loadSslCertCustomConfig(cert_id, config.sslHostPort())
# Verify the config
- self.assertEqual(config.sslCertificate().toPem(), configback.sslCertificate().toPem())
+ self.assertEqual(
+ config.sslCertificate().toPem(), configback.sslCertificate().toPem()
+ )
self.assertEqual(config.sslHostPort(), configback.sslHostPort())
# Remove custom config
- self.assertTrue(self.storage.removeSslCertCustomConfig(cert_id, config.sslHostPort()))
+ self.assertTrue(
+ self.storage.removeSslCertCustomConfig(cert_id, config.sslHostPort())
+ )
# Check it's empty
- self.assertFalse(self.storage.sslCertCustomConfigExists(cert_id, config.sslHostPort()))
+ self.assertFalse(
+ self.storage.sslCertCustomConfigExists(cert_id, config.sslHostPort())
+ )
def testTrust(self):
@@ -400,20 +747,50 @@ def testTrust(self):
self.assertTrue(self.storage.initialize(), self.storage.lastError())
- if not bool(self.storage.capabilities() & Qgis.AuthConfigurationStorageCapability.ReadCertificateTrustPolicy):
- raise unittest.SkipTest('Storage does not support reading certificate trust policies')
-
- self.assertTrue(bool(self.storage.capabilities() & Qgis.AuthConfigurationStorageCapability.ReadCertificateTrustPolicy))
- self.assertTrue(bool(self.storage.capabilities() & Qgis.AuthConfigurationStorageCapability.DeleteCertificateTrustPolicy))
- self.assertTrue(bool(self.storage.capabilities() & Qgis.AuthConfigurationStorageCapability.UpdateCertificateTrustPolicy))
- self.assertTrue(bool(self.storage.capabilities() & Qgis.AuthConfigurationStorageCapability.CreateCertificateTrustPolicy))
- self.assertTrue(bool(self.storage.capabilities() & Qgis.AuthConfigurationStorageCapability.ClearStorage))
-
- sslrootcert_path = os.path.join(self.certdata_path, 'qgis_ca.crt')
- sslcert = os.path.join(self.certdata_path, 'Gerardus.crt')
- sslkey_path = os.path.join(self.certdata_path, 'Gerardus.key')
+ if not bool(
+ self.storage.capabilities()
+ & Qgis.AuthConfigurationStorageCapability.ReadCertificateTrustPolicy
+ ):
+ raise unittest.SkipTest(
+ "Storage does not support reading certificate trust policies"
+ )
+
+ self.assertTrue(
+ bool(
+ self.storage.capabilities()
+ & Qgis.AuthConfigurationStorageCapability.ReadCertificateTrustPolicy
+ )
+ )
+ self.assertTrue(
+ bool(
+ self.storage.capabilities()
+ & Qgis.AuthConfigurationStorageCapability.DeleteCertificateTrustPolicy
+ )
+ )
+ self.assertTrue(
+ bool(
+ self.storage.capabilities()
+ & Qgis.AuthConfigurationStorageCapability.UpdateCertificateTrustPolicy
+ )
+ )
+ self.assertTrue(
+ bool(
+ self.storage.capabilities()
+ & Qgis.AuthConfigurationStorageCapability.CreateCertificateTrustPolicy
+ )
+ )
+ self.assertTrue(
+ bool(
+ self.storage.capabilities()
+ & Qgis.AuthConfigurationStorageCapability.ClearStorage
+ )
+ )
+
+ sslrootcert_path = os.path.join(self.certdata_path, "qgis_ca.crt")
+ sslcert = os.path.join(self.certdata_path, "Gerardus.crt")
+ sslkey_path = os.path.join(self.certdata_path, "Gerardus.key")
# In real life, key should be encrypted (the auth manager does that)
- with open(sslkey_path, 'r') as f:
+ with open(sslkey_path) as f:
sslkey = f.read()
cert = QSslCertificate.fromPath(sslcert)[0]
@@ -444,16 +821,46 @@ def testAuthority(self):
self.assertTrue(self.storage.initialize(), self.storage.lastError())
- if not bool(self.storage.capabilities() & Qgis.AuthConfigurationStorageCapability.ReadCertificateAuthority):
- raise unittest.SkipTest('Storage does not support reading certificate authorities')
-
- self.assertTrue(bool(self.storage.capabilities() & Qgis.AuthConfigurationStorageCapability.ReadCertificateAuthority))
- self.assertTrue(bool(self.storage.capabilities() & Qgis.AuthConfigurationStorageCapability.DeleteCertificateAuthority))
- self.assertTrue(bool(self.storage.capabilities() & Qgis.AuthConfigurationStorageCapability.UpdateCertificateAuthority))
- self.assertTrue(bool(self.storage.capabilities() & Qgis.AuthConfigurationStorageCapability.CreateCertificateAuthority))
- self.assertTrue(bool(self.storage.capabilities() & Qgis.AuthConfigurationStorageCapability.ClearStorage))
-
- sslrootcert_path = os.path.join(self.certdata_path, 'qgis_ca.crt')
+ if not bool(
+ self.storage.capabilities()
+ & Qgis.AuthConfigurationStorageCapability.ReadCertificateAuthority
+ ):
+ raise unittest.SkipTest(
+ "Storage does not support reading certificate authorities"
+ )
+
+ self.assertTrue(
+ bool(
+ self.storage.capabilities()
+ & Qgis.AuthConfigurationStorageCapability.ReadCertificateAuthority
+ )
+ )
+ self.assertTrue(
+ bool(
+ self.storage.capabilities()
+ & Qgis.AuthConfigurationStorageCapability.DeleteCertificateAuthority
+ )
+ )
+ self.assertTrue(
+ bool(
+ self.storage.capabilities()
+ & Qgis.AuthConfigurationStorageCapability.UpdateCertificateAuthority
+ )
+ )
+ self.assertTrue(
+ bool(
+ self.storage.capabilities()
+ & Qgis.AuthConfigurationStorageCapability.CreateCertificateAuthority
+ )
+ )
+ self.assertTrue(
+ bool(
+ self.storage.capabilities()
+ & Qgis.AuthConfigurationStorageCapability.ClearStorage
+ )
+ )
+
+ sslrootcert_path = os.path.join(self.certdata_path, "qgis_ca.crt")
rootcert = QSslCertificate.fromPath(sslrootcert_path)[0]
# Create an authority
@@ -479,8 +886,13 @@ def testAuthority(self):
def testUpdateReadOnly(self):
"""Tests that updating a setting in a read-only storage fails"""
- if not bool(self.storage.capabilities() & Qgis.AuthConfigurationStorageCapability.UpdateSetting):
- raise unittest.SkipTest('Storage does not support reading certificate authorities')
+ if not bool(
+ self.storage.capabilities()
+ & Qgis.AuthConfigurationStorageCapability.UpdateSetting
+ ):
+ raise unittest.SkipTest(
+ "Storage does not support reading certificate authorities"
+ )
auth_manager = QgsApplication.authManager()
auth_manager.ensureInitialized()
@@ -489,8 +901,8 @@ def testUpdateReadOnly(self):
temp_dir_path = temp_dir.path()
# Create an empty sqlite database using GDAL
- db_path = os.path.join(temp_dir_path, 'test.sqlite')
- ds = gdal.GetDriverByName('SQLite').Create(db_path, 0, 0, 0)
+ db_path = os.path.join(temp_dir_path, "test.sqlite")
+ ds = gdal.GetDriverByName("SQLite").Create(db_path, 0, 0, 0)
del ds
uri = f"QSQLITE://{db_path}"
@@ -506,13 +918,13 @@ def testUpdateReadOnly(self):
self.assertEqual(len(registry.readyStorages()), 2)
# Create a setting
- self.assertTrue(self.storage.storeAuthSetting('test', 'test value'))
+ self.assertTrue(self.storage.storeAuthSetting("test", "test value"))
# Set the original storage as read-only
self.storage.setReadOnly(True)
# Try to update the setting using auth manager
- self.assertFalse(auth_manager.storeAuthSetting('test', 'test value 2'))
+ self.assertFalse(auth_manager.storeAuthSetting("test", "test value 2"))
# Remove the temp storage
self.assertTrue(registry.removeStorage(tmp_storage.id()))
diff --git a/tests/src/python/test_authmanager_storage_custom.py b/tests/src/python/test_authmanager_storage_custom.py
index fe82e2dcea6d..84d10416a892 100644
--- a/tests/src/python/test_authmanager_storage_custom.py
+++ b/tests/src/python/test_authmanager_storage_custom.py
@@ -12,12 +12,15 @@
import unittest
-from test_authmanager_storage_base import AuthManagerStorageBaseTestCase, TestAuthManagerStorageBase
+from test_authmanager_storage_base import (
+ AuthManagerStorageBaseTestCase,
+ TestAuthManagerStorageBase,
+)
from qgsauthconfigurationcustomstorage import QgsAuthConfigurationCustomStorage
-__author__ = 'Alessandro Pasotti'
-__date__ = '2024-06-24'
-__copyright__ = 'Copyright 2024, The QGIS Project'
+__author__ = "Alessandro Pasotti"
+__date__ = "2024-06-24"
+__copyright__ = "Copyright 2024, The QGIS Project"
class TestAuthStorageCustom(AuthManagerStorageBaseTestCase, TestAuthManagerStorageBase):
@@ -28,11 +31,11 @@ def setUpClass(cls):
super().setUpClass()
- config = {'is_encrypted': 'false'}
+ config = {"is_encrypted": "false"}
cls.storage = QgsAuthConfigurationCustomStorage(config)
assert not cls.storage.isEncrypted()
- assert cls.storage.type() == 'custom'
+ assert cls.storage.type() == "custom"
-if __name__ == '__main__':
+if __name__ == "__main__":
unittest.main()
diff --git a/tests/src/python/test_authmanager_storage_psql.py b/tests/src/python/test_authmanager_storage_psql.py
index 89dae8ddd62f..a63f1e9f61f5 100644
--- a/tests/src/python/test_authmanager_storage_psql.py
+++ b/tests/src/python/test_authmanager_storage_psql.py
@@ -13,7 +13,10 @@
import os
import unittest
-from test_authmanager_storage_base import AuthManagerStorageBaseTestCase, TestAuthManagerStorageBase
+from test_authmanager_storage_base import (
+ AuthManagerStorageBaseTestCase,
+ TestAuthManagerStorageBase,
+)
from qgis.PyQt.QtCore import QTemporaryDir
from qgis.core import (
QgsAuthConfigurationStorageDb,
@@ -22,52 +25,65 @@
)
from qgis.PyQt import QtSql
-__author__ = 'Alessandro Pasotti'
-__date__ = '2024-06-24'
-__copyright__ = 'Copyright 2024, The QGIS Project'
+__author__ = "Alessandro Pasotti"
+__date__ = "2024-06-24"
+__copyright__ = "Copyright 2024, The QGIS Project"
# Skip if driver QPSQL/QPSQL7 is not available
-@unittest.skipIf(not QtSql.QSqlDatabase.isDriverAvailable('QPSQL') and not QtSql.QSqlDatabase.isDriverAvailable('QPSQL7'), 'QPSQL/QPSQL7 driver not available')
+@unittest.skipIf(
+ not QtSql.QSqlDatabase.isDriverAvailable("QPSQL")
+ and not QtSql.QSqlDatabase.isDriverAvailable("QPSQL7"),
+ "QPSQL/QPSQL7 driver not available",
+)
class TestAuthStoragePsql(AuthManagerStorageBaseTestCase, TestAuthManagerStorageBase):
@classmethod
def setUpClass(cls):
"""Run before tests"""
- if 'QGIS_PGTEST_DB' not in os.environ:
- raise unittest.SkipTest('QGIS_PGTEST_DB not defined')
+ if "QGIS_PGTEST_DB" not in os.environ:
+ raise unittest.SkipTest("QGIS_PGTEST_DB not defined")
- cls.db_path = os.environ['QGIS_PGTEST_DB']
+ cls.db_path = os.environ["QGIS_PGTEST_DB"]
config = dict()
- if cls.db_path.startswith('service='):
+ if cls.db_path.startswith("service="):
try:
# This needs to be installed with pip install pgserviceparser
import pgserviceparser
+
service_name = cls.db_path[8:]
# Remove single quotes if present
if service_name.startswith("'") and service_name.endswith("'"):
service_name = service_name[1:-1]
config = pgserviceparser.service_config(service_name)
except ImportError:
- raise unittest.SkipTest('QGIS_PGTEST_DB is a service connection string (which is not supported by QtSql) and pgserviceparser is not available')
+ raise unittest.SkipTest(
+ "QGIS_PGTEST_DB is a service connection string (which is not supported by QtSql) and pgserviceparser is not available"
+ )
else:
# Parse the connection string
for item in cls.db_path.split():
- key, value = item.split('=')
+ key, value = item.split("=")
config[key] = value
- config['driver'] = 'QPSQL' if QtSql.QSqlDatabase.isDriverAvailable('QPSQL') else 'QPSQL7'
- config['database'] = config['dbname']
+ config["driver"] = (
+ "QPSQL" if QtSql.QSqlDatabase.isDriverAvailable("QPSQL") else "QPSQL7"
+ )
+ config["database"] = config["dbname"]
# Remove single quotes if present in user and password and database
- for key in ['user', 'password', 'database', 'dbname']:
- if key in config and config[key].startswith("'") and config[key].endswith("'"):
+ for key in ["user", "password", "database", "dbname"]:
+ if (
+ key in config
+ and config[key].startswith("'")
+ and config[key].endswith("'")
+ ):
config[key] = config[key][1:-1]
- config['schema'] = 'qgis_auth_test'
+ config["schema"] = "qgis_auth_test"
cls.storage_uri = f"{config['driver']}://{config['user']}:{config['password']}@{config['host']}:{config['port']}/{config['dbname']}?schema={config['schema']}"
@@ -76,27 +92,30 @@ def setUpClass(cls):
super().setUpClass()
# Make sure all tables are dropped by dropping the schema
- md = QgsProviderRegistry.instance().providerMetadata('postgres')
+ md = QgsProviderRegistry.instance().providerMetadata("postgres")
# connection uri
uri = f"dbname='{config['dbname']}' host={config['host']} port={config['port']} user='{config['user']}' password='{config['password']}'"
conn = md.createConnection(uri, {})
- if config['schema'] in conn.schemas():
- conn.dropSchema(config['schema'], True)
+ if config["schema"] in conn.schemas():
+ conn.dropSchema(config["schema"], True)
- conn.createSchema(config['schema'])
+ conn.createSchema(config["schema"])
cls.storage = QgsAuthConfigurationStorageDb(config)
- assert cls.storage.type() == 'DB-QPSQL'
+ assert cls.storage.type() == "DB-QPSQL"
- if config['schema']:
+ if config["schema"]:
schema = f"\"{config['schema']}\"."
else:
- schema = ''
+ schema = ""
- assert cls.storage.quotedQualifiedIdentifier(cls.storage.methodConfigTableName()) == f'{schema}"auth_configs"'
+ assert (
+ cls.storage.quotedQualifiedIdentifier(cls.storage.methodConfigTableName())
+ == f'{schema}"auth_configs"'
+ )
-if __name__ == '__main__':
+if __name__ == "__main__":
unittest.main()
diff --git a/tests/src/python/test_authmanager_storage_sqlite.py b/tests/src/python/test_authmanager_storage_sqlite.py
index bdb74981bb85..90ac85872bed 100644
--- a/tests/src/python/test_authmanager_storage_sqlite.py
+++ b/tests/src/python/test_authmanager_storage_sqlite.py
@@ -14,13 +14,16 @@
from osgeo import gdal
import unittest
-from test_authmanager_storage_base import AuthManagerStorageBaseTestCase, TestAuthManagerStorageBase
+from test_authmanager_storage_base import (
+ AuthManagerStorageBaseTestCase,
+ TestAuthManagerStorageBase,
+)
from qgis.PyQt.QtCore import QTemporaryDir
from qgis.core import QgsAuthConfigurationStorageDb
-__author__ = 'Alessandro Pasotti'
-__date__ = '2024-06-24'
-__copyright__ = 'Copyright 2024, The QGIS Project'
+__author__ = "Alessandro Pasotti"
+__date__ = "2024-06-24"
+__copyright__ = "Copyright 2024, The QGIS Project"
class TestAuthStorageSqlite(AuthManagerStorageBaseTestCase, TestAuthManagerStorageBase):
@@ -33,8 +36,8 @@ def setUpClass(cls):
cls.temp_dir_path = cls.temp_dir.path()
# Create an empty sqlite database using GDAL
- cls.db_path = os.path.join(cls.temp_dir_path, 'test.sqlite')
- ds = gdal.GetDriverByName('SQLite').Create(cls.db_path, 0, 0, 0)
+ cls.db_path = os.path.join(cls.temp_dir_path, "test.sqlite")
+ ds = gdal.GetDriverByName("SQLite").Create(cls.db_path, 0, 0, 0)
del ds
# Verify that the file was created
@@ -44,17 +47,17 @@ def setUpClass(cls):
cls.storage_uri = uri
cls.storage = QgsAuthConfigurationStorageDb(uri)
- assert cls.storage.type() == 'DB-QSQLITE'
+ assert cls.storage.type() == "DB-QSQLITE"
super().setUpClass()
def testCannotCreateDb(self):
"""Generic DB storage cannot create databases"""
- path = os.path.join(self.temp_dir_path, 'test_not_exist.sqlite')
+ path = os.path.join(self.temp_dir_path, "test_not_exist.sqlite")
storage = QgsAuthConfigurationStorageDb(self.storage_uri)
assert not os.path.exists(path)
-if __name__ == '__main__':
+if __name__ == "__main__":
unittest.main()
diff --git a/tests/src/python/test_authsettingswidget.py b/tests/src/python/test_authsettingswidget.py
index d3ec981a8659..9df49f302c2e 100644
--- a/tests/src/python/test_authsettingswidget.py
+++ b/tests/src/python/test_authsettingswidget.py
@@ -9,6 +9,7 @@
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
"""
+
import os
import random
import string
@@ -23,13 +24,13 @@
import unittest
from qgis.testing import start_app, QgisTestCase
-__author__ = 'Alessandro Pasotti'
-__date__ = '27/09/2017'
-__copyright__ = 'Copyright 2017, The QGIS Project'
+__author__ = "Alessandro Pasotti"
+__date__ = "27/09/2017"
+__copyright__ = "Copyright 2017, The QGIS Project"
QGIS_AUTH_DB_DIR_PATH = tempfile.mkdtemp()
-os.environ['QGIS_AUTH_DB_DIR_PATH'] = QGIS_AUTH_DB_DIR_PATH
+os.environ["QGIS_AUTH_DB_DIR_PATH"] = QGIS_AUTH_DB_DIR_PATH
qgis_app = start_app()
@@ -44,14 +45,16 @@ def setUpClass(cls):
# Enable auth
# os.environ['QGIS_AUTH_PASSWORD_FILE'] = QGIS_AUTH_PASSWORD_FILE
authm = QgsApplication.authManager()
- assert (authm.setMasterPassword('masterpassword', True))
- cls.auth_config = QgsAuthMethodConfig('Basic')
- cls.auth_config.setName('test_auth_config')
- cls.username = ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(6))
+ assert authm.setMasterPassword("masterpassword", True)
+ cls.auth_config = QgsAuthMethodConfig("Basic")
+ cls.auth_config.setName("test_auth_config")
+ cls.username = "".join(
+ random.choice(string.ascii_uppercase + string.digits) for _ in range(6)
+ )
cls.password = cls.username[::-1] # reversed
- cls.auth_config.setConfig('username', cls.username)
- cls.auth_config.setConfig('password', cls.password)
- assert (authm.storeAuthenticationConfig(cls.auth_config)[0])
+ cls.auth_config.setConfig("username", cls.username)
+ cls.auth_config.setConfig("password", cls.password)
+ assert authm.storeAuthenticationConfig(cls.auth_config)[0]
@classmethod
def tearDownClass(cls):
@@ -72,9 +75,9 @@ def testWidgetNoArgs(self):
Test the widget with no args
"""
w = QgsAuthSettingsWidget()
- self.assertEqual(w.username(), '')
- self.assertEqual(w.password(), '')
- self.assertEqual(w.configId(), '')
+ self.assertEqual(w.username(), "")
+ self.assertEqual(w.password(), "")
+ self.assertEqual(w.configId(), "")
self.assertTrue(w.configurationTabIsSelected())
self.assertFalse(w.btnConvertToEncryptedIsEnabled())
@@ -83,8 +86,8 @@ def testWidgetConfigId(self):
Test the widget with configId
"""
w = QgsAuthSettingsWidget(None, self.auth_config.id())
- self.assertEqual(w.username(), '')
- self.assertEqual(w.password(), '')
+ self.assertEqual(w.username(), "")
+ self.assertEqual(w.password(), "")
self.assertEqual(w.configId(), self.auth_config.id())
self.assertTrue(w.configurationTabIsSelected())
self.assertFalse(w.btnConvertToEncryptedIsEnabled())
@@ -93,30 +96,30 @@ def testWidgetUsername(self):
"""
Test the widget with username only
"""
- w = QgsAuthSettingsWidget(None, None, 'username')
- self.assertEqual(w.username(), 'username')
- self.assertEqual(w.password(), '')
- self.assertEqual(w.configId(), '')
+ w = QgsAuthSettingsWidget(None, None, "username")
+ self.assertEqual(w.username(), "username")
+ self.assertEqual(w.password(), "")
+ self.assertEqual(w.configId(), "")
self.assertFalse(w.configurationTabIsSelected())
def testWidgetPassword(self):
"""
Test the widget with password only
"""
- w = QgsAuthSettingsWidget(None, None, None, 'password')
- self.assertEqual(w.username(), '')
- self.assertEqual(w.password(), 'password')
- self.assertEqual(w.configId(), '')
+ w = QgsAuthSettingsWidget(None, None, None, "password")
+ self.assertEqual(w.username(), "")
+ self.assertEqual(w.password(), "password")
+ self.assertEqual(w.configId(), "")
self.assertFalse(w.configurationTabIsSelected())
def testWidgetUsernameAndPassword(self):
"""
Test the widget with username and password
"""
- w = QgsAuthSettingsWidget(None, None, 'username', 'password')
- self.assertEqual(w.username(), 'username')
- self.assertEqual(w.password(), 'password')
- self.assertEqual(w.configId(), '')
+ w = QgsAuthSettingsWidget(None, None, "username", "password")
+ self.assertEqual(w.username(), "username")
+ self.assertEqual(w.password(), "password")
+ self.assertEqual(w.configId(), "")
self.assertFalse(w.configurationTabIsSelected())
self.assertTrue(w.btnConvertToEncryptedIsEnabled())
@@ -124,16 +127,16 @@ def testConvertToEncrypted(self):
"""
Test the widget to encrypted conversion
"""
- w = QgsAuthSettingsWidget(None, None, 'username', 'password')
- self.assertEqual(w.username(), 'username')
- self.assertEqual(w.password(), 'password')
- self.assertEqual(w.configId(), '')
+ w = QgsAuthSettingsWidget(None, None, "username", "password")
+ self.assertEqual(w.username(), "username")
+ self.assertEqual(w.password(), "password")
+ self.assertEqual(w.configId(), "")
self.assertFalse(w.configurationTabIsSelected())
self.assertTrue(w.btnConvertToEncryptedIsEnabled())
self.assertTrue(w.convertToEncrypted())
- self.assertNotEqual(w.configId(), '')
- self.assertEqual(w.username(), '')
- self.assertEqual(w.password(), '')
+ self.assertNotEqual(w.configId(), "")
+ self.assertEqual(w.username(), "")
+ self.assertEqual(w.password(), "")
self.assertTrue(w.configurationTabIsSelected())
self.assertFalse(w.btnConvertToEncryptedIsEnabled())
@@ -142,13 +145,13 @@ def test_setters(self):
Test setters
"""
w = QgsAuthSettingsWidget()
- w.setUsername('username')
+ w.setUsername("username")
self.assertFalse(w.configurationTabIsSelected())
- self.assertEqual(w.username(), 'username')
+ self.assertEqual(w.username(), "username")
w = QgsAuthSettingsWidget()
- w.setPassword('password')
- self.assertEqual(w.password(), 'password')
+ w.setPassword("password")
+ self.assertEqual(w.password(), "password")
self.assertFalse(w.configurationTabIsSelected())
w = QgsAuthSettingsWidget()
@@ -157,15 +160,15 @@ def test_setters(self):
self.assertTrue(w.configurationTabIsSelected())
w = QgsAuthSettingsWidget()
- w.setUsername('username')
- w.setPassword('password')
+ w.setUsername("username")
+ w.setPassword("password")
w.setConfigId(self.auth_config.id())
self.assertEqual(w.configId(), self.auth_config.id())
self.assertTrue(w.configurationTabIsSelected())
w = QgsAuthSettingsWidget()
- w.setDataprovider('db2')
- self.assertEqual(w.dataprovider(), 'db2')
+ w.setDataprovider("db2")
+ self.assertEqual(w.dataprovider(), "db2")
def test_storeCheckBoxes(self):
"""
@@ -192,5 +195,5 @@ def test_storeCheckBoxes(self):
self.assertTrue(w.storeUsernameIsChecked())
-if __name__ == '__main__':
+if __name__ == "__main__":
unittest.main()
diff --git a/tests/src/python/test_console.py b/tests/src/python/test_console.py
index 83bb64028a0f..b9e1469275b3 100644
--- a/tests/src/python/test_console.py
+++ b/tests/src/python/test_console.py
@@ -5,9 +5,10 @@
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
"""
-__author__ = 'Matthias Kuhn'
-__date__ = '15.4.2016'
-__copyright__ = 'Copyright 2015, The QGIS Project'
+
+__author__ = "Matthias Kuhn"
+__date__ = "15.4.2016"
+__copyright__ = "Copyright 2015, The QGIS Project"
import os
@@ -23,10 +24,10 @@
class TestConsole(QgisTestCase):
def setUp(self):
- QgsSettings().setValue('pythonConsole/contextHelpOnFirstLaunch', False)
+ QgsSettings().setValue("pythonConsole/contextHelpOnFirstLaunch", False)
def test_show_console(self):
- if os.name == 'nt':
+ if os.name == "nt":
QCoreApplication.setOrganizationName("QGIS")
QCoreApplication.setOrganizationDomain("qgis.org")
QCoreApplication.setApplicationName("QGIS-TEST")
diff --git a/tests/src/python/test_core_additions.py b/tests/src/python/test_core_additions.py
index 108b517c7de0..18592fa06bc3 100644
--- a/tests/src/python/test_core_additions.py
+++ b/tests/src/python/test_core_additions.py
@@ -7,9 +7,10 @@
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
"""
-__author__ = 'Denis Rouzaud'
-__date__ = '15.5.2018'
-__copyright__ = 'Copyright 2015, The QGIS Project'
+
+__author__ = "Denis Rouzaud"
+__date__ = "15.5.2018"
+__copyright__ = "Copyright 2015, The QGIS Project"
from qgis.core import (
@@ -29,12 +30,12 @@ class TestCoreAdditions(QgisTestCase):
def testMetaEnum(self):
me = metaEnumFromValue(Qgis.MapToolUnit.Pixels)
self.assertIsNotNone(me)
- self.assertEqual(me.valueToKey(Qgis.MapToolUnit.Pixels), 'Pixels')
+ self.assertEqual(me.valueToKey(Qgis.MapToolUnit.Pixels), "Pixels")
# check that using same variable twice doesn't segfault
me = metaEnumFromValue(Qgis.MapToolUnit.Pixels, QgsTolerance)
self.assertIsNotNone(me)
- self.assertEqual(me.valueToKey(Qgis.MapToolUnit.Pixels), 'Pixels')
+ self.assertEqual(me.valueToKey(Qgis.MapToolUnit.Pixels), "Pixels")
# do not raise error
self.assertIsNone(metaEnumFromValue(1, QgsTolerance, False))
diff --git a/tests/src/python/test_db_manager_gpkg.py b/tests/src/python/test_db_manager_gpkg.py
index c49602cbb032..16eb7f38af94 100644
--- a/tests/src/python/test_db_manager_gpkg.py
+++ b/tests/src/python/test_db_manager_gpkg.py
@@ -5,9 +5,10 @@
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
"""
-__author__ = 'Even Rouault'
-__date__ = '2016-10-17'
-__copyright__ = 'Copyright 2016, Even Rouault'
+
+__author__ = "Even Rouault"
+__date__ = "2016-10-17"
+__copyright__ = "Copyright 2016, Even Rouault"
import os
import shutil
@@ -25,7 +26,7 @@
def GDAL_COMPUTE_VERSION(maj, min, rev):
- return ((maj) * 1000000 + (min) * 10000 + (rev) * 100)
+ return (maj) * 1000000 + (min) * 10000 + (rev) * 100
class TestPyQgsDBManagerGpkg(QgisTestCase):
@@ -43,14 +44,16 @@ def setUpClass(cls):
cls.basetestpath = tempfile.mkdtemp()
- cls.test_gpkg = os.path.join(cls.basetestpath, 'TestPyQgsDBManagerGpkg.gpkg')
- ds = ogr.GetDriverByName('GPKG').CreateDataSource(cls.test_gpkg)
- lyr = ds.CreateLayer('testLayer', geom_type=ogr.wkbLineString, options=['SPATIAL_INDEX=NO'])
+ cls.test_gpkg = os.path.join(cls.basetestpath, "TestPyQgsDBManagerGpkg.gpkg")
+ ds = ogr.GetDriverByName("GPKG").CreateDataSource(cls.test_gpkg)
+ lyr = ds.CreateLayer(
+ "testLayer", geom_type=ogr.wkbLineString, options=["SPATIAL_INDEX=NO"]
+ )
cls.supportsAlterFieldDefn = lyr.TestCapability(ogr.OLCAlterFieldDefn) == 1
- lyr.CreateField(ogr.FieldDefn('text_field', ogr.OFTString))
+ lyr.CreateField(ogr.FieldDefn("text_field", ogr.OFTString))
f = ogr.Feature(lyr.GetLayerDefn())
- f['text_field'] = 'foo'
- f.SetGeometry(ogr.CreateGeometryFromWkt('LINESTRING(1 2,3 4)'))
+ f["text_field"] = "foo"
+ f.SetGeometry(ogr.CreateGeometryFromWkt("LINESTRING(1 2,3 4)"))
lyr.CreateFeature(f)
f = None
ds = None
@@ -64,15 +67,15 @@ def tearDownClass(cls):
shutil.rmtree(cls.basetestpath, True)
def testSupportedDbTypes(self):
- self.assertIn('gpkg', supportedDbTypes())
+ self.assertIn("gpkg", supportedDbTypes())
def testCreateDbPlugin(self):
- plugin = createDbPlugin('gpkg')
+ plugin = createDbPlugin("gpkg")
self.assertIsNotNone(plugin)
def testConnect(self):
- connection_name = 'testConnect'
- plugin = createDbPlugin('gpkg')
+ connection_name = "testConnect"
+ plugin = createDbPlugin("gpkg")
uri = QgsDataSourceUri()
uri.setDatabase(self.test_gpkg)
@@ -81,14 +84,14 @@ def testConnect(self):
connections = plugin.connections()
self.assertEqual(len(connections), 1)
- connection = createDbPlugin('gpkg', connection_name + '_does_not_exist')
+ connection = createDbPlugin("gpkg", connection_name + "_does_not_exist")
connection_succeeded = False
try:
connection.connect()
connection_succeeded = True
except:
pass
- self.assertFalse(connection_succeeded, 'exception should have been raised')
+ self.assertFalse(connection_succeeded, "exception should have been raised")
connection = connections[0]
connection.connect()
@@ -99,23 +102,23 @@ def testConnect(self):
self.assertEqual(len(plugin.connections()), 0)
- connection = createDbPlugin('gpkg', connection_name)
+ connection = createDbPlugin("gpkg", connection_name)
connection_succeeded = False
try:
connection.connect()
connection_succeeded = True
except:
pass
- self.assertFalse(connection_succeeded, 'exception should have been raised')
+ self.assertFalse(connection_succeeded, "exception should have been raised")
def testListLayer(self):
- connection_name = 'testListLayer'
- plugin = createDbPlugin('gpkg')
+ connection_name = "testListLayer"
+ plugin = createDbPlugin("gpkg")
uri = QgsDataSourceUri()
uri.setDatabase(self.test_gpkg)
self.assertTrue(plugin.addConnection(connection_name, uri))
- connection = createDbPlugin('gpkg', connection_name)
+ connection = createDbPlugin("gpkg", connection_name)
connection.connect()
db = connection.database()
@@ -124,7 +127,7 @@ def testListLayer(self):
tables = db.tables()
self.assertEqual(len(tables), 1)
table = tables[0]
- self.assertEqual(table.name, 'testLayer')
+ self.assertEqual(table.name, "testLayer")
info = table.info()
expected_html = """General info Relation type: Table Rows: 1
GeoPackage Column: geom Geometry: LINESTRING Dimension: XY Spatial ref: Undefined (-1) Extent: 1.00000, 2.00000 - 3.00000, 4.00000
No spatial index defined (create it )
"""
@@ -138,20 +141,23 @@ def testListLayer(self):
connection.remove()
- @unittest.skipIf(os.environ.get('QGIS_CONTINUOUS_INTEGRATION_RUN', 'true'),
- 'Test flaky') # see https://travis-ci.org/qgis/QGIS/jobs/502556996
+ @unittest.skipIf(
+ os.environ.get("QGIS_CONTINUOUS_INTEGRATION_RUN", "true"), "Test flaky"
+ ) # see https://travis-ci.org/qgis/QGIS/jobs/502556996
def testCreateRenameDeleteTable(self):
- connection_name = 'testCreateRenameDeleteTable'
- plugin = createDbPlugin('gpkg')
+ connection_name = "testCreateRenameDeleteTable"
+ plugin = createDbPlugin("gpkg")
uri = QgsDataSourceUri()
- test_gpkg_new = os.path.join(self.basetestpath, 'testCreateRenameDeleteTable.gpkg')
+ test_gpkg_new = os.path.join(
+ self.basetestpath, "testCreateRenameDeleteTable.gpkg"
+ )
shutil.copy(self.test_gpkg, test_gpkg_new)
uri.setDatabase(test_gpkg_new)
self.assertTrue(plugin.addConnection(connection_name, uri))
- connection = createDbPlugin('gpkg', connection_name)
+ connection = createDbPlugin("gpkg", connection_name)
connection.connect()
db = connection.database()
@@ -160,8 +166,8 @@ def testCreateRenameDeleteTable(self):
tables = db.tables()
self.assertEqual(len(tables), 1)
table = tables[0]
- self.assertTrue(table.rename('newName'))
- self.assertEqual(table.name, 'newName')
+ self.assertTrue(table.rename("newName"))
+ self.assertEqual(table.name, "newName")
connection.reconnect()
@@ -169,28 +175,28 @@ def testCreateRenameDeleteTable(self):
tables = db.tables()
self.assertEqual(len(tables), 1)
table = tables[0]
- self.assertEqual(table.name, 'newName')
+ self.assertEqual(table.name, "newName")
fields = []
- geom = ['geometry', 'POINT', 4326, 3]
+ geom = ["geometry", "POINT", 4326, 3]
field1 = TableField(table)
- field1.name = 'fid'
- field1.dataType = 'INTEGER'
+ field1.name = "fid"
+ field1.dataType = "INTEGER"
field1.notNull = True
field1.primaryKey = True
field2 = TableField(table)
- field2.name = 'str_field'
- field2.dataType = 'TEXT'
+ field2.name = "str_field"
+ field2.dataType = "TEXT"
field2.modifier = 20
fields = [field1, field2]
- self.assertTrue(db.createVectorTable('newName2', fields, geom))
+ self.assertTrue(db.createVectorTable("newName2", fields, geom))
tables = db.tables()
self.assertEqual(len(tables), 2)
new_table = tables[1]
- self.assertEqual(new_table.name, 'newName2')
+ self.assertEqual(new_table.name, "newName2")
fields = new_table.fields()
self.assertEqual(len(fields), 3)
self.assertFalse(new_table.hasSpatialIndex())
@@ -214,21 +220,25 @@ def testCreateRenameDeleteFields(self):
if not self.supportsAlterFieldDefn:
return
- connection_name = 'testCreateRenameDeleteFields'
- plugin = createDbPlugin('gpkg')
+ connection_name = "testCreateRenameDeleteFields"
+ plugin = createDbPlugin("gpkg")
uri = QgsDataSourceUri()
- test_gpkg_new = os.path.join(self.basetestpath, 'testCreateRenameDeleteFields.gpkg')
+ test_gpkg_new = os.path.join(
+ self.basetestpath, "testCreateRenameDeleteFields.gpkg"
+ )
- ds = ogr.GetDriverByName('GPKG').CreateDataSource(test_gpkg_new)
- lyr = ds.CreateLayer('testLayer', geom_type=ogr.wkbLineString, options=['SPATIAL_INDEX=NO'])
- lyr.CreateField(ogr.FieldDefn('text_field', ogr.OFTString))
+ ds = ogr.GetDriverByName("GPKG").CreateDataSource(test_gpkg_new)
+ lyr = ds.CreateLayer(
+ "testLayer", geom_type=ogr.wkbLineString, options=["SPATIAL_INDEX=NO"]
+ )
+ lyr.CreateField(ogr.FieldDefn("text_field", ogr.OFTString))
del ds
uri.setDatabase(test_gpkg_new)
self.assertTrue(plugin.addConnection(connection_name, uri))
- connection = createDbPlugin('gpkg', connection_name)
+ connection = createDbPlugin("gpkg", connection_name)
connection.connect()
db = connection.database()
@@ -241,17 +251,24 @@ def testCreateRenameDeleteFields(self):
field_before_count = len(table.fields())
field = TableField(table)
- field.name = 'real_field'
- field.dataType = 'DOUBLE'
+ field.name = "real_field"
+ field.dataType = "DOUBLE"
self.assertTrue(table.addField(field))
self.assertEqual(len(table.fields()), field_before_count + 1)
- self.assertTrue(field.update('real_field2', new_type_str='TEXT (30)', new_not_null=True, new_default_str='foo'))
+ self.assertTrue(
+ field.update(
+ "real_field2",
+ new_type_str="TEXT (30)",
+ new_not_null=True,
+ new_default_str="foo",
+ )
+ )
field = table.fields()[field_before_count]
- self.assertEqual(field.name, 'real_field2')
- self.assertEqual(field.dataType, 'TEXT(30)')
+ self.assertEqual(field.name, "real_field2")
+ self.assertEqual(field.dataType, "TEXT(30)")
self.assertEqual(field.notNull, 1)
self.assertEqual(field.default, "'foo'")
@@ -262,13 +279,13 @@ def testCreateRenameDeleteFields(self):
connection.remove()
def testTableDataModel(self):
- connection_name = 'testTableDataModel'
- plugin = createDbPlugin('gpkg')
+ connection_name = "testTableDataModel"
+ plugin = createDbPlugin("gpkg")
uri = QgsDataSourceUri()
uri.setDatabase(self.test_gpkg)
self.assertTrue(plugin.addConnection(connection_name, uri))
- connection = createDbPlugin('gpkg', connection_name)
+ connection = createDbPlugin("gpkg", connection_name)
connection.connect()
db = connection.database()
@@ -277,36 +294,39 @@ def testTableDataModel(self):
tables = db.tables()
self.assertEqual(len(tables), 1)
table = tables[0]
- self.assertEqual(table.name, 'testLayer')
+ self.assertEqual(table.name, "testLayer")
model = table.tableDataModel(None)
self.assertEqual(model.rowCount(), 1)
self.assertEqual(model.getData(0, 0), 1) # fid
- self.assertEqual(model.getData(0, 1), 'LINESTRING (1 2,3 4)')
- self.assertEqual(model.getData(0, 2), 'foo')
+ self.assertEqual(model.getData(0, 1), "LINESTRING (1 2,3 4)")
+ self.assertEqual(model.getData(0, 2), "foo")
connection.remove()
def testRaster(self):
- connection_name = 'testRaster'
- plugin = createDbPlugin('gpkg')
+ connection_name = "testRaster"
+ plugin = createDbPlugin("gpkg")
uri = QgsDataSourceUri()
- test_gpkg_new = os.path.join(self.basetestpath, 'testRaster.gpkg')
+ test_gpkg_new = os.path.join(self.basetestpath, "testRaster.gpkg")
shutil.copy(self.test_gpkg, test_gpkg_new)
- mem_ds = gdal.GetDriverByName('MEM').Create('', 20, 20)
+ mem_ds = gdal.GetDriverByName("MEM").Create("", 20, 20)
mem_ds.SetGeoTransform([2, 0.01, 0, 49, 0, -0.01])
sr = osr.SpatialReference()
sr.ImportFromEPSG(4326)
mem_ds.SetProjection(sr.ExportToWkt())
mem_ds.GetRasterBand(1).Fill(255)
- gdal.GetDriverByName('GPKG').CreateCopy(test_gpkg_new, mem_ds,
- options=['APPEND_SUBDATASET=YES', 'RASTER_TABLE=raster_table'])
+ gdal.GetDriverByName("GPKG").CreateCopy(
+ test_gpkg_new,
+ mem_ds,
+ options=["APPEND_SUBDATASET=YES", "RASTER_TABLE=raster_table"],
+ )
mem_ds = None
uri.setDatabase(test_gpkg_new)
self.assertTrue(plugin.addConnection(connection_name, uri))
- connection = createDbPlugin('gpkg', connection_name)
+ connection = createDbPlugin("gpkg", connection_name)
connection.connect()
db = connection.database()
@@ -316,7 +336,7 @@ def testRaster(self):
self.assertEqual(len(tables), 2)
table = None
for i in range(2):
- if tables[i].name == 'raster_table':
+ if tables[i].name == "raster_table":
table = tables[i]
break
self.assertIsNotNone(table)
@@ -328,28 +348,33 @@ def testRaster(self):
connection.remove()
def testTwoRaster(self):
- connection_name = 'testTwoRaster'
- plugin = createDbPlugin('gpkg')
+ connection_name = "testTwoRaster"
+ plugin = createDbPlugin("gpkg")
uri = QgsDataSourceUri()
- test_gpkg_new = os.path.join(self.basetestpath, 'testTwoRaster.gpkg')
+ test_gpkg_new = os.path.join(self.basetestpath, "testTwoRaster.gpkg")
shutil.copy(self.test_gpkg, test_gpkg_new)
- mem_ds = gdal.GetDriverByName('MEM').Create('', 20, 20)
+ mem_ds = gdal.GetDriverByName("MEM").Create("", 20, 20)
mem_ds.SetGeoTransform([2, 0.01, 0, 49, 0, -0.01])
sr = osr.SpatialReference()
sr.ImportFromEPSG(4326)
mem_ds.SetProjection(sr.ExportToWkt())
mem_ds.GetRasterBand(1).Fill(255)
for i in range(2):
- gdal.GetDriverByName('GPKG').CreateCopy(test_gpkg_new, mem_ds, options=['APPEND_SUBDATASET=YES',
- 'RASTER_TABLE=raster_table%d' % (
- i + 1)])
+ gdal.GetDriverByName("GPKG").CreateCopy(
+ test_gpkg_new,
+ mem_ds,
+ options=[
+ "APPEND_SUBDATASET=YES",
+ "RASTER_TABLE=raster_table%d" % (i + 1),
+ ],
+ )
mem_ds = None
uri.setDatabase(test_gpkg_new)
self.assertTrue(plugin.addConnection(connection_name, uri))
- connection = createDbPlugin('gpkg', connection_name)
+ connection = createDbPlugin("gpkg", connection_name)
connection.connect()
db = connection.database()
@@ -359,7 +384,7 @@ def testTwoRaster(self):
self.assertEqual(len(tables), 3)
table = None
for i in range(2):
- if tables[i].name.startswith('raster_table'):
+ if tables[i].name.startswith("raster_table"):
table = tables[i]
info = table.info()
info.toHtml()
@@ -368,16 +393,16 @@ def testTwoRaster(self):
def testNonSpatial(self):
- connection_name = 'testNonSpatial'
- plugin = createDbPlugin('gpkg')
+ connection_name = "testNonSpatial"
+ plugin = createDbPlugin("gpkg")
uri = QgsDataSourceUri()
- test_gpkg = os.path.join(self.basetestpath, 'testNonSpatial.gpkg')
- ds = ogr.GetDriverByName('GPKG').CreateDataSource(test_gpkg)
- lyr = ds.CreateLayer('testNonSpatial', geom_type=ogr.wkbNone)
- lyr.CreateField(ogr.FieldDefn('text_field', ogr.OFTString))
+ test_gpkg = os.path.join(self.basetestpath, "testNonSpatial.gpkg")
+ ds = ogr.GetDriverByName("GPKG").CreateDataSource(test_gpkg)
+ lyr = ds.CreateLayer("testNonSpatial", geom_type=ogr.wkbNone)
+ lyr.CreateField(ogr.FieldDefn("text_field", ogr.OFTString))
f = ogr.Feature(lyr.GetLayerDefn())
- f['text_field'] = 'foo'
+ f["text_field"] = "foo"
lyr.CreateFeature(f)
f = None
ds = None
@@ -385,7 +410,7 @@ def testNonSpatial(self):
uri.setDatabase(test_gpkg)
self.assertTrue(plugin.addConnection(connection_name, uri))
- connection = createDbPlugin('gpkg', connection_name)
+ connection = createDbPlugin("gpkg", connection_name)
connection.connect()
db = connection.database()
@@ -394,7 +419,7 @@ def testNonSpatial(self):
tables = db.tables()
self.assertEqual(len(tables), 1)
table = tables[0]
- self.assertEqual(table.name, 'testNonSpatial')
+ self.assertEqual(table.name, "testNonSpatial")
info = table.info()
expected_html = """General info Relation type: Table Rows: 1
"""
@@ -403,36 +428,40 @@ def testNonSpatial(self):
# GDAL 2.3.0
expected_html_3 = """General info Relation type: Table Rows: 1
"""
- self.assertIn(info.toHtml(), [expected_html, expected_html_2, expected_html_3], info.toHtml())
+ self.assertIn(
+ info.toHtml(),
+ [expected_html, expected_html_2, expected_html_3],
+ info.toHtml(),
+ )
connection.remove()
def testAllGeometryTypes(self):
- connection_name = 'testAllGeometryTypes'
- plugin = createDbPlugin('gpkg')
+ connection_name = "testAllGeometryTypes"
+ plugin = createDbPlugin("gpkg")
uri = QgsDataSourceUri()
- test_gpkg = os.path.join(self.basetestpath, 'testAllGeometryTypes.gpkg')
- ds = ogr.GetDriverByName('GPKG').CreateDataSource(test_gpkg)
- ds.CreateLayer('testPoint', geom_type=ogr.wkbPoint)
- ds.CreateLayer('testLineString', geom_type=ogr.wkbLineString)
- ds.CreateLayer('testPolygon', geom_type=ogr.wkbPolygon)
- ds.CreateLayer('testMultiPoint', geom_type=ogr.wkbMultiPoint)
- ds.CreateLayer('testMultiLineString', geom_type=ogr.wkbMultiLineString)
- ds.CreateLayer('testMultiPolygon', geom_type=ogr.wkbMultiPolygon)
- ds.CreateLayer('testGeometryCollection', geom_type=ogr.wkbGeometryCollection)
- ds.CreateLayer('testCircularString', geom_type=ogr.wkbCircularString)
- ds.CreateLayer('testCompoundCurve', geom_type=ogr.wkbCompoundCurve)
- ds.CreateLayer('testCurvePolygon', geom_type=ogr.wkbCurvePolygon)
- ds.CreateLayer('testMultiCurve', geom_type=ogr.wkbMultiCurve)
- ds.CreateLayer('testMultiSurface', geom_type=ogr.wkbMultiSurface)
+ test_gpkg = os.path.join(self.basetestpath, "testAllGeometryTypes.gpkg")
+ ds = ogr.GetDriverByName("GPKG").CreateDataSource(test_gpkg)
+ ds.CreateLayer("testPoint", geom_type=ogr.wkbPoint)
+ ds.CreateLayer("testLineString", geom_type=ogr.wkbLineString)
+ ds.CreateLayer("testPolygon", geom_type=ogr.wkbPolygon)
+ ds.CreateLayer("testMultiPoint", geom_type=ogr.wkbMultiPoint)
+ ds.CreateLayer("testMultiLineString", geom_type=ogr.wkbMultiLineString)
+ ds.CreateLayer("testMultiPolygon", geom_type=ogr.wkbMultiPolygon)
+ ds.CreateLayer("testGeometryCollection", geom_type=ogr.wkbGeometryCollection)
+ ds.CreateLayer("testCircularString", geom_type=ogr.wkbCircularString)
+ ds.CreateLayer("testCompoundCurve", geom_type=ogr.wkbCompoundCurve)
+ ds.CreateLayer("testCurvePolygon", geom_type=ogr.wkbCurvePolygon)
+ ds.CreateLayer("testMultiCurve", geom_type=ogr.wkbMultiCurve)
+ ds.CreateLayer("testMultiSurface", geom_type=ogr.wkbMultiSurface)
ds = None
uri.setDatabase(test_gpkg)
self.assertTrue(plugin.addConnection(connection_name, uri))
- connection = createDbPlugin('gpkg', connection_name)
+ connection = createDbPlugin("gpkg", connection_name)
connection.connect()
db = connection.database()
@@ -445,24 +474,42 @@ def testAllGeometryTypes(self):
connection.remove()
- def testAmphibiousMode(self, ):
- connectionName = 'geopack1'
- plugin = createDbPlugin('gpkg')
+ def testAmphibiousMode(
+ self,
+ ):
+ connectionName = "geopack1"
+ plugin = createDbPlugin("gpkg")
uri = QgsDataSourceUri()
- test_gpkg = os.path.join(os.path.join(unitTestDataPath(), 'provider'), 'test_json.gpkg')
+ test_gpkg = os.path.join(
+ os.path.join(unitTestDataPath(), "provider"), "test_json.gpkg"
+ )
uri.setDatabase(test_gpkg)
plugin.addConnection(connectionName, uri)
- connection = createDbPlugin('gpkg', connectionName)
+ connection = createDbPlugin("gpkg", connectionName)
connection.connect()
db = connection.database()
- res = db.connector._execute(None, f"SELECT St_area({db.tables()[0].fields()[1].name}) from foo")
+ res = db.connector._execute(
+ None, f"SELECT St_area({db.tables()[0].fields()[1].name}) from foo"
+ )
results = [row for row in res]
- self.assertEqual(results,
- [(215229.265625,), (247328.171875,), (261752.78125,), (547597.2109375,), (15775.7578125,),
- (101429.9765625,), (268597.625,), (1634833.390625,), (596610.3359375,), (5268.8125,)])
+ self.assertEqual(
+ results,
+ [
+ (215229.265625,),
+ (247328.171875,),
+ (261752.78125,),
+ (547597.2109375,),
+ (15775.7578125,),
+ (101429.9765625,),
+ (268597.625,),
+ (1634833.390625,),
+ (596610.3359375,),
+ (5268.8125,),
+ ],
+ )
connection.remove()
-if __name__ == '__main__':
+if __name__ == "__main__":
unittest.main()
diff --git a/tests/src/python/test_db_manager_postgis.py b/tests/src/python/test_db_manager_postgis.py
index 438c5ec51d2a..95505e1bc0a8 100644
--- a/tests/src/python/test_db_manager_postgis.py
+++ b/tests/src/python/test_db_manager_postgis.py
@@ -5,9 +5,10 @@
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
"""
-__author__ = 'Luigi Pirelli'
-__date__ = '2017-11-02'
-__copyright__ = 'Copyright 2017, Boundless Spatial Inc'
+
+__author__ = "Luigi Pirelli"
+__date__ = "2017-11-02"
+__copyright__ = "Copyright 2017, Boundless Spatial Inc"
import glob
import os
@@ -33,8 +34,10 @@
from utilities import unitTestDataPath
-QGIS_POSTGRES_SERVER_PORT = os.environ.get('QGIS_POSTGRES_SERVER_PORT', '55432')
-QGIS_POSTGRES_EXECUTABLE_PATH = os.environ.get('QGIS_POSTGRES_EXECUTABLE_PATH', '/usr/lib/postgresql/9.4/bin')
+QGIS_POSTGRES_SERVER_PORT = os.environ.get("QGIS_POSTGRES_SERVER_PORT", "55432")
+QGIS_POSTGRES_EXECUTABLE_PATH = os.environ.get(
+ "QGIS_POSTGRES_EXECUTABLE_PATH", "/usr/lib/postgresql/9.4/bin"
+)
assert os.path.exists(QGIS_POSTGRES_EXECUTABLE_PATH)
@@ -43,7 +46,7 @@
# Postgres test path
QGIS_PG_TEST_PATH = tempfile.mkdtemp()
-os.environ['QGIS_AUTH_DB_DIR_PATH'] = QGIS_AUTH_DB_DIR_PATH
+os.environ["QGIS_AUTH_DB_DIR_PATH"] = QGIS_AUTH_DB_DIR_PATH
qgis_app = start_app()
@@ -68,7 +71,7 @@
host all all ::1/32 trust
"""
-TEST_CONNECTION_NAME = 'test_connection'
+TEST_CONNECTION_NAME = "test_connection"
class TestPyQgsDBManagerPostgis(QgisTestCase):
@@ -77,13 +80,15 @@ class TestPyQgsDBManagerPostgis(QgisTestCase):
def setUpAuth(cls):
"""Run before all tests and set up authentication"""
authm = QgsApplication.authManager()
- assert (authm.setMasterPassword('masterpassword', True))
- cls.pg_conf = os.path.join(cls.tempfolder, 'postgresql.conf')
- cls.pg_hba = os.path.join(cls.tempfolder, 'pg_hba.conf')
+ assert authm.setMasterPassword("masterpassword", True)
+ cls.pg_conf = os.path.join(cls.tempfolder, "postgresql.conf")
+ cls.pg_hba = os.path.join(cls.tempfolder, "pg_hba.conf")
# Client side
- cls.sslrootcert_path = os.path.join(cls.certsdata_path, 'chains_subissuer-issuer-root_issuer2-root2.pem')
- cls.sslcert = os.path.join(cls.certsdata_path, 'gerardus_cert.pem')
- cls.sslkey = os.path.join(cls.certsdata_path, 'gerardus_key.pem')
+ cls.sslrootcert_path = os.path.join(
+ cls.certsdata_path, "chains_subissuer-issuer-root_issuer2-root2.pem"
+ )
+ cls.sslcert = os.path.join(cls.certsdata_path, "gerardus_cert.pem")
+ cls.sslkey = os.path.join(cls.certsdata_path, "gerardus_key.pem")
assert os.path.isfile(cls.sslcert)
assert os.path.isfile(cls.sslkey)
assert os.path.isfile(cls.sslrootcert_path)
@@ -91,38 +96,41 @@ def setUpAuth(cls):
os.chmod(cls.sslkey, stat.S_IRUSR)
os.chmod(cls.sslrootcert_path, stat.S_IRUSR)
cls.auth_config = QgsAuthMethodConfig("PKI-Paths")
- cls.auth_config.setConfig('certpath', cls.sslcert)
- cls.auth_config.setConfig('keypath', cls.sslkey)
- cls.auth_config.setName('test_pki_auth_config')
- cls.username = 'Gerardus'
+ cls.auth_config.setConfig("certpath", cls.sslcert)
+ cls.auth_config.setConfig("keypath", cls.sslkey)
+ cls.auth_config.setName("test_pki_auth_config")
+ cls.username = "Gerardus"
cls.sslrootcert = QSslCertificate.fromPath(cls.sslrootcert_path)
assert cls.sslrootcert is not None
authm.storeCertAuthorities(cls.sslrootcert)
authm.rebuildCaCertsCache()
authm.rebuildTrustedCaCertsCache()
authm.rebuildCertTrustCache()
- assert (authm.storeAuthenticationConfig(cls.auth_config)[0])
+ assert authm.storeAuthenticationConfig(cls.auth_config)[0]
assert cls.auth_config.isValid()
# Server side
- cls.server_cert = os.path.join(cls.certsdata_path, 'localhost_ssl_cert.pem')
- cls.server_key = os.path.join(cls.certsdata_path, 'localhost_ssl_key.pem')
+ cls.server_cert = os.path.join(cls.certsdata_path, "localhost_ssl_cert.pem")
+ cls.server_key = os.path.join(cls.certsdata_path, "localhost_ssl_key.pem")
cls.server_rootcert = cls.sslrootcert_path
os.chmod(cls.server_cert, stat.S_IRUSR)
os.chmod(cls.server_key, stat.S_IRUSR)
os.chmod(cls.server_rootcert, stat.S_IRUSR)
# Place conf in the data folder
- with open(cls.pg_conf, 'w+') as f:
- f.write(QGIS_POSTGRES_CONF_TEMPLATE % {
- 'port': cls.port,
- 'tempfolder': cls.tempfolder,
- 'server_cert': cls.server_cert,
- 'server_key': cls.server_key,
- 'sslrootcert_path': cls.sslrootcert_path,
- })
-
- with open(cls.pg_hba, 'w+') as f:
+ with open(cls.pg_conf, "w+") as f:
+ f.write(
+ QGIS_POSTGRES_CONF_TEMPLATE
+ % {
+ "port": cls.port,
+ "tempfolder": cls.tempfolder,
+ "server_cert": cls.server_cert,
+ "server_key": cls.server_key,
+ "sslrootcert_path": cls.sslrootcert_path,
+ }
+ )
+
+ with open(cls.pg_hba, "w+") as f:
f.write(QGIS_POSTGRES_HBA_TEMPLATE)
@classmethod
@@ -130,22 +138,30 @@ def setUpServer(cls):
"""Run before all tests:
Creates an auth configuration"""
cls.port = QGIS_POSTGRES_SERVER_PORT
- cls.dbname = 'test_pki'
+ cls.dbname = "test_pki"
cls.tempfolder = QGIS_PG_TEST_PATH
- cls.certsdata_path = os.path.join(unitTestDataPath('auth_system'), 'certs_keys')
- cls.hostname = 'localhost'
- cls.data_path = os.path.join(cls.tempfolder, 'data')
+ cls.certsdata_path = os.path.join(unitTestDataPath("auth_system"), "certs_keys")
+ cls.hostname = "localhost"
+ cls.data_path = os.path.join(cls.tempfolder, "data")
os.mkdir(cls.data_path)
cls.setUpAuth()
- subprocess.check_call([os.path.join(QGIS_POSTGRES_EXECUTABLE_PATH, 'initdb'), '-D', cls.data_path])
-
- cls.server = subprocess.Popen([os.path.join(QGIS_POSTGRES_EXECUTABLE_PATH, 'postgres'), '-D',
- cls.data_path, '-c',
- f"config_file={cls.pg_conf}"],
- env=os.environ,
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE)
+ subprocess.check_call(
+ [os.path.join(QGIS_POSTGRES_EXECUTABLE_PATH, "initdb"), "-D", cls.data_path]
+ )
+
+ cls.server = subprocess.Popen(
+ [
+ os.path.join(QGIS_POSTGRES_EXECUTABLE_PATH, "postgres"),
+ "-D",
+ cls.data_path,
+ "-c",
+ f"config_file={cls.pg_conf}",
+ ],
+ env=os.environ,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ )
# Wait max 10 secs for the server to start
end = time.time() + 10
while True:
@@ -156,28 +172,71 @@ def setUpServer(cls):
if time.time() > end:
raise Exception("Timeout connecting to PostgreSQL")
# Create a DB
- subprocess.check_call([os.path.join(QGIS_POSTGRES_EXECUTABLE_PATH, 'createdb'), '-h', 'localhost', '-p', cls.port, 'test_pki'])
+ subprocess.check_call(
+ [
+ os.path.join(QGIS_POSTGRES_EXECUTABLE_PATH, "createdb"),
+ "-h",
+ "localhost",
+ "-p",
+ cls.port,
+ "test_pki",
+ ]
+ )
# Inject test SQL from test path
- test_sql = os.path.join(unitTestDataPath('provider'), 'testdata_pg.sql')
- subprocess.check_call([os.path.join(QGIS_POSTGRES_EXECUTABLE_PATH, 'psql'), '-h', 'localhost', '-p', cls.port, '-f', test_sql, cls.dbname])
+ test_sql = os.path.join(unitTestDataPath("provider"), "testdata_pg.sql")
+ subprocess.check_call(
+ [
+ os.path.join(QGIS_POSTGRES_EXECUTABLE_PATH, "psql"),
+ "-h",
+ "localhost",
+ "-p",
+ cls.port,
+ "-f",
+ test_sql,
+ cls.dbname,
+ ]
+ )
# Create a role
- subprocess.check_call([os.path.join(QGIS_POSTGRES_EXECUTABLE_PATH, 'psql'), '-h', 'localhost', '-p', cls.port, '-c', f'CREATE ROLE "{cls.username}" WITH SUPERUSER LOGIN', cls.dbname])
+ subprocess.check_call(
+ [
+ os.path.join(QGIS_POSTGRES_EXECUTABLE_PATH, "psql"),
+ "-h",
+ "localhost",
+ "-p",
+ cls.port,
+ "-c",
+ f'CREATE ROLE "{cls.username}" WITH SUPERUSER LOGIN',
+ cls.dbname,
+ ]
+ )
@classmethod
def setUpProvider(cls, authId):
- cls.dbconn = 'service=qgis_test'
- if 'QGIS_PGTEST_DB' in os.environ:
- cls.dbconn = os.environ['QGIS_PGTEST_DB']
+ cls.dbconn = "service=qgis_test"
+ if "QGIS_PGTEST_DB" in os.environ:
+ cls.dbconn = os.environ["QGIS_PGTEST_DB"]
uri = QgsDataSourceUri()
- uri.setConnection("localhost", cls.port, cls.dbname, "", "", QgsDataSourceUri.SslMode.SslVerifyFull, authId)
- uri.setKeyColumn('pk')
- uri.setSrid('EPSG:4326')
- uri.setDataSource('qgis_test', 'someData', "geom", "", "pk")
- provider = QgsProviderRegistry.instance().createProvider('postgres', uri.uri(False))
+ uri.setConnection(
+ "localhost",
+ cls.port,
+ cls.dbname,
+ "",
+ "",
+ QgsDataSourceUri.SslMode.SslVerifyFull,
+ authId,
+ )
+ uri.setKeyColumn("pk")
+ uri.setSrid("EPSG:4326")
+ uri.setDataSource("qgis_test", "someData", "geom", "", "pk")
+ provider = QgsProviderRegistry.instance().createProvider(
+ "postgres", uri.uri(False)
+ )
if provider is None:
raise Exception("cannot create postgres provider")
if not provider.isValid():
- raise Exception(f"Created postgres provider is not valid: {str(provider.errors())}")
+ raise Exception(
+ f"Created postgres provider is not valid: {str(provider.errors())}"
+ )
# save provider config that is the way how db_manager is aware of a PG connection
cls.addConnectionConfig(TEST_CONNECTION_NAME, uri)
@@ -231,10 +290,10 @@ def tearDownClass(cls):
###########################################
def testSupportedDbTypes(self):
- self.assertIn('postgis', supportedDbTypes())
+ self.assertIn("postgis", supportedDbTypes())
def testCreateDbPlugin(self):
- plugin = createDbPlugin('postgis')
+ plugin = createDbPlugin("postgis")
self.assertIsNotNone(plugin)
def testConnect(self):
@@ -242,7 +301,7 @@ def testConnect(self):
# that will be listed in postgis connection of db_manager
self.setUpProvider(self.auth_config.id())
- plugin = createDbPlugin('postgis')
+ plugin = createDbPlugin("postgis")
connections = plugin.connections()
self.assertEqual(len(connections), 1)
# test connection
@@ -252,14 +311,14 @@ def testConnect(self):
self.assertTrue(postgisConnPlugin.remove())
self.assertEqual(len(plugin.connections()), 0)
# test without connection params => fail
- connection = createDbPlugin('postgis', 'conn name')
+ connection = createDbPlugin("postgis", "conn name")
connection_succeeded = False
try:
connection.connect()
connection_succeeded = True
except:
pass
- self.assertFalse(connection_succeeded, 'exception should have been raised')
+ self.assertFalse(connection_succeeded, "exception should have been raised")
def testRemoveTemporaryCerts(self):
"""
@@ -268,7 +327,7 @@ def testRemoveTemporaryCerts(self):
"""
def cleanTempPki():
- pkies = glob.glob(os.path.join(tempfile.gettempdir(), 'tmp*_{*}.pem'))
+ pkies = glob.glob(os.path.join(tempfile.gettempdir(), "tmp*_{*}.pem"))
for fn in pkies:
f = QFile(fn)
f.setPermissions(QFile.Permission.WriteOwner)
@@ -279,16 +338,16 @@ def cleanTempPki():
cleanTempPki()
# connect
self.setUpProvider(self.auth_config.id())
- plugin = createDbPlugin('postgis')
+ plugin = createDbPlugin("postgis")
connections = plugin.connections()
self.assertEqual(len(connections), 1)
# test connection
postgisConnPlugin = connections[0]
self.assertTrue(postgisConnPlugin.connect())
# do test no certs remained
- pkies = glob.glob(os.path.join(tempfile.gettempdir(), 'tmp*_{*}.pem'))
+ pkies = glob.glob(os.path.join(tempfile.gettempdir(), "tmp*_{*}.pem"))
self.assertEqual(len(pkies), 0)
-if __name__ == '__main__':
+if __name__ == "__main__":
unittest.main()
diff --git a/tests/src/python/test_db_manager_spatialite.py b/tests/src/python/test_db_manager_spatialite.py
index 213e14273a89..db83c4c3c133 100644
--- a/tests/src/python/test_db_manager_spatialite.py
+++ b/tests/src/python/test_db_manager_spatialite.py
@@ -5,9 +5,10 @@
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
"""
-__author__ = 'Even Rouault'
-__date__ = '2016-10-17'
-__copyright__ = 'Copyright 2016, Even Rouault'
+
+__author__ = "Even Rouault"
+__date__ = "2016-10-17"
+__copyright__ = "Copyright 2016, Even Rouault"
import os
import shutil
@@ -23,7 +24,7 @@
def GDAL_COMPUTE_VERSION(maj, min, rev):
- return ((maj) * 1000000 + (min) * 10000 + (rev) * 100)
+ return (maj) * 1000000 + (min) * 10000 + (rev) * 100
class TestPyQgsDBManagerSpatialite(QgisTestCase):
@@ -41,14 +42,18 @@ def setUpClass(cls):
cls.basetestpath = tempfile.mkdtemp()
- cls.test_spatialite = os.path.join(cls.basetestpath, 'TestPyQgsDBManagerSpatialite.spatialite')
- ds = ogr.GetDriverByName('SQLite').CreateDataSource(cls.test_spatialite)
- lyr = ds.CreateLayer('testlayer', geom_type=ogr.wkbLineString, options=['SPATIAL_INDEX=NO'])
+ cls.test_spatialite = os.path.join(
+ cls.basetestpath, "TestPyQgsDBManagerSpatialite.spatialite"
+ )
+ ds = ogr.GetDriverByName("SQLite").CreateDataSource(cls.test_spatialite)
+ lyr = ds.CreateLayer(
+ "testlayer", geom_type=ogr.wkbLineString, options=["SPATIAL_INDEX=NO"]
+ )
cls.supportsAlterFieldDefn = lyr.TestCapability(ogr.OLCAlterFieldDefn) == 1
- lyr.CreateField(ogr.FieldDefn('text_field', ogr.OFTString))
+ lyr.CreateField(ogr.FieldDefn("text_field", ogr.OFTString))
f = ogr.Feature(lyr.GetLayerDefn())
- f['text_field'] = 'foo'
- f.SetGeometry(ogr.CreateGeometryFromWkt('LINESTRING(1 2,3 4)'))
+ f["text_field"] = "foo"
+ f.SetGeometry(ogr.CreateGeometryFromWkt("LINESTRING(1 2,3 4)"))
lyr.CreateFeature(f)
f = None
ds = None
@@ -62,15 +67,15 @@ def tearDownClass(cls):
super().tearDownClass()
def testSupportedDbTypes(self):
- self.assertIn('spatialite', supportedDbTypes())
+ self.assertIn("spatialite", supportedDbTypes())
def testCreateDbPlugin(self):
- plugin = createDbPlugin('spatialite')
+ plugin = createDbPlugin("spatialite")
self.assertIsNotNone(plugin)
def testConnect(self):
- connection_name = 'testConnect'
- plugin = createDbPlugin('spatialite')
+ connection_name = "testConnect"
+ plugin = createDbPlugin("spatialite")
uri = QgsDataSourceUri()
uri.setDatabase(self.test_spatialite)
@@ -79,14 +84,14 @@ def testConnect(self):
connections = plugin.connections()
self.assertEqual(len(connections), 1)
- connection = createDbPlugin('spatialite', connection_name + '_does_not_exist')
+ connection = createDbPlugin("spatialite", connection_name + "_does_not_exist")
connection_succeeded = False
try:
connection.connect()
connection_succeeded = True
except:
pass
- self.assertFalse(connection_succeeded, 'exception should have been raised')
+ self.assertFalse(connection_succeeded, "exception should have been raised")
connection = connections[0]
connection.connect()
@@ -97,37 +102,37 @@ def testConnect(self):
self.assertEqual(len(plugin.connections()), 0)
- connection = createDbPlugin('spatialite', connection_name)
+ connection = createDbPlugin("spatialite", connection_name)
connection_succeeded = False
try:
connection.connect()
connection_succeeded = True
except:
pass
- self.assertFalse(connection_succeeded, 'exception should have been raised')
+ self.assertFalse(connection_succeeded, "exception should have been raised")
def testExecuteRegExp(self):
"""This test checks for REGEXP syntax support, which is enabled in Qgis.utils' spatialite_connection()"""
- connection_name = 'testListLayer'
- plugin = createDbPlugin('spatialite')
+ connection_name = "testListLayer"
+ plugin = createDbPlugin("spatialite")
uri = QgsDataSourceUri()
uri.setDatabase(self.test_spatialite)
self.assertTrue(plugin.addConnection(connection_name, uri))
- connection = createDbPlugin('spatialite', connection_name)
+ connection = createDbPlugin("spatialite", connection_name)
connection.connect()
db = connection.database()
- db.connector._execute(None, 'SELECT \'ABC\' REGEXP \'[CBA]\'')
+ db.connector._execute(None, "SELECT 'ABC' REGEXP '[CBA]'")
def testListLayer(self):
- connection_name = 'testListLayer'
- plugin = createDbPlugin('spatialite')
+ connection_name = "testListLayer"
+ plugin = createDbPlugin("spatialite")
uri = QgsDataSourceUri()
uri.setDatabase(self.test_spatialite)
self.assertTrue(plugin.addConnection(connection_name, uri))
- connection = createDbPlugin('spatialite', connection_name)
+ connection = createDbPlugin("spatialite", connection_name)
connection.connect()
db = connection.database()
@@ -136,7 +141,7 @@ def testListLayer(self):
tables = db.tables()
self.assertEqual(len(tables), 1)
table = tables[0]
- self.assertEqual(table.name, 'testlayer')
+ self.assertEqual(table.name, "testlayer")
info = table.info()
# expected_html = """General info Relation type: Table Rows: 1
GeoPackage Column: geom Geometry: LINESTRING Dimension: XY Spatial ref: Undefined (-1) Extent: 1.00000, 2.00000 - 3.00000, 4.00000
No spatial index defined (create it )
"""
@@ -155,17 +160,19 @@ def testListLayer(self):
connection.remove()
def testCreateRenameDeleteTable(self):
- connection_name = 'testCreateRenameDeleteTable'
- plugin = createDbPlugin('spatialite')
+ connection_name = "testCreateRenameDeleteTable"
+ plugin = createDbPlugin("spatialite")
uri = QgsDataSourceUri()
- test_spatialite_new = os.path.join(self.basetestpath, 'testCreateRenameDeleteTable.spatialite')
+ test_spatialite_new = os.path.join(
+ self.basetestpath, "testCreateRenameDeleteTable.spatialite"
+ )
shutil.copy(self.test_spatialite, test_spatialite_new)
uri.setDatabase(test_spatialite_new)
self.assertTrue(plugin.addConnection(connection_name, uri))
- connection = createDbPlugin('spatialite', connection_name)
+ connection = createDbPlugin("spatialite", connection_name)
connection.connect()
db = connection.database()
@@ -174,8 +181,8 @@ def testCreateRenameDeleteTable(self):
tables = db.tables()
self.assertEqual(len(tables), 1)
table = tables[0]
- self.assertTrue(table.rename('newName'))
- self.assertEqual(table.name, 'newName')
+ self.assertTrue(table.rename("newName"))
+ self.assertEqual(table.name, "newName")
connection.reconnect()
@@ -183,28 +190,28 @@ def testCreateRenameDeleteTable(self):
tables = db.tables()
self.assertEqual(len(tables), 1)
table = tables[0]
- self.assertEqual(table.name, 'newName')
+ self.assertEqual(table.name, "newName")
fields = []
- geom = ['geometry', 'POINT', 4326, 3]
+ geom = ["geometry", "POINT", 4326, 3]
field1 = TableField(table)
- field1.name = 'fid'
- field1.dataType = 'INTEGER'
+ field1.name = "fid"
+ field1.dataType = "INTEGER"
field1.notNull = True
field1.primaryKey = True
field2 = TableField(table)
- field2.name = 'str_field'
- field2.dataType = 'TEXT'
+ field2.name = "str_field"
+ field2.dataType = "TEXT"
field2.modifier = 20
fields = [field1, field2]
- self.assertTrue(db.createVectorTable('newName2', fields, geom))
+ self.assertTrue(db.createVectorTable("newName2", fields, geom))
tables = db.tables()
self.assertEqual(len(tables), 2)
new_table = tables[1]
- self.assertEqual(new_table.name, 'newName2')
+ self.assertEqual(new_table.name, "newName2")
fields = new_table.fields()
self.assertEqual(len(fields), 2)
@@ -226,17 +233,19 @@ def testCreateRenameDeleteFields(self):
if not self.supportsAlterFieldDefn:
return
- connection_name = 'testCreateRenameDeleteFields'
- plugin = createDbPlugin('spatialite')
+ connection_name = "testCreateRenameDeleteFields"
+ plugin = createDbPlugin("spatialite")
uri = QgsDataSourceUri()
- test_spatialite_new = os.path.join(self.basetestpath, 'testCreateRenameDeleteFields.spatialite')
+ test_spatialite_new = os.path.join(
+ self.basetestpath, "testCreateRenameDeleteFields.spatialite"
+ )
shutil.copy(self.test_spatialite, test_spatialite_new)
uri.setDatabase(test_spatialite_new)
self.assertTrue(plugin.addConnection(connection_name, uri))
- connection = createDbPlugin('spatialite', connection_name)
+ connection = createDbPlugin("spatialite", connection_name)
connection.connect()
db = connection.database()
@@ -249,8 +258,8 @@ def testCreateRenameDeleteFields(self):
field_before_count = len(table.fields())
field = TableField(table)
- field.name = 'real_field'
- field.dataType = 'DOUBLE'
+ field.name = "real_field"
+ field.dataType = "DOUBLE"
self.assertTrue(table.addField(field))
self.assertEqual(len(table.fields()), field_before_count + 1)
@@ -259,8 +268,8 @@ def testCreateRenameDeleteFields(self):
# self.assertTrue(field.update('real_field2', new_type_str='TEXT (30)', new_not_null=True, new_default_str='foo'))
field = table.fields()[field_before_count]
- self.assertEqual(field.name, 'real_field')
- self.assertEqual(field.dataType, 'DOUBLE')
+ self.assertEqual(field.name, "real_field")
+ self.assertEqual(field.dataType, "DOUBLE")
# self.assertEqual(field.notNull, 1)
# self.assertEqual(field.default, "'foo'")
@@ -271,13 +280,13 @@ def testCreateRenameDeleteFields(self):
connection.remove()
def testTableDataModel(self):
- connection_name = 'testTableDataModel'
- plugin = createDbPlugin('spatialite')
+ connection_name = "testTableDataModel"
+ plugin = createDbPlugin("spatialite")
uri = QgsDataSourceUri()
uri.setDatabase(self.test_spatialite)
self.assertTrue(plugin.addConnection(connection_name, uri))
- connection = createDbPlugin('spatialite', connection_name)
+ connection = createDbPlugin("spatialite", connection_name)
connection.connect()
db = connection.database()
@@ -286,7 +295,7 @@ def testTableDataModel(self):
tables = db.tables()
self.assertEqual(len(tables), 1)
table = tables[0]
- self.assertEqual(table.name, 'testlayer')
+ self.assertEqual(table.name, "testlayer")
model = table.tableDataModel(None)
self.assertEqual(model.rowCount(), 1)
@@ -294,9 +303,9 @@ def testTableDataModel(self):
wkb = model.getData(0, 1)
geometry = ogr.CreateGeometryFromWkb(wkb)
- self.assertEqual(geometry.ExportToWkt(), 'LINESTRING (1 2,3 4)')
+ self.assertEqual(geometry.ExportToWkt(), "LINESTRING (1 2,3 4)")
- self.assertEqual(model.getData(0, 2), 'foo')
+ self.assertEqual(model.getData(0, 2), "foo")
connection.remove()
@@ -379,16 +388,16 @@ def testTableDataModel(self):
def testNonSpatial(self):
- connection_name = 'testnonspatial'
- plugin = createDbPlugin('spatialite')
+ connection_name = "testnonspatial"
+ plugin = createDbPlugin("spatialite")
uri = QgsDataSourceUri()
- test_spatialite = os.path.join(self.basetestpath, 'testnonspatial.spatialite')
- ds = ogr.GetDriverByName('SQLite').CreateDataSource(test_spatialite)
- lyr = ds.CreateLayer('testnonspatial', geom_type=ogr.wkbNone)
- lyr.CreateField(ogr.FieldDefn('text_field', ogr.OFTString))
+ test_spatialite = os.path.join(self.basetestpath, "testnonspatial.spatialite")
+ ds = ogr.GetDriverByName("SQLite").CreateDataSource(test_spatialite)
+ lyr = ds.CreateLayer("testnonspatial", geom_type=ogr.wkbNone)
+ lyr.CreateField(ogr.FieldDefn("text_field", ogr.OFTString))
f = ogr.Feature(lyr.GetLayerDefn())
- f['text_field'] = 'foo'
+ f["text_field"] = "foo"
lyr.CreateFeature(f)
f = None
ds = None
@@ -396,7 +405,7 @@ def testNonSpatial(self):
uri.setDatabase(test_spatialite)
self.assertTrue(plugin.addConnection(connection_name, uri))
- connection = createDbPlugin('spatialite', connection_name)
+ connection = createDbPlugin("spatialite", connection_name)
connection.connect()
db = connection.database()
@@ -405,7 +414,7 @@ def testNonSpatial(self):
tables = db.tables()
self.assertEqual(len(tables), 1)
table = tables[0]
- self.assertEqual(table.name, 'testnonspatial')
+ self.assertEqual(table.name, "testnonspatial")
info = table.info()
# expected_html = """General info Relation type: Table Rows: 1
"""
@@ -420,30 +429,32 @@ def testNonSpatial(self):
def testAllGeometryTypes(self):
- connection_name = 'testAllGeometryTypes'
- plugin = createDbPlugin('spatialite')
+ connection_name = "testAllGeometryTypes"
+ plugin = createDbPlugin("spatialite")
uri = QgsDataSourceUri()
- test_spatialite = os.path.join(self.basetestpath, 'testAllGeometryTypes.spatialite')
- ds = ogr.GetDriverByName('SQLite').CreateDataSource(test_spatialite)
- ds.CreateLayer('testPoint', geom_type=ogr.wkbPoint)
- ds.CreateLayer('testLineString', geom_type=ogr.wkbLineString)
- ds.CreateLayer('testPolygon', geom_type=ogr.wkbPolygon)
- ds.CreateLayer('testMultiPoint', geom_type=ogr.wkbMultiPoint)
- ds.CreateLayer('testMultiLineString', geom_type=ogr.wkbMultiLineString)
- ds.CreateLayer('testMultiPolygon', geom_type=ogr.wkbMultiPolygon)
- ds.CreateLayer('testGeometryCollection', geom_type=ogr.wkbGeometryCollection)
- ds.CreateLayer('testCircularString', geom_type=ogr.wkbCircularString)
- ds.CreateLayer('testCompoundCurve', geom_type=ogr.wkbCompoundCurve)
- ds.CreateLayer('testCurvePolygon', geom_type=ogr.wkbCurvePolygon)
- ds.CreateLayer('testMultiCurve', geom_type=ogr.wkbMultiCurve)
- ds.CreateLayer('testMultiSurface', geom_type=ogr.wkbMultiSurface)
+ test_spatialite = os.path.join(
+ self.basetestpath, "testAllGeometryTypes.spatialite"
+ )
+ ds = ogr.GetDriverByName("SQLite").CreateDataSource(test_spatialite)
+ ds.CreateLayer("testPoint", geom_type=ogr.wkbPoint)
+ ds.CreateLayer("testLineString", geom_type=ogr.wkbLineString)
+ ds.CreateLayer("testPolygon", geom_type=ogr.wkbPolygon)
+ ds.CreateLayer("testMultiPoint", geom_type=ogr.wkbMultiPoint)
+ ds.CreateLayer("testMultiLineString", geom_type=ogr.wkbMultiLineString)
+ ds.CreateLayer("testMultiPolygon", geom_type=ogr.wkbMultiPolygon)
+ ds.CreateLayer("testGeometryCollection", geom_type=ogr.wkbGeometryCollection)
+ ds.CreateLayer("testCircularString", geom_type=ogr.wkbCircularString)
+ ds.CreateLayer("testCompoundCurve", geom_type=ogr.wkbCompoundCurve)
+ ds.CreateLayer("testCurvePolygon", geom_type=ogr.wkbCurvePolygon)
+ ds.CreateLayer("testMultiCurve", geom_type=ogr.wkbMultiCurve)
+ ds.CreateLayer("testMultiSurface", geom_type=ogr.wkbMultiSurface)
ds = None
uri.setDatabase(test_spatialite)
self.assertTrue(plugin.addConnection(connection_name, uri))
- connection = createDbPlugin('spatialite', connection_name)
+ connection = createDbPlugin("spatialite", connection_name)
connection.connect()
db = connection.database()
@@ -457,5 +468,5 @@ def testAllGeometryTypes(self):
connection.remove()
-if __name__ == '__main__':
+if __name__ == "__main__":
unittest.main()
diff --git a/tests/src/python/test_db_manager_sql_window.py b/tests/src/python/test_db_manager_sql_window.py
index fff40ec7faac..374d281bded4 100644
--- a/tests/src/python/test_db_manager_sql_window.py
+++ b/tests/src/python/test_db_manager_sql_window.py
@@ -7,9 +7,10 @@
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
"""
-__author__ = 'Stephen Knox'
-__date__ = '2019-08-27'
-__copyright__ = 'Copyright 2019, Stephen Knox'
+
+__author__ = "Stephen Knox"
+__date__ = "2019-08-27"
+__copyright__ = "Copyright 2019, Stephen Knox"
from plugins.db_manager.dlg_sql_window import check_comments_in_sql
from qgis.testing import unittest
@@ -29,11 +30,15 @@ def test_check_comment_parsing(self):
# One comment with a new line
query = "SELECT * FROM test -- WHERE a = 1 \n ORDER BY b"
- self.assertEqual(check_comments_in_sql(query), "SELECT * FROM test ORDER BY b")
+ self.assertEqual(
+ check_comments_in_sql(query), "SELECT * FROM test ORDER BY b"
+ )
# One comment with 2 new lines
query = "SELECT * FROM test \n-- WHERE a = 1 \n ORDER BY b"
- self.assertEqual(check_comments_in_sql(query), "SELECT * FROM test ORDER BY b")
+ self.assertEqual(
+ check_comments_in_sql(query), "SELECT * FROM test ORDER BY b"
+ )
# Only comment
query = "--SELECT * FROM test"
@@ -48,5 +53,5 @@ def test_check_comment_parsing(self):
self.assertEqual(check_comments_in_sql(query), query)
-if __name__ == '__main__':
+if __name__ == "__main__":
unittest.main()
diff --git a/tests/src/python/test_disabled_tests.py b/tests/src/python/test_disabled_tests.py
index 6b920946b00a..64d18e0147ac 100644
--- a/tests/src/python/test_disabled_tests.py
+++ b/tests/src/python/test_disabled_tests.py
@@ -5,9 +5,10 @@
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
"""
-__author__ = 'Nyall Dawson'
-__date__ = '10/08/2022'
-__copyright__ = 'Copyright 2022, The QGIS Project'
+
+__author__ = "Nyall Dawson"
+__date__ = "10/08/2022"
+__copyright__ = "Copyright 2022, The QGIS Project"
import os
import shutil
@@ -38,12 +39,18 @@ def createChildren(self):
children = []
# Add a Python object as child
- pyQgsLayerItem = PyQgsLayerItem(None, "name", "", "uri", QgsLayerItem.LayerType.Vector, "my_provider")
+ pyQgsLayerItem = PyQgsLayerItem(
+ None, "name", "", "uri", QgsLayerItem.LayerType.Vector, "my_provider"
+ )
pyQgsLayerItem.tabSetDestroyedFlag = self.tabSetDestroyedFlag
children.append(pyQgsLayerItem)
# Add a C++ object as child
- children.append(QgsLayerItem(None, "name2", "", "uri", QgsLayerItem.LayerType.Vector, "my_provider"))
+ children.append(
+ QgsLayerItem(
+ None, "name2", "", "uri", QgsLayerItem.LayerType.Vector, "my_provider"
+ )
+ )
return children
@@ -65,12 +72,14 @@ class TestQgsDisabledTests(QgisTestCase):
def setUpClass(cls):
"""Run before all tests."""
super().setUpClass()
- testPath = TEST_DATA_DIR + '/' + 'bug_17878.gpkg'
+ testPath = TEST_DATA_DIR + "/" + "bug_17878.gpkg"
# Copy it
tempdir = tempfile.mkdtemp()
- testPathCopy = os.path.join(tempdir, 'bug_17878.gpkg')
+ testPathCopy = os.path.join(tempdir, "bug_17878.gpkg")
shutil.copy(testPath, testPathCopy)
- cls.vl = QgsVectorLayer(testPathCopy + '|layername=bug_17878', "test_data", "ogr")
+ cls.vl = QgsVectorLayer(
+ testPathCopy + "|layername=bug_17878", "test_data", "ogr"
+ )
assert cls.vl.isValid()
@classmethod
@@ -85,7 +94,7 @@ def test_dummy(self):
"""
pass
- @unittest.skipIf(QT_VERSION >= 0x050d00, 'Crashes on newer Qt/PyQt versions')
+ @unittest.skipIf(QT_VERSION >= 0x050D00, "Crashes on newer Qt/PyQt versions")
def testPythonCreateChildrenCalledFromCplusplus(self):
"""
test createChildren() method implemented in Python, called from C++
@@ -151,23 +160,25 @@ def _fld_checker(self, field):
QValidator::Intermediate 1 The string is a plausible intermediate value.
QValidator::Acceptable 2 The string is acceptable as a final result; i.e. it is valid.
"""
- validator = QgsFieldValidator(None, field, '0.0', '')
+ validator = QgsFieldValidator(None, field, "0.0", "")
def _test(value, expected):
ret = validator.validate(value, 0)
self.assertEqual(ret[0], expected)
if value:
- self.assertEqual(validator.validate('-' + value, 0)[0], expected, '-' + value)
+ self.assertEqual(
+ validator.validate("-" + value, 0)[0], expected, "-" + value
+ )
# Valid
- _test('0.1234', QValidator.State.Acceptable)
+ _test("0.1234", QValidator.State.Acceptable)
# If precision is > 0, regexp validator is used (and it does not support sci notation)
if field.precision() == 0:
- _test('12345.1234e+123', QValidator.State.Acceptable)
- _test('12345.1234e-123', QValidator.State.Acceptable)
+ _test("12345.1234e+123", QValidator.State.Acceptable)
+ _test("12345.1234e-123", QValidator.State.Acceptable)
- @unittest.skipIf(QT_VERSION >= 0x050d00, 'Fails newer Qt/PyQt versions')
+ @unittest.skipIf(QT_VERSION >= 0x050D00, "Fails newer Qt/PyQt versions")
def test_doubleValidatorCommaLocale(self):
"""Test the double with german locale
@@ -182,10 +193,10 @@ def test_doubleValidatorCommaLocale(self):
When fixed these tests should be merged back into test_qgsfieldvalidator.py
"""
QLocale.setDefault(QLocale(QLocale.Language.German, QLocale.Country.Germany))
- self.assertEqual(QLocale().decimalPoint(), ',')
- field = self.vl.fields()[self.vl.fields().indexFromName('double_field')]
+ self.assertEqual(QLocale().decimalPoint(), ",")
+ field = self.vl.fields()[self.vl.fields().indexFromName("double_field")]
self._fld_checker(field)
-if __name__ == '__main__':
+if __name__ == "__main__":
unittest.main()
diff --git a/tests/src/python/test_hana_utils.py b/tests/src/python/test_hana_utils.py
index edace17e8d8c..5955616c7a53 100644
--- a/tests/src/python/test_hana_utils.py
+++ b/tests/src/python/test_hana_utils.py
@@ -7,9 +7,9 @@
"""
-__author__ = 'Maxim Rylov'
-__date__ = '2019-11-21'
-__copyright__ = 'Copyright 2019, The QGIS Project'
+__author__ = "Maxim Rylov"
+__date__ = "2019-11-21"
+__copyright__ = "Copyright 2019, The QGIS Project"
from hdbcli import dbapi
from qgis.core import QgsDataSourceUri, QgsVectorLayer
@@ -21,14 +21,21 @@ class QgsHanaProviderUtils:
def createConnection(uri):
ds_uri = QgsDataSourceUri(uri)
encrypt = ds_uri.param("ENCRYPT") if ds_uri.hasParam("ENCRYPT") else True
- conn = dbapi.connect(address=ds_uri.host(), port=ds_uri.port(), user=ds_uri.username(),
- password=ds_uri.password(), ENCRYPT=encrypt, sslValidateCertificate=False, CHAR_AS_UTF8=1)
+ conn = dbapi.connect(
+ address=ds_uri.host(),
+ port=ds_uri.port(),
+ user=ds_uri.username(),
+ password=ds_uri.password(),
+ ENCRYPT=encrypt,
+ sslValidateCertificate=False,
+ CHAR_AS_UTF8=1,
+ )
conn.setautocommit(False)
return conn
@staticmethod
def createVectorLayer(conn_parameters, layer_name):
- layer = QgsVectorLayer(conn_parameters, layer_name, 'hana')
+ layer = QgsVectorLayer(conn_parameters, layer_name, "hana")
assert layer.isValid()
return layer
@@ -64,18 +71,25 @@ def createAndFillTable(conn, create_statement, insert_statement, insert_args):
@staticmethod
def dropTableIfExists(conn, schema_name, table_name):
- res = QgsHanaProviderUtils.executeSQLFetchOne(conn,
- f"SELECT COUNT(*) FROM SYS.TABLES WHERE "
- f"SCHEMA_NAME='{schema_name}' AND TABLE_NAME='{table_name}'")
+ res = QgsHanaProviderUtils.executeSQLFetchOne(
+ conn,
+ f"SELECT COUNT(*) FROM SYS.TABLES WHERE "
+ f"SCHEMA_NAME='{schema_name}' AND TABLE_NAME='{table_name}'",
+ )
if res != 0:
- QgsHanaProviderUtils.executeSQL(conn, f'DROP TABLE "{schema_name}"."{table_name}" CASCADE')
+ QgsHanaProviderUtils.executeSQL(
+ conn, f'DROP TABLE "{schema_name}"."{table_name}" CASCADE'
+ )
@staticmethod
def dropSchemaIfExists(conn, schema_name):
- res = QgsHanaProviderUtils.executeSQLFetchOne(conn,
- f"SELECT COUNT(*) FROM SYS.SCHEMAS WHERE SCHEMA_NAME='{schema_name}'")
+ res = QgsHanaProviderUtils.executeSQLFetchOne(
+ conn, f"SELECT COUNT(*) FROM SYS.SCHEMAS WHERE SCHEMA_NAME='{schema_name}'"
+ )
if res != 0:
- QgsHanaProviderUtils.executeSQL(conn, f'DROP SCHEMA "{schema_name}" CASCADE')
+ QgsHanaProviderUtils.executeSQL(
+ conn, f'DROP SCHEMA "{schema_name}" CASCADE'
+ )
@staticmethod
def createAndFillDefaultTables(conn, schema_name):
@@ -83,43 +97,105 @@ def createAndFillDefaultTables(conn, schema_name):
QgsHanaProviderUtils.executeSQL(conn, f'CREATE SCHEMA "{schema_name}"')
- create_sql = f'CREATE TABLE "{schema_name}"."some_data" ( ' \
- '"pk" INTEGER GENERATED BY DEFAULT AS IDENTITY NOT NULL PRIMARY KEY,' \
- '"cnt" INTEGER,' \
- '"name" NVARCHAR(32) DEFAULT \'qgis\',' \
- '"name2" NVARCHAR(32) DEFAULT \'qgis\',' \
- '"num_char" NVARCHAR(1),' \
- '"dt" TIMESTAMP,' \
- '"date" DATE,' \
- '"time" TIME,' \
+ create_sql = (
+ f'CREATE TABLE "{schema_name}"."some_data" ( '
+ '"pk" INTEGER GENERATED BY DEFAULT AS IDENTITY NOT NULL PRIMARY KEY,'
+ '"cnt" INTEGER,'
+ "\"name\" NVARCHAR(32) DEFAULT 'qgis',"
+ "\"name2\" NVARCHAR(32) DEFAULT 'qgis',"
+ '"num_char" NVARCHAR(1),'
+ '"dt" TIMESTAMP,'
+ '"date" DATE,'
+ '"time" TIME,'
'"geom" ST_GEOMETRY(4326))'
- insert_sql = f'INSERT INTO "{schema_name}"."some_data" ("pk", "cnt", "name", "name2", "num_char", "dt",' \
+ )
+ insert_sql = (
+ f'INSERT INTO "{schema_name}"."some_data" ("pk", "cnt", "name", "name2", "num_char", "dt",'
'"date", "time", "geom") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ST_GeomFromEWKB(?)) '
+ )
insert_args = [
- [5, -200, None, 'NuLl', '5', '2020-05-04 12:13:14', '2020-05-02', '12:13:01',
- bytes.fromhex('0101000020E61000001D5A643BDFC751C01F85EB51B88E5340')],
- [3, 300, 'Pear', 'PEaR', '3', None, None, None, None],
- [1, 100, 'Orange', 'oranGe', '1', '2020-05-03 12:13:14', '2020-05-03', '12:13:14',
- bytes.fromhex('0101000020E61000006891ED7C3F9551C085EB51B81E955040')],
- [2, 200, 'Apple', 'Apple', '2', '2020-05-04 12:14:14', '2020-05-04', '12:14:14',
- bytes.fromhex('0101000020E6100000CDCCCCCCCC0C51C03333333333B35140')],
- [4, 400, 'Honey', 'Honey', '4', '2021-05-04 13:13:14', '2021-05-04', '13:13:14',
- bytes.fromhex('0101000020E610000014AE47E17A5450C03333333333935340')]]
- QgsHanaProviderUtils.createAndFillTable(conn, create_sql, insert_sql, insert_args)
- QgsHanaProviderUtils.executeSQL(conn, f'COMMENT ON TABLE "{schema_name}"."some_data" IS \'QGIS Test Table\'')
- QgsHanaProviderUtils.executeSQL(conn, f'CREATE VIEW "{schema_name}"."some_data_view" AS SELECT * FROM '
- f'"{schema_name}"."some_data"')
-
- create_sql = f'CREATE TABLE "{schema_name}"."some_poly_data" ( ' \
- '"pk" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,' \
+ [
+ 5,
+ -200,
+ None,
+ "NuLl",
+ "5",
+ "2020-05-04 12:13:14",
+ "2020-05-02",
+ "12:13:01",
+ bytes.fromhex("0101000020E61000001D5A643BDFC751C01F85EB51B88E5340"),
+ ],
+ [3, 300, "Pear", "PEaR", "3", None, None, None, None],
+ [
+ 1,
+ 100,
+ "Orange",
+ "oranGe",
+ "1",
+ "2020-05-03 12:13:14",
+ "2020-05-03",
+ "12:13:14",
+ bytes.fromhex("0101000020E61000006891ED7C3F9551C085EB51B81E955040"),
+ ],
+ [
+ 2,
+ 200,
+ "Apple",
+ "Apple",
+ "2",
+ "2020-05-04 12:14:14",
+ "2020-05-04",
+ "12:14:14",
+ bytes.fromhex("0101000020E6100000CDCCCCCCCC0C51C03333333333B35140"),
+ ],
+ [
+ 4,
+ 400,
+ "Honey",
+ "Honey",
+ "4",
+ "2021-05-04 13:13:14",
+ "2021-05-04",
+ "13:13:14",
+ bytes.fromhex("0101000020E610000014AE47E17A5450C03333333333935340"),
+ ],
+ ]
+ QgsHanaProviderUtils.createAndFillTable(
+ conn, create_sql, insert_sql, insert_args
+ )
+ QgsHanaProviderUtils.executeSQL(
+ conn, f'COMMENT ON TABLE "{schema_name}"."some_data" IS \'QGIS Test Table\''
+ )
+ QgsHanaProviderUtils.executeSQL(
+ conn,
+ f'CREATE VIEW "{schema_name}"."some_data_view" AS SELECT * FROM '
+ f'"{schema_name}"."some_data"',
+ )
+
+ create_sql = (
+ f'CREATE TABLE "{schema_name}"."some_poly_data" ( '
+ '"pk" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,'
'"geom" ST_GEOMETRY(4326))'
+ )
insert_sql = f'INSERT INTO "{schema_name}"."some_poly_data" ("pk", "geom") VALUES (?, ST_GeomFromText(?, 4326))'
insert_args = [
- [1, 'Polygon ((-69.0 81.4, -69.0 80.2, -73.7 80.2, -73.7 76.3, -74.9 76.3, -74.9 81.4, -69.0 81.4))'],
- [2, 'Polygon ((-67.6 81.2, -66.3 81.2, -66.3 76.9, -67.6 76.9, -67.6 81.2))'],
- [3, 'Polygon ((-68.4 75.8, -67.5 72.6, -68.6 73.7, -70.2 72.9, -68.4 75.8))'],
- [4, None]]
- QgsHanaProviderUtils.createAndFillTable(conn, create_sql, insert_sql, insert_args)
+ [
+ 1,
+ "Polygon ((-69.0 81.4, -69.0 80.2, -73.7 80.2, -73.7 76.3, -74.9 76.3, -74.9 81.4, -69.0 81.4))",
+ ],
+ [
+ 2,
+ "Polygon ((-67.6 81.2, -66.3 81.2, -66.3 76.9, -67.6 76.9, -67.6 81.2))",
+ ],
+ [
+ 3,
+ "Polygon ((-68.4 75.8, -67.5 72.6, -68.6 73.7, -70.2 72.9, -68.4 75.8))",
+ ],
+ [4, None],
+ ]
+ QgsHanaProviderUtils.createAndFillTable(
+ conn, create_sql, insert_sql, insert_args
+ )
@staticmethod
def cleanUp(conn, schema_name):
@@ -129,4 +205,4 @@ def cleanUp(conn, schema_name):
def generateSchemaName(conn, prefix):
sql = "SELECT REPLACE(CURRENT_UTCDATE, '-', '') || '_' || BINTOHEX(SYSUUID) FROM DUMMY;"
uid = QgsHanaProviderUtils.executeSQL(conn, sql, return_result=True)
- return f'{prefix}_{uid}'
+ return f"{prefix}_{uid}"
diff --git a/tests/src/python/test_layer_dependencies.py b/tests/src/python/test_layer_dependencies.py
index 4001279f054f..8603a4fdb648 100644
--- a/tests/src/python/test_layer_dependencies.py
+++ b/tests/src/python/test_layer_dependencies.py
@@ -5,9 +5,10 @@
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
"""
-__author__ = 'Hugo Mercier'
-__date__ = '12/07/2016'
-__copyright__ = 'Copyright 2016, The QGIS Project'
+
+__author__ = "Hugo Mercier"
+__date__ = "12/07/2016"
+__copyright__ = "Copyright 2016, The QGIS Project"
import os
import tempfile
@@ -50,24 +51,42 @@ def setUp(self):
cur.execute("SELECT InitSpatialMetadata(1)")
cur.execute("create table node(id integer primary key autoincrement);")
cur.execute("select AddGeometryColumn('node', 'geom', 4326, 'POINT');")
- cur.execute("create table section(id integer primary key autoincrement, node1 integer, node2 integer);")
+ cur.execute(
+ "create table section(id integer primary key autoincrement, node1 integer, node2 integer);"
+ )
cur.execute("select AddGeometryColumn('section', 'geom', 4326, 'LINESTRING');")
- cur.execute("create trigger add_nodes after insert on section begin insert into node (geom) values (st_startpoint(NEW.geom)); insert into node (geom) values (st_endpoint(NEW.geom)); end;")
- cur.execute("insert into node (geom) values (geomfromtext('point(0 0)', 4326));")
- cur.execute("insert into node (geom) values (geomfromtext('point(1 0)', 4326));")
+ cur.execute(
+ "create trigger add_nodes after insert on section begin insert into node (geom) values (st_startpoint(NEW.geom)); insert into node (geom) values (st_endpoint(NEW.geom)); end;"
+ )
+ cur.execute(
+ "insert into node (geom) values (geomfromtext('point(0 0)', 4326));"
+ )
+ cur.execute(
+ "insert into node (geom) values (geomfromtext('point(1 0)', 4326));"
+ )
cur.execute("create table node2(id integer primary key autoincrement);")
cur.execute("select AddGeometryColumn('node2', 'geom', 4326, 'POINT');")
- cur.execute("create trigger add_nodes2 after insert on node begin insert into node2 (geom) values (st_translate(NEW.geom, 0.2, 0, 0)); end;")
+ cur.execute(
+ "create trigger add_nodes2 after insert on node begin insert into node2 (geom) values (st_translate(NEW.geom, 0.2, 0, 0)); end;"
+ )
con.commit()
con.close()
- self.pointsLayer = QgsVectorLayer(f"dbname='{fn}' table=\"node\" (geom) sql=", "points", "spatialite")
- assert (self.pointsLayer.isValid())
- self.linesLayer = QgsVectorLayer(f"dbname='{fn}' table=\"section\" (geom) sql=", "lines", "spatialite")
- assert (self.linesLayer.isValid())
- self.pointsLayer2 = QgsVectorLayer(f"dbname='{fn}' table=\"node2\" (geom) sql=", "_points2", "spatialite")
- assert (self.pointsLayer2.isValid())
- QgsProject.instance().addMapLayers([self.pointsLayer, self.linesLayer, self.pointsLayer2])
+ self.pointsLayer = QgsVectorLayer(
+ f"dbname='{fn}' table=\"node\" (geom) sql=", "points", "spatialite"
+ )
+ assert self.pointsLayer.isValid()
+ self.linesLayer = QgsVectorLayer(
+ f"dbname='{fn}' table=\"section\" (geom) sql=", "lines", "spatialite"
+ )
+ assert self.linesLayer.isValid()
+ self.pointsLayer2 = QgsVectorLayer(
+ f"dbname='{fn}' table=\"node2\" (geom) sql=", "_points2", "spatialite"
+ )
+ assert self.pointsLayer2.isValid()
+ QgsProject.instance().addMapLayers(
+ [self.pointsLayer, self.linesLayer, self.pointsLayer2]
+ )
# save the project file
fo = tempfile.NamedTemporaryFile()
@@ -97,9 +116,12 @@ def test_resetSnappingIndex(self):
cfg = u.config()
cfg.setEnabled(True)
cfg.setMode(Qgis.SnappingMode.AdvancedConfiguration)
- cfg.setIndividualLayerSettings(self.pointsLayer,
- QgsSnappingConfig.IndividualLayerSettings(True,
- Qgis.SnappingType.Vertex, 20, Qgis.MapToolUnit.Pixels, 0.0, 0.0))
+ cfg.setIndividualLayerSettings(
+ self.pointsLayer,
+ QgsSnappingConfig.IndividualLayerSettings(
+ True, Qgis.SnappingType.Vertex, 20, Qgis.MapToolUnit.Pixels, 0.0, 0.0
+ ),
+ )
u.setConfig(cfg)
m = u.snapToMap(QPoint(95, 100))
@@ -140,12 +162,17 @@ def test_resetSnappingIndex(self):
self.pointsLayer.setDependencies([])
# test chained layer dependencies A -> B -> C
- cfg.setIndividualLayerSettings(self.pointsLayer2,
- QgsSnappingConfig.IndividualLayerSettings(True,
- Qgis.SnappingType.Vertex, 20, Qgis.MapToolUnit.Pixels, 0.0, 0.0))
+ cfg.setIndividualLayerSettings(
+ self.pointsLayer2,
+ QgsSnappingConfig.IndividualLayerSettings(
+ True, Qgis.SnappingType.Vertex, 20, Qgis.MapToolUnit.Pixels, 0.0, 0.0
+ ),
+ )
u.setConfig(cfg)
self.pointsLayer.setDependencies([QgsMapLayerDependency(self.linesLayer.id())])
- self.pointsLayer2.setDependencies([QgsMapLayerDependency(self.pointsLayer.id())])
+ self.pointsLayer2.setDependencies(
+ [QgsMapLayerDependency(self.pointsLayer.id())]
+ )
# add another line
f = QgsFeature(self.linesLayer.fields())
f.setId(3)
@@ -170,13 +197,21 @@ def test_circular_dependencies_with_2_layers(self):
spy_lines_repaint_requested = QSignalSpy(self.linesLayer.repaintRequested)
# only points fire dataChanged because we change its dependencies
- self.assertTrue(self.pointsLayer.setDependencies([QgsMapLayerDependency(self.linesLayer.id())]))
+ self.assertTrue(
+ self.pointsLayer.setDependencies(
+ [QgsMapLayerDependency(self.linesLayer.id())]
+ )
+ )
self.assertEqual(len(spy_points_data_changed), 1)
self.assertEqual(len(spy_lines_data_changed), 0)
# lines fire dataChanged because we changes its dependencies
# points fire dataChanged because it depends on line
- self.assertTrue(self.linesLayer.setDependencies([QgsMapLayerDependency(self.pointsLayer.id())]))
+ self.assertTrue(
+ self.linesLayer.setDependencies(
+ [QgsMapLayerDependency(self.pointsLayer.id())]
+ )
+ )
self.assertEqual(len(spy_points_data_changed), 2)
self.assertEqual(len(spy_lines_data_changed), 1)
@@ -223,7 +258,11 @@ def test_circular_dependencies_with_1_layer(self):
spy_lines_repaint_requested = QSignalSpy(self.linesLayer.repaintRequested)
# line fire dataChanged because we change its dependencies
- self.assertTrue(self.linesLayer.setDependencies([QgsMapLayerDependency(self.linesLayer.id())]))
+ self.assertTrue(
+ self.linesLayer.setDependencies(
+ [QgsMapLayerDependency(self.linesLayer.id())]
+ )
+ )
self.assertEqual(len(spy_lines_data_changed), 1)
f = QgsFeature(self.linesLayer.fields())
@@ -245,7 +284,9 @@ def test_circular_dependencies_with_1_layer(self):
self.assertGreaterEqual(len(spy_lines_repaint_requested), 2)
# line fire dataChanged on geometryChanged
- self.linesLayer.changeGeometry(f.id(), QgsGeometry.fromWkt("LINESTRING(0 0, 2 2)"))
+ self.linesLayer.changeGeometry(
+ f.id(), QgsGeometry.fromWkt("LINESTRING(0 0, 2 2)")
+ )
self.assertEqual(len(spy_lines_data_changed), 4)
# commit changes fires dataChanged because external changes could happen (provider side)
@@ -267,13 +308,15 @@ def test_layerDefinitionRewriteId(self):
newPointsLayer = None
newLinesLayer = None
for l in grp.findLayers():
- if l.layerId().startswith('points'):
+ if l.layerId().startswith("points"):
newPointsLayer = l.layer()
- elif l.layerId().startswith('lines'):
+ elif l.layerId().startswith("lines"):
newLinesLayer = l.layer()
self.assertIsNotNone(newPointsLayer)
self.assertIsNotNone(newLinesLayer)
- self.assertIn(newLinesLayer.id(), [dep.layerId() for dep in newPointsLayer.dependencies()])
+ self.assertIn(
+ newLinesLayer.id(), [dep.layerId() for dep in newPointsLayer.dependencies()]
+ )
self.pointsLayer.setDependencies([])
@@ -281,14 +324,22 @@ def test_signalConnection(self):
# remove all layers
QgsProject.instance().removeAllMapLayers()
# set dependencies and add back layers
- self.pointsLayer = QgsVectorLayer(f"dbname='{self.fn}' table=\"node\" (geom) sql=", "points", "spatialite")
+ self.pointsLayer = QgsVectorLayer(
+ f"dbname='{self.fn}' table=\"node\" (geom) sql=", "points", "spatialite"
+ )
self.assertTrue(self.pointsLayer.isValid())
- self.linesLayer = QgsVectorLayer(f"dbname='{self.fn}' table=\"section\" (geom) sql=", "lines", "spatialite")
+ self.linesLayer = QgsVectorLayer(
+ f"dbname='{self.fn}' table=\"section\" (geom) sql=", "lines", "spatialite"
+ )
self.assertTrue(self.linesLayer.isValid())
- self.pointsLayer2 = QgsVectorLayer(f"dbname='{self.fn}' table=\"node2\" (geom) sql=", "_points2", "spatialite")
+ self.pointsLayer2 = QgsVectorLayer(
+ f"dbname='{self.fn}' table=\"node2\" (geom) sql=", "_points2", "spatialite"
+ )
self.assertTrue(self.pointsLayer2.isValid())
self.pointsLayer.setDependencies([QgsMapLayerDependency(self.linesLayer.id())])
- self.pointsLayer2.setDependencies([QgsMapLayerDependency(self.pointsLayer.id())])
+ self.pointsLayer2.setDependencies(
+ [QgsMapLayerDependency(self.pointsLayer.id())]
+ )
# this should update connections between layers
QgsProject.instance().addMapLayers([self.pointsLayer])
QgsProject.instance().addMapLayers([self.linesLayer])
@@ -304,12 +355,18 @@ def test_signalConnection(self):
cfg = u.config()
cfg.setEnabled(True)
cfg.setMode(Qgis.SnappingMode.AdvancedConfiguration)
- cfg.setIndividualLayerSettings(self.pointsLayer,
- QgsSnappingConfig.IndividualLayerSettings(True,
- Qgis.SnappingType.Vertex, 20, Qgis.MapToolUnit.Pixels, 0.0, 0.0))
- cfg.setIndividualLayerSettings(self.pointsLayer2,
- QgsSnappingConfig.IndividualLayerSettings(True,
- Qgis.SnappingType.Vertex, 20, Qgis.MapToolUnit.Pixels, 0.0, 0.0))
+ cfg.setIndividualLayerSettings(
+ self.pointsLayer,
+ QgsSnappingConfig.IndividualLayerSettings(
+ True, Qgis.SnappingType.Vertex, 20, Qgis.MapToolUnit.Pixels, 0.0, 0.0
+ ),
+ )
+ cfg.setIndividualLayerSettings(
+ self.pointsLayer2,
+ QgsSnappingConfig.IndividualLayerSettings(
+ True, Qgis.SnappingType.Vertex, 20, Qgis.MapToolUnit.Pixels, 0.0, 0.0
+ ),
+ )
u.setConfig(cfg)
# add another line
f = QgsFeature(self.linesLayer.fields())
@@ -329,5 +386,5 @@ def test_signalConnection(self):
self.pointsLayer2.setDependencies([])
-if __name__ == '__main__':
+if __name__ == "__main__":
unittest.main()
diff --git a/tests/src/python/test_offline_editing_wfs.py b/tests/src/python/test_offline_editing_wfs.py
index ed2654727f78..bbfa9431a1ed 100644
--- a/tests/src/python/test_offline_editing_wfs.py
+++ b/tests/src/python/test_offline_editing_wfs.py
@@ -20,9 +20,9 @@
(at your option) any later version.
"""
-__author__ = 'Alessandro Pasotti'
-__date__ = '05/15/2016'
-__copyright__ = 'Copyright 2016, The QGIS Project'
+__author__ = "Alessandro Pasotti"
+__date__ = "05/15/2016"
+__copyright__ = "Copyright 2016, The QGIS Project"
import os
import re
@@ -39,9 +39,9 @@
from utilities import unitTestDataPath, waitServer
try:
- QGIS_SERVER_OFFLINE_PORT = os.environ['QGIS_SERVER_OFFLINE_PORT']
+ QGIS_SERVER_OFFLINE_PORT = os.environ["QGIS_SERVER_OFFLINE_PORT"]
except:
- QGIS_SERVER_OFFLINE_PORT = '0' # Auto
+ QGIS_SERVER_OFFLINE_PORT = "0" # Auto
qgis_app = start_app()
@@ -53,57 +53,63 @@ class TestWFST(QgisTestCase, OfflineTestBase):
@classmethod
def setUpClass(cls):
"""Run before all tests"""
- super(TestWFST, cls).setUpClass()
+ super().setUpClass()
cls.port = QGIS_SERVER_OFFLINE_PORT
# Create tmp folder
cls.temp_path = tempfile.mkdtemp()
- cls.testdata_path = cls.temp_path + '/' + 'wfs_transactional' + '/'
- copytree(unitTestDataPath('wfs_transactional') + '/',
- cls.temp_path + '/' + 'wfs_transactional')
- cls.project_path = cls.temp_path + '/' + 'wfs_transactional' + '/' + \
- 'wfs_transactional.qgs'
- assert os.path.exists(cls.project_path), "Project not found: %s" % \
- cls.project_path
+ cls.testdata_path = cls.temp_path + "/" + "wfs_transactional" + "/"
+ copytree(
+ unitTestDataPath("wfs_transactional") + "/",
+ cls.temp_path + "/" + "wfs_transactional",
+ )
+ cls.project_path = (
+ cls.temp_path + "/" + "wfs_transactional" + "/" + "wfs_transactional.qgs"
+ )
+ assert os.path.exists(cls.project_path), (
+ "Project not found: %s" % cls.project_path
+ )
# Clean env just to be sure
- env_vars = ['QUERY_STRING', 'QGIS_PROJECT_FILE']
+ env_vars = ["QUERY_STRING", "QGIS_PROJECT_FILE"]
for ev in env_vars:
try:
del os.environ[ev]
except KeyError:
pass
# Clear all test layers
- cls._clearLayer(cls._getLayer('test_point'))
- os.environ['QGIS_SERVER_PORT'] = str(cls.port)
- cls.server_path = os.path.dirname(os.path.realpath(__file__)) + \
- '/qgis_wrapped_server.py'
+ cls._clearLayer(cls._getLayer("test_point"))
+ os.environ["QGIS_SERVER_PORT"] = str(cls.port)
+ cls.server_path = (
+ os.path.dirname(os.path.realpath(__file__)) + "/qgis_wrapped_server.py"
+ )
@classmethod
def tearDownClass(cls):
"""Run after all tests"""
rmtree(cls.temp_path)
- super(TestWFST, cls).tearDownClass()
+ super().tearDownClass()
def setUp(self):
"""Run before each test."""
- self.server = subprocess.Popen([sys.executable, self.server_path],
- env=os.environ, stdout=subprocess.PIPE)
+ self.server = subprocess.Popen(
+ [sys.executable, self.server_path], env=os.environ, stdout=subprocess.PIPE
+ )
line = self.server.stdout.readline()
- self.port = int(re.findall(br':(\d+)', line)[0])
+ self.port = int(re.findall(rb":(\d+)", line)[0])
assert self.port != 0
# Wait for the server process to start
- assert waitServer(f'http://127.0.0.1:{self.port}'), "Server is not responding!"
+ assert waitServer(f"http://127.0.0.1:{self.port}"), "Server is not responding!"
self._setUp()
def tearDown(self):
"""Run after each test."""
# Clear test layer
- self._clearLayer(self._getOnlineLayer('test_point'))
+ self._clearLayer(self._getOnlineLayer("test_point"))
# Kill the server
self.server.terminate()
self.server.wait()
del self.server
# Delete the sqlite db
- os.unlink(os.path.join(self.temp_path, 'offlineDbFile.sqlite'))
+ os.unlink(os.path.join(self.temp_path, "offlineDbFile.sqlite"))
self._tearDown()
def _getOnlineLayer(self, type_name, layer_name=None):
@@ -111,20 +117,20 @@ def _getOnlineLayer(self, type_name, layer_name=None):
Return a new WFS layer, overriding the WFS cache
"""
if layer_name is None:
- layer_name = 'wfs_' + type_name
+ layer_name = "wfs_" + type_name
parms = {
- 'srsname': 'EPSG:4326',
- 'typename': type_name,
- 'url': 'http://127.0.0.1:{}/{}/?map={}'.format(self.port,
- self.counter,
- self.project_path),
- 'version': 'auto',
- 'table': '',
+ "srsname": "EPSG:4326",
+ "typename": type_name,
+ "url": "http://127.0.0.1:{}/{}/?map={}".format(
+ self.port, self.counter, self.project_path
+ ),
+ "version": "auto",
+ "table": "",
# 'sql': '',
}
self.counter += 1
- uri = ' '.join([(f"{k}='{v}'") for k, v in list(parms.items())])
- wfs_layer = QgsVectorLayer(uri, layer_name, 'WFS')
+ uri = " ".join([(f"{k}='{v}'") for k, v in list(parms.items())])
+ wfs_layer = QgsVectorLayer(uri, layer_name, "WFS")
wfs_layer.setParent(QgsApplication.authManager())
assert wfs_layer.isValid()
return wfs_layer
@@ -134,12 +140,12 @@ def _getLayer(cls, layer_name):
"""
Layer factory (return the backend layer), provider specific
"""
- path = cls.testdata_path + layer_name + '.shp'
+ path = cls.testdata_path + layer_name + ".shp"
layer = QgsVectorLayer(path, layer_name, "ogr")
layer.setParent(QgsApplication.authManager())
assert layer.isValid()
return layer
-if __name__ == '__main__':
+if __name__ == "__main__":
unittest.main()
diff --git a/tests/src/python/test_plugindependencies.py b/tests/src/python/test_plugindependencies.py
index 8315d606fc55..e01e71175ddb 100644
--- a/tests/src/python/test_plugindependencies.py
+++ b/tests/src/python/test_plugindependencies.py
@@ -7,9 +7,9 @@
"""
-__author__ = 'elpaso@itopen.it'
-__date__ = '2018-09-19'
-__copyright__ = 'Copyright 2018, GISCE-TI S.L.'
+__author__ = "elpaso@itopen.it"
+__date__ = "2018-09-19"
+__copyright__ = "Copyright 2018, GISCE-TI S.L."
import json
import os
@@ -40,20 +40,20 @@ def setUpClass(cls):
# Installed plugins
cls.installed_plugins = {
- 'MetaSearch': '0.3.5',
- 'QuickWKT': '3.1',
- 'db_manager': '0.1.20',
- 'firstaid': '2.1.1',
- 'InaSAFE': '5.0.0',
- 'ipyconsole': '1.8',
- 'plugin_reloader': '0.7.4',
- 'processing': '2.12.99',
- 'qgis-geocoding': '2.18',
- 'qgisce': '0.9',
- 'redistrict': '0.1'
+ "MetaSearch": "0.3.5",
+ "QuickWKT": "3.1",
+ "db_manager": "0.1.20",
+ "firstaid": "2.1.1",
+ "InaSAFE": "5.0.0",
+ "ipyconsole": "1.8",
+ "plugin_reloader": "0.7.4",
+ "processing": "2.12.99",
+ "qgis-geocoding": "2.18",
+ "qgisce": "0.9",
+ "redistrict": "0.1",
}
- data_path = os.path.join(TESTDATA_PATH, 'plugindependencies_data.json')
+ data_path = os.path.join(TESTDATA_PATH, "plugindependencies_data.json")
with open(data_path) as f:
cls.plugin_data = json.loads(f.read())
@@ -67,126 +67,157 @@ def tearDown(self):
def test_find_dependencies(self):
- to_install, to_upgrade, not_found = find_dependencies('qgisce',
- self.plugin_data,
- plugin_deps={'InaSAFE': None},
- installed_plugins=self.installed_plugins)
+ to_install, to_upgrade, not_found = find_dependencies(
+ "qgisce",
+ self.plugin_data,
+ plugin_deps={"InaSAFE": None},
+ installed_plugins=self.installed_plugins,
+ )
self.assertEqual(to_install, {})
self.assertEqual(to_upgrade, {})
self.assertEqual(not_found, {})
- to_install, to_upgrade, not_found = find_dependencies('qgisce',
- self.plugin_data,
- plugin_deps={'InaSAFE': '110.1'},
- installed_plugins=self.installed_plugins)
+ to_install, to_upgrade, not_found = find_dependencies(
+ "qgisce",
+ self.plugin_data,
+ plugin_deps={"InaSAFE": "110.1"},
+ installed_plugins=self.installed_plugins,
+ )
self.assertEqual(to_install, {})
self.assertEqual(to_upgrade, {})
- self.assertEqual(not_found['InaSAFE']['version_installed'], '5.0.0')
+ self.assertEqual(not_found["InaSAFE"]["version_installed"], "5.0.0")
# QuickWkt is installed, version is not specified: ignore
installed_plugins = self.installed_plugins
- installed_plugins['QuickWKT'] = '2.1'
- to_install, to_upgrade, not_found = find_dependencies('qgisce',
- self.plugin_data,
- plugin_deps={'QuickMapServices': '0.19.10.1',
- 'QuickWKT': None},
- installed_plugins=self.installed_plugins)
- self.assertEqual(to_install['QuickMapServices']['version_required'], '0.19.10.1')
- self.assertEqual(to_install['QuickMapServices']['version_available'], '0.19.10.1')
- self.assertEqual(to_install['QuickMapServices']['use_stable_version'], True)
+ installed_plugins["QuickWKT"] = "2.1"
+ to_install, to_upgrade, not_found = find_dependencies(
+ "qgisce",
+ self.plugin_data,
+ plugin_deps={"QuickMapServices": "0.19.10.1", "QuickWKT": None},
+ installed_plugins=self.installed_plugins,
+ )
+ self.assertEqual(
+ to_install["QuickMapServices"]["version_required"], "0.19.10.1"
+ )
+ self.assertEqual(
+ to_install["QuickMapServices"]["version_available"], "0.19.10.1"
+ )
+ self.assertEqual(to_install["QuickMapServices"]["use_stable_version"], True)
self.assertEqual(to_upgrade, {})
self.assertEqual(not_found, {})
# QuickWkt is installed, version requires upgrade and it's in the repo: upgrade
- to_install, to_upgrade, not_found = find_dependencies('qgisce',
- self.plugin_data,
- plugin_deps={'QuickWKT': '3.1'},
- installed_plugins=installed_plugins)
+ to_install, to_upgrade, not_found = find_dependencies(
+ "qgisce",
+ self.plugin_data,
+ plugin_deps={"QuickWKT": "3.1"},
+ installed_plugins=installed_plugins,
+ )
self.assertEqual(to_install, {})
- self.assertEqual(to_upgrade['QuickWKT']['version_required'], '3.1')
- self.assertEqual(to_upgrade['QuickWKT']['version_available'], '3.1')
- self.assertEqual(to_upgrade['QuickWKT']['use_stable_version'], True)
+ self.assertEqual(to_upgrade["QuickWKT"]["version_required"], "3.1")
+ self.assertEqual(to_upgrade["QuickWKT"]["version_available"], "3.1")
+ self.assertEqual(to_upgrade["QuickWKT"]["use_stable_version"], True)
self.assertEqual(not_found, {})
# QuickWkt is installed, version requires upgrade and it's NOT in the repo: not found
- to_install, to_upgrade, not_found = find_dependencies('qgisce',
- self.plugin_data,
- plugin_deps={'QuickWKT': '300.11234'},
- installed_plugins=installed_plugins)
+ to_install, to_upgrade, not_found = find_dependencies(
+ "qgisce",
+ self.plugin_data,
+ plugin_deps={"QuickWKT": "300.11234"},
+ installed_plugins=installed_plugins,
+ )
self.assertEqual(to_install, {})
self.assertEqual(to_upgrade, {})
- self.assertEqual(not_found['QuickWKT']['version_required'], '300.11234')
- self.assertEqual(not_found['QuickWKT']['version_installed'], '2.1')
- self.assertEqual(not_found['QuickWKT']['version_available'], '3.1')
+ self.assertEqual(not_found["QuickWKT"]["version_required"], "300.11234")
+ self.assertEqual(not_found["QuickWKT"]["version_installed"], "2.1")
+ self.assertEqual(not_found["QuickWKT"]["version_available"], "3.1")
# Installed version is > than required: ignore (no downgrade is currently possible)
- installed_plugins['QuickWKT'] = '300.1'
- to_install, to_upgrade, not_found = find_dependencies('qgisce',
- self.plugin_data,
- plugin_deps={'QuickWKT': '1.2'},
- installed_plugins=installed_plugins)
+ installed_plugins["QuickWKT"] = "300.1"
+ to_install, to_upgrade, not_found = find_dependencies(
+ "qgisce",
+ self.plugin_data,
+ plugin_deps={"QuickWKT": "1.2"},
+ installed_plugins=installed_plugins,
+ )
self.assertEqual(to_install, {})
self.assertEqual(to_upgrade, {})
self.assertEqual(not_found, {})
# A plugin offers both stable and experimental versions. A dependent plugin requires the experimental one.
- to_install, to_upgrade, not_found = find_dependencies('LADM-COL-Add-on-Ambiente',
- self.plugin_data,
- plugin_deps={'Asistente LADM-COL': '3.2.0-beta-1'},
- installed_plugins=self.installed_plugins)
- self.assertEqual(to_install['Asistente LADM-COL']['version_required'], '3.2.0-beta-1')
- self.assertEqual(to_install['Asistente LADM-COL']['version_available'], '3.2.0-beta-1')
- self.assertEqual(to_install['Asistente LADM-COL']['use_stable_version'], False)
+ to_install, to_upgrade, not_found = find_dependencies(
+ "LADM-COL-Add-on-Ambiente",
+ self.plugin_data,
+ plugin_deps={"Asistente LADM-COL": "3.2.0-beta-1"},
+ installed_plugins=self.installed_plugins,
+ )
+ self.assertEqual(
+ to_install["Asistente LADM-COL"]["version_required"], "3.2.0-beta-1"
+ )
+ self.assertEqual(
+ to_install["Asistente LADM-COL"]["version_available"], "3.2.0-beta-1"
+ )
+ self.assertEqual(to_install["Asistente LADM-COL"]["use_stable_version"], False)
self.assertEqual(to_upgrade, {})
self.assertEqual(not_found, {})
# A plugin offers both stable and experimental versions. A dependent plugin requires the stable one.
- to_install, to_upgrade, not_found = find_dependencies('LADM-COL-Add-on-Ambiente',
- self.plugin_data,
- plugin_deps={'Asistente LADM-COL': '3.1.9'},
- installed_plugins=self.installed_plugins)
- self.assertEqual(to_install['Asistente LADM-COL']['version_required'], '3.1.9')
- self.assertEqual(to_install['Asistente LADM-COL']['version_available'], '3.1.9')
- self.assertEqual(to_install['Asistente LADM-COL']['use_stable_version'], True)
+ to_install, to_upgrade, not_found = find_dependencies(
+ "LADM-COL-Add-on-Ambiente",
+ self.plugin_data,
+ plugin_deps={"Asistente LADM-COL": "3.1.9"},
+ installed_plugins=self.installed_plugins,
+ )
+ self.assertEqual(to_install["Asistente LADM-COL"]["version_required"], "3.1.9")
+ self.assertEqual(to_install["Asistente LADM-COL"]["version_available"], "3.1.9")
+ self.assertEqual(to_install["Asistente LADM-COL"]["use_stable_version"], True)
self.assertEqual(to_upgrade, {})
self.assertEqual(not_found, {})
# A plugin offers both stable and experimental versions. If no version is required, choose the stable one.
- to_install, to_upgrade, not_found = find_dependencies('LADM-COL-Add-on-Ambiente',
- self.plugin_data,
- plugin_deps={'Asistente LADM-COL': None},
- installed_plugins=self.installed_plugins)
- self.assertEqual(to_install['Asistente LADM-COL']['version_required'], None)
- self.assertEqual(to_install['Asistente LADM-COL']['version_available'], '3.1.9')
- self.assertEqual(to_install['Asistente LADM-COL']['use_stable_version'], True)
+ to_install, to_upgrade, not_found = find_dependencies(
+ "LADM-COL-Add-on-Ambiente",
+ self.plugin_data,
+ plugin_deps={"Asistente LADM-COL": None},
+ installed_plugins=self.installed_plugins,
+ )
+ self.assertEqual(to_install["Asistente LADM-COL"]["version_required"], None)
+ self.assertEqual(to_install["Asistente LADM-COL"]["version_available"], "3.1.9")
+ self.assertEqual(to_install["Asistente LADM-COL"]["use_stable_version"], True)
self.assertEqual(to_upgrade, {})
self.assertEqual(not_found, {})
# A plugin only offers experimental version. If the experimental version is required, give it to him.
- to_install, to_upgrade, not_found = find_dependencies('dependent-on-unique_values_viewer',
- self.plugin_data,
- plugin_deps={'UniqueValuesViewer': '0.2'},
- installed_plugins=self.installed_plugins)
- self.assertEqual(to_install['UniqueValuesViewer']['version_required'], '0.2')
- self.assertEqual(to_install['UniqueValuesViewer']['version_available'], '0.2')
- self.assertEqual(to_install['UniqueValuesViewer']['use_stable_version'], False)
+ to_install, to_upgrade, not_found = find_dependencies(
+ "dependent-on-unique_values_viewer",
+ self.plugin_data,
+ plugin_deps={"UniqueValuesViewer": "0.2"},
+ installed_plugins=self.installed_plugins,
+ )
+ self.assertEqual(to_install["UniqueValuesViewer"]["version_required"], "0.2")
+ self.assertEqual(to_install["UniqueValuesViewer"]["version_available"], "0.2")
+ self.assertEqual(to_install["UniqueValuesViewer"]["use_stable_version"], False)
self.assertEqual(to_upgrade, {})
self.assertEqual(not_found, {})
# A plugin only offers experimental version. If no version is required, choose the experimental one.
- to_install, to_upgrade, not_found = find_dependencies('dependent-on-unique_values_viewer',
- self.plugin_data,
- plugin_deps={'UniqueValuesViewer': None},
- installed_plugins=self.installed_plugins)
- self.assertEqual(to_install['UniqueValuesViewer']['version_required'], None)
- self.assertEqual(to_install['UniqueValuesViewer']['version_available'], '0.2')
- self.assertEqual(to_install['UniqueValuesViewer']['use_stable_version'], False)
+ to_install, to_upgrade, not_found = find_dependencies(
+ "dependent-on-unique_values_viewer",
+ self.plugin_data,
+ plugin_deps={"UniqueValuesViewer": None},
+ installed_plugins=self.installed_plugins,
+ )
+ self.assertEqual(to_install["UniqueValuesViewer"]["version_required"], None)
+ self.assertEqual(to_install["UniqueValuesViewer"]["version_available"], "0.2")
+ self.assertEqual(to_install["UniqueValuesViewer"]["use_stable_version"], False)
self.assertEqual(to_upgrade, {})
self.assertEqual(not_found, {})
def pluginSuite():
- return unittest.defaultTestLoader.loadTestsFromTestCase(PluginDependenciesTest, 'test')
+ return unittest.defaultTestLoader.loadTestsFromTestCase(
+ PluginDependenciesTest, "test"
+ )
if __name__ == "__main__":
diff --git a/tests/src/python/test_processing_alg_decorator.py b/tests/src/python/test_processing_alg_decorator.py
index 29cea78f94cb..8a232a5034f5 100644
--- a/tests/src/python/test_processing_alg_decorator.py
+++ b/tests/src/python/test_processing_alg_decorator.py
@@ -5,9 +5,10 @@
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
"""
-__author__ = 'Nathan Woodrow'
-__date__ = '10.12.2018'
-__copyright__ = 'Copyright 2018, The QGIS Project'
+
+__author__ = "Nathan Woodrow"
+__date__ = "10.12.2018"
+__copyright__ = "Copyright 2018, The QGIS Project"
from qgis.processing import alg
@@ -21,8 +22,12 @@
def define_new_no_inputs(newid=1):
- @alg(name="noinputs", label=alg.tr("Test func"), group="unittest",
- group_label=alg.tr("Test label"))
+ @alg(
+ name="noinputs",
+ label=alg.tr("Test func"),
+ group="unittest",
+ group_label=alg.tr("Test label"),
+ )
@alg.output(type=str, name="DISTANCE_OUT", label="Distance out")
def testalg(instance, parameters, context, feedback, inputs):
"""
@@ -31,8 +36,12 @@ def testalg(instance, parameters, context, feedback, inputs):
def define_new_no_outputs_but_sink_instead(newid=1):
- @alg(name=ARGNAME.format(newid), label=alg.tr("Test func"), group="unittest",
- group_label=alg.tr("Test label"))
+ @alg(
+ name=ARGNAME.format(newid),
+ label=alg.tr("Test func"),
+ group="unittest",
+ group_label=alg.tr("Test label"),
+ )
@alg.help(HELPSTRING.format(newid))
@alg.input(type=alg.SOURCE, name="INPUT", label="Input layer")
@alg.input(type=alg.DISTANCE, name="DISTANCE", label="Distance", default=30)
@@ -44,12 +53,32 @@ def testalg(instance, parameters, context, feedback, inputs):
def define_new_input_help(newid=1):
- @alg(name=ARGNAME.format(newid), label=alg.tr("Test func"), group="unittest",
- group_label=alg.tr("Test label"))
+ @alg(
+ name=ARGNAME.format(newid),
+ label=alg.tr("Test func"),
+ group="unittest",
+ group_label=alg.tr("Test label"),
+ )
@alg.help(HELPSTRING.format(newid))
- @alg.input(type=alg.SOURCE, name="INPUT", label="Input layer", help="The input layer as source")
- @alg.input(type=alg.DISTANCE, name="DISTANCE", label="Distance", default=30, help="The distance to split the input layer")
- @alg.input(type=alg.SINK, name="SINK", label="Output layer", help="The output layer as sink")
+ @alg.input(
+ type=alg.SOURCE,
+ name="INPUT",
+ label="Input layer",
+ help="The input layer as source",
+ )
+ @alg.input(
+ type=alg.DISTANCE,
+ name="DISTANCE",
+ label="Distance",
+ default=30,
+ help="The distance to split the input layer",
+ )
+ @alg.input(
+ type=alg.SINK,
+ name="SINK",
+ label="Output layer",
+ help="The output layer as sink",
+ )
@alg.output(type=str, name="DISTANCE_OUT", label="Distance out")
def testalg(instance, parameters, context, feedback, inputs):
"""
@@ -58,8 +87,12 @@ def testalg(instance, parameters, context, feedback, inputs):
def define_new_doc_string(newid=1):
- @alg(name=ARGNAME.format(newid), label=alg.tr("Test func"), group="unittest",
- group_label=alg.tr("Test label"))
+ @alg(
+ name=ARGNAME.format(newid),
+ label=alg.tr("Test func"),
+ group="unittest",
+ group_label=alg.tr("Test label"),
+ )
@alg.input(type=alg.SOURCE, name="INPUT", label="Input layer")
@alg.output(type=str, name="DISTANCE_OUT", label="Distance out")
def testalg(instance, parameters, context, feedback, inputs):
@@ -69,8 +102,12 @@ def testalg(instance, parameters, context, feedback, inputs):
def define_new(newid=1):
- @alg(name=ARGNAME.format(newid), label=alg.tr("Test func"), group="unittest",
- group_label=alg.tr("Test label"))
+ @alg(
+ name=ARGNAME.format(newid),
+ label=alg.tr("Test func"),
+ group="unittest",
+ group_label=alg.tr("Test label"),
+ )
@alg.help(HELPSTRING.format(newid))
@alg.input(type=alg.SOURCE, name="INPUT", label="Input layer")
@alg.input(type=alg.DISTANCE, name="DISTANCE", label="Distance", default=30)
diff --git a/tests/src/python/test_processing_algs_gdal_gdalutils.py b/tests/src/python/test_processing_algs_gdal_gdalutils.py
index ded8357ff8bc..c964a1133e8b 100644
--- a/tests/src/python/test_processing_algs_gdal_gdalutils.py
+++ b/tests/src/python/test_processing_algs_gdal_gdalutils.py
@@ -5,9 +5,10 @@
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
"""
-__author__ = 'Stefanos Natsis'
-__date__ = '03/07/2024'
-__copyright__ = 'Copyright 2024, The QGIS Project'
+
+__author__ = "Stefanos Natsis"
+__date__ = "03/07/2024"
+__copyright__ = "Copyright 2024, The QGIS Project"
import os
@@ -16,14 +17,16 @@
import unittest
from qgis.testing import start_app, QgisTestCase
-from qgis.core import QgsApplication, QgsRasterLayer, QgsDataSourceUri, QgsAuthMethodConfig
-from processing.algs.gdal.GdalUtils import (
- GdalUtils,
- GdalConnectionDetails
+from qgis.core import (
+ QgsApplication,
+ QgsRasterLayer,
+ QgsDataSourceUri,
+ QgsAuthMethodConfig,
)
+from processing.algs.gdal.GdalUtils import GdalUtils, GdalConnectionDetails
QGIS_AUTH_DB_DIR_PATH = tempfile.mkdtemp()
-os.environ['QGIS_AUTH_DB_DIR_PATH'] = QGIS_AUTH_DB_DIR_PATH
+os.environ["QGIS_AUTH_DB_DIR_PATH"] = QGIS_AUTH_DB_DIR_PATH
start_app()
@@ -34,7 +37,7 @@ class TestProcessingAlgsGdalGdalUtils(QgisTestCase):
def tearDownClass(cls):
"""Run after all tests"""
rmtree(QGIS_AUTH_DB_DIR_PATH)
- del os.environ['QGIS_AUTH_DB_DIR_PATH']
+ del os.environ["QGIS_AUTH_DB_DIR_PATH"]
super().tearDownClass()
def test_gdal_connection_details_from_layer_postgresraster(self):
@@ -45,14 +48,16 @@ def test_gdal_connection_details_from_layer_postgresraster(self):
rl = QgsRasterLayer(
"dbname='mydb' host=localhost port=5432 user='asdf' password='42'"
" sslmode=disable table=some_table schema=some_schema column=rast sql=pk = 2",
- 'pg_layer', 'postgresraster')
+ "pg_layer",
+ "postgresraster",
+ )
- self.assertEqual(rl.providerType(), 'postgresraster')
+ self.assertEqual(rl.providerType(), "postgresraster")
connection_details = GdalUtils.gdal_connection_details_from_layer(rl)
s = connection_details.connection_string
- self.assertTrue(s.lower().startswith('pg:'))
+ self.assertTrue(s.lower().startswith("pg:"))
self.assertTrue("schema='some_schema'" in s)
self.assertTrue("password='42'" in s)
self.assertTrue("column='rast'" in s)
@@ -65,25 +70,27 @@ def test_gdal_connection_details_from_layer_postgresraster(self):
# - column is parsed
# - where is skipped
authm = QgsApplication.authManager()
- self.assertTrue(authm.setMasterPassword('masterpassword', True))
+ self.assertTrue(authm.setMasterPassword("masterpassword", True))
config = QgsAuthMethodConfig()
- config.setName('Basic')
- config.setMethod('Basic')
- config.setConfig('username', 'asdf')
- config.setConfig('password', '42')
+ config.setName("Basic")
+ config.setMethod("Basic")
+ config.setConfig("username", "asdf")
+ config.setConfig("password", "42")
self.assertTrue(authm.storeAuthenticationConfig(config, True))
rl = QgsRasterLayer(
f"dbname='mydb' host=localhost port=5432 authcfg={config.id()}"
- f" sslmode=disable table=\"some_schema\".\"some_table\" (rast)",
- 'pg_layer', 'postgresraster')
+ f' sslmode=disable table="some_schema"."some_table" (rast)',
+ "pg_layer",
+ "postgresraster",
+ )
- self.assertEqual(rl.providerType(), 'postgresraster')
+ self.assertEqual(rl.providerType(), "postgresraster")
connection_details = GdalUtils.gdal_connection_details_from_layer(rl)
s = connection_details.connection_string
- self.assertTrue(s.lower().startswith('pg:'))
+ self.assertTrue(s.lower().startswith("pg:"))
self.assertTrue("schema='some_schema'" in s)
self.assertTrue("user='asdf'" in s)
self.assertTrue("password='42'" in s)
@@ -92,5 +99,5 @@ def test_gdal_connection_details_from_layer_postgresraster(self):
self.assertFalse("where=" in s)
-if __name__ == '__main__':
+if __name__ == "__main__":
unittest.main()
diff --git a/tests/src/python/test_processing_importintopostgis.py b/tests/src/python/test_processing_importintopostgis.py
index 8f387c39aeb1..71f683675bd3 100644
--- a/tests/src/python/test_processing_importintopostgis.py
+++ b/tests/src/python/test_processing_importintopostgis.py
@@ -5,9 +5,10 @@
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
"""
-__author__ = 'Alessandro Pasotti'
-__date__ = '2018-09'
-__copyright__ = 'Copyright 2019, The QGIS Project'
+
+__author__ = "Alessandro Pasotti"
+__date__ = "2018-09"
+__copyright__ = "Copyright 2019, The QGIS Project"
from processing.core.Processing import Processing
from processing.gui.AlgorithmExecutor import execute
@@ -43,8 +44,7 @@ def setUpClass(cls):
"""Run before all tests"""
super().setUpClass()
QCoreApplication.setOrganizationName("QGIS_Test")
- QCoreApplication.setOrganizationDomain(
- "QGIS_TestPyQgsExportToPostgis.com")
+ QCoreApplication.setOrganizationDomain("QGIS_TestPyQgsExportToPostgis.com")
QCoreApplication.setApplicationName("QGIS_TestPyQgsExportToPostgis")
QgsSettings().clear()
Processing.initialize()
@@ -53,9 +53,9 @@ def setUpClass(cls):
# Create DB connection in the settings
settings = QgsSettings()
- settings.beginGroup('/PostgreSQL/connections/qgis_test')
- settings.setValue('service', 'qgis_test')
- settings.setValue('database', 'qgis_test')
+ settings.beginGroup("/PostgreSQL/connections/qgis_test")
+ settings.setValue("service", "qgis_test")
+ settings.setValue("database", "qgis_test")
def test_import(self):
"""Test algorithm with CamelCase'singlequote'Schema"""
@@ -63,21 +63,21 @@ def test_import(self):
alg = self.registry.createAlgorithmById("qgis:importintopostgis")
self.assertIsNotNone(alg)
- table_name = 'out_TestPyQgsExportToPostgis'
+ table_name = "out_TestPyQgsExportToPostgis"
parameters = {
- 'CREATEINDEX': True,
- 'DATABASE': 'qgis_test',
- 'DROP_STRING_LENGTH': False,
- 'ENCODING': 'UTF-8',
- 'FORCE_SINGLEPART': False,
- 'GEOMETRY_COLUMN': 'geom',
- 'INPUT': unitTestDataPath() + '/points.shp',
- 'LOWERCASE_NAMES': True,
- 'OVERWRITE': True,
- 'PRIMARY_KEY': None,
- 'SCHEMA': "CamelCase'singlequote'Schema",
- 'TABLENAME': table_name
+ "CREATEINDEX": True,
+ "DATABASE": "qgis_test",
+ "DROP_STRING_LENGTH": False,
+ "ENCODING": "UTF-8",
+ "FORCE_SINGLEPART": False,
+ "GEOMETRY_COLUMN": "geom",
+ "INPUT": unitTestDataPath() + "/points.shp",
+ "LOWERCASE_NAMES": True,
+ "OVERWRITE": True,
+ "PRIMARY_KEY": None,
+ "SCHEMA": "CamelCase'singlequote'Schema",
+ "TABLENAME": table_name,
}
feedback = ConsoleFeedBack()
@@ -88,9 +88,13 @@ def test_import(self):
self.assertEqual(feedback._errors, [])
# Check that data have been imported correctly
- exported = QgsVectorLayer(unitTestDataPath() + '/points.shp', 'exported')
+ exported = QgsVectorLayer(unitTestDataPath() + "/points.shp", "exported")
self.assertTrue(exported.isValid())
- imported = QgsVectorLayer(f"service='qgis_test' table=\"CamelCase'singlequote'Schema\".\"{table_name}\" (geom)", 'imported', 'postgres')
+ imported = QgsVectorLayer(
+ f"service='qgis_test' table=\"CamelCase'singlequote'Schema\".\"{table_name}\" (geom)",
+ "imported",
+ "postgres",
+ )
self.assertTrue(imported.isValid())
imported_fields = [f.name() for f in imported.fields()]
for f in exported.fields():
@@ -104,5 +108,5 @@ def test_import(self):
self.assertEqual(exported_f.geometry().asWkt(), imported_f.geometry().asWkt())
-if __name__ == '__main__':
+if __name__ == "__main__":
unittest.main()
diff --git a/tests/src/python/test_processing_packagelayers.py b/tests/src/python/test_processing_packagelayers.py
index 589ec8ffb329..cf144b53198c 100644
--- a/tests/src/python/test_processing_packagelayers.py
+++ b/tests/src/python/test_processing_packagelayers.py
@@ -5,9 +5,10 @@
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
"""
-__author__ = 'Alessandro Pasotti'
-__date__ = '2022-07'
-__copyright__ = 'Copyright 2022, The QGIS Project'
+
+__author__ = "Alessandro Pasotti"
+__date__ = "2022-07"
+__copyright__ = "Copyright 2022, The QGIS Project"
import os
@@ -55,16 +56,17 @@ def setUpClass(cls):
"""Run before all tests"""
super().setUpClass()
QCoreApplication.setOrganizationName("QGIS_Test")
- QCoreApplication.setOrganizationDomain(
- "QGIS_TestPyQgsPackageLayers.com")
+ QCoreApplication.setOrganizationDomain("QGIS_TestPyQgsPackageLayers.com")
QCoreApplication.setApplicationName("QGIS_TestPyQgsPackageLayers")
QgsSettings().clear()
Processing.initialize()
QgsApplication.processingRegistry().addProvider(QgsNativeAlgorithms())
cls.registry = QgsApplication.instance().processingRegistry()
cls.tmp_dir = QTemporaryDir()
- cls.temp_path = os.path.join(cls.tmp_dir.path(), 'package_layers.gpkg')
- cls.temp_export_path = os.path.join(cls.tmp_dir.path(), 'package_layers_export.gpkg')
+ cls.temp_path = os.path.join(cls.tmp_dir.path(), "package_layers.gpkg")
+ cls.temp_export_path = os.path.join(
+ cls.tmp_dir.path(), "package_layers_export.gpkg"
+ )
# Create test DB
@@ -83,83 +85,83 @@ def setUpClass(cls):
City 4
"""
- ds = ogr.GetDriverByName('GPKG').CreateDataSource(cls.temp_path)
- lyr = ds.CreateLayer('region', geom_type=ogr.wkbNone)
- lyr.CreateField(ogr.FieldDefn('name', ogr.OFTString))
+ ds = ogr.GetDriverByName("GPKG").CreateDataSource(cls.temp_path)
+ lyr = ds.CreateLayer("region", geom_type=ogr.wkbNone)
+ lyr.CreateField(ogr.FieldDefn("name", ogr.OFTString))
f = ogr.Feature(lyr.GetLayerDefn())
- f['name'] = 'region one'
+ f["name"] = "region one"
lyr.CreateFeature(f)
f = ogr.Feature(lyr.GetLayerDefn())
- f['name'] = 'region two'
+ f["name"] = "region two"
lyr.CreateFeature(f)
- lyr = ds.CreateLayer('province', geom_type=ogr.wkbNone)
- lyr.CreateField(ogr.FieldDefn('name', ogr.OFTString))
- lyr.CreateField(ogr.FieldDefn('region', ogr.OFTInteger))
+ lyr = ds.CreateLayer("province", geom_type=ogr.wkbNone)
+ lyr.CreateField(ogr.FieldDefn("name", ogr.OFTString))
+ lyr.CreateField(ogr.FieldDefn("region", ogr.OFTInteger))
f = ogr.Feature(lyr.GetLayerDefn())
- f['name'] = 'province one'
- f['region'] = 1
+ f["name"] = "province one"
+ f["region"] = 1
lyr.CreateFeature(f)
f = ogr.Feature(lyr.GetLayerDefn())
- f['name'] = 'province two'
- f['region'] = 1
+ f["name"] = "province two"
+ f["region"] = 1
lyr.CreateFeature(f)
f = ogr.Feature(lyr.GetLayerDefn())
- f['name'] = 'province three'
- f['region'] = 2
+ f["name"] = "province three"
+ f["region"] = 2
lyr.CreateFeature(f)
f = ogr.Feature(lyr.GetLayerDefn())
- f['name'] = 'province four'
- f['region'] = 2
+ f["name"] = "province four"
+ f["region"] = 2
lyr.CreateFeature(f)
- lyr = ds.CreateLayer('city', geom_type=ogr.wkbNone)
- lyr.CreateField(ogr.FieldDefn('name', ogr.OFTString))
- lyr.CreateField(ogr.FieldDefn('province', ogr.OFTInteger))
+ lyr = ds.CreateLayer("city", geom_type=ogr.wkbNone)
+ lyr.CreateField(ogr.FieldDefn("name", ogr.OFTString))
+ lyr.CreateField(ogr.FieldDefn("province", ogr.OFTInteger))
f = ogr.Feature(lyr.GetLayerDefn())
- f['name'] = 'city one'
- f['province'] = 1
+ f["name"] = "city one"
+ f["province"] = 1
lyr.CreateFeature(f)
f = ogr.Feature(lyr.GetLayerDefn())
- f['name'] = 'city two'
- f['province'] = 1
+ f["name"] = "city two"
+ f["province"] = 1
lyr.CreateFeature(f)
f = ogr.Feature(lyr.GetLayerDefn())
- f['name'] = 'city three'
- f['province'] = 2
+ f["name"] = "city three"
+ f["province"] = 2
lyr.CreateFeature(f)
f = ogr.Feature(lyr.GetLayerDefn())
- f['name'] = 'city four'
- f['province'] = 4
+ f["name"] = "city four"
+ f["province"] = 4
lyr.CreateFeature(f)
f = None
ds = None
- region = QgsVectorLayer(cls.temp_path + '|layername=region', 'region')
- province = QgsVectorLayer(cls.temp_path + '|layername=province', 'province')
- city = QgsVectorLayer(cls.temp_path + '|layername=city', 'city')
+ region = QgsVectorLayer(cls.temp_path + "|layername=region", "region")
+ province = QgsVectorLayer(cls.temp_path + "|layername=province", "province")
+ city = QgsVectorLayer(cls.temp_path + "|layername=city", "city")
QgsProject.instance().addMapLayers([region, province, city])
relMgr = QgsProject.instance().relationManager()
rel = QgsRelation()
- rel.setId('rel1')
- rel.setName('province -> region')
+ rel.setId("rel1")
+ rel.setName("province -> region")
rel.setReferencingLayer(province.id())
rel.setReferencedLayer(region.id())
- rel.addFieldPair('region', 'fid')
+ rel.addFieldPair("region", "fid")
assert rel.isValid()
relMgr.addRelation(rel)
rel = QgsRelation()
- rel.setId('rel2')
- rel.setName('city -> province')
+ rel.setId("rel2")
+ rel.setName("city -> province")
rel.setReferencingLayer(city.id())
rel.setReferencedLayer(province.id())
- rel.addFieldPair('province', 'fid')
+ rel.addFieldPair("province", "fid")
assert rel.isValid()
relMgr.addRelation(rel)
@@ -185,35 +187,37 @@ def _test(parameters):
self.assertEqual(feedback._errors, [])
# Check export
- l = QgsVectorLayer(self.temp_export_path + '|layername=province', 'province')
+ l = QgsVectorLayer(
+ self.temp_export_path + "|layername=province", "province"
+ )
self.assertTrue(l.isValid())
self.assertEqual(l.featureCount(), 4)
- l = QgsVectorLayer(self.temp_export_path + '|layername=region', 'region')
+ l = QgsVectorLayer(self.temp_export_path + "|layername=region", "region")
self.assertTrue(l.isValid())
self.assertEqual(l.featureCount(), 2)
- l = QgsVectorLayer(self.temp_export_path + '|layername=city', 'city')
+ l = QgsVectorLayer(self.temp_export_path + "|layername=city", "city")
self.assertTrue(l.isValid())
self.assertEqual(l.featureCount(), 4)
parameters = {
- 'EXPORT_RELATED_LAYERS': True,
- 'LAYERS': [QgsProject.instance().mapLayersByName('province')[0]],
- 'OUTPUT': self.temp_export_path,
- 'OVERWRITE': True,
- 'SELECTED_FEATURES_ONLY': False
+ "EXPORT_RELATED_LAYERS": True,
+ "LAYERS": [QgsProject.instance().mapLayersByName("province")[0]],
+ "OUTPUT": self.temp_export_path,
+ "OVERWRITE": True,
+ "SELECTED_FEATURES_ONLY": False,
}
# Test province
_test(parameters)
# Test region
- parameters['LAYERS'] = [QgsProject.instance().mapLayersByName('region')[0]]
+ parameters["LAYERS"] = [QgsProject.instance().mapLayersByName("region")[0]]
_test(parameters)
# Test city
- parameters['LAYERS'] = [QgsProject.instance().mapLayersByName('city')[0]]
+ parameters["LAYERS"] = [QgsProject.instance().mapLayersByName("city")[0]]
_test(parameters)
def test_selected_features_export(self):
@@ -234,60 +238,62 @@ def _test(parameters, expected_ids):
# Check export
for layer_name in list(expected_ids.keys()):
- l = QgsVectorLayer(self.temp_export_path + f'|layername={layer_name}', layer_name)
+ l = QgsVectorLayer(
+ self.temp_export_path + f"|layername={layer_name}", layer_name
+ )
self.assertTrue(l.isValid())
ids = {l.id() for l in l.getFeatures()}
self.assertEqual(ids, expected_ids[layer_name], layer_name + str(ids))
- region = QgsProject.instance().mapLayersByName('region')[0]
- province = QgsProject.instance().mapLayersByName('province')[0]
- city = QgsProject.instance().mapLayersByName('city')[0]
+ region = QgsProject.instance().mapLayersByName("region")[0]
+ province = QgsProject.instance().mapLayersByName("province")[0]
+ city = QgsProject.instance().mapLayersByName("city")[0]
parameters = {
- 'EXPORT_RELATED_LAYERS': True,
- 'LAYERS': [province],
- 'OUTPUT': self.temp_export_path,
- 'OVERWRITE': True,
- 'SELECTED_FEATURES_ONLY': True
+ "EXPORT_RELATED_LAYERS": True,
+ "LAYERS": [province],
+ "OUTPUT": self.temp_export_path,
+ "OVERWRITE": True,
+ "SELECTED_FEATURES_ONLY": True,
}
# Test province
province.selectByIds([1])
- _test(parameters, {'region': {1}, 'province': {1}, 'city': {1, 2}})
+ _test(parameters, {"region": {1}, "province": {1}, "city": {1, 2}})
province.selectByIds([])
# Test region
- parameters['LAYERS'] = [region]
+ parameters["LAYERS"] = [region]
region.selectByIds([1])
- _test(parameters, {'region': {1}, 'province': {1, 2}, 'city': {1, 2, 3}})
+ _test(parameters, {"region": {1}, "province": {1, 2}, "city": {1, 2, 3}})
region.selectByIds([])
# Test city
- parameters['LAYERS'] = [city]
+ parameters["LAYERS"] = [city]
city.selectByIds([3])
- _test(parameters, {'region': {1}, 'province': {2}, 'city': {3}})
+ _test(parameters, {"region": {1}, "province": {2}, "city": {3}})
city.selectByIds([])
# Test multiple selection
- parameters['LAYERS'] = [city, province]
+ parameters["LAYERS"] = [city, province]
city.selectByIds([3])
province.selectByIds([3])
- _test(parameters, {'region': {1, 2}, 'province': {2, 3}, 'city': {3}})
+ _test(parameters, {"region": {1, 2}, "province": {2, 3}, "city": {3}})
city.selectByIds([])
province.selectByIds([])
# Test referencing with selection
- parameters['LAYERS'] = [region]
+ parameters["LAYERS"] = [region]
region.selectByIds([2])
- _test(parameters, {'region': {2}, 'province': {3, 4}, 'city': {4}})
+ _test(parameters, {"region": {2}, "province": {3, 4}, "city": {4}})
region.selectByIds([])
# Test referencing with selection, empty city expected not to be exported
- parameters['LAYERS'] = [province]
+ parameters["LAYERS"] = [province]
province.selectByIds([3])
- _test(parameters, {'region': {2}, 'province': {3}})
+ _test(parameters, {"region": {2}, "province": {3}})
province.selectByIds([])
-if __name__ == '__main__':
+if __name__ == "__main__":
unittest.main()
diff --git a/tests/src/python/test_project_storage_base.py b/tests/src/python/test_project_storage_base.py
index 18d68b65acf1..e20c7e71d0b2 100644
--- a/tests/src/python/test_project_storage_base.py
+++ b/tests/src/python/test_project_storage_base.py
@@ -7,9 +7,9 @@
"""
-__author__ = 'Julien Cabieces'
-__date__ = '2022-04-19'
-__copyright__ = 'Copyright 2022, The QGIS Project'
+__author__ = "Julien Cabieces"
+__date__ = "2022-04-19"
+__copyright__ = "Copyright 2022, The QGIS Project"
from qgis.PyQt.QtCore import QDateTime
@@ -31,18 +31,20 @@ def encode_uri(self, ds_uri, schema_name, project_name=None):
def testSaveLoadProject(self):
schema_uri = self.encode_uri(self.ds_uri, self.schema)
- project_uri = self.encode_uri(self.ds_uri, self.schema, 'abc')
+ project_uri = self.encode_uri(self.ds_uri, self.schema, "abc")
self.dropProjectsTable() # make sure we have a clean start
prj = QgsProject()
uri = self.vl.source()
- vl1 = QgsVectorLayer(uri, 'test', self.provider)
+ vl1 = QgsVectorLayer(uri, "test", self.provider)
self.assertEqual(vl1.isValid(), True)
prj.addMapLayer(vl1)
- prj_storage = QgsApplication.projectStorageRegistry().projectStorageFromType(self.project_storage_type)
+ prj_storage = QgsApplication.projectStorageRegistry().projectStorageFromType(
+ self.project_storage_type
+ )
self.assertTrue(prj_storage)
lst0 = prj_storage.listProjects(schema_uri)
@@ -67,8 +69,12 @@ def testSaveLoadProject(self):
self.assertEqual(len(prj2.mapLayers()), 1)
self.assertEqual(prj2.baseName(), "abc")
- self.assertEqual(prj2.absoluteFilePath(), "") # path not supported for project storages
- self.assertLess(abs(prj2.lastModified().secsTo(QDateTime.currentDateTime())), 10)
+ self.assertEqual(
+ prj2.absoluteFilePath(), ""
+ ) # path not supported for project storages
+ self.assertLess(
+ abs(prj2.lastModified().secsTo(QDateTime.currentDateTime())), 10
+ )
lastModified = prj2.lastModified()
# try to see project's metadata
@@ -99,7 +105,9 @@ def testSaveLoadProject(self):
self.assertEqual(list(prj4.mapLayers().values())[0].name(), "testNew")
self.assertEqual(prj4.baseName(), "abc")
- self.assertEqual(prj4.absoluteFilePath(), "") # path not supported for project storages
+ self.assertEqual(
+ prj4.absoluteFilePath(), ""
+ ) # path not supported for project storages
self.assertGreater(prj4.lastModified(), lastModified)
# try to remove the project
diff --git a/tests/src/python/test_project_storage_oracle.py b/tests/src/python/test_project_storage_oracle.py
index ed79f8a5b9fc..72438044f56a 100644
--- a/tests/src/python/test_project_storage_oracle.py
+++ b/tests/src/python/test_project_storage_oracle.py
@@ -7,9 +7,9 @@
"""
-__author__ = 'Julien Cabieces'
-__date__ = '2022-04-19'
-__copyright__ = 'Copyright 2022, The QGIS Project'
+__author__ = "Julien Cabieces"
+__date__ = "2022-04-19"
+__copyright__ = "Copyright 2022, The QGIS Project"
import os
@@ -34,28 +34,34 @@ class TestPyQgsProjectStorageOracle(QgisTestCase, TestPyQgsProjectStorageBase):
@classmethod
def setUpClass(cls):
"""Run before all tests"""
- super(TestPyQgsProjectStorageOracle, cls).setUpClass()
+ super().setUpClass()
- cls.dbconn = "host=localhost dbname=XEPDB1 port=1521 user='QGIS' password='qgis'"
- if 'QGIS_ORACLETEST_DB' in os.environ:
- cls.dbconn = os.environ['QGIS_ORACLETEST_DB']
+ cls.dbconn = (
+ "host=localhost dbname=XEPDB1 port=1521 user='QGIS' password='qgis'"
+ )
+ if "QGIS_ORACLETEST_DB" in os.environ:
+ cls.dbconn = os.environ["QGIS_ORACLETEST_DB"]
cls.ds_uri = QgsDataSourceUri(cls.dbconn)
# Create test layers
cls.vl = QgsVectorLayer(
- cls.dbconn + ' sslmode=disable key=\'pk\' srid=4326 type=POINT table="QGIS"."SOME_DATA" (GEOM) sql=', 'test', 'oracle')
+ cls.dbconn
+ + ' sslmode=disable key=\'pk\' srid=4326 type=POINT table="QGIS"."SOME_DATA" (GEOM) sql=',
+ "test",
+ "oracle",
+ )
assert cls.vl.isValid()
- cls.con = QSqlDatabase.addDatabase('QOCISPATIAL', "oracletest")
- cls.con.setDatabaseName('localhost/XEPDB1')
- if 'QGIS_ORACLETEST_DBNAME' in os.environ:
- cls.con.setDatabaseName(os.environ['QGIS_ORACLETEST_DBNAME'])
- cls.con.setUserName('QGIS')
- cls.con.setPassword('qgis')
+ cls.con = QSqlDatabase.addDatabase("QOCISPATIAL", "oracletest")
+ cls.con.setDatabaseName("localhost/XEPDB1")
+ if "QGIS_ORACLETEST_DBNAME" in os.environ:
+ cls.con.setDatabaseName(os.environ["QGIS_ORACLETEST_DBNAME"])
+ cls.con.setUserName("QGIS")
+ cls.con.setPassword("qgis")
- cls.schema = 'QGIS'
- cls.provider = 'oracle'
- cls.project_storage_type = 'oracle'
+ cls.schema = "QGIS"
+ cls.provider = "oracle"
+ cls.project_storage_type = "oracle"
assert cls.con.open()
@@ -64,7 +70,7 @@ def execSQLCommand(self, sql, ignore_errors=False):
query = QSqlQuery(self.con)
res = query.exec(sql)
if not ignore_errors:
- self.assertTrue(res, sql + ': ' + query.lastError().text())
+ self.assertTrue(res, sql + ": " + query.lastError().text())
query.finish()
def dropProjectsTable(self):
@@ -76,19 +82,21 @@ def encode_uri(self, ds_uri, schema_name, project_name=None):
u.setScheme("oracle")
u.setHost(ds_uri.host())
- if ds_uri.port() != '':
+ if ds_uri.port() != "":
u.setPort(int(ds_uri.port()))
- if ds_uri.username() != '':
+ if ds_uri.username() != "":
u.setUserName(ds_uri.username())
- if ds_uri.password() != '':
+ if ds_uri.password() != "":
u.setPassword(ds_uri.password())
- if ds_uri.service() != '':
+ if ds_uri.service() != "":
urlQuery.addQueryItem("service", ds_uri.service())
- if ds_uri.authConfigId() != '':
+ if ds_uri.authConfigId() != "":
urlQuery.addQueryItem("authcfg", ds_uri.authConfigId())
if ds_uri.sslMode() != QgsDataSourceUri.SslMode.SslPrefer:
- urlQuery.addQueryItem("sslmode", QgsDataSourceUri.encodeSslMode(ds_uri.sslMode()))
+ urlQuery.addQueryItem(
+ "sslmode", QgsDataSourceUri.encodeSslMode(ds_uri.sslMode())
+ )
urlQuery.addQueryItem("dbname", ds_uri.database())
@@ -97,8 +105,8 @@ def encode_uri(self, ds_uri, schema_name, project_name=None):
urlQuery.addQueryItem("project", project_name)
u.setQuery(urlQuery)
- return str(u.toEncoded(), 'utf-8')
+ return str(u.toEncoded(), "utf-8")
-if __name__ == '__main__':
+if __name__ == "__main__":
unittest.main()
diff --git a/tests/src/python/test_project_storage_postgres.py b/tests/src/python/test_project_storage_postgres.py
index 5c33c6bf2d7c..907f7dbbd1d7 100644
--- a/tests/src/python/test_project_storage_postgres.py
+++ b/tests/src/python/test_project_storage_postgres.py
@@ -10,9 +10,9 @@
"""
-__author__ = 'Martin Dobias'
-__date__ = '2018-03-29'
-__copyright__ = 'Copyright 2018, The QGIS Project'
+__author__ = "Martin Dobias"
+__date__ = "2018-03-29"
+__copyright__ = "Copyright 2018, The QGIS Project"
import os
@@ -38,21 +38,26 @@ class TestPyQgsProjectStoragePostgres(QgisTestCase, TestPyQgsProjectStorageBase)
def setUpClass(cls):
"""Run before all tests"""
- super(TestPyQgsProjectStoragePostgres, cls).setUpClass()
+ super().setUpClass()
- cls.dbconn = 'service=qgis_test'
- if 'QGIS_PGTEST_DB' in os.environ:
- cls.dbconn = os.environ['QGIS_PGTEST_DB']
+ cls.dbconn = "service=qgis_test"
+ if "QGIS_PGTEST_DB" in os.environ:
+ cls.dbconn = os.environ["QGIS_PGTEST_DB"]
cls.ds_uri = QgsDataSourceUri(cls.dbconn)
# Create test layers
- cls.vl = QgsVectorLayer(cls.dbconn + ' sslmode=disable key=\'pk\' srid=4326 type=POINT table="qgis_test"."someData" (geom) sql=', 'test', 'postgres')
+ cls.vl = QgsVectorLayer(
+ cls.dbconn
+ + ' sslmode=disable key=\'pk\' srid=4326 type=POINT table="qgis_test"."someData" (geom) sql=',
+ "test",
+ "postgres",
+ )
assert cls.vl.isValid()
cls.con = psycopg2.connect(cls.dbconn)
- cls.schema = 'qgis_test'
- cls.provider = 'postgres'
- cls.project_storage_type = 'postgresql'
+ cls.schema = "qgis_test"
+ cls.provider = "postgres"
+ cls.project_storage_type = "postgresql"
def execSQLCommand(self, sql):
self.assertTrue(self.con)
@@ -71,19 +76,21 @@ def encode_uri(self, ds_uri, schema_name, project_name=None):
u.setScheme("postgresql")
u.setHost(ds_uri.host())
- if ds_uri.port() != '':
+ if ds_uri.port() != "":
u.setPort(int(ds_uri.port()))
- if ds_uri.username() != '':
+ if ds_uri.username() != "":
u.setUserName(ds_uri.username())
- if ds_uri.password() != '':
+ if ds_uri.password() != "":
u.setPassword(ds_uri.password())
- if ds_uri.service() != '':
+ if ds_uri.service() != "":
urlQuery.addQueryItem("service", ds_uri.service())
- if ds_uri.authConfigId() != '':
+ if ds_uri.authConfigId() != "":
urlQuery.addQueryItem("authcfg", ds_uri.authConfigId())
if ds_uri.sslMode() != QgsDataSourceUri.SslMode.SslPrefer:
- urlQuery.addQueryItem("sslmode", QgsDataSourceUri.encodeSslMode(ds_uri.sslMode()))
+ urlQuery.addQueryItem(
+ "sslmode", QgsDataSourceUri.encodeSslMode(ds_uri.sslMode())
+ )
urlQuery.addQueryItem("dbname", ds_uri.database())
@@ -92,8 +99,8 @@ def encode_uri(self, ds_uri, schema_name, project_name=None):
urlQuery.addQueryItem("project", project_name)
u.setQuery(urlQuery)
- return str(u.toEncoded(), 'utf-8')
+ return str(u.toEncoded(), "utf-8")
-if __name__ == '__main__':
+if __name__ == "__main__":
unittest.main()
diff --git a/tests/src/python/test_provider_afs.py b/tests/src/python/test_provider_afs.py
index bdd582704538..e4d087c5c599 100644
--- a/tests/src/python/test_provider_afs.py
+++ b/tests/src/python/test_provider_afs.py
@@ -7,9 +7,10 @@
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
"""
-__author__ = 'Nyall Dawson'
-__date__ = '2018-02-16'
-__copyright__ = 'Copyright 2018, Nyall Dawson'
+
+__author__ = "Nyall Dawson"
+__date__ = "2018-02-16"
+__copyright__ = "Copyright 2018, Nyall Dawson"
import hashlib
import tempfile
@@ -47,7 +48,7 @@
QgsFillSymbol,
QgsSymbolLayer,
QgsColorRampTransformer,
- QgsGradientColorRamp
+ QgsGradientColorRamp,
)
import unittest
from qgis.testing import start_app, QgisTestCase
@@ -56,18 +57,22 @@
def sanitize(endpoint, x):
- if x.startswith('/query'):
- x = x[len('/query'):]
- endpoint = endpoint + '_query'
+ if x.startswith("/query"):
+ x = x[len("/query") :]
+ endpoint = endpoint + "_query"
if len(endpoint + x) > 150:
ret = endpoint + hashlib.md5(x.encode()).hexdigest()
# print('Before: ' + endpoint + x)
# print('After: ' + ret)
return ret
- return endpoint + x.replace('?', '_').replace('&', '_').replace('<', '_').replace('>', '_').replace('"',
- '_').replace(
- "'", '_').replace(' ', '_').replace(':', '_').replace('/', '_').replace('\n', '_')
+ return endpoint + x.replace("?", "_").replace("&", "_").replace("<", "_").replace(
+ ">", "_"
+ ).replace('"', "_").replace("'", "_").replace(" ", "_").replace(":", "_").replace(
+ "/", "_"
+ ).replace(
+ "\n", "_"
+ )
class MessageLogger(QObject):
@@ -86,7 +91,7 @@ def __exit__(self, type, value, traceback):
def logMessage(self, msg, tag, level):
if tag == self.tag or not self.tag:
- self.log.append(msg.encode('UTF-8'))
+ self.log.append(msg.encode("UTF-8"))
def messages(self):
return self.log
@@ -103,7 +108,7 @@ def treat_time_as_string(self):
@classmethod
def setUpClass(cls):
"""Run before all tests"""
- super(TestPyQgsAFSProvider, cls).setUpClass()
+ super().setUpClass()
QCoreApplication.setOrganizationName("QGIS_Test")
QCoreApplication.setOrganizationDomain("TestPyQgsAFSProvider.com")
@@ -113,10 +118,11 @@ def setUpClass(cls):
# On Windows we must make sure that any backslash in the path is
# replaced by a forward slash so that QUrl can process it
- cls.basetestpath = tempfile.mkdtemp().replace('\\', '/')
- endpoint = cls.basetestpath + '/fake_qgis_http_endpoint'
- with open(sanitize(endpoint, '?f=json'), 'wb') as f:
- f.write(b"""
+ cls.basetestpath = tempfile.mkdtemp().replace("\\", "/")
+ endpoint = cls.basetestpath + "/fake_qgis_http_endpoint"
+ with open(sanitize(endpoint, "?f=json"), "wb") as f:
+ f.write(
+ b"""
{"currentVersion":10.22,"id":1,"name":"QGIS Test","type":"Feature Layer","description":
"QGIS Provider Test Layer.\n","geometryType":"esriGeometryPoint","copyrightText":"","parentLayer":{"id":0,"name":"QGIS Tests"},"subLayers":[],
"minScale":72225,"maxScale":0,
@@ -138,10 +144,14 @@ def setUpClass(cls):
"relationships":[],"canModifyLayer":false,"canScaleSymbols":false,"hasLabels":false,
"capabilities":"Map,Query,Data","maxRecordCount":1000,"supportsStatistics":true,
"supportsAdvancedQueries":true,"supportedQueryFormats":"JSON, AMF",
-"ownershipBasedAccessControlForFeatures":{"allowOthersToQuery":true},"useStandardizedQueries":true}""")
-
- with open(sanitize(endpoint, '/query?f=json_where=1=1&returnIdsOnly=true'), 'wb') as f:
- f.write(b"""
+"ownershipBasedAccessControlForFeatures":{"allowOthersToQuery":true},"useStandardizedQueries":true}"""
+ )
+
+ with open(
+ sanitize(endpoint, "/query?f=json_where=1=1&returnIdsOnly=true"), "wb"
+ ) as f:
+ f.write(
+ b"""
{
"objectIdFieldName": "OBJECTID",
"objectIds": [
@@ -152,10 +162,18 @@ def setUpClass(cls):
4
]
}
-""")
-
- with open(sanitize(endpoint, '/query?f=json_where="cnt" > 100 and "cnt" < 410&returnIdsOnly=true'), 'wb') as f:
- f.write(b"""
+"""
+ )
+
+ with open(
+ sanitize(
+ endpoint,
+ '/query?f=json_where="cnt" > 100 and "cnt" < 410&returnIdsOnly=true',
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
{
"objectIdFieldName": "OBJECTID",
"objectIds": [
@@ -164,10 +182,18 @@ def setUpClass(cls):
4
]
}
- """)
-
- with open(sanitize(endpoint, '/query?f=json_where="cnt" > 100 and "cnt" < 400&returnIdsOnly=true'), 'wb') as f:
- f.write(b"""
+ """
+ )
+
+ with open(
+ sanitize(
+ endpoint,
+ '/query?f=json_where="cnt" > 100 and "cnt" < 400&returnIdsOnly=true',
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
{
"objectIdFieldName": "OBJECTID",
"objectIds": [
@@ -175,41 +201,70 @@ def setUpClass(cls):
2
]
}
- """)
-
- with open(sanitize(endpoint, '/query?f=json_where="name"=\'Apple\'&returnIdsOnly=true'), 'wb') as f:
- f.write(b"""
+ """
+ )
+
+ with open(
+ sanitize(
+ endpoint, "/query?f=json_where=\"name\"='Apple'&returnIdsOnly=true"
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
{
"objectIdFieldName": "OBJECTID",
"objectIds": [
2
]
}
- """)
-
- with open(sanitize(endpoint, '/query?f=json_where="name"=\'AppleBearOrangePear\'&returnIdsOnly=true'), 'wb') as f:
- f.write(b"""
+ """
+ )
+
+ with open(
+ sanitize(
+ endpoint,
+ "/query?f=json_where=\"name\"='AppleBearOrangePear'&returnIdsOnly=true",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
{
"objectIdFieldName": "OBJECTID",
"objectIds": [
]
}
- """)
-
- with open(sanitize(endpoint, '/query?f=json&where="cnt" > 100 and "cnt" < 410&returnIdsOnly=true&geometry=-70.000000,70.000000,-60.000000,75.000000&geometryType=esriGeometryEnvelope&spatialRel=esriSpatialRelEnvelopeIntersects'),
- 'wb') as f:
- f.write(b"""
+ """
+ )
+
+ with open(
+ sanitize(
+ endpoint,
+ '/query?f=json&where="cnt" > 100 and "cnt" < 410&returnIdsOnly=true&geometry=-70.000000,70.000000,-60.000000,75.000000&geometryType=esriGeometryEnvelope&spatialRel=esriSpatialRelEnvelopeIntersects',
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
{
"objectIdFieldName": "OBJECTID",
"objectIds": [
2
]
}
- """)
-
- with open(sanitize(endpoint, '/query?f=json&where="cnt" > 100 and "cnt" < 410&returnIdsOnly=true&geometry=-71.000000,65.000000,-60.000000,80.000000&geometryType=esriGeometryEnvelope&spatialRel=esriSpatialRelEnvelopeIntersects'),
- 'wb') as f:
- f.write(b"""
+ """
+ )
+
+ with open(
+ sanitize(
+ endpoint,
+ '/query?f=json&where="cnt" > 100 and "cnt" < 410&returnIdsOnly=true&geometry=-71.000000,65.000000,-60.000000,80.000000&geometryType=esriGeometryEnvelope&spatialRel=esriSpatialRelEnvelopeIntersects',
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
{
"objectIdFieldName": "OBJECTID",
"objectIds": [
@@ -217,17 +272,28 @@ def setUpClass(cls):
4
]
}
- """)
+ """
+ )
# Create test layer
- cls.vl = QgsVectorLayer("url='http://" + endpoint + "' crs='epsg:4326'", 'test', 'arcgisfeatureserver')
+ cls.vl = QgsVectorLayer(
+ "url='http://" + endpoint + "' crs='epsg:4326'",
+ "test",
+ "arcgisfeatureserver",
+ )
assert cls.vl.isValid()
cls.source = cls.vl.dataProvider()
- with open(sanitize(endpoint,
- '/query?f=json&objectIds=5,3,1,2,4&inSR=4326&outSR=4326&returnGeometry=true&outFields=*&returnM=false&returnZ=false'),
- 'wb') as f:
- f.write(("""
+ with open(
+ sanitize(
+ endpoint,
+ "/query?f=json&objectIds=5,3,1,2,4&inSR=4326&outSR=4326&returnGeometry=true&outFields=*&returnM=false&returnZ=false",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ (
+ """
{
"displayFieldName": "name",
"fieldAliases": {
@@ -257,8 +323,18 @@ def setUpClass(cls):
"name": null,
"name2":"NuLl",
"num_char":"5",
- "dt": """ + str(QDateTime(QDate(2020, 5, 4), QTime(12, 13, 14)).toMSecsSinceEpoch()) + """,
- "date": """ + str(QDateTime(QDate(2020, 5, 2), QTime(0, 0, 0)).toMSecsSinceEpoch()) + """,
+ "dt": """
+ + str(
+ QDateTime(
+ QDate(2020, 5, 4), QTime(12, 13, 14)
+ ).toMSecsSinceEpoch()
+ )
+ + """,
+ "date": """
+ + str(
+ QDateTime(QDate(2020, 5, 2), QTime(0, 0, 0)).toMSecsSinceEpoch()
+ )
+ + """,
"time": "12:13:01"
},
"geometry": {
@@ -288,8 +364,18 @@ def setUpClass(cls):
"name": "Orange",
"name2":"oranGe",
"num_char":"1",
- "dt": """ + str(QDateTime(QDate(2020, 5, 3), QTime(12, 13, 14)).toMSecsSinceEpoch()) + """,
- "date": """ + str(QDateTime(QDate(2020, 5, 3), QTime(0, 0, 0)).toMSecsSinceEpoch()) + """,
+ "dt": """
+ + str(
+ QDateTime(
+ QDate(2020, 5, 3), QTime(12, 13, 14)
+ ).toMSecsSinceEpoch()
+ )
+ + """,
+ "date": """
+ + str(
+ QDateTime(QDate(2020, 5, 3), QTime(0, 0, 0)).toMSecsSinceEpoch()
+ )
+ + """,
"time": "12:13:14"
},
"geometry": {
@@ -305,8 +391,18 @@ def setUpClass(cls):
"name": "Apple",
"name2":"Apple",
"num_char":"2",
- "dt": """ + str(QDateTime(QDate(2020, 5, 4), QTime(12, 14, 14)).toMSecsSinceEpoch()) + """,
- "date": """ + str(QDateTime(QDate(2020, 5, 4), QTime(0, 0, 0)).toMSecsSinceEpoch()) + """,
+ "dt": """
+ + str(
+ QDateTime(
+ QDate(2020, 5, 4), QTime(12, 14, 14)
+ ).toMSecsSinceEpoch()
+ )
+ + """,
+ "date": """
+ + str(
+ QDateTime(QDate(2020, 5, 4), QTime(0, 0, 0)).toMSecsSinceEpoch()
+ )
+ + """,
"time": "12:14:14"
},
"geometry": {
@@ -322,8 +418,18 @@ def setUpClass(cls):
"name": "Honey",
"name2":"Honey",
"num_char":"4",
- "dt": """ + str(QDateTime(QDate(2021, 5, 4), QTime(13, 13, 14)).toMSecsSinceEpoch()) + """,
- "date": """ + str(QDateTime(QDate(2021, 5, 4), QTime(0, 0, 0)).toMSecsSinceEpoch()) + """,
+ "dt": """
+ + str(
+ QDateTime(
+ QDate(2021, 5, 4), QTime(13, 13, 14)
+ ).toMSecsSinceEpoch()
+ )
+ + """,
+ "date": """
+ + str(
+ QDateTime(QDate(2021, 5, 4), QTime(0, 0, 0)).toMSecsSinceEpoch()
+ )
+ + """,
"time": "13:13:14"
},
"geometry": {
@@ -332,12 +438,20 @@ def setUpClass(cls):
}
}
]
- }""").encode('UTF-8'))
-
- with open(sanitize(endpoint,
- '/query?f=json&objectIds=3,2,4&inSR=4326&outSR=4326&returnGeometry=true&outFields=*&returnM=false&returnZ=false'),
- 'wb') as f:
- f.write(("""
+ }"""
+ ).encode("UTF-8")
+ )
+
+ with open(
+ sanitize(
+ endpoint,
+ "/query?f=json&objectIds=3,2,4&inSR=4326&outSR=4326&returnGeometry=true&outFields=*&returnM=false&returnZ=false",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ (
+ """
{
"displayFieldName": "name",
"fieldAliases": {
@@ -381,8 +495,18 @@ def setUpClass(cls):
"name": "Apple",
"name2":"Apple",
"num_char":"2",
- "dt": """ + str(QDateTime(QDate(2020, 5, 4), QTime(12, 14, 14)).toMSecsSinceEpoch()) + """,
- "date": """ + str(QDateTime(QDate(2020, 5, 4), QTime(0, 0, 0)).toMSecsSinceEpoch()) + """,
+ "dt": """
+ + str(
+ QDateTime(
+ QDate(2020, 5, 4), QTime(12, 14, 14)
+ ).toMSecsSinceEpoch()
+ )
+ + """,
+ "date": """
+ + str(
+ QDateTime(QDate(2020, 5, 4), QTime(0, 0, 0)).toMSecsSinceEpoch()
+ )
+ + """,
"time": "12:14:14"
},
"geometry": {
@@ -398,8 +522,18 @@ def setUpClass(cls):
"name": "Honey",
"name2":"Honey",
"num_char":"4",
- "dt": """ + str(QDateTime(QDate(2021, 5, 4), QTime(13, 13, 14)).toMSecsSinceEpoch()) + """,
- "date": """ + str(QDateTime(QDate(2021, 5, 4), QTime(0, 0, 0)).toMSecsSinceEpoch()) + """,
+ "dt": """
+ + str(
+ QDateTime(
+ QDate(2021, 5, 4), QTime(13, 13, 14)
+ ).toMSecsSinceEpoch()
+ )
+ + """,
+ "date": """
+ + str(
+ QDateTime(QDate(2021, 5, 4), QTime(0, 0, 0)).toMSecsSinceEpoch()
+ )
+ + """,
"time": "13:13:14"
},
"geometry": {
@@ -408,12 +542,20 @@ def setUpClass(cls):
}
}
]
- }""").encode('UTF-8'))
-
- with open(sanitize(endpoint,
- '/query?f=json&objectIds=3,2&inSR=4326&outSR=4326&returnGeometry=true&outFields=*&returnM=false&returnZ=false'),
- 'wb') as f:
- f.write(("""
+ }"""
+ ).encode("UTF-8")
+ )
+
+ with open(
+ sanitize(
+ endpoint,
+ "/query?f=json&objectIds=3,2&inSR=4326&outSR=4326&returnGeometry=true&outFields=*&returnM=false&returnZ=false",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ (
+ """
{
"displayFieldName": "name",
"fieldAliases": {
@@ -457,8 +599,18 @@ def setUpClass(cls):
"name": "Apple",
"name2":"Apple",
"num_char":"2",
- "dt": """ + str(QDateTime(QDate(2020, 5, 4), QTime(12, 14, 14)).toMSecsSinceEpoch()) + """,
- "date": """ + str(QDateTime(QDate(2020, 5, 4), QTime(0, 0, 0)).toMSecsSinceEpoch()) + """,
+ "dt": """
+ + str(
+ QDateTime(
+ QDate(2020, 5, 4), QTime(12, 14, 14)
+ ).toMSecsSinceEpoch()
+ )
+ + """,
+ "date": """
+ + str(
+ QDateTime(QDate(2020, 5, 4), QTime(0, 0, 0)).toMSecsSinceEpoch()
+ )
+ + """,
"time": "12:14:14"
},
"geometry": {
@@ -474,8 +626,18 @@ def setUpClass(cls):
"name": "Honey",
"name2":"Honey",
"num_char":"4",
- "dt": """ + str(QDateTime(QDate(2021, 5, 4), QTime(13, 13, 14)).toMSecsSinceEpoch()) + """,
- "date": """ + str(QDateTime(QDate(2021, 5, 4), QTime(0, 0, 0)).toMSecsSinceEpoch()) + """,
+ "dt": """
+ + str(
+ QDateTime(
+ QDate(2021, 5, 4), QTime(13, 13, 14)
+ ).toMSecsSinceEpoch()
+ )
+ + """,
+ "date": """
+ + str(
+ QDateTime(QDate(2021, 5, 4), QTime(0, 0, 0)).toMSecsSinceEpoch()
+ )
+ + """,
"time": "13:13:14"
},
"geometry": {
@@ -484,12 +646,19 @@ def setUpClass(cls):
}
}
]
- }""").encode('UTF-8'))
-
- with open(sanitize(endpoint,
- '/query?f=json&objectIds=5,3,1,2,4&inSR=4326&outSR=4326&returnGeometry=true&outFields=*&returnM=false&returnZ=false&geometry=-71.123000,66.330000,-65.320000,78.300000&geometryType=esriGeometryEnvelope&spatialRel=esriSpatialRelEnvelopeIntersects'),
- 'wb') as f:
- f.write(b"""
+ }"""
+ ).encode("UTF-8")
+ )
+
+ with open(
+ sanitize(
+ endpoint,
+ "/query?f=json&objectIds=5,3,1,2,4&inSR=4326&outSR=4326&returnGeometry=true&outFields=*&returnM=false&returnZ=false&geometry=-71.123000,66.330000,-65.320000,78.300000&geometryType=esriGeometryEnvelope&spatialRel=esriSpatialRelEnvelopeIntersects",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
{
"displayFieldName": "name",
"fieldAliases": {
@@ -579,12 +748,18 @@ def setUpClass(cls):
}
}
]
-}""")
-
- with open(sanitize(endpoint,
- '/query?f=json&objectIds=2,4&inSR=4326&outSR=4326&returnGeometry=true&outFields=*&returnM=false&returnZ=false'),
- 'wb') as f:
- f.write(b"""
+}"""
+ )
+
+ with open(
+ sanitize(
+ endpoint,
+ "/query?f=json&objectIds=2,4&inSR=4326&outSR=4326&returnGeometry=true&outFields=*&returnM=false&returnZ=false",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
{
"displayFieldName": "name",
"fieldAliases": {
@@ -635,12 +810,18 @@ def setUpClass(cls):
}
}
]
- }""")
-
- with open(sanitize(endpoint,
- '/query?f=json&where=1=1&returnIdsOnly=true&geometry=-70.000000,67.000000,-60.000000,80.000000&geometryType=esriGeometryEnvelope&spatialRel=esriSpatialRelEnvelopeIntersects'),
- 'wb') as f:
- f.write(b"""
+ }"""
+ )
+
+ with open(
+ sanitize(
+ endpoint,
+ "/query?f=json&where=1=1&returnIdsOnly=true&geometry=-70.000000,67.000000,-60.000000,80.000000&geometryType=esriGeometryEnvelope&spatialRel=esriSpatialRelEnvelopeIntersects",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
{
"objectIdFieldName": "OBJECTID",
"objectIds": [
@@ -648,12 +829,18 @@ def setUpClass(cls):
4
]
}
- """)
-
- with open(sanitize(endpoint,
- '/query?f=json&where==1=&returnIdsOnly=true&geometry=-73.000000,70.000000,-63.000000,80.000000&geometryType=esriGeometryEnvelope&spatialRel=esriSpatialRelEnvelopeIntersects'),
- 'wb') as f:
- f.write(b"""
+ """
+ )
+
+ with open(
+ sanitize(
+ endpoint,
+ "/query?f=json&where==1=&returnIdsOnly=true&geometry=-73.000000,70.000000,-63.000000,80.000000&geometryType=esriGeometryEnvelope&spatialRel=esriSpatialRelEnvelopeIntersects",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
{
"objectIdFieldName": "OBJECTID",
"objectIds": [
@@ -661,12 +848,18 @@ def setUpClass(cls):
4
]
}
- """)
-
- with open(sanitize(endpoint,
- '/query?f=json&where=1=1&returnIdsOnly=true&geometry=-68.721119,68.177676,-64.678700,79.123755&geometryType=esriGeometryEnvelope&spatialRel=esriSpatialRelEnvelopeIntersects'),
- 'wb') as f:
- f.write(b"""
+ """
+ )
+
+ with open(
+ sanitize(
+ endpoint,
+ "/query?f=json&where=1=1&returnIdsOnly=true&geometry=-68.721119,68.177676,-64.678700,79.123755&geometryType=esriGeometryEnvelope&spatialRel=esriSpatialRelEnvelopeIntersects",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
{
"objectIdFieldName": "OBJECTID",
"objectIds": [
@@ -674,12 +867,17 @@ def setUpClass(cls):
4
]
}
- """)
-
- with open(sanitize(endpoint,
- '/query?f=json&where="name"=\'Apple\'&returnExtentOnly=true'),
- 'wb') as f:
- f.write(b"""
+ """
+ )
+
+ with open(
+ sanitize(
+ endpoint, "/query?f=json&where=\"name\"='Apple'&returnExtentOnly=true"
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
{
"extent": {
"xmin": -68.2,
@@ -688,35 +886,44 @@ def setUpClass(cls):
"ymax":70.8
}
}
- """)
-
- with open(sanitize(endpoint,
- '/query?f=json&where="name"=\'AppleBearOrangePear\'&returnExtentOnly=true'),
- 'wb') as f:
- f.write(b"""
+ """
+ )
+
+ with open(
+ sanitize(
+ endpoint,
+ "/query?f=json&where=\"name\"='AppleBearOrangePear'&returnExtentOnly=true",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
{
"extent": {
}
}
- """)
+ """
+ )
@classmethod
def tearDownClass(cls):
"""Run after all tests"""
QgsSettings().clear()
# shutil.rmtree(cls.basetestpath, True)
- cls.vl = None # so as to properly close the provider and remove any temporary file
+ cls.vl = (
+ None # so as to properly close the provider and remove any temporary file
+ )
super().tearDownClass()
def testGetFeaturesSubsetAttributes2(self):
- """ Override and skip this test for AFS provider, as it's actually more efficient for the AFS provider to return
+ """Override and skip this test for AFS provider, as it's actually more efficient for the AFS provider to return
its features as direct copies (due to implicit sharing of QgsFeature), and the nature of the caching
used by the AFS provider.
"""
pass
def testGetFeaturesNoGeometry(self):
- """ Override and skip this test for AFS provider, as it's actually more efficient for the AFS provider to return
+ """Override and skip this test for AFS provider, as it's actually more efficient for the AFS provider to return
its features as direct copies (due to implicit sharing of QgsFeature), and the nature of the caching
used by the AFS provider.
"""
@@ -730,27 +937,51 @@ def testDecodeUri(self):
Test decoding an AFS uri
"""
uri = self.vl.source()
- parts = QgsProviderRegistry.instance().decodeUri(self.vl.dataProvider().name(), uri)
- self.assertEqual(parts, {'crs': 'epsg:4326', 'url': 'http://' + self.basetestpath + '/fake_qgis_http_endpoint'})
+ parts = QgsProviderRegistry.instance().decodeUri(
+ self.vl.dataProvider().name(), uri
+ )
+ self.assertEqual(
+ parts,
+ {
+ "crs": "epsg:4326",
+ "url": "http://" + self.basetestpath + "/fake_qgis_http_endpoint",
+ },
+ )
def testEncodeUri(self):
"""
Test encoding an AFS uri
"""
- parts = {'url': 'http://blah.com', 'crs': 'epsg:4326', 'referer': 'me', 'bounds': QgsRectangle(1, 2, 3, 4)}
- uri = QgsProviderRegistry.instance().encodeUri(self.vl.dataProvider().name(), parts)
- self.assertEqual(uri, " bbox='1,2,3,4' crs='epsg:4326' url='http://blah.com' http-header:referer='me' referer='me'")
+ parts = {
+ "url": "http://blah.com",
+ "crs": "epsg:4326",
+ "referer": "me",
+ "bounds": QgsRectangle(1, 2, 3, 4),
+ }
+ uri = QgsProviderRegistry.instance().encodeUri(
+ self.vl.dataProvider().name(), parts
+ )
+ self.assertEqual(
+ uri,
+ " bbox='1,2,3,4' crs='epsg:4326' url='http://blah.com' http-header:referer='me' referer='me'",
+ )
def testProviderCapabilities(self):
# non-editable layer
- self.assertEqual(self.vl.dataProvider().capabilities(), QgsVectorDataProvider.Capabilities(QgsVectorDataProvider.Capability.SelectAtId
- | QgsVectorDataProvider.Capability.ReadLayerMetadata
- | QgsVectorDataProvider.Capability.ReloadData))
+ self.assertEqual(
+ self.vl.dataProvider().capabilities(),
+ QgsVectorDataProvider.Capabilities(
+ QgsVectorDataProvider.Capability.SelectAtId
+ | QgsVectorDataProvider.Capability.ReadLayerMetadata
+ | QgsVectorDataProvider.Capability.ReloadData
+ ),
+ )
# delete capability
- endpoint = self.basetestpath + '/delete_fake_qgis_http_endpoint'
- with open(sanitize(endpoint, '?f=json'), 'wb') as f:
- f.write(b"""
+ endpoint = self.basetestpath + "/delete_fake_qgis_http_endpoint"
+ with open(sanitize(endpoint, "?f=json"), "wb") as f:
+ f.write(
+ b"""
{"currentVersion":10.22,"id":1,"name":"QGIS Test","type":"Feature Layer","description":
"QGIS Provider Test Layer","geometryType":"esriGeometryPoint","copyrightText":"not copyright","parentLayer":{"id":2,"name":"QGIS Tests"},"subLayers":[],
"minScale":72225,"maxScale":0,
@@ -763,30 +994,45 @@ def testProviderCapabilities(self):
"relationships":[],"canModifyLayer":false,"canScaleSymbols":false,"hasLabels":false,
"capabilities":"Map,Query,Data,Delete","maxRecordCount":1000,"supportsStatistics":true,
"supportsAdvancedQueries":true,"supportedQueryFormats":"JSON, AMF",
- "ownershipBasedAccessControlForFeatures":{"allowOthersToQuery":true},"useStandardizedQueries":true}""")
-
- with open(sanitize(endpoint, '/query?f=json_where=1=1&returnIdsOnly=true'), 'wb') as f:
- f.write(b"""
+ "ownershipBasedAccessControlForFeatures":{"allowOthersToQuery":true},"useStandardizedQueries":true}"""
+ )
+
+ with open(
+ sanitize(endpoint, "/query?f=json_where=1=1&returnIdsOnly=true"), "wb"
+ ) as f:
+ f.write(
+ b"""
{
"objectIdFieldName": "OBJECTID",
"objectIds": [
1
]
}
- """)
+ """
+ )
# Create test layer
- vl = QgsVectorLayer("url='http://" + endpoint + "' crs='epsg:4326'", 'test', 'arcgisfeatureserver')
+ vl = QgsVectorLayer(
+ "url='http://" + endpoint + "' crs='epsg:4326'",
+ "test",
+ "arcgisfeatureserver",
+ )
self.assertTrue(vl.isValid())
- self.assertEqual(vl.dataProvider().capabilities(), QgsVectorDataProvider.Capabilities(QgsVectorDataProvider.Capability.SelectAtId
- | QgsVectorDataProvider.Capability.ReadLayerMetadata
- | QgsVectorDataProvider.Capability.ReloadData
- | QgsVectorDataProvider.Capability.DeleteFeatures))
+ self.assertEqual(
+ vl.dataProvider().capabilities(),
+ QgsVectorDataProvider.Capabilities(
+ QgsVectorDataProvider.Capability.SelectAtId
+ | QgsVectorDataProvider.Capability.ReadLayerMetadata
+ | QgsVectorDataProvider.Capability.ReloadData
+ | QgsVectorDataProvider.Capability.DeleteFeatures
+ ),
+ )
# add capability
- endpoint = self.basetestpath + '/delete_fake_qgis_http_endpoint'
- with open(sanitize(endpoint, '?f=json'), 'wb') as f:
- f.write(b"""
+ endpoint = self.basetestpath + "/delete_fake_qgis_http_endpoint"
+ with open(sanitize(endpoint, "?f=json"), "wb") as f:
+ f.write(
+ b"""
{"currentVersion":10.22,"id":1,"name":"QGIS Test","type":"Feature Layer","description":
"QGIS Provider Test Layer","geometryType":"esriGeometryPoint","copyrightText":"not copyright","parentLayer":{"id":2,"name":"QGIS Tests"},"subLayers":[],
"minScale":72225,"maxScale":0,
@@ -799,19 +1045,30 @@ def testProviderCapabilities(self):
"relationships":[],"canModifyLayer":false,"canScaleSymbols":false,"hasLabels":false,
"capabilities":"Map,Query,Data,Create","maxRecordCount":1000,"supportsStatistics":true,
"supportsAdvancedQueries":true,"supportedQueryFormats":"JSON, AMF",
- "ownershipBasedAccessControlForFeatures":{"allowOthersToQuery":true},"useStandardizedQueries":true}""")
+ "ownershipBasedAccessControlForFeatures":{"allowOthersToQuery":true},"useStandardizedQueries":true}"""
+ )
# Create test layer
- vl = QgsVectorLayer("url='http://" + endpoint + "' crs='epsg:4326'", 'test', 'arcgisfeatureserver')
+ vl = QgsVectorLayer(
+ "url='http://" + endpoint + "' crs='epsg:4326'",
+ "test",
+ "arcgisfeatureserver",
+ )
self.assertTrue(vl.isValid())
- self.assertEqual(vl.dataProvider().capabilities(), QgsVectorDataProvider.Capabilities(QgsVectorDataProvider.Capability.SelectAtId
- | QgsVectorDataProvider.Capability.ReadLayerMetadata
- | QgsVectorDataProvider.Capability.ReloadData
- | QgsVectorDataProvider.Capability.AddFeatures))
+ self.assertEqual(
+ vl.dataProvider().capabilities(),
+ QgsVectorDataProvider.Capabilities(
+ QgsVectorDataProvider.Capability.SelectAtId
+ | QgsVectorDataProvider.Capability.ReadLayerMetadata
+ | QgsVectorDataProvider.Capability.ReloadData
+ | QgsVectorDataProvider.Capability.AddFeatures
+ ),
+ )
# update capability
- endpoint = self.basetestpath + '/delete_fake_qgis_http_endpoint'
- with open(sanitize(endpoint, '?f=json'), 'wb') as f:
- f.write(b"""
+ endpoint = self.basetestpath + "/delete_fake_qgis_http_endpoint"
+ with open(sanitize(endpoint, "?f=json"), "wb") as f:
+ f.write(
+ b"""
{"currentVersion":10.22,"id":1,"name":"QGIS Test","type":"Feature Layer","description":
"QGIS Provider Test Layer","geometryType":"esriGeometryPoint","copyrightText":"not copyright","parentLayer":{"id":2,"name":"QGIS Tests"},"subLayers":[],
"minScale":72225,"maxScale":0,
@@ -824,22 +1081,32 @@ def testProviderCapabilities(self):
"relationships":[],"canModifyLayer":false,"canScaleSymbols":false,"hasLabels":false,
"capabilities":"Map,Query,Data,Update","maxRecordCount":1000,"supportsStatistics":true,
"supportsAdvancedQueries":true,"supportedQueryFormats":"JSON, AMF",
- "ownershipBasedAccessControlForFeatures":{"allowOthersToQuery":true},"useStandardizedQueries":true}""")
+ "ownershipBasedAccessControlForFeatures":{"allowOthersToQuery":true},"useStandardizedQueries":true}"""
+ )
# Create test layer
- vl = QgsVectorLayer("url='http://" + endpoint + "' crs='epsg:4326'", 'test', 'arcgisfeatureserver')
+ vl = QgsVectorLayer(
+ "url='http://" + endpoint + "' crs='epsg:4326'",
+ "test",
+ "arcgisfeatureserver",
+ )
self.assertTrue(vl.isValid())
- self.assertEqual(vl.dataProvider().capabilities(),
- QgsVectorDataProvider.Capabilities(QgsVectorDataProvider.Capability.SelectAtId
- | QgsVectorDataProvider.Capability.ReadLayerMetadata
- | QgsVectorDataProvider.Capability.ReloadData
- | QgsVectorDataProvider.Capability.ChangeAttributeValues
- | QgsVectorDataProvider.Capability.ChangeFeatures
- | QgsVectorDataProvider.Capability.ChangeGeometries))
+ self.assertEqual(
+ vl.dataProvider().capabilities(),
+ QgsVectorDataProvider.Capabilities(
+ QgsVectorDataProvider.Capability.SelectAtId
+ | QgsVectorDataProvider.Capability.ReadLayerMetadata
+ | QgsVectorDataProvider.Capability.ReloadData
+ | QgsVectorDataProvider.Capability.ChangeAttributeValues
+ | QgsVectorDataProvider.Capability.ChangeFeatures
+ | QgsVectorDataProvider.Capability.ChangeGeometries
+ ),
+ )
# circular strings
- with open(sanitize(endpoint, '?f=json'), 'wb') as f:
- f.write(b"""
+ with open(sanitize(endpoint, "?f=json"), "wb") as f:
+ f.write(
+ b"""
{"currentVersion":10.22,"id":1,"name":"QGIS Test","allowTrueCurvesUpdates":true,"type":"Feature Layer","description":
"QGIS Provider Test Layer","geometryType":"esriGeometryPoint","copyrightText":"not copyright","parentLayer":{"id":2,"name":"QGIS Tests"},"subLayers":[],
"minScale":72225,"maxScale":0,
@@ -852,36 +1119,63 @@ def testProviderCapabilities(self):
"relationships":[],"canModifyLayer":false,"canScaleSymbols":false,"hasLabels":false,
"capabilities":"Map,Query,Data,Update","maxRecordCount":1000,"supportsStatistics":true,
"supportsAdvancedQueries":true,"supportedQueryFormats":"JSON, AMF",
- "ownershipBasedAccessControlForFeatures":{"allowOthersToQuery":true},"useStandardizedQueries":true}""")
- vl = QgsVectorLayer("url='http://" + endpoint + "' crs='epsg:4326'", 'test', 'arcgisfeatureserver')
+ "ownershipBasedAccessControlForFeatures":{"allowOthersToQuery":true},"useStandardizedQueries":true}"""
+ )
+ vl = QgsVectorLayer(
+ "url='http://" + endpoint + "' crs='epsg:4326'",
+ "test",
+ "arcgisfeatureserver",
+ )
self.assertTrue(vl.isValid())
- self.assertEqual(vl.dataProvider().capabilities(),
- QgsVectorDataProvider.Capabilities(QgsVectorDataProvider.Capability.SelectAtId
- | QgsVectorDataProvider.Capability.ReadLayerMetadata
- | QgsVectorDataProvider.Capability.ReloadData
- | QgsVectorDataProvider.Capability.ChangeAttributeValues
- | QgsVectorDataProvider.Capability.ChangeFeatures
- | QgsVectorDataProvider.Capability.CircularGeometries
- | QgsVectorDataProvider.Capability.ChangeGeometries))
+ self.assertEqual(
+ vl.dataProvider().capabilities(),
+ QgsVectorDataProvider.Capabilities(
+ QgsVectorDataProvider.Capability.SelectAtId
+ | QgsVectorDataProvider.Capability.ReadLayerMetadata
+ | QgsVectorDataProvider.Capability.ReloadData
+ | QgsVectorDataProvider.Capability.ChangeAttributeValues
+ | QgsVectorDataProvider.Capability.ChangeFeatures
+ | QgsVectorDataProvider.Capability.CircularGeometries
+ | QgsVectorDataProvider.Capability.ChangeGeometries
+ ),
+ )
def testFieldProperties(self):
self.assertEqual(self.vl.dataProvider().pkAttributeIndexes(), [0])
- self.assertEqual(self.vl.dataProvider().fields()[0].constraints().constraints(),
- QgsFieldConstraints.Constraints(QgsFieldConstraints.Constraint.ConstraintNotNull | QgsFieldConstraints.Constraint.ConstraintUnique))
+ self.assertEqual(
+ self.vl.dataProvider().fields()[0].constraints().constraints(),
+ QgsFieldConstraints.Constraints(
+ QgsFieldConstraints.Constraint.ConstraintNotNull
+ | QgsFieldConstraints.Constraint.ConstraintUnique
+ ),
+ )
self.assertFalse(self.vl.dataProvider().fields()[1].constraints().constraints())
- self.assertEqual(self.vl.dataProvider().defaultValueClause(0), 'Autogenerate')
+ self.assertEqual(self.vl.dataProvider().defaultValueClause(0), "Autogenerate")
self.assertFalse(self.vl.dataProvider().defaultValueClause(1))
- self.assertTrue(self.vl.dataProvider().skipConstraintCheck(0, QgsFieldConstraints.Constraint.ConstraintUnique, 'Autogenerate'))
- self.assertFalse(self.vl.dataProvider().skipConstraintCheck(0, QgsFieldConstraints.Constraint.ConstraintUnique, 'aa'))
- self.assertFalse(self.vl.dataProvider().skipConstraintCheck(1, QgsFieldConstraints.Constraint.ConstraintUnique, 'aa'))
+ self.assertTrue(
+ self.vl.dataProvider().skipConstraintCheck(
+ 0, QgsFieldConstraints.Constraint.ConstraintUnique, "Autogenerate"
+ )
+ )
+ self.assertFalse(
+ self.vl.dataProvider().skipConstraintCheck(
+ 0, QgsFieldConstraints.Constraint.ConstraintUnique, "aa"
+ )
+ )
+ self.assertFalse(
+ self.vl.dataProvider().skipConstraintCheck(
+ 1, QgsFieldConstraints.Constraint.ConstraintUnique, "aa"
+ )
+ )
def testObjectIdDifferentName(self):
- """ Test that object id fields not named OBJECTID work correctly """
+ """Test that object id fields not named OBJECTID work correctly"""
- endpoint = self.basetestpath + '/oid_fake_qgis_http_endpoint'
- with open(sanitize(endpoint, '?f=json'), 'wb') as f:
- f.write(b"""
+ endpoint = self.basetestpath + "/oid_fake_qgis_http_endpoint"
+ with open(sanitize(endpoint, "?f=json"), "wb") as f:
+ f.write(
+ b"""
{"currentVersion":10.22,"id":1,"name":"QGIS Test","type":"Feature Layer","description":
"QGIS Provider Test Layer.\n","geometryType":"esriGeometryPoint","copyrightText":"","parentLayer":{"id":0,"name":"QGIS Tests"},"subLayers":[],
"minScale":72225,"maxScale":0,
@@ -896,10 +1190,14 @@ def testObjectIdDifferentName(self):
"relationships":[],"canModifyLayer":false,"canScaleSymbols":false,"hasLabels":false,
"capabilities":"Map,Query,Data","maxRecordCount":1000,"supportsStatistics":true,
"supportsAdvancedQueries":true,"supportedQueryFormats":"JSON, AMF",
- "ownershipBasedAccessControlForFeatures":{"allowOthersToQuery":true},"useStandardizedQueries":true}""")
-
- with open(sanitize(endpoint, '/query?f=json_where=1=1&returnIdsOnly=true'), 'wb') as f:
- f.write(b"""
+ "ownershipBasedAccessControlForFeatures":{"allowOthersToQuery":true},"useStandardizedQueries":true}"""
+ )
+
+ with open(
+ sanitize(endpoint, "/query?f=json_where=1=1&returnIdsOnly=true"), "wb"
+ ) as f:
+ f.write(
+ b"""
{
"objectIdFieldName": "OBJECTID1",
"objectIds": [
@@ -910,12 +1208,18 @@ def testObjectIdDifferentName(self):
4
]
}
- """)
-
- with open(sanitize(endpoint,
- '/query?f=json&objectIds=5,3,1,2,4&inSR=4326&outSR=4326&returnGeometry=true&outFields=*&returnM=false&returnZ=false'),
- 'wb') as f:
- f.write(b"""
+ """
+ )
+
+ with open(
+ sanitize(
+ endpoint,
+ "/query?f=json&objectIds=5,3,1,2,4&inSR=4326&outSR=4326&returnGeometry=true&outFields=*&returnM=false&returnZ=false",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
{
"displayFieldName": "LABEL",
"geometryType": "esriGeometryPoint",
@@ -941,21 +1245,27 @@ def testObjectIdDifferentName(self):
}
}
]
- }""")
+ }"""
+ )
# Create test layer
- vl = QgsVectorLayer("url='http://" + endpoint + "' crs='epsg:4326'", 'test', 'arcgisfeatureserver')
+ vl = QgsVectorLayer(
+ "url='http://" + endpoint + "' crs='epsg:4326'",
+ "test",
+ "arcgisfeatureserver",
+ )
self.assertTrue(vl.isValid())
f = vl.getFeature(0)
self.assertTrue(f.isValid())
def testDateTime(self):
- """ Test that datetime fields work correctly """
+ """Test that datetime fields work correctly"""
- endpoint = self.basetestpath + '/oid_fake_qgis_http_endpoint'
- with open(sanitize(endpoint, '?f=json'), 'wb') as f:
- f.write(b"""
+ endpoint = self.basetestpath + "/oid_fake_qgis_http_endpoint"
+ with open(sanitize(endpoint, "?f=json"), "wb") as f:
+ f.write(
+ b"""
{"currentVersion":10.22,"id":1,"name":"QGIS Test","type":"Feature Layer","description":
"QGIS Provider Test Layer.\n","geometryType":"esriGeometryPoint","copyrightText":"","parentLayer":{"id":0,"name":"QGIS Tests"},"subLayers":[],
"minScale":72225,"maxScale":0,
@@ -970,10 +1280,14 @@ def testDateTime(self):
"relationships":[],"canModifyLayer":false,"canScaleSymbols":false,"hasLabels":false,
"capabilities":"Map,Query,Data","maxRecordCount":1000,"supportsStatistics":true,
"supportsAdvancedQueries":true,"supportedQueryFormats":"JSON, AMF",
- "ownershipBasedAccessControlForFeatures":{"allowOthersToQuery":true},"useStandardizedQueries":true}""")
-
- with open(sanitize(endpoint, '/query?f=json_where=1=1&returnIdsOnly=true'), 'wb') as f:
- f.write(b"""
+ "ownershipBasedAccessControlForFeatures":{"allowOthersToQuery":true},"useStandardizedQueries":true}"""
+ )
+
+ with open(
+ sanitize(endpoint, "/query?f=json_where=1=1&returnIdsOnly=true"), "wb"
+ ) as f:
+ f.write(
+ b"""
{
"objectIdFieldName": "OBJECTID",
"objectIds": [
@@ -981,19 +1295,31 @@ def testDateTime(self):
2
]
}
- """)
+ """
+ )
# Create test layer
- vl = QgsVectorLayer("url='http://" + endpoint + "' crs='epsg:4326'", 'test', 'arcgisfeatureserver')
+ vl = QgsVectorLayer(
+ "url='http://" + endpoint + "' crs='epsg:4326'",
+ "test",
+ "arcgisfeatureserver",
+ )
self.assertTrue(vl.isValid())
- self.assertFalse(vl.dataProvider().temporalCapabilities().hasTemporalCapabilities())
-
- with open(sanitize(endpoint,
- '/query?f=json&objectIds=1,2&inSR=4326&outSR=4326&returnGeometry=true&outFields=*&returnM=false&returnZ=false'),
- 'wb') as f:
- f.write(b"""
+ self.assertFalse(
+ vl.dataProvider().temporalCapabilities().hasTemporalCapabilities()
+ )
+
+ with open(
+ sanitize(
+ endpoint,
+ "/query?f=json&objectIds=1,2&inSR=4326&outSR=4326&returnGeometry=true&outFields=*&returnM=false&returnZ=false",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
{
"displayFieldName": "name",
"fieldAliases": {
@@ -1032,18 +1358,28 @@ def testDateTime(self):
}
}
]
- }""")
+ }"""
+ )
features = [f for f in vl.getFeatures()]
self.assertEqual(len(features), 2)
- self.assertEqual([f['dt'] for f in features], [QDateTime(QDate(2017, 5, 3), QTime(0, 0, 0, 0), Qt.TimeSpec.UTC).toLocalTime(), NULL])
+ self.assertEqual(
+ [f["dt"] for f in features],
+ [
+ QDateTime(
+ QDate(2017, 5, 3), QTime(0, 0, 0, 0), Qt.TimeSpec.UTC
+ ).toLocalTime(),
+ NULL,
+ ],
+ )
def testMetadata(self):
- """ Test that metadata is correctly acquired from provider """
+ """Test that metadata is correctly acquired from provider"""
- endpoint = self.basetestpath + '/metadata_fake_qgis_http_endpoint'
- with open(sanitize(endpoint, '?f=json'), 'wb') as f:
- f.write(b"""
+ endpoint = self.basetestpath + "/metadata_fake_qgis_http_endpoint"
+ with open(sanitize(endpoint, "?f=json"), "wb") as f:
+ f.write(
+ b"""
{"currentVersion":10.22,"id":1,"name":"QGIS Test","type":"Feature Layer","description":
"QGIS Provider Test Layer","geometryType":"esriGeometryPoint","copyrightText":"not copyright","parentLayer":{"id":2,"name":"QGIS Tests"},"subLayers":[],
"minScale":72225,"maxScale":0,
@@ -1056,20 +1392,29 @@ def testMetadata(self):
"relationships":[],"canModifyLayer":false,"canScaleSymbols":false,"hasLabels":false,
"capabilities":"Map,Query,Data","maxRecordCount":1000,"supportsStatistics":true,
"supportsAdvancedQueries":true,"supportedQueryFormats":"JSON, AMF",
- "ownershipBasedAccessControlForFeatures":{"allowOthersToQuery":true},"useStandardizedQueries":true}""")
-
- with open(sanitize(endpoint, '/query?f=json_where=1=1&returnIdsOnly=true'), 'wb') as f:
- f.write(b"""
+ "ownershipBasedAccessControlForFeatures":{"allowOthersToQuery":true},"useStandardizedQueries":true}"""
+ )
+
+ with open(
+ sanitize(endpoint, "/query?f=json_where=1=1&returnIdsOnly=true"), "wb"
+ ) as f:
+ f.write(
+ b"""
{
"objectIdFieldName": "OBJECTID",
"objectIds": [
1
]
}
- """)
+ """
+ )
# Create test layer
- vl = QgsVectorLayer("url='http://" + endpoint + "' crs='epsg:4326'", 'test', 'arcgisfeatureserver')
+ vl = QgsVectorLayer(
+ "url='http://" + endpoint + "' crs='epsg:4326'",
+ "test",
+ "arcgisfeatureserver",
+ )
self.assertTrue(vl.isValid())
extent = QgsLayerMetadata.Extent()
@@ -1080,24 +1425,25 @@ def testMetadata(self):
md = vl.metadata()
self.assertEqual(md.extent(), extent)
self.assertEqual(md.crs(), QgsCoordinateReferenceSystem.fromEpsgId(4326))
- self.assertEqual(md.identifier(), 'http://' + sanitize(endpoint, ''))
- self.assertEqual(md.parentIdentifier(), 'http://' + self.basetestpath + '/2')
- self.assertEqual(md.type(), 'dataset')
- self.assertEqual(md.abstract(), 'QGIS Provider Test Layer')
- self.assertEqual(md.title(), 'QGIS Test')
- self.assertEqual(md.rights(), ['not copyright'])
+ self.assertEqual(md.identifier(), "http://" + sanitize(endpoint, ""))
+ self.assertEqual(md.parentIdentifier(), "http://" + self.basetestpath + "/2")
+ self.assertEqual(md.type(), "dataset")
+ self.assertEqual(md.abstract(), "QGIS Provider Test Layer")
+ self.assertEqual(md.title(), "QGIS Test")
+ self.assertEqual(md.rights(), ["not copyright"])
l = QgsLayerMetadata.Link()
- l.name = 'Source'
- l.type = 'WWW:LINK'
- l.url = 'http://' + sanitize(endpoint, '')
+ l.name = "Source"
+ l.type = "WWW:LINK"
+ l.url = "http://" + sanitize(endpoint, "")
self.assertEqual(md.links(), [l])
def testFieldAlias(self):
- """ Test that field aliases are correctly acquired from provider """
+ """Test that field aliases are correctly acquired from provider"""
- endpoint = self.basetestpath + '/alias_fake_qgis_http_endpoint'
- with open(sanitize(endpoint, '?f=json'), 'wb') as f:
- f.write(b"""
+ endpoint = self.basetestpath + "/alias_fake_qgis_http_endpoint"
+ with open(sanitize(endpoint, "?f=json"), "wb") as f:
+ f.write(
+ b"""
{"currentVersion":10.22,"id":1,"name":"QGIS Test","type":"Feature Layer","description":
"QGIS Provider Test Layer","geometryType":"esriGeometryPoint","copyrightText":"not copyright","parentLayer":{"id":2,"name":"QGIS Tests"},"subLayers":[],
"minScale":72225,"maxScale":0,
@@ -1110,33 +1456,43 @@ def testFieldAlias(self):
"relationships":[],"canModifyLayer":false,"canScaleSymbols":false,"hasLabels":false,
"capabilities":"Map,Query,Data","maxRecordCount":1000,"supportsStatistics":true,
"supportsAdvancedQueries":true,"supportedQueryFormats":"JSON, AMF",
- "ownershipBasedAccessControlForFeatures":{"allowOthersToQuery":true},"useStandardizedQueries":true}""")
-
- with open(sanitize(endpoint, '/query?f=json_where=1=1&returnIdsOnly=true'), 'wb') as f:
- f.write(b"""
+ "ownershipBasedAccessControlForFeatures":{"allowOthersToQuery":true},"useStandardizedQueries":true}"""
+ )
+
+ with open(
+ sanitize(endpoint, "/query?f=json_where=1=1&returnIdsOnly=true"), "wb"
+ ) as f:
+ f.write(
+ b"""
{
"objectIdFieldName": "OBJECTID",
"objectIds": [
1
]
}
- """)
+ """
+ )
# Create test layer
- vl = QgsVectorLayer("url='http://" + endpoint + "' crs='epsg:4326'", 'test', 'arcgisfeatureserver')
+ vl = QgsVectorLayer(
+ "url='http://" + endpoint + "' crs='epsg:4326'",
+ "test",
+ "arcgisfeatureserver",
+ )
self.assertTrue(vl.isValid())
- self.assertEqual(vl.fields().at(0).name(), 'OBJECTID')
- self.assertEqual(vl.fields().at(0).alias(), 'field id')
- self.assertEqual(vl.fields().at(1).name(), 'second')
+ self.assertEqual(vl.fields().at(0).name(), "OBJECTID")
+ self.assertEqual(vl.fields().at(0).alias(), "field id")
+ self.assertEqual(vl.fields().at(1).name(), "second")
self.assertFalse(vl.fields().at(1).alias())
def testCategorizedRenderer(self):
- """ Test that the categorized renderer is correctly acquired from provider """
+ """Test that the categorized renderer is correctly acquired from provider"""
- endpoint = self.basetestpath + '/renderer_fake_qgis_http_endpoint'
- with open(sanitize(endpoint, '?f=json'), 'wb') as f:
- f.write(b"""
+ endpoint = self.basetestpath + "/renderer_fake_qgis_http_endpoint"
+ with open(sanitize(endpoint, "?f=json"), "wb") as f:
+ f.write(
+ b"""
{"currentVersion":10.22,"id":1,"name":"QGIS Test","type":"Feature Layer","description":
"QGIS Provider Test Layer","geometryType":"esriGeometryPoint","copyrightText":"not copyright","parentLayer":{"id":2,"name":"QGIS Tests"},"subLayers":[],
"minScale":72225,"maxScale":0,
@@ -1211,26 +1567,35 @@ def testCategorizedRenderer(self):
},
"label": "Canada"
}]}},
- "ownershipBasedAccessControlForFeatures":{"allowOthersToQuery":true},"useStandardizedQueries":true}""")
-
- with open(sanitize(endpoint, '/query?f=json_where=1=1&returnIdsOnly=true'), 'wb') as f:
- f.write(b"""
+ "ownershipBasedAccessControlForFeatures":{"allowOthersToQuery":true},"useStandardizedQueries":true}"""
+ )
+
+ with open(
+ sanitize(endpoint, "/query?f=json_where=1=1&returnIdsOnly=true"), "wb"
+ ) as f:
+ f.write(
+ b"""
{
"objectIdFieldName": "OBJECTID",
"objectIds": [
1
]
}
- """)
+ """
+ )
# Create test layer
- vl = QgsVectorLayer("url='http://" + endpoint + "' crs='epsg:4326'", 'test', 'arcgisfeatureserver')
+ vl = QgsVectorLayer(
+ "url='http://" + endpoint + "' crs='epsg:4326'",
+ "test",
+ "arcgisfeatureserver",
+ )
self.assertTrue(vl.isValid())
self.assertIsNotNone(vl.dataProvider().createRenderer())
self.assertIsInstance(vl.renderer(), QgsCategorizedSymbolRenderer)
self.assertEqual(len(vl.renderer().categories()), 2)
- self.assertEqual(vl.renderer().categories()[0].value(), 'US')
- self.assertEqual(vl.renderer().categories()[1].value(), 'Canada')
+ self.assertEqual(vl.renderer().categories()[0].value(), "US")
+ self.assertEqual(vl.renderer().categories()[1].value(), "Canada")
def testGraduatedRendererContinuous(self):
"""
@@ -1238,9 +1603,10 @@ def testGraduatedRendererContinuous(self):
is correctly acquired from provider
"""
- endpoint = self.basetestpath + '/class_breaks_renderer_fake_qgis_http_endpoint'
- with open(sanitize(endpoint, '?f=json'), 'wb') as f:
- f.write(b"""{
+ endpoint = self.basetestpath + "/class_breaks_renderer_fake_qgis_http_endpoint"
+ with open(sanitize(endpoint, "?f=json"), "wb") as f:
+ f.write(
+ b"""{
"currentVersion": 11.2,
"id": 0,
"name": "Test graduated renderer",
@@ -1388,37 +1754,54 @@ def testGraduatedRendererContinuous(self):
"transparency": 20
},
"allowGeometryUpdates": true
- }""")
-
- with open(sanitize(endpoint, '/query?f=json_where=1=1&returnIdsOnly=true'), 'wb') as f:
- f.write(b"""
+ }"""
+ )
+
+ with open(
+ sanitize(endpoint, "/query?f=json_where=1=1&returnIdsOnly=true"), "wb"
+ ) as f:
+ f.write(
+ b"""
{
"objectIdFieldName": "OBJECTID",
"objectIds": [
1
]
}
- """)
+ """
+ )
# Create test layer
- vl = QgsVectorLayer("url='http://" + endpoint + "' crs='epsg:3857'", 'test', 'arcgisfeatureserver')
+ vl = QgsVectorLayer(
+ "url='http://" + endpoint + "' crs='epsg:3857'",
+ "test",
+ "arcgisfeatureserver",
+ )
self.assertTrue(vl.isValid())
self.assertIsNotNone(vl.dataProvider().createRenderer())
self.assertIsInstance(vl.renderer(), QgsSingleSymbolRenderer)
self.assertIsInstance(vl.renderer().symbol(), QgsFillSymbol)
- prop = vl.renderer().symbol()[0].dataDefinedProperties().property(QgsSymbolLayer.Property.FillColor)
+ prop = (
+ vl.renderer()
+ .symbol()[0]
+ .dataDefinedProperties()
+ .property(QgsSymbolLayer.Property.FillColor)
+ )
self.assertEqual(prop.propertyType(), Qgis.PropertyType.Field)
- self.assertEqual(prop.field(), 'SUM')
+ self.assertEqual(prop.field(), "SUM")
self.assertIsInstance(prop.transformer(), QgsColorRampTransformer)
self.assertEqual(prop.transformer().minValue(), 10151)
self.assertEqual(prop.transformer().maxValue(), 2500000)
ramp = prop.transformer().colorRamp()
self.assertIsInstance(ramp, QgsGradientColorRamp)
- self.assertEqual(ramp.color1().name(), '#ffc4ae')
- self.assertEqual(ramp.color2().name(), '#7b4238')
+ self.assertEqual(ramp.color1().name(), "#ffc4ae")
+ self.assertEqual(ramp.color2().name(), "#7b4238")
self.assertEqual([stop.offset for stop in ramp.stops()], [0.25, 0.5, 0.75])
- self.assertEqual([stop.color.name() for stop in ramp.stops()], ['#f9816c', '#ec5244', '#c23d33'])
+ self.assertEqual(
+ [stop.color.name() for stop in ramp.stops()],
+ ["#f9816c", "#ec5244", "#c23d33"],
+ )
def testGraduatedRendererClassedColor(self):
"""
@@ -1426,9 +1809,10 @@ def testGraduatedRendererClassedColor(self):
is correctly acquired from provider
"""
- endpoint = self.basetestpath + '/class_breaks_renderer_fake_qgis_http_endpoint'
- with open(sanitize(endpoint, '?f=json'), 'wb') as f:
- f.write(b"""{
+ endpoint = self.basetestpath + "/class_breaks_renderer_fake_qgis_http_endpoint"
+ with open(sanitize(endpoint, "?f=json"), "wb") as f:
+ f.write(
+ b"""{
"currentVersion": 11.2,
"id": 0,
"name": "Test graduated renderer",
@@ -1678,20 +2062,29 @@ def testGraduatedRendererClassedColor(self):
"labelingInfo": null
},
"allowGeometryUpdates": true
-}""")
-
- with open(sanitize(endpoint, '/query?f=json_where=1=1&returnIdsOnly=true'), 'wb') as f:
- f.write(b"""
+}"""
+ )
+
+ with open(
+ sanitize(endpoint, "/query?f=json_where=1=1&returnIdsOnly=true"), "wb"
+ ) as f:
+ f.write(
+ b"""
{
"objectIdFieldName": "OBJECTID",
"objectIds": [
1
]
}
- """)
+ """
+ )
# Create test layer
- vl = QgsVectorLayer("url='http://" + endpoint + "' crs='epsg:3857'", 'test', 'arcgisfeatureserver')
+ vl = QgsVectorLayer(
+ "url='http://" + endpoint + "' crs='epsg:3857'",
+ "test",
+ "arcgisfeatureserver",
+ )
self.assertTrue(vl.isValid())
self.assertIsNotNone(vl.dataProvider().createRenderer())
self.assertIsInstance(vl.renderer(), QgsGraduatedSymbolRenderer)
@@ -1701,58 +2094,58 @@ def testGraduatedRendererClassedColor(self):
_range = vl.renderer().ranges()[0]
self.assertEqual(_range.lowerValue(), 7)
self.assertEqual(_range.upperValue(), 7)
- self.assertEqual(_range.label(), '7.000000')
- self.assertEqual(_range.symbol().color().name(),
- '#e6eecf')
+ self.assertEqual(_range.label(), "7.000000")
+ self.assertEqual(_range.symbol().color().name(), "#e6eecf")
_range = vl.renderer().ranges()[1]
self.assertEqual(_range.lowerValue(), 7)
self.assertEqual(_range.upperValue(), 8)
- self.assertEqual(_range.label(), '7.000001 - 8.000000')
- self.assertEqual(_range.symbol().color().name(),
- '#9bc4c1')
+ self.assertEqual(_range.label(), "7.000001 - 8.000000")
+ self.assertEqual(_range.symbol().color().name(), "#9bc4c1")
_range = vl.renderer().ranges()[2]
self.assertEqual(_range.lowerValue(), 8)
self.assertEqual(_range.upperValue(), 11)
- self.assertEqual(_range.label(), '8.000001 - 11.000000')
- self.assertEqual(_range.symbol().color().name(),
- '#69a8b7')
+ self.assertEqual(_range.label(), "8.000001 - 11.000000")
+ self.assertEqual(_range.symbol().color().name(), "#69a8b7")
_range = vl.renderer().ranges()[3]
self.assertEqual(_range.lowerValue(), 11)
self.assertEqual(_range.upperValue(), 13)
- self.assertEqual(_range.label(), '11.000001 - 13.000000')
- self.assertEqual(_range.symbol().color().name(),
- '#4b7e98')
+ self.assertEqual(_range.label(), "11.000001 - 13.000000")
+ self.assertEqual(_range.symbol().color().name(), "#4b7e98")
_range = vl.renderer().ranges()[4]
self.assertEqual(_range.lowerValue(), 13)
self.assertEqual(_range.upperValue(), 20)
- self.assertEqual(_range.label(), '13.000001 - 20.000000')
- self.assertEqual(_range.symbol().color().name(),
- '#2e557a')
+ self.assertEqual(_range.label(), "13.000001 - 20.000000")
+ self.assertEqual(_range.symbol().color().name(), "#2e557a")
def testBboxRestriction(self):
"""
Test limiting provider to features within a preset bounding box
"""
- endpoint = self.basetestpath + '/fake_qgis_http_endpoint'
+ endpoint = self.basetestpath + "/fake_qgis_http_endpoint"
vl = QgsVectorLayer(
- "url='http://" + endpoint + "' crs='epsg:4326' bbox='-70.000000,67.000000,-60.000000,80.000000'", 'test',
- 'arcgisfeatureserver')
+ "url='http://"
+ + endpoint
+ + "' crs='epsg:4326' bbox='-70.000000,67.000000,-60.000000,80.000000'",
+ "test",
+ "arcgisfeatureserver",
+ )
self.assertTrue(vl.isValid())
self.assertEqual(vl.featureCount(), 2)
- self.assertEqual([f['pk'] for f in vl.getFeatures()], [2, 4])
+ self.assertEqual([f["pk"] for f in vl.getFeatures()], [2, 4])
def testBadMultiPoints(self):
"""
Test invalid server response where a layer's type is multipoint but single point geometries
are returned. Thanks Jack. Thack.
"""
- endpoint = self.basetestpath + '/multipoint_fake_qgis_http_endpoint'
- with open(sanitize(endpoint, '?f=json'), 'wb') as f:
- f.write(b"""
+ endpoint = self.basetestpath + "/multipoint_fake_qgis_http_endpoint"
+ with open(sanitize(endpoint, "?f=json"), "wb") as f:
+ f.write(
+ b"""
{"currentVersion":10.22,"id":1,"name":"QGIS Test","type":"Feature Layer","description":
"QGIS Provider Test Layer.\n","geometryType":"esriGeometryMultipoint","copyrightText":"","parentLayer":{"id":0,"name":"QGIS Tests"},"subLayers":[],
"minScale":72225,"maxScale":0,
@@ -1765,10 +2158,14 @@ def testBadMultiPoints(self):
"relationships":[],"canModifyLayer":false,"canScaleSymbols":false,"hasLabels":false,
"capabilities":"Map,Query,Data","maxRecordCount":1000,"supportsStatistics":true,
"supportsAdvancedQueries":true,"supportedQueryFormats":"JSON, AMF",
- "ownershipBasedAccessControlForFeatures":{"allowOthersToQuery":true},"useStandardizedQueries":true}""")
-
- with open(sanitize(endpoint, '/query?f=json_where=1=1&returnIdsOnly=true'), 'wb') as f:
- f.write(b"""
+ "ownershipBasedAccessControlForFeatures":{"allowOthersToQuery":true},"useStandardizedQueries":true}"""
+ )
+
+ with open(
+ sanitize(endpoint, "/query?f=json_where=1=1&returnIdsOnly=true"), "wb"
+ ) as f:
+ f.write(
+ b"""
{
"objectIdFieldName": "OBJECTID",
"objectIds": [
@@ -1777,16 +2174,26 @@ def testBadMultiPoints(self):
3
]
}
- """)
+ """
+ )
# Create test layer
- vl = QgsVectorLayer("url='http://" + endpoint + "' crs='epsg:4326'", 'test', 'arcgisfeatureserver')
+ vl = QgsVectorLayer(
+ "url='http://" + endpoint + "' crs='epsg:4326'",
+ "test",
+ "arcgisfeatureserver",
+ )
self.assertTrue(vl.isValid())
- with open(sanitize(endpoint,
- '/query?f=json&objectIds=1,2,3&inSR=4326&outSR=4326&returnGeometry=true&outFields=*&returnM=false&returnZ=false'),
- 'wb') as f:
- f.write(b"""
+ with open(
+ sanitize(
+ endpoint,
+ "/query?f=json&objectIds=1,2,3&inSR=4326&outSR=4326&returnGeometry=true&outFields=*&returnM=false&returnZ=false",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
{
"displayFieldName": "name",
"fieldAliases": {
@@ -1825,20 +2232,24 @@ def testBadMultiPoints(self):
}
}
]
- }""")
+ }"""
+ )
features = [f for f in vl.getFeatures()]
self.assertEqual(len(features), 3)
- self.assertEqual([f.geometry().asWkt() for f in features],
- ['MultiPoint ((-70 66))', '', 'MultiPoint ((-68 70),(-22 21))'])
+ self.assertEqual(
+ [f.geometry().asWkt() for f in features],
+ ["MultiPoint ((-70 66))", "", "MultiPoint ((-68 70),(-22 21))"],
+ )
def testDomain(self):
"""
Test fields with a domain are mapped to value map wrapper, for correct value display
"""
- endpoint = self.basetestpath + '/domain_fake_qgis_http_endpoint'
- with open(sanitize(endpoint, '?f=json'), 'wb') as f:
- f.write(b"""
+ endpoint = self.basetestpath + "/domain_fake_qgis_http_endpoint"
+ with open(sanitize(endpoint, "?f=json"), "wb") as f:
+ f.write(
+ b"""
{"currentVersion":10.22,"id":1,"name":"QGIS Test","type":"Feature Layer","description":
"QGIS Provider Test Layer.\n","geometryType":"esriGeometryPoint","copyrightText":"","parentLayer":{"id":0,"name":"QGIS Tests"},"subLayers":[],
"minScale":72225,"maxScale":0,
@@ -1874,10 +2285,14 @@ def testDomain(self):
"relationships":[],"canModifyLayer":false,"canScaleSymbols":false,"hasLabels":false,
"capabilities":"Map,Query,Data","maxRecordCount":1000,"supportsStatistics":true,
"supportsAdvancedQueries":true,"supportedQueryFormats":"JSON, AMF",
- "ownershipBasedAccessControlForFeatures":{"allowOthersToQuery":true},"useStandardizedQueries":true}""")
-
- with open(sanitize(endpoint, '/query?f=json_where=1=1&returnIdsOnly=true'), 'wb') as f:
- f.write(b"""
+ "ownershipBasedAccessControlForFeatures":{"allowOthersToQuery":true},"useStandardizedQueries":true}"""
+ )
+
+ with open(
+ sanitize(endpoint, "/query?f=json_where=1=1&returnIdsOnly=true"), "wb"
+ ) as f:
+ f.write(
+ b"""
{
"objectIdFieldName": "OBJECTID",
"objectIds": [
@@ -1886,24 +2301,32 @@ def testDomain(self):
3
]
}
- """)
+ """
+ )
# Create test layer
- vl = QgsVectorLayer("url='http://" + endpoint + "' crs='epsg:4326'", 'test', 'arcgisfeatureserver')
+ vl = QgsVectorLayer(
+ "url='http://" + endpoint + "' crs='epsg:4326'",
+ "test",
+ "arcgisfeatureserver",
+ )
self.assertTrue(vl.isValid())
self.assertFalse(vl.fields()[0].editorWidgetSetup().type())
- self.assertEqual(vl.fields()[1].editorWidgetSetup().type(), 'ValueMap')
- self.assertEqual(vl.fields()[1].editorWidgetSetup().config(),
- {'map': [{'Value 1': 1.0}, {'Value 2': 2.0}, {'Value 3': 3.0}]})
+ self.assertEqual(vl.fields()[1].editorWidgetSetup().type(), "ValueMap")
+ self.assertEqual(
+ vl.fields()[1].editorWidgetSetup().config(),
+ {"map": [{"Value 1": 1.0}, {"Value 2": 2.0}, {"Value 3": 3.0}]},
+ )
def testTemporal1(self):
"""
Test timeinfo parsing
"""
- endpoint = self.basetestpath + '/temporal1_fake_qgis_http_endpoint'
- with open(sanitize(endpoint, '?f=json'), 'wb') as f:
- f.write(b"""
+ endpoint = self.basetestpath + "/temporal1_fake_qgis_http_endpoint"
+ with open(sanitize(endpoint, "?f=json"), "wb") as f:
+ f.write(
+ b"""
{"currentVersion":10.22,"id":1,"name":"QGIS Test","type":"Feature Layer","description":
"QGIS Provider Test Layer.\n","geometryType":"esriGeometryPoint","copyrightText":"","parentLayer":{"id":0,"name":"QGIS Tests"},"subLayers":[],
"minScale":72225,"maxScale":0,
@@ -1926,10 +2349,14 @@ def testTemporal1(self):
"relationships":[],"canModifyLayer":false,"canScaleSymbols":false,"hasLabels":false,
"capabilities":"Map,Query,Data","maxRecordCount":1000,"supportsStatistics":true,
"supportsAdvancedQueries":true,"supportedQueryFormats":"JSON, AMF",
- "ownershipBasedAccessControlForFeatures":{"allowOthersToQuery":true},"useStandardizedQueries":true}""")
-
- with open(sanitize(endpoint, '/query?f=json_where=1=1&returnIdsOnly=true'), 'wb') as f:
- f.write(b"""
+ "ownershipBasedAccessControlForFeatures":{"allowOthersToQuery":true},"useStandardizedQueries":true}"""
+ )
+
+ with open(
+ sanitize(endpoint, "/query?f=json_where=1=1&returnIdsOnly=true"), "wb"
+ ) as f:
+ f.write(
+ b"""
{
"objectIdFieldName": "OBJECTID",
"objectIds": [
@@ -1938,26 +2365,45 @@ def testTemporal1(self):
3
]
}
- """)
+ """
+ )
# Create test layer
- vl = QgsVectorLayer("url='http://" + endpoint + "' crs='epsg:4326'", 'test', 'arcgisfeatureserver')
+ vl = QgsVectorLayer(
+ "url='http://" + endpoint + "' crs='epsg:4326'",
+ "test",
+ "arcgisfeatureserver",
+ )
self.assertTrue(vl.isValid())
- self.assertTrue(vl.dataProvider().temporalCapabilities().hasTemporalCapabilities())
- self.assertEqual(vl.dataProvider().temporalCapabilities().startField(), 'date_start')
+ self.assertTrue(
+ vl.dataProvider().temporalCapabilities().hasTemporalCapabilities()
+ )
+ self.assertEqual(
+ vl.dataProvider().temporalCapabilities().startField(), "date_start"
+ )
self.assertFalse(vl.dataProvider().temporalCapabilities().endField())
- self.assertEqual(vl.dataProvider().temporalCapabilities().mode(), QgsVectorDataProviderTemporalCapabilities.TemporalMode.ProviderStoresFeatureDateTimeInstantInField)
- self.assertEqual(vl.dataProvider().temporalCapabilities().availableTemporalRange().begin(), QDateTime(QDate(2006, 3, 10), QTime(14, 13, 20), Qt.TimeSpec.UTC))
- self.assertEqual(vl.dataProvider().temporalCapabilities().availableTemporalRange().end(), QDateTime(QDate(2017, 2, 13), QTime(15, 33, 20), Qt.TimeSpec.UTC))
+ self.assertEqual(
+ vl.dataProvider().temporalCapabilities().mode(),
+ QgsVectorDataProviderTemporalCapabilities.TemporalMode.ProviderStoresFeatureDateTimeInstantInField,
+ )
+ self.assertEqual(
+ vl.dataProvider().temporalCapabilities().availableTemporalRange().begin(),
+ QDateTime(QDate(2006, 3, 10), QTime(14, 13, 20), Qt.TimeSpec.UTC),
+ )
+ self.assertEqual(
+ vl.dataProvider().temporalCapabilities().availableTemporalRange().end(),
+ QDateTime(QDate(2017, 2, 13), QTime(15, 33, 20), Qt.TimeSpec.UTC),
+ )
def testTemporal2(self):
"""
Test timeinfo parsing
"""
- endpoint = self.basetestpath + '/temporal2_fake_qgis_http_endpoint'
- with open(sanitize(endpoint, '?f=json'), 'wb') as f:
- f.write(b"""
+ endpoint = self.basetestpath + "/temporal2_fake_qgis_http_endpoint"
+ with open(sanitize(endpoint, "?f=json"), "wb") as f:
+ f.write(
+ b"""
{"currentVersion":10.22,"id":1,"name":"QGIS Test","type":"Feature Layer","description":
"QGIS Provider Test Layer.\n","geometryType":"esriGeometryPoint","copyrightText":"","parentLayer":{"id":0,"name":"QGIS Tests"},"subLayers":[],
"minScale":72225,"maxScale":0,
@@ -1980,10 +2426,14 @@ def testTemporal2(self):
"relationships":[],"canModifyLayer":false,"canScaleSymbols":false,"hasLabels":false,
"capabilities":"Map,Query,Data","maxRecordCount":1000,"supportsStatistics":true,
"supportsAdvancedQueries":true,"supportedQueryFormats":"JSON, AMF",
- "ownershipBasedAccessControlForFeatures":{"allowOthersToQuery":true},"useStandardizedQueries":true}""")
-
- with open(sanitize(endpoint, '/query?f=json_where=1=1&returnIdsOnly=true'), 'wb') as f:
- f.write(b"""
+ "ownershipBasedAccessControlForFeatures":{"allowOthersToQuery":true},"useStandardizedQueries":true}"""
+ )
+
+ with open(
+ sanitize(endpoint, "/query?f=json_where=1=1&returnIdsOnly=true"), "wb"
+ ) as f:
+ f.write(
+ b"""
{
"objectIdFieldName": "OBJECTID",
"objectIds": [
@@ -1992,26 +2442,47 @@ def testTemporal2(self):
3
]
}
- """)
+ """
+ )
# Create test layer
- vl = QgsVectorLayer("url='http://" + endpoint + "' crs='epsg:4326'", 'test', 'arcgisfeatureserver')
+ vl = QgsVectorLayer(
+ "url='http://" + endpoint + "' crs='epsg:4326'",
+ "test",
+ "arcgisfeatureserver",
+ )
self.assertTrue(vl.isValid())
- self.assertTrue(vl.dataProvider().temporalCapabilities().hasTemporalCapabilities())
- self.assertEqual(vl.dataProvider().temporalCapabilities().startField(), 'date_start')
- self.assertEqual(vl.dataProvider().temporalCapabilities().endField(), 'date_end')
- self.assertEqual(vl.dataProvider().temporalCapabilities().mode(), QgsVectorDataProviderTemporalCapabilities.TemporalMode.ProviderStoresFeatureDateTimeStartAndEndInSeparateFields)
- self.assertEqual(vl.dataProvider().temporalCapabilities().availableTemporalRange().begin(), QDateTime(QDate(2006, 3, 10), QTime(14, 13, 20), Qt.TimeSpec.UTC))
- self.assertEqual(vl.dataProvider().temporalCapabilities().availableTemporalRange().end(), QDateTime(QDate(2017, 2, 13), QTime(15, 33, 20), Qt.TimeSpec.UTC))
+ self.assertTrue(
+ vl.dataProvider().temporalCapabilities().hasTemporalCapabilities()
+ )
+ self.assertEqual(
+ vl.dataProvider().temporalCapabilities().startField(), "date_start"
+ )
+ self.assertEqual(
+ vl.dataProvider().temporalCapabilities().endField(), "date_end"
+ )
+ self.assertEqual(
+ vl.dataProvider().temporalCapabilities().mode(),
+ QgsVectorDataProviderTemporalCapabilities.TemporalMode.ProviderStoresFeatureDateTimeStartAndEndInSeparateFields,
+ )
+ self.assertEqual(
+ vl.dataProvider().temporalCapabilities().availableTemporalRange().begin(),
+ QDateTime(QDate(2006, 3, 10), QTime(14, 13, 20), Qt.TimeSpec.UTC),
+ )
+ self.assertEqual(
+ vl.dataProvider().temporalCapabilities().availableTemporalRange().end(),
+ QDateTime(QDate(2017, 2, 13), QTime(15, 33, 20), Qt.TimeSpec.UTC),
+ )
def testImageServer(self):
"""
Test connecting to a image server endpoints works as a footprint featureserver
"""
- endpoint = self.basetestpath + '/imageserver_fake_qgis_http_endpoint'
- with open(sanitize(endpoint, '?f=json'), 'wb') as f:
- f.write(b"""
+ endpoint = self.basetestpath + "/imageserver_fake_qgis_http_endpoint"
+ with open(sanitize(endpoint, "?f=json"), "wb") as f:
+ f.write(
+ b"""
{
"currentVersion": 10.51,
"serviceDescription": "test",
@@ -2205,10 +2676,14 @@ def testImageServer(self):
"wkid": 102100,
"latestWkid": 3857
}
-}""")
-
- with open(sanitize(endpoint, '/query?f=json_where=1=1&returnIdsOnly=true'), 'wb') as f:
- f.write(b"""
+}"""
+ )
+
+ with open(
+ sanitize(endpoint, "/query?f=json_where=1=1&returnIdsOnly=true"), "wb"
+ ) as f:
+ f.write(
+ b"""
{
"objectIdFieldName": "OBJECTID",
"objectIds": [
@@ -2217,19 +2692,25 @@ def testImageServer(self):
3
]
}
- """)
+ """
+ )
# Create test layer
- vl = QgsVectorLayer("url='http://" + endpoint + "' crs='epsg:4326'", 'test', 'arcgisfeatureserver')
+ vl = QgsVectorLayer(
+ "url='http://" + endpoint + "' crs='epsg:4326'",
+ "test",
+ "arcgisfeatureserver",
+ )
self.assertTrue(vl.isValid())
self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.Polygon)
def testDelete(self):
# delete capability
- endpoint = self.basetestpath + '/delete_test_fake_qgis_http_endpoint'
- with open(sanitize(endpoint, '?f=json'), 'wb') as f:
- f.write(b"""
+ endpoint = self.basetestpath + "/delete_test_fake_qgis_http_endpoint"
+ with open(sanitize(endpoint, "?f=json"), "wb") as f:
+ f.write(
+ b"""
{"currentVersion":10.22,"id":1,"name":"QGIS Test","type":"Feature Layer","description":
"QGIS Provider Test Layer","geometryType":"esriGeometryPoint","copyrightText":"not copyright","parentLayer":{"id":2,"name":"QGIS Tests"},"subLayers":[],
"minScale":72225,"maxScale":0,
@@ -2242,44 +2723,56 @@ def testDelete(self):
"relationships":[],"canModifyLayer":false,"canScaleSymbols":false,"hasLabels":false,
"capabilities":"Map,Query,Data,Delete","maxRecordCount":1000,"supportsStatistics":true,
"supportsAdvancedQueries":true,"supportedQueryFormats":"JSON, AMF",
- "ownershipBasedAccessControlForFeatures":{"allowOthersToQuery":true},"useStandardizedQueries":true}""")
-
- with open(sanitize(endpoint, '/query?f=json_where=1=1&returnIdsOnly=true'), 'wb') as f:
- f.write(b"""
+ "ownershipBasedAccessControlForFeatures":{"allowOthersToQuery":true},"useStandardizedQueries":true}"""
+ )
+
+ with open(
+ sanitize(endpoint, "/query?f=json_where=1=1&returnIdsOnly=true"), "wb"
+ ) as f:
+ f.write(
+ b"""
{
"objectIdFieldName": "OBJECTID",
"objectIds": [
1
]
}
- """)
+ """
+ )
- delete_endpoint = sanitize(endpoint, '/deleteFeatures')
- with open(delete_endpoint, 'wb') as f:
- f.write(b"""{
+ delete_endpoint = sanitize(endpoint, "/deleteFeatures")
+ with open(delete_endpoint, "wb") as f:
+ f.write(
+ b"""{
"deleteResults": [
{
"objectId": 1,
"success": true
}
]
-}""")
+}"""
+ )
- vl = QgsVectorLayer("url='http://" + endpoint + "' crs='epsg:4326'", 'test', 'arcgisfeatureserver')
+ vl = QgsVectorLayer(
+ "url='http://" + endpoint + "' crs='epsg:4326'",
+ "test",
+ "arcgisfeatureserver",
+ )
self.assertTrue(vl.isValid())
res = vl.dataProvider().deleteFeatures([0])
self.assertTrue(res)
with open(delete_endpoint + "_payload") as f:
- res = '\n'.join(f.readlines())
- self.assertEqual(res, 'f=json&objectIds=1')
+ res = "\n".join(f.readlines())
+ self.assertEqual(res, "f=json&objectIds=1")
def testAddSuccess(self):
# add capability
- endpoint = self.basetestpath + '/delete_test_fake_qgis_http_endpoint'
- with open(sanitize(endpoint, '?f=json'), 'wb') as f:
- f.write(b"""
+ endpoint = self.basetestpath + "/delete_test_fake_qgis_http_endpoint"
+ with open(sanitize(endpoint, "?f=json"), "wb") as f:
+ f.write(
+ b"""
{"currentVersion":10.22,"id":1,"name":"QGIS Test","type":"Feature Layer","description":
"QGIS Provider Test Layer","geometryType":"esriGeometryPoint","copyrightText":"not copyright","parentLayer":{"id":2,"name":"QGIS Tests"},"subLayers":[],
"minScale":72225,"maxScale":0,
@@ -2292,30 +2785,41 @@ def testAddSuccess(self):
"relationships":[],"canModifyLayer":false,"canScaleSymbols":false,"hasLabels":false,
"capabilities":"Map,Query,Data,Create","maxRecordCount":1000,"supportsStatistics":true,
"supportsAdvancedQueries":true,"supportedQueryFormats":"JSON, AMF",
- "ownershipBasedAccessControlForFeatures":{"allowOthersToQuery":true},"useStandardizedQueries":true}""")
-
- with open(sanitize(endpoint, '/query?f=json_where=1=1&returnIdsOnly=true'), 'wb') as f:
- f.write(b"""
+ "ownershipBasedAccessControlForFeatures":{"allowOthersToQuery":true},"useStandardizedQueries":true}"""
+ )
+
+ with open(
+ sanitize(endpoint, "/query?f=json_where=1=1&returnIdsOnly=true"), "wb"
+ ) as f:
+ f.write(
+ b"""
{
"objectIdFieldName": "OBJECTID",
"objectIds": [
1
]
}
- """)
+ """
+ )
- add_endpoint = sanitize(endpoint, '/addFeatures')
- with open(add_endpoint, 'wb') as f:
- f.write(b"""{
+ add_endpoint = sanitize(endpoint, "/addFeatures")
+ with open(add_endpoint, "wb") as f:
+ f.write(
+ b"""{
"addResults": [
{
"objectId": 617,
"success": true
}
]
-}""")
+}"""
+ )
- vl = QgsVectorLayer("url='http://" + endpoint + "' crs='epsg:4326'", 'test', 'arcgisfeatureserver')
+ vl = QgsVectorLayer(
+ "url='http://" + endpoint + "' crs='epsg:4326'",
+ "test",
+ "arcgisfeatureserver",
+ )
self.assertTrue(vl.isValid())
f = QgsFeature()
@@ -2325,17 +2829,21 @@ def testAddSuccess(self):
self.assertTrue(res)
with open(add_endpoint + "_payload") as f:
- res = '\n'.join(f.readlines())
- self.assertEqual(res, 'f=json&features=[\n\n {\n\n "attributes": {\n\n "OBJECTID": 11\n\n }\n\n }\n\n]')
+ res = "\n".join(f.readlines())
+ self.assertEqual(
+ res,
+ 'f=json&features=[\n\n {\n\n "attributes": {\n\n "OBJECTID": 11\n\n }\n\n }\n\n]',
+ )
# add empty list, should return true for consistency
self.assertTrue(vl.dataProvider().addFeatures([]))
def testAddFail(self):
# add capability
- endpoint = self.basetestpath + '/delete_test_fake_qgis_http_endpoint'
- with open(sanitize(endpoint, '?f=json'), 'wb') as f:
- f.write(b"""
+ endpoint = self.basetestpath + "/delete_test_fake_qgis_http_endpoint"
+ with open(sanitize(endpoint, "?f=json"), "wb") as f:
+ f.write(
+ b"""
{"currentVersion":10.22,"id":1,"name":"QGIS Test","type":"Feature Layer","description":
"QGIS Provider Test Layer","geometryType":"esriGeometryPoint","copyrightText":"not copyright","parentLayer":{"id":2,"name":"QGIS Tests"},"subLayers":[],
"minScale":72225,"maxScale":0,
@@ -2348,21 +2856,27 @@ def testAddFail(self):
"relationships":[],"canModifyLayer":false,"canScaleSymbols":false,"hasLabels":false,
"capabilities":"Map,Query,Data,Create","maxRecordCount":1000,"supportsStatistics":true,
"supportsAdvancedQueries":true,"supportedQueryFormats":"JSON, AMF",
- "ownershipBasedAccessControlForFeatures":{"allowOthersToQuery":true},"useStandardizedQueries":true}""")
-
- with open(sanitize(endpoint, '/query?f=json_where=1=1&returnIdsOnly=true'), 'wb') as f:
- f.write(b"""
+ "ownershipBasedAccessControlForFeatures":{"allowOthersToQuery":true},"useStandardizedQueries":true}"""
+ )
+
+ with open(
+ sanitize(endpoint, "/query?f=json_where=1=1&returnIdsOnly=true"), "wb"
+ ) as f:
+ f.write(
+ b"""
{
"objectIdFieldName": "OBJECTID",
"objectIds": [
1
]
}
- """)
+ """
+ )
- add_endpoint = sanitize(endpoint, '/addFeatures')
- with open(add_endpoint, 'wb') as f:
- f.write(b"""{
+ add_endpoint = sanitize(endpoint, "/addFeatures")
+ with open(add_endpoint, "wb") as f:
+ f.write(
+ b"""{
"addResults": [
{
"success": false,
@@ -2372,9 +2886,14 @@ def testAddFail(self):
}
}
]
-}""")
+}"""
+ )
- vl = QgsVectorLayer("url='http://" + endpoint + "' crs='epsg:4326'", 'test', 'arcgisfeatureserver')
+ vl = QgsVectorLayer(
+ "url='http://" + endpoint + "' crs='epsg:4326'",
+ "test",
+ "arcgisfeatureserver",
+ )
self.assertTrue(vl.isValid())
f = QgsFeature()
@@ -2382,17 +2901,24 @@ def testAddFail(self):
f.setAttributes([11])
res, f = vl.dataProvider().addFeatures([f])
self.assertFalse(res)
- self.assertEqual(vl.dataProvider().lastError(), 'Error while adding features: Setting of Value for depth failed.')
+ self.assertEqual(
+ vl.dataProvider().lastError(),
+ "Error while adding features: Setting of Value for depth failed.",
+ )
with open(add_endpoint + "_payload") as f:
- res = '\n'.join(f.readlines())
- self.assertEqual(res, 'f=json&features=[\n\n {\n\n "attributes": {\n\n "OBJECTID": 11\n\n }\n\n }\n\n]')
+ res = "\n".join(f.readlines())
+ self.assertEqual(
+ res,
+ 'f=json&features=[\n\n {\n\n "attributes": {\n\n "OBJECTID": 11\n\n }\n\n }\n\n]',
+ )
def testChangeAttributeValuesSuccess(self):
# add capability
- endpoint = self.basetestpath + '/change_attr_test_fake_qgis_http_endpoint'
- with open(sanitize(endpoint, '?f=json'), 'wb') as f:
- f.write(b"""
+ endpoint = self.basetestpath + "/change_attr_test_fake_qgis_http_endpoint"
+ with open(sanitize(endpoint, "?f=json"), "wb") as f:
+ f.write(
+ b"""
{"currentVersion":10.22,"id":1,"name":"QGIS Test","type":"Feature Layer","description":
"QGIS Provider Test Layer","geometryType":"esriGeometryPoint","copyrightText":"not copyright","parentLayer":{"id":2,"name":"QGIS Tests"},"subLayers":[],
"minScale":72225,"maxScale":0,
@@ -2409,22 +2935,32 @@ def testChangeAttributeValuesSuccess(self):
"relationships":[],"canModifyLayer":false,"canScaleSymbols":false,"hasLabels":false,
"capabilities":"Map,Query,Data,Create,Update","maxRecordCount":1000,"supportsStatistics":true,
"supportsAdvancedQueries":true,"supportedQueryFormats":"JSON, AMF",
- "ownershipBasedAccessControlForFeatures":{"allowOthersToQuery":true},"useStandardizedQueries":true}""")
-
- with open(sanitize(endpoint, '/query?f=json_where=1=1&returnIdsOnly=true'), 'wb') as f:
- f.write(b"""
+ "ownershipBasedAccessControlForFeatures":{"allowOthersToQuery":true},"useStandardizedQueries":true}"""
+ )
+
+ with open(
+ sanitize(endpoint, "/query?f=json_where=1=1&returnIdsOnly=true"), "wb"
+ ) as f:
+ f.write(
+ b"""
{
"objectIdFieldName": "OBJECTID",
"objectIds": [
1
]
}
- """)
-
- with open(sanitize(endpoint,
- '/query?f=json&objectIds=1&inSR=4326&outSR=4326&returnGeometry=true&outFields=*&returnM=false&returnZ=false'),
- 'wb') as f:
- f.write(b"""
+ """
+ )
+
+ with open(
+ sanitize(
+ endpoint,
+ "/query?f=json&objectIds=1&inSR=4326&outSR=4326&returnGeometry=true&outFields=*&returnM=false&returnZ=false",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
{
"displayFieldName": "name",
"fieldAliases": {
@@ -2454,34 +2990,45 @@ def testChangeAttributeValuesSuccess(self):
}
}
]
- }""")
+ }"""
+ )
- add_endpoint = sanitize(endpoint, '/updateFeatures')
- with open(add_endpoint, 'wb') as f:
- f.write(b"""{
+ add_endpoint = sanitize(endpoint, "/updateFeatures")
+ with open(add_endpoint, "wb") as f:
+ f.write(
+ b"""{
"addResults": [
{
"objectId": 617,
"success": true
}
]
-}""")
+}"""
+ )
- vl = QgsVectorLayer("url='http://" + endpoint + "' crs='epsg:4326'", 'test', 'arcgisfeatureserver')
+ vl = QgsVectorLayer(
+ "url='http://" + endpoint + "' crs='epsg:4326'",
+ "test",
+ "arcgisfeatureserver",
+ )
self.assertTrue(vl.isValid())
- res = vl.dataProvider().changeAttributeValues({0: {1: 'xxname', 2: 'xxname2'}})
+ res = vl.dataProvider().changeAttributeValues({0: {1: "xxname", 2: "xxname2"}})
self.assertTrue(res)
with open(add_endpoint + "_payload") as f:
- res = '\n'.join(f.readlines())
- self.assertEqual(res, 'f=json&features=[\n\n {\n\n "attributes": {\n\n "OBJECTID": 1,\n\n "name": "xxname",\n\n "name2": "xxname2",\n\n "name3": "name3"\n\n }\n\n }\n\n]')
+ res = "\n".join(f.readlines())
+ self.assertEqual(
+ res,
+ 'f=json&features=[\n\n {\n\n "attributes": {\n\n "OBJECTID": 1,\n\n "name": "xxname",\n\n "name2": "xxname2",\n\n "name3": "name3"\n\n }\n\n }\n\n]',
+ )
def testChangeGeometriesSuccess(self):
# add capability
- endpoint = self.basetestpath + '/change_geom_test_fake_qgis_http_endpoint'
- with open(sanitize(endpoint, '?f=json'), 'wb') as f:
- f.write(b"""
+ endpoint = self.basetestpath + "/change_geom_test_fake_qgis_http_endpoint"
+ with open(sanitize(endpoint, "?f=json"), "wb") as f:
+ f.write(
+ b"""
{"currentVersion":10.22,"id":1,"name":"QGIS Test","type":"Feature Layer","description":
"QGIS Provider Test Layer","geometryType":"esriGeometryPoint","copyrightText":"not copyright","parentLayer":{"id":2,"name":"QGIS Tests"},"subLayers":[],
"minScale":72225,"maxScale":0,
@@ -2498,22 +3045,32 @@ def testChangeGeometriesSuccess(self):
"relationships":[],"canModifyLayer":false,"canScaleSymbols":false,"hasLabels":false,
"capabilities":"Map,Query,Data,Create,Update","maxRecordCount":1000,"supportsStatistics":true,
"supportsAdvancedQueries":true,"supportedQueryFormats":"JSON, AMF",
- "ownershipBasedAccessControlForFeatures":{"allowOthersToQuery":true},"useStandardizedQueries":true}""")
-
- with open(sanitize(endpoint, '/query?f=json_where=1=1&returnIdsOnly=true'), 'wb') as f:
- f.write(b"""
+ "ownershipBasedAccessControlForFeatures":{"allowOthersToQuery":true},"useStandardizedQueries":true}"""
+ )
+
+ with open(
+ sanitize(endpoint, "/query?f=json_where=1=1&returnIdsOnly=true"), "wb"
+ ) as f:
+ f.write(
+ b"""
{
"objectIdFieldName": "OBJECTID",
"objectIds": [
1
]
}
- """)
-
- with open(sanitize(endpoint,
- '/query?f=json&objectIds=1&inSR=4326&outSR=4326&returnGeometry=true&outFields=*&returnM=false&returnZ=false'),
- 'wb') as f:
- f.write(b"""
+ """
+ )
+
+ with open(
+ sanitize(
+ endpoint,
+ "/query?f=json&objectIds=1&inSR=4326&outSR=4326&returnGeometry=true&outFields=*&returnM=false&returnZ=false",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
{
"displayFieldName": "name",
"fieldAliases": {
@@ -2543,34 +3100,47 @@ def testChangeGeometriesSuccess(self):
}
}
]
- }""")
+ }"""
+ )
- add_endpoint = sanitize(endpoint, '/updateFeatures')
- with open(add_endpoint, 'wb') as f:
- f.write(b"""{
+ add_endpoint = sanitize(endpoint, "/updateFeatures")
+ with open(add_endpoint, "wb") as f:
+ f.write(
+ b"""{
"addResults": [
{
"objectId": 617,
"success": true
}
]
-}""")
+}"""
+ )
- vl = QgsVectorLayer("url='http://" + endpoint + "' crs='epsg:4326'", 'test', 'arcgisfeatureserver')
+ vl = QgsVectorLayer(
+ "url='http://" + endpoint + "' crs='epsg:4326'",
+ "test",
+ "arcgisfeatureserver",
+ )
self.assertTrue(vl.isValid())
- res = vl.dataProvider().changeGeometryValues({0: QgsGeometry.fromWkt('Point( 111 222)')})
+ res = vl.dataProvider().changeGeometryValues(
+ {0: QgsGeometry.fromWkt("Point( 111 222)")}
+ )
self.assertTrue(res)
with open(add_endpoint + "_payload") as f:
- res = '\n'.join(f.readlines())
- self.assertEqual(res, 'f=json&features=[\n\n {\n\n "attributes": {\n\n "OBJECTID": 1\n\n },\n\n "geometry": {\n\n "x": 111.0,\n\n "y": 222.0\n\n }\n\n }\n\n]')
+ res = "\n".join(f.readlines())
+ self.assertEqual(
+ res,
+ 'f=json&features=[\n\n {\n\n "attributes": {\n\n "OBJECTID": 1\n\n },\n\n "geometry": {\n\n "x": 111.0,\n\n "y": 222.0\n\n }\n\n }\n\n]',
+ )
def testChangeFeaturesSuccess(self):
# add capability
- endpoint = self.basetestpath + '/change_geom_test_fake_qgis_http_endpoint'
- with open(sanitize(endpoint, '?f=json'), 'wb') as f:
- f.write(b"""
+ endpoint = self.basetestpath + "/change_geom_test_fake_qgis_http_endpoint"
+ with open(sanitize(endpoint, "?f=json"), "wb") as f:
+ f.write(
+ b"""
{"currentVersion":10.22,"id":1,"name":"QGIS Test","type":"Feature Layer","description":
"QGIS Provider Test Layer","geometryType":"esriGeometryPoint","copyrightText":"not copyright","parentLayer":{"id":2,"name":"QGIS Tests"},"subLayers":[],
"minScale":72225,"maxScale":0,
@@ -2587,10 +3157,14 @@ def testChangeFeaturesSuccess(self):
"relationships":[],"canModifyLayer":false,"canScaleSymbols":false,"hasLabels":false,
"capabilities":"Map,Query,Data,Create,Update","maxRecordCount":1000,"supportsStatistics":true,
"supportsAdvancedQueries":true,"supportedQueryFormats":"JSON, AMF",
- "ownershipBasedAccessControlForFeatures":{"allowOthersToQuery":true},"useStandardizedQueries":true}""")
-
- with open(sanitize(endpoint, '/query?f=json_where=1=1&returnIdsOnly=true'), 'wb') as f:
- f.write(b"""
+ "ownershipBasedAccessControlForFeatures":{"allowOthersToQuery":true},"useStandardizedQueries":true}"""
+ )
+
+ with open(
+ sanitize(endpoint, "/query?f=json_where=1=1&returnIdsOnly=true"), "wb"
+ ) as f:
+ f.write(
+ b"""
{
"objectIdFieldName": "OBJECTID",
"objectIds": [
@@ -2598,12 +3172,18 @@ def testChangeFeaturesSuccess(self):
2
]
}
- """)
-
- with open(sanitize(endpoint,
- '/query?f=json&objectIds=1,2&inSR=4326&outSR=4326&returnGeometry=true&outFields=*&returnM=false&returnZ=false'),
- 'wb') as f:
- f.write(b"""
+ """
+ )
+
+ with open(
+ sanitize(
+ endpoint,
+ "/query?f=json&objectIds=1,2&inSR=4326&outSR=4326&returnGeometry=true&outFields=*&returnM=false&returnZ=false",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
{
"displayFieldName": "name",
"fieldAliases": {
@@ -2644,29 +3224,42 @@ def testChangeFeaturesSuccess(self):
}
}
]
- }""")
+ }"""
+ )
- add_endpoint = sanitize(endpoint, '/updateFeatures')
- with open(add_endpoint, 'wb') as f:
- f.write(b"""{
+ add_endpoint = sanitize(endpoint, "/updateFeatures")
+ with open(add_endpoint, "wb") as f:
+ f.write(
+ b"""{
"addResults": [
{
"objectId": 617,
"success": true
}
]
-}""")
+}"""
+ )
- vl = QgsVectorLayer("url='http://" + endpoint + "' crs='epsg:4326'", 'test', 'arcgisfeatureserver')
+ vl = QgsVectorLayer(
+ "url='http://" + endpoint + "' crs='epsg:4326'",
+ "test",
+ "arcgisfeatureserver",
+ )
self.assertTrue(vl.isValid())
- res = vl.dataProvider().changeFeatures({1: {1: 'bname1_x', 3: 'bname3_x'}}, {0: QgsGeometry.fromWkt('Point( 111 222)')})
+ res = vl.dataProvider().changeFeatures(
+ {1: {1: "bname1_x", 3: "bname3_x"}},
+ {0: QgsGeometry.fromWkt("Point( 111 222)")},
+ )
self.assertTrue(res)
with open(add_endpoint + "_payload") as f:
- res = '\n'.join(f.readlines())
- self.assertEqual(res, 'f=json&features=[\n\n {\n\n "attributes": {\n\n "OBJECTID": 1,\n\n "name": "name1",\n\n "name2": "name2",\n\n "name3": "name3"\n\n },\n\n "geometry": {\n\n "x": 111.0,\n\n "y": 222.0\n\n }\n\n },\n\n {\n\n "attributes": {\n\n "OBJECTID": 2,\n\n "name": "bname1_x",\n\n "name2": "bname2",\n\n "name3": "bname3_x"\n\n },\n\n "geometry": {\n\n "x": -11.123,\n\n "y": 18.23\n\n }\n\n }\n\n]')
+ res = "\n".join(f.readlines())
+ self.assertEqual(
+ res,
+ 'f=json&features=[\n\n {\n\n "attributes": {\n\n "OBJECTID": 1,\n\n "name": "name1",\n\n "name2": "name2",\n\n "name3": "name3"\n\n },\n\n "geometry": {\n\n "x": 111.0,\n\n "y": 222.0\n\n }\n\n },\n\n {\n\n "attributes": {\n\n "OBJECTID": 2,\n\n "name": "bname1_x",\n\n "name2": "bname2",\n\n "name3": "bname3_x"\n\n },\n\n "geometry": {\n\n "x": -11.123,\n\n "y": 18.23\n\n }\n\n }\n\n]',
+ )
-if __name__ == '__main__':
+if __name__ == "__main__":
unittest.main()
diff --git a/tests/src/python/test_provider_gdal.py b/tests/src/python/test_provider_gdal.py
index 88c473437aad..40c17ef9f77e 100644
--- a/tests/src/python/test_provider_gdal.py
+++ b/tests/src/python/test_provider_gdal.py
@@ -5,9 +5,10 @@
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
"""
-__author__ = 'Nyall Dawson'
-__date__ = '2018-30-10'
-__copyright__ = 'Copyright 2018, Nyall Dawson'
+
+__author__ = "Nyall Dawson"
+__date__ = "2018-30-10"
+__copyright__ = "Copyright 2018, Nyall Dawson"
import math
import os
@@ -32,7 +33,7 @@
def GDAL_COMPUTE_VERSION(maj, min, rev):
- return ((maj) * 1000000 + (min) * 10000 + (rev) * 100)
+ return (maj) * 1000000 + (min) * 10000 + (rev) * 100
class PyQgsGdalProvider(QgisTestCase):
@@ -46,23 +47,42 @@ def checkBlockContents(self, block, expected):
def testRasterBlock(self):
"""Test raster block with extent"""
- path = os.path.join(unitTestDataPath(), 'landsat_4326.tif')
- raster_layer = QgsRasterLayer(path, 'test')
+ path = os.path.join(unitTestDataPath(), "landsat_4326.tif")
+ raster_layer = QgsRasterLayer(path, "test")
self.assertTrue(raster_layer.isValid())
- extent = QgsRectangle(17.94284482577178252, 30.23021770271909503, 17.94407867909909626, 30.23154272264058307)
+ extent = QgsRectangle(
+ 17.94284482577178252,
+ 30.23021770271909503,
+ 17.94407867909909626,
+ 30.23154272264058307,
+ )
block = raster_layer.dataProvider().block(1, extent, 2, 3)
- self.checkBlockContents(block, [
- 125.0, 125.0,
- 125.0, 125.0,
- 125.0, 124.0,
- ])
+ self.checkBlockContents(
+ block,
+ [
+ 125.0,
+ 125.0,
+ 125.0,
+ 125.0,
+ 125.0,
+ 124.0,
+ ],
+ )
full_content = [
- 125.0, 125.0, 125.0,
- 125.0, 125.0, 125.0,
- 125.0, 124.0, 125.0,
- 126.0, 127.0, 127.0,
+ 125.0,
+ 125.0,
+ 125.0,
+ 125.0,
+ 125.0,
+ 125.0,
+ 125.0,
+ 124.0,
+ 125.0,
+ 126.0,
+ 127.0,
+ 127.0,
]
extent = raster_layer.extent()
@@ -81,130 +101,260 @@ def testRasterBlock(self):
extent.setYMaximum(extent.yMaximum() - row_height * row)
extent.setYMinimum(extent.yMaximum() - row_height)
block = raster_layer.dataProvider().block(1, extent, 3, 1)
- self.checkBlockContents(block, full_content[row * 3:row * 3 + 3])
+ self.checkBlockContents(block, full_content[row * 3 : row * 3 + 3])
def testDecodeEncodeUriGpkg(self):
"""Test decodeUri/encodeUri geopackage support"""
- uri = '/my/raster.gpkg'
- parts = QgsProviderRegistry.instance().decodeUri('gdal', uri)
- self.assertEqual(parts, {'path': '/my/raster.gpkg', 'layerName': None})
- encodedUri = QgsProviderRegistry.instance().encodeUri('gdal', parts)
+ uri = "/my/raster.gpkg"
+ parts = QgsProviderRegistry.instance().decodeUri("gdal", uri)
+ self.assertEqual(parts, {"path": "/my/raster.gpkg", "layerName": None})
+ encodedUri = QgsProviderRegistry.instance().encodeUri("gdal", parts)
self.assertEqual(encodedUri, uri)
- uri = 'GPKG:/my/raster.gpkg'
- parts = QgsProviderRegistry.instance().decodeUri('gdal', uri)
- self.assertEqual(parts, {'path': '/my/raster.gpkg', 'layerName': None})
- encodedUri = QgsProviderRegistry.instance().encodeUri('gdal', parts)
- self.assertEqual(encodedUri, '/my/raster.gpkg')
+ uri = "GPKG:/my/raster.gpkg"
+ parts = QgsProviderRegistry.instance().decodeUri("gdal", uri)
+ self.assertEqual(parts, {"path": "/my/raster.gpkg", "layerName": None})
+ encodedUri = QgsProviderRegistry.instance().encodeUri("gdal", parts)
+ self.assertEqual(encodedUri, "/my/raster.gpkg")
- uri = 'GPKG:/my/raster.gpkg:mylayer'
- parts = QgsProviderRegistry.instance().decodeUri('gdal', uri)
- self.assertEqual(parts, {'path': '/my/raster.gpkg', 'layerName': 'mylayer'})
- encodedUri = QgsProviderRegistry.instance().encodeUri('gdal', parts)
+ uri = "GPKG:/my/raster.gpkg:mylayer"
+ parts = QgsProviderRegistry.instance().decodeUri("gdal", uri)
+ self.assertEqual(parts, {"path": "/my/raster.gpkg", "layerName": "mylayer"})
+ encodedUri = QgsProviderRegistry.instance().encodeUri("gdal", parts)
self.assertEqual(encodedUri, uri)
def testDecodeEncodeUriOptions(self):
"""Test decodeUri/encodeUri options support"""
- uri = '/my/raster.pdf|option:DPI=300|option:GIVEME=TWO'
- parts = QgsProviderRegistry.instance().decodeUri('gdal', uri)
- self.assertEqual(parts, {'path': '/my/raster.pdf', 'layerName': None, 'openOptions': ['DPI=300', 'GIVEME=TWO']})
- encodedUri = QgsProviderRegistry.instance().encodeUri('gdal', parts)
+ uri = "/my/raster.pdf|option:DPI=300|option:GIVEME=TWO"
+ parts = QgsProviderRegistry.instance().decodeUri("gdal", uri)
+ self.assertEqual(
+ parts,
+ {
+ "path": "/my/raster.pdf",
+ "layerName": None,
+ "openOptions": ["DPI=300", "GIVEME=TWO"],
+ },
+ )
+ encodedUri = QgsProviderRegistry.instance().encodeUri("gdal", parts)
self.assertEqual(encodedUri, uri)
def testDecodeEncodeUriCredentialOptions(self):
"""Test decodeUri/encodeUri credential options support"""
- uri = '/my/raster.pdf|option:AN=OPTION|credential:ANOTHER=BBB|credential:SOMEKEY=AAAAA'
- parts = QgsProviderRegistry.instance().decodeUri('gdal', uri)
- self.assertEqual(parts, {
- 'path': '/my/raster.pdf',
- 'layerName': None,
- 'credentialOptions': {
- 'ANOTHER': 'BBB',
- 'SOMEKEY': 'AAAAA'
+ uri = "/my/raster.pdf|option:AN=OPTION|credential:ANOTHER=BBB|credential:SOMEKEY=AAAAA"
+ parts = QgsProviderRegistry.instance().decodeUri("gdal", uri)
+ self.assertEqual(
+ parts,
+ {
+ "path": "/my/raster.pdf",
+ "layerName": None,
+ "credentialOptions": {"ANOTHER": "BBB", "SOMEKEY": "AAAAA"},
+ "openOptions": ["AN=OPTION"],
},
- 'openOptions': ['AN=OPTION']
- })
- encodedUri = QgsProviderRegistry.instance().encodeUri('gdal', parts)
+ )
+ encodedUri = QgsProviderRegistry.instance().encodeUri("gdal", parts)
self.assertEqual(encodedUri, uri)
def testDecodeEncodeUriVsizip(self):
"""Test decodeUri/encodeUri for /vsizip/ prefixed URIs"""
- uri = '/vsizip//my/file.zip/image.tif'
- parts = QgsProviderRegistry.instance().decodeUri('gdal', uri)
- self.assertEqual(parts, {'path': '/my/file.zip', 'layerName': None, 'vsiPrefix': '/vsizip/',
- 'vsiSuffix': '/image.tif'})
- encodedUri = QgsProviderRegistry.instance().encodeUri('gdal', parts)
+ uri = "/vsizip//my/file.zip/image.tif"
+ parts = QgsProviderRegistry.instance().decodeUri("gdal", uri)
+ self.assertEqual(
+ parts,
+ {
+ "path": "/my/file.zip",
+ "layerName": None,
+ "vsiPrefix": "/vsizip/",
+ "vsiSuffix": "/image.tif",
+ },
+ )
+ encodedUri = QgsProviderRegistry.instance().encodeUri("gdal", parts)
self.assertEqual(encodedUri, uri)
def test_provider_sidecar_files_for_uri(self):
"""
Test retrieving sidecar files for uris
"""
- metadata = QgsProviderRegistry.instance().providerMetadata('gdal')
-
- self.assertEqual(metadata.sidecarFilesForUri(''), [])
- self.assertEqual(metadata.sidecarFilesForUri('/home/me/some_file.asc'),
- ['/home/me/some_file.aux.xml', '/home/me/some_file.asc.aux.xml', '/home/me/some_file.vat.dbf',
- '/home/me/some_file.asc.vat.dbf', '/home/me/some_file.ovr', '/home/me/some_file.asc.ovr',
- '/home/me/some_file.wld', '/home/me/some_file.asc.wld'])
- self.assertEqual(metadata.sidecarFilesForUri('/home/me/special.jpg'),
- ['/home/me/special.jpw', '/home/me/special.jgw', '/home/me/special.jpgw',
- '/home/me/special.jpegw', '/home/me/special.aux.xml', '/home/me/special.jpg.aux.xml',
- '/home/me/special.vat.dbf', '/home/me/special.jpg.vat.dbf', '/home/me/special.ovr',
- '/home/me/special.jpg.ovr', '/home/me/special.wld', '/home/me/special.jpg.wld'])
- self.assertEqual(metadata.sidecarFilesForUri('/home/me/special.img'),
- ['/home/me/special.ige', '/home/me/special.aux.xml', '/home/me/special.img.aux.xml',
- '/home/me/special.vat.dbf', '/home/me/special.img.vat.dbf', '/home/me/special.ovr',
- '/home/me/special.img.ovr', '/home/me/special.wld', '/home/me/special.img.wld'])
- self.assertEqual(metadata.sidecarFilesForUri('/home/me/special.sid'),
- ['/home/me/special.j2w', '/home/me/special.aux.xml', '/home/me/special.sid.aux.xml',
- '/home/me/special.vat.dbf', '/home/me/special.sid.vat.dbf', '/home/me/special.ovr',
- '/home/me/special.sid.ovr', '/home/me/special.wld', '/home/me/special.sid.wld'])
- self.assertEqual(metadata.sidecarFilesForUri('/home/me/special.tif'),
- ['/home/me/special.tifw', '/home/me/special.tfw', '/home/me/special.aux.xml',
- '/home/me/special.tif.aux.xml', '/home/me/special.vat.dbf', '/home/me/special.tif.vat.dbf',
- '/home/me/special.ovr', '/home/me/special.tif.ovr', '/home/me/special.wld',
- '/home/me/special.tif.wld'])
- self.assertEqual(metadata.sidecarFilesForUri('/home/me/special.bil'),
- ['/home/me/special.bilw', '/home/me/special.blw', '/home/me/special.aux.xml',
- '/home/me/special.bil.aux.xml', '/home/me/special.vat.dbf', '/home/me/special.bil.vat.dbf',
- '/home/me/special.ovr', '/home/me/special.bil.ovr', '/home/me/special.wld',
- '/home/me/special.bil.wld'])
- self.assertEqual(metadata.sidecarFilesForUri('/home/me/special.raster'),
- ['/home/me/special.rasterw', '/home/me/special.aux.xml', '/home/me/special.raster.aux.xml',
- '/home/me/special.vat.dbf', '/home/me/special.raster.vat.dbf', '/home/me/special.ovr',
- '/home/me/special.raster.ovr', '/home/me/special.wld', '/home/me/special.raster.wld'])
- self.assertEqual(metadata.sidecarFilesForUri('/home/me/special.bt'),
- ['/home/me/special.btw', '/home/me/special.aux.xml', '/home/me/special.bt.aux.xml',
- '/home/me/special.vat.dbf', '/home/me/special.bt.vat.dbf', '/home/me/special.ovr',
- '/home/me/special.bt.ovr', '/home/me/special.wld', '/home/me/special.bt.wld'])
- self.assertEqual(metadata.sidecarFilesForUri('/home/me/special.rst'),
- ['/home/me/special.rdc', '/home/me/special.smp', '/home/me/special.ref',
- '/home/me/special.vct', '/home/me/special.vdc', '/home/me/special.avl',
- '/home/me/special.aux.xml', '/home/me/special.rst.aux.xml', '/home/me/special.vat.dbf',
- '/home/me/special.rst.vat.dbf', '/home/me/special.ovr', '/home/me/special.rst.ovr',
- '/home/me/special.wld', '/home/me/special.rst.wld'])
- self.assertEqual(metadata.sidecarFilesForUri('/home/me/special.sdat'),
- ['/home/me/special.sgrd', '/home/me/special.mgrd', '/home/me/special.prj',
- '/home/me/special.aux.xml', '/home/me/special.sdat.aux.xml', '/home/me/special.vat.dbf',
- '/home/me/special.sdat.vat.dbf', '/home/me/special.ovr', '/home/me/special.sdat.ovr',
- '/home/me/special.wld', '/home/me/special.sdat.wld'])
-
- @unittest.skipIf(int(gdal.VersionInfo('VERSION_NUM')) < GDAL_COMPUTE_VERSION(3, 5, 0), "GDAL 3.5.0 required")
+ metadata = QgsProviderRegistry.instance().providerMetadata("gdal")
+
+ self.assertEqual(metadata.sidecarFilesForUri(""), [])
+ self.assertEqual(
+ metadata.sidecarFilesForUri("/home/me/some_file.asc"),
+ [
+ "/home/me/some_file.aux.xml",
+ "/home/me/some_file.asc.aux.xml",
+ "/home/me/some_file.vat.dbf",
+ "/home/me/some_file.asc.vat.dbf",
+ "/home/me/some_file.ovr",
+ "/home/me/some_file.asc.ovr",
+ "/home/me/some_file.wld",
+ "/home/me/some_file.asc.wld",
+ ],
+ )
+ self.assertEqual(
+ metadata.sidecarFilesForUri("/home/me/special.jpg"),
+ [
+ "/home/me/special.jpw",
+ "/home/me/special.jgw",
+ "/home/me/special.jpgw",
+ "/home/me/special.jpegw",
+ "/home/me/special.aux.xml",
+ "/home/me/special.jpg.aux.xml",
+ "/home/me/special.vat.dbf",
+ "/home/me/special.jpg.vat.dbf",
+ "/home/me/special.ovr",
+ "/home/me/special.jpg.ovr",
+ "/home/me/special.wld",
+ "/home/me/special.jpg.wld",
+ ],
+ )
+ self.assertEqual(
+ metadata.sidecarFilesForUri("/home/me/special.img"),
+ [
+ "/home/me/special.ige",
+ "/home/me/special.aux.xml",
+ "/home/me/special.img.aux.xml",
+ "/home/me/special.vat.dbf",
+ "/home/me/special.img.vat.dbf",
+ "/home/me/special.ovr",
+ "/home/me/special.img.ovr",
+ "/home/me/special.wld",
+ "/home/me/special.img.wld",
+ ],
+ )
+ self.assertEqual(
+ metadata.sidecarFilesForUri("/home/me/special.sid"),
+ [
+ "/home/me/special.j2w",
+ "/home/me/special.aux.xml",
+ "/home/me/special.sid.aux.xml",
+ "/home/me/special.vat.dbf",
+ "/home/me/special.sid.vat.dbf",
+ "/home/me/special.ovr",
+ "/home/me/special.sid.ovr",
+ "/home/me/special.wld",
+ "/home/me/special.sid.wld",
+ ],
+ )
+ self.assertEqual(
+ metadata.sidecarFilesForUri("/home/me/special.tif"),
+ [
+ "/home/me/special.tifw",
+ "/home/me/special.tfw",
+ "/home/me/special.aux.xml",
+ "/home/me/special.tif.aux.xml",
+ "/home/me/special.vat.dbf",
+ "/home/me/special.tif.vat.dbf",
+ "/home/me/special.ovr",
+ "/home/me/special.tif.ovr",
+ "/home/me/special.wld",
+ "/home/me/special.tif.wld",
+ ],
+ )
+ self.assertEqual(
+ metadata.sidecarFilesForUri("/home/me/special.bil"),
+ [
+ "/home/me/special.bilw",
+ "/home/me/special.blw",
+ "/home/me/special.aux.xml",
+ "/home/me/special.bil.aux.xml",
+ "/home/me/special.vat.dbf",
+ "/home/me/special.bil.vat.dbf",
+ "/home/me/special.ovr",
+ "/home/me/special.bil.ovr",
+ "/home/me/special.wld",
+ "/home/me/special.bil.wld",
+ ],
+ )
+ self.assertEqual(
+ metadata.sidecarFilesForUri("/home/me/special.raster"),
+ [
+ "/home/me/special.rasterw",
+ "/home/me/special.aux.xml",
+ "/home/me/special.raster.aux.xml",
+ "/home/me/special.vat.dbf",
+ "/home/me/special.raster.vat.dbf",
+ "/home/me/special.ovr",
+ "/home/me/special.raster.ovr",
+ "/home/me/special.wld",
+ "/home/me/special.raster.wld",
+ ],
+ )
+ self.assertEqual(
+ metadata.sidecarFilesForUri("/home/me/special.bt"),
+ [
+ "/home/me/special.btw",
+ "/home/me/special.aux.xml",
+ "/home/me/special.bt.aux.xml",
+ "/home/me/special.vat.dbf",
+ "/home/me/special.bt.vat.dbf",
+ "/home/me/special.ovr",
+ "/home/me/special.bt.ovr",
+ "/home/me/special.wld",
+ "/home/me/special.bt.wld",
+ ],
+ )
+ self.assertEqual(
+ metadata.sidecarFilesForUri("/home/me/special.rst"),
+ [
+ "/home/me/special.rdc",
+ "/home/me/special.smp",
+ "/home/me/special.ref",
+ "/home/me/special.vct",
+ "/home/me/special.vdc",
+ "/home/me/special.avl",
+ "/home/me/special.aux.xml",
+ "/home/me/special.rst.aux.xml",
+ "/home/me/special.vat.dbf",
+ "/home/me/special.rst.vat.dbf",
+ "/home/me/special.ovr",
+ "/home/me/special.rst.ovr",
+ "/home/me/special.wld",
+ "/home/me/special.rst.wld",
+ ],
+ )
+ self.assertEqual(
+ metadata.sidecarFilesForUri("/home/me/special.sdat"),
+ [
+ "/home/me/special.sgrd",
+ "/home/me/special.mgrd",
+ "/home/me/special.prj",
+ "/home/me/special.aux.xml",
+ "/home/me/special.sdat.aux.xml",
+ "/home/me/special.vat.dbf",
+ "/home/me/special.sdat.vat.dbf",
+ "/home/me/special.ovr",
+ "/home/me/special.sdat.ovr",
+ "/home/me/special.wld",
+ "/home/me/special.sdat.wld",
+ ],
+ )
+
+ @unittest.skipIf(
+ int(gdal.VersionInfo("VERSION_NUM")) < GDAL_COMPUTE_VERSION(3, 5, 0),
+ "GDAL 3.5.0 required",
+ )
def testInt64(self):
"""Test Int64 support"""
tmp_dir = QTemporaryDir()
- tmpfile = os.path.join(tmp_dir.path(), 'testInt64.tif')
- ds = gdal.GetDriverByName('GTiff').Create(tmpfile, 2, 2, 1, gdal.GDT_Int64)
- ds.WriteRaster(0, 0, 2, 2, struct.pack('q' * 4, -1234567890123, 1234567890123, -(1 << 63), (1 << 63) - 1))
+ tmpfile = os.path.join(tmp_dir.path(), "testInt64.tif")
+ ds = gdal.GetDriverByName("GTiff").Create(tmpfile, 2, 2, 1, gdal.GDT_Int64)
+ ds.WriteRaster(
+ 0,
+ 0,
+ 2,
+ 2,
+ struct.pack(
+ "q" * 4, -1234567890123, 1234567890123, -(1 << 63), (1 << 63) - 1
+ ),
+ )
ds = None
- raster_layer = QgsRasterLayer(tmpfile, 'test')
+ raster_layer = QgsRasterLayer(tmpfile, "test")
self.assertTrue(raster_layer.isValid())
self.assertEqual(raster_layer.dataProvider().dataType(1), Qgis.DataType.Float64)
@@ -212,7 +362,10 @@ def testInt64(self):
block = raster_layer.dataProvider().block(1, extent, 2, 2)
full_content = [
- -1234567890123, 1234567890123, float(-(1 << 63)), float((1 << 63) - 1)
+ -1234567890123,
+ 1234567890123,
+ float(-(1 << 63)),
+ float((1 << 63) - 1),
]
self.checkBlockContents(block, full_content)
@@ -230,28 +383,33 @@ def testInt64(self):
pos = QgsPointXY(1, -1)
value_sample = raster_layer.dataProvider().sample(pos, 1)[0]
- self.assertTrue(math.isnan(value_sample)) # (1 << 63) - 1 not exactly representable as double
-
- @unittest.skipIf(int(gdal.VersionInfo('VERSION_NUM')) < GDAL_COMPUTE_VERSION(3, 5, 0), "GDAL 3.5.0 required")
+ self.assertTrue(
+ math.isnan(value_sample)
+ ) # (1 << 63) - 1 not exactly representable as double
+
+ @unittest.skipIf(
+ int(gdal.VersionInfo("VERSION_NUM")) < GDAL_COMPUTE_VERSION(3, 5, 0),
+ "GDAL 3.5.0 required",
+ )
def testUInt64(self):
"""Test Int64 support"""
tmp_dir = QTemporaryDir()
- tmpfile = os.path.join(tmp_dir.path(), 'testUInt64.tif')
- ds = gdal.GetDriverByName('GTiff').Create(tmpfile, 2, 2, 1, gdal.GDT_UInt64)
- ds.WriteRaster(0, 0, 2, 2, struct.pack('Q' * 4, 1, 1234567890123, 0, (1 << 64) - 1))
+ tmpfile = os.path.join(tmp_dir.path(), "testUInt64.tif")
+ ds = gdal.GetDriverByName("GTiff").Create(tmpfile, 2, 2, 1, gdal.GDT_UInt64)
+ ds.WriteRaster(
+ 0, 0, 2, 2, struct.pack("Q" * 4, 1, 1234567890123, 0, (1 << 64) - 1)
+ )
ds = None
- raster_layer = QgsRasterLayer(tmpfile, 'test')
+ raster_layer = QgsRasterLayer(tmpfile, "test")
self.assertTrue(raster_layer.isValid())
self.assertEqual(raster_layer.dataProvider().dataType(1), Qgis.DataType.Float64)
extent = raster_layer.extent()
block = raster_layer.dataProvider().block(1, extent, 2, 2)
- full_content = [
- 1, 1234567890123, 0, float((1 << 64) - 1)
- ]
+ full_content = [1, 1234567890123, 0, float((1 << 64) - 1)]
self.checkBlockContents(block, full_content)
pos = QgsPointXY(0, 0)
@@ -270,37 +428,44 @@ def testUInt64(self):
value_sample = raster_layer.dataProvider().sample(pos, 1)[0]
self.assertTrue(math.isnan(value_sample))
- @unittest.skipIf(int(gdal.VersionInfo('VERSION_NUM')) < GDAL_COMPUTE_VERSION(3, 2, 0) or int(gdal.VersionInfo('VERSION_NUM')) >= GDAL_COMPUTE_VERSION(3, 5, 2), "Test only relevant on GDAL >= 3.2.0 and < 3.5.2")
+ @unittest.skipIf(
+ int(gdal.VersionInfo("VERSION_NUM")) < GDAL_COMPUTE_VERSION(3, 2, 0)
+ or int(gdal.VersionInfo("VERSION_NUM")) >= GDAL_COMPUTE_VERSION(3, 5, 2),
+ "Test only relevant on GDAL >= 3.2.0 and < 3.5.2",
+ )
def testSanitizeVRT(self):
- """Test qgsgdalprovider.cpp sanitizeVRTFile() / workaround for https://github.com/qgis/QGIS/issues/49285 """
+ """Test qgsgdalprovider.cpp sanitizeVRTFile() / workaround for https://github.com/qgis/QGIS/issues/49285"""
tmp_dir = QTemporaryDir()
- tmpfilename = os.path.join(tmp_dir.path(), 'tmp.tif')
- path = os.path.join(unitTestDataPath(), 'landsat_4326.tif')
- tmp_ds = gdal.Translate(tmpfilename, path, options='-outsize 1024 0')
- tmp_ds.BuildOverviews('NEAR', [2])
+ tmpfilename = os.path.join(tmp_dir.path(), "tmp.tif")
+ path = os.path.join(unitTestDataPath(), "landsat_4326.tif")
+ tmp_ds = gdal.Translate(tmpfilename, path, options="-outsize 1024 0")
+ tmp_ds.BuildOverviews("NEAR", [2])
tmp_ds = None
- vrtfilename = os.path.join(tmp_dir.path(), 'out.vrt')
+ vrtfilename = os.path.join(tmp_dir.path(), "out.vrt")
ds = gdal.BuildVRT(vrtfilename, [tmpfilename])
ds = None
- self.assertIn('OverviewList', open(vrtfilename).read())
+ self.assertIn("OverviewList", open(vrtfilename).read())
- raster_layer = QgsRasterLayer(vrtfilename, 'test')
+ raster_layer = QgsRasterLayer(vrtfilename, "test")
del raster_layer
- self.assertNotIn('OverviewList', open(vrtfilename).read())
+ self.assertNotIn("OverviewList", open(vrtfilename).read())
- @unittest.skipIf(int(gdal.VersionInfo('VERSION_NUM')) < GDAL_COMPUTE_VERSION(3, 7, 0), "GDAL 3.7.0 required")
+ @unittest.skipIf(
+ int(gdal.VersionInfo("VERSION_NUM")) < GDAL_COMPUTE_VERSION(3, 7, 0),
+ "GDAL 3.7.0 required",
+ )
def testInt8(self):
"""Test Int8 support"""
tmp_dir = QTemporaryDir()
- tmpfile = os.path.join(tmp_dir.path(), 'testInt8.tif')
- ds = gdal.GetDriverByName('GTiff').Create(tmpfile, 2, 2, 1, gdal.GDT_Int8)
- ds.WriteRaster(0, 0, 2, 2, struct.pack('b' * 4, 1, 127, 0, -128))
+ tmpfile = os.path.join(tmp_dir.path(), "testInt8.tif")
+ ds = gdal.GetDriverByName("GTiff").Create(tmpfile, 2, 2, 1, gdal.GDT_Int8)
+ ds.WriteRaster(0, 0, 2, 2, struct.pack("b" * 4, 1, 127, 0, -128))
ds = None
- raster_layer = QgsRasterLayer(tmpfile, 'test')
+ raster_layer = QgsRasterLayer(tmpfile, "test")
self.assertTrue(raster_layer.isValid())
self.assertEqual(raster_layer.dataProvider().dataType(1), Qgis.DataType.Int8)
@@ -326,41 +491,48 @@ def testInt8(self):
value_sample = raster_layer.dataProvider().sample(pos, 1)[0]
self.assertEqual(value_sample, full_content[3])
- @unittest.skipIf(int(gdal.VersionInfo('VERSION_NUM')) < GDAL_COMPUTE_VERSION(3, 7, 0), "GDAL 3.7.0 required")
+ @unittest.skipIf(
+ int(gdal.VersionInfo("VERSION_NUM")) < GDAL_COMPUTE_VERSION(3, 7, 0),
+ "GDAL 3.7.0 required",
+ )
def testGdbMetadata(self):
"""Test reading GDB layer metadata"""
- path = os.path.join(unitTestDataPath(), 'raster_metadata.gdb')
- rl = QgsRasterLayer(f'OpenFileGDB:{path}:int', 'gdb', 'gdal')
+ path = os.path.join(unitTestDataPath(), "raster_metadata.gdb")
+ rl = QgsRasterLayer(f"OpenFileGDB:{path}:int", "gdb", "gdal")
self.assertTrue(rl.isValid())
- self.assertEqual(rl.metadata().identifier(), 'int')
- self.assertEqual(rl.metadata().title(), 'Raster title')
- self.assertEqual(rl.metadata().type(), 'dataset')
- self.assertEqual(rl.metadata().abstract(), 'My description (abstract)\n\nmy raster summary')
+ self.assertEqual(rl.metadata().identifier(), "int")
+ self.assertEqual(rl.metadata().title(), "Raster title")
+ self.assertEqual(rl.metadata().type(), "dataset")
+ self.assertEqual(
+ rl.metadata().abstract(), "My description (abstract)\n\nmy raster summary"
+ )
def testBandDescription(self):
"""Test band description getter"""
tmp_dir = QTemporaryDir()
- tmpfile = os.path.join(tmp_dir.path(), 'testInt8.tif')
- ds = gdal.GetDriverByName('GTiff').Create(tmpfile, 2, 2, 1, gdal.GDT_Byte)
- ds.WriteRaster(0, 0, 2, 2, struct.pack('b' * 4, 1, 127, 0, -128))
+ tmpfile = os.path.join(tmp_dir.path(), "testInt8.tif")
+ ds = gdal.GetDriverByName("GTiff").Create(tmpfile, 2, 2, 1, gdal.GDT_Byte)
+ ds.WriteRaster(0, 0, 2, 2, struct.pack("b" * 4, 1, 127, 0, -128))
band = ds.GetRasterBand(1)
- band.SetDescription('my description')
+ band.SetDescription("my description")
ds.FlushCache()
ds = None
rl = QgsRasterLayer(tmpfile)
- self.assertEqual(rl.dataProvider().bandDescription(1), 'my description')
+ self.assertEqual(rl.dataProvider().bandDescription(1), "my description")
ds = gdal.OpenEx(tmpfile)
band = ds.GetRasterBand(1)
- band.SetMetadataItem('DESCRIPTION', 'my metadata description')
+ band.SetMetadataItem("DESCRIPTION", "my metadata description")
ds.FlushCache()
ds = None
rl = QgsRasterLayer(tmpfile)
- self.assertEqual(rl.dataProvider().bandDescription(1), 'my metadata description')
+ self.assertEqual(
+ rl.dataProvider().bandDescription(1), "my metadata description"
+ )
def testDisplayBandNameBadLayer(self):
"""Test crash from issue GH #54702"""
@@ -368,10 +540,10 @@ def testDisplayBandNameBadLayer(self):
rl = QgsRasterLayer("https://FAKESERVER/ImageServer/WCSServer", "BadWCS", "wcs")
self.assertFalse(rl.isValid())
# This was triggering a std::bad_alloc exception:
- self.assertEqual(rl.dataProvider().displayBandName(1), 'Band 1')
+ self.assertEqual(rl.dataProvider().displayBandName(1), "Band 1")
# This was triggering another crash:
- self.assertEqual(rl.dataProvider().colorInterpretationName(1), 'Undefined')
+ self.assertEqual(rl.dataProvider().colorInterpretationName(1), "Undefined")
-if __name__ == '__main__':
+if __name__ == "__main__":
unittest.main()
diff --git a/tests/src/python/test_provider_gpx.py b/tests/src/python/test_provider_gpx.py
index cad0a3cbc390..a765627343a2 100644
--- a/tests/src/python/test_provider_gpx.py
+++ b/tests/src/python/test_provider_gpx.py
@@ -5,9 +5,10 @@
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
"""
-__author__ = 'Nyall Dawson'
-__date__ = '2021-07-30'
-__copyright__ = 'Copyright 2021, The QGIS Project'
+
+__author__ = "Nyall Dawson"
+__date__ = "2021-07-30"
+__copyright__ = "Copyright 2021, The QGIS Project"
import os
@@ -36,138 +37,138 @@ class TestPyQgsGpxProvider(QgisTestCase, ProviderTestCase):
@classmethod
def createLayer(cls):
vl = QgsVectorLayer(
- f'{unitTestDataPath()}/gpx_test_suite.gpx?type=waypoint',
- 'test', 'gpx')
- assert (vl.isValid())
+ f"{unitTestDataPath()}/gpx_test_suite.gpx?type=waypoint", "test", "gpx"
+ )
+ assert vl.isValid()
return vl
@classmethod
def setUpClass(cls):
"""Run before all tests"""
- super(TestPyQgsGpxProvider, cls).setUpClass()
+ super().setUpClass()
# Create test layer
cls.vl = cls.createLayer()
- assert (cls.vl.isValid())
+ assert cls.vl.isValid()
cls.source = cls.vl.dataProvider()
@property
def pk_name(self):
"""Return the primary key name, override if different than the default 'pk'"""
- return 'comment'
+ return "comment"
- @unittest.skip('Base provider test is not suitable for GPX provider')
+ @unittest.skip("Base provider test is not suitable for GPX provider")
def testGetFeatures(self):
pass
- @unittest.skip('Base provider test is not suitable for GPX provider')
+ @unittest.skip("Base provider test is not suitable for GPX provider")
def testGetFeaturesDestinationCrs(self):
pass
- @unittest.skip('Base provider test is not suitable for GPX provider')
+ @unittest.skip("Base provider test is not suitable for GPX provider")
def testGetFeaturesCoordinateTransform(self):
pass
- @unittest.skip('Base provider test is not suitable for GPX provider')
+ @unittest.skip("Base provider test is not suitable for GPX provider")
def testGetFeaturesLimit(self):
pass
- @unittest.skip('Base provider test is not suitable for GPX provider')
+ @unittest.skip("Base provider test is not suitable for GPX provider")
def testGetFeaturesSubsetAttributes(self):
pass
- @unittest.skip('Base provider test is not suitable for GPX provider')
+ @unittest.skip("Base provider test is not suitable for GPX provider")
def testGetFeaturesWithGeometry(self):
pass
- @unittest.skip('Base provider test is not suitable for GPX provider')
+ @unittest.skip("Base provider test is not suitable for GPX provider")
def testOrderBy(self):
pass
- @unittest.skip('Base provider test is not suitable for GPX provider')
+ @unittest.skip("Base provider test is not suitable for GPX provider")
def testRectAndFids(self):
pass
- @unittest.skip('Base provider test is not suitable for GPX provider')
+ @unittest.skip("Base provider test is not suitable for GPX provider")
def testCloneLayer(self):
pass
- @unittest.skip('Base provider test is not suitable for GPX provider')
+ @unittest.skip("Base provider test is not suitable for GPX provider")
def testExtent(self):
pass
- @unittest.skip('Base provider test is not suitable for GPX provider')
+ @unittest.skip("Base provider test is not suitable for GPX provider")
def testFeatureCount(self):
pass
- @unittest.skip('Base provider test is not suitable for GPX provider')
+ @unittest.skip("Base provider test is not suitable for GPX provider")
def testGetFeaturesFilterRectTests(self):
pass
- @unittest.skip('Base provider test is not suitable for GPX provider')
+ @unittest.skip("Base provider test is not suitable for GPX provider")
def testGetFeaturesFilterRectTestsNoGeomFlag(self):
pass
- @unittest.skip('Base provider test is not suitable for GPX provider')
+ @unittest.skip("Base provider test is not suitable for GPX provider")
def testGetFeaturesDistanceWithinTests(self):
pass
- @unittest.skip('Base provider test is not suitable for GPX provider')
+ @unittest.skip("Base provider test is not suitable for GPX provider")
def testFields(self):
pass
- @unittest.skip('Base provider test is not suitable for GPX provider')
+ @unittest.skip("Base provider test is not suitable for GPX provider")
def testGeomAndAllAttributes(self):
pass
- @unittest.skip('Base provider test is not suitable for GPX provider')
+ @unittest.skip("Base provider test is not suitable for GPX provider")
def testGetFeaturesFidTests(self):
pass
- @unittest.skip('Base provider test is not suitable for GPX provider')
+ @unittest.skip("Base provider test is not suitable for GPX provider")
def testGetFeaturesFidsTests(self):
pass
- @unittest.skip('Base provider test is not suitable for GPX provider')
+ @unittest.skip("Base provider test is not suitable for GPX provider")
def testGetFeaturesSubsetAttributes2(self):
pass
- @unittest.skip('Base provider test is not suitable for GPX provider')
+ @unittest.skip("Base provider test is not suitable for GPX provider")
def testGetFeaturesUncompiled(self):
pass
- @unittest.skip('Base provider test is not suitable for GPX provider')
+ @unittest.skip("Base provider test is not suitable for GPX provider")
def testMaxValue(self):
pass
- @unittest.skip('Base provider test is not suitable for GPX provider')
+ @unittest.skip("Base provider test is not suitable for GPX provider")
def testMaximumValue(self):
pass
- @unittest.skip('Base provider test is not suitable for GPX provider')
+ @unittest.skip("Base provider test is not suitable for GPX provider")
def testMinValue(self):
pass
- @unittest.skip('Base provider test is not suitable for GPX provider')
+ @unittest.skip("Base provider test is not suitable for GPX provider")
def testMinimumValue(self):
pass
- @unittest.skip('Base provider test is not suitable for GPX provider')
+ @unittest.skip("Base provider test is not suitable for GPX provider")
def testRectAndExpression(self):
pass
- @unittest.skip('Base provider test is not suitable for GPX provider')
+ @unittest.skip("Base provider test is not suitable for GPX provider")
def testStringComparison(self):
pass
- @unittest.skip('Base provider test is not suitable for GPX provider')
+ @unittest.skip("Base provider test is not suitable for GPX provider")
def testUnique(self):
pass
- @unittest.skip('Base provider test is not suitable for GPX provider')
+ @unittest.skip("Base provider test is not suitable for GPX provider")
def testUniqueStringsMatching(self):
pass
- @unittest.skip('Base provider test is not suitable for GPX provider')
+ @unittest.skip("Base provider test is not suitable for GPX provider")
def testUniqueValues(self):
pass
@@ -175,7 +176,7 @@ def test_invalid_source(self):
"""
Test various methods with an invalid source
"""
- vl = QgsVectorLayer('not a gpx?type=waypoint', 'test', 'gpx')
+ vl = QgsVectorLayer("not a gpx?type=waypoint", "test", "gpx")
self.assertFalse(vl.isValid())
self.assertEqual(vl.featureCount(), -1)
self.assertTrue(vl.extent().isNull())
@@ -187,52 +188,83 @@ def test_invalid_source(self):
self.assertFalse(vl.dataProvider().deleteFeatures([1, 2]))
- self.assertFalse(vl.dataProvider().changeAttributeValues({1: {1: 'a'}}))
+ self.assertFalse(vl.dataProvider().changeAttributeValues({1: {1: "a"}}))
source = vl.dataProvider().featureSource()
self.assertFalse(list(source.getFeatures()))
def test_encode_decode_uri(self):
- metadata = QgsProviderRegistry.instance().providerMetadata('gpx')
+ metadata = QgsProviderRegistry.instance().providerMetadata("gpx")
self.assertIsNotNone(metadata)
- self.assertEqual(metadata.encodeUri({}), '')
- self.assertEqual(metadata.decodeUri(''), {})
- self.assertEqual(metadata.encodeUri({'path': '/home/me/test.gpx'}), '/home/me/test.gpx')
- self.assertEqual(metadata.decodeUri('/home/me/test.gpx'), {'path': '/home/me/test.gpx'})
- self.assertEqual(metadata.encodeUri({'path': '/home/me/test.gpx',
- 'layerName': 'waypoints'}), '/home/me/test.gpx?type=waypoints')
- self.assertEqual(metadata.decodeUri('/home/me/test.gpx?type=waypoints'), {'path': '/home/me/test.gpx',
- 'layerName': 'waypoints'})
- self.assertEqual(metadata.encodeUri({'path': '/home/me/test.gpx',
- 'layerName': 'tracks'}), '/home/me/test.gpx?type=tracks')
- self.assertEqual(metadata.decodeUri('/home/me/test.gpx?type=tracks'), {'path': '/home/me/test.gpx',
- 'layerName': 'tracks'})
- self.assertEqual(metadata.encodeUri({'path': '/home/me/test.gpx',
- 'layerName': 'routes'}), '/home/me/test.gpx?type=routes')
- self.assertEqual(metadata.decodeUri('/home/me/test.gpx?type=routes'), {'path': '/home/me/test.gpx',
- 'layerName': 'routes'})
+ self.assertEqual(metadata.encodeUri({}), "")
+ self.assertEqual(metadata.decodeUri(""), {})
+ self.assertEqual(
+ metadata.encodeUri({"path": "/home/me/test.gpx"}), "/home/me/test.gpx"
+ )
+ self.assertEqual(
+ metadata.decodeUri("/home/me/test.gpx"), {"path": "/home/me/test.gpx"}
+ )
+ self.assertEqual(
+ metadata.encodeUri({"path": "/home/me/test.gpx", "layerName": "waypoints"}),
+ "/home/me/test.gpx?type=waypoints",
+ )
+ self.assertEqual(
+ metadata.decodeUri("/home/me/test.gpx?type=waypoints"),
+ {"path": "/home/me/test.gpx", "layerName": "waypoints"},
+ )
+ self.assertEqual(
+ metadata.encodeUri({"path": "/home/me/test.gpx", "layerName": "tracks"}),
+ "/home/me/test.gpx?type=tracks",
+ )
+ self.assertEqual(
+ metadata.decodeUri("/home/me/test.gpx?type=tracks"),
+ {"path": "/home/me/test.gpx", "layerName": "tracks"},
+ )
+ self.assertEqual(
+ metadata.encodeUri({"path": "/home/me/test.gpx", "layerName": "routes"}),
+ "/home/me/test.gpx?type=routes",
+ )
+ self.assertEqual(
+ metadata.decodeUri("/home/me/test.gpx?type=routes"),
+ {"path": "/home/me/test.gpx", "layerName": "routes"},
+ )
def test_absolute_relative_uri(self):
context = QgsReadWriteContext()
- context.setPathResolver(QgsPathResolver(os.path.join(TEST_DATA_DIR, "project.qgs")))
+ context.setPathResolver(
+ QgsPathResolver(os.path.join(TEST_DATA_DIR, "project.qgs"))
+ )
- absolute_uri = os.path.join(TEST_DATA_DIR, 'gpx_test_suite.gpx') + '?type=waypoint'
- relative_uri = './gpx_test_suite.gpx?type=waypoint'
+ absolute_uri = (
+ os.path.join(TEST_DATA_DIR, "gpx_test_suite.gpx") + "?type=waypoint"
+ )
+ relative_uri = "./gpx_test_suite.gpx?type=waypoint"
meta = QgsProviderRegistry.instance().providerMetadata("gpx")
assert meta is not None
- self.assertEqual(meta.absoluteToRelativeUri(absolute_uri, context), relative_uri)
- self.assertEqual(meta.relativeToAbsoluteUri(relative_uri, context), absolute_uri)
+ self.assertEqual(
+ meta.absoluteToRelativeUri(absolute_uri, context), relative_uri
+ )
+ self.assertEqual(
+ meta.relativeToAbsoluteUri(relative_uri, context), absolute_uri
+ )
def test_waypoint_layer(self):
- vl = QgsVectorLayer(f'{unitTestDataPath()}/gpx_test_suite.gpx' + "?type=waypoint", 'test2', 'gpx')
+ vl = QgsVectorLayer(
+ f"{unitTestDataPath()}/gpx_test_suite.gpx" + "?type=waypoint",
+ "test2",
+ "gpx",
+ )
self.assertTrue(vl.isValid())
self.assertEqual(vl.fields().field("time").type(), QVariant.DateTime)
values = [f["time"] for f in vl.getFeatures()]
- self.assertEqual(values[0], QDateTime(QDate(2023, 4, 25), QTime(9, 52, 14, 0), Qt.TimeSpec(1)))
+ self.assertEqual(
+ values[0],
+ QDateTime(QDate(2023, 4, 25), QTime(9, 52, 14, 0), Qt.TimeSpec(1)),
+ )
-if __name__ == '__main__':
+if __name__ == "__main__":
unittest.main()
diff --git a/tests/src/python/test_provider_hana.py b/tests/src/python/test_provider_hana.py
index db77e43b3890..d93d22f12e03 100644
--- a/tests/src/python/test_provider_hana.py
+++ b/tests/src/python/test_provider_hana.py
@@ -11,9 +11,9 @@
"""
-__author__ = 'Maxim Rylov'
-__date__ = '2019-11-21'
-__copyright__ = 'Copyright 2019, The QGIS Project'
+__author__ = "Maxim Rylov"
+__date__ = "2019-11-21"
+__copyright__ = "Copyright 2019, The QGIS Project"
import os
@@ -52,28 +52,35 @@ class TestPyQgsHanaProvider(QgisTestCase, ProviderTestCase):
# HANA connection object
conn = None
# Name of the schema
- schemaName = ''
+ schemaName = ""
@classmethod
def setUpClass(cls):
"""Run before all tests"""
- super(TestPyQgsHanaProvider, cls).setUpClass()
- cls.uri = 'driver=\'/usr/sap/hdbclient/libodbcHDB.so\' host=localhost port=30015 user=SYSTEM ' \
- 'password=mypassword sslEnabled=true sslValidateCertificate=False'
- if 'QGIS_HANA_TEST_DB' in os.environ:
- cls.uri = os.environ['QGIS_HANA_TEST_DB']
+ super().setUpClass()
+ cls.uri = (
+ "driver='/usr/sap/hdbclient/libodbcHDB.so' host=localhost port=30015 user=SYSTEM "
+ "password=mypassword sslEnabled=true sslValidateCertificate=False"
+ )
+ if "QGIS_HANA_TEST_DB" in os.environ:
+ cls.uri = os.environ["QGIS_HANA_TEST_DB"]
cls.conn = QgsHanaProviderUtils.createConnection(cls.uri)
- cls.schemaName = QgsHanaProviderUtils.generateSchemaName(cls.conn, 'qgis_test')
+ cls.schemaName = QgsHanaProviderUtils.generateSchemaName(cls.conn, "qgis_test")
QgsHanaProviderUtils.createAndFillDefaultTables(cls.conn, cls.schemaName)
# Create test layers
cls.vl = QgsHanaProviderUtils.createVectorLayer(
- cls.uri + f' key=\'pk\' srid=4326 type=POINT table="{cls.schemaName}"."some_data" (geom) sql=', 'test')
+ cls.uri
+ + f' key=\'pk\' srid=4326 type=POINT table="{cls.schemaName}"."some_data" (geom) sql=',
+ "test",
+ )
cls.source = cls.vl.dataProvider()
cls.poly_vl = QgsHanaProviderUtils.createVectorLayer(
- cls.uri + f' key=\'pk\' srid=4326 type=POLYGON table="{cls.schemaName}"."some_poly_data" (geom) sql=',
- 'test')
+ cls.uri
+ + f' key=\'pk\' srid=4326 type=POLYGON table="{cls.schemaName}"."some_poly_data" (geom) sql=',
+ "test",
+ )
cls.poly_provider = cls.poly_vl.dataProvider()
@classmethod
@@ -82,111 +89,161 @@ def tearDownClass(cls):
QgsHanaProviderUtils.cleanUp(cls.conn, cls.schemaName)
cls.conn.close()
- super(TestPyQgsHanaProvider, cls).tearDownClass()
+ super().tearDownClass()
def createVectorLayer(self, conn_parameters, layer_name):
- layer = QgsHanaProviderUtils.createVectorLayer(self.uri + ' ' + conn_parameters, layer_name)
+ layer = QgsHanaProviderUtils.createVectorLayer(
+ self.uri + " " + conn_parameters, layer_name
+ )
self.assertTrue(layer.isValid())
return layer
def prepareTestTable(self, table_name, create_sql, insert_sql, insert_args):
- res = QgsHanaProviderUtils.executeSQLFetchOne(self.conn,
- f"SELECT COUNT(*) FROM SYS.TABLES WHERE "
- f"SCHEMA_NAME='{self.schemaName}' AND TABLE_NAME='{table_name}'")
+ res = QgsHanaProviderUtils.executeSQLFetchOne(
+ self.conn,
+ f"SELECT COUNT(*) FROM SYS.TABLES WHERE "
+ f"SCHEMA_NAME='{self.schemaName}' AND TABLE_NAME='{table_name}'",
+ )
if res != 0:
- QgsHanaProviderUtils.executeSQL(self.conn, f'DROP TABLE "{self.schemaName}"."{table_name}" CASCADE')
- QgsHanaProviderUtils.createAndFillTable(self.conn, create_sql, insert_sql, insert_args)
+ QgsHanaProviderUtils.executeSQL(
+ self.conn, f'DROP TABLE "{self.schemaName}"."{table_name}" CASCADE'
+ )
+ QgsHanaProviderUtils.createAndFillTable(
+ self.conn, create_sql, insert_sql, insert_args
+ )
def getSource(self):
# create temporary table for edit tests
- create_sql = f'CREATE TABLE "{self.schemaName}"."edit_data" ( ' \
- '"pk" INTEGER NOT NULL PRIMARY KEY,' \
- '"cnt" INTEGER,' \
- '"name" NVARCHAR(100), ' \
- '"name2" NVARCHAR(100), ' \
- '"num_char" NVARCHAR(100),' \
- '"dt" TIMESTAMP,' \
- '"date" DATE,' \
- '"time" TIME,' \
+ create_sql = (
+ f'CREATE TABLE "{self.schemaName}"."edit_data" ( '
+ '"pk" INTEGER NOT NULL PRIMARY KEY,'
+ '"cnt" INTEGER,'
+ '"name" NVARCHAR(100), '
+ '"name2" NVARCHAR(100), '
+ '"num_char" NVARCHAR(100),'
+ '"dt" TIMESTAMP,'
+ '"date" DATE,'
+ '"time" TIME,'
'"geom" ST_POINT(4326))'
- insert_sql = f'INSERT INTO "{self.schemaName}"."edit_data" ("pk", "cnt", "name", "name2", "num_char", "dt", "date", ' \
+ )
+ insert_sql = (
+ f'INSERT INTO "{self.schemaName}"."edit_data" ("pk", "cnt", "name", "name2", "num_char", "dt", "date", '
'"time", "geom") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ST_GeomFromEWKB(?)) '
+ )
insert_args = [
- [5, -200, None, 'NuLl', '5', '2020-05-04 12:13:14', '2020-05-02', '12:13:01',
- bytes.fromhex('0101000020E61000001D5A643BDFC751C01F85EB51B88E5340')],
- [3, 300, 'Pear', 'PEaR', '3', None, None, None, None],
- [1, 100, 'Orange', 'oranGe', '1', '2020-05-03 12:13:14', '2020-05-03', '12:13:14',
- bytes.fromhex('0101000020E61000006891ED7C3F9551C085EB51B81E955040')],
- [2, 200, 'Apple', 'Apple', '2', '2020-05-04 12:14:14', '2020-05-04', '12:14:14',
- bytes.fromhex('0101000020E6100000CDCCCCCCCC0C51C03333333333B35140')],
- [4, 400, 'Honey', 'Honey', '4', '2021-05-04 13:13:14', '2021-05-04', '13:13:14',
- bytes.fromhex('0101000020E610000014AE47E17A5450C03333333333935340')]]
- self.prepareTestTable('edit_data', create_sql, insert_sql, insert_args)
+ [
+ 5,
+ -200,
+ None,
+ "NuLl",
+ "5",
+ "2020-05-04 12:13:14",
+ "2020-05-02",
+ "12:13:01",
+ bytes.fromhex("0101000020E61000001D5A643BDFC751C01F85EB51B88E5340"),
+ ],
+ [3, 300, "Pear", "PEaR", "3", None, None, None, None],
+ [
+ 1,
+ 100,
+ "Orange",
+ "oranGe",
+ "1",
+ "2020-05-03 12:13:14",
+ "2020-05-03",
+ "12:13:14",
+ bytes.fromhex("0101000020E61000006891ED7C3F9551C085EB51B81E955040"),
+ ],
+ [
+ 2,
+ 200,
+ "Apple",
+ "Apple",
+ "2",
+ "2020-05-04 12:14:14",
+ "2020-05-04",
+ "12:14:14",
+ bytes.fromhex("0101000020E6100000CDCCCCCCCC0C51C03333333333B35140"),
+ ],
+ [
+ 4,
+ 400,
+ "Honey",
+ "Honey",
+ "4",
+ "2021-05-04 13:13:14",
+ "2021-05-04",
+ "13:13:14",
+ bytes.fromhex("0101000020E610000014AE47E17A5450C03333333333935340"),
+ ],
+ ]
+ self.prepareTestTable("edit_data", create_sql, insert_sql, insert_args)
return self.createVectorLayer(
f'key=\'pk\' srid=4326 type=POINT table="{self.schemaName}"."edit_data" (geom) sql=',
- 'test')
+ "test",
+ )
def getEditableLayer(self):
return self.getSource()
def enableCompiler(self):
- QgsSettings().setValue('/qgis/compileExpressions', True)
+ QgsSettings().setValue("/qgis/compileExpressions", True)
return True
def disableCompiler(self):
- QgsSettings().setValue('/qgis/compileExpressions', False)
+ QgsSettings().setValue("/qgis/compileExpressions", False)
def uncompiledFilters(self):
filters = {
- '(name = \'Apple\') is not null',
- 'false and NULL',
- 'true and NULL',
- 'NULL and false',
- 'NULL and true',
- 'NULL and NULL',
- 'false or NULL',
- 'true or NULL',
- 'NULL or false',
- 'NULL or true',
- 'NULL or NULL',
- 'not null',
- '\'x\' || "name" IS NOT NULL',
- '\'x\' || "name" IS NULL',
- 'radians(cnt) < 2',
- 'degrees(pk) <= 200',
- 'log10(pk) < 0.5',
- 'x($geometry) < -70',
- 'y($geometry) > 70',
- 'xmin($geometry) < -70',
- 'ymin($geometry) > 70',
- 'xmax($geometry) < -70',
- 'ymax($geometry) > 70',
- 'disjoint($geometry,geom_from_wkt( \'Polygon ((-72.2 66.1, -65.2 66.1, -65.2 72.0, -72.2 72.0, -72.2 66.1))\'))',
- 'intersects($geometry,geom_from_wkt( \'Polygon ((-72.2 66.1, -65.2 66.1, -65.2 72.0, -72.2 72.0, -72.2 66.1))\'))',
- 'contains(geom_from_wkt( \'Polygon ((-72.2 66.1, -65.2 66.1, -65.2 72.0, -72.2 72.0, -72.2 66.1))\'),$geometry)',
- 'distance($geometry,geom_from_wkt( \'Point (-70 70)\')) > 7',
- 'intersects($geometry,geom_from_gml( \'-72.2,66.1 -65.2,66.1 -65.2,72.0 -72.2,72.0 -72.2,66.1 \'))',
- 'x($geometry) < -70',
- 'y($geometry) > 79',
- 'xmin($geometry) < -70',
- 'ymin($geometry) < 76',
- 'xmax($geometry) > -68',
- 'ymax($geometry) > 80',
- 'area($geometry) > 10',
- 'perimeter($geometry) < 12',
- 'relate($geometry,geom_from_wkt( \'Polygon ((-68.2 82.1, -66.95 82.1, -66.95 79.05, -68.2 79.05, -68.2 82.1))\')) = \'FF2FF1212\'',
- 'relate($geometry,geom_from_wkt( \'Polygon ((-68.2 82.1, -66.95 82.1, -66.95 79.05, -68.2 79.05, -68.2 82.1))\'), \'****F****\')',
- 'crosses($geometry,geom_from_wkt( \'Linestring (-68.2 82.1, -66.95 82.1, -66.95 79.05)\'))',
- 'overlaps($geometry,geom_from_wkt( \'Polygon ((-68.2 82.1, -66.95 82.1, -66.95 79.05, -68.2 79.05, -68.2 82.1))\'))',
- 'within($geometry,geom_from_wkt( \'Polygon ((-75.1 76.1, -75.1 81.6, -68.8 81.6, -68.8 76.1, -75.1 76.1))\'))',
- 'overlaps(translate($geometry,-1,-1),geom_from_wkt( \'Polygon ((-75.1 76.1, -75.1 81.6, -68.8 81.6, -68.8 76.1, -75.1 76.1))\'))',
- 'overlaps(buffer($geometry,1),geom_from_wkt( \'Polygon ((-75.1 76.1, -75.1 81.6, -68.8 81.6, -68.8 76.1, -75.1 76.1))\'))',
- 'intersects(centroid($geometry),geom_from_wkt( \'Polygon ((-74.4 78.2, -74.4 79.1, -66.8 79.1, -66.8 78.2, -74.4 78.2))\'))',
- 'intersects(point_on_surface($geometry),geom_from_wkt( \'Polygon ((-74.4 78.2, -74.4 79.1, -66.8 79.1, -66.8 78.2, -74.4 78.2))\'))',
- '"dt" = to_datetime(\'000www14ww13ww12www4ww5ww2020\',\'zzzwwwsswwmmwwhhwwwdwwMwwyyyy\')',
- '"date" = to_date(\'www4ww5ww2020\',\'wwwdwwMwwyyyy\')',
- '"time" = to_time(\'000www14ww13ww12www\',\'zzzwwwsswwmmwwhhwww\')',
+ "(name = 'Apple') is not null",
+ "false and NULL",
+ "true and NULL",
+ "NULL and false",
+ "NULL and true",
+ "NULL and NULL",
+ "false or NULL",
+ "true or NULL",
+ "NULL or false",
+ "NULL or true",
+ "NULL or NULL",
+ "not null",
+ "'x' || \"name\" IS NOT NULL",
+ "'x' || \"name\" IS NULL",
+ "radians(cnt) < 2",
+ "degrees(pk) <= 200",
+ "log10(pk) < 0.5",
+ "x($geometry) < -70",
+ "y($geometry) > 70",
+ "xmin($geometry) < -70",
+ "ymin($geometry) > 70",
+ "xmax($geometry) < -70",
+ "ymax($geometry) > 70",
+ "disjoint($geometry,geom_from_wkt( 'Polygon ((-72.2 66.1, -65.2 66.1, -65.2 72.0, -72.2 72.0, -72.2 66.1))'))",
+ "intersects($geometry,geom_from_wkt( 'Polygon ((-72.2 66.1, -65.2 66.1, -65.2 72.0, -72.2 72.0, -72.2 66.1))'))",
+ "contains(geom_from_wkt( 'Polygon ((-72.2 66.1, -65.2 66.1, -65.2 72.0, -72.2 72.0, -72.2 66.1))'),$geometry)",
+ "distance($geometry,geom_from_wkt( 'Point (-70 70)')) > 7",
+ "intersects($geometry,geom_from_gml( '-72.2,66.1 -65.2,66.1 -65.2,72.0 -72.2,72.0 -72.2,66.1 '))",
+ "x($geometry) < -70",
+ "y($geometry) > 79",
+ "xmin($geometry) < -70",
+ "ymin($geometry) < 76",
+ "xmax($geometry) > -68",
+ "ymax($geometry) > 80",
+ "area($geometry) > 10",
+ "perimeter($geometry) < 12",
+ "relate($geometry,geom_from_wkt( 'Polygon ((-68.2 82.1, -66.95 82.1, -66.95 79.05, -68.2 79.05, -68.2 82.1))')) = 'FF2FF1212'",
+ "relate($geometry,geom_from_wkt( 'Polygon ((-68.2 82.1, -66.95 82.1, -66.95 79.05, -68.2 79.05, -68.2 82.1))'), '****F****')",
+ "crosses($geometry,geom_from_wkt( 'Linestring (-68.2 82.1, -66.95 82.1, -66.95 79.05)'))",
+ "overlaps($geometry,geom_from_wkt( 'Polygon ((-68.2 82.1, -66.95 82.1, -66.95 79.05, -68.2 79.05, -68.2 82.1))'))",
+ "within($geometry,geom_from_wkt( 'Polygon ((-75.1 76.1, -75.1 81.6, -68.8 81.6, -68.8 76.1, -75.1 76.1))'))",
+ "overlaps(translate($geometry,-1,-1),geom_from_wkt( 'Polygon ((-75.1 76.1, -75.1 81.6, -68.8 81.6, -68.8 76.1, -75.1 76.1))'))",
+ "overlaps(buffer($geometry,1),geom_from_wkt( 'Polygon ((-75.1 76.1, -75.1 81.6, -68.8 81.6, -68.8 76.1, -75.1 76.1))'))",
+ "intersects(centroid($geometry),geom_from_wkt( 'Polygon ((-74.4 78.2, -74.4 79.1, -66.8 79.1, -66.8 78.2, -74.4 78.2))'))",
+ "intersects(point_on_surface($geometry),geom_from_wkt( 'Polygon ((-74.4 78.2, -74.4 79.1, -66.8 79.1, -66.8 78.2, -74.4 78.2))'))",
+ "\"dt\" = to_datetime('000www14ww13ww12www4ww5ww2020','zzzwwwsswwmmwwhhwwwdwwMwwyyyy')",
+ "\"date\" = to_date('www4ww5ww2020','wwwdwwMwwyyyy')",
+ "\"time\" = to_time('000www14ww13ww12www','zzzwwwsswwmmwwhhwww')",
}
return filters
@@ -197,76 +254,115 @@ def partiallyCompiledFilters(self):
def testMetadata(self):
metadata = self.vl.metadata()
self.assertEqual(metadata.crs(), QgsCoordinateReferenceSystem.fromEpsgId(4326))
- self.assertEqual(metadata.type(), 'dataset')
- self.assertEqual(metadata.abstract(), 'QGIS Test Table')
+ self.assertEqual(metadata.type(), "dataset")
+ self.assertEqual(metadata.abstract(), "QGIS Test Table")
def testDefaultValue(self):
- self.source.setProviderProperty(QgsDataProvider.ProviderProperty.EvaluateDefaultValues, True)
+ self.source.setProviderProperty(
+ QgsDataProvider.ProviderProperty.EvaluateDefaultValues, True
+ )
self.assertEqual(self.source.defaultValue(0), NULL)
self.assertEqual(self.source.defaultValue(1), NULL)
- self.assertEqual(self.source.defaultValue(2), 'qgis')
- self.assertEqual(self.source.defaultValue(3), 'qgis')
+ self.assertEqual(self.source.defaultValue(2), "qgis")
+ self.assertEqual(self.source.defaultValue(3), "qgis")
self.assertEqual(self.source.defaultValue(4), NULL)
- self.source.setProviderProperty(QgsDataProvider.ProviderProperty.EvaluateDefaultValues, False)
+ self.source.setProviderProperty(
+ QgsDataProvider.ProviderProperty.EvaluateDefaultValues, False
+ )
def testCompositeUniqueConstraints(self):
- create_sql = f'CREATE TABLE "{self.schemaName}"."unique_composite_constraints" ( ' \
- '"ID" INTEGER PRIMARY KEY,' \
- '"VAL1" INTEGER,' \
- '"VAL2" INTEGER,' \
- '"VAL3" INTEGER,' \
- 'UNIQUE (VAL1, VAL2))'
+ create_sql = (
+ f'CREATE TABLE "{self.schemaName}"."unique_composite_constraints" ( '
+ '"ID" INTEGER PRIMARY KEY,'
+ '"VAL1" INTEGER,'
+ '"VAL2" INTEGER,'
+ '"VAL3" INTEGER,'
+ "UNIQUE (VAL1, VAL2))"
+ )
QgsHanaProviderUtils.executeSQL(self.conn, create_sql)
- vl = self.createVectorLayer(f'table="{self.schemaName}"."unique_composite_constraints" sql=',
- 'testcompositeuniqueconstraints')
+ vl = self.createVectorLayer(
+ f'table="{self.schemaName}"."unique_composite_constraints" sql=',
+ "testcompositeuniqueconstraints",
+ )
fields = vl.dataProvider().fields()
- id_field_idx = fields.indexFromName('ID')
- val1_field_idx = vl.fields().indexFromName('VAL1')
- val2_field_idx = vl.fields().indexFromName('VAL2')
- val3_field_idx = vl.fields().indexFromName('VAL3')
+ id_field_idx = fields.indexFromName("ID")
+ val1_field_idx = vl.fields().indexFromName("VAL1")
+ val2_field_idx = vl.fields().indexFromName("VAL2")
+ val3_field_idx = vl.fields().indexFromName("VAL3")
self.assertGreaterEqual(id_field_idx, 0)
self.assertGreaterEqual(val1_field_idx, 0)
self.assertGreaterEqual(val2_field_idx, 0)
self.assertGreaterEqual(val3_field_idx, 0)
- self.assertTrue(bool(vl.fieldConstraints(id_field_idx) & QgsFieldConstraints.Constraint.ConstraintUnique))
- self.assertFalse(bool(vl.fieldConstraints(val1_field_idx) & QgsFieldConstraints.Constraint.ConstraintUnique))
- self.assertFalse(bool(vl.fieldConstraints(val2_field_idx) & QgsFieldConstraints.Constraint.ConstraintUnique))
- self.assertFalse(bool(vl.fieldConstraints(val3_field_idx) & QgsFieldConstraints.Constraint.ConstraintUnique))
+ self.assertTrue(
+ bool(
+ vl.fieldConstraints(id_field_idx)
+ & QgsFieldConstraints.Constraint.ConstraintUnique
+ )
+ )
+ self.assertFalse(
+ bool(
+ vl.fieldConstraints(val1_field_idx)
+ & QgsFieldConstraints.Constraint.ConstraintUnique
+ )
+ )
+ self.assertFalse(
+ bool(
+ vl.fieldConstraints(val2_field_idx)
+ & QgsFieldConstraints.Constraint.ConstraintUnique
+ )
+ )
+ self.assertFalse(
+ bool(
+ vl.fieldConstraints(val3_field_idx)
+ & QgsFieldConstraints.Constraint.ConstraintUnique
+ )
+ )
def testQueryLayers(self):
- def test_query(query, key, geometry, attribute_names, wkb_type=QgsWkbTypes.Type.NoGeometry):
+ def test_query(
+ query, key, geometry, attribute_names, wkb_type=QgsWkbTypes.Type.NoGeometry
+ ):
uri = QgsDataSourceUri()
uri.setSchema(self.schemaName)
uri.setTable(query)
uri.setKeyColumn(key)
uri.setGeometryColumn(geometry)
- vl = self.createVectorLayer(uri.uri(False), 'testquery')
-
- for capability in [QgsVectorDataProvider.Capability.SelectAtId,
- QgsVectorDataProvider.Capability.TransactionSupport,
- QgsVectorDataProvider.Capability.CircularGeometries,
- QgsVectorDataProvider.Capability.ReadLayerMetadata]:
+ vl = self.createVectorLayer(uri.uri(False), "testquery")
+
+ for capability in [
+ QgsVectorDataProvider.Capability.SelectAtId,
+ QgsVectorDataProvider.Capability.TransactionSupport,
+ QgsVectorDataProvider.Capability.CircularGeometries,
+ QgsVectorDataProvider.Capability.ReadLayerMetadata,
+ ]:
self.assertTrue(vl.dataProvider().capabilities() & capability)
- for capability in [QgsVectorDataProvider.Capability.AddAttributes,
- QgsVectorDataProvider.Capability.ChangeAttributeValues,
- QgsVectorDataProvider.Capability.DeleteAttributes,
- QgsVectorDataProvider.Capability.RenameAttributes,
- QgsVectorDataProvider.Capability.AddFeatures,
- QgsVectorDataProvider.Capability.ChangeFeatures,
- QgsVectorDataProvider.Capability.DeleteFeatures,
- QgsVectorDataProvider.Capability.ChangeGeometries,
- QgsVectorDataProvider.Capability.FastTruncate]:
+ for capability in [
+ QgsVectorDataProvider.Capability.AddAttributes,
+ QgsVectorDataProvider.Capability.ChangeAttributeValues,
+ QgsVectorDataProvider.Capability.DeleteAttributes,
+ QgsVectorDataProvider.Capability.RenameAttributes,
+ QgsVectorDataProvider.Capability.AddFeatures,
+ QgsVectorDataProvider.Capability.ChangeFeatures,
+ QgsVectorDataProvider.Capability.DeleteFeatures,
+ QgsVectorDataProvider.Capability.ChangeGeometries,
+ QgsVectorDataProvider.Capability.FastTruncate,
+ ]:
self.assertFalse(vl.dataProvider().capabilities() & capability)
fields = vl.dataProvider().fields()
self.assertCountEqual(attribute_names, fields.names())
for field_idx in vl.primaryKeyAttributes():
self.assertIn(fields[field_idx].name(), key.split(","))
- self.assertEqual(len(vl.primaryKeyAttributes()) == 1,
- bool(vl.fieldConstraints(field_idx) & QgsFieldConstraints.Constraint.ConstraintUnique))
+ self.assertEqual(
+ len(vl.primaryKeyAttributes()) == 1,
+ bool(
+ vl.fieldConstraints(field_idx)
+ & QgsFieldConstraints.Constraint.ConstraintUnique
+ ),
+ )
if fields.count() > 0:
if vl.featureCount() == 0:
self.assertEqual(NULL, vl.maximumValue(0))
@@ -278,225 +374,326 @@ def test_query(query, key, geometry, attribute_names, wkb_type=QgsWkbTypes.Type.
self.assertFalse(vl.addFeatures([QgsFeature()]))
self.assertFalse(vl.deleteFeatures([0]))
self.assertEqual(wkb_type, vl.wkbType())
- self.assertEqual(wkb_type == QgsWkbTypes.Type.NoGeometry or wkb_type == QgsWkbTypes.Type.Unknown,
- vl.extent().isNull())
-
- test_query('(SELECT * FROM DUMMY)', None, None, ['DUMMY'], QgsWkbTypes.Type.NoGeometry)
- test_query('(SELECT CAST(NULL AS INT) ID1, CAST(NULL AS INT) ID2, CAST(NULL AS ST_GEOMETRY) SHAPE FROM DUMMY)',
- 'ID1,ID2', None, ['ID1', 'ID2', 'SHAPE'], QgsWkbTypes.Type.NoGeometry)
- test_query('(SELECT CAST(1 AS INT) ID1, CAST(NULL AS BIGINT) ID2 FROM DUMMY)',
- 'ID1', None, ['ID1', 'ID2'], QgsWkbTypes.Type.NoGeometry)
- test_query('(SELECT CAST(NULL AS INT) ID1, CAST(NULL AS INT) ID2, CAST(NULL AS ST_GEOMETRY) SHAPE FROM DUMMY)',
- None, 'SHAPE', ['ID1', 'ID2'], QgsWkbTypes.Type.Unknown)
- test_query('(SELECT CAST(NULL AS INT) ID1, CAST(NULL AS BIGINT) ID2, CAST(NULL AS ST_GEOMETRY) SHAPE FROM '
- 'DUMMY)', 'ID2', 'SHAPE', ['ID1', 'ID2'], QgsWkbTypes.Type.Unknown)
- test_query('(SELECT CAST(NULL AS INT) ID1, CAST(NULL AS ST_GEOMETRY) SHAPE1, CAST(NULL AS ST_GEOMETRY) SHAPE2 '
- 'FROM DUMMY)', 'ID1', 'SHAPE1', ['ID1', 'SHAPE2'], QgsWkbTypes.Type.Unknown)
- test_query(f'(SELECT "pk" AS "key", "cnt", "geom" AS "g" FROM "{self.schemaName}"."some_data")',
- 'key', 'g', ['key', 'cnt'], QgsWkbTypes.Type.Point)
+ self.assertEqual(
+ wkb_type == QgsWkbTypes.Type.NoGeometry
+ or wkb_type == QgsWkbTypes.Type.Unknown,
+ vl.extent().isNull(),
+ )
+
+ test_query(
+ "(SELECT * FROM DUMMY)", None, None, ["DUMMY"], QgsWkbTypes.Type.NoGeometry
+ )
+ test_query(
+ "(SELECT CAST(NULL AS INT) ID1, CAST(NULL AS INT) ID2, CAST(NULL AS ST_GEOMETRY) SHAPE FROM DUMMY)",
+ "ID1,ID2",
+ None,
+ ["ID1", "ID2", "SHAPE"],
+ QgsWkbTypes.Type.NoGeometry,
+ )
+ test_query(
+ "(SELECT CAST(1 AS INT) ID1, CAST(NULL AS BIGINT) ID2 FROM DUMMY)",
+ "ID1",
+ None,
+ ["ID1", "ID2"],
+ QgsWkbTypes.Type.NoGeometry,
+ )
+ test_query(
+ "(SELECT CAST(NULL AS INT) ID1, CAST(NULL AS INT) ID2, CAST(NULL AS ST_GEOMETRY) SHAPE FROM DUMMY)",
+ None,
+ "SHAPE",
+ ["ID1", "ID2"],
+ QgsWkbTypes.Type.Unknown,
+ )
+ test_query(
+ "(SELECT CAST(NULL AS INT) ID1, CAST(NULL AS BIGINT) ID2, CAST(NULL AS ST_GEOMETRY) SHAPE FROM "
+ "DUMMY)",
+ "ID2",
+ "SHAPE",
+ ["ID1", "ID2"],
+ QgsWkbTypes.Type.Unknown,
+ )
+ test_query(
+ "(SELECT CAST(NULL AS INT) ID1, CAST(NULL AS ST_GEOMETRY) SHAPE1, CAST(NULL AS ST_GEOMETRY) SHAPE2 "
+ "FROM DUMMY)",
+ "ID1",
+ "SHAPE1",
+ ["ID1", "SHAPE2"],
+ QgsWkbTypes.Type.Unknown,
+ )
+ test_query(
+ f'(SELECT "pk" AS "key", "cnt", "geom" AS "g" FROM "{self.schemaName}"."some_data")',
+ "key",
+ "g",
+ ["key", "cnt"],
+ QgsWkbTypes.Type.Point,
+ )
def testBooleanType(self):
- create_sql = f'CREATE TABLE "{self.schemaName}"."boolean_type" ( ' \
- '"id" INTEGER NOT NULL PRIMARY KEY,' \
+ create_sql = (
+ f'CREATE TABLE "{self.schemaName}"."boolean_type" ( '
+ '"id" INTEGER NOT NULL PRIMARY KEY,'
'"fld1" BOOLEAN)'
+ )
insert_sql = f'INSERT INTO "{self.schemaName}"."boolean_type" ("id", "fld1") VALUES (?, ?)'
- insert_args = [[1, 'TRUE'], [2, 'FALSE'], [3, None]]
- self.prepareTestTable('boolean_type', create_sql, insert_sql, insert_args)
+ insert_args = [[1, "TRUE"], [2, "FALSE"], [3, None]]
+ self.prepareTestTable("boolean_type", create_sql, insert_sql, insert_args)
- vl = self.createVectorLayer(f'table="{self.schemaName}"."boolean_type" sql=', 'testbool')
+ vl = self.createVectorLayer(
+ f'table="{self.schemaName}"."boolean_type" sql=', "testbool"
+ )
fields = vl.dataProvider().fields()
- self.assertEqual(fields.at(fields.indexFromName('fld1')).type(), QVariant.Bool)
+ self.assertEqual(fields.at(fields.indexFromName("fld1")).type(), QVariant.Bool)
- values = {feat['id']: feat['fld1'] for feat in vl.getFeatures()}
+ values = {feat["id"]: feat["fld1"] for feat in vl.getFeatures()}
expected = {1: True, 2: False, 3: NULL}
self.assertEqual(values, expected)
def testDecimalAndFloatTypes(self):
- create_sql = f'CREATE TABLE "{self.schemaName}"."decimal_and_float_type" ( ' \
- '"id" INTEGER NOT NULL PRIMARY KEY,' \
- '"decimal_field" DECIMAL(15,4),' \
+ create_sql = (
+ f'CREATE TABLE "{self.schemaName}"."decimal_and_float_type" ( '
+ '"id" INTEGER NOT NULL PRIMARY KEY,'
+ '"decimal_field" DECIMAL(15,4),'
'"float_field" FLOAT(12))'
- insert_sql = f'INSERT INTO "{self.schemaName}"."decimal_and_float_type" ("id", "decimal_field", ' \
+ )
+ insert_sql = (
+ f'INSERT INTO "{self.schemaName}"."decimal_and_float_type" ("id", "decimal_field", '
f'"float_field") VALUES (?, ?, ?) '
+ )
insert_args = [[1, 1.1234, 1.76543]]
- self.prepareTestTable('decimal_and_float_type', create_sql, insert_sql, insert_args)
+ self.prepareTestTable(
+ "decimal_and_float_type", create_sql, insert_sql, insert_args
+ )
- vl = self.createVectorLayer(f'table="{self.schemaName}"."decimal_and_float_type" sql=', 'testdecimalfloat')
+ vl = self.createVectorLayer(
+ f'table="{self.schemaName}"."decimal_and_float_type" sql=',
+ "testdecimalfloat",
+ )
fields = vl.dataProvider().fields()
- decimal_field = fields.at(fields.indexFromName('decimal_field'))
+ decimal_field = fields.at(fields.indexFromName("decimal_field"))
self.assertEqual(decimal_field.type(), QVariant.Double)
self.assertEqual(decimal_field.length(), 15)
self.assertEqual(decimal_field.precision(), 4)
- float_field = fields.at(fields.indexFromName('float_field'))
+ float_field = fields.at(fields.indexFromName("float_field"))
self.assertEqual(float_field.type(), QVariant.Double)
self.assertEqual(float_field.length(), 7)
self.assertEqual(float_field.precision(), 0)
feat = next(vl.getFeatures(QgsFeatureRequest()))
- decimal_idx = vl.fields().lookupField('decimal_field')
+ decimal_idx = vl.fields().lookupField("decimal_field")
self.assertIsInstance(feat.attributes()[decimal_idx], float)
self.assertEqual(feat.attributes()[decimal_idx], 1.1234)
- float_idx = vl.fields().lookupField('float_field')
+ float_idx = vl.fields().lookupField("float_field")
self.assertIsInstance(feat.attributes()[float_idx], float)
self.assertAlmostEqual(feat.attributes()[float_idx], 1.76543, 5)
def testDateTimeTypes(self):
- create_sql = f'CREATE TABLE "{self.schemaName}"."date_time_type" ( ' \
- '"id" INTEGER NOT NULL PRIMARY KEY,' \
- '"date_field" DATE,' \
- '"time_field" TIME,' \
+ create_sql = (
+ f'CREATE TABLE "{self.schemaName}"."date_time_type" ( '
+ '"id" INTEGER NOT NULL PRIMARY KEY,'
+ '"date_field" DATE,'
+ '"time_field" TIME,'
'"datetime_field" TIMESTAMP)'
- insert_sql = f'INSERT INTO "{self.schemaName}"."date_time_type" ("id", "date_field", "time_field", "datetime_field") ' \
- 'VALUES (?, ?, ?, ?)'
- insert_args = [[1, '2004-03-04', '13:41:52', '2004-03-04 13:41:52']]
- self.prepareTestTable('date_time_type', create_sql, insert_sql, insert_args)
-
- vl = self.createVectorLayer(f'table="{self.schemaName}"."date_time_type" sql=', 'testdatetimes')
+ )
+ insert_sql = (
+ f'INSERT INTO "{self.schemaName}"."date_time_type" ("id", "date_field", "time_field", "datetime_field") '
+ "VALUES (?, ?, ?, ?)"
+ )
+ insert_args = [[1, "2004-03-04", "13:41:52", "2004-03-04 13:41:52"]]
+ self.prepareTestTable("date_time_type", create_sql, insert_sql, insert_args)
+
+ vl = self.createVectorLayer(
+ f'table="{self.schemaName}"."date_time_type" sql=', "testdatetimes"
+ )
fields = vl.dataProvider().fields()
- self.assertEqual(fields.at(fields.indexFromName('date_field')).type(), QVariant.Date)
- self.assertEqual(fields.at(fields.indexFromName('time_field')).type(), QVariant.Time)
- self.assertEqual(fields.at(fields.indexFromName('datetime_field')).type(), QVariant.DateTime)
+ self.assertEqual(
+ fields.at(fields.indexFromName("date_field")).type(), QVariant.Date
+ )
+ self.assertEqual(
+ fields.at(fields.indexFromName("time_field")).type(), QVariant.Time
+ )
+ self.assertEqual(
+ fields.at(fields.indexFromName("datetime_field")).type(), QVariant.DateTime
+ )
f = next(vl.getFeatures(QgsFeatureRequest()))
- date_idx = vl.fields().lookupField('date_field')
+ date_idx = vl.fields().lookupField("date_field")
self.assertIsInstance(f.attributes()[date_idx], QDate)
self.assertEqual(f.attributes()[date_idx], QDate(2004, 3, 4))
- time_idx = vl.fields().lookupField('time_field')
+ time_idx = vl.fields().lookupField("time_field")
self.assertIsInstance(f.attributes()[time_idx], QTime)
self.assertEqual(f.attributes()[time_idx], QTime(13, 41, 52))
- datetime_idx = vl.fields().lookupField('datetime_field')
+ datetime_idx = vl.fields().lookupField("datetime_field")
self.assertIsInstance(f.attributes()[datetime_idx], QDateTime)
- self.assertEqual(f.attributes()[datetime_idx], QDateTime(QDate(2004, 3, 4), QTime(13, 41, 52)))
+ self.assertEqual(
+ f.attributes()[datetime_idx],
+ QDateTime(QDate(2004, 3, 4), QTime(13, 41, 52)),
+ )
def testBinaryType(self):
- create_sql = f'CREATE TABLE "{self.schemaName}"."binary_type" ( ' \
- '"id" INTEGER NOT NULL PRIMARY KEY,' \
+ create_sql = (
+ f'CREATE TABLE "{self.schemaName}"."binary_type" ( '
+ '"id" INTEGER NOT NULL PRIMARY KEY,'
'"blob" VARBINARY(114))'
+ )
insert_sql = f'INSERT INTO "{self.schemaName}"."binary_type" ("id", "blob") VALUES (?, ?)'
- insert_args = [[1, QByteArray(b'YmludmFsdWU=')], [2, None]]
- self.prepareTestTable('binary_type', create_sql, insert_sql, insert_args)
+ insert_args = [[1, QByteArray(b"YmludmFsdWU=")], [2, None]]
+ self.prepareTestTable("binary_type", create_sql, insert_sql, insert_args)
- vl = self.createVectorLayer(f'table="{self.schemaName}"."binary_type" sql=', 'testbinary')
+ vl = self.createVectorLayer(
+ f'table="{self.schemaName}"."binary_type" sql=', "testbinary"
+ )
fields = vl.dataProvider().fields()
- self.assertEqual(fields.at(fields.indexFromName('blob')).type(), QVariant.ByteArray)
- self.assertEqual(fields.at(fields.indexFromName('blob')).length(), 114)
+ self.assertEqual(
+ fields.at(fields.indexFromName("blob")).type(), QVariant.ByteArray
+ )
+ self.assertEqual(fields.at(fields.indexFromName("blob")).length(), 114)
- values = {feat['id']: feat['blob'] for feat in vl.getFeatures()}
- expected = {1: QByteArray(b'YmludmFsdWU='), 2: QByteArray()}
+ values = {feat["id"]: feat["blob"] for feat in vl.getFeatures()}
+ expected = {1: QByteArray(b"YmludmFsdWU="), 2: QByteArray()}
self.assertEqual(values, expected)
def testBinaryTypeEdit(self):
- create_sql = f'CREATE TABLE "{self.schemaName}"."binary_type_edit" ( ' \
- '"id" INTEGER NOT NULL PRIMARY KEY,' \
+ create_sql = (
+ f'CREATE TABLE "{self.schemaName}"."binary_type_edit" ( '
+ '"id" INTEGER NOT NULL PRIMARY KEY,'
'"blob" VARBINARY(1000))'
+ )
insert_sql = f'INSERT INTO "{self.schemaName}"."binary_type_edit" ("id", "blob") VALUES (?, ?)'
- insert_args = [[1, QByteArray(b'YmJi')]]
- self.prepareTestTable('binary_type_edit', create_sql, insert_sql, insert_args)
-
- vl = self.createVectorLayer(f'key=\'id\' table="{self.schemaName}"."binary_type_edit" sql=', 'testbinaryedit')
- values = {feat['id']: feat['blob'] for feat in vl.getFeatures()}
- expected = {1: QByteArray(b'YmJi')}
+ insert_args = [[1, QByteArray(b"YmJi")]]
+ self.prepareTestTable("binary_type_edit", create_sql, insert_sql, insert_args)
+
+ vl = self.createVectorLayer(
+ f'key=\'id\' table="{self.schemaName}"."binary_type_edit" sql=',
+ "testbinaryedit",
+ )
+ values = {feat["id"]: feat["blob"] for feat in vl.getFeatures()}
+ expected = {1: QByteArray(b"YmJi")}
self.assertEqual(values, expected)
# change attribute value
- self.assertTrue(vl.dataProvider().changeAttributeValues({1: {1: QByteArray(b'bbbvx')}}))
- values = {feat['id']: feat['blob'] for feat in vl.getFeatures()}
- expected = {1: QByteArray(b'bbbvx')}
+ self.assertTrue(
+ vl.dataProvider().changeAttributeValues({1: {1: QByteArray(b"bbbvx")}})
+ )
+ values = {feat["id"]: feat["blob"] for feat in vl.getFeatures()}
+ expected = {1: QByteArray(b"bbbvx")}
self.assertEqual(values, expected)
# add feature
f = QgsFeature()
- f.setAttributes([2, QByteArray(b'cccc')])
+ f.setAttributes([2, QByteArray(b"cccc")])
self.assertTrue(vl.dataProvider().addFeature(f))
- values = {feat['id']: feat['blob'] for feat in vl.getFeatures()}
- expected = {1: QByteArray(b'bbbvx'), 2: QByteArray(b'cccc')}
+ values = {feat["id"]: feat["blob"] for feat in vl.getFeatures()}
+ expected = {1: QByteArray(b"bbbvx"), 2: QByteArray(b"cccc")}
self.assertEqual(values, expected)
# change feature
- self.assertTrue(vl.dataProvider().changeFeatures({2: {1: QByteArray(b'dddd')}}, {}))
- values = {feat['id']: feat['blob'] for feat in vl.getFeatures()}
- expected = {1: QByteArray(b'bbbvx'), 2: QByteArray(b'dddd')}
+ self.assertTrue(
+ vl.dataProvider().changeFeatures({2: {1: QByteArray(b"dddd")}}, {})
+ )
+ values = {feat["id"]: feat["blob"] for feat in vl.getFeatures()}
+ expected = {1: QByteArray(b"bbbvx"), 2: QByteArray(b"dddd")}
self.assertEqual(values, expected)
def testRealVectorType(self):
table_name = "real_vector_type"
- create_sql = f'CREATE TABLE "{self.schemaName}"."{table_name}" ( ' \
- '"id" INTEGER NOT NULL PRIMARY KEY,' \
+ create_sql = (
+ f'CREATE TABLE "{self.schemaName}"."{table_name}" ( '
+ '"id" INTEGER NOT NULL PRIMARY KEY,'
'"emb" REAL_VECTOR(3))'
+ )
insert_sql = f'INSERT INTO "{self.schemaName}"."{table_name}" ("id", "emb") VALUES (?, TO_REAL_VECTOR(?))'
- insert_args = [[1, '[0.1,0.2,0.1]'], [2, None]]
- self.prepareTestTable('real_vector_type', create_sql, insert_sql, insert_args)
+ insert_args = [[1, "[0.1,0.2,0.1]"], [2, None]]
+ self.prepareTestTable("real_vector_type", create_sql, insert_sql, insert_args)
- vl = self.createVectorLayer(f'table="{self.schemaName}"."{table_name}" sql=', 'testrealvector')
+ vl = self.createVectorLayer(
+ f'table="{self.schemaName}"."{table_name}" sql=', "testrealvector"
+ )
fields = vl.dataProvider().fields()
- self.assertEqual(fields.at(fields.indexFromName('emb')).type(), QVariant.String)
- self.assertEqual(fields.at(fields.indexFromName('emb')).length(), 3)
+ self.assertEqual(fields.at(fields.indexFromName("emb")).type(), QVariant.String)
+ self.assertEqual(fields.at(fields.indexFromName("emb")).length(), 3)
- values = {feat['id']: feat['emb'] for feat in vl.getFeatures()}
- expected = {1: '[0.1,0.2,0.1]', 2: NULL}
+ values = {feat["id"]: feat["emb"] for feat in vl.getFeatures()}
+ expected = {1: "[0.1,0.2,0.1]", 2: NULL}
self.assertEqual(values, expected)
def testRealVectorTypeEdit(self):
table_name = "real_vector_type_edit"
- create_sql = f'CREATE TABLE "{self.schemaName}"."{table_name}" ( ' \
- '"id" INTEGER NOT NULL PRIMARY KEY,' \
+ create_sql = (
+ f'CREATE TABLE "{self.schemaName}"."{table_name}" ( '
+ '"id" INTEGER NOT NULL PRIMARY KEY,'
'"emb" REAL_VECTOR)'
+ )
insert_sql = f'INSERT INTO "{self.schemaName}"."{table_name}" ("id", "emb") VALUES (?, TO_REAL_VECTOR(?))'
- insert_args = [[1, '[0.1,0.2,0.3]']]
+ insert_args = [[1, "[0.1,0.2,0.3]"]]
self.prepareTestTable(table_name, create_sql, insert_sql, insert_args)
- vl = self.createVectorLayer(f'key=\'id\' table="{self.schemaName}"."{table_name}" sql=', 'testrealvectoredit')
+ vl = self.createVectorLayer(
+ f'key=\'id\' table="{self.schemaName}"."{table_name}" sql=',
+ "testrealvectoredit",
+ )
def check_values(expected):
- actual = {feat['id']: feat['emb'] for feat in vl.getFeatures()}
+ actual = {feat["id"]: feat["emb"] for feat in vl.getFeatures()}
self.assertEqual(actual, expected)
- check_values({1: '[0.1,0.2,0.3]'})
+ check_values({1: "[0.1,0.2,0.3]"})
# change attribute value
- self.assertTrue(vl.dataProvider().changeAttributeValues({1: {1: '[0.82,0.5,1]'}}))
- check_values({1: '[0.82,0.5,1]'})
+ self.assertTrue(
+ vl.dataProvider().changeAttributeValues({1: {1: "[0.82,0.5,1]"}})
+ )
+ check_values({1: "[0.82,0.5,1]"})
# add feature
f = QgsFeature()
- f.setAttributes([2, '[1,1,1]'])
+ f.setAttributes([2, "[1,1,1]"])
self.assertTrue(vl.dataProvider().addFeature(f))
- check_values({1: '[0.82,0.5,1]', 2: '[1,1,1]'})
+ check_values({1: "[0.82,0.5,1]", 2: "[1,1,1]"})
# change feature
- self.assertTrue(vl.dataProvider().changeFeatures({2: {1: '[2,2,2]'}}, {}))
- check_values({1: '[0.82,0.5,1]', 2: '[2,2,2]'})
+ self.assertTrue(vl.dataProvider().changeFeatures({2: {1: "[2,2,2]"}}, {}))
+ check_values({1: "[0.82,0.5,1]", 2: "[2,2,2]"})
def testGeometryAttributes(self):
- create_sql = f'CREATE TABLE "{self.schemaName}"."geometry_attribute" ( ' \
- 'ID INTEGER NOT NULL PRIMARY KEY,' \
- 'GEOM1 ST_GEOMETRY(4326),' \
- 'GEOM2 ST_GEOMETRY(4326))'
- insert_sql = f'INSERT INTO "{self.schemaName}"."geometry_attribute" (ID, GEOM1, GEOM2) ' \
- f'VALUES (?, ST_GeomFromText(?, 4326), ST_GeomFromText(?, 4326)) '
- insert_args = [[1, 'POINT (1 2)', 'LINESTRING (0 0,1 1)']]
- self.prepareTestTable('geometry_attribute', create_sql, insert_sql, insert_args)
-
- vl = self.createVectorLayer(f'table="{self.schemaName}"."geometry_attribute" (GEOM1) sql=',
- 'testgeometryattribute')
+ create_sql = (
+ f'CREATE TABLE "{self.schemaName}"."geometry_attribute" ( '
+ "ID INTEGER NOT NULL PRIMARY KEY,"
+ "GEOM1 ST_GEOMETRY(4326),"
+ "GEOM2 ST_GEOMETRY(4326))"
+ )
+ insert_sql = (
+ f'INSERT INTO "{self.schemaName}"."geometry_attribute" (ID, GEOM1, GEOM2) '
+ f"VALUES (?, ST_GeomFromText(?, 4326), ST_GeomFromText(?, 4326)) "
+ )
+ insert_args = [[1, "POINT (1 2)", "LINESTRING (0 0,1 1)"]]
+ self.prepareTestTable("geometry_attribute", create_sql, insert_sql, insert_args)
+
+ vl = self.createVectorLayer(
+ f'table="{self.schemaName}"."geometry_attribute" (GEOM1) sql=',
+ "testgeometryattribute",
+ )
fields = vl.dataProvider().fields()
- self.assertEqual(fields.names(), ['ID', 'GEOM2'])
- self.assertEqual(fields.at(fields.indexFromName('ID')).type(), QVariant.Int)
- self.assertEqual(fields.at(fields.indexFromName('GEOM2')).type(), QVariant.String)
- values = {feat['ID']: feat['GEOM2'] for feat in vl.getFeatures()}
- self.assertEqual(values, {1: 'LINESTRING (0 0,1 1)'})
+ self.assertEqual(fields.names(), ["ID", "GEOM2"])
+ self.assertEqual(fields.at(fields.indexFromName("ID")).type(), QVariant.Int)
+ self.assertEqual(
+ fields.at(fields.indexFromName("GEOM2")).type(), QVariant.String
+ )
+ values = {feat["ID"]: feat["GEOM2"] for feat in vl.getFeatures()}
+ self.assertEqual(values, {1: "LINESTRING (0 0,1 1)"})
# change attribute value
- self.assertTrue(vl.dataProvider().changeAttributeValues({1: {1: 'LINESTRING (0 0,2 2)'}}))
- values = {feat['ID']: feat['GEOM2'] for feat in vl.getFeatures()}
- self.assertEqual(values, {1: 'LINESTRING (0 0,2 2)'})
+ self.assertTrue(
+ vl.dataProvider().changeAttributeValues({1: {1: "LINESTRING (0 0,2 2)"}})
+ )
+ values = {feat["ID"]: feat["GEOM2"] for feat in vl.getFeatures()}
+ self.assertEqual(values, {1: "LINESTRING (0 0,2 2)"})
def testCreateLayerViaExport(self):
def runTest(crs, primaryKey, attributeNames, attributeValues):
@@ -505,16 +702,22 @@ def runTest(crs, primaryKey, attributeNames, attributeValues):
layer = QgsVectorLayer(f"Point?crs={crs.authid()}", "new_table", "memory")
pr = layer.dataProvider()
- fields = [QgsField("fldid", QVariant.LongLong),
- QgsField("fldtxt", QVariant.String),
- QgsField("fldint", QVariant.Int)]
+ fields = [
+ QgsField("fldid", QVariant.LongLong),
+ QgsField("fldtxt", QVariant.String),
+ QgsField("fldint", QVariant.Int),
+ ]
if primaryKey == "fldid":
constraints = QgsFieldConstraints()
- constraints.setConstraint(QgsFieldConstraints.Constraint.ConstraintNotNull,
- QgsFieldConstraints.ConstraintOrigin.ConstraintOriginProvider)
- constraints.setConstraint(QgsFieldConstraints.Constraint.ConstraintUnique,
- QgsFieldConstraints.ConstraintOrigin.ConstraintOriginProvider)
+ constraints.setConstraint(
+ QgsFieldConstraints.Constraint.ConstraintNotNull,
+ QgsFieldConstraints.ConstraintOrigin.ConstraintOriginProvider,
+ )
+ constraints.setConstraint(
+ QgsFieldConstraints.Constraint.ConstraintUnique,
+ QgsFieldConstraints.ConstraintOrigin.ConstraintOriginProvider,
+ )
fields[0].setConstraints(constraints)
layer.startEditing()
@@ -536,35 +739,56 @@ def runTest(crs, primaryKey, attributeNames, attributeValues):
pr.addFeatures([f1, f2, f3, f4])
layer.commitChanges()
- QgsHanaProviderUtils.dropTableIfExists(self.conn, self.schemaName, 'import_data')
+ QgsHanaProviderUtils.dropTableIfExists(
+ self.conn, self.schemaName, "import_data"
+ )
params = f' key=\'{primaryKey}\' table="{self.schemaName}"."import_data" (geom) sql='
- error, message = QgsVectorLayerExporter.exportLayer(layer, self.uri + params, 'hana', crs)
+ error, message = QgsVectorLayerExporter.exportLayer(
+ layer, self.uri + params, "hana", crs
+ )
self.assertEqual(error, QgsVectorLayerExporter.ExportError.NoError)
- import_layer = self.createVectorLayer(params, 'testimportedlayer')
+ import_layer = self.createVectorLayer(params, "testimportedlayer")
self.assertEqual(import_layer.wkbType(), QgsWkbTypes.Type.Point)
self.assertEqual([f.name() for f in import_layer.fields()], attributeNames)
features = [f.attributes() for f in import_layer.getFeatures()]
self.assertEqual(features, attributeValues)
geom = [f.geometry().asWkt() for f in import_layer.getFeatures()]
- self.assertEqual(geom, ['Point (1 2)', '', 'Point (3 2)', 'Point (4 3)'])
+ self.assertEqual(geom, ["Point (1 2)", "", "Point (3 2)", "Point (4 3)"])
- QgsHanaProviderUtils.dropTableIfExists(self.conn, self.schemaName, 'import_data')
+ QgsHanaProviderUtils.dropTableIfExists(
+ self.conn, self.schemaName, "import_data"
+ )
def is_crs_installed(srid):
- num_crs = QgsHanaProviderUtils.executeSQLFetchOne(self.conn,
- f'SELECT COUNT(*) FROM SYS.ST_SPATIAL_REFERENCE_SYSTEMS '
- f'WHERE SRS_ID = {srid}')
+ num_crs = QgsHanaProviderUtils.executeSQLFetchOne(
+ self.conn,
+ f"SELECT COUNT(*) FROM SYS.ST_SPATIAL_REFERENCE_SYSTEMS "
+ f"WHERE SRS_ID = {srid}",
+ )
return num_crs == 1
- crs_4326 = QgsCoordinateReferenceSystem('EPSG:4326')
+ crs_4326 = QgsCoordinateReferenceSystem("EPSG:4326")
# primary key already exists in the imported layer
- runTest(crs_4326, 'fldid', ['fldid', 'fldtxt', 'fldint'], [[1, 'test', 11], [2, 'test2', 13],
- [3, 'test2', NULL], [4, NULL, 13]])
+ runTest(
+ crs_4326,
+ "fldid",
+ ["fldid", "fldtxt", "fldint"],
+ [[1, "test", 11], [2, "test2", 13], [3, "test2", NULL], [4, NULL, 13]],
+ )
# primary key doesn't exist in the imported layer
- runTest(crs_4326, 'pk', ['pk', 'fldid', 'fldtxt', 'fldint'], [[1, 1, 'test', 11], [2, 2, 'test2', 13],
- [3, 3, 'test2', NULL], [4, 4, NULL, 13]])
+ runTest(
+ crs_4326,
+ "pk",
+ ["pk", "fldid", "fldtxt", "fldint"],
+ [
+ [1, 1, "test", 11],
+ [2, 2, "test2", 13],
+ [3, 3, "test2", NULL],
+ [4, 4, NULL, 13],
+ ],
+ )
# crs id that do not exist
# unfortunately, we cannot test new units of measure as
# QgsCoordinateReferenceSystem does not allow creating
@@ -574,157 +798,204 @@ def is_crs_installed(srid):
if not is_crs_installed(unknown_srid):
crs = QgsCoordinateReferenceSystem.fromEpsgId(unknown_srid)
- runTest(crs, 'fldid', ['fldid', 'fldtxt', 'fldint'], [[1, 'test', 11], [2, 'test2', 13],
- [3, 'test2', NULL], [4, NULL, 13]])
+ runTest(
+ crs,
+ "fldid",
+ ["fldid", "fldtxt", "fldint"],
+ [[1, "test", 11], [2, "test2", 13], [3, "test2", NULL], [4, NULL, 13]],
+ )
self.assertTrue(is_crs_installed(unknown_srid))
- QgsHanaProviderUtils.executeSQL(self.conn, f'DROP SPATIAL REFERENCE SYSTEM "{crs.description()}"')
+ QgsHanaProviderUtils.executeSQL(
+ self.conn, f'DROP SPATIAL REFERENCE SYSTEM "{crs.description()}"'
+ )
# QgsHanaProviderUtils.executeSQL(self.conn, 'DROP SPATIAL UNIT OF MEASURE degree_qgis')
def testCreateLayerViaExportWithSpecialTypesHandledAsString(self):
- table_name = 'binary_types_as_string'
- create_sql = f'''CREATE COLUMN TABLE "{self.schemaName}"."{table_name}" (
+ table_name = "binary_types_as_string"
+ create_sql = f"""CREATE COLUMN TABLE "{self.schemaName}"."{table_name}" (
"pk" INTEGER NOT NULL PRIMARY KEY,
"vec" REAL_VECTOR(3),
"geom1" ST_GEOMETRY(4326),
- "geom2" ST_GEOMETRY(4326))'''
+ "geom2" ST_GEOMETRY(4326))"""
- insert_sql = f'INSERT INTO "{self.schemaName}"."{table_name}" ("pk", "vec", "geom1", "geom2") ' \
- 'VALUES (?, TO_REAL_VECTOR(?), ST_GeomFromWKT(?, 4326), ST_GeomFromWKT(?, 4326)) '
+ insert_sql = (
+ f'INSERT INTO "{self.schemaName}"."{table_name}" ("pk", "vec", "geom1", "geom2") '
+ "VALUES (?, TO_REAL_VECTOR(?), ST_GeomFromWKT(?, 4326), ST_GeomFromWKT(?, 4326)) "
+ )
insert_args = [
- [1, '[0.1,0.3,0.2]', None, 'POINT (-71.123 78.23)'],
+ [1, "[0.1,0.3,0.2]", None, "POINT (-71.123 78.23)"],
[2, None, None, None],
- [3, '[0.5,0.8,0.4]', 'POINT (-70.332 66.33)', 'POINT (-71.123 78.23)']]
+ [3, "[0.5,0.8,0.4]", "POINT (-70.332 66.33)", "POINT (-71.123 78.23)"],
+ ]
self.prepareTestTable(table_name, create_sql, insert_sql, insert_args)
- layer = self.createVectorLayer(f'table="{self.schemaName}"."{table_name}" (geom1) sql=',
- 'testbinaryattributes')
- crs = QgsCoordinateReferenceSystem('EPSG:4326')
- params = f' key=\'pk\' table="{self.schemaName}"."import_data_binaries" (geom1) sql='
- error, message = QgsVectorLayerExporter.exportLayer(layer, self.uri + params, 'hana', crs)
+ layer = self.createVectorLayer(
+ f'table="{self.schemaName}"."{table_name}" (geom1) sql=',
+ "testbinaryattributes",
+ )
+ crs = QgsCoordinateReferenceSystem("EPSG:4326")
+ params = (
+ f' key=\'pk\' table="{self.schemaName}"."import_data_binaries" (geom1) sql='
+ )
+ error, message = QgsVectorLayerExporter.exportLayer(
+ layer, self.uri + params, "hana", crs
+ )
self.assertEqual(error, QgsVectorLayerExporter.ExportError.NoError)
- import_layer = self.createVectorLayer(params, 'testimportedlayer')
+ import_layer = self.createVectorLayer(params, "testimportedlayer")
fields = import_layer.dataProvider().fields()
self.assertEqual(fields.size(), 3)
- pk_field = fields.at(fields.indexFromName('pk'))
+ pk_field = fields.at(fields.indexFromName("pk"))
self.assertEqual(pk_field.type(), QVariant.Int)
- self.assertEqual(pk_field.typeName(), 'INTEGER')
- vec_field = fields.at(fields.indexFromName('vec'))
+ self.assertEqual(pk_field.typeName(), "INTEGER")
+ vec_field = fields.at(fields.indexFromName("vec"))
self.assertEqual(vec_field.type(), QVariant.String)
- self.assertEqual(vec_field.typeName(), 'REAL_VECTOR')
+ self.assertEqual(vec_field.typeName(), "REAL_VECTOR")
self.assertEqual(vec_field.length(), 3)
- geom2_field = fields.at(fields.indexFromName('geom2'))
+ geom2_field = fields.at(fields.indexFromName("geom2"))
self.assertEqual(geom2_field.type(), QVariant.String)
- self.assertEqual(geom2_field.typeName(), 'ST_GEOMETRY')
+ self.assertEqual(geom2_field.typeName(), "ST_GEOMETRY")
i = 0
for feat in import_layer.getFeatures():
- self.assertEqual(feat['pk'], insert_args[i][0])
- self.assertEqual(feat['vec'], insert_args[i][1])
- self.assertEqual(feat['geom2'], insert_args[i][3])
+ self.assertEqual(feat["pk"], insert_args[i][0])
+ self.assertEqual(feat["vec"], insert_args[i][1])
+ self.assertEqual(feat["geom2"], insert_args[i][3])
i += 1
def testFilterRectOutsideSrsExtent(self):
"""Test filterRect which partially lies outside of the srs extent"""
self.source.setSubsetString(None)
extent = QgsRectangle(-103, 46, -25, 97)
- result = {f[self.pk_name] for f in self.source.getFeatures(QgsFeatureRequest().setFilterRect(extent))}
+ result = {
+ f[self.pk_name]
+ for f in self.source.getFeatures(QgsFeatureRequest().setFilterRect(extent))
+ }
expected = {1, 2, 4, 5}
self.assertEqual(set(expected), result)
def testExtentWithEstimatedMetadata(self):
- create_sql = f'CREATE TABLE "{self.schemaName}"."test_extent" ( ' \
- 'ID INTEGER NOT NULL PRIMARY KEY,' \
- 'GEOM1 ST_GEOMETRY(0),' \
- 'GEOM2 ST_GEOMETRY(4326))'
- insert_sql = f'INSERT INTO "{self.schemaName}"."test_extent" (ID, GEOM1, GEOM2) ' \
- f'VALUES (?, ST_GeomFromText(?), ST_GeomFromText(?, 4326)) '
- insert_args = [[1, 'POLYGON ((0 0, 20 0, 20 20, 0 20, 0 0))', 'POLYGON ((0 0, 20 0, 20 20, 0 20, 0 0))']]
- self.prepareTestTable('test_extent', create_sql, insert_sql, insert_args)
-
- vl_geom1 = self.createVectorLayer(f'estimatedmetadata=true table="{self.schemaName}"."test_extent" (GEOM1) sql=', 'test_extent')
- vl_geom2 = self.createVectorLayer(f'estimatedmetadata=true table="{self.schemaName}"."test_extent" (GEOM2) sql=', 'test_extent')
+ create_sql = (
+ f'CREATE TABLE "{self.schemaName}"."test_extent" ( '
+ "ID INTEGER NOT NULL PRIMARY KEY,"
+ "GEOM1 ST_GEOMETRY(0),"
+ "GEOM2 ST_GEOMETRY(4326))"
+ )
+ insert_sql = (
+ f'INSERT INTO "{self.schemaName}"."test_extent" (ID, GEOM1, GEOM2) '
+ f"VALUES (?, ST_GeomFromText(?), ST_GeomFromText(?, 4326)) "
+ )
+ insert_args = [
+ [
+ 1,
+ "POLYGON ((0 0, 20 0, 20 20, 0 20, 0 0))",
+ "POLYGON ((0 0, 20 0, 20 20, 0 20, 0 0))",
+ ]
+ ]
+ self.prepareTestTable("test_extent", create_sql, insert_sql, insert_args)
+
+ vl_geom1 = self.createVectorLayer(
+ f'estimatedmetadata=true table="{self.schemaName}"."test_extent" (GEOM1) sql=',
+ "test_extent",
+ )
+ vl_geom2 = self.createVectorLayer(
+ f'estimatedmetadata=true table="{self.schemaName}"."test_extent" (GEOM2) sql=',
+ "test_extent",
+ )
self.assertEqual(QgsRectangle(0, 0, 20, 20), vl_geom1.dataProvider().extent())
- self.assertEqual(QgsRectangle(0, 0, 20, 20.284).toString(3), vl_geom2.dataProvider().extent().toString(3))
+ self.assertEqual(
+ QgsRectangle(0, 0, 20, 20.284).toString(3),
+ vl_geom2.dataProvider().extent().toString(3),
+ )
def testEncodeDecodeUri(self):
"""Test HANA encode/decode URI"""
- md = QgsProviderRegistry.instance().providerMetadata('hana')
+ md = QgsProviderRegistry.instance().providerMetadata("hana")
self.maxDiff = None
- self.assertEqual(md.decodeUri(
- "connectionType=0 dsn='HANADB1' "
- "driver='/usr/sap/hdbclient/libodbcHDB.so' dbname='qgis_tests' host=localhost port=30015 "
- "user='myuser' password='mypwd' srid=2016 table=\"public\".\"gis\" (geom) type=MultiPolygon key='id' "
- "sslEnabled='true' sslCryptoProvider='commoncrypto' sslValidateCertificate='false' "
- "sslHostNameInCertificate='hostname.domain.com' sslKeyStore='mykey.pem' "
- "sslTrustStore='server_root.crt' "
- "proxyEnabled='true' proxyHttp='true' proxyHost='h' proxyPort=2 proxyUsername='u' proxyPassword='p' "),
+ self.assertEqual(
+ md.decodeUri(
+ "connectionType=0 dsn='HANADB1' "
+ "driver='/usr/sap/hdbclient/libodbcHDB.so' dbname='qgis_tests' host=localhost port=30015 "
+ "user='myuser' password='mypwd' srid=2016 table=\"public\".\"gis\" (geom) type=MultiPolygon key='id' "
+ "sslEnabled='true' sslCryptoProvider='commoncrypto' sslValidateCertificate='false' "
+ "sslHostNameInCertificate='hostname.domain.com' sslKeyStore='mykey.pem' "
+ "sslTrustStore='server_root.crt' "
+ "proxyEnabled='true' proxyHttp='true' proxyHost='h' proxyPort=2 proxyUsername='u' proxyPassword='p' "
+ ),
{
- 'connectionType': '0',
- 'dsn': 'HANADB1',
- 'driver': '/usr/sap/hdbclient/libodbcHDB.so',
- 'dbname': 'qgis_tests',
- 'host': 'localhost',
- 'port': '30015',
- 'username': 'myuser',
- 'password': 'mypwd',
- 'schema': 'public',
- 'table': 'gis',
- 'geometrycolumn': 'geom',
- 'srid': '2016',
- 'type': 6,
- 'key': 'id',
- 'sslEnabled': 'true',
- 'sslCryptoProvider': 'commoncrypto',
- 'sslValidateCertificate': 'false',
- 'sslHostNameInCertificate': 'hostname.domain.com',
- 'sslKeyStore': 'mykey.pem',
- 'sslTrustStore': 'server_root.crt',
- 'selectatid': False,
- 'proxyEnabled': 'true',
- 'proxyHttp': 'true',
- 'proxyHost': 'h',
- 'proxyPort': '2',
- 'proxyUsername': 'u',
- 'proxyPassword': 'p'})
-
- self.assertEqual(md.encodeUri({'connectionType': '0',
- 'dsn': 'HANADB1',
- 'driver': '/usr/sap/hdbclient/libodbcHDB.so',
- 'dbname': 'qgis_tests',
- 'host': 'localhost',
- 'port': '30015',
- 'username': 'myuser',
- 'password': 'mypwd',
- 'schema': 'public',
- 'table': 'gis',
- 'geometrycolumn': 'geom',
- 'srid': '2016',
- 'type': 6,
- 'key': 'id',
- 'sslEnabled': 'true',
- 'sslCryptoProvider': 'commoncrypto',
- 'sslValidateCertificate': 'false',
- 'sslHostNameInCertificate': 'hostname.domain.com',
- 'sslKeyStore': 'mykey.pem',
- 'sslTrustStore': 'server_root.crt',
- 'selectatid': False,
- 'proxyEnabled': 'true',
- 'proxyHttp': 'false',
- 'proxyHost': 'h',
- 'proxyPort': '3',
- 'proxyUsername': 'u',
- 'proxyPassword': 'p'}),
- "dbname='qgis_tests' driver='/usr/sap/hdbclient/libodbcHDB.so' user='myuser' password='mypwd' "
- "key='id' srid=2016 connectionType='0' dsn='HANADB1' host='localhost' port='30015' "
- "proxyEnabled='true' proxyHost='h' proxyHttp='false' proxyPassword='p' proxyPort='3' "
- "proxyUsername='u' selectatid='false' sslCryptoProvider='commoncrypto' sslEnabled='true' "
- "sslHostNameInCertificate='hostname.domain.com' sslKeyStore='mykey.pem' "
- "sslTrustStore='server_root.crt' sslValidateCertificate='false' type='MultiPolygon' "
- "table=\"public\".\"gis\" (geom)")
-
-
-if __name__ == '__main__':
+ "connectionType": "0",
+ "dsn": "HANADB1",
+ "driver": "/usr/sap/hdbclient/libodbcHDB.so",
+ "dbname": "qgis_tests",
+ "host": "localhost",
+ "port": "30015",
+ "username": "myuser",
+ "password": "mypwd",
+ "schema": "public",
+ "table": "gis",
+ "geometrycolumn": "geom",
+ "srid": "2016",
+ "type": 6,
+ "key": "id",
+ "sslEnabled": "true",
+ "sslCryptoProvider": "commoncrypto",
+ "sslValidateCertificate": "false",
+ "sslHostNameInCertificate": "hostname.domain.com",
+ "sslKeyStore": "mykey.pem",
+ "sslTrustStore": "server_root.crt",
+ "selectatid": False,
+ "proxyEnabled": "true",
+ "proxyHttp": "true",
+ "proxyHost": "h",
+ "proxyPort": "2",
+ "proxyUsername": "u",
+ "proxyPassword": "p",
+ },
+ )
+
+ self.assertEqual(
+ md.encodeUri(
+ {
+ "connectionType": "0",
+ "dsn": "HANADB1",
+ "driver": "/usr/sap/hdbclient/libodbcHDB.so",
+ "dbname": "qgis_tests",
+ "host": "localhost",
+ "port": "30015",
+ "username": "myuser",
+ "password": "mypwd",
+ "schema": "public",
+ "table": "gis",
+ "geometrycolumn": "geom",
+ "srid": "2016",
+ "type": 6,
+ "key": "id",
+ "sslEnabled": "true",
+ "sslCryptoProvider": "commoncrypto",
+ "sslValidateCertificate": "false",
+ "sslHostNameInCertificate": "hostname.domain.com",
+ "sslKeyStore": "mykey.pem",
+ "sslTrustStore": "server_root.crt",
+ "selectatid": False,
+ "proxyEnabled": "true",
+ "proxyHttp": "false",
+ "proxyHost": "h",
+ "proxyPort": "3",
+ "proxyUsername": "u",
+ "proxyPassword": "p",
+ }
+ ),
+ "dbname='qgis_tests' driver='/usr/sap/hdbclient/libodbcHDB.so' user='myuser' password='mypwd' "
+ "key='id' srid=2016 connectionType='0' dsn='HANADB1' host='localhost' port='30015' "
+ "proxyEnabled='true' proxyHost='h' proxyHttp='false' proxyPassword='p' proxyPort='3' "
+ "proxyUsername='u' selectatid='false' sslCryptoProvider='commoncrypto' sslEnabled='true' "
+ "sslHostNameInCertificate='hostname.domain.com' sslKeyStore='mykey.pem' "
+ "sslTrustStore='server_root.crt' sslValidateCertificate='false' type='MultiPolygon' "
+ 'table="public"."gis" (geom)',
+ )
+
+
+if __name__ == "__main__":
unittest.main()
diff --git a/tests/src/python/test_provider_memory.py b/tests/src/python/test_provider_memory.py
index 7d2210d99ed8..d4fbc466b279 100644
--- a/tests/src/python/test_provider_memory.py
+++ b/tests/src/python/test_provider_memory.py
@@ -5,9 +5,10 @@
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
"""
-__author__ = 'Matthias Kuhn'
-__date__ = '2015-04-23'
-__copyright__ = 'Copyright 2015, The QGIS Project'
+
+__author__ = "Matthias Kuhn"
+__date__ = "2015-04-23"
+__copyright__ = "Copyright 2015, The QGIS Project"
from urllib.parse import parse_qs
@@ -47,36 +48,74 @@ class TestPyQgsMemoryProvider(QgisTestCase, ProviderTestCase):
@classmethod
def createLayer(cls):
vl = QgsVectorLayer(
- 'Point?crs=epsg:4326&field=pk:integer&field=cnt:integer&field=name:string(0)&field=name2:string(0)&field=num_char:string&field=dt:datetime&field=date:date&field=time:time&key=pk',
- 'test', 'memory')
- assert (vl.isValid())
+ "Point?crs=epsg:4326&field=pk:integer&field=cnt:integer&field=name:string(0)&field=name2:string(0)&field=num_char:string&field=dt:datetime&field=date:date&field=time:time&key=pk",
+ "test",
+ "memory",
+ )
+ assert vl.isValid()
f1 = QgsFeature()
f1.setAttributes(
- [5, -200, NULL, 'NuLl', '5', QDateTime(QDate(2020, 5, 4), QTime(12, 13, 14)), QDate(2020, 5, 2),
- QTime(12, 13, 1)])
- f1.setGeometry(QgsGeometry.fromWkt('Point (-71.123 78.23)'))
+ [
+ 5,
+ -200,
+ NULL,
+ "NuLl",
+ "5",
+ QDateTime(QDate(2020, 5, 4), QTime(12, 13, 14)),
+ QDate(2020, 5, 2),
+ QTime(12, 13, 1),
+ ]
+ )
+ f1.setGeometry(QgsGeometry.fromWkt("Point (-71.123 78.23)"))
f2 = QgsFeature()
- f2.setAttributes([3, 300, 'Pear', 'PEaR', '3', NULL, NULL, NULL])
+ f2.setAttributes([3, 300, "Pear", "PEaR", "3", NULL, NULL, NULL])
f3 = QgsFeature()
f3.setAttributes(
- [1, 100, 'Orange', 'oranGe', '1', QDateTime(QDate(2020, 5, 3), QTime(12, 13, 14)), QDate(2020, 5, 3),
- QTime(12, 13, 14)])
- f3.setGeometry(QgsGeometry.fromWkt('Point (-70.332 66.33)'))
+ [
+ 1,
+ 100,
+ "Orange",
+ "oranGe",
+ "1",
+ QDateTime(QDate(2020, 5, 3), QTime(12, 13, 14)),
+ QDate(2020, 5, 3),
+ QTime(12, 13, 14),
+ ]
+ )
+ f3.setGeometry(QgsGeometry.fromWkt("Point (-70.332 66.33)"))
f4 = QgsFeature()
f4.setAttributes(
- [2, 200, 'Apple', 'Apple', '2', QDateTime(QDate(2020, 5, 4), QTime(12, 14, 14)), QDate(2020, 5, 4),
- QTime(12, 14, 14)])
- f4.setGeometry(QgsGeometry.fromWkt('Point (-68.2 70.8)'))
+ [
+ 2,
+ 200,
+ "Apple",
+ "Apple",
+ "2",
+ QDateTime(QDate(2020, 5, 4), QTime(12, 14, 14)),
+ QDate(2020, 5, 4),
+ QTime(12, 14, 14),
+ ]
+ )
+ f4.setGeometry(QgsGeometry.fromWkt("Point (-68.2 70.8)"))
f5 = QgsFeature()
f5.setAttributes(
- [4, 400, 'Honey', 'Honey', '4', QDateTime(QDate(2021, 5, 4), QTime(13, 13, 14)), QDate(2021, 5, 4),
- QTime(13, 13, 14)])
- f5.setGeometry(QgsGeometry.fromWkt('Point (-65.32 78.3)'))
+ [
+ 4,
+ 400,
+ "Honey",
+ "Honey",
+ "4",
+ QDateTime(QDate(2021, 5, 4), QTime(13, 13, 14)),
+ QDate(2021, 5, 4),
+ QTime(13, 13, 14),
+ ]
+ )
+ f5.setGeometry(QgsGeometry.fromWkt("Point (-65.32 78.3)"))
vl.dataProvider().addFeatures([f1, f2, f3, f4, f5])
return vl
@@ -84,32 +123,42 @@ def createLayer(cls):
@classmethod
def setUpClass(cls):
"""Run before all tests"""
- super(TestPyQgsMemoryProvider, cls).setUpClass()
+ super().setUpClass()
# Create test layer
cls.vl = cls.createLayer()
- assert (cls.vl.isValid())
+ assert cls.vl.isValid()
cls.source = cls.vl.dataProvider()
# poly layer
- cls.poly_vl = QgsVectorLayer('Polygon?crs=epsg:4326&field=pk:integer&key=pk',
- 'test', 'memory')
- assert (cls.poly_vl.isValid())
+ cls.poly_vl = QgsVectorLayer(
+ "Polygon?crs=epsg:4326&field=pk:integer&key=pk", "test", "memory"
+ )
+ assert cls.poly_vl.isValid()
cls.poly_provider = cls.poly_vl.dataProvider()
f1 = QgsFeature()
f1.setAttributes([1])
- f1.setGeometry(QgsGeometry.fromWkt(
- 'Polygon ((-69.03664108 81.35818902, -69.09237722 80.24346619, -73.718477 80.1319939, -73.718477 76.28620011, -74.88893598 76.34193625, -74.83319983 81.35818902, -69.03664108 81.35818902))'))
+ f1.setGeometry(
+ QgsGeometry.fromWkt(
+ "Polygon ((-69.03664108 81.35818902, -69.09237722 80.24346619, -73.718477 80.1319939, -73.718477 76.28620011, -74.88893598 76.34193625, -74.83319983 81.35818902, -69.03664108 81.35818902))"
+ )
+ )
f2 = QgsFeature()
f2.setAttributes([2])
- f2.setGeometry(QgsGeometry.fromWkt(
- 'Polygon ((-67.58750139 81.1909806, -66.30557012 81.24671674, -66.30557012 76.89929767, -67.58750139 76.89929767, -67.58750139 81.1909806))'))
+ f2.setGeometry(
+ QgsGeometry.fromWkt(
+ "Polygon ((-67.58750139 81.1909806, -66.30557012 81.24671674, -66.30557012 76.89929767, -67.58750139 76.89929767, -67.58750139 81.1909806))"
+ )
+ )
f3 = QgsFeature()
f3.setAttributes([3])
- f3.setGeometry(QgsGeometry.fromWkt(
- 'Polygon ((-68.36780737 75.78457483, -67.53176524 72.60761475, -68.64648808 73.66660144, -70.20710006 72.9420316, -68.36780737 75.78457483))'))
+ f3.setGeometry(
+ QgsGeometry.fromWkt(
+ "Polygon ((-68.36780737 75.78457483, -67.53176524 72.60761475, -68.64648808 73.66660144, -70.20710006 72.9420316, -68.36780737 75.78457483))"
+ )
+ )
f4 = QgsFeature()
f4.setAttributes([4])
@@ -120,55 +169,177 @@ def getEditableLayer(self):
return self.createLayer()
def testGetFeaturesSubsetAttributes2(self):
- """ Override and skip this test for memory provider, as it's actually more efficient for the memory provider to return
+ """Override and skip this test for memory provider, as it's actually more efficient for the memory provider to return
its features as direct copies (due to implicit sharing of QgsFeature)
"""
pass
def testGetFeaturesNoGeometry(self):
- """ Override and skip this test for memory provider, as it's actually more efficient for the memory provider to return
+ """Override and skip this test for memory provider, as it's actually more efficient for the memory provider to return
its features as direct copies (due to implicit sharing of QgsFeature)
"""
pass
def testCtors(self):
- testVectors = ["Point", "LineString", "Polygon", "MultiPoint", "MultiLineString", "MultiPolygon", "None"]
+ testVectors = [
+ "Point",
+ "LineString",
+ "Polygon",
+ "MultiPoint",
+ "MultiLineString",
+ "MultiPolygon",
+ "None",
+ ]
for v in testVectors:
layer = QgsVectorLayer(v, "test", "memory")
self.assertTrue(layer.isValid(), f"Failed to create valid {v} memory layer")
def testLayerGeometry(self):
- testVectors = [("Point", QgsWkbTypes.GeometryType.PointGeometry, QgsWkbTypes.Type.Point),
- ("LineString", QgsWkbTypes.GeometryType.LineGeometry, QgsWkbTypes.Type.LineString),
- ("Polygon", QgsWkbTypes.GeometryType.PolygonGeometry, QgsWkbTypes.Type.Polygon),
- ("MultiPoint", QgsWkbTypes.GeometryType.PointGeometry, QgsWkbTypes.Type.MultiPoint),
- ("MultiLineString", QgsWkbTypes.GeometryType.LineGeometry, QgsWkbTypes.Type.MultiLineString),
- ("MultiPolygon", QgsWkbTypes.GeometryType.PolygonGeometry, QgsWkbTypes.Type.MultiPolygon),
- ("PointZ", QgsWkbTypes.GeometryType.PointGeometry, QgsWkbTypes.Type.PointZ),
- ("LineStringZ", QgsWkbTypes.GeometryType.LineGeometry, QgsWkbTypes.Type.LineStringZ),
- ("PolygonZ", QgsWkbTypes.GeometryType.PolygonGeometry, QgsWkbTypes.Type.PolygonZ),
- ("MultiPointZ", QgsWkbTypes.GeometryType.PointGeometry, QgsWkbTypes.Type.MultiPointZ),
- ("MultiLineStringZ", QgsWkbTypes.GeometryType.LineGeometry, QgsWkbTypes.Type.MultiLineStringZ),
- ("MultiPolygonZ", QgsWkbTypes.GeometryType.PolygonGeometry, QgsWkbTypes.Type.MultiPolygonZ),
- ("PointM", QgsWkbTypes.GeometryType.PointGeometry, QgsWkbTypes.Type.PointM),
- ("LineStringM", QgsWkbTypes.GeometryType.LineGeometry, QgsWkbTypes.Type.LineStringM),
- ("PolygonM", QgsWkbTypes.GeometryType.PolygonGeometry, QgsWkbTypes.Type.PolygonM),
- ("MultiPointM", QgsWkbTypes.GeometryType.PointGeometry, QgsWkbTypes.Type.MultiPointM),
- ("MultiLineStringM", QgsWkbTypes.GeometryType.LineGeometry, QgsWkbTypes.Type.MultiLineStringM),
- ("MultiPolygonM", QgsWkbTypes.GeometryType.PolygonGeometry, QgsWkbTypes.Type.MultiPolygonM),
- ("PointZM", QgsWkbTypes.GeometryType.PointGeometry, QgsWkbTypes.Type.PointZM),
- ("LineStringZM", QgsWkbTypes.GeometryType.LineGeometry, QgsWkbTypes.Type.LineStringZM),
- ("PolygonZM", QgsWkbTypes.GeometryType.PolygonGeometry, QgsWkbTypes.Type.PolygonZM),
- ("MultiPointZM", QgsWkbTypes.GeometryType.PointGeometry, QgsWkbTypes.Type.MultiPointZM),
- ("MultiLineStringZM", QgsWkbTypes.GeometryType.LineGeometry, QgsWkbTypes.Type.MultiLineStringZM),
- ("MultiPolygonZM", QgsWkbTypes.GeometryType.PolygonGeometry, QgsWkbTypes.Type.MultiPolygonZM),
- ("Point25D", QgsWkbTypes.GeometryType.PointGeometry, QgsWkbTypes.Type.Point25D),
- ("LineString25D", QgsWkbTypes.GeometryType.LineGeometry, QgsWkbTypes.Type.LineString25D),
- ("Polygon25D", QgsWkbTypes.GeometryType.PolygonGeometry, QgsWkbTypes.Type.Polygon25D),
- ("MultiPoint25D", QgsWkbTypes.GeometryType.PointGeometry, QgsWkbTypes.Type.MultiPoint25D),
- ("MultiLineString25D", QgsWkbTypes.GeometryType.LineGeometry, QgsWkbTypes.Type.MultiLineString25D),
- ("MultiPolygon25D", QgsWkbTypes.GeometryType.PolygonGeometry, QgsWkbTypes.Type.MultiPolygon25D),
- ("None", QgsWkbTypes.GeometryType.NullGeometry, QgsWkbTypes.Type.NoGeometry)]
+ testVectors = [
+ ("Point", QgsWkbTypes.GeometryType.PointGeometry, QgsWkbTypes.Type.Point),
+ (
+ "LineString",
+ QgsWkbTypes.GeometryType.LineGeometry,
+ QgsWkbTypes.Type.LineString,
+ ),
+ (
+ "Polygon",
+ QgsWkbTypes.GeometryType.PolygonGeometry,
+ QgsWkbTypes.Type.Polygon,
+ ),
+ (
+ "MultiPoint",
+ QgsWkbTypes.GeometryType.PointGeometry,
+ QgsWkbTypes.Type.MultiPoint,
+ ),
+ (
+ "MultiLineString",
+ QgsWkbTypes.GeometryType.LineGeometry,
+ QgsWkbTypes.Type.MultiLineString,
+ ),
+ (
+ "MultiPolygon",
+ QgsWkbTypes.GeometryType.PolygonGeometry,
+ QgsWkbTypes.Type.MultiPolygon,
+ ),
+ ("PointZ", QgsWkbTypes.GeometryType.PointGeometry, QgsWkbTypes.Type.PointZ),
+ (
+ "LineStringZ",
+ QgsWkbTypes.GeometryType.LineGeometry,
+ QgsWkbTypes.Type.LineStringZ,
+ ),
+ (
+ "PolygonZ",
+ QgsWkbTypes.GeometryType.PolygonGeometry,
+ QgsWkbTypes.Type.PolygonZ,
+ ),
+ (
+ "MultiPointZ",
+ QgsWkbTypes.GeometryType.PointGeometry,
+ QgsWkbTypes.Type.MultiPointZ,
+ ),
+ (
+ "MultiLineStringZ",
+ QgsWkbTypes.GeometryType.LineGeometry,
+ QgsWkbTypes.Type.MultiLineStringZ,
+ ),
+ (
+ "MultiPolygonZ",
+ QgsWkbTypes.GeometryType.PolygonGeometry,
+ QgsWkbTypes.Type.MultiPolygonZ,
+ ),
+ ("PointM", QgsWkbTypes.GeometryType.PointGeometry, QgsWkbTypes.Type.PointM),
+ (
+ "LineStringM",
+ QgsWkbTypes.GeometryType.LineGeometry,
+ QgsWkbTypes.Type.LineStringM,
+ ),
+ (
+ "PolygonM",
+ QgsWkbTypes.GeometryType.PolygonGeometry,
+ QgsWkbTypes.Type.PolygonM,
+ ),
+ (
+ "MultiPointM",
+ QgsWkbTypes.GeometryType.PointGeometry,
+ QgsWkbTypes.Type.MultiPointM,
+ ),
+ (
+ "MultiLineStringM",
+ QgsWkbTypes.GeometryType.LineGeometry,
+ QgsWkbTypes.Type.MultiLineStringM,
+ ),
+ (
+ "MultiPolygonM",
+ QgsWkbTypes.GeometryType.PolygonGeometry,
+ QgsWkbTypes.Type.MultiPolygonM,
+ ),
+ (
+ "PointZM",
+ QgsWkbTypes.GeometryType.PointGeometry,
+ QgsWkbTypes.Type.PointZM,
+ ),
+ (
+ "LineStringZM",
+ QgsWkbTypes.GeometryType.LineGeometry,
+ QgsWkbTypes.Type.LineStringZM,
+ ),
+ (
+ "PolygonZM",
+ QgsWkbTypes.GeometryType.PolygonGeometry,
+ QgsWkbTypes.Type.PolygonZM,
+ ),
+ (
+ "MultiPointZM",
+ QgsWkbTypes.GeometryType.PointGeometry,
+ QgsWkbTypes.Type.MultiPointZM,
+ ),
+ (
+ "MultiLineStringZM",
+ QgsWkbTypes.GeometryType.LineGeometry,
+ QgsWkbTypes.Type.MultiLineStringZM,
+ ),
+ (
+ "MultiPolygonZM",
+ QgsWkbTypes.GeometryType.PolygonGeometry,
+ QgsWkbTypes.Type.MultiPolygonZM,
+ ),
+ (
+ "Point25D",
+ QgsWkbTypes.GeometryType.PointGeometry,
+ QgsWkbTypes.Type.Point25D,
+ ),
+ (
+ "LineString25D",
+ QgsWkbTypes.GeometryType.LineGeometry,
+ QgsWkbTypes.Type.LineString25D,
+ ),
+ (
+ "Polygon25D",
+ QgsWkbTypes.GeometryType.PolygonGeometry,
+ QgsWkbTypes.Type.Polygon25D,
+ ),
+ (
+ "MultiPoint25D",
+ QgsWkbTypes.GeometryType.PointGeometry,
+ QgsWkbTypes.Type.MultiPoint25D,
+ ),
+ (
+ "MultiLineString25D",
+ QgsWkbTypes.GeometryType.LineGeometry,
+ QgsWkbTypes.Type.MultiLineString25D,
+ ),
+ (
+ "MultiPolygon25D",
+ QgsWkbTypes.GeometryType.PolygonGeometry,
+ QgsWkbTypes.Type.MultiPolygon25D,
+ ),
+ (
+ "None",
+ QgsWkbTypes.GeometryType.NullGeometry,
+ QgsWkbTypes.Type.NoGeometry,
+ ),
+ ]
for v in testVectors:
layer = QgsVectorLayer(v[0], "test", "memory")
@@ -179,18 +350,20 @@ def testAddFeatures(self):
layer = QgsVectorLayer("Point", "test", "memory")
provider = layer.dataProvider()
- res = provider.addAttributes([QgsField("name", QVariant.String),
- QgsField("age", QVariant.Int),
- QgsField("size", QVariant.Double)])
+ res = provider.addAttributes(
+ [
+ QgsField("name", QVariant.String),
+ QgsField("age", QVariant.Int),
+ QgsField("size", QVariant.Double),
+ ]
+ )
self.assertTrue(res)
self.assertEqual(len(provider.fields()), 3)
ft = QgsFeature()
ft.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(10, 10)))
- ft.setAttributes(["Johny",
- 20,
- 0.3])
+ ft.setAttributes(["Johny", 20, 0.3])
res, t = provider.addFeatures([ft])
self.assertTrue(res)
@@ -211,8 +384,8 @@ def testCloneFeatures(self):
Test that cloning a memory layer also clones features
"""
vl = QgsVectorLayer(
- 'Point?crs=epsg:4326&field=f1:integer&field=f2:integer',
- 'test', 'memory')
+ "Point?crs=epsg:4326&field=f1:integer&field=f2:integer", "test", "memory"
+ )
self.assertTrue(vl.isValid())
f1 = QgsFeature()
@@ -227,42 +400,55 @@ def testCloneFeatures(self):
vl2 = vl.clone()
self.assertEqual(vl2.featureCount(), 3)
features = [f for f in vl2.getFeatures()]
- self.assertTrue([f for f in features if f['f1'] == 5])
- self.assertTrue([f for f in features if f['f1'] == 3])
- self.assertTrue([f for f in features if f['f1'] == 1])
+ self.assertTrue([f for f in features if f["f1"] == 5])
+ self.assertTrue([f for f in features if f["f1"] == 3])
+ self.assertTrue([f for f in features if f["f1"] == 1])
def testCloneId(self):
"""Test that a cloned layer has a single new id and
the same fields as the source layer"""
- vl = QgsVectorLayer(
- 'Point?crs=epsg:4326',
- 'test', 'memory')
+ vl = QgsVectorLayer("Point?crs=epsg:4326", "test", "memory")
self.assertTrue(vl.isValid)
dp = vl.dataProvider()
- self.assertTrue(dp.addAttributes([QgsField("name", QVariant.String),
- QgsField("age", QVariant.Int),
- QgsField("size", QVariant.Double)]))
+ self.assertTrue(
+ dp.addAttributes(
+ [
+ QgsField("name", QVariant.String),
+ QgsField("age", QVariant.Int),
+ QgsField("size", QVariant.Double),
+ ]
+ )
+ )
vl2 = vl.clone()
self.assertTrue(
- 'memory?geometry=Point&crs=EPSG:4326&field=name:string(0,0)&field=age:integer(0,0)&field=size:double(0,0)' in vl2.publicSource())
- self.assertEqual(len(parse_qs(vl.publicSource())['uid']), 1)
- self.assertEqual(len(parse_qs(vl2.publicSource())['uid']), 1)
- self.assertNotEqual(parse_qs(vl2.publicSource())['uid'][0], parse_qs(vl.publicSource())['uid'][0])
+ "memory?geometry=Point&crs=EPSG:4326&field=name:string(0,0)&field=age:integer(0,0)&field=size:double(0,0)"
+ in vl2.publicSource()
+ )
+ self.assertEqual(len(parse_qs(vl.publicSource())["uid"]), 1)
+ self.assertEqual(len(parse_qs(vl2.publicSource())["uid"]), 1)
+ self.assertNotEqual(
+ parse_qs(vl2.publicSource())["uid"][0],
+ parse_qs(vl.publicSource())["uid"][0],
+ )
def testGetFields(self):
layer = QgsVectorLayer("Point", "test", "memory")
provider = layer.dataProvider()
- provider.addAttributes([QgsField("name", QVariant.String),
- QgsField("age", QVariant.Int),
- QgsField("size", QVariant.Double),
- QgsField("vallist", QVariant.List, subType=QVariant.Int),
- QgsField("stringlist", QVariant.List, subType=QVariant.String),
- QgsField("reallist", QVariant.List, subType=QVariant.Double),
- QgsField("longlist", QVariant.List, subType=QVariant.LongLong),
- QgsField("dict", QVariant.Map),
- QgsField("geom", QVariant.UserType, typeName='geometry')])
+ provider.addAttributes(
+ [
+ QgsField("name", QVariant.String),
+ QgsField("age", QVariant.Int),
+ QgsField("size", QVariant.Double),
+ QgsField("vallist", QVariant.List, subType=QVariant.Int),
+ QgsField("stringlist", QVariant.List, subType=QVariant.String),
+ QgsField("reallist", QVariant.List, subType=QVariant.Double),
+ QgsField("longlist", QVariant.List, subType=QVariant.LongLong),
+ QgsField("dict", QVariant.Map),
+ QgsField("geom", QVariant.UserType, typeName="geometry"),
+ ]
+ )
self.assertEqual(len(provider.fields()), 9)
self.assertEqual(provider.fields()[0].name(), "name")
self.assertEqual(provider.fields()[0].type(), QVariant.String)
@@ -289,32 +475,51 @@ def testGetFields(self):
self.assertEqual(provider.fields()[7].type(), QVariant.Map)
self.assertEqual(provider.fields()[8].name(), "geom")
self.assertEqual(provider.fields()[8].type(), QVariant.UserType)
- self.assertEqual(provider.fields()[8].typeName(), 'geometry')
+ self.assertEqual(provider.fields()[8].typeName(), "geometry")
ft = QgsFeature(provider.fields())
ft.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(10, 10)))
- ft.setAttributes(["Johny",
- 20,
- 0.3,
- [1, 2, 3],
- ['a', 'b', 'c'],
- [1.1, 2.2, 3.3],
- [1, 2, 3],
- {'a': 1, 'b': 2},
- QgsGeometry.fromWkt('Point( 1 2)')])
+ ft.setAttributes(
+ [
+ "Johny",
+ 20,
+ 0.3,
+ [1, 2, 3],
+ ["a", "b", "c"],
+ [1.1, 2.2, 3.3],
+ [1, 2, 3],
+ {"a": 1, "b": 2},
+ QgsGeometry.fromWkt("Point( 1 2)"),
+ ]
+ )
self.assertTrue(provider.addFeatures([ft]))
for f in provider.getFeatures(QgsFeatureRequest()):
- self.assertEqual(f.attributes()[:8], ['Johny', 20, 0.3, [1, 2, 3], ['a', 'b', 'c'], [1.1, 2.2, 3.3], [1, 2, 3], {'a': 1, 'b': 2}])
- self.assertEqual(f.attributes()[8].asWkt(), 'Point (1 2)')
+ self.assertEqual(
+ f.attributes()[:8],
+ [
+ "Johny",
+ 20,
+ 0.3,
+ [1, 2, 3],
+ ["a", "b", "c"],
+ [1.1, 2.2, 3.3],
+ [1, 2, 3],
+ {"a": 1, "b": 2},
+ ],
+ )
+ self.assertEqual(f.attributes()[8].asWkt(), "Point (1 2)")
def testFromUri(self):
"""Test we can construct the mem provider from a uri"""
myMemoryLayer = QgsVectorLayer(
- ('Point?crs=epsg:4326&field=name:string(20)&'
- 'field=age:integer&field=size:double&index=yes'),
- 'test',
- 'memory')
+ (
+ "Point?crs=epsg:4326&field=name:string(20)&"
+ "field=age:integer&field=size:double&index=yes"
+ ),
+ "test",
+ "memory",
+ )
self.assertIsNotNone(myMemoryLayer)
myProvider = myMemoryLayer.dataProvider()
@@ -323,111 +528,103 @@ def testFromUri(self):
def testLengthPrecisionFromUri(self):
"""Test we can assign length and precision from a uri"""
myMemoryLayer = QgsVectorLayer(
- ('Point?crs=epsg:4326&field=size:double(12,9)&index=yes'),
- 'test',
- 'memory')
+ ("Point?crs=epsg:4326&field=size:double(12,9)&index=yes"), "test", "memory"
+ )
- self.assertEqual(myMemoryLayer.fields().field('size').length(), 12)
- self.assertEqual(myMemoryLayer.fields().field('size').precision(), 9)
+ self.assertEqual(myMemoryLayer.fields().field("size").length(), 12)
+ self.assertEqual(myMemoryLayer.fields().field("size").precision(), 9)
myMemoryLayer = QgsVectorLayer(
- ('Point?crs=epsg:4326&field=size:double(-1,-1)&index=yes'),
- 'test',
- 'memory')
+ ("Point?crs=epsg:4326&field=size:double(-1,-1)&index=yes"), "test", "memory"
+ )
- self.assertEqual(myMemoryLayer.fields().field('size').length(), -1)
- self.assertEqual(myMemoryLayer.fields().field('size').precision(), -1)
+ self.assertEqual(myMemoryLayer.fields().field("size").length(), -1)
+ self.assertEqual(myMemoryLayer.fields().field("size").precision(), -1)
myMemoryLayer = QgsVectorLayer(
- ('Point?crs=epsg:4326&field=size:string(-1)&index=yes'),
- 'test',
- 'memory')
+ ("Point?crs=epsg:4326&field=size:string(-1)&index=yes"), "test", "memory"
+ )
- self.assertEqual(myMemoryLayer.fields().field('size').length(), -1)
+ self.assertEqual(myMemoryLayer.fields().field("size").length(), -1)
def testListFromUri(self):
"""Test we can create list type fields from a uri"""
myMemoryLayer = QgsVectorLayer(
- ('Point?crs=epsg:4326&field=a:string(-1)[]&index=yes'),
- 'test',
- 'memory')
+ ("Point?crs=epsg:4326&field=a:string(-1)[]&index=yes"), "test", "memory"
+ )
- self.assertEqual(myMemoryLayer.fields().field('a').type(), QVariant.StringList)
- self.assertEqual(myMemoryLayer.fields().field('a').subType(), QVariant.String)
+ self.assertEqual(myMemoryLayer.fields().field("a").type(), QVariant.StringList)
+ self.assertEqual(myMemoryLayer.fields().field("a").subType(), QVariant.String)
myMemoryLayer = QgsVectorLayer(
- ('Point?crs=epsg:4326&field=a:double(-1,-1)[]&index=yes'),
- 'test',
- 'memory')
+ ("Point?crs=epsg:4326&field=a:double(-1,-1)[]&index=yes"), "test", "memory"
+ )
- self.assertEqual(myMemoryLayer.fields().field('a').type(), QVariant.List)
- self.assertEqual(myMemoryLayer.fields().field('a').subType(), QVariant.Double)
+ self.assertEqual(myMemoryLayer.fields().field("a").type(), QVariant.List)
+ self.assertEqual(myMemoryLayer.fields().field("a").subType(), QVariant.Double)
myMemoryLayer = QgsVectorLayer(
- ('Point?crs=epsg:4326&field=a:long(-1,-1)[]&index=yes'),
- 'test',
- 'memory')
+ ("Point?crs=epsg:4326&field=a:long(-1,-1)[]&index=yes"), "test", "memory"
+ )
- self.assertEqual(myMemoryLayer.fields().field('a').type(), QVariant.List)
- self.assertEqual(myMemoryLayer.fields().field('a').subType(), QVariant.LongLong)
+ self.assertEqual(myMemoryLayer.fields().field("a").type(), QVariant.List)
+ self.assertEqual(myMemoryLayer.fields().field("a").subType(), QVariant.LongLong)
myMemoryLayer = QgsVectorLayer(
- ('Point?crs=epsg:4326&field=a:int(-1,-1)[]&index=yes'),
- 'test',
- 'memory')
+ ("Point?crs=epsg:4326&field=a:int(-1,-1)[]&index=yes"), "test", "memory"
+ )
- self.assertEqual(myMemoryLayer.fields().field('a').type(), QVariant.List)
- self.assertEqual(myMemoryLayer.fields().field('a').subType(), QVariant.Int)
+ self.assertEqual(myMemoryLayer.fields().field("a").type(), QVariant.List)
+ self.assertEqual(myMemoryLayer.fields().field("a").subType(), QVariant.Int)
def testMapFromUri(self):
"""Test we can create map type fields from a uri"""
layer = QgsVectorLayer(
- ('Point?crs=epsg:4326&field=a:map(-1)&index=yes'),
- 'test',
- 'memory')
- self.assertEqual(layer.fields().field('a').type(), QVariant.Map)
+ ("Point?crs=epsg:4326&field=a:map(-1)&index=yes"), "test", "memory"
+ )
+ self.assertEqual(layer.fields().field("a").type(), QVariant.Map)
def testGeomFieldFromUri(self):
"""Test we can create geometry type fields from a uri"""
layer = QgsVectorLayer(
- ('Point?crs=epsg:4326&field=a:geometry&index=yes'),
- 'test',
- 'memory')
- self.assertEqual(layer.fields().field('a').type(), QVariant.UserType)
- self.assertEqual(layer.fields().field('a').typeName(), 'geometry')
+ ("Point?crs=epsg:4326&field=a:geometry&index=yes"), "test", "memory"
+ )
+ self.assertEqual(layer.fields().field("a").type(), QVariant.UserType)
+ self.assertEqual(layer.fields().field("a").typeName(), "geometry")
def testFromUriWithEncodedField(self):
"""Test we can construct the mem provider from a uri when a field name is encoded"""
layer = QgsVectorLayer(
- ('Point?crs=epsg:4326&field=name:string(20)&'
- 'field=test%2Ffield:integer'),
- 'test',
- 'memory')
+ ("Point?crs=epsg:4326&field=name:string(20)&" "field=test%2Ffield:integer"),
+ "test",
+ "memory",
+ )
self.assertTrue(layer.isValid())
- self.assertEqual([f.name() for f in layer.fields()], ['name', 'test/field'])
+ self.assertEqual([f.name() for f in layer.fields()], ["name", "test/field"])
def testSaveFields(self):
# Create a new memory layer with no fields
myMemoryLayer = QgsVectorLayer(
- ('Point?crs=epsg:4326&index=yes'),
- 'test',
- 'memory')
+ ("Point?crs=epsg:4326&index=yes"), "test", "memory"
+ )
# Add some fields to the layer
- myFields = [QgsField('TestInt', QVariant.Int, 'integer', 2, 0),
- QgsField('TestLong', QVariant.LongLong, 'long', -1, 0),
- QgsField('TestDbl', QVariant.Double, 'double', 8, 6),
- QgsField('TestString', QVariant.String, 'string', 50, 0),
- QgsField('TestDate', QVariant.Date, 'date'),
- QgsField('TestTime', QVariant.Time, 'time'),
- QgsField('TestDateTime', QVariant.DateTime, 'datetime'),
- QgsField("vallist", QVariant.List, subType=QVariant.Int),
- QgsField("stringlist", QVariant.StringList, subType=QVariant.String),
- QgsField("stringlist2", QVariant.List, subType=QVariant.String),
- QgsField("reallist", QVariant.List, subType=QVariant.Double),
- QgsField("longlist", QVariant.List, subType=QVariant.LongLong),
- QgsField("dict", QVariant.Map),
- QgsField("geom", QVariant.UserType, typeName="geometry")]
+ myFields = [
+ QgsField("TestInt", QVariant.Int, "integer", 2, 0),
+ QgsField("TestLong", QVariant.LongLong, "long", -1, 0),
+ QgsField("TestDbl", QVariant.Double, "double", 8, 6),
+ QgsField("TestString", QVariant.String, "string", 50, 0),
+ QgsField("TestDate", QVariant.Date, "date"),
+ QgsField("TestTime", QVariant.Time, "time"),
+ QgsField("TestDateTime", QVariant.DateTime, "datetime"),
+ QgsField("vallist", QVariant.List, subType=QVariant.Int),
+ QgsField("stringlist", QVariant.StringList, subType=QVariant.String),
+ QgsField("stringlist2", QVariant.List, subType=QVariant.String),
+ QgsField("reallist", QVariant.List, subType=QVariant.Double),
+ QgsField("longlist", QVariant.List, subType=QVariant.LongLong),
+ QgsField("dict", QVariant.Map),
+ QgsField("geom", QVariant.UserType, typeName="geometry"),
+ ]
self.assertTrue(myMemoryLayer.startEditing())
for f in myFields:
self.assertTrue(myMemoryLayer.addAttribute(f))
@@ -438,11 +635,15 @@ def testSaveFields(self):
self.assertEqual(f, myMemoryLayer.fields().field(f.name()))
# Export the layer to a layer-definition-XML
- qlr = QgsLayerDefinition.exportLayerDefinitionLayers([myMemoryLayer], QgsReadWriteContext())
+ qlr = QgsLayerDefinition.exportLayerDefinitionLayers(
+ [myMemoryLayer], QgsReadWriteContext()
+ )
self.assertIsNotNone(qlr)
# Import the layer from the layer-definition-XML
- layers = QgsLayerDefinition.loadLayerDefinitionLayers(qlr, QgsReadWriteContext())
+ layers = QgsLayerDefinition.loadLayerDefinitionLayers(
+ qlr, QgsReadWriteContext()
+ )
self.assertTrue(layers)
myImportedLayer = layers[0]
self.assertIsNotNone(myImportedLayer)
@@ -451,11 +652,13 @@ def testSaveFields(self):
importedFields = myImportedLayer.fields()
for f in myFields:
self.assertEqual(f.name(), importedFields.field(f.name()).name())
- if f.name() != 'stringlist2':
+ if f.name() != "stringlist2":
self.assertEqual(f.type(), importedFields.field(f.name()).type())
else:
# we automatically convert List with String subtype to StringList, to match other data providers
- self.assertEqual(importedFields.field(f.name()).type(), QVariant.StringList)
+ self.assertEqual(
+ importedFields.field(f.name()).type(), QVariant.StringList
+ )
self.assertEqual(f.subType(), importedFields.field(f.name()).subType())
self.assertEqual(f.precision(), importedFields.field(f.name()).precision())
@@ -468,8 +671,8 @@ def testSaveFieldWithEditorWidget(self):
"""
layer = QgsVectorLayer("Point", "test", "memory")
- widget = QgsEditorWidgetSetup('ValueMap', {'map': {'key': 'value'}})
- field = QgsField('my_field', QVariant.String)
+ widget = QgsEditorWidgetSetup("ValueMap", {"map": {"key": "value"}})
+ field = QgsField("my_field", QVariant.String)
self.assertTrue(layer.startEditing())
@@ -484,39 +687,43 @@ def testRenameAttributes(self):
layer = QgsVectorLayer("Point", "test", "memory")
provider = layer.dataProvider()
- res = provider.addAttributes([QgsField("name", QVariant.String),
- QgsField("age", QVariant.Int),
- QgsField("size", QVariant.Double)])
+ res = provider.addAttributes(
+ [
+ QgsField("name", QVariant.String),
+ QgsField("age", QVariant.Int),
+ QgsField("size", QVariant.Double),
+ ]
+ )
layer.updateFields()
self.assertTrue(res)
ft = QgsFeature()
ft.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(10, 10)))
- ft.setAttributes(["Johny",
- 20,
- 0.3])
+ ft.setAttributes(["Johny", 20, 0.3])
res, t = provider.addFeatures([ft])
# bad rename
- self.assertFalse(provider.renameAttributes({-1: 'not_a_field'}))
- self.assertFalse(provider.renameAttributes({100: 'not_a_field'}))
+ self.assertFalse(provider.renameAttributes({-1: "not_a_field"}))
+ self.assertFalse(provider.renameAttributes({100: "not_a_field"}))
# already exists
- self.assertFalse(provider.renameAttributes({1: 'name'}))
+ self.assertFalse(provider.renameAttributes({1: "name"}))
# rename one field
- self.assertTrue(provider.renameAttributes({1: 'this_is_the_new_age'}))
- self.assertEqual(provider.fields().at(1).name(), 'this_is_the_new_age')
+ self.assertTrue(provider.renameAttributes({1: "this_is_the_new_age"}))
+ self.assertEqual(provider.fields().at(1).name(), "this_is_the_new_age")
layer.updateFields()
fet = next(layer.getFeatures())
- self.assertEqual(fet.fields()[1].name(), 'this_is_the_new_age')
+ self.assertEqual(fet.fields()[1].name(), "this_is_the_new_age")
# rename two fields
- self.assertTrue(provider.renameAttributes({1: 'mapinfo_is_the_stone_age', 2: 'super_size'}))
- self.assertEqual(provider.fields().at(1).name(), 'mapinfo_is_the_stone_age')
- self.assertEqual(provider.fields().at(2).name(), 'super_size')
+ self.assertTrue(
+ provider.renameAttributes({1: "mapinfo_is_the_stone_age", 2: "super_size"})
+ )
+ self.assertEqual(provider.fields().at(1).name(), "mapinfo_is_the_stone_age")
+ self.assertEqual(provider.fields().at(2).name(), "super_size")
layer.updateFields()
fet = next(layer.getFeatures())
- self.assertEqual(fet.fields()[1].name(), 'mapinfo_is_the_stone_age')
- self.assertEqual(fet.fields()[2].name(), 'super_size')
+ self.assertEqual(fet.fields()[1].name(), "mapinfo_is_the_stone_age")
+ self.assertEqual(fet.fields()[2].name(), "super_size")
def testUniqueSource(self):
"""
@@ -533,45 +740,60 @@ def testCreateMemoryLayer(self):
"""
# no fields
- layer = QgsMemoryProviderUtils.createMemoryLayer('my name', QgsFields())
+ layer = QgsMemoryProviderUtils.createMemoryLayer("my name", QgsFields())
self.assertTrue(layer.isValid())
- self.assertEqual(layer.name(), 'my name')
+ self.assertEqual(layer.name(), "my name")
self.assertTrue(layer.fields().isEmpty())
self.assertFalse(layer.dataProvider().crs().isValid())
# similar layers should have unique sources
- layer2 = QgsMemoryProviderUtils.createMemoryLayer('my name', QgsFields())
+ layer2 = QgsMemoryProviderUtils.createMemoryLayer("my name", QgsFields())
self.assertNotEqual(layer.source(), layer2.source())
# geometry type
- layer = QgsMemoryProviderUtils.createMemoryLayer('my name', QgsFields(), QgsWkbTypes.Type.Point)
+ layer = QgsMemoryProviderUtils.createMemoryLayer(
+ "my name", QgsFields(), QgsWkbTypes.Type.Point
+ )
self.assertTrue(layer.isValid())
self.assertEqual(layer.wkbType(), QgsWkbTypes.Type.Point)
- layer = QgsMemoryProviderUtils.createMemoryLayer('my name', QgsFields(), QgsWkbTypes.Type.PolygonZM)
+ layer = QgsMemoryProviderUtils.createMemoryLayer(
+ "my name", QgsFields(), QgsWkbTypes.Type.PolygonZM
+ )
self.assertTrue(layer.isValid())
self.assertEqual(layer.wkbType(), QgsWkbTypes.Type.PolygonZM)
# crs
- layer = QgsMemoryProviderUtils.createMemoryLayer('my name', QgsFields(), QgsWkbTypes.Type.PolygonZM,
- QgsCoordinateReferenceSystem.fromEpsgId(3111))
+ layer = QgsMemoryProviderUtils.createMemoryLayer(
+ "my name",
+ QgsFields(),
+ QgsWkbTypes.Type.PolygonZM,
+ QgsCoordinateReferenceSystem.fromEpsgId(3111),
+ )
self.assertTrue(layer.isValid())
self.assertEqual(layer.wkbType(), QgsWkbTypes.Type.PolygonZM)
self.assertTrue(layer.crs().isValid())
- self.assertEqual(layer.crs().authid(), 'EPSG:3111')
+ self.assertEqual(layer.crs().authid(), "EPSG:3111")
# custom CRS
crs = QgsCoordinateReferenceSystem.fromProj(
- '+proj=qsc +lat_0=0 +lon_0=0 +x_0=0 +y_0=0 +ellps=WGS84 +units=m +no_defs')
- layer = QgsMemoryProviderUtils.createMemoryLayer('my name', QgsFields(), QgsWkbTypes.Type.PolygonZM, crs)
+ "+proj=qsc +lat_0=0 +lon_0=0 +x_0=0 +y_0=0 +ellps=WGS84 +units=m +no_defs"
+ )
+ layer = QgsMemoryProviderUtils.createMemoryLayer(
+ "my name", QgsFields(), QgsWkbTypes.Type.PolygonZM, crs
+ )
self.assertTrue(layer.isValid())
self.assertTrue(layer.crs().isValid())
- self.assertEqual(layer.crs().toProj(),
- '+proj=qsc +lat_0=0 +lon_0=0 +x_0=0 +y_0=0 +ellps=WGS84 +units=m +no_defs +type=crs')
+ self.assertEqual(
+ layer.crs().toProj(),
+ "+proj=qsc +lat_0=0 +lon_0=0 +x_0=0 +y_0=0 +ellps=WGS84 +units=m +no_defs +type=crs",
+ )
# clone it, just to check
layer2 = layer.clone()
- self.assertEqual(layer2.crs().toProj(),
- '+proj=qsc +lat_0=0 +lon_0=0 +x_0=0 +y_0=0 +ellps=WGS84 +units=m +no_defs +type=crs')
+ self.assertEqual(
+ layer2.crs().toProj(),
+ "+proj=qsc +lat_0=0 +lon_0=0 +x_0=0 +y_0=0 +ellps=WGS84 +units=m +no_defs +type=crs",
+ )
# fields
fields = QgsFields()
@@ -587,35 +809,41 @@ def testCreateMemoryLayer(self):
fields.append(QgsField("binaryfield", QVariant.ByteArray))
fields.append(QgsField("boolfield", QVariant.Bool))
fields.append(QgsField("vallist", QVariant.List, subType=QVariant.Int))
- fields.append(QgsField("stringlist", QVariant.StringList, subType=QVariant.String))
+ fields.append(
+ QgsField("stringlist", QVariant.StringList, subType=QVariant.String)
+ )
fields.append(QgsField("stringlist2", QVariant.List, subType=QVariant.String))
fields.append(QgsField("reallist", QVariant.List, subType=QVariant.Double))
fields.append(QgsField("longlist", QVariant.List, subType=QVariant.LongLong))
fields.append(QgsField("dict", QVariant.Map))
fields.append(QgsField("geom", QVariant.UserType, typeName="geometry"))
- layer = QgsMemoryProviderUtils.createMemoryLayer('my name', fields)
+ layer = QgsMemoryProviderUtils.createMemoryLayer("my name", fields)
self.assertTrue(layer.isValid())
self.assertFalse(layer.fields().isEmpty())
self.assertEqual(len(layer.fields()), len(fields))
for i in range(len(fields)):
self.assertEqual(layer.fields()[i].name(), fields[i].name())
- if layer.fields()[i].name() != 'stringlist2':
+ if layer.fields()[i].name() != "stringlist2":
self.assertEqual(layer.fields()[i].type(), fields[i].type())
else:
# we automatically convert List with String subtype to StringList, to match other data providers
self.assertEqual(layer.fields()[i].type(), QVariant.StringList)
self.assertEqual(layer.fields()[i].length(), fields[i].length())
- self.assertEqual(layer.fields()[i].precision(), fields[i].precision(), fields[i].name())
+ self.assertEqual(
+ layer.fields()[i].precision(), fields[i].precision(), fields[i].name()
+ )
# unsupported field type
fields = QgsFields()
fields.append(QgsField("rect", QVariant.RectF))
- layer = QgsMemoryProviderUtils.createMemoryLayer('my name', fields)
+ layer = QgsMemoryProviderUtils.createMemoryLayer("my name", fields)
self.assertTrue(layer.isValid())
self.assertFalse(layer.fields().isEmpty())
- self.assertEqual(layer.fields()[0].name(), 'rect')
- self.assertEqual(layer.fields()[0].type(), QVariant.String) # should be mapped to string
+ self.assertEqual(layer.fields()[0].name(), "rect")
+ self.assertEqual(
+ layer.fields()[0].type(), QVariant.String
+ ) # should be mapped to string
# field precision
fields = QgsFields()
@@ -623,7 +851,7 @@ def testCreateMemoryLayer(self):
fields.append(QgsField("long", QVariant.LongLong, len=6))
fields.append(QgsField("double", QVariant.Double, len=10, prec=7))
fields.append(QgsField("double2", QVariant.Double, len=-1, prec=-1))
- layer = QgsMemoryProviderUtils.createMemoryLayer('my name', fields)
+ layer = QgsMemoryProviderUtils.createMemoryLayer("my name", fields)
self.assertTrue(layer.isValid())
self.assertFalse(layer.fields().isEmpty())
self.assertEqual(len(layer.fields()), len(fields))
@@ -638,7 +866,8 @@ def testChangeAttributeValuesInvalidFieldIndex(self):
Test there's no crash when changeAttributeValues is called with a non existing field index (https://github.com/qgis/QGIS/issues/54817)
"""
layer = QgsVectorLayer(
- 'Point?crs=epsg:4326&index=yes&field=pk:integer', 'test', 'memory')
+ "Point?crs=epsg:4326&index=yes&field=pk:integer", "test", "memory"
+ )
provider = layer.dataProvider()
f = QgsFeature()
f.setAttributes([0])
@@ -647,51 +876,69 @@ def testChangeAttributeValuesInvalidFieldIndex(self):
saved_feature = next(provider.getFeatures())
self.assertTrue(provider.changeAttributeValues({saved_feature.id(): {-1: 42}}))
self.assertTrue(provider.changeAttributeValues({saved_feature.id(): {42: 42}}))
- self.assertTrue(provider.changeAttributeValues({saved_feature.id(): {'fortytwo': 42}}))
+ self.assertTrue(
+ provider.changeAttributeValues({saved_feature.id(): {"fortytwo": 42}})
+ )
def testAddChangeFeatureConvertAttribute(self):
"""
Test add features with attribute values which require conversion
"""
layer = QgsVectorLayer(
- 'Point?crs=epsg:4326&index=yes&field=pk:integer&field=cnt:int8&field=dt:datetime', 'test', 'memory')
+ "Point?crs=epsg:4326&index=yes&field=pk:integer&field=cnt:int8&field=dt:datetime",
+ "test",
+ "memory",
+ )
provider = layer.dataProvider()
f = QgsFeature()
# string value specified for datetime field -- must be converted when adding the feature
- f.setAttributes([5, -200, '2021-02-10 00:00'])
+ f.setAttributes([5, -200, "2021-02-10 00:00"])
self.assertTrue(provider.addFeatures([f]))
saved_feature = next(provider.getFeatures())
# saved feature must have a QDateTime value for field, not string
- self.assertEqual(saved_feature.attributes(), [5, -200, QDateTime(2021, 2, 10, 0, 0)])
+ self.assertEqual(
+ saved_feature.attributes(), [5, -200, QDateTime(2021, 2, 10, 0, 0)]
+ )
- self.assertTrue(provider.changeAttributeValues({saved_feature.id(): {2: '2021-02-12 00:00'}}))
+ self.assertTrue(
+ provider.changeAttributeValues(
+ {saved_feature.id(): {2: "2021-02-12 00:00"}}
+ )
+ )
saved_feature = next(provider.getFeatures())
# saved feature must have a QDateTime value for field, not string
- self.assertEqual(saved_feature.attributes(), [5, -200, QDateTime(2021, 2, 12, 0, 0)])
+ self.assertEqual(
+ saved_feature.attributes(), [5, -200, QDateTime(2021, 2, 12, 0, 0)]
+ )
layer = QgsVectorLayer(
- 'Point?crs=epsg:4326&index=yes&field=pk:integer&field=geom:geometry', 'test', 'memory')
+ "Point?crs=epsg:4326&index=yes&field=pk:integer&field=geom:geometry",
+ "test",
+ "memory",
+ )
provider = layer.dataProvider()
f = QgsFeature()
# string value specified for geom field -- must be converted when adding the feature
- f.setAttributes([5, 'Point(1 2)'])
+ f.setAttributes([5, "Point(1 2)"])
self.assertTrue(provider.addFeatures([f]))
saved_feature = next(provider.getFeatures())
# saved feature must have a QgsGeometry value for field, not string
self.assertEqual(saved_feature.attributes()[0], 5)
- self.assertEqual(saved_feature.attributes()[1].asWkt(), 'Point (1 2)')
+ self.assertEqual(saved_feature.attributes()[1].asWkt(), "Point (1 2)")
def testThreadSafetyWithIndex(self):
layer = QgsVectorLayer(
- 'Point?crs=epsg:4326&index=yes&field=pk:integer&field=cnt:int8&field=name:string(0)&field=name2:string(0)&field=num_char:string&key=pk',
- 'test', 'memory')
+ "Point?crs=epsg:4326&index=yes&field=pk:integer&field=cnt:int8&field=name:string(0)&field=name2:string(0)&field=num_char:string&key=pk",
+ "test",
+ "memory",
+ )
provider = layer.dataProvider()
f = QgsFeature()
- f.setAttributes([5, -200, NULL, 'NuLl', '5'])
- f.setGeometry(QgsGeometry.fromWkt('Point (-71.123 78.23)'))
+ f.setAttributes([5, -200, NULL, "NuLl", "5"])
+ f.setGeometry(QgsGeometry.fromWkt("Point (-71.123 78.23)"))
for i in range(100000):
provider.addFeatures([f])
@@ -699,7 +946,9 @@ def testThreadSafetyWithIndex(self):
# filter rect request
extent = QgsRectangle(-73, 70, -63, 80)
request = QgsFeatureRequest().setFilterRect(extent)
- self.assertTrue(QgsTestUtils.testProviderIteratorThreadSafety(self.source, request))
+ self.assertTrue(
+ QgsTestUtils.testProviderIteratorThreadSafety(self.source, request)
+ )
def testMinMaxCache(self):
"""
@@ -707,8 +956,8 @@ def testMinMaxCache(self):
:return:
"""
vl = QgsVectorLayer(
- 'Point?crs=epsg:4326&field=f1:integer&field=f2:integer',
- 'test', 'memory')
+ "Point?crs=epsg:4326&field=f1:integer&field=f2:integer", "test", "memory"
+ )
self.assertTrue(vl.isValid())
f1 = QgsFeature()
@@ -748,7 +997,11 @@ def testMinMaxCache(self):
self.assertEqual(vl.dataProvider().maximumValue(1), 1400)
# change attribute values
- self.assertTrue(vl.dataProvider().changeAttributeValues({f6.id(): {0: 3, 1: 150}, f7.id(): {0: 4, 1: -100}}))
+ self.assertTrue(
+ vl.dataProvider().changeAttributeValues(
+ {f6.id(): {0: 3, 1: 150}, f7.id(): {0: 4, 1: -100}}
+ )
+ )
self.assertEqual(vl.dataProvider().minimumValue(0), 1)
self.assertEqual(vl.dataProvider().minimumValue(1), -200)
self.assertEqual(vl.dataProvider().maximumValue(0), 5)
@@ -768,18 +1021,18 @@ def testMinMaxCache(self):
def testBinary(self):
vl = QgsVectorLayer(
- 'Point?crs=epsg:4326&field=f1:integer&field=f2:binary',
- 'test', 'memory')
+ "Point?crs=epsg:4326&field=f1:integer&field=f2:binary", "test", "memory"
+ )
self.assertTrue(vl.isValid())
dp = vl.dataProvider()
fields = dp.fields()
- self.assertEqual([f.name() for f in fields], ['f1', 'f2'])
+ self.assertEqual([f.name() for f in fields], ["f1", "f2"])
self.assertEqual([f.type() for f in fields], [QVariant.Int, QVariant.ByteArray])
- self.assertEqual([f.typeName() for f in fields], ['integer', 'binary'])
+ self.assertEqual([f.typeName() for f in fields], ["integer", "binary"])
f = QgsFeature(dp.fields())
- bin_1 = b'xxx'
+ bin_1 = b"xxx"
bin_val1 = QByteArray(bin_1)
f.setAttributes([1, bin_val1])
self.assertTrue(dp.addFeature(f))
@@ -788,15 +1041,17 @@ def testBinary(self):
self.assertEqual(f2.attributes(), [1, bin_val1])
# add binary field
- self.assertTrue(dp.addAttributes([QgsField('binfield2', QVariant.ByteArray, 'Binary')]))
+ self.assertTrue(
+ dp.addAttributes([QgsField("binfield2", QVariant.ByteArray, "Binary")])
+ )
fields = dp.fields()
- bin2_field = fields[fields.lookupField('binfield2')]
+ bin2_field = fields[fields.lookupField("binfield2")]
self.assertEqual(bin2_field.type(), QVariant.ByteArray)
- self.assertEqual(bin2_field.typeName(), 'Binary')
+ self.assertEqual(bin2_field.typeName(), "Binary")
f = QgsFeature(fields)
- bin_2 = b'yyy'
+ bin_2 = b"yyy"
bin_val2 = QByteArray(bin_2)
f.setAttributes([2, NULL, bin_val2])
self.assertTrue(dp.addFeature(f))
@@ -808,15 +1063,15 @@ def testBinary(self):
def testBool(self):
vl = QgsVectorLayer(
- 'Point?crs=epsg:4326&field=f1:integer&field=f2:bool',
- 'test', 'memory')
+ "Point?crs=epsg:4326&field=f1:integer&field=f2:bool", "test", "memory"
+ )
self.assertTrue(vl.isValid())
dp = vl.dataProvider()
fields = dp.fields()
- self.assertEqual([f.name() for f in fields], ['f1', 'f2'])
+ self.assertEqual([f.name() for f in fields], ["f1", "f2"])
self.assertEqual([f.type() for f in fields], [QVariant.Int, QVariant.Bool])
- self.assertEqual([f.typeName() for f in fields], ['integer', 'boolean'])
+ self.assertEqual([f.typeName() for f in fields], ["integer", "boolean"])
f = QgsFeature(dp.fields())
f.setAttributes([1, True])
@@ -826,41 +1081,52 @@ def testBool(self):
f3.setAttributes([3, NULL])
self.assertTrue(dp.addFeatures([f, f2, f3]))
- self.assertEqual([f.attributes() for f in dp.getFeatures()], [[1, True], [2, False], [3, NULL]])
+ self.assertEqual(
+ [f.attributes() for f in dp.getFeatures()],
+ [[1, True], [2, False], [3, NULL]],
+ )
# add boolean field
- self.assertTrue(dp.addAttributes([QgsField('boolfield2', QVariant.Bool, 'Boolean')]))
+ self.assertTrue(
+ dp.addAttributes([QgsField("boolfield2", QVariant.Bool, "Boolean")])
+ )
fields = dp.fields()
- bool2_field = fields[fields.lookupField('boolfield2')]
+ bool2_field = fields[fields.lookupField("boolfield2")]
self.assertEqual(bool2_field.type(), QVariant.Bool)
- self.assertEqual(bool2_field.typeName(), 'Boolean')
+ self.assertEqual(bool2_field.typeName(), "Boolean")
f = QgsFeature(fields)
f.setAttributes([2, NULL, True])
self.assertTrue(dp.addFeature(f))
- self.assertEqual([f.attributes() for f in dp.getFeatures()],
- [[1, True, NULL], [2, False, NULL], [3, NULL, NULL], [2, NULL, True]])
+ self.assertEqual(
+ [f.attributes() for f in dp.getFeatures()],
+ [[1, True, NULL], [2, False, NULL], [3, NULL, NULL], [2, NULL, True]],
+ )
def testSpatialIndex(self):
vl = QgsVectorLayer(
- 'Point?crs=epsg:4326&field=f1:integer&field=f2:bool',
- 'test', 'memory')
- self.assertEqual(vl.hasSpatialIndex(), QgsFeatureSource.SpatialIndexPresence.SpatialIndexNotPresent)
+ "Point?crs=epsg:4326&field=f1:integer&field=f2:bool", "test", "memory"
+ )
+ self.assertEqual(
+ vl.hasSpatialIndex(),
+ QgsFeatureSource.SpatialIndexPresence.SpatialIndexNotPresent,
+ )
vl.dataProvider().createSpatialIndex()
- self.assertEqual(vl.hasSpatialIndex(), QgsFeatureSource.SpatialIndexPresence.SpatialIndexPresent)
+ self.assertEqual(
+ vl.hasSpatialIndex(),
+ QgsFeatureSource.SpatialIndexPresence.SpatialIndexPresent,
+ )
def testTypeValidation(self):
"""Test that incompatible types in attributes raise errors"""
- vl = QgsVectorLayer(
- 'Point?crs=epsg:4326&field=int:integer',
- 'test', 'memory')
+ vl = QgsVectorLayer("Point?crs=epsg:4326&field=int:integer", "test", "memory")
self.assertTrue(vl.isValid())
invalid = QgsFeature(vl.fields())
- invalid.setAttribute('int', 'A string')
- invalid.setGeometry(QgsGeometry.fromWkt('point(9 45)'))
+ invalid.setAttribute("int", "A string")
+ invalid.setGeometry(QgsGeometry.fromWkt("point(9 45)"))
self.assertTrue(vl.startEditing())
# Validation happens on commit
self.assertTrue(vl.addFeatures([invalid]))
@@ -870,19 +1136,17 @@ def testTypeValidation(self):
# Add a valid feature
valid = QgsFeature(vl.fields())
- valid.setAttribute('int', 123)
+ valid.setAttribute("int", 123)
self.assertTrue(vl.startEditing())
self.assertTrue(vl.addFeatures([valid]))
self.assertTrue(vl.commitChanges())
self.assertEqual(vl.featureCount(), 1)
f = vl.getFeature(1)
- self.assertEqual(f.attribute('int'), 123)
+ self.assertEqual(f.attribute("int"), 123)
# Add both
- vl = QgsVectorLayer(
- 'Point?crs=epsg:4326&field=int:integer',
- 'test', 'memory')
+ vl = QgsVectorLayer("Point?crs=epsg:4326&field=int:integer", "test", "memory")
self.assertEqual(vl.featureCount(), 0)
self.assertTrue(vl.startEditing())
self.assertTrue(vl.addFeatures([valid, invalid]))
@@ -892,9 +1156,7 @@ def testTypeValidation(self):
self.assertEqual(vl.featureCount(), 0)
# Add both swapped
- vl = QgsVectorLayer(
- 'Point?crs=epsg:4326&field=int:integer',
- 'test', 'memory')
+ vl = QgsVectorLayer("Point?crs=epsg:4326&field=int:integer", "test", "memory")
self.assertTrue(vl.startEditing())
self.assertTrue(vl.addFeatures([invalid, valid]))
self.assertFalse(vl.commitChanges())
@@ -903,65 +1165,59 @@ def testTypeValidation(self):
self.assertEqual(vl.featureCount(), 0)
# Change attribute value
- vl = QgsVectorLayer(
- 'Point?crs=epsg:4326&field=int:integer',
- 'test', 'memory')
+ vl = QgsVectorLayer("Point?crs=epsg:4326&field=int:integer", "test", "memory")
self.assertTrue(vl.startEditing())
self.assertTrue(vl.addFeatures([valid]))
self.assertTrue(vl.commitChanges())
self.assertTrue(vl.startEditing())
- self.assertTrue(vl.changeAttributeValue(1, 0, 'A string'))
+ self.assertTrue(vl.changeAttributeValue(1, 0, "A string"))
self.assertFalse(vl.commitChanges())
f = vl.getFeature(1)
- self.assertEqual(f.attribute('int'), 'A string')
+ self.assertEqual(f.attribute("int"), "A string")
self.assertTrue(vl.rollBack())
f = vl.getFeature(1)
- self.assertEqual(f.attribute('int'), 123)
+ self.assertEqual(f.attribute("int"), 123)
# Change attribute values
- vl = QgsVectorLayer(
- 'Point?crs=epsg:4326&field=int:integer',
- 'test', 'memory')
+ vl = QgsVectorLayer("Point?crs=epsg:4326&field=int:integer", "test", "memory")
self.assertTrue(vl.startEditing())
self.assertTrue(vl.addFeatures([valid]))
self.assertTrue(vl.commitChanges())
self.assertTrue(vl.startEditing())
- self.assertTrue(vl.changeAttributeValues(1, {0: 'A string'}))
+ self.assertTrue(vl.changeAttributeValues(1, {0: "A string"}))
self.assertFalse(vl.commitChanges())
f = vl.getFeature(1)
- self.assertEqual(f.attribute('int'), 'A string')
+ self.assertEqual(f.attribute("int"), "A string")
self.assertTrue(vl.rollBack())
f = vl.getFeature(1)
- self.assertEqual(f.attribute('int'), 123)
+ self.assertEqual(f.attribute("int"), 123)
##############################################
# Test direct data provider calls
# No rollback (old behavior)
- vl = QgsVectorLayer(
- 'Point?crs=epsg:4326&field=int:integer',
- 'test', 'memory')
+ vl = QgsVectorLayer("Point?crs=epsg:4326&field=int:integer", "test", "memory")
dp = vl.dataProvider()
self.assertFalse(dp.addFeatures([valid, invalid])[0])
self.assertEqual([f.attributes() for f in dp.getFeatures()], [[123]])
f = vl.getFeature(1)
- self.assertEqual(f.attribute('int'), 123)
+ self.assertEqual(f.attribute("int"), 123)
# Roll back
- vl = QgsVectorLayer(
- 'Point?crs=epsg:4326&field=int:integer',
- 'test', 'memory')
+ vl = QgsVectorLayer("Point?crs=epsg:4326&field=int:integer", "test", "memory")
dp = vl.dataProvider()
- self.assertFalse(dp.addFeatures([valid, invalid], QgsFeatureSink.Flag.RollBackOnErrors)[0])
+ self.assertFalse(
+ dp.addFeatures([valid, invalid], QgsFeatureSink.Flag.RollBackOnErrors)[0]
+ )
self.assertFalse(dp.hasFeatures())
# Expected behavior for changeAttributeValues is to always roll back
self.assertTrue(dp.addFeatures([valid])[0])
- self.assertFalse(dp.changeAttributeValues({1: {0: 'A string'}}))
+ self.assertFalse(dp.changeAttributeValues({1: {0: "A string"}}))
f = vl.getFeature(1)
- self.assertEqual(f.attribute('int'), 123)
+ self.assertEqual(f.attribute("int"), 123)
def testAddAttributes(self):
"""Test that fields with empty/invalid typenames are updated to native type names"""
@@ -970,20 +1226,24 @@ def testAddAttributes(self):
pr = vl.dataProvider()
# add fields
- pr.addAttributes([QgsField("name", QVariant.String),
- QgsField("age", QVariant.Int, "invalidInteger"),
- QgsField("size", QVariant.Double),
- QgsField("mytext", QVariant.String, "text"),
- QgsField("size2", QVariant.Double, "double precision"),
- QgsField("short", QVariant.Int, "int2"),
- QgsField("lessshort", QVariant.Int, "int4"),
- QgsField("numericfield", QVariant.Double, "numeric"),
- QgsField("decimalfield", QVariant.Double, "decimal"),
- QgsField("stringlistfield", QVariant.StringList, "stringlist"),
- QgsField("integerlistfield", QVariant.List, "integerlist"),
- QgsField("doublelistfield", QVariant.List, "doublelist"),
- QgsField("dict", QVariant.Map),
- QgsField("geom", QVariant.UserType, typeName="geometry")])
+ pr.addAttributes(
+ [
+ QgsField("name", QVariant.String),
+ QgsField("age", QVariant.Int, "invalidInteger"),
+ QgsField("size", QVariant.Double),
+ QgsField("mytext", QVariant.String, "text"),
+ QgsField("size2", QVariant.Double, "double precision"),
+ QgsField("short", QVariant.Int, "int2"),
+ QgsField("lessshort", QVariant.Int, "int4"),
+ QgsField("numericfield", QVariant.Double, "numeric"),
+ QgsField("decimalfield", QVariant.Double, "decimal"),
+ QgsField("stringlistfield", QVariant.StringList, "stringlist"),
+ QgsField("integerlistfield", QVariant.List, "integerlist"),
+ QgsField("doublelistfield", QVariant.List, "doublelist"),
+ QgsField("dict", QVariant.Map),
+ QgsField("geom", QVariant.UserType, typeName="geometry"),
+ ]
+ )
self.assertEqual(pr.fields()[0].typeName(), "string")
self.assertEqual(pr.fields()[1].typeName(), "integer")
@@ -1039,62 +1299,112 @@ class TestPyQgsMemoryProviderIndexed(QgisTestCase, ProviderTestCase):
@classmethod
def setUpClass(cls):
"""Run before all tests"""
- super(TestPyQgsMemoryProviderIndexed, cls).setUpClass()
+ super().setUpClass()
# Create test layer
cls.vl = QgsVectorLayer(
- 'Point?crs=epsg:4326&field=pk:integer&field=cnt:integer&field=name:string(0)&field=name2:string(0)&field=num_char:string&field=dt:datetime&field=date:date&field=time:time&key=pk',
- 'test', 'memory')
- assert (cls.vl.isValid())
+ "Point?crs=epsg:4326&field=pk:integer&field=cnt:integer&field=name:string(0)&field=name2:string(0)&field=num_char:string&field=dt:datetime&field=date:date&field=time:time&key=pk",
+ "test",
+ "memory",
+ )
+ assert cls.vl.isValid()
cls.source = cls.vl.dataProvider()
f1 = QgsFeature()
f1.setAttributes(
- [5, -200, NULL, 'NuLl', '5', QDateTime(QDate(2020, 5, 4), QTime(12, 13, 14)), QDate(2020, 5, 2),
- QTime(12, 13, 1)])
- f1.setGeometry(QgsGeometry.fromWkt('Point (-71.123 78.23)'))
+ [
+ 5,
+ -200,
+ NULL,
+ "NuLl",
+ "5",
+ QDateTime(QDate(2020, 5, 4), QTime(12, 13, 14)),
+ QDate(2020, 5, 2),
+ QTime(12, 13, 1),
+ ]
+ )
+ f1.setGeometry(QgsGeometry.fromWkt("Point (-71.123 78.23)"))
f2 = QgsFeature()
- f2.setAttributes([3, 300, 'Pear', 'PEaR', '3', NULL, NULL, NULL])
+ f2.setAttributes([3, 300, "Pear", "PEaR", "3", NULL, NULL, NULL])
f3 = QgsFeature()
f3.setAttributes(
- [1, 100, 'Orange', 'oranGe', '1', QDateTime(QDate(2020, 5, 3), QTime(12, 13, 14)), QDate(2020, 5, 3),
- QTime(12, 13, 14)])
- f3.setGeometry(QgsGeometry.fromWkt('Point (-70.332 66.33)'))
+ [
+ 1,
+ 100,
+ "Orange",
+ "oranGe",
+ "1",
+ QDateTime(QDate(2020, 5, 3), QTime(12, 13, 14)),
+ QDate(2020, 5, 3),
+ QTime(12, 13, 14),
+ ]
+ )
+ f3.setGeometry(QgsGeometry.fromWkt("Point (-70.332 66.33)"))
f4 = QgsFeature()
f4.setAttributes(
- [2, 200, 'Apple', 'Apple', '2', QDateTime(QDate(2020, 5, 4), QTime(12, 14, 14)), QDate(2020, 5, 4),
- QTime(12, 14, 14)])
- f4.setGeometry(QgsGeometry.fromWkt('Point (-68.2 70.8)'))
+ [
+ 2,
+ 200,
+ "Apple",
+ "Apple",
+ "2",
+ QDateTime(QDate(2020, 5, 4), QTime(12, 14, 14)),
+ QDate(2020, 5, 4),
+ QTime(12, 14, 14),
+ ]
+ )
+ f4.setGeometry(QgsGeometry.fromWkt("Point (-68.2 70.8)"))
f5 = QgsFeature()
f5.setAttributes(
- [4, 400, 'Honey', 'Honey', '4', QDateTime(QDate(2021, 5, 4), QTime(13, 13, 14)), QDate(2021, 5, 4),
- QTime(13, 13, 14)])
- f5.setGeometry(QgsGeometry.fromWkt('Point (-65.32 78.3)'))
+ [
+ 4,
+ 400,
+ "Honey",
+ "Honey",
+ "4",
+ QDateTime(QDate(2021, 5, 4), QTime(13, 13, 14)),
+ QDate(2021, 5, 4),
+ QTime(13, 13, 14),
+ ]
+ )
+ f5.setGeometry(QgsGeometry.fromWkt("Point (-65.32 78.3)"))
cls.source.addFeatures([f1, f2, f3, f4, f5])
# poly layer
- cls.poly_vl = QgsVectorLayer('Polygon?crs=epsg:4326&index=yes&field=pk:integer&key=pk',
- 'test', 'memory')
- assert (cls.poly_vl.isValid())
+ cls.poly_vl = QgsVectorLayer(
+ "Polygon?crs=epsg:4326&index=yes&field=pk:integer&key=pk", "test", "memory"
+ )
+ assert cls.poly_vl.isValid()
cls.poly_provider = cls.poly_vl.dataProvider()
f1 = QgsFeature()
f1.setAttributes([1])
- f1.setGeometry(QgsGeometry.fromWkt(
- 'Polygon ((-69.0 81.4, -69.0 80.2, -73.7 80.2, -73.7 76.3, -74.9 76.3, -74.9 81.4, -69.0 81.4))'))
+ f1.setGeometry(
+ QgsGeometry.fromWkt(
+ "Polygon ((-69.0 81.4, -69.0 80.2, -73.7 80.2, -73.7 76.3, -74.9 76.3, -74.9 81.4, -69.0 81.4))"
+ )
+ )
f2 = QgsFeature()
f2.setAttributes([2])
- f2.setGeometry(QgsGeometry.fromWkt('Polygon ((-67.6 81.2, -66.3 81.2, -66.3 76.9, -67.6 76.9, -67.6 81.2))'))
+ f2.setGeometry(
+ QgsGeometry.fromWkt(
+ "Polygon ((-67.6 81.2, -66.3 81.2, -66.3 76.9, -67.6 76.9, -67.6 81.2))"
+ )
+ )
f3 = QgsFeature()
f3.setAttributes([3])
- f3.setGeometry(QgsGeometry.fromWkt('Polygon ((-68.4 75.8, -67.5 72.6, -68.6 73.7, -70.2 72.9, -68.4 75.8))'))
+ f3.setGeometry(
+ QgsGeometry.fromWkt(
+ "Polygon ((-68.4 75.8, -67.5 72.6, -68.6 73.7, -70.2 72.9, -68.4 75.8))"
+ )
+ )
f4 = QgsFeature()
f4.setAttributes([4])
@@ -1102,17 +1412,17 @@ def setUpClass(cls):
cls.poly_provider.addFeatures([f1, f2, f3, f4])
def testGetFeaturesSubsetAttributes2(self):
- """ Override and skip this test for memory provider, as it's actually more efficient for the memory provider to return
+ """Override and skip this test for memory provider, as it's actually more efficient for the memory provider to return
its features as direct copies (due to implicit sharing of QgsFeature)
"""
pass
def testGetFeaturesNoGeometry(self):
- """ Override and skip this test for memory provider, as it's actually more efficient for the memory provider to return
+ """Override and skip this test for memory provider, as it's actually more efficient for the memory provider to return
its features as direct copies (due to implicit sharing of QgsFeature)
"""
pass
-if __name__ == '__main__':
+if __name__ == "__main__":
unittest.main()
diff --git a/tests/src/python/test_provider_mssql.py b/tests/src/python/test_provider_mssql.py
index 7969db95a052..dab797efbe60 100644
--- a/tests/src/python/test_provider_mssql.py
+++ b/tests/src/python/test_provider_mssql.py
@@ -5,9 +5,10 @@
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
"""
-__author__ = 'Nyall Dawson'
-__date__ = '2015-12-07'
-__copyright__ = 'Copyright 2015, The QGIS Project'
+
+__author__ = "Nyall Dawson"
+__date__ = "2015-12-07"
+__copyright__ = "Copyright 2015, The QGIS Project"
import os
@@ -46,35 +47,43 @@ class TestPyQgsMssqlProvider(QgisTestCase, ProviderTestCase):
@classmethod
def setUpClass(cls):
"""Run before all tests"""
- super(TestPyQgsMssqlProvider, cls).setUpClass()
+ super().setUpClass()
# These are the connection details for the SQL Server instance running on Travis
cls.dbconn = "service='testsqlserver' user=sa password='' "
- if 'QGIS_MSSQLTEST_DB' in os.environ:
- cls.dbconn = os.environ['QGIS_MSSQLTEST_DB']
+ if "QGIS_MSSQLTEST_DB" in os.environ:
+ cls.dbconn = os.environ["QGIS_MSSQLTEST_DB"]
# Create test layers
cls.vl = QgsVectorLayer(
- cls.dbconn + ' sslmode=disable key=\'pk\' srid=4326 type=POINT table="qgis_test"."someData" (geom) sql=',
- 'test', 'mssql')
- assert cls.vl.dataProvider() is not None, f"No data provider for {cls.vl.source()}"
+ cls.dbconn
+ + ' sslmode=disable key=\'pk\' srid=4326 type=POINT table="qgis_test"."someData" (geom) sql=',
+ "test",
+ "mssql",
+ )
+ assert (
+ cls.vl.dataProvider() is not None
+ ), f"No data provider for {cls.vl.source()}"
assert cls.vl.isValid(), cls.vl.dataProvider().error().message()
cls.source = cls.vl.dataProvider()
cls.poly_vl = QgsVectorLayer(
- cls.dbconn + ' sslmode=disable key=\'pk\' srid=4326 type=POLYGON table="qgis_test"."some_poly_data" (geom) sql=',
- 'test', 'mssql')
+ cls.dbconn
+ + ' sslmode=disable key=\'pk\' srid=4326 type=POLYGON table="qgis_test"."some_poly_data" (geom) sql=',
+ "test",
+ "mssql",
+ )
assert cls.poly_vl.isValid(), cls.poly_vl.dataProvider().error().message()
cls.poly_provider = cls.poly_vl.dataProvider()
# Triggers a segfault in the sql server odbc driver on Travis - TODO test with more recent Ubuntu base image
- if os.environ.get('QGIS_CONTINUOUS_INTEGRATION_RUN', 'true'):
+ if os.environ.get("QGIS_CONTINUOUS_INTEGRATION_RUN", "true"):
del cls.getEditableLayer
# Use connections API
- md = QgsProviderRegistry.instance().providerMetadata('mssql')
+ md = QgsProviderRegistry.instance().providerMetadata("mssql")
cls.conn_api = md.createConnection(cls.dbconn, {})
def setUp(self):
- for t in ['new_table', 'new_table_multipoint', 'new_table_multipolygon']:
- self.execSQLCommand(f'DROP TABLE IF EXISTS qgis_test.[{t}]')
+ for t in ["new_table", "new_table_multipoint", "new_table_multipolygon"]:
+ self.execSQLCommand(f"DROP TABLE IF EXISTS qgis_test.[{t}]")
def execSQLCommand(self, sql):
self.assertTrue(self.conn_api)
@@ -82,19 +91,25 @@ def execSQLCommand(self, sql):
def getSource(self):
# create temporary table for edit tests
- self.execSQLCommand('DROP TABLE IF EXISTS qgis_test.edit_data')
+ self.execSQLCommand("DROP TABLE IF EXISTS qgis_test.edit_data")
+ self.execSQLCommand(
+ """CREATE TABLE qgis_test.edit_data (pk INTEGER PRIMARY KEY,cnt integer, name nvarchar(max), name2 nvarchar(max), num_char nvarchar(max), dt datetime, [date] date, [time] time, geom geometry)"""
+ )
self.execSQLCommand(
- """CREATE TABLE qgis_test.edit_data (pk INTEGER PRIMARY KEY,cnt integer, name nvarchar(max), name2 nvarchar(max), num_char nvarchar(max), dt datetime, [date] date, [time] time, geom geometry)""")
- self.execSQLCommand("INSERT INTO [qgis_test].[edit_data] (pk, cnt, name, name2, num_char, dt, [date], [time], geom) VALUES "
- "(5, -200, NULL, 'NuLl', '5', '2020-05-04T12:13:14', '2020-05-02', '12:13:01', geometry::STGeomFromText('POINT(-71.123 78.23)', 4326)),"
- "(3, 300, 'Pear', 'PEaR', '3', NULL, NULL, NULL, NULL),"
- "(1, 100, 'Orange', 'oranGe', '1', '2020-05-03T12:13:14', '2020-05-03', '12:13:14', geometry::STGeomFromText('POINT(-70.332 66.33)', 4326)),"
- "(2, 200, 'Apple', 'Apple', '2', '2020-05-04T12:14:14', '2020-05-04', '12:14:14', geometry::STGeomFromText('POINT(-68.2 70.8)', 4326)),"
- "(4, 400, 'Honey', 'Honey', '4', '2021-05-04T13:13:14', '2021-05-04', '13:13:14', geometry::STGeomFromText('POINT(-65.32 78.3)', 4326))")
+ "INSERT INTO [qgis_test].[edit_data] (pk, cnt, name, name2, num_char, dt, [date], [time], geom) VALUES "
+ "(5, -200, NULL, 'NuLl', '5', '2020-05-04T12:13:14', '2020-05-02', '12:13:01', geometry::STGeomFromText('POINT(-71.123 78.23)', 4326)),"
+ "(3, 300, 'Pear', 'PEaR', '3', NULL, NULL, NULL, NULL),"
+ "(1, 100, 'Orange', 'oranGe', '1', '2020-05-03T12:13:14', '2020-05-03', '12:13:14', geometry::STGeomFromText('POINT(-70.332 66.33)', 4326)),"
+ "(2, 200, 'Apple', 'Apple', '2', '2020-05-04T12:14:14', '2020-05-04', '12:14:14', geometry::STGeomFromText('POINT(-68.2 70.8)', 4326)),"
+ "(4, 400, 'Honey', 'Honey', '4', '2021-05-04T13:13:14', '2021-05-04', '13:13:14', geometry::STGeomFromText('POINT(-65.32 78.3)', 4326))"
+ )
vl = QgsVectorLayer(
- self.dbconn + ' sslmode=disable key=\'pk\' srid=4326 type=POINT table="qgis_test"."edit_data" (geom) sql=',
- 'test', 'mssql')
+ self.dbconn
+ + ' sslmode=disable key=\'pk\' srid=4326 type=POINT table="qgis_test"."edit_data" (geom) sql=',
+ "test",
+ "mssql",
+ )
return vl
def testDeleteFeaturesPktInt(self):
@@ -120,30 +135,30 @@ def getEditableLayer(self):
return self.getSource()
def enableCompiler(self):
- QgsSettings().setValue('/qgis/compileExpressions', True)
+ QgsSettings().setValue("/qgis/compileExpressions", True)
return True
def disableCompiler(self):
- QgsSettings().setValue('/qgis/compileExpressions', False)
+ QgsSettings().setValue("/qgis/compileExpressions", False)
def partiallyCompiledFilters(self):
filters = {
- 'name ILIKE \'QGIS\'',
- 'name = \'Apple\'',
- '\"NaMe\" = \'Apple\'',
- 'name = \'apple\'',
- 'name LIKE \'Apple\'',
- 'name LIKE \'aPple\'',
- 'name ILIKE \'aPple\'',
- 'name LIKE \'Ap_le\'',
- 'name LIKE \'Ap\\_le\'',
- 'name ILIKE \'%pp%\'',
- '"name" || \' \' || "name" = \'Orange Orange\'',
- '"name" || \' \' || "cnt" = \'Orange 100\'',
+ "name ILIKE 'QGIS'",
+ "name = 'Apple'",
+ "\"NaMe\" = 'Apple'",
+ "name = 'apple'",
+ "name LIKE 'Apple'",
+ "name LIKE 'aPple'",
+ "name ILIKE 'aPple'",
+ "name LIKE 'Ap_le'",
+ "name LIKE 'Ap\\_le'",
+ "name ILIKE '%pp%'",
+ "\"name\" || ' ' || \"name\" = 'Orange Orange'",
+ "\"name\" || ' ' || \"cnt\" = 'Orange 100'",
'"name"="name2"',
- 'lower(name) = \'apple\'',
- 'upper(name) = \'APPLE\'',
- 'name = trim(\' Apple \')'
+ "lower(name) = 'apple'",
+ "upper(name) = 'APPLE'",
+ "name = trim(' Apple ')",
}
return filters
@@ -151,147 +166,159 @@ def uncompiledFilters(self):
filters = {
'"name" IS NULL',
'"name" IS NOT NULL',
- '"name" NOT LIKE \'Ap%\'',
- '"name" NOT ILIKE \'QGIS\'',
- '"name" NOT ILIKE \'pEAR\'',
- 'name <> \'Apple\'',
- '"name" <> \'apple\'',
- '(name = \'Apple\') is not null',
- '\'x\' || "name" IS NOT NULL',
- '\'x\' || "name" IS NULL',
- '"name" ~ \'[OP]ra[gne]+\'',
- 'false and NULL',
- 'true and NULL',
- 'NULL and false',
- 'NULL and true',
- 'NULL and NULL',
- 'false or NULL',
- 'true or NULL',
- 'NULL or false',
- 'NULL or true',
- 'NULL or NULL',
- 'not null',
- 'not name = \'Apple\'',
- 'not name IS NULL',
- 'not name = \'Apple\' or name = \'Apple\'',
- 'not name = \'Apple\' or not name = \'Apple\'',
- 'not name = \'Apple\' and pk = 4',
- 'not name = \'Apple\' and not pk = 4',
- 'pk = coalesce(NULL,3,4)',
- 'x($geometry) < -70',
- 'y($geometry) > 70',
- 'xmin($geometry) < -70',
- 'ymin($geometry) > 70',
- 'xmax($geometry) < -70',
- 'ymax($geometry) > 70',
- 'disjoint($geometry,geom_from_wkt( \'Polygon ((-72.2 66.1, -65.2 66.1, -65.2 72.0, -72.2 72.0, -72.2 66.1))\'))',
- 'intersects($geometry,geom_from_wkt( \'Polygon ((-72.2 66.1, -65.2 66.1, -65.2 72.0, -72.2 72.0, -72.2 66.1))\'))',
- 'contains(geom_from_wkt( \'Polygon ((-72.2 66.1, -65.2 66.1, -65.2 72.0, -72.2 72.0, -72.2 66.1))\'),$geometry)',
- 'distance($geometry,geom_from_wkt( \'Point (-70 70)\')) > 7',
- 'intersects($geometry,geom_from_gml( \'-72.2,66.1 -65.2,66.1 -65.2,72.0 -72.2,72.0 -72.2,66.1 \'))',
- 'x($geometry) < -70',
- 'y($geometry) > 79',
- 'xmin($geometry) < -70',
- 'ymin($geometry) < 76',
- 'xmax($geometry) > -68',
- 'ymax($geometry) > 80',
- 'area($geometry) > 10',
- 'perimeter($geometry) < 12',
- 'relate($geometry,geom_from_wkt( \'Polygon ((-68.2 82.1, -66.95 82.1, -66.95 79.05, -68.2 79.05, -68.2 82.1))\')) = \'FF2FF1212\'',
- 'relate($geometry,geom_from_wkt( \'Polygon ((-68.2 82.1, -66.95 82.1, -66.95 79.05, -68.2 79.05, -68.2 82.1))\'), \'****F****\')',
- 'crosses($geometry,geom_from_wkt( \'Linestring (-68.2 82.1, -66.95 82.1, -66.95 79.05)\'))',
- 'overlaps($geometry,geom_from_wkt( \'Polygon ((-68.2 82.1, -66.95 82.1, -66.95 79.05, -68.2 79.05, -68.2 82.1))\'))',
- 'within($geometry,geom_from_wkt( \'Polygon ((-75.1 76.1, -75.1 81.6, -68.8 81.6, -68.8 76.1, -75.1 76.1))\'))',
- 'overlaps(translate($geometry,-1,-1),geom_from_wkt( \'Polygon ((-75.1 76.1, -75.1 81.6, -68.8 81.6, -68.8 76.1, -75.1 76.1))\'))',
- 'overlaps(buffer($geometry,1),geom_from_wkt( \'Polygon ((-75.1 76.1, -75.1 81.6, -68.8 81.6, -68.8 76.1, -75.1 76.1))\'))',
- 'intersects(centroid($geometry),geom_from_wkt( \'Polygon ((-74.4 78.2, -74.4 79.1, -66.8 79.1, -66.8 78.2, -74.4 78.2))\'))',
- 'intersects(point_on_surface($geometry),geom_from_wkt( \'Polygon ((-74.4 78.2, -74.4 79.1, -66.8 79.1, -66.8 78.2, -74.4 78.2))\'))',
- '"dt" = to_datetime(\'000www14ww13ww12www4ww5ww2020\',\'zzzwwwsswwmmwwhhwwwdwwMwwyyyy\')',
- '"date" = to_date(\'www4ww5ww2020\',\'wwwdwwMwwyyyy\')',
- '"time" = to_time(\'000www14ww13ww12www\',\'zzzwwwsswwmmwwhhwww\')'
+ "\"name\" NOT LIKE 'Ap%'",
+ "\"name\" NOT ILIKE 'QGIS'",
+ "\"name\" NOT ILIKE 'pEAR'",
+ "name <> 'Apple'",
+ "\"name\" <> 'apple'",
+ "(name = 'Apple') is not null",
+ "'x' || \"name\" IS NOT NULL",
+ "'x' || \"name\" IS NULL",
+ "\"name\" ~ '[OP]ra[gne]+'",
+ "false and NULL",
+ "true and NULL",
+ "NULL and false",
+ "NULL and true",
+ "NULL and NULL",
+ "false or NULL",
+ "true or NULL",
+ "NULL or false",
+ "NULL or true",
+ "NULL or NULL",
+ "not null",
+ "not name = 'Apple'",
+ "not name IS NULL",
+ "not name = 'Apple' or name = 'Apple'",
+ "not name = 'Apple' or not name = 'Apple'",
+ "not name = 'Apple' and pk = 4",
+ "not name = 'Apple' and not pk = 4",
+ "pk = coalesce(NULL,3,4)",
+ "x($geometry) < -70",
+ "y($geometry) > 70",
+ "xmin($geometry) < -70",
+ "ymin($geometry) > 70",
+ "xmax($geometry) < -70",
+ "ymax($geometry) > 70",
+ "disjoint($geometry,geom_from_wkt( 'Polygon ((-72.2 66.1, -65.2 66.1, -65.2 72.0, -72.2 72.0, -72.2 66.1))'))",
+ "intersects($geometry,geom_from_wkt( 'Polygon ((-72.2 66.1, -65.2 66.1, -65.2 72.0, -72.2 72.0, -72.2 66.1))'))",
+ "contains(geom_from_wkt( 'Polygon ((-72.2 66.1, -65.2 66.1, -65.2 72.0, -72.2 72.0, -72.2 66.1))'),$geometry)",
+ "distance($geometry,geom_from_wkt( 'Point (-70 70)')) > 7",
+ "intersects($geometry,geom_from_gml( '-72.2,66.1 -65.2,66.1 -65.2,72.0 -72.2,72.0 -72.2,66.1 '))",
+ "x($geometry) < -70",
+ "y($geometry) > 79",
+ "xmin($geometry) < -70",
+ "ymin($geometry) < 76",
+ "xmax($geometry) > -68",
+ "ymax($geometry) > 80",
+ "area($geometry) > 10",
+ "perimeter($geometry) < 12",
+ "relate($geometry,geom_from_wkt( 'Polygon ((-68.2 82.1, -66.95 82.1, -66.95 79.05, -68.2 79.05, -68.2 82.1))')) = 'FF2FF1212'",
+ "relate($geometry,geom_from_wkt( 'Polygon ((-68.2 82.1, -66.95 82.1, -66.95 79.05, -68.2 79.05, -68.2 82.1))'), '****F****')",
+ "crosses($geometry,geom_from_wkt( 'Linestring (-68.2 82.1, -66.95 82.1, -66.95 79.05)'))",
+ "overlaps($geometry,geom_from_wkt( 'Polygon ((-68.2 82.1, -66.95 82.1, -66.95 79.05, -68.2 79.05, -68.2 82.1))'))",
+ "within($geometry,geom_from_wkt( 'Polygon ((-75.1 76.1, -75.1 81.6, -68.8 81.6, -68.8 76.1, -75.1 76.1))'))",
+ "overlaps(translate($geometry,-1,-1),geom_from_wkt( 'Polygon ((-75.1 76.1, -75.1 81.6, -68.8 81.6, -68.8 76.1, -75.1 76.1))'))",
+ "overlaps(buffer($geometry,1),geom_from_wkt( 'Polygon ((-75.1 76.1, -75.1 81.6, -68.8 81.6, -68.8 76.1, -75.1 76.1))'))",
+ "intersects(centroid($geometry),geom_from_wkt( 'Polygon ((-74.4 78.2, -74.4 79.1, -66.8 79.1, -66.8 78.2, -74.4 78.2))'))",
+ "intersects(point_on_surface($geometry),geom_from_wkt( 'Polygon ((-74.4 78.2, -74.4 79.1, -66.8 79.1, -66.8 78.2, -74.4 78.2))'))",
+ "\"dt\" = to_datetime('000www14ww13ww12www4ww5ww2020','zzzwwwsswwmmwwhhwwwdwwMwwyyyy')",
+ "\"date\" = to_date('www4ww5ww2020','wwwdwwMwwyyyy')",
+ "\"time\" = to_time('000www14ww13ww12www','zzzwwwsswwmmwwhhwww')",
}
return filters
def testGetFeaturesUncompiled(self):
- if os.environ.get('QGIS_CONTINUOUS_INTEGRATION_RUN', 'true'):
+ if os.environ.get("QGIS_CONTINUOUS_INTEGRATION_RUN", "true"):
return
super().testGetFeaturesUncompiled()
def testGetFeaturesExp(self):
- if os.environ.get('QGIS_CONTINUOUS_INTEGRATION_RUN', 'true'):
+ if os.environ.get("QGIS_CONTINUOUS_INTEGRATION_RUN", "true"):
return
super().testGetFeaturesExp()
def testOrderBy(self):
- if os.environ.get('QGIS_CONTINUOUS_INTEGRATION_RUN', 'true'):
+ if os.environ.get("QGIS_CONTINUOUS_INTEGRATION_RUN", "true"):
return
super().testOrderBy()
def testOrderByCompiled(self):
- if os.environ.get('QGIS_CONTINUOUS_INTEGRATION_RUN', 'true'):
+ if os.environ.get("QGIS_CONTINUOUS_INTEGRATION_RUN", "true"):
return
super().testOrderByCompiled()
# HERE GO THE PROVIDER SPECIFIC TESTS
def testDateTimeTypes(self):
- vl = QgsVectorLayer('%s table="qgis_test"."date_times" sql=' %
- (self.dbconn), "testdatetimes", "mssql")
+ vl = QgsVectorLayer(
+ '%s table="qgis_test"."date_times" sql=' % (self.dbconn),
+ "testdatetimes",
+ "mssql",
+ )
self.assertTrue(vl.isValid())
fields = vl.dataProvider().fields()
- self.assertEqual(fields.at(fields.indexFromName(
- 'date_field')).type(), QVariant.Date)
- self.assertEqual(fields.at(fields.indexFromName(
- 'time_field')).type(), QVariant.Time)
- self.assertEqual(fields.at(fields.indexFromName(
- 'datetime_field')).type(), QVariant.DateTime)
+ self.assertEqual(
+ fields.at(fields.indexFromName("date_field")).type(), QVariant.Date
+ )
+ self.assertEqual(
+ fields.at(fields.indexFromName("time_field")).type(), QVariant.Time
+ )
+ self.assertEqual(
+ fields.at(fields.indexFromName("datetime_field")).type(), QVariant.DateTime
+ )
f = next(vl.getFeatures(QgsFeatureRequest()))
- date_idx = vl.fields().lookupField('date_field')
+ date_idx = vl.fields().lookupField("date_field")
self.assertIsInstance(f.attributes()[date_idx], QDate)
self.assertEqual(f.attributes()[date_idx], QDate(2004, 3, 4))
- time_idx = vl.fields().lookupField('time_field')
+ time_idx = vl.fields().lookupField("time_field")
self.assertIsInstance(f.attributes()[time_idx], QTime)
self.assertEqual(f.attributes()[time_idx], QTime(13, 41, 52))
- datetime_idx = vl.fields().lookupField('datetime_field')
+ datetime_idx = vl.fields().lookupField("datetime_field")
self.assertIsInstance(f.attributes()[datetime_idx], QDateTime)
- self.assertEqual(f.attributes()[datetime_idx], QDateTime(
- QDate(2004, 3, 4), QTime(13, 41, 52)))
+ self.assertEqual(
+ f.attributes()[datetime_idx],
+ QDateTime(QDate(2004, 3, 4), QTime(13, 41, 52)),
+ )
def testFloatDecimalFields(self):
- vl = QgsVectorLayer('%s table="qgis_test"."float_dec" sql=' %
- (self.dbconn), "testprec", "mssql")
+ vl = QgsVectorLayer(
+ '%s table="qgis_test"."float_dec" sql=' % (self.dbconn), "testprec", "mssql"
+ )
self.assertTrue(vl.isValid())
fields = vl.dataProvider().fields()
- self.assertEqual(fields.at(fields.indexFromName(
- 'float_field')).type(), QVariant.Double)
- self.assertEqual(fields.at(fields.indexFromName(
- 'float_field')).length(), 15)
- self.assertEqual(fields.at(fields.indexFromName(
- 'float_field')).precision(), -1)
-
- self.assertEqual(fields.at(fields.indexFromName(
- 'dec_field')).type(), QVariant.Double)
- self.assertEqual(fields.at(fields.indexFromName(
- 'dec_field')).length(), 7)
- self.assertEqual(fields.at(fields.indexFromName(
- 'dec_field')).precision(), 3)
+ self.assertEqual(
+ fields.at(fields.indexFromName("float_field")).type(), QVariant.Double
+ )
+ self.assertEqual(fields.at(fields.indexFromName("float_field")).length(), 15)
+ self.assertEqual(fields.at(fields.indexFromName("float_field")).precision(), -1)
+
+ self.assertEqual(
+ fields.at(fields.indexFromName("dec_field")).type(), QVariant.Double
+ )
+ self.assertEqual(fields.at(fields.indexFromName("dec_field")).length(), 7)
+ self.assertEqual(fields.at(fields.indexFromName("dec_field")).precision(), 3)
f = next(vl.getFeatures(QgsFeatureRequest()))
- float_idx = vl.fields().lookupField('float_field')
+ float_idx = vl.fields().lookupField("float_field")
self.assertIsInstance(f.attributes()[float_idx], float)
self.assertAlmostEqual(f.attributes()[float_idx], 1.1111111111, 5)
- dec_idx = vl.fields().lookupField('dec_field')
+ dec_idx = vl.fields().lookupField("dec_field")
self.assertIsInstance(f.attributes()[dec_idx], float)
self.assertEqual(f.attributes()[dec_idx], 1.123)
- @unittest.skipIf(os.environ.get('QGIS_CONTINUOUS_INTEGRATION_RUN', 'true'), 'Failing on Travis')
+ @unittest.skipIf(
+ os.environ.get("QGIS_CONTINUOUS_INTEGRATION_RUN", "true"), "Failing on Travis"
+ )
def testCreateLayer(self):
- layer = QgsVectorLayer("Point?field=id:integer&field=fldtxt:string&field=fldint:integer",
- "addfeat", "memory")
+ layer = QgsVectorLayer(
+ "Point?field=id:integer&field=fldtxt:string&field=fldint:integer",
+ "addfeat",
+ "memory",
+ )
pr = layer.dataProvider()
f = QgsFeature()
f.setAttributes([1, "test", 1])
@@ -307,111 +334,163 @@ def testCreateLayer(self):
pr.addFeatures([f, f2, f3, f4])
uri = f'{self.dbconn} table="qgis_test"."new_table" sql='
- error, message = QgsVectorLayerExporter.exportLayer(layer, uri, 'mssql',
- QgsCoordinateReferenceSystem('EPSG:4326'))
+ error, message = QgsVectorLayerExporter.exportLayer(
+ layer, uri, "mssql", QgsCoordinateReferenceSystem("EPSG:4326")
+ )
self.assertEqual(error, QgsVectorLayerExporter.ExportError.NoError)
- new_layer = QgsVectorLayer(uri, 'new', 'mssql')
+ new_layer = QgsVectorLayer(uri, "new", "mssql")
self.assertTrue(new_layer.isValid())
self.assertEqual(new_layer.wkbType(), QgsWkbTypes.Type.Point)
- self.assertEqual([f.name() for f in new_layer.fields()], ['qgs_fid', 'id', 'fldtxt', 'fldint'])
+ self.assertEqual(
+ [f.name() for f in new_layer.fields()],
+ ["qgs_fid", "id", "fldtxt", "fldint"],
+ )
features = [f.attributes() for f in new_layer.getFeatures()]
- self.assertEqual(features, [[1, 1, 'test', 1],
- [2, 2, 'test2', 3],
- [3, 3, 'test2', NULL],
- [4, 4, NULL, 3]])
+ self.assertEqual(
+ features,
+ [
+ [1, 1, "test", 1],
+ [2, 2, "test2", 3],
+ [3, 3, "test2", NULL],
+ [4, 4, NULL, 3],
+ ],
+ )
geom = [f.geometry().asWkt() for f in new_layer.getFeatures()]
- self.assertEqual(geom, ['Point (1 2)', '', 'Point (3 2)', 'Point (4 3)'])
+ self.assertEqual(geom, ["Point (1 2)", "", "Point (3 2)", "Point (4 3)"])
- @unittest.skipIf(os.environ.get('QGIS_CONTINUOUS_INTEGRATION_RUN', 'true'), 'Failing on Travis')
+ @unittest.skipIf(
+ os.environ.get("QGIS_CONTINUOUS_INTEGRATION_RUN", "true"), "Failing on Travis"
+ )
def testCreateLayerMultiPoint(self):
- layer = QgsVectorLayer("MultiPoint?crs=epsg:3111&field=id:integer&field=fldtxt:string&field=fldint:integer",
- "addfeat", "memory")
+ layer = QgsVectorLayer(
+ "MultiPoint?crs=epsg:3111&field=id:integer&field=fldtxt:string&field=fldint:integer",
+ "addfeat",
+ "memory",
+ )
pr = layer.dataProvider()
f = QgsFeature()
f.setAttributes([1, "test", 1])
- f.setGeometry(QgsGeometry.fromWkt('MultiPoint(1 2, 3 4)'))
+ f.setGeometry(QgsGeometry.fromWkt("MultiPoint(1 2, 3 4)"))
f2 = QgsFeature()
f2.setAttributes([2, "test2", 3])
f3 = QgsFeature()
f3.setAttributes([3, "test2", NULL])
- f3.setGeometry(QgsGeometry.fromWkt('MultiPoint(7 8)'))
+ f3.setGeometry(QgsGeometry.fromWkt("MultiPoint(7 8)"))
pr.addFeatures([f, f2, f3])
uri = f'{self.dbconn} table="qgis_test"."new_table_multipoint" sql='
- error, message = QgsVectorLayerExporter.exportLayer(layer, uri, 'mssql',
- QgsCoordinateReferenceSystem('EPSG:3111'))
+ error, message = QgsVectorLayerExporter.exportLayer(
+ layer, uri, "mssql", QgsCoordinateReferenceSystem("EPSG:3111")
+ )
self.assertEqual(error, QgsVectorLayerExporter.ExportError.NoError)
- new_layer = QgsVectorLayer(uri, 'new', 'mssql')
+ new_layer = QgsVectorLayer(uri, "new", "mssql")
self.assertTrue(new_layer.isValid())
self.assertEqual(new_layer.wkbType(), QgsWkbTypes.Type.MultiPoint)
- self.assertEqual(new_layer.crs().authid(), 'EPSG:3111')
- self.assertEqual([f.name() for f in new_layer.fields()], ['qgs_fid', 'id', 'fldtxt', 'fldint'])
+ self.assertEqual(new_layer.crs().authid(), "EPSG:3111")
+ self.assertEqual(
+ [f.name() for f in new_layer.fields()],
+ ["qgs_fid", "id", "fldtxt", "fldint"],
+ )
features = [f.attributes() for f in new_layer.getFeatures()]
- self.assertEqual(features, [[1, 1, 'test', 1],
- [2, 2, 'test2', 3],
- [3, 3, 'test2', NULL]])
+ self.assertEqual(
+ features, [[1, 1, "test", 1], [2, 2, "test2", 3], [3, 3, "test2", NULL]]
+ )
geom = [f.geometry().asWkt() for f in new_layer.getFeatures()]
- self.assertEqual(geom, ['MultiPoint ((1 2),(3 4))', '', 'MultiPoint ((7 8))'])
+ self.assertEqual(geom, ["MultiPoint ((1 2),(3 4))", "", "MultiPoint ((7 8))"])
- @unittest.skipIf(os.environ.get('QGIS_CONTINUOUS_INTEGRATION_RUN', 'true'), 'Failing on Travis')
+ @unittest.skipIf(
+ os.environ.get("QGIS_CONTINUOUS_INTEGRATION_RUN", "true"), "Failing on Travis"
+ )
def testCurveGeometries(self):
- geomtypes = ['CompoundCurveM', 'CurvePolygonM', 'CircularStringM', 'CompoundCurveZM', 'CurvePolygonZM',
- 'CircularStringZM', 'CompoundCurveZ', 'CurvePolygonZ', 'CircularStringZ', 'CompoundCurve',
- 'CurvePolygon', 'CircularString']
+ geomtypes = [
+ "CompoundCurveM",
+ "CurvePolygonM",
+ "CircularStringM",
+ "CompoundCurveZM",
+ "CurvePolygonZM",
+ "CircularStringZM",
+ "CompoundCurveZ",
+ "CurvePolygonZ",
+ "CircularStringZ",
+ "CompoundCurve",
+ "CurvePolygon",
+ "CircularString",
+ ]
geoms = [
- 'CompoundCurveM ((0 -23.43778 10, 0 23.43778 10),CircularStringM (0 23.43778 10, -45 33.43778 10, -90 23.43778 10),(-90 23.43778 10, -90 -23.43778 10),CircularStringM (-90 -23.43778 10, -45 -23.43778 10, 0 -23.43778 10))',
- 'CurvePolygonM (CompoundCurveM ((0 -23.43778 10, 0 -15.43778 10, 0 23.43778 10),CircularStringM (0 23.43778 10, -45 100 10, -90 23.43778 10),(-90 23.43778 10, -90 -23.43778 10),CircularStringM (-90 -23.43778 10, -45 -16.43778 10, 0 -23.43778 10)),CompoundCurveM (CircularStringM (-30 0 10, -48 -12 10, -60 0 10, -48 -6 10, -30 0 10)))',
- 'CircularStringM (0 0 10, 0.14644660940672 0.35355339059327 10, 0.5 0.5 10, 0.85355339059327 0.35355339059327 10, 1 0 10, 0.85355339059327 -0.35355339059327 10, 0.5 -0.5 10, 0.14644660940672 -0.35355339059327 10, 0 0 10)',
- 'CompoundCurveZM ((0 -23.43778 2 10, 0 23.43778 2 10),CircularStringZM (0 23.43778 2 10, -45 33.43778 2 10, -90 23.43778 2 10),(-90 23.43778 2 10, -90 -23.43778 2 10),CircularStringZM (-90 -23.43778 2 10, -45 -23.43778 2 10, 0 -23.43778 2 10))',
- 'CurvePolygonZM (CompoundCurveZM ((0 -23.43778 5 10, 0 -15.43778 8 10, 0 23.43778 6 10),CircularStringZM (0 23.43778 6 10, -45 100 6 10, -90 23.43778 6 10),(-90 23.43778 6 10, -90 -23.43778 5 10),CircularStringZM (-90 -23.43778 5 10, -45 -16.43778 5 10, 0 -23.43778 5 10)),CompoundCurveZM (CircularStringZM (-30 0 10 10, -48 -12 10 10, -60 0 10 10, -48 -6 10 10, -30 0 10 10)))',
- 'CircularStringZM (0 0 1 10, 0.14644660940672 0.35355339059327 1 10, 0.5 0.5 1 10, 0.85355339059327 0.35355339059327 1 10, 1 0 1 10, 0.85355339059327 -0.35355339059327 1 10, 0.5 -0.5 1 10, 0.14644660940672 -0.35355339059327 1 10, 0 0 1 10)',
- 'CompoundCurveZ ((0 -23.43778 2, 0 23.43778 2),CircularStringZ (0 23.43778 2, -45 33.43778 2, -90 23.43778 2),(-90 23.43778 2, -90 -23.43778 2),CircularStringZ (-90 -23.43778 2, -45 -23.43778 2, 0 -23.43778 2))',
- 'CurvePolygonZ (CompoundCurveZ ((0 -23.43778 5, 0 -15.43778 8, 0 23.43778 6),CircularStringZ (0 23.43778 6, -45 100 6, -90 23.43778 6),(-90 23.43778 6, -90 -23.43778 5),CircularStringZ (-90 -23.43778 5, -45 -16.43778 5, 0 -23.43778 5)),CompoundCurveZ (CircularStringZ (-30 0 10, -48 -12 10, -60 0 10, -48 -6 10, -30 0 10)))',
- 'CircularStringZ (0 0 1, 0.14644660940672 0.35355339059327 1, 0.5 0.5 1, 0.85355339059327 0.35355339059327 1, 1 0 1, 0.85355339059327 -0.35355339059327 1, 0.5 -0.5 1, 0.14644660940672 -0.35355339059327 1, 0 0 1)',
- 'CompoundCurve ((0 -23.43778, 0 23.43778),CircularString (0 23.43778, -45 33.43778, -90 23.43778),(-90 23.43778, -90 -23.43778),CircularString (-90 -23.43778, -45 -23.43778, 0 -23.43778))',
- 'CurvePolygon (CompoundCurve ((0 -23.43778, 0 -15.43778, 0 23.43778),CircularString (0 23.43778, -45 100, -90 23.43778),(-90 23.43778, -90 -23.43778),CircularString (-90 -23.43778, -45 -16.43778, 0 -23.43778)),CompoundCurve (CircularString (-30 0, -48 -12, -60 0, -48 -6, -30 0)))',
- 'CircularString (0 0, 0.14644660940672 0.35355339059327, 0.5 0.5, 0.85355339059327 0.35355339059327, 1 0, 0.85355339059327 -0.35355339059327, 0.5 -0.5, 0.14644660940672 -0.35355339059327, 0 0)']
+ "CompoundCurveM ((0 -23.43778 10, 0 23.43778 10),CircularStringM (0 23.43778 10, -45 33.43778 10, -90 23.43778 10),(-90 23.43778 10, -90 -23.43778 10),CircularStringM (-90 -23.43778 10, -45 -23.43778 10, 0 -23.43778 10))",
+ "CurvePolygonM (CompoundCurveM ((0 -23.43778 10, 0 -15.43778 10, 0 23.43778 10),CircularStringM (0 23.43778 10, -45 100 10, -90 23.43778 10),(-90 23.43778 10, -90 -23.43778 10),CircularStringM (-90 -23.43778 10, -45 -16.43778 10, 0 -23.43778 10)),CompoundCurveM (CircularStringM (-30 0 10, -48 -12 10, -60 0 10, -48 -6 10, -30 0 10)))",
+ "CircularStringM (0 0 10, 0.14644660940672 0.35355339059327 10, 0.5 0.5 10, 0.85355339059327 0.35355339059327 10, 1 0 10, 0.85355339059327 -0.35355339059327 10, 0.5 -0.5 10, 0.14644660940672 -0.35355339059327 10, 0 0 10)",
+ "CompoundCurveZM ((0 -23.43778 2 10, 0 23.43778 2 10),CircularStringZM (0 23.43778 2 10, -45 33.43778 2 10, -90 23.43778 2 10),(-90 23.43778 2 10, -90 -23.43778 2 10),CircularStringZM (-90 -23.43778 2 10, -45 -23.43778 2 10, 0 -23.43778 2 10))",
+ "CurvePolygonZM (CompoundCurveZM ((0 -23.43778 5 10, 0 -15.43778 8 10, 0 23.43778 6 10),CircularStringZM (0 23.43778 6 10, -45 100 6 10, -90 23.43778 6 10),(-90 23.43778 6 10, -90 -23.43778 5 10),CircularStringZM (-90 -23.43778 5 10, -45 -16.43778 5 10, 0 -23.43778 5 10)),CompoundCurveZM (CircularStringZM (-30 0 10 10, -48 -12 10 10, -60 0 10 10, -48 -6 10 10, -30 0 10 10)))",
+ "CircularStringZM (0 0 1 10, 0.14644660940672 0.35355339059327 1 10, 0.5 0.5 1 10, 0.85355339059327 0.35355339059327 1 10, 1 0 1 10, 0.85355339059327 -0.35355339059327 1 10, 0.5 -0.5 1 10, 0.14644660940672 -0.35355339059327 1 10, 0 0 1 10)",
+ "CompoundCurveZ ((0 -23.43778 2, 0 23.43778 2),CircularStringZ (0 23.43778 2, -45 33.43778 2, -90 23.43778 2),(-90 23.43778 2, -90 -23.43778 2),CircularStringZ (-90 -23.43778 2, -45 -23.43778 2, 0 -23.43778 2))",
+ "CurvePolygonZ (CompoundCurveZ ((0 -23.43778 5, 0 -15.43778 8, 0 23.43778 6),CircularStringZ (0 23.43778 6, -45 100 6, -90 23.43778 6),(-90 23.43778 6, -90 -23.43778 5),CircularStringZ (-90 -23.43778 5, -45 -16.43778 5, 0 -23.43778 5)),CompoundCurveZ (CircularStringZ (-30 0 10, -48 -12 10, -60 0 10, -48 -6 10, -30 0 10)))",
+ "CircularStringZ (0 0 1, 0.14644660940672 0.35355339059327 1, 0.5 0.5 1, 0.85355339059327 0.35355339059327 1, 1 0 1, 0.85355339059327 -0.35355339059327 1, 0.5 -0.5 1, 0.14644660940672 -0.35355339059327 1, 0 0 1)",
+ "CompoundCurve ((0 -23.43778, 0 23.43778),CircularString (0 23.43778, -45 33.43778, -90 23.43778),(-90 23.43778, -90 -23.43778),CircularString (-90 -23.43778, -45 -23.43778, 0 -23.43778))",
+ "CurvePolygon (CompoundCurve ((0 -23.43778, 0 -15.43778, 0 23.43778),CircularString (0 23.43778, -45 100, -90 23.43778),(-90 23.43778, -90 -23.43778),CircularString (-90 -23.43778, -45 -16.43778, 0 -23.43778)),CompoundCurve (CircularString (-30 0, -48 -12, -60 0, -48 -6, -30 0)))",
+ "CircularString (0 0, 0.14644660940672 0.35355339059327, 0.5 0.5, 0.85355339059327 0.35355339059327, 1 0, 0.85355339059327 -0.35355339059327, 0.5 -0.5, 0.14644660940672 -0.35355339059327, 0 0)",
+ ]
for idx, t in enumerate(geoms):
f = QgsFeature()
g = QgsGeometry.fromWkt(t)
f.setGeometry(g)
- layer = QgsVectorLayer(geomtypes[idx] + "?crs=epsg:4326", "addfeat", "memory")
+ layer = QgsVectorLayer(
+ geomtypes[idx] + "?crs=epsg:4326", "addfeat", "memory"
+ )
pr = layer.dataProvider()
pr.addFeatures([f])
- uri = self.dbconn + ' table="qgis_test"."new_table_curvegeom_' + str(idx) + '" sql='
- error, message = QgsVectorLayerExporter.exportLayer(layer, uri, 'mssql',
- QgsCoordinateReferenceSystem('EPSG:4326'))
+ uri = (
+ self.dbconn
+ + ' table="qgis_test"."new_table_curvegeom_'
+ + str(idx)
+ + '" sql='
+ )
+ error, message = QgsVectorLayerExporter.exportLayer(
+ layer, uri, "mssql", QgsCoordinateReferenceSystem("EPSG:4326")
+ )
self.assertEqual(error, QgsVectorLayerExporter.ExportError.NoError)
- new_layer = QgsVectorLayer(uri, 'new', 'mssql')
+ new_layer = QgsVectorLayer(uri, "new", "mssql")
self.assertTrue(new_layer.isValid())
self.assertEqual(new_layer.wkbType(), g.wkbType())
- self.assertEqual(new_layer.crs().authid(), 'EPSG:4326')
+ self.assertEqual(new_layer.crs().authid(), "EPSG:4326")
result_geoms = [f.geometry().asWkt(14) for f in new_layer.getFeatures()]
self.assertEqual(result_geoms, [t])
- self.execSQLCommand(f'DROP TABLE IF EXISTS [qgis_test].[new_table_curvegeom_{str(idx)}]')
+ self.execSQLCommand(
+ f"DROP TABLE IF EXISTS [qgis_test].[new_table_curvegeom_{str(idx)}]"
+ )
def testStyle(self):
- self.execSQLCommand('DROP TABLE IF EXISTS layer_styles')
+ self.execSQLCommand("DROP TABLE IF EXISTS layer_styles")
- res, err = QgsProviderRegistry.instance().styleExists('mssql', 'not valid', '')
+ res, err = QgsProviderRegistry.instance().styleExists("mssql", "not valid", "")
self.assertFalse(res)
self.assertTrue(err)
vl = self.getSource()
self.assertTrue(vl.isValid())
- self.assertEqual(int(vl.dataProvider().styleStorageCapabilities()) & Qgis.ProviderStyleStorageCapability.LoadFromDatabase, Qgis.ProviderStyleStorageCapability.LoadFromDatabase)
- self.assertEqual(int(vl.dataProvider().styleStorageCapabilities()) & Qgis.ProviderStyleStorageCapability.SaveToDatabase, Qgis.ProviderStyleStorageCapability.SaveToDatabase)
+ self.assertEqual(
+ int(vl.dataProvider().styleStorageCapabilities())
+ & Qgis.ProviderStyleStorageCapability.LoadFromDatabase,
+ Qgis.ProviderStyleStorageCapability.LoadFromDatabase,
+ )
+ self.assertEqual(
+ int(vl.dataProvider().styleStorageCapabilities())
+ & Qgis.ProviderStyleStorageCapability.SaveToDatabase,
+ Qgis.ProviderStyleStorageCapability.SaveToDatabase,
+ )
# table layer_styles does not exist
- res, err = QgsProviderRegistry.instance().styleExists('mssql', vl.source(), '')
+ res, err = QgsProviderRegistry.instance().styleExists("mssql", vl.source(), "")
self.assertFalse(res)
self.assertFalse(err)
- res, err = QgsProviderRegistry.instance().styleExists('mssql', vl.source(), 'a style')
+ res, err = QgsProviderRegistry.instance().styleExists(
+ "mssql", vl.source(), "a style"
+ )
self.assertFalse(res)
self.assertFalse(err)
@@ -427,22 +506,28 @@ def testStyle(self):
self.assertTrue(errmsg)
mFilePath = QDir.toNativeSeparators(
- f"{unitTestDataPath()}/symbol_layer/singleSymbol.qml")
+ f"{unitTestDataPath()}/symbol_layer/singleSymbol.qml"
+ )
status = vl.loadNamedStyle(mFilePath)
self.assertTrue(status)
# The style is saved as non-default
errorMsg = vl.saveStyleToDatabase(
- "by day", "faded greens and elegant patterns", False, "")
+ "by day", "faded greens and elegant patterns", False, ""
+ )
self.assertFalse(errorMsg)
- res, err = QgsProviderRegistry.instance().styleExists('mssql', vl.source(), '')
+ res, err = QgsProviderRegistry.instance().styleExists("mssql", vl.source(), "")
self.assertFalse(res)
self.assertFalse(err)
- res, err = QgsProviderRegistry.instance().styleExists('mssql', vl.source(), 'a style')
+ res, err = QgsProviderRegistry.instance().styleExists(
+ "mssql", vl.source(), "a style"
+ )
self.assertFalse(res)
self.assertFalse(err)
- res, err = QgsProviderRegistry.instance().styleExists('mssql', vl.source(), 'by day')
+ res, err = QgsProviderRegistry.instance().styleExists(
+ "mssql", vl.source(), "by day"
+ )
self.assertTrue(res)
self.assertFalse(err)
@@ -463,30 +548,40 @@ def testStyle(self):
self.assertTrue(errmsg)
qml, errmsg = vl.getStyleFromDatabase("1")
- self.assertTrue(qml.startswith(' 100 and [cnt] < 410'
+ return "[cnt] > 100 and [cnt] < 410"
def getSubsetString2(self):
- return '[cnt] > 100 and [cnt] < 400'
+ return "[cnt] > 100 and [cnt] < 400"
def getSubsetString3(self):
- return '[name]=\'Apple\''
+ return "[name]='Apple'"
def getSubsetStringNoMatching(self):
- return '[name]=\'AppleBearOrangePear\''
+ return "[name]='AppleBearOrangePear'"
def testExtentFromGeometryTable(self):
"""
Check if the behavior of the mssql provider if extent is defined in the geometry_column table
"""
# Create a layer
- layer = QgsVectorLayer("Point?field=id:integer&field=fldtxt:string&field=fldint:integer",
- "layer", "memory")
+ layer = QgsVectorLayer(
+ "Point?field=id:integer&field=fldtxt:string&field=fldint:integer",
+ "layer",
+ "memory",
+ )
pr = layer.dataProvider()
f1 = QgsFeature()
f1.setAttributes([1, "test", 1])
@@ -908,63 +1187,87 @@ def testExtentFromGeometryTable(self):
f4.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(4, 3)))
pr.addFeatures([f1, f2, f3, f4])
uri = f'{self.dbconn} table="qgis_test"."layer_extent_in_geometry_table" sql='
- QgsVectorLayerExporter.exportLayer(layer, uri, 'mssql', QgsCoordinateReferenceSystem('EPSG:4326'))
+ QgsVectorLayerExporter.exportLayer(
+ layer, uri, "mssql", QgsCoordinateReferenceSystem("EPSG:4326")
+ )
layerUri = QgsDataSourceUri(uri)
# Load and check if the layer is valid
loadedLayer = QgsVectorLayer(layerUri.uri(), "valid", "mssql")
self.assertTrue(loadedLayer.isValid())
extent = loadedLayer.extent()
- self.assertEqual(extent.toString(1),
- QgsRectangle(1.0, 2.0, 4.0, 3.0).toString(1))
+ self.assertEqual(
+ extent.toString(1), QgsRectangle(1.0, 2.0, 4.0, 3.0).toString(1)
+ )
# Load with flag extent in geometry_columns table and check if the layer is still valid and extent doesn't change
- layerUri.setParam('extentInGeometryColumns', '1')
+ layerUri.setParam("extentInGeometryColumns", "1")
loadedLayer = QgsVectorLayer(layerUri.uri(), "invalid", "mssql")
self.assertTrue(loadedLayer.isValid())
extent = loadedLayer.extent()
- self.assertEqual(extent.toString(1),
- QgsRectangle(1.0, 2.0, 4.0, 3.0).toString(1))
+ self.assertEqual(
+ extent.toString(1), QgsRectangle(1.0, 2.0, 4.0, 3.0).toString(1)
+ )
- md = QgsProviderRegistry.instance().providerMetadata('mssql')
+ md = QgsProviderRegistry.instance().providerMetadata("mssql")
conn = md.createConnection(self.dbconn, {})
- conn.addField(QgsField('qgis_xmin', QVariant.Double, 'FLOAT(24)'), 'dbo', 'geometry_columns')
- conn.addField(QgsField('qgis_xmax', QVariant.Double, 'FLOAT(24)'), 'dbo', 'geometry_columns')
- conn.addField(QgsField('qgis_ymin', QVariant.Double, 'FLOAT(24)'), 'dbo', 'geometry_columns')
- conn.addField(QgsField('qgis_ymax', QVariant.Double, 'FLOAT(24)'), 'dbo', 'geometry_columns')
+ conn.addField(
+ QgsField("qgis_xmin", QVariant.Double, "FLOAT(24)"),
+ "dbo",
+ "geometry_columns",
+ )
+ conn.addField(
+ QgsField("qgis_xmax", QVariant.Double, "FLOAT(24)"),
+ "dbo",
+ "geometry_columns",
+ )
+ conn.addField(
+ QgsField("qgis_ymin", QVariant.Double, "FLOAT(24)"),
+ "dbo",
+ "geometry_columns",
+ )
+ conn.addField(
+ QgsField("qgis_ymax", QVariant.Double, "FLOAT(24)"),
+ "dbo",
+ "geometry_columns",
+ )
# try with empty attribute
- layerUri.setParam('extentInGeometryColumns', '1')
+ layerUri.setParam("extentInGeometryColumns", "1")
loadedLayer = QgsVectorLayer(layerUri.uri(), "invalid", "mssql")
self.assertTrue(loadedLayer.isValid())
self.assertTrue(loadedLayer.isValid())
extent = loadedLayer.extent()
- self.assertEqual(extent.toString(1),
- QgsRectangle(1.0, 2.0, 4.0, 3.0).toString(1))
+ self.assertEqual(
+ extent.toString(1), QgsRectangle(1.0, 2.0, 4.0, 3.0).toString(1)
+ )
- conn.execSql('UPDATE dbo.geometry_columns SET qgis_xmin=0, qgis_xmax=5.5, qgis_ymin=0.5, qgis_ymax=6 WHERE f_table_name=\'layer_extent_in_geometry_table\'')
+ conn.execSql(
+ "UPDATE dbo.geometry_columns SET qgis_xmin=0, qgis_xmax=5.5, qgis_ymin=0.5, qgis_ymax=6 WHERE f_table_name='layer_extent_in_geometry_table'"
+ )
# try with valid attribute
- layerUri.setParam('extentInGeometryColumns', '1')
+ layerUri.setParam("extentInGeometryColumns", "1")
loadedLayer = QgsVectorLayer(layerUri.uri(), "valid", "mssql")
self.assertTrue(loadedLayer.isValid())
extent = loadedLayer.extent()
- self.assertEqual(extent.toString(1),
- QgsRectangle(0.0, 0.5, 5.5, 6.0).toString(1))
+ self.assertEqual(
+ extent.toString(1), QgsRectangle(0.0, 0.5, 5.5, 6.0).toString(1)
+ )
def test_insert_pk_escaping(self):
"""
Test that inserting features works with complex pk name
see https://github.com/qgis/QGIS/issues/42290
"""
- md = QgsProviderRegistry.instance().providerMetadata('mssql')
+ md = QgsProviderRegistry.instance().providerMetadata("mssql")
conn = md.createConnection(self.dbconn, {})
- conn.execSql('DROP TABLE IF EXISTS qgis_test.test_complex_pk_name')
- conn.execSql('CREATE TABLE qgis_test.test_complex_pk_name ([test-field] int)')
+ conn.execSql("DROP TABLE IF EXISTS qgis_test.test_complex_pk_name")
+ conn.execSql("CREATE TABLE qgis_test.test_complex_pk_name ([test-field] int)")
uri = f'{self.dbconn} table="qgis_test"."test_complex_pk_name" sql='
- vl = QgsVectorLayer(uri, '', 'mssql')
+ vl = QgsVectorLayer(uri, "", "mssql")
self.assertTrue(vl.isValid())
self.assertEqual(vl.primaryKeyAttributes(), [0])
@@ -975,27 +1278,33 @@ def test_insert_pk_escaping(self):
self.assertTrue(vl.addFeature(f))
self.assertTrue(vl.commitChanges())
- vl = QgsVectorLayer(uri, '', 'mssql')
+ vl = QgsVectorLayer(uri, "", "mssql")
features = list(vl.getFeatures())
- self.assertEqual([f['test-field'] for f in features], [1])
+ self.assertEqual([f["test-field"] for f in features], [1])
def test_nvarchar_length(self):
"""
Test that nvarchar length is correctly set
"""
- md = QgsProviderRegistry.instance().providerMetadata('mssql')
+ md = QgsProviderRegistry.instance().providerMetadata("mssql")
conn = md.createConnection(self.dbconn, {})
- conn.execSql('DROP TABLE IF EXISTS qgis_test.test_nvarchar_length')
- conn.execSql('CREATE TABLE qgis_test.test_nvarchar_length (id integer PRIMARY KEY)')
+ conn.execSql("DROP TABLE IF EXISTS qgis_test.test_nvarchar_length")
+ conn.execSql(
+ "CREATE TABLE qgis_test.test_nvarchar_length (id integer PRIMARY KEY)"
+ )
uri = f'{self.dbconn} table="qgis_test"."test_nvarchar_length" sql='
- vl = QgsVectorLayer(uri, '', 'mssql')
+ vl = QgsVectorLayer(uri, "", "mssql")
self.assertTrue(vl.isValid())
- self.assertTrue(vl.dataProvider().addAttributes([QgsField('name', QMetaType.Type.QString, 'nvarchar', 12)]))
+ self.assertTrue(
+ vl.dataProvider().addAttributes(
+ [QgsField("name", QMetaType.Type.QString, "nvarchar", 12)]
+ )
+ )
self.assertEqual(vl.dataProvider().fields().at(1).length(), 12)
-if __name__ == '__main__':
+if __name__ == "__main__":
unittest.main()
diff --git a/tests/src/python/test_provider_oapif.py b/tests/src/python/test_provider_oapif.py
index 47b8d42d8f5b..1cbc6578d7c9 100644
--- a/tests/src/python/test_provider_oapif.py
+++ b/tests/src/python/test_provider_oapif.py
@@ -5,9 +5,10 @@
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
"""
-__author__ = 'Even Rouault'
-__date__ = '2019-10-12'
-__copyright__ = 'Copyright 2019, Even Rouault'
+
+__author__ = "Even Rouault"
+__date__ = "2019-10-12"
+__copyright__ = "Copyright 2019, Even Rouault"
import copy
import hashlib
@@ -43,11 +44,13 @@ def sanitize(endpoint, query_params):
url = endpoint + query_params
# For REST API using URL subpaths, normalize the subpaths
- afterEndpointStartPos = url.find("fake_qgis_http_endpoint") + len("fake_qgis_http_endpoint")
+ afterEndpointStartPos = url.find("fake_qgis_http_endpoint") + len(
+ "fake_qgis_http_endpoint"
+ )
afterEndpointStart = url[afterEndpointStartPos:]
- afterEndpointStart = afterEndpointStart.replace('/', '_')
+ afterEndpointStart = afterEndpointStart.replace("/", "_")
url = url[0:afterEndpointStartPos] + afterEndpointStart
- posQuotationMark = url.find('?')
+ posQuotationMark = url.find("?")
endpoint = url[0:posQuotationMark]
query_params = url[posQuotationMark:]
@@ -56,23 +59,28 @@ def sanitize(endpoint, query_params):
# print('Before: ' + endpoint + query_params)
# print('After: ' + ret)
return ret
- ret = endpoint + query_params.replace('?', '_').replace('&', '_').replace('<', '_').replace('>', '_').replace('"',
- '_').replace("'",
- '_').replace(
- ' ', '_').replace(':', '_').replace('/', '_').replace('\n', '_')
+ ret = endpoint + query_params.replace("?", "_").replace("&", "_").replace(
+ "<", "_"
+ ).replace(">", "_").replace('"', "_").replace("'", "_").replace(" ", "_").replace(
+ ":", "_"
+ ).replace(
+ "/", "_"
+ ).replace(
+ "\n", "_"
+ )
return ret
def GDAL_COMPUTE_VERSION(maj, min, rev):
- return ((maj) * 1000000 + (min) * 10000 + (rev) * 100)
+ return (maj) * 1000000 + (min) * 10000 + (rev) * 100
-ACCEPT_LANDING = 'Accept=application/json'
-ACCEPT_API = 'Accept=application/vnd.oai.openapi+json;version=3.0, application/openapi+json;version=3.0, application/json'
-ACCEPT_COLLECTION = 'Accept=application/json'
-ACCEPT_CONFORMANCE = 'Accept=application/json'
-ACCEPT_ITEMS = 'Accept=application/geo+json, application/json'
-ACCEPT_QUERYABLES = 'Accept=application/schema+json'
+ACCEPT_LANDING = "Accept=application/json"
+ACCEPT_API = "Accept=application/vnd.oai.openapi+json;version=3.0, application/openapi+json;version=3.0, application/json"
+ACCEPT_COLLECTION = "Accept=application/json"
+ACCEPT_CONFORMANCE = "Accept=application/json"
+ACCEPT_ITEMS = "Accept=application/geo+json, application/json"
+ACCEPT_QUERYABLES = "Accept=application/schema+json"
def mergeDict(d1, d2):
@@ -85,63 +93,97 @@ def mergeDict(d1, d2):
return res
-def create_landing_page_api_collection(endpoint,
- extraparam='',
- storageCrs=None,
- crsList=None,
- bbox=[-71.123, 66.33, -65.32, 78.3],
- additionalApiResponse={},
- additionalConformance=[]):
+def create_landing_page_api_collection(
+ endpoint,
+ extraparam="",
+ storageCrs=None,
+ crsList=None,
+ bbox=[-71.123, 66.33, -65.32, 78.3],
+ additionalApiResponse={},
+ additionalConformance=[],
+):
- questionmark_extraparam = '?' + extraparam if extraparam else ''
+ questionmark_extraparam = "?" + extraparam if extraparam else ""
def add_params(x, y):
if x:
- return x + '&' + y
+ return x + "&" + y
return y
# Landing page
- with open(sanitize(endpoint, '?' + add_params(extraparam, ACCEPT_LANDING)), 'wb') as f:
- f.write(json.dumps({
- "links": [
- {"href": "http://" + endpoint + "/api" + questionmark_extraparam, "rel": "service-desc"},
- {"href": "http://" + endpoint + "/collections" + questionmark_extraparam, "rel": "data"},
- {"href": "http://" + endpoint + "/conformance" + questionmark_extraparam, "rel": "conformance"},
- ]}).encode('UTF-8'))
+ with open(
+ sanitize(endpoint, "?" + add_params(extraparam, ACCEPT_LANDING)), "wb"
+ ) as f:
+ f.write(
+ json.dumps(
+ {
+ "links": [
+ {
+ "href": "http://"
+ + endpoint
+ + "/api"
+ + questionmark_extraparam,
+ "rel": "service-desc",
+ },
+ {
+ "href": "http://"
+ + endpoint
+ + "/collections"
+ + questionmark_extraparam,
+ "rel": "data",
+ },
+ {
+ "href": "http://"
+ + endpoint
+ + "/conformance"
+ + questionmark_extraparam,
+ "rel": "conformance",
+ },
+ ]
+ }
+ ).encode("UTF-8")
+ )
# API
- with open(sanitize(endpoint, '/api?' + add_params(extraparam, ACCEPT_API)), 'wb') as f:
- j = mergeDict(additionalApiResponse, {"components": {
- "parameters": {
- "limit": {
- "schema": {
- "maximum": 1000,
- "default": 100
+ with open(
+ sanitize(endpoint, "/api?" + add_params(extraparam, ACCEPT_API)), "wb"
+ ) as f:
+ j = mergeDict(
+ additionalApiResponse,
+ {
+ "components": {
+ "parameters": {
+ "limit": {"schema": {"maximum": 1000, "default": 100}}
}
}
- }
- }
- })
- f.write(json.dumps(j).encode('UTF-8'))
+ },
+ )
+ f.write(json.dumps(j).encode("UTF-8"))
# conformance
- with open(sanitize(endpoint, '/conformance?' + add_params(extraparam, ACCEPT_CONFORMANCE)), 'wb') as f:
- f.write(json.dumps({
- "conformsTo": ["http://www.opengis.net/spec/ogcapi-features-2/1.0/conf/crs"] + additionalConformance
- }).encode('UTF-8'))
+ with open(
+ sanitize(
+ endpoint, "/conformance?" + add_params(extraparam, ACCEPT_CONFORMANCE)
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ json.dumps(
+ {
+ "conformsTo": [
+ "http://www.opengis.net/spec/ogcapi-features-2/1.0/conf/crs"
+ ]
+ + additionalConformance
+ }
+ ).encode("UTF-8")
+ )
# collection
collection = {
"id": "mycollection",
"title": "my title",
"description": "my description",
- "extent": {
- "spatial": {
- "bbox": [
- bbox
- ]
- }
- }
+ "extent": {"spatial": {"bbox": [bbox]}},
}
if bbox is None:
del collection["extent"]
@@ -150,12 +192,20 @@ def add_params(x, y):
if crsList:
collection["crs"] = crsList
- with open(sanitize(endpoint, '/collections/mycollection?' + add_params(extraparam, ACCEPT_COLLECTION)), 'wb') as f:
- f.write(json.dumps(collection).encode('UTF-8'))
+ with open(
+ sanitize(
+ endpoint,
+ "/collections/mycollection?" + add_params(extraparam, ACCEPT_COLLECTION),
+ ),
+ "wb",
+ ) as f:
+ f.write(json.dumps(collection).encode("UTF-8"))
# Options
- with open(sanitize(endpoint, '/collections/mycollection/items?VERB=OPTIONS'), 'wb') as f:
- f.write("HEAD, GET".encode("UTF-8"))
+ with open(
+ sanitize(endpoint, "/collections/mycollection/items?VERB=OPTIONS"), "wb"
+ ) as f:
+ f.write(b"HEAD, GET")
class TestPyQgsOapifProvider(QgisTestCase, ProviderTestCase):
@@ -163,7 +213,7 @@ class TestPyQgsOapifProvider(QgisTestCase, ProviderTestCase):
@classmethod
def setUpClass(cls):
"""Run before all tests"""
- super(TestPyQgsOapifProvider, cls).setUpClass()
+ super().setUpClass()
QCoreApplication.setOrganizationName("QGIS_Test")
QCoreApplication.setOrganizationDomain("TestPyQgsOapifProvider.com")
@@ -173,8 +223,8 @@ def setUpClass(cls):
# On Windows we must make sure that any backslash in the path is
# replaced by a forward slash so that QUrl can process it
- cls.basetestpath = tempfile.mkdtemp().replace('\\', '/')
- endpoint = cls.basetestpath + '/fake_qgis_http_endpoint'
+ cls.basetestpath = tempfile.mkdtemp().replace("\\", "/")
+ endpoint = cls.basetestpath + "/fake_qgis_http_endpoint"
create_landing_page_api_collection(endpoint)
@@ -182,38 +232,112 @@ def setUpClass(cls):
"type": "FeatureCollection",
"numberMatched": 5,
"features": [
- {"type": "Feature", "id": "feat.1",
- "properties": {"pk": 1, "cnt": 100, "name": "Orange", "name2": "oranGe", "num_char": "1", "dt": "2020-05-03 12:13:14", "date": "2020-05-03", "time": "12:13:14"},
- "geometry": {"type": "Point", "coordinates": [-70.332, 66.33]}},
- {"type": "Feature", "id": "feat.2",
- "properties": {"pk": 2, "cnt": 200, "name": "Apple", "name2": "Apple", "num_char": "2", "dt": "2020-05-04 12:14:14", "date": "2020-05-04", "time": "12:14:14"},
- "geometry": {"type": "Point", "coordinates": [-68.2, 70.8]}},
- {"type": "Feature", "id": "feat.3",
- "properties": {"pk": 4, "cnt": 400, "name": "Honey", "name2": "Honey", "num_char": "4", "dt": "2021-05-04 13:13:14", "date": "2021-05-04", "time": "13:13:14"},
- "geometry": {"type": "Point", "coordinates": [-65.32, 78.3]}},
- {"type": "Feature", "id": "feat.4",
- "properties": {"pk": 3, "cnt": 300, "name": "Pear", "name2": "PEaR", "num_char": "3"},
- "geometry": None},
- {"type": "Feature", "id": "feat.5",
- "properties": {"pk": 5, "cnt": -200, "name": None, "name2": "NuLl", "num_char": "5", "dt": "2020-05-04 12:13:14", "date": "2020-05-02", "time": "12:13:01"},
- "geometry": {"type": "Point", "coordinates": [-71.123, 78.23]}}
- ]
+ {
+ "type": "Feature",
+ "id": "feat.1",
+ "properties": {
+ "pk": 1,
+ "cnt": 100,
+ "name": "Orange",
+ "name2": "oranGe",
+ "num_char": "1",
+ "dt": "2020-05-03 12:13:14",
+ "date": "2020-05-03",
+ "time": "12:13:14",
+ },
+ "geometry": {"type": "Point", "coordinates": [-70.332, 66.33]},
+ },
+ {
+ "type": "Feature",
+ "id": "feat.2",
+ "properties": {
+ "pk": 2,
+ "cnt": 200,
+ "name": "Apple",
+ "name2": "Apple",
+ "num_char": "2",
+ "dt": "2020-05-04 12:14:14",
+ "date": "2020-05-04",
+ "time": "12:14:14",
+ },
+ "geometry": {"type": "Point", "coordinates": [-68.2, 70.8]},
+ },
+ {
+ "type": "Feature",
+ "id": "feat.3",
+ "properties": {
+ "pk": 4,
+ "cnt": 400,
+ "name": "Honey",
+ "name2": "Honey",
+ "num_char": "4",
+ "dt": "2021-05-04 13:13:14",
+ "date": "2021-05-04",
+ "time": "13:13:14",
+ },
+ "geometry": {"type": "Point", "coordinates": [-65.32, 78.3]},
+ },
+ {
+ "type": "Feature",
+ "id": "feat.4",
+ "properties": {
+ "pk": 3,
+ "cnt": 300,
+ "name": "Pear",
+ "name2": "PEaR",
+ "num_char": "3",
+ },
+ "geometry": None,
+ },
+ {
+ "type": "Feature",
+ "id": "feat.5",
+ "properties": {
+ "pk": 5,
+ "cnt": -200,
+ "name": None,
+ "name2": "NuLl",
+ "num_char": "5",
+ "dt": "2020-05-04 12:13:14",
+ "date": "2020-05-02",
+ "time": "12:13:01",
+ },
+ "geometry": {"type": "Point", "coordinates": [-71.123, 78.23]},
+ },
+ ],
}
# limit 1 for getting count
- with open(sanitize(endpoint, '/collections/mycollection/items?limit=1&' + ACCEPT_ITEMS), 'wb') as f:
- f.write(json.dumps(items).encode('UTF-8'))
+ with open(
+ sanitize(
+ endpoint, "/collections/mycollection/items?limit=1&" + ACCEPT_ITEMS
+ ),
+ "wb",
+ ) as f:
+ f.write(json.dumps(items).encode("UTF-8"))
# first items
- with open(sanitize(endpoint, '/collections/mycollection/items?limit=10&' + ACCEPT_ITEMS), 'wb') as f:
- f.write(json.dumps(items).encode('UTF-8'))
+ with open(
+ sanitize(
+ endpoint, "/collections/mycollection/items?limit=10&" + ACCEPT_ITEMS
+ ),
+ "wb",
+ ) as f:
+ f.write(json.dumps(items).encode("UTF-8"))
# real page
- with open(sanitize(endpoint, '/collections/mycollection/items?limit=1000&' + ACCEPT_ITEMS), 'wb') as f:
- f.write(json.dumps(items).encode('UTF-8'))
+ with open(
+ sanitize(
+ endpoint, "/collections/mycollection/items?limit=1000&" + ACCEPT_ITEMS
+ ),
+ "wb",
+ ) as f:
+ f.write(json.dumps(items).encode("UTF-8"))
# Create test layer
- cls.vl = QgsVectorLayer("url='http://" + endpoint + "' typename='mycollection'", 'test', 'OAPIF')
+ cls.vl = QgsVectorLayer(
+ "url='http://" + endpoint + "' typename='mycollection'", "test", "OAPIF"
+ )
assert cls.vl.isValid()
cls.source = cls.vl.dataProvider()
@@ -222,11 +346,13 @@ def tearDownClass(cls):
"""Run after all tests"""
QgsSettings().clear()
shutil.rmtree(cls.basetestpath, True)
- cls.vl = None # so as to properly close the provider and remove any temporary file
- super(TestPyQgsOapifProvider, cls).tearDownClass()
+ cls.vl = (
+ None # so as to properly close the provider and remove any temporary file
+ )
+ super().tearDownClass()
def testCrs(self):
- self.assertEqual(self.source.sourceCrs().authid(), 'OGC:CRS84')
+ self.assertEqual(self.source.sourceCrs().authid(), "OGC:CRS84")
def testExtentSubsetString(self):
# can't run the base provider test suite here - WFS/OAPIF extent handling is different
@@ -235,195 +361,300 @@ def testExtentSubsetString(self):
def testFeaturePaging(self):
- endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_testFeaturePaging'
+ endpoint = (
+ self.__class__.basetestpath + "/fake_qgis_http_endpoint_testFeaturePaging"
+ )
create_landing_page_api_collection(endpoint)
# first items
first_items = {
"type": "FeatureCollection",
"features": [
- {"type": "Feature", "id": "feat.1", "properties": {"pk": 1, "cnt": 100},
- "geometry": {"type": "Point", "coordinates": [-70.332, 66.33]}}
- ]
+ {
+ "type": "Feature",
+ "id": "feat.1",
+ "properties": {"pk": 1, "cnt": 100},
+ "geometry": {"type": "Point", "coordinates": [-70.332, 66.33]},
+ }
+ ],
}
- with open(sanitize(endpoint, '/collections/mycollection/items?limit=10&' + ACCEPT_ITEMS), 'wb') as f:
- f.write(json.dumps(first_items).encode('UTF-8'))
+ with open(
+ sanitize(
+ endpoint, "/collections/mycollection/items?limit=10&" + ACCEPT_ITEMS
+ ),
+ "wb",
+ ) as f:
+ f.write(json.dumps(first_items).encode("UTF-8"))
- vl = QgsVectorLayer("url='http://" + endpoint + "' typename='mycollection'", 'test', 'OAPIF')
+ vl = QgsVectorLayer(
+ "url='http://" + endpoint + "' typename='mycollection'", "test", "OAPIF"
+ )
self.assertTrue(vl.isValid())
# first real page
first_page = {
"type": "FeatureCollection",
"features": [
- {"type": "Feature", "id": "feat.1", "properties": {"pk": 1, "cnt": 100},
- "geometry": {"type": "Point", "coordinates": [-70.332, 66.33]}},
- {"type": "Feature", "id": "feat.2", "properties": {"pk": 2, "cnt": 200},
- "geometry": {"type": "Point", "coordinates": [-68.2, 70.8]}}
+ {
+ "type": "Feature",
+ "id": "feat.1",
+ "properties": {"pk": 1, "cnt": 100},
+ "geometry": {"type": "Point", "coordinates": [-70.332, 66.33]},
+ },
+ {
+ "type": "Feature",
+ "id": "feat.2",
+ "properties": {"pk": 2, "cnt": 200},
+ "geometry": {"type": "Point", "coordinates": [-68.2, 70.8]},
+ },
],
"links": [
# Test multiple media types for next
- {"href": "http://" + endpoint + "/second_page.html", "rel": "next", "type": "text/html"},
- {"href": "http://" + endpoint + "/second_page", "rel": "next", "type": "application/geo+json"},
- {"href": "http://" + endpoint + "/second_page.xml", "rel": "next", "type": "text/xml"}
- ]
+ {
+ "href": "http://" + endpoint + "/second_page.html",
+ "rel": "next",
+ "type": "text/html",
+ },
+ {
+ "href": "http://" + endpoint + "/second_page",
+ "rel": "next",
+ "type": "application/geo+json",
+ },
+ {
+ "href": "http://" + endpoint + "/second_page.xml",
+ "rel": "next",
+ "type": "text/xml",
+ },
+ ],
}
- with open(sanitize(endpoint, '/collections/mycollection/items?limit=1000&' + ACCEPT_ITEMS), 'wb') as f:
- f.write(json.dumps(first_page).encode('UTF-8'))
+ with open(
+ sanitize(
+ endpoint, "/collections/mycollection/items?limit=1000&" + ACCEPT_ITEMS
+ ),
+ "wb",
+ ) as f:
+ f.write(json.dumps(first_page).encode("UTF-8"))
# second page
second_page = {
"type": "FeatureCollection",
"features": [
# Also add a non expected property
- {"type": "Feature", "id": "feat.3", "properties": {"a_non_expected": "foo", "pk": 4, "cnt": 400},
- "geometry": {"type": "Point", "coordinates": [-65.32, 78.3]}}
+ {
+ "type": "Feature",
+ "id": "feat.3",
+ "properties": {"a_non_expected": "foo", "pk": 4, "cnt": 400},
+ "geometry": {"type": "Point", "coordinates": [-65.32, 78.3]},
+ }
],
- "links": [
- {"href": "http://" + endpoint + "/third_page", "rel": "next"}
- ]
+ "links": [{"href": "http://" + endpoint + "/third_page", "rel": "next"}],
}
- with open(sanitize(endpoint, '/second_page?' + ACCEPT_ITEMS), 'wb') as f:
- f.write(json.dumps(second_page).encode('UTF-8'))
+ with open(sanitize(endpoint, "/second_page?" + ACCEPT_ITEMS), "wb") as f:
+ f.write(json.dumps(second_page).encode("UTF-8"))
# third page
third_page = {
"type": "FeatureCollection",
"features": [],
"links": [
- {"href": "http://" + endpoint + "/third_page", "rel": "next"} # dummy link to ourselves
- ]
+ {
+ "href": "http://" + endpoint + "/third_page",
+ "rel": "next",
+ } # dummy link to ourselves
+ ],
}
- with open(sanitize(endpoint, '/third_page?' + ACCEPT_ITEMS), 'wb') as f:
- f.write(json.dumps(third_page).encode('UTF-8'))
+ with open(sanitize(endpoint, "/third_page?" + ACCEPT_ITEMS), "wb") as f:
+ f.write(json.dumps(third_page).encode("UTF-8"))
- values = [f['pk'] for f in vl.getFeatures()]
+ values = [f["pk"] for f in vl.getFeatures()]
self.assertEqual(values, [1, 2, 4])
- values = [f['pk'] for f in vl.getFeatures()]
+ values = [f["pk"] for f in vl.getFeatures()]
self.assertEqual(values, [1, 2, 4])
def testBbox(self):
- endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_testBbox'
- create_landing_page_api_collection(endpoint, storageCrs="http://www.opengis.net/def/crs/EPSG/0/4326")
+ endpoint = self.__class__.basetestpath + "/fake_qgis_http_endpoint_testBbox"
+ create_landing_page_api_collection(
+ endpoint, storageCrs="http://www.opengis.net/def/crs/EPSG/0/4326"
+ )
# first items
first_items = {
"type": "FeatureCollection",
"features": [
- {"type": "Feature", "id": "feat.1", "properties": {"pk": 1, "cnt": 100},
- "geometry": {"type": "Point", "coordinates": [66.33, -70.332]}}
- ]
+ {
+ "type": "Feature",
+ "id": "feat.1",
+ "properties": {"pk": 1, "cnt": 100},
+ "geometry": {"type": "Point", "coordinates": [66.33, -70.332]},
+ }
+ ],
}
- with open(sanitize(endpoint, '/collections/mycollection/items?limit=10&' + ACCEPT_ITEMS), 'wb') as f:
- f.write(json.dumps(first_items).encode('UTF-8'))
+ with open(
+ sanitize(
+ endpoint, "/collections/mycollection/items?limit=10&" + ACCEPT_ITEMS
+ ),
+ "wb",
+ ) as f:
+ f.write(json.dumps(first_items).encode("UTF-8"))
- vl = QgsVectorLayer("url='http://" + endpoint + "' typename='mycollection' restrictToRequestBBOX=1", 'test',
- 'OAPIF')
+ vl = QgsVectorLayer(
+ "url='http://"
+ + endpoint
+ + "' typename='mycollection' restrictToRequestBBOX=1",
+ "test",
+ "OAPIF",
+ )
self.assertTrue(vl.isValid())
items = {
"type": "FeatureCollection",
"features": [
- {"type": "Feature", "id": "feat.1", "properties": {"pk": 1, "cnt": 100},
- "geometry": {"type": "Point", "coordinates": [66.33, -70.332]}},
- {"type": "Feature", "id": "feat.2", "properties": {"pk": 2, "cnt": 200},
- "geometry": {"type": "Point", "coordinates": [70.8, -68.2]}}
- ]
+ {
+ "type": "Feature",
+ "id": "feat.1",
+ "properties": {"pk": 1, "cnt": 100},
+ "geometry": {"type": "Point", "coordinates": [66.33, -70.332]},
+ },
+ {
+ "type": "Feature",
+ "id": "feat.2",
+ "properties": {"pk": 2, "cnt": 200},
+ "geometry": {"type": "Point", "coordinates": [70.8, -68.2]},
+ },
+ ],
}
- with open(sanitize(endpoint, '/collections/mycollection/items?limit=1000&bbox=65.5,-71,78,-65&bbox-crs=http://www.opengis.net/def/crs/EPSG/0/4326&crs=http://www.opengis.net/def/crs/EPSG/0/4326&' + ACCEPT_ITEMS),
- 'wb') as f:
- f.write(json.dumps(items).encode('UTF-8'))
+ with open(
+ sanitize(
+ endpoint,
+ "/collections/mycollection/items?limit=1000&bbox=65.5,-71,78,-65&bbox-crs=http://www.opengis.net/def/crs/EPSG/0/4326&crs=http://www.opengis.net/def/crs/EPSG/0/4326&"
+ + ACCEPT_ITEMS,
+ ),
+ "wb",
+ ) as f:
+ f.write(json.dumps(items).encode("UTF-8"))
extent = QgsRectangle(-71, 65.5, -65, 78)
request = QgsFeatureRequest().setFilterRect(extent)
- values = [f['pk'] for f in vl.getFeatures(request)]
+ values = [f["pk"] for f in vl.getFeatures(request)]
self.assertEqual(values, [1, 2])
# Test request inside above one
EPS = 0.1
extent = QgsRectangle(-71 + EPS, 65.5 + EPS, -65 - EPS, 78 - EPS)
request = QgsFeatureRequest().setFilterRect(extent)
- values = [f['pk'] for f in vl.getFeatures(request)]
+ values = [f["pk"] for f in vl.getFeatures(request)]
self.assertEqual(values, [1, 2])
# Test clamping of bbox
with open(
- sanitize(endpoint, '/collections/mycollection/items?limit=1000&bbox=64.5,-180,78,-65&bbox-crs=http://www.opengis.net/def/crs/EPSG/0/4326&crs=http://www.opengis.net/def/crs/EPSG/0/4326&' + ACCEPT_ITEMS),
- 'wb') as f:
- f.write(json.dumps(items).encode('UTF-8'))
+ sanitize(
+ endpoint,
+ "/collections/mycollection/items?limit=1000&bbox=64.5,-180,78,-65&bbox-crs=http://www.opengis.net/def/crs/EPSG/0/4326&crs=http://www.opengis.net/def/crs/EPSG/0/4326&"
+ + ACCEPT_ITEMS,
+ ),
+ "wb",
+ ) as f:
+ f.write(json.dumps(items).encode("UTF-8"))
extent = QgsRectangle(-190, 64.5, -65, 78)
request = QgsFeatureRequest().setFilterRect(extent)
- values = [f['pk'] for f in vl.getFeatures(request)]
+ values = [f["pk"] for f in vl.getFeatures(request)]
self.assertEqual(values, [1, 2])
# Test request completely outside of -180,-90,180,90
extent = QgsRectangle(-1000, -1000, -900, -900)
request = QgsFeatureRequest().setFilterRect(extent)
- values = [f['pk'] for f in vl.getFeatures(request)]
+ values = [f["pk"] for f in vl.getFeatures(request)]
self.assertEqual(values, [])
# Test request containing -180,-90,180,90
items = {
"type": "FeatureCollection",
"features": [
- {"type": "Feature", "id": "feat.1", "properties": {"pk": 1, "cnt": 100},
- "geometry": {"type": "Point", "coordinates": [66.33, -70.332]}},
- {"type": "Feature", "id": "feat.2", "properties": {"pk": 2, "cnt": 200},
- "geometry": {"type": "Point", "coordinates": [70.8, -68.2]}},
- {"type": "Feature", "id": "feat.3", "properties": {"pk": 4, "cnt": 400},
- "geometry": {"type": "Point", "coordinates": [78.3, -65.32]}}
- ]
+ {
+ "type": "Feature",
+ "id": "feat.1",
+ "properties": {"pk": 1, "cnt": 100},
+ "geometry": {"type": "Point", "coordinates": [66.33, -70.332]},
+ },
+ {
+ "type": "Feature",
+ "id": "feat.2",
+ "properties": {"pk": 2, "cnt": 200},
+ "geometry": {"type": "Point", "coordinates": [70.8, -68.2]},
+ },
+ {
+ "type": "Feature",
+ "id": "feat.3",
+ "properties": {"pk": 4, "cnt": 400},
+ "geometry": {"type": "Point", "coordinates": [78.3, -65.32]},
+ },
+ ],
}
- with open(sanitize(endpoint, '/collections/mycollection/items?limit=1000&bbox=-90,-180,90,180&bbox-crs=http://www.opengis.net/def/crs/EPSG/0/4326&crs=http://www.opengis.net/def/crs/EPSG/0/4326&' + ACCEPT_ITEMS), 'wb') as f:
- f.write(json.dumps(items).encode('UTF-8'))
+ with open(
+ sanitize(
+ endpoint,
+ "/collections/mycollection/items?limit=1000&bbox=-90,-180,90,180&bbox-crs=http://www.opengis.net/def/crs/EPSG/0/4326&crs=http://www.opengis.net/def/crs/EPSG/0/4326&"
+ + ACCEPT_ITEMS,
+ ),
+ "wb",
+ ) as f:
+ f.write(json.dumps(items).encode("UTF-8"))
extent = QgsRectangle(-181, -91, 181, 91)
request = QgsFeatureRequest().setFilterRect(extent)
- values = [f['pk'] for f in vl.getFeatures(request)]
+ values = [f["pk"] for f in vl.getFeatures(request)]
self.assertEqual(values, [1, 2, 4])
def testLayerMetadata(self):
- endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_testLayerMetadata'
+ endpoint = (
+ self.__class__.basetestpath + "/fake_qgis_http_endpoint_testLayerMetadata"
+ )
create_landing_page_api_collection(endpoint)
# first items
first_items = {
"type": "FeatureCollection",
"features": [
- {"type": "Feature", "id": "feat.1", "properties": {"pk": 1, "cnt": 100},
- "geometry": {"type": "Point", "coordinates": [-70.332, 66.33]}}
- ]
+ {
+ "type": "Feature",
+ "id": "feat.1",
+ "properties": {"pk": 1, "cnt": 100},
+ "geometry": {"type": "Point", "coordinates": [-70.332, 66.33]},
+ }
+ ],
}
- with open(sanitize(endpoint, '/collections/mycollection/items?limit=10&' + ACCEPT_ITEMS), 'wb') as f:
- f.write(json.dumps(first_items).encode('UTF-8'))
+ with open(
+ sanitize(
+ endpoint, "/collections/mycollection/items?limit=10&" + ACCEPT_ITEMS
+ ),
+ "wb",
+ ) as f:
+ f.write(json.dumps(first_items).encode("UTF-8"))
# API
- with open(sanitize(endpoint, '/api?' + ACCEPT_API), 'wb') as f:
- f.write(json.dumps({
- "components": {
- "parameters": {
- "limit": {
- "schema": {
- "maximum": 1000,
- "default": 100
- }
- }
- }
- },
- "info":
+ with open(sanitize(endpoint, "/api?" + ACCEPT_API), "wb") as f:
+ f.write(
+ json.dumps(
{
- "contact":
- {
+ "components": {
+ "parameters": {
+ "limit": {"schema": {"maximum": 1000, "default": 100}}
+ }
+ },
+ "info": {
+ "contact": {
"name": "contact_name",
"email": "contact_email",
- "url": "contact_url"
+ "url": "contact_url",
}
- }
- }).encode('UTF-8'))
+ },
+ }
+ ).encode("UTF-8")
+ )
# collection
base_collection = {
@@ -437,75 +668,99 @@ def testLayerMetadata(self):
None, # invalid
[1, 2, 3], # invalid
["invalid", 1, 2, 3], # invalid
- [2, 49, -100, 3, 50, 100]
+ [2, 49, -100, 3, 50, 100],
+ ]
+ },
+ "temporal": {
+ "interval": [
+ [None, None], # invalid
+ ["invalid", "invalid"],
+ "another_invalid",
+ ["1980-01-01T12:34:56.789Z", "2020-01-01T00:00:00Z"],
+ ["1980-01-01T12:34:56.789Z", None],
+ [None, "2020-01-01T00:00:00Z"],
]
},
- "temporal":
- {
- "interval": [
- [None, None], # invalid
- ["invalid", "invalid"],
- "another_invalid",
- ["1980-01-01T12:34:56.789Z", "2020-01-01T00:00:00Z"],
- ["1980-01-01T12:34:56.789Z", None],
- [None, "2020-01-01T00:00:00Z"]
- ]
- }
},
"links": [
- {"href": "href_self", "rel": "self", "type": "application/json", "title": "my self link"},
+ {
+ "href": "href_self",
+ "rel": "self",
+ "type": "application/json",
+ "title": "my self link",
+ },
{"href": "href_parent", "rel": "parent", "title": "my parent link"},
- {"href": "http://download.example.org/buildings.gpkg",
- "rel": "enclosure",
- "type": "application/geopackage+sqlite3",
- "title": "Bulk download (GeoPackage)",
- "length": 123456789012345}
+ {
+ "href": "http://download.example.org/buildings.gpkg",
+ "rel": "enclosure",
+ "type": "application/geopackage+sqlite3",
+ "title": "Bulk download (GeoPackage)",
+ "length": 123456789012345,
+ },
],
# STAC specific
- "keywords": ["keyword_a", "keyword_b"]
-
+ "keywords": ["keyword_a", "keyword_b"],
}
collection = copy.deepcopy(base_collection)
- collection['links'].append(
- {"href": "https://creativecommons.org/publicdomain/zero/1.0/",
- "rel": "license", "type": "text/html",
- "title": "CC0-1.0"})
- collection['links'].append(
- {"href": "https://creativecommons.org/publicdomain/zero/1.0/rdf",
- "rel": "license", "type": "application/rdf+xml",
- "title": "CC0-1.0"})
- collection['links'].append(
- {"href": "https://example.com",
- "rel": "license", "type": "text/html",
- "title": "Public domain"})
- with open(sanitize(endpoint, '/collections/mycollection?' + ACCEPT_COLLECTION), 'wb') as f:
- f.write(json.dumps(collection).encode('UTF-8'))
-
- vl = QgsVectorLayer("url='http://" + endpoint + "' typename='mycollection' restrictToRequestBBOX=1", 'test',
- 'OAPIF')
+ collection["links"].append(
+ {
+ "href": "https://creativecommons.org/publicdomain/zero/1.0/",
+ "rel": "license",
+ "type": "text/html",
+ "title": "CC0-1.0",
+ }
+ )
+ collection["links"].append(
+ {
+ "href": "https://creativecommons.org/publicdomain/zero/1.0/rdf",
+ "rel": "license",
+ "type": "application/rdf+xml",
+ "title": "CC0-1.0",
+ }
+ )
+ collection["links"].append(
+ {
+ "href": "https://example.com",
+ "rel": "license",
+ "type": "text/html",
+ "title": "Public domain",
+ }
+ )
+ with open(
+ sanitize(endpoint, "/collections/mycollection?" + ACCEPT_COLLECTION), "wb"
+ ) as f:
+ f.write(json.dumps(collection).encode("UTF-8"))
+
+ vl = QgsVectorLayer(
+ "url='http://"
+ + endpoint
+ + "' typename='mycollection' restrictToRequestBBOX=1",
+ "test",
+ "OAPIF",
+ )
self.assertTrue(vl.isValid())
md = vl.metadata()
- assert md.identifier() == 'href_self'
- assert md.parentIdentifier() == 'href_parent'
- assert md.type() == 'dataset'
- assert md.title() == 'my title'
- assert md.abstract() == 'my description'
+ assert md.identifier() == "href_self"
+ assert md.parentIdentifier() == "href_parent"
+ assert md.type() == "dataset"
+ assert md.title() == "my title"
+ assert md.abstract() == "my description"
contacts = md.contacts()
assert len(contacts) == 1
contact = contacts[0]
- assert contact.name == 'contact_name'
- assert contact.email == 'contact_email'
- assert contact.organization == 'contact_url'
+ assert contact.name == "contact_name"
+ assert contact.email == "contact_email"
+ assert contact.organization == "contact_url"
assert len(md.licenses()) == 2
- assert md.licenses()[0] == 'CC0-1.0'
- assert md.licenses()[1] == 'Public domain'
+ assert md.licenses()[0] == "CC0-1.0"
+ assert md.licenses()[1] == "Public domain"
- assert 'keywords' in md.keywords()
- assert md.keywords()['keywords'] == ["keyword_a", "keyword_b"]
+ assert "keywords" in md.keywords()
+ assert md.keywords()["keywords"] == ["keyword_a", "keyword_b"]
assert md.crs().isValid()
assert md.crs().authid() == "OGC:CRS84"
@@ -514,13 +769,13 @@ def testLayerMetadata(self):
links = md.links()
assert len(links) == 6, len(links)
- assert links[0].type == 'WWW:LINK'
- assert links[0].url == 'href_self'
- assert links[0].name == 'self'
- assert links[0].mimeType == 'application/json'
- assert links[0].description == 'my self link'
- assert links[0].size == ''
- assert links[2].size == '123456789012345'
+ assert links[0].type == "WWW:LINK"
+ assert links[0].url == "href_self"
+ assert links[0].name == "self"
+ assert links[0].mimeType == "application/json"
+ assert links[0].description == "my self link"
+ assert links[0].size == ""
+ assert links[2].size == "123456789012345"
extent = md.extent()
assert len(extent.spatialExtents()) == 2
@@ -528,16 +783,20 @@ def testLayerMetadata(self):
assert spatialExtent.extentCrs.isValid()
assert spatialExtent.extentCrs.isGeographic()
assert not spatialExtent.extentCrs.hasAxisInverted()
- assert spatialExtent.bounds == QgsBox3d(-71.123, 66.33, float("nan"), -65.32, 78.3, float("nan"))
+ assert spatialExtent.bounds == QgsBox3d(
+ -71.123, 66.33, float("nan"), -65.32, 78.3, float("nan")
+ )
spatialExtent = extent.spatialExtents()[1]
assert spatialExtent.bounds == QgsBox3d(2, 49, -100, 3, 50, 100)
temporalExtents = extent.temporalExtents()
assert len(temporalExtents) == 3
- assert temporalExtents[0].begin() == QDateTime.fromString("1980-01-01T12:34:56.789Z", Qt.DateFormat.ISODateWithMs), \
- temporalExtents[0].begin()
- assert temporalExtents[0].end() == QDateTime.fromString("2020-01-01T00:00:00Z", Qt.DateFormat.ISODateWithMs), \
- temporalExtents[0].end()
+ assert temporalExtents[0].begin() == QDateTime.fromString(
+ "1980-01-01T12:34:56.789Z", Qt.DateFormat.ISODateWithMs
+ ), temporalExtents[0].begin()
+ assert temporalExtents[0].end() == QDateTime.fromString(
+ "2020-01-01T00:00:00Z", Qt.DateFormat.ISODateWithMs
+ ), temporalExtents[0].end()
assert temporalExtents[1].begin().isValid()
assert not temporalExtents[1].end().isValid()
assert not temporalExtents[2].begin().isValid()
@@ -545,77 +804,120 @@ def testLayerMetadata(self):
# Variant using STAC license
collection = copy.deepcopy(base_collection)
- collection['license'] = 'STAC license'
- with open(sanitize(endpoint, '/collections/mycollection?' + ACCEPT_COLLECTION), 'wb') as f:
- f.write(json.dumps(collection).encode('UTF-8'))
+ collection["license"] = "STAC license"
+ with open(
+ sanitize(endpoint, "/collections/mycollection?" + ACCEPT_COLLECTION), "wb"
+ ) as f:
+ f.write(json.dumps(collection).encode("UTF-8"))
- vl = QgsVectorLayer("url='http://" + endpoint + "' typename='mycollection' restrictToRequestBBOX=1", 'test',
- 'OAPIF')
+ vl = QgsVectorLayer(
+ "url='http://"
+ + endpoint
+ + "' typename='mycollection' restrictToRequestBBOX=1",
+ "test",
+ "OAPIF",
+ )
self.assertTrue(vl.isValid())
md = vl.metadata()
assert len(md.licenses()) == 1
- assert md.licenses()[0] == 'STAC license'
+ assert md.licenses()[0] == "STAC license"
# Variant using STAC license=various
collection = copy.deepcopy(base_collection)
- collection['license'] = 'various'
- collection['links'].append(
- {"href": "https://creativecommons.org/publicdomain/zero/1.0/",
- "rel": "license", "type": "text/html",
- "title": "CC0-1.0"})
- with open(sanitize(endpoint, '/collections/mycollection?' + ACCEPT_COLLECTION), 'wb') as f:
- f.write(json.dumps(collection).encode('UTF-8'))
-
- vl = QgsVectorLayer("url='http://" + endpoint + "' typename='mycollection' restrictToRequestBBOX=1", 'test',
- 'OAPIF')
+ collection["license"] = "various"
+ collection["links"].append(
+ {
+ "href": "https://creativecommons.org/publicdomain/zero/1.0/",
+ "rel": "license",
+ "type": "text/html",
+ "title": "CC0-1.0",
+ }
+ )
+ with open(
+ sanitize(endpoint, "/collections/mycollection?" + ACCEPT_COLLECTION), "wb"
+ ) as f:
+ f.write(json.dumps(collection).encode("UTF-8"))
+
+ vl = QgsVectorLayer(
+ "url='http://"
+ + endpoint
+ + "' typename='mycollection' restrictToRequestBBOX=1",
+ "test",
+ "OAPIF",
+ )
self.assertTrue(vl.isValid())
md = vl.metadata()
assert len(md.licenses()) == 1
- assert md.licenses()[0] == 'CC0-1.0'
+ assert md.licenses()[0] == "CC0-1.0"
# Variant using STAC license=proprietary
collection = copy.deepcopy(base_collection)
- collection['license'] = 'proprietary'
- collection['links'].append(
- {"href": "https://example.com",
- "rel": "license", "type": "text/html",
- "title": "my proprietary license"})
- with open(sanitize(endpoint, '/collections/mycollection?' + ACCEPT_COLLECTION), 'wb') as f:
- f.write(json.dumps(collection).encode('UTF-8'))
-
- vl = QgsVectorLayer("url='http://" + endpoint + "' typename='mycollection' restrictToRequestBBOX=1", 'test',
- 'OAPIF')
+ collection["license"] = "proprietary"
+ collection["links"].append(
+ {
+ "href": "https://example.com",
+ "rel": "license",
+ "type": "text/html",
+ "title": "my proprietary license",
+ }
+ )
+ with open(
+ sanitize(endpoint, "/collections/mycollection?" + ACCEPT_COLLECTION), "wb"
+ ) as f:
+ f.write(json.dumps(collection).encode("UTF-8"))
+
+ vl = QgsVectorLayer(
+ "url='http://"
+ + endpoint
+ + "' typename='mycollection' restrictToRequestBBOX=1",
+ "test",
+ "OAPIF",
+ )
self.assertTrue(vl.isValid())
md = vl.metadata()
assert len(md.licenses()) == 1
- assert md.licenses()[0] == 'my proprietary license'
+ assert md.licenses()[0] == "my proprietary license"
# Variant using STAC license=proprietary (non conformant: missing a rel=license link)
collection = copy.deepcopy(base_collection)
- collection['license'] = 'proprietary'
- with open(sanitize(endpoint, '/collections/mycollection?' + ACCEPT_COLLECTION), 'wb') as f:
- f.write(json.dumps(collection).encode('UTF-8'))
+ collection["license"] = "proprietary"
+ with open(
+ sanitize(endpoint, "/collections/mycollection?" + ACCEPT_COLLECTION), "wb"
+ ) as f:
+ f.write(json.dumps(collection).encode("UTF-8"))
- vl = QgsVectorLayer("url='http://" + endpoint + "' typename='mycollection' restrictToRequestBBOX=1", 'test',
- 'OAPIF')
+ vl = QgsVectorLayer(
+ "url='http://"
+ + endpoint
+ + "' typename='mycollection' restrictToRequestBBOX=1",
+ "test",
+ "OAPIF",
+ )
self.assertTrue(vl.isValid())
md = vl.metadata()
assert len(md.licenses()) == 1
- assert md.licenses()[0] == 'proprietary'
+ assert md.licenses()[0] == "proprietary"
# Variant with storageCrs
collection = copy.deepcopy(base_collection)
- collection['storageCrs'] = "http://www.opengis.net/def/crs/EPSG/0/4258"
- collection['storageCrsCoordinateEpoch'] = 2020.0
- with open(sanitize(endpoint, '/collections/mycollection?' + ACCEPT_COLLECTION), 'wb') as f:
- f.write(json.dumps(collection).encode('UTF-8'))
+ collection["storageCrs"] = "http://www.opengis.net/def/crs/EPSG/0/4258"
+ collection["storageCrsCoordinateEpoch"] = 2020.0
+ with open(
+ sanitize(endpoint, "/collections/mycollection?" + ACCEPT_COLLECTION), "wb"
+ ) as f:
+ f.write(json.dumps(collection).encode("UTF-8"))
- vl = QgsVectorLayer("url='http://" + endpoint + "' typename='mycollection' restrictToRequestBBOX=1", 'test',
- 'OAPIF')
+ vl = QgsVectorLayer(
+ "url='http://"
+ + endpoint
+ + "' typename='mycollection' restrictToRequestBBOX=1",
+ "test",
+ "OAPIF",
+ )
self.assertTrue(vl.isValid())
md = vl.metadata()
@@ -627,12 +929,22 @@ def testLayerMetadata(self):
# Variant with a list of crs
collection = copy.deepcopy(base_collection)
- collection['crs'] = ["http://www.opengis.net/def/crs/EPSG/0/4258", "http://www.opengis.net/def/crs/EPSG/0/4326"]
- with open(sanitize(endpoint, '/collections/mycollection?' + ACCEPT_COLLECTION), 'wb') as f:
- f.write(json.dumps(collection).encode('UTF-8'))
+ collection["crs"] = [
+ "http://www.opengis.net/def/crs/EPSG/0/4258",
+ "http://www.opengis.net/def/crs/EPSG/0/4326",
+ ]
+ with open(
+ sanitize(endpoint, "/collections/mycollection?" + ACCEPT_COLLECTION), "wb"
+ ) as f:
+ f.write(json.dumps(collection).encode("UTF-8"))
- vl = QgsVectorLayer("url='http://" + endpoint + "' typename='mycollection' restrictToRequestBBOX=1", 'test',
- 'OAPIF')
+ vl = QgsVectorLayer(
+ "url='http://"
+ + endpoint
+ + "' typename='mycollection' restrictToRequestBBOX=1",
+ "test",
+ "OAPIF",
+ )
self.assertTrue(vl.isValid())
md = vl.metadata()
@@ -643,109 +955,149 @@ def testLayerMetadata(self):
def testDateTimeFiltering(self):
- endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_testDateTimeFiltering'
+ endpoint = (
+ self.__class__.basetestpath
+ + "/fake_qgis_http_endpoint_testDateTimeFiltering"
+ )
create_landing_page_api_collection(endpoint)
items = {
"type": "FeatureCollection",
"features": [
- {"type": "Feature", "id": "feat.1", "properties": {"my_dt_field": "2019-10-15T00:34:00Z", "foo": "bar"},
- "geometry": {"type": "Point", "coordinates": [-70.332, 66.33]}}
- ]
+ {
+ "type": "Feature",
+ "id": "feat.1",
+ "properties": {"my_dt_field": "2019-10-15T00:34:00Z", "foo": "bar"},
+ "geometry": {"type": "Point", "coordinates": [-70.332, 66.33]},
+ }
+ ],
}
- no_items = {
- "type": "FeatureCollection",
- "features": [
- ]
- }
+ no_items = {"type": "FeatureCollection", "features": []}
- filename = sanitize(endpoint, '/collections/mycollection/items?limit=10&' + ACCEPT_ITEMS)
- with open(filename, 'wb') as f:
- f.write(json.dumps(items).encode('UTF-8'))
+ filename = sanitize(
+ endpoint, "/collections/mycollection/items?limit=10&" + ACCEPT_ITEMS
+ )
+ with open(filename, "wb") as f:
+ f.write(json.dumps(items).encode("UTF-8"))
vl = QgsVectorLayer(
- "url='http://" + endpoint + "' typename='mycollection' filter='\"my_dt_field\" >= \\'2019-05-15T00:00:00Z\\''",
- 'test', 'OAPIF')
+ "url='http://"
+ + endpoint
+ + "' typename='mycollection' filter='\"my_dt_field\" >= \\'2019-05-15T00:00:00Z\\''",
+ "test",
+ "OAPIF",
+ )
self.assertTrue(vl.isValid())
os.unlink(filename)
- filename = sanitize(endpoint,
- '/collections/mycollection/items?limit=1000&datetime=2019-05-15T00:00:00Z/9999-12-31T00:00:00Z&' + ACCEPT_ITEMS)
- with open(filename, 'wb') as f:
- f.write(json.dumps(items).encode('UTF-8'))
- values = [f['id'] for f in vl.getFeatures()]
+ filename = sanitize(
+ endpoint,
+ "/collections/mycollection/items?limit=1000&datetime=2019-05-15T00:00:00Z/9999-12-31T00:00:00Z&"
+ + ACCEPT_ITEMS,
+ )
+ with open(filename, "wb") as f:
+ f.write(json.dumps(items).encode("UTF-8"))
+ values = [f["id"] for f in vl.getFeatures()]
os.unlink(filename)
- self.assertEqual(values, ['feat.1'])
+ self.assertEqual(values, ["feat.1"])
assert vl.setSubsetString(""""my_dt_field" < '2019-01-01T00:34:00Z'""")
- filename = sanitize(endpoint,
- '/collections/mycollection/items?limit=1000&datetime=0000-01-01T00:00:00Z/2019-01-01T00:34:00Z&' + ACCEPT_ITEMS)
- with open(filename, 'wb') as f:
- f.write(json.dumps(no_items).encode('UTF-8'))
- values = [f['id'] for f in vl.getFeatures()]
+ filename = sanitize(
+ endpoint,
+ "/collections/mycollection/items?limit=1000&datetime=0000-01-01T00:00:00Z/2019-01-01T00:34:00Z&"
+ + ACCEPT_ITEMS,
+ )
+ with open(filename, "wb") as f:
+ f.write(json.dumps(no_items).encode("UTF-8"))
+ values = [f["id"] for f in vl.getFeatures()]
os.unlink(filename)
self.assertEqual(values, [])
assert vl.setSubsetString(""""my_dt_field" = '2019-10-15T00:34:00Z'""")
- filename = sanitize(endpoint,
- '/collections/mycollection/items?limit=1000&datetime=2019-10-15T00:34:00Z&' + ACCEPT_ITEMS)
- with open(filename, 'wb') as f:
- f.write(json.dumps(items).encode('UTF-8'))
- values = [f['id'] for f in vl.getFeatures()]
+ filename = sanitize(
+ endpoint,
+ "/collections/mycollection/items?limit=1000&datetime=2019-10-15T00:34:00Z&"
+ + ACCEPT_ITEMS,
+ )
+ with open(filename, "wb") as f:
+ f.write(json.dumps(items).encode("UTF-8"))
+ values = [f["id"] for f in vl.getFeatures()]
os.unlink(filename)
- self.assertEqual(values, ['feat.1'])
+ self.assertEqual(values, ["feat.1"])
assert vl.setSubsetString(
- """("my_dt_field" >= '2019-01-01T00:34:00Z') AND ("my_dt_field" <= '2019-12-31T00:00:00Z')""")
-
- filename = sanitize(endpoint,
- '/collections/mycollection/items?limit=1000&datetime=2019-01-01T00:34:00Z/2019-12-31T00:00:00Z&' + ACCEPT_ITEMS)
- with open(filename, 'wb') as f:
- f.write(json.dumps(items).encode('UTF-8'))
- values = [f['id'] for f in vl.getFeatures()]
+ """("my_dt_field" >= '2019-01-01T00:34:00Z') AND ("my_dt_field" <= '2019-12-31T00:00:00Z')"""
+ )
+
+ filename = sanitize(
+ endpoint,
+ "/collections/mycollection/items?limit=1000&datetime=2019-01-01T00:34:00Z/2019-12-31T00:00:00Z&"
+ + ACCEPT_ITEMS,
+ )
+ with open(filename, "wb") as f:
+ f.write(json.dumps(items).encode("UTF-8"))
+ values = [f["id"] for f in vl.getFeatures()]
os.unlink(filename)
- self.assertEqual(values, ['feat.1'])
+ self.assertEqual(values, ["feat.1"])
# Partial on client side
- assert vl.setSubsetString("""("my_dt_field" >= '2019-01-01T00:34:00Z') AND ("foo" = 'bar')""")
-
- filename = sanitize(endpoint,
- '/collections/mycollection/items?limit=1000&datetime=2019-01-01T00:34:00Z/9999-12-31T00:00:00Z&' + ACCEPT_ITEMS)
- with open(filename, 'wb') as f:
- f.write(json.dumps(items).encode('UTF-8'))
- values = [f['id'] for f in vl.getFeatures()]
+ assert vl.setSubsetString(
+ """("my_dt_field" >= '2019-01-01T00:34:00Z') AND ("foo" = 'bar')"""
+ )
+
+ filename = sanitize(
+ endpoint,
+ "/collections/mycollection/items?limit=1000&datetime=2019-01-01T00:34:00Z/9999-12-31T00:00:00Z&"
+ + ACCEPT_ITEMS,
+ )
+ with open(filename, "wb") as f:
+ f.write(json.dumps(items).encode("UTF-8"))
+ values = [f["id"] for f in vl.getFeatures()]
os.unlink(filename)
- self.assertEqual(values, ['feat.1'])
+ self.assertEqual(values, ["feat.1"])
# Same but with non-matching client-side part
- assert vl.setSubsetString("""("my_dt_field" >= '2019-01-01T00:34:00Z') AND ("foo" != 'bar')""")
-
- filename = sanitize(endpoint,
- '/collections/mycollection/items?limit=1000&datetime=2019-01-01T00:34:00Z/9999-12-31T00:00:00Z&' + ACCEPT_ITEMS)
- with open(filename, 'wb') as f:
- f.write(json.dumps(items).encode('UTF-8'))
- values = [f['id'] for f in vl.getFeatures()]
+ assert vl.setSubsetString(
+ """("my_dt_field" >= '2019-01-01T00:34:00Z') AND ("foo" != 'bar')"""
+ )
+
+ filename = sanitize(
+ endpoint,
+ "/collections/mycollection/items?limit=1000&datetime=2019-01-01T00:34:00Z/9999-12-31T00:00:00Z&"
+ + ACCEPT_ITEMS,
+ )
+ with open(filename, "wb") as f:
+ f.write(json.dumps(items).encode("UTF-8"))
+ values = [f["id"] for f in vl.getFeatures()]
os.unlink(filename)
self.assertEqual(values, [])
# Switch order
- assert vl.setSubsetString("""("foo" = 'bar') AND ("my_dt_field" >= '2019-01-01T00:34:00Z')""")
-
- filename = sanitize(endpoint,
- '/collections/mycollection/items?limit=1000&datetime=2019-01-01T00:34:00Z/9999-12-31T00:00:00Z&' + ACCEPT_ITEMS)
- with open(filename, 'wb') as f:
- f.write(json.dumps(items).encode('UTF-8'))
- values = [f['id'] for f in vl.getFeatures()]
+ assert vl.setSubsetString(
+ """("foo" = 'bar') AND ("my_dt_field" >= '2019-01-01T00:34:00Z')"""
+ )
+
+ filename = sanitize(
+ endpoint,
+ "/collections/mycollection/items?limit=1000&datetime=2019-01-01T00:34:00Z/9999-12-31T00:00:00Z&"
+ + ACCEPT_ITEMS,
+ )
+ with open(filename, "wb") as f:
+ f.write(json.dumps(items).encode("UTF-8"))
+ values = [f["id"] for f in vl.getFeatures()]
os.unlink(filename)
- self.assertEqual(values, ['feat.1'])
+ self.assertEqual(values, ["feat.1"])
def testSimpleQueryableFiltering(self):
"""Test simple filtering capabilities, not requiring Part 3"""
- endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_encoded_query_testSimpleQueryableFiltering'
+ endpoint = (
+ self.__class__.basetestpath
+ + "/fake_qgis_http_endpoint_encoded_query_testSimpleQueryableFiltering"
+ )
additionalApiResponse = {
"paths": {
"/collections/mycollection/items": {
@@ -759,28 +1111,22 @@ def testSimpleQueryableFiltering(self):
"in": "query",
"style": "form",
"explode": False,
- "schema": {
- "type": "integer"
- }
+ "schema": {"type": "integer"},
},
{
"name": "doublefield",
"in": "query",
"style": "form",
"explode": False,
- "schema": {
- "type": "number"
- }
+ "schema": {"type": "number"},
},
{
"name": "boolfield",
"in": "query",
"style": "form",
"explode": False,
- "schema": {
- "type": "boolean"
- }
- }
+ "schema": {"type": "boolean"},
+ },
]
}
}
@@ -792,66 +1138,80 @@ def testSimpleQueryableFiltering(self):
"in": "query",
"style": "form",
"explode": False,
- "schema": {
- "type": "string"
- }
+ "schema": {"type": "string"},
}
}
- }
+ },
}
- create_landing_page_api_collection(endpoint, additionalApiResponse=additionalApiResponse)
+ create_landing_page_api_collection(
+ endpoint, additionalApiResponse=additionalApiResponse
+ )
items = {
"type": "FeatureCollection",
"features": [
- {"type": "Feature", "id": "feat.1", "properties":
- {"strfield": "foo=bar",
- "intfield": 1,
- "doublefield": 1.5,
- "boolfield": True},
- "geometry": {"type": "Point", "coordinates": [-70.332, 66.33]}}
- ]
+ {
+ "type": "Feature",
+ "id": "feat.1",
+ "properties": {
+ "strfield": "foo=bar",
+ "intfield": 1,
+ "doublefield": 1.5,
+ "boolfield": True,
+ },
+ "geometry": {"type": "Point", "coordinates": [-70.332, 66.33]},
+ }
+ ],
}
- no_items = {
- "type": "FeatureCollection",
- "features": [
- ]
- }
+ no_items = {"type": "FeatureCollection", "features": []}
- filename = sanitize(endpoint, '/collections/mycollection/items?limit=10&' + ACCEPT_ITEMS)
- with open(filename, 'wb') as f:
- f.write(json.dumps(items).encode('UTF-8'))
+ filename = sanitize(
+ endpoint, "/collections/mycollection/items?limit=10&" + ACCEPT_ITEMS
+ )
+ with open(filename, "wb") as f:
+ f.write(json.dumps(items).encode("UTF-8"))
vl = QgsVectorLayer(
- "url='http://" + endpoint + "' typename='mycollection'", 'test', 'OAPIF')
+ "url='http://" + endpoint + "' typename='mycollection'", "test", "OAPIF"
+ )
self.assertTrue(vl.isValid())
os.unlink(filename)
- assert vl.setSubsetString(""""strfield" = 'foo=bar' and intfield = 1 and doublefield = 1.5 and boolfield = true""")
-
- filename = sanitize(endpoint,
- '/collections/mycollection/items?limit=1000&strfield=foo%3Dbar&intfield=1&doublefield=1.5&boolfield=true&' + ACCEPT_ITEMS)
- with open(filename, 'wb') as f:
- f.write(json.dumps(items).encode('UTF-8'))
- values = [f['id'] for f in vl.getFeatures()]
+ assert vl.setSubsetString(
+ """"strfield" = 'foo=bar' and intfield = 1 and doublefield = 1.5 and boolfield = true"""
+ )
+
+ filename = sanitize(
+ endpoint,
+ "/collections/mycollection/items?limit=1000&strfield=foo%3Dbar&intfield=1&doublefield=1.5&boolfield=true&"
+ + ACCEPT_ITEMS,
+ )
+ with open(filename, "wb") as f:
+ f.write(json.dumps(items).encode("UTF-8"))
+ values = [f["id"] for f in vl.getFeatures()]
os.unlink(filename)
- self.assertEqual(values, ['feat.1'])
+ self.assertEqual(values, ["feat.1"])
assert vl.setSubsetString(""""strfield" = 'bar'""")
- filename = sanitize(endpoint,
- '/collections/mycollection/items?limit=1000&strfield=bar&' + ACCEPT_ITEMS)
- with open(filename, 'wb') as f:
- f.write(json.dumps(no_items).encode('UTF-8'))
- values = [f['id'] for f in vl.getFeatures()]
+ filename = sanitize(
+ endpoint,
+ "/collections/mycollection/items?limit=1000&strfield=bar&" + ACCEPT_ITEMS,
+ )
+ with open(filename, "wb") as f:
+ f.write(json.dumps(no_items).encode("UTF-8"))
+ values = [f["id"] for f in vl.getFeatures()]
os.unlink(filename)
self.assertEqual(values, [])
def testCQL2TextFiltering(self):
"""Test Part 3 CQL2-Text filtering"""
- endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_encoded_query_testCQL2TextFiltering'
+ endpoint = (
+ self.__class__.basetestpath
+ + "/fake_qgis_http_endpoint_encoded_query_testCQL2TextFiltering"
+ )
additionalConformance = [
"http://www.opengis.net/spec/cql2/1.0/conf/advanced-comparison-operators",
"http://www.opengis.net/spec/cql2/1.0/conf/basic-cql2",
@@ -862,29 +1222,21 @@ def testCQL2TextFiltering(self):
"http://www.opengis.net/spec/ogcapi-features-3/1.0/conf/filter",
]
- create_landing_page_api_collection(endpoint, additionalConformance=additionalConformance)
+ create_landing_page_api_collection(
+ endpoint, additionalConformance=additionalConformance
+ )
- filename = sanitize(endpoint, '/collections/mycollection/queryables?' + ACCEPT_QUERYABLES)
+ filename = sanitize(
+ endpoint, "/collections/mycollection/queryables?" + ACCEPT_QUERYABLES
+ )
queryables = {
"properties": {
- "strfield": {
- "type": "string"
- },
- "strfield2": {
- "type": "string"
- },
- "intfield": {
- "type": "integer"
- },
- "doublefield": {
- "type": "number"
- },
- "boolfield": {
- "type": "boolean"
- },
- "boolfield2": {
- "type": "boolean"
- },
+ "strfield": {"type": "string"},
+ "strfield2": {"type": "string"},
+ "intfield": {"type": "integer"},
+ "doublefield": {"type": "number"},
+ "boolfield": {"type": "boolean"},
+ "boolfield2": {"type": "boolean"},
"datetimefield": {
"type": "string",
"format": "date-time",
@@ -893,99 +1245,176 @@ def testCQL2TextFiltering(self):
"type": "string",
"format": "date",
},
- "geometry": {
- "$ref": "https://geojson.org/schema/Point.json"
- },
+ "geometry": {"$ref": "https://geojson.org/schema/Point.json"},
}
}
- with open(filename, 'wb') as f:
- f.write(json.dumps(queryables).encode('UTF-8'))
+ with open(filename, "wb") as f:
+ f.write(json.dumps(queryables).encode("UTF-8"))
items = {
"type": "FeatureCollection",
"features": [
- {"type": "Feature", "id": "feat.1", "properties":
- {"strfield": "foo=bar",
- "strfield2": None,
- "intfield": 1,
- "doublefield": 1.5,
- "not_a_queryable": 3,
- "datetimefield": "2023-04-19T12:34:56Z",
- "datefield": "2023-04-19",
- "boolfield": True,
- "boolfield2": False},
- "geometry": {"type": "Point", "coordinates": [-70.5, 66.5]}}
- ]
+ {
+ "type": "Feature",
+ "id": "feat.1",
+ "properties": {
+ "strfield": "foo=bar",
+ "strfield2": None,
+ "intfield": 1,
+ "doublefield": 1.5,
+ "not_a_queryable": 3,
+ "datetimefield": "2023-04-19T12:34:56Z",
+ "datefield": "2023-04-19",
+ "boolfield": True,
+ "boolfield2": False,
+ },
+ "geometry": {"type": "Point", "coordinates": [-70.5, 66.5]},
+ }
+ ],
}
- filename = sanitize(endpoint, '/collections/mycollection/items?limit=10&' + ACCEPT_ITEMS)
- with open(filename, 'wb') as f:
- f.write(json.dumps(items).encode('UTF-8'))
+ filename = sanitize(
+ endpoint, "/collections/mycollection/items?limit=10&" + ACCEPT_ITEMS
+ )
+ with open(filename, "wb") as f:
+ f.write(json.dumps(items).encode("UTF-8"))
vl = QgsVectorLayer(
- "url='http://" + endpoint + "' typename='mycollection'", 'test', 'OAPIF')
+ "url='http://" + endpoint + "' typename='mycollection'", "test", "OAPIF"
+ )
self.assertTrue(vl.isValid())
os.unlink(filename)
tests = [
- (""""strfield" = 'foo=bar' and intfield = 1""",
- """filter=((strfield%20%3D%20'foo%3Dbar')%20AND%20(intfield%20%3D%201))&filter-lang=cql2-text"""),
- ("""doublefield = 1.5 or boolfield = true""",
- """filter=((doublefield%20%3D%201.5)%20OR%20(boolfield%20%3D%20TRUE))&filter-lang=cql2-text"""),
- ("boolfield2 = false", "filter=(boolfield2%20%3D%20FALSE)&filter-lang=cql2-text"""),
- ("NOT(intfield = 0)", """filter=(NOT%20((intfield%20%3D%200)))&filter-lang=cql2-text"""),
- ("intfield <> 0", """filter=(intfield%20%3C%3E%200)&filter-lang=cql2-text"""),
+ (
+ """"strfield" = 'foo=bar' and intfield = 1""",
+ """filter=((strfield%20%3D%20'foo%3Dbar')%20AND%20(intfield%20%3D%201))&filter-lang=cql2-text""",
+ ),
+ (
+ """doublefield = 1.5 or boolfield = true""",
+ """filter=((doublefield%20%3D%201.5)%20OR%20(boolfield%20%3D%20TRUE))&filter-lang=cql2-text""",
+ ),
+ (
+ "boolfield2 = false",
+ "filter=(boolfield2%20%3D%20FALSE)&filter-lang=cql2-text" "",
+ ),
+ (
+ "NOT(intfield = 0)",
+ """filter=(NOT%20((intfield%20%3D%200)))&filter-lang=cql2-text""",
+ ),
+ (
+ "intfield <> 0",
+ """filter=(intfield%20%3C%3E%200)&filter-lang=cql2-text""",
+ ),
("intfield > 0", """filter=(intfield%20%3E%200)&filter-lang=cql2-text"""),
- ("intfield >= 1", """filter=(intfield%20%3E%3D%201)&filter-lang=cql2-text"""),
+ (
+ "intfield >= 1",
+ """filter=(intfield%20%3E%3D%201)&filter-lang=cql2-text""",
+ ),
("intfield < 2", """filter=(intfield%20%3C%202)&filter-lang=cql2-text"""),
- ("intfield <= 1", """filter=(intfield%20%3C%3D%201)&filter-lang=cql2-text"""),
- ("intfield IN (1, 2)", """filter=intfield%20IN%20(1,2)&filter-lang=cql2-text"""),
- ("intfield NOT IN (3, 4)", """filter=intfield%20NOT%20IN%20(3,4)&filter-lang=cql2-text"""),
- ("intfield BETWEEN 0 AND 2", "filter=intfield%20BETWEEN%200%20AND%202&filter-lang=cql2-text"),
- ("intfield NOT BETWEEN 3 AND 4", "filter=intfield%20NOT%20BETWEEN%203%20AND%204&filter-lang=cql2-text"),
- ("strfield2 IS NULL", """filter=(strfield2%20IS%20NULL)&filter-lang=cql2-text"""),
- ("intfield IS NOT NULL", """filter=(intfield%20IS%20NOT%20NULL)&filter-lang=cql2-text"""),
- ("datetimefield = make_datetime(2023, 4, 19, 12, 34, 56)",
- "filter=(datetimefield%20%3D%20TIMESTAMP('2023-04-19T12:34:56.000Z'))&filter-lang=cql2-text"),
- ("datetimefield = '2023-04-19T12:34:56.000Z'",
- "filter=(datetimefield%20%3D%20TIMESTAMP('2023-04-19T12:34:56.000Z'))&filter-lang=cql2-text"),
- ("datefield = make_date(2023, 4, 19)",
- "filter=(datefield%20%3D%20DATE('2023-04-19'))&filter-lang=cql2-text"),
- ("datefield = '2023-04-19'",
- "filter=(datefield%20%3D%20DATE('2023-04-19'))&filter-lang=cql2-text"),
- (""""strfield" LIKE 'foo%'""",
- """filter=(strfield%20LIKE%20'foo%25')&filter-lang=cql2-text"""),
- (""""strfield" NOT LIKE 'bar'""",
- """filter=(strfield%20NOT%20LIKE%20'bar')&filter-lang=cql2-text"""),
- (""""strfield" ILIKE 'fo%'""",
- """filter=(CASEI(strfield)%20LIKE%20CASEI('fo%25'))&filter-lang=cql2-text"""),
- (""""strfield" NOT ILIKE 'bar'""",
- """filter=(CASEI(strfield)%20NOT%20LIKE%20CASEI('bar'))&filter-lang=cql2-text"""),
- ("""intersects_bbox($geometry, geomFromWkt('POLYGON((-180 -90,-180 90,180 90,180 -90,-180 -90))'))""",
- """filter=S_INTERSECTS(geometry,BBOX(-180,-90,180,90))&filter-lang=cql2-text"""),
- ("""intersects($geometry, geomFromWkt('POINT(-70.5 66.5))'))""",
- """filter=S_INTERSECTS(geometry,POINT(-70.5%2066.5))&filter-lang=cql2-text"""),
+ (
+ "intfield <= 1",
+ """filter=(intfield%20%3C%3D%201)&filter-lang=cql2-text""",
+ ),
+ (
+ "intfield IN (1, 2)",
+ """filter=intfield%20IN%20(1,2)&filter-lang=cql2-text""",
+ ),
+ (
+ "intfield NOT IN (3, 4)",
+ """filter=intfield%20NOT%20IN%20(3,4)&filter-lang=cql2-text""",
+ ),
+ (
+ "intfield BETWEEN 0 AND 2",
+ "filter=intfield%20BETWEEN%200%20AND%202&filter-lang=cql2-text",
+ ),
+ (
+ "intfield NOT BETWEEN 3 AND 4",
+ "filter=intfield%20NOT%20BETWEEN%203%20AND%204&filter-lang=cql2-text",
+ ),
+ (
+ "strfield2 IS NULL",
+ """filter=(strfield2%20IS%20NULL)&filter-lang=cql2-text""",
+ ),
+ (
+ "intfield IS NOT NULL",
+ """filter=(intfield%20IS%20NOT%20NULL)&filter-lang=cql2-text""",
+ ),
+ (
+ "datetimefield = make_datetime(2023, 4, 19, 12, 34, 56)",
+ "filter=(datetimefield%20%3D%20TIMESTAMP('2023-04-19T12:34:56.000Z'))&filter-lang=cql2-text",
+ ),
+ (
+ "datetimefield = '2023-04-19T12:34:56.000Z'",
+ "filter=(datetimefield%20%3D%20TIMESTAMP('2023-04-19T12:34:56.000Z'))&filter-lang=cql2-text",
+ ),
+ (
+ "datefield = make_date(2023, 4, 19)",
+ "filter=(datefield%20%3D%20DATE('2023-04-19'))&filter-lang=cql2-text",
+ ),
+ (
+ "datefield = '2023-04-19'",
+ "filter=(datefield%20%3D%20DATE('2023-04-19'))&filter-lang=cql2-text",
+ ),
+ (
+ """"strfield" LIKE 'foo%'""",
+ """filter=(strfield%20LIKE%20'foo%25')&filter-lang=cql2-text""",
+ ),
+ (
+ """"strfield" NOT LIKE 'bar'""",
+ """filter=(strfield%20NOT%20LIKE%20'bar')&filter-lang=cql2-text""",
+ ),
+ (
+ """"strfield" ILIKE 'fo%'""",
+ """filter=(CASEI(strfield)%20LIKE%20CASEI('fo%25'))&filter-lang=cql2-text""",
+ ),
+ (
+ """"strfield" NOT ILIKE 'bar'""",
+ """filter=(CASEI(strfield)%20NOT%20LIKE%20CASEI('bar'))&filter-lang=cql2-text""",
+ ),
+ (
+ """intersects_bbox($geometry, geomFromWkt('POLYGON((-180 -90,-180 90,180 90,180 -90,-180 -90))'))""",
+ """filter=S_INTERSECTS(geometry,BBOX(-180,-90,180,90))&filter-lang=cql2-text""",
+ ),
+ (
+ """intersects($geometry, geomFromWkt('POINT(-70.5 66.5))'))""",
+ """filter=S_INTERSECTS(geometry,POINT(-70.5%2066.5))&filter-lang=cql2-text""",
+ ),
# Partially evaluated on server
- ("intfield >= 1 AND not_a_queryable = 3", """filter=(intfield%20%3E%3D%201)&filter-lang=cql2-text"""),
- ("not_a_queryable = 3 AND intfield >= 1", """filter=(intfield%20%3E%3D%201)&filter-lang=cql2-text"""),
+ (
+ "intfield >= 1 AND not_a_queryable = 3",
+ """filter=(intfield%20%3E%3D%201)&filter-lang=cql2-text""",
+ ),
+ (
+ "not_a_queryable = 3 AND intfield >= 1",
+ """filter=(intfield%20%3E%3D%201)&filter-lang=cql2-text""",
+ ),
# Only evaluated on client
("intfield >= 1 OR not_a_queryable = 3", ""),
("not_a_queryable = 3 AND not_a_queryable = 3", ""),
]
- for (expr, cql_filter) in tests:
+ for expr, cql_filter in tests:
assert vl.setSubsetString(expr)
- filename = sanitize(endpoint,
- "/collections/mycollection/items?limit=1000&" + cql_filter + ("&" if cql_filter else "") + ACCEPT_ITEMS)
- with open(filename, 'wb') as f:
- f.write(json.dumps(items).encode('UTF-8'))
- values = [f['id'] for f in vl.getFeatures()]
+ filename = sanitize(
+ endpoint,
+ "/collections/mycollection/items?limit=1000&"
+ + cql_filter
+ + ("&" if cql_filter else "")
+ + ACCEPT_ITEMS,
+ )
+ with open(filename, "wb") as f:
+ f.write(json.dumps(items).encode("UTF-8"))
+ values = [f["id"] for f in vl.getFeatures()]
os.unlink(filename)
- self.assertEqual(values, ['feat.1'], expr)
+ self.assertEqual(values, ["feat.1"], expr)
def testCQL2TextFilteringAndPart2(self):
- endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_encoded_query_testCQL2TextFilteringAndPart2'
+ endpoint = (
+ self.__class__.basetestpath
+ + "/fake_qgis_http_endpoint_encoded_query_testCQL2TextFilteringAndPart2"
+ )
additionalConformance = [
"http://www.opengis.net/spec/cql2/1.0/conf/basic-cql2",
"http://www.opengis.net/spec/cql2/1.0/conf/basic-spatial-operators",
@@ -994,61 +1423,82 @@ def testCQL2TextFilteringAndPart2(self):
"http://www.opengis.net/spec/ogcapi-features-3/1.0/conf/filter",
]
- create_landing_page_api_collection(endpoint,
- storageCrs="http://www.opengis.net/def/crs/EPSG/0/4258",
- crsList=["http://www.opengis.net/def/crs/OGC/0/CRS84",
- "http://www.opengis.net/def/crs/EPSG/0/4258"],
- additionalConformance=additionalConformance)
+ create_landing_page_api_collection(
+ endpoint,
+ storageCrs="http://www.opengis.net/def/crs/EPSG/0/4258",
+ crsList=[
+ "http://www.opengis.net/def/crs/OGC/0/CRS84",
+ "http://www.opengis.net/def/crs/EPSG/0/4258",
+ ],
+ additionalConformance=additionalConformance,
+ )
- filename = sanitize(endpoint, '/collections/mycollection/queryables?' + ACCEPT_QUERYABLES)
+ filename = sanitize(
+ endpoint, "/collections/mycollection/queryables?" + ACCEPT_QUERYABLES
+ )
queryables = {
"properties": {
- "geometry": {
- "$ref": "https://geojson.org/schema/Point.json"
- },
+ "geometry": {"$ref": "https://geojson.org/schema/Point.json"},
}
}
- with open(filename, 'wb') as f:
- f.write(json.dumps(queryables).encode('UTF-8'))
+ with open(filename, "wb") as f:
+ f.write(json.dumps(queryables).encode("UTF-8"))
items = {
"type": "FeatureCollection",
"features": [
- {"type": "Feature", "id": "feat.1", "properties":
- {},
- # lat, long order
- "geometry": {"type": "Point", "coordinates": [49, 2]}}
- ]
+ {
+ "type": "Feature",
+ "id": "feat.1",
+ "properties": {},
+ # lat, long order
+ "geometry": {"type": "Point", "coordinates": [49, 2]},
+ }
+ ],
}
- filename = sanitize(endpoint, '/collections/mycollection/items?limit=10&' + ACCEPT_ITEMS)
- with open(filename, 'wb') as f:
- f.write(json.dumps(items).encode('UTF-8'))
+ filename = sanitize(
+ endpoint, "/collections/mycollection/items?limit=10&" + ACCEPT_ITEMS
+ )
+ with open(filename, "wb") as f:
+ f.write(json.dumps(items).encode("UTF-8"))
vl = QgsVectorLayer(
- "url='http://" + endpoint + "' typename='mycollection'", 'test', 'OAPIF')
+ "url='http://" + endpoint + "' typename='mycollection'", "test", "OAPIF"
+ )
self.assertTrue(vl.isValid())
os.unlink(filename)
tests = [
- ("""intersects($geometry, geomFromWkt('POINT(2 49))'))""",
- """filter=S_INTERSECTS(geometry,POINT(49%202))&filter-lang=cql2-text&filter-crs=http://www.opengis.net/def/crs/EPSG/0/4258"""),
+ (
+ """intersects($geometry, geomFromWkt('POINT(2 49))'))""",
+ """filter=S_INTERSECTS(geometry,POINT(49%202))&filter-lang=cql2-text&filter-crs=http://www.opengis.net/def/crs/EPSG/0/4258""",
+ ),
]
- for (expr, cql_filter) in tests:
+ for expr, cql_filter in tests:
assert vl.setSubsetString(expr)
- filename = sanitize(endpoint,
- "/collections/mycollection/items?limit=1000&" + cql_filter + ("&" if cql_filter else "") + "crs=http://www.opengis.net/def/crs/EPSG/0/4258&" + ACCEPT_ITEMS)
- with open(filename, 'wb') as f:
- f.write(json.dumps(items).encode('UTF-8'))
- values = [f['id'] for f in vl.getFeatures()]
+ filename = sanitize(
+ endpoint,
+ "/collections/mycollection/items?limit=1000&"
+ + cql_filter
+ + ("&" if cql_filter else "")
+ + "crs=http://www.opengis.net/def/crs/EPSG/0/4258&"
+ + ACCEPT_ITEMS,
+ )
+ with open(filename, "wb") as f:
+ f.write(json.dumps(items).encode("UTF-8"))
+ values = [f["id"] for f in vl.getFeatures()]
os.unlink(filename)
- self.assertEqual(values, ['feat.1'], expr)
+ self.assertEqual(values, ["feat.1"], expr)
def testCQL2TextFilteringGetFeaturesExpression(self):
"""Test Part 3 CQL2-Text filtering"""
- endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_encoded_query_testCQL2TextFilteringGetFeaturesExpression'
+ endpoint = (
+ self.__class__.basetestpath
+ + "/fake_qgis_http_endpoint_encoded_query_testCQL2TextFilteringGetFeaturesExpression"
+ )
additionalConformance = [
"http://www.opengis.net/spec/cql2/1.0/conf/basic-cql2",
"http://www.opengis.net/spec/cql2/1.0/conf/cql2-text",
@@ -1056,228 +1506,428 @@ def testCQL2TextFilteringGetFeaturesExpression(self):
"http://www.opengis.net/spec/ogcapi-features-3/1.0/conf/filter",
]
- create_landing_page_api_collection(endpoint, additionalConformance=additionalConformance)
+ create_landing_page_api_collection(
+ endpoint, additionalConformance=additionalConformance
+ )
- filename = sanitize(endpoint, '/collections/mycollection/queryables?' + ACCEPT_QUERYABLES)
+ filename = sanitize(
+ endpoint, "/collections/mycollection/queryables?" + ACCEPT_QUERYABLES
+ )
queryables = {
"properties": {
- "strfield": {
- "type": "string"
- },
- "geometry": {
- "$ref": "https://geojson.org/schema/Point.json"
- },
+ "strfield": {"type": "string"},
+ "geometry": {"$ref": "https://geojson.org/schema/Point.json"},
}
}
- with open(filename, 'wb') as f:
- f.write(json.dumps(queryables).encode('UTF-8'))
+ with open(filename, "wb") as f:
+ f.write(json.dumps(queryables).encode("UTF-8"))
items = {
"type": "FeatureCollection",
"features": [
- {"type": "Feature", "id": "feat.1", "properties":
- {
- "strfield": "foo=bar",
- },
- "geometry": {"type": "Point", "coordinates": [-70.5, 66.5]}}
- ]
+ {
+ "type": "Feature",
+ "id": "feat.1",
+ "properties": {
+ "strfield": "foo=bar",
+ },
+ "geometry": {"type": "Point", "coordinates": [-70.5, 66.5]},
+ }
+ ],
}
- filename = sanitize(endpoint, '/collections/mycollection/items?limit=10&' + ACCEPT_ITEMS)
- with open(filename, 'wb') as f:
- f.write(json.dumps(items).encode('UTF-8'))
+ filename = sanitize(
+ endpoint, "/collections/mycollection/items?limit=10&" + ACCEPT_ITEMS
+ )
+ with open(filename, "wb") as f:
+ f.write(json.dumps(items).encode("UTF-8"))
vl = QgsVectorLayer(
- "url='http://" + endpoint + "' typename='mycollection'", 'test', 'OAPIF')
+ "url='http://" + endpoint + "' typename='mycollection'", "test", "OAPIF"
+ )
self.assertTrue(vl.isValid())
os.unlink(filename)
tests = [
- ("", """"strfield" = 'foo=bar'""",
- """filter=(strfield%20%3D%20'foo%3Dbar')&filter-lang=cql2-text"""),
- ("strfield <> 'x'", """"strfield" = 'foo=bar'""",
- """filter=((strfield%20%3C%3E%20'x'))%20AND%20((strfield%20%3D%20'foo%3Dbar'))&filter-lang=cql2-text"""),
+ (
+ "",
+ """"strfield" = 'foo=bar'""",
+ """filter=(strfield%20%3D%20'foo%3Dbar')&filter-lang=cql2-text""",
+ ),
+ (
+ "strfield <> 'x'",
+ """"strfield" = 'foo=bar'""",
+ """filter=((strfield%20%3C%3E%20'x'))%20AND%20((strfield%20%3D%20'foo%3Dbar'))&filter-lang=cql2-text""",
+ ),
]
- for (substring_expr, getfeatures_expr, cql_filter) in tests:
+ for substring_expr, getfeatures_expr, cql_filter in tests:
assert vl.setSubsetString(substring_expr)
- filename = sanitize(endpoint,
- "/collections/mycollection/items?limit=1000&" + cql_filter + ("&" if cql_filter else "") + ACCEPT_ITEMS)
- with open(filename, 'wb') as f:
- f.write(json.dumps(items).encode('UTF-8'))
+ filename = sanitize(
+ endpoint,
+ "/collections/mycollection/items?limit=1000&"
+ + cql_filter
+ + ("&" if cql_filter else "")
+ + ACCEPT_ITEMS,
+ )
+ with open(filename, "wb") as f:
+ f.write(json.dumps(items).encode("UTF-8"))
request = QgsFeatureRequest()
if getfeatures_expr:
request.setFilterExpression(getfeatures_expr)
- values = [f['id'] for f in vl.getFeatures(request)]
+ values = [f["id"] for f in vl.getFeatures(request)]
os.unlink(filename)
- self.assertEqual(values, ['feat.1'], (substring_expr, getfeatures_expr))
+ self.assertEqual(values, ["feat.1"], (substring_expr, getfeatures_expr))
def testStringList(self):
- endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_testStringList'
+ endpoint = (
+ self.__class__.basetestpath + "/fake_qgis_http_endpoint_testStringList"
+ )
create_landing_page_api_collection(endpoint)
items = {
"type": "FeatureCollection",
"features": [
- {"type": "Feature", "id": "feat.1", "properties": {"my_stringlist_field": ["a", "b"]},
- "geometry": {"type": "Point", "coordinates": [-70.332, 66.33]}}
- ]
+ {
+ "type": "Feature",
+ "id": "feat.1",
+ "properties": {"my_stringlist_field": ["a", "b"]},
+ "geometry": {"type": "Point", "coordinates": [-70.332, 66.33]},
+ }
+ ],
}
- filename = sanitize(endpoint, '/collections/mycollection/items?limit=10&' + ACCEPT_ITEMS)
- with open(filename, 'wb') as f:
- f.write(json.dumps(items).encode('UTF-8'))
+ filename = sanitize(
+ endpoint, "/collections/mycollection/items?limit=10&" + ACCEPT_ITEMS
+ )
+ with open(filename, "wb") as f:
+ f.write(json.dumps(items).encode("UTF-8"))
- vl = QgsVectorLayer("url='http://" + endpoint + "' typename='mycollection'", 'test', 'OAPIF')
+ vl = QgsVectorLayer(
+ "url='http://" + endpoint + "' typename='mycollection'", "test", "OAPIF"
+ )
self.assertTrue(vl.isValid())
os.unlink(filename)
- filename = sanitize(endpoint, '/collections/mycollection/items?limit=1000&' + ACCEPT_ITEMS)
- with open(filename, 'wb') as f:
- f.write(json.dumps(items).encode('UTF-8'))
+ filename = sanitize(
+ endpoint, "/collections/mycollection/items?limit=1000&" + ACCEPT_ITEMS
+ )
+ with open(filename, "wb") as f:
+ f.write(json.dumps(items).encode("UTF-8"))
features = [f for f in vl.getFeatures()]
os.unlink(filename)
- self.assertEqual(features[0]['my_stringlist_field'], ["a", "b"])
+ self.assertEqual(features[0]["my_stringlist_field"], ["a", "b"])
def testApikey(self):
- endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_apikey'
- create_landing_page_api_collection(endpoint, extraparam='apikey=mykey')
+ endpoint = self.__class__.basetestpath + "/fake_qgis_http_endpoint_apikey"
+ create_landing_page_api_collection(endpoint, extraparam="apikey=mykey")
# first items
first_items = {
"type": "FeatureCollection",
"features": [
- {"type": "Feature", "id": "feat.1", "properties": {"pk": 1, "cnt": 100},
- "geometry": {"type": "Point", "coordinates": [-70.332, 66.33]}}
- ]
+ {
+ "type": "Feature",
+ "id": "feat.1",
+ "properties": {"pk": 1, "cnt": 100},
+ "geometry": {"type": "Point", "coordinates": [-70.332, 66.33]},
+ }
+ ],
}
- with open(sanitize(endpoint, '/collections/mycollection/items?limit=10&apikey=mykey&' + ACCEPT_ITEMS), 'wb') as f:
- f.write(json.dumps(first_items).encode('UTF-8'))
+ with open(
+ sanitize(
+ endpoint,
+ "/collections/mycollection/items?limit=10&apikey=mykey&" + ACCEPT_ITEMS,
+ ),
+ "wb",
+ ) as f:
+ f.write(json.dumps(first_items).encode("UTF-8"))
- with open(sanitize(endpoint, '/collections/mycollection/items?limit=1000&apikey=mykey&' + ACCEPT_ITEMS), 'wb') as f:
- f.write(json.dumps(first_items).encode('UTF-8'))
+ with open(
+ sanitize(
+ endpoint,
+ "/collections/mycollection/items?limit=1000&apikey=mykey&"
+ + ACCEPT_ITEMS,
+ ),
+ "wb",
+ ) as f:
+ f.write(json.dumps(first_items).encode("UTF-8"))
app_log = QgsApplication.messageLog()
# signals should be emitted by application log
app_spy = QSignalSpy(app_log.messageReceived)
- vl = QgsVectorLayer("url='http://" + endpoint + "?apikey=mykey' typename='mycollection'", 'test', 'OAPIF')
+ vl = QgsVectorLayer(
+ "url='http://" + endpoint + "?apikey=mykey' typename='mycollection'",
+ "test",
+ "OAPIF",
+ )
self.assertTrue(vl.isValid())
- values = [f['id'] for f in vl.getFeatures()]
- self.assertEqual(values, ['feat.1'])
+ values = [f["id"] for f in vl.getFeatures()]
+ self.assertEqual(values, ["feat.1"])
self.assertEqual(len(app_spy), 0, list(app_spy))
def testDefaultCRS(self):
# On Windows we must make sure that any backslash in the path is
# replaced by a forward slash so that QUrl can process it
- basetestpath = tempfile.mkdtemp().replace('\\', '/')
- endpoint = basetestpath + '/fake_qgis_http_endpoint_ogc84'
+ basetestpath = tempfile.mkdtemp().replace("\\", "/")
+ endpoint = basetestpath + "/fake_qgis_http_endpoint_ogc84"
- create_landing_page_api_collection(endpoint,
- bbox=[66.33, -71.123, 78.3, -65.32])
+ create_landing_page_api_collection(
+ endpoint, bbox=[66.33, -71.123, 78.3, -65.32]
+ )
items = {
"type": "FeatureCollection",
"features": [
- {"type": "Feature", "id": "feat.1",
- "properties": {"pk": 1, "cnt": 100, "name": "Orange", "name2": "oranGe", "num_char": "1", "dt": "2020-05-03 12:13:14", "date": "2020-05-03", "time": "12:13:14"},
- "geometry": {"type": "Point", "coordinates": [66.33, -70.332]}},
- {"type": "Feature", "id": "feat.2",
- "properties": {"pk": 2, "cnt": 200, "name": "Apple", "name2": "Apple", "num_char": "2", "dt": "2020-05-04 12:14:14", "date": "2020-05-04", "time": "12:14:14"},
- "geometry": {"type": "Point", "coordinates": [70.8, -68.2]}},
- {"type": "Feature", "id": "feat.3",
- "properties": {"pk": 4, "cnt": 400, "name": "Honey", "name2": "Honey", "num_char": "4", "dt": "2021-05-04 13:13:14", "date": "2021-05-04", "time": "13:13:14"},
- "geometry": {"type": "Point", "coordinates": [78.3, -65.32]}},
- {"type": "Feature", "id": "feat.4",
- "properties": {"pk": 3, "cnt": 300, "name": "Pear", "name2": "PEaR", "num_char": "3"},
- "geometry": None},
- {"type": "Feature", "id": "feat.5",
- "properties": {"pk": 5, "cnt": -200, "name": None, "name2": "NuLl", "num_char": "5", "dt": "2020-05-04 12:13:14", "date": "2020-05-02", "time": "12:13:01"},
- "geometry": {"type": "Point", "coordinates": [78.23, -71.123]}}
- ]
+ {
+ "type": "Feature",
+ "id": "feat.1",
+ "properties": {
+ "pk": 1,
+ "cnt": 100,
+ "name": "Orange",
+ "name2": "oranGe",
+ "num_char": "1",
+ "dt": "2020-05-03 12:13:14",
+ "date": "2020-05-03",
+ "time": "12:13:14",
+ },
+ "geometry": {"type": "Point", "coordinates": [66.33, -70.332]},
+ },
+ {
+ "type": "Feature",
+ "id": "feat.2",
+ "properties": {
+ "pk": 2,
+ "cnt": 200,
+ "name": "Apple",
+ "name2": "Apple",
+ "num_char": "2",
+ "dt": "2020-05-04 12:14:14",
+ "date": "2020-05-04",
+ "time": "12:14:14",
+ },
+ "geometry": {"type": "Point", "coordinates": [70.8, -68.2]},
+ },
+ {
+ "type": "Feature",
+ "id": "feat.3",
+ "properties": {
+ "pk": 4,
+ "cnt": 400,
+ "name": "Honey",
+ "name2": "Honey",
+ "num_char": "4",
+ "dt": "2021-05-04 13:13:14",
+ "date": "2021-05-04",
+ "time": "13:13:14",
+ },
+ "geometry": {"type": "Point", "coordinates": [78.3, -65.32]},
+ },
+ {
+ "type": "Feature",
+ "id": "feat.4",
+ "properties": {
+ "pk": 3,
+ "cnt": 300,
+ "name": "Pear",
+ "name2": "PEaR",
+ "num_char": "3",
+ },
+ "geometry": None,
+ },
+ {
+ "type": "Feature",
+ "id": "feat.5",
+ "properties": {
+ "pk": 5,
+ "cnt": -200,
+ "name": None,
+ "name2": "NuLl",
+ "num_char": "5",
+ "dt": "2020-05-04 12:13:14",
+ "date": "2020-05-02",
+ "time": "12:13:01",
+ },
+ "geometry": {"type": "Point", "coordinates": [78.23, -71.123]},
+ },
+ ],
}
# first items
- with open(sanitize(endpoint, '/collections/mycollection/items?limit=10&' + ACCEPT_ITEMS), 'wb') as f:
- f.write(json.dumps(items).encode('UTF-8'))
+ with open(
+ sanitize(
+ endpoint, "/collections/mycollection/items?limit=10&" + ACCEPT_ITEMS
+ ),
+ "wb",
+ ) as f:
+ f.write(json.dumps(items).encode("UTF-8"))
# real page
- with open(sanitize(endpoint, '/collections/mycollection/items?limit=1000&' + ACCEPT_ITEMS), 'wb') as f:
- f.write(json.dumps(items).encode('UTF-8'))
+ with open(
+ sanitize(
+ endpoint, "/collections/mycollection/items?limit=1000&" + ACCEPT_ITEMS
+ ),
+ "wb",
+ ) as f:
+ f.write(json.dumps(items).encode("UTF-8"))
# Create test layer
- vl = QgsVectorLayer("url='http://" + endpoint + "' typename='mycollection'", 'test', 'OAPIF')
+ vl = QgsVectorLayer(
+ "url='http://" + endpoint + "' typename='mycollection'", "test", "OAPIF"
+ )
assert vl.isValid()
source = vl.dataProvider()
- self.assertEqual(source.sourceCrs().authid(), 'OGC:CRS84')
+ self.assertEqual(source.sourceCrs().authid(), "OGC:CRS84")
def testCRS2056(self):
# On Windows we must make sure that any backslash in the path is
# replaced by a forward slash so that QUrl can process it
- basetestpath = tempfile.mkdtemp().replace('\\', '/')
- endpoint = basetestpath + '/fake_qgis_http_endpoint_epsg_2056'
-
- create_landing_page_api_collection(endpoint,
- storageCrs="http://www.opengis.net/def/crs/EPSG/0/2056",
- crsList=["http://www.opengis.net/def/crs/OGC/0/CRS84", "http://www.opengis.net/def/crs/EPSG/0/2056"])
+ basetestpath = tempfile.mkdtemp().replace("\\", "/")
+ endpoint = basetestpath + "/fake_qgis_http_endpoint_epsg_2056"
+
+ create_landing_page_api_collection(
+ endpoint,
+ storageCrs="http://www.opengis.net/def/crs/EPSG/0/2056",
+ crsList=[
+ "http://www.opengis.net/def/crs/OGC/0/CRS84",
+ "http://www.opengis.net/def/crs/EPSG/0/2056",
+ ],
+ )
items = {
"type": "FeatureCollection",
"features": [
- {"type": "Feature", "id": "feat.1",
- "properties": {"pk": 1, "cnt": 100, "name": "Orange", "name2": "oranGe", "num_char": "1", "dt": "2020-05-03 12:13:14", "date": "2020-05-03", "time": "12:13:14"},
- "geometry": {"type": "Point", "coordinates": [2510100, 1155050]}},
- {"type": "Feature", "id": "feat.2",
- "properties": {"pk": 2, "cnt": 200, "name": "Apple", "name2": "Apple", "num_char": "2", "dt": "2020-05-04 12:14:14", "date": "2020-05-04", "time": "12:14:14"},
- "geometry": {"type": "Point", "coordinates": [2511250, 1154600]}},
- {"type": "Feature", "id": "feat.3",
- "properties": {"pk": 4, "cnt": 400, "name": "Honey", "name2": "Honey", "num_char": "4", "dt": "2021-05-04 13:13:14", "date": "2021-05-04", "time": "13:13:14"},
- "geometry": {"type": "Point", "coordinates": [2511260, 1154610]}},
- {"type": "Feature", "id": "feat.4",
- "properties": {"pk": 3, "cnt": 300, "name": "Pear", "name2": "PEaR", "num_char": "3"},
- "geometry": None},
- {"type": "Feature", "id": "feat.5",
- "properties": {"pk": 5, "cnt": -200, "name": None, "name2": "NuLl", "num_char": "5", "dt": "2020-05-04 12:13:14", "date": "2020-05-02", "time": "12:13:01"},
- "geometry": {"type": "Point", "coordinates": [2511270, 1154620]}}
- ]
+ {
+ "type": "Feature",
+ "id": "feat.1",
+ "properties": {
+ "pk": 1,
+ "cnt": 100,
+ "name": "Orange",
+ "name2": "oranGe",
+ "num_char": "1",
+ "dt": "2020-05-03 12:13:14",
+ "date": "2020-05-03",
+ "time": "12:13:14",
+ },
+ "geometry": {"type": "Point", "coordinates": [2510100, 1155050]},
+ },
+ {
+ "type": "Feature",
+ "id": "feat.2",
+ "properties": {
+ "pk": 2,
+ "cnt": 200,
+ "name": "Apple",
+ "name2": "Apple",
+ "num_char": "2",
+ "dt": "2020-05-04 12:14:14",
+ "date": "2020-05-04",
+ "time": "12:14:14",
+ },
+ "geometry": {"type": "Point", "coordinates": [2511250, 1154600]},
+ },
+ {
+ "type": "Feature",
+ "id": "feat.3",
+ "properties": {
+ "pk": 4,
+ "cnt": 400,
+ "name": "Honey",
+ "name2": "Honey",
+ "num_char": "4",
+ "dt": "2021-05-04 13:13:14",
+ "date": "2021-05-04",
+ "time": "13:13:14",
+ },
+ "geometry": {"type": "Point", "coordinates": [2511260, 1154610]},
+ },
+ {
+ "type": "Feature",
+ "id": "feat.4",
+ "properties": {
+ "pk": 3,
+ "cnt": 300,
+ "name": "Pear",
+ "name2": "PEaR",
+ "num_char": "3",
+ },
+ "geometry": None,
+ },
+ {
+ "type": "Feature",
+ "id": "feat.5",
+ "properties": {
+ "pk": 5,
+ "cnt": -200,
+ "name": None,
+ "name2": "NuLl",
+ "num_char": "5",
+ "dt": "2020-05-04 12:13:14",
+ "date": "2020-05-02",
+ "time": "12:13:01",
+ },
+ "geometry": {"type": "Point", "coordinates": [2511270, 1154620]},
+ },
+ ],
}
# first items
- with open(sanitize(endpoint, '/collections/mycollection/items?limit=10&' + ACCEPT_ITEMS), 'wb') as f:
- f.write(json.dumps(items).encode('UTF-8'))
+ with open(
+ sanitize(
+ endpoint, "/collections/mycollection/items?limit=10&" + ACCEPT_ITEMS
+ ),
+ "wb",
+ ) as f:
+ f.write(json.dumps(items).encode("UTF-8"))
# real page
- with open(sanitize(endpoint, '/collections/mycollection/items?limit=1000&' + ACCEPT_ITEMS), 'wb') as f:
- f.write(json.dumps(items).encode('UTF-8'))
+ with open(
+ sanitize(
+ endpoint, "/collections/mycollection/items?limit=1000&" + ACCEPT_ITEMS
+ ),
+ "wb",
+ ) as f:
+ f.write(json.dumps(items).encode("UTF-8"))
# Create test layer
- vl = QgsVectorLayer("url='http://" + endpoint + "' typename='mycollection'", 'test', 'OAPIF')
+ vl = QgsVectorLayer(
+ "url='http://" + endpoint + "' typename='mycollection'", "test", "OAPIF"
+ )
assert vl.isValid()
source = vl.dataProvider()
- self.assertEqual(source.sourceCrs().authid(), 'EPSG:2056')
+ self.assertEqual(source.sourceCrs().authid(), "EPSG:2056")
# Test srsname parameter overrides default CRS
- vl = QgsVectorLayer("url='http://" + endpoint + "' typename='mycollection' srsname='OGC:CRS84'", 'test', 'OAPIF')
+ vl = QgsVectorLayer(
+ "url='http://" + endpoint + "' typename='mycollection' srsname='OGC:CRS84'",
+ "test",
+ "OAPIF",
+ )
assert vl.isValid()
source = vl.dataProvider()
- self.assertEqual(source.sourceCrs().authid(), 'OGC:CRS84')
+ self.assertEqual(source.sourceCrs().authid(), "OGC:CRS84")
def testFeatureCountFallbackAndNoBboxInCollection(self):
# On Windows we must make sure that any backslash in the path is
# replaced by a forward slash so that QUrl can process it
- basetestpath = tempfile.mkdtemp().replace('\\', '/')
- endpoint = basetestpath + '/fake_qgis_http_endpoint_feature_count_fallback'
+ basetestpath = tempfile.mkdtemp().replace("\\", "/")
+ endpoint = basetestpath + "/fake_qgis_http_endpoint_feature_count_fallback"
- create_landing_page_api_collection(endpoint, storageCrs="http://www.opengis.net/def/crs/EPSG/0/2056", bbox=None)
+ create_landing_page_api_collection(
+ endpoint, storageCrs="http://www.opengis.net/def/crs/EPSG/0/2056", bbox=None
+ )
items = {
"type": "FeatureCollection",
@@ -1285,20 +1935,35 @@ def testFeatureCountFallbackAndNoBboxInCollection(self):
"links": [
# should not be hit
{"href": "http://" + endpoint + "/next_page", "rel": "next"}
- ]
+ ],
}
for i in range(10):
- items["features"].append({"type": "Feature", "id": f"feat.{i}",
- "properties": {},
- "geometry": {"type": "Point", "coordinates": [23, 63]}})
+ items["features"].append(
+ {
+ "type": "Feature",
+ "id": f"feat.{i}",
+ "properties": {},
+ "geometry": {"type": "Point", "coordinates": [23, 63]},
+ }
+ )
# first items
- with open(sanitize(endpoint, '/collections/mycollection/items?limit=1&' + ACCEPT_ITEMS), 'wb') as f:
- f.write(json.dumps(items).encode('UTF-8'))
+ with open(
+ sanitize(
+ endpoint, "/collections/mycollection/items?limit=1&" + ACCEPT_ITEMS
+ ),
+ "wb",
+ ) as f:
+ f.write(json.dumps(items).encode("UTF-8"))
# first items
- with open(sanitize(endpoint, '/collections/mycollection/items?limit=10&' + ACCEPT_ITEMS), 'wb') as f:
- f.write(json.dumps(items).encode('UTF-8'))
+ with open(
+ sanitize(
+ endpoint, "/collections/mycollection/items?limit=10&" + ACCEPT_ITEMS
+ ),
+ "wb",
+ ) as f:
+ f.write(json.dumps(items).encode("UTF-8"))
# real page
@@ -1308,29 +1973,44 @@ def testFeatureCountFallbackAndNoBboxInCollection(self):
"links": [
# should not be hit
{"href": "http://" + endpoint + "/next_page", "rel": "next"}
- ]
+ ],
}
for i in range(1001):
- items["features"].append({"type": "Feature", "id": f"feat.{i}",
- "properties": {},
- "geometry": None})
+ items["features"].append(
+ {
+ "type": "Feature",
+ "id": f"feat.{i}",
+ "properties": {},
+ "geometry": None,
+ }
+ )
- with open(sanitize(endpoint, '/collections/mycollection/items?limit=1000&crs=http://www.opengis.net/def/crs/EPSG/0/2056&' + ACCEPT_ITEMS), 'wb') as f:
- f.write(json.dumps(items).encode('UTF-8'))
+ with open(
+ sanitize(
+ endpoint,
+ "/collections/mycollection/items?limit=1000&crs=http://www.opengis.net/def/crs/EPSG/0/2056&"
+ + ACCEPT_ITEMS,
+ ),
+ "wb",
+ ) as f:
+ f.write(json.dumps(items).encode("UTF-8"))
# Create test layer
- vl = QgsVectorLayer("url='http://" + endpoint + "' typename='mycollection'", 'test', 'OAPIF')
+ vl = QgsVectorLayer(
+ "url='http://" + endpoint + "' typename='mycollection'", "test", "OAPIF"
+ )
assert vl.isValid()
source = vl.dataProvider()
# Extent got from first fetched features
reference = QgsGeometry.fromRect(
- QgsRectangle(3415684, 3094884,
- 3415684, 3094884))
+ QgsRectangle(3415684, 3094884, 3415684, 3094884)
+ )
vl_extent = QgsGeometry.fromRect(vl.extent())
- assert QgsGeometry.compare(vl_extent.asPolygon()[0], reference.asPolygon()[0],
- 10), f'Expected {reference.asWkt()}, got {vl_extent.asWkt()}'
+ assert QgsGeometry.compare(
+ vl_extent.asPolygon()[0], reference.asPolygon()[0], 10
+ ), f"Expected {reference.asWkt()}, got {vl_extent.asWkt()}"
app_log = QgsApplication.messageLog()
# signals should be emitted by application log
@@ -1342,73 +2022,148 @@ def testFeatureCountFallbackAndNoBboxInCollection(self):
def testFeatureInsertionDeletion(self):
- endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_testFeatureInsertion'
+ endpoint = (
+ self.__class__.basetestpath
+ + "/fake_qgis_http_endpoint_testFeatureInsertion"
+ )
create_landing_page_api_collection(endpoint)
# first items
first_items = {
"type": "FeatureCollection",
"features": [
- {"type": "Feature", "id": "feat.1", "properties": {"pk": 1, "cnt": 100},
- "geometry": {"type": "Point", "coordinates": [66.33, -70.332]}}
- ]
+ {
+ "type": "Feature",
+ "id": "feat.1",
+ "properties": {"pk": 1, "cnt": 100},
+ "geometry": {"type": "Point", "coordinates": [66.33, -70.332]},
+ }
+ ],
}
- with open(sanitize(endpoint, '/collections/mycollection/items?limit=10&' + ACCEPT_ITEMS), 'wb') as f:
- f.write(json.dumps(first_items).encode('UTF-8'))
+ with open(
+ sanitize(
+ endpoint, "/collections/mycollection/items?limit=10&" + ACCEPT_ITEMS
+ ),
+ "wb",
+ ) as f:
+ f.write(json.dumps(first_items).encode("UTF-8"))
- vl = QgsVectorLayer("url='http://" + endpoint + "' typename='mycollection' restrictToRequestBBOX=1", 'test',
- 'OAPIF')
+ vl = QgsVectorLayer(
+ "url='http://"
+ + endpoint
+ + "' typename='mycollection' restrictToRequestBBOX=1",
+ "test",
+ "OAPIF",
+ )
self.assertTrue(vl.isValid())
# Basic OPTIONS response: no AddFeatures capability
- self.assertEqual(vl.dataProvider().capabilities() & vl.dataProvider().AddFeatures,
- vl.dataProvider().NoCapabilities)
+ self.assertEqual(
+ vl.dataProvider().capabilities() & vl.dataProvider().AddFeatures,
+ vl.dataProvider().NoCapabilities,
+ )
# POST on /items, but no DELETE on /items/id
- with open(sanitize(endpoint, '/collections/mycollection/items?VERB=OPTIONS'), 'wb') as f:
- f.write("HEAD, GET, POST".encode("UTF-8"))
- with open(sanitize(endpoint, '/collections/mycollection/items/feat.1?VERB=OPTIONS'), 'wb') as f:
- f.write("HEAD, GET".encode("UTF-8"))
+ with open(
+ sanitize(endpoint, "/collections/mycollection/items?VERB=OPTIONS"), "wb"
+ ) as f:
+ f.write(b"HEAD, GET, POST")
+ with open(
+ sanitize(endpoint, "/collections/mycollection/items/feat.1?VERB=OPTIONS"),
+ "wb",
+ ) as f:
+ f.write(b"HEAD, GET")
- vl = QgsVectorLayer("url='http://" + endpoint + "' typename='mycollection' restrictToRequestBBOX=1", 'test',
- 'OAPIF')
+ vl = QgsVectorLayer(
+ "url='http://"
+ + endpoint
+ + "' typename='mycollection' restrictToRequestBBOX=1",
+ "test",
+ "OAPIF",
+ )
self.assertTrue(vl.isValid())
- self.assertNotEqual(vl.dataProvider().capabilities() & vl.dataProvider().AddFeatures,
- vl.dataProvider().NoCapabilities)
- self.assertEqual(vl.dataProvider().capabilities() & vl.dataProvider().DeleteFeatures,
- vl.dataProvider().NoCapabilities)
+ self.assertNotEqual(
+ vl.dataProvider().capabilities() & vl.dataProvider().AddFeatures,
+ vl.dataProvider().NoCapabilities,
+ )
+ self.assertEqual(
+ vl.dataProvider().capabilities() & vl.dataProvider().DeleteFeatures,
+ vl.dataProvider().NoCapabilities,
+ )
# DELETE on /items/id
- with open(sanitize(endpoint, '/collections/mycollection/items/feat.1?VERB=OPTIONS'), 'wb') as f:
- f.write("HEAD, GET, DELETE".encode("UTF-8"))
+ with open(
+ sanitize(endpoint, "/collections/mycollection/items/feat.1?VERB=OPTIONS"),
+ "wb",
+ ) as f:
+ f.write(b"HEAD, GET, DELETE")
- vl = QgsVectorLayer("url='http://" + endpoint + "' typename='mycollection' restrictToRequestBBOX=1", 'test',
- 'OAPIF')
+ vl = QgsVectorLayer(
+ "url='http://"
+ + endpoint
+ + "' typename='mycollection' restrictToRequestBBOX=1",
+ "test",
+ "OAPIF",
+ )
self.assertTrue(vl.isValid())
- self.assertNotEqual(vl.dataProvider().capabilities() & vl.dataProvider().AddFeatures,
- vl.dataProvider().NoCapabilities)
- self.assertNotEqual(vl.dataProvider().capabilities() & vl.dataProvider().DeleteFeatures,
- vl.dataProvider().NoCapabilities)
+ self.assertNotEqual(
+ vl.dataProvider().capabilities() & vl.dataProvider().AddFeatures,
+ vl.dataProvider().NoCapabilities,
+ )
+ self.assertNotEqual(
+ vl.dataProvider().capabilities() & vl.dataProvider().DeleteFeatures,
+ vl.dataProvider().NoCapabilities,
+ )
- with open(sanitize(endpoint, '/collections/mycollection/items?POSTDATA={"geometry":{"coordinates":[2.0,49.0],"type":"Point"},"properties":{"cnt":1234567890123,"pk":1},"type":"Feature"}'), 'wb') as f:
+ with open(
+ sanitize(
+ endpoint,
+ '/collections/mycollection/items?POSTDATA={"geometry":{"coordinates":[2.0,49.0],"type":"Point"},"properties":{"cnt":1234567890123,"pk":1},"type":"Feature"}',
+ ),
+ "wb",
+ ) as f:
f.write(b"Location: /collections/mycollection/items/new_id\r\n")
- with open(sanitize(endpoint, '/collections/mycollection/items?POSTDATA={"geometry":null,"properties":{"cnt":null,"pk":null},"type":"Feature"}'), 'wb') as f:
+ with open(
+ sanitize(
+ endpoint,
+ '/collections/mycollection/items?POSTDATA={"geometry":null,"properties":{"cnt":null,"pk":null},"type":"Feature"}',
+ ),
+ "wb",
+ ) as f:
f.write(b"Location: /collections/mycollection/items/other_id\r\n")
- new_id = {"type": "Feature", "id": "new_id", "properties": {"pk": 1, "cnt": 1234567890123},
- "geometry": {"type": "Point", "coordinates": [2, 49]}}
- with open(sanitize(endpoint, '/collections/mycollection/items/new_id?' + ACCEPT_ITEMS), 'wb') as f:
- f.write(json.dumps(new_id).encode('UTF-8'))
-
- other_id = {"type": "Feature", "id": "other_id", "properties": {"pk": 2, "cnt": 123},
- "geometry": None}
- with open(sanitize(endpoint, '/collections/mycollection/items/other_id?' + ACCEPT_ITEMS), 'wb') as f:
- f.write(json.dumps(other_id).encode('UTF-8'))
+ new_id = {
+ "type": "Feature",
+ "id": "new_id",
+ "properties": {"pk": 1, "cnt": 1234567890123},
+ "geometry": {"type": "Point", "coordinates": [2, 49]},
+ }
+ with open(
+ sanitize(
+ endpoint, "/collections/mycollection/items/new_id?" + ACCEPT_ITEMS
+ ),
+ "wb",
+ ) as f:
+ f.write(json.dumps(new_id).encode("UTF-8"))
+
+ other_id = {
+ "type": "Feature",
+ "id": "other_id",
+ "properties": {"pk": 2, "cnt": 123},
+ "geometry": None,
+ }
+ with open(
+ sanitize(
+ endpoint, "/collections/mycollection/items/other_id?" + ACCEPT_ITEMS
+ ),
+ "wb",
+ ) as f:
+ f.write(json.dumps(other_id).encode("UTF-8"))
f = QgsFeature()
f.setFields(vl.fields())
f.setAttributes([None, 1, 1234567890123])
- f.setGeometry(QgsGeometry.fromWkt('Point (2 49)'))
+ f.setGeometry(QgsGeometry.fromWkt("Point (2 49)"))
f2 = QgsFeature()
f2.setFields(vl.fields())
@@ -1429,90 +2184,165 @@ def testFeatureInsertionDeletion(self):
# Failed attempt
self.assertFalse(vl.dataProvider().deleteFeatures([1]))
- with open(sanitize(endpoint, '/collections/mycollection/items/new_id?VERB=DELETE'), 'wb') as f:
+ with open(
+ sanitize(endpoint, "/collections/mycollection/items/new_id?VERB=DELETE"),
+ "wb",
+ ) as f:
f.write(b"")
- with open(sanitize(endpoint, '/collections/mycollection/items/other_id?VERB=DELETE'), 'wb') as f:
+ with open(
+ sanitize(endpoint, "/collections/mycollection/items/other_id?VERB=DELETE"),
+ "wb",
+ ) as f:
f.write(b"")
self.assertTrue(vl.dataProvider().deleteFeatures([1, 2]))
def testFeatureInsertionNonDefaultCrs(self):
- endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_testFeatureInsertionNonDefaultCrs'
- create_landing_page_api_collection(endpoint, storageCrs="http://www.opengis.net/def/crs/EPSG/0/4326")
+ endpoint = (
+ self.__class__.basetestpath
+ + "/fake_qgis_http_endpoint_testFeatureInsertionNonDefaultCrs"
+ )
+ create_landing_page_api_collection(
+ endpoint, storageCrs="http://www.opengis.net/def/crs/EPSG/0/4326"
+ )
# first items (lat, long) order
first_items = {
"type": "FeatureCollection",
"features": [
- {"type": "Feature", "id": "feat.1", "properties": {"pk": 1, "cnt": 100},
- "geometry": {"type": "Point", "coordinates": [-70.332, 66.33]}}
- ]
+ {
+ "type": "Feature",
+ "id": "feat.1",
+ "properties": {"pk": 1, "cnt": 100},
+ "geometry": {"type": "Point", "coordinates": [-70.332, 66.33]},
+ }
+ ],
}
- with open(sanitize(endpoint, '/collections/mycollection/items?limit=10&' + ACCEPT_ITEMS), 'wb') as f:
- f.write(json.dumps(first_items).encode('UTF-8'))
+ with open(
+ sanitize(
+ endpoint, "/collections/mycollection/items?limit=10&" + ACCEPT_ITEMS
+ ),
+ "wb",
+ ) as f:
+ f.write(json.dumps(first_items).encode("UTF-8"))
# POST on /items, but no DELETE on /items/id
- with open(sanitize(endpoint, '/collections/mycollection/items?VERB=OPTIONS'), 'wb') as f:
- f.write("HEAD, GET, POST".encode("UTF-8"))
- with open(sanitize(endpoint, '/collections/mycollection/items/feat.1?VERB=OPTIONS'), 'wb') as f:
- f.write("HEAD, GET".encode("UTF-8"))
+ with open(
+ sanitize(endpoint, "/collections/mycollection/items?VERB=OPTIONS"), "wb"
+ ) as f:
+ f.write(b"HEAD, GET, POST")
+ with open(
+ sanitize(endpoint, "/collections/mycollection/items/feat.1?VERB=OPTIONS"),
+ "wb",
+ ) as f:
+ f.write(b"HEAD, GET")
- vl = QgsVectorLayer("url='http://" + endpoint + "' typename='mycollection' restrictToRequestBBOX=1", 'test',
- 'OAPIF')
+ vl = QgsVectorLayer(
+ "url='http://"
+ + endpoint
+ + "' typename='mycollection' restrictToRequestBBOX=1",
+ "test",
+ "OAPIF",
+ )
self.assertTrue(vl.isValid())
# (lat, long) order
- with open(sanitize(endpoint, '/collections/mycollection/items?POSTDATA={"geometry":{"coordinates":[49.0,2.0],"type":"Point"},"properties":{"cnt":1234567890123,"pk":1},"type":"Feature"}&Content-Crs=http://www.opengis.net/def/crs/EPSG/0/4326'), 'wb') as f:
+ with open(
+ sanitize(
+ endpoint,
+ '/collections/mycollection/items?POSTDATA={"geometry":{"coordinates":[49.0,2.0],"type":"Point"},"properties":{"cnt":1234567890123,"pk":1},"type":"Feature"}&Content-Crs=http://www.opengis.net/def/crs/EPSG/0/4326',
+ ),
+ "wb",
+ ) as f:
f.write(b"Location: /collections/mycollection/items/new_id\r\n")
f = QgsFeature()
f.setFields(vl.fields())
f.setAttributes([None, 1, 1234567890123])
- f.setGeometry(QgsGeometry.fromWkt('Point (2 49)'))
+ f.setGeometry(QgsGeometry.fromWkt("Point (2 49)"))
ret, _ = vl.dataProvider().addFeatures([f])
self.assertTrue(ret)
def testFeatureGeometryChange(self):
- endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_testFeatureGeometryChange'
+ endpoint = (
+ self.__class__.basetestpath
+ + "/fake_qgis_http_endpoint_testFeatureGeometryChange"
+ )
create_landing_page_api_collection(endpoint)
# first items
first_items = {
"type": "FeatureCollection",
"features": [
- {"type": "Feature", "id": "feat.1", "properties": {"pk": 1, "cnt": 100},
- "geometry": {"type": "Point", "coordinates": [66.33, -70.332]}}
- ]
+ {
+ "type": "Feature",
+ "id": "feat.1",
+ "properties": {"pk": 1, "cnt": 100},
+ "geometry": {"type": "Point", "coordinates": [66.33, -70.332]},
+ }
+ ],
}
- with open(sanitize(endpoint, '/collections/mycollection/items?limit=10&' + ACCEPT_ITEMS), 'wb') as f:
- f.write(json.dumps(first_items).encode('UTF-8'))
+ with open(
+ sanitize(
+ endpoint, "/collections/mycollection/items?limit=10&" + ACCEPT_ITEMS
+ ),
+ "wb",
+ ) as f:
+ f.write(json.dumps(first_items).encode("UTF-8"))
- with open(sanitize(endpoint, '/collections/mycollection/items?VERB=OPTIONS'), 'wb') as f:
- f.write("HEAD, GET, POST".encode("UTF-8"))
- with open(sanitize(endpoint, '/collections/mycollection/items/feat.1?VERB=OPTIONS'), 'wb') as f:
- f.write("HEAD, GET, PUT, DELETE".encode("UTF-8"))
+ with open(
+ sanitize(endpoint, "/collections/mycollection/items?VERB=OPTIONS"), "wb"
+ ) as f:
+ f.write(b"HEAD, GET, POST")
+ with open(
+ sanitize(endpoint, "/collections/mycollection/items/feat.1?VERB=OPTIONS"),
+ "wb",
+ ) as f:
+ f.write(b"HEAD, GET, PUT, DELETE")
- vl = QgsVectorLayer("url='http://" + endpoint + "' typename='mycollection' restrictToRequestBBOX=1", 'test',
- 'OAPIF')
+ vl = QgsVectorLayer(
+ "url='http://"
+ + endpoint
+ + "' typename='mycollection' restrictToRequestBBOX=1",
+ "test",
+ "OAPIF",
+ )
self.assertTrue(vl.isValid())
- self.assertNotEqual(vl.dataProvider().capabilities() & vl.dataProvider().ChangeGeometries,
- vl.dataProvider().NoCapabilities)
+ self.assertNotEqual(
+ vl.dataProvider().capabilities() & vl.dataProvider().ChangeGeometries,
+ vl.dataProvider().NoCapabilities,
+ )
# real page
- with open(sanitize(endpoint, '/collections/mycollection/items?limit=1000&' + ACCEPT_ITEMS), 'wb') as f:
- f.write(json.dumps(first_items).encode('UTF-8'))
+ with open(
+ sanitize(
+ endpoint, "/collections/mycollection/items?limit=1000&" + ACCEPT_ITEMS
+ ),
+ "wb",
+ ) as f:
+ f.write(json.dumps(first_items).encode("UTF-8"))
values = [f.id() for f in vl.getFeatures()]
self.assertEqual(values, [1])
- with open(sanitize(endpoint, '/collections/mycollection/items/feat.1?PUTDATA={"geometry":{"coordinates":[3.0,50.0],"type":"Point"},"id":"feat.1","properties":{"cnt":100,"pk":1},"type":"Feature"}'), 'wb') as f:
+ with open(
+ sanitize(
+ endpoint,
+ '/collections/mycollection/items/feat.1?PUTDATA={"geometry":{"coordinates":[3.0,50.0],"type":"Point"},"id":"feat.1","properties":{"cnt":100,"pk":1},"type":"Feature"}',
+ ),
+ "wb",
+ ) as f:
f.write(b"")
- self.assertTrue(vl.dataProvider().changeGeometryValues({1: QgsGeometry.fromWkt('Point (3 50)')}))
+ self.assertTrue(
+ vl.dataProvider().changeGeometryValues(
+ {1: QgsGeometry.fromWkt("Point (3 50)")}
+ )
+ )
got_f = [f for f in vl.getFeatures()]
got = got_f[0].geometry().constGet()
@@ -1520,43 +2350,86 @@ def testFeatureGeometryChange(self):
def testFeatureGeometryChangeNonDefaultCrs(self):
- endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_testFeatureGeometryChangeNonDefaultCrs'
- create_landing_page_api_collection(endpoint, storageCrs="http://www.opengis.net/def/crs/EPSG/0/4326")
+ endpoint = (
+ self.__class__.basetestpath
+ + "/fake_qgis_http_endpoint_testFeatureGeometryChangeNonDefaultCrs"
+ )
+ create_landing_page_api_collection(
+ endpoint, storageCrs="http://www.opengis.net/def/crs/EPSG/0/4326"
+ )
# first items
first_items = {
"type": "FeatureCollection",
"features": [
- {"type": "Feature", "id": "feat.1", "properties": {"pk": 1, "cnt": 100},
- "geometry": {"type": "Point", "coordinates": [-70.332, 66.33]}}
- ]
+ {
+ "type": "Feature",
+ "id": "feat.1",
+ "properties": {"pk": 1, "cnt": 100},
+ "geometry": {"type": "Point", "coordinates": [-70.332, 66.33]},
+ }
+ ],
}
- with open(sanitize(endpoint, '/collections/mycollection/items?limit=10&' + ACCEPT_ITEMS), 'wb') as f:
- f.write(json.dumps(first_items).encode('UTF-8'))
+ with open(
+ sanitize(
+ endpoint, "/collections/mycollection/items?limit=10&" + ACCEPT_ITEMS
+ ),
+ "wb",
+ ) as f:
+ f.write(json.dumps(first_items).encode("UTF-8"))
- with open(sanitize(endpoint, '/collections/mycollection/items?VERB=OPTIONS'), 'wb') as f:
- f.write("HEAD, GET, POST".encode("UTF-8"))
- with open(sanitize(endpoint, '/collections/mycollection/items/feat.1?VERB=OPTIONS'), 'wb') as f:
- f.write("HEAD, GET, PUT, DELETE".encode("UTF-8"))
+ with open(
+ sanitize(endpoint, "/collections/mycollection/items?VERB=OPTIONS"), "wb"
+ ) as f:
+ f.write(b"HEAD, GET, POST")
+ with open(
+ sanitize(endpoint, "/collections/mycollection/items/feat.1?VERB=OPTIONS"),
+ "wb",
+ ) as f:
+ f.write(b"HEAD, GET, PUT, DELETE")
- vl = QgsVectorLayer("url='http://" + endpoint + "' typename='mycollection' restrictToRequestBBOX=1", 'test',
- 'OAPIF')
+ vl = QgsVectorLayer(
+ "url='http://"
+ + endpoint
+ + "' typename='mycollection' restrictToRequestBBOX=1",
+ "test",
+ "OAPIF",
+ )
self.assertTrue(vl.isValid())
- self.assertNotEqual(vl.dataProvider().capabilities() & vl.dataProvider().ChangeGeometries,
- vl.dataProvider().NoCapabilities)
+ self.assertNotEqual(
+ vl.dataProvider().capabilities() & vl.dataProvider().ChangeGeometries,
+ vl.dataProvider().NoCapabilities,
+ )
# real page
- with open(sanitize(endpoint, '/collections/mycollection/items?limit=1000&crs=http://www.opengis.net/def/crs/EPSG/0/4326&' + ACCEPT_ITEMS), 'wb') as f:
- f.write(json.dumps(first_items).encode('UTF-8'))
+ with open(
+ sanitize(
+ endpoint,
+ "/collections/mycollection/items?limit=1000&crs=http://www.opengis.net/def/crs/EPSG/0/4326&"
+ + ACCEPT_ITEMS,
+ ),
+ "wb",
+ ) as f:
+ f.write(json.dumps(first_items).encode("UTF-8"))
values = [f.id() for f in vl.getFeatures()]
self.assertEqual(values, [1])
# (Lat, Long) order
- with open(sanitize(endpoint, '/collections/mycollection/items/feat.1?PUTDATA={"geometry":{"coordinates":[50.0,3.0],"type":"Point"},"id":"feat.1","properties":{"cnt":100,"pk":1},"type":"Feature"}&Content-Crs=http://www.opengis.net/def/crs/EPSG/0/4326'), 'wb') as f:
+ with open(
+ sanitize(
+ endpoint,
+ '/collections/mycollection/items/feat.1?PUTDATA={"geometry":{"coordinates":[50.0,3.0],"type":"Point"},"id":"feat.1","properties":{"cnt":100,"pk":1},"type":"Feature"}&Content-Crs=http://www.opengis.net/def/crs/EPSG/0/4326',
+ ),
+ "wb",
+ ) as f:
f.write(b"")
- self.assertTrue(vl.dataProvider().changeGeometryValues({1: QgsGeometry.fromWkt('Point (3 50)')}))
+ self.assertTrue(
+ vl.dataProvider().changeGeometryValues(
+ {1: QgsGeometry.fromWkt("Point (3 50)")}
+ )
+ )
got_f = [f for f in vl.getFeatures()]
got = got_f[0].geometry().constGet()
@@ -1564,43 +2437,86 @@ def testFeatureGeometryChangeNonDefaultCrs(self):
def testFeatureGeometryChangePatch(self):
- endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_testFeatureGeometryChangePatch'
- create_landing_page_api_collection(endpoint, storageCrs="http://www.opengis.net/def/crs/EPSG/0/4326")
+ endpoint = (
+ self.__class__.basetestpath
+ + "/fake_qgis_http_endpoint_testFeatureGeometryChangePatch"
+ )
+ create_landing_page_api_collection(
+ endpoint, storageCrs="http://www.opengis.net/def/crs/EPSG/0/4326"
+ )
# first items
first_items = {
"type": "FeatureCollection",
"features": [
- {"type": "Feature", "id": "feat.1", "properties": {"pk": 1, "cnt": 100},
- "geometry": {"type": "Point", "coordinates": [-70.332, 66.33]}}
- ]
+ {
+ "type": "Feature",
+ "id": "feat.1",
+ "properties": {"pk": 1, "cnt": 100},
+ "geometry": {"type": "Point", "coordinates": [-70.332, 66.33]},
+ }
+ ],
}
- with open(sanitize(endpoint, '/collections/mycollection/items?limit=10&' + ACCEPT_ITEMS), 'wb') as f:
- f.write(json.dumps(first_items).encode('UTF-8'))
+ with open(
+ sanitize(
+ endpoint, "/collections/mycollection/items?limit=10&" + ACCEPT_ITEMS
+ ),
+ "wb",
+ ) as f:
+ f.write(json.dumps(first_items).encode("UTF-8"))
- with open(sanitize(endpoint, '/collections/mycollection/items?VERB=OPTIONS'), 'wb') as f:
- f.write("HEAD, GET, POST".encode("UTF-8"))
- with open(sanitize(endpoint, '/collections/mycollection/items/feat.1?VERB=OPTIONS'), 'wb') as f:
- f.write("HEAD, GET, PUT, DELETE, PATCH".encode("UTF-8"))
+ with open(
+ sanitize(endpoint, "/collections/mycollection/items?VERB=OPTIONS"), "wb"
+ ) as f:
+ f.write(b"HEAD, GET, POST")
+ with open(
+ sanitize(endpoint, "/collections/mycollection/items/feat.1?VERB=OPTIONS"),
+ "wb",
+ ) as f:
+ f.write(b"HEAD, GET, PUT, DELETE, PATCH")
- vl = QgsVectorLayer("url='http://" + endpoint + "' typename='mycollection' restrictToRequestBBOX=1", 'test',
- 'OAPIF')
+ vl = QgsVectorLayer(
+ "url='http://"
+ + endpoint
+ + "' typename='mycollection' restrictToRequestBBOX=1",
+ "test",
+ "OAPIF",
+ )
self.assertTrue(vl.isValid())
- self.assertNotEqual(vl.dataProvider().capabilities() & vl.dataProvider().ChangeGeometries,
- vl.dataProvider().NoCapabilities)
+ self.assertNotEqual(
+ vl.dataProvider().capabilities() & vl.dataProvider().ChangeGeometries,
+ vl.dataProvider().NoCapabilities,
+ )
# real page
- with open(sanitize(endpoint, '/collections/mycollection/items?limit=1000&crs=http://www.opengis.net/def/crs/EPSG/0/4326&' + ACCEPT_ITEMS), 'wb') as f:
- f.write(json.dumps(first_items).encode('UTF-8'))
+ with open(
+ sanitize(
+ endpoint,
+ "/collections/mycollection/items?limit=1000&crs=http://www.opengis.net/def/crs/EPSG/0/4326&"
+ + ACCEPT_ITEMS,
+ ),
+ "wb",
+ ) as f:
+ f.write(json.dumps(first_items).encode("UTF-8"))
values = [f.id() for f in vl.getFeatures()]
self.assertEqual(values, [1])
# (Lat, Long) order
- with open(sanitize(endpoint, '/collections/mycollection/items/feat.1?PATCHDATA={"geometry":{"coordinates":[50.0,3.0],"type":"Point"}}&Content-Crs=http://www.opengis.net/def/crs/EPSG/0/4326&Content-Type=application_merge-patch+json'), 'wb') as f:
+ with open(
+ sanitize(
+ endpoint,
+ '/collections/mycollection/items/feat.1?PATCHDATA={"geometry":{"coordinates":[50.0,3.0],"type":"Point"}}&Content-Crs=http://www.opengis.net/def/crs/EPSG/0/4326&Content-Type=application_merge-patch+json',
+ ),
+ "wb",
+ ) as f:
f.write(b"")
- self.assertTrue(vl.dataProvider().changeGeometryValues({1: QgsGeometry.fromWkt('Point (3 50)')}))
+ self.assertTrue(
+ vl.dataProvider().changeGeometryValues(
+ {1: QgsGeometry.fromWkt("Point (3 50)")}
+ )
+ )
got_f = [f for f in vl.getFeatures()]
got = got_f[0].geometry().constGet()
@@ -1608,132 +2524,223 @@ def testFeatureGeometryChangePatch(self):
def testFeatureAttributeChange(self):
- endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_testFeatureAttributeChange'
+ endpoint = (
+ self.__class__.basetestpath
+ + "/fake_qgis_http_endpoint_testFeatureAttributeChange"
+ )
create_landing_page_api_collection(endpoint)
# first items
first_items = {
"type": "FeatureCollection",
"features": [
- {"type": "Feature", "id": "feat.1", "properties": {"pk": 1, "cnt": 100},
- "geometry": {"type": "Point", "coordinates": [66.33, -70.332]}}
- ]
+ {
+ "type": "Feature",
+ "id": "feat.1",
+ "properties": {"pk": 1, "cnt": 100},
+ "geometry": {"type": "Point", "coordinates": [66.33, -70.332]},
+ }
+ ],
}
- with open(sanitize(endpoint, '/collections/mycollection/items?limit=10&' + ACCEPT_ITEMS), 'wb') as f:
- f.write(json.dumps(first_items).encode('UTF-8'))
+ with open(
+ sanitize(
+ endpoint, "/collections/mycollection/items?limit=10&" + ACCEPT_ITEMS
+ ),
+ "wb",
+ ) as f:
+ f.write(json.dumps(first_items).encode("UTF-8"))
- with open(sanitize(endpoint, '/collections/mycollection/items?VERB=OPTIONS'), 'wb') as f:
- f.write("HEAD, GET, POST".encode("UTF-8"))
- with open(sanitize(endpoint, '/collections/mycollection/items/feat.1?VERB=OPTIONS'), 'wb') as f:
- f.write("HEAD, GET, PUT, DELETE".encode("UTF-8"))
+ with open(
+ sanitize(endpoint, "/collections/mycollection/items?VERB=OPTIONS"), "wb"
+ ) as f:
+ f.write(b"HEAD, GET, POST")
+ with open(
+ sanitize(endpoint, "/collections/mycollection/items/feat.1?VERB=OPTIONS"),
+ "wb",
+ ) as f:
+ f.write(b"HEAD, GET, PUT, DELETE")
- vl = QgsVectorLayer("url='http://" + endpoint + "' typename='mycollection' restrictToRequestBBOX=1", 'test',
- 'OAPIF')
+ vl = QgsVectorLayer(
+ "url='http://"
+ + endpoint
+ + "' typename='mycollection' restrictToRequestBBOX=1",
+ "test",
+ "OAPIF",
+ )
self.assertTrue(vl.isValid())
- self.assertNotEqual(vl.dataProvider().capabilities() & vl.dataProvider().ChangeGeometries,
- vl.dataProvider().NoCapabilities)
+ self.assertNotEqual(
+ vl.dataProvider().capabilities() & vl.dataProvider().ChangeGeometries,
+ vl.dataProvider().NoCapabilities,
+ )
# real page
- with open(sanitize(endpoint, '/collections/mycollection/items?limit=1000&' + ACCEPT_ITEMS), 'wb') as f:
- f.write(json.dumps(first_items).encode('UTF-8'))
+ with open(
+ sanitize(
+ endpoint, "/collections/mycollection/items?limit=1000&" + ACCEPT_ITEMS
+ ),
+ "wb",
+ ) as f:
+ f.write(json.dumps(first_items).encode("UTF-8"))
values = [f.id() for f in vl.getFeatures()]
self.assertEqual(values, [1])
- with open(sanitize(endpoint, '/collections/mycollection/items/feat.1?PUTDATA={"geometry":{"coordinates":[66.33,-70.332],"type":"Point"},"id":"feat.1","properties":{"cnt":200,"pk":1},"type":"Feature"}'), 'wb') as f:
+ with open(
+ sanitize(
+ endpoint,
+ '/collections/mycollection/items/feat.1?PUTDATA={"geometry":{"coordinates":[66.33,-70.332],"type":"Point"},"id":"feat.1","properties":{"cnt":200,"pk":1},"type":"Feature"}',
+ ),
+ "wb",
+ ) as f:
f.write(b"")
self.assertTrue(vl.dataProvider().changeAttributeValues({1: {2: 200}}))
- values = [f['cnt'] for f in vl.getFeatures()]
+ values = [f["cnt"] for f in vl.getFeatures()]
self.assertEqual(values, [200])
def testFeatureAttributeChangePatch(self):
- endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_testFeatureAttributeChangePatch'
+ endpoint = (
+ self.__class__.basetestpath
+ + "/fake_qgis_http_endpoint_testFeatureAttributeChangePatch"
+ )
create_landing_page_api_collection(endpoint)
# first items
first_items = {
"type": "FeatureCollection",
"features": [
- {"type": "Feature", "id": "feat.1", "properties": {"pk": 1, "cnt": 100},
- "geometry": {"type": "Point", "coordinates": [66.33, -70.332]}}
- ]
+ {
+ "type": "Feature",
+ "id": "feat.1",
+ "properties": {"pk": 1, "cnt": 100},
+ "geometry": {"type": "Point", "coordinates": [66.33, -70.332]},
+ }
+ ],
}
- with open(sanitize(endpoint, '/collections/mycollection/items?limit=10&' + ACCEPT_ITEMS), 'wb') as f:
- f.write(json.dumps(first_items).encode('UTF-8'))
+ with open(
+ sanitize(
+ endpoint, "/collections/mycollection/items?limit=10&" + ACCEPT_ITEMS
+ ),
+ "wb",
+ ) as f:
+ f.write(json.dumps(first_items).encode("UTF-8"))
- with open(sanitize(endpoint, '/collections/mycollection/items?VERB=OPTIONS'), 'wb') as f:
- f.write("HEAD, GET, POST".encode("UTF-8"))
- with open(sanitize(endpoint, '/collections/mycollection/items/feat.1?VERB=OPTIONS'), 'wb') as f:
- f.write("HEAD, GET, PUT, DELETE, PATCH".encode("UTF-8"))
+ with open(
+ sanitize(endpoint, "/collections/mycollection/items?VERB=OPTIONS"), "wb"
+ ) as f:
+ f.write(b"HEAD, GET, POST")
+ with open(
+ sanitize(endpoint, "/collections/mycollection/items/feat.1?VERB=OPTIONS"),
+ "wb",
+ ) as f:
+ f.write(b"HEAD, GET, PUT, DELETE, PATCH")
- vl = QgsVectorLayer("url='http://" + endpoint + "' typename='mycollection' restrictToRequestBBOX=1", 'test',
- 'OAPIF')
+ vl = QgsVectorLayer(
+ "url='http://"
+ + endpoint
+ + "' typename='mycollection' restrictToRequestBBOX=1",
+ "test",
+ "OAPIF",
+ )
self.assertTrue(vl.isValid())
- self.assertNotEqual(vl.dataProvider().capabilities() & vl.dataProvider().ChangeGeometries,
- vl.dataProvider().NoCapabilities)
+ self.assertNotEqual(
+ vl.dataProvider().capabilities() & vl.dataProvider().ChangeGeometries,
+ vl.dataProvider().NoCapabilities,
+ )
# real page
- with open(sanitize(endpoint, '/collections/mycollection/items?limit=1000&' + ACCEPT_ITEMS), 'wb') as f:
- f.write(json.dumps(first_items).encode('UTF-8'))
+ with open(
+ sanitize(
+ endpoint, "/collections/mycollection/items?limit=1000&" + ACCEPT_ITEMS
+ ),
+ "wb",
+ ) as f:
+ f.write(json.dumps(first_items).encode("UTF-8"))
values = [f.id() for f in vl.getFeatures()]
self.assertEqual(values, [1])
- with open(sanitize(endpoint, '/collections/mycollection/items/feat.1?PATCHDATA={"properties":{"cnt":200}}&Content-Type=application_merge-patch+json'), 'wb') as f:
+ with open(
+ sanitize(
+ endpoint,
+ '/collections/mycollection/items/feat.1?PATCHDATA={"properties":{"cnt":200}}&Content-Type=application_merge-patch+json',
+ ),
+ "wb",
+ ) as f:
f.write(b"")
self.assertTrue(vl.dataProvider().changeAttributeValues({1: {2: 200}}))
- values = [f['cnt'] for f in vl.getFeatures()]
+ values = [f["cnt"] for f in vl.getFeatures()]
self.assertEqual(values, [200])
# GDAL 3.5.0 is required since it is the first version that tags "complex"
# fields as OFSTJSON
- @unittest.skipIf(int(gdal.VersionInfo('VERSION_NUM')) < GDAL_COMPUTE_VERSION(3, 5, 0), "GDAL 3.5.0 required")
+ @unittest.skipIf(
+ int(gdal.VersionInfo("VERSION_NUM")) < GDAL_COMPUTE_VERSION(3, 5, 0),
+ "GDAL 3.5.0 required",
+ )
def testFeatureComplexAttribute(self):
- endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_testFeatureComplexAttribute'
+ endpoint = (
+ self.__class__.basetestpath
+ + "/fake_qgis_http_endpoint_testFeatureComplexAttribute"
+ )
create_landing_page_api_collection(endpoint)
# first items
first_items = {
"type": "FeatureCollection",
"features": [
- {"type": "Feature", "id": "feat.1", "properties": {"center": {
- "type": "Point",
- "coordinates": [
- 6.50,
- 51.80
- ]
- }},
- "geometry": {"type": "Point", "coordinates": [66.33, -70.332]}}
- ]
+ {
+ "type": "Feature",
+ "id": "feat.1",
+ "properties": {
+ "center": {"type": "Point", "coordinates": [6.50, 51.80]}
+ },
+ "geometry": {"type": "Point", "coordinates": [66.33, -70.332]},
+ }
+ ],
}
- with open(sanitize(endpoint, '/collections/mycollection/items?limit=10&' + ACCEPT_ITEMS), 'wb') as f:
- f.write(json.dumps(first_items).encode('UTF-8'))
+ with open(
+ sanitize(
+ endpoint, "/collections/mycollection/items?limit=10&" + ACCEPT_ITEMS
+ ),
+ "wb",
+ ) as f:
+ f.write(json.dumps(first_items).encode("UTF-8"))
# real page
- with open(sanitize(endpoint, '/collections/mycollection/items?limit=1000&' + ACCEPT_ITEMS), 'wb') as f:
- f.write(json.dumps(first_items).encode('UTF-8'))
+ with open(
+ sanitize(
+ endpoint, "/collections/mycollection/items?limit=1000&" + ACCEPT_ITEMS
+ ),
+ "wb",
+ ) as f:
+ f.write(json.dumps(first_items).encode("UTF-8"))
- vl = QgsVectorLayer("url='http://" + endpoint + "' typename='mycollection' restrictToRequestBBOX=1", 'test',
- 'OAPIF')
+ vl = QgsVectorLayer(
+ "url='http://"
+ + endpoint
+ + "' typename='mycollection' restrictToRequestBBOX=1",
+ "test",
+ "OAPIF",
+ )
self.assertTrue(vl.isValid())
self.assertEqual(vl.fields().field("center").type(), QVariant.Map)
# First time we getFeatures(): comes directly from the GeoJSON layer
values = [f["center"] for f in vl.getFeatures()]
- self.assertEqual(values, [{'coordinates': [6.5, 51.8], 'type': 'Point'}])
+ self.assertEqual(values, [{"coordinates": [6.5, 51.8], "type": "Point"}])
# Now, that comes from the Spatialite cache, through
# serialization and deserialization
values = [f["center"] for f in vl.getFeatures()]
- self.assertEqual(values, [{'coordinates': [6.5, 51.8], 'type': 'Point'}])
+ self.assertEqual(values, [{"coordinates": [6.5, 51.8], "type": "Point"}])
-if __name__ == '__main__':
+if __name__ == "__main__":
unittest.main()
diff --git a/tests/src/python/test_provider_ogr.py b/tests/src/python/test_provider_ogr.py
index e03ee1ca34a8..aa0d15a90ef4 100644
--- a/tests/src/python/test_provider_ogr.py
+++ b/tests/src/python/test_provider_ogr.py
@@ -5,9 +5,10 @@
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
"""
-__author__ = 'Even Rouault'
-__date__ = '2016-04-11'
-__copyright__ = 'Copyright 2016, Even Rouault'
+
+__author__ = "Even Rouault"
+__date__ = "2016-04-11"
+__copyright__ = "Copyright 2016, Even Rouault"
import hashlib
import os
@@ -71,7 +72,7 @@
def GDAL_COMPUTE_VERSION(maj, min, rev):
- return ((maj) * 1000000 + (min) * 10000 + (rev) * 100)
+ return (maj) * 1000000 + (min) * 10000 + (rev) * 100
# Note - doesn't implement ProviderTestCase as most OGR provider is tested by the shapefile provider test
@@ -79,12 +80,12 @@ def GDAL_COMPUTE_VERSION(maj, min, rev):
def count_opened_filedescriptors(filename_to_test):
count = -1
- if sys.platform.startswith('linux'):
+ if sys.platform.startswith("linux"):
count = 0
- open_files_dirname = '/proc/%d/fd' % os.getpid()
+ open_files_dirname = "/proc/%d/fd" % os.getpid()
filenames = os.listdir(open_files_dirname)
for filename in filenames:
- full_filename = open_files_dirname + '/' + filename
+ full_filename = open_files_dirname + "/" + filename
if os.path.exists(full_filename):
link = os.readlink(full_filename)
if os.path.basename(link) == os.path.basename(filename_to_test):
@@ -100,15 +101,20 @@ def setUpClass(cls):
super().setUpClass()
# Create test layer
cls.basetestpath = tempfile.mkdtemp()
- cls.datasource = os.path.join(cls.basetestpath, 'test.csv')
- with open(cls.datasource, 'w') as f:
- f.write('id,WKT\n')
- f.write('1,POINT(2 49)\n')
+ cls.datasource = os.path.join(cls.basetestpath, "test.csv")
+ with open(cls.datasource, "w") as f:
+ f.write("id,WKT\n")
+ f.write("1,POINT(2 49)\n")
# Copy GPKG files to a temporary directory
cls.temp_dir = tempfile.TemporaryDirectory()
cls.temp_dir_path = cls.temp_dir.name
- for f in ('curved_polys.gpkg', 'domains.gpkg', 'gps_timestamp.gpkg', 'mixed_layers.gpkg'):
+ for f in (
+ "curved_polys.gpkg",
+ "domains.gpkg",
+ "gps_timestamp.gpkg",
+ "mixed_layers.gpkg",
+ ):
shutil.copy(os.path.join(unitTestDataPath(), f), cls.temp_dir_path)
cls.dirs_to_cleanup = [cls.basetestpath]
@@ -123,7 +129,7 @@ def tearDownClass(cls):
def testUpdateMode(self):
- vl = QgsVectorLayer(f'{self.datasource}|layerid=0', 'test', 'ogr')
+ vl = QgsVectorLayer(f"{self.datasource}|layerid=0", "test", "ogr")
self.assertTrue(vl.isValid())
caps = vl.dataProvider().capabilities()
self.assertTrue(caps & QgsVectorDataProvider.Capability.AddFeatures)
@@ -140,60 +146,72 @@ def testUpdateMode(self):
def testGeometryTypeKnownAtSecondFeature(self):
- datasource = os.path.join(self.basetestpath, 'testGeometryTypeKnownAtSecondFeature.csv')
- with open(datasource, 'w') as f:
- f.write('id,WKT\n')
- f.write('1,\n')
- f.write('2,POINT(2 49)\n')
+ datasource = os.path.join(
+ self.basetestpath, "testGeometryTypeKnownAtSecondFeature.csv"
+ )
+ with open(datasource, "w") as f:
+ f.write("id,WKT\n")
+ f.write("1,\n")
+ f.write("2,POINT(2 49)\n")
- vl = QgsVectorLayer(f'{datasource}|layerid=0', 'test', 'ogr')
+ vl = QgsVectorLayer(f"{datasource}|layerid=0", "test", "ogr")
self.assertTrue(vl.isValid())
self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.Point)
def testMixOfPolygonCurvePolygon(self):
- datasource = os.path.join(self.basetestpath, 'testMixOfPolygonCurvePolygon.csv')
- with open(datasource, 'w') as f:
- f.write('id,WKT\n')
+ datasource = os.path.join(self.basetestpath, "testMixOfPolygonCurvePolygon.csv")
+ with open(datasource, "w") as f:
+ f.write("id,WKT\n")
f.write('1,"POLYGON((0 0,0 1,1 1,0 0))"\n')
f.write('2,"CURVEPOLYGON((0 0,0 1,1 1,0 0))"\n')
f.write('3,"MULTIPOLYGON(((0 0,0 1,1 1,0 0)))"\n')
f.write('4,"MULTISURFACE(((0 0,0 1,1 1,0 0)))"\n')
- vl = QgsVectorLayer(f'{datasource}|layerid=0', 'test', 'ogr')
+ vl = QgsVectorLayer(f"{datasource}|layerid=0", "test", "ogr")
self.assertTrue(vl.isValid())
self.assertEqual(len(vl.dataProvider().subLayers()), 1)
- self.assertEqual(vl.dataProvider().subLayers()[0], QgsDataProvider.SUBLAYER_SEPARATOR.join(
- ['0', 'testMixOfPolygonCurvePolygon', '4', 'CurvePolygon', '', '']))
+ self.assertEqual(
+ vl.dataProvider().subLayers()[0],
+ QgsDataProvider.SUBLAYER_SEPARATOR.join(
+ ["0", "testMixOfPolygonCurvePolygon", "4", "CurvePolygon", "", ""]
+ ),
+ )
def testMixOfLineStringCompoundCurve(self):
- datasource = os.path.join(self.basetestpath, 'testMixOfLineStringCompoundCurve.csv')
- with open(datasource, 'w') as f:
- f.write('id,WKT\n')
+ datasource = os.path.join(
+ self.basetestpath, "testMixOfLineStringCompoundCurve.csv"
+ )
+ with open(datasource, "w") as f:
+ f.write("id,WKT\n")
f.write('1,"LINESTRING(0 0,0 1)"\n')
f.write('2,"COMPOUNDCURVE((0 0,0 1))"\n')
f.write('3,"MULTILINESTRING((0 0,0 1))"\n')
f.write('4,"MULTICURVE((0 0,0 1))"\n')
f.write('5,"CIRCULARSTRING(0 0,1 1,2 0)"\n')
- vl = QgsVectorLayer(f'{datasource}|layerid=0', 'test', 'ogr')
+ vl = QgsVectorLayer(f"{datasource}|layerid=0", "test", "ogr")
self.assertTrue(vl.isValid())
self.assertEqual(len(vl.dataProvider().subLayers()), 1)
- self.assertEqual(vl.dataProvider().subLayers()[0], QgsDataProvider.SUBLAYER_SEPARATOR.join(
- ['0', 'testMixOfLineStringCompoundCurve', '5', 'CompoundCurve', '', '']))
+ self.assertEqual(
+ vl.dataProvider().subLayers()[0],
+ QgsDataProvider.SUBLAYER_SEPARATOR.join(
+ ["0", "testMixOfLineStringCompoundCurve", "5", "CompoundCurve", "", ""]
+ ),
+ )
def testGpxElevation(self):
# GPX without elevation data
- datasource = os.path.join(TEST_DATA_DIR, 'noelev.gpx')
- vl = QgsVectorLayer(f'{datasource}|layername=routes', 'test', 'ogr')
+ datasource = os.path.join(TEST_DATA_DIR, "noelev.gpx")
+ vl = QgsVectorLayer(f"{datasource}|layername=routes", "test", "ogr")
self.assertTrue(vl.isValid())
f = next(vl.getFeatures())
self.assertEqual(f.geometry().wkbType(), QgsWkbTypes.Type.LineString)
# GPX with elevation data
- datasource = os.path.join(TEST_DATA_DIR, 'elev.gpx')
- vl = QgsVectorLayer(f'{datasource}|layername=routes', 'test', 'ogr')
+ datasource = os.path.join(TEST_DATA_DIR, "elev.gpx")
+ vl = QgsVectorLayer(f"{datasource}|layername=routes", "test", "ogr")
self.assertTrue(vl.isValid())
f = next(vl.getFeatures())
self.assertEqual(f.geometry().wkbType(), QgsWkbTypes.Type.LineStringZ)
@@ -202,15 +220,17 @@ def testGpxElevation(self):
self.assertEqual(f.geometry().constGet().pointN(2).z(), 3)
def testNoDanglingFileDescriptorAfterCloseVariant1(self):
- ''' Test that when closing the provider all file handles are released '''
+ """Test that when closing the provider all file handles are released"""
- datasource = os.path.join(self.basetestpath, 'testNoDanglingFileDescriptorAfterCloseVariant1.csv')
- with open(datasource, 'w') as f:
- f.write('id,WKT\n')
- f.write('1,\n')
- f.write('2,POINT(2 49)\n')
+ datasource = os.path.join(
+ self.basetestpath, "testNoDanglingFileDescriptorAfterCloseVariant1.csv"
+ )
+ with open(datasource, "w") as f:
+ f.write("id,WKT\n")
+ f.write("1,\n")
+ f.write("2,POINT(2 49)\n")
- vl = QgsVectorLayer(f'{datasource}|layerid=0', 'test', 'ogr')
+ vl = QgsVectorLayer(f"{datasource}|layerid=0", "test", "ogr")
self.assertTrue(vl.isValid())
# The iterator will take one extra connection
myiter = vl.getFeatures()
@@ -218,14 +238,14 @@ def testNoDanglingFileDescriptorAfterCloseVariant1(self):
f = next(myiter)
self.assertTrue(f.isValid())
- if sys.platform.startswith('linux'):
+ if sys.platform.startswith("linux"):
self.assertEqual(count_opened_filedescriptors(datasource), 2)
# Should release one file descriptor
del vl
# Non portable, but Windows testing is done with trying to unlink
- if sys.platform.startswith('linux'):
+ if sys.platform.startswith("linux"):
self.assertEqual(count_opened_filedescriptors(datasource), 1)
f = next(myiter)
@@ -235,7 +255,7 @@ def testNoDanglingFileDescriptorAfterCloseVariant1(self):
del myiter
# Non portable, but Windows testing is done with trying to unlink
- if sys.platform.startswith('linux'):
+ if sys.platform.startswith("linux"):
self.assertEqual(count_opened_filedescriptors(datasource), 0)
# Check that deletion works well (can only fail on Windows)
@@ -243,29 +263,31 @@ def testNoDanglingFileDescriptorAfterCloseVariant1(self):
self.assertFalse(os.path.exists(datasource))
def testNoDanglingFileDescriptorAfterCloseVariant2(self):
- ''' Test that when closing the provider all file handles are released '''
+ """Test that when closing the provider all file handles are released"""
- datasource = os.path.join(self.basetestpath, 'testNoDanglingFileDescriptorAfterCloseVariant2.csv')
- with open(datasource, 'w') as f:
- f.write('id,WKT\n')
- f.write('1,\n')
- f.write('2,POINT(2 49)\n')
+ datasource = os.path.join(
+ self.basetestpath, "testNoDanglingFileDescriptorAfterCloseVariant2.csv"
+ )
+ with open(datasource, "w") as f:
+ f.write("id,WKT\n")
+ f.write("1,\n")
+ f.write("2,POINT(2 49)\n")
- vl = QgsVectorLayer(f'{datasource}|layerid=0', 'test', 'ogr')
+ vl = QgsVectorLayer(f"{datasource}|layerid=0", "test", "ogr")
self.assertTrue(vl.isValid())
# Consume all features.
myiter = vl.getFeatures()
for feature in myiter:
pass
# The iterator is closed, but the corresponding connection still not closed
- if sys.platform.startswith('linux'):
+ if sys.platform.startswith("linux"):
self.assertEqual(count_opened_filedescriptors(datasource), 2)
# Should release one file descriptor
del vl
# Non portable, but Windows testing is done with trying to unlink
- if sys.platform.startswith('linux'):
+ if sys.platform.startswith("linux"):
self.assertEqual(count_opened_filedescriptors(datasource), 0)
# Check that deletion works well (can only fail on Windows)
@@ -273,19 +295,21 @@ def testNoDanglingFileDescriptorAfterCloseVariant2(self):
self.assertFalse(os.path.exists(datasource))
def testGeometryCollection(self):
- ''' Test that we can at least retrieves attribute of features with geometry collection '''
+ """Test that we can at least retrieves attribute of features with geometry collection"""
- datasource = os.path.join(self.basetestpath, 'testGeometryCollection.csv')
- with open(datasource, 'w') as f:
- f.write('id,WKT\n')
- f.write('1,POINT Z(2 49 0)\n')
- f.write('2,GEOMETRYCOLLECTION Z (POINT Z (2 49 0))\n')
+ datasource = os.path.join(self.basetestpath, "testGeometryCollection.csv")
+ with open(datasource, "w") as f:
+ f.write("id,WKT\n")
+ f.write("1,POINT Z(2 49 0)\n")
+ f.write("2,GEOMETRYCOLLECTION Z (POINT Z (2 49 0))\n")
- vl = QgsVectorLayer(f'{datasource}|layerid=0|geometrytype=GeometryCollection', 'test', 'ogr')
+ vl = QgsVectorLayer(
+ f"{datasource}|layerid=0|geometrytype=GeometryCollection", "test", "ogr"
+ )
self.assertTrue(vl.isValid())
self.assertTrue(vl.featureCount(), 1)
- values = [f['id'] for f in vl.getFeatures()]
- self.assertEqual(values, ['2'])
+ values = [f["id"] for f in vl.getFeatures()]
+ self.assertEqual(values, ["2"])
del vl
os.unlink(datasource)
@@ -295,66 +319,80 @@ def test_request_invalid_attributes(self):
"""
Test asking for invalid attributes in feature request
"""
- points_layer = QgsVectorLayer(os.path.join(unitTestDataPath(), 'points.shp'), 'points')
+ points_layer = QgsVectorLayer(
+ os.path.join(unitTestDataPath(), "points.shp"), "points"
+ )
self.assertTrue(points_layer.isValid())
req = QgsFeatureRequest()
req.setSubsetOfAttributes([8, 0, 3, 7, 9, 10, 11, 13, 14])
features = list(points_layer.dataProvider().getFeatures(req))
- self.assertCountEqual([f.attributes() for f in features],
- [['Jet', None, None, 2, None, None],
- ['Biplane', None, None, 3, None, None],
- ['Jet', None, None, 1, None, None],
- ['Jet', None, None, 1, None, None],
- ['Jet', None, None, 1, None, None],
- ['Biplane', None, None, 3, None, None],
- ['Biplane', None, None, 3, None, None],
- ['Biplane', None, None, 3, None, None],
- ['Biplane', None, None, 3, None, None],
- ['B52', None, None, 2, None, None],
- ['B52', None, None, 1, None, None],
- ['B52', None, None, 2, None, None],
- ['B52', None, None, 2, None, None],
- ['Jet', None, None, 2, None, None],
- ['Jet', None, None, 1, None, None],
- ['Jet', None, None, 1, None, None],
- ['Jet', None, None, 3, None, None]])
+ self.assertCountEqual(
+ [f.attributes() for f in features],
+ [
+ ["Jet", None, None, 2, None, None],
+ ["Biplane", None, None, 3, None, None],
+ ["Jet", None, None, 1, None, None],
+ ["Jet", None, None, 1, None, None],
+ ["Jet", None, None, 1, None, None],
+ ["Biplane", None, None, 3, None, None],
+ ["Biplane", None, None, 3, None, None],
+ ["Biplane", None, None, 3, None, None],
+ ["Biplane", None, None, 3, None, None],
+ ["B52", None, None, 2, None, None],
+ ["B52", None, None, 1, None, None],
+ ["B52", None, None, 2, None, None],
+ ["B52", None, None, 2, None, None],
+ ["Jet", None, None, 2, None, None],
+ ["Jet", None, None, 1, None, None],
+ ["Jet", None, None, 1, None, None],
+ ["Jet", None, None, 3, None, None],
+ ],
+ )
req = QgsFeatureRequest()
- req.setSubsetOfAttributes(['nope', 'Class', 'Pilots', 'nope2'], points_layer.dataProvider().fields())
+ req.setSubsetOfAttributes(
+ ["nope", "Class", "Pilots", "nope2"], points_layer.dataProvider().fields()
+ )
features = list(points_layer.dataProvider().getFeatures(req))
- self.assertCountEqual([f.attributes() for f in features],
- [['Jet', None, None, 2, None, None],
- ['Biplane', None, None, 3, None, None],
- ['Jet', None, None, 1, None, None],
- ['Jet', None, None, 1, None, None],
- ['Jet', None, None, 1, None, None],
- ['Biplane', None, None, 3, None, None],
- ['Biplane', None, None, 3, None, None],
- ['Biplane', None, None, 3, None, None],
- ['Biplane', None, None, 3, None, None],
- ['B52', None, None, 2, None, None],
- ['B52', None, None, 1, None, None],
- ['B52', None, None, 2, None, None],
- ['B52', None, None, 2, None, None],
- ['Jet', None, None, 2, None, None],
- ['Jet', None, None, 1, None, None],
- ['Jet', None, None, 1, None, None],
- ['Jet', None, None, 3, None, None]])
+ self.assertCountEqual(
+ [f.attributes() for f in features],
+ [
+ ["Jet", None, None, 2, None, None],
+ ["Biplane", None, None, 3, None, None],
+ ["Jet", None, None, 1, None, None],
+ ["Jet", None, None, 1, None, None],
+ ["Jet", None, None, 1, None, None],
+ ["Biplane", None, None, 3, None, None],
+ ["Biplane", None, None, 3, None, None],
+ ["Biplane", None, None, 3, None, None],
+ ["Biplane", None, None, 3, None, None],
+ ["B52", None, None, 2, None, None],
+ ["B52", None, None, 1, None, None],
+ ["B52", None, None, 2, None, None],
+ ["B52", None, None, 2, None, None],
+ ["Jet", None, None, 2, None, None],
+ ["Jet", None, None, 1, None, None],
+ ["Jet", None, None, 1, None, None],
+ ["Jet", None, None, 3, None, None],
+ ],
+ )
def testGdb(self):
- """ Test opening a GDB database layer"""
- gdb_path = os.path.join(unitTestDataPath(), 'test_gdb.gdb')
+ """Test opening a GDB database layer"""
+ gdb_path = os.path.join(unitTestDataPath(), "test_gdb.gdb")
for i in range(3):
- l = QgsVectorLayer(gdb_path + '|layerid=' + str(i), 'test', 'ogr')
+ l = QgsVectorLayer(gdb_path + "|layerid=" + str(i), "test", "ogr")
self.assertTrue(l.isValid())
def testGdbFilter(self):
- """ Test opening a GDB database layer with filter"""
- gdb_path = os.path.join(unitTestDataPath(), 'test_gdb.gdb')
- l = QgsVectorLayer(gdb_path + '|layerid=1|subset="text" = \'shape 2\'', 'test', 'ogr')
+ """Test opening a GDB database layer with filter"""
+ gdb_path = os.path.join(unitTestDataPath(), "test_gdb.gdb")
+ l = QgsVectorLayer(
+ gdb_path + "|layerid=1|subset=\"text\" = 'shape 2'", "test", "ogr"
+ )
self.assertTrue(l.isValid())
it = l.getFeatures()
f = QgsFeature()
@@ -362,46 +400,76 @@ def testGdbFilter(self):
self.assertEqual(f.attribute("text"), "shape 2")
def testTriangleTINPolyhedralSurface(self):
- """ Test support for Triangles (mapped to Polygons) """
+ """Test support for Triangles (mapped to Polygons)"""
testsets = (
- ("Triangle((0 0, 0 1, 1 1, 0 0))", QgsWkbTypes.Type.Triangle, "Triangle ((0 0, 0 1, 1 1, 0 0))"),
- ("Triangle Z((0 0 1, 0 1 2, 1 1 3, 0 0 1))", QgsWkbTypes.Type.TriangleZ,
- "Triangle Z ((0 0 1, 0 1 2, 1 1 3, 0 0 1))"),
- ("Triangle M((0 0 4, 0 1 5, 1 1 6, 0 0 4))", QgsWkbTypes.Type.TriangleM,
- "Triangle M ((0 0 4, 0 1 5, 1 1 6, 0 0 4))"),
- ("Triangle ZM((0 0 0 1, 0 1 2 3, 1 1 4 5, 0 0 0 1))", QgsWkbTypes.Type.TriangleZM,
- "Triangle ZM ((0 0 0 1, 0 1 2 3, 1 1 4 5, 0 0 0 1))"),
-
- ("TIN (((0 0, 0 1, 1 1, 0 0)),((0 0, 1 0, 1 1, 0 0)))", QgsWkbTypes.Type.TIN,
- "TIN (((0 0, 0 1, 1 1, 0 0)),((0 0, 1 0, 1 1, 0 0)))"),
- ("TIN Z(((0 0 0, 0 1 1, 1 1 1, 0 0 0)),((0 0 0, 1 0 0, 1 1 1, 0 0 0)))", QgsWkbTypes.Type.TINZ,
- "TIN Z (((0 0 0, 0 1 1, 1 1 1, 0 0 0)),((0 0 0, 1 0 0, 1 1 1, 0 0 0)))"),
- ("TIN M(((0 0 0, 0 1 2, 1 1 3, 0 0 0)),((0 0 0, 1 0 4, 1 1 3, 0 0 0)))", QgsWkbTypes.Type.TINM,
- "TIN M (((0 0 0, 0 1 2, 1 1 3, 0 0 0)),((0 0 0, 1 0 4, 1 1 3, 0 0 0)))"),
- ("TIN ZM(((0 0 0 0, 0 1 1 2, 1 1 1 3, 0 0 0 0)),((0 0 0 0, 1 0 0 4, 1 1 1 3, 0 0 0 0)))",
- QgsWkbTypes.Type.TINZM,
- "TIN ZM (((0 0 0 0, 0 1 1 2, 1 1 1 3, 0 0 0 0)),((0 0 0 0, 1 0 0 4, 1 1 1 3, 0 0 0 0)))"),
-
- ("PolyhedralSurface (((0 0, 0 1, 1 1, 0 0)),((0 0, 1 0, 1 1, 0 0)))", QgsWkbTypes.Type.PolyhedralSurface,
- "PolyhedralSurface (((0 0, 0 1, 1 1, 0 0)),((0 0, 1 0, 1 1, 0 0)))"),
- ("PolyhedralSurface Z(((0 0 0, 0 1 1, 1 1 1, 0 0 0)),((0 0 0, 1 0 0, 1 1 1, 0 0 0)))",
-
- QgsWkbTypes.Type.PolyhedralSurfaceZ,
- "PolyhedralSurface Z (((0 0 0, 0 1 1, 1 1 1, 0 0 0)),((0 0 0, 1 0 0, 1 1 1, 0 0 0)))"),
- ("PolyhedralSurface M(((0 0 0, 0 1 2, 1 1 3, 0 0 0)),((0 0 0, 1 0 4, 1 1 3, 0 0 0)))",
- QgsWkbTypes.Type.PolyhedralSurfaceM,
- "PolyhedralSurface M (((0 0 0, 0 1 2, 1 1 3, 0 0 0)),((0 0 0, 1 0 4, 1 1 3, 0 0 0)))"),
- ("PolyhedralSurface ZM(((0 0 0 0, 0 1 1 2, 1 1 1 3, 0 0 0 0)),((0 0 0 0, 1 0 0 4, 1 1 1 3, 0 0 0 0)))",
- QgsWkbTypes.Type.PolyhedralSurfaceZM,
- "PolyhedralSurface ZM (((0 0 0 0, 0 1 1 2, 1 1 1 3, 0 0 0 0)),((0 0 0 0, 1 0 0 4, 1 1 1 3, 0 0 0 0)))")
+ (
+ "Triangle((0 0, 0 1, 1 1, 0 0))",
+ QgsWkbTypes.Type.Triangle,
+ "Triangle ((0 0, 0 1, 1 1, 0 0))",
+ ),
+ (
+ "Triangle Z((0 0 1, 0 1 2, 1 1 3, 0 0 1))",
+ QgsWkbTypes.Type.TriangleZ,
+ "Triangle Z ((0 0 1, 0 1 2, 1 1 3, 0 0 1))",
+ ),
+ (
+ "Triangle M((0 0 4, 0 1 5, 1 1 6, 0 0 4))",
+ QgsWkbTypes.Type.TriangleM,
+ "Triangle M ((0 0 4, 0 1 5, 1 1 6, 0 0 4))",
+ ),
+ (
+ "Triangle ZM((0 0 0 1, 0 1 2 3, 1 1 4 5, 0 0 0 1))",
+ QgsWkbTypes.Type.TriangleZM,
+ "Triangle ZM ((0 0 0 1, 0 1 2 3, 1 1 4 5, 0 0 0 1))",
+ ),
+ (
+ "TIN (((0 0, 0 1, 1 1, 0 0)),((0 0, 1 0, 1 1, 0 0)))",
+ QgsWkbTypes.Type.TIN,
+ "TIN (((0 0, 0 1, 1 1, 0 0)),((0 0, 1 0, 1 1, 0 0)))",
+ ),
+ (
+ "TIN Z(((0 0 0, 0 1 1, 1 1 1, 0 0 0)),((0 0 0, 1 0 0, 1 1 1, 0 0 0)))",
+ QgsWkbTypes.Type.TINZ,
+ "TIN Z (((0 0 0, 0 1 1, 1 1 1, 0 0 0)),((0 0 0, 1 0 0, 1 1 1, 0 0 0)))",
+ ),
+ (
+ "TIN M(((0 0 0, 0 1 2, 1 1 3, 0 0 0)),((0 0 0, 1 0 4, 1 1 3, 0 0 0)))",
+ QgsWkbTypes.Type.TINM,
+ "TIN M (((0 0 0, 0 1 2, 1 1 3, 0 0 0)),((0 0 0, 1 0 4, 1 1 3, 0 0 0)))",
+ ),
+ (
+ "TIN ZM(((0 0 0 0, 0 1 1 2, 1 1 1 3, 0 0 0 0)),((0 0 0 0, 1 0 0 4, 1 1 1 3, 0 0 0 0)))",
+ QgsWkbTypes.Type.TINZM,
+ "TIN ZM (((0 0 0 0, 0 1 1 2, 1 1 1 3, 0 0 0 0)),((0 0 0 0, 1 0 0 4, 1 1 1 3, 0 0 0 0)))",
+ ),
+ (
+ "PolyhedralSurface (((0 0, 0 1, 1 1, 0 0)),((0 0, 1 0, 1 1, 0 0)))",
+ QgsWkbTypes.Type.PolyhedralSurface,
+ "PolyhedralSurface (((0 0, 0 1, 1 1, 0 0)),((0 0, 1 0, 1 1, 0 0)))",
+ ),
+ (
+ "PolyhedralSurface Z(((0 0 0, 0 1 1, 1 1 1, 0 0 0)),((0 0 0, 1 0 0, 1 1 1, 0 0 0)))",
+ QgsWkbTypes.Type.PolyhedralSurfaceZ,
+ "PolyhedralSurface Z (((0 0 0, 0 1 1, 1 1 1, 0 0 0)),((0 0 0, 1 0 0, 1 1 1, 0 0 0)))",
+ ),
+ (
+ "PolyhedralSurface M(((0 0 0, 0 1 2, 1 1 3, 0 0 0)),((0 0 0, 1 0 4, 1 1 3, 0 0 0)))",
+ QgsWkbTypes.Type.PolyhedralSurfaceM,
+ "PolyhedralSurface M (((0 0 0, 0 1 2, 1 1 3, 0 0 0)),((0 0 0, 1 0 4, 1 1 3, 0 0 0)))",
+ ),
+ (
+ "PolyhedralSurface ZM(((0 0 0 0, 0 1 1 2, 1 1 1 3, 0 0 0 0)),((0 0 0 0, 1 0 0 4, 1 1 1 3, 0 0 0 0)))",
+ QgsWkbTypes.Type.PolyhedralSurfaceZM,
+ "PolyhedralSurface ZM (((0 0 0 0, 0 1 1 2, 1 1 1 3, 0 0 0 0)),((0 0 0 0, 1 0 0 4, 1 1 1 3, 0 0 0 0)))",
+ ),
)
for row in testsets:
- datasource = os.path.join(self.basetestpath, 'test.csv')
- with open(datasource, 'w') as f:
- f.write('id,WKT\n')
+ datasource = os.path.join(self.basetestpath, "test.csv")
+ with open(datasource, "w") as f:
+ f.write("id,WKT\n")
f.write(f'1,"{row[0]}"')
- vl = QgsVectorLayer(datasource, 'test', 'ogr')
+ vl = QgsVectorLayer(datasource, "test", "ogr")
self.assertTrue(vl.isValid())
self.assertEqual(vl.wkbType(), row[1])
@@ -414,40 +482,52 @@ def testSetupProxy(self):
"""Test proxy setup"""
settings = QgsSettings()
settings.setValue("proxy/proxyEnabled", True)
- settings.setValue("proxy/proxyPort", '1234')
- settings.setValue("proxy/proxyHost", 'myproxyhostname.com')
- settings.setValue("proxy/proxyUser", 'username')
- settings.setValue("proxy/proxyPassword", 'password')
- settings.setValue("proxy/proxyExcludedUrls", "http://www.myhost.com|http://www.myotherhost.com")
+ settings.setValue("proxy/proxyPort", "1234")
+ settings.setValue("proxy/proxyHost", "myproxyhostname.com")
+ settings.setValue("proxy/proxyUser", "username")
+ settings.setValue("proxy/proxyPassword", "password")
+ settings.setValue(
+ "proxy/proxyExcludedUrls",
+ "http://www.myhost.com|http://www.myotherhost.com",
+ )
QgsNetworkAccessManager.instance().setupDefaultProxyAndCache()
- vl = QgsVectorLayer(TEST_DATA_DIR + '/' + 'lines.shp', 'proxy_test', 'ogr')
+ vl = QgsVectorLayer(TEST_DATA_DIR + "/" + "lines.shp", "proxy_test", "ogr")
self.assertTrue(vl.isValid())
- self.assertEqual(gdal.GetConfigOption("GDAL_HTTP_PROXY"), "myproxyhostname.com:1234")
- self.assertEqual(gdal.GetConfigOption("GDAL_HTTP_PROXYUSERPWD"), "username:password")
+ self.assertEqual(
+ gdal.GetConfigOption("GDAL_HTTP_PROXY"), "myproxyhostname.com:1234"
+ )
+ self.assertEqual(
+ gdal.GetConfigOption("GDAL_HTTP_PROXYUSERPWD"), "username:password"
+ )
settings.setValue("proxy/proxyEnabled", True)
settings.remove("proxy/proxyPort")
- settings.setValue("proxy/proxyHost", 'myproxyhostname.com')
- settings.setValue("proxy/proxyUser", 'username')
+ settings.setValue("proxy/proxyHost", "myproxyhostname.com")
+ settings.setValue("proxy/proxyUser", "username")
settings.remove("proxy/proxyPassword")
- settings.setValue("proxy/proxyExcludedUrls", "http://www.myhost.com|http://www.myotherhost.com")
+ settings.setValue(
+ "proxy/proxyExcludedUrls",
+ "http://www.myhost.com|http://www.myotherhost.com",
+ )
QgsNetworkAccessManager.instance().setupDefaultProxyAndCache()
- vl = QgsVectorLayer(TEST_DATA_DIR + '/' + 'lines.shp', 'proxy_test', 'ogr')
+ vl = QgsVectorLayer(TEST_DATA_DIR + "/" + "lines.shp", "proxy_test", "ogr")
self.assertTrue(vl.isValid())
self.assertEqual(gdal.GetConfigOption("GDAL_HTTP_PROXY"), "myproxyhostname.com")
self.assertEqual(gdal.GetConfigOption("GDAL_HTTP_PROXYUSERPWD"), "username")
def testEditGeoJsonRemoveField(self):
- """ Test bugfix of https://github.com/qgis/QGIS/issues/26484 (deleting an existing field)"""
+ """Test bugfix of https://github.com/qgis/QGIS/issues/26484 (deleting an existing field)"""
- datasource = os.path.join(self.basetestpath, 'testEditGeoJsonRemoveField.json')
- with open(datasource, 'w') as f:
- f.write("""{
+ datasource = os.path.join(self.basetestpath, "testEditGeoJsonRemoveField.json")
+ with open(datasource, "w") as f:
+ f.write(
+ """{
"type": "FeatureCollection",
"features": [
-{ "type": "Feature", "properties": { "x": 1, "y": 2, "z": 3, "w": 4 }, "geometry": { "type": "Point", "coordinates": [ 0, 0 ] } } ] }""")
+{ "type": "Feature", "properties": { "x": 1, "y": 2, "z": 3, "w": 4 }, "geometry": { "type": "Point", "coordinates": [ 0, 0 ] } } ] }"""
+ )
- vl = QgsVectorLayer(datasource, 'test', 'ogr')
+ vl = QgsVectorLayer(datasource, "test", "ogr")
self.assertTrue(vl.isValid())
self.assertTrue(vl.startEditing())
self.assertTrue(vl.deleteAttribute(1))
@@ -456,70 +536,76 @@ def testEditGeoJsonRemoveField(self):
f = QgsFeature()
self.assertTrue(vl.getFeatures(QgsFeatureRequest()).nextFeature(f))
- self.assertEqual(f['x'], 1)
- self.assertEqual(f['z'], 3)
- self.assertEqual(f['w'], 4)
+ self.assertEqual(f["x"], 1)
+ self.assertEqual(f["z"], 3)
+ self.assertEqual(f["w"], 4)
def testEditGeoJsonAddField(self):
- """ Test bugfix of https://github.com/qgis/QGIS/issues/26484 (adding a new field)"""
+ """Test bugfix of https://github.com/qgis/QGIS/issues/26484 (adding a new field)"""
- datasource = os.path.join(self.basetestpath, 'testEditGeoJsonAddField.json')
- with open(datasource, 'w') as f:
- f.write("""{
+ datasource = os.path.join(self.basetestpath, "testEditGeoJsonAddField.json")
+ with open(datasource, "w") as f:
+ f.write(
+ """{
"type": "FeatureCollection",
"features": [
-{ "type": "Feature", "properties": { "x": 1 }, "geometry": { "type": "Point", "coordinates": [ 0, 0 ] } } ] }""")
+{ "type": "Feature", "properties": { "x": 1 }, "geometry": { "type": "Point", "coordinates": [ 0, 0 ] } } ] }"""
+ )
- vl = QgsVectorLayer(datasource, 'test', 'ogr')
+ vl = QgsVectorLayer(datasource, "test", "ogr")
self.assertTrue(vl.isValid())
self.assertTrue(vl.startEditing())
- self.assertTrue(vl.addAttribute(QgsField('strfield', QVariant.String)))
+ self.assertTrue(vl.addAttribute(QgsField("strfield", QVariant.String)))
self.assertTrue(vl.commitChanges())
self.assertEqual(len(vl.dataProvider().fields()), 1 + 1)
f = QgsFeature()
self.assertTrue(vl.getFeatures(QgsFeatureRequest()).nextFeature(f))
- self.assertIsNone(f['strfield'])
+ self.assertIsNone(f["strfield"])
# Completely reload file
- vl = QgsVectorLayer(datasource, 'test', 'ogr')
+ vl = QgsVectorLayer(datasource, "test", "ogr")
# As we didn't set any value to the new field, it is not written at
# all in the GeoJSON file, so it has disappeared
self.assertEqual(len(vl.fields()), 1)
def testEditGeoJsonAddFieldAndThenAddFeatures(self):
- """ Test bugfix of https://github.com/qgis/QGIS/issues/26484 (adding a new field)"""
+ """Test bugfix of https://github.com/qgis/QGIS/issues/26484 (adding a new field)"""
- datasource = os.path.join(self.basetestpath, 'testEditGeoJsonAddField.json')
- with open(datasource, 'w') as f:
- f.write("""{
+ datasource = os.path.join(self.basetestpath, "testEditGeoJsonAddField.json")
+ with open(datasource, "w") as f:
+ f.write(
+ """{
"type": "FeatureCollection",
"features": [
-{ "type": "Feature", "properties": { "x": 1 }, "geometry": { "type": "Point", "coordinates": [ 0, 0 ] } } ] }""")
+{ "type": "Feature", "properties": { "x": 1 }, "geometry": { "type": "Point", "coordinates": [ 0, 0 ] } } ] }"""
+ )
- vl = QgsVectorLayer(datasource, 'test', 'ogr')
+ vl = QgsVectorLayer(datasource, "test", "ogr")
self.assertTrue(vl.isValid())
self.assertTrue(vl.startEditing())
- self.assertTrue(vl.addAttribute(QgsField('strfield', QVariant.String)))
+ self.assertTrue(vl.addAttribute(QgsField("strfield", QVariant.String)))
self.assertTrue(vl.commitChanges())
self.assertEqual(len(vl.dataProvider().fields()), 1 + 1)
- self.assertEqual([f.name() for f in vl.dataProvider().fields()], ['x', 'strfield'])
+ self.assertEqual(
+ [f.name() for f in vl.dataProvider().fields()], ["x", "strfield"]
+ )
f = QgsFeature()
self.assertTrue(vl.getFeatures(QgsFeatureRequest()).nextFeature(f))
- self.assertIsNone(f['strfield'])
- self.assertEqual([field.name() for field in f.fields()], ['x', 'strfield'])
+ self.assertIsNone(f["strfield"])
+ self.assertEqual([field.name() for field in f.fields()], ["x", "strfield"])
self.assertTrue(vl.startEditing())
- vl.changeAttributeValue(f.id(), 1, 'x')
+ vl.changeAttributeValue(f.id(), 1, "x")
self.assertTrue(vl.commitChanges())
f = QgsFeature()
self.assertTrue(vl.getFeatures(QgsFeatureRequest()).nextFeature(f))
- self.assertEqual(f['strfield'], 'x')
- self.assertEqual([field.name() for field in f.fields()], ['x', 'strfield'])
+ self.assertEqual(f["strfield"], "x")
+ self.assertEqual([field.name() for field in f.fields()], ["x", "strfield"])
# Completely reload file
- vl = QgsVectorLayer(datasource, 'test', 'ogr')
+ vl = QgsVectorLayer(datasource, "test", "ogr")
self.assertEqual(len(vl.fields()), 2)
def testAddFeatureWithUnsetValue(self):
@@ -527,108 +613,158 @@ def testAddFeatureWithUnsetValue(self):
Test adding features with unset values
"""
with tempfile.TemporaryDirectory() as temp_dir:
- tmpfile = os.path.join(temp_dir, 'test_unset_value.gpkg')
+ tmpfile = os.path.join(temp_dir, "test_unset_value.gpkg")
- ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile)
+ ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile)
ds.ExecuteSQL(
- "CREATE TABLE test(fid INTEGER PRIMARY KEY, name TEXT DEFAULT 'default_value', auto_number INTEGER DEFAULT 55)")
+ "CREATE TABLE test(fid INTEGER PRIMARY KEY, name TEXT DEFAULT 'default_value', auto_number INTEGER DEFAULT 55)"
+ )
ds = None
- layer = QgsVectorLayer(tmpfile, 'test')
+ layer = QgsVectorLayer(tmpfile, "test")
self.assertTrue(layer.isValid())
self.assertFalse(
- layer.dataProvider().skipConstraintCheck(0, QgsFieldConstraints.Constraint.ConstraintUnique, 5))
- self.assertTrue(layer.dataProvider().skipConstraintCheck(0, QgsFieldConstraints.Constraint.ConstraintUnique, 'Autogenerate'))
+ layer.dataProvider().skipConstraintCheck(
+ 0, QgsFieldConstraints.Constraint.ConstraintUnique, 5
+ )
+ )
self.assertTrue(
- layer.dataProvider().skipConstraintCheck(0, QgsFieldConstraints.Constraint.ConstraintUnique, QgsUnsetAttributeValue()))
+ layer.dataProvider().skipConstraintCheck(
+ 0, QgsFieldConstraints.Constraint.ConstraintUnique, "Autogenerate"
+ )
+ )
+ self.assertTrue(
+ layer.dataProvider().skipConstraintCheck(
+ 0,
+ QgsFieldConstraints.Constraint.ConstraintUnique,
+ QgsUnsetAttributeValue(),
+ )
+ )
self.assertTrue(
- layer.dataProvider().skipConstraintCheck(0, QgsFieldConstraints.Constraint.ConstraintUnique, QgsUnsetAttributeValue('Autogenerate')))
- self.assertFalse(layer.dataProvider().skipConstraintCheck(1, QgsFieldConstraints.Constraint.ConstraintUnique, 'my name'))
+ layer.dataProvider().skipConstraintCheck(
+ 0,
+ QgsFieldConstraints.Constraint.ConstraintUnique,
+ QgsUnsetAttributeValue("Autogenerate"),
+ )
+ )
+ self.assertFalse(
+ layer.dataProvider().skipConstraintCheck(
+ 1, QgsFieldConstraints.Constraint.ConstraintUnique, "my name"
+ )
+ )
self.assertFalse(
- layer.dataProvider().skipConstraintCheck(1, QgsFieldConstraints.Constraint.ConstraintUnique, NULL))
+ layer.dataProvider().skipConstraintCheck(
+ 1, QgsFieldConstraints.Constraint.ConstraintUnique, NULL
+ )
+ )
self.assertTrue(
- layer.dataProvider().skipConstraintCheck(1, QgsFieldConstraints.Constraint.ConstraintUnique, QgsUnsetAttributeValue()))
+ layer.dataProvider().skipConstraintCheck(
+ 1,
+ QgsFieldConstraints.Constraint.ConstraintUnique,
+ QgsUnsetAttributeValue(),
+ )
+ )
self.assertFalse(
- layer.dataProvider().skipConstraintCheck(2, QgsFieldConstraints.Constraint.ConstraintUnique, 11))
+ layer.dataProvider().skipConstraintCheck(
+ 2, QgsFieldConstraints.Constraint.ConstraintUnique, 11
+ )
+ )
self.assertTrue(
- layer.dataProvider().skipConstraintCheck(2, QgsFieldConstraints.Constraint.ConstraintUnique, QgsUnsetAttributeValue()))
+ layer.dataProvider().skipConstraintCheck(
+ 2,
+ QgsFieldConstraints.Constraint.ConstraintUnique,
+ QgsUnsetAttributeValue(),
+ )
+ )
feature = QgsFeature(layer.fields())
- feature.setAttributes([1, 'test1', 11])
+ feature.setAttributes([1, "test1", 11])
self.assertTrue(layer.dataProvider().addFeature(feature))
f1 = feature.id()
- feature.setAttributes([QgsUnsetAttributeValue('Autonumber'), 'test2', 22])
+ feature.setAttributes([QgsUnsetAttributeValue("Autonumber"), "test2", 22])
self.assertTrue(layer.dataProvider().addFeature(feature))
f2 = feature.id()
del layer
- layer = QgsVectorLayer(tmpfile, 'test')
+ layer = QgsVectorLayer(tmpfile, "test")
# read back in features and test
f1_read = layer.getFeature(f1)
- self.assertEqual(f1_read.attributes(), [1, 'test1', 11])
+ self.assertEqual(f1_read.attributes(), [1, "test1", 11])
f2_read = layer.getFeature(f2)
- self.assertEqual(f2_read.attributes(), [f2, 'test2', 22])
+ self.assertEqual(f2_read.attributes(), [f2, "test2", 22])
def testDataItems(self):
- dataitem = QgsDirectoryItem(None, 'name', unitTestDataPath())
+ dataitem = QgsDirectoryItem(None, "name", unitTestDataPath())
children = dataitem.createChildren()
# Single layer
- item = [i for i in children if i.path().endswith('lines.shp')][0]
- self.assertTrue(item.uri().endswith('lines.shp'))
+ item = [i for i in children if i.path().endswith("lines.shp")][0]
+ self.assertTrue(item.uri().endswith("lines.shp"))
# Multiple layer
- item = [i for i in children if i.path().endswith('multilayer.kml')][0]
+ item = [i for i in children if i.path().endswith("multilayer.kml")][0]
children = item.createChildren()
self.assertEqual(len(children), 2)
- self.assertIn('multilayer.kml|layername=Layer1', children[0].uri())
- self.assertIn('multilayer.kml|layername=Layer2', children[1].uri())
+ self.assertIn("multilayer.kml|layername=Layer1", children[0].uri())
+ self.assertIn("multilayer.kml|layername=Layer2", children[1].uri())
# Multiple layer (geopackage)
- tmpfile = os.path.join(self.basetestpath, 'testDataItems.gpkg')
- ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile)
- lyr = ds.CreateLayer('Layer1', geom_type=ogr.wkbPoint)
- lyr = ds.CreateLayer('Layer2', geom_type=ogr.wkbPoint)
+ tmpfile = os.path.join(self.basetestpath, "testDataItems.gpkg")
+ ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile)
+ lyr = ds.CreateLayer("Layer1", geom_type=ogr.wkbPoint)
+ lyr = ds.CreateLayer("Layer2", geom_type=ogr.wkbPoint)
ds = None
- dataitem = QgsDirectoryItem(None, 'name', self.basetestpath)
+ dataitem = QgsDirectoryItem(None, "name", self.basetestpath)
children = dataitem.createChildren()
- item = [i for i in children if i.path().endswith('testDataItems.gpkg')][0]
+ item = [i for i in children if i.path().endswith("testDataItems.gpkg")][0]
children = item.createChildren()
self.assertEqual(len(children), 2)
- self.assertIn('testDataItems.gpkg|layername=Layer1', children[0].uri())
- self.assertIn('testDataItems.gpkg|layername=Layer2', children[1].uri())
+ self.assertIn("testDataItems.gpkg|layername=Layer1", children[0].uri())
+ self.assertIn("testDataItems.gpkg|layername=Layer2", children[1].uri())
def testDataItemsRaster(self):
- dataitem = QgsDirectoryItem(None, 'name', unitTestDataPath())
+ dataitem = QgsDirectoryItem(None, "name", unitTestDataPath())
dir_children = dataitem.createChildren()
# Multiple layer (geopackage)
- item = [i for i in dir_children if i.path().endswith('two_raster_layers.gpkg')][0]
+ item = [i for i in dir_children if i.path().endswith("two_raster_layers.gpkg")][
+ 0
+ ]
children = item.createChildren()
self.assertEqual(len(children), 2)
- self.assertIn('GPKG:' + unitTestDataPath() + '/two_raster_layers.gpkg:layer01', children[0].uri())
- self.assertIn('GPKG:' + unitTestDataPath() + '/two_raster_layers.gpkg:layer02', children[1].uri())
+ self.assertIn(
+ "GPKG:" + unitTestDataPath() + "/two_raster_layers.gpkg:layer01",
+ children[0].uri(),
+ )
+ self.assertIn(
+ "GPKG:" + unitTestDataPath() + "/two_raster_layers.gpkg:layer02",
+ children[1].uri(),
+ )
def testOSM(self):
- """ Test that opening several layers of the same OSM datasource works properly """
+ """Test that opening several layers of the same OSM datasource works properly"""
- datasource = os.path.join(TEST_DATA_DIR, 'test.osm')
- vl_points = QgsVectorLayer(datasource + "|layername=points", 'test', 'ogr')
- vl_multipolygons = QgsVectorLayer(datasource + "|layername=multipolygons", 'test', 'ogr')
+ datasource = os.path.join(TEST_DATA_DIR, "test.osm")
+ vl_points = QgsVectorLayer(datasource + "|layername=points", "test", "ogr")
+ vl_multipolygons = QgsVectorLayer(
+ datasource + "|layername=multipolygons", "test", "ogr"
+ )
f = QgsFeature()
# When sharing the same dataset handle, the spatial filter of test
# points layer would apply to the other layers
- iter_points = vl_points.getFeatures(QgsFeatureRequest().setFilterRect(QgsRectangle(-200, -200, -200, -200)))
+ iter_points = vl_points.getFeatures(
+ QgsFeatureRequest().setFilterRect(QgsRectangle(-200, -200, -200, -200))
+ )
self.assertFalse(iter_points.nextFeature(f))
iter_multipolygons = vl_multipolygons.getFeatures(QgsFeatureRequest())
@@ -655,7 +791,9 @@ def testOSM(self):
self.assertEqual(f.id(), 5)
# 6 doesn't exist
- it = vl_multipolygons.getFeatures(QgsFeatureRequest().setFilterFids([1, 5, 6, 8]))
+ it = vl_multipolygons.getFeatures(
+ QgsFeatureRequest().setFilterFids([1, 5, 6, 8])
+ )
f = next(it)
self.assertTrue(f.isValid())
self.assertEqual(f.id(), 1)
@@ -668,43 +806,49 @@ def testOSM(self):
del it
def testBinaryField(self):
- source = os.path.join(TEST_DATA_DIR, 'attachments.gdb')
+ source = os.path.join(TEST_DATA_DIR, "attachments.gdb")
vl = QgsVectorLayer(source + "|layername=points__ATTACH")
self.assertTrue(vl.isValid())
fields = vl.fields()
- data_field = fields[fields.lookupField('DATA')]
+ data_field = fields[fields.lookupField("DATA")]
self.assertEqual(data_field.type(), QVariant.ByteArray)
- self.assertEqual(data_field.typeName(), 'Binary')
+ self.assertEqual(data_field.typeName(), "Binary")
- features = {f['ATTACHMENTID']: f for f in vl.getFeatures()}
+ features = {f["ATTACHMENTID"]: f for f in vl.getFeatures()}
self.assertEqual(len(features), 2)
- self.assertIsInstance(features[1]['DATA'], QByteArray)
- self.assertEqual(hashlib.md5(features[1]['DATA'].data()).hexdigest(), 'ef3dbc530cc39a545832a6c82aac57b6')
- self.assertIsInstance(features[2]['DATA'], QByteArray)
- self.assertEqual(hashlib.md5(features[2]['DATA'].data()).hexdigest(), '4b952b80e4288ca5111be2f6dd5d6809')
+ self.assertIsInstance(features[1]["DATA"], QByteArray)
+ self.assertEqual(
+ hashlib.md5(features[1]["DATA"].data()).hexdigest(),
+ "ef3dbc530cc39a545832a6c82aac57b6",
+ )
+ self.assertIsInstance(features[2]["DATA"], QByteArray)
+ self.assertEqual(
+ hashlib.md5(features[2]["DATA"].data()).hexdigest(),
+ "4b952b80e4288ca5111be2f6dd5d6809",
+ )
def testGmlStringListField(self):
- source = os.path.join(TEST_DATA_DIR, 'stringlist.gml')
+ source = os.path.join(TEST_DATA_DIR, "stringlist.gml")
vl = QgsVectorLayer(source)
self.assertTrue(vl.isValid())
fields = vl.fields()
- descriptive_group_field = fields[fields.lookupField('descriptiveGroup')]
+ descriptive_group_field = fields[fields.lookupField("descriptiveGroup")]
self.assertEqual(descriptive_group_field.type(), QVariant.StringList)
- self.assertEqual(descriptive_group_field.typeName(), 'StringList')
+ self.assertEqual(descriptive_group_field.typeName(), "StringList")
self.assertEqual(descriptive_group_field.subType(), QVariant.String)
feature = vl.getFeature(1000002717654)
- self.assertEqual(feature['descriptiveGroup'], ['Building'])
- self.assertEqual(feature['reasonForChange'], ['Reclassified', 'Attributes'])
-
- tmpfile = os.path.join(self.basetestpath, 'newstringlistfield.gml')
- ds = ogr.GetDriverByName('GML').CreateDataSource(tmpfile)
- lyr = ds.CreateLayer('test', geom_type=ogr.wkbPoint)
- lyr.CreateField(ogr.FieldDefn('strfield', ogr.OFTString))
- lyr.CreateField(ogr.FieldDefn('intfield', ogr.OFTInteger))
- lyr.CreateField(ogr.FieldDefn('strlistfield', ogr.OFTStringList))
+ self.assertEqual(feature["descriptiveGroup"], ["Building"])
+ self.assertEqual(feature["reasonForChange"], ["Reclassified", "Attributes"])
+
+ tmpfile = os.path.join(self.basetestpath, "newstringlistfield.gml")
+ ds = ogr.GetDriverByName("GML").CreateDataSource(tmpfile)
+ lyr = ds.CreateLayer("test", geom_type=ogr.wkbPoint)
+ lyr.CreateField(ogr.FieldDefn("strfield", ogr.OFTString))
+ lyr.CreateField(ogr.FieldDefn("intfield", ogr.OFTInteger))
+ lyr.CreateField(ogr.FieldDefn("strlistfield", ogr.OFTStringList))
ds = None
vl = QgsVectorLayer(tmpfile)
@@ -712,24 +856,24 @@ def testGmlStringListField(self):
dp = vl.dataProvider()
fields = dp.fields()
- list_field = fields[fields.lookupField('strlistfield')]
+ list_field = fields[fields.lookupField("strlistfield")]
self.assertEqual(list_field.type(), QVariant.StringList)
- self.assertEqual(list_field.typeName(), 'StringList')
+ self.assertEqual(list_field.typeName(), "StringList")
self.assertEqual(list_field.subType(), QVariant.String)
def testStringListField(self):
- tmpfile = os.path.join(self.basetestpath, 'newstringlistfield.geojson')
- ds = ogr.GetDriverByName('GeoJSON').CreateDataSource(tmpfile)
- lyr = ds.CreateLayer('test', geom_type=ogr.wkbPoint)
- lyr.CreateField(ogr.FieldDefn('strfield', ogr.OFTString))
- lyr.CreateField(ogr.FieldDefn('intfield', ogr.OFTInteger))
- lyr.CreateField(ogr.FieldDefn('stringlistfield', ogr.OFTStringList))
+ tmpfile = os.path.join(self.basetestpath, "newstringlistfield.geojson")
+ ds = ogr.GetDriverByName("GeoJSON").CreateDataSource(tmpfile)
+ lyr = ds.CreateLayer("test", geom_type=ogr.wkbPoint)
+ lyr.CreateField(ogr.FieldDefn("strfield", ogr.OFTString))
+ lyr.CreateField(ogr.FieldDefn("intfield", ogr.OFTInteger))
+ lyr.CreateField(ogr.FieldDefn("stringlistfield", ogr.OFTStringList))
f = ogr.Feature(lyr.GetLayerDefn())
- f.SetGeometry(ogr.CreateGeometryFromWkt('POINT (1 1)'))
- f.SetField('strfield', 'one')
- f.SetField('intfield', 1)
- f.SetFieldStringList(2, ['a', 'b', 'c'])
+ f.SetGeometry(ogr.CreateGeometryFromWkt("POINT (1 1)"))
+ f.SetField("strfield", "one")
+ f.SetField("intfield", 1)
+ f.SetFieldStringList(2, ["a", "b", "c"])
lyr.CreateFeature(f)
lyr = None
@@ -740,21 +884,21 @@ def testStringListField(self):
dp = vl.dataProvider()
fields = dp.fields()
- list_field = fields[fields.lookupField('stringlistfield')]
+ list_field = fields[fields.lookupField("stringlistfield")]
self.assertEqual(list_field.type(), QVariant.StringList)
- self.assertEqual(list_field.typeName(), 'StringList')
+ self.assertEqual(list_field.typeName(), "StringList")
self.assertEqual(list_field.subType(), QVariant.String)
f = next(vl.getFeatures())
- self.assertEqual(f.attributes(), ['one', 1, ['a', 'b', 'c']])
+ self.assertEqual(f.attributes(), ["one", 1, ["a", "b", "c"]])
# add features
f = QgsFeature()
- f.setAttributes(['two', 2, ['z', 'y', 'x']])
+ f.setAttributes(["two", 2, ["z", "y", "x"]])
self.assertTrue(vl.dataProvider().addFeature(f))
- f.setAttributes(['three', 3, NULL])
+ f.setAttributes(["three", 3, NULL])
self.assertTrue(vl.dataProvider().addFeature(f))
- f.setAttributes(['four', 4, []])
+ f.setAttributes(["four", 4, []])
self.assertTrue(vl.dataProvider().addFeature(f))
vl = None
@@ -762,54 +906,81 @@ def testStringListField(self):
vl = QgsVectorLayer(tmpfile)
self.assertTrue(vl.isValid())
- self.assertEqual([f.attributes() for f in vl.getFeatures()],
- [['one', 1, ['a', 'b', 'c']],
- ['two', 2, ['z', 'y', 'x']],
- ['three', 3, NULL],
- ['four', 4, NULL]])
+ self.assertEqual(
+ [f.attributes() for f in vl.getFeatures()],
+ [
+ ["one", 1, ["a", "b", "c"]],
+ ["two", 2, ["z", "y", "x"]],
+ ["three", 3, NULL],
+ ["four", 4, NULL],
+ ],
+ )
# change attribute values
f1_id = [f.id() for f in vl.getFeatures() if f.attributes()[1] == 1][0]
f3_id = [f.id() for f in vl.getFeatures() if f.attributes()[1] == 3][0]
- self.assertTrue(vl.dataProvider().changeAttributeValues({f1_id: {2: NULL}, f3_id: {2: ['m', 'n', 'o']}}))
+ self.assertTrue(
+ vl.dataProvider().changeAttributeValues(
+ {f1_id: {2: NULL}, f3_id: {2: ["m", "n", "o"]}}
+ )
+ )
vl = QgsVectorLayer(tmpfile)
self.assertTrue(vl.isValid())
- self.assertEqual([f.attributes() for f in vl.getFeatures()],
- [['one', 1, NULL],
- ['two', 2, ['z', 'y', 'x']],
- ['three', 3, ['m', 'n', 'o']],
- ['four', 4, NULL]])
+ self.assertEqual(
+ [f.attributes() for f in vl.getFeatures()],
+ [
+ ["one", 1, NULL],
+ ["two", 2, ["z", "y", "x"]],
+ ["three", 3, ["m", "n", "o"]],
+ ["four", 4, NULL],
+ ],
+ )
# add attribute
self.assertTrue(
- vl.dataProvider().addAttributes([QgsField('new_list', type=QVariant.StringList, subType=QVariant.String)]))
+ vl.dataProvider().addAttributes(
+ [
+ QgsField(
+ "new_list", type=QVariant.StringList, subType=QVariant.String
+ )
+ ]
+ )
+ )
f1_id = [f.id() for f in vl.getFeatures() if f.attributes()[1] == 1][0]
f3_id = [f.id() for f in vl.getFeatures() if f.attributes()[1] == 3][0]
- self.assertTrue(vl.dataProvider().changeAttributeValues({f1_id: {3: ['111', '222']}, f3_id: {3: ['121', '122', '123']}}))
+ self.assertTrue(
+ vl.dataProvider().changeAttributeValues(
+ {f1_id: {3: ["111", "222"]}, f3_id: {3: ["121", "122", "123"]}}
+ )
+ )
vl = QgsVectorLayer(tmpfile)
self.assertTrue(vl.isValid())
- self.assertEqual([f.attributes() for f in vl.getFeatures()],
- [['one', 1, NULL, ['111', '222']],
- ['two', 2, ['z', 'y', 'x'], NULL],
- ['three', 3, ['m', 'n', 'o'], ['121', '122', '123']],
- ['four', 4, NULL, NULL]])
+ self.assertEqual(
+ [f.attributes() for f in vl.getFeatures()],
+ [
+ ["one", 1, NULL, ["111", "222"]],
+ ["two", 2, ["z", "y", "x"], NULL],
+ ["three", 3, ["m", "n", "o"], ["121", "122", "123"]],
+ ["four", 4, NULL, NULL],
+ ],
+ )
def testIntListField(self):
- tmpfile = os.path.join(self.basetestpath, 'newintlistfield.geojson')
- ds = ogr.GetDriverByName('GeoJSON').CreateDataSource(tmpfile)
- lyr = ds.CreateLayer('test', geom_type=ogr.wkbPoint)
- lyr.CreateField(ogr.FieldDefn('strfield', ogr.OFTString))
- lyr.CreateField(ogr.FieldDefn('intfield', ogr.OFTInteger))
- lyr.CreateField(ogr.FieldDefn('intlistfield', ogr.OFTIntegerList))
+ tmpfile = os.path.join(self.basetestpath, "newintlistfield.geojson")
+ ds = ogr.GetDriverByName("GeoJSON").CreateDataSource(tmpfile)
+ lyr = ds.CreateLayer("test", geom_type=ogr.wkbPoint)
+ lyr.CreateField(ogr.FieldDefn("strfield", ogr.OFTString))
+ lyr.CreateField(ogr.FieldDefn("intfield", ogr.OFTInteger))
+ lyr.CreateField(ogr.FieldDefn("intlistfield", ogr.OFTIntegerList))
f = ogr.Feature(lyr.GetLayerDefn())
- f.SetGeometry(ogr.CreateGeometryFromWkt('POINT (1 1)'))
- f.SetField('strfield', 'one')
- f.SetField('intfield', 1)
+ f.SetGeometry(ogr.CreateGeometryFromWkt("POINT (1 1)"))
+ f.SetField("strfield", "one")
+ f.SetField("intfield", 1)
f.SetFieldIntegerList(2, [1, 2, 3, 4])
lyr.CreateFeature(f)
@@ -821,21 +992,21 @@ def testIntListField(self):
dp = vl.dataProvider()
fields = dp.fields()
- list_field = fields[fields.lookupField('intlistfield')]
+ list_field = fields[fields.lookupField("intlistfield")]
self.assertEqual(list_field.type(), QVariant.List)
- self.assertEqual(list_field.typeName(), 'IntegerList')
+ self.assertEqual(list_field.typeName(), "IntegerList")
self.assertEqual(list_field.subType(), QVariant.Int)
f = next(vl.getFeatures())
- self.assertEqual(f.attributes(), ['one', 1, [1, 2, 3, 4]])
+ self.assertEqual(f.attributes(), ["one", 1, [1, 2, 3, 4]])
# add features
f = QgsFeature()
- f.setAttributes(['two', 2, [11, 12, 13, 14]])
+ f.setAttributes(["two", 2, [11, 12, 13, 14]])
self.assertTrue(vl.dataProvider().addFeature(f))
- f.setAttributes(['three', 3, NULL])
+ f.setAttributes(["three", 3, NULL])
self.assertTrue(vl.dataProvider().addFeature(f))
- f.setAttributes(['four', 4, []])
+ f.setAttributes(["four", 4, []])
self.assertTrue(vl.dataProvider().addFeature(f))
vl = None
@@ -843,54 +1014,77 @@ def testIntListField(self):
vl = QgsVectorLayer(tmpfile)
self.assertTrue(vl.isValid())
- self.assertEqual([f.attributes() for f in vl.getFeatures()],
- [['one', 1, [1, 2, 3, 4]],
- ['two', 2, [11, 12, 13, 14]],
- ['three', 3, NULL],
- ['four', 4, NULL]])
+ self.assertEqual(
+ [f.attributes() for f in vl.getFeatures()],
+ [
+ ["one", 1, [1, 2, 3, 4]],
+ ["two", 2, [11, 12, 13, 14]],
+ ["three", 3, NULL],
+ ["four", 4, NULL],
+ ],
+ )
# change attribute values
f1_id = [f.id() for f in vl.getFeatures() if f.attributes()[1] == 1][0]
f3_id = [f.id() for f in vl.getFeatures() if f.attributes()[1] == 3][0]
- self.assertTrue(vl.dataProvider().changeAttributeValues({f1_id: {2: NULL}, f3_id: {2: [21, 22, 23]}}))
+ self.assertTrue(
+ vl.dataProvider().changeAttributeValues(
+ {f1_id: {2: NULL}, f3_id: {2: [21, 22, 23]}}
+ )
+ )
vl = QgsVectorLayer(tmpfile)
self.assertTrue(vl.isValid())
- self.assertEqual([f.attributes() for f in vl.getFeatures()],
- [['one', 1, NULL],
- ['two', 2, [11, 12, 13, 14]],
- ['three', 3, [21, 22, 23]],
- ['four', 4, NULL]])
+ self.assertEqual(
+ [f.attributes() for f in vl.getFeatures()],
+ [
+ ["one", 1, NULL],
+ ["two", 2, [11, 12, 13, 14]],
+ ["three", 3, [21, 22, 23]],
+ ["four", 4, NULL],
+ ],
+ )
# add attribute
self.assertTrue(
- vl.dataProvider().addAttributes([QgsField('new_list', type=QVariant.List, subType=QVariant.Int)]))
+ vl.dataProvider().addAttributes(
+ [QgsField("new_list", type=QVariant.List, subType=QVariant.Int)]
+ )
+ )
f1_id = [f.id() for f in vl.getFeatures() if f.attributes()[1] == 1][0]
f3_id = [f.id() for f in vl.getFeatures() if f.attributes()[1] == 3][0]
- self.assertTrue(vl.dataProvider().changeAttributeValues({f1_id: {3: [111, 222]}, f3_id: {3: [121, 122, 123]}}))
+ self.assertTrue(
+ vl.dataProvider().changeAttributeValues(
+ {f1_id: {3: [111, 222]}, f3_id: {3: [121, 122, 123]}}
+ )
+ )
vl = QgsVectorLayer(tmpfile)
self.assertTrue(vl.isValid())
- self.assertEqual([f.attributes() for f in vl.getFeatures()],
- [['one', 1, NULL, [111, 222]],
- ['two', 2, [11, 12, 13, 14], NULL],
- ['three', 3, [21, 22, 23], [121, 122, 123]],
- ['four', 4, NULL, NULL]])
+ self.assertEqual(
+ [f.attributes() for f in vl.getFeatures()],
+ [
+ ["one", 1, NULL, [111, 222]],
+ ["two", 2, [11, 12, 13, 14], NULL],
+ ["three", 3, [21, 22, 23], [121, 122, 123]],
+ ["four", 4, NULL, NULL],
+ ],
+ )
def testDoubleListField(self):
- tmpfile = os.path.join(self.basetestpath, 'newdoublelistfield.geojson')
- ds = ogr.GetDriverByName('GeoJSON').CreateDataSource(tmpfile)
- lyr = ds.CreateLayer('test', geom_type=ogr.wkbPoint)
- lyr.CreateField(ogr.FieldDefn('strfield', ogr.OFTString))
- lyr.CreateField(ogr.FieldDefn('intfield', ogr.OFTInteger))
- lyr.CreateField(ogr.FieldDefn('doublelistfield', ogr.OFTRealList))
+ tmpfile = os.path.join(self.basetestpath, "newdoublelistfield.geojson")
+ ds = ogr.GetDriverByName("GeoJSON").CreateDataSource(tmpfile)
+ lyr = ds.CreateLayer("test", geom_type=ogr.wkbPoint)
+ lyr.CreateField(ogr.FieldDefn("strfield", ogr.OFTString))
+ lyr.CreateField(ogr.FieldDefn("intfield", ogr.OFTInteger))
+ lyr.CreateField(ogr.FieldDefn("doublelistfield", ogr.OFTRealList))
f = ogr.Feature(lyr.GetLayerDefn())
- f.SetGeometry(ogr.CreateGeometryFromWkt('POINT (1 1)'))
- f.SetField('strfield', 'one')
- f.SetField('intfield', 1)
+ f.SetGeometry(ogr.CreateGeometryFromWkt("POINT (1 1)"))
+ f.SetField("strfield", "one")
+ f.SetField("intfield", 1)
f.SetFieldDoubleList(2, [1.1, 2.2, 3.3, 4.4])
lyr.CreateFeature(f)
@@ -902,21 +1096,21 @@ def testDoubleListField(self):
dp = vl.dataProvider()
fields = dp.fields()
- list_field = fields[fields.lookupField('doublelistfield')]
+ list_field = fields[fields.lookupField("doublelistfield")]
self.assertEqual(list_field.type(), QVariant.List)
- self.assertEqual(list_field.typeName(), 'RealList')
+ self.assertEqual(list_field.typeName(), "RealList")
self.assertEqual(list_field.subType(), QVariant.Double)
f = next(vl.getFeatures())
- self.assertEqual(f.attributes(), ['one', 1, [1.1, 2.2, 3.3, 4.4]])
+ self.assertEqual(f.attributes(), ["one", 1, [1.1, 2.2, 3.3, 4.4]])
# add features
f = QgsFeature()
- f.setAttributes(['two', 2, [11.1, 12.2, 13.3, 14.4]])
+ f.setAttributes(["two", 2, [11.1, 12.2, 13.3, 14.4]])
self.assertTrue(vl.dataProvider().addFeature(f))
- f.setAttributes(['three', 3, NULL])
+ f.setAttributes(["three", 3, NULL])
self.assertTrue(vl.dataProvider().addFeature(f))
- f.setAttributes(['four', 4, []])
+ f.setAttributes(["four", 4, []])
self.assertTrue(vl.dataProvider().addFeature(f))
vl = None
@@ -924,56 +1118,80 @@ def testDoubleListField(self):
vl = QgsVectorLayer(tmpfile)
self.assertTrue(vl.isValid())
- self.assertEqual([f.attributes() for f in vl.getFeatures()],
- [['one', 1, [1.1, 2.2, 3.3, 4.4]],
- ['two', 2, [11.1, 12.2, 13.3, 14.4]],
- ['three', 3, NULL],
- ['four', 4, NULL]])
+ self.assertEqual(
+ [f.attributes() for f in vl.getFeatures()],
+ [
+ ["one", 1, [1.1, 2.2, 3.3, 4.4]],
+ ["two", 2, [11.1, 12.2, 13.3, 14.4]],
+ ["three", 3, NULL],
+ ["four", 4, NULL],
+ ],
+ )
# change attribute values
f1_id = [f.id() for f in vl.getFeatures() if f.attributes()[1] == 1][0]
f3_id = [f.id() for f in vl.getFeatures() if f.attributes()[1] == 3][0]
- self.assertTrue(vl.dataProvider().changeAttributeValues({f1_id: {2: NULL}, f3_id: {2: [21.1, 22.2, 23.3]}}))
+ self.assertTrue(
+ vl.dataProvider().changeAttributeValues(
+ {f1_id: {2: NULL}, f3_id: {2: [21.1, 22.2, 23.3]}}
+ )
+ )
vl = QgsVectorLayer(tmpfile)
self.assertTrue(vl.isValid())
- self.assertEqual([f.attributes() for f in vl.getFeatures()],
- [['one', 1, NULL],
- ['two', 2, [11.1, 12.2, 13.3, 14.4]],
- ['three', 3, [21.1, 22.2, 23.3]],
- ['four', 4, NULL]])
+ self.assertEqual(
+ [f.attributes() for f in vl.getFeatures()],
+ [
+ ["one", 1, NULL],
+ ["two", 2, [11.1, 12.2, 13.3, 14.4]],
+ ["three", 3, [21.1, 22.2, 23.3]],
+ ["four", 4, NULL],
+ ],
+ )
# add attribute
self.assertTrue(
- vl.dataProvider().addAttributes([QgsField('new_list', type=QVariant.List, subType=QVariant.Double)]))
+ vl.dataProvider().addAttributes(
+ [QgsField("new_list", type=QVariant.List, subType=QVariant.Double)]
+ )
+ )
f1_id = [f.id() for f in vl.getFeatures() if f.attributes()[1] == 1][0]
f3_id = [f.id() for f in vl.getFeatures() if f.attributes()[1] == 3][0]
self.assertTrue(
- vl.dataProvider().changeAttributeValues({f1_id: {3: [111.1, 222.2]}, f3_id: {3: [121.1, 122.2, 123.3]}}))
+ vl.dataProvider().changeAttributeValues(
+ {f1_id: {3: [111.1, 222.2]}, f3_id: {3: [121.1, 122.2, 123.3]}}
+ )
+ )
vl = QgsVectorLayer(tmpfile)
self.assertTrue(vl.isValid())
- self.assertEqual([f.attributes() for f in vl.getFeatures()],
- [['one', 1, NULL, [111.1, 222.2]],
- ['two', 2, [11.1, 12.2, 13.3, 14.4], NULL],
- ['three', 3, [21.1, 22.2, 23.3], [121.1, 122.2, 123.3]],
- ['four', 4, NULL, NULL]])
+ self.assertEqual(
+ [f.attributes() for f in vl.getFeatures()],
+ [
+ ["one", 1, NULL, [111.1, 222.2]],
+ ["two", 2, [11.1, 12.2, 13.3, 14.4], NULL],
+ ["three", 3, [21.1, 22.2, 23.3], [121.1, 122.2, 123.3]],
+ ["four", 4, NULL, NULL],
+ ],
+ )
def testInteger64ListField(self):
- tmpfile = os.path.join(self.basetestpath, 'newlonglonglistfield.geojson')
- ds = ogr.GetDriverByName('GeoJSON').CreateDataSource(tmpfile)
- lyr = ds.CreateLayer('test', geom_type=ogr.wkbPoint)
- lyr.CreateField(ogr.FieldDefn('strfield', ogr.OFTString))
- lyr.CreateField(ogr.FieldDefn('intfield', ogr.OFTInteger))
- lyr.CreateField(ogr.FieldDefn('longlonglistfield', ogr.OFTInteger64List))
+ tmpfile = os.path.join(self.basetestpath, "newlonglonglistfield.geojson")
+ ds = ogr.GetDriverByName("GeoJSON").CreateDataSource(tmpfile)
+ lyr = ds.CreateLayer("test", geom_type=ogr.wkbPoint)
+ lyr.CreateField(ogr.FieldDefn("strfield", ogr.OFTString))
+ lyr.CreateField(ogr.FieldDefn("intfield", ogr.OFTInteger))
+ lyr.CreateField(ogr.FieldDefn("longlonglistfield", ogr.OFTInteger64List))
f = ogr.Feature(lyr.GetLayerDefn())
- f.SetGeometry(ogr.CreateGeometryFromWkt('POINT (1 1)'))
- f.SetField('strfield', 'one')
- f.SetField('intfield', 1)
- f.SetFieldDoubleList(2, [1234567890123, 1234567890124, 1234567890125, 1234567890126])
+ f.SetGeometry(ogr.CreateGeometryFromWkt("POINT (1 1)"))
+ f.SetField("strfield", "one")
+ f.SetField("intfield", 1)
+ f.SetFieldDoubleList(
+ 2, [1234567890123, 1234567890124, 1234567890125, 1234567890126]
+ )
lyr.CreateFeature(f)
lyr = None
@@ -984,21 +1202,26 @@ def testInteger64ListField(self):
dp = vl.dataProvider()
fields = dp.fields()
- list_field = fields[fields.lookupField('longlonglistfield')]
+ list_field = fields[fields.lookupField("longlonglistfield")]
self.assertEqual(list_field.type(), QVariant.List)
- self.assertEqual(list_field.typeName(), 'Integer64List')
+ self.assertEqual(list_field.typeName(), "Integer64List")
self.assertEqual(list_field.subType(), QVariant.LongLong)
f = next(vl.getFeatures())
- self.assertEqual(f.attributes(), ['one', 1, [1234567890123, 1234567890124, 1234567890125, 1234567890126]])
+ self.assertEqual(
+ f.attributes(),
+ ["one", 1, [1234567890123, 1234567890124, 1234567890125, 1234567890126]],
+ )
# add features
f = QgsFeature()
- f.setAttributes(['two', 2, [2234567890123, 2234567890124, 2234567890125, 2234567890126]])
+ f.setAttributes(
+ ["two", 2, [2234567890123, 2234567890124, 2234567890125, 2234567890126]]
+ )
self.assertTrue(vl.dataProvider().addFeature(f))
- f.setAttributes(['three', 3, NULL])
+ f.setAttributes(["three", 3, NULL])
self.assertTrue(vl.dataProvider().addFeature(f))
- f.setAttributes(['four', 4, []])
+ f.setAttributes(["four", 4, []])
self.assertTrue(vl.dataProvider().addFeature(f))
vl = None
@@ -1006,54 +1229,108 @@ def testInteger64ListField(self):
vl = QgsVectorLayer(tmpfile)
self.assertTrue(vl.isValid())
- self.assertEqual([f.attributes() for f in vl.getFeatures()],
- [['one', 1, [1234567890123, 1234567890124, 1234567890125, 1234567890126]],
- ['two', 2, [2234567890123, 2234567890124, 2234567890125, 2234567890126]],
- ['three', 3, NULL],
- ['four', 4, NULL]])
+ self.assertEqual(
+ [f.attributes() for f in vl.getFeatures()],
+ [
+ [
+ "one",
+ 1,
+ [1234567890123, 1234567890124, 1234567890125, 1234567890126],
+ ],
+ [
+ "two",
+ 2,
+ [2234567890123, 2234567890124, 2234567890125, 2234567890126],
+ ],
+ ["three", 3, NULL],
+ ["four", 4, NULL],
+ ],
+ )
# change attribute values
f1_id = [f.id() for f in vl.getFeatures() if f.attributes()[1] == 1][0]
f3_id = [f.id() for f in vl.getFeatures() if f.attributes()[1] == 3][0]
- self.assertTrue(vl.dataProvider().changeAttributeValues(
- {f1_id: {2: NULL}, f3_id: {2: [3234567890123, 3234567890124, 3234567890125, 3234567890126]}}))
+ self.assertTrue(
+ vl.dataProvider().changeAttributeValues(
+ {
+ f1_id: {2: NULL},
+ f3_id: {
+ 2: [3234567890123, 3234567890124, 3234567890125, 3234567890126]
+ },
+ }
+ )
+ )
vl = QgsVectorLayer(tmpfile)
self.assertTrue(vl.isValid())
- self.assertEqual([f.attributes() for f in vl.getFeatures()],
- [['one', 1, NULL],
- ['two', 2, [2234567890123, 2234567890124, 2234567890125, 2234567890126]],
- ['three', 3, [3234567890123, 3234567890124, 3234567890125, 3234567890126]],
- ['four', 4, NULL]])
+ self.assertEqual(
+ [f.attributes() for f in vl.getFeatures()],
+ [
+ ["one", 1, NULL],
+ [
+ "two",
+ 2,
+ [2234567890123, 2234567890124, 2234567890125, 2234567890126],
+ ],
+ [
+ "three",
+ 3,
+ [3234567890123, 3234567890124, 3234567890125, 3234567890126],
+ ],
+ ["four", 4, NULL],
+ ],
+ )
# add attribute
self.assertTrue(
- vl.dataProvider().addAttributes([QgsField('new_list', type=QVariant.List, subType=QVariant.LongLong)]))
+ vl.dataProvider().addAttributes(
+ [QgsField("new_list", type=QVariant.List, subType=QVariant.LongLong)]
+ )
+ )
f1_id = [f.id() for f in vl.getFeatures() if f.attributes()[1] == 1][0]
f3_id = [f.id() for f in vl.getFeatures() if f.attributes()[1] == 3][0]
- self.assertTrue(vl.dataProvider().changeAttributeValues(
- {f1_id: {3: [4234567890123, 4234567890124]}, f3_id: {3: [5234567890123, 5234567890124, 5234567890125]}}))
+ self.assertTrue(
+ vl.dataProvider().changeAttributeValues(
+ {
+ f1_id: {3: [4234567890123, 4234567890124]},
+ f3_id: {3: [5234567890123, 5234567890124, 5234567890125]},
+ }
+ )
+ )
vl = QgsVectorLayer(tmpfile)
self.assertTrue(vl.isValid())
- self.assertEqual([f.attributes() for f in vl.getFeatures()],
- [['one', 1, NULL, [4234567890123, 4234567890124]],
- ['two', 2, [2234567890123, 2234567890124, 2234567890125, 2234567890126], NULL],
- ['three', 3, [3234567890123, 3234567890124, 3234567890125, 3234567890126],
- [5234567890123, 5234567890124, 5234567890125]],
- ['four', 4, NULL, NULL]])
+ self.assertEqual(
+ [f.attributes() for f in vl.getFeatures()],
+ [
+ ["one", 1, NULL, [4234567890123, 4234567890124]],
+ [
+ "two",
+ 2,
+ [2234567890123, 2234567890124, 2234567890125, 2234567890126],
+ NULL,
+ ],
+ [
+ "three",
+ 3,
+ [3234567890123, 3234567890124, 3234567890125, 3234567890126],
+ [5234567890123, 5234567890124, 5234567890125],
+ ],
+ ["four", 4, NULL, NULL],
+ ],
+ )
def testBlobCreation(self):
"""
Test creating binary blob field in existing table
"""
- tmpfile = os.path.join(self.basetestpath, 'newbinaryfield.sqlite')
- ds = ogr.GetDriverByName('SQLite').CreateDataSource(tmpfile)
- lyr = ds.CreateLayer('test', geom_type=ogr.wkbPoint, options=['FID=fid'])
- lyr.CreateField(ogr.FieldDefn('strfield', ogr.OFTString))
- lyr.CreateField(ogr.FieldDefn('intfield', ogr.OFTInteger))
+ tmpfile = os.path.join(self.basetestpath, "newbinaryfield.sqlite")
+ ds = ogr.GetDriverByName("SQLite").CreateDataSource(tmpfile)
+ lyr = ds.CreateLayer("test", geom_type=ogr.wkbPoint, options=["FID=fid"])
+ lyr.CreateField(ogr.FieldDefn("strfield", ogr.OFTString))
+ lyr.CreateField(ogr.FieldDefn("intfield", ogr.OFTInteger))
f = None
ds = None
@@ -1062,53 +1339,59 @@ def testBlobCreation(self):
dp = vl.dataProvider()
f = QgsFeature(dp.fields())
- f.setAttributes([1, 'str', 100])
+ f.setAttributes([1, "str", 100])
self.assertTrue(dp.addFeature(f))
# add binary field
- self.assertTrue(dp.addAttributes([QgsField('binfield', QVariant.ByteArray)]))
+ self.assertTrue(dp.addAttributes([QgsField("binfield", QVariant.ByteArray)]))
fields = dp.fields()
- bin1_field = fields[fields.lookupField('binfield')]
+ bin1_field = fields[fields.lookupField("binfield")]
self.assertEqual(bin1_field.type(), QVariant.ByteArray)
- self.assertEqual(bin1_field.typeName(), 'Binary')
+ self.assertEqual(bin1_field.typeName(), "Binary")
f = QgsFeature(fields)
- bin_1 = b'xxx'
+ bin_1 = b"xxx"
bin_val1 = QByteArray(bin_1)
- f.setAttributes([2, 'str2', 200, bin_val1])
+ f.setAttributes([2, "str2", 200, bin_val1])
self.assertTrue(dp.addFeature(f))
f2 = [f for f in dp.getFeatures()][1]
- self.assertEqual(f2.attributes(), [2, 'str2', 200, QByteArray(bin_1)])
+ self.assertEqual(f2.attributes(), [2, "str2", 200, QByteArray(bin_1)])
def testBoolFieldEvaluation(self):
- datasource = os.path.join(unitTestDataPath(), 'bool_geojson.json')
- vl = QgsVectorLayer(datasource, 'test', 'ogr')
+ datasource = os.path.join(unitTestDataPath(), "bool_geojson.json")
+ vl = QgsVectorLayer(datasource, "test", "ogr")
self.assertTrue(vl.isValid())
- self.assertEqual(vl.fields().at(0).name(), 'bool')
+ self.assertEqual(vl.fields().at(0).name(), "bool")
self.assertEqual(vl.fields().at(0).type(), QVariant.Bool)
self.assertEqual([f[0] for f in vl.getFeatures()], [True, False, NULL])
def testReloadDataAndFeatureCount(self):
- filename = '/vsimem/test.json'
- gdal.FileFromMemBuffer(filename, """{
+ filename = "/vsimem/test.json"
+ gdal.FileFromMemBuffer(
+ filename,
+ """{
"type": "FeatureCollection",
"features": [
{ "type": "Feature", "properties": null, "geometry": { "type": "Point", "coordinates": [2, 49] } },
{ "type": "Feature", "properties": null, "geometry": { "type": "Point", "coordinates": [3, 50] } }
]
-}""")
- vl = QgsVectorLayer(filename, 'test', 'ogr')
+}""",
+ )
+ vl = QgsVectorLayer(filename, "test", "ogr")
self.assertTrue(vl.isValid())
self.assertEqual(vl.featureCount(), 2)
- gdal.FileFromMemBuffer(filename, """{
+ gdal.FileFromMemBuffer(
+ filename,
+ """{
"type": "FeatureCollection",
"features": [
{ "type": "Feature", "properties": null, "geometry": { "type": "Point", "coordinates": [2, 49] } }
]
-}""")
+}""",
+ )
vl.reload()
self.assertEqual(vl.featureCount(), 1)
gdal.Unlink(filename)
@@ -1143,7 +1426,11 @@ def testSpatialiteDefaultValues(self):
cur.execute("COMMIT")
con.close()
- vl = QgsVectorLayer(dbname + '|layername=test_table_default_values', 'test_table_default_values', 'ogr')
+ vl = QgsVectorLayer(
+ dbname + "|layername=test_table_default_values",
+ "test_table_default_values",
+ "ogr",
+ )
self.assertTrue(vl.isValid())
# Save it for the test
@@ -1155,12 +1442,12 @@ def testSpatialiteDefaultValues(self):
self.assertIsNone(dp.defaultValue(1))
# FIXME: This fails because there is no backend-side evaluation in this provider
# self.assertTrue(dp.defaultValue(2).startswith(now.strftime('%Y-%m-%d')))
- self.assertTrue(dp.defaultValue(3).startswith(now.strftime('%Y-%m-%d')))
+ self.assertTrue(dp.defaultValue(3).startswith(now.strftime("%Y-%m-%d")))
self.assertEqual(dp.defaultValue(4), 123)
- self.assertEqual(dp.defaultValue(5), 'My default')
+ self.assertEqual(dp.defaultValue(5), "My default")
- self.assertEqual(dp.defaultValueClause(0), 'Autogenerate')
- self.assertEqual(dp.defaultValueClause(1), '')
+ self.assertEqual(dp.defaultValueClause(0), "Autogenerate")
+ self.assertEqual(dp.defaultValueClause(1), "")
self.assertEqual(dp.defaultValueClause(2), "datetime('now','localtime')")
self.assertEqual(dp.defaultValueClause(3), "CURRENT_TIMESTAMP")
# FIXME: ogr provider simply returns values when asked for clauses
@@ -1171,153 +1458,264 @@ def testSpatialiteDefaultValues(self):
for idx in range(vl.fields().count()):
default = vl.dataProvider().defaultValue(idx)
if not default:
- feature.setAttribute(idx, 'A comment')
+ feature.setAttribute(idx, "A comment")
else:
feature.setAttribute(idx, default)
self.assertTrue(vl.dataProvider().addFeature(feature))
- del (vl)
+ del vl
# Verify
- vl2 = QgsVectorLayer(dbname + '|layername=test_table_default_values', 'test_table_default_values', 'ogr')
+ vl2 = QgsVectorLayer(
+ dbname + "|layername=test_table_default_values",
+ "test_table_default_values",
+ "ogr",
+ )
self.assertTrue(vl2.isValid())
feature = next(vl2.getFeatures())
- self.assertEqual(feature.attribute(1), 'A comment')
- self.assertTrue(feature.attribute(2).startswith(now.strftime('%Y-%m-%d')))
- self.assertTrue(feature.attribute(3).startswith(now.strftime('%Y-%m-%d')))
+ self.assertEqual(feature.attribute(1), "A comment")
+ self.assertTrue(feature.attribute(2).startswith(now.strftime("%Y-%m-%d")))
+ self.assertTrue(feature.attribute(3).startswith(now.strftime("%Y-%m-%d")))
self.assertEqual(feature.attribute(4), 123)
- self.assertEqual(feature.attribute(5), 'My default')
+ self.assertEqual(feature.attribute(5), "My default")
- def testMixOfFilterExpressionAndSubsetStringWhenFilterExpressionCompilationFails(self):
- datasource = os.path.join(unitTestDataPath(), 'filter_test.shp')
- vl = QgsVectorLayer(datasource, 'test', 'ogr')
+ def testMixOfFilterExpressionAndSubsetStringWhenFilterExpressionCompilationFails(
+ self,
+ ):
+ datasource = os.path.join(unitTestDataPath(), "filter_test.shp")
+ vl = QgsVectorLayer(datasource, "test", "ogr")
self.assertTrue(vl.isValid())
- self.assertCountEqual([f.attributes() for f in vl.getFeatures()], [['circle', '1'],
- ['circle', '2'],
- ['rectangle', '1'],
- ['rectangle', '2']])
+ self.assertCountEqual(
+ [f.attributes() for f in vl.getFeatures()],
+ [["circle", "1"], ["circle", "2"], ["rectangle", "1"], ["rectangle", "2"]],
+ )
# note - request uses wrong type for match (string vs int). This is OK for QGIS expressions,
# but will be rejected after we try to compile the expression for OGR to use.
request = QgsFeatureRequest().setFilterExpression('"color" = 1')
- self.assertCountEqual([f.attributes() for f in vl.getFeatures(request)], [['circle', '1'],
- ['rectangle', '1']])
+ self.assertCountEqual(
+ [f.attributes() for f in vl.getFeatures(request)],
+ [["circle", "1"], ["rectangle", "1"]],
+ )
request = QgsFeatureRequest().setFilterExpression('"color" = 1')
- self.assertCountEqual([f.attributes() for f in vl.getFeatures(request)], [['circle', '1'],
- ['rectangle', '1']])
+ self.assertCountEqual(
+ [f.attributes() for f in vl.getFeatures(request)],
+ [["circle", "1"], ["rectangle", "1"]],
+ )
vl.setSubsetString("\"shape\" = 'rectangle'")
- self.assertCountEqual([f.attributes() for f in vl.getFeatures()], [['rectangle', '1'],
- ['rectangle', '2']])
+ self.assertCountEqual(
+ [f.attributes() for f in vl.getFeatures()],
+ [["rectangle", "1"], ["rectangle", "2"]],
+ )
- self.assertCountEqual([f.attributes() for f in vl.getFeatures(request)], [['rectangle', '1']])
+ self.assertCountEqual(
+ [f.attributes() for f in vl.getFeatures(request)], [["rectangle", "1"]]
+ )
- @unittest.skipIf(int(gdal.VersionInfo('VERSION_NUM')) < GDAL_COMPUTE_VERSION(3, 2, 0), "GDAL 3.2 required")
+ @unittest.skipIf(
+ int(gdal.VersionInfo("VERSION_NUM")) < GDAL_COMPUTE_VERSION(3, 2, 0),
+ "GDAL 3.2 required",
+ )
def testFieldAliases(self):
"""
Test that field aliases are taken from OGR where available (requires GDAL 3.2 or later)
"""
- datasource = os.path.join(unitTestDataPath(), 'field_alias.gdb')
- vl = QgsVectorLayer(datasource, 'test', 'ogr')
+ datasource = os.path.join(unitTestDataPath(), "field_alias.gdb")
+ vl = QgsVectorLayer(datasource, "test", "ogr")
self.assertTrue(vl.isValid())
fields = vl.fields()
# proprietary FileGDB driver doesn't have the raster column
- if 'raster' not in {f.name() for f in fields}:
- expected_fieldnames = ['OBJECTID', 'text', 'short_int', 'long_int', 'float', 'double', 'date', 'blob',
- 'guid', 'SHAPE_Length', 'SHAPE_Area']
- expected_alias = ['', 'My Text Field', 'My Short Int Field', 'My Long Int Field', 'My Float Field',
- 'My Double Field', 'My Date Field', 'My Blob Field', 'My GUID field', '', '']
- expected_alias_map = {'OBJECTID': '', 'SHAPE_Area': '', 'SHAPE_Length': '', 'blob': 'My Blob Field',
- 'date': 'My Date Field', 'double': 'My Double Field', 'float': 'My Float Field',
- 'guid': 'My GUID field', 'long_int': 'My Long Int Field',
- 'short_int': 'My Short Int Field', 'text': 'My Text Field'}
+ if "raster" not in {f.name() for f in fields}:
+ expected_fieldnames = [
+ "OBJECTID",
+ "text",
+ "short_int",
+ "long_int",
+ "float",
+ "double",
+ "date",
+ "blob",
+ "guid",
+ "SHAPE_Length",
+ "SHAPE_Area",
+ ]
+ expected_alias = [
+ "",
+ "My Text Field",
+ "My Short Int Field",
+ "My Long Int Field",
+ "My Float Field",
+ "My Double Field",
+ "My Date Field",
+ "My Blob Field",
+ "My GUID field",
+ "",
+ "",
+ ]
+ expected_alias_map = {
+ "OBJECTID": "",
+ "SHAPE_Area": "",
+ "SHAPE_Length": "",
+ "blob": "My Blob Field",
+ "date": "My Date Field",
+ "double": "My Double Field",
+ "float": "My Float Field",
+ "guid": "My GUID field",
+ "long_int": "My Long Int Field",
+ "short_int": "My Short Int Field",
+ "text": "My Text Field",
+ }
else:
- expected_fieldnames = ['OBJECTID', 'text', 'short_int', 'long_int', 'float', 'double', 'date', 'blob',
- 'guid', 'raster', 'SHAPE_Length', 'SHAPE_Area']
- expected_alias = ['', 'My Text Field', 'My Short Int Field', 'My Long Int Field', 'My Float Field',
- 'My Double Field', 'My Date Field', 'My Blob Field', 'My GUID field', 'My Raster Field',
- '', '']
- expected_alias_map = {'OBJECTID': '', 'SHAPE_Area': '', 'SHAPE_Length': '', 'blob': 'My Blob Field',
- 'date': 'My Date Field', 'double': 'My Double Field', 'float': 'My Float Field',
- 'guid': 'My GUID field', 'long_int': 'My Long Int Field', 'raster': 'My Raster Field',
- 'short_int': 'My Short Int Field', 'text': 'My Text Field'}
+ expected_fieldnames = [
+ "OBJECTID",
+ "text",
+ "short_int",
+ "long_int",
+ "float",
+ "double",
+ "date",
+ "blob",
+ "guid",
+ "raster",
+ "SHAPE_Length",
+ "SHAPE_Area",
+ ]
+ expected_alias = [
+ "",
+ "My Text Field",
+ "My Short Int Field",
+ "My Long Int Field",
+ "My Float Field",
+ "My Double Field",
+ "My Date Field",
+ "My Blob Field",
+ "My GUID field",
+ "My Raster Field",
+ "",
+ "",
+ ]
+ expected_alias_map = {
+ "OBJECTID": "",
+ "SHAPE_Area": "",
+ "SHAPE_Length": "",
+ "blob": "My Blob Field",
+ "date": "My Date Field",
+ "double": "My Double Field",
+ "float": "My Float Field",
+ "guid": "My GUID field",
+ "long_int": "My Long Int Field",
+ "raster": "My Raster Field",
+ "short_int": "My Short Int Field",
+ "text": "My Text Field",
+ }
self.assertEqual([f.name() for f in fields], expected_fieldnames)
self.assertEqual([f.alias() for f in fields], expected_alias)
self.assertEqual(vl.attributeAliases(), expected_alias_map)
- @unittest.skipIf(int(gdal.VersionInfo('VERSION_NUM')) < GDAL_COMPUTE_VERSION(3, 3, 0), "GDAL 3.3 required")
+ @unittest.skipIf(
+ int(gdal.VersionInfo("VERSION_NUM")) < GDAL_COMPUTE_VERSION(3, 3, 0),
+ "GDAL 3.3 required",
+ )
def testFieldDomainNames(self):
"""
Test that field domain names are taken from OGR where available (requires GDAL 3.3 or later)
"""
- datasource = os.path.join(self.temp_dir_path, 'domains.gpkg')
- vl = QgsVectorLayer(datasource, 'test', 'ogr')
+ datasource = os.path.join(self.temp_dir_path, "domains.gpkg")
+ vl = QgsVectorLayer(datasource, "test", "ogr")
self.assertTrue(vl.isValid())
fields = vl.fields()
- self.assertEqual(fields.field('with_range_domain_int').constraints().domainName(), 'range_domain_int')
- self.assertEqual(fields.field('with_glob_domain').constraints().domainName(), 'glob_domain')
+ self.assertEqual(
+ fields.field("with_range_domain_int").constraints().domainName(),
+ "range_domain_int",
+ )
+ self.assertEqual(
+ fields.field("with_glob_domain").constraints().domainName(), "glob_domain"
+ )
- self.assertEqual(fields.field('with_range_domain_int').splitPolicy(), Qgis.FieldDomainSplitPolicy.DefaultValue)
- self.assertEqual(fields.field('with_glob_domain').splitPolicy(), Qgis.FieldDomainSplitPolicy.DefaultValue)
+ self.assertEqual(
+ fields.field("with_range_domain_int").splitPolicy(),
+ Qgis.FieldDomainSplitPolicy.DefaultValue,
+ )
+ self.assertEqual(
+ fields.field("with_glob_domain").splitPolicy(),
+ Qgis.FieldDomainSplitPolicy.DefaultValue,
+ )
- datasource = os.path.join(self.temp_dir_path, 'gps_timestamp.gpkg')
- vl = QgsVectorLayer(datasource, 'test', 'ogr')
+ datasource = os.path.join(self.temp_dir_path, "gps_timestamp.gpkg")
+ vl = QgsVectorLayer(datasource, "test", "ogr")
self.assertTrue(vl.isValid())
fields = vl.fields()
- self.assertFalse(fields.field('stringf').constraints().domainName())
+ self.assertFalse(fields.field("stringf").constraints().domainName())
with tempfile.TemporaryDirectory() as temp_dir:
- src_file_name = os.path.join(unitTestDataPath(), 'domains.gdb')
- dest_file_name = os.path.join(temp_dir, 'domains.gdb')
+ src_file_name = os.path.join(unitTestDataPath(), "domains.gdb")
+ dest_file_name = os.path.join(temp_dir, "domains.gdb")
shutil.copytree(src_file_name, dest_file_name)
- vl = QgsVectorLayer(dest_file_name + '|layername=test', 'test', 'ogr')
+ vl = QgsVectorLayer(dest_file_name + "|layername=test", "test", "ogr")
self.assertTrue(vl.isValid())
fields = vl.fields()
- self.assertEqual(fields.field('default_value').splitPolicy(),
- Qgis.FieldDomainSplitPolicy.DefaultValue)
- self.assertEqual(fields.field('duplicate').splitPolicy(),
- Qgis.FieldDomainSplitPolicy.Duplicate)
- self.assertEqual(fields.field('ratio').splitPolicy(),
- Qgis.FieldDomainSplitPolicy.GeometryRatio)
+ self.assertEqual(
+ fields.field("default_value").splitPolicy(),
+ Qgis.FieldDomainSplitPolicy.DefaultValue,
+ )
+ self.assertEqual(
+ fields.field("duplicate").splitPolicy(),
+ Qgis.FieldDomainSplitPolicy.Duplicate,
+ )
+ self.assertEqual(
+ fields.field("ratio").splitPolicy(),
+ Qgis.FieldDomainSplitPolicy.GeometryRatio,
+ )
def testGdbLayerMetadata(self):
"""
Test that we translate GDB metadata to QGIS layer metadata on loading a GDB source
"""
- datasource = os.path.join(unitTestDataPath(), 'gdb_metadata.gdb')
- vl = QgsVectorLayer(datasource, 'test', 'ogr')
- self.assertTrue(vl.isValid())
- self.assertEqual(vl.metadata().identifier(), 'Test')
- self.assertEqual(vl.metadata().title(), 'Title')
- self.assertEqual(vl.metadata().type(), 'dataset')
- self.assertEqual(vl.metadata().language(), 'ENG')
- self.assertIn('This is the abstract', vl.metadata().abstract())
- self.assertEqual(vl.metadata().keywords(), {'Search keys': ['Tags']})
- self.assertEqual(vl.metadata().rights(), ['This is the credits'])
- self.assertEqual(vl.metadata().constraints()[0].type, 'Limitations of use')
- self.assertEqual(vl.metadata().constraints()[0].constraint, 'This is the use limitation')
- self.assertEqual(vl.metadata().extent().spatialExtents()[0].bounds.xMinimum(), 1)
- self.assertEqual(vl.metadata().extent().spatialExtents()[0].bounds.xMaximum(), 2)
- self.assertEqual(vl.metadata().extent().spatialExtents()[0].bounds.yMinimum(), 3)
- self.assertEqual(vl.metadata().extent().spatialExtents()[0].bounds.yMaximum(), 4)
+ datasource = os.path.join(unitTestDataPath(), "gdb_metadata.gdb")
+ vl = QgsVectorLayer(datasource, "test", "ogr")
+ self.assertTrue(vl.isValid())
+ self.assertEqual(vl.metadata().identifier(), "Test")
+ self.assertEqual(vl.metadata().title(), "Title")
+ self.assertEqual(vl.metadata().type(), "dataset")
+ self.assertEqual(vl.metadata().language(), "ENG")
+ self.assertIn("This is the abstract", vl.metadata().abstract())
+ self.assertEqual(vl.metadata().keywords(), {"Search keys": ["Tags"]})
+ self.assertEqual(vl.metadata().rights(), ["This is the credits"])
+ self.assertEqual(vl.metadata().constraints()[0].type, "Limitations of use")
+ self.assertEqual(
+ vl.metadata().constraints()[0].constraint, "This is the use limitation"
+ )
+ self.assertEqual(
+ vl.metadata().extent().spatialExtents()[0].bounds.xMinimum(), 1
+ )
+ self.assertEqual(
+ vl.metadata().extent().spatialExtents()[0].bounds.xMaximum(), 2
+ )
+ self.assertEqual(
+ vl.metadata().extent().spatialExtents()[0].bounds.yMinimum(), 3
+ )
+ self.assertEqual(
+ vl.metadata().extent().spatialExtents()[0].bounds.yMaximum(), 4
+ )
def testShpLayerMetadata(self):
"""
Test that we translate .shp.xml metadata to QGIS layer metadata on loading a shp file (if present)
"""
- datasource = os.path.join(unitTestDataPath(), 'france_parts.shp')
- vl = QgsVectorLayer(datasource, 'test', 'ogr')
+ datasource = os.path.join(unitTestDataPath(), "france_parts.shp")
+ vl = QgsVectorLayer(datasource, "test", "ogr")
self.assertTrue(vl.isValid())
- self.assertEqual(vl.metadata().identifier(), 'QLD_STRUCTURAL_FRAMEWORK_OUTLINE')
- self.assertEqual(vl.metadata().title(), 'QLD_STRUCTURAL_FRAMEWORK_OUTLINE')
- self.assertEqual(vl.metadata().type(), 'dataset')
- self.assertEqual(vl.metadata().language(), 'EN')
+ self.assertEqual(vl.metadata().identifier(), "QLD_STRUCTURAL_FRAMEWORK_OUTLINE")
+ self.assertEqual(vl.metadata().title(), "QLD_STRUCTURAL_FRAMEWORK_OUTLINE")
+ self.assertEqual(vl.metadata().type(), "dataset")
+ self.assertEqual(vl.metadata().language(), "EN")
def testOpenOptions(self):
@@ -1330,17 +1728,19 @@ def testOpenOptions(self):
ds.ExecuteSQL("INSERT INTO foo VALUES(1, 'bar');")
ds = None
- vl = QgsVectorLayer(filename + "|option:LIST_ALL_TABLES=NO", 'test', 'ogr')
+ vl = QgsVectorLayer(filename + "|option:LIST_ALL_TABLES=NO", "test", "ogr")
self.assertTrue(vl.isValid())
self.assertEqual(len(vl.dataProvider().subLayers()), 1)
del vl
- vl = QgsVectorLayer(filename + "|option:LIST_ALL_TABLES=YES", 'test', 'ogr')
+ vl = QgsVectorLayer(filename + "|option:LIST_ALL_TABLES=YES", "test", "ogr")
self.assertTrue(vl.isValid())
self.assertEqual(len(vl.dataProvider().subLayers()), 2)
del vl
- vl = QgsVectorLayer(filename + "|layername=foo|option:LIST_ALL_TABLES=YES", 'test', 'ogr')
+ vl = QgsVectorLayer(
+ filename + "|layername=foo|option:LIST_ALL_TABLES=YES", "test", "ogr"
+ )
self.assertTrue(vl.isValid())
self.assertEqual(len([f for f in vl.getFeatures()]), 1)
del vl
@@ -1353,35 +1753,41 @@ def testTransactionGroupExpressionFields(self):
project = QgsProject()
project.setTransactionMode(Qgis.TransactionMode.AutomaticGroups)
tmpfile = os.path.join(
- self.basetestpath, 'tempGeoPackageTransactionExpressionFields.gpkg')
- ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile)
- lyr = ds.CreateLayer('test', geom_type=ogr.wkbPoint)
- lyr.CreateField(ogr.FieldDefn('str_field', ogr.OFTString))
+ self.basetestpath, "tempGeoPackageTransactionExpressionFields.gpkg"
+ )
+ ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile)
+ lyr = ds.CreateLayer("test", geom_type=ogr.wkbPoint)
+ lyr.CreateField(ogr.FieldDefn("str_field", ogr.OFTString))
f = ogr.Feature(lyr.GetLayerDefn())
- f.SetGeometry(ogr.CreateGeometryFromWkt('POINT (1 1)'))
- f.SetField('str_field', 'one')
+ f.SetGeometry(ogr.CreateGeometryFromWkt("POINT (1 1)"))
+ f.SetField("str_field", "one")
lyr.CreateFeature(f)
del lyr
del ds
- vl = QgsVectorLayer(tmpfile + '|layername=test', 'test', 'ogr')
- f = QgsField('expression_field', QVariant.Int)
- idx = vl.addExpressionField('123', f)
- self.assertEqual(vl.fields().fieldOrigin(idx), QgsFields.FieldOrigin.OriginExpression)
+ vl = QgsVectorLayer(tmpfile + "|layername=test", "test", "ogr")
+ f = QgsField("expression_field", QVariant.Int)
+ idx = vl.addExpressionField("123", f)
+ self.assertEqual(
+ vl.fields().fieldOrigin(idx), QgsFields.FieldOrigin.OriginExpression
+ )
project.addMapLayers([vl])
feature = next(vl.getFeatures())
- feature.setAttributes([None, 'two', 123])
+ feature.setAttributes([None, "two", 123])
self.assertTrue(vl.startEditing())
self.assertTrue(vl.addFeature(feature))
self.assertFalse(vl.dataProvider().hasErrors())
- @unittest.skipIf(int(gdal.VersionInfo('VERSION_NUM')) < GDAL_COMPUTE_VERSION(3, 2, 0), "GDAL 3.2 required")
- @unittest.skipIf(ogr.GetDriverByName('OAPIF') is None, "OAPIF driver not available")
+ @unittest.skipIf(
+ int(gdal.VersionInfo("VERSION_NUM")) < GDAL_COMPUTE_VERSION(3, 2, 0),
+ "GDAL 3.2 required",
+ )
+ @unittest.skipIf(ogr.GetDriverByName("OAPIF") is None, "OAPIF driver not available")
def testHTTPRequestsOverrider(self):
"""
Test that GDAL curl network requests are redirected through QGIS networking
@@ -1391,108 +1797,183 @@ def testHTTPRequestsOverrider(self):
# Check failed network requests
# Check that the driver requested Accept header is well propagated
- handler.add('GET', '/collections/foo', 404, expected_headers={'Accept': 'application/json'})
+ handler.add(
+ "GET",
+ "/collections/foo",
+ 404,
+ expected_headers={"Accept": "application/json"},
+ )
with mockedwebserver.install_http_handler(handler):
- QgsVectorLayer("OAPIF:http://127.0.0.1:%d/collections/foo" % port, 'test', 'ogr')
+ QgsVectorLayer(
+ "OAPIF:http://127.0.0.1:%d/collections/foo" % port, "test", "ogr"
+ )
# Error coming from Qt network stack, not GDAL/CURL one
- self.assertIn('server replied: Not Found', gdal.GetLastErrorMsg())
+ self.assertIn("server replied: Not Found", gdal.GetLastErrorMsg())
# Test a nominal case
handler = mockedwebserver.SequentialHandler()
# Asked when ogr provider try to open. See QgsOgrProvider::QgsOgrProvider#453 open( OpenModeForceReadOnly );
- handler.add('GET', '/collections/foo', 200, {'Content-Type': 'application/json'}, '{ "id": "foo" }')
+ handler.add(
+ "GET",
+ "/collections/foo",
+ 200,
+ {"Content-Type": "application/json"},
+ '{ "id": "foo" }',
+ )
# 3.8.3 not necessarily the minimum version
- if int(gdal.VersionInfo('VERSION_NUM')) >= GDAL_COMPUTE_VERSION(3, 8, 3):
- handler.add('GET', '/', 200, {'Content-Type': 'application/json'}, '{ "id": "foo" }')
- handler.add('GET', '/api', 200, {'Content-Type': 'application/json'}, '{ "id": "foo" }')
-
- handler.add('GET', '/collections/foo/items?limit=20', 200, {'Content-Type': 'application/geo+json'},
- '{ "type": "FeatureCollection", "features": [] }')
- handler.add('GET', '/collections/foo/items?limit=1000', 200, {'Content-Type': 'application/geo+json'},
- '{ "type": "FeatureCollection", "features": [] }')
+ if int(gdal.VersionInfo("VERSION_NUM")) >= GDAL_COMPUTE_VERSION(3, 8, 3):
+ handler.add(
+ "GET",
+ "/",
+ 200,
+ {"Content-Type": "application/json"},
+ '{ "id": "foo" }',
+ )
+ handler.add(
+ "GET",
+ "/api",
+ 200,
+ {"Content-Type": "application/json"},
+ '{ "id": "foo" }',
+ )
+
+ handler.add(
+ "GET",
+ "/collections/foo/items?limit=20",
+ 200,
+ {"Content-Type": "application/geo+json"},
+ '{ "type": "FeatureCollection", "features": [] }',
+ )
+ handler.add(
+ "GET",
+ "/collections/foo/items?limit=1000",
+ 200,
+ {"Content-Type": "application/geo+json"},
+ '{ "type": "FeatureCollection", "features": [] }',
+ )
else:
# See QgsOgrProvider::open#4012 mOgrOrigLayer = QgsOgrProviderUtils::getLayer( mFilePath, false, options, mLayerName, errCause, true );
- handler.add('GET', '/collections/foo/items?limit=10', 200, {'Content-Type': 'application/geo+json'},
- '{ "type": "FeatureCollection", "features": [] }')
+ handler.add(
+ "GET",
+ "/collections/foo/items?limit=10",
+ 200,
+ {"Content-Type": "application/geo+json"},
+ '{ "type": "FeatureCollection", "features": [] }',
+ )
# See QgsOgrProvider::open#4066 computeCapabilities();
- handler.add('GET', '/collections/foo/items?limit=10', 200, {'Content-Type': 'application/geo+json'},
- '{ "type": "FeatureCollection", "features": [] }')
-
- if int(gdal.VersionInfo('VERSION_NUM')) < GDAL_COMPUTE_VERSION(3, 3, 0):
- handler.add('GET', '/collections/foo/items?limit=10', 200, {'Content-Type': 'application/geo+json'},
- '{ "type": "FeatureCollection", "features": [] }')
+ handler.add(
+ "GET",
+ "/collections/foo/items?limit=10",
+ 200,
+ {"Content-Type": "application/geo+json"},
+ '{ "type": "FeatureCollection", "features": [] }',
+ )
+
+ if int(gdal.VersionInfo("VERSION_NUM")) < GDAL_COMPUTE_VERSION(3, 3, 0):
+ handler.add(
+ "GET",
+ "/collections/foo/items?limit=10",
+ 200,
+ {"Content-Type": "application/geo+json"},
+ '{ "type": "FeatureCollection", "features": [] }',
+ )
with mockedwebserver.install_http_handler(handler):
- vl = QgsVectorLayer("OAPIF:http://127.0.0.1:%d/collections/foo" % port, 'test', 'ogr')
+ vl = QgsVectorLayer(
+ "OAPIF:http://127.0.0.1:%d/collections/foo" % port, "test", "ogr"
+ )
self.assertTrue(vl.isValid())
# More complicated test using an anthentication configuration
authm = QgsApplication.authManager()
- self.assertTrue(authm.setMasterPassword('masterpassword', True))
+ self.assertTrue(authm.setMasterPassword("masterpassword", True))
config = QgsAuthMethodConfig()
- config.setName('Basic')
- config.setMethod('Basic')
- config.setConfig('username', 'username')
- config.setConfig('password', 'password')
+ config.setName("Basic")
+ config.setMethod("Basic")
+ config.setConfig("username", "username")
+ config.setConfig("password", "password")
self.assertTrue(authm.storeAuthenticationConfig(config, True))
handler = mockedwebserver.SequentialHandler()
# Check that the authcfg gets expanded during the network request !
- handler.add('GET', '/collections/foo', 404, expected_headers={
- 'Authorization': 'Basic dXNlcm5hbWU6cGFzc3dvcmQ='})
+ handler.add(
+ "GET",
+ "/collections/foo",
+ 404,
+ expected_headers={"Authorization": "Basic dXNlcm5hbWU6cGFzc3dvcmQ="},
+ )
with mockedwebserver.install_http_handler(handler):
- QgsVectorLayer("OAPIF:http://127.0.0.1:%d/collections/foo authcfg='%s'" % (port, config.id()), 'test',
- 'ogr')
+ QgsVectorLayer(
+ "OAPIF:http://127.0.0.1:%d/collections/foo authcfg='%s'"
+ % (port, config.id()),
+ "test",
+ "ogr",
+ )
def testShapefilesWithNoAttributes(self):
"""Test issue GH #38834"""
- ml = QgsVectorLayer('Point?crs=epsg:4326', 'test', 'memory')
+ ml = QgsVectorLayer("Point?crs=epsg:4326", "test", "memory")
self.assertTrue(ml.isValid())
d = QTemporaryDir()
options = QgsVectorFileWriter.SaveVectorOptions()
- options.driverName = 'ESRI Shapefile'
- options.layerName = 'writetest'
- err, _ = QgsVectorFileWriter.writeAsVectorFormatV2(ml, os.path.join(d.path(), 'writetest.shp'),
- QgsCoordinateTransformContext(), options)
+ options.driverName = "ESRI Shapefile"
+ options.layerName = "writetest"
+ err, _ = QgsVectorFileWriter.writeAsVectorFormatV2(
+ ml,
+ os.path.join(d.path(), "writetest.shp"),
+ QgsCoordinateTransformContext(),
+ options,
+ )
self.assertEqual(err, QgsVectorFileWriter.WriterError.NoError)
- self.assertTrue(os.path.isfile(os.path.join(d.path(), 'writetest.shp')))
+ self.assertTrue(os.path.isfile(os.path.join(d.path(), "writetest.shp")))
- vl = QgsVectorLayer(os.path.join(d.path(), 'writetest.shp'))
- self.assertTrue(bool(vl.dataProvider().capabilities() & QgsVectorDataProvider.Capability.AddFeatures))
+ vl = QgsVectorLayer(os.path.join(d.path(), "writetest.shp"))
+ self.assertTrue(
+ bool(
+ vl.dataProvider().capabilities()
+ & QgsVectorDataProvider.Capability.AddFeatures
+ )
+ )
# Let's try if we can really add features
feature = QgsFeature(vl.fields())
- geom = QgsGeometry.fromWkt('POINT(9 45)')
+ geom = QgsGeometry.fromWkt("POINT(9 45)")
feature.setGeometry(geom)
self.assertTrue(vl.startEditing())
self.assertTrue(vl.addFeatures([feature]))
self.assertTrue(vl.commitChanges())
- del (vl)
+ del vl
- vl = QgsVectorLayer(os.path.join(d.path(), 'writetest.shp'))
+ vl = QgsVectorLayer(os.path.join(d.path(), "writetest.shp"))
self.assertEqual(vl.featureCount(), 1)
def testFidDoubleSaveAsGeopackage(self):
"""Test issue GH #25795"""
- ml = QgsVectorLayer('Point?crs=epsg:4326&field=fid:double(20,0)', 'test', 'memory')
+ ml = QgsVectorLayer(
+ "Point?crs=epsg:4326&field=fid:double(20,0)", "test", "memory"
+ )
self.assertTrue(ml.isValid())
self.assertEqual(ml.fields()[0].type(), QVariant.Double)
d = QTemporaryDir()
options = QgsVectorFileWriter.SaveVectorOptions()
- options.driverName = 'GPKG'
- options.layerName = 'fid_double_test'
- err, _ = QgsVectorFileWriter.writeAsVectorFormatV2(ml, os.path.join(d.path(), 'fid_double_test.gpkg'),
- QgsCoordinateTransformContext(), options)
+ options.driverName = "GPKG"
+ options.layerName = "fid_double_test"
+ err, _ = QgsVectorFileWriter.writeAsVectorFormatV2(
+ ml,
+ os.path.join(d.path(), "fid_double_test.gpkg"),
+ QgsCoordinateTransformContext(),
+ options,
+ )
self.assertEqual(err, QgsVectorFileWriter.WriterError.NoError)
- self.assertTrue(os.path.isfile(os.path.join(d.path(), 'fid_double_test.gpkg')))
+ self.assertTrue(os.path.isfile(os.path.join(d.path(), "fid_double_test.gpkg")))
- vl = QgsVectorLayer(os.path.join(d.path(), 'fid_double_test.gpkg'))
+ vl = QgsVectorLayer(os.path.join(d.path(), "fid_double_test.gpkg"))
self.assertEqual(vl.fields()[0].type(), QVariant.LongLong)
def testNonGeopackageSaveMetadata(self):
@@ -1500,58 +1981,66 @@ def testNonGeopackageSaveMetadata(self):
Save layer metadata for a file-based format which doesn't have native metadata support.
In this case we should resort to a sidecar file instead.
"""
- ml = QgsVectorLayer('Point?crs=epsg:4326&field=pk:integer&field=cnt:int8', 'test', 'memory')
+ ml = QgsVectorLayer(
+ "Point?crs=epsg:4326&field=pk:integer&field=cnt:int8", "test", "memory"
+ )
self.assertTrue(ml.isValid())
d = QTemporaryDir()
options = QgsVectorFileWriter.SaveVectorOptions()
- options.driverName = 'ESRI Shapefile'
- options.layerName = 'metadatatest'
- err, _ = QgsVectorFileWriter.writeAsVectorFormatV2(ml, os.path.join(d.path(), 'metadatatest.shp'),
- QgsCoordinateTransformContext(), options)
+ options.driverName = "ESRI Shapefile"
+ options.layerName = "metadatatest"
+ err, _ = QgsVectorFileWriter.writeAsVectorFormatV2(
+ ml,
+ os.path.join(d.path(), "metadatatest.shp"),
+ QgsCoordinateTransformContext(),
+ options,
+ )
self.assertEqual(err, QgsVectorFileWriter.WriterError.NoError)
- self.assertTrue(os.path.isfile(os.path.join(d.path(), 'metadatatest.shp')))
+ self.assertTrue(os.path.isfile(os.path.join(d.path(), "metadatatest.shp")))
- uri = d.path() + '/metadatatest.shp'
+ uri = d.path() + "/metadatatest.shp"
# now save some metadata
metadata = QgsLayerMetadata()
- metadata.setAbstract('my abstract')
- metadata.setIdentifier('my identifier')
- metadata.setLicenses(['l1', 'l2'])
- ok, err = QgsProviderRegistry.instance().saveLayerMetadata('ogr', uri, metadata)
+ metadata.setAbstract("my abstract")
+ metadata.setIdentifier("my identifier")
+ metadata.setLicenses(["l1", "l2"])
+ ok, err = QgsProviderRegistry.instance().saveLayerMetadata("ogr", uri, metadata)
self.assertTrue(ok)
- self.assertTrue(os.path.exists(os.path.join(d.path(), 'metadatatest.qmd')))
- with open(os.path.join(d.path(), 'metadatatest.qmd')) as f:
- metadata_xml = ''.join(f.readlines())
+ self.assertTrue(os.path.exists(os.path.join(d.path(), "metadatatest.qmd")))
+ with open(os.path.join(d.path(), "metadatatest.qmd")) as f:
+ metadata_xml = "".join(f.readlines())
metadata2 = QgsLayerMetadata()
doc = QDomDocument()
doc.setContent(metadata_xml)
self.assertTrue(metadata2.readMetadataXml(doc.documentElement()))
- self.assertEqual(metadata2.abstract(), 'my abstract')
- self.assertEqual(metadata2.identifier(), 'my identifier')
- self.assertEqual(metadata2.licenses(), ['l1', 'l2'])
+ self.assertEqual(metadata2.abstract(), "my abstract")
+ self.assertEqual(metadata2.identifier(), "my identifier")
+ self.assertEqual(metadata2.licenses(), ["l1", "l2"])
# try updating existing metadata -- file should be overwritten
- metadata2.setAbstract('my abstract 2')
- metadata2.setIdentifier('my identifier 2')
- metadata2.setHistory(['h1', 'h2'])
- ok, err = QgsProviderRegistry.instance().saveLayerMetadata('ogr', uri, metadata2)
+ metadata2.setAbstract("my abstract 2")
+ metadata2.setIdentifier("my identifier 2")
+ metadata2.setHistory(["h1", "h2"])
+ ok, err = QgsProviderRegistry.instance().saveLayerMetadata(
+ "ogr", uri, metadata2
+ )
self.assertTrue(ok)
- with open(os.path.join(d.path(), 'metadatatest.qmd')) as f:
- metadata_xml = ''.join(f.readlines())
+ with open(os.path.join(d.path(), "metadatatest.qmd")) as f:
+ metadata_xml = "".join(f.readlines())
metadata3 = QgsLayerMetadata()
doc = QDomDocument()
doc.setContent(metadata_xml)
self.assertTrue(metadata3.readMetadataXml(doc.documentElement()))
- self.assertEqual(metadata3.abstract(), 'my abstract 2')
- self.assertEqual(metadata3.identifier(), 'my identifier 2')
- self.assertEqual(metadata3.licenses(), ['l1', 'l2'])
- self.assertEqual(metadata3.history(), ['h1', 'h2'])
+ self.assertEqual(metadata3.abstract(), "my abstract 2")
+ self.assertEqual(metadata3.identifier(), "my identifier 2")
+ self.assertEqual(metadata3.licenses(), ["l1", "l2"])
+ self.assertEqual(metadata3.history(), ["h1", "h2"])
def testSaveMetadataUnsupported(self):
"""
@@ -1560,70 +2049,110 @@ def testSaveMetadataUnsupported(self):
metadata = QgsLayerMetadata()
# this should raise a QgsNotSupportedException, as we don't support writing metadata to a WFS uri
with self.assertRaises(QgsNotSupportedException):
- QgsProviderRegistry.instance().saveLayerMetadata('ogr', 'WFS:http://www2.dmsolutions.ca/cgi-bin/mswfs_gmap', metadata)
+ QgsProviderRegistry.instance().saveLayerMetadata(
+ "ogr", "WFS:http://www2.dmsolutions.ca/cgi-bin/mswfs_gmap", metadata
+ )
def testSaveDefaultMetadataUnsupported(self):
"""
Test saving default metadata to an unsupported layer
"""
- layer = QgsVectorLayer('WFS:http://www2.dmsolutions.ca/cgi-bin/mswfs_gmap', 'test')
+ layer = QgsVectorLayer(
+ "WFS:http://www2.dmsolutions.ca/cgi-bin/mswfs_gmap", "test"
+ )
# now save some metadata
metadata = QgsLayerMetadata()
- metadata.setAbstract('my abstract')
- metadata.setIdentifier('my identifier')
- metadata.setLicenses(['l1', 'l2'])
+ metadata.setAbstract("my abstract")
+ metadata.setIdentifier("my identifier")
+ metadata.setLicenses(["l1", "l2"])
layer.setMetadata(metadata)
# save as default
msg, res = layer.saveDefaultMetadata()
self.assertFalse(res)
- self.assertEqual(msg, 'Storing metadata for the specified uri is not supported')
+ self.assertEqual(msg, "Storing metadata for the specified uri is not supported")
def testEmbeddedSymbolsKml(self):
"""
Test retrieving embedded symbols from a KML file
"""
- layer = QgsVectorLayer(os.path.join(TEST_DATA_DIR, 'embedded_symbols', 'samples.kml') + '|layername=Paths',
- 'Lines')
+ layer = QgsVectorLayer(
+ os.path.join(TEST_DATA_DIR, "embedded_symbols", "samples.kml")
+ + "|layername=Paths",
+ "Lines",
+ )
self.assertTrue(layer.isValid())
# symbols should not be fetched by default
self.assertFalse(any(f.embeddedSymbol() for f in layer.getFeatures()))
- symbols = [f.embeddedSymbol().clone() if f.embeddedSymbol() else None for f in
- layer.getFeatures(QgsFeatureRequest().setFlags(QgsFeatureRequest.Flag.EmbeddedSymbols))]
- self.assertCountEqual([s.color().name() for s in symbols if s is not None],
- ['#ff00ff', '#ffff00', '#000000', '#ff0000'])
- self.assertCountEqual([s.color().alpha() for s in symbols if s is not None], [127, 135, 255, 127])
+ symbols = [
+ f.embeddedSymbol().clone() if f.embeddedSymbol() else None
+ for f in layer.getFeatures(
+ QgsFeatureRequest().setFlags(QgsFeatureRequest.Flag.EmbeddedSymbols)
+ )
+ ]
+ self.assertCountEqual(
+ [s.color().name() for s in symbols if s is not None],
+ ["#ff00ff", "#ffff00", "#000000", "#ff0000"],
+ )
+ self.assertCountEqual(
+ [s.color().alpha() for s in symbols if s is not None], [127, 135, 255, 127]
+ )
self.assertEqual(len([s for s in symbols if s is None]), 2)
def testDecodeEncodeUriVsizip(self):
"""Test decodeUri/encodeUri for /vsizip/ prefixed URIs"""
- uri = '/vsizip//my/file.zip/shapefile.shp'
- parts = QgsProviderRegistry.instance().decodeUri('ogr', uri)
- self.assertEqual(parts, {'path': '/my/file.zip', 'layerName': None, 'layerId': None, 'vsiPrefix': '/vsizip/',
- 'vsiSuffix': '/shapefile.shp'})
- encodedUri = QgsProviderRegistry.instance().encodeUri('ogr', parts)
+ uri = "/vsizip//my/file.zip/shapefile.shp"
+ parts = QgsProviderRegistry.instance().decodeUri("ogr", uri)
+ self.assertEqual(
+ parts,
+ {
+ "path": "/my/file.zip",
+ "layerName": None,
+ "layerId": None,
+ "vsiPrefix": "/vsizip/",
+ "vsiSuffix": "/shapefile.shp",
+ },
+ )
+ encodedUri = QgsProviderRegistry.instance().encodeUri("ogr", parts)
self.assertEqual(encodedUri, uri)
- uri = '/my/file.zip'
- parts = QgsProviderRegistry.instance().decodeUri('ogr', uri)
- self.assertEqual(parts, {'path': '/my/file.zip', 'layerName': None, 'layerId': None})
- encodedUri = QgsProviderRegistry.instance().encodeUri('ogr', parts)
+ uri = "/my/file.zip"
+ parts = QgsProviderRegistry.instance().decodeUri("ogr", uri)
+ self.assertEqual(
+ parts, {"path": "/my/file.zip", "layerName": None, "layerId": None}
+ )
+ encodedUri = QgsProviderRegistry.instance().encodeUri("ogr", parts)
self.assertEqual(encodedUri, uri)
- uri = '/vsizip//my/file.zip|layername=shapefile'
- parts = QgsProviderRegistry.instance().decodeUri('ogr', uri)
- self.assertEqual(parts,
- {'path': '/my/file.zip', 'layerName': 'shapefile', 'layerId': None, 'vsiPrefix': '/vsizip/'})
- encodedUri = QgsProviderRegistry.instance().encodeUri('ogr', parts)
+ uri = "/vsizip//my/file.zip|layername=shapefile"
+ parts = QgsProviderRegistry.instance().decodeUri("ogr", uri)
+ self.assertEqual(
+ parts,
+ {
+ "path": "/my/file.zip",
+ "layerName": "shapefile",
+ "layerId": None,
+ "vsiPrefix": "/vsizip/",
+ },
+ )
+ encodedUri = QgsProviderRegistry.instance().encodeUri("ogr", parts)
self.assertEqual(encodedUri, uri)
- uri = '/vsizip//my/file.zip|layername=shapefile|subset="field"=\'value\''
- parts = QgsProviderRegistry.instance().decodeUri('ogr', uri)
- self.assertEqual(parts, {'path': '/my/file.zip', 'layerName': 'shapefile', 'layerId': None,
- 'subset': '"field"=\'value\'', 'vsiPrefix': '/vsizip/'})
- encodedUri = QgsProviderRegistry.instance().encodeUri('ogr', parts)
+ uri = "/vsizip//my/file.zip|layername=shapefile|subset=\"field\"='value'"
+ parts = QgsProviderRegistry.instance().decodeUri("ogr", uri)
+ self.assertEqual(
+ parts,
+ {
+ "path": "/my/file.zip",
+ "layerName": "shapefile",
+ "layerId": None,
+ "subset": "\"field\"='value'",
+ "vsiPrefix": "/vsizip/",
+ },
+ )
+ encodedUri = QgsProviderRegistry.instance().encodeUri("ogr", parts)
self.assertEqual(encodedUri, uri)
@unittest.skipIf(gdal.GetDriverByName("GTFS") is None, "GTFS driver required")
@@ -1631,84 +2160,99 @@ def testDecodeGTFS(self):
"""Test querySublayers() for GTFS .zip dataset"""
uri = os.path.join(TEST_DATA_DIR, "ogr", "gtfs_extract.zip")
- metadata = QgsProviderRegistry.instance().providerMetadata('ogr')
+ metadata = QgsProviderRegistry.instance().providerMetadata("ogr")
res = metadata.querySublayers(uri)
self.assertEqual(len(res), 9)
def testDecodeEncodeUriCredentialOptions(self):
"""Test decodeUri/encodeUri credential options support"""
- uri = '/my/vector.shp|option:AN=OPTION|credential:ANOTHER=BBB|credential:SOMEKEY=AAAAA'
- parts = QgsProviderRegistry.instance().decodeUri('ogr', uri)
- self.assertEqual(parts, {
- 'path': '/my/vector.shp',
- 'layerId': None,
- 'layerName': None,
- 'credentialOptions': {
- 'ANOTHER': 'BBB',
- 'SOMEKEY': 'AAAAA'
+ uri = "/my/vector.shp|option:AN=OPTION|credential:ANOTHER=BBB|credential:SOMEKEY=AAAAA"
+ parts = QgsProviderRegistry.instance().decodeUri("ogr", uri)
+ self.assertEqual(
+ parts,
+ {
+ "path": "/my/vector.shp",
+ "layerId": None,
+ "layerName": None,
+ "credentialOptions": {"ANOTHER": "BBB", "SOMEKEY": "AAAAA"},
+ "openOptions": ["AN=OPTION"],
},
- 'openOptions': ['AN=OPTION']
- })
- encodedUri = QgsProviderRegistry.instance().encodeUri('ogr', parts)
+ )
+ encodedUri = QgsProviderRegistry.instance().encodeUri("ogr", parts)
self.assertEqual(encodedUri, uri)
- @unittest.skipIf(int(gdal.VersionInfo('VERSION_NUM')) < GDAL_COMPUTE_VERSION(3, 3, 0), "GDAL 3.3 required")
+ @unittest.skipIf(
+ int(gdal.VersionInfo("VERSION_NUM")) < GDAL_COMPUTE_VERSION(3, 3, 0),
+ "GDAL 3.3 required",
+ )
def testFieldDomains(self):
"""
Test that field domains are translated from OGR where available (requires GDAL 3.3 or later)
"""
- datasource = os.path.join(self.temp_dir_path, 'domains.gpkg')
- vl = QgsVectorLayer(datasource, 'test', 'ogr')
+ datasource = os.path.join(self.temp_dir_path, "domains.gpkg")
+ vl = QgsVectorLayer(datasource, "test", "ogr")
self.assertTrue(vl.isValid())
fields = vl.fields()
- range_int_field = fields[fields.lookupField('with_range_domain_int')]
+ range_int_field = fields[fields.lookupField("with_range_domain_int")]
range_int_setup = range_int_field.editorWidgetSetup()
- self.assertEqual(range_int_setup.type(), 'Range')
- self.assertTrue(range_int_setup.config()['AllowNull'])
- self.assertEqual(range_int_setup.config()['Max'], 2)
- self.assertEqual(range_int_setup.config()['Min'], 1)
- self.assertEqual(range_int_setup.config()['Precision'], 0)
- self.assertEqual(range_int_setup.config()['Step'], 1)
- self.assertEqual(range_int_setup.config()['Style'], 'SpinBox')
+ self.assertEqual(range_int_setup.type(), "Range")
+ self.assertTrue(range_int_setup.config()["AllowNull"])
+ self.assertEqual(range_int_setup.config()["Max"], 2)
+ self.assertEqual(range_int_setup.config()["Min"], 1)
+ self.assertEqual(range_int_setup.config()["Precision"], 0)
+ self.assertEqual(range_int_setup.config()["Step"], 1)
+ self.assertEqual(range_int_setup.config()["Style"], "SpinBox")
# make sure editor widget config from provider has been copied to layer!
- self.assertEqual(vl.editorWidgetSetup(fields.lookupField('with_range_domain_int')).type(), 'Range')
+ self.assertEqual(
+ vl.editorWidgetSetup(fields.lookupField("with_range_domain_int")).type(),
+ "Range",
+ )
- range_int64_field = fields[fields.lookupField('with_range_domain_int64')]
+ range_int64_field = fields[fields.lookupField("with_range_domain_int64")]
range_int64_setup = range_int64_field.editorWidgetSetup()
- self.assertEqual(range_int64_setup.type(), 'Range')
- self.assertTrue(range_int64_setup.config()['AllowNull'])
- self.assertEqual(range_int64_setup.config()['Max'], 1234567890123)
- self.assertEqual(range_int64_setup.config()['Min'], -1234567890123)
- self.assertEqual(range_int64_setup.config()['Precision'], 0)
- self.assertEqual(range_int64_setup.config()['Step'], 1)
- self.assertEqual(range_int64_setup.config()['Style'], 'SpinBox')
- self.assertEqual(vl.editorWidgetSetup(fields.lookupField('with_range_domain_int64')).type(), 'Range')
-
- range_real_field = fields[fields.lookupField('with_range_domain_real')]
+ self.assertEqual(range_int64_setup.type(), "Range")
+ self.assertTrue(range_int64_setup.config()["AllowNull"])
+ self.assertEqual(range_int64_setup.config()["Max"], 1234567890123)
+ self.assertEqual(range_int64_setup.config()["Min"], -1234567890123)
+ self.assertEqual(range_int64_setup.config()["Precision"], 0)
+ self.assertEqual(range_int64_setup.config()["Step"], 1)
+ self.assertEqual(range_int64_setup.config()["Style"], "SpinBox")
+ self.assertEqual(
+ vl.editorWidgetSetup(fields.lookupField("with_range_domain_int64")).type(),
+ "Range",
+ )
+
+ range_real_field = fields[fields.lookupField("with_range_domain_real")]
range_real_setup = range_real_field.editorWidgetSetup()
- self.assertEqual(range_real_setup.type(), 'Range')
- self.assertTrue(range_real_setup.config()['AllowNull'])
- self.assertEqual(range_real_setup.config()['Max'], 2.5)
- self.assertEqual(range_real_setup.config()['Min'], 1.5)
- self.assertEqual(range_real_setup.config()['Precision'], 0)
- self.assertEqual(range_real_setup.config()['Step'], 1)
- self.assertEqual(range_real_setup.config()['Style'], 'SpinBox')
- self.assertEqual(vl.editorWidgetSetup(fields.lookupField('with_range_domain_real')).type(), 'Range')
-
- enum_field = fields[fields.lookupField('with_enum_domain')]
+ self.assertEqual(range_real_setup.type(), "Range")
+ self.assertTrue(range_real_setup.config()["AllowNull"])
+ self.assertEqual(range_real_setup.config()["Max"], 2.5)
+ self.assertEqual(range_real_setup.config()["Min"], 1.5)
+ self.assertEqual(range_real_setup.config()["Precision"], 0)
+ self.assertEqual(range_real_setup.config()["Step"], 1)
+ self.assertEqual(range_real_setup.config()["Style"], "SpinBox")
+ self.assertEqual(
+ vl.editorWidgetSetup(fields.lookupField("with_range_domain_real")).type(),
+ "Range",
+ )
+
+ enum_field = fields[fields.lookupField("with_enum_domain")]
enum_setup = enum_field.editorWidgetSetup()
- self.assertEqual(enum_setup.type(), 'ValueMap')
- self.assertTrue(enum_setup.config()['map'], [{'one': '1'}, {'2': '2'}])
- self.assertEqual(vl.editorWidgetSetup(fields.lookupField('with_enum_domain')).type(), 'ValueMap')
+ self.assertEqual(enum_setup.type(), "ValueMap")
+ self.assertTrue(enum_setup.config()["map"], [{"one": "1"}, {"2": "2"}])
+ self.assertEqual(
+ vl.editorWidgetSetup(fields.lookupField("with_enum_domain")).type(),
+ "ValueMap",
+ )
def test_provider_editorWidgets(self):
if len(QgsGui.editorWidgetRegistry().factories()) == 0:
QgsGui.editorWidgetRegistry().initEditors()
- editor_widget_type = 'Color'
+ editor_widget_type = "Color"
factory = QgsGui.instance().editorWidgetRegistry().factory(editor_widget_type)
self.assertEqual(factory.name(), editor_widget_type)
@@ -1716,15 +2260,17 @@ def test_provider_editorWidgets(self):
uri = "point?crs=epsg:4326&field=id:integer"
layer = QgsVectorLayer(uri, "Scratch point layer", "memory")
- path = '/vsimem/test.gpkg'
- result, msg = QgsVectorLayerExporter.exportLayer(layer, path, 'ogr', layer.crs())
+ path = "/vsimem/test.gpkg"
+ result, msg = QgsVectorLayerExporter.exportLayer(
+ layer, path, "ogr", layer.crs()
+ )
self.assertEqual(result, Qgis.VectorExportResult.Success)
layer = QgsVectorLayer(path)
self.assertTrue(layer.isValid())
- self.assertEqual(layer.providerType(), 'ogr')
+ self.assertEqual(layer.providerType(), "ogr")
- field1 = QgsField(name='field1', type=QVariant.String)
- field2 = QgsField(name='field2', type=QVariant.String)
+ field1 = QgsField(name="field1", type=QVariant.String)
+ field2 = QgsField(name="field2", type=QVariant.String)
setup1 = QgsEditorWidgetSetup(editor_widget_type, {})
setup2 = QgsEditorWidgetSetup(editor_widget_type, {})
@@ -1746,224 +2292,299 @@ def test_provider_editorWidgets(self):
self.assertTrue(layer.commitChanges())
# editor widget should not change by commitChanges
- self.assertEqual(layer.editorWidgetSetup(i).type(),
- editor_widget_type,
- msg='QgsVectorLayer::commitChanged() changed QgsEditorWidgetSetup' +
- f'\nDriver: {layer.dataProvider().name()}')
+ self.assertEqual(
+ layer.editorWidgetSetup(i).type(),
+ editor_widget_type,
+ msg="QgsVectorLayer::commitChanged() changed QgsEditorWidgetSetup"
+ + f"\nDriver: {layer.dataProvider().name()}",
+ )
def test_provider_sublayer_details(self):
"""
Test retrieving sublayer details from data provider metadata
"""
- metadata = QgsProviderRegistry.instance().providerMetadata('ogr')
+ metadata = QgsProviderRegistry.instance().providerMetadata("ogr")
# invalid uri
- res = metadata.querySublayers('')
+ res = metadata.querySublayers("")
self.assertFalse(res)
# not a vector
- res = metadata.querySublayers(os.path.join(TEST_DATA_DIR, 'landsat.tif'))
+ res = metadata.querySublayers(os.path.join(TEST_DATA_DIR, "landsat.tif"))
self.assertFalse(res)
# single layer vector
- res = metadata.querySublayers(os.path.join(TEST_DATA_DIR, 'lines.shp'))
+ res = metadata.querySublayers(os.path.join(TEST_DATA_DIR, "lines.shp"))
self.assertEqual(len(res), 1)
self.assertEqual(res[0].layerNumber(), 0)
self.assertEqual(res[0].name(), "lines")
- self.assertEqual(res[0].description(), '')
+ self.assertEqual(res[0].description(), "")
self.assertEqual(res[0].uri(), TEST_DATA_DIR + "/lines.shp")
self.assertEqual(res[0].providerKey(), "ogr")
self.assertEqual(res[0].type(), QgsMapLayerType.VectorLayer)
self.assertEqual(res[0].wkbType(), QgsWkbTypes.Type.LineString)
- self.assertEqual(res[0].geometryColumnName(), '')
- self.assertEqual(res[0].driverName(), 'ESRI Shapefile')
+ self.assertEqual(res[0].geometryColumnName(), "")
+ self.assertEqual(res[0].driverName(), "ESRI Shapefile")
# zip file layer vector
- res = metadata.querySublayers(os.path.join(TEST_DATA_DIR, 'zip', 'points2.zip'))
+ res = metadata.querySublayers(os.path.join(TEST_DATA_DIR, "zip", "points2.zip"))
self.assertEqual(len(res), 1)
self.assertEqual(res[0].layerNumber(), 0)
self.assertEqual(res[0].name(), "points.shp")
- self.assertEqual(res[0].description(), '')
- self.assertEqual(res[0].uri(), '/vsizip/' + TEST_DATA_DIR + "/zip/points2.zip/points.shp|layername=points")
+ self.assertEqual(res[0].description(), "")
+ self.assertEqual(
+ res[0].uri(),
+ "/vsizip/" + TEST_DATA_DIR + "/zip/points2.zip/points.shp|layername=points",
+ )
self.assertEqual(res[0].providerKey(), "ogr")
self.assertEqual(res[0].type(), QgsMapLayerType.VectorLayer)
self.assertEqual(res[0].wkbType(), QgsWkbTypes.Type.Point)
- self.assertEqual(res[0].geometryColumnName(), '')
- self.assertEqual(res[0].driverName(), 'ESRI Shapefile')
- options = QgsProviderSublayerDetails.LayerOptions(QgsCoordinateTransformContext())
+ self.assertEqual(res[0].geometryColumnName(), "")
+ self.assertEqual(res[0].driverName(), "ESRI Shapefile")
+ options = QgsProviderSublayerDetails.LayerOptions(
+ QgsCoordinateTransformContext()
+ )
vl = res[0].toLayer(options)
self.assertTrue(vl.isValid())
self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.Point)
# zip file layer vector, explicit file in zip
- res = metadata.querySublayers('/vsizip/' + TEST_DATA_DIR + '/zip/points2.zip/points.shp')
+ res = metadata.querySublayers(
+ "/vsizip/" + TEST_DATA_DIR + "/zip/points2.zip/points.shp"
+ )
self.assertEqual(len(res), 1)
self.assertEqual(res[0].layerNumber(), 0)
self.assertEqual(res[0].name(), "points.shp")
- self.assertEqual(res[0].description(), '')
- self.assertEqual(res[0].uri(), '/vsizip/' + TEST_DATA_DIR + "/zip/points2.zip/points.shp|layername=points")
+ self.assertEqual(res[0].description(), "")
+ self.assertEqual(
+ res[0].uri(),
+ "/vsizip/" + TEST_DATA_DIR + "/zip/points2.zip/points.shp|layername=points",
+ )
self.assertEqual(res[0].providerKey(), "ogr")
self.assertEqual(res[0].type(), QgsMapLayerType.VectorLayer)
self.assertEqual(res[0].wkbType(), QgsWkbTypes.Type.Point)
- self.assertEqual(res[0].geometryColumnName(), '')
- self.assertEqual(res[0].driverName(), 'ESRI Shapefile')
- options = QgsProviderSublayerDetails.LayerOptions(QgsCoordinateTransformContext())
+ self.assertEqual(res[0].geometryColumnName(), "")
+ self.assertEqual(res[0].driverName(), "ESRI Shapefile")
+ options = QgsProviderSublayerDetails.LayerOptions(
+ QgsCoordinateTransformContext()
+ )
vl = res[0].toLayer(options)
self.assertTrue(vl.isValid())
self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.Point)
# zip file layer vector, explicit file in zip which is NOT a OGR supported source
- res = metadata.querySublayers('/vsizip/' + TEST_DATA_DIR + '/zip/points2.zip/points.qml')
+ res = metadata.querySublayers(
+ "/vsizip/" + TEST_DATA_DIR + "/zip/points2.zip/points.qml"
+ )
self.assertEqual(len(res), 0)
# multi-layer archive
- res = metadata.querySublayers(os.path.join(TEST_DATA_DIR, 'zip', 'testtar.tgz'))
+ res = metadata.querySublayers(os.path.join(TEST_DATA_DIR, "zip", "testtar.tgz"))
self.assertEqual(len(res), 2)
self.assertEqual(res[0].layerNumber(), 0)
self.assertEqual(res[0].name(), "folder/points.geojson")
- self.assertEqual(res[0].description(), '')
- self.assertEqual(res[0].uri(), '/vsitar/' + TEST_DATA_DIR + "/zip/testtar.tgz/folder/points.geojson|layername=points")
+ self.assertEqual(res[0].description(), "")
+ self.assertEqual(
+ res[0].uri(),
+ "/vsitar/"
+ + TEST_DATA_DIR
+ + "/zip/testtar.tgz/folder/points.geojson|layername=points",
+ )
self.assertEqual(res[0].providerKey(), "ogr")
self.assertEqual(res[0].type(), QgsMapLayerType.VectorLayer)
self.assertEqual(res[0].wkbType(), QgsWkbTypes.Type.Point)
- self.assertEqual(res[0].geometryColumnName(), '')
- self.assertEqual(res[0].driverName(), 'GeoJSON')
- options = QgsProviderSublayerDetails.LayerOptions(QgsCoordinateTransformContext())
+ self.assertEqual(res[0].geometryColumnName(), "")
+ self.assertEqual(res[0].driverName(), "GeoJSON")
+ options = QgsProviderSublayerDetails.LayerOptions(
+ QgsCoordinateTransformContext()
+ )
vl = res[0].toLayer(options)
self.assertTrue(vl.isValid())
self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.Point)
self.assertEqual(res[1].layerNumber(), 0)
self.assertEqual(res[1].name(), "points.shp")
- self.assertEqual(res[1].description(), '')
- self.assertEqual(res[1].uri(), '/vsitar/' + TEST_DATA_DIR + "/zip/testtar.tgz/points.shp|layername=points")
+ self.assertEqual(res[1].description(), "")
+ self.assertEqual(
+ res[1].uri(),
+ "/vsitar/" + TEST_DATA_DIR + "/zip/testtar.tgz/points.shp|layername=points",
+ )
self.assertEqual(res[1].providerKey(), "ogr")
self.assertEqual(res[1].type(), QgsMapLayerType.VectorLayer)
self.assertEqual(res[1].wkbType(), QgsWkbTypes.Type.Point)
- self.assertEqual(res[1].geometryColumnName(), '')
- self.assertEqual(res[1].driverName(), 'ESRI Shapefile')
- options = QgsProviderSublayerDetails.LayerOptions(QgsCoordinateTransformContext())
+ self.assertEqual(res[1].geometryColumnName(), "")
+ self.assertEqual(res[1].driverName(), "ESRI Shapefile")
+ options = QgsProviderSublayerDetails.LayerOptions(
+ QgsCoordinateTransformContext()
+ )
vl = res[1].toLayer(options)
self.assertTrue(vl.isValid())
self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.Point)
# multi-layer archive, but with specific suffix specified
- res = metadata.querySublayers('/vsitar/' + os.path.join(TEST_DATA_DIR, 'zip', 'testtar.tgz') + '/folder/points.geojson')
+ res = metadata.querySublayers(
+ "/vsitar/"
+ + os.path.join(TEST_DATA_DIR, "zip", "testtar.tgz")
+ + "/folder/points.geojson"
+ )
self.assertEqual(len(res), 1)
self.assertEqual(res[0].layerNumber(), 0)
self.assertEqual(res[0].name(), "folder/points.geojson")
- self.assertEqual(res[0].description(), '')
- self.assertEqual(res[0].uri(), '/vsitar/' + TEST_DATA_DIR + "/zip/testtar.tgz/folder/points.geojson|layername=points")
+ self.assertEqual(res[0].description(), "")
+ self.assertEqual(
+ res[0].uri(),
+ "/vsitar/"
+ + TEST_DATA_DIR
+ + "/zip/testtar.tgz/folder/points.geojson|layername=points",
+ )
self.assertEqual(res[0].providerKey(), "ogr")
self.assertEqual(res[0].type(), QgsMapLayerType.VectorLayer)
self.assertEqual(res[0].wkbType(), QgsWkbTypes.Type.Point)
- self.assertEqual(res[0].geometryColumnName(), '')
- self.assertEqual(res[0].driverName(), 'GeoJSON')
- options = QgsProviderSublayerDetails.LayerOptions(QgsCoordinateTransformContext())
+ self.assertEqual(res[0].geometryColumnName(), "")
+ self.assertEqual(res[0].driverName(), "GeoJSON")
+ options = QgsProviderSublayerDetails.LayerOptions(
+ QgsCoordinateTransformContext()
+ )
vl = res[0].toLayer(options)
self.assertTrue(vl.isValid())
self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.Point)
- self.assertEqual(vl.dataProvider().storageType(), 'GeoJSON')
+ self.assertEqual(vl.dataProvider().storageType(), "GeoJSON")
- res = metadata.querySublayers('/vsitar/' + os.path.join(TEST_DATA_DIR, 'zip', 'testtar.tgz') + '/points.shp')
+ res = metadata.querySublayers(
+ "/vsitar/"
+ + os.path.join(TEST_DATA_DIR, "zip", "testtar.tgz")
+ + "/points.shp"
+ )
self.assertEqual(len(res), 1)
self.assertEqual(res[0].layerNumber(), 0)
self.assertEqual(res[0].name(), "points.shp")
- self.assertEqual(res[0].description(), '')
- self.assertEqual(res[0].uri(), '/vsitar/' + TEST_DATA_DIR + "/zip/testtar.tgz/points.shp|layername=points")
+ self.assertEqual(res[0].description(), "")
+ self.assertEqual(
+ res[0].uri(),
+ "/vsitar/" + TEST_DATA_DIR + "/zip/testtar.tgz/points.shp|layername=points",
+ )
self.assertEqual(res[0].providerKey(), "ogr")
self.assertEqual(res[0].type(), QgsMapLayerType.VectorLayer)
self.assertEqual(res[0].wkbType(), QgsWkbTypes.Type.Point)
- self.assertEqual(res[0].geometryColumnName(), '')
- self.assertEqual(res[0].driverName(), 'ESRI Shapefile')
- options = QgsProviderSublayerDetails.LayerOptions(QgsCoordinateTransformContext())
+ self.assertEqual(res[0].geometryColumnName(), "")
+ self.assertEqual(res[0].driverName(), "ESRI Shapefile")
+ options = QgsProviderSublayerDetails.LayerOptions(
+ QgsCoordinateTransformContext()
+ )
vl = res[0].toLayer(options)
self.assertTrue(vl.isValid())
self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.Point)
- self.assertEqual(vl.dataProvider().storageType(), 'ESRI Shapefile')
+ self.assertEqual(vl.dataProvider().storageType(), "ESRI Shapefile")
# archive, with suffix, and layername
- res = metadata.querySublayers('/vsitar/' + os.path.join(TEST_DATA_DIR, 'zip', 'testtar.tgz') + '/points.shp|layername=points')
+ res = metadata.querySublayers(
+ "/vsitar/"
+ + os.path.join(TEST_DATA_DIR, "zip", "testtar.tgz")
+ + "/points.shp|layername=points"
+ )
self.assertEqual(len(res), 1)
self.assertEqual(res[0].layerNumber(), 0)
self.assertEqual(res[0].name(), "points.shp")
- self.assertEqual(res[0].description(), '')
- self.assertEqual(res[0].uri(), '/vsitar/' + TEST_DATA_DIR + "/zip/testtar.tgz/points.shp|layername=points")
+ self.assertEqual(res[0].description(), "")
+ self.assertEqual(
+ res[0].uri(),
+ "/vsitar/" + TEST_DATA_DIR + "/zip/testtar.tgz/points.shp|layername=points",
+ )
self.assertEqual(res[0].providerKey(), "ogr")
self.assertEqual(res[0].type(), QgsMapLayerType.VectorLayer)
self.assertEqual(res[0].wkbType(), QgsWkbTypes.Type.Point)
- self.assertEqual(res[0].geometryColumnName(), '')
- self.assertEqual(res[0].driverName(), 'ESRI Shapefile')
- options = QgsProviderSublayerDetails.LayerOptions(QgsCoordinateTransformContext())
+ self.assertEqual(res[0].geometryColumnName(), "")
+ self.assertEqual(res[0].driverName(), "ESRI Shapefile")
+ options = QgsProviderSublayerDetails.LayerOptions(
+ QgsCoordinateTransformContext()
+ )
vl = res[0].toLayer(options)
self.assertTrue(vl.isValid())
self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.Point)
- self.assertEqual(vl.dataProvider().storageType(), 'ESRI Shapefile')
+ self.assertEqual(vl.dataProvider().storageType(), "ESRI Shapefile")
# geometry collection sublayers -- requires a scan to resolve geometry type
- res = metadata.querySublayers(os.path.join(TEST_DATA_DIR, 'multipatch.shp'))
+ res = metadata.querySublayers(os.path.join(TEST_DATA_DIR, "multipatch.shp"))
self.assertEqual(len(res), 1)
self.assertEqual(res[0].layerNumber(), 0)
self.assertEqual(res[0].name(), "multipatch")
- self.assertEqual(res[0].description(), '')
+ self.assertEqual(res[0].description(), "")
self.assertEqual(res[0].uri(), TEST_DATA_DIR + "/multipatch.shp")
self.assertEqual(res[0].providerKey(), "ogr")
self.assertEqual(res[0].type(), QgsMapLayerType.VectorLayer)
self.assertEqual(res[0].wkbType(), QgsWkbTypes.Type.Unknown)
- self.assertEqual(res[0].geometryColumnName(), '')
- self.assertEqual(res[0].driverName(), 'ESRI Shapefile')
+ self.assertEqual(res[0].geometryColumnName(), "")
+ self.assertEqual(res[0].driverName(), "ESRI Shapefile")
# retry with retrieving geometry types
- res = metadata.querySublayers(os.path.join(TEST_DATA_DIR, 'multipatch.shp'), Qgis.SublayerQueryFlag.ResolveGeometryType)
+ res = metadata.querySublayers(
+ os.path.join(TEST_DATA_DIR, "multipatch.shp"),
+ Qgis.SublayerQueryFlag.ResolveGeometryType,
+ )
self.assertEqual(len(res), 1)
self.assertEqual(res[0].layerNumber(), 0)
self.assertEqual(res[0].name(), "multipatch")
- self.assertEqual(res[0].description(), '')
- self.assertEqual(res[0].uri(), TEST_DATA_DIR + "/multipatch.shp|geometrytype=Polygon25D|uniqueGeometryType=yes")
+ self.assertEqual(res[0].description(), "")
+ self.assertEqual(
+ res[0].uri(),
+ TEST_DATA_DIR
+ + "/multipatch.shp|geometrytype=Polygon25D|uniqueGeometryType=yes",
+ )
self.assertEqual(res[0].providerKey(), "ogr")
self.assertEqual(res[0].type(), QgsMapLayerType.VectorLayer)
self.assertEqual(res[0].wkbType(), QgsWkbTypes.Type.PolygonZ)
- self.assertEqual(res[0].geometryColumnName(), '')
- self.assertEqual(res[0].driverName(), 'ESRI Shapefile')
+ self.assertEqual(res[0].geometryColumnName(), "")
+ self.assertEqual(res[0].driverName(), "ESRI Shapefile")
# check a feature
vl = res[0].toLayer(options)
self.assertTrue(vl.isValid())
feature = next(vl.getFeatures())
self.assertEqual(feature.geometry().wkbType(), QgsWkbTypes.Type.MultiPolygonZ)
- self.assertEqual(feature.geometry().asWkt(), 'MultiPolygon Z (((0 0 0, 0 1 0, 1 1 0, 0 0 0)),((0 0 0, 1 1 0, 1 0 0,'
- ' 0 0 0)),((0 0 0, 0 -1 0, 1 -1 0, 0 0 0)),((0 0 0, 1 -1 0, 1 0 0, 0 0 0)))')
+ self.assertEqual(
+ feature.geometry().asWkt(),
+ "MultiPolygon Z (((0 0 0, 0 1 0, 1 1 0, 0 0 0)),((0 0 0, 1 1 0, 1 0 0,"
+ " 0 0 0)),((0 0 0, 0 -1 0, 1 -1 0, 0 0 0)),((0 0 0, 1 -1 0, 1 0 0, 0 0 0)))",
+ )
# single layer geopackage -- sublayers MUST have the layerName set on the uri,
# in case more layers are added in future to the gpkg
- res = metadata.querySublayers(os.path.join(self.temp_dir_path, 'curved_polys.gpkg'))
+ res = metadata.querySublayers(
+ os.path.join(self.temp_dir_path, "curved_polys.gpkg")
+ )
self.assertEqual(len(res), 1)
self.assertEqual(res[0].layerNumber(), 0)
self.assertEqual(res[0].name(), "polys")
- self.assertEqual(res[0].description(), '')
- self.assertEqual(res[0].uri(), self.temp_dir_path + "/curved_polys.gpkg|layername=polys")
+ self.assertEqual(res[0].description(), "")
+ self.assertEqual(
+ res[0].uri(), self.temp_dir_path + "/curved_polys.gpkg|layername=polys"
+ )
self.assertEqual(res[0].providerKey(), "ogr")
self.assertEqual(res[0].type(), QgsMapLayerType.VectorLayer)
self.assertEqual(res[0].wkbType(), QgsWkbTypes.Type.CurvePolygon)
- self.assertEqual(res[0].geometryColumnName(), 'geometry')
- self.assertEqual(res[0].driverName(), 'GPKG')
+ self.assertEqual(res[0].geometryColumnName(), "geometry")
+ self.assertEqual(res[0].driverName(), "GPKG")
# make sure result is valid to load layer from
vl = res[0].toLayer(options)
self.assertTrue(vl.isValid())
# geopackage with two vector layers
- res = metadata.querySublayers(os.path.join(self.temp_dir_path, "mixed_layers.gpkg"))
+ res = metadata.querySublayers(
+ os.path.join(self.temp_dir_path, "mixed_layers.gpkg")
+ )
self.assertEqual(len(res), 2)
self.assertEqual(res[0].layerNumber(), 0)
self.assertEqual(res[0].name(), "points")
self.assertEqual(res[0].description(), "")
- self.assertEqual(res[0].uri(), f"{self.temp_dir_path}/mixed_layers.gpkg|layername=points")
+ self.assertEqual(
+ res[0].uri(), f"{self.temp_dir_path}/mixed_layers.gpkg|layername=points"
+ )
self.assertEqual(res[0].providerKey(), "ogr")
self.assertEqual(res[0].type(), QgsMapLayerType.VectorLayer)
self.assertEqual(res[0].featureCount(), Qgis.FeatureCountState.Uncounted)
self.assertEqual(res[0].wkbType(), QgsWkbTypes.Type.Point)
- self.assertEqual(res[0].geometryColumnName(), 'geometry')
- self.assertEqual(res[0].driverName(), 'GPKG')
+ self.assertEqual(res[0].geometryColumnName(), "geometry")
+ self.assertEqual(res[0].driverName(), "GPKG")
vl = res[0].toLayer(options)
self.assertTrue(vl.isValid())
self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.Point)
@@ -1971,89 +2592,110 @@ def test_provider_sublayer_details(self):
self.assertEqual(res[1].layerNumber(), 1)
self.assertEqual(res[1].name(), "lines")
self.assertEqual(res[1].description(), "")
- self.assertEqual(res[1].uri(), f"{self.temp_dir_path}/mixed_layers.gpkg|layername=lines")
+ self.assertEqual(
+ res[1].uri(), f"{self.temp_dir_path}/mixed_layers.gpkg|layername=lines"
+ )
self.assertEqual(res[1].providerKey(), "ogr")
self.assertEqual(res[1].type(), QgsMapLayerType.VectorLayer)
self.assertEqual(res[1].featureCount(), Qgis.FeatureCountState.Uncounted)
self.assertEqual(res[1].wkbType(), QgsWkbTypes.Type.MultiLineString)
- self.assertEqual(res[1].geometryColumnName(), 'geom')
- self.assertEqual(res[1].driverName(), 'GPKG')
+ self.assertEqual(res[1].geometryColumnName(), "geom")
+ self.assertEqual(res[1].driverName(), "GPKG")
vl = res[1].toLayer(options)
self.assertTrue(vl.isValid())
self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.MultiLineString)
# request feature count
- res = metadata.querySublayers(os.path.join(self.temp_dir_path, "mixed_layers.gpkg"), Qgis.SublayerQueryFlag.CountFeatures)
+ res = metadata.querySublayers(
+ os.path.join(self.temp_dir_path, "mixed_layers.gpkg"),
+ Qgis.SublayerQueryFlag.CountFeatures,
+ )
self.assertEqual(len(res), 2)
self.assertEqual(res[0].name(), "points")
self.assertEqual(res[0].featureCount(), 0)
- self.assertEqual(res[0].geometryColumnName(), 'geometry')
+ self.assertEqual(res[0].geometryColumnName(), "geometry")
self.assertEqual(res[1].name(), "lines")
self.assertEqual(res[1].featureCount(), 6)
- self.assertEqual(res[1].geometryColumnName(), 'geom')
- self.assertEqual(res[1].driverName(), 'GPKG')
+ self.assertEqual(res[1].geometryColumnName(), "geom")
+ self.assertEqual(res[1].driverName(), "GPKG")
# geopackage with two layers, but specific layer is requested in uri
- res = metadata.querySublayers(os.path.join(self.temp_dir_path, "mixed_layers.gpkg") + '|layerid=0')
+ res = metadata.querySublayers(
+ os.path.join(self.temp_dir_path, "mixed_layers.gpkg") + "|layerid=0"
+ )
self.assertEqual(len(res), 1)
self.assertEqual(res[0].layerNumber(), 0)
self.assertEqual(res[0].name(), "points")
self.assertEqual(res[0].description(), "")
- self.assertEqual(res[0].uri(), f"{self.temp_dir_path}/mixed_layers.gpkg|layername=points")
+ self.assertEqual(
+ res[0].uri(), f"{self.temp_dir_path}/mixed_layers.gpkg|layername=points"
+ )
self.assertEqual(res[0].providerKey(), "ogr")
self.assertEqual(res[0].type(), QgsMapLayerType.VectorLayer)
self.assertEqual(res[0].featureCount(), Qgis.FeatureCountState.Uncounted)
self.assertEqual(res[0].wkbType(), QgsWkbTypes.Type.Point)
- self.assertEqual(res[0].geometryColumnName(), 'geometry')
- self.assertEqual(res[0].driverName(), 'GPKG')
+ self.assertEqual(res[0].geometryColumnName(), "geometry")
+ self.assertEqual(res[0].driverName(), "GPKG")
vl = res[0].toLayer(options)
self.assertTrue(vl.isValid())
self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.Point)
- res = metadata.querySublayers(os.path.join(self.temp_dir_path, "mixed_layers.gpkg") + '|layerid=1')
+ res = metadata.querySublayers(
+ os.path.join(self.temp_dir_path, "mixed_layers.gpkg") + "|layerid=1"
+ )
self.assertEqual(len(res), 1)
self.assertEqual(res[0].layerNumber(), 1)
self.assertEqual(res[0].name(), "lines")
self.assertEqual(res[0].description(), "")
- self.assertEqual(res[0].uri(), f"{self.temp_dir_path}/mixed_layers.gpkg|layername=lines")
+ self.assertEqual(
+ res[0].uri(), f"{self.temp_dir_path}/mixed_layers.gpkg|layername=lines"
+ )
self.assertEqual(res[0].providerKey(), "ogr")
self.assertEqual(res[0].type(), QgsMapLayerType.VectorLayer)
self.assertEqual(res[0].featureCount(), Qgis.FeatureCountState.Uncounted)
self.assertEqual(res[0].wkbType(), QgsWkbTypes.Type.MultiLineString)
- self.assertEqual(res[0].geometryColumnName(), 'geom')
- self.assertEqual(res[0].driverName(), 'GPKG')
+ self.assertEqual(res[0].geometryColumnName(), "geom")
+ self.assertEqual(res[0].driverName(), "GPKG")
vl = res[0].toLayer(options)
self.assertTrue(vl.isValid())
self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.MultiLineString)
- res = metadata.querySublayers(os.path.join(self.temp_dir_path, "mixed_layers.gpkg") + '|layername=points')
+ res = metadata.querySublayers(
+ os.path.join(self.temp_dir_path, "mixed_layers.gpkg") + "|layername=points"
+ )
self.assertEqual(len(res), 1)
self.assertEqual(res[0].layerNumber(), 0)
self.assertEqual(res[0].name(), "points")
self.assertEqual(res[0].description(), "")
- self.assertEqual(res[0].uri(), f"{self.temp_dir_path}/mixed_layers.gpkg|layername=points")
+ self.assertEqual(
+ res[0].uri(), f"{self.temp_dir_path}/mixed_layers.gpkg|layername=points"
+ )
self.assertEqual(res[0].providerKey(), "ogr")
self.assertEqual(res[0].type(), QgsMapLayerType.VectorLayer)
self.assertEqual(res[0].featureCount(), Qgis.FeatureCountState.Uncounted)
self.assertEqual(res[0].wkbType(), QgsWkbTypes.Type.Point)
- self.assertEqual(res[0].geometryColumnName(), 'geometry')
- self.assertEqual(res[0].driverName(), 'GPKG')
+ self.assertEqual(res[0].geometryColumnName(), "geometry")
+ self.assertEqual(res[0].driverName(), "GPKG")
vl = res[0].toLayer(options)
self.assertTrue(vl.isValid())
self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.Point)
- res = metadata.querySublayers(os.path.join(self.temp_dir_path, "mixed_layers.gpkg") + '|layername=lines')
+ res = metadata.querySublayers(
+ os.path.join(self.temp_dir_path, "mixed_layers.gpkg") + "|layername=lines"
+ )
self.assertEqual(len(res), 1)
self.assertEqual(res[0].layerNumber(), 1)
self.assertEqual(res[0].name(), "lines")
self.assertEqual(res[0].description(), "")
- self.assertEqual(res[0].uri(), f"{self.temp_dir_path}/mixed_layers.gpkg|layername=lines")
+ self.assertEqual(
+ res[0].uri(), f"{self.temp_dir_path}/mixed_layers.gpkg|layername=lines"
+ )
self.assertEqual(res[0].providerKey(), "ogr")
self.assertEqual(res[0].type(), QgsMapLayerType.VectorLayer)
self.assertEqual(res[0].featureCount(), Qgis.FeatureCountState.Uncounted)
self.assertEqual(res[0].wkbType(), QgsWkbTypes.Type.MultiLineString)
- self.assertEqual(res[0].geometryColumnName(), 'geom')
- self.assertEqual(res[0].driverName(), 'GPKG')
+ self.assertEqual(res[0].geometryColumnName(), "geom")
+ self.assertEqual(res[0].driverName(), "GPKG")
vl = res[0].toLayer(options)
self.assertTrue(vl.isValid())
self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.MultiLineString)
@@ -2069,13 +2711,16 @@ def test_provider_sublayer_details(self):
self.assertEqual(res[0].type(), QgsMapLayerType.VectorLayer)
self.assertEqual(res[0].featureCount(), Qgis.FeatureCountState.Uncounted)
self.assertEqual(res[0].wkbType(), QgsWkbTypes.Type.Unknown)
- self.assertEqual(res[0].geometryColumnName(), '')
- self.assertEqual(res[0].driverName(), 'MapInfo File')
+ self.assertEqual(res[0].geometryColumnName(), "")
+ self.assertEqual(res[0].driverName(), "MapInfo File")
vl = res[0].toLayer(options)
self.assertTrue(vl.isValid())
# layer with mixed geometry types - without resolving geometry types, but with feature count
- res = metadata.querySublayers(os.path.join(TEST_DATA_DIR, "mixed_types.TAB"), Qgis.SublayerQueryFlag.CountFeatures)
+ res = metadata.querySublayers(
+ os.path.join(TEST_DATA_DIR, "mixed_types.TAB"),
+ Qgis.SublayerQueryFlag.CountFeatures,
+ )
self.assertEqual(len(res), 1)
self.assertEqual(res[0].layerNumber(), 0)
self.assertEqual(res[0].name(), "mixed_types")
@@ -2085,22 +2730,27 @@ def test_provider_sublayer_details(self):
self.assertEqual(res[0].type(), QgsMapLayerType.VectorLayer)
self.assertEqual(res[0].featureCount(), 13)
self.assertEqual(res[0].wkbType(), QgsWkbTypes.Type.Unknown)
- self.assertEqual(res[0].geometryColumnName(), '')
- self.assertEqual(res[0].driverName(), 'MapInfo File')
+ self.assertEqual(res[0].geometryColumnName(), "")
+ self.assertEqual(res[0].driverName(), "MapInfo File")
# layer with mixed geometry types - resolve geometry type (for OGR provider this implies also that we count features!)
- res = metadata.querySublayers(os.path.join(TEST_DATA_DIR, "mixed_types.TAB"), Qgis.SublayerQueryFlag.ResolveGeometryType)
+ res = metadata.querySublayers(
+ os.path.join(TEST_DATA_DIR, "mixed_types.TAB"),
+ Qgis.SublayerQueryFlag.ResolveGeometryType,
+ )
self.assertEqual(len(res), 3)
self.assertEqual(res[0].layerNumber(), 0)
self.assertEqual(res[0].name(), "mixed_types")
self.assertEqual(res[0].description(), "")
- self.assertEqual(res[0].uri(), f"{TEST_DATA_DIR}/mixed_types.TAB|geometrytype=Point")
+ self.assertEqual(
+ res[0].uri(), f"{TEST_DATA_DIR}/mixed_types.TAB|geometrytype=Point"
+ )
self.assertEqual(res[0].providerKey(), "ogr")
self.assertEqual(res[0].type(), QgsMapLayerType.VectorLayer)
self.assertEqual(res[0].featureCount(), 4)
self.assertEqual(res[0].wkbType(), QgsWkbTypes.Type.Point)
- self.assertEqual(res[0].geometryColumnName(), '')
- self.assertEqual(res[0].driverName(), 'MapInfo File')
+ self.assertEqual(res[0].geometryColumnName(), "")
+ self.assertEqual(res[0].driverName(), "MapInfo File")
vl = res[0].toLayer(options)
self.assertTrue(vl.isValid())
self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.Point)
@@ -2108,13 +2758,15 @@ def test_provider_sublayer_details(self):
self.assertEqual(res[1].layerNumber(), 0)
self.assertEqual(res[1].name(), "mixed_types")
self.assertEqual(res[1].description(), "")
- self.assertEqual(res[1].uri(), f"{TEST_DATA_DIR}/mixed_types.TAB|geometrytype=LineString")
+ self.assertEqual(
+ res[1].uri(), f"{TEST_DATA_DIR}/mixed_types.TAB|geometrytype=LineString"
+ )
self.assertEqual(res[1].providerKey(), "ogr")
self.assertEqual(res[1].type(), QgsMapLayerType.VectorLayer)
self.assertEqual(res[1].featureCount(), 4)
self.assertEqual(res[1].wkbType(), QgsWkbTypes.Type.LineString)
- self.assertEqual(res[1].geometryColumnName(), '')
- self.assertEqual(res[1].driverName(), 'MapInfo File')
+ self.assertEqual(res[1].geometryColumnName(), "")
+ self.assertEqual(res[1].driverName(), "MapInfo File")
vl = res[1].toLayer(options)
self.assertTrue(vl.isValid())
self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.LineString)
@@ -2122,38 +2774,47 @@ def test_provider_sublayer_details(self):
self.assertEqual(res[2].layerNumber(), 0)
self.assertEqual(res[2].name(), "mixed_types")
self.assertEqual(res[2].description(), "")
- self.assertEqual(res[2].uri(), f"{TEST_DATA_DIR}/mixed_types.TAB|geometrytype=Polygon")
+ self.assertEqual(
+ res[2].uri(), f"{TEST_DATA_DIR}/mixed_types.TAB|geometrytype=Polygon"
+ )
self.assertEqual(res[2].providerKey(), "ogr")
self.assertEqual(res[2].type(), QgsMapLayerType.VectorLayer)
self.assertEqual(res[2].featureCount(), 3)
self.assertEqual(res[2].wkbType(), QgsWkbTypes.Type.Polygon)
- self.assertEqual(res[2].geometryColumnName(), '')
- self.assertEqual(res[2].driverName(), 'MapInfo File')
+ self.assertEqual(res[2].geometryColumnName(), "")
+ self.assertEqual(res[2].driverName(), "MapInfo File")
vl = res[2].toLayer(options)
self.assertTrue(vl.isValid())
self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.Polygon)
# a layer which reports unknown geometry type and requires a full table scan to resolve, but which only
# contains a single type of geometry
- res = metadata.querySublayers(os.path.join(TEST_DATA_DIR, "mapinfo", "fill_styles.TAB"),
- Qgis.SublayerQueryFlag.ResolveGeometryType)
+ res = metadata.querySublayers(
+ os.path.join(TEST_DATA_DIR, "mapinfo", "fill_styles.TAB"),
+ Qgis.SublayerQueryFlag.ResolveGeometryType,
+ )
self.assertEqual(len(res), 1)
self.assertEqual(res[0].layerNumber(), 0)
self.assertEqual(res[0].name(), "fill_styles")
self.assertEqual(res[0].description(), "")
- self.assertEqual(res[0].uri(), f"{TEST_DATA_DIR}/mapinfo/fill_styles.TAB|geometrytype=Polygon|uniqueGeometryType=yes")
+ self.assertEqual(
+ res[0].uri(),
+ f"{TEST_DATA_DIR}/mapinfo/fill_styles.TAB|geometrytype=Polygon|uniqueGeometryType=yes",
+ )
self.assertEqual(res[0].providerKey(), "ogr")
self.assertEqual(res[0].type(), QgsMapLayerType.VectorLayer)
self.assertEqual(res[0].featureCount(), 49)
self.assertEqual(res[0].wkbType(), QgsWkbTypes.Type.Polygon)
- self.assertEqual(res[0].geometryColumnName(), '')
- self.assertEqual(res[0].driverName(), 'MapInfo File')
+ self.assertEqual(res[0].geometryColumnName(), "")
+ self.assertEqual(res[0].driverName(), "MapInfo File")
vl = res[0].toLayer(options)
self.assertTrue(vl.isValid())
self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.Polygon)
# same, but don't resolve geometry types
- res = metadata.querySublayers(os.path.join(TEST_DATA_DIR, "mapinfo", "fill_styles.TAB"))
+ res = metadata.querySublayers(
+ os.path.join(TEST_DATA_DIR, "mapinfo", "fill_styles.TAB")
+ )
self.assertEqual(len(res), 1)
self.assertEqual(res[0].layerNumber(), 0)
self.assertEqual(res[0].name(), "fill_styles")
@@ -2163,294 +2824,387 @@ def test_provider_sublayer_details(self):
self.assertEqual(res[0].type(), QgsMapLayerType.VectorLayer)
self.assertEqual(res[0].featureCount(), Qgis.FeatureCountState.Uncounted)
self.assertEqual(res[0].wkbType(), QgsWkbTypes.Type.Unknown)
- self.assertEqual(res[0].geometryColumnName(), '')
- self.assertEqual(res[0].driverName(), 'MapInfo File')
+ self.assertEqual(res[0].geometryColumnName(), "")
+ self.assertEqual(res[0].driverName(), "MapInfo File")
vl = res[0].toLayer(options)
self.assertTrue(vl.isValid())
self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.Polygon)
# mixed types source, but with a URI which specifies a particular type. Only this type should be returned
- res = metadata.querySublayers(os.path.join(TEST_DATA_DIR, "mixed_types.TAB|geometrytype=Point"),
- Qgis.SublayerQueryFlag.ResolveGeometryType)
+ res = metadata.querySublayers(
+ os.path.join(TEST_DATA_DIR, "mixed_types.TAB|geometrytype=Point"),
+ Qgis.SublayerQueryFlag.ResolveGeometryType,
+ )
self.assertEqual(len(res), 1)
self.assertEqual(res[0].layerNumber(), 0)
self.assertEqual(res[0].name(), "mixed_types")
self.assertEqual(res[0].description(), "")
- self.assertEqual(res[0].uri(), f"{TEST_DATA_DIR}/mixed_types.TAB|geometrytype=Point")
+ self.assertEqual(
+ res[0].uri(), f"{TEST_DATA_DIR}/mixed_types.TAB|geometrytype=Point"
+ )
self.assertEqual(res[0].providerKey(), "ogr")
self.assertEqual(res[0].type(), QgsMapLayerType.VectorLayer)
self.assertEqual(res[0].featureCount(), 4)
self.assertEqual(res[0].wkbType(), QgsWkbTypes.Type.Point)
- self.assertEqual(res[0].geometryColumnName(), '')
- self.assertEqual(res[0].driverName(), 'MapInfo File')
+ self.assertEqual(res[0].geometryColumnName(), "")
+ self.assertEqual(res[0].driverName(), "MapInfo File")
vl = res[0].toLayer(options)
self.assertTrue(vl.isValid())
self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.Point)
- res = metadata.querySublayers(os.path.join(TEST_DATA_DIR, "mixed_types.TAB|geometrytype=LineString"),
- Qgis.SublayerQueryFlag.ResolveGeometryType)
+ res = metadata.querySublayers(
+ os.path.join(TEST_DATA_DIR, "mixed_types.TAB|geometrytype=LineString"),
+ Qgis.SublayerQueryFlag.ResolveGeometryType,
+ )
self.assertEqual(len(res), 1)
self.assertEqual(res[0].layerNumber(), 0)
self.assertEqual(res[0].name(), "mixed_types")
self.assertEqual(res[0].description(), "")
- self.assertEqual(res[0].uri(), f"{TEST_DATA_DIR}/mixed_types.TAB|geometrytype=LineString")
+ self.assertEqual(
+ res[0].uri(), f"{TEST_DATA_DIR}/mixed_types.TAB|geometrytype=LineString"
+ )
self.assertEqual(res[0].providerKey(), "ogr")
self.assertEqual(res[0].type(), QgsMapLayerType.VectorLayer)
self.assertEqual(res[0].featureCount(), 4)
self.assertEqual(res[0].wkbType(), QgsWkbTypes.Type.LineString)
- self.assertEqual(res[0].geometryColumnName(), '')
- self.assertEqual(res[0].driverName(), 'MapInfo File')
+ self.assertEqual(res[0].geometryColumnName(), "")
+ self.assertEqual(res[0].driverName(), "MapInfo File")
vl = res[0].toLayer(options)
self.assertTrue(vl.isValid())
self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.LineString)
- res = metadata.querySublayers(os.path.join(TEST_DATA_DIR, "mixed_types.TAB|geometrytype=Polygon"),
- Qgis.SublayerQueryFlag.ResolveGeometryType)
+ res = metadata.querySublayers(
+ os.path.join(TEST_DATA_DIR, "mixed_types.TAB|geometrytype=Polygon"),
+ Qgis.SublayerQueryFlag.ResolveGeometryType,
+ )
self.assertEqual(len(res), 1)
self.assertEqual(res[0].layerNumber(), 0)
self.assertEqual(res[0].name(), "mixed_types")
self.assertEqual(res[0].description(), "")
- self.assertEqual(res[0].uri(), f"{TEST_DATA_DIR}/mixed_types.TAB|geometrytype=Polygon")
+ self.assertEqual(
+ res[0].uri(), f"{TEST_DATA_DIR}/mixed_types.TAB|geometrytype=Polygon"
+ )
self.assertEqual(res[0].providerKey(), "ogr")
self.assertEqual(res[0].type(), QgsMapLayerType.VectorLayer)
self.assertEqual(res[0].featureCount(), 3)
self.assertEqual(res[0].wkbType(), QgsWkbTypes.Type.Polygon)
- self.assertEqual(res[0].geometryColumnName(), '')
- self.assertEqual(res[0].driverName(), 'MapInfo File')
+ self.assertEqual(res[0].geometryColumnName(), "")
+ self.assertEqual(res[0].driverName(), "MapInfo File")
vl = res[0].toLayer(options)
self.assertTrue(vl.isValid())
self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.Polygon)
# same as above, but without ResolveGeometryType flag
- res = metadata.querySublayers(os.path.join(TEST_DATA_DIR, "mixed_types.TAB|geometrytype=Point"))
+ res = metadata.querySublayers(
+ os.path.join(TEST_DATA_DIR, "mixed_types.TAB|geometrytype=Point")
+ )
self.assertEqual(len(res), 1)
self.assertEqual(res[0].layerNumber(), 0)
self.assertEqual(res[0].name(), "mixed_types")
self.assertEqual(res[0].description(), "")
- self.assertEqual(res[0].uri(), f"{TEST_DATA_DIR}/mixed_types.TAB|geometrytype=Point")
+ self.assertEqual(
+ res[0].uri(), f"{TEST_DATA_DIR}/mixed_types.TAB|geometrytype=Point"
+ )
self.assertEqual(res[0].providerKey(), "ogr")
self.assertEqual(res[0].type(), QgsMapLayerType.VectorLayer)
self.assertEqual(res[0].featureCount(), Qgis.FeatureCountState.Uncounted)
self.assertEqual(res[0].wkbType(), QgsWkbTypes.Type.Point)
- self.assertEqual(res[0].geometryColumnName(), '')
- self.assertEqual(res[0].driverName(), 'MapInfo File')
+ self.assertEqual(res[0].geometryColumnName(), "")
+ self.assertEqual(res[0].driverName(), "MapInfo File")
vl = res[0].toLayer(options)
self.assertTrue(vl.isValid())
self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.Point)
- res = metadata.querySublayers(os.path.join(TEST_DATA_DIR, "mixed_types.TAB|geometrytype=LineString"))
+ res = metadata.querySublayers(
+ os.path.join(TEST_DATA_DIR, "mixed_types.TAB|geometrytype=LineString")
+ )
self.assertEqual(len(res), 1)
self.assertEqual(res[0].layerNumber(), 0)
self.assertEqual(res[0].name(), "mixed_types")
self.assertEqual(res[0].description(), "")
- self.assertEqual(res[0].uri(), f"{TEST_DATA_DIR}/mixed_types.TAB|geometrytype=LineString")
+ self.assertEqual(
+ res[0].uri(), f"{TEST_DATA_DIR}/mixed_types.TAB|geometrytype=LineString"
+ )
self.assertEqual(res[0].providerKey(), "ogr")
self.assertEqual(res[0].type(), QgsMapLayerType.VectorLayer)
self.assertEqual(res[0].featureCount(), Qgis.FeatureCountState.Uncounted)
self.assertEqual(res[0].wkbType(), QgsWkbTypes.Type.LineString)
- self.assertEqual(res[0].geometryColumnName(), '')
- self.assertEqual(res[0].driverName(), 'MapInfo File')
+ self.assertEqual(res[0].geometryColumnName(), "")
+ self.assertEqual(res[0].driverName(), "MapInfo File")
vl = res[0].toLayer(options)
self.assertTrue(vl.isValid())
self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.LineString)
- res = metadata.querySublayers(os.path.join(TEST_DATA_DIR, "mixed_types.TAB|geometrytype=Polygon"))
+ res = metadata.querySublayers(
+ os.path.join(TEST_DATA_DIR, "mixed_types.TAB|geometrytype=Polygon")
+ )
self.assertEqual(len(res), 1)
self.assertEqual(res[0].layerNumber(), 0)
self.assertEqual(res[0].name(), "mixed_types")
self.assertEqual(res[0].description(), "")
- self.assertEqual(res[0].uri(), f"{TEST_DATA_DIR}/mixed_types.TAB|geometrytype=Polygon")
+ self.assertEqual(
+ res[0].uri(), f"{TEST_DATA_DIR}/mixed_types.TAB|geometrytype=Polygon"
+ )
self.assertEqual(res[0].providerKey(), "ogr")
self.assertEqual(res[0].type(), QgsMapLayerType.VectorLayer)
self.assertEqual(res[0].featureCount(), Qgis.FeatureCountState.Uncounted)
self.assertEqual(res[0].wkbType(), QgsWkbTypes.Type.Polygon)
- self.assertEqual(res[0].geometryColumnName(), '')
- self.assertEqual(res[0].driverName(), 'MapInfo File')
+ self.assertEqual(res[0].geometryColumnName(), "")
+ self.assertEqual(res[0].driverName(), "MapInfo File")
vl = res[0].toLayer(options)
self.assertTrue(vl.isValid())
self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.Polygon)
# spatialite
- res = metadata.querySublayers(os.path.join(TEST_DATA_DIR, "provider/spatialite.db"))
- self.assertCountEqual([{'name': r.name(),
- 'description': r.description(),
- 'uri': r.uri(),
- 'providerKey': r.providerKey(),
- 'wkbType': r.wkbType(),
- 'driverName': r.driverName(),
- 'geomColName': r.geometryColumnName()} for r in res],
- [{'name': 'somedata',
- 'description': '',
- 'uri': f'{TEST_DATA_DIR}/provider/spatialite.db|layername=somedata',
- 'providerKey': 'ogr',
- 'wkbType': 1,
- 'driverName': 'SQLite',
- 'geomColName': 'geom'},
- {'name': 'somepolydata',
- 'description': '',
- 'uri': f'{TEST_DATA_DIR}/provider/spatialite.db|layername=somepolydata',
- 'providerKey': 'ogr',
- 'wkbType': 6,
- 'driverName': 'SQLite',
- 'geomColName': 'geom'},
- {'name': 'some data',
- 'description': '',
- 'uri': f'{TEST_DATA_DIR}/provider/spatialite.db|layername=some data',
- 'providerKey': 'ogr',
- 'wkbType': 1,
- 'driverName': 'SQLite',
- 'geomColName': 'geom'},
- {'name': 'validator_project_test',
- 'description': '',
- 'uri': f'{TEST_DATA_DIR}/provider/spatialite.db|layername=validator_project_test',
- 'providerKey': 'ogr',
- 'wkbType': 1,
- 'driverName': 'SQLite',
- 'geomColName': 'geom'},
- {'name': 'data_licenses',
- 'description': '',
- 'uri': f'{TEST_DATA_DIR}/provider/spatialite.db|layername=data_licenses',
- 'providerKey': 'ogr',
- 'wkbType': 100,
- 'driverName': 'SQLite',
- 'geomColName': ''},
- {'name': 'some view',
- 'description': '',
- 'uri': f'{TEST_DATA_DIR}/provider/spatialite.db|layername=some view',
- 'providerKey': 'ogr',
- 'wkbType': 100,
- 'driverName': 'SQLite',
- 'geomColName': ''}])
+ res = metadata.querySublayers(
+ os.path.join(TEST_DATA_DIR, "provider/spatialite.db")
+ )
+ self.assertCountEqual(
+ [
+ {
+ "name": r.name(),
+ "description": r.description(),
+ "uri": r.uri(),
+ "providerKey": r.providerKey(),
+ "wkbType": r.wkbType(),
+ "driverName": r.driverName(),
+ "geomColName": r.geometryColumnName(),
+ }
+ for r in res
+ ],
+ [
+ {
+ "name": "somedata",
+ "description": "",
+ "uri": f"{TEST_DATA_DIR}/provider/spatialite.db|layername=somedata",
+ "providerKey": "ogr",
+ "wkbType": 1,
+ "driverName": "SQLite",
+ "geomColName": "geom",
+ },
+ {
+ "name": "somepolydata",
+ "description": "",
+ "uri": f"{TEST_DATA_DIR}/provider/spatialite.db|layername=somepolydata",
+ "providerKey": "ogr",
+ "wkbType": 6,
+ "driverName": "SQLite",
+ "geomColName": "geom",
+ },
+ {
+ "name": "some data",
+ "description": "",
+ "uri": f"{TEST_DATA_DIR}/provider/spatialite.db|layername=some data",
+ "providerKey": "ogr",
+ "wkbType": 1,
+ "driverName": "SQLite",
+ "geomColName": "geom",
+ },
+ {
+ "name": "validator_project_test",
+ "description": "",
+ "uri": f"{TEST_DATA_DIR}/provider/spatialite.db|layername=validator_project_test",
+ "providerKey": "ogr",
+ "wkbType": 1,
+ "driverName": "SQLite",
+ "geomColName": "geom",
+ },
+ {
+ "name": "data_licenses",
+ "description": "",
+ "uri": f"{TEST_DATA_DIR}/provider/spatialite.db|layername=data_licenses",
+ "providerKey": "ogr",
+ "wkbType": 100,
+ "driverName": "SQLite",
+ "geomColName": "",
+ },
+ {
+ "name": "some view",
+ "description": "",
+ "uri": f"{TEST_DATA_DIR}/provider/spatialite.db|layername=some view",
+ "providerKey": "ogr",
+ "wkbType": 100,
+ "driverName": "SQLite",
+ "geomColName": "",
+ },
+ ],
+ )
# sqlite
res = metadata.querySublayers(
- os.path.join(TEST_DATA_DIR, "valuerelation_widget_wrapper_test.spatialite.sqlite"))
- self.assertCountEqual([{'name': r.name(),
- 'systemTable': bool(r.flags() & Qgis.SublayerFlag.SystemTable)} for r in res],
- [{'name': 'authors', 'systemTable': False},
- {'name': 'json', 'systemTable': False}])
+ os.path.join(
+ TEST_DATA_DIR, "valuerelation_widget_wrapper_test.spatialite.sqlite"
+ )
+ )
+ self.assertCountEqual(
+ [
+ {
+ "name": r.name(),
+ "systemTable": bool(r.flags() & Qgis.SublayerFlag.SystemTable),
+ }
+ for r in res
+ ],
+ [
+ {"name": "authors", "systemTable": False},
+ {"name": "json", "systemTable": False},
+ ],
+ )
# retrieve system tables
res = metadata.querySublayers(
- os.path.join(TEST_DATA_DIR, "valuerelation_widget_wrapper_test.spatialite.sqlite"),
- Qgis.SublayerQueryFlag.IncludeSystemTables)
- self.assertCountEqual([{'name': r.name(),
- 'systemTable': bool(r.flags() & Qgis.SublayerFlag.SystemTable)} for r in res],
- [{'name': 'ElementaryGeometries', 'systemTable': True},
- {'name': 'SpatialIndex', 'systemTable': True},
- {'name': 'authors', 'systemTable': False},
- {'name': 'geom_cols_ref_sys', 'systemTable': True},
- {'name': 'geometry_columns', 'systemTable': True},
- {'name': 'geometry_columns_auth', 'systemTable': True},
- {'name': 'geometry_columns_field_infos', 'systemTable': True},
- {'name': 'geometry_columns_statistics', 'systemTable': True},
- {'name': 'geometry_columns_time', 'systemTable': True},
- {'name': 'json', 'systemTable': False},
- {'name': 'spatial_ref_sys', 'systemTable': True},
- {'name': 'spatial_ref_sys_all', 'systemTable': True},
- {'name': 'spatial_ref_sys_aux', 'systemTable': True},
- {'name': 'spatialite_history', 'systemTable': True},
- {'name': 'sql_statements_log', 'systemTable': True},
- {'name': 'sqlite_sequence', 'systemTable': True},
- {'name': 'vector_layers', 'systemTable': True},
- {'name': 'vector_layers_auth', 'systemTable': True},
- {'name': 'vector_layers_field_infos', 'systemTable': True},
- {'name': 'vector_layers_statistics', 'systemTable': True},
- {'name': 'views_geometry_columns', 'systemTable': True},
- {'name': 'views_geometry_columns_auth', 'systemTable': True},
- {'name': 'views_geometry_columns_field_infos', 'systemTable': True},
- {'name': 'views_geometry_columns_statistics', 'systemTable': True},
- {'name': 'virts_geometry_columns', 'systemTable': True},
- {'name': 'virts_geometry_columns_auth', 'systemTable': True},
- {'name': 'virts_geometry_columns_field_infos', 'systemTable': True},
- {'name': 'virts_geometry_columns_statistics', 'systemTable': True}])
+ os.path.join(
+ TEST_DATA_DIR, "valuerelation_widget_wrapper_test.spatialite.sqlite"
+ ),
+ Qgis.SublayerQueryFlag.IncludeSystemTables,
+ )
+ self.assertCountEqual(
+ [
+ {
+ "name": r.name(),
+ "systemTable": bool(r.flags() & Qgis.SublayerFlag.SystemTable),
+ }
+ for r in res
+ ],
+ [
+ {"name": "ElementaryGeometries", "systemTable": True},
+ {"name": "SpatialIndex", "systemTable": True},
+ {"name": "authors", "systemTable": False},
+ {"name": "geom_cols_ref_sys", "systemTable": True},
+ {"name": "geometry_columns", "systemTable": True},
+ {"name": "geometry_columns_auth", "systemTable": True},
+ {"name": "geometry_columns_field_infos", "systemTable": True},
+ {"name": "geometry_columns_statistics", "systemTable": True},
+ {"name": "geometry_columns_time", "systemTable": True},
+ {"name": "json", "systemTable": False},
+ {"name": "spatial_ref_sys", "systemTable": True},
+ {"name": "spatial_ref_sys_all", "systemTable": True},
+ {"name": "spatial_ref_sys_aux", "systemTable": True},
+ {"name": "spatialite_history", "systemTable": True},
+ {"name": "sql_statements_log", "systemTable": True},
+ {"name": "sqlite_sequence", "systemTable": True},
+ {"name": "vector_layers", "systemTable": True},
+ {"name": "vector_layers_auth", "systemTable": True},
+ {"name": "vector_layers_field_infos", "systemTable": True},
+ {"name": "vector_layers_statistics", "systemTable": True},
+ {"name": "views_geometry_columns", "systemTable": True},
+ {"name": "views_geometry_columns_auth", "systemTable": True},
+ {"name": "views_geometry_columns_field_infos", "systemTable": True},
+ {"name": "views_geometry_columns_statistics", "systemTable": True},
+ {"name": "virts_geometry_columns", "systemTable": True},
+ {"name": "virts_geometry_columns_auth", "systemTable": True},
+ {"name": "virts_geometry_columns_field_infos", "systemTable": True},
+ {"name": "virts_geometry_columns_statistics", "systemTable": True},
+ ],
+ )
# metadata.xml file next to tdenv?.adf file -- this is a subcomponent of an ESRI tin layer, should not be exposed
res = metadata.querySublayers(
- os.path.join(TEST_DATA_DIR, 'esri_tin', 'metadata.xml'))
+ os.path.join(TEST_DATA_DIR, "esri_tin", "metadata.xml")
+ )
self.assertFalse(res)
# ESRI Arcinfo file
- res = metadata.querySublayers(os.path.join(TEST_DATA_DIR, 'esri_coverage', 'testpolyavc'))
+ res = metadata.querySublayers(
+ os.path.join(TEST_DATA_DIR, "esri_coverage", "testpolyavc")
+ )
self.assertEqual(len(res), 4)
self.assertEqual(res[0].layerNumber(), 0)
self.assertEqual(res[0].name(), "ARC")
self.assertEqual(res[0].description(), "")
- self.assertEqual(res[0].uri(), f"{os.path.join(TEST_DATA_DIR, 'esri_coverage', 'testpolyavc')}|layername=ARC")
+ self.assertEqual(
+ res[0].uri(),
+ f"{os.path.join(TEST_DATA_DIR, 'esri_coverage', 'testpolyavc')}|layername=ARC",
+ )
self.assertEqual(res[0].providerKey(), "ogr")
self.assertEqual(res[0].type(), QgsMapLayerType.VectorLayer)
self.assertFalse(res[0].skippedContainerScan())
- @unittest.skipIf(int(gdal.VersionInfo('VERSION_NUM')) < GDAL_COMPUTE_VERSION(3, 4, 0), "GDAL 3.4 required")
+ @unittest.skipIf(
+ int(gdal.VersionInfo("VERSION_NUM")) < GDAL_COMPUTE_VERSION(3, 4, 0),
+ "GDAL 3.4 required",
+ )
def test_provider_sublayer_details_hierarchy(self):
"""
Test retrieving sublayer details from a datasource with a hierarchy of layers
"""
- metadata = QgsProviderRegistry.instance().providerMetadata('ogr')
+ metadata = QgsProviderRegistry.instance().providerMetadata("ogr")
- res = metadata.querySublayers(os.path.join(TEST_DATA_DIR, 'featuredataset.gdb'))
+ res = metadata.querySublayers(os.path.join(TEST_DATA_DIR, "featuredataset.gdb"))
self.assertEqual(len(res), 4)
- self.assertEqual(res[0].name(), 'fd1_lyr1')
- self.assertEqual(res[0].path(), ['fd1'])
- self.assertEqual(res[1].name(), 'fd1_lyr2')
- self.assertEqual(res[1].path(), ['fd1'])
- self.assertEqual(res[2].name(), 'standalone')
+ self.assertEqual(res[0].name(), "fd1_lyr1")
+ self.assertEqual(res[0].path(), ["fd1"])
+ self.assertEqual(res[1].name(), "fd1_lyr2")
+ self.assertEqual(res[1].path(), ["fd1"])
+ self.assertEqual(res[2].name(), "standalone")
self.assertEqual(res[2].path(), [])
- self.assertEqual(res[3].name(), 'fd2_lyr')
- self.assertEqual(res[3].path(), ['fd2'])
+ self.assertEqual(res[3].name(), "fd2_lyr")
+ self.assertEqual(res[3].path(), ["fd2"])
def test_provider_sublayer_details_fast_scan(self):
"""
Test retrieving sublayer details from data provider metadata, using fast scan
"""
- metadata = QgsProviderRegistry.instance().providerMetadata('ogr')
+ metadata = QgsProviderRegistry.instance().providerMetadata("ogr")
# invalid uri
- res = metadata.querySublayers('', Qgis.SublayerQueryFlag.FastScan)
+ res = metadata.querySublayers("", Qgis.SublayerQueryFlag.FastScan)
self.assertFalse(res)
# not a vector
- res = metadata.querySublayers(os.path.join(TEST_DATA_DIR, 'landsat.tif'), Qgis.SublayerQueryFlag.FastScan)
+ res = metadata.querySublayers(
+ os.path.join(TEST_DATA_DIR, "landsat.tif"), Qgis.SublayerQueryFlag.FastScan
+ )
self.assertFalse(res)
# single layer vector
- res = metadata.querySublayers(os.path.join(TEST_DATA_DIR, 'lines.shp'), Qgis.SublayerQueryFlag.FastScan)
+ res = metadata.querySublayers(
+ os.path.join(TEST_DATA_DIR, "lines.shp"), Qgis.SublayerQueryFlag.FastScan
+ )
self.assertEqual(len(res), 1)
self.assertEqual(res[0].layerNumber(), 0)
self.assertEqual(res[0].name(), "lines")
- self.assertEqual(res[0].description(), '')
+ self.assertEqual(res[0].description(), "")
self.assertEqual(res[0].uri(), TEST_DATA_DIR + "/lines.shp")
self.assertEqual(res[0].providerKey(), "ogr")
self.assertEqual(res[0].type(), QgsMapLayerType.VectorLayer)
self.assertFalse(res[0].skippedContainerScan())
# geometry collection sublayers -- requires a scan to resolve geometry type
- res = metadata.querySublayers(os.path.join(TEST_DATA_DIR, 'multipatch.shp'), Qgis.SublayerQueryFlag.FastScan)
+ res = metadata.querySublayers(
+ os.path.join(TEST_DATA_DIR, "multipatch.shp"),
+ Qgis.SublayerQueryFlag.FastScan,
+ )
self.assertEqual(len(res), 1)
self.assertEqual(res[0].layerNumber(), 0)
self.assertEqual(res[0].name(), "multipatch")
- self.assertEqual(res[0].description(), '')
+ self.assertEqual(res[0].description(), "")
self.assertEqual(res[0].uri(), TEST_DATA_DIR + "/multipatch.shp")
self.assertEqual(res[0].providerKey(), "ogr")
self.assertEqual(res[0].type(), QgsMapLayerType.VectorLayer)
self.assertEqual(res[0].wkbType(), QgsWkbTypes.Type.Unknown)
- self.assertEqual(res[0].geometryColumnName(), '')
+ self.assertEqual(res[0].geometryColumnName(), "")
self.assertFalse(res[0].skippedContainerScan())
# single layer geopackage -- sublayers MUST have the layerName set on the uri,
# in case more layers are added in future to the gpkg
- res = metadata.querySublayers(os.path.join(self.temp_dir_path, 'curved_polys.gpkg'), Qgis.SublayerQueryFlag.FastScan)
+ res = metadata.querySublayers(
+ os.path.join(self.temp_dir_path, "curved_polys.gpkg"),
+ Qgis.SublayerQueryFlag.FastScan,
+ )
self.assertEqual(len(res), 1)
self.assertEqual(res[0].layerNumber(), 0)
self.assertEqual(res[0].name(), "curved_polys")
- self.assertEqual(res[0].description(), '')
+ self.assertEqual(res[0].description(), "")
self.assertEqual(res[0].uri(), self.temp_dir_path + "/curved_polys.gpkg")
self.assertEqual(res[0].providerKey(), "ogr")
self.assertEqual(res[0].type(), QgsMapLayerType.VectorLayer)
self.assertTrue(res[0].skippedContainerScan())
# geopackage with two vector layers
- res = metadata.querySublayers(os.path.join(self.temp_dir_path, "mixed_layers.gpkg"), Qgis.SublayerQueryFlag.FastScan)
+ res = metadata.querySublayers(
+ os.path.join(self.temp_dir_path, "mixed_layers.gpkg"),
+ Qgis.SublayerQueryFlag.FastScan,
+ )
self.assertEqual(len(res), 1)
self.assertEqual(res[0].layerNumber(), 0)
self.assertEqual(res[0].name(), "mixed_layers")
@@ -2461,7 +3215,10 @@ def test_provider_sublayer_details_fast_scan(self):
self.assertTrue(res[0].skippedContainerScan())
# layer with mixed geometry types - without resolving geometry types
- res = metadata.querySublayers(os.path.join(TEST_DATA_DIR, "mixed_types.TAB"), Qgis.SublayerQueryFlag.FastScan)
+ res = metadata.querySublayers(
+ os.path.join(TEST_DATA_DIR, "mixed_types.TAB"),
+ Qgis.SublayerQueryFlag.FastScan,
+ )
self.assertEqual(len(res), 1)
self.assertEqual(res[0].layerNumber(), 0)
self.assertEqual(res[0].name(), "mixed_types")
@@ -2472,7 +3229,10 @@ def test_provider_sublayer_details_fast_scan(self):
self.assertFalse(res[0].skippedContainerScan())
# spatialite
- res = metadata.querySublayers(os.path.join(TEST_DATA_DIR, "provider/spatialite.db"), Qgis.SublayerQueryFlag.FastScan)
+ res = metadata.querySublayers(
+ os.path.join(TEST_DATA_DIR, "provider/spatialite.db"),
+ Qgis.SublayerQueryFlag.FastScan,
+ )
self.assertEqual(len(res), 1)
self.assertEqual(res[0].layerNumber(), 0)
self.assertEqual(res[0].name(), "spatialite")
@@ -2483,12 +3243,17 @@ def test_provider_sublayer_details_fast_scan(self):
self.assertTrue(res[0].skippedContainerScan())
# fast scan, but for trivial type -- fast scan flag will be ignored
- res = metadata.querySublayers(os.path.join(TEST_DATA_DIR, "spreadsheet.ods"), Qgis.SublayerQueryFlag.FastScan)
+ res = metadata.querySublayers(
+ os.path.join(TEST_DATA_DIR, "spreadsheet.ods"),
+ Qgis.SublayerQueryFlag.FastScan,
+ )
self.assertEqual(len(res), 2)
self.assertEqual(res[0].layerNumber(), 0)
self.assertEqual(res[0].name(), "Sheet1")
self.assertEqual(res[0].description(), "")
- self.assertEqual(res[0].uri(), f"{TEST_DATA_DIR}/spreadsheet.ods|layername=Sheet1")
+ self.assertEqual(
+ res[0].uri(), f"{TEST_DATA_DIR}/spreadsheet.ods|layername=Sheet1"
+ )
self.assertEqual(res[0].providerKey(), "ogr")
self.assertEqual(res[0].driverName(), "ODS")
self.assertEqual(res[0].type(), QgsMapLayerType.VectorLayer)
@@ -2496,14 +3261,19 @@ def test_provider_sublayer_details_fast_scan(self):
self.assertEqual(res[1].layerNumber(), 1)
self.assertEqual(res[1].name(), "Sheet2")
self.assertEqual(res[1].description(), "")
- self.assertEqual(res[1].uri(), f"{TEST_DATA_DIR}/spreadsheet.ods|layername=Sheet2")
+ self.assertEqual(
+ res[1].uri(), f"{TEST_DATA_DIR}/spreadsheet.ods|layername=Sheet2"
+ )
self.assertEqual(res[1].providerKey(), "ogr")
self.assertEqual(res[1].driverName(), "ODS")
self.assertEqual(res[1].type(), QgsMapLayerType.VectorLayer)
self.assertFalse(res[1].skippedContainerScan())
# vector vrt
- res = metadata.querySublayers(os.path.join(TEST_DATA_DIR, "vector_vrt.vrt"), Qgis.SublayerQueryFlag.FastScan)
+ res = metadata.querySublayers(
+ os.path.join(TEST_DATA_DIR, "vector_vrt.vrt"),
+ Qgis.SublayerQueryFlag.FastScan,
+ )
self.assertEqual(len(res), 1)
self.assertEqual(res[0].layerNumber(), 0)
self.assertEqual(res[0].name(), "vector_vrt")
@@ -2514,76 +3284,126 @@ def test_provider_sublayer_details_fast_scan(self):
self.assertTrue(res[0].skippedContainerScan())
# raster vrt
- res = metadata.querySublayers(os.path.join(TEST_DATA_DIR, "/raster/hub13263.vrt"), Qgis.SublayerQueryFlag.FastScan)
+ res = metadata.querySublayers(
+ os.path.join(TEST_DATA_DIR, "/raster/hub13263.vrt"),
+ Qgis.SublayerQueryFlag.FastScan,
+ )
self.assertEqual(len(res), 0)
# metadata.xml file next to tdenv?.adf file -- this is a subcomponent of an ESRI tin layer, should not be exposed
res = metadata.querySublayers(
- os.path.join(TEST_DATA_DIR, 'esri_tin', 'metadata.xml'), Qgis.SublayerQueryFlag.FastScan)
+ os.path.join(TEST_DATA_DIR, "esri_tin", "metadata.xml"),
+ Qgis.SublayerQueryFlag.FastScan,
+ )
self.assertFalse(res)
# ESRI Arcinfo file
res = metadata.querySublayers(
- os.path.join(TEST_DATA_DIR, 'esri_coverage', 'testpolyavc'), Qgis.SublayerQueryFlag.FastScan)
+ os.path.join(TEST_DATA_DIR, "esri_coverage", "testpolyavc"),
+ Qgis.SublayerQueryFlag.FastScan,
+ )
self.assertEqual(len(res), 4)
self.assertEqual(res[0].layerNumber(), 0)
self.assertEqual(res[0].name(), "ARC")
self.assertEqual(res[0].description(), "")
- self.assertEqual(res[0].uri(), f"{os.path.join(TEST_DATA_DIR, 'esri_coverage', 'testpolyavc')}|layername=ARC")
+ self.assertEqual(
+ res[0].uri(),
+ f"{os.path.join(TEST_DATA_DIR, 'esri_coverage', 'testpolyavc')}|layername=ARC",
+ )
self.assertEqual(res[0].providerKey(), "ogr")
self.assertEqual(res[0].type(), QgsMapLayerType.VectorLayer)
self.assertFalse(res[0].skippedContainerScan())
# zip file layer vector, explicit file in zip
- res = metadata.querySublayers('/vsizip/' + TEST_DATA_DIR + '/zip/points2.zip/points.shp', Qgis.SublayerQueryFlag.FastScan)
+ res = metadata.querySublayers(
+ "/vsizip/" + TEST_DATA_DIR + "/zip/points2.zip/points.shp",
+ Qgis.SublayerQueryFlag.FastScan,
+ )
self.assertEqual(len(res), 1)
self.assertEqual(res[0].layerNumber(), 0)
self.assertEqual(res[0].name(), "points")
- self.assertEqual(res[0].description(), '')
- self.assertEqual(res[0].uri(), '/vsizip/' + TEST_DATA_DIR + "/zip/points2.zip/points.shp")
+ self.assertEqual(res[0].description(), "")
+ self.assertEqual(
+ res[0].uri(), "/vsizip/" + TEST_DATA_DIR + "/zip/points2.zip/points.shp"
+ )
self.assertEqual(res[0].providerKey(), "ogr")
self.assertEqual(res[0].type(), QgsMapLayerType.VectorLayer)
self.assertEqual(res[0].wkbType(), QgsWkbTypes.Type.Unknown)
- self.assertEqual(res[0].geometryColumnName(), '')
- options = QgsProviderSublayerDetails.LayerOptions(QgsCoordinateTransformContext())
+ self.assertEqual(res[0].geometryColumnName(), "")
+ options = QgsProviderSublayerDetails.LayerOptions(
+ QgsCoordinateTransformContext()
+ )
vl = res[0].toLayer(options)
self.assertTrue(vl.isValid())
self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.Point)
# zip file layer vector, explicit file in zip which is NOT a OGR supported source
- res = metadata.querySublayers('/vsizip/' + TEST_DATA_DIR + '/zip/points2.zip/points.qml', Qgis.SublayerQueryFlag.FastScan)
+ res = metadata.querySublayers(
+ "/vsizip/" + TEST_DATA_DIR + "/zip/points2.zip/points.qml",
+ Qgis.SublayerQueryFlag.FastScan,
+ )
self.assertEqual(len(res), 0)
def test_provider_sidecar_files_for_uri(self):
"""
Test retrieving sidecar files for uris
"""
- metadata = QgsProviderRegistry.instance().providerMetadata('ogr')
-
- self.assertEqual(metadata.sidecarFilesForUri(''), [])
- self.assertEqual(metadata.sidecarFilesForUri('/home/me/not special.doc'), [])
- self.assertEqual(metadata.sidecarFilesForUri('/home/me/special.shp'),
- ['/home/me/special.shx', '/home/me/special.dbf', '/home/me/special.sbn',
- '/home/me/special.sbx', '/home/me/special.prj', '/home/me/special.idm',
- '/home/me/special.ind', '/home/me/special.qix', '/home/me/special.cpg',
- '/home/me/special.qpj', '/home/me/special.shp.xml'])
- self.assertEqual(metadata.sidecarFilesForUri('/home/me/special.tab'),
- ['/home/me/special.dat', '/home/me/special.id', '/home/me/special.map', '/home/me/special.ind',
- '/home/me/special.tda', '/home/me/special.tin', '/home/me/special.tma',
- '/home/me/special.lda', '/home/me/special.lin', '/home/me/special.lma'])
- self.assertEqual(metadata.sidecarFilesForUri('/home/me/special.mif'),
- ['/home/me/special.mid'])
- self.assertEqual(metadata.sidecarFilesForUri('/home/me/special.gml'),
- ['/home/me/special.gfs', '/home/me/special.xsd'])
- self.assertEqual(metadata.sidecarFilesForUri('/home/me/special.csv'), ['/home/me/special.csvt'])
+ metadata = QgsProviderRegistry.instance().providerMetadata("ogr")
+
+ self.assertEqual(metadata.sidecarFilesForUri(""), [])
+ self.assertEqual(metadata.sidecarFilesForUri("/home/me/not special.doc"), [])
+ self.assertEqual(
+ metadata.sidecarFilesForUri("/home/me/special.shp"),
+ [
+ "/home/me/special.shx",
+ "/home/me/special.dbf",
+ "/home/me/special.sbn",
+ "/home/me/special.sbx",
+ "/home/me/special.prj",
+ "/home/me/special.idm",
+ "/home/me/special.ind",
+ "/home/me/special.qix",
+ "/home/me/special.cpg",
+ "/home/me/special.qpj",
+ "/home/me/special.shp.xml",
+ ],
+ )
+ self.assertEqual(
+ metadata.sidecarFilesForUri("/home/me/special.tab"),
+ [
+ "/home/me/special.dat",
+ "/home/me/special.id",
+ "/home/me/special.map",
+ "/home/me/special.ind",
+ "/home/me/special.tda",
+ "/home/me/special.tin",
+ "/home/me/special.tma",
+ "/home/me/special.lda",
+ "/home/me/special.lin",
+ "/home/me/special.lma",
+ ],
+ )
+ self.assertEqual(
+ metadata.sidecarFilesForUri("/home/me/special.mif"),
+ ["/home/me/special.mid"],
+ )
+ self.assertEqual(
+ metadata.sidecarFilesForUri("/home/me/special.gml"),
+ ["/home/me/special.gfs", "/home/me/special.xsd"],
+ )
+ self.assertEqual(
+ metadata.sidecarFilesForUri("/home/me/special.csv"),
+ ["/home/me/special.csvt"],
+ )
def testGeoJsonFieldOrder(self):
"""Test issue GH #45139"""
d = QTemporaryDir()
- json_path = os.path.join(d.path(), 'test.geojson')
- with open(json_path, 'w+') as f:
- f.write("""
+ json_path = os.path.join(d.path(), "test.geojson")
+ with open(json_path, "w+") as f:
+ f.write(
+ """
{
"type": "FeatureCollection",
"features": [
@@ -2610,70 +3430,81 @@ def testGeoJsonFieldOrder(self):
}
]
}
- """)
+ """
+ )
- vl = QgsVectorLayer(json_path, 'json')
+ vl = QgsVectorLayer(json_path, "json")
self.assertTrue(vl.isValid())
self.assertEqual(vl.featureCount(), 2)
- self.assertEqual(vl.fields().names(), ['A', 'B'])
+ self.assertEqual(vl.fields().names(), ["A", "B"])
# Append a field
self.assertTrue(vl.startEditing())
- self.assertTrue(vl.addAttribute(QgsField('C', QVariant.String)))
+ self.assertTrue(vl.addAttribute(QgsField("C", QVariant.String)))
for f in vl.getFeatures():
- vl.changeAttributeValue(f.id(), 2, 'C')
+ vl.changeAttributeValue(f.id(), 2, "C")
- self.assertEqual(vl.fields().names(), ['A', 'B', 'C'])
+ self.assertEqual(vl.fields().names(), ["A", "B", "C"])
features = [f for f in vl.getFeatures()]
- self.assertEqual(features[0].attribute('B'), NULL)
- self.assertEqual(features[0].attribute('C'), 'C')
- self.assertEqual(features[1].attribute('B'), 'B')
- self.assertEqual(features[1].attribute('C'), 'C')
+ self.assertEqual(features[0].attribute("B"), NULL)
+ self.assertEqual(features[0].attribute("C"), "C")
+ self.assertEqual(features[1].attribute("B"), "B")
+ self.assertEqual(features[1].attribute("C"), "C")
self.assertTrue(vl.commitChanges())
# This has been fixed in GDAL >= 3.4
- if int(gdal.VersionInfo('VERSION_NUM')) >= GDAL_COMPUTE_VERSION(3, 4, 0):
- self.assertEqual(vl.fields().names(), ['A', 'B', 'C'])
+ if int(gdal.VersionInfo("VERSION_NUM")) >= GDAL_COMPUTE_VERSION(3, 4, 0):
+ self.assertEqual(vl.fields().names(), ["A", "B", "C"])
else:
- self.assertEqual(vl.fields().names(), ['A', 'C', 'B'])
+ self.assertEqual(vl.fields().names(), ["A", "C", "B"])
features = [f for f in vl.getFeatures()]
- self.assertEqual(features[0].attribute('B'), NULL)
- self.assertEqual(features[0].attribute('C'), 'C')
- self.assertEqual(features[1].attribute('B'), 'B')
- self.assertEqual(features[1].attribute('C'), 'C')
+ self.assertEqual(features[0].attribute("B"), NULL)
+ self.assertEqual(features[0].attribute("C"), "C")
+ self.assertEqual(features[1].attribute("B"), "B")
+ self.assertEqual(features[1].attribute("C"), "C")
def test_provider_feature_iterator_options(self):
"""Test issue GH #45534"""
- datasource = os.path.join(self.basetestpath, 'testProviderFeatureIteratorOptions.csv')
- with open(datasource, 'w') as f:
- f.write('id,Longitude,Latitude\n')
- f.write('1,1.0,1.0\n')
- f.write('2,2.0,2.0\n')
-
- vl = QgsVectorLayer(f'{datasource}|option:X_POSSIBLE_NAMES=Longitude|option:Y_POSSIBLE_NAMES=Latitude', 'test', 'ogr')
+ datasource = os.path.join(
+ self.basetestpath, "testProviderFeatureIteratorOptions.csv"
+ )
+ with open(datasource, "w") as f:
+ f.write("id,Longitude,Latitude\n")
+ f.write("1,1.0,1.0\n")
+ f.write("2,2.0,2.0\n")
+
+ vl = QgsVectorLayer(
+ f"{datasource}|option:X_POSSIBLE_NAMES=Longitude|option:Y_POSSIBLE_NAMES=Latitude",
+ "test",
+ "ogr",
+ )
self.assertTrue(vl.isValid())
self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.Point)
f = vl.getFeature(1)
- self.assertEqual(f.geometry().asWkt(), 'Point (1 1)')
+ self.assertEqual(f.geometry().asWkt(), "Point (1 1)")
f = vl.getFeature(2)
- self.assertEqual(f.geometry().asWkt(), 'Point (2 2)')
+ self.assertEqual(f.geometry().asWkt(), "Point (2 2)")
def test_provider_dxf_3d(self):
"""Test issue GH #45938"""
- metadata = QgsProviderRegistry.instance().providerMetadata('ogr')
- layers = metadata.querySublayers(os.path.join(TEST_DATA_DIR, 'points_lines_3d.dxf'),
- Qgis.SublayerQueryFlag.ResolveGeometryType)
+ metadata = QgsProviderRegistry.instance().providerMetadata("ogr")
+ layers = metadata.querySublayers(
+ os.path.join(TEST_DATA_DIR, "points_lines_3d.dxf"),
+ Qgis.SublayerQueryFlag.ResolveGeometryType,
+ )
- options = QgsProviderSublayerDetails.LayerOptions(QgsCoordinateTransformContext())
+ options = QgsProviderSublayerDetails.LayerOptions(
+ QgsCoordinateTransformContext()
+ )
for ld in layers:
if ld.wkbType() == QgsWkbTypes.Type.PointZ:
@@ -2686,41 +3517,51 @@ def test_provider_dxf_3d(self):
feature = next(point_layer.getFeatures())
self.assertTrue(feature.isValid())
self.assertEqual(feature.geometry().wkbType(), QgsWkbTypes.Type.PointZ)
- self.assertEqual(feature.geometry().asWkt(),
- 'Point Z (635660.10747100005391985 1768912.79759799991734326 3.36980799999999991)')
+ self.assertEqual(
+ feature.geometry().asWkt(),
+ "Point Z (635660.10747100005391985 1768912.79759799991734326 3.36980799999999991)",
+ )
self.assertTrue(polyline_layer.isValid())
self.assertEqual(polyline_layer.featureCount(), 2)
feature = next(polyline_layer.getFeatures())
self.assertTrue(feature.isValid())
self.assertEqual(feature.geometry().wkbType(), QgsWkbTypes.Type.LineStringZ)
- self.assertEqual(feature.geometry().vertexAt(1).asWkt(),
- 'Point Z (635660.11699699994642287 1768910.93880999996326864 3.33884099999999995)')
+ self.assertEqual(
+ feature.geometry().vertexAt(1).asWkt(),
+ "Point Z (635660.11699699994642287 1768910.93880999996326864 3.33884099999999995)",
+ )
def test_provider_connection_shp(self):
"""
Test creating connections for OGR provider
"""
- layer = QgsVectorLayer(TEST_DATA_DIR + '/' + 'lines.shp', 'lines')
+ layer = QgsVectorLayer(TEST_DATA_DIR + "/" + "lines.shp", "lines")
- metadata = QgsProviderRegistry.instance().providerMetadata('ogr')
+ metadata = QgsProviderRegistry.instance().providerMetadata("ogr")
# start with a connection which only supports one layer
- conn = metadata.createConnection(TEST_DATA_DIR + '/' + 'lines.shp', {})
+ conn = metadata.createConnection(TEST_DATA_DIR + "/" + "lines.shp", {})
self.assertTrue(conn)
- self.assertEqual(conn.tableUri('unused', 'unused'), TEST_DATA_DIR + '/' + 'lines.shp')
+ self.assertEqual(
+ conn.tableUri("unused", "unused"), TEST_DATA_DIR + "/" + "lines.shp"
+ )
- table = conn.table('unused', 'unused')
+ table = conn.table("unused", "unused")
# not set for single layer formats
self.assertFalse(table.tableName())
self.assertFalse(table.primaryKeyColumns())
self.assertEqual(table.geometryColumnCount(), 1)
self.assertEqual(len(table.geometryColumnTypes()), 1)
self.assertEqual(table.geometryColumnTypes()[0].crs, layer.crs())
- self.assertEqual(table.geometryColumnTypes()[0].wkbType, QgsWkbTypes.Type.LineString)
- self.assertEqual(table.flags(), QgsAbstractDatabaseProviderConnection.TableFlag.Vector)
+ self.assertEqual(
+ table.geometryColumnTypes()[0].wkbType, QgsWkbTypes.Type.LineString
+ )
+ self.assertEqual(
+ table.flags(), QgsAbstractDatabaseProviderConnection.TableFlag.Vector
+ )
- tables = conn.tables('unused')
+ tables = conn.tables("unused")
self.assertEqual(len(tables), 1)
table = tables[0]
self.assertFalse(table.tableName())
@@ -2728,100 +3569,161 @@ def test_provider_connection_shp(self):
self.assertEqual(table.geometryColumnCount(), 1)
self.assertEqual(len(table.geometryColumnTypes()), 1)
self.assertEqual(table.geometryColumnTypes()[0].crs, layer.crs())
- self.assertEqual(table.geometryColumnTypes()[0].wkbType, QgsWkbTypes.Type.LineString)
- self.assertEqual(table.flags(), QgsAbstractDatabaseProviderConnection.TableFlag.Vector)
+ self.assertEqual(
+ table.geometryColumnTypes()[0].wkbType, QgsWkbTypes.Type.LineString
+ )
+ self.assertEqual(
+ table.flags(), QgsAbstractDatabaseProviderConnection.TableFlag.Vector
+ )
def test_provider_connection_gdb(self):
"""
Test creating connections for OGR provider
"""
- metadata = QgsProviderRegistry.instance().providerMetadata('ogr')
+ metadata = QgsProviderRegistry.instance().providerMetadata("ogr")
# start with a connection which only supports one layer
- conn = metadata.createConnection(TEST_DATA_DIR + '/' + 'field_alias.gdb', {})
+ conn = metadata.createConnection(TEST_DATA_DIR + "/" + "field_alias.gdb", {})
self.assertTrue(conn)
- self.assertEqual(conn.tableUri('unused', 'aliases'), TEST_DATA_DIR + '/' + 'field_alias.gdb|layername=aliases')
+ self.assertEqual(
+ conn.tableUri("unused", "aliases"),
+ TEST_DATA_DIR + "/" + "field_alias.gdb|layername=aliases",
+ )
with self.assertRaises(QgsProviderConnectionException):
- conn.table('unused', 'notpresent')
+ conn.table("unused", "notpresent")
- table = conn.table('unused', 'aliases')
- self.assertEqual(table.tableName(), 'aliases')
- self.assertEqual(table.primaryKeyColumns(), ['OBJECTID'])
+ table = conn.table("unused", "aliases")
+ self.assertEqual(table.tableName(), "aliases")
+ self.assertEqual(table.primaryKeyColumns(), ["OBJECTID"])
self.assertEqual(table.geometryColumnCount(), 1)
self.assertEqual(len(table.geometryColumnTypes()), 1)
- self.assertEqual(table.geometryColumnTypes()[0].wkbType, QgsWkbTypes.Type.MultiPolygon)
- self.assertEqual(table.flags(), QgsAbstractDatabaseProviderConnection.TableFlag.Vector)
+ self.assertEqual(
+ table.geometryColumnTypes()[0].wkbType, QgsWkbTypes.Type.MultiPolygon
+ )
+ self.assertEqual(
+ table.flags(), QgsAbstractDatabaseProviderConnection.TableFlag.Vector
+ )
# aspatial table
- table = conn.table('unused', 'fras_aux_aliases')
- self.assertEqual(table.tableName(), 'fras_aux_aliases')
- self.assertEqual(table.primaryKeyColumns(), ['OBJECTID'])
+ table = conn.table("unused", "fras_aux_aliases")
+ self.assertEqual(table.tableName(), "fras_aux_aliases")
+ self.assertEqual(table.primaryKeyColumns(), ["OBJECTID"])
self.assertEqual(table.geometryColumnCount(), 0)
self.assertFalse(table.geometryColumnTypes())
- self.assertEqual(table.flags(), QgsAbstractDatabaseProviderConnection.TableFlag.Aspatial)
+ self.assertEqual(
+ table.flags(), QgsAbstractDatabaseProviderConnection.TableFlag.Aspatial
+ )
# test tables
- conn = metadata.createConnection(TEST_DATA_DIR + '/' + 'featuredataset.gdb', {})
- tables = conn.tables('unused')
+ conn = metadata.createConnection(TEST_DATA_DIR + "/" + "featuredataset.gdb", {})
+ tables = conn.tables("unused")
self.assertGreaterEqual(len(tables), 4)
- table = [t for t in tables if t.tableName() == 'fd1_lyr1'][0]
- self.assertEqual(table.tableName(), 'fd1_lyr1')
- self.assertEqual(table.primaryKeyColumns(), ['OBJECTID'])
+ table = [t for t in tables if t.tableName() == "fd1_lyr1"][0]
+ self.assertEqual(table.tableName(), "fd1_lyr1")
+ self.assertEqual(table.primaryKeyColumns(), ["OBJECTID"])
self.assertEqual(table.geometryColumnCount(), 1)
self.assertEqual(len(table.geometryColumnTypes()), 1)
self.assertEqual(table.geometryColumnTypes()[0].wkbType, QgsWkbTypes.Type.Point)
- self.assertEqual(table.flags(), QgsAbstractDatabaseProviderConnection.TableFlag.Vector)
+ self.assertEqual(
+ table.flags(), QgsAbstractDatabaseProviderConnection.TableFlag.Vector
+ )
def testCreateEmptyDatabase(self):
- """ Test creating an empty database via the provider metadata """
- metadata = QgsProviderRegistry.instance().providerMetadata('ogr')
- self.assertTrue(metadata.capabilities() & QgsProviderMetadata.ProviderMetadataCapability.CreateDatabase)
+ """Test creating an empty database via the provider metadata"""
+ metadata = QgsProviderRegistry.instance().providerMetadata("ogr")
+ self.assertTrue(
+ metadata.capabilities()
+ & QgsProviderMetadata.ProviderMetadataCapability.CreateDatabase
+ )
# empty path should error out
- ok, err = metadata.createDatabase('')
+ ok, err = metadata.createDatabase("")
self.assertFalse(ok)
self.assertTrue(err)
# invalid driver should error out
- ok, err = metadata.createDatabase('aaa.xyz')
+ ok, err = metadata.createDatabase("aaa.xyz")
self.assertFalse(ok)
self.assertTrue(err)
# non-database driver should error out
- ok, err = metadata.createDatabase('aaa.tif')
+ ok, err = metadata.createDatabase("aaa.tif")
self.assertFalse(ok)
self.assertTrue(err)
- @unittest.skipIf(int(gdal.VersionInfo('VERSION_NUM')) < GDAL_COMPUTE_VERSION(3, 6, 0), "GDAL 3.6 required")
+ @unittest.skipIf(
+ int(gdal.VersionInfo("VERSION_NUM")) < GDAL_COMPUTE_VERSION(3, 6, 0),
+ "GDAL 3.6 required",
+ )
def testDiscoverRelationships(self):
- table1 = QgsVectorLayer(TEST_DATA_DIR + '/' + 'relationships.gdb|layerName=table1')
+ table1 = QgsVectorLayer(
+ TEST_DATA_DIR + "/" + "relationships.gdb|layerName=table1"
+ )
self.assertTrue(table1.isValid())
- table2 = QgsVectorLayer(TEST_DATA_DIR + '/' + 'relationships.gdb|layerName=table2')
+ table2 = QgsVectorLayer(
+ TEST_DATA_DIR + "/" + "relationships.gdb|layerName=table2"
+ )
self.assertTrue(table2.isValid())
- table3 = QgsVectorLayer(TEST_DATA_DIR + '/' + 'relationships.gdb|layerName=table3')
+ table3 = QgsVectorLayer(
+ TEST_DATA_DIR + "/" + "relationships.gdb|layerName=table3"
+ )
self.assertTrue(table3.isValid())
- table4 = QgsVectorLayer(TEST_DATA_DIR + '/' + 'relationships.gdb|layerName=table4')
+ table4 = QgsVectorLayer(
+ TEST_DATA_DIR + "/" + "relationships.gdb|layerName=table4"
+ )
self.assertTrue(table4.isValid())
- table6 = QgsVectorLayer(TEST_DATA_DIR + '/' + 'relationships.gdb|layerName=table6')
+ table6 = QgsVectorLayer(
+ TEST_DATA_DIR + "/" + "relationships.gdb|layerName=table6"
+ )
self.assertTrue(table6.isValid())
- table7 = QgsVectorLayer(TEST_DATA_DIR + '/' + 'relationships.gdb|layerName=table7')
+ table7 = QgsVectorLayer(
+ TEST_DATA_DIR + "/" + "relationships.gdb|layerName=table7"
+ )
self.assertTrue(table7.isValid())
- table8 = QgsVectorLayer(TEST_DATA_DIR + '/' + 'relationships.gdb|layerName=table8')
+ table8 = QgsVectorLayer(
+ TEST_DATA_DIR + "/" + "relationships.gdb|layerName=table8"
+ )
self.assertTrue(table8.isValid())
- table9 = QgsVectorLayer(TEST_DATA_DIR + '/' + 'relationships.gdb|layerName=table9')
+ table9 = QgsVectorLayer(
+ TEST_DATA_DIR + "/" + "relationships.gdb|layerName=table9"
+ )
self.assertTrue(table9.isValid())
- composite_many_to_many = QgsVectorLayer(TEST_DATA_DIR + '/' + 'relationships.gdb|layerName=composite_many_to_many')
+ composite_many_to_many = QgsVectorLayer(
+ TEST_DATA_DIR + "/" + "relationships.gdb|layerName=composite_many_to_many"
+ )
self.assertTrue(composite_many_to_many.isValid())
- points = QgsVectorLayer(TEST_DATA_DIR + '/' + 'relationships.gdb|layerName=points')
+ points = QgsVectorLayer(
+ TEST_DATA_DIR + "/" + "relationships.gdb|layerName=points"
+ )
self.assertTrue(points.isValid())
- points__ATTACH = QgsVectorLayer(TEST_DATA_DIR + '/' + 'relationships.gdb|layerName=points__ATTACH')
+ points__ATTACH = QgsVectorLayer(
+ TEST_DATA_DIR + "/" + "relationships.gdb|layerName=points__ATTACH"
+ )
self.assertTrue(points__ATTACH.isValid())
- simple_attributed = QgsVectorLayer(TEST_DATA_DIR + '/' + 'relationships.gdb|layerName=simple_attributed')
+ simple_attributed = QgsVectorLayer(
+ TEST_DATA_DIR + "/" + "relationships.gdb|layerName=simple_attributed"
+ )
self.assertTrue(simple_attributed.isValid())
- simple_many_to_many = QgsVectorLayer(TEST_DATA_DIR + '/' + 'relationships.gdb|layerName=simple_many_to_many')
+ simple_many_to_many = QgsVectorLayer(
+ TEST_DATA_DIR + "/" + "relationships.gdb|layerName=simple_many_to_many"
+ )
self.assertTrue(simple_many_to_many.isValid())
- all_tables = [table1, table2, table3, table4, table6, table7, table8, table9, composite_many_to_many, points, points__ATTACH, simple_attributed, simple_many_to_many]
+ all_tables = [
+ table1,
+ table2,
+ table3,
+ table4,
+ table6,
+ table7,
+ table8,
+ table9,
+ composite_many_to_many,
+ points,
+ points__ATTACH,
+ simple_attributed,
+ simple_many_to_many,
+ ]
for table in all_tables:
QgsProject.instance().addMapLayer(table)
@@ -2830,249 +3732,404 @@ def testDiscoverRelationships(self):
self.assertFalse(relations)
relations = table1.dataProvider().discoverRelations(table1, all_tables)
- self.assertCountEqual([r.id() for r in relations], ['composite_one_to_one', 'simple_many_to_many_forward', 'simple_many_to_many_backward', 'simple_one_to_many', 'simple_relationship_one_to_one'])
- rel = [r for r in relations if r.name() == 'simple_relationship_one_to_one'][0]
- self.assertEqual(rel.id(), 'simple_relationship_one_to_one')
+ self.assertCountEqual(
+ [r.id() for r in relations],
+ [
+ "composite_one_to_one",
+ "simple_many_to_many_forward",
+ "simple_many_to_many_backward",
+ "simple_one_to_many",
+ "simple_relationship_one_to_one",
+ ],
+ )
+ rel = [r for r in relations if r.name() == "simple_relationship_one_to_one"][0]
+ self.assertEqual(rel.id(), "simple_relationship_one_to_one")
self.assertEqual(rel.referencedLayer(), table1)
self.assertEqual(rel.referencingLayer(), table2)
self.assertEqual(rel.strength(), QgsRelation.RelationStrength.Association)
- self.assertEqual(rel.fieldPairs(), {'parent_pk': 'pk'})
+ self.assertEqual(rel.fieldPairs(), {"parent_pk": "pk"})
- rel = [r for r in relations if r.name() == 'simple_one_to_many'][0]
- self.assertEqual(rel.id(), 'simple_one_to_many')
+ rel = [r for r in relations if r.name() == "simple_one_to_many"][0]
+ self.assertEqual(rel.id(), "simple_one_to_many")
self.assertEqual(rel.referencedLayer(), table1)
self.assertEqual(rel.referencingLayer(), table2)
self.assertEqual(rel.strength(), QgsRelation.RelationStrength.Association)
- self.assertEqual(rel.fieldPairs(), {'parent_pk': 'pk'})
+ self.assertEqual(rel.fieldPairs(), {"parent_pk": "pk"})
- rel = [r for r in relations if r.name() == 'composite_one_to_one'][0]
- self.assertEqual(rel.id(), 'composite_one_to_one')
+ rel = [r for r in relations if r.name() == "composite_one_to_one"][0]
+ self.assertEqual(rel.id(), "composite_one_to_one")
self.assertEqual(rel.referencedLayer(), table1)
self.assertEqual(rel.referencingLayer(), table3)
self.assertEqual(rel.strength(), QgsRelation.RelationStrength.Composition)
- self.assertEqual(rel.fieldPairs(), {'parent_pk': 'pk'})
+ self.assertEqual(rel.fieldPairs(), {"parent_pk": "pk"})
- rel = [r for r in relations if r.id() == 'simple_many_to_many_forward'][0]
- self.assertEqual(rel.name(), 'simple_many_to_many')
- self.assertEqual(rel.id(), 'simple_many_to_many_forward')
+ rel = [r for r in relations if r.id() == "simple_many_to_many_forward"][0]
+ self.assertEqual(rel.name(), "simple_many_to_many")
+ self.assertEqual(rel.id(), "simple_many_to_many_forward")
self.assertEqual(rel.referencedLayer(), table1)
self.assertEqual(rel.referencingLayer(), simple_many_to_many)
self.assertEqual(rel.strength(), QgsRelation.RelationStrength.Association)
- self.assertEqual(rel.fieldPairs(), {'origin_foreign_key': 'pk'})
+ self.assertEqual(rel.fieldPairs(), {"origin_foreign_key": "pk"})
- rel = [r for r in relations if r.id() == 'simple_many_to_many_backward'][0]
- self.assertEqual(rel.name(), 'simple_many_to_many')
- self.assertEqual(rel.id(), 'simple_many_to_many_backward')
+ rel = [r for r in relations if r.id() == "simple_many_to_many_backward"][0]
+ self.assertEqual(rel.name(), "simple_many_to_many")
+ self.assertEqual(rel.id(), "simple_many_to_many_backward")
self.assertEqual(rel.referencedLayer(), table2)
self.assertEqual(rel.referencingLayer(), simple_many_to_many)
self.assertEqual(rel.strength(), QgsRelation.RelationStrength.Association)
- self.assertEqual(rel.fieldPairs(), {'destination_foreign_key': 'parent_pk'})
+ self.assertEqual(rel.fieldPairs(), {"destination_foreign_key": "parent_pk"})
relations = table6.dataProvider().discoverRelations(table6, all_tables)
- self.assertCountEqual([r.id() for r in relations],
- ['composite_many_to_many_forward', 'composite_many_to_many_backward'])
- rel = [r for r in relations if r.id() == 'composite_many_to_many_forward'][0]
- self.assertEqual(rel.id(), 'composite_many_to_many_forward')
+ self.assertCountEqual(
+ [r.id() for r in relations],
+ ["composite_many_to_many_forward", "composite_many_to_many_backward"],
+ )
+ rel = [r for r in relations if r.id() == "composite_many_to_many_forward"][0]
+ self.assertEqual(rel.id(), "composite_many_to_many_forward")
self.assertEqual(rel.referencedLayer(), table6)
self.assertEqual(rel.referencingLayer(), composite_many_to_many)
self.assertEqual(rel.strength(), QgsRelation.RelationStrength.Composition)
- self.assertEqual(rel.fieldPairs(), {'origin_foreign_key': 'pk'})
+ self.assertEqual(rel.fieldPairs(), {"origin_foreign_key": "pk"})
- rel = [r for r in relations if r.id() == 'composite_many_to_many_backward'][0]
- self.assertEqual(rel.id(), 'composite_many_to_many_backward')
+ rel = [r for r in relations if r.id() == "composite_many_to_many_backward"][0]
+ self.assertEqual(rel.id(), "composite_many_to_many_backward")
self.assertEqual(rel.referencedLayer(), table7)
self.assertEqual(rel.referencingLayer(), composite_many_to_many)
self.assertEqual(rel.strength(), QgsRelation.RelationStrength.Composition)
- self.assertEqual(rel.fieldPairs(), {'dest_foreign_key': 'parent_pk'})
+ self.assertEqual(rel.fieldPairs(), {"dest_foreign_key": "parent_pk"})
relations = table8.dataProvider().discoverRelations(table8, all_tables)
- self.assertCountEqual([r.id() for r in relations],
- ['simple_attributed', 'simple_backward_message_direction', 'simple_both_message_direction', 'simple_forward_message_direction'])
- rel = [r for r in relations if r.id() == 'simple_attributed'][0]
- self.assertEqual(rel.id(), 'simple_attributed')
+ self.assertCountEqual(
+ [r.id() for r in relations],
+ [
+ "simple_attributed",
+ "simple_backward_message_direction",
+ "simple_both_message_direction",
+ "simple_forward_message_direction",
+ ],
+ )
+ rel = [r for r in relations if r.id() == "simple_attributed"][0]
+ self.assertEqual(rel.id(), "simple_attributed")
self.assertEqual(rel.referencedLayer(), table8)
self.assertEqual(rel.referencingLayer(), table9)
self.assertEqual(rel.strength(), QgsRelation.RelationStrength.Association)
- self.assertEqual(rel.fieldPairs(), {'parent_pk': 'pk'})
+ self.assertEqual(rel.fieldPairs(), {"parent_pk": "pk"})
relations = points.dataProvider().discoverRelations(points, all_tables)
- self.assertCountEqual([r.id() for r in relations],
- ['points__ATTACHREL'])
- rel = [r for r in relations if r.id() == 'points__ATTACHREL'][0]
- self.assertEqual(rel.id(), 'points__ATTACHREL')
+ self.assertCountEqual([r.id() for r in relations], ["points__ATTACHREL"])
+ rel = [r for r in relations if r.id() == "points__ATTACHREL"][0]
+ self.assertEqual(rel.id(), "points__ATTACHREL")
self.assertEqual(rel.referencedLayer(), points)
self.assertEqual(rel.referencingLayer(), points__ATTACH)
self.assertEqual(rel.strength(), QgsRelation.RelationStrength.Composition)
- self.assertEqual(rel.fieldPairs(), {'REL_OBJECTID': 'OBJECTID'})
+ self.assertEqual(rel.fieldPairs(), {"REL_OBJECTID": "OBJECTID"})
def test_provider_connection_tables(self):
"""
Test retrieving tables via the connections API
"""
- metadata = QgsProviderRegistry.instance().providerMetadata('ogr')
+ metadata = QgsProviderRegistry.instance().providerMetadata("ogr")
# start with a connection which only supports one layer
- conn = metadata.createConnection(TEST_DATA_DIR + '/' + 'relationships.gdb', {})
+ conn = metadata.createConnection(TEST_DATA_DIR + "/" + "relationships.gdb", {})
self.assertTrue(conn)
# don't want system tables included
- self.assertCountEqual([t.tableName() for t in conn.tables()],
- ['table1', 'table2', 'table3', 'table4', 'table6', 'table7',
- 'table8', 'table9', 'points', 'points__ATTACH',
- 'composite_many_to_many', 'simple_attributed',
- 'simple_many_to_many'])
+ self.assertCountEqual(
+ [t.tableName() for t in conn.tables()],
+ [
+ "table1",
+ "table2",
+ "table3",
+ "table4",
+ "table6",
+ "table7",
+ "table8",
+ "table9",
+ "points",
+ "points__ATTACH",
+ "composite_many_to_many",
+ "simple_attributed",
+ "simple_many_to_many",
+ ],
+ )
# DO want system tables included
- self.assertCountEqual([t.tableName() for t in conn.tables('',
- QgsAbstractDatabaseProviderConnection.TableFlag.Aspatial | QgsAbstractDatabaseProviderConnection.TableFlag.Vector | QgsAbstractDatabaseProviderConnection.TableFlag.IncludeSystemTables)],
- ['table1', 'table2', 'table3', 'table4', 'table6', 'table7',
- 'table8', 'table9', 'points', 'points__ATTACH',
- 'composite_many_to_many', 'simple_attributed',
- 'simple_many_to_many', 'GDB_DBTune', 'GDB_ItemRelationshipTypes',
- 'GDB_ItemRelationships', 'GDB_ItemTypes', 'GDB_Items',
- 'GDB_SpatialRefs', 'GDB_SystemCatalog'])
+ self.assertCountEqual(
+ [
+ t.tableName()
+ for t in conn.tables(
+ "",
+ QgsAbstractDatabaseProviderConnection.TableFlag.Aspatial
+ | QgsAbstractDatabaseProviderConnection.TableFlag.Vector
+ | QgsAbstractDatabaseProviderConnection.TableFlag.IncludeSystemTables,
+ )
+ ],
+ [
+ "table1",
+ "table2",
+ "table3",
+ "table4",
+ "table6",
+ "table7",
+ "table8",
+ "table9",
+ "points",
+ "points__ATTACH",
+ "composite_many_to_many",
+ "simple_attributed",
+ "simple_many_to_many",
+ "GDB_DBTune",
+ "GDB_ItemRelationshipTypes",
+ "GDB_ItemRelationships",
+ "GDB_ItemTypes",
+ "GDB_Items",
+ "GDB_SpatialRefs",
+ "GDB_SystemCatalog",
+ ],
+ )
def test_provider_connection_illegal_fields(self):
"""
Test retrieving illegal field names via the connections API
"""
- metadata = QgsProviderRegistry.instance().providerMetadata('ogr')
+ metadata = QgsProviderRegistry.instance().providerMetadata("ogr")
# start with a connection which only supports one layer
- conn = metadata.createConnection(TEST_DATA_DIR + '/' + 'relationships.gdb', {})
+ conn = metadata.createConnection(TEST_DATA_DIR + "/" + "relationships.gdb", {})
self.assertTrue(conn)
- self.assertEqual(conn.illegalFieldNames(),
- {'ALTER', 'NULL', 'UPDATE', 'LIKE', 'FROM', 'WHERE', 'INSERT', 'CREATE',
- 'EXISTS', 'ORDER', 'DROP', 'TABLE', 'BETWEEN', 'SELECT', 'FOR', 'ADD',
- 'IS', 'GROUP', 'COLUMN', 'DELETE', 'VALUES', 'IN', 'NOT', 'BY', 'OR',
- 'INTO', 'AND', 'SET'})
+ self.assertEqual(
+ conn.illegalFieldNames(),
+ {
+ "ALTER",
+ "NULL",
+ "UPDATE",
+ "LIKE",
+ "FROM",
+ "WHERE",
+ "INSERT",
+ "CREATE",
+ "EXISTS",
+ "ORDER",
+ "DROP",
+ "TABLE",
+ "BETWEEN",
+ "SELECT",
+ "FOR",
+ "ADD",
+ "IS",
+ "GROUP",
+ "COLUMN",
+ "DELETE",
+ "VALUES",
+ "IN",
+ "NOT",
+ "BY",
+ "OR",
+ "INTO",
+ "AND",
+ "SET",
+ },
+ )
def test_provider_related_table_types(self):
"""
Test retrieving related table types
"""
- metadata = QgsProviderRegistry.instance().providerMetadata('ogr')
+ metadata = QgsProviderRegistry.instance().providerMetadata("ogr")
# GDB
- conn = metadata.createConnection(TEST_DATA_DIR + '/' + 'relationships.gdb', {})
- self.assertCountEqual(conn.relatedTableTypes(), ['media', 'features'])
+ conn = metadata.createConnection(TEST_DATA_DIR + "/" + "relationships.gdb", {})
+ self.assertCountEqual(conn.relatedTableTypes(), ["media", "features"])
# GPKG
- conn = metadata.createConnection(self.temp_dir_path + '/' + 'domains.gpkg', {})
- self.assertCountEqual(conn.relatedTableTypes(), ['media', 'features', 'simple_attributes', 'attributes', 'tiles'])
+ conn = metadata.createConnection(self.temp_dir_path + "/" + "domains.gpkg", {})
+ self.assertCountEqual(
+ conn.relatedTableTypes(),
+ ["media", "features", "simple_attributes", "attributes", "tiles"],
+ )
# other (not supported)
- conn = metadata.createConnection(TEST_DATA_DIR + '/' + 'lines.shp', {})
+ conn = metadata.createConnection(TEST_DATA_DIR + "/" + "lines.shp", {})
self.assertEqual(conn.relatedTableTypes(), [])
- @unittest.skipIf(int(gdal.VersionInfo('VERSION_NUM')) < GDAL_COMPUTE_VERSION(3, 6, 0), "GDAL 3.6 required")
+ @unittest.skipIf(
+ int(gdal.VersionInfo("VERSION_NUM")) < GDAL_COMPUTE_VERSION(3, 6, 0),
+ "GDAL 3.6 required",
+ )
def test_provider_relationship_capabilities(self):
"""
Test retrieving relationship capabilities
"""
- metadata = QgsProviderRegistry.instance().providerMetadata('ogr')
+ metadata = QgsProviderRegistry.instance().providerMetadata("ogr")
# GDB
- conn = metadata.createConnection(TEST_DATA_DIR + '/' + 'relationships.gdb', {})
- self.assertCountEqual(conn.supportedRelationshipCardinalities(), [Qgis.RelationshipCardinality.OneToMany, Qgis.RelationshipCardinality.ManyToMany, Qgis.RelationshipCardinality.OneToOne])
- self.assertCountEqual(conn.supportedRelationshipStrengths(), [Qgis.RelationshipStrength.Composition, Qgis.RelationshipStrength.Association])
- self.assertEqual(conn.supportedRelationshipCapabilities(), Qgis.RelationshipCapabilities(Qgis.RelationshipCapability.ForwardPathLabel | Qgis.RelationshipCapability.BackwardPathLabel))
+ conn = metadata.createConnection(TEST_DATA_DIR + "/" + "relationships.gdb", {})
+ self.assertCountEqual(
+ conn.supportedRelationshipCardinalities(),
+ [
+ Qgis.RelationshipCardinality.OneToMany,
+ Qgis.RelationshipCardinality.ManyToMany,
+ Qgis.RelationshipCardinality.OneToOne,
+ ],
+ )
+ self.assertCountEqual(
+ conn.supportedRelationshipStrengths(),
+ [
+ Qgis.RelationshipStrength.Composition,
+ Qgis.RelationshipStrength.Association,
+ ],
+ )
+ self.assertEqual(
+ conn.supportedRelationshipCapabilities(),
+ Qgis.RelationshipCapabilities(
+ Qgis.RelationshipCapability.ForwardPathLabel
+ | Qgis.RelationshipCapability.BackwardPathLabel
+ ),
+ )
# GPKG
- conn = metadata.createConnection(self.temp_dir_path + '/' + 'domains.gpkg', {})
- self.assertCountEqual(conn.supportedRelationshipCardinalities(), [Qgis.RelationshipCardinality.ManyToMany])
- self.assertCountEqual(conn.supportedRelationshipStrengths(), [Qgis.RelationshipStrength.Association])
- self.assertEqual(conn.supportedRelationshipCapabilities(), Qgis.RelationshipCapabilities())
+ conn = metadata.createConnection(self.temp_dir_path + "/" + "domains.gpkg", {})
+ self.assertCountEqual(
+ conn.supportedRelationshipCardinalities(),
+ [Qgis.RelationshipCardinality.ManyToMany],
+ )
+ self.assertCountEqual(
+ conn.supportedRelationshipStrengths(),
+ [Qgis.RelationshipStrength.Association],
+ )
+ self.assertEqual(
+ conn.supportedRelationshipCapabilities(), Qgis.RelationshipCapabilities()
+ )
# other (not supported)
- conn = metadata.createConnection(TEST_DATA_DIR + '/' + 'lines.shp', {})
+ conn = metadata.createConnection(TEST_DATA_DIR + "/" + "lines.shp", {})
self.assertCountEqual(conn.supportedRelationshipCardinalities(), [])
self.assertCountEqual(conn.supportedRelationshipStrengths(), [])
- self.assertEqual(conn.supportedRelationshipCapabilities(), Qgis.RelationshipCapabilities())
+ self.assertEqual(
+ conn.supportedRelationshipCapabilities(), Qgis.RelationshipCapabilities()
+ )
- @unittest.skipIf(int(gdal.VersionInfo('VERSION_NUM')) < GDAL_COMPUTE_VERSION(3, 6, 0), "GDAL 3.6 required")
+ @unittest.skipIf(
+ int(gdal.VersionInfo("VERSION_NUM")) < GDAL_COMPUTE_VERSION(3, 6, 0),
+ "GDAL 3.6 required",
+ )
def test_provider_connection_relationships(self):
"""
Test retrieving relationships via the connections API
"""
- metadata = QgsProviderRegistry.instance().providerMetadata('ogr')
+ metadata = QgsProviderRegistry.instance().providerMetadata("ogr")
# start with a connection which only supports one layer
- conn = metadata.createConnection(TEST_DATA_DIR + '/' + 'relationships.gdb', {})
+ conn = metadata.createConnection(TEST_DATA_DIR + "/" + "relationships.gdb", {})
self.assertTrue(conn)
- self.assertTrue(conn.capabilities() & QgsAbstractDatabaseProviderConnection.Capability.RetrieveRelationships)
+ self.assertTrue(
+ conn.capabilities()
+ & QgsAbstractDatabaseProviderConnection.Capability.RetrieveRelationships
+ )
relationships = conn.relationships()
- self.assertCountEqual([r.id() for r in relationships],
- ['composite_many_to_many',
- 'composite_one_to_many',
- 'composite_one_to_one',
- 'points__ATTACHREL',
- 'simple_attributed',
- 'simple_backward_message_direction',
- 'simple_both_message_direction',
- 'simple_forward_message_direction',
- 'simple_many_to_many',
- 'simple_one_to_many',
- 'simple_relationship_one_to_one'])
-
- rel = [r for r in relationships if r.name() == 'simple_relationship_one_to_one'][0]
- self.assertEqual(rel.id(), 'simple_relationship_one_to_one')
- self.assertEqual(rel.referencedLayerSource(), TEST_DATA_DIR + '/' + 'relationships.gdb|layername=table1')
- self.assertEqual(rel.referencedLayerName(), 'table1')
- self.assertEqual(rel.referencedLayerProvider(), 'ogr')
- self.assertEqual(rel.referencingLayerSource(), TEST_DATA_DIR + '/' + 'relationships.gdb|layername=table2')
- self.assertEqual(rel.referencingLayerProvider(), 'ogr')
- self.assertEqual(rel.referencingLayerName(), 'table2')
+ self.assertCountEqual(
+ [r.id() for r in relationships],
+ [
+ "composite_many_to_many",
+ "composite_one_to_many",
+ "composite_one_to_one",
+ "points__ATTACHREL",
+ "simple_attributed",
+ "simple_backward_message_direction",
+ "simple_both_message_direction",
+ "simple_forward_message_direction",
+ "simple_many_to_many",
+ "simple_one_to_many",
+ "simple_relationship_one_to_one",
+ ],
+ )
+
+ rel = [
+ r for r in relationships if r.name() == "simple_relationship_one_to_one"
+ ][0]
+ self.assertEqual(rel.id(), "simple_relationship_one_to_one")
+ self.assertEqual(
+ rel.referencedLayerSource(),
+ TEST_DATA_DIR + "/" + "relationships.gdb|layername=table1",
+ )
+ self.assertEqual(rel.referencedLayerName(), "table1")
+ self.assertEqual(rel.referencedLayerProvider(), "ogr")
+ self.assertEqual(
+ rel.referencingLayerSource(),
+ TEST_DATA_DIR + "/" + "relationships.gdb|layername=table2",
+ )
+ self.assertEqual(rel.referencingLayerProvider(), "ogr")
+ self.assertEqual(rel.referencingLayerName(), "table2")
self.assertEqual(rel.strength(), QgsRelation.RelationStrength.Association)
- self.assertEqual(rel.referencingLayerFields(), ['parent_pk'])
- self.assertEqual(rel.referencedLayerFields(), ['pk'])
+ self.assertEqual(rel.referencingLayerFields(), ["parent_pk"])
+ self.assertEqual(rel.referencedLayerFields(), ["pk"])
self.assertEqual(rel.cardinality(), Qgis.RelationshipCardinality.OneToOne)
- self.assertEqual(rel.forwardPathLabel(), 'my forward path label')
- self.assertEqual(rel.backwardPathLabel(), 'my backward path label')
+ self.assertEqual(rel.forwardPathLabel(), "my forward path label")
+ self.assertEqual(rel.backwardPathLabel(), "my backward path label")
# result depends on gdal version
- self.assertIn(rel.relatedTableType(), ('feature', 'features'))
-
- rel = [r for r in relationships if r.id() == 'composite_many_to_many'][0]
- self.assertEqual(rel.id(), 'composite_many_to_many')
- self.assertEqual(rel.name(), 'composite_many_to_many')
- self.assertEqual(rel.referencedLayerSource(), TEST_DATA_DIR + '/' + 'relationships.gdb|layername=table6')
- self.assertEqual(rel.referencedLayerProvider(), 'ogr')
- self.assertEqual(rel.referencedLayerName(), 'table6')
- self.assertEqual(rel.referencingLayerSource(), TEST_DATA_DIR + '/' + 'relationships.gdb|layername=table7')
- self.assertEqual(rel.referencingLayerProvider(), 'ogr')
- self.assertEqual(rel.referencingLayerName(), 'table7')
- self.assertEqual(rel.mappingTableSource(), TEST_DATA_DIR + '/' + 'relationships.gdb|layername=composite_many_to_many')
- self.assertEqual(rel.mappingTableProvider(), 'ogr')
- self.assertEqual(rel.mappingTableName(), 'composite_many_to_many')
+ self.assertIn(rel.relatedTableType(), ("feature", "features"))
+
+ rel = [r for r in relationships if r.id() == "composite_many_to_many"][0]
+ self.assertEqual(rel.id(), "composite_many_to_many")
+ self.assertEqual(rel.name(), "composite_many_to_many")
+ self.assertEqual(
+ rel.referencedLayerSource(),
+ TEST_DATA_DIR + "/" + "relationships.gdb|layername=table6",
+ )
+ self.assertEqual(rel.referencedLayerProvider(), "ogr")
+ self.assertEqual(rel.referencedLayerName(), "table6")
+ self.assertEqual(
+ rel.referencingLayerSource(),
+ TEST_DATA_DIR + "/" + "relationships.gdb|layername=table7",
+ )
+ self.assertEqual(rel.referencingLayerProvider(), "ogr")
+ self.assertEqual(rel.referencingLayerName(), "table7")
+ self.assertEqual(
+ rel.mappingTableSource(),
+ TEST_DATA_DIR + "/" + "relationships.gdb|layername=composite_many_to_many",
+ )
+ self.assertEqual(rel.mappingTableProvider(), "ogr")
+ self.assertEqual(rel.mappingTableName(), "composite_many_to_many")
self.assertEqual(rel.strength(), QgsRelation.RelationStrength.Composition)
self.assertEqual(rel.cardinality(), Qgis.RelationshipCardinality.ManyToMany)
- self.assertEqual(rel.referencingLayerFields(), ['parent_pk'])
- self.assertEqual(rel.mappingReferencingLayerFields(), ['dest_foreign_key'])
- self.assertEqual(rel.referencedLayerFields(), ['pk'])
- self.assertEqual(rel.mappingReferencedLayerFields(), ['origin_foreign_key'])
+ self.assertEqual(rel.referencingLayerFields(), ["parent_pk"])
+ self.assertEqual(rel.mappingReferencingLayerFields(), ["dest_foreign_key"])
+ self.assertEqual(rel.referencedLayerFields(), ["pk"])
+ self.assertEqual(rel.mappingReferencedLayerFields(), ["origin_foreign_key"])
# with table filter
- relationships = conn.relationships('', 'table5')
- self.assertCountEqual([r.id() for r in relationships],
- ['composite_one_to_many'])
-
- rel = [r for r in relationships if r.name() == 'composite_one_to_many'][0]
- self.assertEqual(rel.id(), 'composite_one_to_many')
- self.assertEqual(rel.referencedLayerSource(), TEST_DATA_DIR + '/' + 'relationships.gdb|layername=table5')
- self.assertEqual(rel.referencedLayerProvider(), 'ogr')
- self.assertEqual(rel.referencingLayerSource(), TEST_DATA_DIR + '/' + 'relationships.gdb|layername=table4')
- self.assertEqual(rel.referencingLayerProvider(), 'ogr')
+ relationships = conn.relationships("", "table5")
+ self.assertCountEqual(
+ [r.id() for r in relationships], ["composite_one_to_many"]
+ )
+
+ rel = [r for r in relationships if r.name() == "composite_one_to_many"][0]
+ self.assertEqual(rel.id(), "composite_one_to_many")
+ self.assertEqual(
+ rel.referencedLayerSource(),
+ TEST_DATA_DIR + "/" + "relationships.gdb|layername=table5",
+ )
+ self.assertEqual(rel.referencedLayerProvider(), "ogr")
+ self.assertEqual(
+ rel.referencingLayerSource(),
+ TEST_DATA_DIR + "/" + "relationships.gdb|layername=table4",
+ )
+ self.assertEqual(rel.referencingLayerProvider(), "ogr")
self.assertEqual(rel.strength(), QgsRelation.RelationStrength.Composition)
self.assertEqual(rel.cardinality(), Qgis.RelationshipCardinality.OneToMany)
- self.assertEqual(rel.referencingLayerFields(), ['parent_pk'])
- self.assertEqual(rel.referencedLayerFields(), ['pk'])
+ self.assertEqual(rel.referencingLayerFields(), ["parent_pk"])
+ self.assertEqual(rel.referencedLayerFields(), ["pk"])
- relationships = conn.relationships('', 'table2')
+ relationships = conn.relationships("", "table2")
self.assertFalse(relationships)
- @unittest.skipIf(int(gdal.VersionInfo('VERSION_NUM')) < GDAL_COMPUTE_VERSION(3, 6, 0), "GDAL 3.6 required")
+ @unittest.skipIf(
+ int(gdal.VersionInfo("VERSION_NUM")) < GDAL_COMPUTE_VERSION(3, 6, 0),
+ "GDAL 3.6 required",
+ )
def test_provider_connection_modify_relationship(self):
"""
Test creating relationship via the connections API
"""
- metadata = QgsProviderRegistry.instance().providerMetadata('ogr')
+ metadata = QgsProviderRegistry.instance().providerMetadata("ogr")
with tempfile.TemporaryDirectory() as temp_dir:
- tmpfile = os.path.join(temp_dir, 'test_gdb.gdb')
+ tmpfile = os.path.join(temp_dir, "test_gdb.gdb")
ok, err = metadata.createDatabase(tmpfile)
self.assertTrue(ok)
@@ -3081,75 +4138,103 @@ def test_provider_connection_modify_relationship(self):
conn = metadata.createConnection(tmpfile, {})
self.assertTrue(conn)
- conn.createVectorTable('', 'child', QgsFields(), QgsWkbTypes.Type.Point, QgsCoordinateReferenceSystem('EPSG:4326'), False, {})
- layer = QgsVectorLayer(tmpfile + '|layername=child')
+ conn.createVectorTable(
+ "",
+ "child",
+ QgsFields(),
+ QgsWkbTypes.Type.Point,
+ QgsCoordinateReferenceSystem("EPSG:4326"),
+ False,
+ {},
+ )
+ layer = QgsVectorLayer(tmpfile + "|layername=child")
self.assertTrue(layer.isValid())
- conn.createVectorTable('', 'parent', QgsFields(), QgsWkbTypes.Type.Point, QgsCoordinateReferenceSystem('EPSG:4326'), False, {})
- layer = QgsVectorLayer(tmpfile + '|layername=parent')
+ conn.createVectorTable(
+ "",
+ "parent",
+ QgsFields(),
+ QgsWkbTypes.Type.Point,
+ QgsCoordinateReferenceSystem("EPSG:4326"),
+ False,
+ {},
+ )
+ layer = QgsVectorLayer(tmpfile + "|layername=parent")
self.assertTrue(layer.isValid())
del layer
self.assertTrue(
- conn.capabilities() & QgsAbstractDatabaseProviderConnection.Capability.AddRelationship)
+ conn.capabilities()
+ & QgsAbstractDatabaseProviderConnection.Capability.AddRelationship
+ )
relationships = conn.relationships()
self.assertFalse(relationships)
- rel = QgsWeakRelation('id',
- 'rel_name',
- Qgis.RelationshipStrength.Association,
- 'referencing_id',
- 'referencing_name',
- tmpfile + '|layername=child',
- 'ogr',
- 'referenced_id',
- 'referenced_name',
- tmpfile + '|layername=parent',
- 'ogr'
- )
- rel.setReferencedLayerFields(['fielda'])
- rel.setReferencingLayerFields(['fieldb'])
+ rel = QgsWeakRelation(
+ "id",
+ "rel_name",
+ Qgis.RelationshipStrength.Association,
+ "referencing_id",
+ "referencing_name",
+ tmpfile + "|layername=child",
+ "ogr",
+ "referenced_id",
+ "referenced_name",
+ tmpfile + "|layername=parent",
+ "ogr",
+ )
+ rel.setReferencedLayerFields(["fielda"])
+ rel.setReferencingLayerFields(["fieldb"])
conn.addRelationship(rel)
relationships = conn.relationships()
self.assertEqual(len(relationships), 1)
result = relationships[0]
- self.assertEqual(result.name(), 'rel_name')
- self.assertEqual(result.referencingLayerSource(), tmpfile + '|layername=child')
- self.assertEqual(result.referencedLayerSource(), tmpfile + '|layername=parent')
- self.assertEqual(result.referencingLayerFields(), ['fieldb'])
- self.assertEqual(result.referencedLayerFields(), ['fielda'])
+ self.assertEqual(result.name(), "rel_name")
+ self.assertEqual(
+ result.referencingLayerSource(), tmpfile + "|layername=child"
+ )
+ self.assertEqual(
+ result.referencedLayerSource(), tmpfile + "|layername=parent"
+ )
+ self.assertEqual(result.referencingLayerFields(), ["fieldb"])
+ self.assertEqual(result.referencedLayerFields(), ["fielda"])
# update relationship
- rel.setReferencedLayerFields(['fieldc'])
- rel.setReferencingLayerFields(['fieldd'])
+ rel.setReferencedLayerFields(["fieldc"])
+ rel.setReferencingLayerFields(["fieldd"])
conn.updateRelationship(rel)
relationships = conn.relationships()
self.assertEqual(len(relationships), 1)
result = relationships[0]
- self.assertEqual(result.name(), 'rel_name')
- self.assertEqual(result.referencingLayerSource(), tmpfile + '|layername=child')
- self.assertEqual(result.referencedLayerSource(), tmpfile + '|layername=parent')
- self.assertEqual(result.referencingLayerFields(), ['fieldd'])
- self.assertEqual(result.referencedLayerFields(), ['fieldc'])
+ self.assertEqual(result.name(), "rel_name")
+ self.assertEqual(
+ result.referencingLayerSource(), tmpfile + "|layername=child"
+ )
+ self.assertEqual(
+ result.referencedLayerSource(), tmpfile + "|layername=parent"
+ )
+ self.assertEqual(result.referencingLayerFields(), ["fieldd"])
+ self.assertEqual(result.referencedLayerFields(), ["fieldc"])
# try updating non-existing relationship
- rel2 = QgsWeakRelation('id',
- 'nope',
- Qgis.RelationshipStrength.Association,
- 'referencing_id',
- 'referencing_name',
- tmpfile + '|layername=child',
- 'ogr',
- 'referenced_id',
- 'referenced_name',
- tmpfile + '|layername=parent',
- 'ogr'
- )
+ rel2 = QgsWeakRelation(
+ "id",
+ "nope",
+ Qgis.RelationshipStrength.Association,
+ "referencing_id",
+ "referencing_name",
+ tmpfile + "|layername=child",
+ "ogr",
+ "referenced_id",
+ "referenced_name",
+ tmpfile + "|layername=parent",
+ "ogr",
+ )
with self.assertRaises(QgsProviderConnectionException):
conn.updateRelationship(rel2)
@@ -3166,18 +4251,22 @@ def testUniqueGeometryType(self):
Test accessing a layer of type wkbUnknown that contains a single geometry type but also null geometries
"""
- datasource = os.path.join(self.basetestpath, 'testUniqueGeometryType.csv')
- with open(datasource, 'w') as f:
- f.write('id,WKT\n')
+ datasource = os.path.join(self.basetestpath, "testUniqueGeometryType.csv")
+ with open(datasource, "w") as f:
+ f.write("id,WKT\n")
f.write('1,"POINT(1 2)"\n')
- f.write('2,\n')
+ f.write("2,\n")
- metadata = QgsProviderRegistry.instance().providerMetadata('ogr')
- res = metadata.querySublayers(datasource, Qgis.SublayerQueryFlag.ResolveGeometryType)
+ metadata = QgsProviderRegistry.instance().providerMetadata("ogr")
+ res = metadata.querySublayers(
+ datasource, Qgis.SublayerQueryFlag.ResolveGeometryType
+ )
self.assertEqual(len(res), 1)
- self.assertEqual(res[0].uri(), datasource + "|geometrytype=Point|uniqueGeometryType=yes")
+ self.assertEqual(
+ res[0].uri(), datasource + "|geometrytype=Point|uniqueGeometryType=yes"
+ )
- vl = QgsVectorLayer(res[0].uri(), 'test', 'ogr')
+ vl = QgsVectorLayer(res[0].uri(), "test", "ogr")
self.assertTrue(vl.isValid())
self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.Point)
self.assertEqual(vl.featureCount(), 2)
@@ -3188,18 +4277,22 @@ def testUnknownButNoGeometry(self):
Test accessing a layer of type wkbUnknown that contains only null geometries
"""
- datasource = os.path.join(self.basetestpath, 'testUnknownButNoGeometry.csv')
- with open(datasource, 'w') as f:
- f.write('id,WKT\n')
+ datasource = os.path.join(self.basetestpath, "testUnknownButNoGeometry.csv")
+ with open(datasource, "w") as f:
+ f.write("id,WKT\n")
f.write('1,""\n')
- f.write('2,\n')
+ f.write("2,\n")
- metadata = QgsProviderRegistry.instance().providerMetadata('ogr')
- res = metadata.querySublayers(datasource, Qgis.SublayerQueryFlag.ResolveGeometryType)
+ metadata = QgsProviderRegistry.instance().providerMetadata("ogr")
+ res = metadata.querySublayers(
+ datasource, Qgis.SublayerQueryFlag.ResolveGeometryType
+ )
self.assertEqual(len(res), 1)
- self.assertEqual(res[0].uri(), datasource + "|geometrytype=None|uniqueGeometryType=yes")
+ self.assertEqual(
+ res[0].uri(), datasource + "|geometrytype=None|uniqueGeometryType=yes"
+ )
- vl = QgsVectorLayer(res[0].uri(), 'test', 'ogr')
+ vl = QgsVectorLayer(res[0].uri(), "test", "ogr")
self.assertTrue(vl.isValid())
self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.NoGeometry)
self.assertEqual(vl.featureCount(), 2)
@@ -3210,44 +4303,50 @@ def testCsvInterleavedUpdate(self):
temp_dir = QTemporaryDir()
temp_path = temp_dir.path()
- csv_path = os.path.join(temp_path, 'test.csv')
- with open(csv_path, 'w+') as f:
- f.write('fid\tname\n')
+ csv_path = os.path.join(temp_path, "test.csv")
+ with open(csv_path, "w+") as f:
+ f.write("fid\tname\n")
f.write('1\t"feat 1"\n')
f.write('2\t"feat 2"\n')
f.write('3\t"feat 3"\n')
- vl = QgsVectorLayer(csv_path, 'csv')
+ vl = QgsVectorLayer(csv_path, "csv")
self.assertTrue(vl.isValid())
self.assertEqual(vl.featureCount(), 3)
f = next(vl.getFeatures())
- self.assertEqual(f.attributes(), ['1', "feat 1"])
+ self.assertEqual(f.attributes(), ["1", "feat 1"])
self.assertTrue(vl.startEditing())
- self.assertTrue(vl.addAttribute(QgsField('newf', QVariant.String)))
- self.assertTrue(vl.changeAttributeValues(3, {2: 'fid 3'}))
- self.assertTrue(vl.changeAttributeValues(1, {2: 'fid 1'}))
- self.assertTrue(vl.changeAttributeValues(2, {2: 'fid 2'}))
+ self.assertTrue(vl.addAttribute(QgsField("newf", QVariant.String)))
+ self.assertTrue(vl.changeAttributeValues(3, {2: "fid 3"}))
+ self.assertTrue(vl.changeAttributeValues(1, {2: "fid 1"}))
+ self.assertTrue(vl.changeAttributeValues(2, {2: "fid 2"}))
self.assertTrue(vl.commitChanges())
- vl = QgsVectorLayer(csv_path, 'csv')
+ vl = QgsVectorLayer(csv_path, "csv")
self.assertTrue(vl.isValid())
self.assertEqual(vl.featureCount(), 3)
features = {f.id(): f.attributes() for f in vl.getFeatures()}
- self.assertEqual(features, {
- 1: ['1', 'feat 1', 'fid 1'],
- 2: ['2', 'feat 2', 'fid 2'],
- 3: ['3', 'feat 3', 'fid 3']
- })
+ self.assertEqual(
+ features,
+ {
+ 1: ["1", "feat 1", "fid 1"],
+ 2: ["2", "feat 2", "fid 2"],
+ 3: ["3", "feat 3", "fid 3"],
+ },
+ )
- @unittest.skipIf(int(gdal.VersionInfo('VERSION_NUM')) < GDAL_COMPUTE_VERSION(3, 7, 0), "GDAL 3.7 required")
+ @unittest.skipIf(
+ int(gdal.VersionInfo("VERSION_NUM")) < GDAL_COMPUTE_VERSION(3, 7, 0),
+ "GDAL 3.7 required",
+ )
def test_provider_connection_set_field_alias(self):
"""
Test setting field alias via the connections api
"""
- metadata = QgsProviderRegistry.instance().providerMetadata('ogr')
+ metadata = QgsProviderRegistry.instance().providerMetadata("ogr")
with tempfile.TemporaryDirectory() as temp_dir:
- tmpfile = os.path.join(temp_dir, 'test_gdb.gdb')
+ tmpfile = os.path.join(temp_dir, "test_gdb.gdb")
ok, err = metadata.createDatabase(tmpfile)
self.assertTrue(ok)
@@ -3257,37 +4356,50 @@ def test_provider_connection_set_field_alias(self):
self.assertTrue(conn)
fields = QgsFields()
- field = QgsField('my_field', QVariant.String)
+ field = QgsField("my_field", QVariant.String)
fields.append(field)
- conn.createVectorTable('', 'test', fields, QgsWkbTypes.Type.Point, QgsCoordinateReferenceSystem('EPSG:4326'), False, {})
- layer = QgsVectorLayer(tmpfile + '|layername=test')
+ conn.createVectorTable(
+ "",
+ "test",
+ fields,
+ QgsWkbTypes.Type.Point,
+ QgsCoordinateReferenceSystem("EPSG:4326"),
+ False,
+ {},
+ )
+ layer = QgsVectorLayer(tmpfile + "|layername=test")
self.assertTrue(layer.isValid())
del layer
self.assertTrue(
- conn.capabilities2() & Qgis.DatabaseProviderConnectionCapability2.SetFieldAlias)
+ conn.capabilities2()
+ & Qgis.DatabaseProviderConnectionCapability2.SetFieldAlias
+ )
# field does not exist
with self.assertRaises(QgsProviderConnectionException):
- conn.setFieldAlias('not field', '', 'test', 'my alias')
+ conn.setFieldAlias("not field", "", "test", "my alias")
- conn.setFieldAlias('my_field', '', 'test', 'my alias')
+ conn.setFieldAlias("my_field", "", "test", "my alias")
- layer = QgsVectorLayer(tmpfile + '|layername=test')
+ layer = QgsVectorLayer(tmpfile + "|layername=test")
self.assertTrue(layer.isValid())
fields = layer.fields()
- self.assertEqual(fields['my_field'].alias(), 'my alias')
+ self.assertEqual(fields["my_field"].alias(), "my alias")
- @unittest.skipIf(int(gdal.VersionInfo('VERSION_NUM')) < GDAL_COMPUTE_VERSION(3, 7, 0), "GDAL 3.7 required")
+ @unittest.skipIf(
+ int(gdal.VersionInfo("VERSION_NUM")) < GDAL_COMPUTE_VERSION(3, 7, 0),
+ "GDAL 3.7 required",
+ )
def test_provider_connection_set_field_comment(self):
"""
Test setting field comments via the connections api
"""
- metadata = QgsProviderRegistry.instance().providerMetadata('ogr')
+ metadata = QgsProviderRegistry.instance().providerMetadata("ogr")
with tempfile.TemporaryDirectory() as temp_dir:
- tmpfile = os.path.join(temp_dir, 'test_gpkg.gpkg')
+ tmpfile = os.path.join(temp_dir, "test_gpkg.gpkg")
ok, err = metadata.createDatabase(tmpfile)
self.assertTrue(ok)
@@ -3297,37 +4409,50 @@ def test_provider_connection_set_field_comment(self):
self.assertTrue(conn)
fields = QgsFields()
- field = QgsField('my_field', QVariant.String)
+ field = QgsField("my_field", QVariant.String)
fields.append(field)
- conn.createVectorTable('', 'test', fields, QgsWkbTypes.Type.Point, QgsCoordinateReferenceSystem('EPSG:4326'), False, {})
- layer = QgsVectorLayer(tmpfile + '|layername=test')
+ conn.createVectorTable(
+ "",
+ "test",
+ fields,
+ QgsWkbTypes.Type.Point,
+ QgsCoordinateReferenceSystem("EPSG:4326"),
+ False,
+ {},
+ )
+ layer = QgsVectorLayer(tmpfile + "|layername=test")
self.assertTrue(layer.isValid())
del layer
self.assertTrue(
- conn.capabilities2() & Qgis.DatabaseProviderConnectionCapability2.SetFieldComment)
+ conn.capabilities2()
+ & Qgis.DatabaseProviderConnectionCapability2.SetFieldComment
+ )
# field does not exist
with self.assertRaises(QgsProviderConnectionException):
- conn.setFieldComment('not field', '', 'test', 'my comment')
+ conn.setFieldComment("not field", "", "test", "my comment")
- conn.setFieldComment('my_field', '', 'test', 'my comment')
+ conn.setFieldComment("my_field", "", "test", "my comment")
- layer = QgsVectorLayer(tmpfile + '|layername=test')
+ layer = QgsVectorLayer(tmpfile + "|layername=test")
self.assertTrue(layer.isValid())
fields = layer.fields()
- self.assertEqual(fields['my_field'].comment(), 'my comment')
+ self.assertEqual(fields["my_field"].comment(), "my comment")
- @unittest.skipIf(int(gdal.VersionInfo('VERSION_NUM')) < GDAL_COMPUTE_VERSION(3, 7, 0), "GDAL 3.7 required")
+ @unittest.skipIf(
+ int(gdal.VersionInfo("VERSION_NUM")) < GDAL_COMPUTE_VERSION(3, 7, 0),
+ "GDAL 3.7 required",
+ )
def test_provider_set_field_alias(self):
"""
Test setting field alias via the vector data provider api
"""
- metadata = QgsProviderRegistry.instance().providerMetadata('ogr')
+ metadata = QgsProviderRegistry.instance().providerMetadata("ogr")
with tempfile.TemporaryDirectory() as temp_dir:
- tmpfile = os.path.join(temp_dir, 'test_gdb.gdb')
+ tmpfile = os.path.join(temp_dir, "test_gdb.gdb")
ok, err = metadata.createDatabase(tmpfile)
self.assertTrue(ok)
@@ -3337,41 +4462,54 @@ def test_provider_set_field_alias(self):
self.assertTrue(conn)
fields = QgsFields()
- field = QgsField('my_field', QVariant.String)
- field.setAlias('my alias')
+ field = QgsField("my_field", QVariant.String)
+ field.setAlias("my alias")
fields.append(field)
- conn.createVectorTable('', 'test', fields, QgsWkbTypes.Type.Point, QgsCoordinateReferenceSystem('EPSG:4326'), False, {})
- layer = QgsVectorLayer(tmpfile + '|layername=test')
+ conn.createVectorTable(
+ "",
+ "test",
+ fields,
+ QgsWkbTypes.Type.Point,
+ QgsCoordinateReferenceSystem("EPSG:4326"),
+ False,
+ {},
+ )
+ layer = QgsVectorLayer(tmpfile + "|layername=test")
self.assertTrue(layer.isValid())
fields = layer.fields()
- self.assertEqual(fields['my_field'].alias(), 'my alias')
+ self.assertEqual(fields["my_field"].alias(), "my alias")
self.assertTrue(
- layer.dataProvider().attributeEditCapabilities() & Qgis.VectorDataProviderAttributeEditCapability.EditAlias)
+ layer.dataProvider().attributeEditCapabilities()
+ & Qgis.VectorDataProviderAttributeEditCapability.EditAlias
+ )
- field2 = QgsField('my_field2', QVariant.String)
- field2.setAlias('my alias2')
+ field2 = QgsField("my_field2", QVariant.String)
+ field2.setAlias("my alias2")
self.assertTrue(layer.dataProvider().addAttributes([field2]))
del layer
- layer = QgsVectorLayer(tmpfile + '|layername=test')
+ layer = QgsVectorLayer(tmpfile + "|layername=test")
self.assertTrue(layer.isValid())
fields = layer.fields()
- self.assertEqual(fields['my_field'].alias(), 'my alias')
- self.assertEqual(fields['my_field2'].alias(), 'my alias2')
+ self.assertEqual(fields["my_field"].alias(), "my alias")
+ self.assertEqual(fields["my_field2"].alias(), "my alias2")
- @unittest.skipIf(int(gdal.VersionInfo('VERSION_NUM')) < GDAL_COMPUTE_VERSION(3, 7, 0), "GDAL 3.7 required")
+ @unittest.skipIf(
+ int(gdal.VersionInfo("VERSION_NUM")) < GDAL_COMPUTE_VERSION(3, 7, 0),
+ "GDAL 3.7 required",
+ )
def test_provider_set_field_comment(self):
"""
Test setting field comments via the vector data provider api
"""
- metadata = QgsProviderRegistry.instance().providerMetadata('ogr')
+ metadata = QgsProviderRegistry.instance().providerMetadata("ogr")
with tempfile.TemporaryDirectory() as temp_dir:
- tmpfile = os.path.join(temp_dir, 'test_gpkg.gpkg')
+ tmpfile = os.path.join(temp_dir, "test_gpkg.gpkg")
ok, err = metadata.createDatabase(tmpfile)
self.assertTrue(ok)
@@ -3381,42 +4519,55 @@ def test_provider_set_field_comment(self):
self.assertTrue(conn)
fields = QgsFields()
- field = QgsField('my_field', QVariant.String)
- field.setComment('my comment')
+ field = QgsField("my_field", QVariant.String)
+ field.setComment("my comment")
fields.append(field)
- conn.createVectorTable('', 'test', fields, QgsWkbTypes.Type.Point, QgsCoordinateReferenceSystem('EPSG:4326'), False, {})
- layer = QgsVectorLayer(tmpfile + '|layername=test')
+ conn.createVectorTable(
+ "",
+ "test",
+ fields,
+ QgsWkbTypes.Type.Point,
+ QgsCoordinateReferenceSystem("EPSG:4326"),
+ False,
+ {},
+ )
+ layer = QgsVectorLayer(tmpfile + "|layername=test")
self.assertTrue(layer.isValid())
fields = layer.fields()
- self.assertEqual(fields['my_field'].comment(), 'my comment')
+ self.assertEqual(fields["my_field"].comment(), "my comment")
self.assertTrue(
- layer.dataProvider().attributeEditCapabilities() & Qgis.VectorDataProviderAttributeEditCapability.EditComment)
+ layer.dataProvider().attributeEditCapabilities()
+ & Qgis.VectorDataProviderAttributeEditCapability.EditComment
+ )
- field2 = QgsField('my_field2', QVariant.String)
- field2.setComment('my comment2')
+ field2 = QgsField("my_field2", QVariant.String)
+ field2.setComment("my comment2")
self.assertTrue(layer.dataProvider().addAttributes([field2]))
del layer
- layer = QgsVectorLayer(tmpfile + '|layername=test')
+ layer = QgsVectorLayer(tmpfile + "|layername=test")
self.assertTrue(layer.isValid())
fields = layer.fields()
- self.assertEqual(fields['my_field'].comment(), 'my comment')
- self.assertEqual(fields['my_field2'].comment(), 'my comment2')
+ self.assertEqual(fields["my_field"].comment(), "my comment")
+ self.assertEqual(fields["my_field2"].comment(), "my comment2")
- @unittest.skipIf(int(gdal.VersionInfo('VERSION_NUM')) < GDAL_COMPUTE_VERSION(3, 7, 0), "GDAL 3.7.0 required")
+ @unittest.skipIf(
+ int(gdal.VersionInfo("VERSION_NUM")) < GDAL_COMPUTE_VERSION(3, 7, 0),
+ "GDAL 3.7.0 required",
+ )
def testFieldComment(self):
"""Test reading field comments"""
with tempfile.TemporaryDirectory() as dest_dir:
- database_path = os.path.join(dest_dir, 'new_gpkg.gpkg')
- ds = ogr.GetDriverByName('GPKG').CreateDataSource(database_path)
- lyr = ds.CreateLayer('test', geom_type=ogr.wkbPoint)
- lyr.CreateField(ogr.FieldDefn('field1', ogr.OFTString))
- lyr.CreateField(ogr.FieldDefn('field2', ogr.OFTString))
+ database_path = os.path.join(dest_dir, "new_gpkg.gpkg")
+ ds = ogr.GetDriverByName("GPKG").CreateDataSource(database_path)
+ lyr = ds.CreateLayer("test", geom_type=ogr.wkbPoint)
+ lyr.CreateField(ogr.FieldDefn("field1", ogr.OFTString))
+ lyr.CreateField(ogr.FieldDefn("field2", ogr.OFTString))
ds.ExecuteSQL(
"""CREATE TABLE gpkg_data_columns (
@@ -3438,60 +4589,69 @@ def testFieldComment(self):
ds = None
- vl = QgsVectorLayer(f'{database_path}|layername=test', 'test')
+ vl = QgsVectorLayer(f"{database_path}|layername=test", "test")
self.assertTrue(vl.isValid())
fields = vl.fields()
- self.assertEqual(fields[0].name(), 'fid')
+ self.assertEqual(fields[0].name(), "fid")
- self.assertEqual(fields[1].name(), 'field1')
- self.assertEqual(fields[1].comment(), 'my description')
+ self.assertEqual(fields[1].name(), "field1")
+ self.assertEqual(fields[1].comment(), "my description")
- self.assertEqual(fields[2].name(), 'field2')
- self.assertEqual(fields[2].comment(), '')
+ self.assertEqual(fields[2].name(), "field2")
+ self.assertEqual(fields[2].comment(), "")
- @unittest.skipIf(int(gdal.VersionInfo('VERSION_NUM')) < GDAL_COMPUTE_VERSION(3, 7, 0), "GDAL 3.7 required")
+ @unittest.skipIf(
+ int(gdal.VersionInfo("VERSION_NUM")) < GDAL_COMPUTE_VERSION(3, 7, 0),
+ "GDAL 3.7 required",
+ )
def test_exporter_capabilities(self):
with tempfile.TemporaryDirectory() as temp_dir:
- dest_file_name = os.path.join(temp_dir,
- 'test_gpkg.gpkg')
+ dest_file_name = os.path.join(temp_dir, "test_gpkg.gpkg")
- layer = QgsVectorLayer("point?crs=epsg:4326&field=id:integer",
- "Scratch point layer", "memory")
+ layer = QgsVectorLayer(
+ "point?crs=epsg:4326&field=id:integer", "Scratch point layer", "memory"
+ )
- exporter = QgsVectorLayerExporter(dest_file_name,
- 'ogr',
- layer.fields(),
- layer.wkbType(),
- layer.crs())
+ exporter = QgsVectorLayerExporter(
+ dest_file_name, "ogr", layer.fields(), layer.wkbType(), layer.crs()
+ )
self.assertTrue(
- exporter.attributeEditCapabilities() & Qgis.VectorDataProviderAttributeEditCapability.EditAlias)
+ exporter.attributeEditCapabilities()
+ & Qgis.VectorDataProviderAttributeEditCapability.EditAlias
+ )
self.assertTrue(
- exporter.attributeEditCapabilities() & Qgis.VectorDataProviderAttributeEditCapability.EditComment)
+ exporter.attributeEditCapabilities()
+ & Qgis.VectorDataProviderAttributeEditCapability.EditComment
+ )
- dest_file_name = os.path.join(temp_dir,
- 'test_shp.shp')
+ dest_file_name = os.path.join(temp_dir, "test_shp.shp")
- exporter = QgsVectorLayerExporter(dest_file_name,
- 'ogr',
- layer.fields(),
- layer.wkbType(),
- layer.crs())
+ exporter = QgsVectorLayerExporter(
+ dest_file_name, "ogr", layer.fields(), layer.wkbType(), layer.crs()
+ )
self.assertFalse(
- exporter.attributeEditCapabilities() & Qgis.VectorDataProviderAttributeEditCapability.EditAlias)
+ exporter.attributeEditCapabilities()
+ & Qgis.VectorDataProviderAttributeEditCapability.EditAlias
+ )
self.assertFalse(
- exporter.attributeEditCapabilities() & Qgis.VectorDataProviderAttributeEditCapability.EditComment)
+ exporter.attributeEditCapabilities()
+ & Qgis.VectorDataProviderAttributeEditCapability.EditComment
+ )
- @unittest.skipIf(int(gdal.VersionInfo('VERSION_NUM')) < GDAL_COMPUTE_VERSION(3, 7, 0), "GDAL 3.7 required")
+ @unittest.skipIf(
+ int(gdal.VersionInfo("VERSION_NUM")) < GDAL_COMPUTE_VERSION(3, 7, 0),
+ "GDAL 3.7 required",
+ )
def testGeoJsonMapType(self):
"""Test issue GH #54966: Geojson and maps attribute not working"""
temp_dir = QTemporaryDir()
temp_path = temp_dir.path()
- json_path = os.path.join(temp_path, 'test.json')
+ json_path = os.path.join(temp_path, "test.json")
data = """
{
@@ -3512,10 +4672,10 @@ def testGeoJsonMapType(self):
]
}"""
- with open(json_path, 'w+') as f:
+ with open(json_path, "w+") as f:
f.write(data)
- vl = QgsVectorLayer(json_path, 'vl')
+ vl = QgsVectorLayer(json_path, "vl")
self.assertTrue(vl.isValid())
self.assertEqual(vl.fields()[0].type(), QVariant.Map)
self.assertEqual(vl.fields()[1].type(), QVariant.List)
@@ -3525,61 +4685,74 @@ def testGeoJsonMapType(self):
self.assertEqual(fid, 0)
self.assertEqual(f.attributes()[1], [1, 2])
- self.assertTrue(vl.dataProvider().changeAttributeValues({fid: {0: {"style": {"color": "green"}}}}))
- vl = QgsVectorLayer(json_path, 'vl')
+ self.assertTrue(
+ vl.dataProvider().changeAttributeValues(
+ {fid: {0: {"style": {"color": "green"}}}}
+ )
+ )
+ vl = QgsVectorLayer(json_path, "vl")
self.assertTrue(vl.isValid())
self.assertEqual(vl.fields()[0].type(), QVariant.Map)
f = next(vl.getFeatures())
- self.assertEqual(f.attributes()[0], {'style': {'color': 'green'}})
+ self.assertEqual(f.attributes()[0], {"style": {"color": "green"}})
f = QgsFeature(vl.fields())
- f.setGeometry(QgsGeometry.fromWkt('POINT(15 40)'))
- f.setAttribute(0, {'style': {'color': 'yellow'}})
+ f.setGeometry(QgsGeometry.fromWkt("POINT(15 40)"))
+ f.setAttribute(0, {"style": {"color": "yellow"}})
self.assertTrue(vl.dataProvider().addFeatures([f]))
- vl = QgsVectorLayer(json_path, 'vl')
+ vl = QgsVectorLayer(json_path, "vl")
self.assertTrue(vl.isValid())
self.assertEqual(vl.fields()[0].type(), QVariant.Map)
f = vl.getFeature(1)
- self.assertEqual(f.attributes()[0], {'style': {'color': 'yellow'}})
+ self.assertEqual(f.attributes()[0], {"style": {"color": "yellow"}})
- @unittest.skipIf(int(gdal.VersionInfo('VERSION_NUM')) < GDAL_COMPUTE_VERSION(3, 8, 0), "GDAL 3.8 required")
+ @unittest.skipIf(
+ int(gdal.VersionInfo("VERSION_NUM")) < GDAL_COMPUTE_VERSION(3, 8, 0),
+ "GDAL 3.8 required",
+ )
def testDataCommentFileGeodatabase(self):
with tempfile.TemporaryDirectory() as temp_dir:
- dest_file_name = os.path.join(temp_dir, 'testDataCommentFileGeodatabase.gdb')
+ dest_file_name = os.path.join(
+ temp_dir, "testDataCommentFileGeodatabase.gdb"
+ )
ds = ogr.GetDriverByName("OpenFileGDB").CreateDataSource(dest_file_name)
- ds.CreateLayer("test", geom_type=ogr.wkbPoint, options=["LAYER_ALIAS=my_alias"])
+ ds.CreateLayer(
+ "test", geom_type=ogr.wkbPoint, options=["LAYER_ALIAS=my_alias"]
+ )
ds = None
- vl = QgsVectorLayer(dest_file_name, 'vl')
+ vl = QgsVectorLayer(dest_file_name, "vl")
self.assertEqual(vl.dataComment(), "my_alias")
def testExtentCsv(self):
# 2D points
- datasource_2d = os.path.join(self.basetestpath, 'testExtent2D.csv')
- with open(datasource_2d, 'w') as f:
- f.write('id,WKT\n')
+ datasource_2d = os.path.join(self.basetestpath, "testExtent2D.csv")
+ with open(datasource_2d, "w") as f:
+ f.write("id,WKT\n")
for i in range(9):
- f.write(f'{i},POINT ({2 * i} {i - 3})\n')
+ f.write(f"{i},POINT ({2 * i} {i - 3})\n")
- vl = QgsVectorLayer(f'{datasource_2d}|layerid=0', 'test', 'ogr')
+ vl = QgsVectorLayer(f"{datasource_2d}|layerid=0", "test", "ogr")
self.assertTrue(vl.isValid())
self.assertTrue(vl.featureCount(), 9)
self.assertEqual(vl.extent(), QgsRectangle(0, -3, 16, 5))
- self.assertEqual(vl.extent3D(), QgsBox3D(0, -3, float('nan'), 16, 5, float('nan')))
+ self.assertEqual(
+ vl.extent3D(), QgsBox3D(0, -3, float("nan"), 16, 5, float("nan"))
+ )
del vl
os.unlink(datasource_2d)
self.assertFalse(os.path.exists(datasource_2d))
# 3D points
- datasource_3d = os.path.join(self.basetestpath, 'testExtent3D.csv')
- with open(datasource_3d, 'w') as f:
- f.write('id,WKT\n')
+ datasource_3d = os.path.join(self.basetestpath, "testExtent3D.csv")
+ with open(datasource_3d, "w") as f:
+ f.write("id,WKT\n")
for i in range(13):
- f.write(f'{i},POINT Z({2 * i} {i - 3} {i - 5})\n')
+ f.write(f"{i},POINT Z({2 * i} {i - 3} {i - 5})\n")
- vl = QgsVectorLayer(f'{datasource_3d}|layerid=0', 'test', 'ogr')
+ vl = QgsVectorLayer(f"{datasource_3d}|layerid=0", "test", "ogr")
self.assertTrue(vl.isValid())
self.assertTrue(vl.featureCount(), 12)
self.assertEqual(vl.extent(), QgsRectangle(0, -3, 24, 9))
@@ -3591,7 +4764,9 @@ def testExtentCsv(self):
def testExtentShp(self):
# 2D points
- vl = QgsVectorLayer(os.path.join(unitTestDataPath(), 'points.shp'), 'points', 'ogr')
+ vl = QgsVectorLayer(
+ os.path.join(unitTestDataPath(), "points.shp"), "points", "ogr"
+ )
self.assertTrue(vl.isValid())
self.assertTrue(vl.featureCount(), 9)
self.assertAlmostEqual(vl.extent().xMinimum(), -118.8888, places=3)
@@ -3608,7 +4783,9 @@ def testExtentShp(self):
del vl
# 3D points
- vl = QgsVectorLayer(os.path.join(unitTestDataPath(), '3d', 'points_with_z.shp'), 'points', 'ogr')
+ vl = QgsVectorLayer(
+ os.path.join(unitTestDataPath(), "3d", "points_with_z.shp"), "points", "ogr"
+ )
self.assertTrue(vl.isValid())
self.assertTrue(vl.featureCount(), 9)
self.assertAlmostEqual(vl.extent().xMinimum(), 321384.94, places=3)
@@ -3624,25 +4801,43 @@ def testExtentShp(self):
self.assertAlmostEqual(vl.extent3D().zMaximum(), 105.6, places=3)
del vl
- @unittest.skipIf(int(gdal.VersionInfo('VERSION_NUM')) < GDAL_COMPUTE_VERSION(3, 6, 0), "GDAL 3.6 required")
- @unittest.skipIf(gdal.GetDriverByName("OpenFileGDB") is None, "GDAL OpenFileGDB driver required")
+ @unittest.skipIf(
+ int(gdal.VersionInfo("VERSION_NUM")) < GDAL_COMPUTE_VERSION(3, 6, 0),
+ "GDAL 3.6 required",
+ )
+ @unittest.skipIf(
+ gdal.GetDriverByName("OpenFileGDB") is None, "GDAL OpenFileGDB driver required"
+ )
def testReadOnlyFieldsFileGeodatabase(self):
with tempfile.TemporaryDirectory() as temp_dir:
- dest_file_name = os.path.join(temp_dir, 'testReadOnlyFieldsFileGeodatabase.gdb')
+ dest_file_name = os.path.join(
+ temp_dir, "testReadOnlyFieldsFileGeodatabase.gdb"
+ )
ds = ogr.GetDriverByName("OpenFileGDB").CreateDataSource(dest_file_name)
- ds.CreateLayer("test", geom_type=ogr.wkbPolygon, options=["CREATE_SHAPE_AREA_AND_LENGTH_FIELDS=YES"])
+ ds.CreateLayer(
+ "test",
+ geom_type=ogr.wkbPolygon,
+ options=["CREATE_SHAPE_AREA_AND_LENGTH_FIELDS=YES"],
+ )
ds = None
- vl = QgsVectorLayer(dest_file_name, 'vl')
+ vl = QgsVectorLayer(dest_file_name, "vl")
self.assertTrue(vl.fields()["Shape_Area"].isReadOnly())
- @unittest.skipIf(int(gdal.VersionInfo('VERSION_NUM')) < GDAL_COMPUTE_VERSION(3, 6, 0), "GDAL 3.6 required")
- @unittest.skipIf(gdal.GetDriverByName("OpenFileGDB") is None, "GDAL OpenFileGDB driver required")
+ @unittest.skipIf(
+ int(gdal.VersionInfo("VERSION_NUM")) < GDAL_COMPUTE_VERSION(3, 6, 0),
+ "GDAL 3.6 required",
+ )
+ @unittest.skipIf(
+ gdal.GetDriverByName("OpenFileGDB") is None, "GDAL OpenFileGDB driver required"
+ )
def testDeleteFieldFileGeodatabase(self):
with tempfile.TemporaryDirectory() as temp_dir:
- dest_file_name = os.path.join(temp_dir, 'testDeleteFieldFileGeodatabase.gdb')
+ dest_file_name = os.path.join(
+ temp_dir, "testDeleteFieldFileGeodatabase.gdb"
+ )
ds = ogr.GetDriverByName("OpenFileGDB").CreateDataSource(dest_file_name)
lyr = ds.CreateLayer("test", geom_type=ogr.wkbNone)
lyr.CreateField(ogr.FieldDefn("fld1"))
@@ -3657,19 +4852,16 @@ def testDeleteFieldFileGeodatabase(self):
lyr.CreateFeature(f)
ds = None
- vl = QgsVectorLayer(dest_file_name, 'vl')
+ vl = QgsVectorLayer(dest_file_name, "vl")
self.assertTrue(vl.startEditing())
self.assertTrue(vl.deleteAttribute(1)) # delete field fld1
self.assertTrue(vl.commitChanges())
# Re-open a connection without explicitly closing the one we've edited
- vl2 = QgsVectorLayer(dest_file_name, 'vl2')
+ vl2 = QgsVectorLayer(dest_file_name, "vl2")
features = {f.id(): f.attributes() for f in vl2.getFeatures()}
- self.assertEqual(features, {
- 1: [1, 'b'],
- 2: [2, 'd']
- })
+ self.assertEqual(features, {1: [1, "b"], 2: [2, "d"]})
-if __name__ == '__main__':
+if __name__ == "__main__":
unittest.main()
diff --git a/tests/src/python/test_provider_ogr_gpkg.py b/tests/src/python/test_provider_ogr_gpkg.py
index 88c9268ac310..a012ba1d2a6a 100644
--- a/tests/src/python/test_provider_ogr_gpkg.py
+++ b/tests/src/python/test_provider_ogr_gpkg.py
@@ -8,9 +8,10 @@
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
"""
-__author__ = 'Even Rouault'
-__date__ = '2016-04-21'
-__copyright__ = 'Copyright 2016, Even Rouault'
+
+__author__ = "Even Rouault"
+__date__ = "2016-04-21"
+__copyright__ = "Copyright 2016, Even Rouault"
import os
import re
@@ -70,7 +71,8 @@
def GDAL_COMPUTE_VERSION(maj, min, rev):
- return ((maj) * 1000000 + (min) * 10000 + (rev) * 100)
+ return (maj) * 1000000 + (min) * 10000 + (rev) * 100
+
#########################################################################
# Standard conformance tests for a provider
@@ -82,23 +84,22 @@ class TestPyQgsOGRProviderGpkgConformance(QgisTestCase, ProviderTestCase):
@classmethod
def setUpClass(cls):
"""Run before all tests"""
- super(TestPyQgsOGRProviderGpkgConformance, cls).setUpClass()
+ super().setUpClass()
# Create test layer
cls.basetestpath = tempfile.mkdtemp()
cls.repackfilepath = tempfile.mkdtemp()
- srcpath = os.path.join(TEST_DATA_DIR, 'provider')
- shutil.copy(os.path.join(srcpath, 'geopackage.gpkg'), cls.basetestpath)
- shutil.copy(os.path.join(srcpath, 'geopackage_poly.gpkg'),
- cls.basetestpath)
- cls.basetestfile = os.path.join(cls.basetestpath, 'geopackage.gpkg')
- cls.basetestpolyfile = os.path.join(
- cls.basetestpath, 'geopackage_poly.gpkg')
+ srcpath = os.path.join(TEST_DATA_DIR, "provider")
+ shutil.copy(os.path.join(srcpath, "geopackage.gpkg"), cls.basetestpath)
+ shutil.copy(os.path.join(srcpath, "geopackage_poly.gpkg"), cls.basetestpath)
+ cls.basetestfile = os.path.join(cls.basetestpath, "geopackage.gpkg")
+ cls.basetestpolyfile = os.path.join(cls.basetestpath, "geopackage_poly.gpkg")
cls.vl = QgsVectorLayer(
- cls.basetestfile + '|layername=geopackage', 'test', 'ogr')
+ cls.basetestfile + "|layername=geopackage", "test", "ogr"
+ )
assert cls.vl.isValid()
cls.source = cls.vl.dataProvider()
- cls.vl_poly = QgsVectorLayer(cls.basetestpolyfile, 'test', 'ogr')
+ cls.vl_poly = QgsVectorLayer(cls.basetestpolyfile, "test", "ogr")
assert cls.vl_poly.isValid()
cls.poly_provider = cls.vl_poly.dataProvider()
@@ -106,12 +107,16 @@ def setUpClass(cls):
# Create the other layer for constraints check
cls.check_constraint = QgsVectorLayer(
- cls.basetestfile + '|layername=check_constraint', 'check_constraint', 'ogr')
+ cls.basetestfile + "|layername=check_constraint", "check_constraint", "ogr"
+ )
cls.check_constraint_editing_started = False
# Create the other layer for unique and not null constraints check
cls.unique_not_null_constraints = QgsVectorLayer(
- cls.basetestfile + '|layername=unique_not_null_constraints', 'unique_not_null_constraints', 'ogr')
+ cls.basetestfile + "|layername=unique_not_null_constraints",
+ "unique_not_null_constraints",
+ "ogr",
+ )
assert cls.unique_not_null_constraints.isValid()
@classmethod
@@ -123,16 +128,16 @@ def tearDownClass(cls):
del cls.unique_not_null_constraints
for dirname in cls.dirs_to_cleanup:
shutil.rmtree(dirname, True)
- super(TestPyQgsOGRProviderGpkgConformance, cls).tearDownClass()
+ super().tearDownClass()
def getSource(self):
tmpdir = tempfile.mkdtemp()
self.dirs_to_cleanup.append(tmpdir)
- srcpath = os.path.join(TEST_DATA_DIR, 'provider')
- shutil.copy(os.path.join(srcpath, 'geopackage.gpkg'), tmpdir)
- datasource = os.path.join(tmpdir, 'geopackage.gpkg')
+ srcpath = os.path.join(TEST_DATA_DIR, "provider")
+ shutil.copy(os.path.join(srcpath, "geopackage.gpkg"), tmpdir)
+ datasource = os.path.join(tmpdir, "geopackage.gpkg")
- vl = QgsVectorLayer(datasource, 'test', 'ogr')
+ vl = QgsVectorLayer(datasource, "test", "ogr")
return vl
@@ -155,11 +160,11 @@ def getEditableLayerWithUniqueNotNullConstraints(self):
return self.unique_not_null_constraints
def enableCompiler(self):
- QgsSettings().setValue('/qgis/compileExpressions', True)
+ QgsSettings().setValue("/qgis/compileExpressions", True)
return True
def disableCompiler(self):
- QgsSettings().setValue('/qgis/compileExpressions', False)
+ QgsSettings().setValue("/qgis/compileExpressions", False)
def treat_time_as_string(self):
return True
@@ -168,69 +173,71 @@ def treat_datetime_tz_as_utc(self):
return True
def uncompiledFilters(self):
- return {'cnt = 10 ^ 2',
- '"name" ~ \'[OP]ra[gne]+\'',
- 'sqrt(pk) >= 2',
- 'radians(cnt) < 2',
- 'degrees(pk) <= 200',
- 'cos(pk) < 0',
- 'sin(pk) < 0',
- 'tan(pk) < 0',
- 'acos(-1) < pk',
- 'asin(1) < pk',
- 'atan(3.14) < pk',
- 'atan2(3.14, pk) < 1',
- 'exp(pk) < 10',
- 'ln(pk) <= 1',
- 'log(3, pk) <= 1',
- 'log10(pk) < 0.5',
- 'floor(3.14) <= pk',
- 'ceil(3.14) <= pk',
- 'pk < pi()',
- 'floor(cnt / 66.67) <= 2',
- 'ceil(cnt / 66.67) <= 2',
- 'pk < pi() / 2',
- 'x($geometry) < -70',
- 'y($geometry) > 70',
- 'xmin($geometry) < -70',
- 'ymin($geometry) > 70',
- 'xmax($geometry) < -70',
- 'ymax($geometry) > 70',
- 'disjoint($geometry,geom_from_wkt( \'Polygon ((-72.2 66.1, -65.2 66.1, -65.2 72.0, -72.2 72.0, -72.2 66.1))\'))',
- 'intersects($geometry,geom_from_wkt( \'Polygon ((-72.2 66.1, -65.2 66.1, -65.2 72.0, -72.2 72.0, -72.2 66.1))\'))',
- 'contains(geom_from_wkt( \'Polygon ((-72.2 66.1, -65.2 66.1, -65.2 72.0, -72.2 72.0, -72.2 66.1))\'),$geometry)',
- 'distance($geometry,geom_from_wkt( \'Point (-70 70)\')) > 7',
- 'intersects($geometry,geom_from_gml( \'-72.2,66.1 -65.2,66.1 -65.2,72.0 -72.2,72.0 -72.2,66.1 \'))',
- 'x($geometry) < -70',
- 'y($geometry) > 79',
- 'xmin($geometry) < -70',
- 'ymin($geometry) < 76',
- 'xmax($geometry) > -68',
- 'ymax($geometry) > 80',
- 'area($geometry) > 10',
- 'perimeter($geometry) < 12',
- 'relate($geometry,geom_from_wkt( \'Polygon ((-68.2 82.1, -66.95 82.1, -66.95 79.05, -68.2 79.05, -68.2 82.1))\')) = \'FF2FF1212\'',
- 'relate($geometry,geom_from_wkt( \'Polygon ((-68.2 82.1, -66.95 82.1, -66.95 79.05, -68.2 79.05, -68.2 82.1))\'), \'****F****\')',
- 'crosses($geometry,geom_from_wkt( \'Linestring (-68.2 82.1, -66.95 82.1, -66.95 79.05)\'))',
- 'overlaps($geometry,geom_from_wkt( \'Polygon ((-68.2 82.1, -66.95 82.1, -66.95 79.05, -68.2 79.05, -68.2 82.1))\'))',
- 'within($geometry,geom_from_wkt( \'Polygon ((-75.1 76.1, -75.1 81.6, -68.8 81.6, -68.8 76.1, -75.1 76.1))\'))',
- 'overlaps(translate($geometry,-1,-1),geom_from_wkt( \'Polygon ((-75.1 76.1, -75.1 81.6, -68.8 81.6, -68.8 76.1, -75.1 76.1))\'))',
- 'overlaps(buffer($geometry,1),geom_from_wkt( \'Polygon ((-75.1 76.1, -75.1 81.6, -68.8 81.6, -68.8 76.1, -75.1 76.1))\'))',
- 'intersects(centroid($geometry),geom_from_wkt( \'Polygon ((-74.4 78.2, -74.4 79.1, -66.8 79.1, -66.8 78.2, -74.4 78.2))\'))',
- 'intersects(point_on_surface($geometry),geom_from_wkt( \'Polygon ((-74.4 78.2, -74.4 79.1, -66.8 79.1, -66.8 78.2, -74.4 78.2))\'))',
- '"dt" = to_datetime(\'000www14ww13ww12www4ww5ww2020\',\'zzzwwwsswwmmwwhhwwwdwwMwwyyyy\')',
- 'to_time("time") >= make_time(12, 14, 14)',
- 'to_time("time") = to_time(\'000www14ww13ww12www\',\'zzzwwwsswwmmwwhhwww\')',
- '"date" = to_date(\'www4ww5ww2020\',\'wwwdwwMwwyyyy\')'
- }
+ return {
+ "cnt = 10 ^ 2",
+ "\"name\" ~ '[OP]ra[gne]+'",
+ "sqrt(pk) >= 2",
+ "radians(cnt) < 2",
+ "degrees(pk) <= 200",
+ "cos(pk) < 0",
+ "sin(pk) < 0",
+ "tan(pk) < 0",
+ "acos(-1) < pk",
+ "asin(1) < pk",
+ "atan(3.14) < pk",
+ "atan2(3.14, pk) < 1",
+ "exp(pk) < 10",
+ "ln(pk) <= 1",
+ "log(3, pk) <= 1",
+ "log10(pk) < 0.5",
+ "floor(3.14) <= pk",
+ "ceil(3.14) <= pk",
+ "pk < pi()",
+ "floor(cnt / 66.67) <= 2",
+ "ceil(cnt / 66.67) <= 2",
+ "pk < pi() / 2",
+ "x($geometry) < -70",
+ "y($geometry) > 70",
+ "xmin($geometry) < -70",
+ "ymin($geometry) > 70",
+ "xmax($geometry) < -70",
+ "ymax($geometry) > 70",
+ "disjoint($geometry,geom_from_wkt( 'Polygon ((-72.2 66.1, -65.2 66.1, -65.2 72.0, -72.2 72.0, -72.2 66.1))'))",
+ "intersects($geometry,geom_from_wkt( 'Polygon ((-72.2 66.1, -65.2 66.1, -65.2 72.0, -72.2 72.0, -72.2 66.1))'))",
+ "contains(geom_from_wkt( 'Polygon ((-72.2 66.1, -65.2 66.1, -65.2 72.0, -72.2 72.0, -72.2 66.1))'),$geometry)",
+ "distance($geometry,geom_from_wkt( 'Point (-70 70)')) > 7",
+ "intersects($geometry,geom_from_gml( '-72.2,66.1 -65.2,66.1 -65.2,72.0 -72.2,72.0 -72.2,66.1 '))",
+ "x($geometry) < -70",
+ "y($geometry) > 79",
+ "xmin($geometry) < -70",
+ "ymin($geometry) < 76",
+ "xmax($geometry) > -68",
+ "ymax($geometry) > 80",
+ "area($geometry) > 10",
+ "perimeter($geometry) < 12",
+ "relate($geometry,geom_from_wkt( 'Polygon ((-68.2 82.1, -66.95 82.1, -66.95 79.05, -68.2 79.05, -68.2 82.1))')) = 'FF2FF1212'",
+ "relate($geometry,geom_from_wkt( 'Polygon ((-68.2 82.1, -66.95 82.1, -66.95 79.05, -68.2 79.05, -68.2 82.1))'), '****F****')",
+ "crosses($geometry,geom_from_wkt( 'Linestring (-68.2 82.1, -66.95 82.1, -66.95 79.05)'))",
+ "overlaps($geometry,geom_from_wkt( 'Polygon ((-68.2 82.1, -66.95 82.1, -66.95 79.05, -68.2 79.05, -68.2 82.1))'))",
+ "within($geometry,geom_from_wkt( 'Polygon ((-75.1 76.1, -75.1 81.6, -68.8 81.6, -68.8 76.1, -75.1 76.1))'))",
+ "overlaps(translate($geometry,-1,-1),geom_from_wkt( 'Polygon ((-75.1 76.1, -75.1 81.6, -68.8 81.6, -68.8 76.1, -75.1 76.1))'))",
+ "overlaps(buffer($geometry,1),geom_from_wkt( 'Polygon ((-75.1 76.1, -75.1 81.6, -68.8 81.6, -68.8 76.1, -75.1 76.1))'))",
+ "intersects(centroid($geometry),geom_from_wkt( 'Polygon ((-74.4 78.2, -74.4 79.1, -66.8 79.1, -66.8 78.2, -74.4 78.2))'))",
+ "intersects(point_on_surface($geometry),geom_from_wkt( 'Polygon ((-74.4 78.2, -74.4 79.1, -66.8 79.1, -66.8 78.2, -74.4 78.2))'))",
+ "\"dt\" = to_datetime('000www14ww13ww12www4ww5ww2020','zzzwwwsswwmmwwhhwwwdwwMwwyyyy')",
+ 'to_time("time") >= make_time(12, 14, 14)',
+ "to_time(\"time\") = to_time('000www14ww13ww12www','zzzwwwsswwmmwwhhwww')",
+ "\"date\" = to_date('www4ww5ww2020','wwwdwwMwwyyyy')",
+ }
def partiallyCompiledFilters(self):
- return {'"name" NOT LIKE \'Ap%\'',
- 'name LIKE \'Apple\'',
- 'name LIKE \'aPple\'',
- 'name LIKE \'Ap_le\'',
- 'name LIKE \'Ap\\_le\''
- }
+ return {
+ "\"name\" NOT LIKE 'Ap%'",
+ "name LIKE 'Apple'",
+ "name LIKE 'aPple'",
+ "name LIKE 'Ap_le'",
+ "name LIKE 'Ap\\_le'",
+ }
def testOrderByCompiled(self):
self.runOrderByTests()
@@ -239,24 +246,28 @@ def testOrderByCompiled(self):
# Geopackage
# Test orderBy + filter expression
- request = QgsFeatureRequest().setFilterExpression('"cnt">=200').addOrderBy('num_char')
- values = [f['pk'] for f in self.source.getFeatures(request)]
+ request = (
+ QgsFeatureRequest().setFilterExpression('"cnt">=200').addOrderBy("num_char")
+ )
+ values = [f["pk"] for f in self.source.getFeatures(request)]
self.assertEqual(values, [2, 3, 4])
values = [f.geometry().asWkt() for f in self.source.getFeatures(request)]
# Check that we get geometries
assert compareWkt(values[0], "Point (-68.2 70.8)"), values[0]
# Test orderBy + subset string
- request = QgsFeatureRequest().addOrderBy('num_char')
+ request = QgsFeatureRequest().addOrderBy("num_char")
self.source.setSubsetString("cnt >= 200")
- values = [f['pk'] for f in self.source.getFeatures(request)]
+ values = [f["pk"] for f in self.source.getFeatures(request)]
self.source.setSubsetString(None)
self.assertEqual(values, [2, 3, 4])
# Test orderBy + subset string + filter expression
- request = QgsFeatureRequest().setFilterExpression('"cnt"<=300').addOrderBy('num_char')
+ request = (
+ QgsFeatureRequest().setFilterExpression('"cnt"<=300').addOrderBy("num_char")
+ )
self.source.setSubsetString("cnt >= 200")
- values = [f['pk'] for f in self.source.getFeatures(request)]
+ values = [f["pk"] for f in self.source.getFeatures(request)]
self.source.setSubsetString(None)
self.assertEqual(values, [2, 3])
@@ -266,28 +277,28 @@ def testOrderByCompiled(self):
# to analyze the SQL SELECT, but QGIS could probably add the JOIN with
# the RTree)
extent = QgsRectangle(-70, 67, -60, 80)
- request = QgsFeatureRequest().setFilterRect(extent).addOrderBy('num_char')
- values = [f['pk'] for f in self.source.getFeatures(request)]
+ request = QgsFeatureRequest().setFilterRect(extent).addOrderBy("num_char")
+ values = [f["pk"] for f in self.source.getFeatures(request)]
self.assertEqual(values, [2, 4])
# Test orderBy + subset string which is a SELECT
# (excluded by the optimization)
# For some weird reason, we need to re-open a new connection to the
# dataset (this weird behavior predates the optimization)
- request = QgsFeatureRequest().addOrderBy('num_char')
+ request = QgsFeatureRequest().addOrderBy("num_char")
tmpdir = tempfile.mkdtemp()
self.dirs_to_cleanup.append(tmpdir)
- srcpath = os.path.join(TEST_DATA_DIR, 'provider')
- shutil.copy(os.path.join(srcpath, 'geopackage.gpkg'), tmpdir)
- datasource = os.path.join(tmpdir, 'geopackage.gpkg')
- vl = QgsVectorLayer(datasource, 'test', 'ogr')
- vl.setSubsetString("SELECT * FROM \"geopackage\" WHERE cnt >= 200")
- values = [f['pk'] for f in vl.getFeatures(request)]
+ srcpath = os.path.join(TEST_DATA_DIR, "provider")
+ shutil.copy(os.path.join(srcpath, "geopackage.gpkg"), tmpdir)
+ datasource = os.path.join(tmpdir, "geopackage.gpkg")
+ vl = QgsVectorLayer(datasource, "test", "ogr")
+ vl.setSubsetString('SELECT * FROM "geopackage" WHERE cnt >= 200')
+ values = [f["pk"] for f in vl.getFeatures(request)]
self.assertEqual(values, [2, 3, 4])
del vl
-class ErrorReceiver():
+class ErrorReceiver:
def __init__(self):
self.msg = None
@@ -298,18 +309,19 @@ def receiveError(self, msg):
def count_opened_filedescriptors(filename_to_test):
count = -1
- if sys.platform.startswith('linux'):
+ if sys.platform.startswith("linux"):
count = 0
- open_files_dirname = '/proc/%d/fd' % os.getpid()
+ open_files_dirname = "/proc/%d/fd" % os.getpid()
filenames = os.listdir(open_files_dirname)
for filename in filenames:
- full_filename = open_files_dirname + '/' + filename
+ full_filename = open_files_dirname + "/" + filename
if os.path.exists(full_filename):
link = os.readlink(full_filename)
if os.path.basename(link) == os.path.basename(filename_to_test):
count += 1
return count
+
# #########################################################################
# # Other tests specific to GPKG handling in OGR provider
# #########################################################################
@@ -341,116 +353,130 @@ def tearDownClass(cls):
def testDecodeUri(self):
- filename = '/home/to/path/my_file.gpkg'
+ filename = "/home/to/path/my_file.gpkg"
registry = QgsProviderRegistry.instance()
uri = filename
- components = registry.decodeUri('ogr', uri)
+ components = registry.decodeUri("ogr", uri)
self.assertEqual(components["path"], filename)
- uri = f'{filename}|layername=test'
- components = registry.decodeUri('ogr', uri)
+ uri = f"{filename}|layername=test"
+ components = registry.decodeUri("ogr", uri)
self.assertEqual(components["path"], filename)
- self.assertEqual(components["layerName"], 'test')
+ self.assertEqual(components["layerName"], "test")
- uri = f'{filename}|layerName=test'
- components = registry.decodeUri('ogr', uri)
+ uri = f"{filename}|layerName=test"
+ components = registry.decodeUri("ogr", uri)
self.assertEqual(components["path"], filename)
- self.assertEqual(components["layerName"], 'test')
+ self.assertEqual(components["layerName"], "test")
- uri = f'{filename}|layerid=0'
- components = registry.decodeUri('ogr', uri)
+ uri = f"{filename}|layerid=0"
+ components = registry.decodeUri("ogr", uri)
self.assertEqual(components["path"], filename)
self.assertEqual(components["layerId"], 0)
- uri = f'{filename}|layerId=0'
- components = registry.decodeUri('ogr', uri)
+ uri = f"{filename}|layerId=0"
+ components = registry.decodeUri("ogr", uri)
self.assertEqual(components["path"], filename)
self.assertEqual(components["layerId"], 0)
- uri = f'{filename}|geometryType=POINT'
- components = registry.decodeUri('ogr', uri)
+ uri = f"{filename}|geometryType=POINT"
+ components = registry.decodeUri("ogr", uri)
self.assertEqual(components["path"], filename)
- self.assertEqual(components["geometryType"], 'POINT')
+ self.assertEqual(components["geometryType"], "POINT")
def testEncodeUri(self):
- filename = '/home/to/path/my_file.gpkg'
+ filename = "/home/to/path/my_file.gpkg"
registry = QgsProviderRegistry.instance()
parts = {"path": filename}
- uri = registry.encodeUri('ogr', parts)
+ uri = registry.encodeUri("ogr", parts)
self.assertEqual(uri, filename)
# layerName only
parts["layerName"] = "test"
- uri = registry.encodeUri('ogr', parts)
- self.assertEqual(uri, f'{filename}|layername=test')
+ uri = registry.encodeUri("ogr", parts)
+ self.assertEqual(uri, f"{filename}|layername=test")
del parts["layerName"]
# layerId only
parts["layerId"] = "0"
- uri = registry.encodeUri('ogr', parts)
- self.assertEqual(uri, f'{filename}|layerid=0')
+ uri = registry.encodeUri("ogr", parts)
+ self.assertEqual(uri, f"{filename}|layerid=0")
# Both layerName and layerId: layerName takes precedence
parts["layerName"] = "test"
- uri = registry.encodeUri('ogr', parts)
- self.assertEqual(uri, f'{filename}|layername=test')
+ uri = registry.encodeUri("ogr", parts)
+ self.assertEqual(uri, f"{filename}|layername=test")
def testSingleToMultiPolygonPromotion(self):
- tmpfile = os.path.join(self.basetestpath, 'testSingleToMultiPolygonPromotion.gpkg')
- ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile)
- ds.CreateLayer('test', geom_type=ogr.wkbMultiPolygon)
+ tmpfile = os.path.join(
+ self.basetestpath, "testSingleToMultiPolygonPromotion.gpkg"
+ )
+ ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile)
+ ds.CreateLayer("test", geom_type=ogr.wkbMultiPolygon)
ds = None
- vl = QgsVectorLayer(f'{tmpfile}|layerid=0', 'test', 'ogr')
+ vl = QgsVectorLayer(f"{tmpfile}|layerid=0", "test", "ogr")
f = QgsFeature()
- f.setGeometry(QgsGeometry.fromWkt('POLYGON ((0 0,0 1,1 1,0 0))'))
+ f.setGeometry(QgsGeometry.fromWkt("POLYGON ((0 0,0 1,1 1,0 0))"))
vl.dataProvider().addFeatures([f])
got = [feat for feat in vl.getFeatures()][0]
got_geom = got.geometry()
- reference = QgsGeometry.fromWkt('MultiPolygon (((0 0, 0 1, 1 1, 0 0)))')
+ reference = QgsGeometry.fromWkt("MultiPolygon (((0 0, 0 1, 1 1, 0 0)))")
# The geometries must be binarily identical
- self.assertEqual(got_geom.asWkb(), reference.asWkb(),
- f'Expected {reference.asWkt()}, got {got_geom.asWkt()}')
+ self.assertEqual(
+ got_geom.asWkb(),
+ reference.asWkb(),
+ f"Expected {reference.asWkt()}, got {got_geom.asWkt()}",
+ )
def testCurveGeometryType(self):
- tmpfile = os.path.join(self.basetestpath, 'testCurveGeometryType.gpkg')
- ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile)
- ds.CreateLayer('test', geom_type=ogr.wkbCurvePolygon)
+ tmpfile = os.path.join(self.basetestpath, "testCurveGeometryType.gpkg")
+ ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile)
+ ds.CreateLayer("test", geom_type=ogr.wkbCurvePolygon)
ds = None
- vl = QgsVectorLayer(f'{tmpfile}', 'test', 'ogr')
+ vl = QgsVectorLayer(f"{tmpfile}", "test", "ogr")
self.assertEqual(1, vl.dataProvider().subLayerCount())
- self.assertEqual(vl.dataProvider().subLayers(),
- [QgsDataProvider.SUBLAYER_SEPARATOR.join(['0', 'test', '0', 'CurvePolygon', 'geom', ''])])
+ self.assertEqual(
+ vl.dataProvider().subLayers(),
+ [
+ QgsDataProvider.SUBLAYER_SEPARATOR.join(
+ ["0", "test", "0", "CurvePolygon", "geom", ""]
+ )
+ ],
+ )
f = QgsFeature()
- f.setGeometry(QgsGeometry.fromWkt('POLYGON ((0 0,0 1,1 1,0 0))'))
+ f.setGeometry(QgsGeometry.fromWkt("POLYGON ((0 0,0 1,1 1,0 0))"))
vl.dataProvider().addFeatures([f])
got = [feat for feat in vl.getFeatures()][0]
got_geom = got.geometry()
- reference = QgsGeometry.fromWkt('CurvePolygon ((0 0, 0 1, 1 1, 0 0))')
+ reference = QgsGeometry.fromWkt("CurvePolygon ((0 0, 0 1, 1 1, 0 0))")
# The geometries must be binarily identical
- self.assertEqual(got_geom.asWkb(), reference.asWkb(),
- f'Expected {reference.asWkt()}, got {got_geom.asWkt()}')
+ self.assertEqual(
+ got_geom.asWkb(),
+ reference.asWkb(),
+ f"Expected {reference.asWkt()}, got {got_geom.asWkt()}",
+ )
def internalTestBug15351(self, orderClosing):
- tmpfile = os.path.join(self.basetestpath, 'testBug15351.gpkg')
- ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile)
- lyr = ds.CreateLayer('test', geom_type=ogr.wkbPoint)
+ tmpfile = os.path.join(self.basetestpath, "testBug15351.gpkg")
+ ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile)
+ lyr = ds.CreateLayer("test", geom_type=ogr.wkbPoint)
f = ogr.Feature(lyr.GetLayerDefn())
- f.SetGeometry(ogr.CreateGeometryFromWkt('POINT(0 0)'))
+ f.SetGeometry(ogr.CreateGeometryFromWkt("POINT(0 0)"))
lyr.CreateFeature(f)
f = None
ds = None
- vl = QgsVectorLayer(f'{tmpfile}', 'test', 'ogr')
+ vl = QgsVectorLayer(f"{tmpfile}", "test", "ogr")
self.assertTrue(vl.startEditing())
- self.assertTrue(vl.changeGeometry(1, QgsGeometry.fromWkt('Point (3 50)')))
+ self.assertTrue(vl.changeGeometry(1, QgsGeometry.fromWkt("Point (3 50)")))
# Iterate over features (will open a new OGR connection), but do not
# close the iterator for now
@@ -458,7 +484,7 @@ def internalTestBug15351(self, orderClosing):
f = QgsFeature()
it.nextFeature(f)
- if orderClosing == 'closeIter_commit_closeProvider':
+ if orderClosing == "closeIter_commit_closeProvider":
it = None
# Commit changes
@@ -468,73 +494,77 @@ def internalTestBug15351(self, orderClosing):
self.assertIsNone(cbk.msg)
# Close layer and iterator in different orders
- if orderClosing == 'closeIter_commit_closeProvider':
+ if orderClosing == "closeIter_commit_closeProvider":
vl = None
- elif orderClosing == 'commit_closeProvider_closeIter':
+ elif orderClosing == "commit_closeProvider_closeIter":
vl = None
it = None
else:
- assert orderClosing == 'commit_closeIter_closeProvider'
+ assert orderClosing == "commit_closeIter_closeProvider"
it = None
vl = None
# Test that we succeeded restoring default journal mode, and we
# are not let in WAL mode.
ds = ogr.Open(tmpfile)
- lyr = ds.ExecuteSQL('PRAGMA journal_mode')
+ lyr = ds.ExecuteSQL("PRAGMA journal_mode")
f = lyr.GetNextFeature()
res = f.GetField(0)
ds.ReleaseResultSet(lyr)
ds = None
- self.assertEqual(res, 'delete')
+ self.assertEqual(res, "delete")
# We need GDAL 2.0 to issue PRAGMA journal_mode
# Note: for that case, we don't strictly need turning on WAL
def testBug15351_closeIter_commit_closeProvider(self):
- self.internalTestBug15351('closeIter_commit_closeProvider')
+ self.internalTestBug15351("closeIter_commit_closeProvider")
# We need GDAL 2.0 to issue PRAGMA journal_mode
def testBug15351_commit_closeProvider_closeIter(self):
- self.internalTestBug15351('commit_closeProvider_closeIter')
+ self.internalTestBug15351("commit_closeProvider_closeIter")
# We need GDAL 2.0 to issue PRAGMA journal_mode
def testBug15351_commit_closeIter_closeProvider(self):
- self.internalTestBug15351('commit_closeIter_closeProvider')
+ self.internalTestBug15351("commit_closeIter_closeProvider")
def testGeopackageExtentUpdate(self):
- ''' test https://github.com/qgis/QGIS/issues/23209 '''
- tmpfile = os.path.join(self.basetestpath, 'testGeopackageExtentUpdate.gpkg')
- ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile)
- lyr = ds.CreateLayer('test', geom_type=ogr.wkbPoint)
+ """test https://github.com/qgis/QGIS/issues/23209"""
+ tmpfile = os.path.join(self.basetestpath, "testGeopackageExtentUpdate.gpkg")
+ ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile)
+ lyr = ds.CreateLayer("test", geom_type=ogr.wkbPoint)
f = ogr.Feature(lyr.GetLayerDefn())
- f.SetGeometry(ogr.CreateGeometryFromWkt('POINT(0 0)'))
+ f.SetGeometry(ogr.CreateGeometryFromWkt("POINT(0 0)"))
lyr.CreateFeature(f)
f = ogr.Feature(lyr.GetLayerDefn())
- f.SetGeometry(ogr.CreateGeometryFromWkt('POINT(1 1)'))
+ f.SetGeometry(ogr.CreateGeometryFromWkt("POINT(1 1)"))
lyr.CreateFeature(f)
f = None
f = ogr.Feature(lyr.GetLayerDefn())
- f.SetGeometry(ogr.CreateGeometryFromWkt('POINT(1 0.5)'))
+ f.SetGeometry(ogr.CreateGeometryFromWkt("POINT(1 0.5)"))
lyr.CreateFeature(f)
f = None
gdal.ErrorReset()
- ds.ExecuteSQL('RECOMPUTE EXTENT ON test')
- has_error = gdal.GetLastErrorMsg() != ''
+ ds.ExecuteSQL("RECOMPUTE EXTENT ON test")
+ has_error = gdal.GetLastErrorMsg() != ""
ds = None
if has_error:
- print('Too old GDAL trunk version. Please update')
+ print("Too old GDAL trunk version. Please update")
return
- vl = QgsVectorLayer(f'{tmpfile}', 'test', 'ogr')
+ vl = QgsVectorLayer(f"{tmpfile}", "test", "ogr")
# Test moving a geometry that touches the bbox
self.assertTrue(vl.startEditing())
- self.assertTrue(vl.changeGeometry(1, QgsGeometry.fromWkt('Point (0.5 0)')))
+ self.assertTrue(vl.changeGeometry(1, QgsGeometry.fromWkt("Point (0.5 0)")))
self.assertTrue(vl.commitChanges())
reference = QgsGeometry.fromRect(QgsRectangle(0.5, 0.0, 1.0, 1.0))
provider_extent = QgsGeometry.fromRect(vl.extent())
- self.assertTrue(QgsGeometry.compare(provider_extent.asPolygon()[0], reference.asPolygon()[0], 0.00001),
- provider_extent.asPolygon()[0])
+ self.assertTrue(
+ QgsGeometry.compare(
+ provider_extent.asPolygon()[0], reference.asPolygon()[0], 0.00001
+ ),
+ provider_extent.asPolygon()[0],
+ )
# Test deleting a geometry that touches the bbox
self.assertTrue(vl.startEditing())
@@ -542,39 +572,45 @@ def testGeopackageExtentUpdate(self):
self.assertTrue(vl.commitChanges())
reference = QgsGeometry.fromRect(QgsRectangle(0.5, 0.0, 1.0, 0.5))
provider_extent = QgsGeometry.fromRect(vl.extent())
- self.assertTrue(QgsGeometry.compare(provider_extent.asPolygon()[0], reference.asPolygon()[0], 0.00001),
- provider_extent.asPolygon()[0])
+ self.assertTrue(
+ QgsGeometry.compare(
+ provider_extent.asPolygon()[0], reference.asPolygon()[0], 0.00001
+ ),
+ provider_extent.asPolygon()[0],
+ )
def testSelectSubsetString(self):
- tmpfile = os.path.join(self.basetestpath, 'testSelectSubsetString.gpkg')
- ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile)
- lyr = ds.CreateLayer('test', geom_type=ogr.wkbMultiPolygon)
- lyr.CreateField(ogr.FieldDefn('foo', ogr.OFTString))
+ tmpfile = os.path.join(self.basetestpath, "testSelectSubsetString.gpkg")
+ ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile)
+ lyr = ds.CreateLayer("test", geom_type=ogr.wkbMultiPolygon)
+ lyr.CreateField(ogr.FieldDefn("foo", ogr.OFTString))
f = ogr.Feature(lyr.GetLayerDefn())
- f['foo'] = 'bar'
+ f["foo"] = "bar"
lyr.CreateFeature(f)
f = None
f = ogr.Feature(lyr.GetLayerDefn())
- f['foo'] = 'baz'
+ f["foo"] = "baz"
lyr.CreateFeature(f)
f = None
ds = None
- vl = QgsVectorLayer(f'{tmpfile}|layerid=0', 'test', 'ogr')
+ vl = QgsVectorLayer(f"{tmpfile}|layerid=0", "test", "ogr")
vl.setSubsetString("SELECT fid, foo FROM test WHERE foo = 'baz'")
got = [feat for feat in vl.getFeatures()]
self.assertEqual(len(got), 1)
# test SQLite CTE Common Table Expression (issue https://github.com/qgis/QGIS/issues/54677)
- vl.setSubsetString("WITH test_cte AS (SELECT fid, foo FROM test WHERE foo = 'baz') SELECT * FROM test_cte")
+ vl.setSubsetString(
+ "WITH test_cte AS (SELECT fid, foo FROM test WHERE foo = 'baz') SELECT * FROM test_cte"
+ )
self.assertEqual(len(got), 1)
del vl
- testdata_path = unitTestDataPath('provider')
- shutil.copy(os.path.join(testdata_path, 'bug_19826.gpkg'), tmpfile)
- vl = QgsVectorLayer(f'{tmpfile}|layerid=0', 'test', 'ogr')
+ testdata_path = unitTestDataPath("provider")
+ shutil.copy(os.path.join(testdata_path, "bug_19826.gpkg"), tmpfile)
+ vl = QgsVectorLayer(f"{tmpfile}|layerid=0", "test", "ogr")
vl.setSubsetString("name = 'two'")
got = [feat for feat in vl.getFeatures()]
self.assertEqual(len(got), 1)
@@ -582,7 +618,7 @@ def testSelectSubsetString(self):
attributes = got[0].attributes()
self.assertEqual(got[0].id(), 2)
self.assertEqual(attributes[0], 2)
- self.assertEqual(attributes[1], 'two')
+ self.assertEqual(attributes[1], "two")
self.assertNotEqual(attributes[2], None)
# Request by FeatureId on a subset layer
@@ -591,7 +627,7 @@ def testSelectSubsetString(self):
attributes = got[0].attributes()
self.assertEqual(got[0].id(), 2)
self.assertEqual(attributes[0], 2)
- self.assertEqual(attributes[1], 'two')
+ self.assertEqual(attributes[1], "two")
self.assertNotEqual(attributes[2], None)
request = QgsFeatureRequest(2).setSubsetOfAttributes([0])
@@ -611,38 +647,38 @@ def testSelectSubsetString(self):
# Test setSubsetString() with a SELECT ... statement not selecting
# the FID column
- vl = QgsVectorLayer(f'{tmpfile}', 'test', 'ogr')
+ vl = QgsVectorLayer(f"{tmpfile}", "test", "ogr")
vl.setSubsetString("SELECT name FROM test_layer WHERE name = 'two'")
got = [feat for feat in vl.getFeatures()]
self.assertEqual(len(got), 1)
attributes = got[0].attributes()
- self.assertEqual(attributes[0], 'two')
+ self.assertEqual(attributes[0], "two")
def testEditSubsetString(self):
- tmpfile = os.path.join(self.basetestpath, 'testEditSubsetString.gpkg')
- ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile)
- lyr = ds.CreateLayer('test', geom_type=ogr.wkbMultiPolygon)
- lyr.CreateField(ogr.FieldDefn('foo', ogr.OFTString))
+ tmpfile = os.path.join(self.basetestpath, "testEditSubsetString.gpkg")
+ ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile)
+ lyr = ds.CreateLayer("test", geom_type=ogr.wkbMultiPolygon)
+ lyr.CreateField(ogr.FieldDefn("foo", ogr.OFTString))
f = ogr.Feature(lyr.GetLayerDefn())
- f['foo'] = 'bar'
+ f["foo"] = "bar"
lyr.CreateFeature(f)
f = None
f = ogr.Feature(lyr.GetLayerDefn())
- f['foo'] = 'baz'
+ f["foo"] = "baz"
lyr.CreateFeature(f)
f = None
ds = None
- vl = QgsVectorLayer(f'{tmpfile}|layerid=0', 'test', 'ogr')
+ vl = QgsVectorLayer(f"{tmpfile}|layerid=0", "test", "ogr")
self.assertEqual(vl.dataProvider().featureCount(), 2)
# Test adding features
vl.setSubsetString("foo = 'baz'")
self.assertTrue(vl.startEditing())
feature = QgsFeature(vl.fields())
- feature['foo'] = 'abc'
+ feature["foo"] = "abc"
vl.addFeature(feature)
vl.commitChanges()
vl.setSubsetString(None)
@@ -659,23 +695,35 @@ def testEditSubsetString(self):
# Test editing a feature
vl.setSubsetString("foo = 'baz'")
self.assertTrue(vl.startEditing())
- vl.changeAttributeValue(2, 1, 'xx')
+ vl.changeAttributeValue(2, 1, "xx")
vl.commitChanges()
vl.setSubsetString(None)
- self.assertEqual({feat['foo'] for feat in vl.getFeatures()}, {'xx', 'abc'})
+ self.assertEqual({feat["foo"] for feat in vl.getFeatures()}, {"xx", "abc"})
def testStyle(self):
# First test with invalid URI
- vl = QgsVectorLayer('/idont/exist.gpkg', 'test', 'ogr')
-
- self.assertEqual(int(vl.dataProvider().styleStorageCapabilities()) & Qgis.ProviderStyleStorageCapability.LoadFromDatabase, 0)
- self.assertEqual(int(vl.dataProvider().styleStorageCapabilities()) & Qgis.ProviderStyleStorageCapability.SaveToDatabase, 0)
-
- res, err = QgsProviderRegistry.instance().styleExists('ogr', '/idont/exist.gpkg', '')
+ vl = QgsVectorLayer("/idont/exist.gpkg", "test", "ogr")
+
+ self.assertEqual(
+ int(vl.dataProvider().styleStorageCapabilities())
+ & Qgis.ProviderStyleStorageCapability.LoadFromDatabase,
+ 0,
+ )
+ self.assertEqual(
+ int(vl.dataProvider().styleStorageCapabilities())
+ & Qgis.ProviderStyleStorageCapability.SaveToDatabase,
+ 0,
+ )
+
+ res, err = QgsProviderRegistry.instance().styleExists(
+ "ogr", "/idont/exist.gpkg", ""
+ )
self.assertFalse(res)
self.assertTrue(err)
- res, err = QgsProviderRegistry.instance().styleExists('ogr', '/idont/exist.gpkg', 'a style')
+ res, err = QgsProviderRegistry.instance().styleExists(
+ "ogr", "/idont/exist.gpkg", "a style"
+ )
self.assertFalse(res)
self.assertTrue(err)
@@ -690,43 +738,53 @@ def testStyle(self):
self.assertFalse(qml)
self.assertTrue(errmsg)
- qml, success = vl.loadNamedStyle('/idont/exist.gpkg')
+ qml, success = vl.loadNamedStyle("/idont/exist.gpkg")
self.assertFalse(success)
errorMsg = vl.saveStyleToDatabase("name", "description", False, "")
self.assertTrue(errorMsg)
# Now with valid URI
- tmpfile = os.path.join(self.basetestpath, 'testStyle.gpkg')
- ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile)
- lyr = ds.CreateLayer('test', geom_type=ogr.wkbMultiPolygon)
- lyr.CreateField(ogr.FieldDefn('foo', ogr.OFTString))
+ tmpfile = os.path.join(self.basetestpath, "testStyle.gpkg")
+ ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile)
+ lyr = ds.CreateLayer("test", geom_type=ogr.wkbMultiPolygon)
+ lyr.CreateField(ogr.FieldDefn("foo", ogr.OFTString))
f = ogr.Feature(lyr.GetLayerDefn())
- f['foo'] = 'bar'
+ f["foo"] = "bar"
lyr.CreateFeature(f)
f = None
- lyr = ds.CreateLayer('test2', geom_type=ogr.wkbMultiPolygon)
- lyr.CreateField(ogr.FieldDefn('foo', ogr.OFTString))
+ lyr = ds.CreateLayer("test2", geom_type=ogr.wkbMultiPolygon)
+ lyr.CreateField(ogr.FieldDefn("foo", ogr.OFTString))
f = ogr.Feature(lyr.GetLayerDefn())
- f['foo'] = 'bar'
+ f["foo"] = "bar"
lyr.CreateFeature(f)
f = None
ds = None
- vl = QgsVectorLayer(f'{tmpfile}|layername=test', 'test', 'ogr')
+ vl = QgsVectorLayer(f"{tmpfile}|layername=test", "test", "ogr")
self.assertTrue(vl.isValid())
- vl2 = QgsVectorLayer(f'{tmpfile}|layername=test2', 'test2', 'ogr')
+ vl2 = QgsVectorLayer(f"{tmpfile}|layername=test2", "test2", "ogr")
self.assertTrue(vl2.isValid())
- self.assertEqual(int(vl.dataProvider().styleStorageCapabilities()) & Qgis.ProviderStyleStorageCapability.LoadFromDatabase, Qgis.ProviderStyleStorageCapability.LoadFromDatabase)
- self.assertEqual(int(vl.dataProvider().styleStorageCapabilities()) & Qgis.ProviderStyleStorageCapability.SaveToDatabase, Qgis.ProviderStyleStorageCapability.SaveToDatabase)
+ self.assertEqual(
+ int(vl.dataProvider().styleStorageCapabilities())
+ & Qgis.ProviderStyleStorageCapability.LoadFromDatabase,
+ Qgis.ProviderStyleStorageCapability.LoadFromDatabase,
+ )
+ self.assertEqual(
+ int(vl.dataProvider().styleStorageCapabilities())
+ & Qgis.ProviderStyleStorageCapability.SaveToDatabase,
+ Qgis.ProviderStyleStorageCapability.SaveToDatabase,
+ )
# style tables don't exist yet
- res, err = QgsProviderRegistry.instance().styleExists('ogr', vl.source(), '')
+ res, err = QgsProviderRegistry.instance().styleExists("ogr", vl.source(), "")
self.assertFalse(res)
self.assertFalse(err)
- res, err = QgsProviderRegistry.instance().styleExists('ogr', vl2.source(), 'a style')
+ res, err = QgsProviderRegistry.instance().styleExists(
+ "ogr", vl2.source(), "a style"
+ )
self.assertFalse(res)
self.assertFalse(err)
@@ -741,19 +799,23 @@ def testStyle(self):
self.assertFalse(qml)
self.assertTrue(errmsg)
- qml, success = vl.loadNamedStyle(f'{tmpfile}|layerid=0')
+ qml, success = vl.loadNamedStyle(f"{tmpfile}|layerid=0")
self.assertFalse(success)
errorMsg = vl.saveStyleToDatabase("name", "description", False, "")
self.assertFalse(errorMsg)
- res, err = QgsProviderRegistry.instance().styleExists('ogr', vl.source(), '')
+ res, err = QgsProviderRegistry.instance().styleExists("ogr", vl.source(), "")
self.assertFalse(res)
self.assertFalse(err)
- res, err = QgsProviderRegistry.instance().styleExists('ogr', vl.source(), 'a style')
+ res, err = QgsProviderRegistry.instance().styleExists(
+ "ogr", vl.source(), "a style"
+ )
self.assertFalse(res)
self.assertFalse(err)
- res, err = QgsProviderRegistry.instance().styleExists('ogr', vl.source(), 'name')
+ res, err = QgsProviderRegistry.instance().styleExists(
+ "ogr", vl.source(), "name"
+ )
self.assertTrue(res)
self.assertFalse(err)
@@ -764,63 +826,74 @@ def testStyle(self):
related_count, idlist, namelist, desclist, errmsg = vl.listStylesInDatabase()
self.assertEqual(related_count, 1)
self.assertFalse(errmsg)
- self.assertEqual(idlist, ['1'])
- self.assertEqual(namelist, ['name'])
- self.assertEqual(desclist, ['description'])
+ self.assertEqual(idlist, ["1"])
+ self.assertEqual(namelist, ["name"])
+ self.assertEqual(desclist, ["description"])
qml, errmsg = vl.getStyleFromDatabase("100")
self.assertFalse(qml)
self.assertTrue(errmsg)
qml, errmsg = vl.getStyleFromDatabase("1")
- self.assertTrue(qml.startswith('= 3.4.2 opening a GPKG file doesn't turn on WAL journal_mode """
+ """Test that with GDAL >= 3.4.2 opening a GPKG file doesn't turn on WAL journal_mode"""
- srcpath = os.path.join(TEST_DATA_DIR, 'provider')
- srcfile = os.path.join(srcpath, 'geopackage.gpkg')
+ srcpath = os.path.join(TEST_DATA_DIR, "provider")
+ srcfile = os.path.join(srcpath, "geopackage.gpkg")
last_modified = QFileInfo(srcfile).lastModified()
- vl = QgsVectorLayer(f'{srcfile}' + "|layername=geopackage", 'test', 'ogr')
- self.assertEqual(TestPyQgsOGRProviderGpkg._getJournalMode(srcfile), 'delete')
+ vl = QgsVectorLayer(f"{srcfile}" + "|layername=geopackage", "test", "ogr")
+ self.assertEqual(TestPyQgsOGRProviderGpkg._getJournalMode(srcfile), "delete")
del vl
self.assertEqual(last_modified, QFileInfo(srcfile).lastModified())
- shutil.copy(os.path.join(srcpath, 'geopackage.gpkg'), self.basetestpath)
- tmpfile = os.path.join(self.basetestpath, 'geopackage.gpkg')
+ shutil.copy(os.path.join(srcpath, "geopackage.gpkg"), self.basetestpath)
+ tmpfile = os.path.join(self.basetestpath, "geopackage.gpkg")
- vl = QgsVectorLayer(f'{tmpfile}' + "|layername=geopackage", 'test', 'ogr')
+ vl = QgsVectorLayer(f"{tmpfile}" + "|layername=geopackage", "test", "ogr")
- self.assertEqual(TestPyQgsOGRProviderGpkg._getJournalMode(tmpfile), 'delete')
+ self.assertEqual(TestPyQgsOGRProviderGpkg._getJournalMode(tmpfile), "delete")
vl.startEditing()
- self.assertEqual(TestPyQgsOGRProviderGpkg._getJournalMode(tmpfile), 'wal')
+ self.assertEqual(TestPyQgsOGRProviderGpkg._getJournalMode(tmpfile), "wal")
vl.commitChanges()
- self.assertEqual(TestPyQgsOGRProviderGpkg._getJournalMode(tmpfile), 'delete')
+ self.assertEqual(TestPyQgsOGRProviderGpkg._getJournalMode(tmpfile), "delete")
def testSimulatedDBManagerImport(self):
- uri = 'point?field=f1:int'
- uri += '&field=f2:double(6,4)'
- uri += '&field=f3:string(20)'
+ uri = "point?field=f1:int"
+ uri += "&field=f2:double(6,4)"
+ uri += "&field=f3:string(20)"
mem_lyr = QgsVectorLayer(uri, "x", "memory")
self.assertTrue(mem_lyr.isValid())
f = QgsFeature(mem_lyr.fields())
- f['f1'] = 1
- f['f2'] = 123.456
- f['f3'] = '12345678.90123456789'
+ f["f1"] = 1
+ f["f2"] = 123.456
+ f["f3"] = "12345678.90123456789"
f2 = QgsFeature(mem_lyr.fields())
- f2['f1'] = 2
+ f2["f1"] = 2
mem_lyr.dataProvider().addFeatures([f, f2])
# Test creating new DB
- tmpfile = os.path.join(self.basetestpath, 'testSimulatedDBManagerImport.gpkg')
+ tmpfile = os.path.join(self.basetestpath, "testSimulatedDBManagerImport.gpkg")
options = {}
- options['driverName'] = 'GPKG'
- err = QgsVectorLayerExporter.exportLayer(mem_lyr, tmpfile, "ogr", mem_lyr.crs(), False, options)
- self.assertEqual(err[0], QgsVectorLayerExporter.ExportError.NoError,
- f'unexpected import error {err}')
+ options["driverName"] = "GPKG"
+ err = QgsVectorLayerExporter.exportLayer(
+ mem_lyr, tmpfile, "ogr", mem_lyr.crs(), False, options
+ )
+ self.assertEqual(
+ err[0],
+ QgsVectorLayerExporter.ExportError.NoError,
+ f"unexpected import error {err}",
+ )
lyr = QgsVectorLayer(tmpfile, "y", "ogr")
self.assertTrue(lyr.isValid())
features = lyr.getFeatures()
f = next(features)
- self.assertEqual(f['f1'], 1)
- self.assertEqual(f['f2'], 123.456)
- self.assertEqual(f['f3'], '12345678.90123456789')
+ self.assertEqual(f["f1"], 1)
+ self.assertEqual(f["f2"], 123.456)
+ self.assertEqual(f["f3"], "12345678.90123456789")
f = next(features)
- self.assertEqual(f['f1'], 2)
+ self.assertEqual(f["f1"], 2)
features = None
del lyr
@@ -931,107 +1012,137 @@ def testSimulatedDBManagerImport(self):
mem_lyr = QgsVectorLayer(uri, "x", "memory")
self.assertTrue(mem_lyr.isValid())
f = QgsFeature(mem_lyr.fields())
- f['f1'] = 1
- f['f2'] = 2
+ f["f1"] = 1
+ f["f2"] = 2
mem_lyr.dataProvider().addFeatures([f])
options = {}
- options['update'] = True
- options['driverName'] = 'GPKG'
- options['layerName'] = 'my_out_table'
- err = QgsVectorLayerExporter.exportLayer(mem_lyr, tmpfile, "ogr", mem_lyr.crs(), False, options)
- self.assertEqual(err[0], QgsVectorLayerExporter.ExportError.NoError,
- f'unexpected import error {err}')
+ options["update"] = True
+ options["driverName"] = "GPKG"
+ options["layerName"] = "my_out_table"
+ err = QgsVectorLayerExporter.exportLayer(
+ mem_lyr, tmpfile, "ogr", mem_lyr.crs(), False, options
+ )
+ self.assertEqual(
+ err[0],
+ QgsVectorLayerExporter.ExportError.NoError,
+ f"unexpected import error {err}",
+ )
lyr = QgsVectorLayer(tmpfile + "|layername=my_out_table", "y", "ogr")
self.assertTrue(lyr.isValid())
features = lyr.getFeatures()
f = next(features)
- self.assertEqual(f['f1'], 1)
- self.assertEqual(f['f2'], 2)
+ self.assertEqual(f["f1"], 1)
+ self.assertEqual(f["f2"], 2)
features = None
del lyr
# Test overwriting without overwrite option
- err = QgsVectorLayerExporter.exportLayer(mem_lyr, tmpfile, "ogr", mem_lyr.crs(), False, options)
+ err = QgsVectorLayerExporter.exportLayer(
+ mem_lyr, tmpfile, "ogr", mem_lyr.crs(), False, options
+ )
self.assertEqual(err[0], QgsVectorLayerExporter.ExportError.ErrCreateDataSource)
# Test overwriting, without specifying a layer name
mem_lyr = QgsVectorLayer(uri, "x", "memory")
self.assertTrue(mem_lyr.isValid())
f = QgsFeature(mem_lyr.fields())
- f['f1'] = 3
- f['f2'] = 4
+ f["f1"] = 3
+ f["f2"] = 4
mem_lyr.dataProvider().addFeatures([f])
options = {}
- options['driverName'] = 'GPKG'
- options['overwrite'] = True
- err = QgsVectorLayerExporter.exportLayer(mem_lyr, tmpfile, "ogr", mem_lyr.crs(), False, options)
- self.assertEqual(err[0], QgsVectorLayerExporter.ExportError.NoError,
- f'unexpected import error {err}')
+ options["driverName"] = "GPKG"
+ options["overwrite"] = True
+ err = QgsVectorLayerExporter.exportLayer(
+ mem_lyr, tmpfile, "ogr", mem_lyr.crs(), False, options
+ )
+ self.assertEqual(
+ err[0],
+ QgsVectorLayerExporter.ExportError.NoError,
+ f"unexpected import error {err}",
+ )
lyr = QgsVectorLayer(tmpfile, "y", "ogr")
self.assertTrue(lyr.isValid())
features = lyr.getFeatures()
f = next(features)
- self.assertEqual(f['f1'], 3)
- self.assertEqual(f['f2'], 4)
+ self.assertEqual(f["f1"], 3)
+ self.assertEqual(f["f2"], 4)
features = None
def testExportLayerToExistingDatabase(self):
fields = QgsFields()
- fields.append(QgsField('f1', QVariant.Int))
- tmpfile = os.path.join(self.basetestpath, 'testCreateNewGeopackage.gpkg')
+ fields.append(QgsField("f1", QVariant.Int))
+ tmpfile = os.path.join(self.basetestpath, "testCreateNewGeopackage.gpkg")
options = {}
- options['update'] = True
- options['driverName'] = 'GPKG'
- options['layerName'] = 'table1'
- exporter = QgsVectorLayerExporter(tmpfile, "ogr", fields, QgsWkbTypes.Type.Polygon,
- QgsCoordinateReferenceSystem('EPSG:3111'), False, options)
- self.assertFalse(exporter.errorCode(),
- f'unexpected export error {exporter.errorCode()}: {exporter.errorMessage()}')
+ options["update"] = True
+ options["driverName"] = "GPKG"
+ options["layerName"] = "table1"
+ exporter = QgsVectorLayerExporter(
+ tmpfile,
+ "ogr",
+ fields,
+ QgsWkbTypes.Type.Polygon,
+ QgsCoordinateReferenceSystem("EPSG:3111"),
+ False,
+ options,
+ )
+ self.assertFalse(
+ exporter.errorCode(),
+ f"unexpected export error {exporter.errorCode()}: {exporter.errorMessage()}",
+ )
del exporter
- options['layerName'] = 'table2'
- exporter = QgsVectorLayerExporter(tmpfile, "ogr", fields, QgsWkbTypes.Type.Point, QgsCoordinateReferenceSystem('EPSG:3113'),
- False, options)
- self.assertFalse(exporter.errorCode(),
- f'unexpected export error {exporter.errorCode()} : {exporter.errorMessage()}')
+ options["layerName"] = "table2"
+ exporter = QgsVectorLayerExporter(
+ tmpfile,
+ "ogr",
+ fields,
+ QgsWkbTypes.Type.Point,
+ QgsCoordinateReferenceSystem("EPSG:3113"),
+ False,
+ options,
+ )
+ self.assertFalse(
+ exporter.errorCode(),
+ f"unexpected export error {exporter.errorCode()} : {exporter.errorMessage()}",
+ )
del exporter
# make sure layers exist
- lyr = QgsVectorLayer(f'{tmpfile}|layername=table1', "lyr1", "ogr")
+ lyr = QgsVectorLayer(f"{tmpfile}|layername=table1", "lyr1", "ogr")
self.assertTrue(lyr.isValid())
- self.assertEqual(lyr.crs().authid(), 'EPSG:3111')
+ self.assertEqual(lyr.crs().authid(), "EPSG:3111")
self.assertEqual(lyr.wkbType(), QgsWkbTypes.Type.Polygon)
- lyr2 = QgsVectorLayer(f'{tmpfile}|layername=table2', "lyr2", "ogr")
+ lyr2 = QgsVectorLayer(f"{tmpfile}|layername=table2", "lyr2", "ogr")
self.assertTrue(lyr2.isValid())
- self.assertEqual(lyr2.crs().authid(), 'EPSG:3113')
+ self.assertEqual(lyr2.crs().authid(), "EPSG:3113")
self.assertEqual(lyr2.wkbType(), QgsWkbTypes.Type.Point)
def testGeopackageTwoLayerEdition(self):
- ''' test https://github.com/qgis/QGIS/issues/24933 '''
- tmpfile = os.path.join(self.basetestpath, 'testGeopackageTwoLayerEdition.gpkg')
- ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile)
- lyr = ds.CreateLayer('layer1', geom_type=ogr.wkbPoint)
- lyr.CreateField(ogr.FieldDefn('attr', ogr.OFTInteger))
+ """test https://github.com/qgis/QGIS/issues/24933"""
+ tmpfile = os.path.join(self.basetestpath, "testGeopackageTwoLayerEdition.gpkg")
+ ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile)
+ lyr = ds.CreateLayer("layer1", geom_type=ogr.wkbPoint)
+ lyr.CreateField(ogr.FieldDefn("attr", ogr.OFTInteger))
f = ogr.Feature(lyr.GetLayerDefn())
- f.SetGeometry(ogr.CreateGeometryFromWkt('POINT(0 0)'))
+ f.SetGeometry(ogr.CreateGeometryFromWkt("POINT(0 0)"))
lyr.CreateFeature(f)
f = None
- lyr = ds.CreateLayer('layer2', geom_type=ogr.wkbPoint)
- lyr.CreateField(ogr.FieldDefn('attr', ogr.OFTInteger))
+ lyr = ds.CreateLayer("layer2", geom_type=ogr.wkbPoint)
+ lyr.CreateField(ogr.FieldDefn("attr", ogr.OFTInteger))
f = ogr.Feature(lyr.GetLayerDefn())
- f.SetGeometry(ogr.CreateGeometryFromWkt('POINT(1 1)'))
+ f.SetGeometry(ogr.CreateGeometryFromWkt("POINT(1 1)"))
lyr.CreateFeature(f)
f = None
ds = None
- vl1 = QgsVectorLayer(f'{tmpfile}' + "|layername=layer1", 'layer1', 'ogr')
- vl2 = QgsVectorLayer(f'{tmpfile}' + "|layername=layer2", 'layer2', 'ogr')
+ vl1 = QgsVectorLayer(f"{tmpfile}" + "|layername=layer1", "layer1", "ogr")
+ vl2 = QgsVectorLayer(f"{tmpfile}" + "|layername=layer2", "layer2", "ogr")
# Edit vl1, vl2 multiple times
self.assertTrue(vl1.startEditing())
self.assertTrue(vl2.startEditing())
- self.assertTrue(vl1.changeGeometry(1, QgsGeometry.fromWkt('Point (2 2)')))
- self.assertTrue(vl2.changeGeometry(1, QgsGeometry.fromWkt('Point (3 3)')))
+ self.assertTrue(vl1.changeGeometry(1, QgsGeometry.fromWkt("Point (2 2)")))
+ self.assertTrue(vl2.changeGeometry(1, QgsGeometry.fromWkt("Point (3 3)")))
self.assertTrue(vl1.commitChanges())
self.assertTrue(vl2.commitChanges())
@@ -1044,8 +1155,8 @@ def testGeopackageTwoLayerEdition(self):
self.assertTrue(vl1.startEditing())
self.assertTrue(vl2.startEditing())
- self.assertTrue(vl1.changeGeometry(1, QgsGeometry.fromWkt('Point (4 4)')))
- self.assertTrue(vl2.changeGeometry(1, QgsGeometry.fromWkt('Point (5 5)')))
+ self.assertTrue(vl1.changeGeometry(1, QgsGeometry.fromWkt("Point (4 4)")))
+ self.assertTrue(vl2.changeGeometry(1, QgsGeometry.fromWkt("Point (5 5)")))
self.assertTrue(vl1.commitChanges())
self.assertTrue(vl2.commitChanges())
@@ -1053,36 +1164,42 @@ def testGeopackageTwoLayerEdition(self):
vl2 = None
# Check everything is as expected after re-opening
- vl1 = QgsVectorLayer(f'{tmpfile}' + "|layername=layer1", 'layer1', 'ogr')
- vl2 = QgsVectorLayer(f'{tmpfile}' + "|layername=layer2", 'layer2', 'ogr')
+ vl1 = QgsVectorLayer(f"{tmpfile}" + "|layername=layer1", "layer1", "ogr")
+ vl2 = QgsVectorLayer(f"{tmpfile}" + "|layername=layer2", "layer2", "ogr")
got = [feat for feat in vl1.getFeatures()][0]
got_geom = got.geometry()
- self.assertEqual(got['attr'], 100)
- reference = QgsGeometry.fromWkt('Point (4 4)')
- self.assertEqual(got_geom.asWkb(), reference.asWkb(),
- f'Expected {reference.asWkt()}, got {got_geom.asWkt()}')
+ self.assertEqual(got["attr"], 100)
+ reference = QgsGeometry.fromWkt("Point (4 4)")
+ self.assertEqual(
+ got_geom.asWkb(),
+ reference.asWkb(),
+ f"Expected {reference.asWkt()}, got {got_geom.asWkt()}",
+ )
got = [feat for feat in vl2.getFeatures()][0]
got_geom = got.geometry()
- self.assertEqual(got['attr'], 101)
- reference = QgsGeometry.fromWkt('Point (5 5)')
- self.assertEqual(got_geom.asWkb(), reference.asWkb(),
- f'Expected {reference.asWkt()}, got {got_geom.asWkt()}')
+ self.assertEqual(got["attr"], 101)
+ reference = QgsGeometry.fromWkt("Point (5 5)")
+ self.assertEqual(
+ got_geom.asWkb(),
+ reference.asWkb(),
+ f"Expected {reference.asWkt()}, got {got_geom.asWkt()}",
+ )
def testReplaceLayerWhileOpen(self):
- ''' Replace an existing geopackage layer whilst it's open in the project'''
- tmpfile = os.path.join(self.basetestpath, 'testGeopackageReplaceOpenLayer.gpkg')
- ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile)
- lyr = ds.CreateLayer('layer1', geom_type=ogr.wkbPoint)
- lyr.CreateField(ogr.FieldDefn('attr', ogr.OFTInteger))
- lyr.CreateField(ogr.FieldDefn('attr2', ogr.OFTInteger))
+ """Replace an existing geopackage layer whilst it's open in the project"""
+ tmpfile = os.path.join(self.basetestpath, "testGeopackageReplaceOpenLayer.gpkg")
+ ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile)
+ lyr = ds.CreateLayer("layer1", geom_type=ogr.wkbPoint)
+ lyr.CreateField(ogr.FieldDefn("attr", ogr.OFTInteger))
+ lyr.CreateField(ogr.FieldDefn("attr2", ogr.OFTInteger))
f = ogr.Feature(lyr.GetLayerDefn())
- f.SetGeometry(ogr.CreateGeometryFromWkt('POINT(0 0)'))
+ f.SetGeometry(ogr.CreateGeometryFromWkt("POINT(0 0)"))
lyr.CreateFeature(f)
f = None
- vl1 = QgsVectorLayer(f'{tmpfile}' + "|layername=layer1", 'layer1', 'ogr')
+ vl1 = QgsVectorLayer(f"{tmpfile}" + "|layername=layer1", "layer1", "ogr")
p = QgsProject()
p.addMapLayer(vl1)
request = QgsFeatureRequest().setSubsetOfAttributes([0])
@@ -1090,68 +1207,88 @@ def testReplaceLayerWhileOpen(self):
self.assertEqual(len(features), 1)
# now, overwrite the layer with a different geometry type and fields
- ds.DeleteLayer('layer1')
- lyr = ds.CreateLayer('layer1', geom_type=ogr.wkbLineString)
- lyr.CreateField(ogr.FieldDefn('attr', ogr.OFTString))
+ ds.DeleteLayer("layer1")
+ lyr = ds.CreateLayer("layer1", geom_type=ogr.wkbLineString)
+ lyr.CreateField(ogr.FieldDefn("attr", ogr.OFTString))
f = ogr.Feature(lyr.GetLayerDefn())
- f.SetGeometry(ogr.CreateGeometryFromWkt('LineString(0 0, 1 1)'))
+ f.SetGeometry(ogr.CreateGeometryFromWkt("LineString(0 0, 1 1)"))
lyr.CreateFeature(f)
f = None
- vl2 = QgsVectorLayer(f'{tmpfile}' + "|layername=layer1", 'layer2', 'ogr')
+ vl2 = QgsVectorLayer(f"{tmpfile}" + "|layername=layer1", "layer2", "ogr")
p.addMapLayer(vl2)
features = [f for f in vl1.getFeatures(request)]
self.assertEqual(len(features), 1)
def testPkAttributeIndexes(self):
- ''' Test the primary key index '''
- tmpfile = os.path.join(self.basetestpath, 'testPkAttributeIndexes.gpkg')
- ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile)
- ds.CreateLayer('test', geom_type=ogr.wkbPoint,
- options=['COLUMN_TYPES=foo=int8,bar=string', 'GEOMETRY_NAME=the_geom', 'FID=customfid'])
+ """Test the primary key index"""
+ tmpfile = os.path.join(self.basetestpath, "testPkAttributeIndexes.gpkg")
+ ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile)
+ ds.CreateLayer(
+ "test",
+ geom_type=ogr.wkbPoint,
+ options=[
+ "COLUMN_TYPES=foo=int8,bar=string",
+ "GEOMETRY_NAME=the_geom",
+ "FID=customfid",
+ ],
+ )
ds = None
- vl = QgsVectorLayer(f'{tmpfile}|layerid=0', 'test', 'ogr')
+ vl = QgsVectorLayer(f"{tmpfile}|layerid=0", "test", "ogr")
pks = vl.primaryKeyAttributes()
fields = vl.fields()
pkfield = fields.at(pks[0])
self.assertEqual(len(pks), 1)
self.assertEqual(pks[0], 0)
- self.assertEqual(pkfield.name(), 'customfid')
- self.assertTrue(pkfield.constraints().constraints() & QgsFieldConstraints.Constraint.ConstraintUnique)
+ self.assertEqual(pkfield.name(), "customfid")
+ self.assertTrue(
+ pkfield.constraints().constraints()
+ & QgsFieldConstraints.Constraint.ConstraintUnique
+ )
def testSublayerWithComplexLayerName(self):
- ''' Test reading a gpkg with a sublayer name containing : '''
- tmpfile = os.path.join(self.basetestpath, 'testGeopackageComplexLayerName.gpkg')
- ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile)
- lyr = ds.CreateLayer('layer1:', geom_type=ogr.wkbPoint, options=['GEOMETRY_NAME=geom:'])
- lyr.CreateField(ogr.FieldDefn('attr', ogr.OFTInteger))
+ """Test reading a gpkg with a sublayer name containing :"""
+ tmpfile = os.path.join(self.basetestpath, "testGeopackageComplexLayerName.gpkg")
+ ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile)
+ lyr = ds.CreateLayer(
+ "layer1:", geom_type=ogr.wkbPoint, options=["GEOMETRY_NAME=geom:"]
+ )
+ lyr.CreateField(ogr.FieldDefn("attr", ogr.OFTInteger))
f = ogr.Feature(lyr.GetLayerDefn())
- f.SetGeometry(ogr.CreateGeometryFromWkt('POINT(0 0)'))
+ f.SetGeometry(ogr.CreateGeometryFromWkt("POINT(0 0)"))
lyr.CreateFeature(f)
f = None
- vl = QgsVectorLayer(f'{tmpfile}', 'layer', 'ogr')
+ vl = QgsVectorLayer(f"{tmpfile}", "layer", "ogr")
self.assertEqual(1, vl.dataProvider().subLayerCount())
- self.assertEqual(vl.dataProvider().subLayers(),
- [QgsDataProvider.SUBLAYER_SEPARATOR.join(['0', 'layer1:', '1', 'Point', 'geom:', ''])])
+ self.assertEqual(
+ vl.dataProvider().subLayers(),
+ [
+ QgsDataProvider.SUBLAYER_SEPARATOR.join(
+ ["0", "layer1:", "1", "Point", "geom:", ""]
+ )
+ ],
+ )
def testGeopackageManyLayers(self):
- ''' test opening more than 64 layers without running out of Spatialite connections '''
+ """test opening more than 64 layers without running out of Spatialite connections"""
- tmpfile = os.path.join(self.basetestpath, 'testGeopackageManyLayers.gpkg')
- ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile)
+ tmpfile = os.path.join(self.basetestpath, "testGeopackageManyLayers.gpkg")
+ ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile)
for i in range(70):
- lyr = ds.CreateLayer('layer%d' % i, geom_type=ogr.wkbPoint)
+ lyr = ds.CreateLayer("layer%d" % i, geom_type=ogr.wkbPoint)
f = ogr.Feature(lyr.GetLayerDefn())
- f.SetGeometry(ogr.CreateGeometryFromWkt('POINT(%d 0)' % i))
+ f.SetGeometry(ogr.CreateGeometryFromWkt("POINT(%d 0)" % i))
lyr.CreateFeature(f)
f = None
ds = None
vl_tab = []
for i in range(70):
- layername = 'layer%d' % i
- vl = QgsVectorLayer(f'{tmpfile}' + "|layername=" + layername, layername, 'ogr')
+ layername = "layer%d" % i
+ vl = QgsVectorLayer(
+ f"{tmpfile}" + "|layername=" + layername, layername, "ogr"
+ )
self.assertTrue(vl.isValid())
vl_tab += [vl]
@@ -1174,52 +1311,66 @@ def testGeopackageManyLayers(self):
self.assertIn(count, (2, 3))
# Re-open an already opened layers. We should get a new handle
- layername = 'layer%d' % 0
- vl_extra0 = QgsVectorLayer(f'{tmpfile}' + "|layername=" + layername, layername, 'ogr')
+ layername = "layer%d" % 0
+ vl_extra0 = QgsVectorLayer(
+ f"{tmpfile}" + "|layername=" + layername, layername, "ogr"
+ )
self.assertTrue(vl_extra0.isValid())
countNew = count_opened_filedescriptors(tmpfile)
if countNew > 0:
self.assertLessEqual(countNew, 4) # for some reason we get 4 and not 3
- layername = 'layer%d' % 1
- vl_extra1 = QgsVectorLayer(f'{tmpfile}' + "|layername=" + layername, layername, 'ogr')
+ layername = "layer%d" % 1
+ vl_extra1 = QgsVectorLayer(
+ f"{tmpfile}" + "|layername=" + layername, layername, "ogr"
+ )
self.assertTrue(vl_extra1.isValid())
countNew2 = count_opened_filedescriptors(tmpfile)
self.assertEqual(countNew2, countNew)
def testGeopackageRefreshIfTableListUpdated(self):
- ''' test that creating/deleting a layer is reflected when opening a new layer '''
+ """test that creating/deleting a layer is reflected when opening a new layer"""
- tmpfile = os.path.join(self.basetestpath, 'testGeopackageRefreshIfTableListUpdated.gpkg')
- ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile)
- ds.CreateLayer('test', geom_type=ogr.wkbPoint)
+ tmpfile = os.path.join(
+ self.basetestpath, "testGeopackageRefreshIfTableListUpdated.gpkg"
+ )
+ ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile)
+ ds.CreateLayer("test", geom_type=ogr.wkbPoint)
ds = None
- vl = QgsVectorLayer(f'{tmpfile}' + "|layername=" + "test", 'test', 'ogr')
+ vl = QgsVectorLayer(f"{tmpfile}" + "|layername=" + "test", "test", "ogr")
self.assertTrue(vl.extent().isNull())
time.sleep(1) # so timestamp gets updated
ds = ogr.Open(tmpfile, update=1)
- ds.CreateLayer('test2', geom_type=ogr.wkbPoint)
+ ds.CreateLayer("test2", geom_type=ogr.wkbPoint)
ds = None
- vl2 = QgsVectorLayer(f'{tmpfile}', 'test', 'ogr')
+ vl2 = QgsVectorLayer(f"{tmpfile}", "test", "ogr")
self.assertEqual(2, vl2.dataProvider().subLayerCount())
vl2.subLayers()
- self.assertEqual(vl2.dataProvider().subLayers(),
- [QgsDataProvider.SUBLAYER_SEPARATOR.join(['0', 'test', '0', 'Point', 'geom', '']),
- QgsDataProvider.SUBLAYER_SEPARATOR.join(['1', 'test2', '0', 'Point', 'geom', ''])])
+ self.assertEqual(
+ vl2.dataProvider().subLayers(),
+ [
+ QgsDataProvider.SUBLAYER_SEPARATOR.join(
+ ["0", "test", "0", "Point", "geom", ""]
+ ),
+ QgsDataProvider.SUBLAYER_SEPARATOR.join(
+ ["1", "test2", "0", "Point", "geom", ""]
+ ),
+ ],
+ )
def testGeopackageLargeFID(self):
- tmpfile = os.path.join(self.basetestpath, 'testGeopackageLargeFID.gpkg')
- ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile)
- lyr = ds.CreateLayer('test', geom_type=ogr.wkbPoint)
- lyr.CreateField(ogr.FieldDefn('str_field', ogr.OFTString))
+ tmpfile = os.path.join(self.basetestpath, "testGeopackageLargeFID.gpkg")
+ ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile)
+ lyr = ds.CreateLayer("test", geom_type=ogr.wkbPoint)
+ lyr.CreateField(ogr.FieldDefn("str_field", ogr.OFTString))
ds = None
- vl = QgsVectorLayer(f'{tmpfile}' + "|layername=" + "test", 'test', 'ogr')
+ vl = QgsVectorLayer(f"{tmpfile}" + "|layername=" + "test", "test", "ogr")
f = QgsFeature()
f.setAttributes([1234567890123, None])
f2 = QgsFeature()
@@ -1229,42 +1380,53 @@ def testGeopackageLargeFID(self):
self.assertTrue(vl.commitChanges())
got = [feat for feat in vl.getFeatures(QgsFeatureRequest(1234567890123))][0]
- self.assertEqual(got['fid'], 1234567890123)
+ self.assertEqual(got["fid"], 1234567890123)
self.assertTrue(vl.startEditing())
- self.assertTrue(vl.changeGeometry(1234567890123, QgsGeometry.fromWkt('Point (3 50)')))
- self.assertTrue(vl.changeAttributeValue(1234567890123, 1, 'foo'))
+ self.assertTrue(
+ vl.changeGeometry(1234567890123, QgsGeometry.fromWkt("Point (3 50)"))
+ )
+ self.assertTrue(vl.changeAttributeValue(1234567890123, 1, "foo"))
self.assertTrue(vl.commitChanges())
got = [feat for feat in vl.getFeatures(QgsFeatureRequest(1234567890123))][0]
- self.assertEqual(got['str_field'], 'foo')
+ self.assertEqual(got["str_field"], "foo")
got_geom = got.geometry()
self.assertIsNotNone(got_geom)
# We don't change the FID, so OK
self.assertTrue(vl.startEditing())
- self.assertTrue(vl.dataProvider().changeAttributeValues({1234567890123: {0: 1234567890123, 1: 'bar'},
- 1234567890124: {0: 1234567890124, 1: 'bar2'}}))
+ self.assertTrue(
+ vl.dataProvider().changeAttributeValues(
+ {
+ 1234567890123: {0: 1234567890123, 1: "bar"},
+ 1234567890124: {0: 1234567890124, 1: "bar2"},
+ }
+ )
+ )
self.assertTrue(vl.commitChanges())
got = [feat for feat in vl.getFeatures(QgsFeatureRequest(1234567890123))][0]
- self.assertEqual(got['str_field'], 'bar')
+ self.assertEqual(got["str_field"], "bar")
got = [feat for feat in vl.getFeatures(QgsFeatureRequest(1234567890124))][0]
- self.assertEqual(got['str_field'], 'bar2')
+ self.assertEqual(got["str_field"], "bar2")
# We try to change the FID, not allowed
# also check that all changes where reverted
self.assertTrue(vl.startEditing())
- self.assertFalse(vl.dataProvider().changeAttributeValues({1234567890123: {0: 1, 1: 'baz'},
- 1234567890124: {1: 'baz2'}}))
+ self.assertFalse(
+ vl.dataProvider().changeAttributeValues(
+ {1234567890123: {0: 1, 1: "baz"}, 1234567890124: {1: "baz2"}}
+ )
+ )
self.assertTrue(vl.commitChanges())
got = [feat for feat in vl.getFeatures(QgsFeatureRequest(1234567890123))][0]
- self.assertEqual(got['str_field'], 'bar')
+ self.assertEqual(got["str_field"], "bar")
got = [feat for feat in vl.getFeatures(QgsFeatureRequest(1234567890124))][0]
- self.assertEqual(got['str_field'], 'bar2')
+ self.assertEqual(got["str_field"], "bar2")
self.assertTrue(vl.startEditing())
self.assertTrue(vl.deleteFeature(1234567890123))
@@ -1272,134 +1434,171 @@ def testGeopackageLargeFID(self):
def test_AddFeatureNullFid(self):
"""Test gpkg feature with NULL fid can be added"""
- tmpfile = os.path.join(self.basetestpath, 'testGeopackageSplitFeatures.gpkg')
- ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile)
- lyr = ds.CreateLayer('test', geom_type=ogr.wkbPolygon)
- lyr.CreateField(ogr.FieldDefn('str_field', ogr.OFTString))
+ tmpfile = os.path.join(self.basetestpath, "testGeopackageSplitFeatures.gpkg")
+ ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile)
+ lyr = ds.CreateLayer("test", geom_type=ogr.wkbPolygon)
+ lyr.CreateField(ogr.FieldDefn("str_field", ogr.OFTString))
ds = None
- layer = QgsVectorLayer(f'{tmpfile}' + "|layername=" + "test", 'test', 'ogr')
+ layer = QgsVectorLayer(f"{tmpfile}" + "|layername=" + "test", "test", "ogr")
# Check that pk field has unique constraint
fields = layer.fields()
pkfield = fields.at(0)
- self.assertTrue(pkfield.constraints().constraints() & QgsFieldConstraints.Constraint.ConstraintUnique)
+ self.assertTrue(
+ pkfield.constraints().constraints()
+ & QgsFieldConstraints.Constraint.ConstraintUnique
+ )
# Test add feature with default Fid (NULL)
layer.startEditing()
f = QgsFeature()
feat = QgsFeature(layer.fields())
- feat.setGeometry(QgsGeometry.fromWkt('Polygon ((0 0, 0 1, 1 1, 1 0, 0 0))'))
- feat.setAttribute(1, 'test_value')
+ feat.setGeometry(QgsGeometry.fromWkt("Polygon ((0 0, 0 1, 1 1, 1 0, 0 0))"))
+ feat.setAttribute(1, "test_value")
layer.addFeature(feat)
self.assertTrue(layer.commitChanges())
self.assertEqual(layer.featureCount(), 1)
def test_SplitFeature(self):
"""Test gpkg feature can be split"""
- tmpfile = os.path.join(self.basetestpath, 'testGeopackageSplitFeatures.gpkg')
- ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile)
- lyr = ds.CreateLayer('test', geom_type=ogr.wkbPolygon)
- lyr.CreateField(ogr.FieldDefn('str_field', ogr.OFTString))
+ tmpfile = os.path.join(self.basetestpath, "testGeopackageSplitFeatures.gpkg")
+ ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile)
+ lyr = ds.CreateLayer("test", geom_type=ogr.wkbPolygon)
+ lyr.CreateField(ogr.FieldDefn("str_field", ogr.OFTString))
f = ogr.Feature(lyr.GetLayerDefn())
- f.SetGeometry(ogr.CreateGeometryFromWkt('POLYGON ((0 0,0 1,1 1,1 0,0 0))'))
+ f.SetGeometry(ogr.CreateGeometryFromWkt("POLYGON ((0 0,0 1,1 1,1 0,0 0))"))
lyr.CreateFeature(f)
f = None
ds = None
# Split features
- layer = QgsVectorLayer(f'{tmpfile}' + "|layername=" + "test", 'test', 'ogr')
+ layer = QgsVectorLayer(f"{tmpfile}" + "|layername=" + "test", "test", "ogr")
self.assertTrue(layer.isValid())
self.assertTrue(layer.isSpatial())
- self.assertEqual([f for f in layer.getFeatures()][0].geometry().asWkt(), 'Polygon ((0 0, 0 1, 1 1, 1 0, 0 0))')
+ self.assertEqual(
+ [f for f in layer.getFeatures()][0].geometry().asWkt(),
+ "Polygon ((0 0, 0 1, 1 1, 1 0, 0 0))",
+ )
layer.startEditing()
- self.assertEqual(layer.splitFeatures([QgsPointXY(0.5, 0), QgsPointXY(0.5, 1)], 0), 0)
+ self.assertEqual(
+ layer.splitFeatures([QgsPointXY(0.5, 0), QgsPointXY(0.5, 1)], 0), 0
+ )
self.assertTrue(layer.commitChanges())
self.assertEqual(layer.featureCount(), 2)
- layer = QgsVectorLayer(f'{tmpfile}' + "|layername=" + "test", 'test', 'ogr')
+ layer = QgsVectorLayer(f"{tmpfile}" + "|layername=" + "test", "test", "ogr")
self.assertEqual(layer.featureCount(), 2)
g, g2 = (f.geometry() for f in layer.getFeatures())
g.normalize()
g2.normalize()
- self.assertCountEqual([geom.asWkt() for geom in [g, g2]], ['Polygon ((0 0, 0 1, 0.5 1, 0.5 0, 0 0))',
- 'Polygon ((0.5 0, 0.5 1, 1 1, 1 0, 0.5 0))'])
+ self.assertCountEqual(
+ [geom.asWkt() for geom in [g, g2]],
+ [
+ "Polygon ((0 0, 0 1, 0.5 1, 0.5 0, 0 0))",
+ "Polygon ((0.5 0, 0.5 1, 1 1, 1 0, 0.5 0))",
+ ],
+ )
def test_SplitFeatureErrorIncompatibleGeometryType(self):
"""Test we behave correctly when split feature is not possible due to incompatible geometry type"""
- tmpfile = os.path.join(self.basetestpath, 'test_SplitFeatureErrorIncompatibleGeometryType.gpkg')
- ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile)
- lyr = ds.CreateLayer('test', geom_type=ogr.wkbPoint)
+ tmpfile = os.path.join(
+ self.basetestpath, "test_SplitFeatureErrorIncompatibleGeometryType.gpkg"
+ )
+ ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile)
+ lyr = ds.CreateLayer("test", geom_type=ogr.wkbPoint)
f = ogr.Feature(lyr.GetLayerDefn())
# For the purpose of this test, we insert a Polygon in a Point layer
# which is normally not allowed
- f.SetGeometry(ogr.CreateGeometryFromWkt('POLYGON ((0 0,0 1,1 1,1 0,0 0))'))
- gdal.PushErrorHandler('CPLQuietErrorHandler')
+ f.SetGeometry(ogr.CreateGeometryFromWkt("POLYGON ((0 0,0 1,1 1,1 0,0 0))"))
+ gdal.PushErrorHandler("CPLQuietErrorHandler")
self.assertEqual(lyr.CreateFeature(f), ogr.OGRERR_NONE)
gdal.PopErrorHandler()
f = None
ds = None
# Split features
- layer = QgsVectorLayer(f'{tmpfile}' + "|layername=" + "test", 'test', 'ogr')
+ layer = QgsVectorLayer(f"{tmpfile}" + "|layername=" + "test", "test", "ogr")
self.assertTrue(layer.isValid())
self.assertTrue(layer.isSpatial())
- self.assertEqual([f for f in layer.getFeatures()][0].geometry().asWkt(), 'Polygon ((0 0, 0 1, 1 1, 1 0, 0 0))')
+ self.assertEqual(
+ [f for f in layer.getFeatures()][0].geometry().asWkt(),
+ "Polygon ((0 0, 0 1, 1 1, 1 0, 0 0))",
+ )
layer.startEditing()
- self.assertEqual(layer.splitFeatures([QgsPointXY(0.5, 0), QgsPointXY(0.5, 1)], 0), 0)
+ self.assertEqual(
+ layer.splitFeatures([QgsPointXY(0.5, 0), QgsPointXY(0.5, 1)], 0), 0
+ )
self.assertFalse(layer.commitChanges())
- layer = QgsVectorLayer(f'{tmpfile}' + "|layername=" + "test", 'test', 'ogr')
+ layer = QgsVectorLayer(f"{tmpfile}" + "|layername=" + "test", "test", "ogr")
self.assertEqual(layer.featureCount(), 1)
g = [f.geometry() for f in layer.getFeatures()][0]
- self.assertEqual(g.asWkt(), 'Polygon ((0 0, 0 1, 1 1, 1 0, 0 0))')
+ self.assertEqual(g.asWkt(), "Polygon ((0 0, 0 1, 1 1, 1 0, 0 0))")
def test_SplitFeatureErrorIncompatibleGeometryType2(self):
"""Test we behave correctly when split a single-part multipolygon of a polygon layer (https://github.com/qgis/QGIS/issues/41283)"""
# This is really a non-nominal case. Failing properly would also be understandable.
- tmpfile = os.path.join(self.basetestpath, 'test_SplitFeatureErrorIncompatibleGeometryType2.gpkg')
- ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile)
- lyr = ds.CreateLayer('test', geom_type=ogr.wkbPolygon)
+ tmpfile = os.path.join(
+ self.basetestpath, "test_SplitFeatureErrorIncompatibleGeometryType2.gpkg"
+ )
+ ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile)
+ lyr = ds.CreateLayer("test", geom_type=ogr.wkbPolygon)
f = ogr.Feature(lyr.GetLayerDefn())
# For the purpose of this test, we insert a MultiPolygon in a Polygon layer
# which is normally not allowed
- f.SetGeometry(ogr.CreateGeometryFromWkt('MULTIPOLYGON (((0 0,0 1,1 1,1 0,0 0)))'))
- gdal.PushErrorHandler('CPLQuietErrorHandler')
+ f.SetGeometry(
+ ogr.CreateGeometryFromWkt("MULTIPOLYGON (((0 0,0 1,1 1,1 0,0 0)))")
+ )
+ gdal.PushErrorHandler("CPLQuietErrorHandler")
self.assertEqual(lyr.CreateFeature(f), ogr.OGRERR_NONE)
gdal.PopErrorHandler()
f = None
ds = None
# Split features
- layer = QgsVectorLayer(f'{tmpfile}' + "|layername=" + "test", 'test', 'ogr')
+ layer = QgsVectorLayer(f"{tmpfile}" + "|layername=" + "test", "test", "ogr")
self.assertTrue(layer.isValid())
self.assertTrue(layer.isSpatial())
- self.assertEqual([f for f in layer.getFeatures()][0].geometry().asWkt(), 'MultiPolygon (((0 0, 0 1, 1 1, 1 0, 0 0)))')
+ self.assertEqual(
+ [f for f in layer.getFeatures()][0].geometry().asWkt(),
+ "MultiPolygon (((0 0, 0 1, 1 1, 1 0, 0 0)))",
+ )
layer.startEditing()
- self.assertEqual(layer.splitFeatures([QgsPointXY(0.5, 0), QgsPointXY(0.5, 1)], 0), 0)
+ self.assertEqual(
+ layer.splitFeatures([QgsPointXY(0.5, 0), QgsPointXY(0.5, 1)], 0), 0
+ )
self.assertTrue(layer.commitChanges())
self.assertEqual(layer.featureCount(), 2)
- layer = QgsVectorLayer(f'{tmpfile}' + "|layername=" + "test", 'test', 'ogr')
+ layer = QgsVectorLayer(f"{tmpfile}" + "|layername=" + "test", "test", "ogr")
self.assertEqual(layer.featureCount(), 2)
g, g2 = (f.geometry() for f in layer.getFeatures())
g.normalize()
g2.normalize()
- self.assertCountEqual([geom.asWkt() for geom in [g, g2]], ['Polygon ((0 0, 0 1, 0.5 1, 0.5 0, 0 0))',
- 'Polygon ((0.5 0, 0.5 1, 1 1, 1 0, 0.5 0))'])
+ self.assertCountEqual(
+ [geom.asWkt() for geom in [g, g2]],
+ [
+ "Polygon ((0 0, 0 1, 0.5 1, 0.5 0, 0 0))",
+ "Polygon ((0.5 0, 0.5 1, 1 1, 1 0, 0.5 0))",
+ ],
+ )
def testCreateAttributeIndex(self):
- tmpfile = os.path.join(self.basetestpath, 'testGeopackageAttributeIndex.gpkg')
- ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile)
- lyr = ds.CreateLayer('test', geom_type=ogr.wkbPolygon)
- lyr.CreateField(ogr.FieldDefn('str_field', ogr.OFTString))
- lyr.CreateField(ogr.FieldDefn('str_field2', ogr.OFTString))
+ tmpfile = os.path.join(self.basetestpath, "testGeopackageAttributeIndex.gpkg")
+ ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile)
+ lyr = ds.CreateLayer("test", geom_type=ogr.wkbPolygon)
+ lyr.CreateField(ogr.FieldDefn("str_field", ogr.OFTString))
+ lyr.CreateField(ogr.FieldDefn("str_field2", ogr.OFTString))
f = None
ds = None
- vl = QgsVectorLayer(f'{tmpfile}' + "|layername=" + "test", 'test', 'ogr')
+ vl = QgsVectorLayer(f"{tmpfile}" + "|layername=" + "test", "test", "ogr")
self.assertTrue(vl.isValid())
- self.assertTrue(vl.dataProvider().capabilities() & QgsVectorDataProvider.Capability.CreateAttributeIndex)
+ self.assertTrue(
+ vl.dataProvider().capabilities()
+ & QgsVectorDataProvider.Capability.CreateAttributeIndex
+ )
self.assertFalse(vl.dataProvider().createAttributeIndex(-1))
self.assertFalse(vl.dataProvider().createAttributeIndex(100))
@@ -1410,18 +1609,22 @@ def testCreateAttributeIndex(self):
con = spatialite_connect(tmpfile, isolation_level=None)
cur = con.cursor()
- rs = cur.execute("SELECT * FROM sqlite_master WHERE type='index' AND tbl_name='test'")
+ rs = cur.execute(
+ "SELECT * FROM sqlite_master WHERE type='index' AND tbl_name='test'"
+ )
res = [row for row in rs]
self.assertEqual(len(res), 1)
index_name = res[0][1]
rs = cur.execute(f"PRAGMA index_info({index_name})")
res = [row for row in rs]
self.assertEqual(len(res), 1)
- self.assertEqual(res[0][2], 'str_field')
+ self.assertEqual(res[0][2], "str_field")
# second index
self.assertTrue(vl.dataProvider().createAttributeIndex(2))
- rs = cur.execute("SELECT * FROM sqlite_master WHERE type='index' AND tbl_name='test'")
+ rs = cur.execute(
+ "SELECT * FROM sqlite_master WHERE type='index' AND tbl_name='test'"
+ )
res = [row for row in rs]
self.assertEqual(len(res), 2)
indexed_columns = []
@@ -1432,124 +1635,147 @@ def testCreateAttributeIndex(self):
self.assertEqual(len(res), 1)
indexed_columns.append(res[0][2])
- self.assertCountEqual(indexed_columns, ['str_field', 'str_field2'])
+ self.assertCountEqual(indexed_columns, ["str_field", "str_field2"])
con.close()
def testCreateSpatialIndex(self):
- tmpfile = os.path.join(self.basetestpath, 'testGeopackageSpatialIndex.gpkg')
- ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile)
- lyr = ds.CreateLayer('test', geom_type=ogr.wkbPolygon, options=['SPATIAL_INDEX=NO'])
- lyr.CreateField(ogr.FieldDefn('str_field', ogr.OFTString))
- lyr.CreateField(ogr.FieldDefn('str_field2', ogr.OFTString))
+ tmpfile = os.path.join(self.basetestpath, "testGeopackageSpatialIndex.gpkg")
+ ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile)
+ lyr = ds.CreateLayer(
+ "test", geom_type=ogr.wkbPolygon, options=["SPATIAL_INDEX=NO"]
+ )
+ lyr.CreateField(ogr.FieldDefn("str_field", ogr.OFTString))
+ lyr.CreateField(ogr.FieldDefn("str_field2", ogr.OFTString))
f = None
ds = None
- vl = QgsVectorLayer(f'{tmpfile}' + "|layername=" + "test", 'test', 'ogr')
+ vl = QgsVectorLayer(f"{tmpfile}" + "|layername=" + "test", "test", "ogr")
self.assertTrue(vl.isValid())
- self.assertTrue(vl.dataProvider().capabilities() & QgsVectorDataProvider.Capability.CreateSpatialIndex)
+ self.assertTrue(
+ vl.dataProvider().capabilities()
+ & QgsVectorDataProvider.Capability.CreateSpatialIndex
+ )
self.assertTrue(vl.dataProvider().createSpatialIndex())
def testSubSetStringEditable_bug17795_but_with_modified_behavior(self):
"""Test that a layer is editable after setting a subset"""
- tmpfile = os.path.join(self.basetestpath, 'testSubSetStringEditable_bug17795.gpkg')
- shutil.copy(TEST_DATA_DIR + '/' + 'provider/bug_17795.gpkg', tmpfile)
+ tmpfile = os.path.join(
+ self.basetestpath, "testSubSetStringEditable_bug17795.gpkg"
+ )
+ shutil.copy(TEST_DATA_DIR + "/" + "provider/bug_17795.gpkg", tmpfile)
isEditable = QgsVectorDataProvider.Capability.ChangeAttributeValues
- testPath = tmpfile + '|layername=bug_17795'
+ testPath = tmpfile + "|layername=bug_17795"
- vl = QgsVectorLayer(testPath, 'subset_test', 'ogr')
+ vl = QgsVectorLayer(testPath, "subset_test", "ogr")
self.assertTrue(vl.isValid())
self.assertTrue(vl.dataProvider().capabilities() & isEditable)
- vl = QgsVectorLayer(testPath, 'subset_test', 'ogr')
- vl.setSubsetString('')
+ vl = QgsVectorLayer(testPath, "subset_test", "ogr")
+ vl.setSubsetString("")
self.assertTrue(vl.isValid())
self.assertTrue(vl.dataProvider().capabilities() & isEditable)
- vl = QgsVectorLayer(testPath, 'subset_test', 'ogr')
- vl.setSubsetString('"category" = \'one\'')
+ vl = QgsVectorLayer(testPath, "subset_test", "ogr")
+ vl.setSubsetString("\"category\" = 'one'")
self.assertTrue(vl.isValid())
self.assertTrue(vl.dataProvider().capabilities() & isEditable)
- vl.setSubsetString('')
+ vl.setSubsetString("")
self.assertTrue(vl.dataProvider().capabilities() & isEditable)
def testSubsetStringExtent_bug17863(self):
"""Check that the extent is correct when applied in the ctor and when
- modified after a subset string is set """
+ modified after a subset string is set"""
def _lessdigits(s):
- return re.sub(r'(\d+\.\d{3})\d+', r'\1', s)
+ return re.sub(r"(\d+\.\d{3})\d+", r"\1", s)
- tmpfile = os.path.join(self.basetestpath, 'testSubsetStringExtent_bug17863.gpkg')
- shutil.copy(TEST_DATA_DIR + '/' + 'provider/bug_17795.gpkg', tmpfile)
+ tmpfile = os.path.join(
+ self.basetestpath, "testSubsetStringExtent_bug17863.gpkg"
+ )
+ shutil.copy(TEST_DATA_DIR + "/" + "provider/bug_17795.gpkg", tmpfile)
- testPath = tmpfile + '|layername=bug_17795'
- subSetString = '"name" = \'int\''
- subSet = f'|subset={subSetString}'
+ testPath = tmpfile + "|layername=bug_17795"
+ subSetString = "\"name\" = 'int'"
+ subSet = f"|subset={subSetString}"
# unfiltered
- vl = QgsVectorLayer(testPath, 'test', 'ogr')
+ vl = QgsVectorLayer(testPath, "test", "ogr")
self.assertTrue(vl.isValid())
unfiltered_extent = _lessdigits(vl.extent().toString())
- del (vl)
+ del vl
# filter after construction ...
- subSet_vl2 = QgsVectorLayer(testPath, 'test', 'ogr')
+ subSet_vl2 = QgsVectorLayer(testPath, "test", "ogr")
self.assertEqual(_lessdigits(subSet_vl2.extent().toString()), unfiltered_extent)
# ... apply filter now!
subSet_vl2.setSubsetString(subSetString)
self.assertEqual(subSet_vl2.subsetString(), subSetString)
- self.assertNotEqual(_lessdigits(subSet_vl2.extent().toString()), unfiltered_extent)
+ self.assertNotEqual(
+ _lessdigits(subSet_vl2.extent().toString()), unfiltered_extent
+ )
filtered_extent = _lessdigits(subSet_vl2.extent().toString())
- del (subSet_vl2)
+ del subSet_vl2
# filtered in constructor
- subSet_vl = QgsVectorLayer(testPath + subSet, 'subset_test', 'ogr')
+ subSet_vl = QgsVectorLayer(testPath + subSet, "subset_test", "ogr")
self.assertEqual(subSet_vl.subsetString(), subSetString)
self.assertTrue(subSet_vl.isValid())
# This was failing in bug 17863
self.assertEqual(_lessdigits(subSet_vl.extent().toString()), filtered_extent)
- self.assertNotEqual(_lessdigits(subSet_vl.extent().toString()), unfiltered_extent)
+ self.assertNotEqual(
+ _lessdigits(subSet_vl.extent().toString()), unfiltered_extent
+ )
def testRequestWithoutGeometryOnLayerMixedGeometry(self):
- """ Test bugfix for https://github.com/qgis/QGIS/issues/26907 """
+ """Test bugfix for https://github.com/qgis/QGIS/issues/26907"""
# Issue is more a generic one of the OGR provider, but easy to trigger with GPKG
- tmpfile = os.path.join(self.basetestpath, 'testRequestWithoutGeometryOnLayerMixedGeometry.gpkg')
- ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile)
- lyr = ds.CreateLayer('test', geom_type=ogr.wkbUnknown, options=['SPATIAL_INDEX=NO'])
+ tmpfile = os.path.join(
+ self.basetestpath, "testRequestWithoutGeometryOnLayerMixedGeometry.gpkg"
+ )
+ ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile)
+ lyr = ds.CreateLayer(
+ "test", geom_type=ogr.wkbUnknown, options=["SPATIAL_INDEX=NO"]
+ )
f = ogr.Feature(lyr.GetLayerDefn())
- f.SetGeometry(ogr.CreateGeometryFromWkt('POINT(0 1)'))
+ f.SetGeometry(ogr.CreateGeometryFromWkt("POINT(0 1)"))
lyr.CreateFeature(f)
f = ogr.Feature(lyr.GetLayerDefn())
- f.SetGeometry(ogr.CreateGeometryFromWkt('LINESTRING(0 0,1 0)'))
+ f.SetGeometry(ogr.CreateGeometryFromWkt("LINESTRING(0 0,1 0)"))
lyr.CreateFeature(f)
f = ogr.Feature(lyr.GetLayerDefn())
- f.SetGeometry(ogr.CreateGeometryFromWkt('LINESTRING(0 0,1 0)'))
+ f.SetGeometry(ogr.CreateGeometryFromWkt("LINESTRING(0 0,1 0)"))
lyr.CreateFeature(f)
f = None
ds = None
- vl = QgsVectorLayer(f'{tmpfile}' + "|geometrytype=Point|layername=" + "test", 'test', 'ogr')
+ vl = QgsVectorLayer(
+ f"{tmpfile}" + "|geometrytype=Point|layername=" + "test", "test", "ogr"
+ )
self.assertTrue(vl.isValid())
request = QgsFeatureRequest().setFlags(QgsFeatureRequest.Flag.NoGeometry)
features = [f for f in vl.getFeatures(request)]
self.assertEqual(len(features), 1)
def testAddingTwoIntFieldsWithWidth(self):
- """ Test buggfix for https://github.com/qgis/QGIS/issues/26840 """
+ """Test buggfix for https://github.com/qgis/QGIS/issues/26840"""
- tmpfile = os.path.join(self.basetestpath, 'testRequestWithoutGeometryOnLayerMixedGeometry.gpkg')
- ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile)
- lyr = ds.CreateLayer('test', geom_type=ogr.wkbPoint, options=['SPATIAL_INDEX=NO'])
- lyr.CreateField(ogr.FieldDefn('a', ogr.OFTInteger))
+ tmpfile = os.path.join(
+ self.basetestpath, "testRequestWithoutGeometryOnLayerMixedGeometry.gpkg"
+ )
+ ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile)
+ lyr = ds.CreateLayer(
+ "test", geom_type=ogr.wkbPoint, options=["SPATIAL_INDEX=NO"]
+ )
+ lyr.CreateField(ogr.FieldDefn("a", ogr.OFTInteger))
ds = None
- vl = QgsVectorLayer(f'{tmpfile}' + "|layername=" + "test", 'test', 'ogr')
+ vl = QgsVectorLayer(f"{tmpfile}" + "|layername=" + "test", "test", "ogr")
self.assertTrue(vl.isValid())
vl.startEditing()
@@ -1561,143 +1787,168 @@ def testAddingTwoIntFieldsWithWidth(self):
self.assertTrue(vl.commitChanges())
def testApproxFeatureCountAndExtent(self):
- """ Test perf improvement for for https://github.com/qgis/QGIS/issues/26292 """
+ """Test perf improvement for for https://github.com/qgis/QGIS/issues/26292"""
- tmpfile = os.path.join(self.basetestpath, 'testApproxFeatureCountAndExtent.gpkg')
- ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile)
- lyr = ds.CreateLayer('test', geom_type=ogr.wkbPoint)
+ tmpfile = os.path.join(
+ self.basetestpath, "testApproxFeatureCountAndExtent.gpkg"
+ )
+ ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile)
+ lyr = ds.CreateLayer("test", geom_type=ogr.wkbPoint)
f = ogr.Feature(lyr.GetLayerDefn())
- f.SetGeometry(ogr.CreateGeometryFromWkt('POINT(0 1)'))
+ f.SetGeometry(ogr.CreateGeometryFromWkt("POINT(0 1)"))
lyr.CreateFeature(f)
f = ogr.Feature(lyr.GetLayerDefn())
- f.SetGeometry(ogr.CreateGeometryFromWkt('POINT(2 3)'))
+ f.SetGeometry(ogr.CreateGeometryFromWkt("POINT(2 3)"))
lyr.CreateFeature(f)
fid = f.GetFID()
f = ogr.Feature(lyr.GetLayerDefn())
- f.SetGeometry(ogr.CreateGeometryFromWkt('POINT(4 5)'))
+ f.SetGeometry(ogr.CreateGeometryFromWkt("POINT(4 5)"))
lyr.CreateFeature(f)
lyr.DeleteFeature(fid)
ds = None
ds = ogr.Open(tmpfile, update=1)
- ds.ExecuteSQL('DROP TABLE gpkg_ogr_contents')
+ ds.ExecuteSQL("DROP TABLE gpkg_ogr_contents")
ds = None
- os.environ['QGIS_GPKG_FC_THRESHOLD'] = '1'
- vl = QgsVectorLayer(f'{tmpfile}' + "|layername=" + "test", 'test', 'ogr')
+ os.environ["QGIS_GPKG_FC_THRESHOLD"] = "1"
+ vl = QgsVectorLayer(f"{tmpfile}" + "|layername=" + "test", "test", "ogr")
self.assertTrue(vl.isValid())
fc = vl.featureCount()
- del os.environ['QGIS_GPKG_FC_THRESHOLD']
+ del os.environ["QGIS_GPKG_FC_THRESHOLD"]
self.assertEqual(fc, 3) # didn't notice the hole
reference = QgsGeometry.fromRect(QgsRectangle(0, 1, 4, 5))
provider_extent = QgsGeometry.fromRect(vl.extent())
- self.assertTrue(QgsGeometry.compare(provider_extent.asPolygon()[0], reference.asPolygon()[0], 0.00001),
- provider_extent.asPolygon()[0])
+ self.assertTrue(
+ QgsGeometry.compare(
+ provider_extent.asPolygon()[0], reference.asPolygon()[0], 0.00001
+ ),
+ provider_extent.asPolygon()[0],
+ )
def testRegenerateFid(self):
- """ Test regenerating feature ids """
+ """Test regenerating feature ids"""
fields = QgsFields()
- fields.append(QgsField('fid', QVariant.Int))
- fields.append(QgsField('f1', QVariant.Int))
- tmpfile = os.path.join(self.basetestpath, 'testRegenerateFid.gpkg')
+ fields.append(QgsField("fid", QVariant.Int))
+ fields.append(QgsField("f1", QVariant.Int))
+ tmpfile = os.path.join(self.basetestpath, "testRegenerateFid.gpkg")
options = {}
- options['update'] = True
- options['driverName'] = 'GPKG'
- options['layerName'] = 'table1'
- exporter = QgsVectorLayerExporter(tmpfile, "ogr", fields, QgsWkbTypes.Type.Polygon,
- QgsCoordinateReferenceSystem('EPSG:3111'), False, options,
- QgsFeatureSink.SinkFlag.RegeneratePrimaryKey)
- self.assertFalse(exporter.errorCode(),
- f'unexpected export error {exporter.errorCode()}: {exporter.errorMessage()}')
+ options["update"] = True
+ options["driverName"] = "GPKG"
+ options["layerName"] = "table1"
+ exporter = QgsVectorLayerExporter(
+ tmpfile,
+ "ogr",
+ fields,
+ QgsWkbTypes.Type.Polygon,
+ QgsCoordinateReferenceSystem("EPSG:3111"),
+ False,
+ options,
+ QgsFeatureSink.SinkFlag.RegeneratePrimaryKey,
+ )
+ self.assertFalse(
+ exporter.errorCode(),
+ f"unexpected export error {exporter.errorCode()}: {exporter.errorMessage()}",
+ )
feat = QgsFeature(fields)
- feat['fid'] = 0
- feat['f1'] = 10
+ feat["fid"] = 0
+ feat["f1"] = 10
exporter.addFeature(feat)
- feat['fid'] = 0
- feat['f1'] = 20
+ feat["fid"] = 0
+ feat["f1"] = 20
exporter.addFeature(feat)
- feat['fid'] = 1
- feat['f1'] = 30
+ feat["fid"] = 1
+ feat["f1"] = 30
exporter.addFeature(feat)
- feat['fid'] = 1
- feat['f1'] = 40
+ feat["fid"] = 1
+ feat["f1"] = 40
exporter.addFeature(feat)
del exporter
# make sure layers exist
- lyr = QgsVectorLayer(f'{tmpfile}|layername=table1', "lyr1", "ogr")
+ lyr = QgsVectorLayer(f"{tmpfile}|layername=table1", "lyr1", "ogr")
self.assertTrue(lyr.isValid())
- self.assertEqual(lyr.crs().authid(), 'EPSG:3111')
+ self.assertEqual(lyr.crs().authid(), "EPSG:3111")
self.assertEqual(lyr.wkbType(), QgsWkbTypes.Type.Polygon)
- values = {f['f1'] for f in lyr.getFeatures()}
+ values = {f["f1"] for f in lyr.getFeatures()}
self.assertEqual(values, {10, 20, 30, 40})
- fids = {f['fid'] for f in lyr.getFeatures()}
+ fids = {f["fid"] for f in lyr.getFeatures()}
self.assertEqual(len(fids), 4)
def testExportWithoutFids(self):
- """ Test export with a feature without fid, regression GH #32927
+ """Test export with a feature without fid, regression GH #32927
This test case is related to testRegenerateFid
"""
fields = QgsFields()
- fields.append(QgsField('one', QVariant.Int))
- fields.append(QgsField('two', QVariant.Int))
- tmpfile = os.path.join(self.basetestpath, 'testExportWithoutFids.gpkg')
+ fields.append(QgsField("one", QVariant.Int))
+ fields.append(QgsField("two", QVariant.Int))
+ tmpfile = os.path.join(self.basetestpath, "testExportWithoutFids.gpkg")
options = {}
- options['update'] = True
- options['driverName'] = 'GPKG'
- options['layerName'] = 'output'
- exporter = QgsVectorLayerExporter(tmpfile, "ogr", fields, QgsWkbTypes.Type.Point, QgsCoordinateReferenceSystem('EPSG:4326'),
- False, options, QgsFeatureSink.SinkFlag.RegeneratePrimaryKey)
- self.assertFalse(exporter.errorCode(),
- f'unexpected export error {exporter.errorCode()}: {exporter.errorMessage()}')
+ options["update"] = True
+ options["driverName"] = "GPKG"
+ options["layerName"] = "output"
+ exporter = QgsVectorLayerExporter(
+ tmpfile,
+ "ogr",
+ fields,
+ QgsWkbTypes.Type.Point,
+ QgsCoordinateReferenceSystem("EPSG:4326"),
+ False,
+ options,
+ QgsFeatureSink.SinkFlag.RegeneratePrimaryKey,
+ )
+ self.assertFalse(
+ exporter.errorCode(),
+ f"unexpected export error {exporter.errorCode()}: {exporter.errorMessage()}",
+ )
feat = QgsFeature(fields)
- feat['one'] = 100
- feat['two'] = 200
- feat.setGeometry(QgsGeometry.fromWkt('point(4 45)'))
+ feat["one"] = 100
+ feat["two"] = 200
+ feat.setGeometry(QgsGeometry.fromWkt("point(4 45)"))
exporter.addFeature(feat)
del exporter
# make sure layers exist
- lyr = QgsVectorLayer(f'{tmpfile}|layername=output', "lyr1", "ogr")
+ lyr = QgsVectorLayer(f"{tmpfile}|layername=output", "lyr1", "ogr")
self.assertTrue(lyr.isValid())
- self.assertEqual(lyr.crs().authid(), 'EPSG:4326')
+ self.assertEqual(lyr.crs().authid(), "EPSG:4326")
self.assertEqual(lyr.wkbType(), QgsWkbTypes.Type.Point)
feat_out = next(lyr.getFeatures())
- self.assertEqual(feat_out.attribute('two'), 200)
- self.assertEqual(feat_out.attribute('one'), 100)
+ self.assertEqual(feat_out.attribute("two"), 200)
+ self.assertEqual(feat_out.attribute("one"), 100)
def testTransaction(self):
- tmpfile = os.path.join(self.basetestpath, 'testTransaction.gpkg')
- ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile)
- lyr = ds.CreateLayer('lyr1', geom_type=ogr.wkbPoint)
+ tmpfile = os.path.join(self.basetestpath, "testTransaction.gpkg")
+ ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile)
+ lyr = ds.CreateLayer("lyr1", geom_type=ogr.wkbPoint)
f = ogr.Feature(lyr.GetLayerDefn())
- f.SetGeometry(ogr.CreateGeometryFromWkt('POINT(0 1)'))
+ f.SetGeometry(ogr.CreateGeometryFromWkt("POINT(0 1)"))
lyr.CreateFeature(f)
- lyr = ds.CreateLayer('lyr2', geom_type=ogr.wkbPoint)
+ lyr = ds.CreateLayer("lyr2", geom_type=ogr.wkbPoint)
f = ogr.Feature(lyr.GetLayerDefn())
- f.SetGeometry(ogr.CreateGeometryFromWkt('POINT(2 3)'))
+ f.SetGeometry(ogr.CreateGeometryFromWkt("POINT(2 3)"))
lyr.CreateFeature(f)
f = ogr.Feature(lyr.GetLayerDefn())
- f.SetGeometry(ogr.CreateGeometryFromWkt('POINT(4 5)'))
+ f.SetGeometry(ogr.CreateGeometryFromWkt("POINT(4 5)"))
lyr.CreateFeature(f)
ds = None
- vl1 = QgsVectorLayer(f'{tmpfile}' + "|layername=" + "lyr1", 'test', 'ogr')
+ vl1 = QgsVectorLayer(f"{tmpfile}" + "|layername=" + "lyr1", "test", "ogr")
self.assertTrue(vl1.isValid())
- vl2 = QgsVectorLayer(f'{tmpfile}' + "|layername=" + "lyr2", 'test', 'ogr')
+ vl2 = QgsVectorLayer(f"{tmpfile}" + "|layername=" + "lyr2", "test", "ogr")
self.assertTrue(vl2.isValid())
# prepare a project with transactions enabled
@@ -1713,9 +1964,13 @@ def testTransaction(self):
self.assertEqual(len([f for f in vl1.getFeatures(QgsFeatureRequest())]), 0)
# But not if opened from another connection
- vl1_external = QgsVectorLayer(f'{tmpfile}' + "|layername=" + "lyr1", 'test', 'ogr')
+ vl1_external = QgsVectorLayer(
+ f"{tmpfile}" + "|layername=" + "lyr1", "test", "ogr"
+ )
self.assertTrue(vl1_external.isValid())
- self.assertEqual(len([f for f in vl1_external.getFeatures(QgsFeatureRequest())]), 1)
+ self.assertEqual(
+ len([f for f in vl1_external.getFeatures(QgsFeatureRequest())]), 1
+ )
del vl1_external
self.assertTrue(vl1.commitChanges())
@@ -1743,9 +1998,13 @@ def testTransaction(self):
del vl1
del vl2
- vl2_external = QgsVectorLayer(f'{tmpfile}' + "|layername=" + "lyr2", 'test', 'ogr')
+ vl2_external = QgsVectorLayer(
+ f"{tmpfile}" + "|layername=" + "lyr2", "test", "ogr"
+ )
self.assertTrue(vl2_external.isValid())
- self.assertEqual(len([f for f in vl2_external.getFeatures(QgsFeatureRequest())]), 1)
+ self.assertEqual(
+ len([f for f in vl2_external.getFeatures(QgsFeatureRequest())]), 1
+ )
del vl2_external
def testTransactionGroupAutomatic(self):
@@ -1753,18 +2012,22 @@ def testTransactionGroupAutomatic(self):
temp_dir = QTemporaryDir()
temp_path = temp_dir.path()
- tmpfile = os.path.join(temp_path, 'testTransactionGroupAutomatic.gpkg')
- ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile)
- lyr = ds.CreateLayer('types', geom_type=ogr.wkbNone)
- lyr.CreateField(ogr.FieldDefn('name', ogr.OFTString))
- lyr = ds.CreateLayer('shops', geom_type=ogr.wkbPoint)
- lyr.CreateField(ogr.FieldDefn('name', ogr.OFTString))
- lyr.CreateField(ogr.FieldDefn('type_fk', ogr.OFTString))
+ tmpfile = os.path.join(temp_path, "testTransactionGroupAutomatic.gpkg")
+ ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile)
+ lyr = ds.CreateLayer("types", geom_type=ogr.wkbNone)
+ lyr.CreateField(ogr.FieldDefn("name", ogr.OFTString))
+ lyr = ds.CreateLayer("shops", geom_type=ogr.wkbPoint)
+ lyr.CreateField(ogr.FieldDefn("name", ogr.OFTString))
+ lyr.CreateField(ogr.FieldDefn("type_fk", ogr.OFTString))
ds = None
- type_layer = QgsVectorLayer(f'{tmpfile}' + "|layername=" + "types", 'types', 'ogr')
+ type_layer = QgsVectorLayer(
+ f"{tmpfile}" + "|layername=" + "types", "types", "ogr"
+ )
self.assertTrue(type_layer.isValid())
- shops_layer = QgsVectorLayer(f'{tmpfile}' + "|layername=" + "shops", 'shops', 'ogr')
+ shops_layer = QgsVectorLayer(
+ f"{tmpfile}" + "|layername=" + "shops", "shops", "ogr"
+ )
self.assertTrue(shops_layer.isValid())
# prepare a project with transactions enabled
@@ -1774,11 +2037,11 @@ def testTransactionGroupAutomatic(self):
# Add one to many relation
relation = QgsRelation(QgsRelationContext(p))
- relation.setName('shops_types')
- relation.setId('shops_types')
+ relation.setName("shops_types")
+ relation.setId("shops_types")
relation.setReferencingLayer(shops_layer.id())
relation.setReferencedLayer(type_layer.id())
- relation.addFieldPair('type_fk', 'name')
+ relation.addFieldPair("type_fk", "name")
self.assertTrue(relation.isValid(), relation.validationError())
p.relationManager().addRelation(relation)
@@ -1787,7 +2050,7 @@ def testTransactionGroupAutomatic(self):
self.assertTrue(shops_layer.isEditable())
self.assertTrue(type_layer.isEditable())
f = QgsFeature(shops_layer.fields())
- f['name'] = 'shop1'
+ f["name"] = "shop1"
self.assertTrue(shops_layer.addFeature(f))
self.assertTrue(p.commitChanges(True, shops_layer))
@@ -1802,113 +2065,163 @@ def testTransactionGroupAutomatic(self):
self.assertTrue(p.rollBack(True, shops_layer))
def testJson(self):
- tmpfile = os.path.join(self.basetestpath, 'test_json.gpkg')
- testdata_path = unitTestDataPath('provider')
- shutil.copy(os.path.join(unitTestDataPath('provider'), 'test_json.gpkg'), tmpfile)
+ tmpfile = os.path.join(self.basetestpath, "test_json.gpkg")
+ testdata_path = unitTestDataPath("provider")
+ shutil.copy(
+ os.path.join(unitTestDataPath("provider"), "test_json.gpkg"), tmpfile
+ )
- vl = QgsVectorLayer(f'{tmpfile}|layerid=0', 'foo', 'ogr')
+ vl = QgsVectorLayer(f"{tmpfile}|layerid=0", "foo", "ogr")
self.assertTrue(vl.isValid())
fields = vl.dataProvider().fields()
- self.assertEqual(fields.at(fields.indexFromName('json_content')).type(), QVariant.Map)
+ self.assertEqual(
+ fields.at(fields.indexFromName("json_content")).type(), QVariant.Map
+ )
fi = vl.getFeatures(QgsFeatureRequest())
f = QgsFeature()
# test reading dict value from attribute
while fi.nextFeature(f):
- if f['fid'] == 1:
- self.assertIsInstance(f['json_content'], dict)
- self.assertEqual(f['json_content'], {'foo': 'bar'})
+ if f["fid"] == 1:
+ self.assertIsInstance(f["json_content"], dict)
+ self.assertEqual(f["json_content"], {"foo": "bar"})
# test changing dict value in attribute
- f['json_content'] = {'foo': 'baz'}
- self.assertEqual(f['json_content'], {'foo': 'baz'})
+ f["json_content"] = {"foo": "baz"}
+ self.assertEqual(f["json_content"], {"foo": "baz"})
# test changint dict to list
- f['json_content'] = ['eins', 'zwei', 'drei']
- self.assertEqual(f['json_content'], ['eins', 'zwei', 'drei'])
+ f["json_content"] = ["eins", "zwei", "drei"]
+ self.assertEqual(f["json_content"], ["eins", "zwei", "drei"])
# test changing list value in attribute
- f['json_content'] = ['eins', 'zwei', 'drei', 4]
- self.assertEqual(f['json_content'], ['eins', 'zwei', 'drei', 4])
+ f["json_content"] = ["eins", "zwei", "drei", 4]
+ self.assertEqual(f["json_content"], ["eins", "zwei", "drei", 4])
# test changing to complex json structure
- f['json_content'] = {'name': 'Lily', 'age': '0',
- 'cars': {'car1': ['fiat tipo', 'fiat punto', 'davoser schlitten'],
- 'car2': 'bobbycar', 'car3': 'tesla'}}
- self.assertEqual(f['json_content'], {'name': 'Lily', 'age': '0',
- 'cars': {'car1': ['fiat tipo', 'fiat punto', 'davoser schlitten'],
- 'car2': 'bobbycar', 'car3': 'tesla'}})
+ f["json_content"] = {
+ "name": "Lily",
+ "age": "0",
+ "cars": {
+ "car1": ["fiat tipo", "fiat punto", "davoser schlitten"],
+ "car2": "bobbycar",
+ "car3": "tesla",
+ },
+ }
+ self.assertEqual(
+ f["json_content"],
+ {
+ "name": "Lily",
+ "age": "0",
+ "cars": {
+ "car1": ["fiat tipo", "fiat punto", "davoser schlitten"],
+ "car2": "bobbycar",
+ "car3": "tesla",
+ },
+ },
+ )
# test adding attribute
vl.startEditing()
self.assertTrue(
- vl.addAttribute(QgsField('json_content2', QVariant.Map, "JSON", 60, 0, 'no comment', QVariant.String)))
+ vl.addAttribute(
+ QgsField(
+ "json_content2",
+ QVariant.Map,
+ "JSON",
+ 60,
+ 0,
+ "no comment",
+ QVariant.String,
+ )
+ )
+ )
self.assertTrue(vl.commitChanges())
vl.startEditing()
self.assertTrue(
- vl.addAttribute(QgsField('json_content3', QVariant.Map, "JSON", 60, 0, 'no comment', QVariant.String)))
+ vl.addAttribute(
+ QgsField(
+ "json_content3",
+ QVariant.Map,
+ "JSON",
+ 60,
+ 0,
+ "no comment",
+ QVariant.String,
+ )
+ )
+ )
self.assertTrue(vl.commitChanges())
# test setting values to new attributes
while fi.nextFeature(f):
- if f['fid'] == 2:
- f['json_content'] = {'uno': 'foo'}
- f['json_content2'] = ['uno', 'due', 'tre']
- f['json_content3'] = {'uno': ['uno', 'due', 'tre']}
- self.assertEqual(f['json_content'], {'foo': 'baz'})
- self.assertEqual(f['json_content2'], ['uno', 'due', 'tre'])
- self.assertEqual(f['json_content3'], {'uno': ['uno', 'due', 'tre']})
+ if f["fid"] == 2:
+ f["json_content"] = {"uno": "foo"}
+ f["json_content2"] = ["uno", "due", "tre"]
+ f["json_content3"] = {"uno": ["uno", "due", "tre"]}
+ self.assertEqual(f["json_content"], {"foo": "baz"})
+ self.assertEqual(f["json_content2"], ["uno", "due", "tre"])
+ self.assertEqual(f["json_content3"], {"uno": ["uno", "due", "tre"]})
# test deleting attribute
vl.startEditing()
- self.assertTrue(vl.deleteAttribute(vl.fields().indexFromName('json_content3')))
+ self.assertTrue(vl.deleteAttribute(vl.fields().indexFromName("json_content3")))
self.assertTrue(vl.commitChanges())
# test if index of existent field is not -1 and the one of the deleted is -1
- self.assertNotEqual(vl.fields().indexFromName('json_content2'), -1)
- self.assertEqual(vl.fields().indexFromName('json_content3'), -1)
+ self.assertNotEqual(vl.fields().indexFromName("json_content2"), -1)
+ self.assertEqual(vl.fields().indexFromName("json_content3"), -1)
def test_quote_identifier(self):
"""Regression #21100"""
- tmpfile = os.path.join(self.basetestpath, 'bug_21100-wierd_field_names.gpkg') # spellok
- shutil.copy(os.path.join(unitTestDataPath(''), 'bug_21100-wierd_field_names.gpkg'), tmpfile) # spellok
- vl = QgsVectorLayer(f'{tmpfile}|layerid=0', 'foo', 'ogr')
+ tmpfile = os.path.join(
+ self.basetestpath, "bug_21100-wierd_field_names.gpkg"
+ ) # spellok
+ shutil.copy(
+ os.path.join(unitTestDataPath(""), "bug_21100-wierd_field_names.gpkg"),
+ tmpfile,
+ ) # spellok
+ vl = QgsVectorLayer(f"{tmpfile}|layerid=0", "foo", "ogr")
self.assertTrue(vl.isValid())
for i in range(1, len(vl.fields())):
- self.assertEqual(vl.uniqueValues(i), {'a', 'b', 'c'})
+ self.assertEqual(vl.uniqueValues(i), {"a", "b", "c"})
def testGeopackageLayerMetadata(self):
"""
Geopackage layer description and identifier should be read into layer metadata automatically
"""
- tmpfile = os.path.join(self.basetestpath, 'testGeopackageLayerMetadata.gpkg')
- ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile)
- lyr = ds.CreateLayer('layer1', geom_type=ogr.wkbPoint)
- lyr.SetMetadataItem('DESCRIPTION', "my desc")
- lyr.SetMetadataItem('IDENTIFIER', "my title") # see geopackage specs -- "'identifier' is analogous to 'title'"
- lyr.CreateField(ogr.FieldDefn('attr', ogr.OFTInteger))
+ tmpfile = os.path.join(self.basetestpath, "testGeopackageLayerMetadata.gpkg")
+ ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile)
+ lyr = ds.CreateLayer("layer1", geom_type=ogr.wkbPoint)
+ lyr.SetMetadataItem("DESCRIPTION", "my desc")
+ lyr.SetMetadataItem(
+ "IDENTIFIER", "my title"
+ ) # see geopackage specs -- "'identifier' is analogous to 'title'"
+ lyr.CreateField(ogr.FieldDefn("attr", ogr.OFTInteger))
f = ogr.Feature(lyr.GetLayerDefn())
- f.SetGeometry(ogr.CreateGeometryFromWkt('POINT(0 0)'))
+ f.SetGeometry(ogr.CreateGeometryFromWkt("POINT(0 0)"))
lyr.CreateFeature(f)
f = None
- vl1 = QgsVectorLayer(f'{tmpfile}' + "|layername=" + "layer1", 'test', 'ogr')
+ vl1 = QgsVectorLayer(f"{tmpfile}" + "|layername=" + "layer1", "test", "ogr")
self.assertTrue(vl1.isValid())
- self.assertEqual(vl1.metadata().title(), 'my title')
- self.assertEqual(vl1.metadata().abstract(), 'my desc')
+ self.assertEqual(vl1.metadata().title(), "my title")
+ self.assertEqual(vl1.metadata().abstract(), "my desc")
def testGeopackageSaveMetadata(self):
- tmpfile = os.path.join(self.basetestpath, 'testGeopackageSaveMetadata.gpkg')
- ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile)
- lyr = ds.CreateLayer('test', geom_type=ogr.wkbPolygon)
- lyr.CreateField(ogr.FieldDefn('str_field', ogr.OFTString))
- lyr.CreateField(ogr.FieldDefn('str_field2', ogr.OFTString))
+ tmpfile = os.path.join(self.basetestpath, "testGeopackageSaveMetadata.gpkg")
+ ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile)
+ lyr = ds.CreateLayer("test", geom_type=ogr.wkbPolygon)
+ lyr.CreateField(ogr.FieldDefn("str_field", ogr.OFTString))
+ lyr.CreateField(ogr.FieldDefn("str_field2", ogr.OFTString))
f = None
ds = None
con = spatialite_connect(tmpfile, isolation_level=None)
cur = con.cursor()
try:
- rs = cur.execute("SELECT * FROM gpkg_metadata_reference WHERE table_name='test'")
+ rs = cur.execute(
+ "SELECT * FROM gpkg_metadata_reference WHERE table_name='test'"
+ )
res = [row for row in rs]
self.assertEqual(len(res), 0)
con.close()
@@ -1918,30 +2231,42 @@ def testGeopackageSaveMetadata(self):
# now save some metadata
metadata = QgsLayerMetadata()
- metadata.setAbstract('my abstract')
- metadata.setIdentifier('my identifier')
- metadata.setLicenses(['l1', 'l2'])
- ok, err = QgsProviderRegistry.instance().saveLayerMetadata('ogr', QgsProviderRegistry.instance().encodeUri('ogr', {'path': tmpfile, 'layerName': 'test'}), metadata)
+ metadata.setAbstract("my abstract")
+ metadata.setIdentifier("my identifier")
+ metadata.setLicenses(["l1", "l2"])
+ ok, err = QgsProviderRegistry.instance().saveLayerMetadata(
+ "ogr",
+ QgsProviderRegistry.instance().encodeUri(
+ "ogr", {"path": tmpfile, "layerName": "test"}
+ ),
+ metadata,
+ )
self.assertTrue(ok)
con = spatialite_connect(tmpfile, isolation_level=None)
cur = con.cursor()
# check that main gpkg_contents metadata columns have been updated
- rs = cur.execute("SELECT identifier, description FROM gpkg_contents WHERE table_name='test'")
+ rs = cur.execute(
+ "SELECT identifier, description FROM gpkg_contents WHERE table_name='test'"
+ )
rows = [r for r in rs]
- self.assertCountEqual(rows[0], ['my identifier', 'my abstract'])
+ self.assertCountEqual(rows[0], ["my identifier", "my abstract"])
- rs = cur.execute("SELECT md_file_id FROM gpkg_metadata_reference WHERE table_name='test'")
+ rs = cur.execute(
+ "SELECT md_file_id FROM gpkg_metadata_reference WHERE table_name='test'"
+ )
file_ids = [row[0] for row in rs]
self.assertTrue(file_ids)
- rs = cur.execute("SELECT id, md_scope, mime_type, metadata FROM gpkg_metadata WHERE md_standard_uri='http://mrcc.com/qgis.dtd'")
+ rs = cur.execute(
+ "SELECT id, md_scope, mime_type, metadata FROM gpkg_metadata WHERE md_standard_uri='http://mrcc.com/qgis.dtd'"
+ )
res = [row for row in rs]
# id must match md_file_id from gpkg_metadata_reference
self.assertIn(res[0][0], file_ids)
- self.assertEqual(res[0][1], 'dataset')
- self.assertEqual(res[0][2], 'text/xml')
+ self.assertEqual(res[0][1], "dataset")
+ self.assertEqual(res[0][2], "text/xml")
metadata_xml = res[0][3]
con.close()
@@ -1949,38 +2274,50 @@ def testGeopackageSaveMetadata(self):
doc = QDomDocument()
doc.setContent(metadata_xml)
self.assertTrue(metadata2.readMetadataXml(doc.documentElement()))
- self.assertEqual(metadata2.abstract(), 'my abstract')
- self.assertEqual(metadata2.identifier(), 'my identifier')
- self.assertEqual(metadata2.licenses(), ['l1', 'l2'])
+ self.assertEqual(metadata2.abstract(), "my abstract")
+ self.assertEqual(metadata2.identifier(), "my identifier")
+ self.assertEqual(metadata2.licenses(), ["l1", "l2"])
# try updating existing metadata -- current row must be updated, not a new row added
- metadata2.setAbstract('my abstract 2')
- metadata2.setIdentifier('my identifier 2')
- metadata2.setHistory(['h1', 'h2'])
- ok, err = QgsProviderRegistry.instance().saveLayerMetadata('ogr', QgsProviderRegistry.instance().encodeUri('ogr', {'path': tmpfile, 'layerName': 'test'}), metadata2)
+ metadata2.setAbstract("my abstract 2")
+ metadata2.setIdentifier("my identifier 2")
+ metadata2.setHistory(["h1", "h2"])
+ ok, err = QgsProviderRegistry.instance().saveLayerMetadata(
+ "ogr",
+ QgsProviderRegistry.instance().encodeUri(
+ "ogr", {"path": tmpfile, "layerName": "test"}
+ ),
+ metadata2,
+ )
self.assertTrue(ok)
con = spatialite_connect(tmpfile, isolation_level=None)
cur = con.cursor()
# check that main gpkg_contents metadata columns have been updated
- rs = cur.execute("SELECT identifier, description FROM gpkg_contents WHERE table_name='test'")
+ rs = cur.execute(
+ "SELECT identifier, description FROM gpkg_contents WHERE table_name='test'"
+ )
rows = [r for r in rs]
self.assertEqual(len(rows), 1)
- self.assertCountEqual(rows[0], ['my identifier 2', 'my abstract 2'])
+ self.assertCountEqual(rows[0], ["my identifier 2", "my abstract 2"])
- rs = cur.execute("SELECT md_file_id FROM gpkg_metadata_reference WHERE table_name='test'")
+ rs = cur.execute(
+ "SELECT md_file_id FROM gpkg_metadata_reference WHERE table_name='test'"
+ )
rows = [r for r in rs]
file_ids = [row[0] for row in rows]
self.assertTrue(file_ids)
- rs = cur.execute("SELECT id, md_scope, mime_type, metadata FROM gpkg_metadata WHERE md_standard_uri='http://mrcc.com/qgis.dtd'")
+ rs = cur.execute(
+ "SELECT id, md_scope, mime_type, metadata FROM gpkg_metadata WHERE md_standard_uri='http://mrcc.com/qgis.dtd'"
+ )
res = [row for row in rs]
self.assertEqual(len(res), 1)
# id must match md_file_id from gpkg_metadata_reference
self.assertIn(res[0][0], file_ids)
- self.assertEqual(res[0][1], 'dataset')
- self.assertEqual(res[0][2], 'text/xml')
+ self.assertEqual(res[0][1], "dataset")
+ self.assertEqual(res[0][2], "text/xml")
metadata_xml = res[0][3]
con.close()
@@ -1988,151 +2325,177 @@ def testGeopackageSaveMetadata(self):
doc = QDomDocument()
doc.setContent(metadata_xml)
self.assertTrue(metadata3.readMetadataXml(doc.documentElement()))
- self.assertEqual(metadata3.abstract(), 'my abstract 2')
- self.assertEqual(metadata3.identifier(), 'my identifier 2')
- self.assertEqual(metadata3.licenses(), ['l1', 'l2'])
- self.assertEqual(metadata3.history(), ['h1', 'h2'])
+ self.assertEqual(metadata3.abstract(), "my abstract 2")
+ self.assertEqual(metadata3.identifier(), "my identifier 2")
+ self.assertEqual(metadata3.licenses(), ["l1", "l2"])
+ self.assertEqual(metadata3.history(), ["h1", "h2"])
def testGeopackageRestoreMetadata(self):
"""
Test that metadata saved to gpkg_metadata is automatically restored on layer load
"""
- tmpfile = os.path.join(self.basetestpath, 'testGeopackageRestoreMetadata.gpkg')
- ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile)
- lyr = ds.CreateLayer('test', geom_type=ogr.wkbPolygon)
- lyr.CreateField(ogr.FieldDefn('str_field', ogr.OFTString))
- lyr.CreateField(ogr.FieldDefn('str_field2', ogr.OFTString))
+ tmpfile = os.path.join(self.basetestpath, "testGeopackageRestoreMetadata.gpkg")
+ ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile)
+ lyr = ds.CreateLayer("test", geom_type=ogr.wkbPolygon)
+ lyr.CreateField(ogr.FieldDefn("str_field", ogr.OFTString))
+ lyr.CreateField(ogr.FieldDefn("str_field2", ogr.OFTString))
f = None
ds = None
# now save some metadata
metadata = QgsLayerMetadata()
- metadata.setAbstract('my abstract')
- metadata.setIdentifier('my identifier')
- metadata.setLicenses(['l1', 'l2'])
- ok, err = QgsProviderRegistry.instance().saveLayerMetadata('ogr', QgsProviderRegistry.instance().encodeUri('ogr', {'path': tmpfile, 'layerName': 'test'}), metadata)
+ metadata.setAbstract("my abstract")
+ metadata.setIdentifier("my identifier")
+ metadata.setLicenses(["l1", "l2"])
+ ok, err = QgsProviderRegistry.instance().saveLayerMetadata(
+ "ogr",
+ QgsProviderRegistry.instance().encodeUri(
+ "ogr", {"path": tmpfile, "layerName": "test"}
+ ),
+ metadata,
+ )
self.assertTrue(ok)
- vl = QgsVectorLayer(tmpfile, 'test')
+ vl = QgsVectorLayer(tmpfile, "test")
self.assertTrue(vl.isValid())
metadata2 = vl.metadata()
- self.assertEqual(metadata2.abstract(), 'my abstract')
- self.assertEqual(metadata2.identifier(), 'my identifier')
- self.assertEqual(metadata2.licenses(), ['l1', 'l2'])
+ self.assertEqual(metadata2.abstract(), "my abstract")
+ self.assertEqual(metadata2.identifier(), "my identifier")
+ self.assertEqual(metadata2.licenses(), ["l1", "l2"])
def testGeopackageSaveDefaultMetadata(self):
"""
Test saving layer metadata as default to a gpkg file
"""
- tmpfile = os.path.join(self.basetestpath, 'testGeopackageSaveMetadataDefault.gpkg')
- ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile)
- lyr = ds.CreateLayer('test', geom_type=ogr.wkbPolygon)
- lyr.CreateField(ogr.FieldDefn('str_field', ogr.OFTString))
- lyr.CreateField(ogr.FieldDefn('str_field2', ogr.OFTString))
+ tmpfile = os.path.join(
+ self.basetestpath, "testGeopackageSaveMetadataDefault.gpkg"
+ )
+ ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile)
+ lyr = ds.CreateLayer("test", geom_type=ogr.wkbPolygon)
+ lyr.CreateField(ogr.FieldDefn("str_field", ogr.OFTString))
+ lyr.CreateField(ogr.FieldDefn("str_field2", ogr.OFTString))
f = None
ds = None
- uri = QgsProviderRegistry.instance().encodeUri('ogr', {'path': tmpfile, 'layerName': 'test'})
- layer = QgsVectorLayer(uri, 'test')
+ uri = QgsProviderRegistry.instance().encodeUri(
+ "ogr", {"path": tmpfile, "layerName": "test"}
+ )
+ layer = QgsVectorLayer(uri, "test")
self.assertTrue(layer.isValid())
# now save some metadata
metadata = QgsLayerMetadata()
- metadata.setAbstract('my abstract')
- metadata.setIdentifier('my identifier')
- metadata.setLicenses(['l1', 'l2'])
+ metadata.setAbstract("my abstract")
+ metadata.setIdentifier("my identifier")
+ metadata.setLicenses(["l1", "l2"])
layer.setMetadata(metadata)
# save as default
msg, res = layer.saveDefaultMetadata()
self.assertTrue(res)
# QMD sidecar should NOT exist -- metadata should be written to gpkg_metadata table
- self.assertFalse(os.path.exists(os.path.join(self.basetestpath, 'testGeopackageSaveMetadataDefault.qmd')))
+ self.assertFalse(
+ os.path.exists(
+ os.path.join(self.basetestpath, "testGeopackageSaveMetadataDefault.qmd")
+ )
+ )
con = spatialite_connect(tmpfile, isolation_level=None)
cur = con.cursor()
# check that main gpkg_contents metadata columns have been updated
- rs = cur.execute("SELECT identifier, description FROM gpkg_contents WHERE table_name='test'")
+ rs = cur.execute(
+ "SELECT identifier, description FROM gpkg_contents WHERE table_name='test'"
+ )
rows = [r for r in rs]
self.assertEqual(len(rows), 1)
- self.assertCountEqual(rows[0], ['my identifier', 'my abstract'])
+ self.assertCountEqual(rows[0], ["my identifier", "my abstract"])
- rs = cur.execute("SELECT md_file_id FROM gpkg_metadata_reference WHERE table_name='test'")
+ rs = cur.execute(
+ "SELECT md_file_id FROM gpkg_metadata_reference WHERE table_name='test'"
+ )
rows = [r for r in rs]
file_ids = [row[0] for row in rows]
self.assertTrue(file_ids)
- rs = cur.execute("SELECT id, md_scope, mime_type, metadata FROM gpkg_metadata WHERE md_standard_uri='http://mrcc.com/qgis.dtd'")
+ rs = cur.execute(
+ "SELECT id, md_scope, mime_type, metadata FROM gpkg_metadata WHERE md_standard_uri='http://mrcc.com/qgis.dtd'"
+ )
res = [row for row in rs]
self.assertEqual(len(res), 1)
# id must match md_file_id from gpkg_metadata_reference
self.assertIn(res[0][0], file_ids)
- self.assertEqual(res[0][1], 'dataset')
- self.assertEqual(res[0][2], 'text/xml')
+ self.assertEqual(res[0][1], "dataset")
+ self.assertEqual(res[0][2], "text/xml")
con.close()
# reload layer and check that metadata was restored
- layer2 = QgsVectorLayer(uri, 'test')
+ layer2 = QgsVectorLayer(uri, "test")
self.assertTrue(layer2.isValid())
- self.assertEqual(layer2.metadata().abstract(), 'my abstract')
- self.assertEqual(layer2.metadata().identifier(), 'my identifier')
- self.assertEqual(layer2.metadata().licenses(), ['l1', 'l2'])
+ self.assertEqual(layer2.metadata().abstract(), "my abstract")
+ self.assertEqual(layer2.metadata().identifier(), "my identifier")
+ self.assertEqual(layer2.metadata().licenses(), ["l1", "l2"])
def testUniqueValuesOnFidColumn(self):
"""Test regression #21311 OGR provider returns an empty set for GPKG uniqueValues"""
- tmpfile = os.path.join(self.basetestpath, 'testGeopackageUniqueValuesOnFidColumn.gpkg')
- ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile)
- lyr = ds.CreateLayer('test', geom_type=ogr.wkbPolygon)
- lyr.CreateField(ogr.FieldDefn('str_field', ogr.OFTString))
+ tmpfile = os.path.join(
+ self.basetestpath, "testGeopackageUniqueValuesOnFidColumn.gpkg"
+ )
+ ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile)
+ lyr = ds.CreateLayer("test", geom_type=ogr.wkbPolygon)
+ lyr.CreateField(ogr.FieldDefn("str_field", ogr.OFTString))
f = ogr.Feature(lyr.GetLayerDefn())
- f.SetGeometry(ogr.CreateGeometryFromWkt('POLYGON ((0 0,0 1,1 1,1 0,0 0))'))
- f.SetField('str_field', 'one')
+ f.SetGeometry(ogr.CreateGeometryFromWkt("POLYGON ((0 0,0 1,1 1,1 0,0 0))"))
+ f.SetField("str_field", "one")
lyr.CreateFeature(f)
f = ogr.Feature(lyr.GetLayerDefn())
- f.SetGeometry(ogr.CreateGeometryFromWkt('POLYGON ((0 0,0 2,2 2,2 0,0 0))'))
- f.SetField('str_field', 'two')
+ f.SetGeometry(ogr.CreateGeometryFromWkt("POLYGON ((0 0,0 2,2 2,2 0,0 0))"))
+ f.SetField("str_field", "two")
lyr.CreateFeature(f)
f = None
ds = None
- vl1 = QgsVectorLayer(f'{tmpfile}' + "|layername=" + "test", 'test', 'ogr')
+ vl1 = QgsVectorLayer(f"{tmpfile}" + "|layername=" + "test", "test", "ogr")
self.assertTrue(vl1.isValid())
self.assertEqual(vl1.uniqueValues(0), {1, 2})
- self.assertEqual(vl1.uniqueValues(1), {'one', 'two'})
+ self.assertEqual(vl1.uniqueValues(1), {"one", "two"})
def testForeignKeyViolation(self):
"""Test that we can open a dataset with a foreign key violation"""
- tmpfile = os.path.join(self.basetestpath, 'testForeignKeyViolation.gpkg')
- ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile)
- lyr = ds.CreateLayer('test', geom_type=ogr.wkbPoint)
+ tmpfile = os.path.join(self.basetestpath, "testForeignKeyViolation.gpkg")
+ ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile)
+ lyr = ds.CreateLayer("test", geom_type=ogr.wkbPoint)
f = ogr.Feature(lyr.GetLayerDefn())
- f.SetGeometry(ogr.CreateGeometryFromWkt('POINT(0 1)'))
+ f.SetGeometry(ogr.CreateGeometryFromWkt("POINT(0 1)"))
lyr.CreateFeature(f)
ds.ExecuteSQL("PRAGMA foreign_keys = OFF")
ds.ExecuteSQL("CREATE TABLE foo(id INTEGER)")
ds.ExecuteSQL(
- "CREATE TABLE bar(fkey INTEGER, CONSTRAINT fkey_constraint FOREIGN KEY (fkey) REFERENCES foo(id))")
+ "CREATE TABLE bar(fkey INTEGER, CONSTRAINT fkey_constraint FOREIGN KEY (fkey) REFERENCES foo(id))"
+ )
ds.ExecuteSQL("INSERT INTO bar VALUES (1)")
ds = None
- vl = QgsVectorLayer(f'{tmpfile}' + "|layername=" + "test", 'test', 'ogr')
+ vl = QgsVectorLayer(f"{tmpfile}" + "|layername=" + "test", "test", "ogr")
self.assertTrue(vl.isValid())
- fids = {f['fid'] for f in vl.getFeatures()}
+ fids = {f["fid"] for f in vl.getFeatures()}
self.assertEqual(len(fids), 1)
def testForeignKeyViolationAfterOpening(self):
"""Test that foreign keys are enforced"""
- tmpfile = os.path.join(self.basetestpath, 'testForeignKeyViolationAfterOpening.gpkg')
- ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile)
- lyr = ds.CreateLayer('test', geom_type=ogr.wkbPoint)
+ tmpfile = os.path.join(
+ self.basetestpath, "testForeignKeyViolationAfterOpening.gpkg"
+ )
+ ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile)
+ lyr = ds.CreateLayer("test", geom_type=ogr.wkbPoint)
f = ogr.Feature(lyr.GetLayerDefn())
- f.SetGeometry(ogr.CreateGeometryFromWkt('POINT(0 1)'))
+ f.SetGeometry(ogr.CreateGeometryFromWkt("POINT(0 1)"))
lyr.CreateFeature(f)
ds.ExecuteSQL(
- "CREATE TABLE bar(fid INTEGER PRIMARY KEY, fkey INTEGER, CONSTRAINT fkey_constraint FOREIGN KEY (fkey) REFERENCES test(fid))")
+ "CREATE TABLE bar(fid INTEGER PRIMARY KEY, fkey INTEGER, CONSTRAINT fkey_constraint FOREIGN KEY (fkey) REFERENCES test(fid))"
+ )
ds = None
- vl = QgsVectorLayer(f'{tmpfile}' + "|layername=bar", 'test', 'ogr')
+ vl = QgsVectorLayer(f"{tmpfile}" + "|layername=bar", "test", "ogr")
self.assertTrue(vl.isValid())
# OK
@@ -2148,120 +2511,156 @@ def testForeignKeyViolationAfterOpening(self):
def testExportMultiFromShp(self):
"""Test if a Point is imported as single geom and MultiPoint as multi"""
- single_tmpfile = os.path.join(self.basetestpath, 'testExportMultiFromShp_point.shp')
- ds = ogr.GetDriverByName('ESRI Shapefile').CreateDataSource(single_tmpfile)
- lyr = ds.CreateLayer('test', geom_type=ogr.wkbPoint)
- lyr.CreateField(ogr.FieldDefn('str_field', ogr.OFTString))
+ single_tmpfile = os.path.join(
+ self.basetestpath, "testExportMultiFromShp_point.shp"
+ )
+ ds = ogr.GetDriverByName("ESRI Shapefile").CreateDataSource(single_tmpfile)
+ lyr = ds.CreateLayer("test", geom_type=ogr.wkbPoint)
+ lyr.CreateField(ogr.FieldDefn("str_field", ogr.OFTString))
f = ogr.Feature(lyr.GetLayerDefn())
- f.SetGeometry(ogr.CreateGeometryFromWkt('POINT (0 0)'))
- f.SetField('str_field', 'one')
+ f.SetGeometry(ogr.CreateGeometryFromWkt("POINT (0 0)"))
+ f.SetField("str_field", "one")
lyr.CreateFeature(f)
f = ogr.Feature(lyr.GetLayerDefn())
- f.SetGeometry(ogr.CreateGeometryFromWkt('POINT (1 1)'))
- f.SetField('str_field', 'two')
+ f.SetGeometry(ogr.CreateGeometryFromWkt("POINT (1 1)"))
+ f.SetField("str_field", "two")
lyr.CreateFeature(f)
f = None
ds = None
- multi_tmpfile = os.path.join(self.basetestpath, 'testExportMultiFromShp_multipoint.shp')
- ds = ogr.GetDriverByName('ESRI Shapefile').CreateDataSource(multi_tmpfile)
- lyr = ds.CreateLayer('test', geom_type=ogr.wkbMultiPoint)
- lyr.CreateField(ogr.FieldDefn('str_field', ogr.OFTString))
+ multi_tmpfile = os.path.join(
+ self.basetestpath, "testExportMultiFromShp_multipoint.shp"
+ )
+ ds = ogr.GetDriverByName("ESRI Shapefile").CreateDataSource(multi_tmpfile)
+ lyr = ds.CreateLayer("test", geom_type=ogr.wkbMultiPoint)
+ lyr.CreateField(ogr.FieldDefn("str_field", ogr.OFTString))
f = ogr.Feature(lyr.GetLayerDefn())
- f.SetGeometry(ogr.CreateGeometryFromWkt('MULTIPOINT ((0 0))'))
- f.SetField('str_field', 'one')
+ f.SetGeometry(ogr.CreateGeometryFromWkt("MULTIPOINT ((0 0))"))
+ f.SetField("str_field", "one")
lyr.CreateFeature(f)
f = ogr.Feature(lyr.GetLayerDefn())
- f.SetGeometry(ogr.CreateGeometryFromWkt('MULTIPOINT ((1 1), (2 2))'))
- f.SetField('str_field', 'two')
+ f.SetGeometry(ogr.CreateGeometryFromWkt("MULTIPOINT ((1 1), (2 2))"))
+ f.SetField("str_field", "two")
lyr.CreateFeature(f)
f = None
ds = None
- tmpfile = os.path.join(self.basetestpath, 'testExportMultiFromShpMulti.gpkg')
+ tmpfile = os.path.join(self.basetestpath, "testExportMultiFromShpMulti.gpkg")
options = {}
- options['driverName'] = 'GPKG'
- lyr = QgsVectorLayer(multi_tmpfile, 'y', 'ogr')
+ options["driverName"] = "GPKG"
+ lyr = QgsVectorLayer(multi_tmpfile, "y", "ogr")
self.assertTrue(lyr.isValid())
self.assertEqual(lyr.featureCount(), 2)
- err, _ = QgsVectorLayerExporter.exportLayer(lyr, tmpfile, "ogr", lyr.crs(), False, options)
+ err, _ = QgsVectorLayerExporter.exportLayer(
+ lyr, tmpfile, "ogr", lyr.crs(), False, options
+ )
self.assertEqual(err, 0)
lyr = QgsVectorLayer(tmpfile, "y", "ogr")
self.assertTrue(lyr.isValid())
self.assertEqual(lyr.wkbType(), QgsWkbTypes.Type.MultiPoint)
features = lyr.getFeatures()
f = next(features)
- self.assertEqual(f.geometry().asWkt().upper(), 'MULTIPOINT ((0 0))')
+ self.assertEqual(f.geometry().asWkt().upper(), "MULTIPOINT ((0 0))")
f = next(features)
- self.assertEqual(f.geometry().asWkt().upper(), 'MULTIPOINT ((1 1),(2 2))')
+ self.assertEqual(f.geometry().asWkt().upper(), "MULTIPOINT ((1 1),(2 2))")
- tmpfile = os.path.join(self.basetestpath, 'testExportMultiFromShpSingle.gpkg')
+ tmpfile = os.path.join(self.basetestpath, "testExportMultiFromShpSingle.gpkg")
options = {}
- options['driverName'] = 'GPKG'
- lyr = QgsVectorLayer(single_tmpfile, 'y', 'ogr')
+ options["driverName"] = "GPKG"
+ lyr = QgsVectorLayer(single_tmpfile, "y", "ogr")
self.assertTrue(lyr.isValid())
self.assertEqual(lyr.featureCount(), 2)
- err, _ = QgsVectorLayerExporter.exportLayer(lyr, tmpfile, "ogr", lyr.crs(), False, options)
+ err, _ = QgsVectorLayerExporter.exportLayer(
+ lyr, tmpfile, "ogr", lyr.crs(), False, options
+ )
self.assertEqual(err, 0)
lyr = QgsVectorLayer(tmpfile, "y", "ogr")
self.assertTrue(lyr.isValid())
self.assertEqual(lyr.wkbType(), QgsWkbTypes.Type.Point)
features = lyr.getFeatures()
f = next(features)
- self.assertEqual(f.geometry().asWkt().upper(), 'POINT (0 0)')
+ self.assertEqual(f.geometry().asWkt().upper(), "POINT (0 0)")
f = next(features)
- self.assertEqual(f.geometry().asWkt().upper(), 'POINT (1 1)')
+ self.assertEqual(f.geometry().asWkt().upper(), "POINT (1 1)")
def testMinMaxDateField(self):
"""
Test that provider min/max calls work with date fields
:return:
"""
- tmpfile = os.path.join(self.basetestpath, 'test_min_max_date_field.gpkg')
- shutil.copy(TEST_DATA_DIR + '/' + 'qgis_server/test_project_api_timefilters.gpkg', tmpfile)
+ tmpfile = os.path.join(self.basetestpath, "test_min_max_date_field.gpkg")
+ shutil.copy(
+ TEST_DATA_DIR + "/" + "qgis_server/test_project_api_timefilters.gpkg",
+ tmpfile,
+ )
- vl = QgsVectorLayer(tmpfile, 'subset_test', 'ogr')
+ vl = QgsVectorLayer(tmpfile, "subset_test", "ogr")
self.assertTrue(vl.isValid())
self.assertEqual(vl.fields().at(2).type(), QVariant.Date)
self.assertEqual(vl.fields().at(3).type(), QVariant.DateTime)
self.assertEqual(vl.dataProvider().minimumValue(2), QDate(2010, 1, 1))
self.assertEqual(vl.dataProvider().maximumValue(2), QDate(2019, 1, 1))
- self.assertEqual(vl.dataProvider().minimumValue(3), QDateTime(2010, 1, 1, 1, 1, 1, 0))
- self.assertEqual(vl.dataProvider().maximumValue(3), QDateTime(2022, 1, 1, 1, 1, 1, 0))
- self.assertEqual(vl.dataProvider().uniqueValues(2),
- {QDate(2017, 1, 1), NULL, QDate(2018, 1, 1), QDate(2019, 1, 1), QDate(2010, 1, 1)})
- self.assertEqual(vl.dataProvider().uniqueValues(3),
- {QDateTime(2022, 1, 1, 1, 1, 1), NULL, QDateTime(2019, 1, 1, 1, 1, 1),
- QDateTime(2021, 1, 1, 1, 1, 1), QDateTime(2010, 1, 1, 1, 1, 1)})
+ self.assertEqual(
+ vl.dataProvider().minimumValue(3), QDateTime(2010, 1, 1, 1, 1, 1, 0)
+ )
+ self.assertEqual(
+ vl.dataProvider().maximumValue(3), QDateTime(2022, 1, 1, 1, 1, 1, 0)
+ )
+ self.assertEqual(
+ vl.dataProvider().uniqueValues(2),
+ {
+ QDate(2017, 1, 1),
+ NULL,
+ QDate(2018, 1, 1),
+ QDate(2019, 1, 1),
+ QDate(2010, 1, 1),
+ },
+ )
+ self.assertEqual(
+ vl.dataProvider().uniqueValues(3),
+ {
+ QDateTime(2022, 1, 1, 1, 1, 1),
+ NULL,
+ QDateTime(2019, 1, 1, 1, 1, 1),
+ QDateTime(2021, 1, 1, 1, 1, 1),
+ QDateTime(2010, 1, 1, 1, 1, 1),
+ },
+ )
def testExporterWithFIDColumn(self):
"""Test issue GH #34333, a memory layer with FID is not exported correctly to GPKG"""
vl = QgsVectorLayer(
- 'Point?crs=epsg:4326&field=FID:integer(0)&field=name:string(20)',
- 'test',
- 'memory')
+ "Point?crs=epsg:4326&field=FID:integer(0)&field=name:string(20)",
+ "test",
+ "memory",
+ )
- self.assertTrue(vl.isValid(), 'Provider not initialized')
+ self.assertTrue(vl.isValid(), "Provider not initialized")
ft = QgsFeature(vl.fields())
- ft.setAttributes([123, 'text1'])
- ft.setGeometry(QgsGeometry.fromWkt('Point(2 49)'))
+ ft.setAttributes([123, "text1"])
+ ft.setGeometry(QgsGeometry.fromWkt("Point(2 49)"))
myResult, myFeatures = vl.dataProvider().addFeatures([ft])
self.assertTrue(myResult)
self.assertTrue(myFeatures)
- dest_file_name = tempfile.mktemp('.gpkg')
- err = QgsVectorLayerExporter.exportLayer(vl, dest_file_name, "ogr", vl.crs(), False)
- self.assertEqual(err[0], QgsVectorLayerExporter.ExportError.NoError,
- f'unexpected import error {err}')
+ dest_file_name = tempfile.mktemp(".gpkg")
+ err = QgsVectorLayerExporter.exportLayer(
+ vl, dest_file_name, "ogr", vl.crs(), False
+ )
+ self.assertEqual(
+ err[0],
+ QgsVectorLayerExporter.ExportError.NoError,
+ f"unexpected import error {err}",
+ )
# Open result and check
- created_layer = QgsVectorLayer(dest_file_name, 'test', 'ogr')
+ created_layer = QgsVectorLayer(dest_file_name, "test", "ogr")
self.assertTrue(created_layer.isValid())
f = next(created_layer.getFeatures())
- self.assertEqual(f.geometry().asWkt(), 'Point (2 49)')
- self.assertEqual(f.attributes(), [123, 'text1'])
+ self.assertEqual(f.geometry().asWkt(), "Point (2 49)")
+ self.assertEqual(f.attributes(), [123, "text1"])
self.assertEqual(f.id(), 123)
def testTransactionGroup(self):
@@ -2269,25 +2668,29 @@ def testTransactionGroup(self):
project = QgsProject()
project.setTransactionMode(Qgis.TransactionMode.AutomaticGroups)
- tmpfile1 = os.path.join(self.basetestpath, 'tempGeoPackageTransactionGroup1.gpkg')
- tmpfile2 = os.path.join(self.basetestpath, 'tempGeoPackageTransactionGroup2.gpkg')
+ tmpfile1 = os.path.join(
+ self.basetestpath, "tempGeoPackageTransactionGroup1.gpkg"
+ )
+ tmpfile2 = os.path.join(
+ self.basetestpath, "tempGeoPackageTransactionGroup2.gpkg"
+ )
for tmpfile in (tmpfile1, tmpfile2):
- ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile)
+ ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile)
for i in range(2):
- lyr = ds.CreateLayer(f'test{i}', geom_type=ogr.wkbPoint)
- lyr.CreateField(ogr.FieldDefn('str_field', ogr.OFTString))
+ lyr = ds.CreateLayer(f"test{i}", geom_type=ogr.wkbPoint)
+ lyr.CreateField(ogr.FieldDefn("str_field", ogr.OFTString))
f = ogr.Feature(lyr.GetLayerDefn())
- f.SetGeometry(ogr.CreateGeometryFromWkt('POINT (1 1)'))
- f.SetField('str_field', 'one')
+ f.SetGeometry(ogr.CreateGeometryFromWkt("POINT (1 1)"))
+ f.SetField("str_field", "one")
lyr.CreateFeature(f)
- vl1_1 = QgsVectorLayer(tmpfile1, 'test1_1', 'ogr')
+ vl1_1 = QgsVectorLayer(tmpfile1, "test1_1", "ogr")
self.assertTrue(vl1_1.isValid())
- vl1_2 = QgsVectorLayer(tmpfile1, 'test1_2', 'ogr')
+ vl1_2 = QgsVectorLayer(tmpfile1, "test1_2", "ogr")
self.assertTrue(vl1_2.isValid())
- vl2_1 = QgsVectorLayer(tmpfile2, 'test2_1', 'ogr')
+ vl2_1 = QgsVectorLayer(tmpfile2, "test2_1", "ogr")
self.assertTrue(vl2_1.isValid())
- vl2_2 = QgsVectorLayer(tmpfile2, 'test2_2', 'ogr')
+ vl2_2 = QgsVectorLayer(tmpfile2, "test2_2", "ogr")
self.assertTrue(vl2_2.isValid())
project.addMapLayers([vl1_1, vl1_2, vl2_1, vl2_2])
@@ -2314,56 +2717,56 @@ def testTransactionGroupIterator(self):
project = QgsProject()
project.setTransactionMode(Qgis.TransactionMode.AutomaticGroups)
tmpfile = os.path.join(
- self.basetestpath, 'tempGeoPackageTransactionGroupIterator.gpkg')
- ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile)
- lyr = ds.CreateLayer('test', geom_type=ogr.wkbPoint)
- lyr.CreateField(ogr.FieldDefn('str_field', ogr.OFTString))
+ self.basetestpath, "tempGeoPackageTransactionGroupIterator.gpkg"
+ )
+ ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile)
+ lyr = ds.CreateLayer("test", geom_type=ogr.wkbPoint)
+ lyr.CreateField(ogr.FieldDefn("str_field", ogr.OFTString))
f = ogr.Feature(lyr.GetLayerDefn())
- f.SetGeometry(ogr.CreateGeometryFromWkt('POINT (1 1)'))
- f.SetField('str_field', 'one')
+ f.SetGeometry(ogr.CreateGeometryFromWkt("POINT (1 1)"))
+ f.SetField("str_field", "one")
lyr.CreateFeature(f)
del lyr
del ds
- vl = QgsVectorLayer(tmpfile + '|layername=test', 'test', 'ogr')
+ vl = QgsVectorLayer(tmpfile + "|layername=test", "test", "ogr")
project.addMapLayers([vl])
self.assertTrue(vl.startEditing())
features = [f for f in vl.getFeatures()]
for f in features:
- self.assertTrue(vl.changeAttributeValue(1, 1, 'new value'))
+ self.assertTrue(vl.changeAttributeValue(1, 1, "new value"))
# Test that QGIS sees the new changes
- self.assertEqual(next(vl.getFeatures()).attribute(1), 'new value')
+ self.assertEqual(next(vl.getFeatures()).attribute(1), "new value")
def testTransactionGroupCrash(self):
"""Test issue GH #39265 segfault"""
project = QgsProject()
project.setTransactionMode(Qgis.TransactionMode.AutomaticGroups)
- tmpfile = os.path.join(
- self.basetestpath, 'tempGeoPackageTransactionCrash.gpkg')
- ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile)
- lyr = ds.CreateLayer('test', geom_type=ogr.wkbPoint)
- lyr.CreateField(ogr.FieldDefn('str_field', ogr.OFTString))
+ tmpfile = os.path.join(self.basetestpath, "tempGeoPackageTransactionCrash.gpkg")
+ ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile)
+ lyr = ds.CreateLayer("test", geom_type=ogr.wkbPoint)
+ lyr.CreateField(ogr.FieldDefn("str_field", ogr.OFTString))
f = ogr.Feature(lyr.GetLayerDefn())
- f.SetGeometry(ogr.CreateGeometryFromWkt('POINT (1 1)'))
- f.SetField('str_field', 'one')
+ f.SetGeometry(ogr.CreateGeometryFromWkt("POINT (1 1)"))
+ f.SetField("str_field", "one")
lyr.CreateFeature(f)
del lyr
del ds
- vl = QgsVectorLayer(tmpfile + '|layername=test', 'test', 'ogr')
+ vl = QgsVectorLayer(tmpfile + "|layername=test", "test", "ogr")
project.addMapLayers([vl])
feature = next(vl.getFeatures())
- feature.setAttributes([None, 'two'])
+ feature.setAttributes([None, "two"])
self.assertTrue(vl.startEditing())
self.assertTrue(vl.addFeature(feature))
@@ -2372,30 +2775,44 @@ def testTransactionGroupCrash(self):
self.assertTrue(vl.commitChanges(False))
# Now add another one
- feature.setAttributes([None, 'three'])
+ feature.setAttributes([None, "three"])
self.assertTrue(vl.addFeature(feature))
self.assertTrue(vl.commitChanges(True))
- def _testVectorLayerExporterDeferredSpatialIndex(self, layerOptions, expectSpatialIndex):
- """ Internal method """
+ def _testVectorLayerExporterDeferredSpatialIndex(
+ self, layerOptions, expectSpatialIndex
+ ):
+ """Internal method"""
tmpfile = os.path.join(
- self.basetestpath, 'testVectorLayerExporterDeferredSpatialIndex.gpkg')
+ self.basetestpath, "testVectorLayerExporterDeferredSpatialIndex.gpkg"
+ )
if os.path.exists(tmpfile):
os.unlink(tmpfile)
options = {}
- options['driverName'] = 'GPKG'
- options['layerName'] = 'table1'
+ options["driverName"] = "GPKG"
+ options["layerName"] = "table1"
if layerOptions:
- options['layerOptions'] = layerOptions
- exporter = QgsVectorLayerExporter(tmpfile, "ogr", QgsFields(), QgsWkbTypes.Type.Polygon,
- QgsCoordinateReferenceSystem('EPSG:3111'), False, options)
- self.assertFalse(exporter.errorCode(),
- f'unexpected export error {exporter.errorCode()}: {exporter.errorMessage()}')
+ options["layerOptions"] = layerOptions
+ exporter = QgsVectorLayerExporter(
+ tmpfile,
+ "ogr",
+ QgsFields(),
+ QgsWkbTypes.Type.Polygon,
+ QgsCoordinateReferenceSystem("EPSG:3111"),
+ False,
+ options,
+ )
+ self.assertFalse(
+ exporter.errorCode(),
+ f"unexpected export error {exporter.errorCode()}: {exporter.errorMessage()}",
+ )
# Check that at that point the rtree is *not* created
ds = ogr.Open(tmpfile)
- sql_lyr = ds.ExecuteSQL("SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = 'gpkg_extensions'")
+ sql_lyr = ds.ExecuteSQL(
+ "SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = 'gpkg_extensions'"
+ )
assert sql_lyr.GetNextFeature() is None
ds.ReleaseResultSet(sql_lyr)
del ds
@@ -2405,21 +2822,27 @@ def _testVectorLayerExporterDeferredSpatialIndex(self, layerOptions, expectSpati
ds = gdal.OpenEx(tmpfile, gdal.OF_VECTOR)
if expectSpatialIndex:
# Check that at that point the rtree is created
- sql_lyr = ds.ExecuteSQL("SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = 'gpkg_extensions'")
+ sql_lyr = ds.ExecuteSQL(
+ "SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = 'gpkg_extensions'"
+ )
assert sql_lyr.GetNextFeature() is not None
ds.ReleaseResultSet(sql_lyr)
- sql_lyr = ds.ExecuteSQL("SELECT 1 FROM gpkg_extensions WHERE table_name = 'table1' AND extension_name = 'gpkg_rtree_index'")
+ sql_lyr = ds.ExecuteSQL(
+ "SELECT 1 FROM gpkg_extensions WHERE table_name = 'table1' AND extension_name = 'gpkg_rtree_index'"
+ )
assert sql_lyr.GetNextFeature() is not None
ds.ReleaseResultSet(sql_lyr)
else:
# Check that at that point the rtree is *still not* created
- sql_lyr = ds.ExecuteSQL("SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = 'gpkg_extensions'")
+ sql_lyr = ds.ExecuteSQL(
+ "SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = 'gpkg_extensions'"
+ )
assert sql_lyr.GetNextFeature() is None
ds.ReleaseResultSet(sql_lyr)
return ds
def testVectorLayerExporterDeferredSpatialIndexNoLayerOptions(self):
- """ Check that a deferred spatial index is created when no layer creation options is provided """
+ """Check that a deferred spatial index is created when no layer creation options is provided"""
ds = self._testVectorLayerExporterDeferredSpatialIndex(None, True)
filename = ds.GetDescription()
@@ -2427,45 +2850,57 @@ def testVectorLayerExporterDeferredSpatialIndexNoLayerOptions(self):
gdal.Unlink(filename)
def testVectorLayerExporterDeferredSpatialIndexLayerOptions(self):
- """ Check that a deferred spatial index is created when other layer creations options is provided """
+ """Check that a deferred spatial index is created when other layer creations options is provided"""
- ds = self._testVectorLayerExporterDeferredSpatialIndex(['GEOMETRY_NAME=my_geom'], True)
+ ds = self._testVectorLayerExporterDeferredSpatialIndex(
+ ["GEOMETRY_NAME=my_geom"], True
+ )
lyr = ds.GetLayer(0)
- self.assertEqual(lyr.GetGeometryColumn(), 'my_geom')
+ self.assertEqual(lyr.GetGeometryColumn(), "my_geom")
filename = ds.GetDescription()
del ds
gdal.Unlink(filename)
def testVectorLayerExporterDeferredSpatialIndexExplicitSpatialIndexAsked(self):
- """ Check that a deferred spatial index is created when explicit asked """
+ """Check that a deferred spatial index is created when explicit asked"""
- ds = self._testVectorLayerExporterDeferredSpatialIndex(['SPATIAL_INDEX=YES'], True)
+ ds = self._testVectorLayerExporterDeferredSpatialIndex(
+ ["SPATIAL_INDEX=YES"], True
+ )
filename = ds.GetDescription()
del ds
gdal.Unlink(filename)
def testVectorLayerExporterDeferredSpatialIndexSpatialIndexDisallowed(self):
- """ Check that a deferred spatial index is NOT created when explicit disallowed """
+ """Check that a deferred spatial index is NOT created when explicit disallowed"""
- ds = self._testVectorLayerExporterDeferredSpatialIndex(['SPATIAL_INDEX=NO'], False)
+ ds = self._testVectorLayerExporterDeferredSpatialIndex(
+ ["SPATIAL_INDEX=NO"], False
+ )
filename = ds.GetDescription()
del ds
gdal.Unlink(filename)
def testRollback(self):
- """ Test that a failed operation is properly rolled back """
- tmpfile = os.path.join(self.basetestpath, 'testRollback.gpkg')
+ """Test that a failed operation is properly rolled back"""
+ tmpfile = os.path.join(self.basetestpath, "testRollback.gpkg")
- ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile)
- lyr = ds.CreateLayer('test', geom_type=ogr.wkbPoint, options=['SPATIAL_INDEX=NO'])
+ ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile)
+ lyr = ds.CreateLayer(
+ "test", geom_type=ogr.wkbPoint, options=["SPATIAL_INDEX=NO"]
+ )
# Ugly hack to be able to create a column with unique constraint with GDAL < 3.2
- ds.ExecuteSQL('CREATE TABLE test2 ("fid" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "geom" POINT, v INTEGER, v_unique INTEGER UNIQUE)')
+ ds.ExecuteSQL(
+ 'CREATE TABLE test2 ("fid" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "geom" POINT, v INTEGER, v_unique INTEGER UNIQUE)'
+ )
ds.ExecuteSQL("UPDATE gpkg_contents SET table_name = 'test2'")
ds.ExecuteSQL("UPDATE gpkg_geometry_columns SET table_name = 'test2'")
- ds.ExecuteSQL('INSERT INTO test2 (fid, geom, v, v_unique) VALUES (1, NULL, -1, 123)')
+ ds.ExecuteSQL(
+ "INSERT INTO test2 (fid, geom, v, v_unique) VALUES (1, NULL, -1, 123)"
+ )
ds = None
- vl = QgsVectorLayer(f'{tmpfile}', 'test', 'ogr')
+ vl = QgsVectorLayer(f"{tmpfile}", "test", "ogr")
self.assertTrue(vl.isValid())
features = [f for f in vl.getFeatures()]
@@ -2491,132 +2926,161 @@ def testRollback(self):
self.assertEqual(features[1].attributes(), [2, -4, 125])
def testFixWrongMetadataReferenceColumnNameUpdate(self):
- """ Test that we (or GDAL) fixes wrong gpkg_metadata_reference_column_name_update trigger """
- tmpfile = os.path.join(self.basetestpath, 'testFixWrongMetadataReferenceColumnNameUpdate.gpkg')
+ """Test that we (or GDAL) fixes wrong gpkg_metadata_reference_column_name_update trigger"""
+ tmpfile = os.path.join(
+ self.basetestpath, "testFixWrongMetadataReferenceColumnNameUpdate.gpkg"
+ )
- ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile)
- ds.CreateLayer('test', geom_type=ogr.wkbPoint)
- ds.SetMetadata('FOO', 'BAR')
+ ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile)
+ ds.CreateLayer("test", geom_type=ogr.wkbPoint)
+ ds.SetMetadata("FOO", "BAR")
ds = None
ds = ogr.Open(tmpfile, update=1)
gdal.PushErrorHandler()
try:
- ds.ExecuteSQL('DROP TRIGGER gpkg_metadata_reference_column_name_update')
+ ds.ExecuteSQL("DROP TRIGGER gpkg_metadata_reference_column_name_update")
except Exception:
pass
gdal.PopErrorHandler()
# inject wrong trigger on purpose
- wrong_trigger = "CREATE TRIGGER 'gpkg_metadata_reference_column_name_update' " + \
- "BEFORE UPDATE OF column_name ON 'gpkg_metadata_reference' " + \
- "FOR EACH ROW BEGIN " + \
- "SELECT RAISE(ABORT, 'update on table gpkg_metadata_reference " + \
- "violates constraint: column name must be NULL when reference_scope " + \
- "is \"geopackage\", \"table\" or \"row\"') " + \
- "WHERE (NEW.reference_scope IN ('geopackage','table','row') " + \
- "AND NEW.column_nameIS NOT NULL); END;"
+ wrong_trigger = (
+ "CREATE TRIGGER 'gpkg_metadata_reference_column_name_update' "
+ + "BEFORE UPDATE OF column_name ON 'gpkg_metadata_reference' "
+ + "FOR EACH ROW BEGIN "
+ + "SELECT RAISE(ABORT, 'update on table gpkg_metadata_reference "
+ + "violates constraint: column name must be NULL when reference_scope "
+ + 'is "geopackage", "table" or "row"\') '
+ + "WHERE (NEW.reference_scope IN ('geopackage','table','row') "
+ + "AND NEW.column_nameIS NOT NULL); END;"
+ )
ds.ExecuteSQL(wrong_trigger)
ds = None
- vl = QgsVectorLayer(f'{tmpfile}', 'test', 'ogr')
+ vl = QgsVectorLayer(f"{tmpfile}", "test", "ogr")
self.assertTrue(vl.isValid())
del vl
# Check trigger afterwards
ds = ogr.Open(tmpfile)
sql_lyr = ds.ExecuteSQL(
- "SELECT sql FROM sqlite_master WHERE type = 'trigger' " +
- "AND name = 'gpkg_metadata_reference_column_name_update'")
+ "SELECT sql FROM sqlite_master WHERE type = 'trigger' "
+ + "AND name = 'gpkg_metadata_reference_column_name_update'"
+ )
f = sql_lyr.GetNextFeature()
- sql = f['sql']
+ sql = f["sql"]
ds.ReleaseResultSet(sql_lyr)
ds = None
gdal.Unlink(tmpfile)
- self.assertNotIn('column_nameIS', sql)
+ self.assertNotIn("column_nameIS", sql)
def testRejectedGeometryUpdate(self):
"""Test that we correctly behave when a geometry update fails"""
- tmpfile = os.path.join(self.basetestpath, 'testRejectedGeometryUpdate.gpkg')
- ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile)
- lyr = ds.CreateLayer('test', geom_type=ogr.wkbUnknown)
+ tmpfile = os.path.join(self.basetestpath, "testRejectedGeometryUpdate.gpkg")
+ ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile)
+ lyr = ds.CreateLayer("test", geom_type=ogr.wkbUnknown)
f = ogr.Feature(lyr.GetLayerDefn())
- f.SetGeometry(ogr.CreateGeometryFromWkt('POLYGON ((0 0,0 1,1 1,1 0,0 0))'))
+ f.SetGeometry(ogr.CreateGeometryFromWkt("POLYGON ((0 0,0 1,1 1,1 0,0 0))"))
lyr.CreateFeature(f)
- ds.ExecuteSQL("CREATE TRIGGER rejectGeometryUpdate BEFORE UPDATE OF geom ON test FOR EACH ROW BEGIN SELECT RAISE(ABORT, 'update forbidden'); END;")
+ ds.ExecuteSQL(
+ "CREATE TRIGGER rejectGeometryUpdate BEFORE UPDATE OF geom ON test FOR EACH ROW BEGIN SELECT RAISE(ABORT, 'update forbidden'); END;"
+ )
f = None
ds = None
- vl = QgsVectorLayer(f'{tmpfile}' + "|layername=" + "test", 'test', 'ogr')
+ vl = QgsVectorLayer(f"{tmpfile}" + "|layername=" + "test", "test", "ogr")
self.assertTrue(vl.isValid())
self.assertTrue(vl.startEditing())
- self.assertTrue(vl.changeGeometry(1, QgsGeometry.fromWkt('Point (0 0)')))
+ self.assertTrue(vl.changeGeometry(1, QgsGeometry.fromWkt("Point (0 0)")))
self.assertFalse(vl.commitChanges())
- vl = QgsVectorLayer(f'{tmpfile}' + "|layername=" + "test", 'test', 'ogr')
+ vl = QgsVectorLayer(f"{tmpfile}" + "|layername=" + "test", "test", "ogr")
self.assertTrue(vl.isValid())
g = [f.geometry() for f in vl.getFeatures()][0]
- self.assertEqual(g.asWkt(), 'Polygon ((0 0, 0 1, 1 1, 1 0, 0 0))')
+ self.assertEqual(g.asWkt(), "Polygon ((0 0, 0 1, 1 1, 1 0, 0 0))")
def testSubsetComments(self):
"""Test issue GH #45754"""
tmp_dir = QTemporaryDir()
- tmpfile = os.path.join(tmp_dir.path(), 'testSubsetComments.gpkg')
- ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile)
- lyr = ds.CreateLayer('my--test', geom_type=ogr.wkbPoint)
- lyr.CreateField(ogr.FieldDefn('text_field', ogr.OFTString))
- lyr.CreateField(ogr.FieldDefn('my--thing\'s', ogr.OFTString))
+ tmpfile = os.path.join(tmp_dir.path(), "testSubsetComments.gpkg")
+ ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile)
+ lyr = ds.CreateLayer("my--test", geom_type=ogr.wkbPoint)
+ lyr.CreateField(ogr.FieldDefn("text_field", ogr.OFTString))
+ lyr.CreateField(ogr.FieldDefn("my--thing's", ogr.OFTString))
f = ogr.Feature(lyr.GetLayerDefn())
- f.SetGeometry(ogr.CreateGeometryFromWkt('POINT(0 0)'))
- f['text_field'] = 'one'
- f['my--thing\'s'] = 'one'
+ f.SetGeometry(ogr.CreateGeometryFromWkt("POINT(0 0)"))
+ f["text_field"] = "one"
+ f["my--thing's"] = "one"
lyr.CreateFeature(f)
f = ogr.Feature(lyr.GetLayerDefn())
- f['text_field'] = 'two'
- f['my--thing\'s'] = 'my "things -- all'
- f.SetGeometry(ogr.CreateGeometryFromWkt('POINT(1 1)'))
+ f["text_field"] = "two"
+ f["my--thing's"] = 'my "things -- all'
+ f.SetGeometry(ogr.CreateGeometryFromWkt("POINT(1 1)"))
lyr.CreateFeature(f)
f = ogr.Feature(lyr.GetLayerDefn())
- f['text_field'] = 'three'
- f['my--thing\'s'] = 'my "things \n all'
- f.SetGeometry(ogr.CreateGeometryFromWkt('POINT(2 2)'))
+ f["text_field"] = "three"
+ f["my--thing's"] = 'my "things \n all'
+ f.SetGeometry(ogr.CreateGeometryFromWkt("POINT(2 2)"))
lyr.CreateFeature(f)
- del (lyr)
+ del lyr
def _test(subset_string):
- vl1 = QgsVectorLayer(f'{tmpfile}|subset={subset_string}'.format(tmpfile, subset_string), 'test', 'ogr')
+ vl1 = QgsVectorLayer(
+ f"{tmpfile}|subset={subset_string}".format(tmpfile, subset_string),
+ "test",
+ "ogr",
+ )
self.assertTrue(vl1.isValid())
self.assertEqual(vl1.featureCount(), 1)
- _test('-- comment\n SELECT * --comment\nFROM "my--test" WHERE text_field=\'one\'')
- _test('\n SELECT * --comment\nFROM "my--test" WHERE\n-- comment \ntext_field=\'one\'')
- _test(' SELECT * --comment\nFROM "my--test" WHERE\ntext_field=\'one\' AND \ntext_field != \'--embedded comment\'')
- _test('SELECT * FROM "my--test" WHERE text_field=\'one\' AND text_field != \' \\\'--embedded comment\'')
- _test('select "my--thing\'s" from "my--test" where "my--thing\'s" = \'my "things -- all\'')
- _test('select "my--thing\'s" from "my--test" where "my--thing\'s" = \'my "things \n all\'')
+ _test(
+ "-- comment\n SELECT * --comment\nFROM \"my--test\" WHERE text_field='one'"
+ )
+ _test(
+ "\n SELECT * --comment\nFROM \"my--test\" WHERE\n-- comment \ntext_field='one'"
+ )
+ _test(
+ " SELECT * --comment\nFROM \"my--test\" WHERE\ntext_field='one' AND \ntext_field != '--embedded comment'"
+ )
+ _test(
+ "SELECT * FROM \"my--test\" WHERE text_field='one' AND text_field != ' \\'--embedded comment'"
+ )
+ _test(
+ 'select "my--thing\'s" from "my--test" where "my--thing\'s" = \'my "things -- all\''
+ )
+ _test(
+ 'select "my--thing\'s" from "my--test" where "my--thing\'s" = \'my "things \n all\''
+ )
def testIsSqlQuery(self):
"""Test that isQuery returns what it should in case of simple filters"""
tmp_dir = QTemporaryDir()
- tmpfile = os.path.join(tmp_dir.path(), 'testQueryLayers.gpkg')
- ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile)
- lyr = ds.CreateLayer('test', geom_type=ogr.wkbPoint)
- lyr.CreateField(ogr.FieldDefn('text_field', ogr.OFTString))
+ tmpfile = os.path.join(tmp_dir.path(), "testQueryLayers.gpkg")
+ ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile)
+ lyr = ds.CreateLayer("test", geom_type=ogr.wkbPoint)
+ lyr.CreateField(ogr.FieldDefn("text_field", ogr.OFTString))
f = ogr.Feature(lyr.GetLayerDefn())
- f.SetGeometry(ogr.CreateGeometryFromWkt('POINT(0 0)'))
- f['text_field'] = 'one'
+ f.SetGeometry(ogr.CreateGeometryFromWkt("POINT(0 0)"))
+ f["text_field"] = "one"
lyr.CreateFeature(f)
f = ogr.Feature(lyr.GetLayerDefn())
- f['text_field'] = 'two'
- f.SetGeometry(ogr.CreateGeometryFromWkt('POINT(1 1)'))
+ f["text_field"] = "two"
+ f.SetGeometry(ogr.CreateGeometryFromWkt("POINT(1 1)"))
lyr.CreateFeature(f)
- del (lyr)
+ del lyr
- vl1 = QgsVectorLayer(f'{tmpfile}|subset=SELECT * FROM test WHERE "text_field"=\'one\''.format(tmpfile), 'test', 'ogr')
+ vl1 = QgsVectorLayer(
+ f"{tmpfile}|subset=SELECT * FROM test WHERE \"text_field\"='one'".format(
+ tmpfile
+ ),
+ "test",
+ "ogr",
+ )
self.assertTrue(vl1.isValid())
self.assertTrue(vl1.isSqlQuery())
self.assertEqual(vl1.featureCount(), 1)
@@ -2624,7 +3088,9 @@ def testIsSqlQuery(self):
# Test flags
self.assertTrue(vl1.vectorLayerTypeFlags() & Qgis.VectorLayerTypeFlag.SqlQuery)
- vl2 = QgsVectorLayer(f'{tmpfile}|subset="text_field"=\'one\''.format(tmpfile), 'test', 'ogr')
+ vl2 = QgsVectorLayer(
+ f"{tmpfile}|subset=\"text_field\"='one'".format(tmpfile), "test", "ogr"
+ )
self.assertTrue(vl2.isValid())
self.assertFalse(vl2.isSqlQuery())
self.assertEqual(vl2.featureCount(), 1)
@@ -2633,112 +3099,155 @@ def testIsSqlQuery(self):
self.assertFalse(vl2.vectorLayerTypeFlags() & Qgis.VectorLayerTypeFlag.SqlQuery)
def testCircularStringOnlyInUnknownTypeLayer(self):
- """ Test bugfix for https://github.com/qgis/QGIS/issues/47610 """
+ """Test bugfix for https://github.com/qgis/QGIS/issues/47610"""
- tmpfile = os.path.join(self.basetestpath, 'testCircularStringOnlyInUnknownTypeLayer.gpkg')
- ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile)
- lyr = ds.CreateLayer('test', geom_type=ogr.wkbUnknown)
+ tmpfile = os.path.join(
+ self.basetestpath, "testCircularStringOnlyInUnknownTypeLayer.gpkg"
+ )
+ ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile)
+ lyr = ds.CreateLayer("test", geom_type=ogr.wkbUnknown)
f = ogr.Feature(lyr.GetLayerDefn())
- f.SetGeometry(ogr.CreateGeometryFromWkt('CIRCULARSTRING(0 0,1 1,2 0)'))
+ f.SetGeometry(ogr.CreateGeometryFromWkt("CIRCULARSTRING(0 0,1 1,2 0)"))
lyr.CreateFeature(f)
ds = None
- vl = QgsVectorLayer(f'{tmpfile}', 'test', 'ogr')
+ vl = QgsVectorLayer(f"{tmpfile}", "test", "ogr")
self.assertEqual(1, vl.dataProvider().subLayerCount())
- self.assertEqual(vl.dataProvider().subLayers(),
- [QgsDataProvider.SUBLAYER_SEPARATOR.join(['0', 'test', '1', 'CircularString', 'geom', ''])])
+ self.assertEqual(
+ vl.dataProvider().subLayers(),
+ [
+ QgsDataProvider.SUBLAYER_SEPARATOR.join(
+ ["0", "test", "1", "CircularString", "geom", ""]
+ )
+ ],
+ )
- vl = QgsVectorLayer(f'{tmpfile}' + '|geometryType=CircularString', 'test', 'ogr')
+ vl = QgsVectorLayer(
+ f"{tmpfile}" + "|geometryType=CircularString", "test", "ogr"
+ )
got = [feat for feat in vl.getFeatures()]
self.assertEqual(len(got), 1)
def testCompoundCurveOnlyInUnknownTypeLayer(self):
- """ Test bugfix for https://github.com/qgis/QGIS/issues/47610 """
+ """Test bugfix for https://github.com/qgis/QGIS/issues/47610"""
- tmpfile = os.path.join(self.basetestpath, 'testCompoundCurveOnlyInUnknownTypeLayer.gpkg')
- ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile)
- lyr = ds.CreateLayer('test', geom_type=ogr.wkbUnknown)
+ tmpfile = os.path.join(
+ self.basetestpath, "testCompoundCurveOnlyInUnknownTypeLayer.gpkg"
+ )
+ ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile)
+ lyr = ds.CreateLayer("test", geom_type=ogr.wkbUnknown)
f = ogr.Feature(lyr.GetLayerDefn())
- f.SetGeometry(ogr.CreateGeometryFromWkt('COMPOUNDCURVE((7 8,9 10))'))
+ f.SetGeometry(ogr.CreateGeometryFromWkt("COMPOUNDCURVE((7 8,9 10))"))
lyr.CreateFeature(f)
ds = None
- vl = QgsVectorLayer(f'{tmpfile}', 'test', 'ogr')
+ vl = QgsVectorLayer(f"{tmpfile}", "test", "ogr")
self.assertEqual(1, vl.dataProvider().subLayerCount())
- self.assertEqual(vl.dataProvider().subLayers(),
- [QgsDataProvider.SUBLAYER_SEPARATOR.join(['0', 'test', '1', 'CompoundCurve', 'geom', ''])])
-
- vl = QgsVectorLayer(f'{tmpfile}' + '|geometryType=CompoundCurve', 'test', 'ogr')
+ self.assertEqual(
+ vl.dataProvider().subLayers(),
+ [
+ QgsDataProvider.SUBLAYER_SEPARATOR.join(
+ ["0", "test", "1", "CompoundCurve", "geom", ""]
+ )
+ ],
+ )
+
+ vl = QgsVectorLayer(f"{tmpfile}" + "|geometryType=CompoundCurve", "test", "ogr")
got = [feat for feat in vl.getFeatures()]
self.assertEqual(len(got), 1)
def testCurvePolygonOnlyInUnknownTypeLayer(self):
- """ Test bugfix for https://github.com/qgis/QGIS/issues/47610 """
+ """Test bugfix for https://github.com/qgis/QGIS/issues/47610"""
- tmpfile = os.path.join(self.basetestpath, 'testCurvePolygonOnlyInUnknownTypeLayer.gpkg')
- ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile)
- lyr = ds.CreateLayer('test', geom_type=ogr.wkbUnknown)
+ tmpfile = os.path.join(
+ self.basetestpath, "testCurvePolygonOnlyInUnknownTypeLayer.gpkg"
+ )
+ ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile)
+ lyr = ds.CreateLayer("test", geom_type=ogr.wkbUnknown)
f = ogr.Feature(lyr.GetLayerDefn())
- f.SetGeometry(ogr.CreateGeometryFromWkt('CURVEPOLYGON((10 10,10 11,11 11,10 10))'))
+ f.SetGeometry(
+ ogr.CreateGeometryFromWkt("CURVEPOLYGON((10 10,10 11,11 11,10 10))")
+ )
lyr.CreateFeature(f)
ds = None
- vl = QgsVectorLayer(f'{tmpfile}', 'test', 'ogr')
+ vl = QgsVectorLayer(f"{tmpfile}", "test", "ogr")
self.assertEqual(1, vl.dataProvider().subLayerCount())
- self.assertEqual(vl.dataProvider().subLayers(),
- [QgsDataProvider.SUBLAYER_SEPARATOR.join(['0', 'test', '1', 'CurvePolygon', 'geom', ''])])
-
- vl = QgsVectorLayer(f'{tmpfile}' + '|geometryType=CurvePolygon', 'test', 'ogr')
+ self.assertEqual(
+ vl.dataProvider().subLayers(),
+ [
+ QgsDataProvider.SUBLAYER_SEPARATOR.join(
+ ["0", "test", "1", "CurvePolygon", "geom", ""]
+ )
+ ],
+ )
+
+ vl = QgsVectorLayer(f"{tmpfile}" + "|geometryType=CurvePolygon", "test", "ogr")
got = [feat for feat in vl.getFeatures()]
self.assertEqual(len(got), 1)
def testCurveGeometryTypeInUnknownTypeLayer(self):
- """ Test bugfix for https://github.com/qgis/QGIS/issues/47610 """
+ """Test bugfix for https://github.com/qgis/QGIS/issues/47610"""
- tmpfile = os.path.join(self.basetestpath, 'testFilterCurveGeometryType.gpkg')
- ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile)
- lyr = ds.CreateLayer('test', geom_type=ogr.wkbUnknown)
+ tmpfile = os.path.join(self.basetestpath, "testFilterCurveGeometryType.gpkg")
+ ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile)
+ lyr = ds.CreateLayer("test", geom_type=ogr.wkbUnknown)
f = ogr.Feature(lyr.GetLayerDefn())
- f.SetGeometry(ogr.CreateGeometryFromWkt('CIRCULARSTRING(0 0,1 1,2 0)'))
+ f.SetGeometry(ogr.CreateGeometryFromWkt("CIRCULARSTRING(0 0,1 1,2 0)"))
lyr.CreateFeature(f)
f = ogr.Feature(lyr.GetLayerDefn())
- f.SetGeometry(ogr.CreateGeometryFromWkt('CIRCULARSTRING Z(0 -10 10,1 -11 10,2 -10 10)'))
+ f.SetGeometry(
+ ogr.CreateGeometryFromWkt("CIRCULARSTRING Z(0 -10 10,1 -11 10,2 -10 10)")
+ )
lyr.CreateFeature(f)
f = ogr.Feature(lyr.GetLayerDefn())
- f.SetGeometry(ogr.CreateGeometryFromWkt('MULTILINESTRING((3 4,5 6))'))
+ f.SetGeometry(ogr.CreateGeometryFromWkt("MULTILINESTRING((3 4,5 6))"))
lyr.CreateFeature(f)
f = ogr.Feature(lyr.GetLayerDefn())
- f.SetGeometry(ogr.CreateGeometryFromWkt('COMPOUNDCURVE((7 8,9 10))'))
+ f.SetGeometry(ogr.CreateGeometryFromWkt("COMPOUNDCURVE((7 8,9 10))"))
lyr.CreateFeature(f)
f = ogr.Feature(lyr.GetLayerDefn())
- f.SetGeometry(ogr.CreateGeometryFromWkt('CURVEPOLYGON((10 10,10 11,11 11,10 10))'))
+ f.SetGeometry(
+ ogr.CreateGeometryFromWkt("CURVEPOLYGON((10 10,10 11,11 11,10 10))")
+ )
lyr.CreateFeature(f)
f = ogr.Feature(lyr.GetLayerDefn())
- f.SetGeometry(ogr.CreateGeometryFromWkt('POLYGON((10 20,10 21,11 21,10 20))'))
+ f.SetGeometry(ogr.CreateGeometryFromWkt("POLYGON((10 20,10 21,11 21,10 20))"))
lyr.CreateFeature(f)
ds = None
- vl = QgsVectorLayer(f'{tmpfile}', 'test', 'ogr')
+ vl = QgsVectorLayer(f"{tmpfile}", "test", "ogr")
self.assertEqual(1, vl.dataProvider().subLayerCount())
- self.assertEqual(vl.dataProvider().subLayers(),
- [QgsDataProvider.SUBLAYER_SEPARATOR.join(['0', 'test', '4', 'CompoundCurve', 'geom', '']),
- QgsDataProvider.SUBLAYER_SEPARATOR.join(['0', 'test', '2', 'CurvePolygon', 'geom', ''])])
-
- vl = QgsVectorLayer(f'{tmpfile}' + '|geometryType=CompoundCurve', 'test', 'ogr')
+ self.assertEqual(
+ vl.dataProvider().subLayers(),
+ [
+ QgsDataProvider.SUBLAYER_SEPARATOR.join(
+ ["0", "test", "4", "CompoundCurve", "geom", ""]
+ ),
+ QgsDataProvider.SUBLAYER_SEPARATOR.join(
+ ["0", "test", "2", "CurvePolygon", "geom", ""]
+ ),
+ ],
+ )
+
+ vl = QgsVectorLayer(f"{tmpfile}" + "|geometryType=CompoundCurve", "test", "ogr")
got = [feat for feat in vl.getFeatures()]
self.assertEqual(len(got), 4)
- vl = QgsVectorLayer(f'{tmpfile}' + '|geometryType=CurvePolygon', 'test', 'ogr')
+ vl = QgsVectorLayer(f"{tmpfile}" + "|geometryType=CurvePolygon", "test", "ogr")
got = [feat for feat in vl.getFeatures()]
self.assertEqual(len(got), 2)
def testCreateEmptyDatabase(self):
- """ Test creating an empty database via the provider metadata """
- metadata = QgsProviderRegistry.instance().providerMetadata('ogr')
- self.assertTrue(metadata.capabilities() & QgsProviderMetadata.ProviderMetadataCapability.CreateDatabase)
+ """Test creating an empty database via the provider metadata"""
+ metadata = QgsProviderRegistry.instance().providerMetadata("ogr")
+ self.assertTrue(
+ metadata.capabilities()
+ & QgsProviderMetadata.ProviderMetadataCapability.CreateDatabase
+ )
with tempfile.TemporaryDirectory() as dest_dir:
- database_path = os.path.join(dest_dir, 'new_gpkg.gpkg')
+ database_path = os.path.join(dest_dir, "new_gpkg.gpkg")
ok, err = metadata.createDatabase(database_path)
self.assertTrue(ok)
self.assertFalse(err)
@@ -2751,16 +3260,23 @@ def testCreateEmptyDatabase(self):
def testDateTimeTimeZoneMilliseconds(self):
- tmpfile = os.path.join(self.basetestpath, 'testDateTimeTimeZoneMilliseconds.gpkg')
- ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile)
- lyr = ds.CreateLayer('test', geom_type=ogr.wkbMultiPolygon)
- lyr.CreateField(ogr.FieldDefn('dt', ogr.OFTDateTime))
+ tmpfile = os.path.join(
+ self.basetestpath, "testDateTimeTimeZoneMilliseconds.gpkg"
+ )
+ ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile)
+ lyr = ds.CreateLayer("test", geom_type=ogr.wkbMultiPolygon)
+ lyr.CreateField(ogr.FieldDefn("dt", ogr.OFTDateTime))
ds = None
- vl = QgsVectorLayer(tmpfile, 'test', 'ogr')
+ vl = QgsVectorLayer(tmpfile, "test", "ogr")
f = QgsFeature(vl.fields())
- dt = QDateTime(QDate(2023, 1, 28), QTime(12, 34, 56, 789), Qt.TimeSpec.OffsetFromUTC, 1 * 3600 + 30 * 60)
+ dt = QDateTime(
+ QDate(2023, 1, 28),
+ QTime(12, 34, 56, 789),
+ Qt.TimeSpec.OffsetFromUTC,
+ 1 * 3600 + 30 * 60,
+ )
f.setAttribute(1, dt)
self.assertTrue(vl.startEditing())
self.assertTrue(vl.addFeatures([f]))
@@ -2770,7 +3286,12 @@ def testDateTimeTimeZoneMilliseconds(self):
self.assertEqual(got[0]["dt"], dt)
self.assertTrue(vl.startEditing())
- new_dt = QDateTime(QDate(2023, 1, 27), QTime(12, 34, 56, 987), Qt.TimeSpec.OffsetFromUTC, 2 * 3600 + 30 * 60)
+ new_dt = QDateTime(
+ QDate(2023, 1, 27),
+ QTime(12, 34, 56, 987),
+ Qt.TimeSpec.OffsetFromUTC,
+ 2 * 3600 + 30 * 60,
+ )
self.assertTrue(vl.changeAttributeValue(1, 1, new_dt))
self.assertTrue(vl.commitChanges())
@@ -2779,16 +3300,18 @@ def testDateTimeTimeZoneMilliseconds(self):
def testWriteDateTimeFromLocalTime(self):
- tmpfile = os.path.join(self.basetestpath, 'testWriteDateTimeFromLocalTime.gpkg')
- ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile)
- lyr = ds.CreateLayer('test', geom_type=ogr.wkbNone)
- lyr.CreateField(ogr.FieldDefn('dt', ogr.OFTDateTime))
+ tmpfile = os.path.join(self.basetestpath, "testWriteDateTimeFromLocalTime.gpkg")
+ ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile)
+ lyr = ds.CreateLayer("test", geom_type=ogr.wkbNone)
+ lyr.CreateField(ogr.FieldDefn("dt", ogr.OFTDateTime))
ds = None
- vl = QgsVectorLayer(tmpfile, 'test', 'ogr')
+ vl = QgsVectorLayer(tmpfile, "test", "ogr")
f = QgsFeature(vl.fields())
- dt = QDateTime(QDate(2023, 1, 28), QTime(12, 34, 56, 789), Qt.TimeSpec.LocalTime)
+ dt = QDateTime(
+ QDate(2023, 1, 28), QTime(12, 34, 56, 789), Qt.TimeSpec.LocalTime
+ )
f.setAttribute(1, dt)
self.assertTrue(vl.startEditing())
self.assertTrue(vl.addFeatures([f]))
@@ -2812,10 +3335,10 @@ def testTransactionModeAutoWithFilter(self):
filename = os.path.join(temp_path, "test.gpkg")
ds = ogr.GetDriverByName("GPKG").CreateDataSource(filename)
lyr = ds.CreateLayer("points", geom_type=ogr.wkbPoint)
- lyr.CreateField(ogr.FieldDefn('name', ogr.OFTString))
+ lyr.CreateField(ogr.FieldDefn("name", ogr.OFTString))
f = ogr.Feature(lyr.GetLayerDefn())
- f['name'] = 'a'
- f.SetGeometry(ogr.CreateGeometryFromWkt('POINT(1 2)'))
+ f["name"] = "a"
+ f.SetGeometry(ogr.CreateGeometryFromWkt("POINT(1 2)"))
lyr.CreateFeature(f)
f = None
ds = None
@@ -2824,19 +3347,19 @@ def testTransactionModeAutoWithFilter(self):
vl = QgsVectorLayer(filename)
self.assertTrue(vl.isValid())
self.assertEqual(vl.featureCount(), 1)
- self.assertEqual(next(vl.getFeatures())['name'], 'a')
+ self.assertEqual(next(vl.getFeatures())["name"], "a")
p = QgsProject()
p.setAutoTransaction(True)
self.assertTrue(p.addMapLayers([vl]))
- self.assertTrue(vl.setSubsetString('"name" IN (\'a\', \'b\')'))
+ self.assertTrue(vl.setSubsetString("\"name\" IN ('a', 'b')"))
self.assertEqual(vl.featureCount(), 1)
self.assertTrue(vl.startEditing())
# Add feature
f = QgsFeature(vl.fields())
- f.setAttribute('name', 'b')
- g = QgsGeometry.fromWkt('POINT(3 4)')
+ f.setAttribute("name", "b")
+ g = QgsGeometry.fromWkt("POINT(3 4)")
f.setGeometry(g)
# This triggers the issue because it sets the subset filter
@@ -2847,16 +3370,16 @@ def testTransactionModeAutoWithFilter(self):
self.assertTrue(vl.addFeatures([f]))
self.assertTrue(vl.commitChanges())
self.assertEqual(vl.featureCount(), 2)
- attrs = [f['name'] for f in vl.getFeatures()]
- self.assertEqual(attrs, ['a', 'b'])
+ attrs = [f["name"] for f in vl.getFeatures()]
+ self.assertEqual(attrs, ["a", "b"])
# verify
del p
vl2 = QgsVectorLayer(filename)
self.assertTrue(vl2.isValid())
self.assertEqual(vl2.featureCount(), 2)
- attrs = [f['name'] for f in vl2.getFeatures()]
- self.assertEqual(attrs, ['a', 'b'])
+ attrs = [f["name"] for f in vl2.getFeatures()]
+ self.assertEqual(attrs, ["a", "b"])
def testChangeAttributeValuesOptimization(self):
"""Test issuing 'UPDATE layer SET column_name = constant' when possible"""
@@ -2864,19 +3387,21 @@ def testChangeAttributeValuesOptimization(self):
# Below value comes from QgsOgrProvider::changeAttributeValues()
THRESHOLD_UPDATE_OPTIM = 100
- tmpfile = os.path.join(self.basetestpath, 'testChangeAttributeValuesOptimization.gpkg')
- ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile)
- lyr = ds.CreateLayer('test', geom_type=ogr.wkbPoint)
- lyr.CreateField(ogr.FieldDefn('str_field', ogr.OFTString))
- lyr.CreateField(ogr.FieldDefn('int_field', ogr.OFTInteger))
- lyr.CreateField(ogr.FieldDefn('int64_field', ogr.OFTInteger64))
- lyr.CreateField(ogr.FieldDefn('real_field', ogr.OFTReal))
+ tmpfile = os.path.join(
+ self.basetestpath, "testChangeAttributeValuesOptimization.gpkg"
+ )
+ ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile)
+ lyr = ds.CreateLayer("test", geom_type=ogr.wkbPoint)
+ lyr.CreateField(ogr.FieldDefn("str_field", ogr.OFTString))
+ lyr.CreateField(ogr.FieldDefn("int_field", ogr.OFTInteger))
+ lyr.CreateField(ogr.FieldDefn("int64_field", ogr.OFTInteger64))
+ lyr.CreateField(ogr.FieldDefn("real_field", ogr.OFTReal))
for i in range(THRESHOLD_UPDATE_OPTIM + 1):
f = ogr.Feature(lyr.GetLayerDefn())
lyr.CreateFeature(f)
ds = None
- vl = QgsVectorLayer(f'{tmpfile}' + "|layername=" + "test", 'test', 'ogr')
+ vl = QgsVectorLayer(f"{tmpfile}" + "|layername=" + "test", "test", "ogr")
# Does not trigger the optim: not constant value
field_name, value, other_value = "str_field", "my_value", "other_value"
@@ -2890,7 +3415,7 @@ def testChangeAttributeValuesOptimization(self):
vl.commitChanges()
got = [feat[field_name] for feat in vl.getFeatures()]
- self.assertEqual(set(got), set([value, other_value]))
+ self.assertEqual(set(got), {value, other_value})
# Does not trigger the optim: update of different fields
vl.startEditing()
@@ -2904,9 +3429,9 @@ def testChangeAttributeValuesOptimization(self):
vl.commitChanges()
got = [feat["int_field"] for feat in vl.getFeatures()]
- self.assertEqual(set(got), set([1, NULL]))
+ self.assertEqual(set(got), {1, NULL})
got = [feat["int64_field"] for feat in vl.getFeatures()]
- self.assertEqual(set(got), set([1, NULL]))
+ self.assertEqual(set(got), {1, NULL})
# Does not trigger the optim: not all features updated
vl.startEditing()
@@ -2918,15 +3443,16 @@ def testChangeAttributeValuesOptimization(self):
vl.commitChanges()
got = [feat["real_field"] for feat in vl.getFeatures()]
- self.assertEqual(set(got), set([1.5, NULL]))
+ self.assertEqual(set(got), {1.5, NULL})
# Triggers the optim
- for field_name, value in [("str_field", "my_value"),
- ("int_field", 123),
- ("int64_field", 1234567890123),
- ("real_field", 2.5),
- ("real_field", None),
- ]:
+ for field_name, value in [
+ ("str_field", "my_value"),
+ ("int_field", 123),
+ ("int64_field", 1234567890123),
+ ("real_field", 2.5),
+ ("real_field", None),
+ ]:
vl.startEditing()
fieldid = vl.fields().indexFromName(field_name)
for feature in vl.getFeatures():
@@ -2935,29 +3461,31 @@ def testChangeAttributeValuesOptimization(self):
got = [feat[field_name] for feat in vl.getFeatures()]
if value:
- self.assertEqual(set(got), set([value]))
+ self.assertEqual(set(got), {value})
else:
- self.assertEqual(set(got), set([NULL]))
+ self.assertEqual(set(got), {NULL})
def testChangeAttributeValuesErrors(self):
- tmpfile = os.path.join(self.basetestpath, 'testChangeAttributeValuesErrors.gpkg')
- ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile)
- lyr = ds.CreateLayer('test', geom_type=ogr.wkbPoint)
- lyr.CreateField(ogr.FieldDefn('int_field', ogr.OFTInteger))
- lyr.CreateField(ogr.FieldDefn('int64_field', ogr.OFTInteger64))
- lyr.CreateField(ogr.FieldDefn('real_field', ogr.OFTReal))
- lyr.CreateField(ogr.FieldDefn('datetime_field', ogr.OFTDateTime))
- lyr.CreateField(ogr.FieldDefn('date_field', ogr.OFTDateTime))
- lyr.CreateField(ogr.FieldDefn('string_field', ogr.OFTString))
- fld_defn = ogr.FieldDefn('bool_field', ogr.OFTInteger)
+ tmpfile = os.path.join(
+ self.basetestpath, "testChangeAttributeValuesErrors.gpkg"
+ )
+ ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile)
+ lyr = ds.CreateLayer("test", geom_type=ogr.wkbPoint)
+ lyr.CreateField(ogr.FieldDefn("int_field", ogr.OFTInteger))
+ lyr.CreateField(ogr.FieldDefn("int64_field", ogr.OFTInteger64))
+ lyr.CreateField(ogr.FieldDefn("real_field", ogr.OFTReal))
+ lyr.CreateField(ogr.FieldDefn("datetime_field", ogr.OFTDateTime))
+ lyr.CreateField(ogr.FieldDefn("date_field", ogr.OFTDateTime))
+ lyr.CreateField(ogr.FieldDefn("string_field", ogr.OFTString))
+ fld_defn = ogr.FieldDefn("bool_field", ogr.OFTInteger)
fld_defn.SetSubType(ogr.OFSTBoolean)
lyr.CreateField(fld_defn)
f = ogr.Feature(lyr.GetLayerDefn())
lyr.CreateFeature(f)
ds = None
- vl = QgsVectorLayer(f'{tmpfile}' + "|layername=" + "test", 'test', 'ogr')
+ vl = QgsVectorLayer(f"{tmpfile}" + "|layername=" + "test", "test", "ogr")
# Changing feature id of feature 1 is not allowed
self.assertFalse(vl.dataProvider().changeAttributeValues({1: {0: "asdf"}}))
@@ -2973,11 +3501,21 @@ def testChangeAttributeValuesErrors(self):
self.assertFalse(vl.dataProvider().changeAttributeValues({1: {"invalid": 1}}))
# wrong data type for attribute ... of feature 1
- self.assertFalse(vl.dataProvider().changeAttributeValues({1: {1: "not a integer"}}))
- self.assertFalse(vl.dataProvider().changeAttributeValues({1: {2: "not a integer64"}}))
- self.assertFalse(vl.dataProvider().changeAttributeValues({1: {3: "not a double"}}))
- self.assertFalse(vl.dataProvider().changeAttributeValues({1: {4: "not a datetime"}}))
- self.assertFalse(vl.dataProvider().changeAttributeValues({1: {5: "not a date"}}))
+ self.assertFalse(
+ vl.dataProvider().changeAttributeValues({1: {1: "not a integer"}})
+ )
+ self.assertFalse(
+ vl.dataProvider().changeAttributeValues({1: {2: "not a integer64"}})
+ )
+ self.assertFalse(
+ vl.dataProvider().changeAttributeValues({1: {3: "not a double"}})
+ )
+ self.assertFalse(
+ vl.dataProvider().changeAttributeValues({1: {4: "not a datetime"}})
+ )
+ self.assertFalse(
+ vl.dataProvider().changeAttributeValues({1: {5: "not a date"}})
+ )
# wrong value for attribute 7 of feature 1: wrong
self.assertFalse(vl.dataProvider().changeAttributeValues({1: {7: "wrong"}}))
@@ -2987,15 +3525,25 @@ def testChangeAttributeValuesErrors(self):
self.assertTrue(vl.dataProvider().changeAttributeValues({1: {1: 1}}))
# int64_field
self.assertTrue(vl.dataProvider().changeAttributeValues({1: {2: 1}}))
- self.assertTrue(vl.dataProvider().changeAttributeValues({1: {2: 1234567890123}}))
+ self.assertTrue(
+ vl.dataProvider().changeAttributeValues({1: {2: 1234567890123}})
+ )
# real_field
self.assertTrue(vl.dataProvider().changeAttributeValues({1: {3: 1}}))
- self.assertTrue(vl.dataProvider().changeAttributeValues({1: {3: 1234567890123}}))
+ self.assertTrue(
+ vl.dataProvider().changeAttributeValues({1: {3: 1234567890123}})
+ )
self.assertTrue(vl.dataProvider().changeAttributeValues({1: {3: 1.5}}))
# datetime_field
- self.assertTrue(vl.dataProvider().changeAttributeValues({1: {4: QDateTime(2022, 1, 1, 1, 1, 1, 0)}}))
+ self.assertTrue(
+ vl.dataProvider().changeAttributeValues(
+ {1: {4: QDateTime(2022, 1, 1, 1, 1, 1, 0)}}
+ )
+ )
# date_field
- self.assertTrue(vl.dataProvider().changeAttributeValues({1: {5: QDate(2022, 1, 1)}}))
+ self.assertTrue(
+ vl.dataProvider().changeAttributeValues({1: {5: QDate(2022, 1, 1)}})
+ )
# string_field
self.assertTrue(vl.dataProvider().changeAttributeValues({1: {6: "foo"}}))
self.assertTrue(vl.dataProvider().changeAttributeValues({1: {6: 12345}}))
@@ -3019,15 +3567,15 @@ def testChangeAttributeValuesErrors(self):
def testAttributeBoolean(self):
- tmpfile = os.path.join(self.basetestpath, 'testAttributeBoolean.gpkg')
- ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile)
- lyr = ds.CreateLayer('test', geom_type=ogr.wkbPoint)
- fld_defn = ogr.FieldDefn('bool_field', ogr.OFTInteger)
+ tmpfile = os.path.join(self.basetestpath, "testAttributeBoolean.gpkg")
+ ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile)
+ lyr = ds.CreateLayer("test", geom_type=ogr.wkbPoint)
+ fld_defn = ogr.FieldDefn("bool_field", ogr.OFTInteger)
fld_defn.SetSubType(ogr.OFSTBoolean)
lyr.CreateField(fld_defn)
ds = None
- vl = QgsVectorLayer(f'{tmpfile}' + "|layername=" + "test", 'test', 'ogr')
+ vl = QgsVectorLayer(f"{tmpfile}" + "|layername=" + "test", "test", "ogr")
f = QgsFeature(vl.fields())
f.setAttribute(1, False)
@@ -3080,12 +3628,16 @@ def testAttributeBoolean(self):
ret, _ = vl.dataProvider().addFeatures([f])
self.assertFalse(ret)
- self.assertEqual([feat["bool_field"] for feat in vl.getFeatures()],
- [False, True, False, True, False, True, False, True])
+ self.assertEqual(
+ [feat["bool_field"] for feat in vl.getFeatures()],
+ [False, True, False, True, False, True, False, True],
+ )
def testExtent(self):
# 2D points
- vl = QgsVectorLayer(os.path.join(unitTestDataPath(), 'points_gpkg.gpkg'), 'points_small', 'ogr')
+ vl = QgsVectorLayer(
+ os.path.join(unitTestDataPath(), "points_gpkg.gpkg"), "points_small", "ogr"
+ )
self.assertTrue(vl.isValid())
self.assertAlmostEqual(vl.extent().xMinimum(), -117.233, places=3)
self.assertAlmostEqual(vl.extent().yMinimum(), 22.8002, places=3)
@@ -3101,7 +3653,11 @@ def testExtent(self):
del vl
# 3D points
- vl = QgsVectorLayer(os.path.join(unitTestDataPath(), '3d', 'points_with_z.gpkg'), 'points_with_z', 'ogr')
+ vl = QgsVectorLayer(
+ os.path.join(unitTestDataPath(), "3d", "points_with_z.gpkg"),
+ "points_with_z",
+ "ogr",
+ )
self.assertTrue(vl.isValid())
self.assertAlmostEqual(vl.extent().xMinimum(), -102.4361, places=3)
@@ -3126,14 +3682,14 @@ def testQueryLayers(self):
ds = ogr.GetDriverByName("GPKG").CreateDataSource(filename)
lyr = ds.CreateLayer("points", geom_type=ogr.wkbPoint)
f = ogr.Feature(lyr.GetLayerDefn())
- f.SetGeometry(ogr.CreateGeometryFromWkt('POINT(1 2)'))
+ f.SetGeometry(ogr.CreateGeometryFromWkt("POINT(1 2)"))
lyr.CreateFeature(f)
f = ogr.Feature(lyr.GetLayerDefn())
- f.SetGeometry(ogr.CreateGeometryFromWkt('POINT(3 4)'))
+ f.SetGeometry(ogr.CreateGeometryFromWkt("POINT(3 4)"))
lyr.CreateFeature(f)
f = None
- vl = QgsVectorLayer(filename + '|layername=points')
+ vl = QgsVectorLayer(filename + "|layername=points")
self.assertTrue(vl.isValid())
self.assertEqual(vl.featureCount(), 2)
@@ -3144,12 +3700,12 @@ def testQueryLayers(self):
# Add lines layer
lyr = ds.CreateLayer("lines", geom_type=ogr.wkbLineString)
f = ogr.Feature(lyr.GetLayerDefn())
- f.SetGeometry(ogr.CreateGeometryFromWkt('LINESTRING(1 2, 3 4)'))
+ f.SetGeometry(ogr.CreateGeometryFromWkt("LINESTRING(1 2, 3 4)"))
lyr.CreateFeature(f)
f = None
ds = None
- vl = QgsVectorLayer(filename + '|layername=lines')
+ vl = QgsVectorLayer(filename + "|layername=lines")
self.assertEqual(vl.geometryType(), Qgis.GeometryType.Line)
self.assertTrue(vl.isValid())
self.assertEqual(vl.featureCount(), 1)
@@ -3160,23 +3716,26 @@ def testQueryLayers(self):
self.assertEqual(vl.featureCount(), 2)
# Set subset string to SELECT * FROM lines
- self.assertTrue(vl.setSubsetString('SELECT * FROM lines WHERE fid > 0'))
+ self.assertTrue(vl.setSubsetString("SELECT * FROM lines WHERE fid > 0"))
self.assertTrue(vl.isValid())
- self.assertIn('|subset=SELECT * FROM lines WHERE fid > 0', vl.dataProvider().dataSourceUri())
+ self.assertIn(
+ "|subset=SELECT * FROM lines WHERE fid > 0",
+ vl.dataProvider().dataSourceUri(),
+ )
f = next(vl.getFeatures())
self.assertEqual(f.geometry().type(), Qgis.GeometryType.Line)
self.assertEqual(vl.featureCount(), 1)
# This fails because the vector layer doesn't know about the new geometry type
# self.assertEqual(vl.geometryType(), Qgis.GeometryType.Line)
- self.assertTrue(vl.setSubsetString(''))
+ self.assertTrue(vl.setSubsetString(""))
self.assertTrue(vl.isValid())
self.assertIn("layername=lines", vl.dataProvider().dataSourceUri())
# This fails because the vector layer doesn't know about the new geometry type
# self.assertEqual(vl.geometryType(), Qgis.GeometryType.Line)
f = next(vl.getFeatures())
self.assertEqual(f.geometry().type(), Qgis.GeometryType.Line)
- self.assertEqual(f.geometry().asWkt().upper(), 'LINESTRING (1 2, 3 4)')
+ self.assertEqual(f.geometry().asWkt().upper(), "LINESTRING (1 2, 3 4)")
self.assertEqual(vl.allFeatureIds(), [1])
# This fails on CI but only on the "5, ALL_BUT_PROVIDERS" workflow
# for some reason that I cannto reproduce locally, featureCount returns 2
@@ -3185,15 +3744,19 @@ def testQueryLayers(self):
def testOrderByEscapedIdentifier(self):
"""Test issue GH #58508"""
- tmpfile = os.path.join(self.basetestpath, 'points_escaped_identifier.gpkg')
- testdata_path = unitTestDataPath('provider')
- shutil.copy(os.path.join(testdata_path, 'points_escaped_identifier.gpkg'), tmpfile)
- vl = QgsVectorLayer(f'{tmpfile}|layername=table\\"\\table', 'test', 'ogr')
+ tmpfile = os.path.join(self.basetestpath, "points_escaped_identifier.gpkg")
+ testdata_path = unitTestDataPath("provider")
+ shutil.copy(
+ os.path.join(testdata_path, "points_escaped_identifier.gpkg"), tmpfile
+ )
+ vl = QgsVectorLayer(f'{tmpfile}|layername=table\\"\\table', "test", "ogr")
self.assertTrue(vl.isValid())
self.assertEqual(vl.featureCount(), 3)
request = QgsFeatureRequest()
- orderBy = QgsFeatureRequest.OrderBy([QgsFeatureRequest.OrderByClause('NAME', False)])
+ orderBy = QgsFeatureRequest.OrderBy(
+ [QgsFeatureRequest.OrderByClause("NAME", False)]
+ )
request.setOrderBy(orderBy)
features = vl.getFeatures(request)
@@ -3204,5 +3767,5 @@ def testOrderByEscapedIdentifier(self):
self.assertEqual(featureCount, 3)
-if __name__ == '__main__':
+if __name__ == "__main__":
unittest.main()
diff --git a/tests/src/python/test_provider_ogr_sqlite.py b/tests/src/python/test_provider_ogr_sqlite.py
index 45d24688887a..192aba2fb4b4 100644
--- a/tests/src/python/test_provider_ogr_sqlite.py
+++ b/tests/src/python/test_provider_ogr_sqlite.py
@@ -5,9 +5,10 @@
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
"""
-__author__ = 'Even Rouault'
-__date__ = '2016-06-01'
-__copyright__ = 'Copyright 2016, Even Rouault'
+
+__author__ = "Even Rouault"
+__date__ = "2016-06-01"
+__copyright__ = "Copyright 2016, Even Rouault"
import os
import shutil
@@ -33,7 +34,7 @@
def GDAL_COMPUTE_VERSION(maj, min, rev):
- return ((maj) * 1000000 + (min) * 10000 + (rev) * 100)
+ return (maj) * 1000000 + (min) * 10000 + (rev) * 100
class TestPyQgsOGRProviderSqlite(QgisTestCase):
@@ -52,72 +53,125 @@ def tearDownClass(cls):
super().tearDownClass()
def testFidSupport(self):
- tmpfile = os.path.join(self.basetestpath, 'testFidSupport.sqlite')
- ds = ogr.GetDriverByName('SQLite').CreateDataSource(tmpfile)
- lyr = ds.CreateLayer('test', geom_type=ogr.wkbPoint, options=['FID=fid'])
- lyr.CreateField(ogr.FieldDefn('strfield', ogr.OFTString))
- lyr.CreateField(ogr.FieldDefn('intfield', ogr.OFTInteger))
+ tmpfile = os.path.join(self.basetestpath, "testFidSupport.sqlite")
+ ds = ogr.GetDriverByName("SQLite").CreateDataSource(tmpfile)
+ lyr = ds.CreateLayer("test", geom_type=ogr.wkbPoint, options=["FID=fid"])
+ lyr.CreateField(ogr.FieldDefn("strfield", ogr.OFTString))
+ lyr.CreateField(ogr.FieldDefn("intfield", ogr.OFTInteger))
f = ogr.Feature(lyr.GetLayerDefn())
f.SetFID(12)
- f.SetField(0, 'foo')
+ f.SetField(0, "foo")
f.SetField(1, 123)
lyr.CreateFeature(f)
f = None
ds = None
- vl = QgsVectorLayer(f'{tmpfile}', 'test', 'ogr')
+ vl = QgsVectorLayer(f"{tmpfile}", "test", "ogr")
self.assertEqual(len(vl.fields()), 3)
- got = [(f.attribute('fid'), f.attribute('strfield'), f.attribute('intfield')) for f in vl.getFeatures()]
- self.assertEqual(got, [(12, 'foo', 123)])
-
- got = [(f.attribute('fid'), f.attribute('strfield')) for f in vl.getFeatures(QgsFeatureRequest().setFilterExpression("strfield = 'foo'"))]
- self.assertEqual(got, [(12, 'foo')])
-
- got = [(f.attribute('fid'), f.attribute('strfield')) for f in vl.getFeatures(QgsFeatureRequest().setFilterExpression("fid = 12"))]
- self.assertEqual(got, [(12, 'foo')])
-
- result = [f['strfield'] for f in vl.dataProvider().getFeatures(QgsFeatureRequest().setSubsetOfAttributes(['strfield'], vl.dataProvider().fields()))]
- self.assertEqual(result, ['foo'])
-
- result = [f['fid'] for f in vl.dataProvider().getFeatures(QgsFeatureRequest().setSubsetOfAttributes(['fid'], vl.dataProvider().fields()))]
+ got = [
+ (f.attribute("fid"), f.attribute("strfield"), f.attribute("intfield"))
+ for f in vl.getFeatures()
+ ]
+ self.assertEqual(got, [(12, "foo", 123)])
+
+ got = [
+ (f.attribute("fid"), f.attribute("strfield"))
+ for f in vl.getFeatures(
+ QgsFeatureRequest().setFilterExpression("strfield = 'foo'")
+ )
+ ]
+ self.assertEqual(got, [(12, "foo")])
+
+ got = [
+ (f.attribute("fid"), f.attribute("strfield"))
+ for f in vl.getFeatures(QgsFeatureRequest().setFilterExpression("fid = 12"))
+ ]
+ self.assertEqual(got, [(12, "foo")])
+
+ result = [
+ f["strfield"]
+ for f in vl.dataProvider().getFeatures(
+ QgsFeatureRequest().setSubsetOfAttributes(
+ ["strfield"], vl.dataProvider().fields()
+ )
+ )
+ ]
+ self.assertEqual(result, ["foo"])
+
+ result = [
+ f["fid"]
+ for f in vl.dataProvider().getFeatures(
+ QgsFeatureRequest().setSubsetOfAttributes(
+ ["fid"], vl.dataProvider().fields()
+ )
+ )
+ ]
self.assertEqual(result, [12])
# Test that when the 'fid' field is not set, regular insertion is done
f = QgsFeature()
f.setFields(vl.fields())
- f.setAttributes([None, 'automatic_id'])
+ f.setAttributes([None, "automatic_id"])
(res, out_f) = vl.dataProvider().addFeatures([f])
self.assertEqual(out_f[0].id(), 13)
- self.assertEqual(out_f[0].attribute('fid'), 13)
- self.assertEqual(out_f[0].attribute('strfield'), 'automatic_id')
+ self.assertEqual(out_f[0].attribute("fid"), 13)
+ self.assertEqual(out_f[0].attribute("strfield"), "automatic_id")
# Test that when the 'fid' field is set, it is really used to set the id
f = QgsFeature()
f.setFields(vl.fields())
- f.setAttributes([9876543210, 'bar'])
+ f.setAttributes([9876543210, "bar"])
(res, out_f) = vl.dataProvider().addFeatures([f])
self.assertEqual(out_f[0].id(), 9876543210)
- self.assertEqual(out_f[0].attribute('fid'), 9876543210)
- self.assertEqual(out_f[0].attribute('strfield'), 'bar')
-
- got = [(f.attribute('fid'), f.attribute('strfield')) for f in vl.getFeatures(QgsFeatureRequest().setFilterExpression("fid = 9876543210"))]
- self.assertEqual(got, [(9876543210, 'bar')])
-
- self.assertTrue(vl.dataProvider().changeAttributeValues({9876543210: {1: 'baz'}}))
-
- got = [(f.attribute('fid'), f.attribute('strfield')) for f in vl.getFeatures(QgsFeatureRequest().setFilterExpression("fid = 9876543210"))]
- self.assertEqual(got, [(9876543210, 'baz')])
-
- self.assertTrue(vl.dataProvider().changeAttributeValues({9876543210: {0: 9876543210, 1: 'baw'}}))
-
- got = [(f.attribute('fid'), f.attribute('strfield')) for f in vl.getFeatures(QgsFeatureRequest().setFilterExpression("fid = 9876543210"))]
- self.assertEqual(got, [(9876543210, 'baw')])
+ self.assertEqual(out_f[0].attribute("fid"), 9876543210)
+ self.assertEqual(out_f[0].attribute("strfield"), "bar")
+
+ got = [
+ (f.attribute("fid"), f.attribute("strfield"))
+ for f in vl.getFeatures(
+ QgsFeatureRequest().setFilterExpression("fid = 9876543210")
+ )
+ ]
+ self.assertEqual(got, [(9876543210, "bar")])
+
+ self.assertTrue(
+ vl.dataProvider().changeAttributeValues({9876543210: {1: "baz"}})
+ )
+
+ got = [
+ (f.attribute("fid"), f.attribute("strfield"))
+ for f in vl.getFeatures(
+ QgsFeatureRequest().setFilterExpression("fid = 9876543210")
+ )
+ ]
+ self.assertEqual(got, [(9876543210, "baz")])
+
+ self.assertTrue(
+ vl.dataProvider().changeAttributeValues(
+ {9876543210: {0: 9876543210, 1: "baw"}}
+ )
+ )
+
+ got = [
+ (f.attribute("fid"), f.attribute("strfield"))
+ for f in vl.getFeatures(
+ QgsFeatureRequest().setFilterExpression("fid = 9876543210")
+ )
+ ]
+ self.assertEqual(got, [(9876543210, "baw")])
# Not allowed: changing the fid regular field
- self.assertFalse(vl.dataProvider().changeAttributeValues({9876543210: {0: 12, 1: 'baw'}}))
-
- got = [(f.attribute('fid'), f.attribute('strfield')) for f in vl.getFeatures(QgsFeatureRequest().setFilterExpression("fid = 9876543210"))]
- self.assertEqual(got, [(9876543210, 'baw')])
+ self.assertFalse(
+ vl.dataProvider().changeAttributeValues({9876543210: {0: 12, 1: "baw"}})
+ )
+
+ got = [
+ (f.attribute("fid"), f.attribute("strfield"))
+ for f in vl.getFeatures(
+ QgsFeatureRequest().setFilterExpression("fid = 9876543210")
+ )
+ ]
+ self.assertEqual(got, [(9876543210, "baw")])
# Cannot delete fid
self.assertFalse(vl.dataProvider().deleteAttributes([0]))
@@ -125,65 +179,97 @@ def testFidSupport(self):
# Delete first "genuine" attribute
self.assertTrue(vl.dataProvider().deleteAttributes([1]))
- got = [(f.attribute('fid'), f.attribute('intfield')) for f in vl.dataProvider().getFeatures(QgsFeatureRequest().setFilterExpression("fid = 12"))]
+ got = [
+ (f.attribute("fid"), f.attribute("intfield"))
+ for f in vl.dataProvider().getFeatures(
+ QgsFeatureRequest().setFilterExpression("fid = 12")
+ )
+ ]
self.assertEqual(got, [(12, 123)])
def testNotNullConstraint(self):
- """ test detection of not null constraint on OGR layer """
+ """test detection of not null constraint on OGR layer"""
- tmpfile = os.path.join(self.basetestpath, 'testNotNullConstraint.sqlite')
- ds = ogr.GetDriverByName('SQLite').CreateDataSource(tmpfile)
- lyr = ds.CreateLayer('test', geom_type=ogr.wkbPoint, options=['FID=fid'])
- lyr.CreateField(ogr.FieldDefn('field1', ogr.OFTInteger))
- fld2 = ogr.FieldDefn('field2', ogr.OFTInteger)
+ tmpfile = os.path.join(self.basetestpath, "testNotNullConstraint.sqlite")
+ ds = ogr.GetDriverByName("SQLite").CreateDataSource(tmpfile)
+ lyr = ds.CreateLayer("test", geom_type=ogr.wkbPoint, options=["FID=fid"])
+ lyr.CreateField(ogr.FieldDefn("field1", ogr.OFTInteger))
+ fld2 = ogr.FieldDefn("field2", ogr.OFTInteger)
fld2.SetNullable(False)
lyr.CreateField(fld2)
ds = None
- vl = QgsVectorLayer(f'{tmpfile}', 'test', 'ogr')
+ vl = QgsVectorLayer(f"{tmpfile}", "test", "ogr")
self.assertTrue(vl.isValid())
# test some bad indexes
- self.assertEqual(vl.dataProvider().fieldConstraints(-1), QgsFieldConstraints.Constraints())
- self.assertEqual(vl.dataProvider().fieldConstraints(1001), QgsFieldConstraints.Constraints())
-
- self.assertTrue(vl.dataProvider().fieldConstraints(0) & QgsFieldConstraints.Constraint.ConstraintNotNull)
- self.assertFalse(vl.dataProvider().fieldConstraints(1) & QgsFieldConstraints.Constraint.ConstraintNotNull)
- self.assertTrue(vl.dataProvider().fieldConstraints(2) & QgsFieldConstraints.Constraint.ConstraintNotNull)
+ self.assertEqual(
+ vl.dataProvider().fieldConstraints(-1), QgsFieldConstraints.Constraints()
+ )
+ self.assertEqual(
+ vl.dataProvider().fieldConstraints(1001), QgsFieldConstraints.Constraints()
+ )
+
+ self.assertTrue(
+ vl.dataProvider().fieldConstraints(0)
+ & QgsFieldConstraints.Constraint.ConstraintNotNull
+ )
+ self.assertFalse(
+ vl.dataProvider().fieldConstraints(1)
+ & QgsFieldConstraints.Constraint.ConstraintNotNull
+ )
+ self.assertTrue(
+ vl.dataProvider().fieldConstraints(2)
+ & QgsFieldConstraints.Constraint.ConstraintNotNull
+ )
# test that constraints have been saved to fields correctly
fields = vl.fields()
- self.assertTrue(fields.at(0).constraints().constraints() & QgsFieldConstraints.Constraint.ConstraintNotNull)
- self.assertFalse(fields.at(1).constraints().constraints() & QgsFieldConstraints.Constraint.ConstraintNotNull)
- self.assertTrue(fields.at(2).constraints().constraints() & QgsFieldConstraints.Constraint.ConstraintNotNull)
- self.assertEqual(fields.at(2).constraints().constraintOrigin(QgsFieldConstraints.Constraint.ConstraintNotNull), QgsFieldConstraints.ConstraintOrigin.ConstraintOriginProvider)
+ self.assertTrue(
+ fields.at(0).constraints().constraints()
+ & QgsFieldConstraints.Constraint.ConstraintNotNull
+ )
+ self.assertFalse(
+ fields.at(1).constraints().constraints()
+ & QgsFieldConstraints.Constraint.ConstraintNotNull
+ )
+ self.assertTrue(
+ fields.at(2).constraints().constraints()
+ & QgsFieldConstraints.Constraint.ConstraintNotNull
+ )
+ self.assertEqual(
+ fields.at(2)
+ .constraints()
+ .constraintOrigin(QgsFieldConstraints.Constraint.ConstraintNotNull),
+ QgsFieldConstraints.ConstraintOrigin.ConstraintOriginProvider,
+ )
def testDefaultValues(self):
- """ test detection of defaults on OGR layer """
-
- tmpfile = os.path.join(self.basetestpath, 'testDefaults.sqlite')
- ds = ogr.GetDriverByName('SQLite').CreateDataSource(tmpfile)
- lyr = ds.CreateLayer('test', geom_type=ogr.wkbPoint, options=['FID=fid'])
- lyr.CreateField(ogr.FieldDefn('field1', ogr.OFTInteger))
- fld2 = ogr.FieldDefn('field2', ogr.OFTInteger)
- fld2.SetDefault('5')
+ """test detection of defaults on OGR layer"""
+
+ tmpfile = os.path.join(self.basetestpath, "testDefaults.sqlite")
+ ds = ogr.GetDriverByName("SQLite").CreateDataSource(tmpfile)
+ lyr = ds.CreateLayer("test", geom_type=ogr.wkbPoint, options=["FID=fid"])
+ lyr.CreateField(ogr.FieldDefn("field1", ogr.OFTInteger))
+ fld2 = ogr.FieldDefn("field2", ogr.OFTInteger)
+ fld2.SetDefault("5")
lyr.CreateField(fld2)
- fld3 = ogr.FieldDefn('field3', ogr.OFTString)
+ fld3 = ogr.FieldDefn("field3", ogr.OFTString)
fld3.SetDefault("'some ''default'")
lyr.CreateField(fld3)
- fld4 = ogr.FieldDefn('field4', ogr.OFTDate)
+ fld4 = ogr.FieldDefn("field4", ogr.OFTDate)
fld4.SetDefault("CURRENT_DATE")
lyr.CreateField(fld4)
- fld5 = ogr.FieldDefn('field5', ogr.OFTTime)
+ fld5 = ogr.FieldDefn("field5", ogr.OFTTime)
fld5.SetDefault("CURRENT_TIME")
lyr.CreateField(fld5)
- fld6 = ogr.FieldDefn('field6', ogr.OFTDateTime)
+ fld6 = ogr.FieldDefn("field6", ogr.OFTDateTime)
fld6.SetDefault("CURRENT_TIMESTAMP")
lyr.CreateField(fld6)
ds = None
- vl = QgsVectorLayer(f'{tmpfile}', 'test', 'ogr')
+ vl = QgsVectorLayer(f"{tmpfile}", "test", "ogr")
self.assertTrue(vl.isValid())
# test some bad indexes
@@ -196,69 +282,73 @@ def testDefaultValues(self):
self.assertEqual(vl.dataProvider().defaultValue(3), "some 'default")
self.assertEqual(vl.dataProvider().defaultValue(4), QDate.currentDate())
# time may pass, so we allow 1 second difference here
- self.assertLess(vl.dataProvider().defaultValue(5).secsTo(QTime.currentTime()), 1)
- self.assertLess(vl.dataProvider().defaultValue(6).secsTo(QDateTime.currentDateTime()), 1)
+ self.assertLess(
+ vl.dataProvider().defaultValue(5).secsTo(QTime.currentTime()), 1
+ )
+ self.assertLess(
+ vl.dataProvider().defaultValue(6).secsTo(QDateTime.currentDateTime()), 1
+ )
def testSubsetStringFids(self):
"""
- - tests that feature ids are stable even if a subset string is set
- - tests that the subset string is correctly set on the ogr layer event when reloading the data source (issue #17122)
+ - tests that feature ids are stable even if a subset string is set
+ - tests that the subset string is correctly set on the ogr layer event when reloading the data source (issue #17122)
"""
- tmpfile = os.path.join(self.basetestpath, 'subsetStringFids.sqlite')
- ds = ogr.GetDriverByName('SQLite').CreateDataSource(tmpfile)
- lyr = ds.CreateLayer('test', geom_type=ogr.wkbPoint, options=['FID=fid'])
- lyr.CreateField(ogr.FieldDefn('type', ogr.OFTInteger))
- lyr.CreateField(ogr.FieldDefn('value', ogr.OFTInteger))
+ tmpfile = os.path.join(self.basetestpath, "subsetStringFids.sqlite")
+ ds = ogr.GetDriverByName("SQLite").CreateDataSource(tmpfile)
+ lyr = ds.CreateLayer("test", geom_type=ogr.wkbPoint, options=["FID=fid"])
+ lyr.CreateField(ogr.FieldDefn("type", ogr.OFTInteger))
+ lyr.CreateField(ogr.FieldDefn("value", ogr.OFTInteger))
f = ogr.Feature(lyr.GetLayerDefn())
f.SetFID(0)
f.SetField(0, 1)
f.SetField(1, 11)
- f.SetGeometry(ogr.CreateGeometryFromWkt('Point (0 0)'))
+ f.SetGeometry(ogr.CreateGeometryFromWkt("Point (0 0)"))
lyr.CreateFeature(f)
f = ogr.Feature(lyr.GetLayerDefn())
f.SetFID(1)
f.SetField(0, 1)
f.SetField(1, 12)
- f.SetGeometry(ogr.CreateGeometryFromWkt('Point (1 1)'))
+ f.SetGeometry(ogr.CreateGeometryFromWkt("Point (1 1)"))
lyr.CreateFeature(f)
f = ogr.Feature(lyr.GetLayerDefn())
f.SetFID(2)
f.SetField(0, 1)
f.SetField(1, 13)
- f.SetGeometry(ogr.CreateGeometryFromWkt('Point (2 2)'))
+ f.SetGeometry(ogr.CreateGeometryFromWkt("Point (2 2)"))
lyr.CreateFeature(f)
f = ogr.Feature(lyr.GetLayerDefn())
f.SetFID(3)
f.SetField(0, 2)
f.SetField(1, 14)
- f.SetGeometry(ogr.CreateGeometryFromWkt('Point (3 3)'))
+ f.SetGeometry(ogr.CreateGeometryFromWkt("Point (3 3)"))
lyr.CreateFeature(f)
f = ogr.Feature(lyr.GetLayerDefn())
f.SetFID(4)
f.SetField(0, 2)
f.SetField(1, 15)
- f.SetGeometry(ogr.CreateGeometryFromWkt('Point (4 4)'))
+ f.SetGeometry(ogr.CreateGeometryFromWkt("Point (4 4)"))
lyr.CreateFeature(f)
f = ogr.Feature(lyr.GetLayerDefn())
f.SetFID(5)
f.SetField(0, 2)
f.SetField(1, 16)
- f.SetGeometry(ogr.CreateGeometryFromWkt('Point (5 5)'))
+ f.SetGeometry(ogr.CreateGeometryFromWkt("Point (5 5)"))
lyr.CreateFeature(f)
f = None
ds = None
- vl = QgsVectorLayer(tmpfile, 'test', 'ogr')
+ vl = QgsVectorLayer(tmpfile, "test", "ogr")
self.assertTrue(vl.isValid())
- self.assertEqual([f.name() for f in vl.fields()], ['fid', 'type', 'value'])
+ self.assertEqual([f.name() for f in vl.fields()], ["fid", "type", "value"])
original_fields = vl.fields()
- vl = QgsVectorLayer(tmpfile + "|subset=type=2", 'test', 'ogr')
+ vl = QgsVectorLayer(tmpfile + "|subset=type=2", "test", "ogr")
self.assertTrue(vl.isValid())
def run_checks():
- self.assertEqual([f.name() for f in vl.fields()], ['fid', 'type', 'value'])
+ self.assertEqual([f.name() for f in vl.fields()], ["fid", "type", "value"])
# expression
req = QgsFeatureRequest()
@@ -268,8 +358,10 @@ def run_checks():
self.assertTrue(it.nextFeature(f))
self.assertEqual(f.id(), 5)
self.assertEqual(f.attributes(), [5, 2, 16])
- self.assertEqual([field.name() for field in f.fields()], ['fid', 'type', 'value'])
- self.assertEqual(f.geometry().asWkt(), 'Point (5 5)')
+ self.assertEqual(
+ [field.name() for field in f.fields()], ["fid", "type", "value"]
+ )
+ self.assertEqual(f.geometry().asWkt(), "Point (5 5)")
# filter fid
req = QgsFeatureRequest()
@@ -279,8 +371,10 @@ def run_checks():
self.assertTrue(it.nextFeature(f))
self.assertEqual(f.id(), 5)
self.assertEqual(f.attributes(), [5, 2, 16])
- self.assertEqual([field.name() for field in f.fields()], ['fid', 'type', 'value'])
- self.assertEqual(f.geometry().asWkt(), 'Point (5 5)')
+ self.assertEqual(
+ [field.name() for field in f.fields()], ["fid", "type", "value"]
+ )
+ self.assertEqual(f.geometry().asWkt(), "Point (5 5)")
# filter fids
req = QgsFeatureRequest()
@@ -290,8 +384,10 @@ def run_checks():
self.assertTrue(it.nextFeature(f))
self.assertEqual(f.id(), 5)
self.assertEqual(f.attributes(), [5, 2, 16])
- self.assertEqual([field.name() for field in f.fields()], ['fid', 'type', 'value'])
- self.assertEqual(f.geometry().asWkt(), 'Point (5 5)')
+ self.assertEqual(
+ [field.name() for field in f.fields()], ["fid", "type", "value"]
+ )
+ self.assertEqual(f.geometry().asWkt(), "Point (5 5)")
# check with subset of attributes
req = QgsFeatureRequest()
@@ -302,8 +398,10 @@ def run_checks():
self.assertTrue(it.nextFeature(f))
self.assertEqual(f.id(), 5)
self.assertEqual(f.attributes()[2], 16)
- self.assertEqual([field.name() for field in f.fields()], ['fid', 'type', 'value'])
- self.assertEqual(f.geometry().asWkt(), 'Point (5 5)')
+ self.assertEqual(
+ [field.name() for field in f.fields()], ["fid", "type", "value"]
+ )
+ self.assertEqual(f.geometry().asWkt(), "Point (5 5)")
# filter rect and expression
req = QgsFeatureRequest()
@@ -314,8 +412,10 @@ def run_checks():
self.assertTrue(it.nextFeature(f))
self.assertEqual(f.id(), 5)
self.assertEqual(f.attributes(), [5, 2, 16])
- self.assertEqual([field.name() for field in f.fields()], ['fid', 'type', 'value'])
- self.assertEqual(f.geometry().asWkt(), 'Point (5 5)')
+ self.assertEqual(
+ [field.name() for field in f.fields()], ["fid", "type", "value"]
+ )
+ self.assertEqual(f.geometry().asWkt(), "Point (5 5)")
# filter rect and fids
req = QgsFeatureRequest()
@@ -326,8 +426,10 @@ def run_checks():
self.assertTrue(it.nextFeature(f))
self.assertEqual(f.id(), 5)
self.assertEqual(f.attributes(), [5, 2, 16])
- self.assertEqual([field.name() for field in f.fields()], ['fid', 'type', 'value'])
- self.assertEqual(f.geometry().asWkt(), 'Point (5 5)')
+ self.assertEqual(
+ [field.name() for field in f.fields()], ["fid", "type", "value"]
+ )
+ self.assertEqual(f.geometry().asWkt(), "Point (5 5)")
# Ensure that orig_ogc_fid is still retrieved even if attribute subset is passed
req = QgsFeatureRequest()
@@ -339,7 +441,9 @@ def run_checks():
ids.append(f.id())
geoms[f.id()] = f.geometry().asWkt()
self.assertCountEqual(ids, [3, 4, 5])
- self.assertEqual(geoms, {3: 'Point (3 3)', 4: 'Point (4 4)', 5: 'Point (5 5)'})
+ self.assertEqual(
+ geoms, {3: "Point (3 3)", 4: "Point (4 4)", 5: "Point (5 5)"}
+ )
run_checks()
# Check that subset string is correctly set on reload
@@ -348,47 +452,61 @@ def run_checks():
def test_SplitFeature(self):
"""Test sqlite feature can be split"""
- tmpfile = os.path.join(self.basetestpath, 'testGeopackageSplitFeatures.sqlite')
- ds = ogr.GetDriverByName('SQlite').CreateDataSource(tmpfile)
- lyr = ds.CreateLayer('test', geom_type=ogr.wkbPolygon)
- lyr.CreateField(ogr.FieldDefn('str_field', ogr.OFTString))
+ tmpfile = os.path.join(self.basetestpath, "testGeopackageSplitFeatures.sqlite")
+ ds = ogr.GetDriverByName("SQlite").CreateDataSource(tmpfile)
+ lyr = ds.CreateLayer("test", geom_type=ogr.wkbPolygon)
+ lyr.CreateField(ogr.FieldDefn("str_field", ogr.OFTString))
f = ogr.Feature(lyr.GetLayerDefn())
- f.SetGeometry(ogr.CreateGeometryFromWkt('POLYGON ((0 0,0 1,1 1,1 0,0 0))'))
+ f.SetGeometry(ogr.CreateGeometryFromWkt("POLYGON ((0 0,0 1,1 1,1 0,0 0))"))
lyr.CreateFeature(f)
f = None
ds = None
- layer = QgsVectorLayer(f'{tmpfile}' + "|layername=" + "test", 'test', 'ogr')
+ layer = QgsVectorLayer(f"{tmpfile}" + "|layername=" + "test", "test", "ogr")
# Check that pk field has unique constraint
fields = layer.fields()
pkfield = fields.at(0)
- self.assertTrue(pkfield.constraints().constraints() & QgsFieldConstraints.Constraint.ConstraintUnique)
+ self.assertTrue(
+ pkfield.constraints().constraints()
+ & QgsFieldConstraints.Constraint.ConstraintUnique
+ )
self.assertTrue(layer.isValid())
self.assertTrue(layer.isSpatial())
- self.assertEqual([f for f in layer.getFeatures()][0].geometry().asWkt(), 'Polygon ((0 0, 0 1, 1 1, 1 0, 0 0))')
+ self.assertEqual(
+ [f for f in layer.getFeatures()][0].geometry().asWkt(),
+ "Polygon ((0 0, 0 1, 1 1, 1 0, 0 0))",
+ )
layer.startEditing()
- self.assertEqual(layer.splitFeatures([QgsPointXY(0.5, 0), QgsPointXY(0.5, 1)], 0), 0)
+ self.assertEqual(
+ layer.splitFeatures([QgsPointXY(0.5, 0), QgsPointXY(0.5, 1)], 0), 0
+ )
self.assertTrue(layer.commitChanges())
self.assertEqual(layer.featureCount(), 2)
- layer = QgsVectorLayer(f'{tmpfile}' + "|layername=" + "test", 'test', 'ogr')
+ layer = QgsVectorLayer(f"{tmpfile}" + "|layername=" + "test", "test", "ogr")
self.assertEqual(layer.featureCount(), 2)
- self.assertEqual([f for f in layer.getFeatures()][0].geometry().asWkt(), 'Polygon ((0.5 0, 0.5 1, 1 1, 1 0, 0.5 0))')
- self.assertEqual([f for f in layer.getFeatures()][1].geometry().asWkt(), 'Polygon ((0.5 1, 0.5 0, 0 0, 0 1, 0.5 1))')
+ self.assertEqual(
+ [f for f in layer.getFeatures()][0].geometry().asWkt(),
+ "Polygon ((0.5 0, 0.5 1, 1 1, 1 0, 0.5 0))",
+ )
+ self.assertEqual(
+ [f for f in layer.getFeatures()][1].geometry().asWkt(),
+ "Polygon ((0.5 1, 0.5 0, 0 0, 0 1, 0.5 1))",
+ )
def testBlob(self):
"""
Test binary blob field
"""
- tmpfile = os.path.join(self.basetestpath, 'binaryfield.sqlite')
- ds = ogr.GetDriverByName('SQLite').CreateDataSource(tmpfile)
- lyr = ds.CreateLayer('test', geom_type=ogr.wkbPoint, options=['FID=fid'])
- lyr.CreateField(ogr.FieldDefn('strfield', ogr.OFTString))
- lyr.CreateField(ogr.FieldDefn('intfield', ogr.OFTInteger))
- lyr.CreateField(ogr.FieldDefn('binfield', ogr.OFTBinary))
- lyr.CreateField(ogr.FieldDefn('binfield2', ogr.OFTBinary))
+ tmpfile = os.path.join(self.basetestpath, "binaryfield.sqlite")
+ ds = ogr.GetDriverByName("SQLite").CreateDataSource(tmpfile)
+ lyr = ds.CreateLayer("test", geom_type=ogr.wkbPoint, options=["FID=fid"])
+ lyr.CreateField(ogr.FieldDefn("strfield", ogr.OFTString))
+ lyr.CreateField(ogr.FieldDefn("intfield", ogr.OFTInteger))
+ lyr.CreateField(ogr.FieldDefn("binfield", ogr.OFTBinary))
+ lyr.CreateField(ogr.FieldDefn("binfield2", ogr.OFTBinary))
f = None
ds = None
@@ -396,184 +514,210 @@ def testBlob(self):
self.assertTrue(vl.isValid())
fields = vl.fields()
- bin1_field = fields[fields.lookupField('binfield')]
+ bin1_field = fields[fields.lookupField("binfield")]
self.assertEqual(bin1_field.type(), QVariant.ByteArray)
- self.assertEqual(bin1_field.typeName(), 'Binary')
- bin2_field = fields[fields.lookupField('binfield2')]
+ self.assertEqual(bin1_field.typeName(), "Binary")
+ bin2_field = fields[fields.lookupField("binfield2")]
self.assertEqual(bin2_field.type(), QVariant.ByteArray)
- self.assertEqual(bin2_field.typeName(), 'Binary')
+ self.assertEqual(bin2_field.typeName(), "Binary")
dp = vl.dataProvider()
f = QgsFeature(fields)
- bin_1 = b'xxx'
- bin_2 = b'yyy'
+ bin_1 = b"xxx"
+ bin_2 = b"yyy"
bin_val1 = QByteArray(bin_1)
bin_val2 = QByteArray(bin_2)
- f.setAttributes([1, 'str', 100, bin_val1, bin_val2])
+ f.setAttributes([1, "str", 100, bin_val1, bin_val2])
self.assertTrue(dp.addFeature(f))
f2 = next(dp.getFeatures())
- self.assertEqual(f2.attributes(), [1, 'str', 100, QByteArray(bin_1), QByteArray(bin_2)])
+ self.assertEqual(
+ f2.attributes(), [1, "str", 100, QByteArray(bin_1), QByteArray(bin_2)]
+ )
- bin_3 = b'zzz'
- bin_4 = b'aaa'
+ bin_3 = b"zzz"
+ bin_4 = b"aaa"
bin_val3 = QByteArray(bin_3)
bin_val4 = QByteArray(bin_4)
- self.assertTrue(dp.changeAttributeValues({f2.id(): {fields.lookupField('intfield'): 200,
- fields.lookupField('binfield'): bin_val4,
- fields.lookupField('binfield2'): bin_val3}}))
+ self.assertTrue(
+ dp.changeAttributeValues(
+ {
+ f2.id(): {
+ fields.lookupField("intfield"): 200,
+ fields.lookupField("binfield"): bin_val4,
+ fields.lookupField("binfield2"): bin_val3,
+ }
+ }
+ )
+ )
f5 = next(dp.getFeatures())
- self.assertEqual(f5.attributes(), [1, 'str', 200, QByteArray(bin_4), QByteArray(bin_3)])
+ self.assertEqual(
+ f5.attributes(), [1, "str", 200, QByteArray(bin_4), QByteArray(bin_3)]
+ )
def testUniqueValuesOnFidColumn(self):
"""Test regression #21311 OGR provider returns an empty set for sqlite uniqueValues"""
- tmpfile = os.path.join(self.basetestpath, 'testSQLiteUniqueValuesOnFidColumn.db')
- ds = ogr.GetDriverByName('SQLite').CreateDataSource(tmpfile)
- lyr = ds.CreateLayer('test', geom_type=ogr.wkbPolygon)
- lyr.CreateField(ogr.FieldDefn('str_field', ogr.OFTString))
+ tmpfile = os.path.join(
+ self.basetestpath, "testSQLiteUniqueValuesOnFidColumn.db"
+ )
+ ds = ogr.GetDriverByName("SQLite").CreateDataSource(tmpfile)
+ lyr = ds.CreateLayer("test", geom_type=ogr.wkbPolygon)
+ lyr.CreateField(ogr.FieldDefn("str_field", ogr.OFTString))
f = ogr.Feature(lyr.GetLayerDefn())
- f.SetGeometry(ogr.CreateGeometryFromWkt('POLYGON ((0 0,0 1,1 1,1 0,0 0))'))
- f.SetField('str_field', 'one')
+ f.SetGeometry(ogr.CreateGeometryFromWkt("POLYGON ((0 0,0 1,1 1,1 0,0 0))"))
+ f.SetField("str_field", "one")
lyr.CreateFeature(f)
f = ogr.Feature(lyr.GetLayerDefn())
- f.SetGeometry(ogr.CreateGeometryFromWkt('POLYGON ((0 0,0 2,2 2,2 0,0 0))'))
- f.SetField('str_field', 'two')
+ f.SetGeometry(ogr.CreateGeometryFromWkt("POLYGON ((0 0,0 2,2 2,2 0,0 0))"))
+ f.SetField("str_field", "two")
lyr.CreateFeature(f)
f = None
ds = None
vl1 = QgsVectorLayer(tmpfile)
self.assertTrue(vl1.isValid())
self.assertEqual(vl1.uniqueValues(0), {1, 2})
- self.assertEqual(vl1.uniqueValues(1), {'one', 'two'})
+ self.assertEqual(vl1.uniqueValues(1), {"one", "two"})
def testSpatialIndexCapability(self):
- """ Test https://github.com/qgis/QGIS/issues/44513 """
+ """Test https://github.com/qgis/QGIS/issues/44513"""
- tmpfile = os.path.join(self.basetestpath, 'testSpatialIndexCapability.db')
- ds = ogr.GetDriverByName('SQLite').CreateDataSource(tmpfile)
- ds.CreateLayer('test', geom_type=ogr.wkbPolygon)
+ tmpfile = os.path.join(self.basetestpath, "testSpatialIndexCapability.db")
+ ds = ogr.GetDriverByName("SQLite").CreateDataSource(tmpfile)
+ ds.CreateLayer("test", geom_type=ogr.wkbPolygon)
ds = None
- vl = QgsVectorLayer(f'{tmpfile}|layerid=0', 'test', 'ogr')
+ vl = QgsVectorLayer(f"{tmpfile}|layerid=0", "test", "ogr")
caps = vl.dataProvider().capabilities()
self.assertFalse(caps & QgsVectorDataProvider.Capability.CreateSpatialIndex)
def testSpatialIndexCapabilitySpatialite(self):
- """ Test https://github.com/qgis/QGIS/issues/44513 """
-
- tmpfile = os.path.join(self.basetestpath, 'testSpatialIndexCapabilitySpatialite.db')
- ds = ogr.GetDriverByName('SQLite').CreateDataSource(tmpfile, options=['SPATIALITE=YES'])
- ds.CreateLayer('test', geom_type=ogr.wkbPolygon)
+ """Test https://github.com/qgis/QGIS/issues/44513"""
+
+ tmpfile = os.path.join(
+ self.basetestpath, "testSpatialIndexCapabilitySpatialite.db"
+ )
+ ds = ogr.GetDriverByName("SQLite").CreateDataSource(
+ tmpfile, options=["SPATIALITE=YES"]
+ )
+ ds.CreateLayer("test", geom_type=ogr.wkbPolygon)
ds = None
- vl = QgsVectorLayer(f'{tmpfile}|layerid=0', 'test', 'ogr')
+ vl = QgsVectorLayer(f"{tmpfile}|layerid=0", "test", "ogr")
caps = vl.dataProvider().capabilities()
self.assertTrue(caps & QgsVectorDataProvider.Capability.CreateSpatialIndex)
def testExtentSqlite(self):
# create 2D dataset
- tmpfile = os.path.join(self.basetestpath, 'points.sqlite')
- ds = ogr.GetDriverByName('SQLite').CreateDataSource(tmpfile)
- lyr = ds.CreateLayer('test', geom_type=ogr.wkbPoint, options=['FID=fid'])
+ tmpfile = os.path.join(self.basetestpath, "points.sqlite")
+ ds = ogr.GetDriverByName("SQLite").CreateDataSource(tmpfile)
+ lyr = ds.CreateLayer("test", geom_type=ogr.wkbPoint, options=["FID=fid"])
f = ogr.Feature(lyr.GetLayerDefn())
f.SetFID(0)
- f.SetGeometry(ogr.CreateGeometryFromWkt('Point (0 0)'))
+ f.SetGeometry(ogr.CreateGeometryFromWkt("Point (0 0)"))
lyr.CreateFeature(f)
f = ogr.Feature(lyr.GetLayerDefn())
f.SetFID(1)
- f.SetGeometry(ogr.CreateGeometryFromWkt('Point (1 1)'))
+ f.SetGeometry(ogr.CreateGeometryFromWkt("Point (1 1)"))
lyr.CreateFeature(f)
f = ogr.Feature(lyr.GetLayerDefn())
f.SetFID(2)
- f.SetGeometry(ogr.CreateGeometryFromWkt('Point (2 2)'))
+ f.SetGeometry(ogr.CreateGeometryFromWkt("Point (2 2)"))
lyr.CreateFeature(f)
f = ogr.Feature(lyr.GetLayerDefn())
f.SetFID(3)
- f.SetGeometry(ogr.CreateGeometryFromWkt('Point (3 3)'))
+ f.SetGeometry(ogr.CreateGeometryFromWkt("Point (3 3)"))
lyr.CreateFeature(f)
f = ogr.Feature(lyr.GetLayerDefn())
f.SetFID(4)
- f.SetGeometry(ogr.CreateGeometryFromWkt('Point (4 4)'))
+ f.SetGeometry(ogr.CreateGeometryFromWkt("Point (4 4)"))
lyr.CreateFeature(f)
f = ogr.Feature(lyr.GetLayerDefn())
f.SetFID(5)
- f.SetGeometry(ogr.CreateGeometryFromWkt('Point (5 5)'))
+ f.SetGeometry(ogr.CreateGeometryFromWkt("Point (5 5)"))
lyr.CreateFeature(f)
f = None
ds = None
# create 3D 2.5d dataset
- tmpfile = os.path.join(self.basetestpath, 'points_with_z.sqlite')
- ds = ogr.GetDriverByName('SQLite').CreateDataSource(tmpfile, options=['SPATIALITE=YES'])
- lyr = ds.CreateLayer('test', geom_type=ogr.wkbPoint25D, options=['FID=fid'])
+ tmpfile = os.path.join(self.basetestpath, "points_with_z.sqlite")
+ ds = ogr.GetDriverByName("SQLite").CreateDataSource(
+ tmpfile, options=["SPATIALITE=YES"]
+ )
+ lyr = ds.CreateLayer("test", geom_type=ogr.wkbPoint25D, options=["FID=fid"])
f = ogr.Feature(lyr.GetLayerDefn())
f.SetFID(0)
- f.SetGeometry(ogr.CreateGeometryFromWkt('Point Z (0 0 -5)'))
+ f.SetGeometry(ogr.CreateGeometryFromWkt("Point Z (0 0 -5)"))
lyr.CreateFeature(f)
f = ogr.Feature(lyr.GetLayerDefn())
f.SetFID(1)
- f.SetGeometry(ogr.CreateGeometryFromWkt('Point Z (1 1 -10)'))
+ f.SetGeometry(ogr.CreateGeometryFromWkt("Point Z (1 1 -10)"))
lyr.CreateFeature(f)
f = ogr.Feature(lyr.GetLayerDefn())
f.SetFID(2)
- f.SetGeometry(ogr.CreateGeometryFromWkt('Point Z (2 2 -15)'))
+ f.SetGeometry(ogr.CreateGeometryFromWkt("Point Z (2 2 -15)"))
lyr.CreateFeature(f)
f = ogr.Feature(lyr.GetLayerDefn())
f.SetFID(3)
- f.SetGeometry(ogr.CreateGeometryFromWkt('Point Z (3 3 5)'))
+ f.SetGeometry(ogr.CreateGeometryFromWkt("Point Z (3 3 5)"))
lyr.CreateFeature(f)
f = ogr.Feature(lyr.GetLayerDefn())
f.SetFID(4)
- f.SetGeometry(ogr.CreateGeometryFromWkt('Point Z (4 4 10)'))
+ f.SetGeometry(ogr.CreateGeometryFromWkt("Point Z (4 4 10)"))
lyr.CreateFeature(f)
f = ogr.Feature(lyr.GetLayerDefn())
f.SetFID(5)
- f.SetGeometry(ogr.CreateGeometryFromWkt('Point Z (5 5 15)'))
+ f.SetGeometry(ogr.CreateGeometryFromWkt("Point Z (5 5 15)"))
lyr.CreateFeature(f)
f = None
ds = None
# create 3D ZM dataset
- tmpfile = os.path.join(self.basetestpath, 'points_with_zm.sqlite')
- ds = ogr.GetDriverByName('SQLite').CreateDataSource(tmpfile, options=['SPATIALITE=YES'])
- lyr = ds.CreateLayer('test', geom_type=ogr.wkbPointZM, options=['FID=fid'])
+ tmpfile = os.path.join(self.basetestpath, "points_with_zm.sqlite")
+ ds = ogr.GetDriverByName("SQLite").CreateDataSource(
+ tmpfile, options=["SPATIALITE=YES"]
+ )
+ lyr = ds.CreateLayer("test", geom_type=ogr.wkbPointZM, options=["FID=fid"])
f = ogr.Feature(lyr.GetLayerDefn())
f.SetFID(0)
- f.SetGeometry(ogr.CreateGeometryFromWkt('Point ZM (0 0 -5 1)'))
+ f.SetGeometry(ogr.CreateGeometryFromWkt("Point ZM (0 0 -5 1)"))
lyr.CreateFeature(f)
f = ogr.Feature(lyr.GetLayerDefn())
f.SetFID(1)
- f.SetGeometry(ogr.CreateGeometryFromWkt('Point ZM (1 1 -10 2)'))
+ f.SetGeometry(ogr.CreateGeometryFromWkt("Point ZM (1 1 -10 2)"))
lyr.CreateFeature(f)
f = ogr.Feature(lyr.GetLayerDefn())
f.SetFID(2)
- f.SetGeometry(ogr.CreateGeometryFromWkt('Point ZM (2 2 -15 3)'))
+ f.SetGeometry(ogr.CreateGeometryFromWkt("Point ZM (2 2 -15 3)"))
lyr.CreateFeature(f)
f = ogr.Feature(lyr.GetLayerDefn())
f.SetFID(3)
- f.SetGeometry(ogr.CreateGeometryFromWkt('Point ZM (3 3 5 4)'))
+ f.SetGeometry(ogr.CreateGeometryFromWkt("Point ZM (3 3 5 4)"))
lyr.CreateFeature(f)
f = ogr.Feature(lyr.GetLayerDefn())
f.SetFID(4)
- f.SetGeometry(ogr.CreateGeometryFromWkt('Point ZM (4 4 10 5)'))
+ f.SetGeometry(ogr.CreateGeometryFromWkt("Point ZM (4 4 10 5)"))
lyr.CreateFeature(f)
f = ogr.Feature(lyr.GetLayerDefn())
f.SetFID(5)
- f.SetGeometry(ogr.CreateGeometryFromWkt('Point ZM (5 5 15 6)'))
+ f.SetGeometry(ogr.CreateGeometryFromWkt("Point ZM (5 5 15 6)"))
lyr.CreateFeature(f)
f = None
ds = None
# create empty 3D dataset
- tmpfile = os.path.join(self.basetestpath, 'points_z_empty.sqlite')
- ds = ogr.GetDriverByName('SQLite').CreateDataSource(tmpfile, options=['SPATIALITE=YES'])
- lyr = ds.CreateLayer('test', geom_type=ogr.wkbPointZM, options=['FID=fid'])
+ tmpfile = os.path.join(self.basetestpath, "points_z_empty.sqlite")
+ ds = ogr.GetDriverByName("SQLite").CreateDataSource(
+ tmpfile, options=["SPATIALITE=YES"]
+ )
+ lyr = ds.CreateLayer("test", geom_type=ogr.wkbPointZM, options=["FID=fid"])
ds = None
# 2D points
- vl = QgsVectorLayer(os.path.join(self.basetestpath, 'points.sqlite'), 'test', 'ogr')
+ vl = QgsVectorLayer(
+ os.path.join(self.basetestpath, "points.sqlite"), "test", "ogr"
+ )
self.assertTrue(vl.isValid())
self.assertAlmostEqual(vl.extent().xMinimum(), 0, places=3)
@@ -590,7 +734,9 @@ def testExtentSqlite(self):
del vl
# 3D points
- vl = QgsVectorLayer(os.path.join(self.basetestpath, 'points_with_z.sqlite'), 'test', 'ogr')
+ vl = QgsVectorLayer(
+ os.path.join(self.basetestpath, "points_with_z.sqlite"), "test", "ogr"
+ )
self.assertTrue(vl.isValid())
self.assertAlmostEqual(vl.extent().xMinimum(), 0, places=3)
@@ -606,7 +752,9 @@ def testExtentSqlite(self):
self.assertAlmostEqual(vl.extent3D().zMaximum(), 15.0, places=3)
del vl
- vl = QgsVectorLayer(os.path.join(self.basetestpath, 'points_with_zm.sqlite'), 'test', 'ogr')
+ vl = QgsVectorLayer(
+ os.path.join(self.basetestpath, "points_with_zm.sqlite"), "test", "ogr"
+ )
self.assertTrue(vl.isValid())
self.assertAlmostEqual(vl.extent().xMinimum(), 0, places=3)
@@ -622,7 +770,9 @@ def testExtentSqlite(self):
self.assertAlmostEqual(vl.extent3D().zMaximum(), 15.0, places=3)
del vl
- vl = QgsVectorLayer(os.path.join(self.basetestpath, 'points_z_empty.sqlite'), 'test', 'ogr')
+ vl = QgsVectorLayer(
+ os.path.join(self.basetestpath, "points_z_empty.sqlite"), "test", "ogr"
+ )
self.assertTrue(vl.isValid())
self.assertTrue(math.isnan(vl.extent().xMinimum()))
@@ -640,69 +790,71 @@ def testExtentSqlite(self):
def testExtentGpkg(self):
# create 2D dataset
- tmpfile = os.path.join(self.basetestpath, 'points.gpkg')
- ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile)
- lyr = ds.CreateLayer('test', geom_type=ogr.wkbPoint, options=['FID=fid'])
+ tmpfile = os.path.join(self.basetestpath, "points.gpkg")
+ ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile)
+ lyr = ds.CreateLayer("test", geom_type=ogr.wkbPoint, options=["FID=fid"])
f = ogr.Feature(lyr.GetLayerDefn())
f.SetFID(0)
- f.SetGeometry(ogr.CreateGeometryFromWkt('Point (0 0)'))
+ f.SetGeometry(ogr.CreateGeometryFromWkt("Point (0 0)"))
lyr.CreateFeature(f)
f = ogr.Feature(lyr.GetLayerDefn())
f.SetFID(1)
- f.SetGeometry(ogr.CreateGeometryFromWkt('Point (1 1)'))
+ f.SetGeometry(ogr.CreateGeometryFromWkt("Point (1 1)"))
lyr.CreateFeature(f)
f = ogr.Feature(lyr.GetLayerDefn())
f.SetFID(2)
- f.SetGeometry(ogr.CreateGeometryFromWkt('Point (2 2)'))
+ f.SetGeometry(ogr.CreateGeometryFromWkt("Point (2 2)"))
lyr.CreateFeature(f)
f = ogr.Feature(lyr.GetLayerDefn())
f.SetFID(3)
- f.SetGeometry(ogr.CreateGeometryFromWkt('Point (3 3)'))
+ f.SetGeometry(ogr.CreateGeometryFromWkt("Point (3 3)"))
lyr.CreateFeature(f)
f = ogr.Feature(lyr.GetLayerDefn())
f.SetFID(4)
- f.SetGeometry(ogr.CreateGeometryFromWkt('Point (4 4)'))
+ f.SetGeometry(ogr.CreateGeometryFromWkt("Point (4 4)"))
lyr.CreateFeature(f)
f = ogr.Feature(lyr.GetLayerDefn())
f.SetFID(5)
- f.SetGeometry(ogr.CreateGeometryFromWkt('Point (5 5)'))
+ f.SetGeometry(ogr.CreateGeometryFromWkt("Point (5 5)"))
lyr.CreateFeature(f)
f = None
ds = None
# create 3D dataset
- tmpfile = os.path.join(self.basetestpath, 'points_with_z.gpkg')
- ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile)
- lyr = ds.CreateLayer('test', geom_type=ogr.wkbPointZM, options=['FID=fid'])
+ tmpfile = os.path.join(self.basetestpath, "points_with_z.gpkg")
+ ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile)
+ lyr = ds.CreateLayer("test", geom_type=ogr.wkbPointZM, options=["FID=fid"])
f = ogr.Feature(lyr.GetLayerDefn())
f.SetFID(0)
- f.SetGeometry(ogr.CreateGeometryFromWkt('Point Z (0 0 -5)'))
+ f.SetGeometry(ogr.CreateGeometryFromWkt("Point Z (0 0 -5)"))
lyr.CreateFeature(f)
f = ogr.Feature(lyr.GetLayerDefn())
f.SetFID(1)
- f.SetGeometry(ogr.CreateGeometryFromWkt('Point Z (1 1 -10)'))
+ f.SetGeometry(ogr.CreateGeometryFromWkt("Point Z (1 1 -10)"))
lyr.CreateFeature(f)
f = ogr.Feature(lyr.GetLayerDefn())
f.SetFID(2)
- f.SetGeometry(ogr.CreateGeometryFromWkt('Point Z (2 2 -15)'))
+ f.SetGeometry(ogr.CreateGeometryFromWkt("Point Z (2 2 -15)"))
lyr.CreateFeature(f)
f = ogr.Feature(lyr.GetLayerDefn())
f.SetFID(3)
- f.SetGeometry(ogr.CreateGeometryFromWkt('Point Z (3 3 5)'))
+ f.SetGeometry(ogr.CreateGeometryFromWkt("Point Z (3 3 5)"))
lyr.CreateFeature(f)
f = ogr.Feature(lyr.GetLayerDefn())
f.SetFID(4)
- f.SetGeometry(ogr.CreateGeometryFromWkt('Point Z (4 4 10)'))
+ f.SetGeometry(ogr.CreateGeometryFromWkt("Point Z (4 4 10)"))
lyr.CreateFeature(f)
f = ogr.Feature(lyr.GetLayerDefn())
f.SetFID(5)
- f.SetGeometry(ogr.CreateGeometryFromWkt('Point Z (5 5 15)'))
+ f.SetGeometry(ogr.CreateGeometryFromWkt("Point Z (5 5 15)"))
lyr.CreateFeature(f)
f = None
ds = None
# 2D points
- vl = QgsVectorLayer(os.path.join(self.basetestpath, 'points.gpkg'), 'test', 'ogr')
+ vl = QgsVectorLayer(
+ os.path.join(self.basetestpath, "points.gpkg"), "test", "ogr"
+ )
self.assertTrue(vl.isValid())
self.assertAlmostEqual(vl.extent().xMinimum(), 0, places=3)
@@ -719,7 +871,9 @@ def testExtentGpkg(self):
del vl
# 3D points
- vl = QgsVectorLayer(os.path.join(self.basetestpath, 'points_with_z.gpkg'), 'test', 'ogr')
+ vl = QgsVectorLayer(
+ os.path.join(self.basetestpath, "points_with_z.gpkg"), "test", "ogr"
+ )
self.assertTrue(vl.isValid())
self.assertAlmostEqual(vl.extent().xMinimum(), 0, places=3)
@@ -736,5 +890,5 @@ def testExtentGpkg(self):
del vl
-if __name__ == '__main__':
+if __name__ == "__main__":
unittest.main()
diff --git a/tests/src/python/test_provider_oracle.py b/tests/src/python/test_provider_oracle.py
index bd234d880138..b9d6a9590162 100644
--- a/tests/src/python/test_provider_oracle.py
+++ b/tests/src/python/test_provider_oracle.py
@@ -5,9 +5,10 @@
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
"""
-__author__ = 'Nyall Dawson'
-__date__ = '2016-07-06'
-__copyright__ = 'Copyright 2016, The QGIS Project'
+
+__author__ = "Nyall Dawson"
+__date__ = "2016-07-06"
+__copyright__ = "Copyright 2016, The QGIS Project"
import os
import re
@@ -49,26 +50,36 @@ class TestPyQgsOracleProvider(QgisTestCase, ProviderTestCase):
@classmethod
def setUpClass(cls):
"""Run before all tests"""
- super(TestPyQgsOracleProvider, cls).setUpClass()
- cls.dbconn = "host=localhost dbname=XEPDB1 port=1521 user='QGIS' password='qgis'"
- if 'QGIS_ORACLETEST_DB' in os.environ:
- cls.dbconn = os.environ['QGIS_ORACLETEST_DB']
+ super().setUpClass()
+ cls.dbconn = (
+ "host=localhost dbname=XEPDB1 port=1521 user='QGIS' password='qgis'"
+ )
+ if "QGIS_ORACLETEST_DB" in os.environ:
+ cls.dbconn = os.environ["QGIS_ORACLETEST_DB"]
# Create test layers
cls.vl = QgsVectorLayer(
- cls.dbconn + ' sslmode=disable key=\'pk\' srid=4326 type=POINT table="QGIS"."SOME_DATA" (GEOM) sql=', 'test', 'oracle')
+ cls.dbconn
+ + ' sslmode=disable key=\'pk\' srid=4326 type=POINT table="QGIS"."SOME_DATA" (GEOM) sql=',
+ "test",
+ "oracle",
+ )
assert cls.vl.isValid()
cls.source = cls.vl.dataProvider()
cls.poly_vl = QgsVectorLayer(
- cls.dbconn + ' sslmode=disable key=\'pk\' srid=4326 type=POLYGON table="QGIS"."SOME_POLY_DATA" (GEOM) sql=', 'test', 'oracle')
+ cls.dbconn
+ + ' sslmode=disable key=\'pk\' srid=4326 type=POLYGON table="QGIS"."SOME_POLY_DATA" (GEOM) sql=',
+ "test",
+ "oracle",
+ )
assert cls.poly_vl.isValid()
cls.poly_provider = cls.poly_vl.dataProvider()
- cls.conn = QSqlDatabase.addDatabase('QOCISPATIAL', "oracletest")
- cls.conn.setDatabaseName('localhost/XEPDB1')
- if 'QGIS_ORACLETEST_DBNAME' in os.environ:
- cls.conn.setDatabaseName(os.environ['QGIS_ORACLETEST_DBNAME'])
- cls.conn.setUserName('QGIS')
- cls.conn.setPassword('qgis')
+ cls.conn = QSqlDatabase.addDatabase("QOCISPATIAL", "oracletest")
+ cls.conn.setDatabaseName("localhost/XEPDB1")
+ if "QGIS_ORACLETEST_DBNAME" in os.environ:
+ cls.conn.setDatabaseName(os.environ["QGIS_ORACLETEST_DBNAME"])
+ cls.conn.setUserName("QGIS")
+ cls.conn.setPassword("qgis")
assert cls.conn.open()
def execSQLCommand(self, sql, ignore_errors=False):
@@ -76,28 +87,44 @@ def execSQLCommand(self, sql, ignore_errors=False):
query = QSqlQuery(self.conn)
res = query.exec(sql)
if not ignore_errors:
- self.assertTrue(res, sql + ': ' + query.lastError().text())
+ self.assertTrue(res, sql + ": " + query.lastError().text())
query.finish()
def getSource(self):
# create temporary table for edit tests
- self.execSQLCommand('ALTER TABLE "QGIS"."EDIT_DATA" MODIFY "pk" DROP IDENTITY', ignore_errors=True)
+ self.execSQLCommand(
+ 'ALTER TABLE "QGIS"."EDIT_DATA" MODIFY "pk" DROP IDENTITY',
+ ignore_errors=True,
+ )
self.execSQLCommand('DROP TABLE "QGIS"."EDIT_DATA"', ignore_errors=True)
- self.execSQLCommand("""CREATE TABLE QGIS.EDIT_DATA ("pk" INTEGER GENERATED by default ON null as IDENTITY(START WITH 1 INCREMENT BY 1) PRIMARY KEY, "cnt" INTEGER, "name" VARCHAR2(100), "name2" VARCHAR2(100), "num_char" VARCHAR2(100), "dt" TIMESTAMP, "date" DATE, "time" VARCHAR2(100), GEOM SDO_GEOMETRY)""")
- self.execSQLCommand("""DELETE FROM user_sdo_geom_metadata where TABLE_NAME = 'EDIT_DATA'""")
self.execSQLCommand(
- """INSERT INTO user_sdo_geom_metadata (TABLE_NAME, COLUMN_NAME, DIMINFO, SRID) VALUES ( 'EDIT_DATA', 'GEOM', sdo_dim_array(sdo_dim_element('X',-75,-55,0.005),sdo_dim_element('Y',65,85,0.005)),4326)""", ignore_errors=True)
- self.execSQLCommand("""CREATE INDEX edit_data_spatial_idx ON QGIS.EDIT_DATA(GEOM) INDEXTYPE IS MDSYS.SPATIAL_INDEX""")
- self.execSQLCommand("""INSERT INTO QGIS.EDIT_DATA ("pk", "cnt", "name", "name2", "num_char", "dt", "date", "time", GEOM)
+ """CREATE TABLE QGIS.EDIT_DATA ("pk" INTEGER GENERATED by default ON null as IDENTITY(START WITH 1 INCREMENT BY 1) PRIMARY KEY, "cnt" INTEGER, "name" VARCHAR2(100), "name2" VARCHAR2(100), "num_char" VARCHAR2(100), "dt" TIMESTAMP, "date" DATE, "time" VARCHAR2(100), GEOM SDO_GEOMETRY)"""
+ )
+ self.execSQLCommand(
+ """DELETE FROM user_sdo_geom_metadata where TABLE_NAME = 'EDIT_DATA'"""
+ )
+ self.execSQLCommand(
+ """INSERT INTO user_sdo_geom_metadata (TABLE_NAME, COLUMN_NAME, DIMINFO, SRID) VALUES ( 'EDIT_DATA', 'GEOM', sdo_dim_array(sdo_dim_element('X',-75,-55,0.005),sdo_dim_element('Y',65,85,0.005)),4326)""",
+ ignore_errors=True,
+ )
+ self.execSQLCommand(
+ """CREATE INDEX edit_data_spatial_idx ON QGIS.EDIT_DATA(GEOM) INDEXTYPE IS MDSYS.SPATIAL_INDEX"""
+ )
+ self.execSQLCommand(
+ """INSERT INTO QGIS.EDIT_DATA ("pk", "cnt", "name", "name2", "num_char", "dt", "date", "time", GEOM)
SELECT 5, -200, NULL, 'NuLl', '5', TIMESTAMP '2020-05-04 12:13:14', DATE '2020-05-02','12:13:01', SDO_GEOMETRY( 2001,4326,SDO_POINT_TYPE(-71.123, 78.23, NULL), NULL, NULL) from dual
UNION ALL SELECT 3, 300, 'Pear', 'PEaR', '3', NULL, NULL, NULL, NULL from dual
UNION ALL SELECT 1, 100, 'Orange', 'oranGe', '1', TIMESTAMP '2020-05-03 12:13:14', DATE '2020-05-03','12:13:14', SDO_GEOMETRY( 2001,4326,SDO_POINT_TYPE(-70.332, 66.33, NULL), NULL, NULL) from dual
UNION ALL SELECT 2, 200, 'Apple', 'Apple', '2', TIMESTAMP '2020-05-04 12:14:14', DATE '2020-05-04','12:14:14', SDO_GEOMETRY( 2001,4326,SDO_POINT_TYPE(-68.2, 70.8, NULL), NULL, NULL) from dual
- UNION ALL SELECT 4, 400, 'Honey', 'Honey', '4', TIMESTAMP '2021-05-04 13:13:14', DATE '2021-05-04','13:13:14', SDO_GEOMETRY( 2001,4326,SDO_POINT_TYPE(-65.32, 78.3, NULL), NULL, NULL) from dual""")
+ UNION ALL SELECT 4, 400, 'Honey', 'Honey', '4', TIMESTAMP '2021-05-04 13:13:14', DATE '2021-05-04','13:13:14', SDO_GEOMETRY( 2001,4326,SDO_POINT_TYPE(-65.32, 78.3, NULL), NULL, NULL) from dual"""
+ )
vl = QgsVectorLayer(
- self.dbconn + ' sslmode=disable key=\'pk\' srid=4326 type=POINT table="QGIS"."EDIT_DATA" (GEOM) sql=',
- 'test', 'oracle')
+ self.dbconn
+ + ' sslmode=disable key=\'pk\' srid=4326 type=POINT table="QGIS"."EDIT_DATA" (GEOM) sql=',
+ "test",
+ "oracle",
+ )
return vl
def treat_time_as_string(self):
@@ -110,73 +137,73 @@ def getEditableLayer(self):
return self.getSource()
def enableCompiler(self):
- QgsSettings().setValue('/qgis/compileExpressions', True)
+ QgsSettings().setValue("/qgis/compileExpressions", True)
return True
def disableCompiler(self):
- QgsSettings().setValue('/qgis/compileExpressions', False)
+ QgsSettings().setValue("/qgis/compileExpressions", False)
def uncompiledFilters(self):
filters = {
- '(name = \'Apple\') is not null',
- '"name" || \' \' || "name" = \'Orange Orange\'',
- '"name" || \' \' || "cnt" = \'Orange 100\'',
- '\'x\' || "name" IS NOT NULL',
- '\'x\' || "name" IS NULL',
- 'false and NULL',
- 'true and NULL',
- 'NULL and false',
- 'NULL and true',
- 'NULL and NULL',
- 'false or NULL',
- 'true or NULL',
- 'NULL or false',
- 'NULL or true',
- 'NULL or NULL',
- 'not null',
- 'radians(cnt) < 2',
- 'degrees(pk) <= 200',
- 'atan2(3.14, pk) < 1',
- 'pk < pi()',
- 'log10(pk) < 0.5',
- 'pk < pi() / 2',
- 'pk = char(51)',
- 'pk = coalesce(NULL,3,4)',
- 'name = trim(\' Apple \')',
- 'x($geometry) < -70',
- 'y($geometry) > 70',
- 'xmin($geometry) < -70',
- 'ymin($geometry) > 70',
- 'xmax($geometry) < -70',
- 'ymax($geometry) > 70',
- 'disjoint($geometry,geom_from_wkt( \'Polygon ((-72.2 66.1, -65.2 66.1, -65.2 72.0, -72.2 72.0, -72.2 66.1))\'))',
- 'intersects($geometry,geom_from_wkt( \'Polygon ((-72.2 66.1, -65.2 66.1, -65.2 72.0, -72.2 72.0, -72.2 66.1))\'))',
- 'contains(geom_from_wkt( \'Polygon ((-72.2 66.1, -65.2 66.1, -65.2 72.0, -72.2 72.0, -72.2 66.1))\'),$geometry)',
- 'distance($geometry,geom_from_wkt( \'Point (-70 70)\')) > 7',
- 'intersects($geometry,geom_from_gml( \'-72.2,66.1 -65.2,66.1 -65.2,72.0 -72.2,72.0 -72.2,66.1 \'))',
- 'x($geometry) < -70',
- 'y($geometry) > 79',
- 'xmin($geometry) < -70',
- 'ymin($geometry) < 76',
- 'xmax($geometry) > -68',
- 'ymax($geometry) > 80',
- 'area($geometry) > 10',
- 'perimeter($geometry) < 12',
- 'relate($geometry,geom_from_wkt( \'Polygon ((-68.2 82.1, -66.95 82.1, -66.95 79.05, -68.2 79.05, -68.2 82.1))\')) = \'FF2FF1212\'',
- 'relate($geometry,geom_from_wkt( \'Polygon ((-68.2 82.1, -66.95 82.1, -66.95 79.05, -68.2 79.05, -68.2 82.1))\'), \'****F****\')',
- 'crosses($geometry,geom_from_wkt( \'Linestring (-68.2 82.1, -66.95 82.1, -66.95 79.05)\'))',
- 'overlaps($geometry,geom_from_wkt( \'Polygon ((-68.2 82.1, -66.95 82.1, -66.95 79.05, -68.2 79.05, -68.2 82.1))\'))',
- 'within($geometry,geom_from_wkt( \'Polygon ((-75.1 76.1, -75.1 81.6, -68.8 81.6, -68.8 76.1, -75.1 76.1))\'))',
- 'overlaps(translate($geometry,-1,-1),geom_from_wkt( \'Polygon ((-75.1 76.1, -75.1 81.6, -68.8 81.6, -68.8 76.1, -75.1 76.1))\'))',
- 'overlaps(buffer($geometry,1),geom_from_wkt( \'Polygon ((-75.1 76.1, -75.1 81.6, -68.8 81.6, -68.8 76.1, -75.1 76.1))\'))',
- 'intersects(centroid($geometry),geom_from_wkt( \'Polygon ((-74.4 78.2, -74.4 79.1, -66.8 79.1, -66.8 78.2, -74.4 78.2))\'))',
- 'intersects(point_on_surface($geometry),geom_from_wkt( \'Polygon ((-74.4 78.2, -74.4 79.1, -66.8 79.1, -66.8 78.2, -74.4 78.2))\'))',
+ "(name = 'Apple') is not null",
+ "\"name\" || ' ' || \"name\" = 'Orange Orange'",
+ "\"name\" || ' ' || \"cnt\" = 'Orange 100'",
+ "'x' || \"name\" IS NOT NULL",
+ "'x' || \"name\" IS NULL",
+ "false and NULL",
+ "true and NULL",
+ "NULL and false",
+ "NULL and true",
+ "NULL and NULL",
+ "false or NULL",
+ "true or NULL",
+ "NULL or false",
+ "NULL or true",
+ "NULL or NULL",
+ "not null",
+ "radians(cnt) < 2",
+ "degrees(pk) <= 200",
+ "atan2(3.14, pk) < 1",
+ "pk < pi()",
+ "log10(pk) < 0.5",
+ "pk < pi() / 2",
+ "pk = char(51)",
+ "pk = coalesce(NULL,3,4)",
+ "name = trim(' Apple ')",
+ "x($geometry) < -70",
+ "y($geometry) > 70",
+ "xmin($geometry) < -70",
+ "ymin($geometry) > 70",
+ "xmax($geometry) < -70",
+ "ymax($geometry) > 70",
+ "disjoint($geometry,geom_from_wkt( 'Polygon ((-72.2 66.1, -65.2 66.1, -65.2 72.0, -72.2 72.0, -72.2 66.1))'))",
+ "intersects($geometry,geom_from_wkt( 'Polygon ((-72.2 66.1, -65.2 66.1, -65.2 72.0, -72.2 72.0, -72.2 66.1))'))",
+ "contains(geom_from_wkt( 'Polygon ((-72.2 66.1, -65.2 66.1, -65.2 72.0, -72.2 72.0, -72.2 66.1))'),$geometry)",
+ "distance($geometry,geom_from_wkt( 'Point (-70 70)')) > 7",
+ "intersects($geometry,geom_from_gml( '-72.2,66.1 -65.2,66.1 -65.2,72.0 -72.2,72.0 -72.2,66.1 '))",
+ "x($geometry) < -70",
+ "y($geometry) > 79",
+ "xmin($geometry) < -70",
+ "ymin($geometry) < 76",
+ "xmax($geometry) > -68",
+ "ymax($geometry) > 80",
+ "area($geometry) > 10",
+ "perimeter($geometry) < 12",
+ "relate($geometry,geom_from_wkt( 'Polygon ((-68.2 82.1, -66.95 82.1, -66.95 79.05, -68.2 79.05, -68.2 82.1))')) = 'FF2FF1212'",
+ "relate($geometry,geom_from_wkt( 'Polygon ((-68.2 82.1, -66.95 82.1, -66.95 79.05, -68.2 79.05, -68.2 82.1))'), '****F****')",
+ "crosses($geometry,geom_from_wkt( 'Linestring (-68.2 82.1, -66.95 82.1, -66.95 79.05)'))",
+ "overlaps($geometry,geom_from_wkt( 'Polygon ((-68.2 82.1, -66.95 82.1, -66.95 79.05, -68.2 79.05, -68.2 82.1))'))",
+ "within($geometry,geom_from_wkt( 'Polygon ((-75.1 76.1, -75.1 81.6, -68.8 81.6, -68.8 76.1, -75.1 76.1))'))",
+ "overlaps(translate($geometry,-1,-1),geom_from_wkt( 'Polygon ((-75.1 76.1, -75.1 81.6, -68.8 81.6, -68.8 76.1, -75.1 76.1))'))",
+ "overlaps(buffer($geometry,1),geom_from_wkt( 'Polygon ((-75.1 76.1, -75.1 81.6, -68.8 81.6, -68.8 76.1, -75.1 76.1))'))",
+ "intersects(centroid($geometry),geom_from_wkt( 'Polygon ((-74.4 78.2, -74.4 79.1, -66.8 79.1, -66.8 78.2, -74.4 78.2))'))",
+ "intersects(point_on_surface($geometry),geom_from_wkt( 'Polygon ((-74.4 78.2, -74.4 79.1, -66.8 79.1, -66.8 78.2, -74.4 78.2))'))",
'"dt" < make_date(2020, 5, 4)',
- '"dt" = to_datetime(\'000www14ww13ww12www4ww5ww2020\',\'zzzwwwsswwmmwwhhwwwdwwMwwyyyy\')',
+ "\"dt\" = to_datetime('000www14ww13ww12www4ww5ww2020','zzzwwwsswwmmwwhhwwwdwwMwwyyyy')",
'"date" >= make_date(2020, 5, 4)',
- '"date" = to_date(\'www4ww5ww2020\',\'wwwdwwMwwyyyy\')',
+ "\"date\" = to_date('www4ww5ww2020','wwwdwwMwwyyyy')",
'to_time("time") >= make_time(12, 14, 14)',
- 'to_time("time") = to_time(\'000www14ww13ww12www\',\'zzzwwwsswwmmwwhhwww\')'
+ "to_time(\"time\") = to_time('000www14ww13ww12www','zzzwwwsswwmmwwhhwww')",
}
return filters
@@ -198,30 +225,40 @@ def testCrs(self):
# HERE GO THE PROVIDER SPECIFIC TESTS
def testDateTimeTypes(self):
- vl = QgsVectorLayer('%s table="QGIS"."DATE_TIMES" sql=' %
- (self.dbconn), "testdatetimes", "oracle")
+ vl = QgsVectorLayer(
+ '%s table="QGIS"."DATE_TIMES" sql=' % (self.dbconn),
+ "testdatetimes",
+ "oracle",
+ )
self.assertTrue(vl.isValid())
fields = vl.dataProvider().fields()
- self.assertEqual(fields.at(fields.indexFromName(
- 'date_field')).type(), QVariant.DateTime)
- self.assertEqual(fields.at(fields.indexFromName(
- 'datetime_field')).type(), QVariant.DateTime)
+ self.assertEqual(
+ fields.at(fields.indexFromName("date_field")).type(), QVariant.DateTime
+ )
+ self.assertEqual(
+ fields.at(fields.indexFromName("datetime_field")).type(), QVariant.DateTime
+ )
f = next(vl.getFeatures(QgsFeatureRequest()))
- date_idx = vl.fields().lookupField('date_field')
+ date_idx = vl.fields().lookupField("date_field")
self.assertIsInstance(f.attributes()[date_idx], QDateTime)
self.assertEqual(f.attributes()[date_idx], QDateTime(2004, 3, 4, 0, 0, 0))
- datetime_idx = vl.fields().lookupField('datetime_field')
+ datetime_idx = vl.fields().lookupField("datetime_field")
self.assertIsInstance(f.attributes()[datetime_idx], QDateTime)
- self.assertEqual(f.attributes()[datetime_idx], QDateTime(
- QDate(2004, 3, 4), QTime(13, 41, 52)))
+ self.assertEqual(
+ f.attributes()[datetime_idx],
+ QDateTime(QDate(2004, 3, 4), QTime(13, 41, 52)),
+ )
def testDateInsertion(self):
# fix for https://github.com/qgis/QGIS/issues/27087
- vl = QgsVectorLayer('%s table="QGIS"."DATE_TIMES" sql=' %
- (self.dbconn), "testdatetimes", "oracle")
+ vl = QgsVectorLayer(
+ '%s table="QGIS"."DATE_TIMES" sql=' % (self.dbconn),
+ "testdatetimes",
+ "oracle",
+ )
self.assertTrue(vl.isValid())
for f in vl.getFeatures():
@@ -234,7 +271,7 @@ def testDateInsertion(self):
# add a new feature
newf = QgsFeature(f.fields(), new_id)
- date_idx = vl.fields().lookupField('date_field')
+ date_idx = vl.fields().lookupField("date_field")
dt = QDate(2019, 10, 15)
newf.setAttribute(0, new_id)
newf.setAttribute(date_idx, dt)
@@ -253,11 +290,19 @@ def testValidLayerDiscoverRelationsSimple(self):
"""
Test implicit relations that can be discovers between tables, based on declared foreign keys.
"""
- vl = QgsVectorLayer(f'{self.dbconn} table="QGIS"."REFERENCING_TABLE_SIMPLE" sql=', "test_referencing_table_simple", "oracle")
+ vl = QgsVectorLayer(
+ f'{self.dbconn} table="QGIS"."REFERENCING_TABLE_SIMPLE" sql=',
+ "test_referencing_table_simple",
+ "oracle",
+ )
self.assertTrue(vl.isValid())
QgsProject.instance().addMapLayer(vl)
vls = [
- QgsVectorLayer(f'{self.dbconn} table="QGIS"."REFERENCED_TABLE_1" sql=', "test_referenced_table_1", "oracle"),
+ QgsVectorLayer(
+ f'{self.dbconn} table="QGIS"."REFERENCED_TABLE_1" sql=',
+ "test_referenced_table_1",
+ "oracle",
+ ),
]
for lyr in vls:
self.assertTrue(lyr.isValid())
@@ -274,13 +319,29 @@ def testValidLayerDiscoverRelationsMulti(self):
- two fk referencing the same layer
- the third fk referencing another layer
"""
- vl = QgsVectorLayer(f'{self.dbconn} table="QGIS"."REFERENCING_TABLE_MULTI" sql=', "test_referencing_table_multi", "oracle")
+ vl = QgsVectorLayer(
+ f'{self.dbconn} table="QGIS"."REFERENCING_TABLE_MULTI" sql=',
+ "test_referencing_table_multi",
+ "oracle",
+ )
QgsProject.instance().addMapLayer(vl)
self.assertTrue(vl.isValid())
vls = [
- QgsVectorLayer(f'{self.dbconn} table="QGIS"."REFERENCED_TABLE_1" sql=', "test_referenced_table_1", "oracle"),
- QgsVectorLayer(f'{self.dbconn} table="QGIS"."REFERENCED_TABLE_2" sql=', "test_referenced_table_2", "oracle"),
- QgsVectorLayer(f'{self.dbconn} table="QGIS"."POINT_DATA" (GEOM) srid=4326 type=POINT sql=', "testpoints", "oracle")
+ QgsVectorLayer(
+ f'{self.dbconn} table="QGIS"."REFERENCED_TABLE_1" sql=',
+ "test_referenced_table_1",
+ "oracle",
+ ),
+ QgsVectorLayer(
+ f'{self.dbconn} table="QGIS"."REFERENCED_TABLE_2" sql=',
+ "test_referenced_table_2",
+ "oracle",
+ ),
+ QgsVectorLayer(
+ f'{self.dbconn} table="QGIS"."POINT_DATA" (GEOM) srid=4326 type=POINT sql=',
+ "testpoints",
+ "oracle",
+ ),
]
for lyr in vls:
self.assertTrue(lyr.isValid())
@@ -292,13 +353,29 @@ def testValidLayerDiscoverRelationsComposite(self):
"""
Test implicit relations that can be discovers between tables, based on composite declared foreign keys.
"""
- vl = QgsVectorLayer(f'{self.dbconn} table="QGIS"."REFERENCING_TABLE_COMPOSITE" sql=', "test_referencing_table_composite", "oracle")
+ vl = QgsVectorLayer(
+ f'{self.dbconn} table="QGIS"."REFERENCING_TABLE_COMPOSITE" sql=',
+ "test_referencing_table_composite",
+ "oracle",
+ )
QgsProject.instance().addMapLayer(vl)
self.assertTrue(vl.isValid())
vls = [
- QgsVectorLayer(f'{self.dbconn} table="QGIS"."REFERENCED_TABLE_COMPOSITE" sql=', "test_referenced_table_composite", "oracle"),
- QgsVectorLayer(f'{self.dbconn} table="QGIS"."REFERENCED_TABLE_2" sql=', "test_referenced_table_2", "oracle"),
- QgsVectorLayer(f'{self.dbconn} table="QGIS"."POINT_DATA" (GEOM) srid=4326 type=POINT sql=', "testpoints", "oracle")
+ QgsVectorLayer(
+ f'{self.dbconn} table="QGIS"."REFERENCED_TABLE_COMPOSITE" sql=',
+ "test_referenced_table_composite",
+ "oracle",
+ ),
+ QgsVectorLayer(
+ f'{self.dbconn} table="QGIS"."REFERENCED_TABLE_2" sql=',
+ "test_referenced_table_2",
+ "oracle",
+ ),
+ QgsVectorLayer(
+ f'{self.dbconn} table="QGIS"."POINT_DATA" (GEOM) srid=4326 type=POINT sql=',
+ "testpoints",
+ "oracle",
+ ),
]
for lyr in vls:
self.assertTrue(lyr.isValid())
@@ -311,7 +388,9 @@ def testInvalidLayerDiscoverRelations(self):
"""
Test that discover relations feature can be used on invalid layer.
"""
- vl = QgsVectorLayer(f'{self.dbconn} table="QGIS"."invalid_layer"', "invalid_layer", "oracle")
+ vl = QgsVectorLayer(
+ f'{self.dbconn} table="QGIS"."invalid_layer"', "invalid_layer", "oracle"
+ )
self.assertFalse(vl.isValid())
self.assertEqual(vl.dataProvider().discoverRelations(vl, []), [])
@@ -319,66 +398,90 @@ def testValidLayerDiscoverRelationsNone(self):
"""
Test checks that discover relation feature can be used on a layer that has no relation.
"""
- vl = QgsVectorLayer('%s table="QGIS"."POINT_DATA" (GEOM) srid=4326 type=POINT sql=' %
- (self.dbconn), "testpoints", "oracle")
+ vl = QgsVectorLayer(
+ '%s table="QGIS"."POINT_DATA" (GEOM) srid=4326 type=POINT sql='
+ % (self.dbconn),
+ "testpoints",
+ "oracle",
+ )
self.assertTrue(vl.isValid())
self.assertEqual(vl.dataProvider().discoverRelations(vl, []), [])
def testPoints(self):
- vl = QgsVectorLayer('%s table="QGIS"."POINT_DATA" (GEOM) srid=4326 type=POINT sql=' %
- (self.dbconn), "testpoints", "oracle")
+ vl = QgsVectorLayer(
+ '%s table="QGIS"."POINT_DATA" (GEOM) srid=4326 type=POINT sql='
+ % (self.dbconn),
+ "testpoints",
+ "oracle",
+ )
self.assertTrue(vl.isValid())
features = [f for f in vl.getFeatures()]
- self.assertEqual(features[0].geometry().asWkt(), 'Point (1 2)')
- self.assertEqual(features[1].geometry().asWkt(), 'Point Z (1 2 3)')
- self.assertEqual(features[2].geometry().asWkt(), 'MultiPoint Z ((1 2 3),(4 5 6))')
- self.assertEqual(features[3].geometry().asWkt(), 'MultiPoint ((1 2),(3 4))')
- self.assertEqual(features[4].geometry().asWkt(), 'MultiPoint Z ((1 2 3),(4 5 6))')
- self.assertEqual(features[5].geometry().asWkt(), 'Point (1 2)')
- self.assertEqual(features[6].geometry().asWkt(), 'Point (3 4)')
- self.assertEqual(features[7].geometry().asWkt(), 'Point (5 6)')
+ self.assertEqual(features[0].geometry().asWkt(), "Point (1 2)")
+ self.assertEqual(features[1].geometry().asWkt(), "Point Z (1 2 3)")
+ self.assertEqual(
+ features[2].geometry().asWkt(), "MultiPoint Z ((1 2 3),(4 5 6))"
+ )
+ self.assertEqual(features[3].geometry().asWkt(), "MultiPoint ((1 2),(3 4))")
+ self.assertEqual(
+ features[4].geometry().asWkt(), "MultiPoint Z ((1 2 3),(4 5 6))"
+ )
+ self.assertEqual(features[5].geometry().asWkt(), "Point (1 2)")
+ self.assertEqual(features[6].geometry().asWkt(), "Point (3 4)")
+ self.assertEqual(features[7].geometry().asWkt(), "Point (5 6)")
def testEditPoints(self):
- self.createTable('EDIT_POINTS_DATA', 2, 3857)
+ self.createTable("EDIT_POINTS_DATA", 2, 3857)
# We choose SRID=5698 to get Oracle valid geometries because it support 3D
- self.createTable('EDIT_POINTSZ_DATA', 3, 5698)
+ self.createTable("EDIT_POINTSZ_DATA", 3, 5698)
points = QgsVectorLayer(
- self.dbconn + ' sslmode=disable key=\'pk\' srid=3857 type=Point table="QGIS"."EDIT_POINTS_DATA" (GEOM) sql=',
- 'test_lines', 'oracle')
+ self.dbconn
+ + ' sslmode=disable key=\'pk\' srid=3857 type=Point table="QGIS"."EDIT_POINTS_DATA" (GEOM) sql=',
+ "test_lines",
+ "oracle",
+ )
self.assertTrue(points.isValid())
fid = 1
- self.check_geom(points, fid, 'Point (1 2)')
+ self.check_geom(points, fid, "Point (1 2)")
points_z = QgsVectorLayer(
- self.dbconn + ' sslmode=disable key=\'pk\' srid=3857 type=PointZ table="QGIS"."EDIT_POINTSZ_DATA" (GEOM) sql=',
- 'test_lines', 'oracle')
+ self.dbconn
+ + ' sslmode=disable key=\'pk\' srid=3857 type=PointZ table="QGIS"."EDIT_POINTSZ_DATA" (GEOM) sql=',
+ "test_lines",
+ "oracle",
+ )
self.assertTrue(points_z.isValid())
fid += 1
- self.check_geom(points_z, fid, 'Point Z (1 2 3)')
+ self.check_geom(points_z, fid, "Point Z (1 2 3)")
multipoints = QgsVectorLayer(
- self.dbconn + ' sslmode=disable key=\'pk\' srid=3857 type=MultiPoint table="QGIS"."EDIT_POINTS_DATA" (GEOM) sql=',
- 'test_lines', 'oracle')
+ self.dbconn
+ + ' sslmode=disable key=\'pk\' srid=3857 type=MultiPoint table="QGIS"."EDIT_POINTS_DATA" (GEOM) sql=',
+ "test_lines",
+ "oracle",
+ )
self.assertTrue(multipoints.isValid())
fid += 1
- self.check_geom(multipoints, fid, 'MultiPoint ((1 2),(3 4))')
+ self.check_geom(multipoints, fid, "MultiPoint ((1 2),(3 4))")
fid += 1
- self.check_geom(multipoints, fid, 'MultiPoint ((1 2))')
+ self.check_geom(multipoints, fid, "MultiPoint ((1 2))")
multipoints_z = QgsVectorLayer(
- self.dbconn + ' sslmode=disable key=\'pk\' srid=3857 type=MultiPointZ table="QGIS"."EDIT_POINTSZ_DATA" (GEOM) sql=',
- 'test_lines', 'oracle')
+ self.dbconn
+ + ' sslmode=disable key=\'pk\' srid=3857 type=MultiPointZ table="QGIS"."EDIT_POINTSZ_DATA" (GEOM) sql=',
+ "test_lines",
+ "oracle",
+ )
self.assertTrue(multipoints_z.isValid())
fid += 1
- self.check_geom(multipoints_z, fid, 'MultiPointZ ((1 2 7),(3 4 8))')
+ self.check_geom(multipoints_z, fid, "MultiPointZ ((1 2 7),(3 4 8))")
def testLayerStyles(self):
@@ -386,50 +489,134 @@ def testLayerStyles(self):
# Table without geometry column
vl_no_geom = QgsVectorLayer(
- self.dbconn + ' sslmode=disable key=\'id\' table="QGIS"."DATE_TIMES" sql=', 'test', 'oracle')
+ self.dbconn + ' sslmode=disable key=\'id\' table="QGIS"."DATE_TIMES" sql=',
+ "test",
+ "oracle",
+ )
# Save layer styles
- self.assertEqual(self.vl.saveStyleToDatabase("mystyle", "the best", True, "something.ui"), "")
- self.assertEqual(vl_no_geom.saveStyleToDatabase("my_other_style", "the very best", True, "else.ui"), "")
+ self.assertEqual(
+ self.vl.saveStyleToDatabase("mystyle", "the best", True, "something.ui"), ""
+ )
+ self.assertEqual(
+ vl_no_geom.saveStyleToDatabase(
+ "my_other_style", "the very best", True, "else.ui"
+ ),
+ "",
+ )
# Verify presence of styles in database
- res, err = QgsProviderRegistry.instance().styleExists('oracle', self.vl.source(), 'mystyle')
+ res, err = QgsProviderRegistry.instance().styleExists(
+ "oracle", self.vl.source(), "mystyle"
+ )
self.assertTrue(res)
self.assertFalse(err)
- res, err = QgsProviderRegistry.instance().styleExists('oracle', vl_no_geom.source(), 'my_other_style')
+ res, err = QgsProviderRegistry.instance().styleExists(
+ "oracle", vl_no_geom.source(), "my_other_style"
+ )
self.assertTrue(res)
self.assertFalse(err)
# Verify listing and loading of styles
- self.assertEqual(self.vl.listStylesInDatabase(), (1, ['0', '1'], ['mystyle', 'my_other_style'], ['the best', 'the very best'], ''))
+ self.assertEqual(
+ self.vl.listStylesInDatabase(),
+ (
+ 1,
+ ["0", "1"],
+ ["mystyle", "my_other_style"],
+ ["the best", "the very best"],
+ "",
+ ),
+ )
_, res = self.vl.loadNamedStyle(self.vl.source())
self.assertTrue(res)
- self.assertEqual(vl_no_geom.listStylesInDatabase(), (1, ['1', '0'], ['my_other_style', 'mystyle'], ['the very best', 'the best'], ''))
+ self.assertEqual(
+ vl_no_geom.listStylesInDatabase(),
+ (
+ 1,
+ ["1", "0"],
+ ["my_other_style", "mystyle"],
+ ["the very best", "the best"],
+ "",
+ ),
+ )
_, res = vl_no_geom.loadNamedStyle(vl_no_geom.source())
self.assertTrue(res)
self.execSQLCommand('DROP TABLE "QGIS"."LAYER_STYLES"')
def testCurves(self):
- vl = QgsVectorLayer('%s table="QGIS"."LINE_DATA" (GEOM) srid=4326 type=LINESTRING sql=' %
- (self.dbconn), "testlines", "oracle")
+ vl = QgsVectorLayer(
+ '%s table="QGIS"."LINE_DATA" (GEOM) srid=4326 type=LINESTRING sql='
+ % (self.dbconn),
+ "testlines",
+ "oracle",
+ )
self.assertTrue(vl.isValid())
- features = {f['pk']: f for f in vl.getFeatures()}
- self.assertTrue(compareWkt(features[1].geometry().asWkt(), 'LineString (1 2, 3 4, 5 6)', 0.00001), features[1].geometry().asWkt())
- self.assertTrue(compareWkt(features[2].geometry().asWkt(), 'CircularString (1 2, 5 4, 7 2.2, 10 0.1, 13 4)', 0.00001), features[2].geometry().asWkt())
+ features = {f["pk"]: f for f in vl.getFeatures()}
self.assertTrue(
- compareWkt(features[3].geometry().asWkt(), 'CompoundCurve ((-1 -5, 1 2),CircularString (1 2, 5 4, 7 2.20, 10 0.1, 13 4),(13 4, 17 -6))', 0.00001), features[3].geometry().asWkt())
+ compareWkt(
+ features[1].geometry().asWkt(), "LineString (1 2, 3 4, 5 6)", 0.00001
+ ),
+ features[1].geometry().asWkt(),
+ )
self.assertTrue(
- compareWkt(features[4].geometry().asWkt(), 'LineStringZ (1 2 3, 4 5 6, 7 8 9)', 0.00001), features[4].geometry().asWkt())
+ compareWkt(
+ features[2].geometry().asWkt(),
+ "CircularString (1 2, 5 4, 7 2.2, 10 0.1, 13 4)",
+ 0.00001,
+ ),
+ features[2].geometry().asWkt(),
+ )
self.assertTrue(
- compareWkt(features[5].geometry().asWkt(), 'MultiLineString ((1 2, 3 4),(5 6, 7 8, 9 10))', 0.00001), features[5].geometry().asWkt())
+ compareWkt(
+ features[3].geometry().asWkt(),
+ "CompoundCurve ((-1 -5, 1 2),CircularString (1 2, 5 4, 7 2.20, 10 0.1, 13 4),(13 4, 17 -6))",
+ 0.00001,
+ ),
+ features[3].geometry().asWkt(),
+ )
self.assertTrue(
- compareWkt(features[6].geometry().asWkt(), 'MultiLineStringZ ((1 2 11, 3 4 -11),(5 6 9, 7 8 1, 9 10 -3))', 0.00001), features[6].geometry().asWkt())
+ compareWkt(
+ features[4].geometry().asWkt(),
+ "LineStringZ (1 2 3, 4 5 6, 7 8 9)",
+ 0.00001,
+ ),
+ features[4].geometry().asWkt(),
+ )
self.assertTrue(
- compareWkt(features[7].geometry().asWkt(), 'MultiCurve (CircularString (1 2, 5 4, 7 2.2, 10 0.1, 13 4),CircularString (-11 -3, 5 7, 10 -1))', 0.00001), features[7].geometry().asWkt())
+ compareWkt(
+ features[5].geometry().asWkt(),
+ "MultiLineString ((1 2, 3 4),(5 6, 7 8, 9 10))",
+ 0.00001,
+ ),
+ features[5].geometry().asWkt(),
+ )
self.assertTrue(
- compareWkt(features[8].geometry().asWkt(), 'MultiCurve (CompoundCurve ((-1 -5, 1 2),CircularString (1 2, 5 4, 7 2.2, 10 0.1, 13 4),(13 4, 17 -6)), CircularString (1 3, 5 5, 7 3.2, 10 1.1, 13 5),LineString (-11 -3, 5 7, 10 -1))', 0.00001), features[8].geometry().asWkt())
+ compareWkt(
+ features[6].geometry().asWkt(),
+ "MultiLineStringZ ((1 2 11, 3 4 -11),(5 6 9, 7 8 1, 9 10 -3))",
+ 0.00001,
+ ),
+ features[6].geometry().asWkt(),
+ )
+ self.assertTrue(
+ compareWkt(
+ features[7].geometry().asWkt(),
+ "MultiCurve (CircularString (1 2, 5 4, 7 2.2, 10 0.1, 13 4),CircularString (-11 -3, 5 7, 10 -1))",
+ 0.00001,
+ ),
+ features[7].geometry().asWkt(),
+ )
+ self.assertTrue(
+ compareWkt(
+ features[8].geometry().asWkt(),
+ "MultiCurve (CompoundCurve ((-1 -5, 1 2),CircularString (1 2, 5 4, 7 2.2, 10 0.1, 13 4),(13 4, 17 -6)), CircularString (1 3, 5 5, 7 3.2, 10 1.1, 13 5),LineString (-11 -3, 5 7, 10 -1))",
+ 0.00001,
+ ),
+ features[8].geometry().asWkt(),
+ )
def check_geom(self, layer, pk, wkt, wkt_ref=None, check_valid=True):
"""
@@ -449,97 +636,159 @@ def check_geom(self, layer, pk, wkt, wkt_ref=None, check_valid=True):
if check_valid:
self.assertTrue(self.conn)
query = QSqlQuery(self.conn)
- sql = f"""select p.GEOM.st_isvalid() from QGIS.{table} p where "pk" = {pk}"""
+ sql = (
+ f"""select p.GEOM.st_isvalid() from QGIS.{table} p where "pk" = {pk}"""
+ )
res = query.exec(sql)
- self.assertTrue(res, sql + ': ' + query.lastError().text())
+ self.assertTrue(res, sql + ": " + query.lastError().text())
query.next()
valid = query.value(0)
- self.assertTrue(valid, f"geometry '{wkt}' inserted in database is not valid")
+ self.assertTrue(
+ valid, f"geometry '{wkt}' inserted in database is not valid"
+ )
query.finish()
expected_wkt = wkt if wkt_ref is None else wkt_ref
res_wkt = layer.getFeature(pk).geometry().asWkt()
- self.assertTrue(compareWkt(res_wkt, expected_wkt, 0.00001), f"\nactual = {res_wkt}\nexpected = {expected_wkt}")
+ self.assertTrue(
+ compareWkt(res_wkt, expected_wkt, 0.00001),
+ f"\nactual = {res_wkt}\nexpected = {expected_wkt}",
+ )
def createTable(self, name, dims, srid):
self.execSQLCommand(f'DROP TABLE "QGIS"."{name}"', ignore_errors=True)
- self.execSQLCommand(f"""DELETE FROM user_sdo_geom_metadata where TABLE_NAME = '{name}'""")
- self.execSQLCommand(f"""CREATE TABLE QGIS.{name} ("pk" INTEGER PRIMARY KEY, GEOM SDO_GEOMETRY)""")
- self.execSQLCommand("""INSERT INTO user_sdo_geom_metadata (TABLE_NAME, COLUMN_NAME, DIMINFO, SRID) VALUES ( '{}', 'GEOM', sdo_dim_array(sdo_dim_element('X',-50,50,0.005),sdo_dim_element('Y',-50,50,0.005){}),{})""".format(
- name, ",sdo_dim_element('Z',-50,50,0.005)" if dims > 2 else "", srid), ignore_errors=True)
- self.execSQLCommand("""CREATE INDEX {0}_spatial_idx ON QGIS.{0}(GEOM) INDEXTYPE IS MDSYS.SPATIAL_INDEX""".format(name))
+ self.execSQLCommand(
+ f"""DELETE FROM user_sdo_geom_metadata where TABLE_NAME = '{name}'"""
+ )
+ self.execSQLCommand(
+ f"""CREATE TABLE QGIS.{name} ("pk" INTEGER PRIMARY KEY, GEOM SDO_GEOMETRY)"""
+ )
+ self.execSQLCommand(
+ """INSERT INTO user_sdo_geom_metadata (TABLE_NAME, COLUMN_NAME, DIMINFO, SRID) VALUES ( '{}', 'GEOM', sdo_dim_array(sdo_dim_element('X',-50,50,0.005),sdo_dim_element('Y',-50,50,0.005){}),{})""".format(
+ name, ",sdo_dim_element('Z',-50,50,0.005)" if dims > 2 else "", srid
+ ),
+ ignore_errors=True,
+ )
+ self.execSQLCommand(
+ """CREATE INDEX {0}_spatial_idx ON QGIS.{0}(GEOM) INDEXTYPE IS MDSYS.SPATIAL_INDEX""".format(
+ name
+ )
+ )
def testEditCurves(self):
- self.createTable('EDIT_CURVE_DATA', 2, 3857)
+ self.createTable("EDIT_CURVE_DATA", 2, 3857)
# We choose SRID=5698 (see https://docs.oracle.com/database/121/SPATL/three-dimensional-coordinate-reference-system-support.htm#SPATL626)
# to get Oracle valid geometries because it support 3D and arcs (arcs are not supported in geodetic projection)
- self.createTable('EDIT_CURVEZ_DATA', 3, 5698)
+ self.createTable("EDIT_CURVEZ_DATA", 3, 5698)
lines = QgsVectorLayer(
- self.dbconn + ' sslmode=disable key=\'pk\' srid=3857 type=LineString table="QGIS"."EDIT_CURVE_DATA" (GEOM) sql=',
- 'test_lines', 'oracle')
+ self.dbconn
+ + ' sslmode=disable key=\'pk\' srid=3857 type=LineString table="QGIS"."EDIT_CURVE_DATA" (GEOM) sql=',
+ "test_lines",
+ "oracle",
+ )
self.assertTrue(lines.isValid())
fid = 1
- self.check_geom(lines, fid, 'LineString (1 2, 3 4, 5 6)')
+ self.check_geom(lines, fid, "LineString (1 2, 3 4, 5 6)")
fid += 1
- self.check_geom(lines, fid, 'CircularString (1 2, 5 4, 7 2.2, 10 0.1, 13 4)')
+ self.check_geom(lines, fid, "CircularString (1 2, 5 4, 7 2.2, 10 0.1, 13 4)")
fid += 1
- self.check_geom(lines, fid, 'CompoundCurve ((-1 -5, 1 2),CircularString (1 2, 5 4, 7 2.20, 10 0.1, 13 4),(13 4, 17 -6))')
+ self.check_geom(
+ lines,
+ fid,
+ "CompoundCurve ((-1 -5, 1 2),CircularString (1 2, 5 4, 7 2.20, 10 0.1, 13 4),(13 4, 17 -6))",
+ )
# We choose SRID=5698 (see https://docs.oracle.com/database/121/SPATL/three-dimensional-coordinate-reference-system-support.htm#SPATL626)
# to get Oracle valid geometries because it support 3D and arcs (arcs are not supported in geodetic projection)
lines_z = QgsVectorLayer(
- self.dbconn + ' sslmode=disable key=\'pk\' srid=5698 type=LineStringZ table="QGIS"."EDIT_CURVEZ_DATA" (GEOM) sql=',
- 'test_lines', 'oracle')
+ self.dbconn
+ + ' sslmode=disable key=\'pk\' srid=5698 type=LineStringZ table="QGIS"."EDIT_CURVEZ_DATA" (GEOM) sql=',
+ "test_lines",
+ "oracle",
+ )
self.assertTrue(lines_z.isValid())
fid += 1
- self.check_geom(lines_z, fid, 'LineStringZ (1 2 3, 4 5 6, 7 8 9)')
+ self.check_geom(lines_z, fid, "LineStringZ (1 2 3, 4 5 6, 7 8 9)")
# 3D arcs and compound curve are invalid
# https://support.oracle.com/knowledge/Oracle%20Database%20Products/1446335_1.html
# https://support.oracle.com/knowledge/Oracle%20Database%20Products/1641672_1.html
fid += 1
- self.check_geom(lines_z, fid, 'CircularStringZ (1 2 1, 5 4 2, 7 2.2 3, 10 0.1 4, 13 4 5)', check_valid=False)
+ self.check_geom(
+ lines_z,
+ fid,
+ "CircularStringZ (1 2 1, 5 4 2, 7 2.2 3, 10 0.1 4, 13 4 5)",
+ check_valid=False,
+ )
fid += 1
- self.check_geom(lines_z, fid, 'CompoundCurveZ ((-1 -5 1, 1 2 2),CircularStringZ (1 2 2, 5 4 3, 7 2.20 4, 10 0.1 5, 13 4 6),(13 4 6, 17 -6 7))', check_valid=False)
+ self.check_geom(
+ lines_z,
+ fid,
+ "CompoundCurveZ ((-1 -5 1, 1 2 2),CircularStringZ (1 2 2, 5 4 3, 7 2.20 4, 10 0.1 5, 13 4 6),(13 4 6, 17 -6 7))",
+ check_valid=False,
+ )
multi_lines = QgsVectorLayer(
- self.dbconn + ' sslmode=disable key=\'pk\' srid=3857 type=MultiLineString table="QGIS"."EDIT_CURVE_DATA" (GEOM) sql=',
- 'test_multilines', 'oracle')
+ self.dbconn
+ + ' sslmode=disable key=\'pk\' srid=3857 type=MultiLineString table="QGIS"."EDIT_CURVE_DATA" (GEOM) sql=',
+ "test_multilines",
+ "oracle",
+ )
self.assertTrue(multi_lines.isValid())
fid += 1
- self.check_geom(multi_lines, fid, 'MultiLineString ((1 2, 3 4),(5 6, 7 8, 9 10), (11 12, 13 14))')
+ self.check_geom(
+ multi_lines,
+ fid,
+ "MultiLineString ((1 2, 3 4),(5 6, 7 8, 9 10), (11 12, 13 14))",
+ )
fid += 1
- self.check_geom(multi_lines, fid, 'MultiLineString ((1 2, 3 4),(5 6, 7 8, 9 10))')
+ self.check_geom(
+ multi_lines, fid, "MultiLineString ((1 2, 3 4),(5 6, 7 8, 9 10))"
+ )
fid += 1
- self.check_geom(multi_lines, fid, 'MultiLineString ((1 2, 3 4))')
+ self.check_geom(multi_lines, fid, "MultiLineString ((1 2, 3 4))")
multi_lines_z = QgsVectorLayer(
- self.dbconn + ' sslmode=disable key=\'pk\' srid=5698 type=MultiLineStringZ table="QGIS"."EDIT_CURVEZ_DATA" (GEOM) sql=',
- 'test_multilines', 'oracle')
+ self.dbconn
+ + ' sslmode=disable key=\'pk\' srid=5698 type=MultiLineStringZ table="QGIS"."EDIT_CURVEZ_DATA" (GEOM) sql=',
+ "test_multilines",
+ "oracle",
+ )
self.assertTrue(multi_lines_z.isValid())
fid += 1
- self.check_geom(multi_lines_z, fid, 'MultiLineStringZ ((1 2 11, 3 4 -11),(5 6 9, 7 8 1, 9 10 -3))')
+ self.check_geom(
+ multi_lines_z,
+ fid,
+ "MultiLineStringZ ((1 2 11, 3 4 -11),(5 6 9, 7 8 1, 9 10 -3))",
+ )
fid += 1
- self.check_geom(multi_lines_z, fid, 'MultiLineStringZ ((1 2 1, 3 4 2),(5 6 3, 7 8 4, 9 10 5), (11 12 6, 13 14 7))')
+ self.check_geom(
+ multi_lines_z,
+ fid,
+ "MultiLineStringZ ((1 2 1, 3 4 2),(5 6 3, 7 8 4, 9 10 5), (11 12 6, 13 14 7))",
+ )
fid += 1
- self.check_geom(multi_lines_z, fid, 'MultiLineStringZ ((1 2 1, 3 4 2))')
+ self.check_geom(multi_lines_z, fid, "MultiLineStringZ ((1 2 1, 3 4 2))")
multi_curves = QgsVectorLayer(
- self.dbconn + ' sslmode=disable key=\'pk\' srid=3857 type=MultiCurve table="QGIS"."EDIT_CURVE_DATA" (GEOM) sql=',
- 'test_multicurves', 'oracle')
+ self.dbconn
+ + ' sslmode=disable key=\'pk\' srid=3857 type=MultiCurve table="QGIS"."EDIT_CURVE_DATA" (GEOM) sql=',
+ "test_multicurves",
+ "oracle",
+ )
self.assertTrue(multi_curves.isValid())
# There is no way to represent a compound curve with only one LineString or CircularString in Oracle database
@@ -547,238 +796,556 @@ def testEditCurves(self):
# So, this two different WKTs inputs generate the same data in Oracle database, and so the same WKT
# output representation (with CompoundCurve() around each MultiCurve parts)
fid += 1
- self.check_geom(multi_curves, fid,
- 'MultiCurve (CompoundCurve ((-1 -5, 1 2),CircularString (1 2, 5 4, 7 2.2, 10 0.1, 13 4),(13 4, 17 -6)),CircularString (1 3, 5 5, 7 3.2, 10 1.1, 13 5),LineString (-11 -3, 5 7, 10 -1))')
+ self.check_geom(
+ multi_curves,
+ fid,
+ "MultiCurve (CompoundCurve ((-1 -5, 1 2),CircularString (1 2, 5 4, 7 2.2, 10 0.1, 13 4),(13 4, 17 -6)),CircularString (1 3, 5 5, 7 3.2, 10 1.1, 13 5),LineString (-11 -3, 5 7, 10 -1))",
+ )
fid += 1
- self.check_geom(multi_curves, fid,
- 'MultiCurve (CompoundCurve ((-1 -5, 1 2),CircularString (1 2, 5 4, 7 2.2, 10 0.1, 13 4),(13 4, 17 -6)),CompoundCurve (CircularString (1 3, 5 5, 7 3.2, 10 1.1, 13 5)),(-11 -3, 5 7, 10 -1))',
- 'MultiCurve (CompoundCurve ((-1 -5, 1 2),CircularString (1 2, 5 4, 7 2.2, 10 0.1, 13 4),(13 4, 17 -6)),CircularString (1 3, 5 5, 7 3.2, 10 1.1, 13 5),LineString (-11 -3, 5 7, 10 -1))')
+ self.check_geom(
+ multi_curves,
+ fid,
+ "MultiCurve (CompoundCurve ((-1 -5, 1 2),CircularString (1 2, 5 4, 7 2.2, 10 0.1, 13 4),(13 4, 17 -6)),CompoundCurve (CircularString (1 3, 5 5, 7 3.2, 10 1.1, 13 5)),(-11 -3, 5 7, 10 -1))",
+ "MultiCurve (CompoundCurve ((-1 -5, 1 2),CircularString (1 2, 5 4, 7 2.2, 10 0.1, 13 4),(13 4, 17 -6)),CircularString (1 3, 5 5, 7 3.2, 10 1.1, 13 5),LineString (-11 -3, 5 7, 10 -1))",
+ )
fid += 1
- self.check_geom(multi_curves, fid,
- 'MultiCurve (CompoundCurve ((-1 -5, 1 2),(1 2, 17 -6)),CircularString (1 2, 5 4, 7 2.2, 10 0.1, 13 4))')
+ self.check_geom(
+ multi_curves,
+ fid,
+ "MultiCurve (CompoundCurve ((-1 -5, 1 2),(1 2, 17 -6)),CircularString (1 2, 5 4, 7 2.2, 10 0.1, 13 4))",
+ )
fid += 1
- self.check_geom(multi_curves, fid,
- 'MultiCurve (CompoundCurve ((-1 -5, 1 2),(1 2, 17 -6)))')
+ self.check_geom(
+ multi_curves, fid, "MultiCurve (CompoundCurve ((-1 -5, 1 2),(1 2, 17 -6)))"
+ )
multi_curves_z = QgsVectorLayer(
- self.dbconn + ' sslmode=disable key=\'pk\' srid=5698 type=MultiCurveZ table="QGIS"."EDIT_CURVEZ_DATA" (GEOM) sql=',
- 'test_multicurves_z', 'oracle')
+ self.dbconn
+ + ' sslmode=disable key=\'pk\' srid=5698 type=MultiCurveZ table="QGIS"."EDIT_CURVEZ_DATA" (GEOM) sql=',
+ "test_multicurves_z",
+ "oracle",
+ )
self.assertTrue(multi_curves_z.isValid())
# ora-54530 : 3D compound lines are invalid since 11.2.0.3 : https://support.oracle.com/knowledge/Oracle%20Database%20Products/1446335_1.html
fid += 1
- self.check_geom(multi_curves_z, fid,
- 'MultiCurveZ (CompoundCurveZ ((-1 -5 3, 1 2 4),CircularStringZ (1 2 4, 5 4 5, 7 2.2 6, 10 0.1 7, 13 4 8),(13 4 8, 17 -6 9)), CircularStringZ (1 3 2, 5 5 3, 7 3.2 4, 10 1.1 5, 13 5 6),LineStringZ (-11 -3 1, 5 7 2, 10 -1 3))',
- check_valid=False)
+ self.check_geom(
+ multi_curves_z,
+ fid,
+ "MultiCurveZ (CompoundCurveZ ((-1 -5 3, 1 2 4),CircularStringZ (1 2 4, 5 4 5, 7 2.2 6, 10 0.1 7, 13 4 8),(13 4 8, 17 -6 9)), CircularStringZ (1 3 2, 5 5 3, 7 3.2 4, 10 1.1 5, 13 5 6),LineStringZ (-11 -3 1, 5 7 2, 10 -1 3))",
+ check_valid=False,
+ )
fid += 1
- self.check_geom(multi_curves_z, fid,
- 'MultiCurveZ (CompoundCurveZ ((-1 -5 3, 1 2 4),CircularStringZ (1 2 4, 5 4 5, 7 2.2 6, 10 0.1 7, 13 4 8),(13 4 8, 17 -6 9)),CompoundCurveZ (CircularStringZ (1 3 2, 5 5 3, 7 3.2 4, 10 1.1 5, 13 5 6)),(-11 -3 1, 5 7 2, 10 -1 3))',
- 'MultiCurveZ (CompoundCurveZ ((-1 -5 3, 1 2 4),CircularStringZ (1 2 4, 5 4 5, 7 2.2 6, 10 0.1 7, 13 4 8),(13 4 8, 17 -6 9)), CircularStringZ (1 3 2, 5 5 3, 7 3.2 4, 10 1.1 5, 13 5 6),LineStringZ (-11 -3 1, 5 7 2, 10 -1 3))',
- check_valid=False)
+ self.check_geom(
+ multi_curves_z,
+ fid,
+ "MultiCurveZ (CompoundCurveZ ((-1 -5 3, 1 2 4),CircularStringZ (1 2 4, 5 4 5, 7 2.2 6, 10 0.1 7, 13 4 8),(13 4 8, 17 -6 9)),CompoundCurveZ (CircularStringZ (1 3 2, 5 5 3, 7 3.2 4, 10 1.1 5, 13 5 6)),(-11 -3 1, 5 7 2, 10 -1 3))",
+ "MultiCurveZ (CompoundCurveZ ((-1 -5 3, 1 2 4),CircularStringZ (1 2 4, 5 4 5, 7 2.2 6, 10 0.1 7, 13 4 8),(13 4 8, 17 -6 9)), CircularStringZ (1 3 2, 5 5 3, 7 3.2 4, 10 1.1 5, 13 5 6),LineStringZ (-11 -3 1, 5 7 2, 10 -1 3))",
+ check_valid=False,
+ )
fid += 1
- self.check_geom(multi_curves_z, fid,
- 'MultiCurveZ (CompoundCurveZ ((-1 -5 3, 1 2 4),(1 2 4, 17 -6 8)))',
- check_valid=False)
+ self.check_geom(
+ multi_curves_z,
+ fid,
+ "MultiCurveZ (CompoundCurveZ ((-1 -5 3, 1 2 4),(1 2 4, 17 -6 8)))",
+ check_valid=False,
+ )
def testSurfaces(self):
- vl = QgsVectorLayer('%s table="QGIS"."POLY_DATA" (GEOM) srid=4326 type=POLYGON sql=' %
- (self.dbconn), "testpoly", "oracle")
+ vl = QgsVectorLayer(
+ '%s table="QGIS"."POLY_DATA" (GEOM) srid=4326 type=POLYGON sql='
+ % (self.dbconn),
+ "testpoly",
+ "oracle",
+ )
self.assertTrue(vl.isValid())
- features = {f['pk']: f for f in vl.getFeatures()}
- self.assertTrue(compareWkt(features[1].geometry().asWkt(), 'Polygon ((1 2, 11 2, 11 22, 1 22, 1 2))', 0.00001), features[1].geometry().asWkt())
- self.assertTrue(compareWkt(features[2].geometry().asWkt(), 'PolygonZ ((1 2 3, 11 2 13, 11 22 15, 1 22 7, 1 2 3))', 0.00001), features[2].geometry().asWkt())
+ features = {f["pk"]: f for f in vl.getFeatures()}
+ self.assertTrue(
+ compareWkt(
+ features[1].geometry().asWkt(),
+ "Polygon ((1 2, 11 2, 11 22, 1 22, 1 2))",
+ 0.00001,
+ ),
+ features[1].geometry().asWkt(),
+ )
self.assertTrue(
- compareWkt(features[3].geometry().asWkt(), 'Polygon ((1 2, 11 2, 11 22, 1 22, 1 2),(5 6, 8 9, 8 6, 5 6),(3 4, 5 6, 3 6, 3 4))', 0.00001), features[3].geometry().asWkt())
+ compareWkt(
+ features[2].geometry().asWkt(),
+ "PolygonZ ((1 2 3, 11 2 13, 11 22 15, 1 22 7, 1 2 3))",
+ 0.00001,
+ ),
+ features[2].geometry().asWkt(),
+ )
self.assertTrue(
- compareWkt(features[4].geometry().asWkt(), 'PolygonZ ((1 2 3, 11 2 13, 11 22 15, 1 22 7, 1 2 3),(5 6 1, 8 9 -1, 8 6 2, 5 6 1))', 0.00001), features[4].geometry().asWkt())
+ compareWkt(
+ features[3].geometry().asWkt(),
+ "Polygon ((1 2, 11 2, 11 22, 1 22, 1 2),(5 6, 8 9, 8 6, 5 6),(3 4, 5 6, 3 6, 3 4))",
+ 0.00001,
+ ),
+ features[3].geometry().asWkt(),
+ )
self.assertTrue(
- compareWkt(features[5].geometry().asWkt(), 'Polygon ((1 2, 11 2, 11 22, 1 22, 1 2))', 0.00001), features[5].geometry().asWkt())
+ compareWkt(
+ features[4].geometry().asWkt(),
+ "PolygonZ ((1 2 3, 11 2 13, 11 22 15, 1 22 7, 1 2 3),(5 6 1, 8 9 -1, 8 6 2, 5 6 1))",
+ 0.00001,
+ ),
+ features[4].geometry().asWkt(),
+ )
self.assertTrue(
- compareWkt(features[6].geometry().asWkt(), 'CurvePolygon (CircularString (6.76923076923076916 22.82875364393326834, 17.98259979777942519 11.61538461538461497, 6.76923076923076916 0.40201558683595984, -4.44413825931788598 11.61538461538461497, 6.76923076923076916 22.82875364393326834))', 0.00001), features[6].geometry().asWkt())
+ compareWkt(
+ features[5].geometry().asWkt(),
+ "Polygon ((1 2, 11 2, 11 22, 1 22, 1 2))",
+ 0.00001,
+ ),
+ features[5].geometry().asWkt(),
+ )
self.assertTrue(
- compareWkt(features[7].geometry().asWkt(), 'MultiPolygon (((1 2, 11 2, 11 22, 1 22, 1 2)),((1 2, 11 2, 11 22, 1 22, 1 2),(5 6, 8 9, 8 6, 5 6),(3 4, 5 6, 3 6, 3 4)))', 0.00001), features[7].geometry().asWkt())
+ compareWkt(
+ features[6].geometry().asWkt(),
+ "CurvePolygon (CircularString (6.76923076923076916 22.82875364393326834, 17.98259979777942519 11.61538461538461497, 6.76923076923076916 0.40201558683595984, -4.44413825931788598 11.61538461538461497, 6.76923076923076916 22.82875364393326834))",
+ 0.00001,
+ ),
+ features[6].geometry().asWkt(),
+ )
self.assertTrue(
- compareWkt(features[8].geometry().asWkt(), 'MultiPolygonZ (((1 2 3, 11 2 13, 11 22 15, 1 22 7, 1 2 3)),((1 2 3, 11 2 13, 11 22 15, 1 22 7, 1 2 3),(5 6 1, 8 9 -1, 8 6 2, 5 6 1)))', 0.00001), features[8].geometry().asWkt())
+ compareWkt(
+ features[7].geometry().asWkt(),
+ "MultiPolygon (((1 2, 11 2, 11 22, 1 22, 1 2)),((1 2, 11 2, 11 22, 1 22, 1 2),(5 6, 8 9, 8 6, 5 6),(3 4, 5 6, 3 6, 3 4)))",
+ 0.00001,
+ ),
+ features[7].geometry().asWkt(),
+ )
self.assertTrue(
- compareWkt(features[9].geometry().asWkt(), 'CurvePolygon (CircularString (1 3, 3 5, 4 7, 7 3, 1 3))', 0.00001), features[9].geometry().asWkt())
+ compareWkt(
+ features[8].geometry().asWkt(),
+ "MultiPolygonZ (((1 2 3, 11 2 13, 11 22 15, 1 22 7, 1 2 3)),((1 2 3, 11 2 13, 11 22 15, 1 22 7, 1 2 3),(5 6 1, 8 9 -1, 8 6 2, 5 6 1)))",
+ 0.00001,
+ ),
+ features[8].geometry().asWkt(),
+ )
self.assertTrue(
- compareWkt(features[10].geometry().asWkt(), 'CurvePolygon (CircularString (1 3, 3 5, 4 7, 7 3, 1 3),CircularString (3.1 3.3, 3.3 3.5, 3.4 3.7, 3.7 3.3, 3.1 3.3))', 0.00001), features[10].geometry().asWkt())
+ compareWkt(
+ features[9].geometry().asWkt(),
+ "CurvePolygon (CircularString (1 3, 3 5, 4 7, 7 3, 1 3))",
+ 0.00001,
+ ),
+ features[9].geometry().asWkt(),
+ )
self.assertTrue(
- compareWkt(features[11].geometry().asWkt(), 'CurvePolygon(CompoundCurve ((-1 -5, 1 2),CircularString (1 2, 5 4, 7 2.20, 10 0.1, 13 4),(13 4, 17 -6),CircularString (17 -6, 5 -7, -1 -5)))', 0.00001), features[11].geometry().asWkt())
+ compareWkt(
+ features[10].geometry().asWkt(),
+ "CurvePolygon (CircularString (1 3, 3 5, 4 7, 7 3, 1 3),CircularString (3.1 3.3, 3.3 3.5, 3.4 3.7, 3.7 3.3, 3.1 3.3))",
+ 0.00001,
+ ),
+ features[10].geometry().asWkt(),
+ )
self.assertTrue(
- compareWkt(features[12].geometry().asWkt(), 'MultiSurface (CurvePolygon (CircularString (1 3, 3 5, 4 7, 7 3, 1 3)),CurvePolygon (CircularString (11 3, 13 5, 14 7, 17 3, 11 3)))', 0.00001), features[12].geometry().asWkt())
+ compareWkt(
+ features[11].geometry().asWkt(),
+ "CurvePolygon(CompoundCurve ((-1 -5, 1 2),CircularString (1 2, 5 4, 7 2.20, 10 0.1, 13 4),(13 4, 17 -6),CircularString (17 -6, 5 -7, -1 -5)))",
+ 0.00001,
+ ),
+ features[11].geometry().asWkt(),
+ )
self.assertTrue(
- compareWkt(features[13].geometry().asWkt(), 'CurvePolygonZ(CompoundCurveZ (CircularStringZ (-1 -5 1, 5 -7 2, 17 -6 3), (17 -6 3, 13 4 4), CircularStringZ (13 4 4, 10 0.1 5, 7 2.20 6, 5 4 7, 1 2 8),(1 2 8, -1 -5 1)))', 0.00001), features[13].geometry().asWkt())
+ compareWkt(
+ features[12].geometry().asWkt(),
+ "MultiSurface (CurvePolygon (CircularString (1 3, 3 5, 4 7, 7 3, 1 3)),CurvePolygon (CircularString (11 3, 13 5, 14 7, 17 3, 11 3)))",
+ 0.00001,
+ ),
+ features[12].geometry().asWkt(),
+ )
self.assertTrue(
- compareWkt(features[14].geometry().asWkt(), 'MultiPolygon (((22 22, 28 22, 28 26, 22 26, 22 22)))', 0.00001), features[14].geometry().asWkt())
+ compareWkt(
+ features[13].geometry().asWkt(),
+ "CurvePolygonZ(CompoundCurveZ (CircularStringZ (-1 -5 1, 5 -7 2, 17 -6 3), (17 -6 3, 13 4 4), CircularStringZ (13 4 4, 10 0.1 5, 7 2.20 6, 5 4 7, 1 2 8),(1 2 8, -1 -5 1)))",
+ 0.00001,
+ ),
+ features[13].geometry().asWkt(),
+ )
self.assertTrue(
- compareWkt(features[15].geometry().asWkt(), 'MultiSurface (CurvePolygon(CompoundCurve (CircularString (-1 -5, 5 -7, 17 -6), (17 -6, -1 -5))), CurvePolygon (CircularString (1 3, 7 3, 4 7, 3 5, 1 3)))', 0.00001), features[15].geometry().asWkt())
+ compareWkt(
+ features[14].geometry().asWkt(),
+ "MultiPolygon (((22 22, 28 22, 28 26, 22 26, 22 22)))",
+ 0.00001,
+ ),
+ features[14].geometry().asWkt(),
+ )
+ self.assertTrue(
+ compareWkt(
+ features[15].geometry().asWkt(),
+ "MultiSurface (CurvePolygon(CompoundCurve (CircularString (-1 -5, 5 -7, 17 -6), (17 -6, -1 -5))), CurvePolygon (CircularString (1 3, 7 3, 4 7, 3 5, 1 3)))",
+ 0.00001,
+ ),
+ features[15].geometry().asWkt(),
+ )
def testEditSurfaces(self):
- self.createTable('EDIT_SURFACE_DATA', 2, 3857)
+ self.createTable("EDIT_SURFACE_DATA", 2, 3857)
# We choose SRID=5698 (see https://docs.oracle.com/database/121/SPATL/three-dimensional-coordinate-reference-system-support.htm#SPATL626)
# to get Oracle valid geometries because it support 3D and arcs (arcs are not supported in geodetic projection)
- self.createTable('EDIT_SURFACEZ_DATA', 3, 5698)
+ self.createTable("EDIT_SURFACEZ_DATA", 3, 5698)
polygon = QgsVectorLayer(
- self.dbconn + ' sslmode=disable key=\'pk\' srid=3857 type=Polygon table="QGIS"."EDIT_SURFACE_DATA" (GEOM) sql=',
- 'test_polygon', 'oracle')
+ self.dbconn
+ + ' sslmode=disable key=\'pk\' srid=3857 type=Polygon table="QGIS"."EDIT_SURFACE_DATA" (GEOM) sql=',
+ "test_polygon",
+ "oracle",
+ )
self.assertTrue(polygon.isValid())
fid = 1
- self.check_geom(polygon, fid, 'Polygon ((1 2, 11 2, 11 22, 1 22, 1 2))')
+ self.check_geom(polygon, fid, "Polygon ((1 2, 11 2, 11 22, 1 22, 1 2))")
fid += 1
- self.check_geom(polygon, fid, 'Polygon ((1 2, 11 2, 11 22, 1 22, 1 2),(5 6, 8 9, 8 6, 5 6),(3 4, 3 6, 5 6, 3 4))')
+ self.check_geom(
+ polygon,
+ fid,
+ "Polygon ((1 2, 11 2, 11 22, 1 22, 1 2),(5 6, 8 9, 8 6, 5 6),(3 4, 3 6, 5 6, 3 4))",
+ )
fid += 1
# Outer ring in clockwise order --> reversed on writing
- self.check_geom(polygon, fid, 'Polygon ((0 0, 0 1, 1 1, 0 0))', 'Polygon ((0 0, 1 1, 0 1, 0 0))')
+ self.check_geom(
+ polygon,
+ fid,
+ "Polygon ((0 0, 0 1, 1 1, 0 0))",
+ "Polygon ((0 0, 1 1, 0 1, 0 0))",
+ )
fid += 1
# Outer ring in clockwise order --> reversed on writing. Inner ring in clockwise order --> unmodified
- self.check_geom(polygon, fid, 'Polygon ((0 0, 0 1, 1 1, 0 0),(0.1 0.2, 0.1 0.9, 0.7 0.9, 0.1 0.2))', 'Polygon ((0 0, 1 1, 0 1, 0 0),(0.1 0.2, 0.1 0.9, 0.7 0.9, 0.1 0.2))')
+ self.check_geom(
+ polygon,
+ fid,
+ "Polygon ((0 0, 0 1, 1 1, 0 0),(0.1 0.2, 0.1 0.9, 0.7 0.9, 0.1 0.2))",
+ "Polygon ((0 0, 1 1, 0 1, 0 0),(0.1 0.2, 0.1 0.9, 0.7 0.9, 0.1 0.2))",
+ )
fid += 1
# Inner ring in counterclockwise order --> reversed on writing. Outer ring in counterclockwise order --> unmodified
- self.check_geom(polygon, fid, 'Polygon ((0 0, 1 1, 0 1, 0 0),(0.1 0.2, 0.7 0.9, 0.1 0.9, 0.1 0.2))', 'Polygon ((0 0, 1 1, 0 1, 0 0),(0.1 0.2, 0.1 0.9, 0.7 0.9, 0.1 0.2))')
+ self.check_geom(
+ polygon,
+ fid,
+ "Polygon ((0 0, 1 1, 0 1, 0 0),(0.1 0.2, 0.7 0.9, 0.1 0.9, 0.1 0.2))",
+ "Polygon ((0 0, 1 1, 0 1, 0 0),(0.1 0.2, 0.1 0.9, 0.7 0.9, 0.1 0.2))",
+ )
fid += 1
polygon_z = QgsVectorLayer(
- self.dbconn + ' sslmode=disable key=\'pk\' srid=5698 type=PolygonZ table="QGIS"."EDIT_SURFACEZ_DATA" (GEOM) sql=',
- 'test_polygon_z', 'oracle')
+ self.dbconn
+ + ' sslmode=disable key=\'pk\' srid=5698 type=PolygonZ table="QGIS"."EDIT_SURFACEZ_DATA" (GEOM) sql=',
+ "test_polygon_z",
+ "oracle",
+ )
self.assertTrue(polygon_z.isValid())
# non planar polygon are invalid : to http://ora.codes/ora-54505/
- self.check_geom(polygon_z, fid, 'PolygonZ ((1 2 3, 11 2 3, 11 22 3, 1 22 3, 1 2 3))')
+ self.check_geom(
+ polygon_z, fid, "PolygonZ ((1 2 3, 11 2 3, 11 22 3, 1 22 3, 1 2 3))"
+ )
fid += 1
- self.check_geom(polygon_z, fid, 'PolygonZ ((1 2 4, 11 2 5, 11 22 6, 1 22 7, 1 2 1))', check_valid=False)
+ self.check_geom(
+ polygon_z,
+ fid,
+ "PolygonZ ((1 2 4, 11 2 5, 11 22 6, 1 22 7, 1 2 1))",
+ check_valid=False,
+ )
fid += 1
- self.check_geom(polygon_z, fid, 'PolygonZ ((1 2 3, 11 2 3, 11 22 3, 1 22 3, 1 2 3),(5 6 3, 8 9 3, 8 6 3, 5 6 3))')
+ self.check_geom(
+ polygon_z,
+ fid,
+ "PolygonZ ((1 2 3, 11 2 3, 11 22 3, 1 22 3, 1 2 3),(5 6 3, 8 9 3, 8 6 3, 5 6 3))",
+ )
fid += 1
- self.check_geom(polygon_z, fid, 'PolygonZ ((1 2 3, 11 2 13, 11 22 15, 1 22 7, 1 2 3),(5 6 1, 8 9 -1, 8 6 2, 5 6 1))', check_valid=False)
+ self.check_geom(
+ polygon_z,
+ fid,
+ "PolygonZ ((1 2 3, 11 2 13, 11 22 15, 1 22 7, 1 2 3),(5 6 1, 8 9 -1, 8 6 2, 5 6 1))",
+ check_valid=False,
+ )
fid += 1
multi_polygon = QgsVectorLayer(
- self.dbconn + ' sslmode=disable key=\'pk\' srid=3857 type=MultiPolygon table="QGIS"."EDIT_SURFACE_DATA" (GEOM) sql=',
- 'multi_polygon', 'oracle')
+ self.dbconn
+ + ' sslmode=disable key=\'pk\' srid=3857 type=MultiPolygon table="QGIS"."EDIT_SURFACE_DATA" (GEOM) sql=',
+ "multi_polygon",
+ "oracle",
+ )
self.assertTrue(multi_polygon.isValid())
- self.check_geom(multi_polygon, fid, 'MultiPolygon (((22 22, 28 22, 28 26, 22 26, 22 22)),((1 2, 11 2, 11 22, 1 22, 1 2),(5 6, 8 9, 8 6, 5 6),(3 4, 3 6, 5 6, 3 4)))')
+ self.check_geom(
+ multi_polygon,
+ fid,
+ "MultiPolygon (((22 22, 28 22, 28 26, 22 26, 22 22)),((1 2, 11 2, 11 22, 1 22, 1 2),(5 6, 8 9, 8 6, 5 6),(3 4, 3 6, 5 6, 3 4)))",
+ )
fid += 1
- self.check_geom(multi_polygon, fid, 'MultiPolygon (((22 22, 28 22, 28 26, 22 26, 22 22)))')
+ self.check_geom(
+ multi_polygon, fid, "MultiPolygon (((22 22, 28 22, 28 26, 22 26, 22 22)))"
+ )
fid += 1
multi_polygon_z = QgsVectorLayer(
- self.dbconn + ' sslmode=disable key=\'pk\' srid=5698 type=MultiPolygonZ table="QGIS"."EDIT_SURFACEZ_DATA" (GEOM) sql=',
- 'multi_polygon_z', 'oracle')
+ self.dbconn
+ + ' sslmode=disable key=\'pk\' srid=5698 type=MultiPolygonZ table="QGIS"."EDIT_SURFACEZ_DATA" (GEOM) sql=',
+ "multi_polygon_z",
+ "oracle",
+ )
self.assertTrue(multi_polygon_z.isValid())
- self.check_geom(multi_polygon_z, fid, 'MultiPolygonZ (((22 22 1, 28 22 2, 28 26 3, 22 26 4, 22 22 1)),((1 2 3, 11 2 4, 11 22 5, 1 22 6, 1 2 3),(5 6 1, 8 9 2, 8 6 3, 5 6 1),(3 4 0, 3 6 1, 5 6 2, 3 4 0)))', check_valid=False)
+ self.check_geom(
+ multi_polygon_z,
+ fid,
+ "MultiPolygonZ (((22 22 1, 28 22 2, 28 26 3, 22 26 4, 22 22 1)),((1 2 3, 11 2 4, 11 22 5, 1 22 6, 1 2 3),(5 6 1, 8 9 2, 8 6 3, 5 6 1),(3 4 0, 3 6 1, 5 6 2, 3 4 0)))",
+ check_valid=False,
+ )
fid += 1
curve_polygon = QgsVectorLayer(
- self.dbconn + ' sslmode=disable key=\'pk\' srid=3857 type=CurvePolygon table="QGIS"."EDIT_SURFACE_DATA" (GEOM) sql=',
- 'curve_polygon', 'oracle')
+ self.dbconn
+ + ' sslmode=disable key=\'pk\' srid=3857 type=CurvePolygon table="QGIS"."EDIT_SURFACE_DATA" (GEOM) sql=',
+ "curve_polygon",
+ "oracle",
+ )
self.assertTrue(curve_polygon.isValid())
- self.check_geom(curve_polygon, fid, 'CurvePolygon (CircularString (6.76923076923076916 22.82875364393326834, -4.44413825931788598 11.61538461538461497, 6.76923076923076916 0.40201558683595984, 17.98259979777942519 11.61538461538461497, 6.76923076923076916 22.82875364393326834))')
+ self.check_geom(
+ curve_polygon,
+ fid,
+ "CurvePolygon (CircularString (6.76923076923076916 22.82875364393326834, -4.44413825931788598 11.61538461538461497, 6.76923076923076916 0.40201558683595984, 17.98259979777942519 11.61538461538461497, 6.76923076923076916 22.82875364393326834))",
+ )
fid += 1
- self.check_geom(curve_polygon, fid, 'CurvePolygon (CircularString (1 3, 7 3, 4 7, 3 5, 1 3))')
+ self.check_geom(
+ curve_polygon,
+ fid,
+ "CurvePolygon (CircularString (1 3, 7 3, 4 7, 3 5, 1 3))",
+ )
fid += 1
- self.check_geom(curve_polygon, fid, 'CurvePolygon (CircularString (1 3, 7 3, 4 7, 3 5, 1 3),CircularString (3.1 3.3, 3.3 3.5, 3.4 3.7, 3.7 3.3, 3.1 3.3))')
+ self.check_geom(
+ curve_polygon,
+ fid,
+ "CurvePolygon (CircularString (1 3, 7 3, 4 7, 3 5, 1 3),CircularString (3.1 3.3, 3.3 3.5, 3.4 3.7, 3.7 3.3, 3.1 3.3))",
+ )
fid += 1
- self.check_geom(curve_polygon, fid, 'CurvePolygon(CompoundCurve (CircularString (-1 -5, 5 -7, 17 -6), (17 -6, 13 4), CircularString (13 4, 10 0.1, 7 2.20, 5 4, 1 2),(1 2, -1 -5)))')
+ self.check_geom(
+ curve_polygon,
+ fid,
+ "CurvePolygon(CompoundCurve (CircularString (-1 -5, 5 -7, 17 -6), (17 -6, 13 4), CircularString (13 4, 10 0.1, 7 2.20, 5 4, 1 2),(1 2, -1 -5)))",
+ )
fid += 1
- self.check_geom(curve_polygon, fid, 'CurvePolygon(CircularString (0 0, 30 0, 30 20, 0 30, 0 0), CompoundCurve ((13 10, 17 2), CircularString (17 2, 1 1, 13 10)))')
+ self.check_geom(
+ curve_polygon,
+ fid,
+ "CurvePolygon(CircularString (0 0, 30 0, 30 20, 0 30, 0 0), CompoundCurve ((13 10, 17 2), CircularString (17 2, 1 1, 13 10)))",
+ )
fid += 1
- self.check_geom(curve_polygon, fid, 'CurvePolygon(CircularString (0 0, 30 0, 30 20, 0 30, 0 0), (13 10, 17 2, 1 1, 13 10))')
+ self.check_geom(
+ curve_polygon,
+ fid,
+ "CurvePolygon(CircularString (0 0, 30 0, 30 20, 0 30, 0 0), (13 10, 17 2, 1 1, 13 10))",
+ )
fid += 1
- self.check_geom(curve_polygon, fid, 'CurvePolygon((0 0, 30 0, 30 20, 0 30, 0 0), CircularString (1 3, 3 5, 4 7, 7 3, 1 3))')
+ self.check_geom(
+ curve_polygon,
+ fid,
+ "CurvePolygon((0 0, 30 0, 30 20, 0 30, 0 0), CircularString (1 3, 3 5, 4 7, 7 3, 1 3))",
+ )
fid += 1
# Reverse orientation of outer ring
- self.check_geom(curve_polygon, fid, 'CurvePolygon((0 0, 0 30, 30 20, 30 0, 0 0), CircularString (1 3, 3 5, 4 7, 7 3, 1 3))', 'CurvePolygon((0 0, 30 0, 30 20, 0 30, 0 0), CircularString (1 3, 3 5, 4 7, 7 3, 1 3))')
+ self.check_geom(
+ curve_polygon,
+ fid,
+ "CurvePolygon((0 0, 0 30, 30 20, 30 0, 0 0), CircularString (1 3, 3 5, 4 7, 7 3, 1 3))",
+ "CurvePolygon((0 0, 30 0, 30 20, 0 30, 0 0), CircularString (1 3, 3 5, 4 7, 7 3, 1 3))",
+ )
fid += 1
# Reverse orientation of outer ring
- self.check_geom(curve_polygon, fid, 'CurvePolygon( CompoundCurve ((0 0, 0 1, 1 1),(1 1,0 0)))', 'CurvePolygon (CompoundCurve ((0 0, 1 1),(1 1, 0 1, 0 0)))')
+ self.check_geom(
+ curve_polygon,
+ fid,
+ "CurvePolygon( CompoundCurve ((0 0, 0 1, 1 1),(1 1,0 0)))",
+ "CurvePolygon (CompoundCurve ((0 0, 1 1),(1 1, 0 1, 0 0)))",
+ )
fid += 1
curve_polygon_z = QgsVectorLayer(
- self.dbconn + ' sslmode=disable key=\'pk\' srid=5698 type=CurvePolygonZ table="QGIS"."EDIT_SURFACEZ_DATA" (GEOM) sql=',
- 'curve_polygon_z', 'oracle')
+ self.dbconn
+ + ' sslmode=disable key=\'pk\' srid=5698 type=CurvePolygonZ table="QGIS"."EDIT_SURFACEZ_DATA" (GEOM) sql=',
+ "curve_polygon_z",
+ "oracle",
+ )
self.assertTrue(curve_polygon_z.isValid())
# There is no way to build a valid 3D curve polygon (even with make3d from the valid 2D one)
# we get ora-13033 although everything is OK in sdo_elem_array ...
- self.check_geom(curve_polygon_z, fid, 'CurvePolygonZ (CircularStringZ (6.76923076923076916 22.82875364393326834 1, -4.44413825931788598 11.61538461538461497 2, 6.76923076923076916 0.40201558683595984 3, 17.98259979777942519 11.61538461538461497 4, 6.76923076923076916 22.82875364393326834 1))', check_valid=False)
+ self.check_geom(
+ curve_polygon_z,
+ fid,
+ "CurvePolygonZ (CircularStringZ (6.76923076923076916 22.82875364393326834 1, -4.44413825931788598 11.61538461538461497 2, 6.76923076923076916 0.40201558683595984 3, 17.98259979777942519 11.61538461538461497 4, 6.76923076923076916 22.82875364393326834 1))",
+ check_valid=False,
+ )
fid += 1
- self.check_geom(curve_polygon_z, fid, 'CurvePolygonZ (CircularStringZ (1 3 1, 7 3 2, 4 7 3, 3 5 2, 1 3 1))', check_valid=False)
+ self.check_geom(
+ curve_polygon_z,
+ fid,
+ "CurvePolygonZ (CircularStringZ (1 3 1, 7 3 2, 4 7 3, 3 5 2, 1 3 1))",
+ check_valid=False,
+ )
fid += 1
- self.check_geom(curve_polygon_z, fid, 'CurvePolygonZ (CircularStringZ (1 3 1, 7 3 2, 4 7 3, 3 5 4, 1 3 1),CircularStringZ (3.1 3.3 1, 3.3 3.5 2, 3.4 3.7 3, 3.7 3.3 4, 3.1 3.3 1))', check_valid=False)
+ self.check_geom(
+ curve_polygon_z,
+ fid,
+ "CurvePolygonZ (CircularStringZ (1 3 1, 7 3 2, 4 7 3, 3 5 4, 1 3 1),CircularStringZ (3.1 3.3 1, 3.3 3.5 2, 3.4 3.7 3, 3.7 3.3 4, 3.1 3.3 1))",
+ check_valid=False,
+ )
fid += 1
- self.check_geom(curve_polygon_z, fid, 'CurvePolygonZ(CompoundCurveZ (CircularStringZ (-1 -5 1, 5 -7 2, 17 -6 3), (17 -6 3, 13 4 4), CircularStringZ (13 4 4, 10 0.1 5, 7 2.20 6, 5 4 7, 1 2 8),(1 2 8, -1 -5 1)))', check_valid=False)
+ self.check_geom(
+ curve_polygon_z,
+ fid,
+ "CurvePolygonZ(CompoundCurveZ (CircularStringZ (-1 -5 1, 5 -7 2, 17 -6 3), (17 -6 3, 13 4 4), CircularStringZ (13 4 4, 10 0.1 5, 7 2.20 6, 5 4 7, 1 2 8),(1 2 8, -1 -5 1)))",
+ check_valid=False,
+ )
fid += 1
- self.check_geom(curve_polygon_z, fid, 'CurvePolygonZ(CircularStringZ (0 0 1, 30 0 2, 30 20 3, 0 30 4, 0 0 5), CompoundCurveZ ((13 10 1, 17 2 3), CircularStringZ (17 2 3, 1 1 5, 13 10 1)))', check_valid=False)
+ self.check_geom(
+ curve_polygon_z,
+ fid,
+ "CurvePolygonZ(CircularStringZ (0 0 1, 30 0 2, 30 20 3, 0 30 4, 0 0 5), CompoundCurveZ ((13 10 1, 17 2 3), CircularStringZ (17 2 3, 1 1 5, 13 10 1)))",
+ check_valid=False,
+ )
fid += 1
multi_surface = QgsVectorLayer(
- self.dbconn + ' sslmode=disable key=\'pk\' srid=3857 type=MultiSurface table="QGIS"."EDIT_SURFACE_DATA" (GEOM) sql=',
- 'multi_surface', 'oracle')
+ self.dbconn
+ + ' sslmode=disable key=\'pk\' srid=3857 type=MultiSurface table="QGIS"."EDIT_SURFACE_DATA" (GEOM) sql=',
+ "multi_surface",
+ "oracle",
+ )
self.assertTrue(multi_surface.isValid())
- self.check_geom(multi_surface, fid, 'MultiSurface (CurvePolygon (CircularString (1 3, 7 3, 4 7, 3 5, 1 3)),CurvePolygon (CircularString (11 3, 17 3, 14 7, 13 5, 11 3)))')
+ self.check_geom(
+ multi_surface,
+ fid,
+ "MultiSurface (CurvePolygon (CircularString (1 3, 7 3, 4 7, 3 5, 1 3)),CurvePolygon (CircularString (11 3, 17 3, 14 7, 13 5, 11 3)))",
+ )
fid += 1
- self.check_geom(multi_surface, fid, 'MultiSurface (CurvePolygon (CircularString (1 3, 7 3, 4 7, 3 5, 1 3)))')
+ self.check_geom(
+ multi_surface,
+ fid,
+ "MultiSurface (CurvePolygon (CircularString (1 3, 7 3, 4 7, 3 5, 1 3)))",
+ )
fid += 1
- self.check_geom(multi_surface, fid, 'MultiSurface (CurvePolygon(CompoundCurve (CircularString (-1 -5, 5 -7, 17 -6), (17 -6, -1 -5))), CurvePolygon (CircularString (1 3, 7 3, 4 7, 3 5, 1 3)))')
+ self.check_geom(
+ multi_surface,
+ fid,
+ "MultiSurface (CurvePolygon(CompoundCurve (CircularString (-1 -5, 5 -7, 17 -6), (17 -6, -1 -5))), CurvePolygon (CircularString (1 3, 7 3, 4 7, 3 5, 1 3)))",
+ )
fid += 1
- wkt = 'MultiSurface (((0 0, 1 0, 1 1, 0 0)),((100 100, 101 100, 101 101, 100 100)))'
- self.check_geom(multi_surface, fid, wkt, wkt.replace('MultiSurface', 'MultiPolygon'))
+ wkt = "MultiSurface (((0 0, 1 0, 1 1, 0 0)),((100 100, 101 100, 101 101, 100 100)))"
+ self.check_geom(
+ multi_surface, fid, wkt, wkt.replace("MultiSurface", "MultiPolygon")
+ )
fid += 1
# Outer ring in clockwise order --> reversed on writing
- self.check_geom(multi_surface, fid, 'MultiSurface( Polygon ((0 0, 0 1, 1 1, 0 0)))', 'MultiPolygon (((0 0, 1 1, 0 1, 0 0)))')
+ self.check_geom(
+ multi_surface,
+ fid,
+ "MultiSurface( Polygon ((0 0, 0 1, 1 1, 0 0)))",
+ "MultiPolygon (((0 0, 1 1, 0 1, 0 0)))",
+ )
fid += 1
# Outer ring in clockwise order --> reversed on writing. Inner ring in clockwise order --> unmodified
- self.check_geom(multi_surface, fid, 'MultiSurface(Polygon ((0 0, 0 1, 1 1, 0 0),(0.1 0.2, 0.1 0.9, 0.7 0.9, 0.1 0.2)))', 'MultiPolygon (((0 0, 1 1, 0 1, 0 0),(0.1 0.2, 0.1 0.9, 0.7 0.9, 0.1 0.2)))')
+ self.check_geom(
+ multi_surface,
+ fid,
+ "MultiSurface(Polygon ((0 0, 0 1, 1 1, 0 0),(0.1 0.2, 0.1 0.9, 0.7 0.9, 0.1 0.2)))",
+ "MultiPolygon (((0 0, 1 1, 0 1, 0 0),(0.1 0.2, 0.1 0.9, 0.7 0.9, 0.1 0.2)))",
+ )
fid += 1
# Inner ring in counterclockwise order --> reversed on writing. Outer ring in counterclockwise order --> unmodified
- self.check_geom(multi_surface, fid, 'MultiSurface(Polygon ((0 0, 1 1, 0 1, 0 0),(0.1 0.2, 0.7 0.9, 0.1 0.9, 0.1 0.2)))', 'MultiPolygon (((0 0, 1 1, 0 1, 0 0),(0.1 0.2, 0.1 0.9, 0.7 0.9, 0.1 0.2)))')
+ self.check_geom(
+ multi_surface,
+ fid,
+ "MultiSurface(Polygon ((0 0, 1 1, 0 1, 0 0),(0.1 0.2, 0.7 0.9, 0.1 0.9, 0.1 0.2)))",
+ "MultiPolygon (((0 0, 1 1, 0 1, 0 0),(0.1 0.2, 0.1 0.9, 0.7 0.9, 0.1 0.2)))",
+ )
fid += 1
- self.check_geom(multi_surface, fid, 'MultiSurface (Polygon ((0 0, 1 0, 1 1, 0 0)),CurvePolygon (CompoundCurve (CircularString (100 100, 105.5 99.5, 101 100, 101.5 100.5, 101 101),(101 101, 100 100))))')
+ self.check_geom(
+ multi_surface,
+ fid,
+ "MultiSurface (Polygon ((0 0, 1 0, 1 1, 0 0)),CurvePolygon (CompoundCurve (CircularString (100 100, 105.5 99.5, 101 100, 101.5 100.5, 101 101),(101 101, 100 100))))",
+ )
fid += 1
- self.check_geom(multi_surface, fid, 'MultiSurface (CurvePolygon (CompoundCurve (CircularString (100 100, 101 100, 101 101),(101 101, 100 100))),Polygon ((0 0, 1 0, 1 1, 0 0)))')
+ self.check_geom(
+ multi_surface,
+ fid,
+ "MultiSurface (CurvePolygon (CompoundCurve (CircularString (100 100, 101 100, 101 101),(101 101, 100 100))),Polygon ((0 0, 1 0, 1 1, 0 0)))",
+ )
fid += 1
- self.check_geom(multi_surface, fid, 'MultiSurface(Polygon((100 100, 101 100, 101 101, 100 100)), CurvePolygon((0 0, 30 0, 30 20, 0 30, 0 0), CircularString (1 3, 3 5, 4 7, 7 3, 1 3)))')
+ self.check_geom(
+ multi_surface,
+ fid,
+ "MultiSurface(Polygon((100 100, 101 100, 101 101, 100 100)), CurvePolygon((0 0, 30 0, 30 20, 0 30, 0 0), CircularString (1 3, 3 5, 4 7, 7 3, 1 3)))",
+ )
fid += 1
multi_surface_z = QgsVectorLayer(
- self.dbconn + ' sslmode=disable key=\'pk\' srid=5698 type=MultiSurfaceZ table="QGIS"."EDIT_SURFACEZ_DATA" (GEOM) sql=',
- 'multi_surface_z', 'oracle')
+ self.dbconn
+ + ' sslmode=disable key=\'pk\' srid=5698 type=MultiSurfaceZ table="QGIS"."EDIT_SURFACEZ_DATA" (GEOM) sql=',
+ "multi_surface_z",
+ "oracle",
+ )
self.assertTrue(multi_surface_z.isValid())
# ora-54530 : 3D compound lines are invalid since 11.2.0.3 : https://support.oracle.com/knowledge/Oracle%20Database%20Products/1446335_1.html
- self.check_geom(multi_surface_z, fid, 'MultiSurfaceZ (CurvePolygonZ (CircularStringZ (1 3 1, 7 3 2, 4 7 3, 3 5 4, 1 3 1)),CurvePolygonZ (CircularStringZ (11 3 1, 17 3 2, 14 7 3, 13 5 4, 11 3 1)))', check_valid=False)
+ self.check_geom(
+ multi_surface_z,
+ fid,
+ "MultiSurfaceZ (CurvePolygonZ (CircularStringZ (1 3 1, 7 3 2, 4 7 3, 3 5 4, 1 3 1)),CurvePolygonZ (CircularStringZ (11 3 1, 17 3 2, 14 7 3, 13 5 4, 11 3 1)))",
+ check_valid=False,
+ )
fid += 1
- self.check_geom(multi_surface_z, fid, 'MultiSurfaceZ (CurvePolygonZ (CircularStringZ (1 3 1, 7 3 2, 4 7 3, 3 5 4, 1 3 1)))', check_valid=False)
+ self.check_geom(
+ multi_surface_z,
+ fid,
+ "MultiSurfaceZ (CurvePolygonZ (CircularStringZ (1 3 1, 7 3 2, 4 7 3, 3 5 4, 1 3 1)))",
+ check_valid=False,
+ )
fid += 1
- self.check_geom(multi_surface_z, fid, 'MultiSurfaceZ (CurvePolygonZ(CompoundCurveZ (CircularStringZ (-1 -5 1, 5 -7 2, 17 -6 3), (17 -6 3, -1 -5 1))), CurvePolygonZ (CircularStringZ (1 3 1, 7 3 2, 4 7 3, 3 5 4, 1 3 1)))', check_valid=False)
+ self.check_geom(
+ multi_surface_z,
+ fid,
+ "MultiSurfaceZ (CurvePolygonZ(CompoundCurveZ (CircularStringZ (-1 -5 1, 5 -7 2, 17 -6 3), (17 -6 3, -1 -5 1))), CurvePolygonZ (CircularStringZ (1 3 1, 7 3 2, 4 7 3, 3 5 4, 1 3 1)))",
+ check_valid=False,
+ )
fid += 1
def testFeatureCount(self):
- self.execSQLCommand('CREATE OR REPLACE VIEW QGIS.VIEW_POLY_DATA AS SELECT * FROM QGIS.POLY_DATA')
- self.execSQLCommand("BEGIN DBMS_STATS.GATHER_TABLE_STATS('QGIS', 'SOME_DATA'); END;")
-
- view_layer = QgsVectorLayer(self.dbconn + ' sslmode=disable table="QGIS"."VIEW_POLY_DATA" key=\'pk\'',
- 'test', 'oracle')
+ self.execSQLCommand(
+ "CREATE OR REPLACE VIEW QGIS.VIEW_POLY_DATA AS SELECT * FROM QGIS.POLY_DATA"
+ )
+ self.execSQLCommand(
+ "BEGIN DBMS_STATS.GATHER_TABLE_STATS('QGIS', 'SOME_DATA'); END;"
+ )
+
+ view_layer = QgsVectorLayer(
+ self.dbconn + ' sslmode=disable table="QGIS"."VIEW_POLY_DATA" key=\'pk\'',
+ "test",
+ "oracle",
+ )
self.assertTrue(view_layer.isValid())
self.assertGreater(view_layer.featureCount(), 0)
self.assertTrue(view_layer.setSubsetString('"pk" = 5'))
self.assertGreaterEqual(view_layer.featureCount(), 0)
- view_layer_estimated = QgsVectorLayer(self.dbconn + ' sslmode=disable estimatedmetadata=true table="QGIS"."VIEW_POLY_DATA" key=\'pk\'',
- 'test', 'oracle')
+ view_layer_estimated = QgsVectorLayer(
+ self.dbconn
+ + ' sslmode=disable estimatedmetadata=true table="QGIS"."VIEW_POLY_DATA" key=\'pk\'',
+ "test",
+ "oracle",
+ )
self.assertTrue(view_layer_estimated.isValid())
self.assertGreater(view_layer_estimated.featureCount(), 0)
self.assertTrue(view_layer_estimated.setSubsetString('"pk" = 5'))
@@ -787,16 +1354,20 @@ def testFeatureCount(self):
self.assertGreater(self.vl.featureCount(), 0)
self.assertTrue(self.vl.setSubsetString('"pk" = 3'))
self.assertGreaterEqual(self.vl.featureCount(), 1)
- self.assertTrue(self.vl.setSubsetString(''))
-
- vl_estimated = QgsVectorLayer(self.dbconn + ' sslmode=disable estimatedmetadata=true table="QGIS"."SOME_DATA"',
- 'test', 'oracle')
+ self.assertTrue(self.vl.setSubsetString(""))
+
+ vl_estimated = QgsVectorLayer(
+ self.dbconn
+ + ' sslmode=disable estimatedmetadata=true table="QGIS"."SOME_DATA"',
+ "test",
+ "oracle",
+ )
self.assertTrue(vl_estimated.isValid())
self.assertGreater(vl_estimated.featureCount(), 0)
self.assertTrue(vl_estimated.setSubsetString('"pk" = 3'))
self.assertGreaterEqual(vl_estimated.featureCount(), 1)
- self.execSQLCommand('DROP VIEW QGIS.VIEW_POLY_DATA')
+ self.execSQLCommand("DROP VIEW QGIS.VIEW_POLY_DATA")
def testNestedInsert(self):
tg = QgsTransactionGroup()
@@ -804,7 +1375,7 @@ def testNestedInsert(self):
self.vl.startEditing()
it = self.vl.getFeatures()
f = next(it)
- f['pk'] = NULL
+ f["pk"] = NULL
self.vl.addFeature(f) # Should not deadlock during an active iteration
f = next(it)
self.vl.rollBack()
@@ -833,7 +1404,11 @@ def testTimeout(self):
def testTransactionDirtyName(self):
# create a vector layer based on oracle
vl = QgsVectorLayer(
- self.dbconn + ' sslmode=disable key=\'pk\' srid=4326 type=POLYGON table="QGIS"."SOME_POLY_DATA" (GEOM) sql=', 'test', 'oracle')
+ self.dbconn
+ + ' sslmode=disable key=\'pk\' srid=4326 type=POLYGON table="QGIS"."SOME_POLY_DATA" (GEOM) sql=',
+ "test",
+ "oracle",
+ )
self.assertTrue(vl.isValid())
# prepare a project with transactions enabled
@@ -857,7 +1432,11 @@ def testTransactionDirtyName(self):
def testTransactionDirty(self):
# create a vector layer based on oracle
vl = QgsVectorLayer(
- self.dbconn + ' sslmode=disable key=\'pk\' srid=4326 type=POLYGON table="QGIS"."SOME_POLY_DATA" (GEOM) sql=', 'test', 'oracle')
+ self.dbconn
+ + ' sslmode=disable key=\'pk\' srid=4326 type=POLYGON table="QGIS"."SOME_POLY_DATA" (GEOM) sql=',
+ "test",
+ "oracle",
+ )
self.assertTrue(vl.isValid())
# prepare a project with transactions enabled
@@ -867,7 +1446,7 @@ def testTransactionDirty(self):
vl.startEditing()
# check that the feature used for testing is ok
- ft0 = vl.getFeatures('pk=1')
+ ft0 = vl.getFeatures("pk=1")
f = QgsFeature()
self.assertTrue(ft0.nextFeature(f))
@@ -877,10 +1456,10 @@ def testTransactionDirty(self):
self.assertTrue(tr.executeSql(sql, True)[0])
# check that the pk of the feature has been changed
- ft = vl.getFeatures('pk=1')
+ ft = vl.getFeatures("pk=1")
self.assertFalse(ft.nextFeature(f))
- ft = vl.getFeatures('pk=33')
+ ft = vl.getFeatures("pk=33")
self.assertTrue(ft.nextFeature(f))
# underlying data has been modified but the layer is not tagged as
@@ -891,14 +1470,14 @@ def testTransactionDirty(self):
vl.undoStack().undo()
# check that the original feature with pk is back
- ft0 = vl.getFeatures('pk=1')
+ ft0 = vl.getFeatures("pk=1")
self.assertTrue(ft0.nextFeature(f))
# redo
vl.undoStack().redo()
# check that the pk of the feature has been changed
- ft1 = vl.getFeatures('pk=1')
+ ft1 = vl.getFeatures("pk=1")
self.assertFalse(ft1.nextFeature(f))
# rollback
@@ -907,8 +1486,11 @@ def testTransactionDirty(self):
def testTransactionTuple(self):
# create a vector layer based on oracle
vl = QgsVectorLayer(
- self.dbconn + ' sslmode=disable key=\'pk\' srid=4326 type=POLYGON table="QGIS"."SOME_POLY_DATA" (GEOM) sql=',
- 'test', 'oracle')
+ self.dbconn
+ + ' sslmode=disable key=\'pk\' srid=4326 type=POLYGON table="QGIS"."SOME_POLY_DATA" (GEOM) sql=',
+ "test",
+ "oracle",
+ )
self.assertTrue(vl.isValid())
# prepare a project with transactions enabled
@@ -928,8 +1510,11 @@ def testTransactionTuple(self):
def testIdentityCommit(self):
# create a vector layer based on oracle
vl = QgsVectorLayer(
- self.dbconn + ' sslmode=disable key=\'pk\' srid=4326 type=POINT table="QGIS"."POINT_DATA_IDENTITY" (GEOM) sql=',
- 'test', 'oracle')
+ self.dbconn
+ + ' sslmode=disable key=\'pk\' srid=4326 type=POINT table="QGIS"."POINT_DATA_IDENTITY" (GEOM) sql=',
+ "test",
+ "oracle",
+ )
self.assertTrue(vl.isValid())
features = [f for f in vl.getFeatures()]
@@ -948,15 +1533,28 @@ def testGetFeatureFidInvalid(self):
Get feature with an invalid fid
https://github.com/qgis/QGIS/issues/31626
"""
- self.execSQLCommand('DROP TABLE "QGIS"."TABLE_QGIS_ISSUE_FLOAT_KEY"', ignore_errors=True)
- self.execSQLCommand("""CREATE TABLE "QGIS"."TABLE_QGIS_ISSUE_FLOAT_KEY" (CODE NUMBER PRIMARY KEY, DESCRIPTION VARCHAR2(25))""")
- self.execSQLCommand("""INSERT INTO "QGIS"."TABLE_QGIS_ISSUE_FLOAT_KEY" VALUES(1000,'Desc for 1st record')""")
- self.execSQLCommand("""INSERT INTO "QGIS"."TABLE_QGIS_ISSUE_FLOAT_KEY" VALUES(2000,'Desc for 2nd record')""")
- self.execSQLCommand("""CREATE OR REPLACE VIEW "QGIS"."VIEW_QGIS_ISSUE_FLOAT_KEY" AS SELECT * FROM "QGIS"."TABLE_QGIS_ISSUE_FLOAT_KEY" """)
+ self.execSQLCommand(
+ 'DROP TABLE "QGIS"."TABLE_QGIS_ISSUE_FLOAT_KEY"', ignore_errors=True
+ )
+ self.execSQLCommand(
+ """CREATE TABLE "QGIS"."TABLE_QGIS_ISSUE_FLOAT_KEY" (CODE NUMBER PRIMARY KEY, DESCRIPTION VARCHAR2(25))"""
+ )
+ self.execSQLCommand(
+ """INSERT INTO "QGIS"."TABLE_QGIS_ISSUE_FLOAT_KEY" VALUES(1000,'Desc for 1st record')"""
+ )
+ self.execSQLCommand(
+ """INSERT INTO "QGIS"."TABLE_QGIS_ISSUE_FLOAT_KEY" VALUES(2000,'Desc for 2nd record')"""
+ )
+ self.execSQLCommand(
+ """CREATE OR REPLACE VIEW "QGIS"."VIEW_QGIS_ISSUE_FLOAT_KEY" AS SELECT * FROM "QGIS"."TABLE_QGIS_ISSUE_FLOAT_KEY" """
+ )
vl = QgsVectorLayer(
- self.dbconn + ' sslmode=disable key=\'CODE\' table="QGIS"."VIEW_QGIS_ISSUE_FLOAT_KEY" sql=',
- 'test', 'oracle')
+ self.dbconn
+ + ' sslmode=disable key=\'CODE\' table="QGIS"."VIEW_QGIS_ISSUE_FLOAT_KEY" sql=',
+ "test",
+ "oracle",
+ )
# feature are not loaded yet, mapping between CODE and fid is not built so feature
# is invalid
@@ -976,28 +1574,44 @@ def testDeterminePKOnView(self):
"""
self.execSQLCommand('DROP TABLE "QGIS"."TABLE_TESTPKS"', ignore_errors=True)
- self.execSQLCommand("""CREATE TABLE "QGIS"."TABLE_TESTPKS" (pk1 INTEGER, DESCRIPTION VARCHAR2(25), pk2 NUMBER, CONSTRAINT cons_pk PRIMARY KEY(pk1, pk2))""")
- self.execSQLCommand("""INSERT INTO "QGIS"."TABLE_TESTPKS" VALUES(1000,'Desc for 1st record', 1)""")
- self.execSQLCommand("""INSERT INTO "QGIS"."TABLE_TESTPKS" VALUES(2000,'Desc for 2nd record', 2)""")
- self.execSQLCommand("""CREATE OR REPLACE VIEW "QGIS"."VIEW_TESTPKS" AS SELECT * FROM "QGIS"."TABLE_TESTPKS" """)
+ self.execSQLCommand(
+ """CREATE TABLE "QGIS"."TABLE_TESTPKS" (pk1 INTEGER, DESCRIPTION VARCHAR2(25), pk2 NUMBER, CONSTRAINT cons_pk PRIMARY KEY(pk1, pk2))"""
+ )
+ self.execSQLCommand(
+ """INSERT INTO "QGIS"."TABLE_TESTPKS" VALUES(1000,'Desc for 1st record', 1)"""
+ )
+ self.execSQLCommand(
+ """INSERT INTO "QGIS"."TABLE_TESTPKS" VALUES(2000,'Desc for 2nd record', 2)"""
+ )
+ self.execSQLCommand(
+ """CREATE OR REPLACE VIEW "QGIS"."VIEW_TESTPKS" AS SELECT * FROM "QGIS"."TABLE_TESTPKS" """
+ )
vl = QgsVectorLayer(
self.dbconn + ' sslmode=disable table="QGIS"."TABLE_TESTPKS" sql=',
- 'test', 'oracle')
+ "test",
+ "oracle",
+ )
self.assertEqual(vl.dataProvider().pkAttributeIndexes(), [0, 2])
vl = QgsVectorLayer(
self.dbconn + ' sslmode=disable table="QGIS"."VIEW_TESTPKS" sql=',
- 'test', 'oracle')
+ "test",
+ "oracle",
+ )
self.assertEqual(vl.dataProvider().pkAttributeIndexes(), [])
- self.execSQLCommand("""ALTER VIEW VIEW_TESTPKS ADD CONSTRAINT const_view_pks PRIMARY KEY (pk1,pk2) DISABLE""")
+ self.execSQLCommand(
+ """ALTER VIEW VIEW_TESTPKS ADD CONSTRAINT const_view_pks PRIMARY KEY (pk1,pk2) DISABLE"""
+ )
vl = QgsVectorLayer(
self.dbconn + ' sslmode=disable table="QGIS"."VIEW_TESTPKS" sql=',
- 'test', 'oracle')
+ "test",
+ "oracle",
+ )
self.assertEqual(vl.dataProvider().pkAttributeIndexes(), [0, 2])
@@ -1005,8 +1619,14 @@ def getGeneratedColumnsData(self):
"""
return a tuple with the generated column test layer and the expected generated value
"""
- return (QgsVectorLayer(self.dbconn + ' sslmode=disable table="QGIS"."GENERATED_COLUMNS"', 'test', 'oracle'),
- """'test:'||TO_CHAR("pk")""")
+ return (
+ QgsVectorLayer(
+ self.dbconn + ' sslmode=disable table="QGIS"."GENERATED_COLUMNS"',
+ "test",
+ "oracle",
+ ),
+ """'test:'||TO_CHAR("pk")""",
+ )
def testEvaluateDefaultValues(self):
"""
@@ -1015,11 +1635,15 @@ def testEvaluateDefaultValues(self):
"""
self.execSQLCommand('DROP TABLE "QGIS"."TEST_EVAL_EXPR"', ignore_errors=True)
- self.execSQLCommand("""CREATE TABLE "QGIS"."TEST_EVAL_EXPR" (pk INTEGER, "name" VARCHAR2(100) DEFAULT 'qgis')""")
+ self.execSQLCommand(
+ """CREATE TABLE "QGIS"."TEST_EVAL_EXPR" (pk INTEGER, "name" VARCHAR2(100) DEFAULT 'qgis')"""
+ )
vl = QgsVectorLayer(
self.dbconn + ' sslmode=disable table="QGIS"."TEST_EVAL_EXPR" sql=',
- 'test', 'oracle')
+ "test",
+ "oracle",
+ )
self.assertTrue(vl.isValid())
@@ -1028,35 +1652,49 @@ def testEvaluateDefaultValues(self):
feat1.setAttributes([1, "'qgis'"])
feat2 = QgsFeature(vl.fields())
- feat2.setAttributes([2, 'test'])
+ feat2.setAttributes([2, "test"])
self.assertTrue(vl.dataProvider().addFeatures([feat1, feat2]))
attributes = [feat.attributes() for feat in vl.getFeatures()]
- self.assertEqual(attributes, [[1, 'qgis'], [2, 'test']])
+ self.assertEqual(attributes, [[1, "qgis"], [2, "test"]])
- vl.dataProvider().setProviderProperty(QgsDataProvider.ProviderProperty.EvaluateDefaultValues, True)
+ vl.dataProvider().setProviderProperty(
+ QgsDataProvider.ProviderProperty.EvaluateDefaultValues, True
+ )
# feature with already evaluated default value
feat1 = QgsFeature(vl.fields())
- feat1.setAttributes([3, 'qgis'])
+ feat1.setAttributes([3, "qgis"])
feat2 = QgsFeature(vl.fields())
- feat2.setAttributes([4, 'test'])
+ feat2.setAttributes([4, "test"])
self.assertTrue(vl.dataProvider().addFeatures([feat1, feat2]))
attributes = [feat.attributes() for feat in vl.getFeatures()]
- self.assertEqual(attributes, [[1, 'qgis'], [2, 'test'], [3, 'qgis'], [4, 'test']])
+ self.assertEqual(
+ attributes, [[1, "qgis"], [2, "test"], [3, "qgis"], [4, "test"]]
+ )
def testCreateEmptyLayer(self):
# cleanup (it seems overwrite option doesn't clean the sdo_geom_metadata table)
self.execSQLCommand('DROP TABLE "QGIS"."EMPTY_LAYER"', ignore_errors=True)
- self.execSQLCommand("DELETE FROM user_sdo_geom_metadata where TABLE_NAME='EMPTY_LAYER'", ignore_errors=True)
-
- uri = self.dbconn + "srid=4326 type=POINT table=\"EMPTY_LAYER\" (GEOM)"
- exporter = QgsVectorLayerExporter(uri=uri, provider='oracle', fields=QgsFields(), geometryType=QgsWkbTypes.Type.Point, crs=QgsCoordinateReferenceSystem('EPSG:4326'), overwrite=True)
+ self.execSQLCommand(
+ "DELETE FROM user_sdo_geom_metadata where TABLE_NAME='EMPTY_LAYER'",
+ ignore_errors=True,
+ )
+
+ uri = self.dbconn + 'srid=4326 type=POINT table="EMPTY_LAYER" (GEOM)'
+ exporter = QgsVectorLayerExporter(
+ uri=uri,
+ provider="oracle",
+ fields=QgsFields(),
+ geometryType=QgsWkbTypes.Type.Point,
+ crs=QgsCoordinateReferenceSystem("EPSG:4326"),
+ overwrite=True,
+ )
self.assertEqual(exporter.errorCount(), 0)
self.assertEqual(exporter.errorCode(), 0)
@@ -1065,7 +1703,11 @@ def testCreateEmptyLayer(self):
# check that metadata table has been correctly populated
query = QSqlQuery(self.conn)
- self.assertTrue(query.exec("SELECT column_name, srid FROM user_sdo_geom_metadata WHERE table_name = 'EMPTY_LAYER'"))
+ self.assertTrue(
+ query.exec(
+ "SELECT column_name, srid FROM user_sdo_geom_metadata WHERE table_name = 'EMPTY_LAYER'"
+ )
+ )
self.assertTrue(query.next())
self.assertEqual(query.value(0), "GEOM")
# Cannot work with proj version < 7 because it cannot identify properly EPSG:4326
@@ -1077,21 +1719,32 @@ def testCreateEmptyLayer(self):
# no feature, so we cannot guess the geometry type, so the layer is not valid
# but srid is set for provider in case you want to add a feature even if the layer is invalid!
# layer sourceCrs is empty because the layer is not considered spatial (not know geometry type)
- vl = QgsVectorLayer(self.dbconn + ' sslmode=disable table="QGIS"."EMPTY_LAYER" (GEOM) sql=', 'test', 'oracle')
+ vl = QgsVectorLayer(
+ self.dbconn + ' sslmode=disable table="QGIS"."EMPTY_LAYER" (GEOM) sql=',
+ "test",
+ "oracle",
+ )
self.assertFalse(vl.isValid())
self.assertEqual(vl.dataProvider().sourceCrs().authid(), "EPSG:4326")
# so we set the geometry type
- vl = QgsVectorLayer(self.dbconn + ' sslmode=disable type=POINT table="QGIS"."EMPTY_LAYER" (GEOM) sql=', 'test', 'oracle')
+ vl = QgsVectorLayer(
+ self.dbconn
+ + ' sslmode=disable type=POINT table="QGIS"."EMPTY_LAYER" (GEOM) sql=',
+ "test",
+ "oracle",
+ )
self.assertTrue(vl.isValid())
self.assertEqual(vl.sourceCrs().authid(), "EPSG:4326")
f = QgsFeature(vl.fields())
- f.setGeometry(QgsGeometry.fromWkt('POINT (43.5 1.42)'))
+ f.setGeometry(QgsGeometry.fromWkt("POINT (43.5 1.42)"))
vl.dataProvider().addFeatures([f])
query = QSqlQuery(self.conn)
- self.assertTrue(query.exec('SELECT "l"."GEOM"."SDO_SRID" from "QGIS"."EMPTY_LAYER" "l"'))
+ self.assertTrue(
+ query.exec('SELECT "l"."GEOM"."SDO_SRID" from "QGIS"."EMPTY_LAYER" "l"')
+ )
self.assertTrue(query.next())
# Cannot work with proj version < 7 because it cannot identify properly EPSG:4326
# TODO remove this when PROJ will be >= 7
@@ -1100,7 +1753,11 @@ def testCreateEmptyLayer(self):
query.finish()
# now we can autodetect geom type and srid
- vl = QgsVectorLayer(self.dbconn + ' sslmode=disable table="QGIS"."EMPTY_LAYER" (GEOM) sql=', 'test', 'oracle')
+ vl = QgsVectorLayer(
+ self.dbconn + ' sslmode=disable table="QGIS"."EMPTY_LAYER" (GEOM) sql=',
+ "test",
+ "oracle",
+ )
self.assertTrue(vl.isValid())
# Cannot work with proj version < 7 because it cannot identify properly EPSG:4326
# TODO remove this when PROJ will be >= 7
@@ -1118,13 +1775,24 @@ def testCreateAspatialLayer(self):
fields = QgsFields()
fields.append(QgsField("INTEGER_T", QVariant.Int))
- uri = self.dbconn + "table=\"ASPATIAL_LAYER\""
- exporter = QgsVectorLayerExporter(uri=uri, provider='oracle', fields=fields, geometryType=QgsWkbTypes.Type.NoGeometry, crs=QgsCoordinateReferenceSystem(), overwrite=True)
+ uri = self.dbconn + 'table="ASPATIAL_LAYER"'
+ exporter = QgsVectorLayerExporter(
+ uri=uri,
+ provider="oracle",
+ fields=fields,
+ geometryType=QgsWkbTypes.Type.NoGeometry,
+ crs=QgsCoordinateReferenceSystem(),
+ overwrite=True,
+ )
self.assertEqual(exporter.errorCount(), 0)
self.assertEqual(exporter.errorCode(), 0)
self.execSQLCommand('SELECT count(*) FROM "QGIS"."ASPATIAL_LAYER"')
- vl = QgsVectorLayer(self.dbconn + ' sslmode=disable table="QGIS"."ASPATIAL_LAYER" sql=', 'test', 'oracle')
+ vl = QgsVectorLayer(
+ self.dbconn + ' sslmode=disable table="QGIS"."ASPATIAL_LAYER" sql=',
+ "test",
+ "oracle",
+ )
self.assertTrue(vl.isValid())
self.assertEqual(vl.fields().names(), ["INTEGER_T"])
@@ -1139,9 +1807,18 @@ def testCreateInvalidLayer(self):
fields = QgsFields()
- uri = self.dbconn + "table=\"INVALID_LAYER\""
- exporter = QgsVectorLayerExporter(uri=uri, provider='oracle', fields=fields, geometryType=QgsWkbTypes.Type.NoGeometry, crs=QgsCoordinateReferenceSystem(), overwrite=True)
- self.assertEqual(exporter.errorCode(), QgsVectorLayerExporter.ExportError.ErrCreateDataSource)
+ uri = self.dbconn + 'table="INVALID_LAYER"'
+ exporter = QgsVectorLayerExporter(
+ uri=uri,
+ provider="oracle",
+ fields=fields,
+ geometryType=QgsWkbTypes.Type.NoGeometry,
+ crs=QgsCoordinateReferenceSystem(),
+ overwrite=True,
+ )
+ self.assertEqual(
+ exporter.errorCode(), QgsVectorLayerExporter.ExportError.ErrCreateDataSource
+ )
def testAddEmptyFeature(self):
"""
@@ -1157,34 +1834,52 @@ def countFeature(table_name):
query.finish()
return count
- self.execSQLCommand('DROP TABLE "QGIS"."EMPTYFEATURE_LAYER"', ignore_errors=True)
- self.execSQLCommand('CREATE TABLE "QGIS"."EMPTYFEATURE_LAYER" ( "num" INTEGER, GEOM SDO_GEOMETRY)')
+ self.execSQLCommand(
+ 'DROP TABLE "QGIS"."EMPTYFEATURE_LAYER"', ignore_errors=True
+ )
+ self.execSQLCommand(
+ 'CREATE TABLE "QGIS"."EMPTYFEATURE_LAYER" ( "num" INTEGER, GEOM SDO_GEOMETRY)'
+ )
- vl = QgsVectorLayer(self.dbconn + ' sslmode=disable type=Point table="QGIS"."EMPTYFEATURE_LAYER" (GEOM) sql=', 'test', 'oracle')
+ vl = QgsVectorLayer(
+ self.dbconn
+ + ' sslmode=disable type=Point table="QGIS"."EMPTYFEATURE_LAYER" (GEOM) sql=',
+ "test",
+ "oracle",
+ )
self.assertTrue(vl.isValid())
# add feature with no attributes, no geometry
feature = QgsFeature(vl.fields())
self.assertTrue(vl.dataProvider().addFeatures([feature])[0])
- self.assertEqual(countFeature('EMPTYFEATURE_LAYER'), 1)
+ self.assertEqual(countFeature("EMPTYFEATURE_LAYER"), 1)
# add feature with no attribute and one geometry
feature = QgsFeature(vl.fields())
- feature.setGeometry(QgsGeometry.fromWkt('Point (43.5 1.42)'))
+ feature.setGeometry(QgsGeometry.fromWkt("Point (43.5 1.42)"))
self.assertTrue(vl.dataProvider().addFeatures([feature])[0])
- self.assertEqual(countFeature('EMPTYFEATURE_LAYER'), 2)
+ self.assertEqual(countFeature("EMPTYFEATURE_LAYER"), 2)
- self.execSQLCommand('DROP TABLE "QGIS"."EMPTYFEATURE_NOGEOM_LAYER"', ignore_errors=True)
- self.execSQLCommand('CREATE TABLE "QGIS"."EMPTYFEATURE_NOGEOM_LAYER" ( "num" INTEGER)')
+ self.execSQLCommand(
+ 'DROP TABLE "QGIS"."EMPTYFEATURE_NOGEOM_LAYER"', ignore_errors=True
+ )
+ self.execSQLCommand(
+ 'CREATE TABLE "QGIS"."EMPTYFEATURE_NOGEOM_LAYER" ( "num" INTEGER)'
+ )
# same tests but with no geometry in table definition
- vl = QgsVectorLayer(self.dbconn + ' sslmode=disable table="QGIS"."EMPTYFEATURE_NOGEOM_LAYER" sql=', 'test', 'oracle')
+ vl = QgsVectorLayer(
+ self.dbconn
+ + ' sslmode=disable table="QGIS"."EMPTYFEATURE_NOGEOM_LAYER" sql=',
+ "test",
+ "oracle",
+ )
self.assertTrue(vl.isValid())
# add feature with no attributes
feature = QgsFeature(vl.fields())
self.assertTrue(vl.dataProvider().addFeatures([feature])[0])
- self.assertEqual(countFeature('EMPTYFEATURE_NOGEOM_LAYER'), 1)
+ self.assertEqual(countFeature("EMPTYFEATURE_NOGEOM_LAYER"), 1)
def testCreateLayerLongFieldNames(self):
"""
@@ -1199,13 +1894,24 @@ def testCreateLayerLongFieldNames(self):
fields = QgsFields()
fields.append(QgsField(long_name, QVariant.Int))
- uri = self.dbconn + "table=\"LONGFIELD_LAYER\""
- exporter = QgsVectorLayerExporter(uri=uri, provider='oracle', fields=fields, geometryType=QgsWkbTypes.Type.Point, crs=QgsCoordinateReferenceSystem("EPSG:4326"), overwrite=True)
+ uri = self.dbconn + 'table="LONGFIELD_LAYER"'
+ exporter = QgsVectorLayerExporter(
+ uri=uri,
+ provider="oracle",
+ fields=fields,
+ geometryType=QgsWkbTypes.Type.Point,
+ crs=QgsCoordinateReferenceSystem("EPSG:4326"),
+ overwrite=True,
+ )
self.assertEqual(exporter.errorCount(), 0)
self.assertEqual(exporter.errorCode(), 0)
self.execSQLCommand('SELECT count(*) FROM "QGIS"."LONGFIELD_LAYER"')
- vl = QgsVectorLayer(self.dbconn + ' sslmode=disable table="QGIS"."LONGFIELD_LAYER" sql=', 'test', 'oracle')
+ vl = QgsVectorLayer(
+ self.dbconn + ' sslmode=disable table="QGIS"."LONGFIELD_LAYER" sql=',
+ "test",
+ "oracle",
+ )
self.assertTrue(vl.isValid())
self.assertEqual(vl.fields().names(), [long_name])
@@ -1221,30 +1927,57 @@ def testCreateGeomLowercase(self):
fields = QgsFields()
fields.append(QgsField("test", QVariant.Int))
- uri = self.dbconn + "table=\"lowercase_layer\" (GEOM)"
- exporter = QgsVectorLayerExporter(uri=uri, provider='oracle', fields=fields, geometryType=QgsWkbTypes.Type.Point, crs=QgsCoordinateReferenceSystem("EPSG:4326"), overwrite=True)
+ uri = self.dbconn + 'table="lowercase_layer" (GEOM)'
+ exporter = QgsVectorLayerExporter(
+ uri=uri,
+ provider="oracle",
+ fields=fields,
+ geometryType=QgsWkbTypes.Type.Point,
+ crs=QgsCoordinateReferenceSystem("EPSG:4326"),
+ overwrite=True,
+ )
self.assertEqual(exporter.errorCode(), 2)
# geom column is lower case -> fails
- self.execSQLCommand('DROP TABLE "QGIS"."LOWERCASEGEOM_LAYER"', ignore_errors=True)
+ self.execSQLCommand(
+ 'DROP TABLE "QGIS"."LOWERCASEGEOM_LAYER"', ignore_errors=True
+ )
fields = QgsFields()
fields.append(QgsField("test", QVariant.Int))
- uri = self.dbconn + "table=\"LOWERCASEGEOM\" (geom)"
- exporter = QgsVectorLayerExporter(uri=uri, provider='oracle', fields=fields, geometryType=QgsWkbTypes.Type.Point, crs=QgsCoordinateReferenceSystem("EPSG:4326"), overwrite=True)
+ uri = self.dbconn + 'table="LOWERCASEGEOM" (geom)'
+ exporter = QgsVectorLayerExporter(
+ uri=uri,
+ provider="oracle",
+ fields=fields,
+ geometryType=QgsWkbTypes.Type.Point,
+ crs=QgsCoordinateReferenceSystem("EPSG:4326"),
+ overwrite=True,
+ )
self.assertEqual(exporter.errorCode(), 2)
# table and geom column are uppercase -> success
- self.execSQLCommand('DROP TABLE "QGIS"."UPPERCASEGEOM_LAYER"', ignore_errors=True)
- self.execSQLCommand("""DELETE FROM user_sdo_geom_metadata where TABLE_NAME = 'UPPERCASEGEOM_LAYER'""")
+ self.execSQLCommand(
+ 'DROP TABLE "QGIS"."UPPERCASEGEOM_LAYER"', ignore_errors=True
+ )
+ self.execSQLCommand(
+ """DELETE FROM user_sdo_geom_metadata where TABLE_NAME = 'UPPERCASEGEOM_LAYER'"""
+ )
fields = QgsFields()
fields.append(QgsField("test", QVariant.Int))
- uri = self.dbconn + "table=\"UPPERCASEGEOM_LAYER\" (GEOM)"
+ uri = self.dbconn + 'table="UPPERCASEGEOM_LAYER" (GEOM)'
- exporter = QgsVectorLayerExporter(uri=uri, provider='oracle', fields=fields, geometryType=QgsWkbTypes.Type.Point, crs=QgsCoordinateReferenceSystem("EPSG:4326"), overwrite=True)
+ exporter = QgsVectorLayerExporter(
+ uri=uri,
+ provider="oracle",
+ fields=fields,
+ geometryType=QgsWkbTypes.Type.Point,
+ crs=QgsCoordinateReferenceSystem("EPSG:4326"),
+ overwrite=True,
+ )
print(exporter.errorMessage())
self.assertEqual(exporter.errorCount(), 0)
self.assertEqual(exporter.errorCode(), 0)
@@ -1255,37 +1988,122 @@ def testDetectedGeomType(self):
"""
testdata = [
- ("POINT", 2, "SDO_GEOMETRY( 2001,5698,SDO_POINT_TYPE(1, 2, NULL), NULL, NULL)", QgsWkbTypes.Type.Point),
- ("POINTZ", 3, "SDO_GEOMETRY( 3001,5698,SDO_POINT_TYPE(1, 2, 3), NULL, NULL)", QgsWkbTypes.Type.PointZ),
+ (
+ "POINT",
+ 2,
+ "SDO_GEOMETRY( 2001,5698,SDO_POINT_TYPE(1, 2, NULL), NULL, NULL)",
+ QgsWkbTypes.Type.Point,
+ ),
+ (
+ "POINTZ",
+ 3,
+ "SDO_GEOMETRY( 3001,5698,SDO_POINT_TYPE(1, 2, 3), NULL, NULL)",
+ QgsWkbTypes.Type.PointZ,
+ ),
# there is difference between line and curve so everything is a compoundcurve to cover both
# https://docs.oracle.com/database/121/SPATL/sdo_geometry-object-type.htm
- ("LINE", 2, "SDO_GEOMETRY( 2002,5698,NULL, SDO_ELEM_INFO_ARRAY(1,2,1), SDO_ORDINATE_ARRAY(1,2,3,4,5,6))", QgsWkbTypes.Type.CompoundCurve),
- ("LINEZ", 3, "SDO_GEOMETRY(3002,5698,NULL, SDO_ELEM_INFO_ARRAY(1,2,1), SDO_ORDINATE_ARRAY(1,2,3,4,5,6,7,8,9))", QgsWkbTypes.Type.CompoundCurveZ),
- ("CURVE", 2, "SDO_GEOMETRY(2002,5698,NULL, SDO_ELEM_INFO_ARRAY(1, 2, 2), SDO_ORDINATE_ARRAY(1, 2, 5, 4, 7, 2.2, 10, .1, 13, 4))", QgsWkbTypes.Type.CompoundCurve),
- ("CURVEZ", 3, "SDO_GEOMETRY(3002,5698,NULL, SDO_ELEM_INFO_ARRAY(1, 2, 2), SDO_ORDINATE_ARRAY(1, 2, 1, 5, 4, 2, 7, 2.2, 3, 10, 0.1, 4, 13, 4, 5))", QgsWkbTypes.Type.CompoundCurveZ),
- ("POLYGON", 2, "SDO_GEOMETRY(2003,5698,NULL, SDO_ELEM_INFO_ARRAY(1,1003,1), SDO_ORDINATE_ARRAY(1, 2, 11, 2, 11, 22, 1, 22, 1, 2))", QgsWkbTypes.Type.Polygon),
- ("POLYGONZ", 3, "SDO_GEOMETRY(3003,5698,NULL, SDO_ELEM_INFO_ARRAY(1,1003,1), SDO_ORDINATE_ARRAY(1, 2, 3, 11, 2, 13, 11, 22, 15, 1, 22, 7, 1, 2, 3))", QgsWkbTypes.Type.PolygonZ),
-
- ("MULTIPOINT", 2, "SDO_GEOMETRY( 2005,5698,NULL, sdo_elem_info_array (1,1,1, 3,1,1), sdo_ordinate_array (1,2, 3,4))", QgsWkbTypes.Type.MultiPoint),
- ("MULTIPOINTZ", 3, "SDO_GEOMETRY( 3005,5698,NULL, sdo_elem_info_array (1,1,2), sdo_ordinate_array (1,2,3, 4,5,6))", QgsWkbTypes.Type.MultiPointZ),
+ (
+ "LINE",
+ 2,
+ "SDO_GEOMETRY( 2002,5698,NULL, SDO_ELEM_INFO_ARRAY(1,2,1), SDO_ORDINATE_ARRAY(1,2,3,4,5,6))",
+ QgsWkbTypes.Type.CompoundCurve,
+ ),
+ (
+ "LINEZ",
+ 3,
+ "SDO_GEOMETRY(3002,5698,NULL, SDO_ELEM_INFO_ARRAY(1,2,1), SDO_ORDINATE_ARRAY(1,2,3,4,5,6,7,8,9))",
+ QgsWkbTypes.Type.CompoundCurveZ,
+ ),
+ (
+ "CURVE",
+ 2,
+ "SDO_GEOMETRY(2002,5698,NULL, SDO_ELEM_INFO_ARRAY(1, 2, 2), SDO_ORDINATE_ARRAY(1, 2, 5, 4, 7, 2.2, 10, .1, 13, 4))",
+ QgsWkbTypes.Type.CompoundCurve,
+ ),
+ (
+ "CURVEZ",
+ 3,
+ "SDO_GEOMETRY(3002,5698,NULL, SDO_ELEM_INFO_ARRAY(1, 2, 2), SDO_ORDINATE_ARRAY(1, 2, 1, 5, 4, 2, 7, 2.2, 3, 10, 0.1, 4, 13, 4, 5))",
+ QgsWkbTypes.Type.CompoundCurveZ,
+ ),
+ (
+ "POLYGON",
+ 2,
+ "SDO_GEOMETRY(2003,5698,NULL, SDO_ELEM_INFO_ARRAY(1,1003,1), SDO_ORDINATE_ARRAY(1, 2, 11, 2, 11, 22, 1, 22, 1, 2))",
+ QgsWkbTypes.Type.Polygon,
+ ),
+ (
+ "POLYGONZ",
+ 3,
+ "SDO_GEOMETRY(3003,5698,NULL, SDO_ELEM_INFO_ARRAY(1,1003,1), SDO_ORDINATE_ARRAY(1, 2, 3, 11, 2, 13, 11, 22, 15, 1, 22, 7, 1, 2, 3))",
+ QgsWkbTypes.Type.PolygonZ,
+ ),
+ (
+ "MULTIPOINT",
+ 2,
+ "SDO_GEOMETRY( 2005,5698,NULL, sdo_elem_info_array (1,1,1, 3,1,1), sdo_ordinate_array (1,2, 3,4))",
+ QgsWkbTypes.Type.MultiPoint,
+ ),
+ (
+ "MULTIPOINTZ",
+ 3,
+ "SDO_GEOMETRY( 3005,5698,NULL, sdo_elem_info_array (1,1,2), sdo_ordinate_array (1,2,3, 4,5,6))",
+ QgsWkbTypes.Type.MultiPointZ,
+ ),
# there is difference between line and curve so everything is a compoundcurve to cover both
# https://docs.oracle.com/database/121/SPATL/sdo_geometry-object-type.htm
- ("MULTILINE", 2, "SDO_GEOMETRY(2006,5698,NULL, SDO_ELEM_INFO_ARRAY(1,2,1, 5,2,1), SDO_ORDINATE_ARRAY(1, 2, 3, 4, 5, 6, 7, 8, 9, 10))", QgsWkbTypes.Type.MultiCurve),
- ("MULTILINEZ", 3, "SDO_GEOMETRY(3006,5698,NULL, SDO_ELEM_INFO_ARRAY(1,2,1, 7,2,1), SDO_ORDINATE_ARRAY(1, 2, 11, 3, 4, -11, 5, 6, 9, 7, 8, 1, 9, 10, -3))", QgsWkbTypes.Type.MultiCurveZ),
- ("MULTICURVE", 2, "SDO_GEOMETRY(2006,5698,NULL, SDO_ELEM_INFO_ARRAY(1,2,2, 11,2,2), SDO_ORDINATE_ARRAY(1, 2, 5, 4, 7, 2.2, 10, .1, 13, 4, -11, -3, 5, 7, 10, -1))", QgsWkbTypes.Type.MultiCurve),
- ("MULTICURVEZ", 3, "SDO_GEOMETRY(3006,5698,NULL, SDO_ELEM_INFO_ARRAY(1,2,2, 16,2,2), SDO_ORDINATE_ARRAY(1, 2, 1, 5, 4, 2, 7, 2.2, 3, 10, .1, 4, 13, 4, 5, -11, -3, 6, 5, 7, 8, 10, -1, 9))", QgsWkbTypes.Type.MultiCurveZ),
- ("MULTIPOLYGON", 2, "SDO_GEOMETRY(2007,5698,NULL, SDO_ELEM_INFO_ARRAY(1,1003,1, 11,1003,1, 21,2003,1, 29,2003,1), SDO_ORDINATE_ARRAY(1, 2, 11, 2, 11, 22, 1, 22, 1, 2, 1, 2, 11, 2, 11, 22, 1, 22, 1, 2, 5, 6, 8, 9, 8, 6, 5, 6, 3, 4, 5, 6, 3, 6, 3, 4))", QgsWkbTypes.Type.MultiPolygon),
- ("MULTIPOLYGONZ", 3, "SDO_GEOMETRY(3007,5698,NULL, SDO_ELEM_INFO_ARRAY(1,1003,1, 16,1003,1, 31,2003,1), SDO_ORDINATE_ARRAY(1, 2, 3, 11, 2, 13, 11, 22, 15, 1, 22, 7, 1, 2, 3, 1, 2, 3, 11, 2, 13, 11, 22, 15, 1, 22, 7, 1, 2, 3, 5, 6, 1, 8, 9, -1, 8, 6, 2, 5, 6, 1))", QgsWkbTypes.Type.MultiPolygonZ)
+ (
+ "MULTILINE",
+ 2,
+ "SDO_GEOMETRY(2006,5698,NULL, SDO_ELEM_INFO_ARRAY(1,2,1, 5,2,1), SDO_ORDINATE_ARRAY(1, 2, 3, 4, 5, 6, 7, 8, 9, 10))",
+ QgsWkbTypes.Type.MultiCurve,
+ ),
+ (
+ "MULTILINEZ",
+ 3,
+ "SDO_GEOMETRY(3006,5698,NULL, SDO_ELEM_INFO_ARRAY(1,2,1, 7,2,1), SDO_ORDINATE_ARRAY(1, 2, 11, 3, 4, -11, 5, 6, 9, 7, 8, 1, 9, 10, -3))",
+ QgsWkbTypes.Type.MultiCurveZ,
+ ),
+ (
+ "MULTICURVE",
+ 2,
+ "SDO_GEOMETRY(2006,5698,NULL, SDO_ELEM_INFO_ARRAY(1,2,2, 11,2,2), SDO_ORDINATE_ARRAY(1, 2, 5, 4, 7, 2.2, 10, .1, 13, 4, -11, -3, 5, 7, 10, -1))",
+ QgsWkbTypes.Type.MultiCurve,
+ ),
+ (
+ "MULTICURVEZ",
+ 3,
+ "SDO_GEOMETRY(3006,5698,NULL, SDO_ELEM_INFO_ARRAY(1,2,2, 16,2,2), SDO_ORDINATE_ARRAY(1, 2, 1, 5, 4, 2, 7, 2.2, 3, 10, .1, 4, 13, 4, 5, -11, -3, 6, 5, 7, 8, 10, -1, 9))",
+ QgsWkbTypes.Type.MultiCurveZ,
+ ),
+ (
+ "MULTIPOLYGON",
+ 2,
+ "SDO_GEOMETRY(2007,5698,NULL, SDO_ELEM_INFO_ARRAY(1,1003,1, 11,1003,1, 21,2003,1, 29,2003,1), SDO_ORDINATE_ARRAY(1, 2, 11, 2, 11, 22, 1, 22, 1, 2, 1, 2, 11, 2, 11, 22, 1, 22, 1, 2, 5, 6, 8, 9, 8, 6, 5, 6, 3, 4, 5, 6, 3, 6, 3, 4))",
+ QgsWkbTypes.Type.MultiPolygon,
+ ),
+ (
+ "MULTIPOLYGONZ",
+ 3,
+ "SDO_GEOMETRY(3007,5698,NULL, SDO_ELEM_INFO_ARRAY(1,1003,1, 16,1003,1, 31,2003,1), SDO_ORDINATE_ARRAY(1, 2, 3, 11, 2, 13, 11, 22, 15, 1, 22, 7, 1, 2, 3, 1, 2, 3, 11, 2, 13, 11, 22, 15, 1, 22, 7, 1, 2, 3, 5, 6, 1, 8, 9, -1, 8, 6, 2, 5, 6, 1))",
+ QgsWkbTypes.Type.MultiPolygonZ,
+ ),
]
for name, dim, geom, wkb_type in testdata:
# We choose SRID=5698 (see https://docs.oracle.com/database/121/SPATL/three-dimensional-coordinate-reference-system-support.htm#SPATL626)
# to get Oracle valid geometries because it support 3D and arcs (arcs are not supported in geodetic projection)
- self.createTable(f'DETECT_{name}', dim, 5698)
- self.execSQLCommand(f'INSERT INTO "QGIS"."DETECT_{name}" ("pk", GEOM) SELECT 1, {geom} from dual')
+ self.createTable(f"DETECT_{name}", dim, 5698)
+ self.execSQLCommand(
+ f'INSERT INTO "QGIS"."DETECT_{name}" ("pk", GEOM) SELECT 1, {geom} from dual'
+ )
layer = QgsVectorLayer(
- self.dbconn + f' sslmode=disable key=\'pk\' srid=3857 table="QGIS"."DETECT_{name}" (GEOM) sql=', f'test{name}', 'oracle')
+ self.dbconn
+ + f' sslmode=disable key=\'pk\' srid=3857 table="QGIS"."DETECT_{name}" (GEOM) sql=',
+ f"test{name}",
+ "oracle",
+ )
self.assertTrue(layer.isValid())
self.assertEqual(layer.wkbType(), wkb_type)
@@ -1332,20 +2150,28 @@ def request(self, realm, username, pwd, msg):
self.assertEqual(credentials, QgsCredentials.instance())
# no user/pwd -> credential is called
- transaction = QgsProviderRegistry.instance().createTransaction("oracle", conn_wo_login_pwd)
+ transaction = QgsProviderRegistry.instance().createTransaction(
+ "oracle", conn_wo_login_pwd
+ )
self.assertEqual(transaction.begin()[0], True)
self.assertEqual(credentials.nbCall, 1)
# no user/pwd second times -> use cache
- transaction = QgsProviderRegistry.instance().createTransaction("oracle", conn_wo_login_pwd)
+ transaction = QgsProviderRegistry.instance().createTransaction(
+ "oracle", conn_wo_login_pwd
+ )
self.assertEqual(transaction.begin()[0], True)
self.assertEqual(credentials.nbCall, 1)
# same connection, different user, don't use cache (credentials.nbCall is incremented)
- transaction = QgsProviderRegistry.instance().createTransaction("oracle", conn_wo_login_pwd + " user='titi'")
- self.assertEqual(transaction.begin()[0], True) # test credentials always return valid credentials so it's valid, but we don't care
+ transaction = QgsProviderRegistry.instance().createTransaction(
+ "oracle", conn_wo_login_pwd + " user='titi'"
+ )
+ self.assertEqual(
+ transaction.begin()[0], True
+ ) # test credentials always return valid credentials so it's valid, but we don't care
self.assertEqual(credentials.nbCall, 2)
-if __name__ == '__main__':
+if __name__ == "__main__":
unittest.main()
diff --git a/tests/src/python/test_provider_postgres.py b/tests/src/python/test_provider_postgres.py
index 0d396417a3c4..fbd4e98279eb 100644
--- a/tests/src/python/test_provider_postgres.py
+++ b/tests/src/python/test_provider_postgres.py
@@ -14,9 +14,9 @@
"""
-__author__ = 'Matthias Kuhn'
-__date__ = '2015-04-23'
-__copyright__ = 'Copyright 2015, The QGIS Project'
+__author__ = "Matthias Kuhn"
+__date__ = "2015-04-23"
+__copyright__ = "Copyright 2015, The QGIS Project"
import os
import time
@@ -66,7 +66,7 @@
QgsVectorLayerExporter,
QgsVectorLayerUtils,
QgsWkbTypes,
- QgsSettingsTree
+ QgsSettingsTree,
)
from qgis.gui import QgsAttributeForm, QgsGui
import unittest
@@ -84,24 +84,36 @@ class TestPyQgsPostgresProvider(QgisTestCase, ProviderTestCase):
@classmethod
def setUpClass(cls):
"""Run before all tests"""
- super(TestPyQgsPostgresProvider, cls).setUpClass()
- cls.dbconn = 'service=qgis_test'
- if 'QGIS_PGTEST_DB' in os.environ:
- cls.dbconn = os.environ['QGIS_PGTEST_DB']
+ super().setUpClass()
+ cls.dbconn = "service=qgis_test"
+ if "QGIS_PGTEST_DB" in os.environ:
+ cls.dbconn = os.environ["QGIS_PGTEST_DB"]
# Create test layers
cls.vl = QgsVectorLayer(
- cls.dbconn +
- ' sslmode=disable key=\'pk\' srid=4326 type=POINT table="qgis_test"."someData" (geom) sql=',
- 'test', 'postgres')
- assert cls.vl.isValid(), "Could not create a layer from the 'qgis_test.someData' table using dbconn '" + cls.dbconn + "'"
+ cls.dbconn
+ + ' sslmode=disable key=\'pk\' srid=4326 type=POINT table="qgis_test"."someData" (geom) sql=',
+ "test",
+ "postgres",
+ )
+ assert cls.vl.isValid(), (
+ "Could not create a layer from the 'qgis_test.someData' table using dbconn '"
+ + cls.dbconn
+ + "'"
+ )
cls.source = cls.vl.dataProvider()
cls.poly_vl = QgsVectorLayer(
- cls.dbconn +
- ' sslmode=disable key=\'pk\' srid=4326 type=POLYGON table="qgis_test"."some_poly_data" (geom) sql=',
- 'test', 'postgres')
- assert cls.poly_vl.isValid(), "Could not create a layer from the 'qgis_test.some_poly_data' table using dbconn '" + cls.dbconn + "'"
+ cls.dbconn
+ + ' sslmode=disable key=\'pk\' srid=4326 type=POLYGON table="qgis_test"."some_poly_data" (geom) sql=',
+ "test",
+ "postgres",
+ )
+ assert cls.poly_vl.isValid(), (
+ "Could not create a layer from the 'qgis_test.some_poly_data' table using dbconn '"
+ + cls.dbconn
+ + "'"
+ )
cls.poly_provider = cls.poly_vl.dataProvider()
QgsGui.editorWidgetRegistry().initEditors()
@@ -117,14 +129,23 @@ def execSQLCommand(self, sql):
def assertAcceptableEstimatedExtent(self, realExt, estmExt, msg):
# 1. test that the estimated extent contains the real one
- self.assertTrue(estmExt.contains(realExt),
- "Estimated extent {} does not contain real extent {}"
- .format(estmExt, realExt))
+ self.assertTrue(
+ estmExt.contains(realExt),
+ "Estimated extent {} does not contain real extent {}".format(
+ estmExt, realExt
+ ),
+ )
# 2. test that the estimated extent is not larger than 10% of real extent
- self.assertLess(estmExt.width() - realExt.width(), realExt.width() / 10,
- 'extent width estimated {}, real {} ({})'.format(estmExt.width(), realExt.width(), msg))
- self.assertLess(estmExt.height() - realExt.height(), realExt.height() / 10,
- 'extent height estimated {}, real {} ({})'.format(estmExt.height(), realExt.height(), msg))
+ self.assertLess(
+ estmExt.width() - realExt.width(),
+ realExt.width() / 10,
+ f"extent width estimated {estmExt.width()}, real {realExt.width()} ({msg})",
+ )
+ self.assertLess(
+ estmExt.height() - realExt.height(),
+ realExt.height() / 10,
+ f"extent height estimated {estmExt.height()}, real {realExt.height()} ({msg})",
+ )
# Create instances of this class for scoped backups,
# example:
@@ -134,55 +155,71 @@ def assertAcceptableEstimatedExtent(self, realExt, estmExt, msg):
#
def scopedTableBackup(self, schema, table):
- class ScopedBackup():
+ class ScopedBackup:
def __init__(self, tester, schema, table):
self.schema = schema
self.table = table
self.tester = tester
- tester.execSQLCommand(f'DROP TABLE IF EXISTS {schema}.{table}_edit CASCADE')
- tester.execSQLCommand('CREATE TABLE {s}.{t}_edit AS SELECT * FROM {s}.{t}'.format(s=schema, t=table))
+ tester.execSQLCommand(
+ f"DROP TABLE IF EXISTS {schema}.{table}_edit CASCADE"
+ )
+ tester.execSQLCommand(
+ "CREATE TABLE {s}.{t}_edit AS SELECT * FROM {s}.{t}".format(
+ s=schema, t=table
+ )
+ )
def __del__(self):
- self.tester.execSQLCommand(f'TRUNCATE TABLE {self.schema}.{self.table}')
- self.tester.execSQLCommand('INSERT INTO {s}.{t} SELECT * FROM {s}.{t}_edit'.format(s=self.schema, t=self.table))
- self.tester.execSQLCommand(f'DROP TABLE {self.schema}.{self.table}_edit')
+ self.tester.execSQLCommand(f"TRUNCATE TABLE {self.schema}.{self.table}")
+ self.tester.execSQLCommand(
+ "INSERT INTO {s}.{t} SELECT * FROM {s}.{t}_edit".format(
+ s=self.schema, t=self.table
+ )
+ )
+ self.tester.execSQLCommand(
+ f"DROP TABLE {self.schema}.{self.table}_edit"
+ )
return ScopedBackup(self, schema, table)
def temporarySchema(self, name):
- class TemporarySchema():
+ class TemporarySchema:
def __init__(self, tester, name):
self.tester = tester
- self.name = name + '_tmp'
+ self.name = name + "_tmp"
def __enter__(self):
- self.tester.execSQLCommand(f'DROP SCHEMA IF EXISTS {self.name} CASCADE')
- self.tester.execSQLCommand(f'CREATE SCHEMA {self.name}')
+ self.tester.execSQLCommand(f"DROP SCHEMA IF EXISTS {self.name} CASCADE")
+ self.tester.execSQLCommand(f"CREATE SCHEMA {self.name}")
return self.name
def __exit__(self, type, value, traceback):
- self.tester.execSQLCommand(f'DROP SCHEMA {self.name} CASCADE')
+ self.tester.execSQLCommand(f"DROP SCHEMA {self.name} CASCADE")
- return TemporarySchema(self, 'qgis_test_' + name)
+ return TemporarySchema(self, "qgis_test_" + name)
def getSource(self):
# create temporary table for edit tests
+ self.execSQLCommand('DROP TABLE IF EXISTS qgis_test."editData" CASCADE')
self.execSQLCommand(
- 'DROP TABLE IF EXISTS qgis_test."editData" CASCADE')
+ 'CREATE TABLE qgis_test."editData" ( pk SERIAL NOT NULL PRIMARY KEY, cnt integer, name text, name2 text, num_char text, dt timestamp without time zone, "date" date, "time" time without time zone, geom public.geometry(Point, 4326))'
+ )
self.execSQLCommand(
- 'CREATE TABLE qgis_test."editData" ( pk SERIAL NOT NULL PRIMARY KEY, cnt integer, name text, name2 text, num_char text, dt timestamp without time zone, "date" date, "time" time without time zone, geom public.geometry(Point, 4326))')
- self.execSQLCommand("INSERT INTO qgis_test.\"editData\" (pk, cnt, name, name2, num_char, dt, \"date\", \"time\", geom) VALUES "
- "(5, -200, NULL, 'NuLl', '5', TIMESTAMP '2020-05-04 12:13:14', '2020-05-02', '12:13:01', '0101000020E61000001D5A643BDFC751C01F85EB51B88E5340'),"
- "(3, 300, 'Pear', 'PEaR', '3', NULL, NULL, NULL, NULL),"
- "(1, 100, 'Orange', 'oranGe', '1', TIMESTAMP '2020-05-03 12:13:14', '2020-05-03', '12:13:14', '0101000020E61000006891ED7C3F9551C085EB51B81E955040'),"
- "(2, 200, 'Apple', 'Apple', '2', TIMESTAMP '2020-05-04 12:14:14', '2020-05-04', '12:14:14', '0101000020E6100000CDCCCCCCCC0C51C03333333333B35140'),"
- "(4, 400, 'Honey', 'Honey', '4', TIMESTAMP '2021-05-04 13:13:14', '2021-05-04', '13:13:14', '0101000020E610000014AE47E17A5450C03333333333935340')")
+ 'INSERT INTO qgis_test."editData" (pk, cnt, name, name2, num_char, dt, "date", "time", geom) VALUES '
+ "(5, -200, NULL, 'NuLl', '5', TIMESTAMP '2020-05-04 12:13:14', '2020-05-02', '12:13:01', '0101000020E61000001D5A643BDFC751C01F85EB51B88E5340'),"
+ "(3, 300, 'Pear', 'PEaR', '3', NULL, NULL, NULL, NULL),"
+ "(1, 100, 'Orange', 'oranGe', '1', TIMESTAMP '2020-05-03 12:13:14', '2020-05-03', '12:13:14', '0101000020E61000006891ED7C3F9551C085EB51B81E955040'),"
+ "(2, 200, 'Apple', 'Apple', '2', TIMESTAMP '2020-05-04 12:14:14', '2020-05-04', '12:14:14', '0101000020E6100000CDCCCCCCCC0C51C03333333333B35140'),"
+ "(4, 400, 'Honey', 'Honey', '4', TIMESTAMP '2021-05-04 13:13:14', '2021-05-04', '13:13:14', '0101000020E610000014AE47E17A5450C03333333333935340')"
+ )
self.execSQLCommand("SELECT setval('qgis_test.\"editData_pk_seq\"', 5, true)")
vl = QgsVectorLayer(
- self.dbconn +
- ' sslmode=disable key=\'pk\' srid=4326 type=POINT table="qgis_test"."editData" (geom) sql=',
- 'test', 'postgres')
+ self.dbconn
+ + ' sslmode=disable key=\'pk\' srid=4326 type=POINT table="qgis_test"."editData" (geom) sql=',
+ "test",
+ "postgres",
+ )
return vl
def getEditableLayer(self):
@@ -191,19 +228,26 @@ def getEditableLayer(self):
def getEditableLayerWithCheckConstraint(self):
"""Returns the layer for attribute change CHECK constraint violation"""
- return QgsVectorLayer(self.dbconn + ' sslmode=disable key=\'id\' srid=4326 type=POINT table="public"."test_check_constraint" (geom) sql=', 'test_check_constraint', 'postgres')
+ return QgsVectorLayer(
+ self.dbconn
+ + ' sslmode=disable key=\'id\' srid=4326 type=POINT table="public"."test_check_constraint" (geom) sql=',
+ "test_check_constraint",
+ "postgres",
+ )
def enableCompiler(self):
- QgsSettings().setValue('/qgis/compileExpressions', True)
+ QgsSettings().setValue("/qgis/compileExpressions", True)
return True
def disableCompiler(self):
- QgsSettings().setValue('/qgis/compileExpressions', False)
+ QgsSettings().setValue("/qgis/compileExpressions", False)
def uncompiledFilters(self):
- return {'"dt" = to_datetime(\'000www14ww13ww12www4ww5ww2020\',\'zzzwwwsswwmmwwhhwwwdwwMwwyyyy\')',
- '"date" = to_date(\'www4ww5ww2020\',\'wwwdwwMwwyyyy\')',
- '"time" = to_time(\'000www14ww13ww12www\',\'zzzwwwsswwmmwwhhwww\')'}
+ return {
+ "\"dt\" = to_datetime('000www14ww13ww12www4ww5ww2020','zzzwwwsswwmmwwhhwwwdwwMwwyyyy')",
+ "\"date\" = to_date('www4ww5ww2020','wwwdwwMwwyyyy')",
+ "\"time\" = to_time('000www14ww13ww12www','zzzwwwsswwmmwwhhwww')",
+ }
def partiallyCompiledFilters(self):
return set()
@@ -220,252 +264,285 @@ def getGeneratedColumnsData(self):
if pgversion < 120000:
return (None, None)
else:
- return (QgsVectorLayer(self.dbconn + ' sslmode=disable table="qgis_test"."generated_columns"', 'test', 'postgres'),
- """('test:'::text || ((pk)::character varying)::text)""")
+ return (
+ QgsVectorLayer(
+ self.dbconn
+ + ' sslmode=disable table="qgis_test"."generated_columns"',
+ "test",
+ "postgres",
+ ),
+ """('test:'::text || ((pk)::character varying)::text)""",
+ )
# HERE GO THE PROVIDER SPECIFIC TESTS
def testDefaultValue(self):
self.source.setProviderProperty(
- QgsDataProvider.ProviderProperty.EvaluateDefaultValues, True)
+ QgsDataProvider.ProviderProperty.EvaluateDefaultValues, True
+ )
self.assertIsInstance(self.source.defaultValue(0), int)
self.assertEqual(self.source.defaultValue(1), NULL)
- self.assertEqual(self.source.defaultValue(2), 'qgis')
+ self.assertEqual(self.source.defaultValue(2), "qgis")
self.source.setProviderProperty(
- QgsDataProvider.ProviderProperty.EvaluateDefaultValues, False)
+ QgsDataProvider.ProviderProperty.EvaluateDefaultValues, False
+ )
def testDefaultValueClause(self):
self.source.setProviderProperty(
- QgsDataProvider.ProviderProperty.EvaluateDefaultValues, False)
- self.assertEqual(self.source.defaultValueClause(
- 0), 'nextval(\'qgis_test."someData_pk_seq"\'::regclass)')
+ QgsDataProvider.ProviderProperty.EvaluateDefaultValues, False
+ )
+ self.assertEqual(
+ self.source.defaultValueClause(0),
+ "nextval('qgis_test.\"someData_pk_seq\"'::regclass)",
+ )
self.assertFalse(self.source.defaultValueClause(1))
- self.assertEqual(self.source.defaultValueClause(2), '\'qgis\'::text')
+ self.assertEqual(self.source.defaultValueClause(2), "'qgis'::text")
def testDateTimeTypes(self):
- vl = QgsVectorLayer('%s table="qgis_test"."date_times" sql=' % (
- self.dbconn), "testdatetimes", "postgres")
+ vl = QgsVectorLayer(
+ '%s table="qgis_test"."date_times" sql=' % (self.dbconn),
+ "testdatetimes",
+ "postgres",
+ )
self.assertTrue(vl.isValid())
fields = vl.dataProvider().fields()
- self.assertEqual(fields.at(fields.indexFromName(
- 'date_field')).type(), QVariant.Date)
- self.assertEqual(fields.at(fields.indexFromName(
- 'time_field')).type(), QVariant.Time)
- self.assertEqual(fields.at(fields.indexFromName(
- 'datetime_field')).type(), QVariant.DateTime)
+ self.assertEqual(
+ fields.at(fields.indexFromName("date_field")).type(), QVariant.Date
+ )
+ self.assertEqual(
+ fields.at(fields.indexFromName("time_field")).type(), QVariant.Time
+ )
+ self.assertEqual(
+ fields.at(fields.indexFromName("datetime_field")).type(), QVariant.DateTime
+ )
f = next(vl.getFeatures(QgsFeatureRequest()))
- date_idx = vl.fields().lookupField('date_field')
+ date_idx = vl.fields().lookupField("date_field")
self.assertIsInstance(f.attributes()[date_idx], QDate)
self.assertEqual(f.attributes()[date_idx], QDate(2004, 3, 4))
- time_idx = vl.fields().lookupField('time_field')
+ time_idx = vl.fields().lookupField("time_field")
self.assertIsInstance(f.attributes()[time_idx], QTime)
self.assertEqual(f.attributes()[time_idx], QTime(13, 41, 52))
- datetime_idx = vl.fields().lookupField('datetime_field')
+ datetime_idx = vl.fields().lookupField("datetime_field")
self.assertIsInstance(f.attributes()[datetime_idx], QDateTime)
- self.assertEqual(f.attributes()[datetime_idx], QDateTime(
- QDate(2004, 3, 4), QTime(13, 41, 52)))
+ self.assertEqual(
+ f.attributes()[datetime_idx],
+ QDateTime(QDate(2004, 3, 4), QTime(13, 41, 52)),
+ )
def testBooleanType(self):
- vl = QgsVectorLayer('{} table="qgis_test"."boolean_table" sql='.format(
- self.dbconn), "testbool", "postgres")
+ vl = QgsVectorLayer(
+ f'{self.dbconn} table="qgis_test"."boolean_table" sql=',
+ "testbool",
+ "postgres",
+ )
self.assertTrue(vl.isValid())
fields = vl.dataProvider().fields()
- self.assertEqual(
- fields.at(fields.indexFromName('fld1')).type(), QVariant.Bool)
+ self.assertEqual(fields.at(fields.indexFromName("fld1")).type(), QVariant.Bool)
- values = {feat['id']: feat['fld1'] for feat in vl.getFeatures()}
- expected = {
- 1: True,
- 2: False,
- 3: NULL
- }
+ values = {feat["id"]: feat["fld1"] for feat in vl.getFeatures()}
+ expected = {1: True, 2: False, 3: NULL}
self.assertEqual(values, expected)
def testByteaType(self):
- vl = QgsVectorLayer('{} table="qgis_test"."byte_a_table" sql='.format(
- self.dbconn), "testbytea", "postgres")
+ vl = QgsVectorLayer(
+ f'{self.dbconn} table="qgis_test"."byte_a_table" sql=',
+ "testbytea",
+ "postgres",
+ )
self.assertTrue(vl.isValid())
fields = vl.dataProvider().fields()
- self.assertEqual(fields.at(fields.indexFromName(
- 'fld1')).type(), QVariant.ByteArray)
+ self.assertEqual(
+ fields.at(fields.indexFromName("fld1")).type(), QVariant.ByteArray
+ )
- values = {feat['id']: feat['fld1'] for feat in vl.getFeatures()}
- expected = {
- 1: QByteArray(b'YmludmFsdWU='),
- 2: QByteArray()
- }
+ values = {feat["id"]: feat["fld1"] for feat in vl.getFeatures()}
+ expected = {1: QByteArray(b"YmludmFsdWU="), 2: QByteArray()}
self.assertEqual(values, expected)
# editing binary values
self.execSQLCommand(
- 'DROP TABLE IF EXISTS qgis_test."byte_a_table_edit" CASCADE')
+ 'DROP TABLE IF EXISTS qgis_test."byte_a_table_edit" CASCADE'
+ )
+ self.execSQLCommand(
+ 'CREATE TABLE qgis_test."byte_a_table_edit" ( pk SERIAL NOT NULL PRIMARY KEY, blobby bytea)'
+ )
self.execSQLCommand(
- 'CREATE TABLE qgis_test."byte_a_table_edit" ( pk SERIAL NOT NULL PRIMARY KEY, blobby bytea)')
- self.execSQLCommand("INSERT INTO qgis_test.\"byte_a_table_edit\" (pk, blobby) VALUES "
- "(1, encode('bbb', 'base64')::bytea)")
+ 'INSERT INTO qgis_test."byte_a_table_edit" (pk, blobby) VALUES '
+ "(1, encode('bbb', 'base64')::bytea)"
+ )
vl = QgsVectorLayer(
self.dbconn + ' sslmode=disable table="qgis_test"."byte_a_table_edit" sql=',
- 'test', 'postgres')
+ "test",
+ "postgres",
+ )
self.assertTrue(vl.isValid())
- values = {feat['pk']: feat['blobby'] for feat in vl.getFeatures()}
- expected = {
- 1: QByteArray(b'YmJi')
- }
+ values = {feat["pk"]: feat["blobby"] for feat in vl.getFeatures()}
+ expected = {1: QByteArray(b"YmJi")}
self.assertEqual(values, expected)
# change attribute value
- self.assertTrue(vl.dataProvider().changeAttributeValues(
- {1: {1: QByteArray(b'bbbvx')}}))
- values = {feat['pk']: feat['blobby'] for feat in vl.getFeatures()}
- expected = {
- 1: QByteArray(b'bbbvx')
- }
+ self.assertTrue(
+ vl.dataProvider().changeAttributeValues({1: {1: QByteArray(b"bbbvx")}})
+ )
+ values = {feat["pk"]: feat["blobby"] for feat in vl.getFeatures()}
+ expected = {1: QByteArray(b"bbbvx")}
self.assertEqual(values, expected)
# add feature
f = QgsFeature()
- f.setAttributes([2, QByteArray(b'cccc')])
+ f.setAttributes([2, QByteArray(b"cccc")])
self.assertTrue(vl.dataProvider().addFeature(f))
- values = {feat['pk']: feat['blobby'] for feat in vl.getFeatures()}
- expected = {
- 1: QByteArray(b'bbbvx'),
- 2: QByteArray(b'cccc')
- }
+ values = {feat["pk"]: feat["blobby"] for feat in vl.getFeatures()}
+ expected = {1: QByteArray(b"bbbvx"), 2: QByteArray(b"cccc")}
self.assertEqual(values, expected)
# change feature
- self.assertTrue(vl.dataProvider().changeFeatures(
- {2: {1: QByteArray(b'dddd')}}, {}))
- values = {feat['pk']: feat['blobby'] for feat in vl.getFeatures()}
- expected = {
- 1: QByteArray(b'bbbvx'),
- 2: QByteArray(b'dddd')
- }
+ self.assertTrue(
+ vl.dataProvider().changeFeatures({2: {1: QByteArray(b"dddd")}}, {})
+ )
+ values = {feat["pk"]: feat["blobby"] for feat in vl.getFeatures()}
+ expected = {1: QByteArray(b"bbbvx"), 2: QByteArray(b"dddd")}
self.assertEqual(values, expected)
def testCitextType(self):
- vl = QgsVectorLayer('{} table="qgis_test"."citext_table" sql='.format(
- self.dbconn), "testbytea", "postgres")
+ vl = QgsVectorLayer(
+ f'{self.dbconn} table="qgis_test"."citext_table" sql=',
+ "testbytea",
+ "postgres",
+ )
self.assertTrue(vl.isValid())
fields = vl.dataProvider().fields()
self.assertEqual(
- fields.at(fields.indexFromName('fld1')).type(), QVariant.String)
+ fields.at(fields.indexFromName("fld1")).type(), QVariant.String
+ )
- values = {feat['id']: feat['fld1'] for feat in vl.getFeatures()}
- expected = {
- 1: 'test val',
- 2: NULL
- }
+ values = {feat["id"]: feat["fld1"] for feat in vl.getFeatures()}
+ expected = {1: "test val", 2: NULL}
self.assertEqual(values, expected)
# editing citext values
self.execSQLCommand(
- 'DROP TABLE IF EXISTS qgis_test."citext_table_edit" CASCADE')
+ 'DROP TABLE IF EXISTS qgis_test."citext_table_edit" CASCADE'
+ )
+ self.execSQLCommand(
+ 'CREATE TABLE qgis_test."citext_table_edit" ( pk SERIAL NOT NULL PRIMARY KEY, txt citext)'
+ )
self.execSQLCommand(
- 'CREATE TABLE qgis_test."citext_table_edit" ( pk SERIAL NOT NULL PRIMARY KEY, txt citext)')
- self.execSQLCommand("INSERT INTO qgis_test.\"citext_table_edit\" (pk, txt) VALUES "
- "(1, 'text')")
+ 'INSERT INTO qgis_test."citext_table_edit" (pk, txt) VALUES ' "(1, 'text')"
+ )
vl = QgsVectorLayer(
self.dbconn + ' sslmode=disable table="qgis_test"."citext_table_edit" sql=',
- 'test', 'postgres')
+ "test",
+ "postgres",
+ )
self.assertTrue(vl.isValid())
- values = {feat['pk']: feat['txt'] for feat in vl.getFeatures()}
- expected = {
- 1: 'text'
- }
+ values = {feat["pk"]: feat["txt"] for feat in vl.getFeatures()}
+ expected = {1: "text"}
self.assertEqual(values, expected)
# change attribute value
- self.assertTrue(
- vl.dataProvider().changeAttributeValues({1: {1: 'teeeext'}}))
- values = {feat['pk']: feat['txt'] for feat in vl.getFeatures()}
- expected = {
- 1: 'teeeext'
- }
+ self.assertTrue(vl.dataProvider().changeAttributeValues({1: {1: "teeeext"}}))
+ values = {feat["pk"]: feat["txt"] for feat in vl.getFeatures()}
+ expected = {1: "teeeext"}
self.assertEqual(values, expected)
# add feature
f = QgsFeature()
- f.setAttributes([2, 'teeeeeeeeeext'])
+ f.setAttributes([2, "teeeeeeeeeext"])
self.assertTrue(vl.dataProvider().addFeature(f))
- values = {feat['pk']: feat['txt'] for feat in vl.getFeatures()}
- expected = {
- 1: 'teeeext',
- 2: 'teeeeeeeeeext'
- }
+ values = {feat["pk"]: feat["txt"] for feat in vl.getFeatures()}
+ expected = {1: "teeeext", 2: "teeeeeeeeeext"}
self.assertEqual(values, expected)
# change feature
- self.assertTrue(vl.dataProvider().changeFeatures(
- {2: {1: 'teeeeeeeeeeeeeeeeeeeeeeext'}}, {}))
- values = {feat['pk']: feat['txt'] for feat in vl.getFeatures()}
- expected = {
- 1: 'teeeext',
- 2: 'teeeeeeeeeeeeeeeeeeeeeeext'
- }
+ self.assertTrue(
+ vl.dataProvider().changeFeatures({2: {1: "teeeeeeeeeeeeeeeeeeeeeeext"}}, {})
+ )
+ values = {feat["pk"]: feat["txt"] for feat in vl.getFeatures()}
+ expected = {1: "teeeext", 2: "teeeeeeeeeeeeeeeeeeeeeeext"}
self.assertEqual(values, expected)
def testQueryLayers(self):
def test_query(dbconn, query, key):
ql = QgsVectorLayer(
- '{} srid=4326 table="{}" (geom) key=\'{}\' sql='.format(
- dbconn, query.replace('"', '\\"'), key), "testgeom",
- "postgres")
- self.assertTrue(ql.isValid(), f'{query} ({key})')
-
- test_query(self.dbconn,
- '(SELECT NULL::integer "Id1", NULL::integer "Id2", NULL::geometry(Point, 4326) geom LIMIT 0)',
- '"Id1","Id2"')
+ "{} srid=4326 table=\"{}\" (geom) key='{}' sql=".format(
+ dbconn, query.replace('"', '\\"'), key
+ ),
+ "testgeom",
+ "postgres",
+ )
+ self.assertTrue(ql.isValid(), f"{query} ({key})")
+
+ test_query(
+ self.dbconn,
+ '(SELECT NULL::integer "Id1", NULL::integer "Id2", NULL::geometry(Point, 4326) geom LIMIT 0)',
+ '"Id1","Id2"',
+ )
def testWkbTypes(self):
def test_table(dbconn, table_name, wkt):
- vl = QgsVectorLayer(f'{dbconn} srid=4326 table="qgis_test".{table_name} (geom) sql=', "testgeom",
- "postgres")
+ vl = QgsVectorLayer(
+ f'{dbconn} srid=4326 table="qgis_test".{table_name} (geom) sql=',
+ "testgeom",
+ "postgres",
+ )
self.assertTrue(vl.isValid())
for f in vl.getFeatures():
self.assertEqual(f.geometry().asWkt(), wkt)
- test_table(self.dbconn, 'p2d', 'Polygon ((0 0, 1 0, 1 1, 0 1, 0 0))')
- test_table(self.dbconn, 'p3d',
- 'Polygon Z ((0 0 0, 1 0 0, 1 1 0, 0 1 0, 0 0 0))')
- test_table(self.dbconn, 'triangle2d', 'Triangle ((0 0, 1 0, 1 1, 0 0))')
- test_table(self.dbconn, 'triangle3d',
- 'Triangle Z ((0 0 0, 1 0 0, 1 1 0, 0 0 0))')
- test_table(self.dbconn, 'tin2d',
- 'TIN (((0 0, 1 0, 1 1, 0 0)),((0 0, 0 1, 1 1, 0 0)))')
- test_table(self.dbconn, 'tin3d',
- 'TIN Z (((0 0 0, 1 0 0, 1 1 0, 0 0 0)),((0 0 0, 0 1 0, 1 1 0, 0 0 0)))')
- test_table(self.dbconn, 'ps2d',
- 'PolyhedralSurface (((0 0, 1 0, 1 1, 0 1, 0 0)))')
- test_table(self.dbconn, 'ps3d',
- 'PolyhedralSurface Z (((0 0 0, 0 1 0, 1 1 0, 1 0 0, 0 0 0)),((0 0 1, 1 0 1, 1 1 1, 0 1 1, 0 0 1)),((0 0 0, 0 0 1, 0 1 1, 0 1 0, 0 0 0)),((0 1 0, 0 1 1, 1 1 1, 1 1 0, 0 1 0)),((1 1 0, 1 1 1, 1 0 1, 1 0 0, 1 1 0)),((1 0 0, 1 0 1, 0 0 1, 0 0 0, 1 0 0)))')
- test_table(self.dbconn, 'mp3d',
- 'MultiPolygon Z (((0 0 0, 0 1 0, 1 1 0, 1 0 0, 0 0 0)),((0 0 1, 1 0 1, 1 1 1, 0 1 1, 0 0 1)),((0 0 0, 0 0 1, 0 1 1, 0 1 0, 0 0 0)),((0 1 0, 0 1 1, 1 1 1, 1 1 0, 0 1 0)),((1 1 0, 1 1 1, 1 0 1, 1 0 0, 1 1 0)),((1 0 0, 1 0 1, 0 0 1, 0 0 0, 1 0 0)))')
- test_table(self.dbconn, 'pt2d', 'Point (0 0)')
- test_table(self.dbconn, 'pt3d', 'Point Z (0 0 0)')
- test_table(self.dbconn, 'ls2d', 'LineString (0 0, 1 1)')
- test_table(self.dbconn, 'ls3d', 'LineString Z (0 0 0, 1 1 1)')
- test_table(self.dbconn, 'mpt2d', 'MultiPoint ((0 0),(1 1))')
- test_table(self.dbconn, 'mpt3d', 'MultiPoint Z ((0 0 0),(1 1 1))')
- test_table(self.dbconn, 'mls2d',
- 'MultiLineString ((0 0, 1 1),(2 2, 3 3))')
- test_table(self.dbconn, 'mls3d',
- 'MultiLineString Z ((0 0 0, 1 1 1),(2 2 2, 3 3 3))')
-
- test_table(self.dbconn, 'pt4d', 'Point ZM (1 2 3 4)')
+ test_table(self.dbconn, "p2d", "Polygon ((0 0, 1 0, 1 1, 0 1, 0 0))")
+ test_table(
+ self.dbconn, "p3d", "Polygon Z ((0 0 0, 1 0 0, 1 1 0, 0 1 0, 0 0 0))"
+ )
+ test_table(self.dbconn, "triangle2d", "Triangle ((0 0, 1 0, 1 1, 0 0))")
+ test_table(
+ self.dbconn, "triangle3d", "Triangle Z ((0 0 0, 1 0 0, 1 1 0, 0 0 0))"
+ )
+ test_table(
+ self.dbconn, "tin2d", "TIN (((0 0, 1 0, 1 1, 0 0)),((0 0, 0 1, 1 1, 0 0)))"
+ )
+ test_table(
+ self.dbconn,
+ "tin3d",
+ "TIN Z (((0 0 0, 1 0 0, 1 1 0, 0 0 0)),((0 0 0, 0 1 0, 1 1 0, 0 0 0)))",
+ )
+ test_table(
+ self.dbconn, "ps2d", "PolyhedralSurface (((0 0, 1 0, 1 1, 0 1, 0 0)))"
+ )
+ test_table(
+ self.dbconn,
+ "ps3d",
+ "PolyhedralSurface Z (((0 0 0, 0 1 0, 1 1 0, 1 0 0, 0 0 0)),((0 0 1, 1 0 1, 1 1 1, 0 1 1, 0 0 1)),((0 0 0, 0 0 1, 0 1 1, 0 1 0, 0 0 0)),((0 1 0, 0 1 1, 1 1 1, 1 1 0, 0 1 0)),((1 1 0, 1 1 1, 1 0 1, 1 0 0, 1 1 0)),((1 0 0, 1 0 1, 0 0 1, 0 0 0, 1 0 0)))",
+ )
+ test_table(
+ self.dbconn,
+ "mp3d",
+ "MultiPolygon Z (((0 0 0, 0 1 0, 1 1 0, 1 0 0, 0 0 0)),((0 0 1, 1 0 1, 1 1 1, 0 1 1, 0 0 1)),((0 0 0, 0 0 1, 0 1 1, 0 1 0, 0 0 0)),((0 1 0, 0 1 1, 1 1 1, 1 1 0, 0 1 0)),((1 1 0, 1 1 1, 1 0 1, 1 0 0, 1 1 0)),((1 0 0, 1 0 1, 0 0 1, 0 0 0, 1 0 0)))",
+ )
+ test_table(self.dbconn, "pt2d", "Point (0 0)")
+ test_table(self.dbconn, "pt3d", "Point Z (0 0 0)")
+ test_table(self.dbconn, "ls2d", "LineString (0 0, 1 1)")
+ test_table(self.dbconn, "ls3d", "LineString Z (0 0 0, 1 1 1)")
+ test_table(self.dbconn, "mpt2d", "MultiPoint ((0 0),(1 1))")
+ test_table(self.dbconn, "mpt3d", "MultiPoint Z ((0 0 0),(1 1 1))")
+ test_table(self.dbconn, "mls2d", "MultiLineString ((0 0, 1 1),(2 2, 3 3))")
+ test_table(
+ self.dbconn, "mls3d", "MultiLineString Z ((0 0 0, 1 1 1),(2 2 2, 3 3 3))"
+ )
+
+ test_table(self.dbconn, "pt4d", "Point ZM (1 2 3 4)")
def testMetadata(self):
- """ Test that metadata is correctly acquired from provider """
+ """Test that metadata is correctly acquired from provider"""
metadata = self.vl.metadata()
- self.assertEqual(
- metadata.crs(), QgsCoordinateReferenceSystem.fromEpsgId(4326))
- self.assertEqual(metadata.type(), 'dataset')
- self.assertEqual(metadata.abstract(), 'QGIS Test Table')
+ self.assertEqual(metadata.crs(), QgsCoordinateReferenceSystem.fromEpsgId(4326))
+ self.assertEqual(metadata.type(), "dataset")
+ self.assertEqual(metadata.abstract(), "QGIS Test Table")
def testGetFeaturesUniqueId(self):
"""
@@ -479,33 +556,48 @@ def test_unique(features, num_features):
featureids.append(f.id())
self.assertEqual(len(features), num_features)
- vl = QgsVectorLayer(f"{self.dbconn} srid=4326 table=\"qgis_test\".someData (geom) sql=", "testgeom",
- "postgres")
+ vl = QgsVectorLayer(
+ f'{self.dbconn} srid=4326 table="qgis_test".someData (geom) sql=',
+ "testgeom",
+ "postgres",
+ )
self.assertTrue(vl.isValid())
# Test someData
test_unique([f for f in vl.getFeatures()], 5)
# Test base_table_bad: layer is invalid
- vl = QgsVectorLayer(f"{self.dbconn} srid=4326 table=\"qgis_test\".base_table_bad (geom) sql=",
- "testgeom", "postgres")
+ vl = QgsVectorLayer(
+ f'{self.dbconn} srid=4326 table="qgis_test".base_table_bad (geom) sql=',
+ "testgeom",
+ "postgres",
+ )
self.assertFalse(vl.isValid())
# Test base_table_bad with use estimated metadata: layer is valid because the unique test is skipped
vl = QgsVectorLayer(
'{} srid=4326 estimatedmetadata="true" table="qgis_test".{} (geom) sql='.format(
- self.dbconn, 'base_table_bad'),
- "testgeom", "postgres")
+ self.dbconn, "base_table_bad"
+ ),
+ "testgeom",
+ "postgres",
+ )
self.assertTrue(vl.isValid())
# Test base_table_good: layer is valid
- vl = QgsVectorLayer(f"{self.dbconn} srid=4326 table=\"qgis_test\".base_table_good (geom) sql=",
- "testgeom", "postgres")
+ vl = QgsVectorLayer(
+ f'{self.dbconn} srid=4326 table="qgis_test".base_table_good (geom) sql=',
+ "testgeom",
+ "postgres",
+ )
self.assertTrue(vl.isValid())
test_unique([f for f in vl.getFeatures()], 4)
# Test base_table_good with use estimated metadata: layer is valid
vl = QgsVectorLayer(
'{} srid=4326 estimatedmetadata="true" table="qgis_test".{} (geom) sql='.format(
- self.dbconn, 'base_table_good'),
- "testgeom", "postgres")
+ self.dbconn, "base_table_good"
+ ),
+ "testgeom",
+ "postgres",
+ )
self.assertTrue(vl.isValid())
test_unique([f for f in vl.getFeatures()], 4)
@@ -526,7 +618,7 @@ def test_layer(ql, att, val, fidval):
def test(dbconn, query, att, val, fidval):
table = query.replace('"', '\\"')
- uri = f'{dbconn} table="{table}" (g) key=\'{att}\''
+ uri = f"{dbconn} table=\"{table}\" (g) key='{att}'"
ql = QgsVectorLayer(uri, "t", "postgres")
test_layer(ql, att, val, fidval)
# now with estimated metadata
@@ -535,58 +627,101 @@ def test(dbconn, query, att, val, fidval):
# --- INT16 ----
# zero
- test(self.dbconn, '(SELECT 0::int2 i, NULL::geometry(Point) g)', 'i', 0, 0)
+ test(self.dbconn, "(SELECT 0::int2 i, NULL::geometry(Point) g)", "i", 0, 0)
# low positive
- test(self.dbconn, '(SELECT 1::int2 i, NULL::geometry(Point) g)', 'i', 1, 1)
+ test(self.dbconn, "(SELECT 1::int2 i, NULL::geometry(Point) g)", "i", 1, 1)
# low negative
- test(self.dbconn, '(SELECT -1::int2 i, NULL::geometry(Point) g)',
- 'i', -1, 4294967295)
+ test(
+ self.dbconn,
+ "(SELECT -1::int2 i, NULL::geometry(Point) g)",
+ "i",
+ -1,
+ 4294967295,
+ )
# max positive signed 16bit integer
- test(self.dbconn, '(SELECT 32767::int2 i, NULL::geometry(Point) g)',
- 'i', 32767, 32767)
+ test(
+ self.dbconn,
+ "(SELECT 32767::int2 i, NULL::geometry(Point) g)",
+ "i",
+ 32767,
+ 32767,
+ )
# max negative signed 16bit integer
- test(self.dbconn, '(SELECT (-32768)::int2 i, NULL::geometry(Point) g)',
- 'i', -32768, 4294934528)
+ test(
+ self.dbconn,
+ "(SELECT (-32768)::int2 i, NULL::geometry(Point) g)",
+ "i",
+ -32768,
+ 4294934528,
+ )
# --- INT32 ----
# zero
- test(self.dbconn, '(SELECT 0::int4 i, NULL::geometry(Point) g)', 'i', 0, 0)
+ test(self.dbconn, "(SELECT 0::int4 i, NULL::geometry(Point) g)", "i", 0, 0)
# low positive
- test(self.dbconn, '(SELECT 2::int4 i, NULL::geometry(Point) g)', 'i', 2, 2)
+ test(self.dbconn, "(SELECT 2::int4 i, NULL::geometry(Point) g)", "i", 2, 2)
# low negative
- test(self.dbconn, '(SELECT -2::int4 i, NULL::geometry(Point) g)',
- 'i', -2, 4294967294)
+ test(
+ self.dbconn,
+ "(SELECT -2::int4 i, NULL::geometry(Point) g)",
+ "i",
+ -2,
+ 4294967294,
+ )
# max positive signed 32bit integer
- test(self.dbconn, '(SELECT 2147483647::int4 i, NULL::geometry(Point) g)',
- 'i', 2147483647, 2147483647)
+ test(
+ self.dbconn,
+ "(SELECT 2147483647::int4 i, NULL::geometry(Point) g)",
+ "i",
+ 2147483647,
+ 2147483647,
+ )
# max negative signed 32bit integer
- test(self.dbconn, '(SELECT (-2147483648)::int4 i, NULL::geometry(Point) g)',
- 'i', -2147483648, 2147483648)
+ test(
+ self.dbconn,
+ "(SELECT (-2147483648)::int4 i, NULL::geometry(Point) g)",
+ "i",
+ -2147483648,
+ 2147483648,
+ )
# --- INT64 (FIDs are always 1 because assigned ex-novo) ----
# zero
- test(self.dbconn, '(SELECT 0::int8 i, NULL::geometry(Point) g)', 'i', 0, 1)
+ test(self.dbconn, "(SELECT 0::int8 i, NULL::geometry(Point) g)", "i", 0, 1)
# low positive
- test(self.dbconn, '(SELECT 3::int8 i, NULL::geometry(Point) g)', 'i', 3, 1)
+ test(self.dbconn, "(SELECT 3::int8 i, NULL::geometry(Point) g)", "i", 3, 1)
# low negative
- test(self.dbconn, '(SELECT -3::int8 i, NULL::geometry(Point) g)', 'i', -3, 1)
+ test(self.dbconn, "(SELECT -3::int8 i, NULL::geometry(Point) g)", "i", -3, 1)
# max positive signed 64bit integer
- test(self.dbconn, '(SELECT 9223372036854775807::int8 i, NULL::geometry(Point) g)',
- 'i', 9223372036854775807, 1)
+ test(
+ self.dbconn,
+ "(SELECT 9223372036854775807::int8 i, NULL::geometry(Point) g)",
+ "i",
+ 9223372036854775807,
+ 1,
+ )
# max negative signed 32bit integer
- test(self.dbconn, '(SELECT (-9223372036854775808)::int8 i, NULL::geometry(Point) g)', 'i', -9223372036854775808,
- 1)
+ test(
+ self.dbconn,
+ "(SELECT (-9223372036854775808)::int8 i, NULL::geometry(Point) g)",
+ "i",
+ -9223372036854775808,
+ 1,
+ )
def testPktIntInsert(self):
- vl = QgsVectorLayer(f"{self.dbconn} table=\"qgis_test\".\"bikes_view\" key=\"pk\" sql=", "bikes_view",
- "postgres")
+ vl = QgsVectorLayer(
+ f'{self.dbconn} table="qgis_test"."bikes_view" key="pk" sql=',
+ "bikes_view",
+ "postgres",
+ )
self.assertTrue(vl.isValid())
f = QgsFeature(vl.fields())
- f['pk'] = NULL
- f['name'] = 'Cilo'
+ f["pk"] = NULL
+ f["name"] = "Cilo"
r, f = vl.dataProvider().addFeatures([f])
self.assertTrue(r)
- self.assertNotEqual(f[0]['pk'], NULL, f[0].attributes())
+ self.assertNotEqual(f[0]["pk"], NULL, f[0].attributes())
vl.deleteFeatures([f[0].id()])
def testGeneratedFields(self):
@@ -600,184 +735,251 @@ def testGeneratedFields(self):
return
# Backup test table (will be edited)
- self.execSQLCommand('DROP TABLE IF EXISTS qgis_test.test_gen_col_edit CASCADE')
- self.execSQLCommand('CREATE TABLE qgis_test.test_gen_col_edit AS SELECT id,name,geom FROM qgis_test.test_gen_col')
+ self.execSQLCommand("DROP TABLE IF EXISTS qgis_test.test_gen_col_edit CASCADE")
+ self.execSQLCommand(
+ "CREATE TABLE qgis_test.test_gen_col_edit AS SELECT id,name,geom FROM qgis_test.test_gen_col"
+ )
# Geometry columns
- vl = QgsVectorLayer(f"{self.dbconn} table=\"qgis_test\".\"test_gen_col\" (geom) srid=4326 type=POLYGON key=\"id\" sql=", "test_gen_col", "postgres")
+ vl = QgsVectorLayer(
+ f'{self.dbconn} table="qgis_test"."test_gen_col" (geom) srid=4326 type=POLYGON key="id" sql=',
+ "test_gen_col",
+ "postgres",
+ )
self.assertTrue(vl.isValid())
# writing geometry...
f = QgsFeature(vl.fields())
- ix_name = f.fieldNameIndex('name')
+ ix_name = f.fieldNameIndex("name")
- f.setGeometry(QgsGeometry.fromWkt('Polygon ((-67 -2, -67 0, -68 0, -70 -1, -67 -2))'))
- f.setAttribute(ix_name, 'QGIS-3')
+ f.setGeometry(
+ QgsGeometry.fromWkt("Polygon ((-67 -2, -67 0, -68 0, -70 -1, -67 -2))")
+ )
+ f.setAttribute(ix_name, "QGIS-3")
self.assertTrue(vl.startEditing())
self.assertTrue(vl.addFeatures([f]))
self.assertTrue(vl.commitChanges())
# reading back to see if we saved the centroid correctly.
- vl2 = QgsVectorLayer(f"{self.dbconn} table=\"qgis_test\".\"test_gen_col\" (cent) srid=4326 type=POINT key=\"id\" sql=", "test_gen_col", "postgres")
+ vl2 = QgsVectorLayer(
+ f'{self.dbconn} table="qgis_test"."test_gen_col" (cent) srid=4326 type=POINT key="id" sql=',
+ "test_gen_col",
+ "postgres",
+ )
f2 = next(vl2.getFeatures(QgsFeatureRequest()))
generated_geometry = f2.geometry().asWkt()
- expected_geometry = 'Point (-68.047619047619051 -0.90476190476190477)'
+ expected_geometry = "Point (-68.047619047619051 -0.90476190476190477)"
expected_area = 43069568296.34387
- assert compareWkt(generated_geometry, expected_geometry), f"Geometry mismatch! Expected:\n{expected_geometry}\nGot:\n{generated_geometry}\n"
- self.assertAlmostEqual(f2['poly_area'], expected_area, places=4)
- self.assertEqual(f2['name'], 'QGIS-3')
+ assert compareWkt(
+ generated_geometry, expected_geometry
+ ), f"Geometry mismatch! Expected:\n{expected_geometry}\nGot:\n{generated_geometry}\n"
+ self.assertAlmostEqual(f2["poly_area"], expected_area, places=4)
+ self.assertEqual(f2["name"], "QGIS-3")
# Checking if we can correctly change values of an existing feature.
self.assertTrue(vl2.startEditing())
- ix2_name = f2.fieldNameIndex('name')
+ ix2_name = f2.fieldNameIndex("name")
fid2 = f2.id()
- vl2.changeAttributeValue(fid2, ix2_name, 'New')
+ vl2.changeAttributeValue(fid2, ix2_name, "New")
self.assertTrue(vl2.commitChanges())
# getting a brand new QgsVectorLayer
- vl = QgsVectorLayer(f"{self.dbconn} table=\"qgis_test\".\"test_gen_col\" (geom) srid=4326 type=POLYGON key=\"id\" sql=", "test_gen_col", "postgres")
+ vl = QgsVectorLayer(
+ f'{self.dbconn} table="qgis_test"."test_gen_col" (geom) srid=4326 type=POLYGON key="id" sql=',
+ "test_gen_col",
+ "postgres",
+ )
self.assertTrue(vl.isValid())
# checking if the name field was correctly updated
f = next(vl.getFeatures(QgsFeatureRequest()))
- self.assertEqual(f['name'], 'New')
+ self.assertEqual(f["name"], "New")
# Now, check if we can change the value of a GENERATED field (we shouldn't)
self.assertTrue(vl.startEditing())
- ix_area = f.fieldNameIndex('poly_area')
+ ix_area = f.fieldNameIndex("poly_area")
fid = f.id()
vl.changeAttributeValue(fid, ix_area, 42)
self.assertTrue(vl.commitChanges())
# reading back
- vl2 = QgsVectorLayer(f"{self.dbconn} table=\"qgis_test\".\"test_gen_col\" (geom) srid=4326 type=POLYGON key=\"id\" sql=", "test_gen_col", "postgres")
+ vl2 = QgsVectorLayer(
+ f'{self.dbconn} table="qgis_test"."test_gen_col" (geom) srid=4326 type=POLYGON key="id" sql=',
+ "test_gen_col",
+ "postgres",
+ )
f2 = next(vl2.getFeatures(QgsFeatureRequest()))
- self.assertAlmostEqual(f2['poly_area'], expected_area, places=4)
+ self.assertAlmostEqual(f2["poly_area"], expected_area, places=4)
# now, getting a brand new QgsVectorLayer to check if changes (UPDATE) in the geometry are reflected in the generated fields
- vl = QgsVectorLayer(f"{self.dbconn} table=\"qgis_test\".\"test_gen_col\" (geom) srid=4326 type=POLYGON key=\"id\" sql=", "test_gen_col", "postgres")
+ vl = QgsVectorLayer(
+ f'{self.dbconn} table="qgis_test"."test_gen_col" (geom) srid=4326 type=POLYGON key="id" sql=',
+ "test_gen_col",
+ "postgres",
+ )
self.assertTrue(vl.isValid())
f = next(vl.getFeatures(QgsFeatureRequest()))
vl.startEditing()
fid = f.id()
- vl.changeGeometry(fid, QgsGeometry.fromWkt('Polygon ((-67 -2, -65 0, -68 0, -70 -1, -67 -2))'))
+ vl.changeGeometry(
+ fid, QgsGeometry.fromWkt("Polygon ((-67 -2, -65 0, -68 0, -70 -1, -67 -2))")
+ )
vl.commitChanges()
# reading back...
- vl2 = QgsVectorLayer(f"{self.dbconn} table=\"qgis_test\".\"test_gen_col\" (cent) srid=4326 type=POINT key=\"id\" sql=", "test_gen_col", "postgres")
+ vl2 = QgsVectorLayer(
+ f'{self.dbconn} table="qgis_test"."test_gen_col" (cent) srid=4326 type=POINT key="id" sql=',
+ "test_gen_col",
+ "postgres",
+ )
f2 = next(vl2.getFeatures(QgsFeatureRequest()))
generated_geometry = f2.geometry().asWkt()
generated_geometry = f2.geometry().asWkt()
- expected_geometry = 'Point (-67.42424242424242209 -0.81818181818181823)'
+ expected_geometry = "Point (-67.42424242424242209 -0.81818181818181823)"
expected_area = 67718478405.28429
- assert compareWkt(generated_geometry, expected_geometry), f"Geometry mismatch! Expected:\n{expected_geometry}\nGot:\n{generated_geometry}\n"
- self.assertAlmostEqual(f2['poly_area'], expected_area, places=4)
- self.assertEqual(f2['name'], 'New')
+ assert compareWkt(
+ generated_geometry, expected_geometry
+ ), f"Geometry mismatch! Expected:\n{expected_geometry}\nGot:\n{generated_geometry}\n"
+ self.assertAlmostEqual(f2["poly_area"], expected_area, places=4)
+ self.assertEqual(f2["name"], "New")
# Geography columns
- vl3 = QgsVectorLayer(f"{self.dbconn} table=\"qgis_test\".\"test_gen_geog_col\" (geog) srid=4326 type=POLYGON key=\"id\" sql=", "test_gen_geog_col", "postgres")
+ vl3 = QgsVectorLayer(
+ f'{self.dbconn} table="qgis_test"."test_gen_geog_col" (geog) srid=4326 type=POLYGON key="id" sql=',
+ "test_gen_geog_col",
+ "postgres",
+ )
self.assertTrue(vl3.isValid())
# writing geography...
f3 = QgsFeature(vl3.fields())
- f3.setGeometry(QgsGeometry.fromWkt('Polygon ((-67 -2, -67 0, -68 0, -70 -1, -67 -2))'))
+ f3.setGeometry(
+ QgsGeometry.fromWkt("Polygon ((-67 -2, -67 0, -68 0, -70 -1, -67 -2))")
+ )
self.assertTrue(vl3.startEditing())
self.assertTrue(vl3.addFeatures([f3]))
self.assertTrue(vl3.commitChanges())
# reading back geography and checking values
- vl4 = QgsVectorLayer(f"{self.dbconn} table=\"qgis_test\".\"test_gen_geog_col\" (cent) srid=4326 type=POINT key=\"id\" sql=", "test_gen_geog_col", "postgres")
+ vl4 = QgsVectorLayer(
+ f'{self.dbconn} table="qgis_test"."test_gen_geog_col" (cent) srid=4326 type=POINT key="id" sql=',
+ "test_gen_geog_col",
+ "postgres",
+ )
f4 = next(vl4.getFeatures(QgsFeatureRequest()))
generated_geometry = f4.geometry().asWkt()
- expected_geometry = 'Point (-68.0477406158202 -0.904960604589168)'
+ expected_geometry = "Point (-68.0477406158202 -0.904960604589168)"
expected_area = 43088884296.69713
- assert compareWkt(generated_geometry, expected_geometry), f"Geometry mismatch! Expected:\n{expected_geometry}\nGot:\n{generated_geometry}\n"
- self.assertEqual(f4['poly_area'], expected_area)
+ assert compareWkt(
+ generated_geometry, expected_geometry
+ ), f"Geometry mismatch! Expected:\n{expected_geometry}\nGot:\n{generated_geometry}\n"
+ self.assertEqual(f4["poly_area"], expected_area)
# Restore test table (after editing it)
- self.execSQLCommand('TRUNCATE TABLE qgis_test.test_gen_col')
- self.execSQLCommand('INSERT INTO qgis_test.test_gen_col(id,name,geom) SELECT id,name,geom FROM qgis_test.test_gen_col_edit')
- self.execSQLCommand('DROP TABLE qgis_test.test_gen_col_edit')
+ self.execSQLCommand("TRUNCATE TABLE qgis_test.test_gen_col")
+ self.execSQLCommand(
+ "INSERT INTO qgis_test.test_gen_col(id,name,geom) SELECT id,name,geom FROM qgis_test.test_gen_col_edit"
+ )
+ self.execSQLCommand("DROP TABLE qgis_test.test_gen_col_edit")
def testNonPkBigintField(self):
"""Test if we can correctly insert, read and change attributes(fields) of type bigint and which are not PKs."""
vl = QgsVectorLayer(
'{} sslmode=disable srid=4326 key="pk" table="qgis_test".{} (geom)'.format(
- self.dbconn, 'bigint_pk'),
- "bigint_pk", "postgres")
+ self.dbconn, "bigint_pk"
+ ),
+ "bigint_pk",
+ "postgres",
+ )
self.assertTrue(vl.isValid())
flds = vl.fields()
# Backup test table (will be edited)
- scopedBackup = self.scopedTableBackup('qgis_test', 'bigint_pk')
+ scopedBackup = self.scopedTableBackup("qgis_test", "bigint_pk")
# check if default values are correctly read back
f = next(vl.getFeatures(QgsFeatureRequest()))
- bigint_with_default_idx = vl.fields().lookupField('bigint_attribute_def')
+ bigint_with_default_idx = vl.fields().lookupField("bigint_attribute_def")
self.assertEqual(f.attributes()[bigint_with_default_idx], 42)
# check if NULL values are correctly read
- bigint_def_null_idx = vl.fields().lookupField('bigint_attribute')
+ bigint_def_null_idx = vl.fields().lookupField("bigint_attribute")
self.assertEqual(f.attributes()[bigint_def_null_idx], NULL)
# check if we can overwrite a default value
vl.startEditing()
vl.changeAttributeValue(f.id(), bigint_with_default_idx, 43)
- pkidx = vl.fields().lookupField('pk')
+ pkidx = vl.fields().lookupField("pk")
editedid = f.attributes()[pkidx]
self.assertTrue(vl.commitChanges())
vl2 = QgsVectorLayer(
'{} sslmode=disable srid=4326 key="pk" table="qgis_test".{} (geom)'.format(
- self.dbconn, 'bigint_pk'),
- "bigint_pk", "postgres")
+ self.dbconn, "bigint_pk"
+ ),
+ "bigint_pk",
+ "postgres",
+ )
flds = vl2.fields()
self.assertTrue(vl2.isValid())
- f = next(vl2.getFeatures(
- QgsFeatureRequest().setFilterExpression('pk = ' + str(editedid))))
- bigint_with_default_idx = vl2.fields().lookupField('bigint_attribute_def')
+ f = next(
+ vl2.getFeatures(
+ QgsFeatureRequest().setFilterExpression("pk = " + str(editedid))
+ )
+ )
+ bigint_with_default_idx = vl2.fields().lookupField("bigint_attribute_def")
self.assertEqual(f.attributes()[bigint_with_default_idx], 43)
# check if we can insert a new value
dp = vl2.dataProvider()
- dp.setProviderProperty(QgsDataProvider.ProviderProperty.EvaluateDefaultValues, 1)
- pkidx = vl2.fields().lookupField('pk')
+ dp.setProviderProperty(
+ QgsDataProvider.ProviderProperty.EvaluateDefaultValues, 1
+ )
+ pkidx = vl2.fields().lookupField("pk")
vl2.startEditing()
f = QgsFeature(vl2.fields())
- f['pk'] = NULL
- f['value'] = 'The answer.'
- f['bigint_attribute'] = 84
+ f["pk"] = NULL
+ f["value"] = "The answer."
+ f["bigint_attribute"] = 84
f.setAttribute(pkidx, vl2.dataProvider().defaultValue(pkidx))
- f.setAttribute(bigint_with_default_idx,
- vl2.dataProvider().defaultValue(bigint_with_default_idx))
+ f.setAttribute(
+ bigint_with_default_idx,
+ vl2.dataProvider().defaultValue(bigint_with_default_idx),
+ )
r, f = vl2.dataProvider().addFeatures([f])
self.assertTrue(r)
vl2.commitChanges()
- inserted_id = f[0]['pk']
+ inserted_id = f[0]["pk"]
- f = next(vl2.getFeatures(
- QgsFeatureRequest().setFilterExpression('pk = ' + str(inserted_id))))
+ f = next(
+ vl2.getFeatures(
+ QgsFeatureRequest().setFilterExpression("pk = " + str(inserted_id))
+ )
+ )
- self.assertEqual(f['bigint_attribute'], 84)
- self.assertEqual(f['bigint_attribute_def'], 42)
+ self.assertEqual(f["bigint_attribute"], 84)
+ self.assertEqual(f["bigint_attribute_def"], 42)
def testPktUpdateBigintPk(self):
"""Test if we can update objects with positive, zero and negative bigint PKs."""
vl = QgsVectorLayer(
'{} sslmode=disable srid=4326 key="pk" table="qgis_test".{} (geom)'.format(
- self.dbconn, 'bigint_pk'),
- "bigint_pk", "postgres")
+ self.dbconn, "bigint_pk"
+ ),
+ "bigint_pk",
+ "postgres",
+ )
flds = vl.fields()
# Backup test table (will be edited)
- scopedBackup = self.scopedTableBackup('qgis_test', 'bigint_pk')
+ scopedBackup = self.scopedTableBackup("qgis_test", "bigint_pk")
self.assertTrue(vl.isValid())
@@ -786,21 +988,17 @@ def testPktUpdateBigintPk(self):
statuses = [-1, -1, -1, -1]
# changing values...
for ft in vl.getFeatures():
- if ft['value'] == 'first value':
- vl.changeAttributeValue(
- ft.id(), flds.indexOf('value'), '1st value')
+ if ft["value"] == "first value":
+ vl.changeAttributeValue(ft.id(), flds.indexOf("value"), "1st value")
statuses[0] = 0
- elif ft['value'] == 'second value':
- vl.changeAttributeValue(
- ft.id(), flds.indexOf('value'), '2nd value')
+ elif ft["value"] == "second value":
+ vl.changeAttributeValue(ft.id(), flds.indexOf("value"), "2nd value")
statuses[1] = 0
- elif ft['value'] == 'zero value':
- vl.changeAttributeValue(
- ft.id(), flds.indexOf('value'), '0th value')
+ elif ft["value"] == "zero value":
+ vl.changeAttributeValue(ft.id(), flds.indexOf("value"), "0th value")
statuses[2] = 0
- elif ft['value'] == 'negative value':
- vl.changeAttributeValue(
- ft.id(), flds.indexOf('value'), '-1th value')
+ elif ft["value"] == "negative value":
+ vl.changeAttributeValue(ft.id(), flds.indexOf("value"), "-1th value")
statuses[3] = 0
self.assertTrue(vl.commitChanges())
self.assertTrue(all(x == 0 for x in statuses))
@@ -808,25 +1006,32 @@ def testPktUpdateBigintPk(self):
# now, let's see if the values were changed
vl2 = QgsVectorLayer(
'{} sslmode=disable srid=4326 key="pk" table="qgis_test".{} (geom)'.format(
- self.dbconn, 'bigint_pk'),
- "bigint_pk", "postgres")
+ self.dbconn, "bigint_pk"
+ ),
+ "bigint_pk",
+ "postgres",
+ )
self.assertTrue(vl2.isValid())
for ft in vl2.getFeatures():
- if ft['value'] == '1st value':
+ if ft["value"] == "1st value":
statuses[0] = 1
- elif ft['value'] == '2nd value':
+ elif ft["value"] == "2nd value":
statuses[1] = 1
- elif ft['value'] == '0th value':
+ elif ft["value"] == "0th value":
statuses[2] = 1
- elif ft['value'] == '-1th value':
+ elif ft["value"] == "-1th value":
statuses[3] = 1
self.assertTrue(all(x == 1 for x in statuses))
def testPktUpdateBigintPkNonFirst(self):
"""Test if we can update objects with positive, zero and negative bigint PKs in tables whose PK is not the first field"""
- vl = QgsVectorLayer('{} sslmode=disable srid=4326 key="pk" table="qgis_test".{} (geom)'.format(self.dbconn,
- 'bigint_non_first_pk'),
- "bigint_non_first_pk", "postgres")
+ vl = QgsVectorLayer(
+ '{} sslmode=disable srid=4326 key="pk" table="qgis_test".{} (geom)'.format(
+ self.dbconn, "bigint_non_first_pk"
+ ),
+ "bigint_non_first_pk",
+ "postgres",
+ )
flds = vl.fields()
self.assertTrue(vl.isValid())
@@ -834,28 +1039,24 @@ def testPktUpdateBigintPkNonFirst(self):
vl.startEditing()
# Backup test table (will be edited)
- scopedBackup = self.scopedTableBackup('qgis_test', 'bigint_non_first_pk')
+ scopedBackup = self.scopedTableBackup("qgis_test", "bigint_non_first_pk")
statuses = [-1, -1, -1, -1]
- values = ['first value', 'second value', 'zero value', 'negative value']
- newvalues = ['1st value', '2nd value', '0th value', '-1th value']
+ values = ["first value", "second value", "zero value", "negative value"]
+ newvalues = ["1st value", "2nd value", "0th value", "-1th value"]
# changing values...
for ft in vl.getFeatures():
- if ft['value'] == values[0]:
- vl.changeAttributeValue(
- ft.id(), flds.indexOf('value'), newvalues[0])
+ if ft["value"] == values[0]:
+ vl.changeAttributeValue(ft.id(), flds.indexOf("value"), newvalues[0])
statuses[0] = 0
- elif ft['value'] == values[1]:
- vl.changeAttributeValue(
- ft.id(), flds.indexOf('value'), newvalues[1])
+ elif ft["value"] == values[1]:
+ vl.changeAttributeValue(ft.id(), flds.indexOf("value"), newvalues[1])
statuses[1] = 0
- elif ft['value'] == values[2]:
- vl.changeAttributeValue(
- ft.id(), flds.indexOf('value'), newvalues[2])
+ elif ft["value"] == values[2]:
+ vl.changeAttributeValue(ft.id(), flds.indexOf("value"), newvalues[2])
statuses[2] = 0
- elif ft['value'] == values[3]:
- vl.changeAttributeValue(
- ft.id(), flds.indexOf('value'), newvalues[3])
+ elif ft["value"] == values[3]:
+ vl.changeAttributeValue(ft.id(), flds.indexOf("value"), newvalues[3])
statuses[3] = 0
self.assertTrue(vl.commitChanges())
for i in range(len(statuses)):
@@ -864,79 +1065,110 @@ def testPktUpdateBigintPkNonFirst(self):
# now, let's see if the values were changed
vl2 = QgsVectorLayer(
'{} sslmode=disable srid=4326 key="pk" table="qgis_test".{} (geom)'.format(
- self.dbconn, 'bigint_non_first_pk'),
- "bigint_pk_nonfirst", "postgres")
+ self.dbconn, "bigint_non_first_pk"
+ ),
+ "bigint_pk_nonfirst",
+ "postgres",
+ )
self.assertTrue(vl2.isValid())
for ft in vl2.getFeatures():
- if ft['value'] == newvalues[0]:
+ if ft["value"] == newvalues[0]:
statuses[0] = 1
- elif ft['value'] == newvalues[1]:
+ elif ft["value"] == newvalues[1]:
statuses[1] = 1
- elif ft['value'] == newvalues[2]:
+ elif ft["value"] == newvalues[2]:
statuses[2] = 1
- elif ft['value'] == newvalues[3]:
+ elif ft["value"] == newvalues[3]:
statuses[3] = 1
for i in range(len(statuses)):
- self.assertEqual(statuses[i], 1, f'changed value "{newvalues[i]}" not found')
+ self.assertEqual(
+ statuses[i], 1, f'changed value "{newvalues[i]}" not found'
+ )
def testPktComposite(self):
"""
Check that tables with PKs composed of many fields of different types are correctly read and written to
"""
- vl = QgsVectorLayer(f'{self.dbconn} sslmode=disable srid=4326 key=\'"pk1","pk2"\' table="qgis_test"."tb_test_compound_pk" (geom)', "test_compound", "postgres")
+ vl = QgsVectorLayer(
+ f'{self.dbconn} sslmode=disable srid=4326 key=\'"pk1","pk2"\' table="qgis_test"."tb_test_compound_pk" (geom)',
+ "test_compound",
+ "postgres",
+ )
self.assertTrue(vl.isValid())
fields = vl.fields()
- f = next(vl.getFeatures(QgsFeatureRequest().setFilterExpression('pk1 = 1 AND pk2 = 2')))
+ f = next(
+ vl.getFeatures(
+ QgsFeatureRequest().setFilterExpression("pk1 = 1 AND pk2 = 2")
+ )
+ )
# first of all: we must be able to fetch a valid feature
self.assertTrue(f.isValid())
- self.assertEqual(f['pk1'], 1)
- self.assertEqual(f['pk2'], 2)
- self.assertEqual(f['value'], 'test 2')
+ self.assertEqual(f["pk1"], 1)
+ self.assertEqual(f["pk2"], 2)
+ self.assertEqual(f["value"], "test 2")
# Backup test table (will be edited)
- scopedBackup = self.scopedTableBackup('qgis_test', 'tb_test_compound_pk')
+ scopedBackup = self.scopedTableBackup("qgis_test", "tb_test_compound_pk")
# can we edit a field?
vl.startEditing()
- vl.changeAttributeValue(f.id(), fields.indexOf('value'), 'Edited Test 2')
+ vl.changeAttributeValue(f.id(), fields.indexOf("value"), "Edited Test 2")
self.assertTrue(vl.commitChanges())
# Did we get it right? Let's create a new QgsVectorLayer and try to read back our changes:
- vl2 = QgsVectorLayer(f'{self.dbconn} sslmode=disable srid=4326 table="qgis_test"."tb_test_compound_pk" (geom) key=\'"pk1","pk2"\' ', "test_compound2", "postgres")
+ vl2 = QgsVectorLayer(
+ f'{self.dbconn} sslmode=disable srid=4326 table="qgis_test"."tb_test_compound_pk" (geom) key=\'"pk1","pk2"\' ',
+ "test_compound2",
+ "postgres",
+ )
self.assertTrue(vl2.isValid())
- f2 = next(vl2.getFeatures(QgsFeatureRequest().setFilterExpression('pk1 = 1 AND pk2 = 2')))
+ f2 = next(
+ vl2.getFeatures(
+ QgsFeatureRequest().setFilterExpression("pk1 = 1 AND pk2 = 2")
+ )
+ )
self.assertTrue(f2.isValid())
# Then, making sure we really did change our value.
- self.assertEqual(f2['value'], 'Edited Test 2')
+ self.assertEqual(f2["value"], "Edited Test 2")
# How about inserting a new field?
f3 = QgsFeature(vl2.fields())
- f3['pk1'] = 4
- f3['pk2'] = -9223372036854775800
- f3['value'] = 'other test'
+ f3["pk1"] = 4
+ f3["pk2"] = -9223372036854775800
+ f3["value"] = "other test"
vl.startEditing()
res, f3 = vl.dataProvider().addFeatures([f3])
self.assertTrue(res)
self.assertTrue(vl.commitChanges())
# can we catch it on another layer?
- f4 = next(vl2.getFeatures(QgsFeatureRequest().setFilterExpression('pk2 = -9223372036854775800')))
+ f4 = next(
+ vl2.getFeatures(
+ QgsFeatureRequest().setFilterExpression("pk2 = -9223372036854775800")
+ )
+ )
self.assertTrue(f4.isValid())
- expected_attrs = [4, -9223372036854775800, 'other test']
+ expected_attrs = [4, -9223372036854775800, "other test"]
self.assertEqual(f4.attributes(), expected_attrs)
# Finally, let's delete one of the features.
- f5 = next(vl2.getFeatures(QgsFeatureRequest().setFilterExpression('pk1 = 2 AND pk2 = 1')))
+ f5 = next(
+ vl2.getFeatures(
+ QgsFeatureRequest().setFilterExpression("pk1 = 2 AND pk2 = 1")
+ )
+ )
vl2.startEditing()
vl2.deleteFeatures([f5.id()])
self.assertTrue(vl2.commitChanges())
# did we really delete? Let's try to get the deleted feature from the first layer.
- f_iterator = vl.getFeatures(QgsFeatureRequest().setFilterExpression('pk1 = 2 AND pk2 = 1'))
+ f_iterator = vl.getFeatures(
+ QgsFeatureRequest().setFilterExpression("pk1 = 2 AND pk2 = 1")
+ )
got_feature = True
try:
@@ -951,70 +1183,94 @@ def testPktCompositeFloat(self):
"""
Check that tables with PKs composed of many fields of different types are correctly read and written to
"""
- vl = QgsVectorLayer(f'{self.dbconn} sslmode=disable srid=4326 key=\'"pk1","pk2","pk3"\' table="qgis_test"."tb_test_composite_float_pk" (geom)', "test_composite_float", "postgres")
+ vl = QgsVectorLayer(
+ f'{self.dbconn} sslmode=disable srid=4326 key=\'"pk1","pk2","pk3"\' table="qgis_test"."tb_test_composite_float_pk" (geom)',
+ "test_composite_float",
+ "postgres",
+ )
self.assertTrue(vl.isValid())
fields = vl.fields()
- f = next(vl.getFeatures(QgsFeatureRequest().setFilterExpression("pk3 = '3.14159274'")))
+ f = next(
+ vl.getFeatures(
+ QgsFeatureRequest().setFilterExpression("pk3 = '3.14159274'")
+ )
+ )
# first of all: we must be able to fetch a valid feature
self.assertTrue(f.isValid())
- self.assertEqual(f['pk1'], 1)
- self.assertEqual(f['pk2'], 2)
+ self.assertEqual(f["pk1"], 1)
+ self.assertEqual(f["pk2"], 2)
- self.assertAlmostEqual(f['pk3'], 3.14159274)
- self.assertEqual(f['value'], 'test 2')
+ self.assertAlmostEqual(f["pk3"], 3.14159274)
+ self.assertEqual(f["value"], "test 2")
# Backup test table (will be edited)
- scopedBackup = self.scopedTableBackup('qgis_test', 'tb_test_composite_float_pk')
+ scopedBackup = self.scopedTableBackup("qgis_test", "tb_test_composite_float_pk")
# can we edit a field?
vl.startEditing()
- vl.changeAttributeValue(f.id(), fields.indexOf('value'), 'Edited Test 2')
+ vl.changeAttributeValue(f.id(), fields.indexOf("value"), "Edited Test 2")
self.assertTrue(vl.commitChanges())
# Did we get it right? Let's create a new QgsVectorLayer and try to read back our changes:
- vl2 = QgsVectorLayer(f'{self.dbconn} sslmode=disable srid=4326 key=\'"pk1","pk2","pk3"\' table="qgis_test"."tb_test_composite_float_pk" (geom)', "test_composite_float2", "postgres")
+ vl2 = QgsVectorLayer(
+ f'{self.dbconn} sslmode=disable srid=4326 key=\'"pk1","pk2","pk3"\' table="qgis_test"."tb_test_composite_float_pk" (geom)',
+ "test_composite_float2",
+ "postgres",
+ )
self.assertTrue(vl2.isValid())
- f2 = next(vl.getFeatures(QgsFeatureRequest().setFilterExpression("pk3 = '3.14159274'")))
+ f2 = next(
+ vl.getFeatures(
+ QgsFeatureRequest().setFilterExpression("pk3 = '3.14159274'")
+ )
+ )
self.assertTrue(f2.isValid())
# just making sure we have the correct feature
- self.assertAlmostEqual(f2['pk3'], 3.14159274)
+ self.assertAlmostEqual(f2["pk3"], 3.14159274)
# Then, making sure we really did change our value.
- self.assertEqual(f2['value'], 'Edited Test 2')
+ self.assertEqual(f2["value"], "Edited Test 2")
# How about inserting a new field?
f3 = QgsFeature(vl2.fields())
- f3['pk1'] = 4
- f3['pk2'] = -9223372036854775800
- f3['pk3'] = 7.29154
- f3['value'] = 'other test'
+ f3["pk1"] = 4
+ f3["pk2"] = -9223372036854775800
+ f3["pk3"] = 7.29154
+ f3["value"] = "other test"
vl.startEditing()
res, f3 = vl.dataProvider().addFeatures([f3])
self.assertTrue(res)
self.assertTrue(vl.commitChanges())
# can we catch it on another layer?
- f4 = next(vl2.getFeatures(QgsFeatureRequest().setFilterExpression("pk2 = '-9223372036854775800'")))
+ f4 = next(
+ vl2.getFeatures(
+ QgsFeatureRequest().setFilterExpression("pk2 = '-9223372036854775800'")
+ )
+ )
self.assertTrue(f4.isValid())
- expected_attrs = [4, -9223372036854775800, 7.29154, 'other test']
- gotten_attrs = [f4['pk1'], f4['pk2'], f4['pk3'], f4['value']]
+ expected_attrs = [4, -9223372036854775800, 7.29154, "other test"]
+ gotten_attrs = [f4["pk1"], f4["pk2"], f4["pk3"], f4["value"]]
self.assertEqual(gotten_attrs[0], expected_attrs[0])
self.assertEqual(gotten_attrs[1], expected_attrs[1])
self.assertAlmostEqual(gotten_attrs[2], expected_attrs[2], places=4)
self.assertEqual(gotten_attrs[3], expected_attrs[3])
# Finally, let's delete one of the features.
- f5 = next(vl2.getFeatures(QgsFeatureRequest().setFilterExpression("pk3 = '7.29154'")))
+ f5 = next(
+ vl2.getFeatures(QgsFeatureRequest().setFilterExpression("pk3 = '7.29154'"))
+ )
vl2.startEditing()
vl2.deleteFeatures([f5.id()])
self.assertTrue(vl2.commitChanges())
# did we really delete?
- f_iterator = vl.getFeatures(QgsFeatureRequest().setFilterExpression("pk3 = '7.29154'"))
+ f_iterator = vl.getFeatures(
+ QgsFeatureRequest().setFilterExpression("pk3 = '7.29154'")
+ )
got_feature = True
try:
@@ -1031,34 +1287,66 @@ def testPktFloatingPoint(self):
"""
# 0. Backup test table (will be edited)
- scopedBackup1 = self.scopedTableBackup('qgis_test', 'tb_test_float_pk')
- scopedBackup2 = self.scopedTableBackup('qgis_test', 'tb_test_double_pk')
+ scopedBackup1 = self.scopedTableBackup("qgis_test", "tb_test_float_pk")
+ scopedBackup2 = self.scopedTableBackup("qgis_test", "tb_test_double_pk")
# 1. 32 bit float (PostgreSQL "REAL" type)
- vl = QgsVectorLayer(self.dbconn + ' sslmode=disable srid=4326 key="pk" table="qgis_test"."tb_test_float_pk" (geom)', "test_float_pk", "postgres")
+ vl = QgsVectorLayer(
+ self.dbconn
+ + ' sslmode=disable srid=4326 key="pk" table="qgis_test"."tb_test_float_pk" (geom)',
+ "test_float_pk",
+ "postgres",
+ )
self.assertTrue(vl.isValid())
# 1.1. Retrieving
- f = next(vl.getFeatures(QgsFeatureRequest().setFilterExpression("pk = '3.141592653589793238462643383279502884197169'")))
+ f = next(
+ vl.getFeatures(
+ QgsFeatureRequest().setFilterExpression(
+ "pk = '3.141592653589793238462643383279502884197169'"
+ )
+ )
+ )
self.assertTrue(f.isValid())
- self.assertEqual(f['value'], 'first teste')
+ self.assertEqual(f["value"], "first teste")
# 1.2. Editing
self.assertTrue(vl.startEditing())
- vl.changeAttributeValue(f.id(), vl.fields().indexOf('value'), 'Changed first')
+ vl.changeAttributeValue(f.id(), vl.fields().indexOf("value"), "Changed first")
self.assertTrue(vl.commitChanges())
# 1.2.1. Checking edit from another vector layer
- vl2 = QgsVectorLayer(self.dbconn + ' sslmode=disable srid=4326 key="pk1" table="qgis_test"."tb_test_float_pk" (geom)', "test_float_pk2", "postgres")
+ vl2 = QgsVectorLayer(
+ self.dbconn
+ + ' sslmode=disable srid=4326 key="pk1" table="qgis_test"."tb_test_float_pk" (geom)',
+ "test_float_pk2",
+ "postgres",
+ )
self.assertTrue(vl2.isValid())
- f2 = next(vl2.getFeatures(QgsFeatureRequest().setFilterExpression("pk = '3.141592653589793238462643383279502884197169'")))
+ f2 = next(
+ vl2.getFeatures(
+ QgsFeatureRequest().setFilterExpression(
+ "pk = '3.141592653589793238462643383279502884197169'"
+ )
+ )
+ )
self.assertTrue(f2.isValid())
- self.assertEqual(f2['value'], 'Changed first')
+ self.assertEqual(f2["value"], "Changed first")
# 1.3. Deleting
- f = next(vl.getFeatures(QgsFeatureRequest().setFilterExpression("pk = '2.718281828459045235360287471352662497757247'")))
+ f = next(
+ vl.getFeatures(
+ QgsFeatureRequest().setFilterExpression(
+ "pk = '2.718281828459045235360287471352662497757247'"
+ )
+ )
+ )
vl.startEditing()
vl.deleteFeatures([f.id()])
self.assertTrue(vl.commitChanges())
# 1.3.1. Checking deletion
- f_iterator = vl2.getFeatures(QgsFeatureRequest().setFilterExpression("pk = '2.718281828459045235360287471352662497757247'"))
+ f_iterator = vl2.getFeatures(
+ QgsFeatureRequest().setFilterExpression(
+ "pk = '2.718281828459045235360287471352662497757247'"
+ )
+ )
got_feature = True
try:
@@ -1068,53 +1356,95 @@ def testPktFloatingPoint(self):
got_feature = False
self.assertFalse(got_feature)
# 1.4. Inserting new feature
- newpointwkt = 'Point(-47.751 -15.644)'
+ newpointwkt = "Point(-47.751 -15.644)"
f = QgsFeature(vl.fields())
- f['pk'] = 0.22222222222222222222222
- f['value'] = 'newly inserted'
+ f["pk"] = 0.22222222222222222222222
+ f["value"] = "newly inserted"
f.setGeometry(QgsGeometry.fromWkt(newpointwkt))
vl.startEditing()
res, f = vl.dataProvider().addFeatures([f])
self.assertTrue(res)
self.assertTrue(vl.commitChanges())
# 1.4.1. Checking insertion
- f2 = next(vl2.getFeatures(QgsFeatureRequest().setFilterExpression("pk = '0.22222222222222222222222'")))
+ f2 = next(
+ vl2.getFeatures(
+ QgsFeatureRequest().setFilterExpression(
+ "pk = '0.22222222222222222222222'"
+ )
+ )
+ )
self.assertTrue(f2.isValid())
- self.assertAlmostEqual(f2['pk'], 0.2222222222222222)
- self.assertEqual(f2['value'], 'newly inserted')
- assert compareWkt(f2.geometry().asWkt(), newpointwkt), f"Geometry mismatch. Expected: {f2.geometry().asWkt()} Got: {newpointwkt} \n"
+ self.assertAlmostEqual(f2["pk"], 0.2222222222222222)
+ self.assertEqual(f2["value"], "newly inserted")
+ assert compareWkt(
+ f2.geometry().asWkt(), newpointwkt
+ ), f"Geometry mismatch. Expected: {f2.geometry().asWkt()} Got: {newpointwkt} \n"
# One more check: can we retrieve the same row with the value that we got from this layer?
- floatpk = f2['pk']
- f3 = next(vl.getFeatures(QgsFeatureRequest().setFilterExpression(f"pk = '{floatpk}'")))
+ floatpk = f2["pk"]
+ f3 = next(
+ vl.getFeatures(QgsFeatureRequest().setFilterExpression(f"pk = '{floatpk}'"))
+ )
self.assertTrue(f3.isValid())
- self.assertEqual(f3['value'], 'newly inserted')
- self.assertEqual(f3['pk'], floatpk)
+ self.assertEqual(f3["value"], "newly inserted")
+ self.assertEqual(f3["pk"], floatpk)
# 2. 64 bit float (PostgreSQL "DOUBLE PRECISION" type)
- vl = QgsVectorLayer(self.dbconn + ' sslmode=disable srid=4326 key="pk" table="qgis_test"."tb_test_double_pk" (geom)', "test_double_pk", "postgres")
+ vl = QgsVectorLayer(
+ self.dbconn
+ + ' sslmode=disable srid=4326 key="pk" table="qgis_test"."tb_test_double_pk" (geom)',
+ "test_double_pk",
+ "postgres",
+ )
self.assertTrue(vl.isValid())
# 2.1. Retrieving
- f = next(vl.getFeatures(QgsFeatureRequest().setFilterExpression("pk = '3.141592653589793238462643383279502884197169'")))
+ f = next(
+ vl.getFeatures(
+ QgsFeatureRequest().setFilterExpression(
+ "pk = '3.141592653589793238462643383279502884197169'"
+ )
+ )
+ )
self.assertTrue(f.isValid())
- self.assertEqual(f['value'], 'first teste')
+ self.assertEqual(f["value"], "first teste")
# 2.2. Editing
self.assertTrue(vl.startEditing())
- vl.changeAttributeValue(f.id(), vl.fields().indexOf('value'), 'Changed first')
+ vl.changeAttributeValue(f.id(), vl.fields().indexOf("value"), "Changed first")
self.assertTrue(vl.commitChanges())
# 2.2.1. Checking edit from another vector layer
- vl2 = QgsVectorLayer(self.dbconn + ' sslmode=disable srid=4326 key="pk" table="qgis_test"."tb_test_double_pk" (geom)', "test_double_pk2", "postgres")
+ vl2 = QgsVectorLayer(
+ self.dbconn
+ + ' sslmode=disable srid=4326 key="pk" table="qgis_test"."tb_test_double_pk" (geom)',
+ "test_double_pk2",
+ "postgres",
+ )
self.assertTrue(vl2.isValid())
- f2 = next(vl2.getFeatures(QgsFeatureRequest().setFilterExpression("pk = '3.141592653589793238462643383279502884197169'")))
+ f2 = next(
+ vl2.getFeatures(
+ QgsFeatureRequest().setFilterExpression(
+ "pk = '3.141592653589793238462643383279502884197169'"
+ )
+ )
+ )
self.assertTrue(f2.isValid())
- self.assertEqual(f2['value'], 'Changed first')
+ self.assertEqual(f2["value"], "Changed first")
# 2.3. Deleting
- f = next(vl.getFeatures(QgsFeatureRequest().setFilterExpression("pk = '2.718281828459045235360287471352662497757247'")))
+ f = next(
+ vl.getFeatures(
+ QgsFeatureRequest().setFilterExpression(
+ "pk = '2.718281828459045235360287471352662497757247'"
+ )
+ )
+ )
vl.startEditing()
vl.deleteFeatures([f.id()])
self.assertTrue(vl.commitChanges())
# 2.3.1. Checking deletion
- f_iterator = vl2.getFeatures(QgsFeatureRequest().setFilterExpression("pk = '2.718281828459045235360287471352662497757247'"))
+ f_iterator = vl2.getFeatures(
+ QgsFeatureRequest().setFilterExpression(
+ "pk = '2.718281828459045235360287471352662497757247'"
+ )
+ )
got_feature = True
try:
@@ -1124,56 +1454,74 @@ def testPktFloatingPoint(self):
got_feature = False
self.assertFalse(got_feature)
# 2.4. Inserting new feature
- newpointwkt = 'Point(-47.751 -15.644)'
+ newpointwkt = "Point(-47.751 -15.644)"
f = QgsFeature(vl.fields())
- f['pk'] = 0.22222222222222222222222
- f['value'] = 'newly inserted'
+ f["pk"] = 0.22222222222222222222222
+ f["value"] = "newly inserted"
f.setGeometry(QgsGeometry.fromWkt(newpointwkt))
vl.startEditing()
res, f = vl.dataProvider().addFeatures([f])
self.assertTrue(res)
self.assertTrue(vl.commitChanges())
# 2.4.1. Checking insertion
- f2 = next(vl2.getFeatures(QgsFeatureRequest().setFilterExpression("pk = '0.22222222222222222222222'")))
+ f2 = next(
+ vl2.getFeatures(
+ QgsFeatureRequest().setFilterExpression(
+ "pk = '0.22222222222222222222222'"
+ )
+ )
+ )
self.assertTrue(f2.isValid())
- self.assertAlmostEqual(f2['pk'], 0.2222222222222222, places=15)
- self.assertEqual(f2['value'], 'newly inserted')
- assert compareWkt(f2.geometry().asWkt(), newpointwkt), f"Geometry mismatch. Expected: {f2.geometry().asWkt()} Got: {newpointwkt} \n"
+ self.assertAlmostEqual(f2["pk"], 0.2222222222222222, places=15)
+ self.assertEqual(f2["value"], "newly inserted")
+ assert compareWkt(
+ f2.geometry().asWkt(), newpointwkt
+ ), f"Geometry mismatch. Expected: {f2.geometry().asWkt()} Got: {newpointwkt} \n"
# One more check: can we retrieve the same row with the value that we got from this layer?
- doublepk = f2['pk']
- f3 = next(vl.getFeatures(QgsFeatureRequest().setFilterExpression(f"pk = '{doublepk}'")))
+ doublepk = f2["pk"]
+ f3 = next(
+ vl.getFeatures(
+ QgsFeatureRequest().setFilterExpression(f"pk = '{doublepk}'")
+ )
+ )
self.assertTrue(f3.isValid())
- self.assertEqual(f3['value'], 'newly inserted')
- self.assertEqual(f3['pk'], doublepk)
+ self.assertEqual(f3["value"], "newly inserted")
+ self.assertEqual(f3["pk"], doublepk)
# no NUMERIC/DECIMAL checks here. NUMERIC primary keys are unsupported.
# TODO: implement NUMERIC primary keys/arbitrary precision arithmethics/fixed point math in QGIS.
def testPktMapInsert(self):
- vl = QgsVectorLayer(f"{self.dbconn} table=\"qgis_test\".\"oid_serial_table\" key=\"obj_id\" sql=",
- "oid_serial", "postgres")
+ vl = QgsVectorLayer(
+ f'{self.dbconn} table="qgis_test"."oid_serial_table" key="obj_id" sql=',
+ "oid_serial",
+ "postgres",
+ )
self.assertTrue(vl.isValid())
f = QgsFeature(vl.fields())
- f['obj_id'] = vl.dataProvider().defaultValueClause(0)
- f['name'] = 'Test'
+ f["obj_id"] = vl.dataProvider().defaultValueClause(0)
+ f["name"] = "Test"
r, f = vl.dataProvider().addFeatures([f])
self.assertTrue(r)
- self.assertNotEqual(f[0]['obj_id'], NULL, f[0].attributes())
+ self.assertNotEqual(f[0]["obj_id"], NULL, f[0].attributes())
vl.deleteFeatures([f[0].id()])
def testClonePreservesFidMap(self):
vl = QgsVectorLayer(
'{} sslmode=disable srid=4326 key="pk" table="qgis_test".{} (geom)'.format(
- self.dbconn, 'bigint_pk'),
- "bigint_pk", "postgres")
+ self.dbconn, "bigint_pk"
+ ),
+ "bigint_pk",
+ "postgres",
+ )
# Generate primary keys
- f = next(vl.getFeatures('pk = 2')) # 1
- f = next(vl.getFeatures('pk = -1')) # 2
+ f = next(vl.getFeatures("pk = 2")) # 1
+ f = next(vl.getFeatures("pk = -1")) # 2
fid_orig = f.id()
clone = vl.clone()
- f = next(clone.getFeatures('pk = -1')) # should still be 2
+ f = next(clone.getFeatures("pk = -1")) # should still be 2
fid_copy = f.id()
self.assertEqual(fid_orig, fid_copy)
@@ -1181,8 +1529,12 @@ def testNull(self):
"""
Asserts that 0, '' and NULL are treated as different values on insert
"""
- vl = QgsVectorLayer(self.dbconn + ' sslmode=disable key=\'gid\' table="qgis_test"."constraints" sql=', 'test1',
- 'postgres')
+ vl = QgsVectorLayer(
+ self.dbconn
+ + ' sslmode=disable key=\'gid\' table="qgis_test"."constraints" sql=',
+ "test1",
+ "postgres",
+ )
self.assertTrue(vl.isValid())
QgsProject.instance().addMapLayer(vl)
tg = QgsTransactionGroup()
@@ -1196,13 +1548,13 @@ def onError(message):
vl.raiseError.connect(onError)
f = QgsFeature(vl.fields())
- f['gid'] = 100
- f['val'] = 0
- f['name'] = ''
+ f["gid"] = 100
+ f["val"] = 0
+ f["name"] = ""
self.assertTrue(vl.addFeature(f))
feature = next(vl.getFeatures('"gid" = 100'))
- self.assertEqual(f['val'], feature['val'])
- self.assertEqual(f['name'], feature['name'])
+ self.assertEqual(f["val"], feature["val"])
+ self.assertEqual(f["name"], feature["name"])
def testNestedInsert(self):
tg = QgsTransactionGroup()
@@ -1211,8 +1563,10 @@ def testNestedInsert(self):
l.startEditing()
it = l.getFeatures()
f = next(it)
- f['pk'] = NULL
- self.assertTrue(l.addFeature(f)) # Should not deadlock during an active iteration
+ f["pk"] = NULL
+ self.assertTrue(
+ l.addFeature(f)
+ ) # Should not deadlock during an active iteration
f = next(it)
l.commitChanges()
@@ -1231,9 +1585,11 @@ def testTimeout(self):
def testTransactionDirtyName(self):
# create a vector ayer based on postgres
vl = QgsVectorLayer(
- self.dbconn +
- ' sslmode=disable key=\'pk\' srid=4326 type=POLYGON table="qgis_test"."some_poly_data" (geom) sql=',
- 'test', 'postgres')
+ self.dbconn
+ + ' sslmode=disable key=\'pk\' srid=4326 type=POLYGON table="qgis_test"."some_poly_data" (geom) sql=',
+ "test",
+ "postgres",
+ )
self.assertTrue(vl.isValid())
# prepare a project with transactions enabled
@@ -1257,9 +1613,11 @@ def testTransactionDirtyName(self):
def testTransactionDirty(self):
# create a vector layer based on postgres
vl = QgsVectorLayer(
- self.dbconn +
- ' sslmode=disable key=\'pk\' srid=4326 type=POLYGON table="qgis_test"."some_poly_data" (geom) sql=',
- 'test', 'postgres')
+ self.dbconn
+ + ' sslmode=disable key=\'pk\' srid=4326 type=POLYGON table="qgis_test"."some_poly_data" (geom) sql=',
+ "test",
+ "postgres",
+ )
self.assertTrue(vl.isValid())
# prepare a project with transactions enabled
@@ -1269,7 +1627,7 @@ def testTransactionDirty(self):
vl.startEditing()
# check that the feature used for testing is ok
- ft0 = vl.getFeatures('pk=1')
+ ft0 = vl.getFeatures("pk=1")
f = QgsFeature()
self.assertTrue(ft0.nextFeature(f))
@@ -1279,10 +1637,10 @@ def testTransactionDirty(self):
self.assertTrue(tr.executeSql(sql, True)[0])
# check that the pk of the feature has been changed
- ft = vl.getFeatures('pk=1')
+ ft = vl.getFeatures("pk=1")
self.assertFalse(ft.nextFeature(f))
- ft = vl.getFeatures('pk=33')
+ ft = vl.getFeatures("pk=33")
self.assertTrue(ft.nextFeature(f))
# underlying data has been modified but the layer is not tagged as
@@ -1293,20 +1651,24 @@ def testTransactionDirty(self):
vl.undoStack().undo()
# check that the original feature with pk is back
- ft0 = vl.getFeatures('pk=1')
+ ft0 = vl.getFeatures("pk=1")
self.assertTrue(ft0.nextFeature(f))
# redo
vl.undoStack().redo()
# check that the pk of the feature has been changed
- ft1 = vl.getFeatures('pk=1')
+ ft1 = vl.getFeatures("pk=1")
self.assertFalse(ft1.nextFeature(f))
def testTransactionConstraints(self):
# create a vector layer based on postgres
- vl = QgsVectorLayer(self.dbconn + ' sslmode=disable key=\'id\' table="qgis_test"."check_constraints" sql=',
- 'test', 'postgres')
+ vl = QgsVectorLayer(
+ self.dbconn
+ + ' sslmode=disable key=\'id\' table="qgis_test"."check_constraints" sql=',
+ "test",
+ "postgres",
+ )
self.assertTrue(vl.isValid())
# prepare a project with transactions enabled
@@ -1316,7 +1678,7 @@ def testTransactionConstraints(self):
# get feature
f = QgsFeature()
- self.assertTrue(vl.getFeatures('id=1').nextFeature(f))
+ self.assertTrue(vl.getFeatures("id=1").nextFeature(f))
self.assertEqual(f.attributes(), [1, 4, 3])
# start edition
@@ -1332,24 +1694,26 @@ def testTransactionConstraints(self):
for w in form.findChildren(QLabel):
if w.buddy():
spinBox = w.buddy()
- if w.text() == 'a':
+ if w.text() == "a":
spinBox.setValue(1)
- elif w.text() == 'b':
+ elif w.text() == "b":
spinBox.setValue(0)
# save
form.save()
# check new values
- self.assertTrue(vl.getFeatures('id=1').nextFeature(f))
+ self.assertTrue(vl.getFeatures("id=1").nextFeature(f))
self.assertEqual(f.attributes(), [1, 1, 0])
def testTransactionTuple(self):
# create a vector layer based on postgres
vl = QgsVectorLayer(
- self.dbconn +
- ' sslmode=disable key=\'pk\' srid=4326 type=POLYGON table="qgis_test"."some_poly_data" (geom) sql=',
- 'test', 'postgres')
+ self.dbconn
+ + ' sslmode=disable key=\'pk\' srid=4326 type=POLYGON table="qgis_test"."some_poly_data" (geom) sql=',
+ "test",
+ "postgres",
+ )
self.assertTrue(vl.isValid())
# prepare a project with transactions enabled
@@ -1369,88 +1733,122 @@ def testTransactionTuple(self):
def testDomainTypes(self):
"""Test that domain types are correctly mapped"""
- vl = QgsVectorLayer('%s table="qgis_test"."domains" sql=' %
- (self.dbconn), "domains", "postgres")
+ vl = QgsVectorLayer(
+ '%s table="qgis_test"."domains" sql=' % (self.dbconn), "domains", "postgres"
+ )
self.assertTrue(vl.isValid())
fields = vl.dataProvider().fields()
expected = {}
- expected['fld_var_char_domain'] = {'type': QVariant.String, 'typeName': 'qgis_test.var_char_domain',
- 'length': -1}
- expected['fld_var_char_domain_6'] = {'type': QVariant.String, 'typeName': 'qgis_test.var_char_domain_6',
- 'length': 6}
- expected['fld_character_domain'] = {'type': QVariant.String, 'typeName': 'qgis_test.character_domain',
- 'length': 1}
- expected['fld_character_domain_6'] = {'type': QVariant.String, 'typeName': 'qgis_test.character_domain_6',
- 'length': 6}
- expected['fld_char_domain'] = {
- 'type': QVariant.String, 'typeName': 'qgis_test.char_domain', 'length': 1}
- expected['fld_char_domain_6'] = {
- 'type': QVariant.String, 'typeName': 'qgis_test.char_domain_6', 'length': 6}
- expected['fld_text_domain'] = {
- 'type': QVariant.String, 'typeName': 'qgis_test.text_domain', 'length': -1}
- expected['fld_numeric_domain'] = {'type': QVariant.Double, 'typeName': 'qgis_test.numeric_domain', 'length': 10,
- 'precision': 4}
+ expected["fld_var_char_domain"] = {
+ "type": QVariant.String,
+ "typeName": "qgis_test.var_char_domain",
+ "length": -1,
+ }
+ expected["fld_var_char_domain_6"] = {
+ "type": QVariant.String,
+ "typeName": "qgis_test.var_char_domain_6",
+ "length": 6,
+ }
+ expected["fld_character_domain"] = {
+ "type": QVariant.String,
+ "typeName": "qgis_test.character_domain",
+ "length": 1,
+ }
+ expected["fld_character_domain_6"] = {
+ "type": QVariant.String,
+ "typeName": "qgis_test.character_domain_6",
+ "length": 6,
+ }
+ expected["fld_char_domain"] = {
+ "type": QVariant.String,
+ "typeName": "qgis_test.char_domain",
+ "length": 1,
+ }
+ expected["fld_char_domain_6"] = {
+ "type": QVariant.String,
+ "typeName": "qgis_test.char_domain_6",
+ "length": 6,
+ }
+ expected["fld_text_domain"] = {
+ "type": QVariant.String,
+ "typeName": "qgis_test.text_domain",
+ "length": -1,
+ }
+ expected["fld_numeric_domain"] = {
+ "type": QVariant.Double,
+ "typeName": "qgis_test.numeric_domain",
+ "length": 10,
+ "precision": 4,
+ }
for f, e in list(expected.items()):
+ self.assertEqual(fields.at(fields.indexFromName(f)).type(), e["type"])
self.assertEqual(
- fields.at(fields.indexFromName(f)).type(), e['type'])
- self.assertEqual(fields.at(fields.indexFromName(f)
- ).typeName(), e['typeName'])
- self.assertEqual(
- fields.at(fields.indexFromName(f)).length(), e['length'])
- if 'precision' in e:
+ fields.at(fields.indexFromName(f)).typeName(), e["typeName"]
+ )
+ self.assertEqual(fields.at(fields.indexFromName(f)).length(), e["length"])
+ if "precision" in e:
self.assertEqual(
- fields.at(fields.indexFromName(f)).precision(), e['precision'])
+ fields.at(fields.indexFromName(f)).precision(), e["precision"]
+ )
def testRenameAttributes(self):
- ''' Test renameAttributes() '''
- vl = QgsVectorLayer('%s table="qgis_test"."rename_table" sql=' % (
- self.dbconn), "renames", "postgres")
+ """Test renameAttributes()"""
+ vl = QgsVectorLayer(
+ '%s table="qgis_test"."rename_table" sql=' % (self.dbconn),
+ "renames",
+ "postgres",
+ )
provider = vl.dataProvider()
- provider.renameAttributes({1: 'field1', 2: 'field2'})
+ provider.renameAttributes({1: "field1", 2: "field2"})
# bad rename
- self.assertFalse(provider.renameAttributes({-1: 'not_a_field'}))
- self.assertFalse(provider.renameAttributes({100: 'not_a_field'}))
+ self.assertFalse(provider.renameAttributes({-1: "not_a_field"}))
+ self.assertFalse(provider.renameAttributes({100: "not_a_field"}))
# already exists
- self.assertFalse(provider.renameAttributes({1: 'field2'}))
+ self.assertFalse(provider.renameAttributes({1: "field2"}))
# rename one field
- self.assertTrue(provider.renameAttributes({1: 'newname'}))
- self.assertEqual(provider.fields().at(1).name(), 'newname')
+ self.assertTrue(provider.renameAttributes({1: "newname"}))
+ self.assertEqual(provider.fields().at(1).name(), "newname")
vl.updateFields()
fet = next(vl.getFeatures())
- self.assertEqual(fet.fields()[1].name(), 'newname')
+ self.assertEqual(fet.fields()[1].name(), "newname")
# rename two fields
- self.assertTrue(provider.renameAttributes(
- {1: 'newname2', 2: 'another'}))
- self.assertEqual(provider.fields().at(1).name(), 'newname2')
- self.assertEqual(provider.fields().at(2).name(), 'another')
+ self.assertTrue(provider.renameAttributes({1: "newname2", 2: "another"}))
+ self.assertEqual(provider.fields().at(1).name(), "newname2")
+ self.assertEqual(provider.fields().at(2).name(), "another")
vl.updateFields()
fet = next(vl.getFeatures())
- self.assertEqual(fet.fields()[1].name(), 'newname2')
- self.assertEqual(fet.fields()[2].name(), 'another')
+ self.assertEqual(fet.fields()[1].name(), "newname2")
+ self.assertEqual(fet.fields()[2].name(), "another")
# close layer and reopen, then recheck to confirm that changes were saved to db
del vl
vl = None
- vl = QgsVectorLayer('%s table="qgis_test"."rename_table" sql=' % (
- self.dbconn), "renames", "postgres")
+ vl = QgsVectorLayer(
+ '%s table="qgis_test"."rename_table" sql=' % (self.dbconn),
+ "renames",
+ "postgres",
+ )
provider = vl.dataProvider()
- self.assertEqual(provider.fields().at(1).name(), 'newname2')
- self.assertEqual(provider.fields().at(2).name(), 'another')
+ self.assertEqual(provider.fields().at(1).name(), "newname2")
+ self.assertEqual(provider.fields().at(2).name(), "another")
fet = next(vl.getFeatures())
- self.assertEqual(fet.fields()[1].name(), 'newname2')
- self.assertEqual(fet.fields()[2].name(), 'another')
+ self.assertEqual(fet.fields()[1].name(), "newname2")
+ self.assertEqual(fet.fields()[2].name(), "another")
def testEditorWidgetTypes(self):
"""Test that editor widget types can be fetched from the qgis_editor_widget_styles table"""
- vl = QgsVectorLayer('%s table="qgis_test"."widget_styles" sql=' % (
- self.dbconn), "widget_styles", "postgres")
+ vl = QgsVectorLayer(
+ '%s table="qgis_test"."widget_styles" sql=' % (self.dbconn),
+ "widget_styles",
+ "postgres",
+ )
self.assertTrue(vl.isValid())
fields = vl.dataProvider().fields()
@@ -1469,45 +1867,50 @@ def testEditorWidgetTypes(self):
self.assertEqual(best2.type(), "TextEdit")
def testHstore(self):
- vl = QgsVectorLayer('%s table="qgis_test"."dict" sql=' %
- (self.dbconn), "testhstore", "postgres")
+ vl = QgsVectorLayer(
+ '%s table="qgis_test"."dict" sql=' % (self.dbconn), "testhstore", "postgres"
+ )
self.assertTrue(vl.isValid())
fields = vl.dataProvider().fields()
- self.assertEqual(
- fields.at(fields.indexFromName('value')).type(), QVariant.Map)
+ self.assertEqual(fields.at(fields.indexFromName("value")).type(), QVariant.Map)
f = next(vl.getFeatures(QgsFeatureRequest()))
- value_idx = vl.fields().lookupField('value')
+ value_idx = vl.fields().lookupField("value")
self.assertIsInstance(f.attributes()[value_idx], dict)
- self.assertEqual(f.attributes()[value_idx], {'a': 'b', '1': '2'})
+ self.assertEqual(f.attributes()[value_idx], {"a": "b", "1": "2"})
new_f = QgsFeature(vl.fields())
- new_f['pk'] = NULL
- new_f['value'] = {'simple': '1', 'doubleQuote': '"y"',
- 'quote': "'q'", 'backslash': '\\'}
+ new_f["pk"] = NULL
+ new_f["value"] = {
+ "simple": "1",
+ "doubleQuote": '"y"',
+ "quote": "'q'",
+ "backslash": "\\",
+ }
r, fs = vl.dataProvider().addFeatures([new_f])
self.assertTrue(r)
- new_pk = fs[0]['pk']
+ new_pk = fs[0]["pk"]
self.assertNotEqual(new_pk, NULL, fs[0].attributes())
try:
read_back = vl.getFeature(new_pk)
- self.assertEqual(read_back['pk'], new_pk)
- self.assertEqual(read_back['value'], new_f['value'])
+ self.assertEqual(read_back["pk"], new_pk)
+ self.assertEqual(read_back["value"], new_f["value"])
finally:
self.assertTrue(vl.startEditing())
self.assertTrue(vl.deleteFeatures([new_pk]))
self.assertTrue(vl.commitChanges())
def testJson(self):
- vl = QgsVectorLayer('%s table="qgis_test"."json" sql=' %
- (self.dbconn), "testjson", "postgres")
+ vl = QgsVectorLayer(
+ '%s table="qgis_test"."json" sql=' % (self.dbconn), "testjson", "postgres"
+ )
self.assertTrue(vl.isValid())
# Backup test table (will be edited)
- tableBackup = self.scopedTableBackup('qgis_test', 'json')
+ tableBackup = self.scopedTableBackup("qgis_test", "json")
attrs = (
123,
@@ -1518,8 +1921,13 @@ def testJson(self):
r"String literal with \"quotes\" 'and' other funny chars []{};#/èé*",
[1, 2, 3.4, None],
[True, False],
- {'a': 123, 'b': 123.34, 'c': 'a string', 'd': [
- 1, 2, 3], 'e': {'a': 123, 'b': 123.45}}
+ {
+ "a": 123,
+ "b": 123.34,
+ "c": "a string",
+ "d": [1, 2, 3],
+ "e": {"a": 123, "b": 123.45},
+ },
)
attrs2 = (
246,
@@ -1530,231 +1938,351 @@ def testJson(self):
r"Yet another string literal with \"quotes\" 'and' other funny chars: π []{};#/èé*",
[2, 4, 3.14159, None],
[True, False],
- {'a': 246, 'b': 246.68, 'c': 'a rounded area: π × r²', 'd': [
- 1, 2, 3], 'e': {'a': 246, 'b': 246.91}}
+ {
+ "a": 246,
+ "b": 246.68,
+ "c": "a rounded area: π × r²",
+ "d": [1, 2, 3],
+ "e": {"a": 246, "b": 246.91},
+ },
)
- json_idx = vl.fields().lookupField('jvalue')
- jsonb_idx = vl.fields().lookupField('jbvalue')
+ json_idx = vl.fields().lookupField("jvalue")
+ jsonb_idx = vl.fields().lookupField("jbvalue")
for attr in attrs:
# Add a new feature
- vl2 = QgsVectorLayer('%s table="qgis_test"."json" sql=' % (
- self.dbconn), "testjson", "postgres")
+ vl2 = QgsVectorLayer(
+ '%s table="qgis_test"."json" sql=' % (self.dbconn),
+ "testjson",
+ "postgres",
+ )
self.assertTrue(vl2.startEditing())
f = QgsFeature(vl2.fields())
f.setAttributes([None, attr, attr])
self.assertTrue(vl2.addFeatures([f]))
self.assertTrue(vl2.commitChanges(), attr)
# Read back
- vl2 = QgsVectorLayer('%s table="qgis_test"."json" sql=' % (
- self.dbconn), "testjson", "postgres")
+ vl2 = QgsVectorLayer(
+ '%s table="qgis_test"."json" sql=' % (self.dbconn),
+ "testjson",
+ "postgres",
+ )
fid = [f.id() for f in vl2.getFeatures()][-1]
f = vl2.getFeature(fid)
self.assertEqual(f.attributes(), [fid, attr, attr])
# Change attribute values
- vl2 = QgsVectorLayer('%s table="qgis_test"."json" sql=' % (
- self.dbconn), "testjson", "postgres")
+ vl2 = QgsVectorLayer(
+ '%s table="qgis_test"."json" sql=' % (self.dbconn),
+ "testjson",
+ "postgres",
+ )
fid = [f.id() for f in vl2.getFeatures()][-1]
self.assertTrue(vl2.startEditing())
- self.assertTrue(vl2.changeAttributeValues(
- fid, {json_idx: attr, jsonb_idx: attr}))
+ self.assertTrue(
+ vl2.changeAttributeValues(fid, {json_idx: attr, jsonb_idx: attr})
+ )
self.assertTrue(vl2.commitChanges())
# Read back
- vl2 = QgsVectorLayer('%s table="qgis_test"."json" sql=' % (
- self.dbconn), "testjson", "postgres")
+ vl2 = QgsVectorLayer(
+ '%s table="qgis_test"."json" sql=' % (self.dbconn),
+ "testjson",
+ "postgres",
+ )
f = vl2.getFeature(fid)
self.assertEqual(f.attributes(), [fid, attr, attr])
# Let's check changeFeatures:
for attr in attrs2:
- vl2 = QgsVectorLayer('%s table="qgis_test"."json" sql=' % (
- self.dbconn), "testjson", "postgres")
+ vl2 = QgsVectorLayer(
+ '%s table="qgis_test"."json" sql=' % (self.dbconn),
+ "testjson",
+ "postgres",
+ )
fid = [f.id() for f in vl2.getFeatures()][-1]
self.assertTrue(vl2.startEditing())
- self.assertTrue(vl2.dataProvider().changeFeatures({fid: {json_idx: attr, jsonb_idx: attr}}, {}))
+ self.assertTrue(
+ vl2.dataProvider().changeFeatures(
+ {fid: {json_idx: attr, jsonb_idx: attr}}, {}
+ )
+ )
self.assertTrue(vl2.commitChanges())
# Read back again
- vl2 = QgsVectorLayer('%s table="qgis_test"."json" sql=' % (
- self.dbconn), "testjson", "postgres")
+ vl2 = QgsVectorLayer(
+ '%s table="qgis_test"."json" sql=' % (self.dbconn),
+ "testjson",
+ "postgres",
+ )
f = vl2.getFeature(fid)
self.assertEqual(f.attributes(), [fid, attr, attr])
def testStringArray(self):
- vl = QgsVectorLayer('%s table="qgis_test"."string_array" sql=' % (
- self.dbconn), "teststringarray", "postgres")
+ vl = QgsVectorLayer(
+ '%s table="qgis_test"."string_array" sql=' % (self.dbconn),
+ "teststringarray",
+ "postgres",
+ )
self.assertTrue(vl.isValid())
fields = vl.dataProvider().fields()
- self.assertEqual(fields.at(fields.indexFromName(
- 'value')).type(), QVariant.StringList)
- self.assertEqual(fields.at(fields.indexFromName(
- 'value')).subType(), QVariant.String)
+ self.assertEqual(
+ fields.at(fields.indexFromName("value")).type(), QVariant.StringList
+ )
+ self.assertEqual(
+ fields.at(fields.indexFromName("value")).subType(), QVariant.String
+ )
f = next(vl.getFeatures(QgsFeatureRequest()))
- value_idx = vl.fields().lookupField('value')
+ value_idx = vl.fields().lookupField("value")
self.assertIsInstance(f.attributes()[value_idx], list)
- self.assertEqual(f.attributes()[value_idx], ['a', 'b', 'c'])
+ self.assertEqual(f.attributes()[value_idx], ["a", "b", "c"])
new_f = QgsFeature(vl.fields())
- new_f['pk'] = NULL
- new_f['value'] = ['simple', '"doubleQuote"', "'quote'", 'back\\slash']
+ new_f["pk"] = NULL
+ new_f["value"] = ["simple", '"doubleQuote"', "'quote'", "back\\slash"]
r, fs = vl.dataProvider().addFeatures([new_f])
self.assertTrue(r)
- new_pk = fs[0]['pk']
+ new_pk = fs[0]["pk"]
self.assertNotEqual(new_pk, NULL, fs[0].attributes())
try:
read_back = vl.getFeature(new_pk)
- self.assertEqual(read_back['pk'], new_pk)
- self.assertEqual(read_back['value'], new_f['value'])
+ self.assertEqual(read_back["pk"], new_pk)
+ self.assertEqual(read_back["value"], new_f["value"])
finally:
self.assertTrue(vl.startEditing())
self.assertTrue(vl.deleteFeatures([new_pk]))
self.assertTrue(vl.commitChanges())
def testIntArray(self):
- vl = QgsVectorLayer('%s table="qgis_test"."int_array" sql=' % (
- self.dbconn), "testintarray", "postgres")
+ vl = QgsVectorLayer(
+ '%s table="qgis_test"."int_array" sql=' % (self.dbconn),
+ "testintarray",
+ "postgres",
+ )
self.assertTrue(vl.isValid())
fields = vl.dataProvider().fields()
+ self.assertEqual(fields.at(fields.indexFromName("value")).type(), QVariant.List)
self.assertEqual(
- fields.at(fields.indexFromName('value')).type(), QVariant.List)
- self.assertEqual(fields.at(fields.indexFromName(
- 'value')).subType(), QVariant.Int)
+ fields.at(fields.indexFromName("value")).subType(), QVariant.Int
+ )
f = next(vl.getFeatures(QgsFeatureRequest()))
- value_idx = vl.fields().lookupField('value')
+ value_idx = vl.fields().lookupField("value")
self.assertIsInstance(f.attributes()[value_idx], list)
self.assertEqual(f.attributes()[value_idx], [1, 2, -5])
def testDoubleArray(self):
- vl = QgsVectorLayer('%s table="qgis_test"."double_array" sql=' % (
- self.dbconn), "testdoublearray", "postgres")
+ vl = QgsVectorLayer(
+ '%s table="qgis_test"."double_array" sql=' % (self.dbconn),
+ "testdoublearray",
+ "postgres",
+ )
self.assertTrue(vl.isValid())
fields = vl.dataProvider().fields()
+ self.assertEqual(fields.at(fields.indexFromName("value")).type(), QVariant.List)
self.assertEqual(
- fields.at(fields.indexFromName('value')).type(), QVariant.List)
- self.assertEqual(fields.at(fields.indexFromName(
- 'value')).subType(), QVariant.Double)
+ fields.at(fields.indexFromName("value")).subType(), QVariant.Double
+ )
f = next(vl.getFeatures(QgsFeatureRequest()))
- value_idx = vl.fields().lookupField('value')
+ value_idx = vl.fields().lookupField("value")
self.assertIsInstance(f.attributes()[value_idx], list)
self.assertEqual(f.attributes()[value_idx], [1.1, 2, -5.12345])
def testNotNullConstraint(self):
- vl = QgsVectorLayer('%s table="qgis_test"."constraints" sql=' % (
- self.dbconn), "constraints", "postgres")
+ vl = QgsVectorLayer(
+ '%s table="qgis_test"."constraints" sql=' % (self.dbconn),
+ "constraints",
+ "postgres",
+ )
self.assertTrue(vl.isValid())
self.assertEqual(len(vl.fields()), 4)
# test some bad field indexes
- self.assertEqual(vl.dataProvider().fieldConstraints(-1),
- QgsFieldConstraints.Constraints())
- self.assertEqual(vl.dataProvider().fieldConstraints(
- 1001), QgsFieldConstraints.Constraints())
-
- self.assertTrue(vl.dataProvider().fieldConstraints(0) &
- QgsFieldConstraints.Constraint.ConstraintNotNull)
- self.assertFalse(vl.dataProvider().fieldConstraints(1)
- & QgsFieldConstraints.Constraint.ConstraintNotNull)
- self.assertTrue(vl.dataProvider().fieldConstraints(2) &
- QgsFieldConstraints.Constraint.ConstraintNotNull)
- self.assertFalse(vl.dataProvider().fieldConstraints(3)
- & QgsFieldConstraints.Constraint.ConstraintNotNull)
+ self.assertEqual(
+ vl.dataProvider().fieldConstraints(-1), QgsFieldConstraints.Constraints()
+ )
+ self.assertEqual(
+ vl.dataProvider().fieldConstraints(1001), QgsFieldConstraints.Constraints()
+ )
+
+ self.assertTrue(
+ vl.dataProvider().fieldConstraints(0)
+ & QgsFieldConstraints.Constraint.ConstraintNotNull
+ )
+ self.assertFalse(
+ vl.dataProvider().fieldConstraints(1)
+ & QgsFieldConstraints.Constraint.ConstraintNotNull
+ )
+ self.assertTrue(
+ vl.dataProvider().fieldConstraints(2)
+ & QgsFieldConstraints.Constraint.ConstraintNotNull
+ )
+ self.assertFalse(
+ vl.dataProvider().fieldConstraints(3)
+ & QgsFieldConstraints.Constraint.ConstraintNotNull
+ )
# test that constraints have been saved to fields correctly
fields = vl.fields()
- self.assertTrue(fields.at(0).constraints().constraints()
- & QgsFieldConstraints.Constraint.ConstraintNotNull)
- self.assertEqual(fields.at(0).constraints().constraintOrigin(QgsFieldConstraints.Constraint.ConstraintNotNull),
- QgsFieldConstraints.ConstraintOrigin.ConstraintOriginProvider)
- self.assertFalse(fields.at(1).constraints().constraints()
- & QgsFieldConstraints.Constraint.ConstraintNotNull)
- self.assertTrue(fields.at(2).constraints().constraints()
- & QgsFieldConstraints.Constraint.ConstraintNotNull)
- self.assertEqual(fields.at(2).constraints().constraintOrigin(QgsFieldConstraints.Constraint.ConstraintNotNull),
- QgsFieldConstraints.ConstraintOrigin.ConstraintOriginProvider)
- self.assertFalse(fields.at(3).constraints().constraints()
- & QgsFieldConstraints.Constraint.ConstraintNotNull)
+ self.assertTrue(
+ fields.at(0).constraints().constraints()
+ & QgsFieldConstraints.Constraint.ConstraintNotNull
+ )
+ self.assertEqual(
+ fields.at(0)
+ .constraints()
+ .constraintOrigin(QgsFieldConstraints.Constraint.ConstraintNotNull),
+ QgsFieldConstraints.ConstraintOrigin.ConstraintOriginProvider,
+ )
+ self.assertFalse(
+ fields.at(1).constraints().constraints()
+ & QgsFieldConstraints.Constraint.ConstraintNotNull
+ )
+ self.assertTrue(
+ fields.at(2).constraints().constraints()
+ & QgsFieldConstraints.Constraint.ConstraintNotNull
+ )
+ self.assertEqual(
+ fields.at(2)
+ .constraints()
+ .constraintOrigin(QgsFieldConstraints.Constraint.ConstraintNotNull),
+ QgsFieldConstraints.ConstraintOrigin.ConstraintOriginProvider,
+ )
+ self.assertFalse(
+ fields.at(3).constraints().constraints()
+ & QgsFieldConstraints.Constraint.ConstraintNotNull
+ )
def testUniqueConstraint(self):
- vl = QgsVectorLayer('%s table="qgis_test"."constraints" sql=' % (
- self.dbconn), "constraints", "postgres")
+ vl = QgsVectorLayer(
+ '%s table="qgis_test"."constraints" sql=' % (self.dbconn),
+ "constraints",
+ "postgres",
+ )
self.assertTrue(vl.isValid())
self.assertEqual(len(vl.fields()), 4)
# test some bad field indexes
- self.assertEqual(vl.dataProvider().fieldConstraints(-1),
- QgsFieldConstraints.Constraints())
- self.assertEqual(vl.dataProvider().fieldConstraints(
- 1001), QgsFieldConstraints.Constraints())
-
- self.assertTrue(vl.dataProvider().fieldConstraints(0)
- & QgsFieldConstraints.Constraint.ConstraintUnique)
- self.assertTrue(vl.dataProvider().fieldConstraints(1)
- & QgsFieldConstraints.Constraint.ConstraintUnique)
- self.assertTrue(vl.dataProvider().fieldConstraints(2)
- & QgsFieldConstraints.Constraint.ConstraintUnique)
- self.assertFalse(vl.dataProvider().fieldConstraints(3)
- & QgsFieldConstraints.Constraint.ConstraintUnique)
+ self.assertEqual(
+ vl.dataProvider().fieldConstraints(-1), QgsFieldConstraints.Constraints()
+ )
+ self.assertEqual(
+ vl.dataProvider().fieldConstraints(1001), QgsFieldConstraints.Constraints()
+ )
+
+ self.assertTrue(
+ vl.dataProvider().fieldConstraints(0)
+ & QgsFieldConstraints.Constraint.ConstraintUnique
+ )
+ self.assertTrue(
+ vl.dataProvider().fieldConstraints(1)
+ & QgsFieldConstraints.Constraint.ConstraintUnique
+ )
+ self.assertTrue(
+ vl.dataProvider().fieldConstraints(2)
+ & QgsFieldConstraints.Constraint.ConstraintUnique
+ )
+ self.assertFalse(
+ vl.dataProvider().fieldConstraints(3)
+ & QgsFieldConstraints.Constraint.ConstraintUnique
+ )
# test that constraints have been saved to fields correctly
fields = vl.fields()
- self.assertTrue(fields.at(0).constraints().constraints()
- & QgsFieldConstraints.Constraint.ConstraintUnique)
- self.assertEqual(fields.at(0).constraints().constraintOrigin(QgsFieldConstraints.Constraint.ConstraintUnique),
- QgsFieldConstraints.ConstraintOrigin.ConstraintOriginProvider)
- self.assertTrue(fields.at(1).constraints().constraints()
- & QgsFieldConstraints.Constraint.ConstraintUnique)
- self.assertEqual(fields.at(1).constraints().constraintOrigin(QgsFieldConstraints.Constraint.ConstraintUnique),
- QgsFieldConstraints.ConstraintOrigin.ConstraintOriginProvider)
- self.assertTrue(fields.at(2).constraints().constraints()
- & QgsFieldConstraints.Constraint.ConstraintUnique)
- self.assertEqual(fields.at(2).constraints().constraintOrigin(QgsFieldConstraints.Constraint.ConstraintUnique),
- QgsFieldConstraints.ConstraintOrigin.ConstraintOriginProvider)
- self.assertFalse(fields.at(3).constraints().constraints()
- & QgsFieldConstraints.Constraint.ConstraintUnique)
+ self.assertTrue(
+ fields.at(0).constraints().constraints()
+ & QgsFieldConstraints.Constraint.ConstraintUnique
+ )
+ self.assertEqual(
+ fields.at(0)
+ .constraints()
+ .constraintOrigin(QgsFieldConstraints.Constraint.ConstraintUnique),
+ QgsFieldConstraints.ConstraintOrigin.ConstraintOriginProvider,
+ )
+ self.assertTrue(
+ fields.at(1).constraints().constraints()
+ & QgsFieldConstraints.Constraint.ConstraintUnique
+ )
+ self.assertEqual(
+ fields.at(1)
+ .constraints()
+ .constraintOrigin(QgsFieldConstraints.Constraint.ConstraintUnique),
+ QgsFieldConstraints.ConstraintOrigin.ConstraintOriginProvider,
+ )
+ self.assertTrue(
+ fields.at(2).constraints().constraints()
+ & QgsFieldConstraints.Constraint.ConstraintUnique
+ )
+ self.assertEqual(
+ fields.at(2)
+ .constraints()
+ .constraintOrigin(QgsFieldConstraints.Constraint.ConstraintUnique),
+ QgsFieldConstraints.ConstraintOrigin.ConstraintOriginProvider,
+ )
+ self.assertFalse(
+ fields.at(3).constraints().constraints()
+ & QgsFieldConstraints.Constraint.ConstraintUnique
+ )
def testConstraintOverwrite(self):
- """ test that Postgres provider constraints can't be overwritten by vector layer method """
- vl = QgsVectorLayer('%s table="qgis_test"."constraints" sql=' % (
- self.dbconn), "constraints", "postgres")
+ """test that Postgres provider constraints can't be overwritten by vector layer method"""
+ vl = QgsVectorLayer(
+ '%s table="qgis_test"."constraints" sql=' % (self.dbconn),
+ "constraints",
+ "postgres",
+ )
self.assertTrue(vl.isValid())
- self.assertTrue(vl.dataProvider().fieldConstraints(0) &
- QgsFieldConstraints.Constraint.ConstraintNotNull)
- self.assertTrue(vl.fields().at(0).constraints().constraints()
- & QgsFieldConstraints.Constraint.ConstraintNotNull)
+ self.assertTrue(
+ vl.dataProvider().fieldConstraints(0)
+ & QgsFieldConstraints.Constraint.ConstraintNotNull
+ )
+ self.assertTrue(
+ vl.fields().at(0).constraints().constraints()
+ & QgsFieldConstraints.Constraint.ConstraintNotNull
+ )
# add a constraint at the layer level
vl.setFieldConstraint(0, QgsFieldConstraints.Constraint.ConstraintUnique)
# should be no change at provider level
- self.assertTrue(vl.dataProvider().fieldConstraints(0) &
- QgsFieldConstraints.Constraint.ConstraintNotNull)
+ self.assertTrue(
+ vl.dataProvider().fieldConstraints(0)
+ & QgsFieldConstraints.Constraint.ConstraintNotNull
+ )
# but layer should still keep provider constraints...
- self.assertTrue(vl.fields().at(0).constraints().constraints()
- & QgsFieldConstraints.Constraint.ConstraintNotNull)
- self.assertTrue(vl.fieldConstraints(
- 0) & QgsFieldConstraints.Constraint.ConstraintNotNull)
+ self.assertTrue(
+ vl.fields().at(0).constraints().constraints()
+ & QgsFieldConstraints.Constraint.ConstraintNotNull
+ )
+ self.assertTrue(
+ vl.fieldConstraints(0) & QgsFieldConstraints.Constraint.ConstraintNotNull
+ )
# ...in addition to layer level constraint
- self.assertTrue(vl.fields().at(0).constraints(
- ).constraints() & QgsFieldConstraints.Constraint.ConstraintUnique)
- self.assertTrue(vl.fieldConstraints(
- 0) & QgsFieldConstraints.Constraint.ConstraintUnique)
+ self.assertTrue(
+ vl.fields().at(0).constraints().constraints()
+ & QgsFieldConstraints.Constraint.ConstraintUnique
+ )
+ self.assertTrue(
+ vl.fieldConstraints(0) & QgsFieldConstraints.Constraint.ConstraintUnique
+ )
def testReadOnly(self):
# Check default edition capabilities
- vl = QgsVectorLayer('%s sslmode=disable key=\'pk\' srid=4326 type=POINT table="qgis_test"."someData" (geom) sql=' %
- (self.dbconn), "someData", "postgres")
+ vl = QgsVectorLayer(
+ '%s sslmode=disable key=\'pk\' srid=4326 type=POINT table="qgis_test"."someData" (geom) sql='
+ % (self.dbconn),
+ "someData",
+ "postgres",
+ )
self.assertFalse(vl.readOnly())
caps = vl.dataProvider().capabilities()
self.assertTrue(caps & QgsVectorDataProvider.Capability.AddFeatures)
@@ -1769,8 +2297,13 @@ def testReadOnly(self):
# Check forceReadOnly
options = QgsVectorLayer.LayerOptions()
options.forceReadOnly = True
- vl = QgsVectorLayer('%s sslmode=disable key=\'pk\' srid=4326 type=POINT table="qgis_test"."someData" (geom) sql=' %
- (self.dbconn), "someData", "postgres", options)
+ vl = QgsVectorLayer(
+ '%s sslmode=disable key=\'pk\' srid=4326 type=POINT table="qgis_test"."someData" (geom) sql='
+ % (self.dbconn),
+ "someData",
+ "postgres",
+ options,
+ )
self.assertTrue(vl.readOnly())
caps = vl.dataProvider().capabilities()
self.assertFalse(caps & QgsVectorDataProvider.Capability.AddFeatures)
@@ -1783,20 +2316,22 @@ def testReadOnly(self):
self.assertTrue(caps & QgsVectorDataProvider.Capability.SelectAtId)
def testVectorLayerUtilsUniqueWithProviderDefault(self):
- vl = QgsVectorLayer('%s table="qgis_test"."someData" sql=' %
- (self.dbconn), "someData", "postgres")
- default_clause = 'nextval(\'qgis_test."someData_pk_seq"\'::regclass)'
+ vl = QgsVectorLayer(
+ '%s table="qgis_test"."someData" sql=' % (self.dbconn),
+ "someData",
+ "postgres",
+ )
+ default_clause = "nextval('qgis_test.\"someData_pk_seq\"'::regclass)"
vl.dataProvider().setProviderProperty(
- QgsDataProvider.ProviderProperty.EvaluateDefaultValues, False)
- self.assertEqual(
- vl.dataProvider().defaultValueClause(0), default_clause)
+ QgsDataProvider.ProviderProperty.EvaluateDefaultValues, False
+ )
+ self.assertEqual(vl.dataProvider().defaultValueClause(0), default_clause)
self.assertTrue(QgsVectorLayerUtils.valueExists(vl, 0, 4))
vl.startEditing()
f = QgsFeature(vl.fields())
f.setAttribute(0, default_clause)
- self.assertFalse(
- QgsVectorLayerUtils.valueExists(vl, 0, default_clause))
+ self.assertFalse(QgsVectorLayerUtils.valueExists(vl, 0, default_clause))
self.assertTrue(vl.addFeatures([f]))
# the default value clause should exist...
@@ -1806,85 +2341,107 @@ def testVectorLayerUtilsUniqueWithProviderDefault(self):
vl.rollBack()
def testSkipConstraintCheck(self):
- vl = QgsVectorLayer('%s table="qgis_test"."someData" sql=' %
- (self.dbconn), "someData", "postgres")
- default_clause = 'nextval(\'qgis_test."someData_pk_seq"\'::regclass)'
+ vl = QgsVectorLayer(
+ '%s table="qgis_test"."someData" sql=' % (self.dbconn),
+ "someData",
+ "postgres",
+ )
+ default_clause = "nextval('qgis_test.\"someData_pk_seq\"'::regclass)"
vl.dataProvider().setProviderProperty(
- QgsDataProvider.ProviderProperty.EvaluateDefaultValues, False)
- self.assertTrue(vl.dataProvider().skipConstraintCheck(
- 0, QgsFieldConstraints.Constraint.ConstraintUnique, default_clause))
- self.assertFalse(vl.dataProvider().skipConstraintCheck(
- 0, QgsFieldConstraints.Constraint.ConstraintUnique, 59))
+ QgsDataProvider.ProviderProperty.EvaluateDefaultValues, False
+ )
+ self.assertTrue(
+ vl.dataProvider().skipConstraintCheck(
+ 0, QgsFieldConstraints.Constraint.ConstraintUnique, default_clause
+ )
+ )
+ self.assertFalse(
+ vl.dataProvider().skipConstraintCheck(
+ 0, QgsFieldConstraints.Constraint.ConstraintUnique, 59
+ )
+ )
def testVectorLayerUtilsCreateFeatureWithProviderDefault(self):
- vl = QgsVectorLayer('%s table="qgis_test"."someData" sql=' %
- (self.dbconn), "someData", "postgres")
- default_clause = 'nextval(\'qgis_test."someData_pk_seq"\'::regclass)'
- self.assertEqual(
- vl.dataProvider().defaultValueClause(0), default_clause)
+ vl = QgsVectorLayer(
+ '%s table="qgis_test"."someData" sql=' % (self.dbconn),
+ "someData",
+ "postgres",
+ )
+ default_clause = "nextval('qgis_test.\"someData_pk_seq\"'::regclass)"
+ self.assertEqual(vl.dataProvider().defaultValueClause(0), default_clause)
# If an attribute map is provided, QgsVectorLayerUtils.createFeature must
# respect it, otherwise default values from provider are checked.
# User's choice will not be respected if the value violates unique constraints.
# See https://github.com/qgis/QGIS/issues/27758
- f = QgsVectorLayerUtils.createFeature(vl, attributes={1: 5, 3: 'map'})
+ f = QgsVectorLayerUtils.createFeature(vl, attributes={1: 5, 3: "map"})
# changed so that createFeature respects user choice
- self.assertEqual(f.attributes(), [
- default_clause, 5, "'qgis'::text", 'map', None, None, None, None, None])
+ self.assertEqual(
+ f.attributes(),
+ [default_clause, 5, "'qgis'::text", "map", None, None, None, None, None],
+ )
vl.setDefaultValueDefinition(3, QgsDefaultValue("'mappy'"))
# test ignore vector layer default value expression overrides postgres provider default clause,
# due to user's choice
- f = QgsVectorLayerUtils.createFeature(vl, attributes={1: 5, 3: 'map'})
- self.assertEqual(f.attributes(), [
- default_clause, 5, "'qgis'::text", 'map', None, None, None, None, None])
+ f = QgsVectorLayerUtils.createFeature(vl, attributes={1: 5, 3: "map"})
+ self.assertEqual(
+ f.attributes(),
+ [default_clause, 5, "'qgis'::text", "map", None, None, None, None, None],
+ )
# Since user did not enter a default for field 3, test must return the default value chosen
f = QgsVectorLayerUtils.createFeature(vl, attributes={1: 5})
- self.assertEqual(f.attributes(), [
- default_clause, 5, "'qgis'::text", 'mappy', None, None, None, None, None])
+ self.assertEqual(
+ f.attributes(),
+ [default_clause, 5, "'qgis'::text", "mappy", None, None, None, None, None],
+ )
# See https://github.com/qgis/QGIS/issues/23127
def testNumericPrecision(self):
- uri = 'point?field=f1:int'
- uri += '&field=f2:double(6,4)'
- uri += '&field=f3:string(20)'
+ uri = "point?field=f1:int"
+ uri += "&field=f2:double(6,4)"
+ uri += "&field=f3:string(20)"
lyr = QgsVectorLayer(uri, "x", "memory")
self.assertTrue(lyr.isValid())
f = QgsFeature(lyr.fields())
- f['f1'] = 1
- f['f2'] = 123.456
- f['f3'] = '12345678.90123456789'
+ f["f1"] = 1
+ f["f2"] = 123.456
+ f["f3"] = "12345678.90123456789"
lyr.dataProvider().addFeatures([f])
uri = f'{self.dbconn} table="qgis_test"."b18155" (g) key=\'f1\''
- self.execSQLCommand('DROP TABLE IF EXISTS qgis_test.b18155')
- err = QgsVectorLayerExporter.exportLayer(
- lyr, uri, "postgres", lyr.crs())
- self.assertEqual(err[0], QgsVectorLayerExporter.ExportError.NoError,
- f'unexpected import error {err}')
+ self.execSQLCommand("DROP TABLE IF EXISTS qgis_test.b18155")
+ err = QgsVectorLayerExporter.exportLayer(lyr, uri, "postgres", lyr.crs())
+ self.assertEqual(
+ err[0],
+ QgsVectorLayerExporter.ExportError.NoError,
+ f"unexpected import error {err}",
+ )
lyr = QgsVectorLayer(uri, "y", "postgres")
self.assertTrue(lyr.isValid())
f = next(lyr.getFeatures())
- self.assertEqual(f['f1'], 1)
- self.assertEqual(f['f2'], 123.456)
- self.assertEqual(f['f3'], '12345678.90123456789')
+ self.assertEqual(f["f1"], 1)
+ self.assertEqual(f["f2"], 123.456)
+ self.assertEqual(f["f3"], "12345678.90123456789")
# See https://github.com/qgis/QGIS/issues/23163
def testImportKey(self):
- uri = 'point?field=f1:int'
- uri += '&field=F2:double(6,4)'
- uri += '&field=f3:string(20)'
+ uri = "point?field=f1:int"
+ uri += "&field=F2:double(6,4)"
+ uri += "&field=f3:string(20)"
lyr = QgsVectorLayer(uri, "x", "memory")
self.assertTrue(lyr.isValid())
def testKey(lyr, key, kfnames):
- self.execSQLCommand('DROP TABLE IF EXISTS qgis_test.import_test')
+ self.execSQLCommand("DROP TABLE IF EXISTS qgis_test.import_test")
uri = f'{self.dbconn} table="qgis_test"."import_test" (g)'
if key is not None:
- uri += f' key=\'{key}\''
- err = QgsVectorLayerExporter.exportLayer(
- lyr, uri, "postgres", lyr.crs())
- self.assertEqual(err[0], QgsVectorLayerExporter.ExportError.NoError,
- f'unexpected import error {err}')
+ uri += f" key='{key}'"
+ err = QgsVectorLayerExporter.exportLayer(lyr, uri, "postgres", lyr.crs())
+ self.assertEqual(
+ err[0],
+ QgsVectorLayerExporter.ExportError.NoError,
+ f"unexpected import error {err}",
+ )
olyr = QgsVectorLayer(uri, "y", "postgres")
self.assertTrue(olyr.isValid())
flds = lyr.fields()
@@ -1905,33 +2462,31 @@ def testKey(lyr, key, kfnames):
for i in range(0, len(kfnames)):
self.assertEqual(oflds[pks[i]].name(), kfnames[i])
- testKey(lyr, 'f1', ['f1'])
- testKey(lyr, '"f1"', ['f1'])
- testKey(lyr, '"f1","F2"', ['f1', 'F2'])
- testKey(lyr, '"f1","F2","f3"', ['f1', 'F2', 'f3'])
- testKey(lyr, None, ['id'])
+ testKey(lyr, "f1", ["f1"])
+ testKey(lyr, '"f1"', ["f1"])
+ testKey(lyr, '"f1","F2"', ["f1", "F2"])
+ testKey(lyr, '"f1","F2","f3"', ["f1", "F2", "f3"])
+ testKey(lyr, None, ["id"])
# See https://github.com/qgis/QGIS/issues/25415
def testImportWithoutSchema(self):
def _test(table, schema=None):
- self.execSQLCommand(f'DROP TABLE IF EXISTS {table} CASCADE')
- uri = 'point?field=f1:int'
- uri += '&field=F2:double(6,4)'
- uri += '&field=f3:string(20)'
+ self.execSQLCommand(f"DROP TABLE IF EXISTS {table} CASCADE")
+ uri = "point?field=f1:int"
+ uri += "&field=F2:double(6,4)"
+ uri += "&field=f3:string(20)"
lyr = QgsVectorLayer(uri, "x", "memory")
self.assertTrue(lyr.isValid())
- table = f"{table}" if schema is None else (
- f"\"{schema}\".\"{table}\"")
+ table = f"{table}" if schema is None else (f'"{schema}"."{table}"')
dest_uri = f"{self.dbconn} sslmode=disable table={table} (geom) sql"
- QgsVectorLayerExporter.exportLayer(
- lyr, dest_uri, "postgres", lyr.crs())
+ QgsVectorLayerExporter.exportLayer(lyr, dest_uri, "postgres", lyr.crs())
olyr = QgsVectorLayer(dest_uri, "y", "postgres")
self.assertTrue(olyr.isValid(), f"Failed URI: {dest_uri}")
# Test bug 17518
- _test('b17518')
+ _test("b17518")
# Test fully qualified table (with schema)
_test("b17518", "qgis_test")
@@ -1947,20 +2502,36 @@ def _test(table, schema=None):
_test("b17518", "qgis_test_wrong")
def testStyle(self):
- self.execSQLCommand('DROP TABLE IF EXISTS layer_styles CASCADE')
+ self.execSQLCommand("DROP TABLE IF EXISTS layer_styles CASCADE")
vl = self.getEditableLayer()
self.assertTrue(vl.isValid())
- self.assertEqual(int(vl.dataProvider().styleStorageCapabilities()) & Qgis.ProviderStyleStorageCapability.LoadFromDatabase, Qgis.ProviderStyleStorageCapability.LoadFromDatabase)
- self.assertEqual(int(vl.dataProvider().styleStorageCapabilities()) & Qgis.ProviderStyleStorageCapability.SaveToDatabase, Qgis.ProviderStyleStorageCapability.SaveToDatabase)
- self.assertEqual(int(vl.dataProvider().styleStorageCapabilities()) & Qgis.ProviderStyleStorageCapability.DeleteFromDatabase, Qgis.ProviderStyleStorageCapability.DeleteFromDatabase)
+ self.assertEqual(
+ int(vl.dataProvider().styleStorageCapabilities())
+ & Qgis.ProviderStyleStorageCapability.LoadFromDatabase,
+ Qgis.ProviderStyleStorageCapability.LoadFromDatabase,
+ )
+ self.assertEqual(
+ int(vl.dataProvider().styleStorageCapabilities())
+ & Qgis.ProviderStyleStorageCapability.SaveToDatabase,
+ Qgis.ProviderStyleStorageCapability.SaveToDatabase,
+ )
+ self.assertEqual(
+ int(vl.dataProvider().styleStorageCapabilities())
+ & Qgis.ProviderStyleStorageCapability.DeleteFromDatabase,
+ Qgis.ProviderStyleStorageCapability.DeleteFromDatabase,
+ )
# table layer_styles does not exist
- res, err = QgsProviderRegistry.instance().styleExists('postgres', vl.source(), '')
+ res, err = QgsProviderRegistry.instance().styleExists(
+ "postgres", vl.source(), ""
+ )
self.assertFalse(res)
self.assertFalse(err)
- res, err = QgsProviderRegistry.instance().styleExists('postgres', vl.source(), 'a style')
+ res, err = QgsProviderRegistry.instance().styleExists(
+ "postgres", vl.source(), "a style"
+ )
self.assertFalse(res)
self.assertFalse(err)
@@ -1976,13 +2547,15 @@ def testStyle(self):
self.assertTrue(errmsg)
mFilePath = QDir.toNativeSeparators(
- f"{unitTestDataPath()}/symbol_layer/singleSymbol.qml")
+ f"{unitTestDataPath()}/symbol_layer/singleSymbol.qml"
+ )
status = vl.loadNamedStyle(mFilePath)
self.assertTrue(status)
# The style is saved as non-default
errorMsg = vl.saveStyleToDatabase(
- "by day", "faded greens and elegant patterns", False, "")
+ "by day", "faded greens and elegant patterns", False, ""
+ )
self.assertFalse(errorMsg)
# the style id should be "1", not "by day"
@@ -1990,13 +2563,19 @@ def testStyle(self):
self.assertEqual(qml, "")
self.assertNotEqual(errmsg, "")
- res, err = QgsProviderRegistry.instance().styleExists('postgres', vl.source(), '')
+ res, err = QgsProviderRegistry.instance().styleExists(
+ "postgres", vl.source(), ""
+ )
self.assertFalse(res)
self.assertFalse(err)
- res, err = QgsProviderRegistry.instance().styleExists('postgres', vl.source(), 'a style')
+ res, err = QgsProviderRegistry.instance().styleExists(
+ "postgres", vl.source(), "a style"
+ )
self.assertFalse(res)
self.assertFalse(err)
- res, err = QgsProviderRegistry.instance().styleExists('postgres', vl.source(), 'by day')
+ res, err = QgsProviderRegistry.instance().styleExists(
+ "postgres", vl.source(), "by day"
+ )
self.assertTrue(res)
self.assertFalse(err)
@@ -2012,7 +2591,7 @@ def testStyle(self):
self.assertTrue(errmsg)
qml, errmsg = vl.getStyleFromDatabase("1")
- self.assertTrue(qml.startswith(' xMax and normalization ==> nothing found
- _test(vl, QgsRectangle(180.0 - 0.0017, 45.0 - 0.0001,
- -(180.0 - 0.0017), 45.0 + 0.0001), [])
+ _test(
+ vl,
+ QgsRectangle(
+ 180.0 - 0.0017, 45.0 - 0.0001, -(180.0 - 0.0017), 45.0 + 0.0001
+ ),
+ [],
+ )
# good order but with xMin > xMax and without normalization
- _test(vl, QgsRectangle(180.0 - 0.0017, 45.0 - 0.0001,
- -(180.0 - 0.0017), 45.0 + 0.0001, False), [4])
+ _test(
+ vl,
+ QgsRectangle(
+ 180.0 - 0.0017, 45.0 - 0.0001, -(180.0 - 0.0017), 45.0 + 0.0001, False
+ ),
+ [4],
+ )
# now from 3857
- _test(vl, QgsRectangle(-20037699.584651027, 5621430.516018896, -20037317.10092746, 5621612.352543215), [4], "EPSG:3857")
+ _test(
+ vl,
+ QgsRectangle(
+ -20037699.584651027,
+ 5621430.516018896,
+ -20037317.10092746,
+ 5621612.352543215,
+ ),
+ [4],
+ "EPSG:3857",
+ )
def testBBoxFilterOnGeographyType(self):
"""Test bounding box filter on geography type"""
- self._doTestBBoxFilter(' sslmode=disable key=\'pk\' srid=4326 type=POINT table="qgis_test"."testgeog" (geog) sql=')
+ self._doTestBBoxFilter(
+ ' sslmode=disable key=\'pk\' srid=4326 type=POINT table="qgis_test"."testgeog" (geog) sql='
+ )
def testBBoxFilterOnGeometryType(self):
"""Test bounding box filter on somegeometry type"""
self._doTestBBoxFilter(
- ' sslmode=disable key=\'pk\' srid=4326 type=POINT table="qgis_test"."someBorderlineData" (geom) sql=')
+ ' sslmode=disable key=\'pk\' srid=4326 type=POINT table="qgis_test"."someBorderlineData" (geom) sql='
+ )
def testReadCustomSRID(self):
"""Test that we can correctly read the SRS from a custom SRID"""
@@ -2944,52 +3744,91 @@ def testReadCustomSRID(self):
# Cleanup if needed
try:
- conn.dropVectorTable('qgis_test', 'test_custom_srid')
+ conn.dropVectorTable("qgis_test", "test_custom_srid")
except QgsProviderConnectionException:
pass
- conn.executeSql("DELETE FROM spatial_ref_sys WHERE srid = 543210 AND auth_name='FOO' AND auth_srid=32600;")
- conn.executeSql("""INSERT INTO spatial_ref_sys (srid, auth_name, auth_srid, srtext, proj4text) VALUES (543210, 'FOO', 32600, 'PROJCS["my_projection",GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563,AUTHORITY["EPSG","7030"]],AUTHORITY["EPSG","6326"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]]],PROJECTION["Transverse_Mercator"],PARAMETER["latitude_of_origin",0],PARAMETER["central_meridian",0],PARAMETER["scale_factor",1],PARAMETER["false_easting",0],PARAMETER["false_northing",0],UNIT["metre",1,AUTHORITY["EPSG","9001"]],AXIS["Easting",EAST],AXIS["Northing",NORTH]]','+proj=tmerc +lat_0=0 +lon_0=0 +k=1 +x_0=0 +y_0=0 +datum=WGS84 +units=m +no_defs');""")
+ conn.executeSql(
+ "DELETE FROM spatial_ref_sys WHERE srid = 543210 AND auth_name='FOO' AND auth_srid=32600;"
+ )
+ conn.executeSql(
+ """INSERT INTO spatial_ref_sys (srid, auth_name, auth_srid, srtext, proj4text) VALUES (543210, 'FOO', 32600, 'PROJCS["my_projection",GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563,AUTHORITY["EPSG","7030"]],AUTHORITY["EPSG","6326"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]]],PROJECTION["Transverse_Mercator"],PARAMETER["latitude_of_origin",0],PARAMETER["central_meridian",0],PARAMETER["scale_factor",1],PARAMETER["false_easting",0],PARAMETER["false_northing",0],UNIT["metre",1,AUTHORITY["EPSG","9001"]],AXIS["Easting",EAST],AXIS["Northing",NORTH]]','+proj=tmerc +lat_0=0 +lon_0=0 +k=1 +x_0=0 +y_0=0 +datum=WGS84 +units=m +no_defs');"""
+ )
- conn.executeSql('''
+ conn.executeSql(
+ """
CREATE TABLE "qgis_test"."test_custom_srid" (
gid serial primary key,
geom geometry(Point, 543210)
- );''')
+ );"""
+ )
- layer = QgsVectorLayer(self.dbconn + ' sslmode=disable key=\'gid\'table="qgis_test"."test_custom_srid" (geom) sql=', 'test', 'postgres')
+ layer = QgsVectorLayer(
+ self.dbconn
+ + ' sslmode=disable key=\'gid\'table="qgis_test"."test_custom_srid" (geom) sql=',
+ "test",
+ "postgres",
+ )
- conn.executeSql("DELETE FROM spatial_ref_sys WHERE srid = 543210 AND auth_name='FOO' AND auth_srid=32600;")
+ conn.executeSql(
+ "DELETE FROM spatial_ref_sys WHERE srid = 543210 AND auth_name='FOO' AND auth_srid=32600;"
+ )
self.assertTrue(layer.isValid())
- self.assertEqual(layer.crs().description(), 'my_projection')
+ self.assertEqual(layer.crs().description(), "my_projection")
def testSingleMultiColumnPkSmallData(self):
"""Test Single and Multi Column PK, `Small` Data"""
from itertools import combinations
- def test_for_pk_combinations(test_type_list, pk_column_name_list, fids_get_count):
- pk_column_name = ','.join(pk_column_name_list)
- set_new_pk = '''
+ def test_for_pk_combinations(
+ test_type_list, pk_column_name_list, fids_get_count
+ ):
+ pk_column_name = ",".join(pk_column_name_list)
+ set_new_pk = """
ALTER TABLE qgis_test.multi_column_pk_small_data_table DROP CONSTRAINT multi_column_pk_small_data_pk;
ALTER TABLE qgis_test.multi_column_pk_small_data_table
- ADD CONSTRAINT multi_column_pk_small_data_pk PRIMARY KEY ({});'''
+ ADD CONSTRAINT multi_column_pk_small_data_pk PRIMARY KEY ({});"""
set_new_layer = ' sslmode=disable key=\'{}\' srid=3857 type=POLYGON table="qgis_test"."multi_column_pk_small_data_{}" (geom) sql='
- error_string = 'from {} with PK - {} : expected {}, got {}'
+ error_string = "from {} with PK - {} : expected {}, got {}"
- if 'table' in test_type_list:
+ if "table" in test_type_list:
self.execSQLCommand(set_new_pk.format(pk_column_name))
for test_type in test_type_list:
- vl = QgsVectorLayer(self.dbconn + set_new_layer.format(pk_column_name, test_type), 'test_multi_column_pk_small_data', 'postgres')
- fids = [f.id() for f in vl.getFeatures(QgsFeatureRequest().setLimit(fids_get_count))]
+ vl = QgsVectorLayer(
+ self.dbconn + set_new_layer.format(pk_column_name, test_type),
+ "test_multi_column_pk_small_data",
+ "postgres",
+ )
+ fids = [
+ f.id()
+ for f in vl.getFeatures(
+ QgsFeatureRequest().setLimit(fids_get_count)
+ )
+ ]
fids2 = [f.id() for f in vl.getFeatures(fids)]
- self.assertEqual(fids_get_count, len(fids), "Get with limit " +
- error_string.format(test_type, pk_column_name, fids_get_count, len(fids)))
- self.assertEqual(fids_get_count, len(fids2), "Get by fids " +
- error_string.format(test_type, pk_column_name, fids_get_count, len(fids2)))
+ self.assertEqual(
+ fids_get_count,
+ len(fids),
+ "Get with limit "
+ + error_string.format(
+ test_type, pk_column_name, fids_get_count, len(fids)
+ ),
+ )
+ self.assertEqual(
+ fids_get_count,
+ len(fids2),
+ "Get by fids "
+ + error_string.format(
+ test_type, pk_column_name, fids_get_count, len(fids2)
+ ),
+ )
- self.execSQLCommand('DROP TABLE IF EXISTS qgis_test.multi_column_pk_small_data_table CASCADE;')
- self.execSQLCommand('''
+ self.execSQLCommand(
+ "DROP TABLE IF EXISTS qgis_test.multi_column_pk_small_data_table CASCADE;"
+ )
+ self.execSQLCommand(
+ """
CREATE TABLE qgis_test.multi_column_pk_small_data_table (
id_serial serial NOT NULL,
id_uuid uuid NOT NULL,
@@ -3007,14 +3846,18 @@ def test_for_pk_combinations(test_type_list, pk_column_name_list, fids_get_count
id_all_null_uuid uuid,
geom geometry(Polygon,3857),
CONSTRAINT multi_column_pk_small_data_pk
- PRIMARY KEY (id_serial, id_uuid, id_int, id_bigint, id_str) );''')
- self.execSQLCommand('''
+ PRIMARY KEY (id_serial, id_uuid, id_int, id_bigint, id_str) );"""
+ )
+ self.execSQLCommand(
+ """
CREATE OR REPLACE VIEW qgis_test.multi_column_pk_small_data_view AS
SELECT * FROM qgis_test.multi_column_pk_small_data_table;
DROP MATERIALIZED VIEW IF EXISTS qgis_test.multi_column_pk_small_data_mat_view;
CREATE MATERIALIZED VIEW qgis_test.multi_column_pk_small_data_mat_view AS
- SELECT * FROM qgis_test.multi_column_pk_small_data_table;''')
- self.execSQLCommand('''
+ SELECT * FROM qgis_test.multi_column_pk_small_data_table;"""
+ )
+ self.execSQLCommand(
+ """
TRUNCATE qgis_test.multi_column_pk_small_data_table;
INSERT INTO qgis_test.multi_column_pk_small_data_table(
id_uuid, id_int, id_bigint, id_str, id_inet4, id_inet6, id_cidr4, id_cidr6,
@@ -3040,18 +3883,42 @@ def test_for_pk_combinations(test_type_list, pk_column_name_list, fids_get_count
100.0 * dx,
100.0 * dy )
FROM generate_series(1,3) dx, generate_series(1,3) dy;
- REFRESH MATERIALIZED VIEW qgis_test.multi_column_pk_small_data_mat_view;''')
+ REFRESH MATERIALIZED VIEW qgis_test.multi_column_pk_small_data_mat_view;"""
+ )
- pk_col_list = ("id_serial", "id_uuid", "id_int", "id_bigint", "id_str", "id_inet4", "id_inet6", "id_cidr4", "id_cidr6", "id_macaddr", "id_macaddr8")
+ pk_col_list = (
+ "id_serial",
+ "id_uuid",
+ "id_int",
+ "id_bigint",
+ "id_str",
+ "id_inet4",
+ "id_inet6",
+ "id_cidr4",
+ "id_cidr6",
+ "id_macaddr",
+ "id_macaddr8",
+ )
test_type_list = ["table", "view", "mat_view"]
for n in [1, 2, len(pk_col_list)]:
pk_col_set_list = list(combinations(pk_col_list, n))
for pk_col_set in pk_col_set_list:
test_for_pk_combinations(test_type_list, pk_col_set, 7)
- for col_name in ["id_serial", "id_uuid", "id_int", "id_bigint", "id_str", "id_inet4"]:
- test_for_pk_combinations(["view", "mat_view"], ["id_half_null_uuid", col_name], 7)
- test_for_pk_combinations(["view", "mat_view"], ["id_all_null_uuid", col_name], 7)
+ for col_name in [
+ "id_serial",
+ "id_uuid",
+ "id_int",
+ "id_bigint",
+ "id_str",
+ "id_inet4",
+ ]:
+ test_for_pk_combinations(
+ ["view", "mat_view"], ["id_half_null_uuid", col_name], 7
+ )
+ test_for_pk_combinations(
+ ["view", "mat_view"], ["id_all_null_uuid", col_name], 7
+ )
def testChangeAttributeWithDefaultValue(self):
"""Test that we can change an attribute value with its default value"""
@@ -3061,23 +3928,32 @@ def testChangeAttributeWithDefaultValue(self):
# Cleanup
try:
- conn.dropVectorTable('qgis_test', 'test_change_att_w_default_value')
+ conn.dropVectorTable("qgis_test", "test_change_att_w_default_value")
except QgsProviderConnectionException:
pass
- conn.executeSql('''
+ conn.executeSql(
+ """
CREATE TABLE "qgis_test"."test_change_att_w_default_value" (
id serial primary key,
thetext1 character varying(8) DEFAULT NULL::character varying,
thetext2 character varying(8) DEFAULT NULL,
thetext3 character varying(8) DEFAULT 'blabla',
thenumber integer DEFAULT 2+2
- );''')
+ );"""
+ )
- conn.executeSql('''
- INSERT INTO "qgis_test"."test_change_att_w_default_value" (thetext1,thetext2,thetext3,thenumber) VALUES ('test1','test2','test3',6);''')
+ conn.executeSql(
+ """
+ INSERT INTO "qgis_test"."test_change_att_w_default_value" (thetext1,thetext2,thetext3,thenumber) VALUES ('test1','test2','test3',6);"""
+ )
- layer = QgsVectorLayer(self.dbconn + ' sslmode=disable key=\'id\'table="qgis_test"."test_change_att_w_default_value" sql=', 'test', 'postgres')
+ layer = QgsVectorLayer(
+ self.dbconn
+ + ' sslmode=disable key=\'id\'table="qgis_test"."test_change_att_w_default_value" sql=',
+ "test",
+ "postgres",
+ )
self.assertTrue(layer.isValid())
self.assertEqual(layer.featureCount(), 1)
feat = next(layer.getFeatures())
@@ -3086,14 +3962,29 @@ def testChangeAttributeWithDefaultValue(self):
self.assertTrue(feat["thetext3"], "test3")
self.assertTrue(feat["thenumber"], 6)
- self.assertEqual(layer.dataProvider().defaultValueClause(1), "NULL::character varying")
- self.assertEqual(layer.dataProvider().defaultValueClause(2), "NULL::character varying")
- self.assertEqual(layer.dataProvider().defaultValueClause(3), "'blabla'::character varying")
+ self.assertEqual(
+ layer.dataProvider().defaultValueClause(1), "NULL::character varying"
+ )
+ self.assertEqual(
+ layer.dataProvider().defaultValueClause(2), "NULL::character varying"
+ )
+ self.assertEqual(
+ layer.dataProvider().defaultValueClause(3), "'blabla'::character varying"
+ )
self.assertEqual(layer.dataProvider().defaultValueClause(4), "(2 + 2)")
layer.startEditing()
- self.assertTrue(layer.changeAttributeValues(1, {1: "NULL::character varying", 2: "NULL::character varying",
- 3: "'blabla'::character varying", 4: "(2 + 2)"}))
+ self.assertTrue(
+ layer.changeAttributeValues(
+ 1,
+ {
+ 1: "NULL::character varying",
+ 2: "NULL::character varying",
+ 3: "'blabla'::character varying",
+ 4: "(2 + 2)",
+ },
+ )
+ )
self.assertTrue(layer.commitChanges())
feat = next(layer.getFeatures())
@@ -3106,87 +3997,135 @@ def testChangeAttributeWithDefaultValue(self):
def testExtractWithinDistanceAlgorithm(self):
- with self.temporarySchema('extract_within_distance') as schema:
+ with self.temporarySchema("extract_within_distance") as schema:
# Create and populate target table in PseudoWebMercator CRS
self.execSQLCommand(
- 'CREATE TABLE {}.target_3857 (id serial primary key, g geometry(linestring, 3857))'
- .format(schema))
+ "CREATE TABLE {}.target_3857 (id serial primary key, g geometry(linestring, 3857))".format(
+ schema
+ )
+ )
# -- first line (id=1)
self.execSQLCommand(
- "INSERT INTO {}.target_3857 (g) values('SRID=3857;LINESTRING(0 0, 1000 1000)')"
- .format(schema))
+ "INSERT INTO {}.target_3857 (g) values('SRID=3857;LINESTRING(0 0, 1000 1000)')".format(
+ schema
+ )
+ )
# -- secodn line is a great circle line on the right (id=2)
self.execSQLCommand(
- "INSERT INTO {}.target_3857 (g) values( ST_Transform('SRID=4326;LINESTRING(80 0,160 80)'::geometry, 3857) )"
- .format(schema))
+ "INSERT INTO {}.target_3857 (g) values( ST_Transform('SRID=4326;LINESTRING(80 0,160 80)'::geometry, 3857) )".format(
+ schema
+ )
+ )
# Create and populate reference table in PseudoWebMercator CRS
self.execSQLCommand(
- 'CREATE TABLE {}.reference_3857 (id serial primary key, g geometry(point, 3857))'
- .format(schema))
+ "CREATE TABLE {}.reference_3857 (id serial primary key, g geometry(point, 3857))".format(
+ schema
+ )
+ )
self.execSQLCommand(
- "INSERT INTO {}.reference_3857 (g) values('SRID=3857;POINT(500 999)')"
- .format(schema))
+ "INSERT INTO {}.reference_3857 (g) values('SRID=3857;POINT(500 999)')".format(
+ schema
+ )
+ )
self.execSQLCommand(
- "INSERT INTO {}.reference_3857 (g) values('SRID=3857;POINT(501 999)')"
- .format(schema))
+ "INSERT INTO {}.reference_3857 (g) values('SRID=3857;POINT(501 999)')".format(
+ schema
+ )
+ )
self.execSQLCommand(
# -- this reference (id=3) is ON the first line (id=1) in webmercator
# -- and probably very close in latlong WGS84
- "INSERT INTO {}.reference_3857 (g) values('SRID=3857;POINT(500 500)')"
- .format(schema))
+ "INSERT INTO {}.reference_3857 (g) values('SRID=3857;POINT(500 500)')".format(
+ schema
+ )
+ )
self.execSQLCommand(
# -- this reference (id=4) is at ~ 5 meters from second line (id=2) in webmercator
- "INSERT INTO {}.reference_3857 (g) values('SRID=3857;POINT(12072440.688888172 5525668.358321408)')"
- .format(schema))
+ "INSERT INTO {}.reference_3857 (g) values('SRID=3857;POINT(12072440.688888172 5525668.358321408)')".format(
+ schema
+ )
+ )
self.execSQLCommand(
- "INSERT INTO {}.reference_3857 (g) values('SRID=3857;POINT(503 999)')"
- .format(schema))
+ "INSERT INTO {}.reference_3857 (g) values('SRID=3857;POINT(503 999)')".format(
+ schema
+ )
+ )
self.execSQLCommand(
- "INSERT INTO {}.reference_3857 (g) values('SRID=3857;POINT(504 999)')"
- .format(schema))
+ "INSERT INTO {}.reference_3857 (g) values('SRID=3857;POINT(504 999)')".format(
+ schema
+ )
+ )
# Create and populate target and reference table in WGS84 latlong
self.execSQLCommand(
- 'CREATE TABLE {0}.target_4326 AS SELECT id, ST_Transform(g, 4326)::geometry(linestring,4326) as g FROM {0}.target_3857'
- .format(schema))
+ "CREATE TABLE {0}.target_4326 AS SELECT id, ST_Transform(g, 4326)::geometry(linestring,4326) as g FROM {0}.target_3857".format(
+ schema
+ )
+ )
self.execSQLCommand(
- 'CREATE TABLE {0}.reference_4326 AS SELECT id, ST_Transform(g, 4326)::geometry(point,4326) as g FROM {0}.reference_3857'
- .format(schema))
+ "CREATE TABLE {0}.reference_4326 AS SELECT id, ST_Transform(g, 4326)::geometry(point,4326) as g FROM {0}.reference_3857".format(
+ schema
+ )
+ )
# Create target and reference layers
vl_target_3857 = QgsVectorLayer(
- '{} sslmode=disable key=id srid=3857 type=LINESTRING table="{}"."target_3857" (g) sql='
- .format(self.dbconn, schema),
- 'target_3857', 'postgres')
- self.assertTrue(vl_target_3857.isValid(), f"Could not create a layer from the '{schema}.target_3857' table using dbconn '{self.dbconn}'")
+ '{} sslmode=disable key=id srid=3857 type=LINESTRING table="{}"."target_3857" (g) sql='.format(
+ self.dbconn, schema
+ ),
+ "target_3857",
+ "postgres",
+ )
+ self.assertTrue(
+ vl_target_3857.isValid(),
+ f"Could not create a layer from the '{schema}.target_3857' table using dbconn '{self.dbconn}'",
+ )
vl_reference_3857 = QgsVectorLayer(
- '{} sslmode=disable key=id srid=3857 type=POINT table="{}"."reference_3857" (g) sql='
- .format(self.dbconn, schema),
- 'reference_3857', 'postgres')
- self.assertTrue(vl_reference_3857.isValid(), f"Could not create a layer from the '{schema}.reference_3857' table using dbconn '{self.dbconn}'")
+ '{} sslmode=disable key=id srid=3857 type=POINT table="{}"."reference_3857" (g) sql='.format(
+ self.dbconn, schema
+ ),
+ "reference_3857",
+ "postgres",
+ )
+ self.assertTrue(
+ vl_reference_3857.isValid(),
+ f"Could not create a layer from the '{schema}.reference_3857' table using dbconn '{self.dbconn}'",
+ )
vl_target_4326 = QgsVectorLayer(
- '{} sslmode=disable key=id srid=4326 type=LINESTRING table="{}"."target_4326" (g) sql='
- .format(self.dbconn, schema),
- 'target_4326', 'postgres')
- self.assertTrue(vl_target_4326.isValid(), f"Could not create a layer from the '{schema}.target_4326' table using dbconn '{self.dbconn}'")
+ '{} sslmode=disable key=id srid=4326 type=LINESTRING table="{}"."target_4326" (g) sql='.format(
+ self.dbconn, schema
+ ),
+ "target_4326",
+ "postgres",
+ )
+ self.assertTrue(
+ vl_target_4326.isValid(),
+ f"Could not create a layer from the '{schema}.target_4326' table using dbconn '{self.dbconn}'",
+ )
vl_reference_4326 = QgsVectorLayer(
- '{} sslmode=disable key=id srid=4326 type=POINT table="{}"."reference_4326" (g) sql='
- .format(self.dbconn, schema),
- 'reference_4326', 'postgres')
- self.assertTrue(vl_reference_4326.isValid(), f"Could not create a layer from the '{schema}.reference_4326' table using dbconn '{self.dbconn}'")
+ '{} sslmode=disable key=id srid=4326 type=POINT table="{}"."reference_4326" (g) sql='.format(
+ self.dbconn, schema
+ ),
+ "reference_4326",
+ "postgres",
+ )
+ self.assertTrue(
+ vl_reference_4326.isValid(),
+ f"Could not create a layer from the '{schema}.reference_4326' table using dbconn '{self.dbconn}'",
+ )
# Create the ExtractWithinDistance algorithm
# TODO: move registry initialization in class initialization ?
QgsApplication.processingRegistry().addProvider(QgsNativeAlgorithms())
registry = QgsApplication.instance().processingRegistry()
- alg = registry.createAlgorithmById('native:extractwithindistance')
+ alg = registry.createAlgorithmById("native:extractwithindistance")
self.assertIsNotNone(alg)
# Utility feedback and context objects
class ConsoleFeedBack(QgsProcessingFeedback):
- _error = ''
+ _error = ""
def reportError(self, error, fatalError=False):
self._error = error
@@ -3201,24 +4140,26 @@ def reportError(self, error, fatalError=False):
parameters = {
# extract features from here:
- 'INPUT': vl_target_3857,
+ "INPUT": vl_target_3857,
# extracted features must be within given
# distance from this layer:
- 'REFERENCE': vl_reference_3857,
+ "REFERENCE": vl_reference_3857,
# distance (in INPUT units)
- 'DISTANCE': 10, # meters
- 'OUTPUT': 'memory:result'
+ "DISTANCE": 10, # meters
+ "OUTPUT": "memory:result",
}
# Note: the following returns true also in case of errors ...
result = alg.run(parameters, context, feedback)
self.assertEqual(result[1], True)
- result_layer_name = result[0]['OUTPUT']
- vl_result = QgsProcessingUtils.mapLayerFromString(result_layer_name, context)
+ result_layer_name = result[0]["OUTPUT"]
+ vl_result = QgsProcessingUtils.mapLayerFromString(
+ result_layer_name, context
+ )
self.assertTrue(vl_result.isValid())
- extracted_fids = [f['id'] for f in vl_result.getFeatures()]
+ extracted_fids = [f["id"] for f in vl_result.getFeatures()]
self.assertEqual(set(extracted_fids), {1, 2})
# ----------------------------------------------------------------
@@ -3227,24 +4168,26 @@ def reportError(self, error, fatalError=False):
parameters = {
# extract features from here:
- 'INPUT': vl_target_4326,
+ "INPUT": vl_target_4326,
# extracted features must be within given
# distance from this layer:
- 'REFERENCE': vl_reference_4326,
+ "REFERENCE": vl_reference_4326,
# distance (in INPUT units)
- 'DISTANCE': 9e-5, # degrees
- 'OUTPUT': 'memory:result'
+ "DISTANCE": 9e-5, # degrees
+ "OUTPUT": "memory:result",
}
# Note: the following returns true also in case of errors ...
result = alg.run(parameters, context, feedback)
self.assertEqual(result[1], True)
- result_layer_name = result[0]['OUTPUT']
- vl_result = QgsProcessingUtils.mapLayerFromString(result_layer_name, context)
+ result_layer_name = result[0]["OUTPUT"]
+ vl_result = QgsProcessingUtils.mapLayerFromString(
+ result_layer_name, context
+ )
self.assertTrue(vl_result.isValid())
- extracted_fids = [f['id'] for f in vl_result.getFeatures()]
+ extracted_fids = [f["id"] for f in vl_result.getFeatures()]
self.assertEqual(set(extracted_fids), {1})
# ----------------------------------------------------------------
@@ -3253,24 +4196,26 @@ def reportError(self, error, fatalError=False):
parameters = {
# extract features from here:
- 'INPUT': vl_target_4326,
+ "INPUT": vl_target_4326,
# extracted features must be within given
# distance from this layer:
- 'REFERENCE': vl_reference_3857,
+ "REFERENCE": vl_reference_3857,
# distance (in INPUT units)
- 'DISTANCE': 9e-5, # degrees
- 'OUTPUT': 'memory:result'
+ "DISTANCE": 9e-5, # degrees
+ "OUTPUT": "memory:result",
}
# Note: the following returns true also in case of errors ...
result = alg.run(parameters, context, feedback)
self.assertEqual(result[1], True)
- result_layer_name = result[0]['OUTPUT']
- vl_result = QgsProcessingUtils.mapLayerFromString(result_layer_name, context)
+ result_layer_name = result[0]["OUTPUT"]
+ vl_result = QgsProcessingUtils.mapLayerFromString(
+ result_layer_name, context
+ )
self.assertTrue(vl_result.isValid())
- extracted_fids = [f['id'] for f in vl_result.getFeatures()]
+ extracted_fids = [f["id"] for f in vl_result.getFeatures()]
self.assertEqual(set(extracted_fids), {1})
# ----------------------------------------------------------------
@@ -3279,45 +4224,60 @@ def reportError(self, error, fatalError=False):
parameters = {
# extract features from here:
- 'INPUT': vl_target_3857,
+ "INPUT": vl_target_3857,
# extracted features must be within given
# distance from this layer:
- 'REFERENCE': vl_reference_4326,
+ "REFERENCE": vl_reference_4326,
# distance (in INPUT units)
- 'DISTANCE': 10, # meters
- 'OUTPUT': 'memory:result'
+ "DISTANCE": 10, # meters
+ "OUTPUT": "memory:result",
}
# Note: the following returns true also in case of errors ...
result = alg.run(parameters, context, feedback)
self.assertEqual(result[1], True)
- result_layer_name = result[0]['OUTPUT']
- vl_result = QgsProcessingUtils.mapLayerFromString(result_layer_name, context)
+ result_layer_name = result[0]["OUTPUT"]
+ vl_result = QgsProcessingUtils.mapLayerFromString(
+ result_layer_name, context
+ )
self.assertTrue(vl_result.isValid())
- extracted_fids = [f['id'] for f in vl_result.getFeatures()]
+ extracted_fids = [f["id"] for f in vl_result.getFeatures()]
self.assertEqual(set(extracted_fids), {1, 2}) # Bug ?
def testGeographyAddFeature(self):
"""Test issue GH #54572 Error saving edit on PostGIS geometry when table also contains geography"""
+ self.execSQLCommand('DROP TABLE IF EXISTS qgis_test."geom_and_geog" CASCADE')
self.execSQLCommand(
- 'DROP TABLE IF EXISTS qgis_test."geom_and_geog" CASCADE')
- self.execSQLCommand("""
+ """
CREATE TABLE qgis_test.geom_and_geog (
pkey SERIAL PRIMARY KEY,
geom geometry(POLYGON, 3857),
geog geography(POLYGON, 4326)
- );""")
+ );"""
+ )
- vl = QgsVectorLayer(self.dbconn + ' sslmode=disable key=\'pkey\' srid=3857 table="qgis_test"."geom_and_geog" (geom) sql=', 'geom_and_geog', 'postgres')
+ vl = QgsVectorLayer(
+ self.dbconn
+ + ' sslmode=disable key=\'pkey\' srid=3857 table="qgis_test"."geom_and_geog" (geom) sql=',
+ "geom_and_geog",
+ "postgres",
+ )
self.assertTrue(vl.isValid())
self.assertEqual(vl.featureCount(), 0)
dp = vl.dataProvider()
f = QgsFeature(vl.fields())
- f.setGeometry(QgsGeometry.fromWkt('POLYGON((28.030080546000004 -26.2055410477482,28.030103891999996 -26.20540054874821,28.030532775999998 -26.205458576748192,28.030553322999996 -26.2056050407482,28.030080546000004 -26.2055410477482))'))
- f.setAttribute('geog', 'POLYGON((28.030080546000004 -26.2055410477482,28.030103891999996 -26.20540054874821,28.030532775999998 -26.205458576748192,28.030553322999996 -26.2056050407482,28.030080546000004 -26.2055410477482))')
+ f.setGeometry(
+ QgsGeometry.fromWkt(
+ "POLYGON((28.030080546000004 -26.2055410477482,28.030103891999996 -26.20540054874821,28.030532775999998 -26.205458576748192,28.030553322999996 -26.2056050407482,28.030080546000004 -26.2055410477482))"
+ )
+ )
+ f.setAttribute(
+ "geog",
+ "POLYGON((28.030080546000004 -26.2055410477482,28.030103891999996 -26.20540054874821,28.030532775999998 -26.205458576748192,28.030553322999996 -26.2056050407482,28.030080546000004 -26.2055410477482))",
+ )
self.assertTrue(dp.addFeature(f))
self.assertEqual(vl.featureCount(), 1)
@@ -3327,67 +4287,76 @@ def testExtent(self):
md = QgsProviderRegistry.instance().providerMetadata("postgres")
conn = md.createConnection(self.dbconn, {})
- conn.executeSql('''
+ conn.executeSql(
+ """
DROP TABLE IF EXISTS public.test_ext;
CREATE TABLE public.test_ext (id SERIAL PRIMARY KEY, g geometry);
INSERT INTO public.test_ext(g)
SELECT ST_MakePoint(n,n*7)
FROM generate_series(2,10,1) n;
- ''')
+ """
+ )
realExtent = QgsRectangle(2, 14, 10, 70)
uri = QgsDataSourceUri(self.dbconn + ' table="public"."test_ext" (g)')
# Create layer with computed (not estimated) metadata
- vlReal = QgsVectorLayer(uri.uri(), 'test', 'postgres')
+ vlReal = QgsVectorLayer(uri.uri(), "test", "postgres")
self.assertTrue(vlReal.isValid())
self.assertEqual(vlReal.extent(), realExtent)
# Create layer with estimated metadata
- vlEstm = QgsVectorLayer(uri.uri() + " estimatedmetadata='true'", 'estimated', 'postgres')
+ vlEstm = QgsVectorLayer(
+ uri.uri() + " estimatedmetadata='true'", "estimated", "postgres"
+ )
self.assertTrue(vlEstm.isValid())
# No stats
- self.assertAcceptableEstimatedExtent(realExtent, vlEstm.extent(), 'with no stats')
+ self.assertAcceptableEstimatedExtent(
+ realExtent, vlEstm.extent(), "with no stats"
+ )
# Add stats
- conn.executeSql('ANALYZE public.test_ext')
+ conn.executeSql("ANALYZE public.test_ext")
vlEstm.updateExtents()
- self.assertAcceptableEstimatedExtent(realExtent, vlEstm.extent(), 'with stats')
+ self.assertAcceptableEstimatedExtent(realExtent, vlEstm.extent(), "with stats")
# Add index
- conn.executeSql('CREATE INDEX ON public.test_ext using gist (g)')
+ conn.executeSql("CREATE INDEX ON public.test_ext using gist (g)")
vlEstm.updateExtents()
- self.assertAcceptableEstimatedExtent(realExtent, vlEstm.extent(), 'with index')
+ self.assertAcceptableEstimatedExtent(realExtent, vlEstm.extent(), "with index")
# Cleanup
- conn.executeSql('DROP TABLE IF EXISTS public.test_ext')
+ conn.executeSql("DROP TABLE IF EXISTS public.test_ext")
def testExtent3D(self):
def test_table(dbconn, table_name, wkt):
- vl = QgsVectorLayer(f'{dbconn} srid=4326 table="qgis_test".{table_name} (geom) sql=', "testgeom",
- "postgres")
+ vl = QgsVectorLayer(
+ f'{dbconn} srid=4326 table="qgis_test".{table_name} (geom) sql=',
+ "testgeom",
+ "postgres",
+ )
self.assertTrue(vl.isValid())
- self.assertEqual(str(vl.extent3D()), '')
-
- test_table(self.dbconn, 'p2d', [0, 0, float('nan'), 1, 1, float('nan')])
- test_table(self.dbconn, 'p3d', [0, 0, 0, 1, 1, 0])
- test_table(self.dbconn, 'triangle2d', [0, 0, float('nan'), 1, 1, float('nan')])
- test_table(self.dbconn, 'triangle3d', [0, 0, 0, 1, 1, 0])
- test_table(self.dbconn, 'tin2d', [0, 0, float('nan'), 1, 1, float('nan')])
- test_table(self.dbconn, 'tin3d', [0, 0, 0, 1, 1, 0])
- test_table(self.dbconn, 'ps2d', [0, 0, float('nan'), 1, 1, float('nan')])
- test_table(self.dbconn, 'ps3d', [0, 0, 0, 1, 1, 1])
- test_table(self.dbconn, 'mp3d', [0, 0, 0, 1, 1, 1])
- test_table(self.dbconn, 'pt2d', [0, 0, float('nan'), 0, 0, float('nan')])
- test_table(self.dbconn, 'pt3d', [0, 0, 0, 0, 0, 0])
- test_table(self.dbconn, 'ls2d', [0, 0, float('nan'), 1, 1, float('nan')])
- test_table(self.dbconn, 'ls3d', [0, 0, 0, 1, 1, 1])
- test_table(self.dbconn, 'mpt2d', [0, 0, float('nan'), 1, 1, float('nan')])
- test_table(self.dbconn, 'mpt3d', [0, 0, 0, 1, 1, 1])
- test_table(self.dbconn, 'mls2d', [0, 0, float('nan'), 3, 3, float('nan')])
- test_table(self.dbconn, 'mls3d', [0, 0, 0, 3, 3, 3])
- test_table(self.dbconn, 'pt4d', [1, 2, 3, 1, 2, 3])
+ self.assertEqual(str(vl.extent3D()), "")
+
+ test_table(self.dbconn, "p2d", [0, 0, float("nan"), 1, 1, float("nan")])
+ test_table(self.dbconn, "p3d", [0, 0, 0, 1, 1, 0])
+ test_table(self.dbconn, "triangle2d", [0, 0, float("nan"), 1, 1, float("nan")])
+ test_table(self.dbconn, "triangle3d", [0, 0, 0, 1, 1, 0])
+ test_table(self.dbconn, "tin2d", [0, 0, float("nan"), 1, 1, float("nan")])
+ test_table(self.dbconn, "tin3d", [0, 0, 0, 1, 1, 0])
+ test_table(self.dbconn, "ps2d", [0, 0, float("nan"), 1, 1, float("nan")])
+ test_table(self.dbconn, "ps3d", [0, 0, 0, 1, 1, 1])
+ test_table(self.dbconn, "mp3d", [0, 0, 0, 1, 1, 1])
+ test_table(self.dbconn, "pt2d", [0, 0, float("nan"), 0, 0, float("nan")])
+ test_table(self.dbconn, "pt3d", [0, 0, 0, 0, 0, 0])
+ test_table(self.dbconn, "ls2d", [0, 0, float("nan"), 1, 1, float("nan")])
+ test_table(self.dbconn, "ls3d", [0, 0, 0, 1, 1, 1])
+ test_table(self.dbconn, "mpt2d", [0, 0, float("nan"), 1, 1, float("nan")])
+ test_table(self.dbconn, "mpt3d", [0, 0, 0, 1, 1, 1])
+ test_table(self.dbconn, "mls2d", [0, 0, float("nan"), 3, 3, float("nan")])
+ test_table(self.dbconn, "mls3d", [0, 0, 0, 3, 3, 3])
+ test_table(self.dbconn, "pt4d", [1, 2, 3, 1, 2, 3])
# See https://github.com/qgis/QGIS/issues/30294
def testGeographyExtent(self):
@@ -3395,41 +4364,49 @@ def testGeographyExtent(self):
conn = md.createConnection(self.dbconn, {})
# Create a 10 rows table with extent -10 -10 to 10 10
- conn.executeSql('''
+ conn.executeSql(
+ """
DROP TABLE IF EXISTS public.test_geog_ext;
CREATE TABLE public.test_geog_ext (id SERIAL PRIMARY KEY, g geography);
INSERT INTO public.test_geog_ext(g)
SELECT ST_MakePoint(n*4,n)
FROM generate_series(-10,10,1) n;
- ''')
+ """
+ )
realExtent = QgsRectangle(-40, -10, 40, 10)
uri = QgsDataSourceUri(self.dbconn + ' table="public"."test_geog_ext" (g)')
# Create layer with computed (not estimated) metadata
- vlReal = QgsVectorLayer(uri.uri(), 'real', 'postgres')
- self.assertTrue(vlReal.isValid(), "Could not create test layer from qgis_test.test_geog_ext")
+ vlReal = QgsVectorLayer(uri.uri(), "real", "postgres")
+ self.assertTrue(
+ vlReal.isValid(), "Could not create test layer from qgis_test.test_geog_ext"
+ )
self.assertEqual(vlReal.extent(), realExtent)
# Create layer with estimated metadata
- vlEstm = QgsVectorLayer(uri.uri() + " estimatedmetadata='true'", 'estimated', 'postgres')
+ vlEstm = QgsVectorLayer(
+ uri.uri() + " estimatedmetadata='true'", "estimated", "postgres"
+ )
self.assertTrue(vlEstm.isValid())
# No stats
- self.assertAcceptableEstimatedExtent(realExtent, vlEstm.extent(), 'with no stats')
+ self.assertAcceptableEstimatedExtent(
+ realExtent, vlEstm.extent(), "with no stats"
+ )
# Add stats
- conn.executeSql('ANALYZE public.test_geog_ext')
+ conn.executeSql("ANALYZE public.test_geog_ext")
vlEstm.updateExtents()
- self.assertAcceptableEstimatedExtent(realExtent, vlEstm.extent(), 'with stats')
+ self.assertAcceptableEstimatedExtent(realExtent, vlEstm.extent(), "with stats")
# Add index
- conn.executeSql('CREATE INDEX ON public.test_geog_ext using gist (g)')
+ conn.executeSql("CREATE INDEX ON public.test_geog_ext using gist (g)")
vlEstm.updateExtents()
- self.assertAcceptableEstimatedExtent(realExtent, vlEstm.extent(), 'with index')
+ self.assertAcceptableEstimatedExtent(realExtent, vlEstm.extent(), "with index")
# Cleanup
- conn.executeSql('DROP TABLE public.test_geog_ext')
+ conn.executeSql("DROP TABLE public.test_geog_ext")
# See: https://github.com/qgis/QGIS/issues/55856
def testPktLowerCase(self):
@@ -3444,11 +4421,23 @@ def testPktLowerCase(self):
self.assertTrue(layer.isValid())
# export the vector layer to postgresql with lowercase field names
- self.execSQLCommand('DROP TABLE IF EXISTS qgis_test.pk_lowercase')
- output_uri = f'{self.dbconn} table="qgis_test"."pk_lowercase" key=\'{pk_key.lower()}\''
- err = QgsVectorLayerExporter.exportLayer(layer, output_uri, "postgres", layer.crs(), False, {'lowercaseFieldNames': True})
- self.assertEqual(err[0], QgsVectorLayerExporter.ExportError.NoError,
- f'unexpected import error {err}')
+ self.execSQLCommand("DROP TABLE IF EXISTS qgis_test.pk_lowercase")
+ output_uri = (
+ f'{self.dbconn} table="qgis_test"."pk_lowercase" key=\'{pk_key.lower()}\''
+ )
+ err = QgsVectorLayerExporter.exportLayer(
+ layer,
+ output_uri,
+ "postgres",
+ layer.crs(),
+ False,
+ {"lowercaseFieldNames": True},
+ )
+ self.assertEqual(
+ err[0],
+ QgsVectorLayerExporter.ExportError.NoError,
+ f"unexpected import error {err}",
+ )
# retrieve the columns and type and check them
cur = self.con.cursor()
@@ -3458,9 +4447,10 @@ def testPktLowerCase(self):
)
cur.execute(sql_cols)
expected_cols = [
- ('dep', 'character varying'),
- ('reg', 'character varying'),
- ('number', 'integer')]
+ ("dep", "character varying"),
+ ("reg", "character varying"),
+ ("number", "integer"),
+ ]
self.assertEqual(cur.fetchall(), expected_cols)
# Retrieve the primary key and check its name and type
@@ -3473,11 +4463,16 @@ def testPktLowerCase(self):
"AND i.indisprimary;"
)
cur.execute(sql_pk)
- self.assertEqual(cur.fetchall(), [('dep', 'character varying')])
+ self.assertEqual(cur.fetchall(), [("dep", "character varying")])
def testNameType(self):
- vl = QgsVectorLayer(self.dbconn + ' sslmode=disable key=\'"table_catalog","table_schema","table_name"\' table="information_schema"."tables" () sql=', 'test', 'postgres')
+ vl = QgsVectorLayer(
+ self.dbconn
+ + ' sslmode=disable key=\'"table_catalog","table_schema","table_name"\' table="information_schema"."tables" () sql=',
+ "test",
+ "postgres",
+ )
self.assertTrue(vl.isValid())
feat = next(vl.getFeatures())
@@ -3486,51 +4481,75 @@ def testNameType(self):
def testColumnRestrictedLayerIsEditable(self):
"""
- Test editability of table with partial column insert privs
- See https://github.com/qgis/QGIS/issues/28835
+ Test editability of table with partial column insert privs
+ See https://github.com/qgis/QGIS/issues/28835
"""
md = QgsProviderRegistry.instance().providerMetadata("postgres")
conn = md.createConnection(self.dbconn, {})
- conn.executeSql('''
+ conn.executeSql(
+ """
DROP TABLE IF EXISTS public.qgis_issue_gh_28835;
CREATE UNLOGGED TABLE public.qgis_issue_gh_28835 (
id INT PRIMARY KEY,
restricted_column TEXT,
geom GEOMETRY(point, 4326)
)
- ''')
+ """
+ )
- uri = QgsDataSourceUri(self.dbconn + ' table="public"."qgis_issue_gh_28835" (geom)')
- uri.setUsername('qgis_test_unprivileged_user')
- uri.setPassword('qgis_test_unprivileged_user_password')
+ uri = QgsDataSourceUri(
+ self.dbconn + ' table="public"."qgis_issue_gh_28835" (geom)'
+ )
+ uri.setUsername("qgis_test_unprivileged_user")
+ uri.setPassword("qgis_test_unprivileged_user_password")
- conn.executeSql('GRANT SELECT ON public.qgis_issue_gh_28835 TO qgis_test_unprivileged_user')
- vl = QgsVectorLayer(uri.uri(), 'test', 'postgres')
+ conn.executeSql(
+ "GRANT SELECT ON public.qgis_issue_gh_28835 TO qgis_test_unprivileged_user"
+ )
+ vl = QgsVectorLayer(uri.uri(), "test", "postgres")
self.assertTrue(vl.isValid(), "qgis_issue_gh_28835 is an invalid layer")
- self.assertFalse(vl.startEditing(), "qgis_issue_gh_28835 is unexpectedly editable by qgis_test_unprivileged_user before grants")
+ self.assertFalse(
+ vl.startEditing(),
+ "qgis_issue_gh_28835 is unexpectedly editable by qgis_test_unprivileged_user before grants",
+ )
- conn.executeSql('GRANT INSERT(geom) ON public.qgis_issue_gh_28835 TO qgis_test_unprivileged_user')
- vl = QgsVectorLayer(uri.uri(), 'test', 'postgres')
+ conn.executeSql(
+ "GRANT INSERT(geom) ON public.qgis_issue_gh_28835 TO qgis_test_unprivileged_user"
+ )
+ vl = QgsVectorLayer(uri.uri(), "test", "postgres")
self.assertTrue(vl.isValid(), "qgis_issue_gh_28835 is an invalid layer")
- self.assertTrue(vl.startEditing(), "qgis_issue_gh_28835 is not editable by qgis_test_unprivileged_user after restricted-column insert grant")
+ self.assertTrue(
+ vl.startEditing(),
+ "qgis_issue_gh_28835 is not editable by qgis_test_unprivileged_user after restricted-column insert grant",
+ )
def testBitAndBitVarying(self):
"""Test issue GH #59129"""
self.execSQLCommand(
- 'ALTER TABLE IF EXISTS qgis_test."bit_and_bit_varying" DROP CONSTRAINT IF EXISTS pk_bit_and_bit_varying;')
+ 'ALTER TABLE IF EXISTS qgis_test."bit_and_bit_varying" DROP CONSTRAINT IF EXISTS pk_bit_and_bit_varying;'
+ )
self.execSQLCommand(
- 'DROP TABLE IF EXISTS qgis_test."bit_and_bit_varying" CASCADE;')
+ 'DROP TABLE IF EXISTS qgis_test."bit_and_bit_varying" CASCADE;'
+ )
self.execSQLCommand(
- 'CREATE TABLE qgis_test."bit_and_bit_varying" ( "T_Id" integer NOT NULL, a BIT(3), b BIT VARYING(5) );')
+ 'CREATE TABLE qgis_test."bit_and_bit_varying" ( "T_Id" integer NOT NULL, a BIT(3), b BIT VARYING(5) );'
+ )
self.execSQLCommand(
- """INSERT INTO qgis_test."bit_and_bit_varying" VALUES (1, B'101', B'00');""")
+ """INSERT INTO qgis_test."bit_and_bit_varying" VALUES (1, B'101', B'00');"""
+ )
self.execSQLCommand(
- 'ALTER TABLE qgis_test."bit_and_bit_varying" ADD CONSTRAINT pk_gh_bit_and_bit_varying PRIMARY KEY ("T_Id");')
+ 'ALTER TABLE qgis_test."bit_and_bit_varying" ADD CONSTRAINT pk_gh_bit_and_bit_varying PRIMARY KEY ("T_Id");'
+ )
- vl = QgsVectorLayer(self.dbconn + ' sslmode=disable key=\'id\' table="qgis_test"."bit_and_bit_varying" () sql=', 'bit_and_bit_varying', 'postgres')
+ vl = QgsVectorLayer(
+ self.dbconn
+ + ' sslmode=disable key=\'id\' table="qgis_test"."bit_and_bit_varying" () sql=',
+ "bit_and_bit_varying",
+ "postgres",
+ )
self.assertTrue(vl.isValid())
feat = next(vl.getFeatures())
@@ -3544,29 +4563,33 @@ class TestPyQgsPostgresProviderCompoundKey(QgisTestCase, ProviderTestCase):
@classmethod
def setUpClass(cls):
"""Run before all tests"""
- super(TestPyQgsPostgresProviderCompoundKey, cls).setUpClass()
- cls.dbconn = 'service=qgis_test'
- if 'QGIS_PGTEST_DB' in os.environ:
- cls.dbconn = os.environ['QGIS_PGTEST_DB']
+ super().setUpClass()
+ cls.dbconn = "service=qgis_test"
+ if "QGIS_PGTEST_DB" in os.environ:
+ cls.dbconn = os.environ["QGIS_PGTEST_DB"]
# Create test layers
cls.vl = QgsVectorLayer(
- cls.dbconn +
- ' sslmode=disable key=\'"key1","key2"\' srid=4326 type=POINT table="qgis_test"."someDataCompound" (geom) sql=',
- 'test', 'postgres')
+ cls.dbconn
+ + ' sslmode=disable key=\'"key1","key2"\' srid=4326 type=POINT table="qgis_test"."someDataCompound" (geom) sql=',
+ "test",
+ "postgres",
+ )
assert cls.vl.isValid()
cls.source = cls.vl.dataProvider()
def enableCompiler(self):
- QgsSettings().setValue('/qgis/compileExpressions', True)
+ QgsSettings().setValue("/qgis/compileExpressions", True)
return True
def disableCompiler(self):
- QgsSettings().setValue('/qgis/compileExpressions', False)
+ QgsSettings().setValue("/qgis/compileExpressions", False)
def uncompiledFilters(self):
- return {'"dt" = to_datetime(\'000www14ww13ww12www4ww5ww2020\',\'zzzwwwsswwmmwwhhwwwdwwMwwyyyy\')',
- '"date" = to_date(\'www4ww5ww2020\',\'wwwdwwMwwyyyy\')',
- '"time" = to_time(\'000www14ww13ww12www\',\'zzzwwwsswwmmwwhhwww\')'}
+ return {
+ "\"dt\" = to_datetime('000www14ww13ww12www4ww5ww2020','zzzwwwsswwmmwwhhwwwdwwMwwyyyy')",
+ "\"date\" = to_date('www4ww5ww2020','wwwdwwMwwyyyy')",
+ "\"time\" = to_time('000www14ww13ww12www','zzzwwwsswwmmwwhhwww')",
+ }
def partiallyCompiledFilters(self):
return set()
@@ -3575,68 +4598,98 @@ def testConstraints(self):
for key in ["key1", "key2"]:
idx = self.vl.dataProvider().fieldNameIndex(key)
self.assertGreaterEqual(idx, 0)
- self.assertFalse(self.vl.dataProvider().fieldConstraints(
- idx) & QgsFieldConstraints.Constraint.ConstraintUnique)
+ self.assertFalse(
+ self.vl.dataProvider().fieldConstraints(idx)
+ & QgsFieldConstraints.Constraint.ConstraintUnique
+ )
def testCompoundPkChanges(self):
- """ Check if fields with compound primary keys can be changed """
+ """Check if fields with compound primary keys can be changed"""
vl = self.vl
self.assertTrue(vl.isValid())
- idx_key1 = vl.fields().lookupField('key1')
- idx_key2 = vl.fields().lookupField('key2')
+ idx_key1 = vl.fields().lookupField("key1")
+ idx_key2 = vl.fields().lookupField("key2")
# the name "pk" for this datasource is misleading;
# the primary key is actually composed by the fields key1 and key2
- idx_pk = vl.fields().lookupField('pk')
- idx_name = vl.fields().lookupField('name')
- idx_name2 = vl.fields().lookupField('name2')
+ idx_pk = vl.fields().lookupField("pk")
+ idx_name = vl.fields().lookupField("name")
+ idx_name2 = vl.fields().lookupField("name2")
- geomwkt = 'Point(-47.945 -15.812)'
+ geomwkt = "Point(-47.945 -15.812)"
# start editing ordinary attribute.
- ft1 = next(vl.getFeatures(QgsFeatureRequest().setFilterExpression("key1 = 2 AND key2 = 2")))
+ ft1 = next(
+ vl.getFeatures(
+ QgsFeatureRequest().setFilterExpression("key1 = 2 AND key2 = 2")
+ )
+ )
self.assertTrue(ft1.isValid())
original_geometry = ft1.geometry().asWkt()
vl.startEditing()
- self.assertTrue(vl.changeAttributeValues(ft1.id(), {idx_name: 'Rose'}))
+ self.assertTrue(vl.changeAttributeValues(ft1.id(), {idx_name: "Rose"}))
self.assertTrue(vl.commitChanges())
# check change
- ft2 = next(vl.getFeatures(QgsFeatureRequest().setFilterExpression("key1 = 2 AND key2 = 2")))
- self.assertEqual(ft2['name'], 'Rose')
- self.assertEqual(ft2['name2'], 'Apple')
- self.assertEqual(ft2['pk'], 2)
+ ft2 = next(
+ vl.getFeatures(
+ QgsFeatureRequest().setFilterExpression("key1 = 2 AND key2 = 2")
+ )
+ )
+ self.assertEqual(ft2["name"], "Rose")
+ self.assertEqual(ft2["name2"], "Apple")
+ self.assertEqual(ft2["pk"], 2)
# now, start editing one of the PK field components
vl.startEditing()
- self.assertTrue(vl.dataProvider().changeFeatures({ft2.id(): {idx_key2: 42, idx_name: 'Orchid', idx_name2: 'Daisy'}}, {ft2.id(): QgsGeometry.fromWkt(geomwkt)}))
+ self.assertTrue(
+ vl.dataProvider().changeFeatures(
+ {ft2.id(): {idx_key2: 42, idx_name: "Orchid", idx_name2: "Daisy"}},
+ {ft2.id(): QgsGeometry.fromWkt(geomwkt)},
+ )
+ )
self.assertTrue(vl.commitChanges())
# let's check if we still have the same fid...
ft2 = next(vl.getFeatures(QgsFeatureRequest().setFilterFid(ft2.id())))
- self.assertEqual(ft2['key2'], 42)
- self.assertEqual(ft2['name'], 'Orchid')
- self.assertEqual(ft2['name2'], 'Daisy')
+ self.assertEqual(ft2["key2"], 42)
+ self.assertEqual(ft2["name"], "Orchid")
+ self.assertEqual(ft2["name2"], "Daisy")
self.assertTrue(vl.startEditing())
- vl.changeAttributeValues(ft2.id(), {idx_key1: 21, idx_name2: 'Hibiscus'})
+ vl.changeAttributeValues(ft2.id(), {idx_key1: 21, idx_name2: "Hibiscus"})
self.assertTrue(vl.commitChanges())
ft2 = next(vl.getFeatures(QgsFeatureRequest().setFilterFid(ft2.id())))
- self.assertEqual(ft2['key1'], 21)
- self.assertEqual(ft2['name2'], 'Hibiscus')
+ self.assertEqual(ft2["key1"], 21)
+ self.assertEqual(ft2["name2"], "Hibiscus")
# lets get a brand new feature and check how it went...
- ft3 = next(vl.getFeatures(QgsFeatureRequest().setFilterExpression('pk = 2')))
- self.assertEqual(ft3['name'], 'Orchid')
- self.assertEqual(ft3['key1'], 21)
- self.assertEqual(ft3['key2'], 42)
+ ft3 = next(vl.getFeatures(QgsFeatureRequest().setFilterExpression("pk = 2")))
+ self.assertEqual(ft3["name"], "Orchid")
+ self.assertEqual(ft3["key1"], 21)
+ self.assertEqual(ft3["key2"], 42)
- assert compareWkt(ft3.geometry().asWkt(), geomwkt), f"Geometry mismatch. Expected: {ft3.geometry().asWkt()} Got: {geomwkt}\n"
+ assert compareWkt(
+ ft3.geometry().asWkt(), geomwkt
+ ), f"Geometry mismatch. Expected: {ft3.geometry().asWkt()} Got: {geomwkt}\n"
# Now, we leave the record as we found it, so further tests can proceed
vl.startEditing()
- self.assertTrue(vl.dataProvider().changeFeatures({ft3.id(): {idx_key1: 2, idx_key2: 2, idx_pk: 2, idx_name: 'Apple', idx_name2: 'Apple'}}, {ft3.id(): QgsGeometry.fromWkt(original_geometry)}))
+ self.assertTrue(
+ vl.dataProvider().changeFeatures(
+ {
+ ft3.id(): {
+ idx_key1: 2,
+ idx_key2: 2,
+ idx_pk: 2,
+ idx_name: "Apple",
+ idx_name2: "Apple",
+ }
+ },
+ {ft3.id(): QgsGeometry.fromWkt(original_geometry)},
+ )
+ )
self.assertTrue(vl.commitChanges())
@@ -3645,36 +4698,43 @@ class TestPyQgsPostgresProviderBigintSinglePk(QgisTestCase, ProviderTestCase):
@classmethod
def setUpClass(cls):
"""Run before all tests"""
- super(TestPyQgsPostgresProviderBigintSinglePk, cls).setUpClass()
- cls.dbconn = 'service=qgis_test'
- if 'QGIS_PGTEST_DB' in os.environ:
- cls.dbconn = os.environ['QGIS_PGTEST_DB']
+ super().setUpClass()
+ cls.dbconn = "service=qgis_test"
+ if "QGIS_PGTEST_DB" in os.environ:
+ cls.dbconn = os.environ["QGIS_PGTEST_DB"]
# Create test layers
cls.vl = QgsVectorLayer(
- cls.dbconn +
- ' sslmode=disable key=\'"pk"\' srid=4326 type=POINT table="qgis_test"."provider_bigint_single_pk" (geom) sql=',
- 'bigint_pk', 'postgres')
+ cls.dbconn
+ + ' sslmode=disable key=\'"pk"\' srid=4326 type=POINT table="qgis_test"."provider_bigint_single_pk" (geom) sql=',
+ "bigint_pk",
+ "postgres",
+ )
assert cls.vl.isValid()
cls.source = cls.vl.dataProvider()
cls.con = psycopg2.connect(cls.dbconn)
def getSource(self):
- """ drops/recreates the test data anew, like TestPyQgsPostgresProvider::getSource above. """
+ """drops/recreates the test data anew, like TestPyQgsPostgresProvider::getSource above."""
self.execSqlCommand(
- "DROP TABLE IF EXISTS qgis_test.provider_edit_bigint_single_pk")
+ "DROP TABLE IF EXISTS qgis_test.provider_edit_bigint_single_pk"
+ )
self.execSqlCommand(
- "CREATE TABLE qgis_test.provider_edit_bigint_single_pk ( pk bigserial PRIMARY KEY, cnt integer, name text DEFAULT 'qgis', name2 text DEFAULT 'qgis', num_char text, dt timestamp without time zone, \"date\" date, \"time\" time without time zone, geom public.geometry(Point,4326), key1 integer, key2 integer)")
+ "CREATE TABLE qgis_test.provider_edit_bigint_single_pk ( pk bigserial PRIMARY KEY, cnt integer, name text DEFAULT 'qgis', name2 text DEFAULT 'qgis', num_char text, dt timestamp without time zone, \"date\" date, \"time\" time without time zone, geom public.geometry(Point,4326), key1 integer, key2 integer)"
+ )
self.execSqlCommand(
- "INSERT INTO qgis_test.provider_edit_bigint_single_pk ( key1, key2, pk, cnt, name, name2, num_char, dt, \"date\", \"time\", geom) VALUES"
+ 'INSERT INTO qgis_test.provider_edit_bigint_single_pk ( key1, key2, pk, cnt, name, name2, num_char, dt, "date", "time", geom) VALUES'
"(1, 1, 5, -200, NULL, 'NuLl', '5', TIMESTAMP '2020-05-04 12:13:14', '2020-05-02', '12:13:01', '0101000020E61000001D5A643BDFC751C01F85EB51B88E5340'),"
"(1, 2, 3, 300, 'Pear', 'PEaR', '3', NULL, NULL, NULL, NULL),"
"(2, 1, 1, 100, 'Orange', 'oranGe', '1', TIMESTAMP '2020-05-03 12:13:14', '2020-05-03', '12:13:14', '0101000020E61000006891ED7C3F9551C085EB51B81E955040'),"
"(2, 2, 2, 200, 'Apple', 'Apple', '2', TIMESTAMP '2020-05-04 12:14:14', '2020-05-04', '12:14:14', '0101000020E6100000CDCCCCCCCC0C51C03333333333B35140'),"
- "(2, 3, 4, 400, 'Honey', 'Honey', '4', TIMESTAMP '2021-05-04 13:13:14', '2021-05-04', '13:13:14', '0101000020E610000014AE47E17A5450C03333333333935340')")
+ "(2, 3, 4, 400, 'Honey', 'Honey', '4', TIMESTAMP '2021-05-04 13:13:14', '2021-05-04', '13:13:14', '0101000020E610000014AE47E17A5450C03333333333935340')"
+ )
vl = QgsVectorLayer(
- self.dbconn +
- ' sslmode=disable key=\'"pk"\' srid=4326 type=POINT table="qgis_test"."provider_edit_bigint_single_pk" (geom) sql=',
- 'edit_bigint_pk', 'postgres')
+ self.dbconn
+ + ' sslmode=disable key=\'"pk"\' srid=4326 type=POINT table="qgis_test"."provider_edit_bigint_single_pk" (geom) sql=',
+ "edit_bigint_pk",
+ "postgres",
+ )
return vl
def getEditableLayer(self):
@@ -3689,16 +4749,18 @@ def execSqlCommand(self, sql):
self.con.commit()
def enableCompiler(self):
- QgsSettings().setValue('/qgis/compileExpressions', True)
+ QgsSettings().setValue("/qgis/compileExpressions", True)
return True
def disableCompiler(self):
- QgsSettings().setValue('/qgis/compileExpressions', False)
+ QgsSettings().setValue("/qgis/compileExpressions", False)
def uncompiledFilters(self):
- return {'"dt" = to_datetime(\'000www14ww13ww12www4ww5ww2020\',\'zzzwwwsswwmmwwhhwwwdwwMwwyyyy\')',
- '"date" = to_date(\'www4ww5ww2020\',\'wwwdwwMwwyyyy\')',
- '"time" = to_time(\'000www14ww13ww12www\',\'zzzwwwsswwmmwwhhwww\')'}
+ return {
+ "\"dt\" = to_datetime('000www14ww13ww12www4ww5ww2020','zzzwwwsswwmmwwhhwwwdwwMwwyyyy')",
+ "\"date\" = to_date('www4ww5ww2020','wwwdwwMwwyyyy')",
+ "\"time\" = to_time('000www14ww13ww12www','zzzwwwsswwmmwwhhwww')",
+ }
def partiallyCompiledFilters(self):
return set()
@@ -3709,18 +4771,22 @@ def testConstraints(self):
def testGetFeaturesFidTests(self):
fids = [f.id() for f in self.source.getFeatures()]
- assert len(fids) == 5, f'Expected 5 features, got {len(fids)} instead'
+ assert len(fids) == 5, f"Expected 5 features, got {len(fids)} instead"
for id in fids:
- features = [f for f in self.source.getFeatures(
- QgsFeatureRequest().setFilterFid(id))]
+ features = [
+ f for f in self.source.getFeatures(QgsFeatureRequest().setFilterFid(id))
+ ]
self.assertEqual(len(features), 1)
feature = features[0]
self.assertTrue(feature.isValid())
result = [feature.id()]
expected = [id]
- assert result == expected, 'Expected {} and got {} when testing for feature ID filter'.format(expected,
- result)
+ assert (
+ result == expected
+ ), "Expected {} and got {} when testing for feature ID filter".format(
+ expected, result
+ )
# test that results match QgsFeatureRequest.acceptFeature
request = QgsFeatureRequest().setFilterFid(id)
@@ -3730,9 +4796,15 @@ def testGetFeaturesFidTests(self):
# TODO: bad features are not tested because the PostgreSQL provider
# doesn't mark explicitly set invalid features as such.
- def testGetFeatures(self, source=None, extra_features=[], skip_features=[], changed_attributes={},
- changed_geometries={}):
- """ Test that expected results are returned when fetching all features """
+ def testGetFeatures(
+ self,
+ source=None,
+ extra_features=[],
+ skip_features=[],
+ changed_attributes={},
+ changed_geometries={},
+ ):
+ """Test that expected results are returned when fetching all features"""
# IMPORTANT - we do not use `for f in source.getFeatures()` as we are also
# testing that existing attributes & geometry in f are overwritten correctly
@@ -3750,26 +4822,30 @@ def testGetFeatures(self, source=None, extra_features=[], skip_features=[], chan
self.assertTrue(f.isValid())
# some source test datasets will include additional attributes which we ignore,
# so cherry pick desired attributes
- attrs = [f['pk'], f['cnt'], f['name'], f['name2'], f['num_char']]
+ attrs = [f["pk"], f["cnt"], f["name"], f["name2"], f["num_char"]]
# DON'T force the num_char attribute to be text - some sources (e.g., delimited text) will
# automatically detect that this attribute contains numbers and set it as a numeric
# field
# TODO: PostgreSQL 12 won't accept conversion from integer to text.
# attrs[4] = str(attrs[4])
- attributes[f['pk']] = attrs
- geometries[f['pk']] = f.hasGeometry() and f.geometry().asWkt()
-
- expected_attributes = {5: [5, -200, NULL, 'NuLl', '5'],
- 3: [3, 300, 'Pear', 'PEaR', '3'],
- 1: [1, 100, 'Orange', 'oranGe', '1'],
- 2: [2, 200, 'Apple', 'Apple', '2'],
- 4: [4, 400, 'Honey', 'Honey', '4']}
-
- expected_geometries = {1: 'Point (-70.332 66.33)',
- 2: 'Point (-68.2 70.8)',
- 3: None,
- 4: 'Point(-65.32 78.3)',
- 5: 'Point(-71.123 78.23)'}
+ attributes[f["pk"]] = attrs
+ geometries[f["pk"]] = f.hasGeometry() and f.geometry().asWkt()
+
+ expected_attributes = {
+ 5: [5, -200, NULL, "NuLl", "5"],
+ 3: [3, 300, "Pear", "PEaR", "3"],
+ 1: [1, 100, "Orange", "oranGe", "1"],
+ 2: [2, 200, "Apple", "Apple", "2"],
+ 4: [4, 400, "Honey", "Honey", "4"],
+ }
+
+ expected_geometries = {
+ 1: "Point (-70.332 66.33)",
+ 2: "Point (-68.2 70.8)",
+ 3: None,
+ 4: "Point(-65.32 78.3)",
+ 5: "Point(-71.123 78.23)",
+ }
for f in extra_features:
expected_attributes[f[0]] = f.attributes()
if f.hasGeometry():
@@ -3783,62 +4859,79 @@ def testGetFeatures(self, source=None, extra_features=[], skip_features=[], chan
for i, a in changed_attributes.items():
for attr_idx, v in a.items():
expected_attributes[i][attr_idx] = v
- for i, g, in changed_geometries.items():
+ for (
+ i,
+ g,
+ ) in changed_geometries.items():
if g:
expected_geometries[i] = g.asWkt()
else:
expected_geometries[i] = None
- self.assertEqual(attributes, expected_attributes, 'Expected {}, got {}'.format(
- expected_attributes, attributes))
+ self.assertEqual(
+ attributes,
+ expected_attributes,
+ f"Expected {expected_attributes}, got {attributes}",
+ )
self.assertEqual(len(expected_geometries), len(geometries))
for pk, geom in list(expected_geometries.items()):
if geom:
- assert compareWkt(geom, geometries[pk]), "Geometry {} mismatch Expected:\n{}\nGot:\n{}\n".format(pk,
- geom,
- geometries[
- pk])
+ assert compareWkt(
+ geom, geometries[pk]
+ ), "Geometry {} mismatch Expected:\n{}\nGot:\n{}\n".format(
+ pk, geom, geometries[pk]
+ )
else:
- self.assertFalse(
- geometries[pk], f'Expected null geometry for {pk}')
+ self.assertFalse(geometries[pk], f"Expected null geometry for {pk}")
def testAddFeatureExtraAttributes(self):
- if not getattr(self, 'getEditableLayer', None):
+ if not getattr(self, "getEditableLayer", None):
return
l = self.getEditableLayer()
self.assertTrue(l.isValid())
- if not l.dataProvider().capabilities() & QgsVectorDataProvider.Capability.AddFeatures:
+ if (
+ not l.dataProvider().capabilities()
+ & QgsVectorDataProvider.Capability.AddFeatures
+ ):
return
# test that adding features with too many attributes drops these attributes
# we be more tricky and also add a valid feature to stress test the provider
f1 = QgsFeature()
- f1.setAttributes([6, -220, 'qgis', 'String', '15'])
+ f1.setAttributes([6, -220, "qgis", "String", "15"])
f2 = QgsFeature()
- f2.setAttributes([7, -230, 'qgis', 'String', '15', 15, 16, 17])
+ f2.setAttributes([7, -230, "qgis", "String", "15", 15, 16, 17])
result, added = l.dataProvider().addFeatures([f1, f2])
- self.assertTrue(result,
- 'Provider returned False to addFeatures with extra attributes. Providers should accept these features but truncate the extra attributes.')
+ self.assertTrue(
+ result,
+ "Provider returned False to addFeatures with extra attributes. Providers should accept these features but truncate the extra attributes.",
+ )
# make sure feature was added correctly
- added = [f for f in l.dataProvider().getFeatures() if f['pk'] == 7][0]
+ added = [f for f in l.dataProvider().getFeatures() if f["pk"] == 7][0]
# TODO: The PostgreSQL provider doesn't truncate extra attributes!
- self.assertNotEqual(added.attributes(), [7, -230, 'qgis', 'String', '15'],
- 'The PostgreSQL provider doesn\'t truncate extra attributes.')
+ self.assertNotEqual(
+ added.attributes(),
+ [7, -230, "qgis", "String", "15"],
+ "The PostgreSQL provider doesn't truncate extra attributes.",
+ )
def testAddFeatureMissingAttributes(self):
- if not getattr(self, 'getEditableLayer', None):
+ if not getattr(self, "getEditableLayer", None):
return
l = self.getEditableLayer()
self.assertTrue(l.isValid())
- if not l.dataProvider().capabilities() & QgsVectorDataProvider.Capability.AddFeatures:
+ if (
+ not l.dataProvider().capabilities()
+ & QgsVectorDataProvider.Capability.AddFeatures
+ ):
return
# test that adding features with missing attributes pads out these
@@ -3850,23 +4943,25 @@ def testAddFeatureMissingAttributes(self):
# that is indicated, or the value mentioned by the user; there is no
# implicit conversion of PyQGIS::NULL to PostgreSQL DEFAULT.
f1 = QgsFeature()
- f1.setAttributes([6, -220, 'qgis', 'String'])
+ f1.setAttributes([6, -220, "qgis", "String"])
f2 = QgsFeature()
f2.setAttributes([7, 330])
result, added = l.dataProvider().addFeatures([f1, f2])
- self.assertTrue(result,
- 'Provider returned False to addFeatures with missing attributes. Providers should accept these features but add NULL attributes to the end of the existing attributes to the required field length.')
+ self.assertTrue(
+ result,
+ "Provider returned False to addFeatures with missing attributes. Providers should accept these features but add NULL attributes to the end of the existing attributes to the required field length.",
+ )
f1.setId(added[0].id())
f2.setId(added[1].id())
# check result - feature attributes MUST be padded out to required number of fields
- f1.setAttributes([6, -220, 'qgis', 'String', NULL])
- f2.setAttributes([7, 330, 'qgis', 'qgis', NULL])
+ f1.setAttributes([6, -220, "qgis", "String", NULL])
+ f2.setAttributes([7, 330, "qgis", "qgis", NULL])
self.testGetFeatures(l.dataProvider(), [f1, f2])
def testAddFeature(self):
- if not getattr(self, 'getEditableLayer', None):
+ if not getattr(self, "getEditableLayer", None):
return
l = self.getEditableLayer()
@@ -3879,17 +4974,22 @@ def testAddFeature(self):
# value; if the attribute is present, the saved value will be NULL if
# that is indicated, or the value mentioned by the user; there is no
# implicit conversion of PyQGIS::NULL to PostgreSQL DEFAULT.
- f1.setAttributes([6, -220, 'qgis', 'String', '15'])
- f1.setGeometry(QgsGeometry.fromWkt('Point (-72.345 71.987)'))
+ f1.setAttributes([6, -220, "qgis", "String", "15"])
+ f1.setGeometry(QgsGeometry.fromWkt("Point (-72.345 71.987)"))
f2 = QgsFeature()
- f2.setAttributes([7, 330, 'Coconut', 'CoCoNut', '13'])
+ f2.setAttributes([7, 330, "Coconut", "CoCoNut", "13"])
- if l.dataProvider().capabilities() & QgsVectorDataProvider.Capability.AddFeatures:
+ if (
+ l.dataProvider().capabilities()
+ & QgsVectorDataProvider.Capability.AddFeatures
+ ):
# expect success
result, added = l.dataProvider().addFeatures([f1, f2])
self.assertTrue(
- result, 'Provider reported AddFeatures capability, but returned False to addFeatures')
+ result,
+ "Provider reported AddFeatures capability, but returned False to addFeatures",
+ )
f1.setId(added[0].id())
f2.setId(added[1].id())
@@ -3900,46 +5000,60 @@ def testAddFeature(self):
self.assertTrue(l.dataProvider().addFeatures([]))
# ensure that returned features have been given the correct id
- f = next(l.getFeatures(
- QgsFeatureRequest().setFilterFid(added[0].id())))
+ f = next(l.getFeatures(QgsFeatureRequest().setFilterFid(added[0].id())))
self.assertTrue(f.isValid())
- self.assertEqual(f['cnt'], -220)
+ self.assertEqual(f["cnt"], -220)
- f = next(l.getFeatures(
- QgsFeatureRequest().setFilterFid(added[1].id())))
+ f = next(l.getFeatures(QgsFeatureRequest().setFilterFid(added[1].id())))
self.assertTrue(f.isValid())
- self.assertEqual(f['cnt'], 330)
+ self.assertEqual(f["cnt"], 330)
else:
# expect fail
- self.assertFalse(l.dataProvider().addFeatures([f1, f2]),
- 'Provider reported no AddFeatures capability, but returned true to addFeatures')
+ self.assertFalse(
+ l.dataProvider().addFeatures([f1, f2]),
+ "Provider reported no AddFeatures capability, but returned true to addFeatures",
+ )
def testModifyPk(self):
- """ Check if we can modify a primary key value. Since this PK is bigint, we also exercise the mapping between fid and values """
+ """Check if we can modify a primary key value. Since this PK is bigint, we also exercise the mapping between fid and values"""
vl = self.getEditableLayer()
self.assertTrue(vl.isValid())
- geomwkt = 'Point(-47.945 -15.812)'
+ geomwkt = "Point(-47.945 -15.812)"
- feature = next(vl.getFeatures(QgsFeatureRequest().setFilterExpression('pk = 4')))
+ feature = next(
+ vl.getFeatures(QgsFeatureRequest().setFilterExpression("pk = 4"))
+ )
self.assertTrue(feature.isValid())
self.assertTrue(vl.startEditing())
- idxpk = vl.fields().lookupField('pk')
+ idxpk = vl.fields().lookupField("pk")
- self.assertTrue(vl.dataProvider().changeFeatures({feature.id(): {idxpk: 42}}, {feature.id(): QgsGeometry.fromWkt(geomwkt)}))
+ self.assertTrue(
+ vl.dataProvider().changeFeatures(
+ {feature.id(): {idxpk: 42}},
+ {feature.id(): QgsGeometry.fromWkt(geomwkt)},
+ )
+ )
self.assertTrue(vl.commitChanges())
# read back
- ft = next(vl.getFeatures(QgsFeatureRequest().setFilterExpression('pk = 42')))
+ ft = next(vl.getFeatures(QgsFeatureRequest().setFilterExpression("pk = 42")))
self.assertTrue(ft.isValid())
- self.assertEqual(ft['name'], 'Honey')
- assert compareWkt(ft.geometry().asWkt(), geomwkt), f"Geometry mismatch. Expected: {ft.geometry().asWkt()} Got: {geomwkt}\n"
+ self.assertEqual(ft["name"], "Honey")
+ assert compareWkt(
+ ft.geometry().asWkt(), geomwkt
+ ), f"Geometry mismatch. Expected: {ft.geometry().asWkt()} Got: {geomwkt}\n"
def testDuplicatedFieldNamesInQueryLayers(self):
"""Test regresssion GH #36205"""
- vl = QgsVectorLayer(self.dbconn + ' sslmode=disable key=\'__rid__\' table="(SELECT row_number() OVER () AS __rid__, * FROM (SELECT * from qgis_test.some_poly_data a, qgis_test.some_poly_data b where ST_Intersects(a.geom,b.geom)) as foo)" sql=', 'test_36205', 'postgres')
+ vl = QgsVectorLayer(
+ self.dbconn
+ + " sslmode=disable key='__rid__' table=\"(SELECT row_number() OVER () AS __rid__, * FROM (SELECT * from qgis_test.some_poly_data a, qgis_test.some_poly_data b where ST_Intersects(a.geom,b.geom)) as foo)\" sql=",
+ "test_36205",
+ "postgres",
+ )
self.assertTrue(vl.isValid())
self.assertEqual(vl.featureCount(), 3)
@@ -3957,70 +5071,113 @@ def testUnrestrictedGeometryType(self):
# Cleanup if needed
try:
- conn.dropVectorTable('qgis_test', 'test_unrestricted_geometry')
+ conn.dropVectorTable("qgis_test", "test_unrestricted_geometry")
except QgsProviderConnectionException:
pass
- conn.executeSql('''
+ conn.executeSql(
+ """
CREATE TABLE "qgis_test"."test_unrestricted_geometry" (
gid serial primary key,
geom geometry(Geometry, 4326)
- );''')
+ );"""
+ )
- points = QgsVectorLayer(self.dbconn + ' sslmode=disable key=\'gid\' srid=4326 type=POINT table="qgis_test"."test_unrestricted_geometry" (geom) sql=', 'test_points', 'postgres')
- lines = QgsVectorLayer(self.dbconn + ' sslmode=disable key=\'gid\' srid=4326 type=LINESTRING table="qgis_test"."test_unrestricted_geometry" (geom) sql=', 'test_lines', 'postgres')
- polygons = QgsVectorLayer(self.dbconn + ' sslmode=disable key=\'gid\' srid=4326 type=POLYGON table="qgis_test"."test_unrestricted_geometry" (geom) sql=', 'test_polygons', 'postgres')
+ points = QgsVectorLayer(
+ self.dbconn
+ + ' sslmode=disable key=\'gid\' srid=4326 type=POINT table="qgis_test"."test_unrestricted_geometry" (geom) sql=',
+ "test_points",
+ "postgres",
+ )
+ lines = QgsVectorLayer(
+ self.dbconn
+ + ' sslmode=disable key=\'gid\' srid=4326 type=LINESTRING table="qgis_test"."test_unrestricted_geometry" (geom) sql=',
+ "test_lines",
+ "postgres",
+ )
+ polygons = QgsVectorLayer(
+ self.dbconn
+ + ' sslmode=disable key=\'gid\' srid=4326 type=POLYGON table="qgis_test"."test_unrestricted_geometry" (geom) sql=',
+ "test_polygons",
+ "postgres",
+ )
self.assertTrue(points.isValid())
self.assertTrue(lines.isValid())
self.assertTrue(polygons.isValid())
f = QgsFeature(points.fields())
- f.setGeometry(QgsGeometry.fromWkt('point(9 45)'))
+ f.setGeometry(QgsGeometry.fromWkt("point(9 45)"))
self.assertTrue(points.dataProvider().addFeatures([f]))
self.assertEqual(points.featureCount(), 1)
self.assertEqual(lines.featureCount(), 0)
self.assertEqual(polygons.featureCount(), 0)
# Fetch from iterator
- self.assertTrue(compareWkt(next(points.getFeatures()).geometry().asWkt(), 'point(9 45)'))
+ self.assertTrue(
+ compareWkt(next(points.getFeatures()).geometry().asWkt(), "point(9 45)")
+ )
with self.assertRaises(StopIteration):
next(lines.getFeatures())
with self.assertRaises(StopIteration):
next(polygons.getFeatures())
- f.setGeometry(QgsGeometry.fromWkt('linestring(9 45, 10 46)'))
+ f.setGeometry(QgsGeometry.fromWkt("linestring(9 45, 10 46)"))
self.assertTrue(lines.dataProvider().addFeatures([f]))
self.assertEqual(points.featureCount(), 1)
self.assertEqual(lines.featureCount(), 1)
self.assertEqual(polygons.featureCount(), 0)
# Fetch from iterator
- self.assertTrue(compareWkt(next(points.getFeatures()).geometry().asWkt(), 'point(9 45)'))
- self.assertTrue(compareWkt(next(lines.getFeatures()).geometry().asWkt(), 'linestring(9 45, 10 46)'))
+ self.assertTrue(
+ compareWkt(next(points.getFeatures()).geometry().asWkt(), "point(9 45)")
+ )
+ self.assertTrue(
+ compareWkt(
+ next(lines.getFeatures()).geometry().asWkt(), "linestring(9 45, 10 46)"
+ )
+ )
with self.assertRaises(StopIteration):
next(polygons.getFeatures())
# Test regression GH #38567 (no SRID requested in the data source URI)
# Cleanup if needed
- conn.executeSql('DELETE FROM "qgis_test"."test_unrestricted_geometry" WHERE \'t\'')
+ conn.executeSql(
+ 'DELETE FROM "qgis_test"."test_unrestricted_geometry" WHERE \'t\''
+ )
- points = QgsVectorLayer(self.dbconn + ' sslmode=disable key=\'gid\' type=POINT table="qgis_test"."test_unrestricted_geometry" (geom) sql=', 'test_points', 'postgres')
- lines = QgsVectorLayer(self.dbconn + ' sslmode=disable key=\'gid\' type=LINESTRING table="qgis_test"."test_unrestricted_geometry" (geom) sql=', 'test_lines', 'postgres')
- polygons = QgsVectorLayer(self.dbconn + ' sslmode=disable key=\'gid\' type=POLYGON table="qgis_test"."test_unrestricted_geometry" (geom) sql=', 'test_polygons', 'postgres')
+ points = QgsVectorLayer(
+ self.dbconn
+ + ' sslmode=disable key=\'gid\' type=POINT table="qgis_test"."test_unrestricted_geometry" (geom) sql=',
+ "test_points",
+ "postgres",
+ )
+ lines = QgsVectorLayer(
+ self.dbconn
+ + ' sslmode=disable key=\'gid\' type=LINESTRING table="qgis_test"."test_unrestricted_geometry" (geom) sql=',
+ "test_lines",
+ "postgres",
+ )
+ polygons = QgsVectorLayer(
+ self.dbconn
+ + ' sslmode=disable key=\'gid\' type=POLYGON table="qgis_test"."test_unrestricted_geometry" (geom) sql=',
+ "test_polygons",
+ "postgres",
+ )
self.assertTrue(points.isValid())
self.assertTrue(lines.isValid())
self.assertTrue(polygons.isValid())
def test_read_wkb(self):
- """ Test to read WKB from Postgis. """
+ """Test to read WKB from Postgis."""
md = QgsProviderRegistry.instance().providerMetadata("postgres")
conn = md.createConnection(self.dbconn, {})
results = conn.executeSql("SELECT ST_AsBinary(ST_MakePoint(5, 10));")
wkb = results[0][0]
geom = QgsGeometry()
import binascii
+
geom.fromWkb(binascii.unhexlify(wkb[2:]))
self.assertEqual(geom.asWkt(), "Point (5 10)")
@@ -4028,9 +5185,11 @@ def testTrustFlag(self):
"""Test regression https://github.com/qgis/QGIS/issues/38809"""
vl = QgsVectorLayer(
- self.dbconn +
- ' sslmode=disable key=\'pk\' srid=4326 type=POINT table="qgis_test"."editData" (geom) sql=',
- 'testTrustFlag', 'postgres')
+ self.dbconn
+ + ' sslmode=disable key=\'pk\' srid=4326 type=POINT table="qgis_test"."editData" (geom) sql=',
+ "testTrustFlag",
+ "postgres",
+ )
self.assertTrue(vl.isValid())
@@ -4039,14 +5198,14 @@ def testTrustFlag(self):
dir_path = d.path()
self.assertTrue(p.addMapLayers([vl]))
- project_path = os.path.join(dir_path, 'testTrustFlag.qgs')
+ project_path = os.path.join(dir_path, "testTrustFlag.qgs")
self.assertTrue(p.write(project_path))
del vl
p.clear()
self.assertTrue(p.read(project_path))
- vl = p.mapLayersByName('testTrustFlag')[0]
+ vl = p.mapLayersByName("testTrustFlag")[0]
self.assertTrue(vl.isValid())
self.assertFalse(p.trustLayerMetadata())
@@ -4058,7 +5217,7 @@ def testTrustFlag(self):
p.clear()
self.assertTrue(p.read(project_path))
self.assertTrue(p.trustLayerMetadata())
- vl = p.mapLayersByName('testTrustFlag')[0]
+ vl = p.mapLayersByName("testTrustFlag")[0]
self.assertTrue(vl.isValid())
def testQueryLayerDuplicatedFields(self):
@@ -4066,35 +5225,49 @@ def testQueryLayerDuplicatedFields(self):
def _get_layer(sql):
return QgsVectorLayer(
- self.dbconn +
- ' sslmode=disable key=\'__rid__\' table=\'(SELECT row_number() OVER () AS __rid__, * FROM (' + sql + ') as foo)\' sql=',
- 'test', 'postgres')
-
- l = _get_layer('SELECT 1, 2')
+ self.dbconn
+ + " sslmode=disable key='__rid__' table='(SELECT row_number() OVER () AS __rid__, * FROM ("
+ + sql
+ + ") as foo)' sql=",
+ "test",
+ "postgres",
+ )
+
+ l = _get_layer("SELECT 1, 2")
self.assertEqual(l.fields().count(), 3)
- self.assertEqual([f.name() for f in l.fields()], ['__rid__', '?column?', '?column? (2)'])
+ self.assertEqual(
+ [f.name() for f in l.fields()], ["__rid__", "?column?", "?column? (2)"]
+ )
- l = _get_layer('SELECT 1 as id, 2 as id')
+ l = _get_layer("SELECT 1 as id, 2 as id")
self.assertEqual(l.fields().count(), 3)
- self.assertEqual([f.name() for f in l.fields()], ['__rid__', 'id', 'id (2)'])
+ self.assertEqual([f.name() for f in l.fields()], ["__rid__", "id", "id (2)"])
def testInsertOnlyFieldIsEditable(self):
"""Test issue #40922 when an INSERT only use cannot insert a new feature"""
md = QgsProviderRegistry.instance().providerMetadata("postgres")
conn = md.createConnection(self.dbconn, {})
- conn.executeSql('DROP TABLE IF EXISTS public.insert_only_points')
- conn.executeSql('DROP USER IF EXISTS insert_only_user')
- conn.executeSql('CREATE USER insert_only_user WITH PASSWORD \'insert_only_user\'')
- conn.executeSql('CREATE TABLE insert_only_points (id SERIAL PRIMARY KEY, name VARCHAR(64))')
- conn.executeSql("SELECT AddGeometryColumn('public', 'insert_only_points', 'geom', 4326, 'POINT', 2 )")
- conn.executeSql('GRANT SELECT ON "public"."insert_only_points" TO insert_only_user')
-
- uri = QgsDataSourceUri(self.dbconn +
- ' sslmode=disable key=\'id\'srid=4326 type=POINT table="public"."insert_only_points" (geom) sql=')
- uri.setUsername('insert_only_user')
- uri.setPassword('insert_only_user')
- vl = QgsVectorLayer(uri.uri(), 'test', 'postgres')
+ conn.executeSql("DROP TABLE IF EXISTS public.insert_only_points")
+ conn.executeSql("DROP USER IF EXISTS insert_only_user")
+ conn.executeSql("CREATE USER insert_only_user WITH PASSWORD 'insert_only_user'")
+ conn.executeSql(
+ "CREATE TABLE insert_only_points (id SERIAL PRIMARY KEY, name VARCHAR(64))"
+ )
+ conn.executeSql(
+ "SELECT AddGeometryColumn('public', 'insert_only_points', 'geom', 4326, 'POINT', 2 )"
+ )
+ conn.executeSql(
+ 'GRANT SELECT ON "public"."insert_only_points" TO insert_only_user'
+ )
+
+ uri = QgsDataSourceUri(
+ self.dbconn
+ + ' sslmode=disable key=\'id\'srid=4326 type=POINT table="public"."insert_only_points" (geom) sql='
+ )
+ uri.setUsername("insert_only_user")
+ uri.setPassword("insert_only_user")
+ vl = QgsVectorLayer(uri.uri(), "test", "postgres")
self.assertTrue(vl.isValid())
self.assertFalse(vl.startEditing())
@@ -4102,8 +5275,10 @@ def testInsertOnlyFieldIsEditable(self):
self.assertFalse(QgsVectorLayerUtils.fieldIsEditable(vl, 0, feature))
self.assertFalse(QgsVectorLayerUtils.fieldIsEditable(vl, 1, feature))
- conn.executeSql('GRANT INSERT ON "public"."insert_only_points" TO insert_only_user')
- vl = QgsVectorLayer(uri.uri(), 'test', 'postgres')
+ conn.executeSql(
+ 'GRANT INSERT ON "public"."insert_only_points" TO insert_only_user'
+ )
+ vl = QgsVectorLayer(uri.uri(), "test", "postgres")
feature = QgsFeature(vl.fields())
self.assertTrue(vl.startEditing())
@@ -4116,13 +5291,19 @@ def testPkeyIntArray(self):
"""
md = QgsProviderRegistry.instance().providerMetadata("postgres")
conn = md.createConnection(self.dbconn, {})
- conn.executeSql('DROP TABLE IF EXISTS public.test_pkey_intarray')
- conn.executeSql('CREATE TABLE public.test_pkey_intarray (id _int8 PRIMARY KEY, name VARCHAR(64))')
- conn.executeSql("""INSERT INTO public.test_pkey_intarray (id, name) VALUES('{0,0,19111815}', 'test')""")
+ conn.executeSql("DROP TABLE IF EXISTS public.test_pkey_intarray")
+ conn.executeSql(
+ "CREATE TABLE public.test_pkey_intarray (id _int8 PRIMARY KEY, name VARCHAR(64))"
+ )
+ conn.executeSql(
+ """INSERT INTO public.test_pkey_intarray (id, name) VALUES('{0,0,19111815}', 'test')"""
+ )
- uri = QgsDataSourceUri(self.dbconn +
- ' sslmode=disable key=\'id\' table="public"."test_pkey_intarray" sql=')
- vl = QgsVectorLayer(uri.uri(), 'test', 'postgres')
+ uri = QgsDataSourceUri(
+ self.dbconn
+ + ' sslmode=disable key=\'id\' table="public"."test_pkey_intarray" sql='
+ )
+ vl = QgsVectorLayer(uri.uri(), "test", "postgres")
self.assertTrue(vl.isValid())
feat = next(vl.getFeatures())
@@ -4142,75 +5323,109 @@ def testExportPkGuessLogic(self):
md = QgsProviderRegistry.instance().providerMetadata("postgres")
conn = md.createConnection(self.dbconn, {})
conn.executeSql(
- 'DROP TABLE IF EXISTS qgis_test."testExportPkGuessLogic_source" CASCADE')
+ 'DROP TABLE IF EXISTS qgis_test."testExportPkGuessLogic_source" CASCADE'
+ )
conn.executeSql(
- 'DROP TABLE IF EXISTS qgis_test."testExportPkGuessLogic_exported" CASCADE')
+ 'DROP TABLE IF EXISTS qgis_test."testExportPkGuessLogic_exported" CASCADE'
+ )
conn.executeSql(
"""CREATE TABLE qgis_test."testExportPkGuessLogic_source" ( id bigint generated always as identity primary key,
geom geometry(Point, 4326) check (st_isvalid(geom)),
- name text unique, author text not null)""")
+ name text unique, author text not null)"""
+ )
- source_layer = QgsVectorLayer(self.dbconn + ' sslmode=disable key=\'id\' srid=4326 type=POINT table="qgis_test"."testExportPkGuessLogic_source" (geom) sql=', 'testExportPkGuessLogic_source', 'postgres')
+ source_layer = QgsVectorLayer(
+ self.dbconn
+ + ' sslmode=disable key=\'id\' srid=4326 type=POINT table="qgis_test"."testExportPkGuessLogic_source" (geom) sql=',
+ "testExportPkGuessLogic_source",
+ "postgres",
+ )
- md = QgsProviderRegistry.instance().providerMetadata('postgres')
+ md = QgsProviderRegistry.instance().providerMetadata("postgres")
conn = md.createConnection(self.dbconn, {})
table = conn.table("qgis_test", "testExportPkGuessLogic_source")
- self.assertEqual(table.primaryKeyColumns(), ['id'])
+ self.assertEqual(table.primaryKeyColumns(), ["id"])
self.assertTrue(source_layer.isValid())
# Create the URI as the browser does (no PK information)
- uri = self.dbconn + ' sslmode=disable srid=4326 type=POINT table="qgis_test"."testExportPkGuessLogic_exported" (geom) sql='
+ uri = (
+ self.dbconn
+ + ' sslmode=disable srid=4326 type=POINT table="qgis_test"."testExportPkGuessLogic_exported" (geom) sql='
+ )
- exporter = QgsVectorLayerExporter(uri, 'postgres', source_layer.fields(), source_layer.wkbType(), source_layer.crs(), True, {})
+ exporter = QgsVectorLayerExporter(
+ uri,
+ "postgres",
+ source_layer.fields(),
+ source_layer.wkbType(),
+ source_layer.crs(),
+ True,
+ {},
+ )
self.assertFalse(exporter.lastError())
- exported_layer = QgsVectorLayer(self.dbconn + ' sslmode=disable srid=4326 type=POINT table="qgis_test"."testExportPkGuessLogic_exported" (geom) sql=', 'testExportPkGuessLogic_exported', 'postgres')
+ exported_layer = QgsVectorLayer(
+ self.dbconn
+ + ' sslmode=disable srid=4326 type=POINT table="qgis_test"."testExportPkGuessLogic_exported" (geom) sql=',
+ "testExportPkGuessLogic_exported",
+ "postgres",
+ )
self.assertTrue(exported_layer.isValid())
table = conn.table("qgis_test", "testExportPkGuessLogic_exported")
- self.assertEqual(table.primaryKeyColumns(), ['id'])
+ self.assertEqual(table.primaryKeyColumns(), ["id"])
- self.assertEqual(exported_layer.fields().names(), ['id', 'name', 'author'])
+ self.assertEqual(exported_layer.fields().names(), ["id", "name", "author"])
def testEwkt(self):
- vl = QgsVectorLayer(f'{self.dbconn} table="qgis_test"."someData" sql=', "someData", "postgres")
+ vl = QgsVectorLayer(
+ f'{self.dbconn} table="qgis_test"."someData" sql=', "someData", "postgres"
+ )
tg = QgsTransactionGroup()
tg.addLayer(vl)
feature = next(vl.getFeatures())
# make sure we get a QgsReferenceGeometry and not "just" a string
- self.assertEqual(feature['geom'].crs().authid(), 'EPSG:4326')
+ self.assertEqual(feature["geom"].crs().authid(), "EPSG:4326")
vl.startEditing()
# Layer accepts a referenced geometry
- feature['geom'] = QgsReferencedGeometry(QgsGeometry.fromWkt('POINT(70 70)'), QgsCoordinateReferenceSystem.fromEpsgId(4326))
+ feature["geom"] = QgsReferencedGeometry(
+ QgsGeometry.fromWkt("POINT(70 70)"),
+ QgsCoordinateReferenceSystem.fromEpsgId(4326),
+ )
self.assertTrue(vl.updateFeature(feature))
# Layer will accept null geometry
- feature['geom'] = QgsReferencedGeometry()
+ feature["geom"] = QgsReferencedGeometry()
self.assertTrue(vl.updateFeature(feature))
# Layer will not accept invalid crs
- feature['geom'] = QgsReferencedGeometry(QgsGeometry.fromWkt('POINT(1 1)'), QgsCoordinateReferenceSystem())
+ feature["geom"] = QgsReferencedGeometry(
+ QgsGeometry.fromWkt("POINT(1 1)"), QgsCoordinateReferenceSystem()
+ )
self.assertFalse(vl.updateFeature(feature))
# EWKT strings are accepted too
- feature['geom'] = 'SRID=4326;Point (71 78)'
+ feature["geom"] = "SRID=4326;Point (71 78)"
self.assertTrue(vl.updateFeature(feature))
# addFeature
- feature['pk'] = 8
+ feature["pk"] = 8
self.assertTrue(vl.addFeature(feature))
# changeAttributeValue
- geom = QgsReferencedGeometry(QgsGeometry.fromWkt('POINT(3 3)'), QgsCoordinateReferenceSystem.fromEpsgId(4326))
+ geom = QgsReferencedGeometry(
+ QgsGeometry.fromWkt("POINT(3 3)"),
+ QgsCoordinateReferenceSystem.fromEpsgId(4326),
+ )
- feature['pk'] = 8
+ feature["pk"] = 8
self.assertTrue(vl.changeAttributeValue(8, 8, geom))
- self.assertEqual(vl.getFeature(8)['geom'].asWkt(), geom.asWkt())
- self.assertEqual(vl.getFeature(8)['geom'].crs(), geom.crs())
+ self.assertEqual(vl.getFeature(8)["geom"].asWkt(), geom.asWkt())
+ self.assertEqual(vl.getFeature(8)["geom"].crs(), geom.crs())
class TestPyQgsPostgresProviderAsyncCreation(QgisTestCase):
@@ -4218,21 +5433,29 @@ class TestPyQgsPostgresProviderAsyncCreation(QgisTestCase):
@classmethod
def setUpClass(cls):
"""Run before all tests"""
- cls.dbconn = 'service=qgis_test'
- if 'QGIS_PGTEST_DB' in os.environ:
- cls.dbconn = os.environ['QGIS_PGTEST_DB']
+ cls.dbconn = "service=qgis_test"
+ if "QGIS_PGTEST_DB" in os.environ:
+ cls.dbconn = os.environ["QGIS_PGTEST_DB"]
# Create test layers
vl1 = QgsVectorLayer(
- cls.dbconn + ' sslmode=disable srid=4326 type=POINT table="qgis_test"."b31799_test_table" (geom) sql=',
- 'layer 1', 'postgres')
+ cls.dbconn
+ + ' sslmode=disable srid=4326 type=POINT table="qgis_test"."b31799_test_table" (geom) sql=',
+ "layer 1",
+ "postgres",
+ )
vl2 = QgsVectorLayer(
- cls.dbconn + ' sslmode=disable srid=3857 type=POINT table="qgis_test"."array_tbl" (geom) sql=', 'layer 2',
- 'postgres')
+ cls.dbconn
+ + ' sslmode=disable srid=3857 type=POINT table="qgis_test"."array_tbl" (geom) sql=',
+ "layer 2",
+ "postgres",
+ )
cls.layers = [vl1, vl2]
cls.con = psycopg2.connect(cls.dbconn)
- cls.projectTempFile = QTemporaryFile(QDir.temp().absoluteFilePath("XXXXXX_test.qgs"))
+ cls.projectTempFile = QTemporaryFile(
+ QDir.temp().absoluteFilePath("XXXXXX_test.qgs")
+ )
cls.projectTempFile.open()
@classmethod
@@ -4253,7 +5476,9 @@ def testReadProject(self):
self.assertTrue(project.write(self.projectTempFile.fileName()))
- settings = QgsSettingsTree.node('core').childSetting('provider-parallel-loading')
+ settings = QgsSettingsTree.node("core").childSetting(
+ "provider-parallel-loading"
+ )
self.assertTrue(settings is not None)
current_value = settings.valueAsVariant()
settings.setVariantValue(True)
@@ -4273,5 +5498,5 @@ def testReadProject(self):
settings.setVariantValue(current_value)
-if __name__ == '__main__':
+if __name__ == "__main__":
unittest.main()
diff --git a/tests/src/python/test_provider_postgres_latency.py b/tests/src/python/test_provider_postgres_latency.py
index 707a24e62a09..82c823e2fdb8 100644
--- a/tests/src/python/test_provider_postgres_latency.py
+++ b/tests/src/python/test_provider_postgres_latency.py
@@ -12,9 +12,9 @@
"""
-__author__ = 'Daryna Dyka'
-__date__ = '2021-06-13'
-__copyright__ = 'Copyright 2021, The QGIS Project'
+__author__ = "Daryna Dyka"
+__date__ = "2021-06-13"
+__copyright__ = "Copyright 2021, The QGIS Project"
import os
import time
@@ -43,29 +43,29 @@ class TestPyQgsPostgresProviderLatency(QgisTestCase):
def setUpClass(cls):
"""Run before all tests"""
super().setUpClass()
- cls.dbconn = 'service=qgis_test'
- if 'QGIS_PGTEST_DB' in os.environ:
- cls.dbconn = os.environ['QGIS_PGTEST_DB']
+ cls.dbconn = "service=qgis_test"
+ if "QGIS_PGTEST_DB" in os.environ:
+ cls.dbconn = os.environ["QGIS_PGTEST_DB"]
cls.con = psycopg2.connect(cls.dbconn)
@classmethod
def tearDownClass(cls):
"""Run after all tests"""
- os.system('tc qdisc del dev eth0 root')
+ os.system("tc qdisc del dev eth0 root")
super().tearDownClass()
def setDelay(self, delay_in_ms):
if delay_in_ms == 0:
- os.system('tc qdisc del dev eth0 root')
+ os.system("tc qdisc del dev eth0 root")
else:
- os.system(f'tc qdisc add dev eth0 root netem delay {delay_in_ms}ms')
+ os.system(f"tc qdisc add dev eth0 root netem delay {delay_in_ms}ms")
def getDelay(self):
self.assertTrue(self.con)
cur = self.con.cursor()
self.assertTrue(cur)
start_time = time.time()
- cur.execute('SELECT 1;')
+ cur.execute("SELECT 1;")
duration = round(1000 * abs(time.time() - start_time), 1)
cur.close()
self.con.commit()
@@ -91,9 +91,13 @@ def testStatsSetDelayToDB(self):
self.setDelay(delay_ms)
delay_get[delay_ms] = self.getDelay()
self.setDelay(0)
- delay_delta[delay_ms] = round(delay_get[delay_ms] / 2.0 - delay_set[delay_ms], 1)
+ delay_delta[delay_ms] = round(
+ delay_get[delay_ms] / 2.0 - delay_set[delay_ms], 1
+ )
- self.assertTrue(False, f'\nset: {delay_set}\nget: {delay_get}\nget/2 - set: {delay_delta}')
+ self.assertTrue(
+ False, f"\nset: {delay_set}\nget: {delay_get}\nget/2 - set: {delay_delta}"
+ )
def testSetDelayToDB(self):
"""Test Set delay to remote DB"""
@@ -101,12 +105,16 @@ def testSetDelayToDB(self):
self.setDelay(100)
delay_get = self.getDelay() / 2
self.setDelay(0)
- self.assertTrue(delay_get > 90 and delay_get < 110, f'set delay to 100ms - unsuccessful (got: {delay_get}ms)')
+ self.assertTrue(
+ delay_get > 90 and delay_get < 110,
+ f"set delay to 100ms - unsuccessful (got: {delay_get}ms)",
+ )
def testSaveChangedGeometryToDB(self):
"""Test Save geometries to remote DB"""
- self.execSQLCommand('''
+ self.execSQLCommand(
+ """
DROP TABLE IF EXISTS qgis_test.speed_test_remote_db CASCADE;
CREATE TABLE qgis_test.speed_test_remote_db (
id_serial serial NOT NULL,
@@ -119,12 +127,15 @@ def testSaveChangedGeometryToDB(self):
3396830.0 6521870.0,3396830.0 6521800.0,3396900.0 6521800.0))\', 3857 ),
100.0 * dx,
100.0 * dy )
- FROM generate_series(1,42) dx, generate_series(1,42) dy;''')
+ FROM generate_series(1,42) dx, generate_series(1,42) dy;"""
+ )
set_new_layer = ' sslmode=disable key=\'id_serial\' srid=3857 type=POLYGON table="qgis_test"."speed_test_remote_db" (geom) sql='
- error_string = 'Save geoms to remote DB : expected < 10s, got {}s'
+ error_string = "Save geoms to remote DB : expected < 10s, got {}s"
- vl = QgsVectorLayer(self.dbconn + set_new_layer, 'test_vl_remote_save', 'postgres')
+ vl = QgsVectorLayer(
+ self.dbconn + set_new_layer, "test_vl_remote_save", "postgres"
+ )
# fids = [f.id() for f in vl.getFeatures(QgsFeatureRequest().setLimit(1000))]
fids = [f.id() for f in vl.getFeatures(QgsFeatureRequest().setLimit(50))]
self.assertTrue(vl.startEditing())
@@ -139,27 +150,41 @@ def testSaveChangedGeometryToDB(self):
self.assertTrue(duration < 10, error_string.format(duration))
def testProjectOpenTime(self):
- """ open project, provider-parallel-loading = False """
+ """open project, provider-parallel-loading = False"""
- projectFile = QTemporaryFile(QDir.temp().absoluteFilePath("testProjectOpenTime.qgz"))
+ projectFile = QTemporaryFile(
+ QDir.temp().absoluteFilePath("testProjectOpenTime.qgz")
+ )
projectFile.open()
project = QgsProject()
set_new_layer = ' sslmode=disable key=\'pk\' srid=4326 type=POINT table="qgis_test"."someData" (geom) sql='
- project.addMapLayer(QgsVectorLayer(self.dbconn + set_new_layer, 'test_vl_01', 'postgres'))
- project.addMapLayer(QgsVectorLayer(self.dbconn + set_new_layer, 'test_vl_02', 'postgres'))
- project.addMapLayer(QgsVectorLayer(self.dbconn + set_new_layer, 'test_vl_03', 'postgres'))
- project.addMapLayer(QgsVectorLayer(self.dbconn + set_new_layer, 'test_vl_04', 'postgres'))
- project.addMapLayer(QgsVectorLayer(self.dbconn + set_new_layer, 'test_vl_05', 'postgres'))
+ project.addMapLayer(
+ QgsVectorLayer(self.dbconn + set_new_layer, "test_vl_01", "postgres")
+ )
+ project.addMapLayer(
+ QgsVectorLayer(self.dbconn + set_new_layer, "test_vl_02", "postgres")
+ )
+ project.addMapLayer(
+ QgsVectorLayer(self.dbconn + set_new_layer, "test_vl_03", "postgres")
+ )
+ project.addMapLayer(
+ QgsVectorLayer(self.dbconn + set_new_layer, "test_vl_04", "postgres")
+ )
+ project.addMapLayer(
+ QgsVectorLayer(self.dbconn + set_new_layer, "test_vl_05", "postgres")
+ )
self.assertTrue(project.write(projectFile.fileName()))
- settings = QgsSettingsTree.node('core').childSetting('provider-parallel-loading')
+ settings = QgsSettingsTree.node("core").childSetting(
+ "provider-parallel-loading"
+ )
settings.setVariantValue(False)
davg = 7.61
dmin = round(davg - 0.2, 2)
dmax = round(davg + 0.3, 2)
- error_string = 'expected from {0}s to {1}s, got {2}s\nHINT: set davg={2} to pass the test :)'
+ error_string = "expected from {0}s to {1}s, got {2}s\nHINT: set davg={2} to pass the test :)"
project = QgsProject()
self.setDelay(100)
@@ -167,8 +192,11 @@ def testProjectOpenTime(self):
self.assertTrue(project.read(projectFile.fileName()))
duration = round(abs(time.time() - start_time), 2)
self.setDelay(0)
- self.assertTrue(duration > dmin and duration < dmax, error_string.format(dmin, dmax, duration))
+ self.assertTrue(
+ duration > dmin and duration < dmax,
+ error_string.format(dmin, dmax, duration),
+ )
-if __name__ == '__main__':
+if __name__ == "__main__":
unittest.main()
diff --git a/tests/src/python/test_provider_postgresraster.py b/tests/src/python/test_provider_postgresraster.py
index 607e1dbd59c8..940429c60a18 100644
--- a/tests/src/python/test_provider_postgresraster.py
+++ b/tests/src/python/test_provider_postgresraster.py
@@ -14,9 +14,9 @@
"""
-__author__ = 'Alessandro Pasotti'
-__date__ = '2019-12-20'
-__copyright__ = 'Copyright 2019, The QGIS Project'
+__author__ = "Alessandro Pasotti"
+__date__ = "2019-12-20"
+__copyright__ = "Copyright 2019, The QGIS Project"
import os
import time
@@ -53,48 +53,55 @@ class TestPyQgsPostgresRasterProvider(QgisTestCase):
def _load_test_table(cls, schemaname, tablename, basename=None):
postgres_conn = cls.dbconn + " sslmode=disable "
- md = QgsProviderRegistry.instance().providerMetadata('postgres')
+ md = QgsProviderRegistry.instance().providerMetadata("postgres")
conn = md.createConnection(postgres_conn, {})
if basename is None:
basename = tablename
if tablename not in [n.tableName() for n in conn.tables(schemaname)]:
- with open(os.path.join(TEST_DATA_DIR, 'provider', 'postgresraster', basename + '.sql')) as f:
+ with open(
+ os.path.join(
+ TEST_DATA_DIR, "provider", "postgresraster", basename + ".sql"
+ )
+ ) as f:
sql = f.read()
conn.executeSql(sql)
- assert (tablename in [n.tableName() for n in conn.tables(
- schemaname)]), tablename + ' not found!'
+ assert tablename in [n.tableName() for n in conn.tables(schemaname)], (
+ tablename + " not found!"
+ )
@classmethod
def setUpClass(cls):
"""Run before all tests"""
super().setUpClass()
cls.iface = get_iface()
- cls.dbconn = 'service=qgis_test'
- if 'QGIS_PGTEST_DB' in os.environ:
- cls.dbconn = os.environ['QGIS_PGTEST_DB']
-
- cls._load_test_table('public', 'raster_tiled_3035')
- cls._load_test_table('public', 'raster_3035_no_constraints')
- cls._load_test_table('public', 'raster_3035_tiled_no_overviews')
- cls._load_test_table('public', 'raster_3035_tiled_no_pk')
- cls._load_test_table('public', 'raster_3035_tiled_composite_pk')
- cls._load_test_table('public', 'raster_3035_untiled_multiple_rows')
- cls._load_test_table('idro', 'cosmo_i5_snow', 'bug_34823_pg_raster')
- cls._load_test_table(
- 'public', 'int16_regression_36689', 'bug_36689_pg_raster')
- cls._load_test_table('public', 'bug_37968_dem_linear_cdn_extract')
- cls._load_test_table('public', 'bug_39017_untiled_no_metadata')
- cls._load_test_table('public', 'raster_sparse_3035')
+ cls.dbconn = "service=qgis_test"
+ if "QGIS_PGTEST_DB" in os.environ:
+ cls.dbconn = os.environ["QGIS_PGTEST_DB"]
+
+ cls._load_test_table("public", "raster_tiled_3035")
+ cls._load_test_table("public", "raster_3035_no_constraints")
+ cls._load_test_table("public", "raster_3035_tiled_no_overviews")
+ cls._load_test_table("public", "raster_3035_tiled_no_pk")
+ cls._load_test_table("public", "raster_3035_tiled_composite_pk")
+ cls._load_test_table("public", "raster_3035_untiled_multiple_rows")
+ cls._load_test_table("idro", "cosmo_i5_snow", "bug_34823_pg_raster")
+ cls._load_test_table("public", "int16_regression_36689", "bug_36689_pg_raster")
+ cls._load_test_table("public", "bug_37968_dem_linear_cdn_extract")
+ cls._load_test_table("public", "bug_39017_untiled_no_metadata")
+ cls._load_test_table("public", "raster_sparse_3035")
# Fix timing issues in backend
# time.sleep(1)
# Create test layer
cls.rl = QgsRasterLayer(
- cls.dbconn + ' sslmode=disable key=\'rid\' srid=3035 table="public"."raster_tiled_3035" sql=', 'test',
- 'postgresraster')
+ cls.dbconn
+ + ' sslmode=disable key=\'rid\' srid=3035 table="public"."raster_tiled_3035" sql=',
+ "test",
+ "postgresraster",
+ )
assert cls.rl.isValid()
cls.source = cls.rl.dataProvider()
@@ -104,61 +111,86 @@ def gdal_block_compare(self, rlayer, band, extent, width, height, value):
uri = rlayer.uri()
gdal_uri = "PG: dbname={dbname} mode=2 host={host} port={port} table={table} schema={schema} sslmode=disable".format(
**{
- 'dbname': uri.database(),
- 'host': uri.host(),
- 'port': uri.port(),
- 'table': uri.table(),
- 'schema': uri.schema()
- })
+ "dbname": uri.database(),
+ "host": uri.host(),
+ "port": uri.port(),
+ "table": uri.table(),
+ "schema": uri.schema(),
+ }
+ )
gdal_rl = QgsRasterLayer(gdal_uri, "rl", "gdal")
self.assertTrue(gdal_rl.isValid())
- self.assertEqual(value, gdal_rl.dataProvider().block(
- band, self.rl.extent(), 6, 5).data().toHex())
+ self.assertEqual(
+ value,
+ gdal_rl.dataProvider().block(band, self.rl.extent(), 6, 5).data().toHex(),
+ )
def testExtent(self):
extent = self.rl.extent()
- self.assertEqual(extent, QgsRectangle(
- 4080050, 2430625, 4080200, 2430750))
+ self.assertEqual(extent, QgsRectangle(4080050, 2430625, 4080200, 2430750))
def testSize(self):
self.assertEqual(self.source.xSize(), 6)
self.assertEqual(self.source.ySize(), 5)
def testCrs(self):
- self.assertEqual(self.source.crs().authid(), 'EPSG:3035')
+ self.assertEqual(self.source.crs().authid(), "EPSG:3035")
def testGetData(self):
- identify = self.source.identify(QgsPointXY(
- 4080137.9, 2430687.9), QgsRaster.IdentifyFormat.IdentifyFormatValue)
+ identify = self.source.identify(
+ QgsPointXY(4080137.9, 2430687.9),
+ QgsRaster.IdentifyFormat.IdentifyFormatValue,
+ )
expected = 192.51044
self.assertAlmostEqual(identify.results()[1], expected, 4)
def testGetDataFromSparse(self):
"""Test issue GH #55753"""
rl = QgsRasterLayer(
- self.dbconn + " sslmode=disable table={table} schema={schema}".format(
- table='raster_sparse_3035', schema='public'), 'pg_layer', 'postgresraster')
+ self.dbconn
+ + " sslmode=disable table={table} schema={schema}".format(
+ table="raster_sparse_3035", schema="public"
+ ),
+ "pg_layer",
+ "postgresraster",
+ )
self.assertTrue(rl.isValid())
- self.assertTrue(compareWkt(rl.extent().asWktPolygon(
- ), 'POLYGON((4080050 2430625, 4080326 2430625, 4080326 2430855, 4080050 2430855, 4080050 2430625))', 0.01))
+ self.assertTrue(
+ compareWkt(
+ rl.extent().asWktPolygon(),
+ "POLYGON((4080050 2430625, 4080326 2430625, 4080326 2430855, 4080050 2430855, 4080050 2430625))",
+ 0.01,
+ )
+ )
app_log = QgsApplication.messageLog()
log_spy = QSignalSpy(app_log.messageReceived)
# Identify pixel from area not containing data
- identify = rl.dataProvider().identify(QgsPointXY(
- 4080320, 2430854), QgsRaster.IdentifyFormat.IdentifyFormatValue)
+ identify = rl.dataProvider().identify(
+ QgsPointXY(4080320, 2430854), QgsRaster.IdentifyFormat.IdentifyFormatValue
+ )
self.assertEqual(identify.results()[1], -9999)
- postgis_warning_logs = list(filter(lambda log: log[2] == Qgis.MessageLevel.Warning and log[1] == "PostGIS", list(log_spy)))
+ postgis_warning_logs = list(
+ filter(
+ lambda log: log[2] == Qgis.MessageLevel.Warning and log[1] == "PostGIS",
+ list(log_spy),
+ )
+ )
# TODO: there is still NOTICE: row number 0 is out of range 0..-1 warning...
- conversion_logs = list(filter(lambda log: "Cannot convert identified value" in log[0], postgis_warning_logs))
+ conversion_logs = list(
+ filter(
+ lambda log: "Cannot convert identified value" in log[0],
+ postgis_warning_logs,
+ )
+ )
self.assertEqual(len(conversion_logs), 0, list(conversion_logs))
def testBlockTiled(self):
- expected = b'6a610843880b0e431cc2194306342543b7633c43861858436e0a1143bbad194359612743a12b334317be4343dece59432b621b43f0e42843132b3843ac824043e6cf48436e465a435c4d2d430fa63d43f87a4843b5494a4349454e4374f35b43906e41433ab54c43b056504358575243b1ec574322615f43'
+ expected = b"6a610843880b0e431cc2194306342543b7633c43861858436e0a1143bbad194359612743a12b334317be4343dece59432b621b43f0e42843132b3843ac824043e6cf48436e465a435c4d2d430fa63d43f87a4843b5494a4349454e4374f35b43906e41433ab54c43b056504358575243b1ec574322615f43"
block = self.source.block(1, self.rl.extent(), 6, 5)
actual = block.data().toHex()
self.assertEqual(len(actual), len(expected))
@@ -168,94 +200,146 @@ def testNoConstraintRaster(self):
"""Read unconstrained raster layer"""
rl = QgsRasterLayer(
- self.dbconn + ' sslmode=disable key=\'pk\' srid=3035 table="public"."raster_3035_no_constraints" sql=',
- 'test', 'postgresraster')
+ self.dbconn
+ + ' sslmode=disable key=\'pk\' srid=3035 table="public"."raster_3035_no_constraints" sql=',
+ "test",
+ "postgresraster",
+ )
self.assertTrue(rl.isValid())
def testPkGuessing(self):
"""Read raster layer with no pkey in uri"""
- rl = QgsRasterLayer(self.dbconn + ' sslmode=disable srid=3035 table="public"."raster_tiled_3035" sql=', 'test',
- 'postgresraster')
+ rl = QgsRasterLayer(
+ self.dbconn
+ + ' sslmode=disable srid=3035 table="public"."raster_tiled_3035" sql=',
+ "test",
+ "postgresraster",
+ )
self.assertTrue(rl.isValid())
def testWhereCondition(self):
"""Read raster layer with where condition"""
rl_nowhere = QgsRasterLayer(
- self.dbconn + ' sslmode=disable srid=3035 table="public"."raster_3035_tiled_no_overviews"' +
- 'sql=', 'test', 'postgresraster')
+ self.dbconn
+ + ' sslmode=disable srid=3035 table="public"."raster_3035_tiled_no_overviews"'
+ + "sql=",
+ "test",
+ "postgresraster",
+ )
self.assertTrue(rl_nowhere.isValid())
rl = QgsRasterLayer(
- self.dbconn + ' sslmode=disable srid=3035 table="public"."raster_3035_tiled_no_overviews"' +
- 'sql="category" = \'cat2\'', 'test', 'postgresraster')
+ self.dbconn
+ + ' sslmode=disable srid=3035 table="public"."raster_3035_tiled_no_overviews"'
+ + "sql=\"category\" = 'cat2'",
+ "test",
+ "postgresraster",
+ )
self.assertTrue(rl.isValid())
self.assertTrue(not rl.extent().isEmpty())
self.assertNotEqual(rl_nowhere.extent(), rl.extent())
self.assertIsNone(
- rl.dataProvider().identify(QgsPointXY(4080137.9, 2430687.9), QgsRaster.IdentifyFormat.IdentifyFormatValue).results()[1])
- self.assertIsNotNone(rl_nowhere.dataProvider().identify(QgsPointXY(4080137.9, 2430687.9),
- QgsRaster.IdentifyFormat.IdentifyFormatValue).results()[1])
+ rl.dataProvider()
+ .identify(
+ QgsPointXY(4080137.9, 2430687.9),
+ QgsRaster.IdentifyFormat.IdentifyFormatValue,
+ )
+ .results()[1]
+ )
+ self.assertIsNotNone(
+ rl_nowhere.dataProvider()
+ .identify(
+ QgsPointXY(4080137.9, 2430687.9),
+ QgsRaster.IdentifyFormat.IdentifyFormatValue,
+ )
+ .results()[1]
+ )
self.assertAlmostEqual(
- rl.dataProvider().identify(rl.extent().center(), QgsRaster.IdentifyFormat.IdentifyFormatValue).results()[1], 223.38, 2)
+ rl.dataProvider()
+ .identify(
+ rl.extent().center(), QgsRaster.IdentifyFormat.IdentifyFormatValue
+ )
+ .results()[1],
+ 223.38,
+ 2,
+ )
- self.assertTrue(compareWkt(rl_nowhere.extent().asWktPolygon(),
- 'POLYGON((4080050 2430625, 4080200 2430625, 4080200 2430750, 4080050 2430750, 4080050 2430625))'))
+ self.assertTrue(
+ compareWkt(
+ rl_nowhere.extent().asWktPolygon(),
+ "POLYGON((4080050 2430625, 4080200 2430625, 4080200 2430750, 4080050 2430750, 4080050 2430625))",
+ )
+ )
- self.assertTrue(compareWkt(rl.extent().asWktPolygon(),
- 'POLYGON((4080150 2430625, 4080200 2430625, 4080200 2430650, 4080150 2430650, 4080150 2430625))'))
+ self.assertTrue(
+ compareWkt(
+ rl.extent().asWktPolygon(),
+ "POLYGON((4080150 2430625, 4080200 2430625, 4080200 2430650, 4080150 2430650, 4080150 2430625))",
+ )
+ )
self.assertNotEqual(rl.extent(), rl_nowhere.extent())
# Now check if setSubsetString updates the extent
- self.assertTrue(rl_nowhere.setSubsetString('"category" = \'cat2\''))
+ self.assertTrue(rl_nowhere.setSubsetString("\"category\" = 'cat2'"))
self.assertEqual(rl.extent(), rl_nowhere.extent())
def testNoPk(self):
"""Read raster with no PK"""
- rl = QgsRasterLayer(self.dbconn + ' sslmode=disable srid=3035 table="public"."raster_3035_tiled_no_pk"' +
- 'sql=', 'test', 'postgresraster')
+ rl = QgsRasterLayer(
+ self.dbconn
+ + ' sslmode=disable srid=3035 table="public"."raster_3035_tiled_no_pk"'
+ + "sql=",
+ "test",
+ "postgresraster",
+ )
self.assertTrue(rl.isValid())
def testCompositeKey(self):
"""Read raster with composite pks"""
rl = QgsRasterLayer(
- self.dbconn + ' sslmode=disable srid=3035 table="public"."raster_3035_tiled_composite_pk"' +
- 'sql=', 'test', 'postgresraster')
+ self.dbconn
+ + ' sslmode=disable srid=3035 table="public"."raster_3035_tiled_composite_pk"'
+ + "sql=",
+ "test",
+ "postgresraster",
+ )
self.assertTrue(rl.isValid())
data = rl.dataProvider().block(1, rl.extent(), 3, 3)
self.assertEqual(int(data.value(0, 0)), 142)
- @unittest.skip('Performance test is disabled in Travis environment')
+ @unittest.skip("Performance test is disabled in Travis environment")
def testSpeed(self):
"""Compare speed with GDAL provider, this test was used during development"""
conn = "user={user} host=localhost port=5432 password={password} dbname={speed_db} ".format(
- user=os.environ.get('USER'),
- password=os.environ.get('USER'),
- speed_db='qgis_test'
+ user=os.environ.get("USER"),
+ password=os.environ.get("USER"),
+ speed_db="qgis_test",
)
- table = 'basic_map_tiled'
- schema = 'public'
+ table = "basic_map_tiled"
+ schema = "public"
def _speed_check(schema, table, width, height):
- print('-' * 80)
+ print("-" * 80)
print(f"Testing: {schema}.{table}")
- print('-' * 80)
+ print("-" * 80)
# GDAL
start = time.time()
rl = QgsRasterLayer(
- "PG: " + conn +
- f"table={table} mode=2 schema={schema}", 'gdal_layer',
- 'gdal')
+ "PG: " + conn + f"table={table} mode=2 schema={schema}",
+ "gdal_layer",
+ "gdal",
+ )
self.assertTrue(rl.isValid())
# Make is smaller than full extent
extent = rl.extent().buffered(-rl.extent().width() * 0.2)
@@ -268,12 +352,13 @@ def _speed_check(schema, table, width, height):
checkpoint_3 = time.time()
print(f"Tiled GDAL second block time: {checkpoint_3 - checkpoint_2:.6f}")
print(f"Total GDAL time: {checkpoint_3 - start:.6f}")
- print('-' * 80)
+ print("-" * 80)
# PG native
start = time.time()
- rl = QgsRasterLayer(conn + f"table={table} schema={schema}", 'gdal_layer',
- 'postgresraster')
+ rl = QgsRasterLayer(
+ conn + f"table={table} schema={schema}", "gdal_layer", "postgresraster"
+ )
self.assertTrue(rl.isValid())
extent = rl.extent().buffered(-rl.extent().width() * 0.2)
checkpoint_1 = time.time()
@@ -285,7 +370,7 @@ def _speed_check(schema, table, width, height):
checkpoint_3 = time.time()
print(f"Tiled PG second block time: {checkpoint_3 - checkpoint_2:.6f}")
print(f"Total PG time: {checkpoint_3 - start:.6f}")
- print('-' * 80)
+ print("-" * 80)
_speed_check(schema, table, 1000, 1000)
@@ -295,16 +380,28 @@ def testOtherSchema(self):
rl = QgsRasterLayer(
self.dbconn + " sslmode=disable table=cosmo_i5_snow schema=idro",
- 'pg_layer', 'postgresraster')
+ "pg_layer",
+ "postgresraster",
+ )
self.assertTrue(rl.isValid())
- self.assertTrue(compareWkt(rl.extent().asWktPolygon(),
- 'POLYGON((-64.79286766849691048 -77.26689086732433509, -62.18292922825105506 -77.26689086732433509, -62.18292922825105506 -74.83694818157819384, -64.79286766849691048 -74.83694818157819384, -64.79286766849691048 -77.26689086732433509))'))
+ self.assertTrue(
+ compareWkt(
+ rl.extent().asWktPolygon(),
+ "POLYGON((-64.79286766849691048 -77.26689086732433509, -62.18292922825105506 -77.26689086732433509, -62.18292922825105506 -74.83694818157819384, -64.79286766849691048 -74.83694818157819384, -64.79286766849691048 -77.26689086732433509))",
+ )
+ )
def testUntiledMultipleRows(self):
"""Test multiple rasters (one per row)"""
- rl = QgsRasterLayer(self.dbconn + " sslmode=disable table={table} schema={schema} sql=\"pk\" = 1".format(
- table='raster_3035_untiled_multiple_rows', schema='public'), 'pg_layer', 'postgresraster')
+ rl = QgsRasterLayer(
+ self.dbconn
+ + ' sslmode=disable table={table} schema={schema} sql="pk" = 1'.format(
+ table="raster_3035_untiled_multiple_rows", schema="public"
+ ),
+ "pg_layer",
+ "postgresraster",
+ )
self.assertTrue(rl.isValid())
block = rl.dataProvider().block(1, rl.extent(), 2, 2)
data = []
@@ -313,8 +410,14 @@ def testUntiledMultipleRows(self):
data.append(int(block.value(i, j)))
self.assertEqual(data, [136, 142, 145, 153])
- rl = QgsRasterLayer(self.dbconn + " sslmode=disable table={table} schema={schema} sql=\"pk\" = 2".format(
- table='raster_3035_untiled_multiple_rows', schema='public'), 'pg_layer', 'postgresraster')
+ rl = QgsRasterLayer(
+ self.dbconn
+ + ' sslmode=disable table={table} schema={schema} sql="pk" = 2'.format(
+ table="raster_3035_untiled_multiple_rows", schema="public"
+ ),
+ "pg_layer",
+ "postgresraster",
+ )
self.assertTrue(rl.isValid())
block = rl.dataProvider().block(1, rl.extent(), 2, 2)
data = []
@@ -326,8 +429,14 @@ def testUntiledMultipleRows(self):
def testSetSubsetString(self):
"""Test setSubsetString"""
- rl = QgsRasterLayer(self.dbconn + " sslmode=disable table={table} schema={schema} sql=\"pk\" = 2".format(
- table='raster_3035_untiled_multiple_rows', schema='public'), 'pg_layer', 'postgresraster')
+ rl = QgsRasterLayer(
+ self.dbconn
+ + ' sslmode=disable table={table} schema={schema} sql="pk" = 2'.format(
+ table="raster_3035_untiled_multiple_rows", schema="public"
+ ),
+ "pg_layer",
+ "postgresraster",
+ )
self.assertTrue(rl.isValid())
block = rl.dataProvider().block(1, rl.extent(), 2, 2)
@@ -338,7 +447,8 @@ def testSetSubsetString(self):
self.assertEqual(data, [136, 142, 161, 169])
stats = rl.dataProvider().bandStatistics(
- 1, QgsRasterBandStats.Stats.Min | QgsRasterBandStats.Stats.Max, rl.extent())
+ 1, QgsRasterBandStats.Stats.Min | QgsRasterBandStats.Stats.Max, rl.extent()
+ )
self.assertEqual(int(stats.minimumValue), 136)
self.assertEqual(int(stats.maximumValue), 169)
@@ -357,7 +467,8 @@ def testSetSubsetString(self):
# Check that we have new statistics
stats = rl.dataProvider().bandStatistics(
- 1, QgsRasterBandStats.Stats.Min | QgsRasterBandStats.Stats.Max, rl.extent())
+ 1, QgsRasterBandStats.Stats.Min | QgsRasterBandStats.Stats.Max, rl.extent()
+ )
self.assertEqual(int(stats.minimumValue), 136)
self.assertEqual(int(stats.maximumValue), 153)
@@ -394,46 +505,76 @@ def _test_block(rl, expected_block, expected_single):
# First check that setting different temporal default values we get different results
rl = QgsRasterLayer(
- self.dbconn + " sslmode=disable table={table} schema={schema} temporalDefaultTime='2020-04-01T00:00:00' temporalFieldIndex='1'".format(
- table='raster_3035_untiled_multiple_rows', schema='public'), 'pg_layer', 'postgresraster')
+ self.dbconn
+ + " sslmode=disable table={table} schema={schema} temporalDefaultTime='2020-04-01T00:00:00' temporalFieldIndex='1'".format(
+ table="raster_3035_untiled_multiple_rows", schema="public"
+ ),
+ "pg_layer",
+ "postgresraster",
+ )
self.assertEqual(rl.subsetString(), "")
_test_block(rl, [136, 142, 145, 153], 153)
rl = QgsRasterLayer(
- self.dbconn + " sslmode=disable table={table} schema={schema} temporalDefaultTime='2020-04-05T00:00:00' temporalFieldIndex='1'".format(
- table='raster_3035_untiled_multiple_rows', schema='public'), 'pg_layer', 'postgresraster')
+ self.dbconn
+ + " sslmode=disable table={table} schema={schema} temporalDefaultTime='2020-04-05T00:00:00' temporalFieldIndex='1'".format(
+ table="raster_3035_untiled_multiple_rows", schema="public"
+ ),
+ "pg_layer",
+ "postgresraster",
+ )
self.assertEqual(rl.subsetString(), "")
_test_block(rl, [136, 142, 161, 169], 169)
# Check that manually setting a subsetString we get the same results
rl = QgsRasterLayer(
- self.dbconn + " sslmode=disable table={table} schema={schema} sql=\"data\" = '2020-04-01'".format(
- table='raster_3035_untiled_multiple_rows', schema='public'), 'pg_layer', 'postgresraster')
- self.assertEqual(rl.subsetString(), '"data" = \'2020-04-01\'')
+ self.dbconn
+ + " sslmode=disable table={table} schema={schema} sql=\"data\" = '2020-04-01'".format(
+ table="raster_3035_untiled_multiple_rows", schema="public"
+ ),
+ "pg_layer",
+ "postgresraster",
+ )
+ self.assertEqual(rl.subsetString(), "\"data\" = '2020-04-01'")
_test_block(rl, [136, 142, 145, 153], 153)
rl = QgsRasterLayer(
- self.dbconn + " sslmode=disable table={table} schema={schema} sql=\"data\" = '2020-04-05'".format(
- table='raster_3035_untiled_multiple_rows', schema='public'), 'pg_layer', 'postgresraster')
- self.assertEqual(rl.subsetString(), '"data" = \'2020-04-05\'')
+ self.dbconn
+ + " sslmode=disable table={table} schema={schema} sql=\"data\" = '2020-04-05'".format(
+ table="raster_3035_untiled_multiple_rows", schema="public"
+ ),
+ "pg_layer",
+ "postgresraster",
+ )
+ self.assertEqual(rl.subsetString(), "\"data\" = '2020-04-05'")
_test_block(rl, [136, 142, 161, 169], 169)
# Now check if the varchar temporal field works the same
rl = QgsRasterLayer(
- self.dbconn + " sslmode=disable table={table} schema={schema} temporalDefaultTime='2020-04-01T00:00:00' temporalFieldIndex='2'".format(
- table='raster_3035_untiled_multiple_rows', schema='public'), 'pg_layer', 'postgresraster')
- self.assertEqual(rl.subsetString(), '')
+ self.dbconn
+ + " sslmode=disable table={table} schema={schema} temporalDefaultTime='2020-04-01T00:00:00' temporalFieldIndex='2'".format(
+ table="raster_3035_untiled_multiple_rows", schema="public"
+ ),
+ "pg_layer",
+ "postgresraster",
+ )
+ self.assertEqual(rl.subsetString(), "")
_test_block(rl, [136, 142, 145, 153], 153)
rl = QgsRasterLayer(
- self.dbconn + " sslmode=disable table={table} schema={schema} temporalDefaultTime='2020-04-05T00:00:00' temporalFieldIndex='2'".format(
- table='raster_3035_untiled_multiple_rows', schema='public'), 'pg_layer', 'postgresraster')
- self.assertEqual(rl.subsetString(), '')
+ self.dbconn
+ + " sslmode=disable table={table} schema={schema} temporalDefaultTime='2020-04-05T00:00:00' temporalFieldIndex='2'".format(
+ table="raster_3035_untiled_multiple_rows", schema="public"
+ ),
+ "pg_layer",
+ "postgresraster",
+ )
+ self.assertEqual(rl.subsetString(), "")
_test_block(rl, [136, 142, 161, 169], 169)
@@ -444,53 +585,67 @@ def _round_trip(uri):
decoded = md.decodeUri(uri)
self.assertEqual(decoded, md.decodeUri(md.encodeUri(decoded)))
- uri = self.dbconn + \
- ' sslmode=disable key=\'rid\' srid=3035 table="public"."raster_tiled_3035" sql='
- md = QgsProviderRegistry.instance().providerMetadata('postgresraster')
+ uri = (
+ self.dbconn
+ + ' sslmode=disable key=\'rid\' srid=3035 table="public"."raster_tiled_3035" sql='
+ )
+ md = QgsProviderRegistry.instance().providerMetadata("postgresraster")
decoded = md.decodeUri(uri)
- self.assertEqual(decoded, {
- 'key': 'rid',
- 'schema': 'public',
- 'service': 'qgis_test',
- 'srid': '3035',
- 'sslmode': QgsDataSourceUri.SslMode.SslDisable,
- 'table': 'raster_tiled_3035',
- })
+ self.assertEqual(
+ decoded,
+ {
+ "key": "rid",
+ "schema": "public",
+ "service": "qgis_test",
+ "srid": "3035",
+ "sslmode": QgsDataSourceUri.SslMode.SslDisable,
+ "table": "raster_tiled_3035",
+ },
+ )
_round_trip(uri)
- uri = self.dbconn + \
- ' sslmode=prefer key=\'rid\' srid=3035 temporalFieldIndex=2 temporalDefaultTime=2020-03-02 ' + \
- 'authcfg=afebeff username=\'my username\' password=\'my secret password=\' ' + \
- 'enableTime=true table="public"."raster_tiled_3035" (rast) sql="a_field" != 1223223'
+ uri = (
+ self.dbconn
+ + " sslmode=prefer key='rid' srid=3035 temporalFieldIndex=2 temporalDefaultTime=2020-03-02 "
+ + "authcfg=afebeff username='my username' password='my secret password=' "
+ + 'enableTime=true table="public"."raster_tiled_3035" (rast) sql="a_field" != 1223223'
+ )
_round_trip(uri)
decoded = md.decodeUri(uri)
- self.assertEqual(decoded, {
- 'authcfg': 'afebeff',
- 'enableTime': 'true',
- 'geometrycolumn': 'rast',
- 'key': 'rid',
- 'password': 'my secret password=',
- 'schema': 'public',
- 'service': 'qgis_test',
- 'sql': '"a_field" != 1223223',
- 'srid': '3035',
- 'sslmode': QgsDataSourceUri.SslMode.SslPrefer,
- 'table': 'raster_tiled_3035',
- 'temporalDefaultTime':
- '2020-03-02',
- 'temporalFieldIndex': '2',
- 'username': 'my username',
- })
+ self.assertEqual(
+ decoded,
+ {
+ "authcfg": "afebeff",
+ "enableTime": "true",
+ "geometrycolumn": "rast",
+ "key": "rid",
+ "password": "my secret password=",
+ "schema": "public",
+ "service": "qgis_test",
+ "sql": '"a_field" != 1223223',
+ "srid": "3035",
+ "sslmode": QgsDataSourceUri.SslMode.SslPrefer,
+ "table": "raster_tiled_3035",
+ "temporalDefaultTime": "2020-03-02",
+ "temporalFieldIndex": "2",
+ "username": "my username",
+ },
+ )
def testInt16(self):
"""Test regression https://github.com/qgis/QGIS/issues/36689"""
rl = QgsRasterLayer(
- self.dbconn + " sslmode=disable table={table} schema={schema}".format(
- table='int16_regression_36689', schema='public'), 'pg_layer', 'postgresraster')
+ self.dbconn
+ + " sslmode=disable table={table} schema={schema}".format(
+ table="int16_regression_36689", schema="public"
+ ),
+ "pg_layer",
+ "postgresraster",
+ )
self.assertTrue(rl.isValid())
block = rl.dataProvider().block(1, rl.extent(), 6, 6)
@@ -499,8 +654,47 @@ def testInt16(self):
for j in range(6):
data.append(int(block.value(i, j)))
- self.assertEqual(data, [55, 52, 46, 39, 33, 30, 58, 54, 49, 45, 41, 37, 58, 54, 50,
- 47, 45, 43, 54, 51, 49, 47, 46, 44, 47, 47, 47, 47, 46, 45, 41, 43, 45, 48, 49, 46])
+ self.assertEqual(
+ data,
+ [
+ 55,
+ 52,
+ 46,
+ 39,
+ 33,
+ 30,
+ 58,
+ 54,
+ 49,
+ 45,
+ 41,
+ 37,
+ 58,
+ 54,
+ 50,
+ 47,
+ 45,
+ 43,
+ 54,
+ 51,
+ 49,
+ 47,
+ 46,
+ 44,
+ 47,
+ 47,
+ 47,
+ 47,
+ 46,
+ 45,
+ 41,
+ 43,
+ 45,
+ 48,
+ 49,
+ 46,
+ ],
+ )
def testNegativeScaleY(self):
"""Test regression https://github.com/qgis/QGIS/issues/37968
@@ -508,51 +702,131 @@ def testNegativeScaleY(self):
"""
rl = QgsRasterLayer(
- self.dbconn + " sslmode=disable table={table} schema={schema}".format(
- table='bug_37968_dem_linear_cdn_extract', schema='public'), 'pg_layer', 'postgresraster')
+ self.dbconn
+ + " sslmode=disable table={table} schema={schema}".format(
+ table="bug_37968_dem_linear_cdn_extract", schema="public"
+ ),
+ "pg_layer",
+ "postgresraster",
+ )
self.assertTrue(rl.isValid())
- self.assertTrue(compareWkt(rl.extent().asWktPolygon(
- ), 'POLYGON((-40953 170588, -40873 170588, -40873 170668, -40953 170668, -40953 170588))', 1))
+ self.assertTrue(
+ compareWkt(
+ rl.extent().asWktPolygon(),
+ "POLYGON((-40953 170588, -40873 170588, -40873 170668, -40953 170668, -40953 170588))",
+ 1,
+ )
+ )
block = rl.dataProvider().block(1, rl.extent(), 6, 6)
data = []
for i in range(6):
for j in range(6):
data.append(int(block.value(i, j)))
- self.assertEqual(data, [52, 52, 52, 52, 44, 43, 52, 52, 52, 48, 44, 44, 49, 52, 49, 44, 44, 44, 43, 47, 46, 44, 44, 44, 42, 42, 43, 44, 44, 48, 42, 43, 43, 44, 44, 47])
+ self.assertEqual(
+ data,
+ [
+ 52,
+ 52,
+ 52,
+ 52,
+ 44,
+ 43,
+ 52,
+ 52,
+ 52,
+ 48,
+ 44,
+ 44,
+ 49,
+ 52,
+ 49,
+ 44,
+ 44,
+ 44,
+ 43,
+ 47,
+ 46,
+ 44,
+ 44,
+ 44,
+ 42,
+ 42,
+ 43,
+ 44,
+ 44,
+ 48,
+ 42,
+ 43,
+ 43,
+ 44,
+ 44,
+ 47,
+ ],
+ )
def testUntiledMosaicNoMetadata(self):
"""Test regression https://github.com/qgis/QGIS/issues/39017
- +-----------+------------------------------+
- | | |
- | rid = 1 | rid = 2 |
- | | |
- +-----------+------------------------------+
+ +-----------+------------------------------+
+ | | |
+ | rid = 1 | rid = 2 |
+ | | |
+ +-----------+------------------------------+
"""
rl = QgsRasterLayer(
- self.dbconn + " sslmode=disable table={table} schema={schema}".format(
- table='bug_39017_untiled_no_metadata', schema='public'), 'pg_layer', 'postgresraster')
+ self.dbconn
+ + " sslmode=disable table={table} schema={schema}".format(
+ table="bug_39017_untiled_no_metadata", schema="public"
+ ),
+ "pg_layer",
+ "postgresraster",
+ )
self.assertTrue(rl.isValid())
- self.assertTrue(compareWkt(rl.extent().asWktPolygon(
- ), 'POLYGON((47.061 40.976, 47.123 40.976, 47.123 41.000, 47.061 41.000, 47.061 40.976))', 0.01))
+ self.assertTrue(
+ compareWkt(
+ rl.extent().asWktPolygon(),
+ "POLYGON((47.061 40.976, 47.123 40.976, 47.123 41.000, 47.061 41.000, 47.061 40.976))",
+ 0.01,
+ )
+ )
rl1 = QgsRasterLayer(
- self.dbconn + " sslmode=disable table={table} schema={schema} sql=\"rid\"=1".format(
- table='bug_39017_untiled_no_metadata', schema='public'), 'pg_layer', 'postgresraster')
+ self.dbconn
+ + ' sslmode=disable table={table} schema={schema} sql="rid"=1'.format(
+ table="bug_39017_untiled_no_metadata", schema="public"
+ ),
+ "pg_layer",
+ "postgresraster",
+ )
self.assertTrue(rl1.isValid())
- self.assertTrue(compareWkt(rl1.extent().asWktPolygon(
- ), 'POLYGON((47.061 40.976, 47.070 40.976, 47.070 41.000, 47.061 41.000, 47.061 40.976))', 0.01))
+ self.assertTrue(
+ compareWkt(
+ rl1.extent().asWktPolygon(),
+ "POLYGON((47.061 40.976, 47.070 40.976, 47.070 41.000, 47.061 41.000, 47.061 40.976))",
+ 0.01,
+ )
+ )
rl2 = QgsRasterLayer(
- self.dbconn + " sslmode=disable table={table} schema={schema} sql=\"rid\"=2".format(
- table='bug_39017_untiled_no_metadata', schema='public'), 'pg_layer', 'postgresraster')
+ self.dbconn
+ + ' sslmode=disable table={table} schema={schema} sql="rid"=2'.format(
+ table="bug_39017_untiled_no_metadata", schema="public"
+ ),
+ "pg_layer",
+ "postgresraster",
+ )
self.assertTrue(rl2.isValid())
- self.assertTrue(compareWkt(rl2.extent().asWktPolygon(
- ), 'POLYGON((47.061 40.976, 47.123 40.976, 47.123 41.000, 47.070 41.000, 47.070 40.976))', 0.01))
+ self.assertTrue(
+ compareWkt(
+ rl2.extent().asWktPolygon(),
+ "POLYGON((47.061 40.976, 47.123 40.976, 47.123 41.000, 47.070 41.000, 47.070 40.976))",
+ 0.01,
+ )
+ )
extent_1 = rl1.extent()
extent_2 = rl2.extent()
@@ -577,8 +851,13 @@ def testView(self):
"""Test issue GH #50841"""
rl = QgsRasterLayer(
- self.dbconn + " key=\'rid\' srid=3035 sslmode=disable table={table} schema={schema}".format(
- table='raster_tiled_3035_view', schema='public'), 'pg_layer', 'postgresraster')
+ self.dbconn
+ + " key='rid' srid=3035 sslmode=disable table={table} schema={schema}".format(
+ table="raster_tiled_3035_view", schema="public"
+ ),
+ "pg_layer",
+ "postgresraster",
+ )
self.assertTrue(rl.isValid())
@@ -586,7 +865,7 @@ def testSparseRaster(self):
"""Test issue GH #55753"""
project: QgsProject = QgsProject.instance()
canvas: QgsMapCanvas = self.iface.mapCanvas()
- project.setCrs(QgsCoordinateReferenceSystem('EPSG:3035'))
+ project.setCrs(QgsCoordinateReferenceSystem("EPSG:3035"))
canvas.setExtent(QgsRectangle(4080050, 2430625, 4080200, 2430750))
bridge = QgsLayerTreeMapCanvasBridge( # noqa: F841, this needs to be assigned
@@ -594,11 +873,21 @@ def testSparseRaster(self):
)
rl = QgsRasterLayer(
- self.dbconn + " sslmode=disable table={table} schema={schema}".format(
- table='raster_sparse_3035', schema='public'), 'pg_layer', 'postgresraster')
+ self.dbconn
+ + " sslmode=disable table={table} schema={schema}".format(
+ table="raster_sparse_3035", schema="public"
+ ),
+ "pg_layer",
+ "postgresraster",
+ )
self.assertTrue(rl.isValid())
- self.assertTrue(compareWkt(rl.extent().asWktPolygon(
- ), 'POLYGON((4080050 2430625, 4080326 2430625, 4080326 2430855, 4080050 2430855, 4080050 2430625))', 0.01))
+ self.assertTrue(
+ compareWkt(
+ rl.extent().asWktPolygon(),
+ "POLYGON((4080050 2430625, 4080326 2430625, 4080326 2430855, 4080050 2430855, 4080050 2430625))",
+ 0.01,
+ )
+ )
app_log = QgsApplication.messageLog()
log_spy = QSignalSpy(app_log.messageReceived)
@@ -616,8 +905,13 @@ def testSparseRaster(self):
project.removeMapLayer(rl.id())
rl2 = QgsRasterLayer(
- self.dbconn + " sslmode=disable table={table} schema={schema}".format(
- table='raster_sparse_3035', schema='public'), 'pg_layer', 'postgresraster')
+ self.dbconn
+ + " sslmode=disable table={table} schema={schema}".format(
+ table="raster_sparse_3035", schema="public"
+ ),
+ "pg_layer",
+ "postgresraster",
+ )
project.addMapLayer(rl2)
for _ in range(zoom_times):
@@ -626,21 +920,34 @@ def testSparseRaster(self):
time.sleep(sleep_time)
# Log should not contain any critical warnings
- critical_postgis_logs = list(filter(lambda log: log[2] == Qgis.MessageLevel.Critical and log[1] == "PostGIS", list(log_spy)))
+ critical_postgis_logs = list(
+ filter(
+ lambda log: log[2] == Qgis.MessageLevel.Critical
+ and log[1] == "PostGIS",
+ list(log_spy),
+ )
+ )
self.assertEqual(len(critical_postgis_logs), 0, list(log_spy))
def testSparseTiles(self):
"""Test issue GH #55784"""
rl = QgsRasterLayer(
- self.dbconn + " key=\'rid\' srid=3035 sslmode=disable table={table} schema={schema}".format(
- table='raster_sparse_3035', schema='public'), 'pg_layer', 'postgresraster')
+ self.dbconn
+ + " key='rid' srid=3035 sslmode=disable table={table} schema={schema}".format(
+ table="raster_sparse_3035", schema="public"
+ ),
+ "pg_layer",
+ "postgresraster",
+ )
self.assertTrue(rl.isValid())
dp = rl.dataProvider()
- r = dp.identify(QgsPointXY(4080317.72, 2430635.68), Qgis.RasterIdentifyFormat.Value).results()
+ r = dp.identify(
+ QgsPointXY(4080317.72, 2430635.68), Qgis.RasterIdentifyFormat.Value
+ ).results()
self.assertEqual(r[1], -9999.0)
# tile request returned no tiles, check nodata
@@ -669,8 +976,13 @@ def testBlockSize(self):
# untiled have blocksize == size
rl = QgsRasterLayer(
- self.dbconn + " sslmode=disable table={table} schema={schema} sql=\"pk\" = 2".format(
- table='raster_3035_untiled_multiple_rows', schema='public'), 'pg_layer', 'postgresraster')
+ self.dbconn
+ + ' sslmode=disable table={table} schema={schema} sql="pk" = 2'.format(
+ table="raster_3035_untiled_multiple_rows", schema="public"
+ ),
+ "pg_layer",
+ "postgresraster",
+ )
self.assertTrue(rl.isValid())
@@ -683,8 +995,13 @@ def testBlockSize(self):
# tiled have blocksize != size
rl = QgsRasterLayer(
- self.dbconn + " srid=3035 sslmode=disable table={table} schema={schema}".format(
- table='raster_3035_tiled_no_overviews', schema='public'), 'pg_layer', 'postgresraster')
+ self.dbconn
+ + " srid=3035 sslmode=disable table={table} schema={schema}".format(
+ table="raster_3035_tiled_no_overviews", schema="public"
+ ),
+ "pg_layer",
+ "postgresraster",
+ )
self.assertTrue(rl.isValid())
@@ -696,5 +1013,5 @@ def testBlockSize(self):
self.assertEqual(dp.yBlockSize(), 2)
-if __name__ == '__main__':
+if __name__ == "__main__":
unittest.main()
diff --git a/tests/src/python/test_provider_python.py b/tests/src/python/test_provider_python.py
index cb77d30547c0..f45bdf8129c0 100644
--- a/tests/src/python/test_provider_python.py
+++ b/tests/src/python/test_provider_python.py
@@ -7,9 +7,10 @@
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
"""
-__author__ = 'Alessandro Pasotti'
-__date__ = '2018-03-18'
-__copyright__ = 'Copyright 2018, The QGIS Project'
+
+__author__ = "Alessandro Pasotti"
+__date__ = "2018-03-18"
+__copyright__ = "Copyright 2018, The QGIS Project"
# -*- coding: utf-8 -*-
"""QGIS Unit tests for the py layerprovider.
@@ -19,9 +20,9 @@
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
"""
-__author__ = 'Matthias Kuhn'
-__date__ = '2015-04-23'
-__copyright__ = 'Copyright 2015, The QGIS Project'
+__author__ = "Matthias Kuhn"
+__date__ = "2015-04-23"
+__copyright__ = "Copyright 2015, The QGIS Project"
from qgis.PyQt.QtCore import QDate, QDateTime, QTime, QVariant
from qgis.core import (
@@ -56,28 +57,74 @@ class TestPyQgsPythonProvider(QgisTestCase, ProviderTestCase):
@classmethod
def createLayer(cls):
vl = QgsVectorLayer(
- 'Point?crs=epsg:4326&field=pk:integer&field=cnt:integer&field=name:string(0)&field=name2:string(0)&field=num_char:string&field=dt:datetime&field=date:date&field=time:time&key=pk',
- 'test', 'pythonprovider')
- assert (vl.isValid())
+ "Point?crs=epsg:4326&field=pk:integer&field=cnt:integer&field=name:string(0)&field=name2:string(0)&field=num_char:string&field=dt:datetime&field=date:date&field=time:time&key=pk",
+ "test",
+ "pythonprovider",
+ )
+ assert vl.isValid()
f1 = QgsFeature()
- f1.setAttributes([5, -200, NULL, 'NuLl', '5', QDateTime(QDate(2020, 5, 4), QTime(12, 13, 14)), QDate(2020, 5, 2), QTime(12, 13, 1)])
- f1.setGeometry(QgsGeometry.fromWkt('Point (-71.123 78.23)'))
+ f1.setAttributes(
+ [
+ 5,
+ -200,
+ NULL,
+ "NuLl",
+ "5",
+ QDateTime(QDate(2020, 5, 4), QTime(12, 13, 14)),
+ QDate(2020, 5, 2),
+ QTime(12, 13, 1),
+ ]
+ )
+ f1.setGeometry(QgsGeometry.fromWkt("Point (-71.123 78.23)"))
f2 = QgsFeature()
- f2.setAttributes([3, 300, 'Pear', 'PEaR', '3', NULL, NULL, NULL])
+ f2.setAttributes([3, 300, "Pear", "PEaR", "3", NULL, NULL, NULL])
f3 = QgsFeature()
- f3.setAttributes([1, 100, 'Orange', 'oranGe', '1', QDateTime(QDate(2020, 5, 3), QTime(12, 13, 14)), QDate(2020, 5, 3), QTime(12, 13, 14)])
- f3.setGeometry(QgsGeometry.fromWkt('Point (-70.332 66.33)'))
+ f3.setAttributes(
+ [
+ 1,
+ 100,
+ "Orange",
+ "oranGe",
+ "1",
+ QDateTime(QDate(2020, 5, 3), QTime(12, 13, 14)),
+ QDate(2020, 5, 3),
+ QTime(12, 13, 14),
+ ]
+ )
+ f3.setGeometry(QgsGeometry.fromWkt("Point (-70.332 66.33)"))
f4 = QgsFeature()
- f4.setAttributes([2, 200, 'Apple', 'Apple', '2', QDateTime(QDate(2020, 5, 4), QTime(12, 14, 14)), QDate(2020, 5, 4), QTime(12, 14, 14)])
- f4.setGeometry(QgsGeometry.fromWkt('Point (-68.2 70.8)'))
+ f4.setAttributes(
+ [
+ 2,
+ 200,
+ "Apple",
+ "Apple",
+ "2",
+ QDateTime(QDate(2020, 5, 4), QTime(12, 14, 14)),
+ QDate(2020, 5, 4),
+ QTime(12, 14, 14),
+ ]
+ )
+ f4.setGeometry(QgsGeometry.fromWkt("Point (-68.2 70.8)"))
f5 = QgsFeature()
- f5.setAttributes([4, 400, 'Honey', 'Honey', '4', QDateTime(QDate(2021, 5, 4), QTime(13, 13, 14)), QDate(2021, 5, 4), QTime(13, 13, 14)])
- f5.setGeometry(QgsGeometry.fromWkt('Point (-65.32 78.3)'))
+ f5.setAttributes(
+ [
+ 4,
+ 400,
+ "Honey",
+ "Honey",
+ "4",
+ QDateTime(QDate(2021, 5, 4), QTime(13, 13, 14)),
+ QDate(2021, 5, 4),
+ QTime(13, 13, 14),
+ ]
+ )
+ f5.setGeometry(QgsGeometry.fromWkt("Point (-65.32 78.3)"))
vl.dataProvider().addFeatures([f1, f2, f3, f4, f5])
return vl
@@ -85,35 +132,52 @@ def createLayer(cls):
@classmethod
def setUpClass(cls):
"""Run before all tests"""
- super(TestPyQgsPythonProvider, cls).setUpClass()
+ super().setUpClass()
# Register the provider
r = QgsProviderRegistry.instance()
- metadata = QgsProviderMetadata(PyProvider.providerKey(), PyProvider.description(), PyProvider.createProvider)
+ metadata = QgsProviderMetadata(
+ PyProvider.providerKey(),
+ PyProvider.description(),
+ PyProvider.createProvider,
+ )
assert r.registerProvider(metadata)
assert r.providerMetadata(PyProvider.providerKey()) == metadata
# Create test layer
cls.vl = cls.createLayer()
- assert (cls.vl.isValid())
+ assert cls.vl.isValid()
cls.source = cls.vl.dataProvider()
# poly layer
- cls.poly_vl = QgsVectorLayer('Polygon?crs=epsg:4326&field=pk:integer&key=pk',
- 'test', 'pythonprovider')
- assert (cls.poly_vl.isValid())
+ cls.poly_vl = QgsVectorLayer(
+ "Polygon?crs=epsg:4326&field=pk:integer&key=pk", "test", "pythonprovider"
+ )
+ assert cls.poly_vl.isValid()
cls.poly_provider = cls.poly_vl.dataProvider()
f1 = QgsFeature()
f1.setAttributes([1])
- f1.setGeometry(QgsGeometry.fromWkt('Polygon ((-69.03664108 81.35818902, -69.09237722 80.24346619, -73.718477 80.1319939, -73.718477 76.28620011, -74.88893598 76.34193625, -74.83319983 81.35818902, -69.03664108 81.35818902))'))
+ f1.setGeometry(
+ QgsGeometry.fromWkt(
+ "Polygon ((-69.03664108 81.35818902, -69.09237722 80.24346619, -73.718477 80.1319939, -73.718477 76.28620011, -74.88893598 76.34193625, -74.83319983 81.35818902, -69.03664108 81.35818902))"
+ )
+ )
f2 = QgsFeature()
f2.setAttributes([2])
- f2.setGeometry(QgsGeometry.fromWkt('Polygon ((-67.58750139 81.1909806, -66.30557012 81.24671674, -66.30557012 76.89929767, -67.58750139 76.89929767, -67.58750139 81.1909806))'))
+ f2.setGeometry(
+ QgsGeometry.fromWkt(
+ "Polygon ((-67.58750139 81.1909806, -66.30557012 81.24671674, -66.30557012 76.89929767, -67.58750139 76.89929767, -67.58750139 81.1909806))"
+ )
+ )
f3 = QgsFeature()
f3.setAttributes([3])
- f3.setGeometry(QgsGeometry.fromWkt('Polygon ((-68.36780737 75.78457483, -67.53176524 72.60761475, -68.64648808 73.66660144, -70.20710006 72.9420316, -68.36780737 75.78457483))'))
+ f3.setGeometry(
+ QgsGeometry.fromWkt(
+ "Polygon ((-68.36780737 75.78457483, -67.53176524 72.60761475, -68.64648808 73.66660144, -70.20710006 72.9420316, -68.36780737 75.78457483))"
+ )
+ )
f4 = QgsFeature()
f4.setAttributes([4])
@@ -124,13 +188,13 @@ def getEditableLayer(self):
return self.createLayer()
def testGetFeaturesSubsetAttributes2(self):
- """ Override and skip this test for pythonprovider provider, as it's actually more efficient for the pythonprovider provider to return
+ """Override and skip this test for pythonprovider provider, as it's actually more efficient for the pythonprovider provider to return
its features as direct copies (due to implicit sharing of QgsFeature)
"""
pass
def testGetFeaturesNoGeometry(self):
- """ Override and skip this test for pythonprovider provider, as it's actually more efficient for the pythonprovider provider to return
+ """Override and skip this test for pythonprovider provider, as it's actually more efficient for the pythonprovider provider to return
its features as direct copies (due to implicit sharing of QgsFeature)
"""
pass
@@ -140,75 +204,199 @@ def testGetFeaturesDestinationCrs(self):
super().testGetFeaturesDestinationCrs()
def testCtors(self):
- testVectors = ["Point", "LineString", "Polygon", "MultiPoint", "MultiLineString", "MultiPolygon", "None"]
+ testVectors = [
+ "Point",
+ "LineString",
+ "Polygon",
+ "MultiPoint",
+ "MultiLineString",
+ "MultiPolygon",
+ "None",
+ ]
for v in testVectors:
layer = QgsVectorLayer(v, "test", "pythonprovider")
assert layer.isValid(), f"Failed to create valid {v} pythonprovider layer"
def testLayerGeometry(self):
- testVectors = [("Point", QgsWkbTypes.GeometryType.PointGeometry, QgsWkbTypes.Type.Point),
- ("LineString", QgsWkbTypes.GeometryType.LineGeometry, QgsWkbTypes.Type.LineString),
- ("Polygon", QgsWkbTypes.GeometryType.PolygonGeometry, QgsWkbTypes.Type.Polygon),
- ("MultiPoint", QgsWkbTypes.GeometryType.PointGeometry, QgsWkbTypes.Type.MultiPoint),
- ("MultiLineString", QgsWkbTypes.GeometryType.LineGeometry, QgsWkbTypes.Type.MultiLineString),
- ("MultiPolygon", QgsWkbTypes.GeometryType.PolygonGeometry, QgsWkbTypes.Type.MultiPolygon),
- ("PointZ", QgsWkbTypes.GeometryType.PointGeometry, QgsWkbTypes.Type.PointZ),
- ("LineStringZ", QgsWkbTypes.GeometryType.LineGeometry, QgsWkbTypes.Type.LineStringZ),
- ("PolygonZ", QgsWkbTypes.GeometryType.PolygonGeometry, QgsWkbTypes.Type.PolygonZ),
- ("MultiPointZ", QgsWkbTypes.GeometryType.PointGeometry, QgsWkbTypes.Type.MultiPointZ),
- ("MultiLineStringZ", QgsWkbTypes.GeometryType.LineGeometry, QgsWkbTypes.Type.MultiLineStringZ),
- ("MultiPolygonZ", QgsWkbTypes.GeometryType.PolygonGeometry, QgsWkbTypes.Type.MultiPolygonZ),
- ("PointM", QgsWkbTypes.GeometryType.PointGeometry, QgsWkbTypes.Type.PointM),
- ("LineStringM", QgsWkbTypes.GeometryType.LineGeometry, QgsWkbTypes.Type.LineStringM),
- ("PolygonM", QgsWkbTypes.GeometryType.PolygonGeometry, QgsWkbTypes.Type.PolygonM),
- ("MultiPointM", QgsWkbTypes.GeometryType.PointGeometry, QgsWkbTypes.Type.MultiPointM),
- ("MultiLineStringM", QgsWkbTypes.GeometryType.LineGeometry, QgsWkbTypes.Type.MultiLineStringM),
- ("MultiPolygonM", QgsWkbTypes.GeometryType.PolygonGeometry, QgsWkbTypes.Type.MultiPolygonM),
- ("PointZM", QgsWkbTypes.GeometryType.PointGeometry, QgsWkbTypes.Type.PointZM),
- ("LineStringZM", QgsWkbTypes.GeometryType.LineGeometry, QgsWkbTypes.Type.LineStringZM),
- ("PolygonZM", QgsWkbTypes.GeometryType.PolygonGeometry, QgsWkbTypes.Type.PolygonZM),
- ("MultiPointZM", QgsWkbTypes.GeometryType.PointGeometry, QgsWkbTypes.Type.MultiPointZM),
- ("MultiLineStringZM", QgsWkbTypes.GeometryType.LineGeometry, QgsWkbTypes.Type.MultiLineStringZM),
- ("MultiPolygonZM", QgsWkbTypes.GeometryType.PolygonGeometry, QgsWkbTypes.Type.MultiPolygonZM),
- ("Point25D", QgsWkbTypes.GeometryType.PointGeometry, QgsWkbTypes.Type.Point25D),
- ("LineString25D", QgsWkbTypes.GeometryType.LineGeometry, QgsWkbTypes.Type.LineString25D),
- ("Polygon25D", QgsWkbTypes.GeometryType.PolygonGeometry, QgsWkbTypes.Type.Polygon25D),
- ("MultiPoint25D", QgsWkbTypes.GeometryType.PointGeometry, QgsWkbTypes.Type.MultiPoint25D),
- ("MultiLineString25D", QgsWkbTypes.GeometryType.LineGeometry, QgsWkbTypes.Type.MultiLineString25D),
- ("MultiPolygon25D", QgsWkbTypes.GeometryType.PolygonGeometry, QgsWkbTypes.Type.MultiPolygon25D),
- ("None", QgsWkbTypes.GeometryType.NullGeometry, QgsWkbTypes.Type.NoGeometry)]
+ testVectors = [
+ ("Point", QgsWkbTypes.GeometryType.PointGeometry, QgsWkbTypes.Type.Point),
+ (
+ "LineString",
+ QgsWkbTypes.GeometryType.LineGeometry,
+ QgsWkbTypes.Type.LineString,
+ ),
+ (
+ "Polygon",
+ QgsWkbTypes.GeometryType.PolygonGeometry,
+ QgsWkbTypes.Type.Polygon,
+ ),
+ (
+ "MultiPoint",
+ QgsWkbTypes.GeometryType.PointGeometry,
+ QgsWkbTypes.Type.MultiPoint,
+ ),
+ (
+ "MultiLineString",
+ QgsWkbTypes.GeometryType.LineGeometry,
+ QgsWkbTypes.Type.MultiLineString,
+ ),
+ (
+ "MultiPolygon",
+ QgsWkbTypes.GeometryType.PolygonGeometry,
+ QgsWkbTypes.Type.MultiPolygon,
+ ),
+ ("PointZ", QgsWkbTypes.GeometryType.PointGeometry, QgsWkbTypes.Type.PointZ),
+ (
+ "LineStringZ",
+ QgsWkbTypes.GeometryType.LineGeometry,
+ QgsWkbTypes.Type.LineStringZ,
+ ),
+ (
+ "PolygonZ",
+ QgsWkbTypes.GeometryType.PolygonGeometry,
+ QgsWkbTypes.Type.PolygonZ,
+ ),
+ (
+ "MultiPointZ",
+ QgsWkbTypes.GeometryType.PointGeometry,
+ QgsWkbTypes.Type.MultiPointZ,
+ ),
+ (
+ "MultiLineStringZ",
+ QgsWkbTypes.GeometryType.LineGeometry,
+ QgsWkbTypes.Type.MultiLineStringZ,
+ ),
+ (
+ "MultiPolygonZ",
+ QgsWkbTypes.GeometryType.PolygonGeometry,
+ QgsWkbTypes.Type.MultiPolygonZ,
+ ),
+ ("PointM", QgsWkbTypes.GeometryType.PointGeometry, QgsWkbTypes.Type.PointM),
+ (
+ "LineStringM",
+ QgsWkbTypes.GeometryType.LineGeometry,
+ QgsWkbTypes.Type.LineStringM,
+ ),
+ (
+ "PolygonM",
+ QgsWkbTypes.GeometryType.PolygonGeometry,
+ QgsWkbTypes.Type.PolygonM,
+ ),
+ (
+ "MultiPointM",
+ QgsWkbTypes.GeometryType.PointGeometry,
+ QgsWkbTypes.Type.MultiPointM,
+ ),
+ (
+ "MultiLineStringM",
+ QgsWkbTypes.GeometryType.LineGeometry,
+ QgsWkbTypes.Type.MultiLineStringM,
+ ),
+ (
+ "MultiPolygonM",
+ QgsWkbTypes.GeometryType.PolygonGeometry,
+ QgsWkbTypes.Type.MultiPolygonM,
+ ),
+ (
+ "PointZM",
+ QgsWkbTypes.GeometryType.PointGeometry,
+ QgsWkbTypes.Type.PointZM,
+ ),
+ (
+ "LineStringZM",
+ QgsWkbTypes.GeometryType.LineGeometry,
+ QgsWkbTypes.Type.LineStringZM,
+ ),
+ (
+ "PolygonZM",
+ QgsWkbTypes.GeometryType.PolygonGeometry,
+ QgsWkbTypes.Type.PolygonZM,
+ ),
+ (
+ "MultiPointZM",
+ QgsWkbTypes.GeometryType.PointGeometry,
+ QgsWkbTypes.Type.MultiPointZM,
+ ),
+ (
+ "MultiLineStringZM",
+ QgsWkbTypes.GeometryType.LineGeometry,
+ QgsWkbTypes.Type.MultiLineStringZM,
+ ),
+ (
+ "MultiPolygonZM",
+ QgsWkbTypes.GeometryType.PolygonGeometry,
+ QgsWkbTypes.Type.MultiPolygonZM,
+ ),
+ (
+ "Point25D",
+ QgsWkbTypes.GeometryType.PointGeometry,
+ QgsWkbTypes.Type.Point25D,
+ ),
+ (
+ "LineString25D",
+ QgsWkbTypes.GeometryType.LineGeometry,
+ QgsWkbTypes.Type.LineString25D,
+ ),
+ (
+ "Polygon25D",
+ QgsWkbTypes.GeometryType.PolygonGeometry,
+ QgsWkbTypes.Type.Polygon25D,
+ ),
+ (
+ "MultiPoint25D",
+ QgsWkbTypes.GeometryType.PointGeometry,
+ QgsWkbTypes.Type.MultiPoint25D,
+ ),
+ (
+ "MultiLineString25D",
+ QgsWkbTypes.GeometryType.LineGeometry,
+ QgsWkbTypes.Type.MultiLineString25D,
+ ),
+ (
+ "MultiPolygon25D",
+ QgsWkbTypes.GeometryType.PolygonGeometry,
+ QgsWkbTypes.Type.MultiPolygon25D,
+ ),
+ (
+ "None",
+ QgsWkbTypes.GeometryType.NullGeometry,
+ QgsWkbTypes.Type.NoGeometry,
+ ),
+ ]
for v in testVectors:
layer = QgsVectorLayer(v[0], "test", "pythonprovider")
- myMessage = f'Expected: {v[1]}\nGot: {layer.geometryType()}\n'
+ myMessage = f"Expected: {v[1]}\nGot: {layer.geometryType()}\n"
assert layer.geometryType() == v[1], myMessage
- myMessage = f'Expected: {v[2]}\nGot: {layer.wkbType()}\n'
+ myMessage = f"Expected: {v[2]}\nGot: {layer.wkbType()}\n"
assert layer.wkbType() == v[2], myMessage
def testAddFeatures(self):
layer = QgsVectorLayer("Point", "test", "pythonprovider")
provider = layer.dataProvider()
- res = provider.addAttributes([QgsField("name", QVariant.String),
- QgsField("age", QVariant.Int),
- QgsField("size", QVariant.Double)])
+ res = provider.addAttributes(
+ [
+ QgsField("name", QVariant.String),
+ QgsField("age", QVariant.Int),
+ QgsField("size", QVariant.Double),
+ ]
+ )
assert res, "Failed to add attributes"
- myMessage = f'Expected: {3}\nGot: {len(provider.fields())}\n'
+ myMessage = f"Expected: {3}\nGot: {len(provider.fields())}\n"
assert len(provider.fields()) == 3, myMessage
ft = QgsFeature()
ft.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(10, 10)))
- ft.setAttributes(["Johny",
- 20,
- 0.3])
+ ft.setAttributes(["Johny", 20, 0.3])
res, t = provider.addFeatures([ft])
assert res, "Failed to add feature"
- myMessage = f'Expected: {1}\nGot: {provider.featureCount()}\n'
+ myMessage = f"Expected: {1}\nGot: {provider.featureCount()}\n"
assert provider.featureCount() == 1, myMessage
for f in provider.getFeatures(QgsFeatureRequest()):
@@ -216,11 +404,11 @@ def testAddFeatures(self):
assert f[0] == "Johny", myMessage
- myMessage = f'Expected: {20}\nGot: {f[1]}\n'
+ myMessage = f"Expected: {20}\nGot: {f[1]}\n"
assert f[1] == 20, myMessage
- myMessage = f'Expected: {0.3}\nGot: {f[2]}\n'
+ myMessage = f"Expected: {0.3}\nGot: {f[2]}\n"
assert (f[2] - 0.3) < 0.0000001, myMessage
@@ -234,18 +422,20 @@ def testGetFields(self):
layer = QgsVectorLayer("Point", "test", "pythonprovider")
provider = layer.dataProvider()
- provider.addAttributes([QgsField("name", QVariant.String),
- QgsField("age", QVariant.Int),
- QgsField("size", QVariant.Double)])
- myMessage = f'Expected: {3}\nGot: {len(provider.fields())}\n'
+ provider.addAttributes(
+ [
+ QgsField("name", QVariant.String),
+ QgsField("age", QVariant.Int),
+ QgsField("size", QVariant.Double),
+ ]
+ )
+ myMessage = f"Expected: {3}\nGot: {len(provider.fields())}\n"
assert len(provider.fields()) == 3, myMessage
ft = QgsFeature()
ft.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(10, 10)))
- ft.setAttributes(["Johny",
- 20,
- 0.3])
+ ft.setAttributes(["Johny", 20, 0.3])
provider.addFeatures([ft])
for f in provider.getFeatures(QgsFeatureRequest()):
@@ -256,41 +446,46 @@ def testGetFields(self):
def testFromUri(self):
"""Test we can construct the mem provider from a uri"""
myPyLayer = QgsVectorLayer(
- ('Point?crs=epsg:4326&field=name:string(20)&'
- 'field=age:integer&field=size:double&index=yes'),
- 'test',
- 'pythonprovider')
-
- assert myPyLayer is not None, 'Provider not initialized'
+ (
+ "Point?crs=epsg:4326&field=name:string(20)&"
+ "field=age:integer&field=size:double&index=yes"
+ ),
+ "test",
+ "pythonprovider",
+ )
+
+ assert myPyLayer is not None, "Provider not initialized"
myProvider = myPyLayer.dataProvider()
assert myProvider is not None
def testLengthPrecisionFromUri(self):
"""Test we can assign length and precision from a uri"""
myPyLayer = QgsVectorLayer(
- ('Point?crs=epsg:4326&field=size:double(12,9)&index=yes'),
- 'test',
- 'pythonprovider')
+ ("Point?crs=epsg:4326&field=size:double(12,9)&index=yes"),
+ "test",
+ "pythonprovider",
+ )
- self.assertEqual(myPyLayer.fields().field('size').length(), 12)
- self.assertEqual(myPyLayer.fields().field('size').precision(), 9)
+ self.assertEqual(myPyLayer.fields().field("size").length(), 12)
+ self.assertEqual(myPyLayer.fields().field("size").precision(), 9)
@QgisTestCase.expectedFailure("Handled layers are hardcoded")
def testSaveFields(self):
# Create a new py layerwith no fields
myPyLayer = QgsVectorLayer(
- ('Point?crs=epsg:4326&index=yes'),
- 'test',
- 'pythonprovider')
+ ("Point?crs=epsg:4326&index=yes"), "test", "pythonprovider"
+ )
# Add some fields to the layer
- myFields = [QgsField('TestInt', QVariant.Int, 'integer', 2, 0),
- QgsField('TestLong', QVariant.LongLong, 'long', -1, 0),
- QgsField('TestDbl', QVariant.Double, 'double', 8, 6),
- QgsField('TestString', QVariant.String, 'string', 50, 0),
- QgsField('TestDate', QVariant.Date, 'date'),
- QgsField('TestTime', QVariant.Time, 'time'),
- QgsField('TestDateTime', QVariant.DateTime, 'datetime')]
+ myFields = [
+ QgsField("TestInt", QVariant.Int, "integer", 2, 0),
+ QgsField("TestLong", QVariant.LongLong, "long", -1, 0),
+ QgsField("TestDbl", QVariant.Double, "double", 8, 6),
+ QgsField("TestString", QVariant.String, "string", 50, 0),
+ QgsField("TestDate", QVariant.Date, "date"),
+ QgsField("TestTime", QVariant.Time, "time"),
+ QgsField("TestDateTime", QVariant.DateTime, "datetime"),
+ ]
assert myPyLayer.startEditing()
for f in myFields:
assert myPyLayer.addAttribute(f)
@@ -298,11 +493,15 @@ def testSaveFields(self):
myPyLayer.updateFields()
# Export the layer to a layer-definition-XML
- qlr = QgsLayerDefinition.exportLayerDefinitionLayers([myPyLayer], QgsReadWriteContext())
+ qlr = QgsLayerDefinition.exportLayerDefinitionLayers(
+ [myPyLayer], QgsReadWriteContext()
+ )
assert qlr is not None
# Import the layer from the layer-definition-XML
- layers = QgsLayerDefinition.loadLayerDefinitionLayers(qlr, QgsReadWriteContext())
+ layers = QgsLayerDefinition.loadLayerDefinitionLayers(
+ qlr, QgsReadWriteContext()
+ )
assert layers is not None
myImportedLayer = layers[0]
assert myImportedLayer is not None
@@ -317,48 +516,55 @@ def testRenameAttributes(self):
layer = QgsVectorLayer("Point", "test", "pythonprovider")
provider = layer.dataProvider()
- res = provider.addAttributes([QgsField("name", QVariant.String),
- QgsField("age", QVariant.Int),
- QgsField("size", QVariant.Double)])
+ res = provider.addAttributes(
+ [
+ QgsField("name", QVariant.String),
+ QgsField("age", QVariant.Int),
+ QgsField("size", QVariant.Double),
+ ]
+ )
layer.updateFields()
assert res, "Failed to add attributes"
ft = QgsFeature()
ft.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(10, 10)))
- ft.setAttributes(["Johny",
- 20,
- 0.3])
+ ft.setAttributes(["Johny", 20, 0.3])
res, t = provider.addFeatures([ft])
# bad rename
- self.assertFalse(provider.renameAttributes({-1: 'not_a_field'}))
- self.assertFalse(provider.renameAttributes({100: 'not_a_field'}))
+ self.assertFalse(provider.renameAttributes({-1: "not_a_field"}))
+ self.assertFalse(provider.renameAttributes({100: "not_a_field"}))
# already exists
- self.assertFalse(provider.renameAttributes({1: 'name'}))
+ self.assertFalse(provider.renameAttributes({1: "name"}))
# rename one field
- self.assertTrue(provider.renameAttributes({1: 'this_is_the_new_age'}))
- self.assertEqual(provider.fields().at(1).name(), 'this_is_the_new_age')
+ self.assertTrue(provider.renameAttributes({1: "this_is_the_new_age"}))
+ self.assertEqual(provider.fields().at(1).name(), "this_is_the_new_age")
layer.updateFields()
fet = next(layer.getFeatures())
- self.assertEqual(fet.fields()[1].name(), 'this_is_the_new_age')
+ self.assertEqual(fet.fields()[1].name(), "this_is_the_new_age")
# rename two fields
- self.assertTrue(provider.renameAttributes({1: 'mapinfo_is_the_stone_age', 2: 'super_size'}))
- self.assertEqual(provider.fields().at(1).name(), 'mapinfo_is_the_stone_age')
- self.assertEqual(provider.fields().at(2).name(), 'super_size')
+ self.assertTrue(
+ provider.renameAttributes({1: "mapinfo_is_the_stone_age", 2: "super_size"})
+ )
+ self.assertEqual(provider.fields().at(1).name(), "mapinfo_is_the_stone_age")
+ self.assertEqual(provider.fields().at(2).name(), "super_size")
layer.updateFields()
fet = next(layer.getFeatures())
- self.assertEqual(fet.fields()[1].name(), 'mapinfo_is_the_stone_age')
- self.assertEqual(fet.fields()[2].name(), 'super_size')
+ self.assertEqual(fet.fields()[1].name(), "mapinfo_is_the_stone_age")
+ self.assertEqual(fet.fields()[2].name(), "super_size")
def testThreadSafetyWithIndex(self):
- layer = QgsVectorLayer('Point?crs=epsg:4326&index=yes&field=pk:integer&field=cnt:int8&field=name:string(0)&field=name2:string(0)&field=num_char:string&key=pk',
- 'test', 'pythonprovider')
+ layer = QgsVectorLayer(
+ "Point?crs=epsg:4326&index=yes&field=pk:integer&field=cnt:int8&field=name:string(0)&field=name2:string(0)&field=num_char:string&key=pk",
+ "test",
+ "pythonprovider",
+ )
provider = layer.dataProvider()
f = QgsFeature()
- f.setAttributes([5, -200, NULL, 'NuLl', '5'])
- f.setGeometry(QgsGeometry.fromWkt('Point (-71.123 78.23)'))
+ f.setAttributes([5, -200, NULL, "NuLl", "5"])
+ f.setGeometry(QgsGeometry.fromWkt("Point (-71.123 78.23)"))
for i in range(100000):
provider.addFeatures([f])
@@ -366,12 +572,18 @@ def testThreadSafetyWithIndex(self):
# filter rect request
extent = QgsRectangle(-73, 70, -63, 80)
request = QgsFeatureRequest().setFilterRect(extent)
- self.assertTrue(QgsTestUtils.testProviderIteratorThreadSafety(self.source, request))
+ self.assertTrue(
+ QgsTestUtils.testProviderIteratorThreadSafety(self.source, request)
+ )
def tesRegisterSameProviderTwice(self):
"""Test that a provider cannot be registered twice"""
r = QgsProviderRegistry.instance()
- metadata = QgsProviderMetadata(PyProvider.providerKey(), PyProvider.description(), PyProvider.createProvider)
+ metadata = QgsProviderMetadata(
+ PyProvider.providerKey(),
+ PyProvider.description(),
+ PyProvider.createProvider,
+ )
self.assertFalse(r.registerProvider(metadata))
def testGetFeaturesFromProvider(self):
@@ -380,12 +592,16 @@ def testGetFeaturesFromProvider(self):
result should be the same...
"""
layer = self.createLayer()
- provider_features = {f.id(): f.attributes() for f in layer.dataProvider().getFeatures()}
+ provider_features = {
+ f.id(): f.attributes() for f in layer.dataProvider().getFeatures()
+ }
self.assertTrue(provider_features)
- layer_features = {f.id(): f.attributes() for f in layer.dataProvider().getFeatures()}
+ layer_features = {
+ f.id(): f.attributes() for f in layer.dataProvider().getFeatures()
+ }
self.assertTrue(layer_features)
self.assertEqual(provider_features, layer_features)
-if __name__ == '__main__':
+if __name__ == "__main__":
unittest.main()
diff --git a/tests/src/python/test_provider_sensorthings.py b/tests/src/python/test_provider_sensorthings.py
index bf8b55b2147a..0f27a5bf98d1 100644
--- a/tests/src/python/test_provider_sensorthings.py
+++ b/tests/src/python/test_provider_sensorthings.py
@@ -7,6 +7,7 @@
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
"""
+
__author__ = "Nyall Dawson"
__date__ = "2023-11-08"
@@ -23,19 +24,21 @@
QgsSensorThingsUtils,
QgsFeatureRequest,
QgsRectangle,
- QgsSensorThingsExpansionDefinition
+ QgsSensorThingsExpansionDefinition,
)
from qgis.testing import start_app, QgisTestCase
def sanitize(endpoint, x):
- for prefix in ('/Locations',
- '/HistoricalLocations',
- '/Things',
- '/FeaturesOfInterest',
- '/MultiDatastreams'):
+ for prefix in (
+ "/Locations",
+ "/HistoricalLocations",
+ "/Things",
+ "/FeaturesOfInterest",
+ "/MultiDatastreams",
+ ):
if x.startswith(prefix):
- x = x[len(prefix):]
+ x = x[len(prefix) :]
endpoint = endpoint + "_" + prefix[1:]
if len(endpoint + x) > 150:
@@ -58,7 +61,7 @@ class TestPyQgsSensorThingsProvider(QgisTestCase): # , ProviderTestCase):
@classmethod
def setUpClass(cls):
"""Run before all tests"""
- super(TestPyQgsSensorThingsProvider, cls).setUpClass()
+ super().setUpClass()
QCoreApplication.setOrganizationName("QGIS_Test")
QCoreApplication.setOrganizationDomain("TestPyQgsSensorThingsProvider.com")
@@ -86,24 +89,34 @@ def test_filter_for_wkb_type(self):
features with a desired WKB type
"""
self.assertEqual(
- QgsSensorThingsUtils.filterForWkbType(Qgis.SensorThingsEntity.Location, Qgis.WkbType.Point),
- "location/type eq 'Point' or location/geometry/type eq 'Point'"
+ QgsSensorThingsUtils.filterForWkbType(
+ Qgis.SensorThingsEntity.Location, Qgis.WkbType.Point
+ ),
+ "location/type eq 'Point' or location/geometry/type eq 'Point'",
)
self.assertEqual(
- QgsSensorThingsUtils.filterForWkbType(Qgis.SensorThingsEntity.Location, Qgis.WkbType.PointZ),
- "location/type eq 'Point' or location/geometry/type eq 'Point'"
+ QgsSensorThingsUtils.filterForWkbType(
+ Qgis.SensorThingsEntity.Location, Qgis.WkbType.PointZ
+ ),
+ "location/type eq 'Point' or location/geometry/type eq 'Point'",
)
self.assertEqual(
- QgsSensorThingsUtils.filterForWkbType(Qgis.SensorThingsEntity.FeatureOfInterest, Qgis.WkbType.Polygon),
- "feature/type eq 'Polygon' or feature/geometry/type eq 'Polygon'"
+ QgsSensorThingsUtils.filterForWkbType(
+ Qgis.SensorThingsEntity.FeatureOfInterest, Qgis.WkbType.Polygon
+ ),
+ "feature/type eq 'Polygon' or feature/geometry/type eq 'Polygon'",
)
self.assertEqual(
- QgsSensorThingsUtils.filterForWkbType(Qgis.SensorThingsEntity.Location, Qgis.WkbType.LineString),
- "location/type eq 'LineString' or location/geometry/type eq 'LineString'"
+ QgsSensorThingsUtils.filterForWkbType(
+ Qgis.SensorThingsEntity.Location, Qgis.WkbType.LineString
+ ),
+ "location/type eq 'LineString' or location/geometry/type eq 'LineString'",
)
self.assertEqual(
- QgsSensorThingsUtils.filterForWkbType(Qgis.SensorThingsEntity.MultiDatastream, Qgis.WkbType.Polygon),
- "observedArea/type eq 'Polygon' or observedArea/geometry/type eq 'Polygon'"
+ QgsSensorThingsUtils.filterForWkbType(
+ Qgis.SensorThingsEntity.MultiDatastream, Qgis.WkbType.Polygon
+ ),
+ "observedArea/type eq 'Polygon' or observedArea/geometry/type eq 'Polygon'",
)
def test_utils_string_to_entity(self):
@@ -192,18 +205,20 @@ def test_utils_string_to_entityset(self):
def test_utils_entity_to_set_string(self):
self.assertEqual(
QgsSensorThingsUtils.entityToSetString(Qgis.SensorThingsEntity.Invalid),
- '',
+ "",
)
self.assertEqual(
QgsSensorThingsUtils.entityToSetString(Qgis.SensorThingsEntity.Thing),
- "Things"
+ "Things",
)
self.assertEqual(
QgsSensorThingsUtils.entityToSetString(Qgis.SensorThingsEntity.Location),
"Locations",
)
self.assertEqual(
- QgsSensorThingsUtils.entityToSetString(Qgis.SensorThingsEntity.HistoricalLocation),
+ QgsSensorThingsUtils.entityToSetString(
+ Qgis.SensorThingsEntity.HistoricalLocation
+ ),
"HistoricalLocations",
)
self.assertEqual(
@@ -212,22 +227,28 @@ def test_utils_entity_to_set_string(self):
)
self.assertEqual(
QgsSensorThingsUtils.entityToSetString(Qgis.SensorThingsEntity.Sensor),
- "Sensors"
+ "Sensors",
)
self.assertEqual(
- QgsSensorThingsUtils.entityToSetString(Qgis.SensorThingsEntity.ObservedProperty),
+ QgsSensorThingsUtils.entityToSetString(
+ Qgis.SensorThingsEntity.ObservedProperty
+ ),
"ObservedProperties",
)
self.assertEqual(
QgsSensorThingsUtils.entityToSetString(Qgis.SensorThingsEntity.Observation),
- "Observations"
+ "Observations",
)
self.assertEqual(
- QgsSensorThingsUtils.entityToSetString(Qgis.SensorThingsEntity.FeatureOfInterest),
+ QgsSensorThingsUtils.entityToSetString(
+ Qgis.SensorThingsEntity.FeatureOfInterest
+ ),
"FeaturesOfInterest",
)
self.assertEqual(
- QgsSensorThingsUtils.entityToSetString(Qgis.SensorThingsEntity.MultiDatastream),
+ QgsSensorThingsUtils.entityToSetString(
+ Qgis.SensorThingsEntity.MultiDatastream
+ ),
"MultiDatastreams",
)
@@ -240,90 +261,149 @@ def test_expansion_definition(self):
self.assertFalse(expansion.asQueryString(Qgis.SensorThingsEntity.Invalid))
# test getters/setters
- expansion = QgsSensorThingsExpansionDefinition(Qgis.SensorThingsEntity.ObservedProperty)
+ expansion = QgsSensorThingsExpansionDefinition(
+ Qgis.SensorThingsEntity.ObservedProperty
+ )
self.assertTrue(expansion.isValid())
- self.assertEqual(expansion.childEntity(), Qgis.SensorThingsEntity.ObservedProperty)
+ self.assertEqual(
+ expansion.childEntity(), Qgis.SensorThingsEntity.ObservedProperty
+ )
self.assertEqual(expansion.limit(), 100)
self.assertFalse(expansion.filter())
- self.assertEqual(repr(expansion), '')
- self.assertEqual(expansion.asQueryString(Qgis.SensorThingsEntity.Datastream), '$expand=ObservedProperty($top=100)')
- self.assertEqual(expansion.asQueryString(Qgis.SensorThingsEntity.Datastream, ['$expand=Locations($top=101)']),
- '$expand=ObservedProperty($top=100;$expand=Locations($top=101))')
+ self.assertEqual(
+ repr(expansion),
+ "",
+ )
+ self.assertEqual(
+ expansion.asQueryString(Qgis.SensorThingsEntity.Datastream),
+ "$expand=ObservedProperty($top=100)",
+ )
+ self.assertEqual(
+ expansion.asQueryString(
+ Qgis.SensorThingsEntity.Datastream, ["$expand=Locations($top=101)"]
+ ),
+ "$expand=ObservedProperty($top=100;$expand=Locations($top=101))",
+ )
expansion.setChildEntity(Qgis.SensorThingsEntity.Location)
- self.assertEqual(expansion.childEntity(),
- Qgis.SensorThingsEntity.Location)
- self.assertEqual(repr(expansion),
- '')
- self.assertEqual(expansion.asQueryString(Qgis.SensorThingsEntity.Thing),
- '$expand=Locations($top=100)')
- self.assertEqual(expansion.asQueryString(Qgis.SensorThingsEntity.Thing, ['$expand=Datastreams($top=101)']),
- '$expand=Locations($top=100;$expand=Datastreams($top=101))')
+ self.assertEqual(expansion.childEntity(), Qgis.SensorThingsEntity.Location)
+ self.assertEqual(
+ repr(expansion), ""
+ )
+ self.assertEqual(
+ expansion.asQueryString(Qgis.SensorThingsEntity.Thing),
+ "$expand=Locations($top=100)",
+ )
+ self.assertEqual(
+ expansion.asQueryString(
+ Qgis.SensorThingsEntity.Thing, ["$expand=Datastreams($top=101)"]
+ ),
+ "$expand=Locations($top=100;$expand=Datastreams($top=101))",
+ )
expansion.setLimit(-1)
self.assertEqual(expansion.limit(), -1)
- self.assertEqual(repr(expansion),
- '')
- self.assertEqual(expansion.asQueryString(Qgis.SensorThingsEntity.Thing),
- '$expand=Locations')
- self.assertEqual(expansion.asQueryString(Qgis.SensorThingsEntity.Thing,
- ['$expand=Datastreams($top=101)']),
- '$expand=Locations($expand=Datastreams($top=101))')
-
- expansion.setOrderBy('id')
- self.assertEqual(expansion.orderBy(), 'id')
- self.assertEqual(repr(expansion),
- '')
- self.assertEqual(expansion.asQueryString(Qgis.SensorThingsEntity.Thing),
- '$expand=Locations($orderby=id)')
- self.assertEqual(expansion.asQueryString(Qgis.SensorThingsEntity.Thing,
- ['$expand=Datastreams($top=101)']),
- '$expand=Locations($orderby=id;$expand=Datastreams($top=101))')
+ self.assertEqual(
+ repr(expansion), ""
+ )
+ self.assertEqual(
+ expansion.asQueryString(Qgis.SensorThingsEntity.Thing), "$expand=Locations"
+ )
+ self.assertEqual(
+ expansion.asQueryString(
+ Qgis.SensorThingsEntity.Thing, ["$expand=Datastreams($top=101)"]
+ ),
+ "$expand=Locations($expand=Datastreams($top=101))",
+ )
+
+ expansion.setOrderBy("id")
+ self.assertEqual(expansion.orderBy(), "id")
+ self.assertEqual(
+ repr(expansion),
+ "",
+ )
+ self.assertEqual(
+ expansion.asQueryString(Qgis.SensorThingsEntity.Thing),
+ "$expand=Locations($orderby=id)",
+ )
+ self.assertEqual(
+ expansion.asQueryString(
+ Qgis.SensorThingsEntity.Thing, ["$expand=Datastreams($top=101)"]
+ ),
+ "$expand=Locations($orderby=id;$expand=Datastreams($top=101))",
+ )
expansion.setSortOrder(Qt.SortOrder.DescendingOrder)
self.assertEqual(expansion.sortOrder(), Qt.SortOrder.DescendingOrder)
- self.assertEqual(repr(expansion),
- '')
- self.assertEqual(expansion.asQueryString(Qgis.SensorThingsEntity.Thing),
- '$expand=Locations($orderby=id desc)')
- self.assertEqual(expansion.asQueryString(Qgis.SensorThingsEntity.Thing, ['$expand=Datastreams($top=101)']),
- '$expand=Locations($orderby=id desc;$expand=Datastreams($top=101))')
+ self.assertEqual(
+ repr(expansion),
+ "",
+ )
+ self.assertEqual(
+ expansion.asQueryString(Qgis.SensorThingsEntity.Thing),
+ "$expand=Locations($orderby=id desc)",
+ )
+ self.assertEqual(
+ expansion.asQueryString(
+ Qgis.SensorThingsEntity.Thing, ["$expand=Datastreams($top=101)"]
+ ),
+ "$expand=Locations($orderby=id desc;$expand=Datastreams($top=101))",
+ )
expansion.setLimit(3)
- self.assertEqual(repr(expansion),
- '')
- self.assertEqual(expansion.asQueryString(Qgis.SensorThingsEntity.Thing),
- '$expand=Locations($orderby=id desc;$top=3)')
- self.assertEqual(expansion.asQueryString(Qgis.SensorThingsEntity.Thing, ['$expand=Datastreams($top=101)']),
- '$expand=Locations($orderby=id desc;$top=3;$expand=Datastreams($top=101))')
-
- expansion.setFilter('result eq 1')
- self.assertEqual(expansion.filter(), 'result eq 1')
- self.assertEqual(repr(expansion),
- '')
- self.assertEqual(expansion.asQueryString(Qgis.SensorThingsEntity.Thing),
- '$expand=Locations($orderby=id desc;$top=3;$filter=result eq 1)')
- self.assertEqual(expansion.asQueryString(Qgis.SensorThingsEntity.Thing, ['$expand=Datastreams($top=101)']),
- '$expand=Locations($orderby=id desc;$top=3;$filter=result eq 1;$expand=Datastreams($top=101))')
+ self.assertEqual(
+ repr(expansion),
+ "",
+ )
+ self.assertEqual(
+ expansion.asQueryString(Qgis.SensorThingsEntity.Thing),
+ "$expand=Locations($orderby=id desc;$top=3)",
+ )
+ self.assertEqual(
+ expansion.asQueryString(
+ Qgis.SensorThingsEntity.Thing, ["$expand=Datastreams($top=101)"]
+ ),
+ "$expand=Locations($orderby=id desc;$top=3;$expand=Datastreams($top=101))",
+ )
+
+ expansion.setFilter("result eq 1")
+ self.assertEqual(expansion.filter(), "result eq 1")
+ self.assertEqual(
+ repr(expansion),
+ "",
+ )
+ self.assertEqual(
+ expansion.asQueryString(Qgis.SensorThingsEntity.Thing),
+ "$expand=Locations($orderby=id desc;$top=3;$filter=result eq 1)",
+ )
+ self.assertEqual(
+ expansion.asQueryString(
+ Qgis.SensorThingsEntity.Thing, ["$expand=Datastreams($top=101)"]
+ ),
+ "$expand=Locations($orderby=id desc;$top=3;$filter=result eq 1;$expand=Datastreams($top=101))",
+ )
# test equality
expansion1 = QgsSensorThingsExpansionDefinition(
- Qgis.SensorThingsEntity.ObservedProperty)
+ Qgis.SensorThingsEntity.ObservedProperty
+ )
expansion2 = QgsSensorThingsExpansionDefinition(
- Qgis.SensorThingsEntity.ObservedProperty)
+ Qgis.SensorThingsEntity.ObservedProperty
+ )
self.assertEqual(expansion1, expansion2)
self.assertNotEqual(expansion1, QgsSensorThingsExpansionDefinition())
self.assertNotEqual(QgsSensorThingsExpansionDefinition(), expansion2)
- self.assertEqual(QgsSensorThingsExpansionDefinition(),
- QgsSensorThingsExpansionDefinition())
+ self.assertEqual(
+ QgsSensorThingsExpansionDefinition(), QgsSensorThingsExpansionDefinition()
+ )
expansion2.setChildEntity(Qgis.SensorThingsEntity.Sensor)
self.assertNotEqual(expansion1, expansion2)
expansion2.setChildEntity(Qgis.SensorThingsEntity.ObservedProperty)
self.assertEqual(expansion1, expansion2)
- expansion2.setOrderBy('x')
+ expansion2.setOrderBy("x")
self.assertNotEqual(expansion1, expansion2)
- expansion2.setOrderBy('')
+ expansion2.setOrderBy("")
self.assertEqual(expansion1, expansion2)
expansion2.setSortOrder(Qt.SortOrder.DescendingOrder)
@@ -336,9 +416,9 @@ def test_expansion_definition(self):
expansion2.setLimit(100)
self.assertEqual(expansion1, expansion2)
- expansion2.setFilter('result eq 1')
+ expansion2.setFilter("result eq 1")
self.assertNotEqual(expansion1, expansion2)
- expansion2.setFilter('')
+ expansion2.setFilter("")
self.assertEqual(expansion1, expansion2)
# test to/from string
@@ -357,12 +437,12 @@ def test_expansion_definition(self):
self.assertFalse(res.orderBy())
self.assertEqual(res.limit(), -1)
- expansion.setOrderBy('test')
+ expansion.setOrderBy("test")
string = expansion.toString()
res = QgsSensorThingsExpansionDefinition.fromString(string)
self.assertTrue(res.isValid())
self.assertEqual(res.childEntity(), Qgis.SensorThingsEntity.Sensor)
- self.assertEqual(res.orderBy(), 'test')
+ self.assertEqual(res.orderBy(), "test")
self.assertEqual(res.sortOrder(), Qt.SortOrder.AscendingOrder)
self.assertEqual(res.limit(), -1)
@@ -371,7 +451,7 @@ def test_expansion_definition(self):
res = QgsSensorThingsExpansionDefinition.fromString(string)
self.assertTrue(res.isValid())
self.assertEqual(res.childEntity(), Qgis.SensorThingsEntity.Sensor)
- self.assertEqual(res.orderBy(), 'test')
+ self.assertEqual(res.orderBy(), "test")
self.assertEqual(res.sortOrder(), Qt.SortOrder.DescendingOrder)
self.assertEqual(res.limit(), -1)
@@ -380,11 +460,11 @@ def test_expansion_definition(self):
res = QgsSensorThingsExpansionDefinition.fromString(string)
self.assertTrue(res.isValid())
self.assertEqual(res.childEntity(), Qgis.SensorThingsEntity.Sensor)
- self.assertEqual(res.orderBy(), 'test')
+ self.assertEqual(res.orderBy(), "test")
self.assertEqual(res.sortOrder(), Qt.SortOrder.DescendingOrder)
self.assertEqual(res.limit(), 5)
- expansion.setOrderBy('')
+ expansion.setOrderBy("")
string = expansion.toString()
res = QgsSensorThingsExpansionDefinition.fromString(string)
self.assertTrue(res.isValid())
@@ -392,7 +472,7 @@ def test_expansion_definition(self):
self.assertFalse(res.orderBy())
self.assertEqual(res.limit(), 5)
- expansion.setFilter('request eq 1:2')
+ expansion.setFilter("request eq 1:2")
string = expansion.toString()
res = QgsSensorThingsExpansionDefinition.fromString(string)
self.assertTrue(res.isValid())
@@ -403,75 +483,88 @@ def test_expansions_as_query_string(self):
Test constructing query strings from a list of expansions
"""
self.assertFalse(
- QgsSensorThingsUtils.asQueryString(Qgis.SensorThingsEntity.Invalid,
- [])
+ QgsSensorThingsUtils.asQueryString(Qgis.SensorThingsEntity.Invalid, [])
)
self.assertEqual(
- QgsSensorThingsUtils.asQueryString(Qgis.SensorThingsEntity.Thing,
- [
- QgsSensorThingsExpansionDefinition(
- Qgis.SensorThingsEntity.Location,
- orderBy='id', limit=3)
- ]),
- '$expand=Locations($orderby=id;$top=3)'
+ QgsSensorThingsUtils.asQueryString(
+ Qgis.SensorThingsEntity.Thing,
+ [
+ QgsSensorThingsExpansionDefinition(
+ Qgis.SensorThingsEntity.Location, orderBy="id", limit=3
+ )
+ ],
+ ),
+ "$expand=Locations($orderby=id;$top=3)",
)
self.assertEqual(
- QgsSensorThingsUtils.asQueryString(Qgis.SensorThingsEntity.Thing,
- [
- QgsSensorThingsExpansionDefinition(),
- QgsSensorThingsExpansionDefinition(
- Qgis.SensorThingsEntity.Datastream,
- orderBy='id', limit=3)
- ]),
- '$expand=Datastreams($orderby=id;$top=3)'
+ QgsSensorThingsUtils.asQueryString(
+ Qgis.SensorThingsEntity.Thing,
+ [
+ QgsSensorThingsExpansionDefinition(),
+ QgsSensorThingsExpansionDefinition(
+ Qgis.SensorThingsEntity.Datastream, orderBy="id", limit=3
+ ),
+ ],
+ ),
+ "$expand=Datastreams($orderby=id;$top=3)",
)
self.assertEqual(
- QgsSensorThingsUtils.asQueryString(Qgis.SensorThingsEntity.Thing,
- [
- QgsSensorThingsExpansionDefinition(
- Qgis.SensorThingsEntity.Datastream,
- orderBy='id', limit=3)
- ]),
- '$expand=Datastreams($orderby=id;$top=3)'
+ QgsSensorThingsUtils.asQueryString(
+ Qgis.SensorThingsEntity.Thing,
+ [
+ QgsSensorThingsExpansionDefinition(
+ Qgis.SensorThingsEntity.Datastream, orderBy="id", limit=3
+ )
+ ],
+ ),
+ "$expand=Datastreams($orderby=id;$top=3)",
)
self.assertEqual(
QgsSensorThingsUtils.asQueryString(
Qgis.SensorThingsEntity.Observation,
- [QgsSensorThingsExpansionDefinition(
- Qgis.SensorThingsEntity.Datastream,
- orderBy='id', limit=3)
- ]),
- '$expand=Datastream($orderby=id;$top=3)'
+ [
+ QgsSensorThingsExpansionDefinition(
+ Qgis.SensorThingsEntity.Datastream, orderBy="id", limit=3
+ )
+ ],
+ ),
+ "$expand=Datastream($orderby=id;$top=3)",
)
self.assertEqual(
- QgsSensorThingsUtils.asQueryString(Qgis.SensorThingsEntity.Thing,
- [
- QgsSensorThingsExpansionDefinition(
- Qgis.SensorThingsEntity.Location,
- orderBy='id', limit=3),
- QgsSensorThingsExpansionDefinition(
- Qgis.SensorThingsEntity.Sensor,
- orderBy='description',
- limit=30)
- ]),
- '$expand=Locations($orderby=id;$top=3;$expand=Sensors($orderby=description;$top=30))'
+ QgsSensorThingsUtils.asQueryString(
+ Qgis.SensorThingsEntity.Thing,
+ [
+ QgsSensorThingsExpansionDefinition(
+ Qgis.SensorThingsEntity.Location, orderBy="id", limit=3
+ ),
+ QgsSensorThingsExpansionDefinition(
+ Qgis.SensorThingsEntity.Sensor, orderBy="description", limit=30
+ ),
+ ],
+ ),
+ "$expand=Locations($orderby=id;$top=3;$expand=Sensors($orderby=description;$top=30))",
)
self.assertEqual(
QgsSensorThingsUtils.asQueryString(
Qgis.SensorThingsEntity.Location,
[
QgsSensorThingsExpansionDefinition(
- Qgis.SensorThingsEntity.Thing,
- orderBy='id', limit=3),
+ Qgis.SensorThingsEntity.Thing, orderBy="id", limit=3
+ ),
QgsSensorThingsExpansionDefinition(
Qgis.SensorThingsEntity.Datastream,
- orderBy='description', limit=30),
+ orderBy="description",
+ limit=30,
+ ),
QgsSensorThingsExpansionDefinition(
Qgis.SensorThingsEntity.ObservedProperty,
- orderBy='name', limit=-1)
- ]),
- '$expand=Things($orderby=id;$top=3;$expand=Datastreams($orderby=description;$top=30;$expand=ObservedProperty($orderby=name)))'
+ orderBy="name",
+ limit=-1,
+ ),
+ ],
+ ),
+ "$expand=Things($orderby=id;$top=3;$expand=Datastreams($orderby=description;$top=30;$expand=ObservedProperty($orderby=name)))",
)
def test_fields_for_expanded_entity(self):
@@ -479,47 +572,71 @@ def test_fields_for_expanded_entity(self):
Test calculating fields for an expanded entity
"""
fields = QgsSensorThingsUtils.fieldsForExpandedEntityType(
- Qgis.SensorThingsEntity.Location,
- [])
- self.assertEqual([field.name() for field in fields],
- ['id', 'selfLink', 'name', 'description',
- 'properties'])
+ Qgis.SensorThingsEntity.Location, []
+ )
+ self.assertEqual(
+ [field.name() for field in fields],
+ ["id", "selfLink", "name", "description", "properties"],
+ )
fields = QgsSensorThingsUtils.fieldsForExpandedEntityType(
- Qgis.SensorThingsEntity.Location,
- [Qgis.SensorThingsEntity.Thing])
- self.assertEqual([field.name() for field in fields],
- ['id', 'selfLink', 'name', 'description',
- 'properties', 'Thing_id', 'Thing_selfLink',
- 'Thing_name', 'Thing_description',
- 'Thing_properties'])
+ Qgis.SensorThingsEntity.Location, [Qgis.SensorThingsEntity.Thing]
+ )
+ self.assertEqual(
+ [field.name() for field in fields],
+ [
+ "id",
+ "selfLink",
+ "name",
+ "description",
+ "properties",
+ "Thing_id",
+ "Thing_selfLink",
+ "Thing_name",
+ "Thing_description",
+ "Thing_properties",
+ ],
+ )
fields = QgsSensorThingsUtils.fieldsForExpandedEntityType(
Qgis.SensorThingsEntity.Location,
- [Qgis.SensorThingsEntity.Thing,
- Qgis.SensorThingsEntity.Datastream])
- self.assertEqual([field.name() for field in fields],
- ['id', 'selfLink', 'name', 'description',
- 'properties', 'Thing_id', 'Thing_selfLink',
- 'Thing_name', 'Thing_description',
- 'Thing_properties', 'Thing_Datastream_id',
- 'Thing_Datastream_selfLink', 'Thing_Datastream_name',
- 'Thing_Datastream_description',
- 'Thing_Datastream_unitOfMeasurement',
- 'Thing_Datastream_observationType',
- 'Thing_Datastream_properties',
- 'Thing_Datastream_phenomenonTimeStart',
- 'Thing_Datastream_phenomenonTimeEnd',
- 'Thing_Datastream_resultTimeStart',
- 'Thing_Datastream_resultTimeEnd'])
+ [Qgis.SensorThingsEntity.Thing, Qgis.SensorThingsEntity.Datastream],
+ )
+ self.assertEqual(
+ [field.name() for field in fields],
+ [
+ "id",
+ "selfLink",
+ "name",
+ "description",
+ "properties",
+ "Thing_id",
+ "Thing_selfLink",
+ "Thing_name",
+ "Thing_description",
+ "Thing_properties",
+ "Thing_Datastream_id",
+ "Thing_Datastream_selfLink",
+ "Thing_Datastream_name",
+ "Thing_Datastream_description",
+ "Thing_Datastream_unitOfMeasurement",
+ "Thing_Datastream_observationType",
+ "Thing_Datastream_properties",
+ "Thing_Datastream_phenomenonTimeStart",
+ "Thing_Datastream_phenomenonTimeEnd",
+ "Thing_Datastream_resultTimeStart",
+ "Thing_Datastream_resultTimeEnd",
+ ],
+ )
def test_expandable_targets(self):
"""
Test valid expansion targets for entity types
"""
- self.assertEqual(QgsSensorThingsUtils.expandableTargets(
- Qgis.SensorThingsEntity.Thing),
- [Qgis.SensorThingsEntity.HistoricalLocation,
- Qgis.SensorThingsEntity.Datastream
- ]
+ self.assertEqual(
+ QgsSensorThingsUtils.expandableTargets(Qgis.SensorThingsEntity.Thing),
+ [
+ Qgis.SensorThingsEntity.HistoricalLocation,
+ Qgis.SensorThingsEntity.Datastream,
+ ],
)
def test_filter_for_extent(self):
@@ -527,22 +644,31 @@ def test_filter_for_extent(self):
Test constructing valid filter strings for features which intersect
an extent
"""
- self.assertFalse(QgsSensorThingsUtils.filterForExtent('', QgsRectangle()))
- self.assertFalse(QgsSensorThingsUtils.filterForExtent('test', QgsRectangle()))
- self.assertFalse(QgsSensorThingsUtils.filterForExtent('', QgsRectangle(1, 2, 3, 4)))
- self.assertEqual(QgsSensorThingsUtils.filterForExtent('test', QgsRectangle(1, 2, 3, 4)),
- "geo.intersects(test, geography'Polygon ((1 2, 3 2, 3 4, 1 4, 1 2))')")
+ self.assertFalse(QgsSensorThingsUtils.filterForExtent("", QgsRectangle()))
+ self.assertFalse(QgsSensorThingsUtils.filterForExtent("test", QgsRectangle()))
+ self.assertFalse(
+ QgsSensorThingsUtils.filterForExtent("", QgsRectangle(1, 2, 3, 4))
+ )
+ self.assertEqual(
+ QgsSensorThingsUtils.filterForExtent("test", QgsRectangle(1, 2, 3, 4)),
+ "geo.intersects(test, geography'Polygon ((1 2, 3 2, 3 4, 1 4, 1 2))')",
+ )
def test_combine_filters(self):
"""
Test combining multiple filter strings into one
"""
self.assertFalse(QgsSensorThingsUtils.combineFilters([]))
- self.assertFalse(QgsSensorThingsUtils.combineFilters(['']))
- self.assertEqual(QgsSensorThingsUtils.combineFilters(['', 'a eq 1']), 'a eq 1')
- self.assertEqual(QgsSensorThingsUtils.combineFilters(['a eq 1', 'b eq 2']), '(a eq 1) and (b eq 2)')
- self.assertEqual(QgsSensorThingsUtils.combineFilters(['a eq 1', '', 'b eq 2', 'c eq 3']),
- '(a eq 1) and (b eq 2) and (c eq 3)')
+ self.assertFalse(QgsSensorThingsUtils.combineFilters([""]))
+ self.assertEqual(QgsSensorThingsUtils.combineFilters(["", "a eq 1"]), "a eq 1")
+ self.assertEqual(
+ QgsSensorThingsUtils.combineFilters(["a eq 1", "b eq 2"]),
+ "(a eq 1) and (b eq 2)",
+ )
+ self.assertEqual(
+ QgsSensorThingsUtils.combineFilters(["a eq 1", "", "b eq 2", "c eq 3"]),
+ "(a eq 1) and (b eq 2) and (c eq 3)",
+ )
def test_invalid_layer(self):
"""
@@ -567,7 +693,7 @@ def test_layer_invalid_json(self):
with tempfile.TemporaryDirectory() as temp_dir:
base_path = temp_dir.replace("\\", "/")
endpoint = base_path + "/fake_qgis_http_endpoint"
- with open(sanitize(endpoint, ""), "wt", encoding="utf8") as f:
+ with open(sanitize(endpoint, ""), "w", encoding="utf8") as f:
f.write(
"""
{
@@ -585,7 +711,7 @@ def test_layer(self):
with tempfile.TemporaryDirectory() as temp_dir:
base_path = temp_dir.replace("\\", "/")
endpoint = base_path + "/fake_qgis_http_endpoint"
- with open(sanitize(endpoint, ""), "wt", encoding="utf8") as f:
+ with open(sanitize(endpoint, ""), "w", encoding="utf8") as f:
f.write(
"""
{
@@ -635,8 +761,11 @@ def test_layer(self):
)
with open(
- sanitize(endpoint, "/Locations?$top=0&$count=true&$filter=location/type eq 'Point' or location/geometry/type eq 'Point'"),
- "wt",
+ sanitize(
+ endpoint,
+ "/Locations?$top=0&$count=true&$filter=location/type eq 'Point' or location/geometry/type eq 'Point'",
+ ),
+ "w",
encoding="utf8",
) as f:
f.write("""{"@iot.count":4962,"value":[]}""")
@@ -689,7 +818,7 @@ def test_thing(self):
with tempfile.TemporaryDirectory() as temp_dir:
base_path = temp_dir.replace("\\", "/")
endpoint = base_path + "/fake_qgis_http_endpoint"
- with open(sanitize(endpoint, ""), "wt", encoding="utf8") as f:
+ with open(sanitize(endpoint, ""), "w", encoding="utf8") as f:
f.write(
"""
{
@@ -708,14 +837,14 @@ def test_thing(self):
with open(
sanitize(endpoint, "/Things?$top=0&$count=true"),
- "wt",
+ "w",
encoding="utf8",
) as f:
f.write("""{"@iot.count":3,"value":[]}""")
with open(
sanitize(endpoint, "/Things?$top=2&$count=false"),
- "wt",
+ "w",
encoding="utf8",
) as f:
f.write(
@@ -758,7 +887,7 @@ def test_thing(self):
with open(
sanitize(endpoint, "/Things?$top=2&$skip=2"),
- "wt",
+ "w",
encoding="utf8",
) as f:
f.write(
@@ -846,7 +975,7 @@ def test_location(self):
with tempfile.TemporaryDirectory() as temp_dir:
base_path = temp_dir.replace("\\", "/")
endpoint = base_path + "/fake_qgis_http_endpoint"
- with open(sanitize(endpoint, ""), "wt", encoding="utf8") as f:
+ with open(sanitize(endpoint, ""), "w", encoding="utf8") as f:
f.write(
"""
{
@@ -864,15 +993,21 @@ def test_location(self):
)
with open(
- sanitize(endpoint, "/Locations?$top=0&$count=true&$filter=location/type eq 'Point' or location/geometry/type eq 'Point'"),
- "wt",
+ sanitize(
+ endpoint,
+ "/Locations?$top=0&$count=true&$filter=location/type eq 'Point' or location/geometry/type eq 'Point'",
+ ),
+ "w",
encoding="utf8",
) as f:
f.write("""{"@iot.count":3,"value":[]}""")
with open(
- sanitize(endpoint, "/Locations?$top=2&$count=false&$filter=location/type eq 'Point' or location/geometry/type eq 'Point'"),
- "wt",
+ sanitize(
+ endpoint,
+ "/Locations?$top=2&$count=false&$filter=location/type eq 'Point' or location/geometry/type eq 'Point'",
+ ),
+ "w",
encoding="utf8",
) as f:
f.write(
@@ -927,8 +1062,11 @@ def test_location(self):
)
with open(
- sanitize(endpoint, "/Locations?$top=2&$skip=2&$filter=location/type eq 'Point' or location/geometry/type eq 'Point'"),
- "wt",
+ sanitize(
+ endpoint,
+ "/Locations?$top=2&$skip=2&$filter=location/type eq 'Point' or location/geometry/type eq 'Point'",
+ ),
+ "w",
encoding="utf8",
) as f:
f.write(
@@ -1033,7 +1171,7 @@ def test_location_formalism(self):
with tempfile.TemporaryDirectory() as temp_dir:
base_path = temp_dir.replace("\\", "/")
endpoint = base_path + "/fake_qgis_http_endpoint"
- with open(sanitize(endpoint, ""), "wt", encoding="utf8") as f:
+ with open(sanitize(endpoint, ""), "w", encoding="utf8") as f:
f.write(
"""
{
@@ -1051,17 +1189,21 @@ def test_location_formalism(self):
)
with open(
- sanitize(endpoint,
- "/Locations?$top=0&$count=true&$filter=location/type eq 'Point' or location/geometry/type eq 'Point'"),
- "wt",
+ sanitize(
+ endpoint,
+ "/Locations?$top=0&$count=true&$filter=location/type eq 'Point' or location/geometry/type eq 'Point'",
+ ),
+ "w",
encoding="utf8",
) as f:
f.write("""{"@iot.count":3,"value":[]}""")
with open(
- sanitize(endpoint,
- "/Locations?$top=2&$count=false&$filter=location/type eq 'Point' or location/geometry/type eq 'Point'"),
- "wt",
+ sanitize(
+ endpoint,
+ "/Locations?$top=2&$count=false&$filter=location/type eq 'Point' or location/geometry/type eq 'Point'",
+ ),
+ "w",
encoding="utf8",
) as f:
f.write(
@@ -1122,9 +1264,11 @@ def test_location_formalism(self):
)
with open(
- sanitize(endpoint,
- "/Locations?$top=2&$skip=2&$filter=location/type eq 'Point' or location/geometry/type eq 'Point'"),
- "wt",
+ sanitize(
+ endpoint,
+ "/Locations?$top=2&$skip=2&$filter=location/type eq 'Point' or location/geometry/type eq 'Point'",
+ ),
+ "w",
encoding="utf8",
) as f:
f.write(
@@ -1172,10 +1316,8 @@ def test_location_formalism(self):
self.assertEqual(vl.extent(), QgsRectangle(-180, -90, 180, 90))
self.assertEqual(vl.featureCount(), 3)
self.assertEqual(vl.crs().authid(), "EPSG:4326")
- self.assertIn("Entity TypeLocation ",
- vl.htmlMetadata())
- self.assertIn(f'href="http://{endpoint}/Locations"',
- vl.htmlMetadata())
+ self.assertIn("Entity TypeLocation ", vl.htmlMetadata())
+ self.assertIn(f'href="http://{endpoint}/Locations"', vl.htmlMetadata())
self.assertEqual(
[f.name() for f in vl.fields()],
@@ -1210,24 +1352,20 @@ def test_location_formalism(self):
["Location 1", "Location 2", "Location 3"],
)
self.assertEqual(
- [f["description"] for f in features],
- ["Desc 1", "Desc 2", "Desc 3"]
+ [f["description"] for f in features], ["Desc 1", "Desc 2", "Desc 3"]
)
self.assertEqual(
[f["properties"] for f in features],
- [{"owner": "owner 1"}, {"owner": "owner 2"},
- {"owner": "owner 3"}],
+ [{"owner": "owner 1"}, {"owner": "owner 2"}, {"owner": "owner 3"}],
)
self.assertEqual(
[f.geometry().asWkt(1) for f in features],
- ["Point (11.6 52.1)", "Point (12.6 53.1)",
- "Point (13.6 55.1)"],
+ ["Point (11.6 52.1)", "Point (12.6 53.1)", "Point (13.6 55.1)"],
)
# all features fetched, accurate extent should be returned
- self.assertEqual(vl.extent(),
- QgsRectangle(11.6, 52.1, 13.6, 55.1))
+ self.assertEqual(vl.extent(), QgsRectangle(11.6, 52.1, 13.6, 55.1))
def test_filter_rect(self):
"""
@@ -1237,7 +1375,7 @@ def test_filter_rect(self):
with tempfile.TemporaryDirectory() as temp_dir:
base_path = temp_dir.replace("\\", "/")
endpoint = base_path + "/fake_qgis_http_endpoint"
- with open(sanitize(endpoint, ""), "wt", encoding="utf8") as f:
+ with open(sanitize(endpoint, ""), "w", encoding="utf8") as f:
f.write(
"""
{
@@ -1255,15 +1393,21 @@ def test_filter_rect(self):
)
with open(
- sanitize(endpoint, "/Locations?$top=0&$count=true&$filter=location/type eq 'Point' or location/geometry/type eq 'Point'"),
- "wt",
+ sanitize(
+ endpoint,
+ "/Locations?$top=0&$count=true&$filter=location/type eq 'Point' or location/geometry/type eq 'Point'",
+ ),
+ "w",
encoding="utf8",
) as f:
f.write("""{"@iot.count":3,"value":[]}""")
with open(
- sanitize(endpoint, "/Locations?$top=2&$count=false&$filter=location/type eq 'Point' or location/geometry/type eq 'Point'"),
- "wt",
+ sanitize(
+ endpoint,
+ "/Locations?$top=2&$count=false&$filter=location/type eq 'Point' or location/geometry/type eq 'Point'",
+ ),
+ "w",
encoding="utf8",
) as f:
f.write(
@@ -1318,8 +1462,11 @@ def test_filter_rect(self):
)
with open(
- sanitize(endpoint, "/Locations?$top=2&$skip=2&$filter=location/type eq 'Point' or location/geometry/type eq 'Point'"),
- "wt",
+ sanitize(
+ endpoint,
+ "/Locations?$top=2&$skip=2&$filter=location/type eq 'Point' or location/geometry/type eq 'Point'",
+ ),
+ "w",
encoding="utf8",
) as f:
f.write(
@@ -1353,9 +1500,11 @@ def test_filter_rect(self):
)
with open(
- sanitize(endpoint,
- "/Locations?$top=2&$count=false&$filter=(location/type eq 'Point' or location/geometry/type eq 'Point') and (geo.intersects(location, geography'Polygon ((1 0, 10 0, 10 80, 1 80, 1 0))'))"),
- "wt",
+ sanitize(
+ endpoint,
+ "/Locations?$top=2&$count=false&$filter=(location/type eq 'Point' or location/geometry/type eq 'Point') and (geo.intersects(location, geography'Polygon ((1 0, 10 0, 10 80, 1 80, 1 0))'))",
+ ),
+ "w",
encoding="utf8",
) as f:
f.write(
@@ -1407,9 +1556,11 @@ def test_filter_rect(self):
)
with open(
- sanitize(endpoint,
- "/Locations?$top=2&$count=false&$filter=(location/type eq 'Point' or location/geometry/type eq 'Point') and (geo.intersects(location, geography'Polygon ((10 0, 20 0, 20 80, 10 80, 10 0))'))"),
- "wt",
+ sanitize(
+ endpoint,
+ "/Locations?$top=2&$count=false&$filter=(location/type eq 'Point' or location/geometry/type eq 'Point') and (geo.intersects(location, geography'Polygon ((10 0, 20 0, 20 80, 10 80, 10 0))'))",
+ ),
+ "w",
encoding="utf8",
) as f:
f.write(
@@ -1453,16 +1604,12 @@ def test_filter_rect(self):
self.assertEqual(vl.wkbType(), Qgis.WkbType.PointZ)
self.assertEqual(vl.featureCount(), 3)
self.assertEqual(vl.crs().authid(), "EPSG:4326")
- self.assertIn("Entity TypeLocation ",
- vl.htmlMetadata())
- self.assertIn(f'href="http://{endpoint}/Locations"',
- vl.htmlMetadata())
+ self.assertIn("Entity TypeLocation ", vl.htmlMetadata())
+ self.assertIn(f'href="http://{endpoint}/Locations"', vl.htmlMetadata())
# test retrieving subset of features from a filter rect only
request = QgsFeatureRequest()
- request.setFilterRect(
- QgsRectangle(1, 0, 10, 80)
- )
+ request.setFilterRect(QgsRectangle(1, 0, 10, 80))
features = list(vl.getFeatures(request))
self.assertEqual([f["id"] for f in features], ["1", "3"])
@@ -1474,27 +1621,20 @@ def test_filter_rect(self):
[f["name"] for f in features],
["Location 1", "Location 3"],
)
- self.assertEqual(
- [f["description"] for f in features],
- ["Desc 1", "Desc 3"]
- )
+ self.assertEqual([f["description"] for f in features], ["Desc 1", "Desc 3"])
self.assertEqual(
[f["properties"] for f in features],
- [{"owner": "owner 1"},
- {"owner": "owner 3"}],
+ [{"owner": "owner 1"}, {"owner": "owner 3"}],
)
self.assertEqual(
[f.geometry().asWkt(1) for f in features],
- ["Point (1.6 52.1)",
- "Point (3.6 55.1)"],
+ ["Point (1.6 52.1)", "Point (3.6 55.1)"],
)
# test retrieving a different subset with a different extent
request = QgsFeatureRequest()
- request.setFilterRect(
- QgsRectangle(10, 0, 20, 80)
- )
+ request.setFilterRect(QgsRectangle(10, 0, 20, 80))
features = list(vl.getFeatures(request))
self.assertEqual([f["id"] for f in features], ["2"])
@@ -1506,10 +1646,7 @@ def test_filter_rect(self):
[f["name"] for f in features],
["Location 2"],
)
- self.assertEqual(
- [f["description"] for f in features],
- ["Desc 2"]
- )
+ self.assertEqual([f["description"] for f in features], ["Desc 2"])
self.assertEqual(
[f["properties"] for f in features],
[{"owner": "owner 2"}],
@@ -1522,9 +1659,7 @@ def test_filter_rect(self):
# a filter rect which covers all features
request = QgsFeatureRequest()
- request.setFilterRect(
- QgsRectangle(0, 0, 20, 80)
- )
+ request.setFilterRect(QgsRectangle(0, 0, 20, 80))
features = list(vl.getFeatures(request))
self.assertEqual([f["id"] for f in features], ["1", "3", "2"])
@@ -1540,7 +1675,7 @@ def test_extent_limit(self):
with tempfile.TemporaryDirectory() as temp_dir:
base_path = temp_dir.replace("\\", "/")
endpoint = base_path + "/fake_qgis_http_endpoint"
- with open(sanitize(endpoint, ""), "wt", encoding="utf8") as f:
+ with open(sanitize(endpoint, ""), "w", encoding="utf8") as f:
f.write(
"""
{
@@ -1558,17 +1693,21 @@ def test_extent_limit(self):
)
with open(
- sanitize(endpoint,
- "/Locations?$top=0&$count=true&$filter=(location/type eq 'Point' or location/geometry/type eq 'Point') and (geo.intersects(location, geography'Polygon ((1 0, 10 0, 10 80, 1 80, 1 0))'))"),
- "wt",
+ sanitize(
+ endpoint,
+ "/Locations?$top=0&$count=true&$filter=(location/type eq 'Point' or location/geometry/type eq 'Point') and (geo.intersects(location, geography'Polygon ((1 0, 10 0, 10 80, 1 80, 1 0))'))",
+ ),
+ "w",
encoding="utf8",
) as f:
f.write("""{"@iot.count":2,"value":[]}""")
with open(
- sanitize(endpoint,
- "/Locations?$top=2&$count=false&$filter=(location/type eq 'Point' or location/geometry/type eq 'Point') and (geo.intersects(location, geography'Polygon ((1 0, 10 0, 10 80, 1 80, 1 0))'))"),
- "wt",
+ sanitize(
+ endpoint,
+ "/Locations?$top=2&$count=false&$filter=(location/type eq 'Point' or location/geometry/type eq 'Point') and (geo.intersects(location, geography'Polygon ((1 0, 10 0, 10 80, 1 80, 1 0))'))",
+ ),
+ "w",
encoding="utf8",
) as f:
f.write(
@@ -1621,9 +1760,11 @@ def test_extent_limit(self):
)
with open(
- sanitize(endpoint,
- "/Locations?$top=2&$count=false&$filter=(location/type eq 'Point' or location/geometry/type eq 'Point') and (geo.intersects(location, geography'Polygon ((1 0, 3 0, 3 50, 1 50, 1 0))'))"),
- "wt",
+ sanitize(
+ endpoint,
+ "/Locations?$top=2&$count=false&$filter=(location/type eq 'Point' or location/geometry/type eq 'Point') and (geo.intersects(location, geography'Polygon ((1 0, 3 0, 3 50, 1 50, 1 0))'))",
+ ),
+ "w",
encoding="utf8",
) as f:
f.write(
@@ -1668,18 +1809,14 @@ def test_extent_limit(self):
# should use the hardcoded extent limit as the initial guess, not global extents
self.assertEqual(vl.extent(), QgsRectangle(1, 0, 10, 80))
self.assertEqual(vl.crs().authid(), "EPSG:4326")
- self.assertIn("Entity TypeLocation ",
- vl.htmlMetadata())
- self.assertIn(f'href="http://{endpoint}/Locations"',
- vl.htmlMetadata())
+ self.assertIn("Entity TypeLocation ", vl.htmlMetadata())
+ self.assertIn(f'href="http://{endpoint}/Locations"', vl.htmlMetadata())
# test retrieving a subset of the features from the layer,
# using a filter rect which only covers a part of the hardcoded
# provider's extent
request = QgsFeatureRequest()
- request.setFilterRect(
- QgsRectangle(1, 0, 3, 50)
- )
+ request.setFilterRect(QgsRectangle(1, 0, 3, 50))
features = list(vl.getFeatures(request))
self.assertEqual([f["id"] for f in features], ["1"])
@@ -1691,10 +1828,7 @@ def test_extent_limit(self):
[f["name"] for f in features],
["Location 1"],
)
- self.assertEqual(
- [f["description"] for f in features],
- ["Desc 1"]
- )
+ self.assertEqual([f["description"] for f in features], ["Desc 1"])
self.assertEqual(
[f["properties"] for f in features],
[{"owner": "owner 1"}],
@@ -1718,25 +1852,27 @@ def test_extent_limit(self):
[f["name"] for f in features],
["Location 1", "Location 3"],
)
- self.assertEqual(
- [f["description"] for f in features],
- ["Desc 1", "Desc 3"]
- )
+ self.assertEqual([f["description"] for f in features], ["Desc 1", "Desc 3"])
self.assertEqual(
[f["properties"] for f in features],
- [{"owner": "owner 1"},
- {"owner": "owner 3"}],
+ [{"owner": "owner 1"}, {"owner": "owner 3"}],
)
self.assertEqual(
[f.geometry().asWkt(1) for f in features],
- ["Point (1.6 52.1)",
- "Point (3.6 55.1)"],
+ ["Point (1.6 52.1)", "Point (3.6 55.1)"],
)
# should have accurate layer extent now
- self.assertEqual(vl.extent(), QgsRectangle(1.62337299999999995, 52.13201699999999761, 3.62337299999999995,
- 55.13201699999999761))
+ self.assertEqual(
+ vl.extent(),
+ QgsRectangle(
+ 1.62337299999999995,
+ 52.13201699999999761,
+ 3.62337299999999995,
+ 55.13201699999999761,
+ ),
+ )
def test_subset_string(self):
"""
@@ -1746,7 +1882,7 @@ def test_subset_string(self):
with tempfile.TemporaryDirectory() as temp_dir:
base_path = temp_dir.replace("\\", "/")
endpoint = base_path + "/fake_qgis_http_endpoint"
- with open(sanitize(endpoint, ""), "wt", encoding="utf8") as f:
+ with open(sanitize(endpoint, ""), "w", encoding="utf8") as f:
f.write(
"""
{
@@ -1764,25 +1900,31 @@ def test_subset_string(self):
)
with open(
- sanitize(endpoint,
- "/Locations?$top=0&$count=true&$filter=location/type eq 'Point' or location/geometry/type eq 'Point'"),
- "wt",
+ sanitize(
+ endpoint,
+ "/Locations?$top=0&$count=true&$filter=location/type eq 'Point' or location/geometry/type eq 'Point'",
+ ),
+ "w",
encoding="utf8",
) as f:
f.write("""{"@iot.count":2,"value":[]}""")
with open(
- sanitize(endpoint,
- "/Locations?$top=0&$count=true&$filter=(location/type eq 'Point' or location/geometry/type eq 'Point') and (name eq 'Location 1')"),
- "wt",
+ sanitize(
+ endpoint,
+ "/Locations?$top=0&$count=true&$filter=(location/type eq 'Point' or location/geometry/type eq 'Point') and (name eq 'Location 1')",
+ ),
+ "w",
encoding="utf8",
) as f:
f.write("""{"@iot.count":1,"value":[]}""")
with open(
- sanitize(endpoint,
- "/Locations?$top=2&$count=false&$filter=(location/type eq 'Point' or location/geometry/type eq 'Point') and (geo.intersects(location, geography'Polygon ((1 0, 3 0, 3 50, 1 50, 1 0))')) and (name eq 'Location 1')"),
- "wt",
+ sanitize(
+ endpoint,
+ "/Locations?$top=2&$count=false&$filter=(location/type eq 'Point' or location/geometry/type eq 'Point') and (geo.intersects(location, geography'Polygon ((1 0, 3 0, 3 50, 1 50, 1 0))')) and (name eq 'Location 1')",
+ ),
+ "w",
encoding="utf8",
) as f:
f.write(
@@ -1816,9 +1958,11 @@ def test_subset_string(self):
)
with open(
- sanitize(endpoint,
- "/Locations?$top=2&$count=false&$filter=(location/type eq 'Point' or location/geometry/type eq 'Point') and (geo.intersects(location, geography'Polygon ((1 0, 3 0, 3 50, 1 50, 1 0))'))"),
- "wt",
+ sanitize(
+ endpoint,
+ "/Locations?$top=2&$count=false&$filter=(location/type eq 'Point' or location/geometry/type eq 'Point') and (geo.intersects(location, geography'Polygon ((1 0, 3 0, 3 50, 1 50, 1 0))'))",
+ ),
+ "w",
encoding="utf8",
) as f:
f.write(
@@ -1863,21 +2007,20 @@ def test_subset_string(self):
vl.setSubsetString("name eq 'Location 1'")
self.assertEqual(vl.subsetString(), "name eq 'Location 1'")
- self.assertEqual(vl.source(), f" type=PointZ entity='Location' pageSize='2' url='http://{endpoint}' sql=name eq 'Location 1'")
+ self.assertEqual(
+ vl.source(),
+ f" type=PointZ entity='Location' pageSize='2' url='http://{endpoint}' sql=name eq 'Location 1'",
+ )
self.assertEqual(vl.featureCount(), 1)
self.assertEqual(vl.crs().authid(), "EPSG:4326")
- self.assertIn("Entity TypeLocation ",
- vl.htmlMetadata())
- self.assertIn(f'href="http://{endpoint}/Locations"',
- vl.htmlMetadata())
+ self.assertIn("Entity TypeLocation ", vl.htmlMetadata())
+ self.assertIn(f'href="http://{endpoint}/Locations"', vl.htmlMetadata())
# test retrieving a subset of features, using a request which
# must be combined with the layer's subset filter
request = QgsFeatureRequest()
- request.setFilterRect(
- QgsRectangle(1, 0, 3, 50)
- )
+ request.setFilterRect(QgsRectangle(1, 0, 3, 50))
features = list(vl.getFeatures(request))
self.assertEqual([f["id"] for f in features], ["1"])
@@ -1889,10 +2032,7 @@ def test_subset_string(self):
[f["name"] for f in features],
["Location 1"],
)
- self.assertEqual(
- [f["description"] for f in features],
- ["Desc 1"]
- )
+ self.assertEqual([f["description"] for f in features], ["Desc 1"])
self.assertEqual(
[f["properties"] for f in features],
[{"owner": "owner 1"}],
@@ -1917,10 +2057,7 @@ def test_subset_string(self):
[f["name"] for f in features],
["Location 1"],
)
- self.assertEqual(
- [f["description"] for f in features],
- ["Desc 1"]
- )
+ self.assertEqual([f["description"] for f in features], ["Desc 1"])
self.assertEqual(
[f["properties"] for f in features],
[{"owner": "owner 1"}],
@@ -1932,10 +2069,15 @@ def test_subset_string(self):
)
# should have accurate layer extent now
- self.assertEqual(vl.extent(), QgsRectangle(1.62337299999999995,
- 52.13201699999999761,
- 1.62337299999999995,
- 52.13201699999999761))
+ self.assertEqual(
+ vl.extent(),
+ QgsRectangle(
+ 1.62337299999999995,
+ 52.13201699999999761,
+ 1.62337299999999995,
+ 52.13201699999999761,
+ ),
+ )
def test_feature_limit(self):
"""
@@ -1945,7 +2087,7 @@ def test_feature_limit(self):
with tempfile.TemporaryDirectory() as temp_dir:
base_path = temp_dir.replace("\\", "/")
endpoint = base_path + "/fake_qgis_http_endpoint"
- with open(sanitize(endpoint, ""), "wt", encoding="utf8") as f:
+ with open(sanitize(endpoint, ""), "w", encoding="utf8") as f:
f.write(
"""
{
@@ -1963,25 +2105,31 @@ def test_feature_limit(self):
)
with open(
- sanitize(endpoint,
- "/Locations?$top=0&$count=true&$filter=location/type eq 'Point' or location/geometry/type eq 'Point'"),
- "wt",
+ sanitize(
+ endpoint,
+ "/Locations?$top=0&$count=true&$filter=location/type eq 'Point' or location/geometry/type eq 'Point'",
+ ),
+ "w",
encoding="utf8",
) as f:
f.write("""{"@iot.count":3,"value":[]}""")
with open(
- sanitize(endpoint,
- "/Locations?$top=0&$count=true&$filter=(location/type eq 'Point' or location/geometry/type eq 'Point') and (name eq 'Location 1')"),
- "wt",
+ sanitize(
+ endpoint,
+ "/Locations?$top=0&$count=true&$filter=(location/type eq 'Point' or location/geometry/type eq 'Point') and (name eq 'Location 1')",
+ ),
+ "w",
encoding="utf8",
) as f:
f.write("""{"@iot.count":1,"value":[]}""")
with open(
- sanitize(endpoint,
- "/Locations?$top=2&$count=false&$filter=(location/type eq 'Point' or location/geometry/type eq 'Point') and (geo.intersects(location, geography'Polygon ((1 0, 3 0, 3 50, 1 50, 1 0))'))"),
- "wt",
+ sanitize(
+ endpoint,
+ "/Locations?$top=2&$count=false&$filter=(location/type eq 'Point' or location/geometry/type eq 'Point') and (geo.intersects(location, geography'Polygon ((1 0, 3 0, 3 50, 1 50, 1 0))'))",
+ ),
+ "w",
encoding="utf8",
) as f:
f.write(
@@ -2014,9 +2162,11 @@ def test_feature_limit(self):
)
with open(
- sanitize(endpoint,
- "/Locations?$top=2&$count=false&$filter=(location/type eq 'Point' or location/geometry/type eq 'Point') and (geo.intersects(location, geography'Polygon ((0 0, 100 0, 100 150, 0 150, 0 0))'))"),
- "wt",
+ sanitize(
+ endpoint,
+ "/Locations?$top=2&$count=false&$filter=(location/type eq 'Point' or location/geometry/type eq 'Point') and (geo.intersects(location, geography'Polygon ((0 0, 100 0, 100 150, 0 150, 0 0))'))",
+ ),
+ "w",
encoding="utf8",
) as f:
f.write(
@@ -2071,9 +2221,11 @@ def test_feature_limit(self):
# Note -- top param here should be replaced by "top=1", NOT be the "top=2" parameter from the previous page's iot.nextLink url!
with open(
- sanitize(endpoint,
- "/Locations?$top=1&$skip=2&$count=false&$filter=(location/type eq 'Point' or location/geometry/type eq 'Point') and (geo.intersects(location, geography'Polygon ((0 0, 100 0, 100 150, 0 150, 0 0))'))"),
- "wt",
+ sanitize(
+ endpoint,
+ "/Locations?$top=1&$skip=2&$count=false&$filter=(location/type eq 'Point' or location/geometry/type eq 'Point') and (geo.intersects(location, geography'Polygon ((0 0, 100 0, 100 150, 0 150, 0 0))'))",
+ ),
+ "w",
encoding="utf8",
) as f:
f.write(
@@ -2121,9 +2273,7 @@ def test_feature_limit(self):
# test retrieving a subset of the 3 features by using
# a request with a filter rect only matching one of the features
request = QgsFeatureRequest()
- request.setFilterRect(
- QgsRectangle(1, 0, 3, 50)
- )
+ request.setFilterRect(QgsRectangle(1, 0, 3, 50))
features = list(vl.getFeatures(request))
self.assertEqual([f["id"] for f in features], ["1"])
@@ -2135,10 +2285,7 @@ def test_feature_limit(self):
[f["name"] for f in features],
["Location 1"],
)
- self.assertEqual(
- [f["description"] for f in features],
- ["Desc 1"]
- )
+ self.assertEqual([f["description"] for f in features], ["Desc 1"])
self.assertEqual(
[f["properties"] for f in features],
[{"owner": "owner 1"}],
@@ -2155,21 +2302,16 @@ def test_feature_limit(self):
# skip/limit values (if it isn't, then we'll get no features
# back since the dummy endpoint address used above won't match)
request = QgsFeatureRequest()
- request.setFilterRect(
- QgsRectangle(0, 0, 100, 150)
- )
+ request.setFilterRect(QgsRectangle(0, 0, 100, 150))
features = list(vl.getFeatures(request))
- self.assertEqual([f["id"] for f in features], ['1', '2', '3'])
+ self.assertEqual([f["id"] for f in features], ["1", "2", "3"])
self.assertEqual(
[f["selfLink"][-13:] for f in features],
["/Locations(1)", "/Locations(2)", "/Locations(3)"],
)
# should have accurate layer extent now
- self.assertEqual(vl.extent(), QgsRectangle(1.62337299999999995,
- 52,
- 82,
- 53))
+ self.assertEqual(vl.extent(), QgsRectangle(1.62337299999999995, 52, 82, 53))
def test_historical_location(self):
"""
@@ -2178,7 +2320,7 @@ def test_historical_location(self):
with tempfile.TemporaryDirectory() as temp_dir:
base_path = temp_dir.replace("\\", "/")
endpoint = base_path + "/fake_qgis_http_endpoint"
- with open(sanitize(endpoint, ""), "wt", encoding="utf8") as f:
+ with open(sanitize(endpoint, ""), "w", encoding="utf8") as f:
f.write(
"""
{
@@ -2197,14 +2339,14 @@ def test_historical_location(self):
with open(
sanitize(endpoint, "/HistoricalLocations?$top=0&$count=true"),
- "wt",
+ "w",
encoding="utf8",
) as f:
f.write("""{"@iot.count":3,"value":[]}""")
with open(
sanitize(endpoint, "/HistoricalLocations?$top=2&$count=false"),
- "wt",
+ "w",
encoding="utf8",
) as f:
f.write(
@@ -2236,7 +2378,7 @@ def test_historical_location(self):
with open(
sanitize(endpoint, "/HistoricalLocations?$top=2&$skip=2"),
- "wt",
+ "w",
encoding="utf8",
) as f:
f.write(
@@ -2307,9 +2449,15 @@ def test_historical_location(self):
self.assertEqual(
[f["time"] for f in features],
[
- QDateTime(QDate(2020, 3, 20), QTime(16, 35, 23, 384), Qt.TimeSpec(1)),
- QDateTime(QDate(2021, 3, 20), QTime(16, 35, 23, 384), Qt.TimeSpec(1)),
- QDateTime(QDate(2022, 3, 20), QTime(16, 35, 23, 384), Qt.TimeSpec(1)),
+ QDateTime(
+ QDate(2020, 3, 20), QTime(16, 35, 23, 384), Qt.TimeSpec(1)
+ ),
+ QDateTime(
+ QDate(2021, 3, 20), QTime(16, 35, 23, 384), Qt.TimeSpec(1)
+ ),
+ QDateTime(
+ QDate(2022, 3, 20), QTime(16, 35, 23, 384), Qt.TimeSpec(1)
+ ),
],
)
@@ -2320,7 +2468,7 @@ def test_datastream(self):
with tempfile.TemporaryDirectory() as temp_dir:
base_path = temp_dir.replace("\\", "/")
endpoint = base_path + "/fake_qgis_http_endpoint"
- with open(sanitize(endpoint, ""), "wt", encoding="utf8") as f:
+ with open(sanitize(endpoint, ""), "w", encoding="utf8") as f:
f.write(
"""
{
@@ -2339,14 +2487,14 @@ def test_datastream(self):
with open(
sanitize(endpoint, "/Datastreams?$top=0&$count=true"),
- "wt",
+ "w",
encoding="utf8",
) as f:
f.write("""{"@iot.count":3,"value":[]}""")
with open(
sanitize(endpoint, "/Datastreams?$top=2&$count=false"),
- "wt",
+ "w",
encoding="utf8",
) as f:
f.write(
@@ -2402,7 +2550,7 @@ def test_datastream(self):
with open(
sanitize(endpoint, "/Datastreams?$top=2&$skip=2"),
- "wt",
+ "w",
encoding="utf8",
) as f:
f.write(
@@ -2569,7 +2717,7 @@ def test_sensor(self):
with tempfile.TemporaryDirectory() as temp_dir:
base_path = temp_dir.replace("\\", "/")
endpoint = base_path + "/fake_qgis_http_endpoint"
- with open(sanitize(endpoint, ""), "wt", encoding="utf8") as f:
+ with open(sanitize(endpoint, ""), "w", encoding="utf8") as f:
f.write(
"""
{
@@ -2588,14 +2736,14 @@ def test_sensor(self):
with open(
sanitize(endpoint, "/Sensors?$top=0&$count=true"),
- "wt",
+ "w",
encoding="utf8",
) as f:
f.write("""{"@iot.count":3,"value":[]}""")
with open(
sanitize(endpoint, "/Sensors?$top=2&$count=false"),
- "wt",
+ "w",
encoding="utf8",
) as f:
f.write(
@@ -2639,7 +2787,7 @@ def test_sensor(self):
with open(
sanitize(endpoint, "/Sensors?$top=2&$skip=2"),
- "wt",
+ "w",
encoding="utf8",
) as f:
f.write(
@@ -2738,7 +2886,7 @@ def test_observed_property(self):
with tempfile.TemporaryDirectory() as temp_dir:
base_path = temp_dir.replace("\\", "/")
endpoint = base_path + "/fake_qgis_http_endpoint"
- with open(sanitize(endpoint, ""), "wt", encoding="utf8") as f:
+ with open(sanitize(endpoint, ""), "w", encoding="utf8") as f:
f.write(
"""
{
@@ -2757,14 +2905,14 @@ def test_observed_property(self):
with open(
sanitize(endpoint, "/ObservedProperties?$top=0&$count=true"),
- "wt",
+ "w",
encoding="utf8",
) as f:
f.write("""{"@iot.count":3,"value":[]}""")
with open(
sanitize(endpoint, "/ObservedProperties?$top=2&$count=false"),
- "wt",
+ "w",
encoding="utf8",
) as f:
f.write(
@@ -2806,7 +2954,7 @@ def test_observed_property(self):
with open(
sanitize(endpoint, "/ObservedProperties?$top=2&$skip=2"),
- "wt",
+ "w",
encoding="utf8",
) as f:
f.write(
@@ -2912,7 +3060,7 @@ def test_observation(self):
with tempfile.TemporaryDirectory() as temp_dir:
base_path = temp_dir.replace("\\", "/")
endpoint = base_path + "/fake_qgis_http_endpoint"
- with open(sanitize(endpoint, ""), "wt", encoding="utf8") as f:
+ with open(sanitize(endpoint, ""), "w", encoding="utf8") as f:
f.write(
"""
{
@@ -2931,14 +3079,14 @@ def test_observation(self):
with open(
sanitize(endpoint, "/Observations?$top=0&$count=true"),
- "wt",
+ "w",
encoding="utf8",
) as f:
f.write("""{"@iot.count":3,"value":[]}""")
with open(
sanitize(endpoint, "/Observations?$top=2&$count=false"),
- "wt",
+ "w",
encoding="utf8",
) as f:
f.write(
@@ -2986,7 +3134,7 @@ def test_observation(self):
with open(
sanitize(endpoint, "/Observations?$top=2&$skip=2"),
- "wt",
+ "w",
encoding="utf8",
) as f:
f.write(
@@ -3124,7 +3272,7 @@ def test_feature_of_interest(self):
with tempfile.TemporaryDirectory() as temp_dir:
base_path = temp_dir.replace("\\", "/")
endpoint = base_path + "/fake_qgis_http_endpoint"
- with open(sanitize(endpoint, ""), "wt", encoding="utf8") as f:
+ with open(sanitize(endpoint, ""), "w", encoding="utf8") as f:
f.write(
"""
{
@@ -3142,15 +3290,21 @@ def test_feature_of_interest(self):
)
with open(
- sanitize(endpoint, "/FeaturesOfInterest?$top=0&$count=true&$filter=feature/type eq 'Point' or feature/geometry/type eq 'Point'"),
- "wt",
+ sanitize(
+ endpoint,
+ "/FeaturesOfInterest?$top=0&$count=true&$filter=feature/type eq 'Point' or feature/geometry/type eq 'Point'",
+ ),
+ "w",
encoding="utf8",
) as f:
f.write("""{"@iot.count":3,"value":[]}""")
with open(
- sanitize(endpoint, "/FeaturesOfInterest?$top=2&$count=false&$filter=feature/type eq 'Point' or feature/geometry/type eq 'Point'"),
- "wt",
+ sanitize(
+ endpoint,
+ "/FeaturesOfInterest?$top=2&$count=false&$filter=feature/type eq 'Point' or feature/geometry/type eq 'Point'",
+ ),
+ "w",
encoding="utf8",
) as f:
f.write(
@@ -3210,8 +3364,11 @@ def test_feature_of_interest(self):
)
with open(
- sanitize(endpoint, "/FeaturesOfInterest?$top=2&$skip=2&$filter=feature/type eq 'Point' or feature/geometry/type eq 'Point'"),
- "wt",
+ sanitize(
+ endpoint,
+ "/FeaturesOfInterest?$top=2&$skip=2&$filter=feature/type eq 'Point' or feature/geometry/type eq 'Point'",
+ ),
+ "w",
encoding="utf8",
) as f:
f.write(
@@ -3292,32 +3449,51 @@ def test_feature_of_interest(self):
self.assertEqual([f["id"] for f in features], ["1", "2", "3"])
self.assertEqual(
[f["selfLink"][-22:] for f in features],
- ["/FeaturesOfInterest(1)", "/FeaturesOfInterest(2)", "/FeaturesOfInterest(3)"],
+ [
+ "/FeaturesOfInterest(1)",
+ "/FeaturesOfInterest(2)",
+ "/FeaturesOfInterest(3)",
+ ],
)
self.assertEqual(
[f["name"] for f in features],
- ['SAM.09.LAA.822.7.1', 'SAM.09.LOB.823.7.1', 'SAM.09.LOB.824.1.1'],
+ ["SAM.09.LAA.822.7.1", "SAM.09.LOB.823.7.1", "SAM.09.LOB.824.1.1"],
)
self.assertEqual(
[f["description"] for f in features],
- ['Air quality sample SAM.09.LAA.822.7.1', None, 'Air quality sample SAM.09.LOB.824.1.1']
+ [
+ "Air quality sample SAM.09.LAA.822.7.1",
+ None,
+ "Air quality sample SAM.09.LOB.824.1.1",
+ ],
)
self.assertEqual(
[f["properties"] for f in features],
- [{'localId': 'SAM.09.LAA.822.7.1',
- 'metadata': 'http://luft.umweltbundesamt.at/inspire/wfs?service=WFS&version=2.0.0&request=GetFeature&typeName=aqd:AQD_Sample',
- 'namespace': 'AT.0008.20.AQ', 'owner': 'http://luft.umweltbundesamt.at'},
- {'localId': 'SAM.09.LOB.823.7.1',
- 'metadata': 'http://luft.umweltbundesamt.at/inspire/wfs?service=WFS&version=2.0.0&request=GetFeature&typeName=aqd:AQD_Sample',
- 'namespace': 'AT.0008.20.AQ', 'owner': 'http://luft.umweltbundesamt.at'},
- {'localId': 'SAM.09.LOB.824.1.1',
- 'metadata': 'http://luft.umweltbundesamt.at/inspire/wfs?service=WFS&version=2.0.0&request=GetFeature&typeName=aqd:AQD_Sample',
- 'namespace': 'AT.0008.20.AQ', 'owner': 'http://luft.umweltbundesamt.at'}],
+ [
+ {
+ "localId": "SAM.09.LAA.822.7.1",
+ "metadata": "http://luft.umweltbundesamt.at/inspire/wfs?service=WFS&version=2.0.0&request=GetFeature&typeName=aqd:AQD_Sample",
+ "namespace": "AT.0008.20.AQ",
+ "owner": "http://luft.umweltbundesamt.at",
+ },
+ {
+ "localId": "SAM.09.LOB.823.7.1",
+ "metadata": "http://luft.umweltbundesamt.at/inspire/wfs?service=WFS&version=2.0.0&request=GetFeature&typeName=aqd:AQD_Sample",
+ "namespace": "AT.0008.20.AQ",
+ "owner": "http://luft.umweltbundesamt.at",
+ },
+ {
+ "localId": "SAM.09.LOB.824.1.1",
+ "metadata": "http://luft.umweltbundesamt.at/inspire/wfs?service=WFS&version=2.0.0&request=GetFeature&typeName=aqd:AQD_Sample",
+ "namespace": "AT.0008.20.AQ",
+ "owner": "http://luft.umweltbundesamt.at",
+ },
+ ],
)
self.assertEqual(
[f.geometry().asWkt(1) for f in features],
- ['Point (16.4 48.2)', 'Point (16.5 48.2)', 'Point (16.5 48.2)'],
+ ["Point (16.4 48.2)", "Point (16.5 48.2)", "Point (16.5 48.2)"],
)
def test_multidatastream_no_geometry(self):
@@ -3327,7 +3503,7 @@ def test_multidatastream_no_geometry(self):
with tempfile.TemporaryDirectory() as temp_dir:
base_path = temp_dir.replace("\\", "/")
endpoint = base_path + "/fake_qgis_http_endpoint"
- with open(sanitize(endpoint, ""), "wt", encoding="utf8") as f:
+ with open(sanitize(endpoint, ""), "w", encoding="utf8") as f:
f.write(
"""
{
@@ -3346,14 +3522,14 @@ def test_multidatastream_no_geometry(self):
with open(
sanitize(endpoint, "/MultiDatastreams?$top=0&$count=true"),
- "wt",
+ "w",
encoding="utf8",
) as f:
f.write("""{"@iot.count":3,"value":[]}""")
with open(
sanitize(endpoint, "/MultiDatastreams?$top=2&$count=false"),
- "wt",
+ "w",
encoding="utf8",
) as f:
f.write(
@@ -3414,7 +3590,7 @@ def test_multidatastream_no_geometry(self):
with open(
sanitize(endpoint, "/MultiDatastreams?$top=2&$skip=2"),
- "wt",
+ "w",
encoding="utf8",
) as f:
f.write(
@@ -3459,10 +3635,10 @@ def test_multidatastream_no_geometry(self):
self.assertEqual(vl.wkbType(), Qgis.WkbType.NoGeometry)
self.assertEqual(vl.featureCount(), 3)
self.assertFalse(vl.crs().isValid())
- self.assertIn("Entity TypeMultiDatastream ",
- vl.htmlMetadata())
- self.assertIn(f'href="http://{endpoint}/MultiDatastreams"',
- vl.htmlMetadata())
+ self.assertIn("Entity TypeMultiDatastream ", vl.htmlMetadata())
+ self.assertIn(
+ f'href="http://{endpoint}/MultiDatastreams"', vl.htmlMetadata()
+ )
self.assertEqual(
[f.name() for f in vl.fields()],
@@ -3505,34 +3681,43 @@ def test_multidatastream_no_geometry(self):
self.assertEqual([f["id"] for f in features], ["1", "2", "3"])
self.assertEqual(
[f["selfLink"][-20:] for f in features],
- ["/MultiDatastreams(1)", "/MultiDatastreams(2)", "/MultiDatastreams(3)"],
+ [
+ "/MultiDatastreams(1)",
+ "/MultiDatastreams(2)",
+ "/MultiDatastreams(3)",
+ ],
)
self.assertEqual(
[f["name"] for f in features],
["MultiDatastream 1", "MultiDatastream 2", "MultiDatastream 3"],
)
self.assertEqual(
- [f["description"] for f in features],
- ["Desc 1", "Desc 2", "Desc 3"]
+ [f["description"] for f in features], ["Desc 1", "Desc 2", "Desc 3"]
)
self.assertEqual(
[f["unitOfMeasurements"] for f in features],
[
- [{
- "definition": "http://dd.eionet.europa.eu/vocabulary/uom/concentration/ug.m-3",
- "name": "ug.m-3",
- "symbol": "ug.m-3",
- }],
- [{
- "definition": "http://dd.eionet.europa.eu/vocabulary/uom/concentration/ug.m-3",
- "name": "ug.m-3",
- "symbol": "ug.m-3",
- }],
- [{
- "definition": "http://dd.eionet.europa.eu/vocabulary/uom/concentration/ug.m-3",
- "name": "ug.m-3",
- "symbol": "ug.m-3",
- }],
+ [
+ {
+ "definition": "http://dd.eionet.europa.eu/vocabulary/uom/concentration/ug.m-3",
+ "name": "ug.m-3",
+ "symbol": "ug.m-3",
+ }
+ ],
+ [
+ {
+ "definition": "http://dd.eionet.europa.eu/vocabulary/uom/concentration/ug.m-3",
+ "name": "ug.m-3",
+ "symbol": "ug.m-3",
+ }
+ ],
+ [
+ {
+ "definition": "http://dd.eionet.europa.eu/vocabulary/uom/concentration/ug.m-3",
+ "name": "ug.m-3",
+ "symbol": "ug.m-3",
+ }
+ ],
],
)
self.assertEqual(
@@ -3546,59 +3731,52 @@ def test_multidatastream_no_geometry(self):
self.assertEqual(
[f["multiObservationDataTypes"] for f in features],
[
- ["http://www.opengis.net/def/observationType/OGC-OM/2.0/OM_Measurement"],
- ["http://www.opengis.net/def/observationType/OGC-OM/2.0/OM_Measurement"],
- ["http://www.opengis.net/def/observationType/OGC-OM/2.0/OM_Measurement"],
+ [
+ "http://www.opengis.net/def/observationType/OGC-OM/2.0/OM_Measurement"
+ ],
+ [
+ "http://www.opengis.net/def/observationType/OGC-OM/2.0/OM_Measurement"
+ ],
+ [
+ "http://www.opengis.net/def/observationType/OGC-OM/2.0/OM_Measurement"
+ ],
],
)
self.assertEqual(
[f["phenomenonTimeStart"] for f in features],
[
- QDateTime(QDate(2017, 12, 31), QTime(23, 0, 0, 0),
- Qt.TimeSpec(1)),
- QDateTime(QDate(2018, 12, 31), QTime(23, 0, 0, 0),
- Qt.TimeSpec(1)),
- QDateTime(QDate(2020, 12, 31), QTime(23, 0, 0, 0),
- Qt.TimeSpec(1)),
+ QDateTime(QDate(2017, 12, 31), QTime(23, 0, 0, 0), Qt.TimeSpec(1)),
+ QDateTime(QDate(2018, 12, 31), QTime(23, 0, 0, 0), Qt.TimeSpec(1)),
+ QDateTime(QDate(2020, 12, 31), QTime(23, 0, 0, 0), Qt.TimeSpec(1)),
],
)
self.assertEqual(
[f["phenomenonTimeEnd"] for f in features],
[
- QDateTime(QDate(2018, 1, 12), QTime(4, 0, 0, 0),
- Qt.TimeSpec(1)),
- QDateTime(QDate(2019, 1, 12), QTime(4, 0, 0, 0),
- Qt.TimeSpec(1)),
- QDateTime(QDate(2021, 1, 12), QTime(4, 0, 0, 0),
- Qt.TimeSpec(1)),
+ QDateTime(QDate(2018, 1, 12), QTime(4, 0, 0, 0), Qt.TimeSpec(1)),
+ QDateTime(QDate(2019, 1, 12), QTime(4, 0, 0, 0), Qt.TimeSpec(1)),
+ QDateTime(QDate(2021, 1, 12), QTime(4, 0, 0, 0), Qt.TimeSpec(1)),
],
)
self.assertEqual(
[f["resultTimeStart"] for f in features],
[
- QDateTime(QDate(2017, 12, 31), QTime(23, 30, 0, 0),
- Qt.TimeSpec(1)),
- QDateTime(QDate(2018, 12, 31), QTime(23, 30, 0, 0),
- Qt.TimeSpec(1)),
- QDateTime(QDate(2020, 12, 31), QTime(23, 30, 0, 0),
- Qt.TimeSpec(1)),
+ QDateTime(QDate(2017, 12, 31), QTime(23, 30, 0, 0), Qt.TimeSpec(1)),
+ QDateTime(QDate(2018, 12, 31), QTime(23, 30, 0, 0), Qt.TimeSpec(1)),
+ QDateTime(QDate(2020, 12, 31), QTime(23, 30, 0, 0), Qt.TimeSpec(1)),
],
)
self.assertEqual(
[f["resultTimeEnd"] for f in features],
[
- QDateTime(QDate(2017, 12, 31), QTime(23, 31, 0, 0),
- Qt.TimeSpec(1)),
- QDateTime(QDate(2018, 12, 31), QTime(23, 31, 0, 0),
- Qt.TimeSpec(1)),
- QDateTime(QDate(2020, 12, 31), QTime(23, 31, 0, 0),
- Qt.TimeSpec(1)),
+ QDateTime(QDate(2017, 12, 31), QTime(23, 31, 0, 0), Qt.TimeSpec(1)),
+ QDateTime(QDate(2018, 12, 31), QTime(23, 31, 0, 0), Qt.TimeSpec(1)),
+ QDateTime(QDate(2020, 12, 31), QTime(23, 31, 0, 0), Qt.TimeSpec(1)),
],
)
self.assertEqual(
[f["properties"] for f in features],
- [{"owner": "owner 1"}, {"owner": "owner 2"},
- {"owner": "owner 3"}],
+ [{"owner": "owner 1"}, {"owner": "owner 2"}, {"owner": "owner 3"}],
)
def test_multidatastream_polygons(self):
@@ -3608,7 +3786,7 @@ def test_multidatastream_polygons(self):
with tempfile.TemporaryDirectory() as temp_dir:
base_path = temp_dir.replace("\\", "/")
endpoint = base_path + "/fake_qgis_http_endpoint"
- with open(sanitize(endpoint, ""), "wt", encoding="utf8") as f:
+ with open(sanitize(endpoint, ""), "w", encoding="utf8") as f:
f.write(
"""
{
@@ -3626,15 +3804,21 @@ def test_multidatastream_polygons(self):
)
with open(
- sanitize(endpoint, "/MultiDatastreams?$top=0&$count=true&$filter=observedArea/type eq 'Polygon' or observedArea/geometry/type eq 'Polygon'"),
- "wt",
+ sanitize(
+ endpoint,
+ "/MultiDatastreams?$top=0&$count=true&$filter=observedArea/type eq 'Polygon' or observedArea/geometry/type eq 'Polygon'",
+ ),
+ "w",
encoding="utf8",
) as f:
f.write("""{"@iot.count":3,"value":[]}""")
with open(
- sanitize(endpoint, "/MultiDatastreams?$top=2&$count=false&$filter=observedArea/type eq 'Polygon' or observedArea/geometry/type eq 'Polygon'"),
- "wt",
+ sanitize(
+ endpoint,
+ "/MultiDatastreams?$top=2&$count=false&$filter=observedArea/type eq 'Polygon' or observedArea/geometry/type eq 'Polygon'",
+ ),
+ "w",
encoding="utf8",
) as f:
f.write(
@@ -3710,8 +3894,11 @@ def test_multidatastream_polygons(self):
)
with open(
- sanitize(endpoint, "/MultiDatastreams?$top=2&$skip=2&$filter=observedArea/type eq 'Polygon' or observedArea/geometry/type eq 'Polygon'"),
- "wt",
+ sanitize(
+ endpoint,
+ "/MultiDatastreams?$top=2&$skip=2&$filter=observedArea/type eq 'Polygon' or observedArea/geometry/type eq 'Polygon'",
+ ),
+ "w",
encoding="utf8",
) as f:
f.write(
@@ -3763,11 +3950,11 @@ def test_multidatastream_polygons(self):
self.assertEqual(vl.storageType(), "OGC SensorThings API")
self.assertEqual(vl.wkbType(), Qgis.WkbType.MultiPolygonZ)
self.assertEqual(vl.featureCount(), 3)
- self.assertEqual(vl.crs().authid(), 'EPSG:4326')
- self.assertIn("Entity TypeMultiDatastream ",
- vl.htmlMetadata())
- self.assertIn(f'href="http://{endpoint}/MultiDatastreams"',
- vl.htmlMetadata())
+ self.assertEqual(vl.crs().authid(), "EPSG:4326")
+ self.assertIn("Entity TypeMultiDatastream ", vl.htmlMetadata())
+ self.assertIn(
+ f'href="http://{endpoint}/MultiDatastreams"', vl.htmlMetadata()
+ )
self.assertEqual(
[f.name() for f in vl.fields()],
@@ -3810,34 +3997,43 @@ def test_multidatastream_polygons(self):
self.assertEqual([f["id"] for f in features], ["1", "2", "3"])
self.assertEqual(
[f["selfLink"][-20:] for f in features],
- ["/MultiDatastreams(1)", "/MultiDatastreams(2)", "/MultiDatastreams(3)"],
+ [
+ "/MultiDatastreams(1)",
+ "/MultiDatastreams(2)",
+ "/MultiDatastreams(3)",
+ ],
)
self.assertEqual(
[f["name"] for f in features],
["MultiDatastream 1", "MultiDatastream 2", "MultiDatastream 3"],
)
self.assertEqual(
- [f["description"] for f in features],
- ["Desc 1", "Desc 2", "Desc 3"]
+ [f["description"] for f in features], ["Desc 1", "Desc 2", "Desc 3"]
)
self.assertEqual(
[f["unitOfMeasurements"] for f in features],
[
- [{
- "definition": "http://dd.eionet.europa.eu/vocabulary/uom/concentration/ug.m-3",
- "name": "ug.m-3",
- "symbol": "ug.m-3",
- }],
- [{
- "definition": "http://dd.eionet.europa.eu/vocabulary/uom/concentration/ug.m-3",
- "name": "ug.m-3",
- "symbol": "ug.m-3",
- }],
- [{
- "definition": "http://dd.eionet.europa.eu/vocabulary/uom/concentration/ug.m-3",
- "name": "ug.m-3",
- "symbol": "ug.m-3",
- }],
+ [
+ {
+ "definition": "http://dd.eionet.europa.eu/vocabulary/uom/concentration/ug.m-3",
+ "name": "ug.m-3",
+ "symbol": "ug.m-3",
+ }
+ ],
+ [
+ {
+ "definition": "http://dd.eionet.europa.eu/vocabulary/uom/concentration/ug.m-3",
+ "name": "ug.m-3",
+ "symbol": "ug.m-3",
+ }
+ ],
+ [
+ {
+ "definition": "http://dd.eionet.europa.eu/vocabulary/uom/concentration/ug.m-3",
+ "name": "ug.m-3",
+ "symbol": "ug.m-3",
+ }
+ ],
],
)
self.assertEqual(
@@ -3851,65 +4047,60 @@ def test_multidatastream_polygons(self):
self.assertEqual(
[f["multiObservationDataTypes"] for f in features],
[
- ["http://www.opengis.net/def/observationType/OGC-OM/2.0/OM_Measurement"],
- ["http://www.opengis.net/def/observationType/OGC-OM/2.0/OM_Measurement"],
- ["http://www.opengis.net/def/observationType/OGC-OM/2.0/OM_Measurement"],
+ [
+ "http://www.opengis.net/def/observationType/OGC-OM/2.0/OM_Measurement"
+ ],
+ [
+ "http://www.opengis.net/def/observationType/OGC-OM/2.0/OM_Measurement"
+ ],
+ [
+ "http://www.opengis.net/def/observationType/OGC-OM/2.0/OM_Measurement"
+ ],
],
)
self.assertEqual(
[f["phenomenonTimeStart"] for f in features],
[
- QDateTime(QDate(2017, 12, 31), QTime(23, 0, 0, 0),
- Qt.TimeSpec(1)),
- QDateTime(QDate(2018, 12, 31), QTime(23, 0, 0, 0),
- Qt.TimeSpec(1)),
- QDateTime(QDate(2020, 12, 31), QTime(23, 0, 0, 0),
- Qt.TimeSpec(1)),
+ QDateTime(QDate(2017, 12, 31), QTime(23, 0, 0, 0), Qt.TimeSpec(1)),
+ QDateTime(QDate(2018, 12, 31), QTime(23, 0, 0, 0), Qt.TimeSpec(1)),
+ QDateTime(QDate(2020, 12, 31), QTime(23, 0, 0, 0), Qt.TimeSpec(1)),
],
)
self.assertEqual(
[f["phenomenonTimeEnd"] for f in features],
[
- QDateTime(QDate(2018, 1, 12), QTime(4, 0, 0, 0),
- Qt.TimeSpec(1)),
- QDateTime(QDate(2019, 1, 12), QTime(4, 0, 0, 0),
- Qt.TimeSpec(1)),
- QDateTime(QDate(2021, 1, 12), QTime(4, 0, 0, 0),
- Qt.TimeSpec(1)),
+ QDateTime(QDate(2018, 1, 12), QTime(4, 0, 0, 0), Qt.TimeSpec(1)),
+ QDateTime(QDate(2019, 1, 12), QTime(4, 0, 0, 0), Qt.TimeSpec(1)),
+ QDateTime(QDate(2021, 1, 12), QTime(4, 0, 0, 0), Qt.TimeSpec(1)),
],
)
self.assertEqual(
[f["resultTimeStart"] for f in features],
[
- QDateTime(QDate(2017, 12, 31), QTime(23, 30, 0, 0),
- Qt.TimeSpec(1)),
- QDateTime(QDate(2018, 12, 31), QTime(23, 30, 0, 0),
- Qt.TimeSpec(1)),
- QDateTime(QDate(2020, 12, 31), QTime(23, 30, 0, 0),
- Qt.TimeSpec(1)),
+ QDateTime(QDate(2017, 12, 31), QTime(23, 30, 0, 0), Qt.TimeSpec(1)),
+ QDateTime(QDate(2018, 12, 31), QTime(23, 30, 0, 0), Qt.TimeSpec(1)),
+ QDateTime(QDate(2020, 12, 31), QTime(23, 30, 0, 0), Qt.TimeSpec(1)),
],
)
self.assertEqual(
[f["resultTimeEnd"] for f in features],
[
- QDateTime(QDate(2017, 12, 31), QTime(23, 31, 0, 0),
- Qt.TimeSpec(1)),
- QDateTime(QDate(2018, 12, 31), QTime(23, 31, 0, 0),
- Qt.TimeSpec(1)),
- QDateTime(QDate(2020, 12, 31), QTime(23, 31, 0, 0),
- Qt.TimeSpec(1)),
+ QDateTime(QDate(2017, 12, 31), QTime(23, 31, 0, 0), Qt.TimeSpec(1)),
+ QDateTime(QDate(2018, 12, 31), QTime(23, 31, 0, 0), Qt.TimeSpec(1)),
+ QDateTime(QDate(2020, 12, 31), QTime(23, 31, 0, 0), Qt.TimeSpec(1)),
],
)
self.assertEqual(
[f["properties"] for f in features],
- [{"owner": "owner 1"}, {"owner": "owner 2"},
- {"owner": "owner 3"}],
+ [{"owner": "owner 1"}, {"owner": "owner 2"}, {"owner": "owner 3"}],
)
self.assertEqual(
[f.geometry().asWkt() for f in features],
- ['Polygon ((100 0, 101 0, 101 1, 100 1, 100 0))',
- 'Polygon ((102 0, 103 0, 103 1, 102 1, 102 0))',
- 'Polygon ((103 0, 104 0, 104 1, 103 1, 103 0))'],
+ [
+ "Polygon ((100 0, 101 0, 101 1, 100 1, 100 0))",
+ "Polygon ((102 0, 103 0, 103 1, 102 1, 102 0))",
+ "Polygon ((103 0, 104 0, 104 1, 103 1, 103 0))",
+ ],
)
def test_feature_expansion(self):
@@ -3919,7 +4110,7 @@ def test_feature_expansion(self):
with tempfile.TemporaryDirectory() as temp_dir:
base_path = temp_dir.replace("\\", "/")
endpoint = base_path + "/fake_qgis_http_endpoint"
- with open(sanitize(endpoint, ""), "wt", encoding="utf8") as f:
+ with open(sanitize(endpoint, ""), "w", encoding="utf8") as f:
f.write(
"""
{
@@ -3937,17 +4128,21 @@ def test_feature_expansion(self):
)
with open(
- sanitize(endpoint,
- "/Locations?$top=0&$count=true&$filter=location/type eq 'Polygon' or location/geometry/type eq 'Polygon'"),
- "wt",
+ sanitize(
+ endpoint,
+ "/Locations?$top=0&$count=true&$filter=location/type eq 'Polygon' or location/geometry/type eq 'Polygon'",
+ ),
+ "w",
encoding="utf8",
) as f:
f.write("""{"@iot.count":3,"value":[]}""")
with open(
- sanitize(endpoint,
- "/Locations?$top=2&$count=false&$expand=Things($expand=Datastreams)&$filter=location/type eq 'Polygon' or location/geometry/type eq 'Polygon'"),
- "wt",
+ sanitize(
+ endpoint,
+ "/Locations?$top=2&$count=false&$expand=Things($expand=Datastreams)&$filter=location/type eq 'Polygon' or location/geometry/type eq 'Polygon'",
+ ),
+ "w",
encoding="utf8",
) as f:
f.write(
@@ -4123,9 +4318,11 @@ def test_feature_expansion(self):
)
with open(
- sanitize(endpoint,
- "/Locations?$top=2&$skip=2&$expand=Things($expand=Datastreams)&$filter=location/type eq 'Polygon' or location/geometry/type eq 'Polygon'"),
- "wt",
+ sanitize(
+ endpoint,
+ "/Locations?$top=2&$skip=2&$expand=Things($expand=Datastreams)&$filter=location/type eq 'Polygon' or location/geometry/type eq 'Polygon'",
+ ),
+ "w",
encoding="utf8",
) as f:
f.write(
@@ -4223,26 +4420,35 @@ def test_feature_expansion(self):
self.assertEqual(vl.wkbType(), Qgis.WkbType.MultiPolygonZ)
self.assertEqual(vl.featureCount(), -1)
- self.assertEqual(vl.crs().authid(), 'EPSG:4326')
- self.assertIn("Entity TypeLocation ",
- vl.htmlMetadata())
- self.assertIn(f'href="http://{endpoint}/Locations"',
- vl.htmlMetadata())
+ self.assertEqual(vl.crs().authid(), "EPSG:4326")
+ self.assertIn("Entity TypeLocation ", vl.htmlMetadata())
+ self.assertIn(f'href="http://{endpoint}/Locations"', vl.htmlMetadata())
self.assertEqual(
[f.name() for f in vl.fields()],
- ['id', 'selfLink', 'name', 'description', 'properties',
- 'Thing_id', 'Thing_selfLink', 'Thing_name',
- 'Thing_description', 'Thing_properties',
- 'Thing_Datastream_id', 'Thing_Datastream_selfLink',
- 'Thing_Datastream_name', 'Thing_Datastream_description',
- 'Thing_Datastream_unitOfMeasurement',
- 'Thing_Datastream_observationType',
- 'Thing_Datastream_properties',
- 'Thing_Datastream_phenomenonTimeStart',
- 'Thing_Datastream_phenomenonTimeEnd',
- 'Thing_Datastream_resultTimeStart',
- 'Thing_Datastream_resultTimeEnd'],
+ [
+ "id",
+ "selfLink",
+ "name",
+ "description",
+ "properties",
+ "Thing_id",
+ "Thing_selfLink",
+ "Thing_name",
+ "Thing_description",
+ "Thing_properties",
+ "Thing_Datastream_id",
+ "Thing_Datastream_selfLink",
+ "Thing_Datastream_name",
+ "Thing_Datastream_description",
+ "Thing_Datastream_unitOfMeasurement",
+ "Thing_Datastream_observationType",
+ "Thing_Datastream_properties",
+ "Thing_Datastream_phenomenonTimeStart",
+ "Thing_Datastream_phenomenonTimeEnd",
+ "Thing_Datastream_resultTimeStart",
+ "Thing_Datastream_resultTimeEnd",
+ ],
)
self.assertEqual(
[f.type() for f in vl.fields()],
@@ -4273,97 +4479,146 @@ def test_feature_expansion(self):
# test retrieving all features from layer
features = list(vl.getFeatures())
- self.assertEqual([f.id() for f in features],
- [0, 1, 2, 3, 4, 5])
- self.assertEqual([f["id"] for f in features],
- ["1", "1", "2", "2", "3", "3"])
+ self.assertEqual([f.id() for f in features], [0, 1, 2, 3, 4, 5])
+ self.assertEqual(
+ [f["id"] for f in features], ["1", "1", "2", "2", "3", "3"]
+ )
self.assertEqual(
[f["selfLink"][-13:] for f in features],
- ["/Locations(1)", "/Locations(1)",
- "/Locations(2)", "/Locations(2)",
- "/Locations(3)", "/Locations(3)"],
+ [
+ "/Locations(1)",
+ "/Locations(1)",
+ "/Locations(2)",
+ "/Locations(2)",
+ "/Locations(3)",
+ "/Locations(3)",
+ ],
)
self.assertEqual(
[f["name"] for f in features],
- ["Location 1", "Location 1",
- "Location 2", "Location 2",
- "Location 3", "Location 3"],
+ [
+ "Location 1",
+ "Location 1",
+ "Location 2",
+ "Location 2",
+ "Location 3",
+ "Location 3",
+ ],
)
self.assertEqual(
[f["description"] for f in features],
- ["Desc 1", "Desc 1",
- "Desc 2", "Desc 2",
- "Desc 3", "Desc 3"]
+ ["Desc 1", "Desc 1", "Desc 2", "Desc 2", "Desc 3", "Desc 3"],
)
self.assertEqual(
[f["properties"] for f in features],
- [{'owner': 'owner 1'}, {'owner': 'owner 1'},
- {'owner': 'owner 2'}, {'owner': 'owner 2'},
- {'owner': 'owner 3'}, {'owner': 'owner 3'}]
+ [
+ {"owner": "owner 1"},
+ {"owner": "owner 1"},
+ {"owner": "owner 2"},
+ {"owner": "owner 2"},
+ {"owner": "owner 3"},
+ {"owner": "owner 3"},
+ ],
)
self.assertEqual(
- [f["Thing_id"] for f in features],
- ['1', '1', '2', '3', '8', '8']
+ [f["Thing_id"] for f in features], ["1", "1", "2", "3", "8", "8"]
)
self.assertEqual(
[f["Thing_selfLink"][-10:] for f in features],
- ['/Things(1)', '/Things(1)', '/Things(2)', '/Things(3)',
- '/Things(8)', '/Things(8)']
+ [
+ "/Things(1)",
+ "/Things(1)",
+ "/Things(2)",
+ "/Things(3)",
+ "/Things(8)",
+ "/Things(8)",
+ ],
)
self.assertEqual(
[f["Thing_name"] for f in features],
- ['Thing 1', 'Thing 1', 'Thing 2', 'Thing 3', 'Thing 8',
- 'Thing 8']
+ ["Thing 1", "Thing 1", "Thing 2", "Thing 3", "Thing 8", "Thing 8"],
)
self.assertEqual(
[f["Thing_description"] for f in features],
- ['Description Thing 1', 'Description Thing 1',
- 'Description Thing 2', 'Description Thing 3',
- 'Description Thing 8', 'Description Thing 8']
+ [
+ "Description Thing 1",
+ "Description Thing 1",
+ "Description Thing 2",
+ "Description Thing 3",
+ "Description Thing 8",
+ "Description Thing 8",
+ ],
)
self.assertEqual(
[f["Thing_properties"] for f in features],
- [{'countryCode': 'AT'}, {'countryCode': 'AT'},
- {'countryCode': 'AT'}, {'countryCode': 'AT'},
- {'countryCode': 'AT'}, {'countryCode': 'AT'}]
+ [
+ {"countryCode": "AT"},
+ {"countryCode": "AT"},
+ {"countryCode": "AT"},
+ {"countryCode": "AT"},
+ {"countryCode": "AT"},
+ {"countryCode": "AT"},
+ ],
)
self.assertEqual(
[f["Thing_Datastream_id"] for f in features],
- ['45', '46', '51', '52', '59', '60']
+ ["45", "46", "51", "52", "59", "60"],
)
self.assertEqual(
[f["Thing_Datastream_selfLink"][-16:] for f in features],
- ['/Datastreams(45)', '/Datastreams(46)',
- '/Datastreams(51)',
- '/Datastreams(52)', '/Datastreams(59)',
- '/Datastreams(60)']
+ [
+ "/Datastreams(45)",
+ "/Datastreams(46)",
+ "/Datastreams(51)",
+ "/Datastreams(52)",
+ "/Datastreams(59)",
+ "/Datastreams(60)",
+ ],
)
self.assertEqual(
[f["Thing_Datastream_name"] for f in features],
- ['Datastream 45', 'Datastream 46', 'Datastream 51',
- 'Datastream 52', 'Datastream 59', 'Datastream 60']
+ [
+ "Datastream 45",
+ "Datastream 46",
+ "Datastream 51",
+ "Datastream 52",
+ "Datastream 59",
+ "Datastream 60",
+ ],
)
self.assertEqual(
[f["Thing_Datastream_description"] for f in features],
- ['Description datastream 45', 'Description datastream 46',
- 'Description datastream 51', 'Description datastream 52',
- 'Description datastream 59', 'Description datastream 60']
+ [
+ "Description datastream 45",
+ "Description datastream 46",
+ "Description datastream 51",
+ "Description datastream 52",
+ "Description datastream 59",
+ "Description datastream 60",
+ ],
)
self.assertEqual(
[f["Thing_Datastream_properties"] for f in features],
- [{'owner': 'someone'}, {'owner': 'someone'},
- {'owner': 'someone'}, {'owner': 'someone'},
- {'owner': 'someone'}, {'owner': 'someone'}]
+ [
+ {"owner": "someone"},
+ {"owner": "someone"},
+ {"owner": "someone"},
+ {"owner": "someone"},
+ {"owner": "someone"},
+ {"owner": "someone"},
+ ],
)
self.assertEqual(
[f.geometry().asWkt() for f in features],
- ['Polygon ((100 0, 101 0, 101 1, 100 1, 100 0))',
- 'Polygon ((100 0, 101 0, 101 1, 100 1, 100 0))',
- 'Polygon ((102 0, 103 0, 103 1, 102 1, 102 0))',
- 'Polygon ((102 0, 103 0, 103 1, 102 1, 102 0))',
- 'Polygon ((103 0, 104 0, 104 1, 103 1, 103 0))',
- 'Polygon ((103 0, 104 0, 104 1, 103 1, 103 0))'],
+ [
+ "Polygon ((100 0, 101 0, 101 1, 100 1, 100 0))",
+ "Polygon ((100 0, 101 0, 101 1, 100 1, 100 0))",
+ "Polygon ((102 0, 103 0, 103 1, 102 1, 102 0))",
+ "Polygon ((102 0, 103 0, 103 1, 102 1, 102 0))",
+ "Polygon ((103 0, 104 0, 104 1, 103 1, 103 0))",
+ "Polygon ((103 0, 104 0, 104 1, 103 1, 103 0))",
+ ],
)
def test_feature_expansion_with_limit(self):
@@ -4373,7 +4628,7 @@ def test_feature_expansion_with_limit(self):
with tempfile.TemporaryDirectory() as temp_dir:
base_path = temp_dir.replace("\\", "/")
endpoint = base_path + "/fake_qgis_http_endpoint"
- with open(sanitize(endpoint, ""), "wt", encoding="utf8") as f:
+ with open(sanitize(endpoint, ""), "w", encoding="utf8") as f:
f.write(
"""
{
@@ -4391,17 +4646,21 @@ def test_feature_expansion_with_limit(self):
)
with open(
- sanitize(endpoint,
- "/Locations?$top=0&$count=true&$filter=location/type eq 'Polygon' or location/geometry/type eq 'Polygon'"),
- "wt",
+ sanitize(
+ endpoint,
+ "/Locations?$top=0&$count=true&$filter=location/type eq 'Polygon' or location/geometry/type eq 'Polygon'",
+ ),
+ "w",
encoding="utf8",
) as f:
f.write("""{"@iot.count":3,"value":[]}""")
with open(
- sanitize(endpoint,
- "/Locations?$top=2&$count=false&$expand=Things($expand=Datastreams($top=1))&$filter=location/type eq 'Polygon' or location/geometry/type eq 'Polygon'"),
- "wt",
+ sanitize(
+ endpoint,
+ "/Locations?$top=2&$count=false&$expand=Things($expand=Datastreams($top=1))&$filter=location/type eq 'Polygon' or location/geometry/type eq 'Polygon'",
+ ),
+ "w",
encoding="utf8",
) as f:
f.write(
@@ -4535,9 +4794,11 @@ def test_feature_expansion_with_limit(self):
)
with open(
- sanitize(endpoint,
- "/Locations?$top=2&$skip=2&$expand=Things($expand=Datastreams($top=1))&$filter=location/type eq 'Polygon' or location/geometry/type eq 'Polygon'"),
- "wt",
+ sanitize(
+ endpoint,
+ "/Locations?$top=2&$skip=2&$expand=Things($expand=Datastreams($top=1))&$filter=location/type eq 'Polygon' or location/geometry/type eq 'Polygon'",
+ ),
+ "w",
encoding="utf8",
) as f:
f.write(
@@ -4619,26 +4880,35 @@ def test_feature_expansion_with_limit(self):
self.assertEqual(vl.wkbType(), Qgis.WkbType.MultiPolygonZ)
self.assertEqual(vl.featureCount(), -1)
- self.assertEqual(vl.crs().authid(), 'EPSG:4326')
- self.assertIn("Entity TypeLocation ",
- vl.htmlMetadata())
- self.assertIn(f'href="http://{endpoint}/Locations"',
- vl.htmlMetadata())
+ self.assertEqual(vl.crs().authid(), "EPSG:4326")
+ self.assertIn("Entity TypeLocation ", vl.htmlMetadata())
+ self.assertIn(f'href="http://{endpoint}/Locations"', vl.htmlMetadata())
self.assertEqual(
[f.name() for f in vl.fields()],
- ['id', 'selfLink', 'name', 'description', 'properties',
- 'Thing_id', 'Thing_selfLink', 'Thing_name',
- 'Thing_description', 'Thing_properties',
- 'Thing_Datastream_id', 'Thing_Datastream_selfLink',
- 'Thing_Datastream_name', 'Thing_Datastream_description',
- 'Thing_Datastream_unitOfMeasurement',
- 'Thing_Datastream_observationType',
- 'Thing_Datastream_properties',
- 'Thing_Datastream_phenomenonTimeStart',
- 'Thing_Datastream_phenomenonTimeEnd',
- 'Thing_Datastream_resultTimeStart',
- 'Thing_Datastream_resultTimeEnd'],
+ [
+ "id",
+ "selfLink",
+ "name",
+ "description",
+ "properties",
+ "Thing_id",
+ "Thing_selfLink",
+ "Thing_name",
+ "Thing_description",
+ "Thing_properties",
+ "Thing_Datastream_id",
+ "Thing_Datastream_selfLink",
+ "Thing_Datastream_name",
+ "Thing_Datastream_description",
+ "Thing_Datastream_unitOfMeasurement",
+ "Thing_Datastream_observationType",
+ "Thing_Datastream_properties",
+ "Thing_Datastream_phenomenonTimeStart",
+ "Thing_Datastream_phenomenonTimeEnd",
+ "Thing_Datastream_resultTimeStart",
+ "Thing_Datastream_resultTimeEnd",
+ ],
)
self.assertEqual(
[f.type() for f in vl.fields()],
@@ -4669,82 +4939,70 @@ def test_feature_expansion_with_limit(self):
# test retrieving all features from layer
features = list(vl.getFeatures())
- self.assertEqual([f.id() for f in features],
- [0, 1, 2])
- self.assertEqual([f["id"] for f in features],
- ["1", "2", "3"])
+ self.assertEqual([f.id() for f in features], [0, 1, 2])
+ self.assertEqual([f["id"] for f in features], ["1", "2", "3"])
self.assertEqual(
[f["selfLink"][-13:] for f in features],
- ["/Locations(1)", "/Locations(2)",
- "/Locations(3)"],
+ ["/Locations(1)", "/Locations(2)", "/Locations(3)"],
)
self.assertEqual(
[f["name"] for f in features],
- ["Location 1", "Location 2",
- "Location 3"],
+ ["Location 1", "Location 2", "Location 3"],
)
self.assertEqual(
- [f["description"] for f in features],
- ["Desc 1", "Desc 2",
- "Desc 3"]
+ [f["description"] for f in features], ["Desc 1", "Desc 2", "Desc 3"]
)
self.assertEqual(
[f["properties"] for f in features],
- [{'owner': 'owner 1'},
- {'owner': 'owner 2'},
- {'owner': 'owner 3'}]
- )
- self.assertEqual(
- [f["Thing_id"] for f in features],
- ['1', '2', '8']
+ [{"owner": "owner 1"}, {"owner": "owner 2"}, {"owner": "owner 3"}],
)
+ self.assertEqual([f["Thing_id"] for f in features], ["1", "2", "8"])
self.assertEqual(
[f["Thing_selfLink"][-10:] for f in features],
- ['/Things(1)', '/Things(2)', '/Things(8)']
+ ["/Things(1)", "/Things(2)", "/Things(8)"],
)
self.assertEqual(
- [f["Thing_name"] for f in features],
- ['Thing 1', 'Thing 2', 'Thing 8']
+ [f["Thing_name"] for f in features], ["Thing 1", "Thing 2", "Thing 8"]
)
self.assertEqual(
[f["Thing_description"] for f in features],
- ['Description Thing 1', 'Description Thing 2',
- 'Description Thing 8']
+ ["Description Thing 1", "Description Thing 2", "Description Thing 8"],
)
self.assertEqual(
[f["Thing_properties"] for f in features],
- [{'countryCode': 'AT'}, {'countryCode': 'AT'},
- {'countryCode': 'AT'}]
+ [{"countryCode": "AT"}, {"countryCode": "AT"}, {"countryCode": "AT"}],
)
self.assertEqual(
- [f["Thing_Datastream_id"] for f in features],
- ['45', '51', '59']
+ [f["Thing_Datastream_id"] for f in features], ["45", "51", "59"]
)
self.assertEqual(
[f["Thing_Datastream_selfLink"][-16:] for f in features],
- ['/Datastreams(45)', '/Datastreams(51)',
- '/Datastreams(59)']
+ ["/Datastreams(45)", "/Datastreams(51)", "/Datastreams(59)"],
)
self.assertEqual(
[f["Thing_Datastream_name"] for f in features],
- ['Datastream 45', 'Datastream 51', 'Datastream 59']
+ ["Datastream 45", "Datastream 51", "Datastream 59"],
)
self.assertEqual(
[f["Thing_Datastream_description"] for f in features],
- ['Description datastream 45', 'Description datastream 51',
- 'Description datastream 59']
+ [
+ "Description datastream 45",
+ "Description datastream 51",
+ "Description datastream 59",
+ ],
)
self.assertEqual(
[f["Thing_Datastream_properties"] for f in features],
- [{'owner': 'someone'}, {'owner': 'someone'},
- {'owner': 'someone'}]
+ [{"owner": "someone"}, {"owner": "someone"}, {"owner": "someone"}],
)
self.assertEqual(
[f.geometry().asWkt() for f in features],
- ['Polygon ((100 0, 101 0, 101 1, 100 1, 100 0))',
- 'Polygon ((102 0, 103 0, 103 1, 102 1, 102 0))',
- 'Polygon ((103 0, 104 0, 104 1, 103 1, 103 0))'],
+ [
+ "Polygon ((100 0, 101 0, 101 1, 100 1, 100 0))",
+ "Polygon ((102 0, 103 0, 103 1, 102 1, 102 0))",
+ "Polygon ((103 0, 104 0, 104 1, 103 1, 103 0))",
+ ],
)
def testDecodeUri(self):
@@ -4811,7 +5069,7 @@ def testDecodeUri(self):
"entity": "Location",
"geometryType": "polygon",
"authcfg": "abc",
- "bounds": QgsRectangle(1, 2, 3, 4)
+ "bounds": QgsRectangle(1, 2, 3, 4),
},
)
@@ -4824,7 +5082,7 @@ def testDecodeUri(self):
"entity": "Location",
"geometryType": "polygon",
"authcfg": "abc",
- "sql": "name eq 'test'"
+ "sql": "name eq 'test'",
},
)
@@ -4837,7 +5095,7 @@ def testDecodeUri(self):
"entity": "Location",
"geometryType": "polygon",
"authcfg": "abc",
- "featureLimit": 50
+ "featureLimit": 50,
},
)
@@ -4850,12 +5108,14 @@ def testDecodeUri(self):
"entity": "Location",
"geometryType": "polygon",
"authcfg": "abc",
- "expandTo": [QgsSensorThingsExpansionDefinition(
- Qgis.SensorThingsEntity.Thing, orderBy='description',
- limit=5),
+ "expandTo": [
QgsSensorThingsExpansionDefinition(
- Qgis.SensorThingsEntity.Datastream,
- orderBy='time', limit=3)],
+ Qgis.SensorThingsEntity.Thing, orderBy="description", limit=5
+ ),
+ QgsSensorThingsExpansionDefinition(
+ Qgis.SensorThingsEntity.Datastream, orderBy="time", limit=3
+ ),
+ ],
},
)
@@ -4917,7 +5177,7 @@ def testEncodeUri(self):
"authcfg": "aaaaa",
"entity": "location",
"geometryType": "polygon",
- "bounds": QgsRectangle(1, 2, 3, 4)
+ "bounds": QgsRectangle(1, 2, 3, 4),
}
uri = QgsProviderRegistry.instance().encodeUri("sensorthings", parts)
self.assertEqual(
@@ -4930,7 +5190,7 @@ def testEncodeUri(self):
"authcfg": "aaaaa",
"entity": "location",
"geometryType": "polygon",
- "sql": "name eq 'test'"
+ "sql": "name eq 'test'",
}
uri = QgsProviderRegistry.instance().encodeUri("sensorthings", parts)
self.assertEqual(
@@ -4943,7 +5203,7 @@ def testEncodeUri(self):
"authcfg": "aaaaa",
"entity": "location",
"geometryType": "polygon",
- "featureLimit": 50
+ "featureLimit": 50,
}
uri = QgsProviderRegistry.instance().encodeUri("sensorthings", parts)
self.assertEqual(
@@ -4956,8 +5216,14 @@ def testEncodeUri(self):
"authcfg": "aaaaa",
"entity": "location",
"geometryType": "polygon",
- "expandTo": [QgsSensorThingsExpansionDefinition(Qgis.SensorThingsEntity.Thing, orderBy='description', limit=5),
- QgsSensorThingsExpansionDefinition(Qgis.SensorThingsEntity.Datastream, orderBy='time', limit=3)]
+ "expandTo": [
+ QgsSensorThingsExpansionDefinition(
+ Qgis.SensorThingsEntity.Thing, orderBy="description", limit=5
+ ),
+ QgsSensorThingsExpansionDefinition(
+ Qgis.SensorThingsEntity.Datastream, orderBy="time", limit=3
+ ),
+ ],
}
uri = QgsProviderRegistry.instance().encodeUri("sensorthings", parts)
self.assertEqual(
diff --git a/tests/src/python/test_provider_shapefile.py b/tests/src/python/test_provider_shapefile.py
index 180e54da95ba..ab1291a54a4a 100644
--- a/tests/src/python/test_provider_shapefile.py
+++ b/tests/src/python/test_provider_shapefile.py
@@ -5,9 +5,10 @@
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
"""
-__author__ = 'Matthias Kuhn'
-__date__ = '2015-04-23'
-__copyright__ = 'Copyright 2015, The QGIS Project'
+
+__author__ = "Matthias Kuhn"
+__date__ = "2015-04-23"
+__copyright__ = "Copyright 2015, The QGIS Project"
import glob
import os
@@ -47,10 +48,10 @@
def GDAL_COMPUTE_VERSION(maj, min, rev):
- return ((maj) * 1000000 + (min) * 10000 + (rev) * 100)
+ return (maj) * 1000000 + (min) * 10000 + (rev) * 100
-class ErrorReceiver():
+class ErrorReceiver:
def __init__(self):
self.msg = None
@@ -64,24 +65,24 @@ class TestPyQgsShapefileProvider(QgisTestCase, ProviderTestCase):
@classmethod
def setUpClass(cls):
"""Run before all tests"""
- super(TestPyQgsShapefileProvider, cls).setUpClass()
+ super().setUpClass()
# Create test layer
cls.basetestpath = tempfile.mkdtemp()
cls.repackfilepath = tempfile.mkdtemp()
- srcpath = os.path.join(TEST_DATA_DIR, 'provider')
- for file in glob.glob(os.path.join(srcpath, 'shapefile.*')):
+ srcpath = os.path.join(TEST_DATA_DIR, "provider")
+ for file in glob.glob(os.path.join(srcpath, "shapefile.*")):
shutil.copy(os.path.join(srcpath, file), cls.basetestpath)
shutil.copy(os.path.join(srcpath, file), cls.repackfilepath)
- for file in glob.glob(os.path.join(srcpath, 'shapefile_poly.*')):
+ for file in glob.glob(os.path.join(srcpath, "shapefile_poly.*")):
shutil.copy(os.path.join(srcpath, file), cls.basetestpath)
- cls.basetestfile = os.path.join(cls.basetestpath, 'shapefile.shp')
- cls.repackfile = os.path.join(cls.repackfilepath, 'shapefile.shp')
- cls.basetestpolyfile = os.path.join(cls.basetestpath, 'shapefile_poly.shp')
- cls.vl = QgsVectorLayer(f'{cls.basetestfile}|layerid=0', 'test', 'ogr')
+ cls.basetestfile = os.path.join(cls.basetestpath, "shapefile.shp")
+ cls.repackfile = os.path.join(cls.repackfilepath, "shapefile.shp")
+ cls.basetestpolyfile = os.path.join(cls.basetestpath, "shapefile_poly.shp")
+ cls.vl = QgsVectorLayer(f"{cls.basetestfile}|layerid=0", "test", "ogr")
assert cls.vl.isValid()
cls.source = cls.vl.dataProvider()
- cls.vl_poly = QgsVectorLayer(f'{cls.basetestpolyfile}|layerid=0', 'test', 'ogr')
+ cls.vl_poly = QgsVectorLayer(f"{cls.basetestpolyfile}|layerid=0", "test", "ogr")
assert cls.vl_poly.isValid()
cls.poly_provider = cls.vl_poly.dataProvider()
@@ -94,7 +95,7 @@ def tearDownClass(cls):
del cls.vl_poly
for dirname in cls.dirs_to_cleanup:
shutil.rmtree(dirname, True)
- super(TestPyQgsShapefileProvider, cls).tearDownClass()
+ super().tearDownClass()
def treat_time_as_string(self):
return True
@@ -105,166 +106,174 @@ def treat_datetime_as_string(self):
def getSource(self):
tmpdir = tempfile.mkdtemp()
self.dirs_to_cleanup.append(tmpdir)
- srcpath = os.path.join(TEST_DATA_DIR, 'provider')
- for file in glob.glob(os.path.join(srcpath, 'shapefile.*')):
+ srcpath = os.path.join(TEST_DATA_DIR, "provider")
+ for file in glob.glob(os.path.join(srcpath, "shapefile.*")):
shutil.copy(os.path.join(srcpath, file), tmpdir)
- datasource = os.path.join(tmpdir, 'shapefile.shp')
+ datasource = os.path.join(tmpdir, "shapefile.shp")
- vl = QgsVectorLayer(f'{datasource}|layerid=0', 'test', 'ogr')
+ vl = QgsVectorLayer(f"{datasource}|layerid=0", "test", "ogr")
return vl
def getEditableLayer(self):
return self.getSource()
def enableCompiler(self):
- QgsSettings().setValue('/qgis/compileExpressions', True)
+ QgsSettings().setValue("/qgis/compileExpressions", True)
return True
def disableCompiler(self):
- QgsSettings().setValue('/qgis/compileExpressions', False)
+ QgsSettings().setValue("/qgis/compileExpressions", False)
def uncompiledFilters(self):
- filters = {'name ILIKE \'QGIS\'',
- '"name" NOT LIKE \'Ap%\'',
- '"name" NOT ILIKE \'QGIS\'',
- '"name" NOT ILIKE \'pEAR\'',
- 'name <> \'Apple\'',
- '"name" <> \'apple\'',
- '(name = \'Apple\') is not null',
- 'name ILIKE \'aPple\'',
- 'name ILIKE \'%pp%\'',
- 'cnt = 1100 % 1000',
- '"name" || \' \' || "name" = \'Orange Orange\'',
- '"name" || \' \' || "cnt" = \'Orange 100\'',
- '\'x\' || "name" IS NOT NULL',
- '\'x\' || "name" IS NULL',
- 'cnt = 10 ^ 2',
- '"name" ~ \'[OP]ra[gne]+\'',
- 'false and NULL',
- 'true and NULL',
- 'NULL and false',
- 'NULL and true',
- 'NULL and NULL',
- 'false or NULL',
- 'true or NULL',
- 'NULL or false',
- 'NULL or true',
- 'NULL or NULL',
- 'not name = \'Apple\'',
- 'not name = \'Apple\' or name = \'Apple\'',
- 'not name = \'Apple\' or not name = \'Apple\'',
- 'not name = \'Apple\' and pk = 4',
- 'not name = \'Apple\' and not pk = 4',
- 'num_char IN (2, 4, 5)',
- '-cnt > 0',
- '-cnt < 0',
- '-cnt - 1 = -101',
- '-(-cnt) = 100',
- '-(cnt) = -(100)',
- 'sqrt(pk) >= 2',
- 'radians(cnt) < 2',
- 'degrees(pk) <= 200',
- 'abs(cnt) <= 200',
- 'cos(pk) < 0',
- 'sin(pk) < 0',
- 'tan(pk) < 0',
- 'acos(-1) < pk',
- 'asin(1) < pk',
- 'atan(3.14) < pk',
- 'atan2(3.14, pk) < 1',
- 'exp(pk) < 10',
- 'ln(pk) <= 1',
- 'log(3, pk) <= 1',
- 'log10(pk) < 0.5',
- 'round(3.14) <= pk',
- 'round(0.314,1) * 10 = pk',
- 'floor(3.14) <= pk',
- 'ceil(3.14) <= pk',
- 'pk < pi()',
- 'round(cnt / 66.67) <= 2',
- 'floor(cnt / 66.67) <= 2',
- 'ceil(cnt / 66.67) <= 2',
- 'pk < pi() / 2',
- 'pk = char(51)',
- 'pk = coalesce(NULL,3,4)',
- 'lower(name) = \'apple\'',
- 'upper(name) = \'APPLE\'',
- 'name = trim(\' Apple \')',
- 'x($geometry) < -70',
- 'y($geometry) > 70',
- 'xmin($geometry) < -70',
- 'ymin($geometry) > 70',
- 'xmax($geometry) < -70',
- 'ymax($geometry) > 70',
- 'disjoint($geometry,geom_from_wkt( \'Polygon ((-72.2 66.1, -65.2 66.1, -65.2 72.0, -72.2 72.0, -72.2 66.1))\'))',
- 'intersects($geometry,geom_from_wkt( \'Polygon ((-72.2 66.1, -65.2 66.1, -65.2 72.0, -72.2 72.0, -72.2 66.1))\'))',
- 'contains(geom_from_wkt( \'Polygon ((-72.2 66.1, -65.2 66.1, -65.2 72.0, -72.2 72.0, -72.2 66.1))\'),$geometry)',
- 'distance($geometry,geom_from_wkt( \'Point (-70 70)\')) > 7',
- 'intersects($geometry,geom_from_gml( \'-72.2,66.1 -65.2,66.1 -65.2,72.0 -72.2,72.0 -72.2,66.1 \'))',
- 'x($geometry) < -70',
- 'y($geometry) > 79',
- 'xmin($geometry) < -70',
- 'ymin($geometry) < 76',
- 'xmax($geometry) > -68',
- 'ymax($geometry) > 80',
- 'area($geometry) > 10',
- 'perimeter($geometry) < 12',
- 'relate($geometry,geom_from_wkt( \'Polygon ((-68.2 82.1, -66.95 82.1, -66.95 79.05, -68.2 79.05, -68.2 82.1))\')) = \'FF2FF1212\'',
- 'relate($geometry,geom_from_wkt( \'Polygon ((-68.2 82.1, -66.95 82.1, -66.95 79.05, -68.2 79.05, -68.2 82.1))\'), \'****F****\')',
- 'crosses($geometry,geom_from_wkt( \'Linestring (-68.2 82.1, -66.95 82.1, -66.95 79.05)\'))',
- 'overlaps($geometry,geom_from_wkt( \'Polygon ((-68.2 82.1, -66.95 82.1, -66.95 79.05, -68.2 79.05, -68.2 82.1))\'))',
- 'within($geometry,geom_from_wkt( \'Polygon ((-75.1 76.1, -75.1 81.6, -68.8 81.6, -68.8 76.1, -75.1 76.1))\'))',
- 'overlaps(translate($geometry,-1,-1),geom_from_wkt( \'Polygon ((-75.1 76.1, -75.1 81.6, -68.8 81.6, -68.8 76.1, -75.1 76.1))\'))',
- 'overlaps(buffer($geometry,1),geom_from_wkt( \'Polygon ((-75.1 76.1, -75.1 81.6, -68.8 81.6, -68.8 76.1, -75.1 76.1))\'))',
- 'intersects(centroid($geometry),geom_from_wkt( \'Polygon ((-74.4 78.2, -74.4 79.1, -66.8 79.1, -66.8 78.2, -74.4 78.2))\'))',
- 'intersects(point_on_surface($geometry),geom_from_wkt( \'Polygon ((-74.4 78.2, -74.4 79.1, -66.8 79.1, -66.8 78.2, -74.4 78.2))\'))',
- '"dt" <= format_date(make_datetime(2020, 5, 4, 12, 13, 14), \'yyyy-MM-dd hh:mm:ss\')',
- '"dt" < format_date(make_date(2020, 5, 4), \'yyyy-MM-dd hh:mm:ss\')',
- '"dt" = format_date(to_datetime(\'000www14ww13ww12www4ww5ww2020\',\'zzzwwwsswwmmwwhhwwwdwwMwwyyyy\'),\'yyyy-MM-dd hh:mm:ss\')',
- """dt BETWEEN format_date(make_datetime(2020, 5, 3, 12, 13, 14), 'yyyy-MM-dd hh:mm:ss') AND format_date(make_datetime(2020, 5, 4, 12, 14, 14), 'yyyy-MM-dd hh:mm:ss')""",
- """dt NOT BETWEEN format_date(make_datetime(2020, 5, 3, 12, 13, 14), 'yyyy-MM-dd hh:mm:ss') AND format_date(make_datetime(2020, 5, 4, 12, 14, 14), 'yyyy-MM-dd hh:mm:ss')""",
- '"date" = to_date(\'www4ww5ww2020\',\'wwwdwwMwwyyyy\')',
- 'to_time("time") >= make_time(12, 14, 14)',
- 'to_time("time") = to_time(\'000www14ww13ww12www\',\'zzzwwwsswwmmwwhhwww\')',
- 'to_datetime("dt", \'yyyy-MM-dd hh:mm:ss\') + make_interval(days:=1) <= make_datetime(2020, 5, 4, 12, 13, 14)',
- 'to_datetime("dt", \'yyyy-MM-dd hh:mm:ss\') + make_interval(days:=0.01) <= make_datetime(2020, 5, 4, 12, 13, 14)',
- 'cnt BETWEEN -200 AND 200' # NoUnaryMinus
- }
+ filters = {
+ "name ILIKE 'QGIS'",
+ "\"name\" NOT LIKE 'Ap%'",
+ "\"name\" NOT ILIKE 'QGIS'",
+ "\"name\" NOT ILIKE 'pEAR'",
+ "name <> 'Apple'",
+ "\"name\" <> 'apple'",
+ "(name = 'Apple') is not null",
+ "name ILIKE 'aPple'",
+ "name ILIKE '%pp%'",
+ "cnt = 1100 % 1000",
+ "\"name\" || ' ' || \"name\" = 'Orange Orange'",
+ "\"name\" || ' ' || \"cnt\" = 'Orange 100'",
+ "'x' || \"name\" IS NOT NULL",
+ "'x' || \"name\" IS NULL",
+ "cnt = 10 ^ 2",
+ "\"name\" ~ '[OP]ra[gne]+'",
+ "false and NULL",
+ "true and NULL",
+ "NULL and false",
+ "NULL and true",
+ "NULL and NULL",
+ "false or NULL",
+ "true or NULL",
+ "NULL or false",
+ "NULL or true",
+ "NULL or NULL",
+ "not name = 'Apple'",
+ "not name = 'Apple' or name = 'Apple'",
+ "not name = 'Apple' or not name = 'Apple'",
+ "not name = 'Apple' and pk = 4",
+ "not name = 'Apple' and not pk = 4",
+ "num_char IN (2, 4, 5)",
+ "-cnt > 0",
+ "-cnt < 0",
+ "-cnt - 1 = -101",
+ "-(-cnt) = 100",
+ "-(cnt) = -(100)",
+ "sqrt(pk) >= 2",
+ "radians(cnt) < 2",
+ "degrees(pk) <= 200",
+ "abs(cnt) <= 200",
+ "cos(pk) < 0",
+ "sin(pk) < 0",
+ "tan(pk) < 0",
+ "acos(-1) < pk",
+ "asin(1) < pk",
+ "atan(3.14) < pk",
+ "atan2(3.14, pk) < 1",
+ "exp(pk) < 10",
+ "ln(pk) <= 1",
+ "log(3, pk) <= 1",
+ "log10(pk) < 0.5",
+ "round(3.14) <= pk",
+ "round(0.314,1) * 10 = pk",
+ "floor(3.14) <= pk",
+ "ceil(3.14) <= pk",
+ "pk < pi()",
+ "round(cnt / 66.67) <= 2",
+ "floor(cnt / 66.67) <= 2",
+ "ceil(cnt / 66.67) <= 2",
+ "pk < pi() / 2",
+ "pk = char(51)",
+ "pk = coalesce(NULL,3,4)",
+ "lower(name) = 'apple'",
+ "upper(name) = 'APPLE'",
+ "name = trim(' Apple ')",
+ "x($geometry) < -70",
+ "y($geometry) > 70",
+ "xmin($geometry) < -70",
+ "ymin($geometry) > 70",
+ "xmax($geometry) < -70",
+ "ymax($geometry) > 70",
+ "disjoint($geometry,geom_from_wkt( 'Polygon ((-72.2 66.1, -65.2 66.1, -65.2 72.0, -72.2 72.0, -72.2 66.1))'))",
+ "intersects($geometry,geom_from_wkt( 'Polygon ((-72.2 66.1, -65.2 66.1, -65.2 72.0, -72.2 72.0, -72.2 66.1))'))",
+ "contains(geom_from_wkt( 'Polygon ((-72.2 66.1, -65.2 66.1, -65.2 72.0, -72.2 72.0, -72.2 66.1))'),$geometry)",
+ "distance($geometry,geom_from_wkt( 'Point (-70 70)')) > 7",
+ "intersects($geometry,geom_from_gml( '-72.2,66.1 -65.2,66.1 -65.2,72.0 -72.2,72.0 -72.2,66.1 '))",
+ "x($geometry) < -70",
+ "y($geometry) > 79",
+ "xmin($geometry) < -70",
+ "ymin($geometry) < 76",
+ "xmax($geometry) > -68",
+ "ymax($geometry) > 80",
+ "area($geometry) > 10",
+ "perimeter($geometry) < 12",
+ "relate($geometry,geom_from_wkt( 'Polygon ((-68.2 82.1, -66.95 82.1, -66.95 79.05, -68.2 79.05, -68.2 82.1))')) = 'FF2FF1212'",
+ "relate($geometry,geom_from_wkt( 'Polygon ((-68.2 82.1, -66.95 82.1, -66.95 79.05, -68.2 79.05, -68.2 82.1))'), '****F****')",
+ "crosses($geometry,geom_from_wkt( 'Linestring (-68.2 82.1, -66.95 82.1, -66.95 79.05)'))",
+ "overlaps($geometry,geom_from_wkt( 'Polygon ((-68.2 82.1, -66.95 82.1, -66.95 79.05, -68.2 79.05, -68.2 82.1))'))",
+ "within($geometry,geom_from_wkt( 'Polygon ((-75.1 76.1, -75.1 81.6, -68.8 81.6, -68.8 76.1, -75.1 76.1))'))",
+ "overlaps(translate($geometry,-1,-1),geom_from_wkt( 'Polygon ((-75.1 76.1, -75.1 81.6, -68.8 81.6, -68.8 76.1, -75.1 76.1))'))",
+ "overlaps(buffer($geometry,1),geom_from_wkt( 'Polygon ((-75.1 76.1, -75.1 81.6, -68.8 81.6, -68.8 76.1, -75.1 76.1))'))",
+ "intersects(centroid($geometry),geom_from_wkt( 'Polygon ((-74.4 78.2, -74.4 79.1, -66.8 79.1, -66.8 78.2, -74.4 78.2))'))",
+ "intersects(point_on_surface($geometry),geom_from_wkt( 'Polygon ((-74.4 78.2, -74.4 79.1, -66.8 79.1, -66.8 78.2, -74.4 78.2))'))",
+ "\"dt\" <= format_date(make_datetime(2020, 5, 4, 12, 13, 14), 'yyyy-MM-dd hh:mm:ss')",
+ "\"dt\" < format_date(make_date(2020, 5, 4), 'yyyy-MM-dd hh:mm:ss')",
+ "\"dt\" = format_date(to_datetime('000www14ww13ww12www4ww5ww2020','zzzwwwsswwmmwwhhwwwdwwMwwyyyy'),'yyyy-MM-dd hh:mm:ss')",
+ """dt BETWEEN format_date(make_datetime(2020, 5, 3, 12, 13, 14), 'yyyy-MM-dd hh:mm:ss') AND format_date(make_datetime(2020, 5, 4, 12, 14, 14), 'yyyy-MM-dd hh:mm:ss')""",
+ """dt NOT BETWEEN format_date(make_datetime(2020, 5, 3, 12, 13, 14), 'yyyy-MM-dd hh:mm:ss') AND format_date(make_datetime(2020, 5, 4, 12, 14, 14), 'yyyy-MM-dd hh:mm:ss')""",
+ "\"date\" = to_date('www4ww5ww2020','wwwdwwMwwyyyy')",
+ 'to_time("time") >= make_time(12, 14, 14)',
+ "to_time(\"time\") = to_time('000www14ww13ww12www','zzzwwwsswwmmwwhhwww')",
+ "to_datetime(\"dt\", 'yyyy-MM-dd hh:mm:ss') + make_interval(days:=1) <= make_datetime(2020, 5, 4, 12, 13, 14)",
+ "to_datetime(\"dt\", 'yyyy-MM-dd hh:mm:ss') + make_interval(days:=0.01) <= make_datetime(2020, 5, 4, 12, 13, 14)",
+ "cnt BETWEEN -200 AND 200", # NoUnaryMinus
+ }
return filters
def partiallyCompiledFilters(self):
- return {'name = \'Apple\'',
- 'name = \'apple\'',
- '\"NaMe\" = \'Apple\'',
- 'name LIKE \'Apple\'',
- 'name LIKE \'aPple\'',
- 'name LIKE \'Ap_le\'',
- 'name LIKE \'Ap\\_le\'',
- '"name"="name2"'}
+ return {
+ "name = 'Apple'",
+ "name = 'apple'",
+ "\"NaMe\" = 'Apple'",
+ "name LIKE 'Apple'",
+ "name LIKE 'aPple'",
+ "name LIKE 'Ap_le'",
+ "name LIKE 'Ap\\_le'",
+ '"name"="name2"',
+ }
def testRepack(self):
- vl = QgsVectorLayer(f'{self.repackfile}|layerid=0', 'test', 'ogr')
+ vl = QgsVectorLayer(f"{self.repackfile}|layerid=0", "test", "ogr")
- ids = [f.id() for f in vl.getFeatures(QgsFeatureRequest().setFilterExpression('pk=1'))]
+ ids = [
+ f.id()
+ for f in vl.getFeatures(QgsFeatureRequest().setFilterExpression("pk=1"))
+ ]
vl.selectByIds(ids)
self.assertEqual(vl.selectedFeatureIds(), ids)
self.assertEqual(vl.featureCount(), 5)
self.assertTrue(vl.startEditing())
self.assertTrue(vl.deleteFeature(3))
self.assertTrue(vl.commitChanges())
- self.assertTrue(vl.selectedFeatureCount() == 0 or vl.selectedFeatures()[0]['pk'] == 1)
+ self.assertTrue(
+ vl.selectedFeatureCount() == 0 or vl.selectedFeatures()[0]["pk"] == 1
+ )
def testUpdateMode(self):
- """ Test that on-the-fly re-opening in update/read-only mode works """
+ """Test that on-the-fly re-opening in update/read-only mode works"""
tmpdir = tempfile.mkdtemp()
self.dirs_to_cleanup.append(tmpdir)
- srcpath = os.path.join(TEST_DATA_DIR, 'provider')
- for file in glob.glob(os.path.join(srcpath, 'shapefile.*')):
+ srcpath = os.path.join(TEST_DATA_DIR, "provider")
+ for file in glob.glob(os.path.join(srcpath, "shapefile.*")):
shutil.copy(os.path.join(srcpath, file), tmpdir)
- datasource = os.path.join(tmpdir, 'shapefile.shp')
+ datasource = os.path.join(tmpdir, "shapefile.shp")
- vl = QgsVectorLayer(f'{datasource}|layerid=0', 'test', 'ogr')
+ vl = QgsVectorLayer(f"{datasource}|layerid=0", "test", "ogr")
caps = vl.dataProvider().capabilities()
self.assertTrue(caps & QgsVectorDataProvider.Capability.AddFeatures)
self.assertTrue(caps & QgsVectorDataProvider.Capability.DeleteFeatures)
@@ -299,23 +308,31 @@ def testUpdateMode(self):
f = QgsFeature()
f.setAttributes([200])
- f.setGeometry(QgsGeometry.fromWkt('Point (2 49)'))
+ f.setGeometry(QgsGeometry.fromWkt("Point (2 49)"))
(ret, feature_list) = vl.dataProvider().addFeatures([f])
self.assertTrue(ret)
fid = feature_list[0].id()
- features = [f_iter for f_iter in vl.getFeatures(QgsFeatureRequest().setFilterFid(fid))]
- values = [f_iter['pk'] for f_iter in features]
+ features = [
+ f_iter for f_iter in vl.getFeatures(QgsFeatureRequest().setFilterFid(fid))
+ ]
+ values = [f_iter["pk"] for f_iter in features]
self.assertEqual(values, [200])
got_geom = [f_iter.geometry() for f_iter in features][0].constGet()
self.assertEqual((got_geom.x(), got_geom.y()), (2.0, 49.0))
- self.assertTrue(vl.dataProvider().changeGeometryValues({fid: QgsGeometry.fromWkt('Point (3 50)')}))
+ self.assertTrue(
+ vl.dataProvider().changeGeometryValues(
+ {fid: QgsGeometry.fromWkt("Point (3 50)")}
+ )
+ )
self.assertTrue(vl.dataProvider().changeAttributeValues({fid: {0: 100}}))
- features = [f_iter for f_iter in vl.getFeatures(QgsFeatureRequest().setFilterFid(fid))]
- values = [f_iter['pk'] for f_iter in features]
+ features = [
+ f_iter for f_iter in vl.getFeatures(QgsFeatureRequest().setFilterFid(fid))
+ ]
+ values = [f_iter["pk"] for f_iter in features]
got_geom = [f_iter.geometry() for f_iter in features][0].constGet()
self.assertEqual((got_geom.x(), got_geom.y()), (3.0, 50.0))
@@ -323,13 +340,21 @@ def testUpdateMode(self):
self.assertTrue(vl.dataProvider().deleteFeatures([fid]))
# Check that it has really disappeared
- osgeo.gdal.PushErrorHandler('CPLQuietErrorHandler')
- features = [f_iter for f_iter in vl.getFeatures(QgsFeatureRequest().setFilterFid(fid))]
+ osgeo.gdal.PushErrorHandler("CPLQuietErrorHandler")
+ features = [
+ f_iter for f_iter in vl.getFeatures(QgsFeatureRequest().setFilterFid(fid))
+ ]
osgeo.gdal.PopErrorHandler()
self.assertEqual(features, [])
- self.assertTrue(vl.dataProvider().addAttributes([QgsField("new_field", QVariant.Int, "integer")]))
- self.assertTrue(vl.dataProvider().deleteAttributes([len(vl.dataProvider().fields()) - 1]))
+ self.assertTrue(
+ vl.dataProvider().addAttributes(
+ [QgsField("new_field", QVariant.Int, "integer")]
+ )
+ )
+ self.assertTrue(
+ vl.dataProvider().deleteAttributes([len(vl.dataProvider().fields()) - 1])
+ )
self.assertTrue(vl.startEditing())
self.assertEqual(vl.dataProvider().property("_debug_open_mode"), "read-write")
@@ -353,21 +378,21 @@ def testUpdateMode(self):
self.assertEqual(vl.dataProvider().property("_debug_open_mode"), "read-write")
def testUpdateModeFailedReopening(self):
- ''' Test that methods on provider don't crash after a failed reopening '''
+ """Test that methods on provider don't crash after a failed reopening"""
# Windows doesn't like removing files opened by OGR, whatever
# their open mode, so that makes it hard to test
- if sys.platform == 'win32':
+ if sys.platform == "win32":
return
tmpdir = tempfile.mkdtemp()
self.dirs_to_cleanup.append(tmpdir)
- srcpath = os.path.join(TEST_DATA_DIR, 'provider')
- for file in glob.glob(os.path.join(srcpath, 'shapefile.*')):
+ srcpath = os.path.join(TEST_DATA_DIR, "provider")
+ for file in glob.glob(os.path.join(srcpath, "shapefile.*")):
shutil.copy(os.path.join(srcpath, file), tmpdir)
- datasource = os.path.join(tmpdir, 'shapefile.shp')
+ datasource = os.path.join(tmpdir, "shapefile.shp")
- vl = QgsVectorLayer(f'{datasource}|layerid=0', 'test', 'ogr')
+ vl = QgsVectorLayer(f"{datasource}|layerid=0", "test", "ogr")
os.unlink(datasource)
@@ -378,29 +403,33 @@ def testUpdateModeFailedReopening(self):
self.assertFalse(vl.dataProvider().isValid())
self.assertEqual(len([f for f in vl.dataProvider().getFeatures()]), 0)
self.assertEqual(len(vl.dataProvider().subLayers()), 0)
- self.assertFalse(vl.dataProvider().setSubsetString('TRUE'))
+ self.assertFalse(vl.dataProvider().setSubsetString("TRUE"))
(ret, _) = vl.dataProvider().addFeatures([QgsFeature()])
self.assertFalse(ret)
self.assertFalse(vl.dataProvider().deleteFeatures([1]))
self.assertFalse(vl.dataProvider().addAttributes([QgsField()]))
self.assertFalse(vl.dataProvider().deleteAttributes([1]))
- self.assertFalse(vl.dataProvider().changeGeometryValues({0: QgsGeometry.fromWkt('Point (3 50)')}))
+ self.assertFalse(
+ vl.dataProvider().changeGeometryValues(
+ {0: QgsGeometry.fromWkt("Point (3 50)")}
+ )
+ )
self.assertFalse(vl.dataProvider().changeAttributeValues({0: {0: 0}}))
self.assertFalse(vl.dataProvider().createSpatialIndex())
self.assertFalse(vl.dataProvider().createAttributeIndex(0))
def testreloadData(self):
- ''' Test reloadData() '''
+ """Test reloadData()"""
tmpdir = tempfile.mkdtemp()
self.dirs_to_cleanup.append(tmpdir)
- srcpath = os.path.join(TEST_DATA_DIR, 'provider')
- for file in glob.glob(os.path.join(srcpath, 'shapefile.*')):
+ srcpath = os.path.join(TEST_DATA_DIR, "provider")
+ for file in glob.glob(os.path.join(srcpath, "shapefile.*")):
shutil.copy(os.path.join(srcpath, file), tmpdir)
- datasource = os.path.join(tmpdir, 'shapefile.shp')
+ datasource = os.path.join(tmpdir, "shapefile.shp")
- vl1 = QgsVectorLayer(f'{datasource}|layerid=0', 'test', 'ogr')
- vl2 = QgsVectorLayer(f'{datasource}|layerid=0', 'test', 'ogr')
+ vl1 = QgsVectorLayer(f"{datasource}|layerid=0", "test", "ogr")
+ vl2 = QgsVectorLayer(f"{datasource}|layerid=0", "test", "ogr")
self.assertTrue(vl1.startEditing())
self.assertTrue(vl1.deleteAttributes([1]))
self.assertTrue(vl1.commitChanges())
@@ -411,80 +440,80 @@ def testreloadData(self):
self.assertEqual(len(vl1.fields()), len(vl2.fields()))
def testRenameAttributes(self):
- ''' Test renameAttributes() '''
+ """Test renameAttributes()"""
tmpdir = tempfile.mkdtemp()
self.dirs_to_cleanup.append(tmpdir)
- srcpath = os.path.join(TEST_DATA_DIR, 'provider')
- for file in glob.glob(os.path.join(srcpath, 'shapefile.*')):
+ srcpath = os.path.join(TEST_DATA_DIR, "provider")
+ for file in glob.glob(os.path.join(srcpath, "shapefile.*")):
shutil.copy(os.path.join(srcpath, file), tmpdir)
- datasource = os.path.join(tmpdir, 'shapefile.shp')
+ datasource = os.path.join(tmpdir, "shapefile.shp")
- vl = QgsVectorLayer(f'{datasource}|layerid=0', 'test', 'ogr')
+ vl = QgsVectorLayer(f"{datasource}|layerid=0", "test", "ogr")
provider = vl.dataProvider()
# bad rename
- self.assertFalse(provider.renameAttributes({-1: 'not_a_field'}))
- self.assertFalse(provider.renameAttributes({100: 'not_a_field'}))
+ self.assertFalse(provider.renameAttributes({-1: "not_a_field"}))
+ self.assertFalse(provider.renameAttributes({100: "not_a_field"}))
# already exists
- self.assertFalse(provider.renameAttributes({2: 'cnt'}))
+ self.assertFalse(provider.renameAttributes({2: "cnt"}))
# rename one field
- self.assertTrue(provider.renameAttributes({2: 'newname'}))
- self.assertEqual(provider.fields().at(2).name(), 'newname')
+ self.assertTrue(provider.renameAttributes({2: "newname"}))
+ self.assertEqual(provider.fields().at(2).name(), "newname")
vl.updateFields()
fet = next(vl.getFeatures())
- self.assertEqual(fet.fields()[2].name(), 'newname')
+ self.assertEqual(fet.fields()[2].name(), "newname")
# rename two fields
- self.assertTrue(provider.renameAttributes({2: 'newname2', 3: 'another'}))
- self.assertEqual(provider.fields().at(2).name(), 'newname2')
- self.assertEqual(provider.fields().at(3).name(), 'another')
+ self.assertTrue(provider.renameAttributes({2: "newname2", 3: "another"}))
+ self.assertEqual(provider.fields().at(2).name(), "newname2")
+ self.assertEqual(provider.fields().at(3).name(), "another")
vl.updateFields()
fet = next(vl.getFeatures())
- self.assertEqual(fet.fields()[2].name(), 'newname2')
- self.assertEqual(fet.fields()[3].name(), 'another')
+ self.assertEqual(fet.fields()[2].name(), "newname2")
+ self.assertEqual(fet.fields()[3].name(), "another")
# close file and reopen, then recheck to confirm that changes were saved to file
del vl
vl = None
- vl = QgsVectorLayer(f'{datasource}|layerid=0', 'test', 'ogr')
+ vl = QgsVectorLayer(f"{datasource}|layerid=0", "test", "ogr")
provider = vl.dataProvider()
- self.assertEqual(provider.fields().at(2).name(), 'newname2')
- self.assertEqual(provider.fields().at(3).name(), 'another')
+ self.assertEqual(provider.fields().at(2).name(), "newname2")
+ self.assertEqual(provider.fields().at(3).name(), "another")
fet = next(vl.getFeatures())
- self.assertEqual(fet.fields()[2].name(), 'newname2')
- self.assertEqual(fet.fields()[3].name(), 'another')
+ self.assertEqual(fet.fields()[2].name(), "newname2")
+ self.assertEqual(fet.fields()[3].name(), "another")
def testDeleteGeometry(self):
- ''' Test changeGeometryValues() with a null geometry '''
+ """Test changeGeometryValues() with a null geometry"""
tmpdir = tempfile.mkdtemp()
self.dirs_to_cleanup.append(tmpdir)
- srcpath = os.path.join(TEST_DATA_DIR, 'provider')
- for file in glob.glob(os.path.join(srcpath, 'shapefile.*')):
+ srcpath = os.path.join(TEST_DATA_DIR, "provider")
+ for file in glob.glob(os.path.join(srcpath, "shapefile.*")):
shutil.copy(os.path.join(srcpath, file), tmpdir)
- datasource = os.path.join(tmpdir, 'shapefile.shp')
+ datasource = os.path.join(tmpdir, "shapefile.shp")
- vl = QgsVectorLayer(f'{datasource}|layerid=0', 'test', 'ogr')
+ vl = QgsVectorLayer(f"{datasource}|layerid=0", "test", "ogr")
self.assertTrue(vl.dataProvider().changeGeometryValues({0: QgsGeometry()}))
vl = None
- vl = QgsVectorLayer(f'{datasource}|layerid=0', 'test', 'ogr')
+ vl = QgsVectorLayer(f"{datasource}|layerid=0", "test", "ogr")
fet = next(vl.getFeatures())
self.assertFalse(fet.hasGeometry())
def testDeleteShapes(self):
- ''' Test fix for #11007 '''
+ """Test fix for #11007"""
tmpdir = tempfile.mkdtemp()
self.dirs_to_cleanup.append(tmpdir)
- srcpath = os.path.join(TEST_DATA_DIR, 'provider')
- for file in glob.glob(os.path.join(srcpath, 'shapefile.*')):
+ srcpath = os.path.join(TEST_DATA_DIR, "provider")
+ for file in glob.glob(os.path.join(srcpath, "shapefile.*")):
shutil.copy(os.path.join(srcpath, file), tmpdir)
- datasource = os.path.join(tmpdir, 'shapefile.shp')
+ datasource = os.path.join(tmpdir, "shapefile.shp")
- vl = QgsVectorLayer(f'{datasource}|layerid=0', 'test', 'ogr')
+ vl = QgsVectorLayer(f"{datasource}|layerid=0", "test", "ogr")
feature_count = vl.featureCount()
# Start an iterator that will open a new connection
iterator = vl.getFeatures()
@@ -520,16 +549,16 @@ def testDeleteShapes(self):
vl = None
def testDontRepackOnReload(self):
- ''' Test fix for #18421 '''
+ """Test fix for #18421"""
tmpdir = tempfile.mkdtemp()
self.dirs_to_cleanup.append(tmpdir)
- srcpath = os.path.join(TEST_DATA_DIR, 'provider')
- for file in glob.glob(os.path.join(srcpath, 'shapefile.*')):
+ srcpath = os.path.join(TEST_DATA_DIR, "provider")
+ for file in glob.glob(os.path.join(srcpath, "shapefile.*")):
shutil.copy(os.path.join(srcpath, file), tmpdir)
- datasource = os.path.join(tmpdir, 'shapefile.shp')
+ datasource = os.path.join(tmpdir, "shapefile.shp")
- vl = QgsVectorLayer(f'{datasource}|layerid=0', 'test', 'ogr')
+ vl = QgsVectorLayer(f"{datasource}|layerid=0", "test", "ogr")
feature_count = vl.featureCount()
# Start an iterator that will open a new connection
iterator = vl.getFeatures()
@@ -548,21 +577,21 @@ def testDontRepackOnReload(self):
vl = None
def testRepackUnderFileLocks(self):
- ''' Test fix for #15570 and #15393 '''
+ """Test fix for #15570 and #15393"""
tmpdir = tempfile.mkdtemp()
self.dirs_to_cleanup.append(tmpdir)
- srcpath = os.path.join(TEST_DATA_DIR, 'provider')
- for file in glob.glob(os.path.join(srcpath, 'shapefile.*')):
+ srcpath = os.path.join(TEST_DATA_DIR, "provider")
+ for file in glob.glob(os.path.join(srcpath, "shapefile.*")):
shutil.copy(os.path.join(srcpath, file), tmpdir)
- datasource = os.path.join(tmpdir, 'shapefile.shp')
+ datasource = os.path.join(tmpdir, "shapefile.shp")
- vl = QgsVectorLayer(f'{datasource}|layerid=0', 'test', 'ogr')
+ vl = QgsVectorLayer(f"{datasource}|layerid=0", "test", "ogr")
feature_count = vl.featureCount()
# Keep a file descriptor opened on the .dbf, .shp and .shx
- f_shp = open(os.path.join(tmpdir, 'shapefile.shp'), 'rb')
- f_shx = open(os.path.join(tmpdir, 'shapefile.shx'), 'rb')
- f_dbf = open(os.path.join(tmpdir, 'shapefile.dbf'), 'rb')
+ f_shp = open(os.path.join(tmpdir, "shapefile.shp"), "rb")
+ f_shx = open(os.path.join(tmpdir, "shapefile.shx"), "rb")
+ f_dbf = open(os.path.join(tmpdir, "shapefile.dbf"), "rb")
# Delete a feature
self.assertTrue(vl.startEditing())
@@ -586,13 +615,13 @@ def testRepackUnderFileLocks(self):
ds = None
def testRepackAtFirstSave(self):
- ''' Test fix for #15407 '''
+ """Test fix for #15407"""
tmpdir = tempfile.mkdtemp()
self.dirs_to_cleanup.append(tmpdir)
- srcpath = os.path.join(TEST_DATA_DIR, 'provider')
- for file in glob.glob(os.path.join(srcpath, 'shapefile.*')):
+ srcpath = os.path.join(TEST_DATA_DIR, "provider")
+ for file in glob.glob(os.path.join(srcpath, "shapefile.*")):
shutil.copy(os.path.join(srcpath, file), tmpdir)
- datasource = os.path.join(tmpdir, 'shapefile.shp')
+ datasource = os.path.join(tmpdir, "shapefile.shp")
ds = osgeo.ogr.Open(datasource, update=1)
lyr = ds.GetLayer(0)
@@ -600,7 +629,7 @@ def testRepackAtFirstSave(self):
lyr.DeleteFeature(2)
ds = None
- vl = QgsVectorLayer(f'{datasource}|layerid=0', 'test', 'ogr')
+ vl = QgsVectorLayer(f"{datasource}|layerid=0", "test", "ogr")
self.assertTrue(vl.featureCount(), original_feature_count)
@@ -624,8 +653,8 @@ def testRepackAtFirstSave(self):
ds = None
def testOpenWithFilter(self):
- file_path = os.path.join(TEST_DATA_DIR, 'provider', 'shapefile.shp')
- uri = f'{file_path}|layerid=0|subset="name" = \'Apple\''
+ file_path = os.path.join(TEST_DATA_DIR, "provider", "shapefile.shp")
+ uri = f"{file_path}|layerid=0|subset=\"name\" = 'Apple'"
options = QgsDataProvider.ProviderOptions()
# ensure that no longer required ogr SQL layers are correctly cleaned up
# we need to run this twice for the incorrect cleanup asserts to trip,
@@ -633,80 +662,83 @@ def testOpenWithFilter(self):
# connection pool
for i in range(2):
vl = QgsVectorLayer(uri)
- self.assertTrue(vl.isValid(), f'Layer not valid, iteration {i + 1}')
+ self.assertTrue(vl.isValid(), f"Layer not valid, iteration {i + 1}")
self.assertEqual(vl.featureCount(), 1)
f = next(vl.getFeatures())
- self.assertEqual(f['name'], 'Apple')
+ self.assertEqual(f["name"], "Apple")
# force close of data provider
- vl.setDataSource('', 'test', 'ogr', options)
+ vl.setDataSource("", "test", "ogr", options)
def testEncoding_iso(self):
- file_path = os.path.join(TEST_DATA_DIR, 'shapefile', 'iso-8859-1.shp')
+ file_path = os.path.join(TEST_DATA_DIR, "shapefile", "iso-8859-1.shp")
vl = QgsVectorLayer(file_path)
self.assertTrue(vl.isValid())
- self.assertEqual(vl.dataProvider().encoding(), 'ISO-8859-1')
- self.assertEqual(next(vl.getFeatures())[1], 'äöü')
+ self.assertEqual(vl.dataProvider().encoding(), "ISO-8859-1")
+ self.assertEqual(next(vl.getFeatures())[1], "äöü")
- file_path = os.path.join(TEST_DATA_DIR, 'shapefile', 'iso-8859-1_ldid.shp')
+ file_path = os.path.join(TEST_DATA_DIR, "shapefile", "iso-8859-1_ldid.shp")
vl = QgsVectorLayer(file_path)
self.assertTrue(vl.isValid())
- self.assertEqual(vl.dataProvider().encoding(), 'ISO-8859-1')
- self.assertEqual(next(vl.getFeatures())[1], 'äöü')
+ self.assertEqual(vl.dataProvider().encoding(), "ISO-8859-1")
+ self.assertEqual(next(vl.getFeatures())[1], "äöü")
- file_path = os.path.join(TEST_DATA_DIR, 'shapefile', 'latin1.shp')
+ file_path = os.path.join(TEST_DATA_DIR, "shapefile", "latin1.shp")
vl = QgsVectorLayer(file_path)
self.assertTrue(vl.isValid())
- self.assertEqual(vl.dataProvider().encoding(), 'ISO-8859-1')
- self.assertEqual(next(vl.getFeatures())[1], 'äöü')
+ self.assertEqual(vl.dataProvider().encoding(), "ISO-8859-1")
+ self.assertEqual(next(vl.getFeatures())[1], "äöü")
- file_path = os.path.join(TEST_DATA_DIR, 'shapefile', 'utf8.shp')
+ file_path = os.path.join(TEST_DATA_DIR, "shapefile", "utf8.shp")
vl = QgsVectorLayer(file_path)
self.assertTrue(vl.isValid())
- self.assertEqual(vl.dataProvider().encoding(), 'UTF-8')
- self.assertEqual(next(vl.getFeatures())[1], 'äöü')
+ self.assertEqual(vl.dataProvider().encoding(), "UTF-8")
+ self.assertEqual(next(vl.getFeatures())[1], "äöü")
- file_path = os.path.join(TEST_DATA_DIR, 'shapefile', 'windows-1252.shp')
+ file_path = os.path.join(TEST_DATA_DIR, "shapefile", "windows-1252.shp")
vl = QgsVectorLayer(file_path)
self.assertTrue(vl.isValid())
- self.assertEqual(vl.dataProvider().encoding(), 'windows-1252')
- self.assertEqual(next(vl.getFeatures())[1], 'äöü')
+ self.assertEqual(vl.dataProvider().encoding(), "windows-1252")
+ self.assertEqual(next(vl.getFeatures())[1], "äöü")
- file_path = os.path.join(TEST_DATA_DIR, 'shapefile', 'windows-1252_ldid.shp')
+ file_path = os.path.join(TEST_DATA_DIR, "shapefile", "windows-1252_ldid.shp")
vl = QgsVectorLayer(file_path)
self.assertTrue(vl.isValid())
- self.assertEqual(vl.dataProvider().encoding(), 'windows-1252')
- self.assertEqual(next(vl.getFeatures())[1], 'äöü')
+ self.assertEqual(vl.dataProvider().encoding(), "windows-1252")
+ self.assertEqual(next(vl.getFeatures())[1], "äöü")
- if int(gdal.VersionInfo('VERSION_NUM')) >= GDAL_COMPUTE_VERSION(3, 1, 0):
+ if int(gdal.VersionInfo("VERSION_NUM")) >= GDAL_COMPUTE_VERSION(3, 1, 0):
# correct autodetection of vsizip based shapefiles depends on GDAL 3.1
- file_path = os.path.join(TEST_DATA_DIR, 'shapefile', 'windows-1252.zip')
- vl = QgsVectorLayer(f'/vsizip/{file_path}')
+ file_path = os.path.join(TEST_DATA_DIR, "shapefile", "windows-1252.zip")
+ vl = QgsVectorLayer(f"/vsizip/{file_path}")
self.assertTrue(vl.isValid())
- self.assertEqual(vl.dataProvider().encoding(), 'windows-1252')
- self.assertEqual(next(vl.getFeatures())[1], 'äöü')
+ self.assertEqual(vl.dataProvider().encoding(), "windows-1252")
+ self.assertEqual(next(vl.getFeatures())[1], "äöü")
- file_path = os.path.join(TEST_DATA_DIR, 'shapefile', 'system_encoding.shp')
+ file_path = os.path.join(TEST_DATA_DIR, "shapefile", "system_encoding.shp")
vl = QgsVectorLayer(file_path)
self.assertTrue(vl.isValid())
# no encoding hints, so it should default to UTF-8 (which is wrong for this particular file, but the correct guess to make first!)
- self.assertEqual(vl.dataProvider().encoding(), 'UTF-8')
- self.assertNotEqual(next(vl.getFeatures())[1], 'äöü')
+ self.assertEqual(vl.dataProvider().encoding(), "UTF-8")
+ self.assertNotEqual(next(vl.getFeatures())[1], "äöü")
# set to correct encoding
- vl.dataProvider().setEncoding('ISO-8859-1')
- self.assertEqual(vl.dataProvider().encoding(), 'ISO-8859-1')
- self.assertEqual(next(vl.getFeatures())[1], 'äöü')
+ vl.dataProvider().setEncoding("ISO-8859-1")
+ self.assertEqual(vl.dataProvider().encoding(), "ISO-8859-1")
+ self.assertEqual(next(vl.getFeatures())[1], "äöü")
def testCreateAttributeIndex(self):
tmpdir = tempfile.mkdtemp()
self.dirs_to_cleanup.append(tmpdir)
- srcpath = os.path.join(TEST_DATA_DIR, 'provider')
- for file in glob.glob(os.path.join(srcpath, 'shapefile.*')):
+ srcpath = os.path.join(TEST_DATA_DIR, "provider")
+ for file in glob.glob(os.path.join(srcpath, "shapefile.*")):
shutil.copy(os.path.join(srcpath, file), tmpdir)
- datasource = os.path.join(tmpdir, 'shapefile.shp')
+ datasource = os.path.join(tmpdir, "shapefile.shp")
- vl = QgsVectorLayer(f'{datasource}|layerid=0', 'test', 'ogr')
+ vl = QgsVectorLayer(f"{datasource}|layerid=0", "test", "ogr")
self.assertTrue(vl.isValid())
- self.assertTrue(vl.dataProvider().capabilities() & QgsVectorDataProvider.Capability.CreateAttributeIndex)
+ self.assertTrue(
+ vl.dataProvider().capabilities()
+ & QgsVectorDataProvider.Capability.CreateAttributeIndex
+ )
self.assertFalse(vl.dataProvider().createAttributeIndex(-1))
self.assertFalse(vl.dataProvider().createAttributeIndex(100))
self.assertTrue(vl.dataProvider().createAttributeIndex(1))
@@ -714,181 +746,206 @@ def testCreateAttributeIndex(self):
def testCreateSpatialIndex(self):
tmpdir = tempfile.mkdtemp()
self.dirs_to_cleanup.append(tmpdir)
- srcpath = os.path.join(TEST_DATA_DIR, 'provider')
- for file in glob.glob(os.path.join(srcpath, 'shapefile.*')):
+ srcpath = os.path.join(TEST_DATA_DIR, "provider")
+ for file in glob.glob(os.path.join(srcpath, "shapefile.*")):
shutil.copy(os.path.join(srcpath, file), tmpdir)
- datasource = os.path.join(tmpdir, 'shapefile.shp')
+ datasource = os.path.join(tmpdir, "shapefile.shp")
- vl = QgsVectorLayer(f'{datasource}|layerid=0', 'test', 'ogr')
+ vl = QgsVectorLayer(f"{datasource}|layerid=0", "test", "ogr")
self.assertTrue(vl.isValid())
- self.assertTrue(vl.dataProvider().capabilities() & QgsVectorDataProvider.Capability.CreateSpatialIndex)
+ self.assertTrue(
+ vl.dataProvider().capabilities()
+ & QgsVectorDataProvider.Capability.CreateSpatialIndex
+ )
self.assertTrue(vl.dataProvider().createSpatialIndex())
def testSubSetStringEditable_bug17795_but_with_modified_behavior(self):
"""Test that a layer is still editable after setting a subset"""
- testPath = TEST_DATA_DIR + '/' + 'lines.shp'
+ testPath = TEST_DATA_DIR + "/" + "lines.shp"
isEditable = QgsVectorDataProvider.Capability.ChangeAttributeValues
- vl = QgsVectorLayer(testPath, 'subset_test', 'ogr')
+ vl = QgsVectorLayer(testPath, "subset_test", "ogr")
self.assertTrue(vl.isValid())
self.assertTrue(vl.dataProvider().capabilities() & isEditable)
- vl = QgsVectorLayer(testPath, 'subset_test', 'ogr')
- vl.setSubsetString('')
+ vl = QgsVectorLayer(testPath, "subset_test", "ogr")
+ vl.setSubsetString("")
self.assertTrue(vl.isValid())
self.assertTrue(vl.dataProvider().capabilities() & isEditable)
- vl = QgsVectorLayer(testPath, 'subset_test', 'ogr')
- vl.setSubsetString('"Name" = \'Arterial\'')
+ vl = QgsVectorLayer(testPath, "subset_test", "ogr")
+ vl.setSubsetString("\"Name\" = 'Arterial'")
self.assertTrue(vl.isValid())
self.assertTrue(vl.dataProvider().capabilities() & isEditable)
- vl.setSubsetString('')
+ vl.setSubsetString("")
self.assertTrue(vl.dataProvider().capabilities() & isEditable)
def testSubsetStringExtent_bug17863(self):
"""Check that the extent is correct when applied in the ctor and when
- modified after a subset string is set """
+ modified after a subset string is set"""
def _lessdigits(s):
- return re.sub(r'(\d+\.\d{3})\d+', r'\1', s)
+ return re.sub(r"(\d+\.\d{3})\d+", r"\1", s)
- testPath = TEST_DATA_DIR + '/' + 'points.shp'
- subSetString = '"Class" = \'Biplane\''
- subSet = f'|layerid=0|subset={subSetString}'
+ testPath = TEST_DATA_DIR + "/" + "points.shp"
+ subSetString = "\"Class\" = 'Biplane'"
+ subSet = f"|layerid=0|subset={subSetString}"
# unfiltered
- vl = QgsVectorLayer(testPath, 'test', 'ogr')
+ vl = QgsVectorLayer(testPath, "test", "ogr")
self.assertTrue(vl.isValid())
unfiltered_extent = _lessdigits(vl.extent().toString())
del vl
# filter after construction ...
- subSet_vl2 = QgsVectorLayer(testPath, 'test', 'ogr')
+ subSet_vl2 = QgsVectorLayer(testPath, "test", "ogr")
self.assertEqual(_lessdigits(subSet_vl2.extent().toString()), unfiltered_extent)
# ... apply filter now!
subSet_vl2.setSubsetString(subSetString)
self.assertEqual(subSet_vl2.subsetString(), subSetString)
- self.assertNotEqual(_lessdigits(subSet_vl2.extent().toString()), unfiltered_extent)
+ self.assertNotEqual(
+ _lessdigits(subSet_vl2.extent().toString()), unfiltered_extent
+ )
filtered_extent = _lessdigits(subSet_vl2.extent().toString())
del subSet_vl2
# filtered in constructor
- subSet_vl = QgsVectorLayer(testPath + subSet, 'subset_test', 'ogr')
+ subSet_vl = QgsVectorLayer(testPath + subSet, "subset_test", "ogr")
self.assertEqual(subSet_vl.subsetString(), subSetString)
self.assertTrue(subSet_vl.isValid())
# This was failing in bug 17863
self.assertEqual(_lessdigits(subSet_vl.extent().toString()), filtered_extent)
- self.assertNotEqual(_lessdigits(subSet_vl.extent().toString()), unfiltered_extent)
+ self.assertNotEqual(
+ _lessdigits(subSet_vl.extent().toString()), unfiltered_extent
+ )
def testMalformedSubsetStrings(self):
"""Test that invalid where clauses always return false"""
- testPath = TEST_DATA_DIR + '/' + 'lines.shp'
+ testPath = TEST_DATA_DIR + "/" + "lines.shp"
- vl = QgsVectorLayer(testPath, 'subset_test', 'ogr')
+ vl = QgsVectorLayer(testPath, "subset_test", "ogr")
self.assertTrue(vl.isValid())
- self.assertTrue(vl.setSubsetString(''))
- self.assertTrue(vl.setSubsetString('"Name" = \'Arterial\''))
- self.assertTrue(vl.setSubsetString('select * from lines where "Name" = \'Arterial\''))
- self.assertFalse(vl.setSubsetString('this is invalid sql'))
- self.assertFalse(vl.setSubsetString('select * from lines where "NonExistentField" = \'someValue\''))
- self.assertFalse(vl.setSubsetString('select * from lines where "Name" = \'Arte...'))
- self.assertFalse(vl.setSubsetString('select * from lines where "Name" in (\'Arterial\', \'Highway\' '))
- self.assertFalse(vl.setSubsetString('select * from NonExistentTable'))
- self.assertFalse(vl.setSubsetString('select NonExistentField from lines'))
- self.assertFalse(vl.setSubsetString('"NonExistentField" = \'someValue\''))
+ self.assertTrue(vl.setSubsetString(""))
+ self.assertTrue(vl.setSubsetString("\"Name\" = 'Arterial'"))
+ self.assertTrue(
+ vl.setSubsetString("select * from lines where \"Name\" = 'Arterial'")
+ )
+ self.assertFalse(vl.setSubsetString("this is invalid sql"))
+ self.assertFalse(
+ vl.setSubsetString(
+ "select * from lines where \"NonExistentField\" = 'someValue'"
+ )
+ )
+ self.assertFalse(
+ vl.setSubsetString('select * from lines where "Name" = \'Arte...')
+ )
+ self.assertFalse(
+ vl.setSubsetString(
+ "select * from lines where \"Name\" in ('Arterial', 'Highway' "
+ )
+ )
+ self.assertFalse(vl.setSubsetString("select * from NonExistentTable"))
+ self.assertFalse(vl.setSubsetString("select NonExistentField from lines"))
+ self.assertFalse(vl.setSubsetString("\"NonExistentField\" = 'someValue'"))
self.assertFalse(vl.setSubsetString('"Name" = \'Arte...'))
- self.assertFalse(vl.setSubsetString('"Name" in (\'Arterial\', \'Highway\' '))
- self.assertTrue(vl.setSubsetString(''))
+ self.assertFalse(vl.setSubsetString("\"Name\" in ('Arterial', 'Highway' "))
+ self.assertTrue(vl.setSubsetString(""))
def testMultipatch(self):
"""Check that we can deal with multipatch shapefiles, returned natively by OGR as GeometryCollection of TIN"""
- testPath = TEST_DATA_DIR + '/' + 'multipatch.shp'
- vl = QgsVectorLayer(testPath, 'test', 'ogr')
+ testPath = TEST_DATA_DIR + "/" + "multipatch.shp"
+ vl = QgsVectorLayer(testPath, "test", "ogr")
self.assertTrue(vl.isValid())
self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.MultiPolygonZ)
f = next(vl.getFeatures())
self.assertEqual(f.geometry().wkbType(), QgsWkbTypes.Type.MultiPolygonZ)
- self.assertEqual(f.geometry().constGet().asWkt(),
- 'MultiPolygon Z (((0 0 0, 0 1 0, 1 1 0, 0 0 0)),((0 0 0, 1 1 0, 1 0 0, 0 0 0)),((0 0 0, 0 -1 0, 1 -1 0, 0 0 0)),((0 0 0, 1 -1 0, 1 0 0, 0 0 0)))')
+ self.assertEqual(
+ f.geometry().constGet().asWkt(),
+ "MultiPolygon Z (((0 0 0, 0 1 0, 1 1 0, 0 0 0)),((0 0 0, 1 1 0, 1 0 0, 0 0 0)),((0 0 0, 0 -1 0, 1 -1 0, 0 0 0)),((0 0 0, 1 -1 0, 1 0 0, 0 0 0)))",
+ )
def testShzSupport(self):
- ''' Test support for single layer compressed shapefiles (.shz) '''
+ """Test support for single layer compressed shapefiles (.shz)"""
- if int(osgeo.gdal.VersionInfo('VERSION_NUM')) < GDAL_COMPUTE_VERSION(3, 1, 0):
+ if int(osgeo.gdal.VersionInfo("VERSION_NUM")) < GDAL_COMPUTE_VERSION(3, 1, 0):
return
- tmpfile = os.path.join(self.basetestpath, 'testShzSupport.shz')
- ds = osgeo.ogr.GetDriverByName('ESRI Shapefile').CreateDataSource(tmpfile)
- lyr = ds.CreateLayer('testShzSupport', geom_type=osgeo.ogr.wkbPoint)
- lyr.CreateField(osgeo.ogr.FieldDefn('attr', osgeo.ogr.OFTInteger))
+ tmpfile = os.path.join(self.basetestpath, "testShzSupport.shz")
+ ds = osgeo.ogr.GetDriverByName("ESRI Shapefile").CreateDataSource(tmpfile)
+ lyr = ds.CreateLayer("testShzSupport", geom_type=osgeo.ogr.wkbPoint)
+ lyr.CreateField(osgeo.ogr.FieldDefn("attr", osgeo.ogr.OFTInteger))
f = osgeo.ogr.Feature(lyr.GetLayerDefn())
- f.SetField('attr', 1)
- f.SetGeometry(osgeo.ogr.CreateGeometryFromWkt('POINT(0 0)'))
+ f.SetField("attr", 1)
+ f.SetGeometry(osgeo.ogr.CreateGeometryFromWkt("POINT(0 0)"))
lyr.CreateFeature(f)
f = None
ds = None
- vl = QgsVectorLayer(tmpfile, 'test', 'ogr')
+ vl = QgsVectorLayer(tmpfile, "test", "ogr")
self.assertTrue(vl.isValid())
self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.Point)
f = next(vl.getFeatures())
- assert f['attr'] == 1
- self.assertEqual(f.geometry().constGet().asWkt(), 'Point (0 0)')
+ assert f["attr"] == 1
+ self.assertEqual(f.geometry().constGet().asWkt(), "Point (0 0)")
self.assertTrue(vl.startEditing())
self.assertTrue(vl.changeAttributeValue(f.id(), 0, -1))
self.assertTrue(vl.commitChanges())
f = next(vl.getFeatures())
- assert f['attr'] == -1
+ assert f["attr"] == -1
# Check DataItem
registry = QgsApplication.dataItemProviderRegistry()
- files_provider = next(provider for provider in registry.providers() if provider.name() == 'files')
+ files_provider = next(
+ provider for provider in registry.providers() if provider.name() == "files"
+ )
item = files_provider.createDataItem(tmpfile, None)
- self.assertTrue(item.uri().endswith('testShzSupport.shz'))
+ self.assertTrue(item.uri().endswith("testShzSupport.shz"))
def testShpZipSupport(self):
- ''' Test support for multi layer compressed shapefiles (.shp.zip) '''
+ """Test support for multi layer compressed shapefiles (.shp.zip)"""
- if int(osgeo.gdal.VersionInfo('VERSION_NUM')) < GDAL_COMPUTE_VERSION(3, 1, 0):
+ if int(osgeo.gdal.VersionInfo("VERSION_NUM")) < GDAL_COMPUTE_VERSION(3, 1, 0):
return
- tmpfile = os.path.join(self.basetestpath, 'testShpZipSupport.shp.zip')
- ds = osgeo.ogr.GetDriverByName('ESRI Shapefile').CreateDataSource(tmpfile)
- lyr = ds.CreateLayer('layer1', geom_type=osgeo.ogr.wkbPoint)
- lyr.CreateField(osgeo.ogr.FieldDefn('attr', osgeo.ogr.OFTInteger))
+ tmpfile = os.path.join(self.basetestpath, "testShpZipSupport.shp.zip")
+ ds = osgeo.ogr.GetDriverByName("ESRI Shapefile").CreateDataSource(tmpfile)
+ lyr = ds.CreateLayer("layer1", geom_type=osgeo.ogr.wkbPoint)
+ lyr.CreateField(osgeo.ogr.FieldDefn("attr", osgeo.ogr.OFTInteger))
f = osgeo.ogr.Feature(lyr.GetLayerDefn())
- f.SetField('attr', 1)
- f.SetGeometry(osgeo.ogr.CreateGeometryFromWkt('POINT(0 0)'))
+ f.SetField("attr", 1)
+ f.SetGeometry(osgeo.ogr.CreateGeometryFromWkt("POINT(0 0)"))
lyr.CreateFeature(f)
f = None
- lyr = ds.CreateLayer('layer2', geom_type=osgeo.ogr.wkbMultiLineString)
- lyr.CreateField(osgeo.ogr.FieldDefn('attr', osgeo.ogr.OFTInteger))
+ lyr = ds.CreateLayer("layer2", geom_type=osgeo.ogr.wkbMultiLineString)
+ lyr.CreateField(osgeo.ogr.FieldDefn("attr", osgeo.ogr.OFTInteger))
f = osgeo.ogr.Feature(lyr.GetLayerDefn())
- f.SetField('attr', 2)
- f.SetGeometry(osgeo.ogr.CreateGeometryFromWkt('LINESTRING(0 0,1 1)'))
+ f.SetField("attr", 2)
+ f.SetGeometry(osgeo.ogr.CreateGeometryFromWkt("LINESTRING(0 0,1 1)"))
lyr.CreateFeature(f)
f = None
ds = None
- vl1 = QgsVectorLayer(tmpfile + '|layername=layer1', 'test', 'ogr')
- vl2 = QgsVectorLayer(tmpfile + '|layername=layer2', 'test', 'ogr')
+ vl1 = QgsVectorLayer(tmpfile + "|layername=layer1", "test", "ogr")
+ vl2 = QgsVectorLayer(tmpfile + "|layername=layer2", "test", "ogr")
self.assertTrue(vl1.isValid())
self.assertTrue(vl2.isValid())
self.assertEqual(vl1.wkbType(), QgsWkbTypes.Type.Point)
self.assertEqual(vl2.wkbType(), QgsWkbTypes.Type.MultiLineString)
f1 = next(vl1.getFeatures())
f2 = next(vl2.getFeatures())
- assert f1['attr'] == 1
- self.assertEqual(f1.geometry().constGet().asWkt(), 'Point (0 0)')
- assert f2['attr'] == 2
- self.assertEqual(f2.geometry().constGet().asWkt(), 'MultiLineString ((0 0, 1 1))')
+ assert f1["attr"] == 1
+ self.assertEqual(f1.geometry().constGet().asWkt(), "Point (0 0)")
+ assert f2["attr"] == 2
+ self.assertEqual(
+ f2.geometry().constGet().asWkt(), "MultiLineString ((0 0, 1 1))"
+ )
self.assertTrue(vl1.startEditing())
self.assertTrue(vl2.startEditing())
@@ -898,20 +955,22 @@ def testShpZipSupport(self):
self.assertTrue(vl2.commitChanges())
f = next(vl1.getFeatures())
- assert f['attr'] == -1
+ assert f["attr"] == -1
f = next(vl2.getFeatures())
- assert f['attr'] == -2
+ assert f["attr"] == -2
# Check DataItem
registry = QgsApplication.dataItemProviderRegistry()
- files_provider = next(provider for provider in registry.providers() if provider.name() == 'files')
+ files_provider = next(
+ provider for provider in registry.providers() if provider.name() == "files"
+ )
item = files_provider.createDataItem(tmpfile, None)
children = item.createChildren()
self.assertEqual(len(children), 2)
uris = sorted([children[i].uri() for i in range(2)])
- self.assertIn('testShpZipSupport.shp.zip|layername=layer1', uris[0])
- self.assertIn('testShpZipSupport.shp.zip|layername=layer2', uris[1])
+ self.assertIn("testShpZipSupport.shp.zip|layername=layer1", uris[0])
+ self.assertIn("testShpZipSupport.shp.zip|layername=layer2", uris[1])
def testWriteShapefileWithSingleConversion(self):
"""Check writing geometries from a POLYGON ESRI shapefile does not
@@ -924,41 +983,40 @@ def testWriteShapefileWithSingleConversion(self):
and not multi.
"""
- ml = QgsVectorLayer(
- ('Polygon?crs=epsg:4326&field=id:int'),
- 'test',
- 'memory')
+ ml = QgsVectorLayer(("Polygon?crs=epsg:4326&field=id:int"), "test", "memory")
provider = ml.dataProvider()
ft = QgsFeature()
- ft.setGeometry(QgsGeometry.fromWkt('Polygon ((0 0, 0 1, 1 1, 1 0, 0 0))'))
+ ft.setGeometry(QgsGeometry.fromWkt("Polygon ((0 0, 0 1, 1 1, 1 0, 0 0))"))
ft.setAttributes([1])
res, features = provider.addFeatures([ft])
- dest_file_name = os.path.join(self.basetestpath, 'multipart.shp')
- write_result, error_message = QgsVectorLayerExporter.exportLayer(ml,
- dest_file_name,
- 'ogr',
- ml.crs(),
- False,
- {"driverName": "ESRI Shapefile"}
- )
- self.assertEqual(write_result, QgsVectorLayerExporter.ExportError.NoError, error_message)
+ dest_file_name = os.path.join(self.basetestpath, "multipart.shp")
+ write_result, error_message = QgsVectorLayerExporter.exportLayer(
+ ml, dest_file_name, "ogr", ml.crs(), False, {"driverName": "ESRI Shapefile"}
+ )
+ self.assertEqual(
+ write_result, QgsVectorLayerExporter.ExportError.NoError, error_message
+ )
# Open the newly created layer
shapefile_layer = QgsVectorLayer(dest_file_name)
- dest_singlepart_file_name = os.path.join(self.basetestpath, 'singlepart.gpkg')
- write_result, error_message = QgsVectorLayerExporter.exportLayer(shapefile_layer,
- dest_singlepart_file_name,
- 'ogr',
- shapefile_layer.crs(),
- False,
- {
- "forceSinglePartGeometryType": True,
- "driverName": "GPKG",
- })
- self.assertEqual(write_result, QgsVectorLayerExporter.ExportError.NoError, error_message)
+ dest_singlepart_file_name = os.path.join(self.basetestpath, "singlepart.gpkg")
+ write_result, error_message = QgsVectorLayerExporter.exportLayer(
+ shapefile_layer,
+ dest_singlepart_file_name,
+ "ogr",
+ shapefile_layer.crs(),
+ False,
+ {
+ "forceSinglePartGeometryType": True,
+ "driverName": "GPKG",
+ },
+ )
+ self.assertEqual(
+ write_result, QgsVectorLayerExporter.ExportError.NoError, error_message
+ )
# Load result layer and check that it's NOT MULTI
single_layer = QgsVectorLayer(dest_singlepart_file_name)
@@ -966,17 +1024,21 @@ def testWriteShapefileWithSingleConversion(self):
self.assertTrue(QgsWkbTypes.isSingleType(single_layer.wkbType()))
# Now save the shapfile layer into a gpkg with no force options
- dest_multipart_file_name = os.path.join(self.basetestpath, 'multipart.gpkg')
- write_result, error_message = QgsVectorLayerExporter.exportLayer(shapefile_layer,
- dest_multipart_file_name,
- 'ogr',
- shapefile_layer.crs(),
- False,
- {
- "forceSinglePartGeometryType": False,
- "driverName": "GPKG",
- })
- self.assertEqual(write_result, QgsVectorLayerExporter.ExportError.NoError, error_message)
+ dest_multipart_file_name = os.path.join(self.basetestpath, "multipart.gpkg")
+ write_result, error_message = QgsVectorLayerExporter.exportLayer(
+ shapefile_layer,
+ dest_multipart_file_name,
+ "ogr",
+ shapefile_layer.crs(),
+ False,
+ {
+ "forceSinglePartGeometryType": False,
+ "driverName": "GPKG",
+ },
+ )
+ self.assertEqual(
+ write_result, QgsVectorLayerExporter.ExportError.NoError, error_message
+ )
# Load result layer and check that it's MULTI
multi_layer = QgsVectorLayer(dest_multipart_file_name)
self.assertTrue(multi_layer.isValid())
@@ -985,119 +1047,268 @@ def testWriteShapefileWithSingleConversion(self):
# Failing case: add a real multi to the shapefile and try to force to single
self.assertTrue(shapefile_layer.startEditing())
ft = QgsFeature()
- ft.setGeometry(QgsGeometry.fromWkt('MultiPolygon (((0 0, 0 1, 1 1, 1 0, 0 0)), ((-10 -10,-10 -9,-9 -9,-10 -10)))'))
+ ft.setGeometry(
+ QgsGeometry.fromWkt(
+ "MultiPolygon (((0 0, 0 1, 1 1, 1 0, 0 0)), ((-10 -10,-10 -9,-9 -9,-10 -10)))"
+ )
+ )
ft.setAttributes([2])
self.assertTrue(shapefile_layer.addFeatures([ft]))
self.assertTrue(shapefile_layer.commitChanges())
- dest_multipart_failure_file_name = os.path.join(self.basetestpath, 'multipart_failure.gpkg')
- write_result, error_message = QgsVectorLayerExporter.exportLayer(shapefile_layer,
- dest_multipart_failure_file_name,
- 'ogr',
- shapefile_layer.crs(),
- False,
- {
- "forceSinglePartGeometryType": True,
- "driverName": "GPKG",
- })
+ dest_multipart_failure_file_name = os.path.join(
+ self.basetestpath, "multipart_failure.gpkg"
+ )
+ write_result, error_message = QgsVectorLayerExporter.exportLayer(
+ shapefile_layer,
+ dest_multipart_failure_file_name,
+ "ogr",
+ shapefile_layer.crs(),
+ False,
+ {
+ "forceSinglePartGeometryType": True,
+ "driverName": "GPKG",
+ },
+ )
self.assertTrue(QgsWkbTypes.isMultiType(multi_layer.wkbType()))
- self.assertEqual(write_result, QgsVectorLayerExporter.ExportError.ErrFeatureWriteFailed, "Failed to transform a feature with ID '1' to single part. Writing stopped.")
+ self.assertEqual(
+ write_result,
+ QgsVectorLayerExporter.ExportError.ErrFeatureWriteFailed,
+ "Failed to transform a feature with ID '1' to single part. Writing stopped.",
+ )
def testReadingLayerGeometryTypes(self):
- tests = [(osgeo.ogr.wkbPoint, 'Point (0 0)', QgsWkbTypes.Type.Point, 'Point (0 0)'),
- (osgeo.ogr.wkbPoint25D, 'Point Z (0 0 1)', QgsWkbTypes.Type.PointZ, 'Point Z (0 0 1)'),
- (osgeo.ogr.wkbPointM, 'Point M (0 0 1)', QgsWkbTypes.Type.PointM, 'Point M (0 0 1)'),
- (osgeo.ogr.wkbPointZM, 'Point ZM (0 0 1 2)', QgsWkbTypes.Type.PointZM, 'Point ZM (0 0 1 2)'),
- (osgeo.ogr.wkbLineString, 'LineString (0 0, 1 1)', QgsWkbTypes.Type.MultiLineString, 'MultiLineString ((0 0, 1 1))'),
- (osgeo.ogr.wkbLineString25D, 'LineString Z (0 0 10, 1 1 10)', QgsWkbTypes.Type.MultiLineStringZ, 'MultiLineString Z ((0 0 10, 1 1 10))'),
- (osgeo.ogr.wkbLineStringM, 'LineString M (0 0 10, 1 1 10)', QgsWkbTypes.Type.MultiLineStringM, 'MultiLineString M ((0 0 10, 1 1 10))'),
- (osgeo.ogr.wkbLineStringZM, 'LineString ZM (0 0 10 20, 1 1 10 20)', QgsWkbTypes.Type.MultiLineStringZM, 'MultiLineString ZM ((0 0 10 20, 1 1 10 20))'),
- (osgeo.ogr.wkbPolygon, 'Polygon ((0 0,0 1,1 1,0 0))', QgsWkbTypes.Type.MultiPolygon, 'MultiPolygon (((0 0, 0 1, 1 1, 0 0)))'),
- (osgeo.ogr.wkbPolygon25D, 'Polygon Z ((0 0 10, 0 1 10, 1 1 10, 0 0 10))', QgsWkbTypes.Type.MultiPolygonZ, 'MultiPolygon Z (((0 0 10, 0 1 10, 1 1 10, 0 0 10)))'),
- (osgeo.ogr.wkbPolygonM, 'Polygon M ((0 0 10, 0 1 10, 1 1 10, 0 0 10))', QgsWkbTypes.Type.MultiPolygonM, 'MultiPolygon M (((0 0 10, 0 1 10, 1 1 10, 0 0 10)))'),
- (osgeo.ogr.wkbPolygonZM, 'Polygon ZM ((0 0 10 20, 0 1 10 20, 1 1 10 20, 0 0 10 20))', QgsWkbTypes.Type.MultiPolygonZM, 'MultiPolygon ZM (((0 0 10 20, 0 1 10 20, 1 1 10 20, 0 0 10 20)))'),
- (osgeo.ogr.wkbMultiPoint, 'MultiPoint (0 0,1 1)', QgsWkbTypes.Type.MultiPoint, 'MultiPoint ((0 0),(1 1))'),
- (osgeo.ogr.wkbMultiPoint25D, 'MultiPoint Z ((0 0 10), (1 1 10))', QgsWkbTypes.Type.MultiPointZ, 'MultiPoint Z ((0 0 10),(1 1 10))'),
- (osgeo.ogr.wkbMultiPointM, 'MultiPoint M ((0 0 10), (1 1 10))', QgsWkbTypes.Type.MultiPointM, 'MultiPoint M ((0 0 10),(1 1 10))'),
- (osgeo.ogr.wkbMultiPointZM, 'MultiPoint ZM ((0 0 10 20), (1 1 10 20))', QgsWkbTypes.Type.MultiPointZM, 'MultiPoint ZM ((0 0 10 20),(1 1 10 20))'),
- (osgeo.ogr.wkbMultiLineString, 'MultiLineString ((0 0, 1 1))', QgsWkbTypes.Type.MultiLineString, 'MultiLineString ((0 0, 1 1))'),
- (osgeo.ogr.wkbMultiLineString25D, 'MultiLineString Z ((0 0 10, 1 1 10))', QgsWkbTypes.Type.MultiLineStringZ, 'MultiLineString Z ((0 0 10, 1 1 10))'),
- (osgeo.ogr.wkbMultiLineStringM, 'MultiLineString M ((0 0 10, 1 1 10))', QgsWkbTypes.Type.MultiLineStringM, 'MultiLineString M ((0 0 10, 1 1 10))'),
- (osgeo.ogr.wkbMultiLineStringZM, 'MultiLineString ZM ((0 0 10 20, 1 1 10 20))', QgsWkbTypes.Type.MultiLineStringZM, 'MultiLineString ZM ((0 0 10 20, 1 1 10 20))'),
- (osgeo.ogr.wkbMultiPolygon, 'MultiPolygon (((0 0,0 1,1 1,0 0)))', QgsWkbTypes.Type.MultiPolygon, 'MultiPolygon (((0 0, 0 1, 1 1, 0 0)))'),
- (osgeo.ogr.wkbMultiPolygon25D, 'MultiPolygon Z (((0 0 10, 0 1 10, 1 1 10, 0 0 10)))', QgsWkbTypes.Type.MultiPolygonZ, 'MultiPolygon Z (((0 0 10, 0 1 10, 1 1 10, 0 0 10)))'),
- (osgeo.ogr.wkbMultiPolygonM, 'MultiPolygon M (((0 0 10, 0 1 10, 1 1 10, 0 0 10)))', QgsWkbTypes.Type.MultiPolygonM, 'MultiPolygon M (((0 0 10, 0 1 10, 1 1 10, 0 0 10)))'),
- (osgeo.ogr.wkbMultiPolygonZM, 'MultiPolygon ZM (((0 0 10 20, 0 1 10 20, 1 1 10 20, 0 0 10 20)))', QgsWkbTypes.Type.MultiPolygonZM, 'MultiPolygon ZM (((0 0 10 20, 0 1 10 20, 1 1 10 20, 0 0 10 20)))'),
- ]
+ tests = [
+ (osgeo.ogr.wkbPoint, "Point (0 0)", QgsWkbTypes.Type.Point, "Point (0 0)"),
+ (
+ osgeo.ogr.wkbPoint25D,
+ "Point Z (0 0 1)",
+ QgsWkbTypes.Type.PointZ,
+ "Point Z (0 0 1)",
+ ),
+ (
+ osgeo.ogr.wkbPointM,
+ "Point M (0 0 1)",
+ QgsWkbTypes.Type.PointM,
+ "Point M (0 0 1)",
+ ),
+ (
+ osgeo.ogr.wkbPointZM,
+ "Point ZM (0 0 1 2)",
+ QgsWkbTypes.Type.PointZM,
+ "Point ZM (0 0 1 2)",
+ ),
+ (
+ osgeo.ogr.wkbLineString,
+ "LineString (0 0, 1 1)",
+ QgsWkbTypes.Type.MultiLineString,
+ "MultiLineString ((0 0, 1 1))",
+ ),
+ (
+ osgeo.ogr.wkbLineString25D,
+ "LineString Z (0 0 10, 1 1 10)",
+ QgsWkbTypes.Type.MultiLineStringZ,
+ "MultiLineString Z ((0 0 10, 1 1 10))",
+ ),
+ (
+ osgeo.ogr.wkbLineStringM,
+ "LineString M (0 0 10, 1 1 10)",
+ QgsWkbTypes.Type.MultiLineStringM,
+ "MultiLineString M ((0 0 10, 1 1 10))",
+ ),
+ (
+ osgeo.ogr.wkbLineStringZM,
+ "LineString ZM (0 0 10 20, 1 1 10 20)",
+ QgsWkbTypes.Type.MultiLineStringZM,
+ "MultiLineString ZM ((0 0 10 20, 1 1 10 20))",
+ ),
+ (
+ osgeo.ogr.wkbPolygon,
+ "Polygon ((0 0,0 1,1 1,0 0))",
+ QgsWkbTypes.Type.MultiPolygon,
+ "MultiPolygon (((0 0, 0 1, 1 1, 0 0)))",
+ ),
+ (
+ osgeo.ogr.wkbPolygon25D,
+ "Polygon Z ((0 0 10, 0 1 10, 1 1 10, 0 0 10))",
+ QgsWkbTypes.Type.MultiPolygonZ,
+ "MultiPolygon Z (((0 0 10, 0 1 10, 1 1 10, 0 0 10)))",
+ ),
+ (
+ osgeo.ogr.wkbPolygonM,
+ "Polygon M ((0 0 10, 0 1 10, 1 1 10, 0 0 10))",
+ QgsWkbTypes.Type.MultiPolygonM,
+ "MultiPolygon M (((0 0 10, 0 1 10, 1 1 10, 0 0 10)))",
+ ),
+ (
+ osgeo.ogr.wkbPolygonZM,
+ "Polygon ZM ((0 0 10 20, 0 1 10 20, 1 1 10 20, 0 0 10 20))",
+ QgsWkbTypes.Type.MultiPolygonZM,
+ "MultiPolygon ZM (((0 0 10 20, 0 1 10 20, 1 1 10 20, 0 0 10 20)))",
+ ),
+ (
+ osgeo.ogr.wkbMultiPoint,
+ "MultiPoint (0 0,1 1)",
+ QgsWkbTypes.Type.MultiPoint,
+ "MultiPoint ((0 0),(1 1))",
+ ),
+ (
+ osgeo.ogr.wkbMultiPoint25D,
+ "MultiPoint Z ((0 0 10), (1 1 10))",
+ QgsWkbTypes.Type.MultiPointZ,
+ "MultiPoint Z ((0 0 10),(1 1 10))",
+ ),
+ (
+ osgeo.ogr.wkbMultiPointM,
+ "MultiPoint M ((0 0 10), (1 1 10))",
+ QgsWkbTypes.Type.MultiPointM,
+ "MultiPoint M ((0 0 10),(1 1 10))",
+ ),
+ (
+ osgeo.ogr.wkbMultiPointZM,
+ "MultiPoint ZM ((0 0 10 20), (1 1 10 20))",
+ QgsWkbTypes.Type.MultiPointZM,
+ "MultiPoint ZM ((0 0 10 20),(1 1 10 20))",
+ ),
+ (
+ osgeo.ogr.wkbMultiLineString,
+ "MultiLineString ((0 0, 1 1))",
+ QgsWkbTypes.Type.MultiLineString,
+ "MultiLineString ((0 0, 1 1))",
+ ),
+ (
+ osgeo.ogr.wkbMultiLineString25D,
+ "MultiLineString Z ((0 0 10, 1 1 10))",
+ QgsWkbTypes.Type.MultiLineStringZ,
+ "MultiLineString Z ((0 0 10, 1 1 10))",
+ ),
+ (
+ osgeo.ogr.wkbMultiLineStringM,
+ "MultiLineString M ((0 0 10, 1 1 10))",
+ QgsWkbTypes.Type.MultiLineStringM,
+ "MultiLineString M ((0 0 10, 1 1 10))",
+ ),
+ (
+ osgeo.ogr.wkbMultiLineStringZM,
+ "MultiLineString ZM ((0 0 10 20, 1 1 10 20))",
+ QgsWkbTypes.Type.MultiLineStringZM,
+ "MultiLineString ZM ((0 0 10 20, 1 1 10 20))",
+ ),
+ (
+ osgeo.ogr.wkbMultiPolygon,
+ "MultiPolygon (((0 0,0 1,1 1,0 0)))",
+ QgsWkbTypes.Type.MultiPolygon,
+ "MultiPolygon (((0 0, 0 1, 1 1, 0 0)))",
+ ),
+ (
+ osgeo.ogr.wkbMultiPolygon25D,
+ "MultiPolygon Z (((0 0 10, 0 1 10, 1 1 10, 0 0 10)))",
+ QgsWkbTypes.Type.MultiPolygonZ,
+ "MultiPolygon Z (((0 0 10, 0 1 10, 1 1 10, 0 0 10)))",
+ ),
+ (
+ osgeo.ogr.wkbMultiPolygonM,
+ "MultiPolygon M (((0 0 10, 0 1 10, 1 1 10, 0 0 10)))",
+ QgsWkbTypes.Type.MultiPolygonM,
+ "MultiPolygon M (((0 0 10, 0 1 10, 1 1 10, 0 0 10)))",
+ ),
+ (
+ osgeo.ogr.wkbMultiPolygonZM,
+ "MultiPolygon ZM (((0 0 10 20, 0 1 10 20, 1 1 10 20, 0 0 10 20)))",
+ QgsWkbTypes.Type.MultiPolygonZM,
+ "MultiPolygon ZM (((0 0 10 20, 0 1 10 20, 1 1 10 20, 0 0 10 20)))",
+ ),
+ ]
for ogr_type, wkt, qgis_type, expected_wkt in tests:
- filename = 'testPromoteToMulti'
+ filename = "testPromoteToMulti"
tmpfile = os.path.join(self.basetestpath, filename)
- ds = osgeo.ogr.GetDriverByName('ESRI Shapefile').CreateDataSource(tmpfile)
+ ds = osgeo.ogr.GetDriverByName("ESRI Shapefile").CreateDataSource(tmpfile)
lyr = ds.CreateLayer(filename, geom_type=ogr_type)
f = osgeo.ogr.Feature(lyr.GetLayerDefn())
f.SetGeometry(osgeo.ogr.CreateGeometryFromWkt(wkt))
lyr.CreateFeature(f)
ds = None
- vl = QgsVectorLayer(tmpfile, 'test', 'ogr')
+ vl = QgsVectorLayer(tmpfile, "test", "ogr")
self.assertTrue(vl.isValid())
self.assertEqual(vl.wkbType(), qgis_type)
f = next(vl.getFeatures())
self.assertEqual(f.geometry().constGet().asWkt(), expected_wkt)
del vl
- osgeo.ogr.GetDriverByName('ESRI Shapefile').DeleteDataSource(tmpfile)
+ osgeo.ogr.GetDriverByName("ESRI Shapefile").DeleteDataSource(tmpfile)
def testEncoding_cp852(self):
- """ Test that CP852 shapefile is read/written correctly """
+ """Test that CP852 shapefile is read/written correctly"""
tmpdir = tempfile.mkdtemp()
self.dirs_to_cleanup.append(tmpdir)
- for file in glob.glob(os.path.join(TEST_DATA_DIR, 'test_852.*')):
+ for file in glob.glob(os.path.join(TEST_DATA_DIR, "test_852.*")):
shutil.copy(os.path.join(TEST_DATA_DIR, file), tmpdir)
- datasource = os.path.join(tmpdir, 'test_852.shp')
+ datasource = os.path.join(tmpdir, "test_852.shp")
- vl = QgsVectorLayer(datasource, 'test')
+ vl = QgsVectorLayer(datasource, "test")
self.assertTrue(vl.isValid())
- self.assertEqual([f.attributes() for f in vl.dataProvider().getFeatures()], [['abcŐ']])
+ self.assertEqual(
+ [f.attributes() for f in vl.dataProvider().getFeatures()], [["abcŐ"]]
+ )
f = QgsFeature()
- f.setAttributes(['abcŐabcŐabcŐ'])
+ f.setAttributes(["abcŐabcŐabcŐ"])
self.assertTrue(vl.dataProvider().addFeature(f))
# read it back in
- vl = QgsVectorLayer(datasource, 'test')
+ vl = QgsVectorLayer(datasource, "test")
self.assertTrue(vl.isValid())
- self.assertEqual([f.attributes() for f in vl.dataProvider().getFeatures()], [['abcŐ'], ['abcŐabcŐabcŐ']])
+ self.assertEqual(
+ [f.attributes() for f in vl.dataProvider().getFeatures()],
+ [["abcŐ"], ["abcŐabcŐabcŐ"]],
+ )
def testSkipFeatureCountOnFeatureCount(self):
"""Test QgsDataProvider.SkipFeatureCount on featureCount()"""
- testPath = TEST_DATA_DIR + '/' + 'lines.shp'
- provider = QgsProviderRegistry.instance().createProvider('ogr', testPath, QgsDataProvider.ProviderOptions(), QgsDataProvider.ReadFlag.SkipFeatureCount)
+ testPath = TEST_DATA_DIR + "/" + "lines.shp"
+ provider = QgsProviderRegistry.instance().createProvider(
+ "ogr",
+ testPath,
+ QgsDataProvider.ProviderOptions(),
+ QgsDataProvider.ReadFlag.SkipFeatureCount,
+ )
self.assertTrue(provider.isValid())
- self.assertEqual(provider.featureCount(), QgsVectorDataProvider.FeatureCountState.UnknownCount)
+ self.assertEqual(
+ provider.featureCount(),
+ QgsVectorDataProvider.FeatureCountState.UnknownCount,
+ )
def testSkipFeatureCountOnSubLayers(self):
"""Test QgsDataProvider.SkipFeatureCount on subLayers()"""
- datasource = os.path.join(TEST_DATA_DIR, 'shapefile')
- provider = QgsProviderRegistry.instance().createProvider('ogr', datasource, QgsDataProvider.ProviderOptions(), QgsDataProvider.ReadFlag.SkipFeatureCount)
+ datasource = os.path.join(TEST_DATA_DIR, "shapefile")
+ provider = QgsProviderRegistry.instance().createProvider(
+ "ogr",
+ datasource,
+ QgsDataProvider.ProviderOptions(),
+ QgsDataProvider.ReadFlag.SkipFeatureCount,
+ )
self.assertTrue(provider.isValid())
sublayers = provider.subLayers()
self.assertGreater(len(sublayers), 1)
- self.assertEqual(int(sublayers[0].split(QgsDataProvider.sublayerSeparator())[2]), int(Qgis.FeatureCountState.Uncounted))
+ self.assertEqual(
+ int(sublayers[0].split(QgsDataProvider.sublayerSeparator())[2]),
+ int(Qgis.FeatureCountState.Uncounted),
+ )
def testLayersOnSameOGRLayerWithAndWithoutFilter(self):
"""Test fix for https://github.com/qgis/QGIS/issues/43361"""
- file_path = os.path.join(TEST_DATA_DIR, 'provider', 'shapefile.shp')
- uri = f'{file_path}|layerId=0|subset="name" = \'Apple\''
+ file_path = os.path.join(TEST_DATA_DIR, "provider", "shapefile.shp")
+ uri = f"{file_path}|layerId=0|subset=\"name\" = 'Apple'"
options = QgsDataProvider.ProviderOptions()
- vl1 = QgsVectorLayer(uri, 'vl1', 'ogr')
- vl2 = QgsVectorLayer(uri, 'vl2', 'ogr')
- vl3 = QgsVectorLayer(f'{file_path}|layerId=0', 'vl3', 'ogr')
+ vl1 = QgsVectorLayer(uri, "vl1", "ogr")
+ vl2 = QgsVectorLayer(uri, "vl2", "ogr")
+ vl3 = QgsVectorLayer(f"{file_path}|layerId=0", "vl3", "ogr")
self.assertEqual(vl1.featureCount(), 1)
vl1_extent = QgsGeometry.fromRect(vl1.extent())
self.assertEqual(vl2.featureCount(), 1)
@@ -1106,23 +1317,26 @@ def testLayersOnSameOGRLayerWithAndWithoutFilter(self):
vl3_extent = QgsGeometry.fromRect(vl3.extent())
reference = QgsGeometry.fromRect(QgsRectangle(-68.2, 70.8, -68.2, 70.8))
- assert QgsGeometry.compare(vl1_extent.asPolygon()[0], reference.asPolygon()[0],
- 0.00001), f'Expected {reference.asWkt()}, got {vl1_extent.asWkt()}'
- assert QgsGeometry.compare(vl2_extent.asPolygon()[0], reference.asPolygon()[0],
- 0.00001), f'Expected {reference.asWkt()}, got {vl2_extent.asWkt()}'
+ assert QgsGeometry.compare(
+ vl1_extent.asPolygon()[0], reference.asPolygon()[0], 0.00001
+ ), f"Expected {reference.asWkt()}, got {vl1_extent.asWkt()}"
+ assert QgsGeometry.compare(
+ vl2_extent.asPolygon()[0], reference.asPolygon()[0], 0.00001
+ ), f"Expected {reference.asWkt()}, got {vl2_extent.asWkt()}"
reference = QgsGeometry.fromRect(QgsRectangle(-71.123, 66.33, -65.32, 78.3))
- assert QgsGeometry.compare(vl3_extent.asPolygon()[0], reference.asPolygon()[0],
- 0.00001), f'Expected {reference.asWkt()}, got {vl3_extent.asWkt()}'
+ assert QgsGeometry.compare(
+ vl3_extent.asPolygon()[0], reference.asPolygon()[0], 0.00001
+ ), f"Expected {reference.asWkt()}, got {vl3_extent.asWkt()}"
def testWritingMultiPolygon(self):
"""Test that a MultiPolygon written to a Shape Polygon layer doesn't get converted to Polygon"""
- tmpfile = os.path.join(self.basetestpath, 'testWritingMultiPolygon.shp')
- ds = osgeo.ogr.GetDriverByName('ESRI Shapefile').CreateDataSource(tmpfile)
- ds.CreateLayer('testWritingMultiPolygon', geom_type=osgeo.ogr.wkbPolygon)
+ tmpfile = os.path.join(self.basetestpath, "testWritingMultiPolygon.shp")
+ ds = osgeo.ogr.GetDriverByName("ESRI Shapefile").CreateDataSource(tmpfile)
+ ds.CreateLayer("testWritingMultiPolygon", geom_type=osgeo.ogr.wkbPolygon)
ds = None
- vl = QgsVectorLayer(tmpfile, 'test')
+ vl = QgsVectorLayer(tmpfile, "test")
f = QgsFeature()
f.setAttributes([200])
wkt = "MultiPolygon (((0 0, 0 1, 1 1, 0 0)),((10 0, 10 1, 11 1, 10 0)))"
@@ -1133,26 +1347,26 @@ def testWritingMultiPolygon(self):
self.assertEqual(f.geometry().constGet().asWkt(), wkt)
def testFilterWithComment(self):
- file_path = os.path.join(TEST_DATA_DIR, 'provider', 'shapefile.shp')
- uri = f'{file_path}|layerid=0|subset="name" = \'Apple\' -- comment'
- vl = QgsVectorLayer(uri, 'test', 'ogr')
+ file_path = os.path.join(TEST_DATA_DIR, "provider", "shapefile.shp")
+ uri = f"{file_path}|layerid=0|subset=\"name\" = 'Apple' -- comment"
+ vl = QgsVectorLayer(uri, "test", "ogr")
self.assertTrue(vl.isValid())
- self.assertEqual(vl.subsetString(), '"name" = \'Apple\' -- comment')
+ self.assertEqual(vl.subsetString(), "\"name\" = 'Apple' -- comment")
self.assertEqual(vl.featureCount(), 1)
f = next(vl.getFeatures())
- self.assertEqual(f['name'], 'Apple')
+ self.assertEqual(f["name"], "Apple")
def testRecomputeExtent(self):
"""Test that extents are recomputed correctly after update"""
tmpdir = tempfile.mkdtemp()
self.dirs_to_cleanup.append(tmpdir)
- srcpath = os.path.join(TEST_DATA_DIR, 'provider')
- for file in glob.glob(os.path.join(srcpath, 'shapefile.*')):
+ srcpath = os.path.join(TEST_DATA_DIR, "provider")
+ for file in glob.glob(os.path.join(srcpath, "shapefile.*")):
shutil.copy(os.path.join(srcpath, file), tmpdir)
- datasource = os.path.join(tmpdir, 'shapefile.shp')
+ datasource = os.path.join(tmpdir, "shapefile.shp")
- vl = QgsVectorLayer(f'{datasource}|layerid=0', 'test', 'ogr')
+ vl = QgsVectorLayer(f"{datasource}|layerid=0", "test", "ogr")
extent = vl.extent()
vl.startEditing()
for fet in vl.getFeatures():
@@ -1167,10 +1381,10 @@ def testRecomputeExtent(self):
# close file and reopen, then recheck to confirm that changes were saved to file
del vl
vl = None
- vl = QgsVectorLayer(f'{datasource}|layerid=0', 'test', 'ogr')
+ vl = QgsVectorLayer(f"{datasource}|layerid=0", "test", "ogr")
reopened_extent = vl.extent()
self.assertEqual(reopened_extent, updated_extent)
-if __name__ == '__main__':
+if __name__ == "__main__":
unittest.main()
diff --git a/tests/src/python/test_provider_spatialite.py b/tests/src/python/test_provider_spatialite.py
index 4bf9f9cbd249..a88a80c3fefa 100644
--- a/tests/src/python/test_provider_spatialite.py
+++ b/tests/src/python/test_provider_spatialite.py
@@ -5,9 +5,10 @@
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
"""
-__author__ = 'Vincent Mora'
-__date__ = '09/07/2013'
-__copyright__ = 'Copyright 2013, The QGIS Project'
+
+__author__ = "Vincent Mora"
+__date__ = "09/07/2013"
+__copyright__ = "Copyright 2013, The QGIS Project"
import os
import re
@@ -38,7 +39,9 @@
QgsVectorLayer,
QgsVectorLayerExporter,
QgsVectorLayerUtils,
- QgsWkbTypes, NULL)
+ QgsWkbTypes,
+ NULL,
+)
import unittest
from qgis.testing import start_app, QgisTestCase
from qgis.utils import spatialite_connect
@@ -53,12 +56,12 @@
def count_opened_filedescriptors(filename_to_test):
count = -1
- if sys.platform.startswith('linux'):
+ if sys.platform.startswith("linux"):
count = 0
- open_files_dirname = '/proc/%d/fd' % os.getpid()
+ open_files_dirname = "/proc/%d/fd" % os.getpid()
filenames = os.listdir(open_files_dirname)
for filename in filenames:
- full_filename = open_files_dirname + '/' + filename
+ full_filename = open_files_dirname + "/" + filename
if os.path.exists(full_filename):
link = os.readlink(full_filename)
if os.path.basename(link) == os.path.basename(filename_to_test):
@@ -71,21 +74,27 @@ class TestQgsSpatialiteProvider(QgisTestCase, ProviderTestCase):
@classmethod
def setUpClass(cls):
"""Run before all tests"""
- super(TestQgsSpatialiteProvider, cls).setUpClass()
- print(' ### Setup Spatialite Provider Test Class')
+ super().setUpClass()
+ print(" ### Setup Spatialite Provider Test Class")
# setup provider for base tests
cls.vl = QgsVectorLayer(
- 'dbname=\'{}/provider/spatialite.db\' table="somedata" (geom) sql='.format(
- TEST_DATA_DIR), 'test',
- 'spatialite')
- assert (cls.vl.isValid())
+ "dbname='{}/provider/spatialite.db' table=\"somedata\" (geom) sql=".format(
+ TEST_DATA_DIR
+ ),
+ "test",
+ "spatialite",
+ )
+ assert cls.vl.isValid()
cls.source = cls.vl.dataProvider()
cls.vl_poly = QgsVectorLayer(
- 'dbname=\'{}/provider/spatialite.db\' table="somepolydata" (geom) sql='.format(
- TEST_DATA_DIR), 'test',
- 'spatialite')
- assert (cls.vl_poly.isValid())
+ "dbname='{}/provider/spatialite.db' table=\"somepolydata\" (geom) sql=".format(
+ TEST_DATA_DIR
+ ),
+ "test",
+ "spatialite",
+ )
+ assert cls.vl_poly.isValid()
cls.poly_provider = cls.vl_poly.dataProvider()
# create test db
@@ -99,16 +108,22 @@ def setUpClass(cls):
cur.execute(sql)
# simple table with primary key
- sql = "CREATE TABLE test_pg (id INTEGER NOT NULL PRIMARY KEY, name TEXT NOT NULL)"
+ sql = (
+ "CREATE TABLE test_pg (id INTEGER NOT NULL PRIMARY KEY, name TEXT NOT NULL)"
+ )
cur.execute(sql)
sql = "SELECT AddGeometryColumn('test_pg', 'geometry', 4326, 'POLYGON', 'XY')"
cur.execute(sql)
sql = "INSERT INTO test_pg (id, name, geometry) "
- sql += "VALUES (1, 'toto 1', GeomFromText('POLYGON((0 0,1 0,1 1,0 1,0 0))', 4326))"
+ sql += (
+ "VALUES (1, 'toto 1', GeomFromText('POLYGON((0 0,1 0,1 1,0 1,0 0))', 4326))"
+ )
cur.execute(sql)
# table with Z dimension geometry, 1 point
- sql = "CREATE TABLE test_z (id INTEGER NOT NULL PRIMARY KEY, name TEXT NOT NULL)"
+ sql = (
+ "CREATE TABLE test_z (id INTEGER NOT NULL PRIMARY KEY, name TEXT NOT NULL)"
+ )
cur.execute(sql)
sql = "SELECT AddGeometryColumn('test_z', 'geometry', 4326, 'POINT', 'XYZ')"
cur.execute(sql)
@@ -117,7 +132,9 @@ def setUpClass(cls):
cur.execute(sql)
# table with Z dimension geometry, multiple points
- sql = "CREATE TABLE test_z2 (id INTEGER NOT NULL PRIMARY KEY, name TEXT NOT NULL)"
+ sql = (
+ "CREATE TABLE test_z2 (id INTEGER NOT NULL PRIMARY KEY, name TEXT NOT NULL)"
+ )
cur.execute(sql)
sql = "SELECT AddGeometryColumn('test_z2', 'geometry', 4326, 'POINT', 'XYZ')"
cur.execute(sql)
@@ -127,7 +144,9 @@ def setUpClass(cls):
cur.execute(sql)
# table with M value geometry
- sql = "CREATE TABLE test_m (id INTEGER NOT NULL PRIMARY KEY, name TEXT NOT NULL)"
+ sql = (
+ "CREATE TABLE test_m (id INTEGER NOT NULL PRIMARY KEY, name TEXT NOT NULL)"
+ )
cur.execute(sql)
sql = "SELECT AddGeometryColumn('test_m', 'geometry', 4326, 'POINT', 'XYM')"
cur.execute(sql)
@@ -136,7 +155,9 @@ def setUpClass(cls):
cur.execute(sql)
# table with Z dimension and M value geometry
- sql = "CREATE TABLE test_zm (id INTEGER NOT NULL PRIMARY KEY, name TEXT NOT NULL)"
+ sql = (
+ "CREATE TABLE test_zm (id INTEGER NOT NULL PRIMARY KEY, name TEXT NOT NULL)"
+ )
cur.execute(sql)
sql = "SELECT AddGeometryColumn('test_zm', 'geometry', 4326, 'POINT', 'XYZM')"
cur.execute(sql)
@@ -147,14 +168,20 @@ def setUpClass(cls):
# table with multiple column primary key
sql = "CREATE TABLE test_pg_mk (id INTEGER NOT NULL, name TEXT NOT NULL, PRIMARY KEY(id,name))"
cur.execute(sql)
- sql = "SELECT AddGeometryColumn('test_pg_mk', 'geometry', 4326, 'POLYGON', 'XY')"
+ sql = (
+ "SELECT AddGeometryColumn('test_pg_mk', 'geometry', 4326, 'POLYGON', 'XY')"
+ )
cur.execute(sql)
sql = "INSERT INTO test_pg_mk (id, name, geometry) "
- sql += "VALUES (1, 'toto 1', GeomFromText('POLYGON((0 0,1 0,1 1,0 1,0 0))', 4326))"
+ sql += (
+ "VALUES (1, 'toto 1', GeomFromText('POLYGON((0 0,1 0,1 1,0 1,0 0))', 4326))"
+ )
cur.execute(sql)
# simple table with primary key
- sql = "CREATE TABLE test_q (id INTEGER NOT NULL PRIMARY KEY, name TEXT NOT NULL)"
+ sql = (
+ "CREATE TABLE test_q (id INTEGER NOT NULL PRIMARY KEY, name TEXT NOT NULL)"
+ )
cur.execute(sql)
sql = "SELECT AddGeometryColumn('test_q', 'geometry', 4326, 'POLYGON', 'XY')"
cur.execute(sql)
@@ -166,21 +193,29 @@ def setUpClass(cls):
cur.execute(sql)
# simple table with a geometry column named 'Geometry'
- sql = "CREATE TABLE test_n (id INTEGER NOT NULL PRIMARY KEY, name TEXT NOT NULL)"
+ sql = (
+ "CREATE TABLE test_n (id INTEGER NOT NULL PRIMARY KEY, name TEXT NOT NULL)"
+ )
cur.execute(sql)
sql = "SELECT AddGeometryColumn('test_n', 'Geometry', 4326, 'POLYGON', 'XY')"
cur.execute(sql)
sql = "INSERT INTO test_n (id, name, geometry) "
- sql += "VALUES (1, 'toto 1', GeomFromText('POLYGON((0 0,1 0,1 1,0 1,0 0))', 4326))"
+ sql += (
+ "VALUES (1, 'toto 1', GeomFromText('POLYGON((0 0,1 0,1 1,0 1,0 0))', 4326))"
+ )
cur.execute(sql)
sql = "INSERT INTO test_n (id, name, geometry) "
- sql += "VALUES (2, 'toto 1', GeomFromText('POLYGON((0 0,1 0,1 1,0 1,0 0))', 4326))"
+ sql += (
+ "VALUES (2, 'toto 1', GeomFromText('POLYGON((0 0,1 0,1 1,0 1,0 0))', 4326))"
+ )
cur.execute(sql)
# table with different array types, stored as JSON
sql = "CREATE TABLE test_arrays (id INTEGER NOT NULL PRIMARY KEY, strings JSONSTRINGLIST NOT NULL, ints JSONINTEGERLIST NOT NULL, reals JSONREALLIST NOT NULL)"
cur.execute(sql)
- sql = "SELECT AddGeometryColumn('test_arrays', 'Geometry', 4326, 'POLYGON', 'XY')"
+ sql = (
+ "SELECT AddGeometryColumn('test_arrays', 'Geometry', 4326, 'POLYGON', 'XY')"
+ )
cur.execute(sql)
sql = "INSERT INTO test_arrays (id, strings, ints, reals, geometry) "
sql += "VALUES (1, '[\"toto\",\"tutu\"]', '[1,-2,724562]', '[1.0, -232567.22]', GeomFromText('POLYGON((0 0,1 0,1 1,0 1,0 0))', 4326))"
@@ -261,9 +296,11 @@ def setUpClass(cls):
cur.execute(sql)
# no fields table
- sql = "CREATE TABLE \"test_nofields\"(pkuid integer primary key autoincrement)"
+ sql = 'CREATE TABLE "test_nofields"(pkuid integer primary key autoincrement)'
cur.execute(sql)
- sql = "SELECT AddGeometryColumn('test_nofields', 'geometry', 4326, 'POINT', 'XY')"
+ sql = (
+ "SELECT AddGeometryColumn('test_nofields', 'geometry', 4326, 'POINT', 'XY')"
+ )
cur.execute(sql)
# constraints check table
@@ -278,7 +315,7 @@ def setUpClass(cls):
cur.execute(sql)
# Unique and not null constraints
- sql = "CREATE TABLE \"unique_not_null_constraints\"(pkuid integer primary key autoincrement, \"unique\" TEXT UNIQUE, \"not_null\" TEXT NOT NULL)"
+ sql = 'CREATE TABLE "unique_not_null_constraints"(pkuid integer primary key autoincrement, "unique" TEXT UNIQUE, "not_null" TEXT NOT NULL)'
cur.execute(sql)
sql = "SELECT AddGeometryColumn('unique_not_null_constraints', 'geometry', 4326, 'POINT', 'XY')"
cur.execute(sql)
@@ -295,11 +332,15 @@ def setUpClass(cls):
cur.execute(sql)
# Transaction tables
- sql = "CREATE TABLE \"test_transactions1\"(pkuid integer primary key autoincrement)"
+ sql = (
+ 'CREATE TABLE "test_transactions1"(pkuid integer primary key autoincrement)'
+ )
cur.execute(sql)
- sql = "CREATE TABLE \"test_transactions2\"(pkuid integer primary key autoincrement)"
+ sql = (
+ 'CREATE TABLE "test_transactions2"(pkuid integer primary key autoincrement)'
+ )
cur.execute(sql)
- sql = "INSERT INTO \"test_transactions2\" VALUES (NULL)"
+ sql = 'INSERT INTO "test_transactions2" VALUES (NULL)'
cur.execute(sql)
# table to test getQueryGeometryDetails() for geometries with Z, M and ZM
@@ -325,36 +366,44 @@ def tearDownClass(cls):
# os.remove(cls.dbname)
for dirname in cls.dirs_to_cleanup:
shutil.rmtree(dirname, True)
- super(TestQgsSpatialiteProvider, cls).tearDownClass()
+ super().tearDownClass()
def getSource(self):
tmpdir = tempfile.mkdtemp()
self.dirs_to_cleanup.append(tmpdir)
- srcpath = os.path.join(TEST_DATA_DIR, 'provider')
- datasource = os.path.join(tmpdir, 'spatialite.db')
- shutil.copy(os.path.join(srcpath, 'spatialite.db'), datasource)
+ srcpath = os.path.join(TEST_DATA_DIR, "provider")
+ datasource = os.path.join(tmpdir, "spatialite.db")
+ shutil.copy(os.path.join(srcpath, "spatialite.db"), datasource)
vl = QgsVectorLayer(
- f'dbname=\'{datasource}\' table="somedata" (geom) sql=', 'test',
- 'spatialite')
+ f"dbname='{datasource}' table=\"somedata\" (geom) sql=",
+ "test",
+ "spatialite",
+ )
return vl
def getEditableLayerWithCheckConstraint(self):
"""Returns the layer for attribute change CHECK constraint violation"""
vl = QgsVectorLayer(
- 'dbname=\'{}\' table="check_constraint" (geometry) sql='.format(
- self.dbname), 'check_constraint',
- 'spatialite')
+ "dbname='{}' table=\"check_constraint\" (geometry) sql=".format(
+ self.dbname
+ ),
+ "check_constraint",
+ "spatialite",
+ )
return vl
def getEditableLayerWithUniqueNotNullConstraints(self):
"""Returns the layer for UNIQUE and NOT NULL constraints detection"""
vl = QgsVectorLayer(
- 'dbname=\'{}\' table="unique_not_null_constraints" (geometry) sql='.format(
- self.dbname), 'unique_not_null_constraints',
- 'spatialite')
+ "dbname='{}' table=\"unique_not_null_constraints\" (geometry) sql=".format(
+ self.dbname
+ ),
+ "unique_not_null_constraints",
+ "spatialite",
+ )
return vl
def treat_time_as_string(self):
@@ -372,109 +421,119 @@ def tearDown(self):
pass
def enableCompiler(self):
- QgsSettings().setValue('/qgis/compileExpressions', True)
+ QgsSettings().setValue("/qgis/compileExpressions", True)
return True
def disableCompiler(self):
- QgsSettings().setValue('/qgis/compileExpressions', False)
+ QgsSettings().setValue("/qgis/compileExpressions", False)
def uncompiledFilters(self):
- return {'cnt = 10 ^ 2',
- '"name" ~ \'[OP]ra[gne]+\'',
- 'sqrt(pk) >= 2',
- 'radians(cnt) < 2',
- 'degrees(pk) <= 200',
- 'cos(pk) < 0',
- 'sin(pk) < 0',
- 'tan(pk) < 0',
- 'acos(-1) < pk',
- 'asin(1) < pk',
- 'atan(3.14) < pk',
- 'atan2(3.14, pk) < 1',
- 'exp(pk) < 10',
- 'ln(pk) <= 1',
- 'log(3, pk) <= 1',
- 'log10(pk) < 0.5',
- 'floor(3.14) <= pk',
- 'ceil(3.14) <= pk',
- 'pk < pi()',
- 'floor(cnt / 66.67) <= 2',
- 'ceil(cnt / 66.67) <= 2',
- 'pk < pi() / 2',
- 'x($geometry) < -70',
- 'y($geometry) > 70',
- 'xmin($geometry) < -70',
- 'ymin($geometry) > 70',
- 'xmax($geometry) < -70',
- 'ymax($geometry) > 70',
- 'disjoint($geometry,geom_from_wkt( \'Polygon ((-72.2 66.1, -65.2 66.1, -65.2 72.0, -72.2 72.0, -72.2 66.1))\'))',
- 'intersects($geometry,geom_from_wkt( \'Polygon ((-72.2 66.1, -65.2 66.1, -65.2 72.0, -72.2 72.0, -72.2 66.1))\'))',
- 'contains(geom_from_wkt( \'Polygon ((-72.2 66.1, -65.2 66.1, -65.2 72.0, -72.2 72.0, -72.2 66.1))\'),$geometry)',
- 'distance($geometry,geom_from_wkt( \'Point (-70 70)\')) > 7',
- 'intersects($geometry,geom_from_gml( \'-72.2,66.1 -65.2,66.1 -65.2,72.0 -72.2,72.0 -72.2,66.1 \'))',
- 'x($geometry) < -70',
- 'y($geometry) > 79',
- 'xmin($geometry) < -70',
- 'ymin($geometry) < 76',
- 'xmax($geometry) > -68',
- 'ymax($geometry) > 80',
- 'area($geometry) > 10',
- 'perimeter($geometry) < 12',
- 'relate($geometry,geom_from_wkt( \'Polygon ((-68.2 82.1, -66.95 82.1, -66.95 79.05, -68.2 79.05, -68.2 82.1))\')) = \'FF2FF1212\'',
- 'relate($geometry,geom_from_wkt( \'Polygon ((-68.2 82.1, -66.95 82.1, -66.95 79.05, -68.2 79.05, -68.2 82.1))\'), \'****F****\')',
- 'crosses($geometry,geom_from_wkt( \'Linestring (-68.2 82.1, -66.95 82.1, -66.95 79.05)\'))',
- 'overlaps($geometry,geom_from_wkt( \'Polygon ((-68.2 82.1, -66.95 82.1, -66.95 79.05, -68.2 79.05, -68.2 82.1))\'))',
- 'within($geometry,geom_from_wkt( \'Polygon ((-75.1 76.1, -75.1 81.6, -68.8 81.6, -68.8 76.1, -75.1 76.1))\'))',
- 'overlaps(translate($geometry,-1,-1),geom_from_wkt( \'Polygon ((-75.1 76.1, -75.1 81.6, -68.8 81.6, -68.8 76.1, -75.1 76.1))\'))',
- 'overlaps(buffer($geometry,1),geom_from_wkt( \'Polygon ((-75.1 76.1, -75.1 81.6, -68.8 81.6, -68.8 76.1, -75.1 76.1))\'))',
- 'intersects(centroid($geometry),geom_from_wkt( \'Polygon ((-74.4 78.2, -74.4 79.1, -66.8 79.1, -66.8 78.2, -74.4 78.2))\'))',
- 'intersects(point_on_surface($geometry),geom_from_wkt( \'Polygon ((-74.4 78.2, -74.4 79.1, -66.8 79.1, -66.8 78.2, -74.4 78.2))\'))',
- '"dt" = to_datetime(\'000www14ww13ww12www4ww5ww2020\',\'zzzwwwsswwmmwwhhwwwdwwMwwyyyy\')',
- '"dt" <= format_date(make_datetime(2020, 5, 4, 12, 13, 14), \'yyyy-MM-dd hh:mm:ss\')',
- '"dt" < format_date(make_date(2020, 5, 4), \'yyyy-MM-dd hh:mm:ss\')',
- '"dt" = format_date(to_datetime(\'000www14ww13ww12www4ww5ww2020\',\'zzzwwwsswwmmwwhhwwwdwwMwwyyyy\'),\'yyyy-MM-dd hh:mm:ss\')',
- 'to_time("time") >= make_time(12, 14, 14)',
- 'to_time("time") = to_time(\'000www14ww13ww12www\',\'zzzwwwsswwmmwwhhwww\')',
- '"date" = to_date(\'www4ww5ww2020\',\'wwwdwwMwwyyyy\')',
- 'dt BETWEEN make_datetime(2020, 5, 3, 12, 13, 14) AND make_datetime(2020, 5, 4, 12, 14, 14)',
- 'dt NOT BETWEEN make_datetime(2020, 5, 3, 12, 13, 14) AND make_datetime(2020, 5, 4, 12, 14, 14)',
- '"dt" <= make_datetime(2020, 5, 4, 12, 13, 14)',
- '"date" <= make_datetime(2020, 5, 4, 12, 13, 14)'
- }
+ return {
+ "cnt = 10 ^ 2",
+ "\"name\" ~ '[OP]ra[gne]+'",
+ "sqrt(pk) >= 2",
+ "radians(cnt) < 2",
+ "degrees(pk) <= 200",
+ "cos(pk) < 0",
+ "sin(pk) < 0",
+ "tan(pk) < 0",
+ "acos(-1) < pk",
+ "asin(1) < pk",
+ "atan(3.14) < pk",
+ "atan2(3.14, pk) < 1",
+ "exp(pk) < 10",
+ "ln(pk) <= 1",
+ "log(3, pk) <= 1",
+ "log10(pk) < 0.5",
+ "floor(3.14) <= pk",
+ "ceil(3.14) <= pk",
+ "pk < pi()",
+ "floor(cnt / 66.67) <= 2",
+ "ceil(cnt / 66.67) <= 2",
+ "pk < pi() / 2",
+ "x($geometry) < -70",
+ "y($geometry) > 70",
+ "xmin($geometry) < -70",
+ "ymin($geometry) > 70",
+ "xmax($geometry) < -70",
+ "ymax($geometry) > 70",
+ "disjoint($geometry,geom_from_wkt( 'Polygon ((-72.2 66.1, -65.2 66.1, -65.2 72.0, -72.2 72.0, -72.2 66.1))'))",
+ "intersects($geometry,geom_from_wkt( 'Polygon ((-72.2 66.1, -65.2 66.1, -65.2 72.0, -72.2 72.0, -72.2 66.1))'))",
+ "contains(geom_from_wkt( 'Polygon ((-72.2 66.1, -65.2 66.1, -65.2 72.0, -72.2 72.0, -72.2 66.1))'),$geometry)",
+ "distance($geometry,geom_from_wkt( 'Point (-70 70)')) > 7",
+ "intersects($geometry,geom_from_gml( '-72.2,66.1 -65.2,66.1 -65.2,72.0 -72.2,72.0 -72.2,66.1 '))",
+ "x($geometry) < -70",
+ "y($geometry) > 79",
+ "xmin($geometry) < -70",
+ "ymin($geometry) < 76",
+ "xmax($geometry) > -68",
+ "ymax($geometry) > 80",
+ "area($geometry) > 10",
+ "perimeter($geometry) < 12",
+ "relate($geometry,geom_from_wkt( 'Polygon ((-68.2 82.1, -66.95 82.1, -66.95 79.05, -68.2 79.05, -68.2 82.1))')) = 'FF2FF1212'",
+ "relate($geometry,geom_from_wkt( 'Polygon ((-68.2 82.1, -66.95 82.1, -66.95 79.05, -68.2 79.05, -68.2 82.1))'), '****F****')",
+ "crosses($geometry,geom_from_wkt( 'Linestring (-68.2 82.1, -66.95 82.1, -66.95 79.05)'))",
+ "overlaps($geometry,geom_from_wkt( 'Polygon ((-68.2 82.1, -66.95 82.1, -66.95 79.05, -68.2 79.05, -68.2 82.1))'))",
+ "within($geometry,geom_from_wkt( 'Polygon ((-75.1 76.1, -75.1 81.6, -68.8 81.6, -68.8 76.1, -75.1 76.1))'))",
+ "overlaps(translate($geometry,-1,-1),geom_from_wkt( 'Polygon ((-75.1 76.1, -75.1 81.6, -68.8 81.6, -68.8 76.1, -75.1 76.1))'))",
+ "overlaps(buffer($geometry,1),geom_from_wkt( 'Polygon ((-75.1 76.1, -75.1 81.6, -68.8 81.6, -68.8 76.1, -75.1 76.1))'))",
+ "intersects(centroid($geometry),geom_from_wkt( 'Polygon ((-74.4 78.2, -74.4 79.1, -66.8 79.1, -66.8 78.2, -74.4 78.2))'))",
+ "intersects(point_on_surface($geometry),geom_from_wkt( 'Polygon ((-74.4 78.2, -74.4 79.1, -66.8 79.1, -66.8 78.2, -74.4 78.2))'))",
+ "\"dt\" = to_datetime('000www14ww13ww12www4ww5ww2020','zzzwwwsswwmmwwhhwwwdwwMwwyyyy')",
+ "\"dt\" <= format_date(make_datetime(2020, 5, 4, 12, 13, 14), 'yyyy-MM-dd hh:mm:ss')",
+ "\"dt\" < format_date(make_date(2020, 5, 4), 'yyyy-MM-dd hh:mm:ss')",
+ "\"dt\" = format_date(to_datetime('000www14ww13ww12www4ww5ww2020','zzzwwwsswwmmwwhhwwwdwwMwwyyyy'),'yyyy-MM-dd hh:mm:ss')",
+ 'to_time("time") >= make_time(12, 14, 14)',
+ "to_time(\"time\") = to_time('000www14ww13ww12www','zzzwwwsswwmmwwhhwww')",
+ "\"date\" = to_date('www4ww5ww2020','wwwdwwMwwyyyy')",
+ "dt BETWEEN make_datetime(2020, 5, 3, 12, 13, 14) AND make_datetime(2020, 5, 4, 12, 14, 14)",
+ "dt NOT BETWEEN make_datetime(2020, 5, 3, 12, 13, 14) AND make_datetime(2020, 5, 4, 12, 14, 14)",
+ '"dt" <= make_datetime(2020, 5, 4, 12, 13, 14)',
+ '"date" <= make_datetime(2020, 5, 4, 12, 13, 14)',
+ }
def partiallyCompiledFilters(self):
- return {'"name" NOT LIKE \'Ap%\'',
- 'name LIKE \'Apple\'',
- 'name LIKE \'aPple\'',
- 'name LIKE \'Ap_le\'',
- 'name LIKE \'Ap\\_le\''
- }
+ return {
+ "\"name\" NOT LIKE 'Ap%'",
+ "name LIKE 'Apple'",
+ "name LIKE 'aPple'",
+ "name LIKE 'Ap_le'",
+ "name LIKE 'Ap\\_le'",
+ }
def test_SplitFeature(self):
"""Create SpatiaLite database"""
- layer = QgsVectorLayer("dbname=%s table=test_pg (geometry)" %
- self.dbname, "test_pg", "spatialite")
+ layer = QgsVectorLayer(
+ "dbname=%s table=test_pg (geometry)" % self.dbname, "test_pg", "spatialite"
+ )
self.assertTrue(layer.isValid())
self.assertTrue(layer.isSpatial())
layer.startEditing()
- self.assertEqual(layer.splitFeatures(
- [QgsPointXY(0.75, -0.5), QgsPointXY(0.75, 1.5)], 0), 0)
- self.assertEqual(layer.splitFeatures(
- [QgsPointXY(-0.5, 0.25), QgsPointXY(1.5, 0.25)], 0), 0)
+ self.assertEqual(
+ layer.splitFeatures([QgsPointXY(0.75, -0.5), QgsPointXY(0.75, 1.5)], 0), 0
+ )
+ self.assertEqual(
+ layer.splitFeatures([QgsPointXY(-0.5, 0.25), QgsPointXY(1.5, 0.25)], 0), 0
+ )
self.assertTrue(layer.commitChanges())
self.assertEqual(layer.featureCount(), 4)
def test_SplitFeatureWithMultiKey(self):
"""Create SpatiaLite database"""
- layer = QgsVectorLayer("dbname=%s table=test_pg_mk (geometry)" %
- self.dbname, "test_pg_mk", "spatialite")
+ layer = QgsVectorLayer(
+ "dbname=%s table=test_pg_mk (geometry)" % self.dbname,
+ "test_pg_mk",
+ "spatialite",
+ )
self.assertTrue(layer.isValid())
self.assertTrue(layer.isSpatial())
layer.startEditing()
- self.assertEqual(layer.splitFeatures(
- [QgsPointXY(0.5, -0.5), QgsPointXY(0.5, 1.5)], 0), 0)
- self.assertEqual(layer.splitFeatures(
- [QgsPointXY(-0.5, 0.5), QgsPointXY(1.5, 0.5)], 0), 0)
+ self.assertEqual(
+ layer.splitFeatures([QgsPointXY(0.5, -0.5), QgsPointXY(0.5, 1.5)], 0), 0
+ )
+ self.assertEqual(
+ layer.splitFeatures([QgsPointXY(-0.5, 0.5), QgsPointXY(1.5, 0.5)], 0), 0
+ )
self.assertTrue(layer.commitChanges())
def test_crash_on_constraint_detection(self):
@@ -482,16 +541,22 @@ def test_crash_on_constraint_detection(self):
Test that constraint detection does not crash
"""
# should be no crash!
- QgsVectorLayer(f"dbname={TEST_DATA_DIR + '/views_test.sqlite'} table=KNN", "KNN",
- "spatialite")
+ QgsVectorLayer(
+ f"dbname={TEST_DATA_DIR + '/views_test.sqlite'} table=KNN",
+ "KNN",
+ "spatialite",
+ )
def test_queries(self):
"""Test loading of query-based layers"""
# a query with a geometry, but no unique id
# the id will be autoincremented
- l = QgsVectorLayer(f"dbname={self.dbname} table='(select * from test_q)' (geometry)", "test_pg_query1",
- "spatialite")
+ l = QgsVectorLayer(
+ f"dbname={self.dbname} table='(select * from test_q)' (geometry)",
+ "test_pg_query1",
+ "spatialite",
+ )
self.assertTrue(l.isValid())
# the id() is autoincremented
sum_id1 = sum(f.id() for f in l.getFeatures())
@@ -501,8 +566,11 @@ def test_queries(self):
self.assertEqual(sum_id2, 32) # 11 + 21
# and now with an id declared
- l = QgsVectorLayer(f"dbname={self.dbname} table='(select * from test_q)' (geometry) key='id'",
- "test_pg_query1", "spatialite")
+ l = QgsVectorLayer(
+ f"dbname={self.dbname} table='(select * from test_q)' (geometry) key='id'",
+ "test_pg_query1",
+ "spatialite",
+ )
self.assertTrue(l.isValid())
sum_id1 = sum(f.id() for f in l.getFeatures())
sum_id2 = sum(f.attributes()[0] for f in l.getFeatures())
@@ -510,8 +578,11 @@ def test_queries(self):
self.assertEqual(sum_id2, 32)
# a query, but no geometry
- l = QgsVectorLayer(f"dbname={self.dbname} table='(select id,name from test_q)' key='id'", "test_pg_query1",
- "spatialite")
+ l = QgsVectorLayer(
+ f"dbname={self.dbname} table='(select id,name from test_q)' key='id'",
+ "test_pg_query1",
+ "spatialite",
+ )
self.assertTrue(l.isValid())
sum_id1 = sum(f.id() for f in l.getFeatures())
sum_id2 = sum(f.attributes()[0] for f in l.getFeatures())
@@ -520,24 +591,33 @@ def test_queries(self):
def test_zm(self):
"""Test Z dimension and M value"""
- l = QgsVectorLayer("dbname=%s table='test_z' (geometry) key='id'" %
- self.dbname, "test_z", "spatialite")
+ l = QgsVectorLayer(
+ "dbname=%s table='test_z' (geometry) key='id'" % self.dbname,
+ "test_z",
+ "spatialite",
+ )
self.assertTrue(l.isValid())
self.assertTrue(QgsWkbTypes.hasZ(l.wkbType()))
feature = l.getFeature(1)
geom = feature.geometry().constGet()
self.assertEqual(geom.z(), 1.0)
- l = QgsVectorLayer("dbname=%s table='test_m' (geometry) key='id'" %
- self.dbname, "test_m", "spatialite")
+ l = QgsVectorLayer(
+ "dbname=%s table='test_m' (geometry) key='id'" % self.dbname,
+ "test_m",
+ "spatialite",
+ )
self.assertTrue(l.isValid())
self.assertTrue(QgsWkbTypes.hasM(l.wkbType()))
feature = l.getFeature(1)
geom = feature.geometry().constGet()
self.assertEqual(geom.m(), 1.0)
- l = QgsVectorLayer("dbname=%s table='test_zm' (geometry) key='id'" %
- self.dbname, "test_zm", "spatialite")
+ l = QgsVectorLayer(
+ "dbname=%s table='test_zm' (geometry) key='id'" % self.dbname,
+ "test_zm",
+ "spatialite",
+ )
self.assertTrue(l.isValid())
self.assertTrue(QgsWkbTypes.hasZ(l.wkbType()))
self.assertTrue(QgsWkbTypes.hasM(l.wkbType()))
@@ -548,34 +628,41 @@ def test_zm(self):
def test_case(self):
"""Test case sensitivity issues"""
- l = QgsVectorLayer("dbname=%s table='test_n' (geometry) key='id'" %
- self.dbname, "test_n1", "spatialite")
+ l = QgsVectorLayer(
+ "dbname=%s table='test_n' (geometry) key='id'" % self.dbname,
+ "test_n1",
+ "spatialite",
+ )
self.assertTrue(l.isValid())
self.assertEqual(l.dataProvider().fields().count(), 2)
fields = [f.name() for f in l.dataProvider().fields()]
- self.assertNotIn('Geometry', fields)
+ self.assertNotIn("Geometry", fields)
def test_invalid_iterator(self):
- """ Test invalid iterator """
- corrupt_dbname = self.dbname + '.corrupt'
+ """Test invalid iterator"""
+ corrupt_dbname = self.dbname + ".corrupt"
shutil.copy(self.dbname, corrupt_dbname)
- layer = QgsVectorLayer("dbname=%s table=test_pg (geometry)" %
- corrupt_dbname, "test_pg", "spatialite")
+ layer = QgsVectorLayer(
+ "dbname=%s table=test_pg (geometry)" % corrupt_dbname,
+ "test_pg",
+ "spatialite",
+ )
# Corrupt the database
- with open(corrupt_dbname, 'wb') as f:
- f.write(b'')
+ with open(corrupt_dbname, "wb") as f:
+ f.write(b"")
layer.getFeatures()
layer = None
os.unlink(corrupt_dbname)
def testNoDanglingFileDescriptorAfterCloseVariant1(self):
- ''' Test that when closing the provider all file handles are released '''
+ """Test that when closing the provider all file handles are released"""
- temp_dbname = self.dbname + '.no_dangling_test1'
+ temp_dbname = self.dbname + ".no_dangling_test1"
shutil.copy(self.dbname, temp_dbname)
- vl = QgsVectorLayer("dbname=%s table=test_n (geometry)" %
- temp_dbname, "test_n", "spatialite")
+ vl = QgsVectorLayer(
+ "dbname=%s table=test_n (geometry)" % temp_dbname, "test_n", "spatialite"
+ )
self.assertTrue(vl.isValid())
# The iterator will take one extra connection
myiter = vl.getFeatures()
@@ -584,14 +671,14 @@ def testNoDanglingFileDescriptorAfterCloseVariant1(self):
f = next(myiter)
self.assertTrue(f.isValid())
- if sys.platform.startswith('linux'):
+ if sys.platform.startswith("linux"):
self.assertEqual(count_opened_filedescriptors(temp_dbname), 2)
# does NO release one file descriptor, because shared with the iterator
del vl
# Non portable, but Windows testing is done with trying to unlink
- if sys.platform.startswith('linux'):
+ if sys.platform.startswith("linux"):
self.assertEqual(count_opened_filedescriptors(temp_dbname), 2)
f = next(myiter)
@@ -601,7 +688,7 @@ def testNoDanglingFileDescriptorAfterCloseVariant1(self):
del myiter
# Non portable, but Windows testing is done with trying to unlink
- if sys.platform.startswith('linux'):
+ if sys.platform.startswith("linux"):
self.assertEqual(count_opened_filedescriptors(temp_dbname), 0)
# Check that deletion works well (can only fail on Windows)
@@ -609,13 +696,14 @@ def testNoDanglingFileDescriptorAfterCloseVariant1(self):
self.assertFalse(os.path.exists(temp_dbname))
def testNoDanglingFileDescriptorAfterCloseVariant2(self):
- ''' Test that when closing the provider all file handles are released '''
+ """Test that when closing the provider all file handles are released"""
- temp_dbname = self.dbname + '.no_dangling_test2'
+ temp_dbname = self.dbname + ".no_dangling_test2"
shutil.copy(self.dbname, temp_dbname)
- vl = QgsVectorLayer("dbname=%s table=test_n (geometry)" %
- temp_dbname, "test_n", "spatialite")
+ vl = QgsVectorLayer(
+ "dbname=%s table=test_n (geometry)" % temp_dbname, "test_n", "spatialite"
+ )
self.assertTrue(vl.isValid())
self.assertTrue(vl.isValid())
# Consume all features.
@@ -623,14 +711,14 @@ def testNoDanglingFileDescriptorAfterCloseVariant2(self):
for feature in myiter:
pass
# The iterator is closed
- if sys.platform.startswith('linux'):
+ if sys.platform.startswith("linux"):
self.assertEqual(count_opened_filedescriptors(temp_dbname), 2)
# Should release one file descriptor
del vl
# Non portable, but Windows testing is done with trying to unlink
- if sys.platform.startswith('linux'):
+ if sys.platform.startswith("linux"):
self.assertEqual(count_opened_filedescriptors(temp_dbname), 0)
# Check that deletion works well (can only fail on Windows)
@@ -639,94 +727,106 @@ def testNoDanglingFileDescriptorAfterCloseVariant2(self):
def test_arrays(self):
"""Test loading of layers with arrays"""
- l = QgsVectorLayer("dbname=%s table=test_arrays (geometry)" %
- self.dbname, "test_arrays", "spatialite")
+ l = QgsVectorLayer(
+ "dbname=%s table=test_arrays (geometry)" % self.dbname,
+ "test_arrays",
+ "spatialite",
+ )
self.assertTrue(l.isValid())
features = [f for f in l.getFeatures()]
self.assertEqual(len(features), 1)
- strings_field = l.fields().field('strings')
- self.assertEqual(strings_field.typeName(), 'jsonstringlist')
+ strings_field = l.fields().field("strings")
+ self.assertEqual(strings_field.typeName(), "jsonstringlist")
self.assertEqual(strings_field.type(), QVariant.StringList)
self.assertEqual(strings_field.subType(), QVariant.String)
strings = features[0].attributes()[1]
- self.assertEqual(strings, ['toto', 'tutu'])
+ self.assertEqual(strings, ["toto", "tutu"])
- ints_field = l.fields().field('ints')
- self.assertEqual(ints_field.typeName(), 'jsonintegerlist')
+ ints_field = l.fields().field("ints")
+ self.assertEqual(ints_field.typeName(), "jsonintegerlist")
self.assertEqual(ints_field.type(), QVariant.List)
self.assertEqual(ints_field.subType(), QVariant.LongLong)
ints = features[0].attributes()[2]
self.assertEqual(ints, [1, -2, 724562])
- reals_field = l.fields().field('reals')
- self.assertEqual(reals_field.typeName(), 'jsonreallist')
+ reals_field = l.fields().field("reals")
+ self.assertEqual(reals_field.typeName(), "jsonreallist")
self.assertEqual(reals_field.type(), QVariant.List)
self.assertEqual(reals_field.subType(), QVariant.Double)
reals = features[0].attributes()[3]
self.assertEqual(reals, [1.0, -232567.22])
new_f = QgsFeature(l.fields())
- new_f['id'] = 2
- new_f['strings'] = ['simple', '"doubleQuote"', "'quote'", 'back\\slash']
- new_f['ints'] = [1, 2, 3, 4]
- new_f['reals'] = [1e67, 1e-56]
+ new_f["id"] = 2
+ new_f["strings"] = ["simple", '"doubleQuote"', "'quote'", "back\\slash"]
+ new_f["ints"] = [1, 2, 3, 4]
+ new_f["reals"] = [1e67, 1e-56]
r, fs = l.dataProvider().addFeatures([new_f])
self.assertTrue(r)
- read_back = l.getFeature(new_f['id'])
- self.assertEqual(read_back['id'], new_f['id'])
- self.assertEqual(read_back['strings'], new_f['strings'])
- self.assertEqual(read_back['ints'], new_f['ints'])
- self.assertEqual(read_back['reals'], new_f['reals'])
+ read_back = l.getFeature(new_f["id"])
+ self.assertEqual(read_back["id"], new_f["id"])
+ self.assertEqual(read_back["strings"], new_f["strings"])
+ self.assertEqual(read_back["ints"], new_f["ints"])
+ self.assertEqual(read_back["reals"], new_f["reals"])
def test_arrays_write(self):
"""Test writing of layers with arrays"""
- l = QgsVectorLayer("dbname=%s table=test_arrays_write (geometry)" %
- self.dbname, "test_arrays", "spatialite")
+ l = QgsVectorLayer(
+ "dbname=%s table=test_arrays_write (geometry)" % self.dbname,
+ "test_arrays",
+ "spatialite",
+ )
self.assertTrue(l.isValid())
new_f = QgsFeature(l.fields())
- new_f['id'] = 2
- new_f['array'] = ['simple', '"doubleQuote"', "'quote'", 'back\\slash']
- new_f['strings'] = ['simple', '"doubleQuote"', "'quote'", 'back\\slash']
- new_f['ints'] = [1, 2, 3, 4]
- new_f['reals'] = [1e67, 1e-56]
+ new_f["id"] = 2
+ new_f["array"] = ["simple", '"doubleQuote"', "'quote'", "back\\slash"]
+ new_f["strings"] = ["simple", '"doubleQuote"', "'quote'", "back\\slash"]
+ new_f["ints"] = [1, 2, 3, 4]
+ new_f["reals"] = [1e67, 1e-56]
r, fs = l.dataProvider().addFeatures([new_f])
self.assertTrue(r)
- read_back = l.getFeature(new_f['id'])
- self.assertEqual(read_back['id'], new_f['id'])
- self.assertEqual(read_back['array'], new_f['array'])
- self.assertEqual(read_back['strings'], new_f['strings'])
- self.assertEqual(read_back['ints'], new_f['ints'])
- self.assertEqual(read_back['reals'], new_f['reals'])
+ read_back = l.getFeature(new_f["id"])
+ self.assertEqual(read_back["id"], new_f["id"])
+ self.assertEqual(read_back["array"], new_f["array"])
+ self.assertEqual(read_back["strings"], new_f["strings"])
+ self.assertEqual(read_back["ints"], new_f["ints"])
+ self.assertEqual(read_back["reals"], new_f["reals"])
new_f = QgsFeature(l.fields())
- new_f['id'] = 3
- new_f['array'] = [1, 1.2345, '"doubleQuote"', "'quote'", 'back\\slash']
- new_f['strings'] = ['simple', '"doubleQuote"', "'quote'", 'back\\slash']
- new_f['ints'] = [1, 2, 3, 4]
- new_f['reals'] = [1e67, 1e-56]
+ new_f["id"] = 3
+ new_f["array"] = [1, 1.2345, '"doubleQuote"', "'quote'", "back\\slash"]
+ new_f["strings"] = ["simple", '"doubleQuote"', "'quote'", "back\\slash"]
+ new_f["ints"] = [1, 2, 3, 4]
+ new_f["reals"] = [1e67, 1e-56]
r, fs = l.dataProvider().addFeatures([new_f])
self.assertTrue(r)
- read_back = l.getFeature(new_f['id'])
- self.assertEqual(read_back['id'], new_f['id'])
- self.assertEqual(read_back['array'], new_f['array'])
- self.assertEqual(read_back['strings'], new_f['strings'])
- self.assertEqual(read_back['ints'], new_f['ints'])
- self.assertEqual(read_back['reals'], new_f['reals'])
+ read_back = l.getFeature(new_f["id"])
+ self.assertEqual(read_back["id"], new_f["id"])
+ self.assertEqual(read_back["array"], new_f["array"])
+ self.assertEqual(read_back["strings"], new_f["strings"])
+ self.assertEqual(read_back["ints"], new_f["ints"])
+ self.assertEqual(read_back["reals"], new_f["reals"])
- read_back = l.getFeature(new_f['id'])
+ read_back = l.getFeature(new_f["id"])
def test_discover_relation(self):
- artist = QgsVectorLayer(f"dbname={self.dbname} table=test_relation_a (geometry)", "test_relation_a",
- "spatialite")
+ artist = QgsVectorLayer(
+ f"dbname={self.dbname} table=test_relation_a (geometry)",
+ "test_relation_a",
+ "spatialite",
+ )
self.assertTrue(artist.isValid())
- track = QgsVectorLayer(f"dbname={self.dbname} table=test_relation_b (geometry)", "test_relation_b",
- "spatialite")
+ track = QgsVectorLayer(
+ f"dbname={self.dbname} table=test_relation_b (geometry)",
+ "test_relation_b",
+ "spatialite",
+ )
self.assertTrue(track.isValid())
QgsProject.instance().addMapLayer(artist)
QgsProject.instance().addMapLayer(track)
@@ -734,12 +834,12 @@ def test_discover_relation(self):
relMgr = QgsProject.instance().relationManager()
relations = relMgr.discoverRelations([], [artist, track])
relations = {r.name(): r for r in relations}
- self.assertEqual({'fk_test_relation_b_0'}, set(relations.keys()))
+ self.assertEqual({"fk_test_relation_b_0"}, set(relations.keys()))
- a2t = relations['fk_test_relation_b_0']
+ a2t = relations["fk_test_relation_b_0"]
self.assertTrue(a2t.isValid())
- self.assertEqual('test_relation_b', a2t.referencingLayer().name())
- self.assertEqual('test_relation_a', a2t.referencedLayer().name())
+ self.assertEqual("test_relation_b", a2t.referencingLayer().name())
+ self.assertEqual("test_relation_a", a2t.referencedLayer().name())
self.assertEqual([2], a2t.referencingFields())
self.assertEqual([0], a2t.referencedFields())
finally:
@@ -747,112 +847,197 @@ def test_discover_relation(self):
QgsProject.instance().removeMapLayer(artist.id())
def testNotNullConstraint(self):
- vl = QgsVectorLayer(f"dbname={self.dbname} table=test_constraints key='id'", "test_constraints",
- "spatialite")
+ vl = QgsVectorLayer(
+ f"dbname={self.dbname} table=test_constraints key='id'",
+ "test_constraints",
+ "spatialite",
+ )
self.assertTrue(vl.isValid())
self.assertEqual(len(vl.fields()), 5)
# test some bad field indexes
- self.assertEqual(vl.dataProvider().fieldConstraints(-1),
- QgsFieldConstraints.Constraints())
- self.assertEqual(vl.dataProvider().fieldConstraints(
- 1001), QgsFieldConstraints.Constraints())
-
- self.assertTrue(vl.dataProvider().fieldConstraints(0) &
- QgsFieldConstraints.Constraint.ConstraintNotNull)
- self.assertTrue(vl.dataProvider().fieldConstraints(1) &
- QgsFieldConstraints.Constraint.ConstraintNotNull)
- self.assertFalse(vl.dataProvider().fieldConstraints(2)
- & QgsFieldConstraints.Constraint.ConstraintNotNull)
- self.assertFalse(vl.dataProvider().fieldConstraints(3)
- & QgsFieldConstraints.Constraint.ConstraintNotNull)
- self.assertTrue(vl.dataProvider().fieldConstraints(4) &
- QgsFieldConstraints.Constraint.ConstraintNotNull)
+ self.assertEqual(
+ vl.dataProvider().fieldConstraints(-1), QgsFieldConstraints.Constraints()
+ )
+ self.assertEqual(
+ vl.dataProvider().fieldConstraints(1001), QgsFieldConstraints.Constraints()
+ )
+
+ self.assertTrue(
+ vl.dataProvider().fieldConstraints(0)
+ & QgsFieldConstraints.Constraint.ConstraintNotNull
+ )
+ self.assertTrue(
+ vl.dataProvider().fieldConstraints(1)
+ & QgsFieldConstraints.Constraint.ConstraintNotNull
+ )
+ self.assertFalse(
+ vl.dataProvider().fieldConstraints(2)
+ & QgsFieldConstraints.Constraint.ConstraintNotNull
+ )
+ self.assertFalse(
+ vl.dataProvider().fieldConstraints(3)
+ & QgsFieldConstraints.Constraint.ConstraintNotNull
+ )
+ self.assertTrue(
+ vl.dataProvider().fieldConstraints(4)
+ & QgsFieldConstraints.Constraint.ConstraintNotNull
+ )
# test that constraints have been saved to fields correctly
fields = vl.fields()
- self.assertTrue(fields.at(0).constraints().constraints()
- & QgsFieldConstraints.Constraint.ConstraintNotNull)
- self.assertEqual(fields.at(0).constraints().constraintOrigin(QgsFieldConstraints.Constraint.ConstraintNotNull),
- QgsFieldConstraints.ConstraintOrigin.ConstraintOriginProvider)
- self.assertTrue(fields.at(1).constraints().constraints()
- & QgsFieldConstraints.Constraint.ConstraintNotNull)
- self.assertEqual(fields.at(1).constraints().constraintOrigin(QgsFieldConstraints.Constraint.ConstraintNotNull),
- QgsFieldConstraints.ConstraintOrigin.ConstraintOriginProvider)
- self.assertFalse(fields.at(2).constraints().constraints()
- & QgsFieldConstraints.Constraint.ConstraintNotNull)
- self.assertFalse(fields.at(3).constraints().constraints()
- & QgsFieldConstraints.Constraint.ConstraintNotNull)
- self.assertTrue(fields.at(4).constraints().constraints()
- & QgsFieldConstraints.Constraint.ConstraintNotNull)
- self.assertEqual(fields.at(4).constraints().constraintOrigin(QgsFieldConstraints.Constraint.ConstraintNotNull),
- QgsFieldConstraints.ConstraintOrigin.ConstraintOriginProvider)
+ self.assertTrue(
+ fields.at(0).constraints().constraints()
+ & QgsFieldConstraints.Constraint.ConstraintNotNull
+ )
+ self.assertEqual(
+ fields.at(0)
+ .constraints()
+ .constraintOrigin(QgsFieldConstraints.Constraint.ConstraintNotNull),
+ QgsFieldConstraints.ConstraintOrigin.ConstraintOriginProvider,
+ )
+ self.assertTrue(
+ fields.at(1).constraints().constraints()
+ & QgsFieldConstraints.Constraint.ConstraintNotNull
+ )
+ self.assertEqual(
+ fields.at(1)
+ .constraints()
+ .constraintOrigin(QgsFieldConstraints.Constraint.ConstraintNotNull),
+ QgsFieldConstraints.ConstraintOrigin.ConstraintOriginProvider,
+ )
+ self.assertFalse(
+ fields.at(2).constraints().constraints()
+ & QgsFieldConstraints.Constraint.ConstraintNotNull
+ )
+ self.assertFalse(
+ fields.at(3).constraints().constraints()
+ & QgsFieldConstraints.Constraint.ConstraintNotNull
+ )
+ self.assertTrue(
+ fields.at(4).constraints().constraints()
+ & QgsFieldConstraints.Constraint.ConstraintNotNull
+ )
+ self.assertEqual(
+ fields.at(4)
+ .constraints()
+ .constraintOrigin(QgsFieldConstraints.Constraint.ConstraintNotNull),
+ QgsFieldConstraints.ConstraintOrigin.ConstraintOriginProvider,
+ )
def testUniqueConstraint(self):
- vl = QgsVectorLayer(f"dbname={self.dbname} table=test_constraints key='id'", "test_constraints",
- "spatialite")
+ vl = QgsVectorLayer(
+ f"dbname={self.dbname} table=test_constraints key='id'",
+ "test_constraints",
+ "spatialite",
+ )
self.assertTrue(vl.isValid())
self.assertEqual(len(vl.fields()), 5)
# test some bad field indexes
- self.assertEqual(vl.dataProvider().fieldConstraints(-1),
- QgsFieldConstraints.Constraints())
- self.assertEqual(vl.dataProvider().fieldConstraints(
- 1001), QgsFieldConstraints.Constraints())
-
- self.assertTrue(vl.dataProvider().fieldConstraints(0)
- & QgsFieldConstraints.Constraint.ConstraintUnique)
- self.assertFalse(vl.dataProvider().fieldConstraints(1)
- & QgsFieldConstraints.Constraint.ConstraintUnique)
- self.assertTrue(vl.dataProvider().fieldConstraints(2)
- & QgsFieldConstraints.Constraint.ConstraintUnique)
- self.assertFalse(vl.dataProvider().fieldConstraints(3)
- & QgsFieldConstraints.Constraint.ConstraintUnique)
- self.assertTrue(vl.dataProvider().fieldConstraints(4)
- & QgsFieldConstraints.Constraint.ConstraintUnique)
+ self.assertEqual(
+ vl.dataProvider().fieldConstraints(-1), QgsFieldConstraints.Constraints()
+ )
+ self.assertEqual(
+ vl.dataProvider().fieldConstraints(1001), QgsFieldConstraints.Constraints()
+ )
+
+ self.assertTrue(
+ vl.dataProvider().fieldConstraints(0)
+ & QgsFieldConstraints.Constraint.ConstraintUnique
+ )
+ self.assertFalse(
+ vl.dataProvider().fieldConstraints(1)
+ & QgsFieldConstraints.Constraint.ConstraintUnique
+ )
+ self.assertTrue(
+ vl.dataProvider().fieldConstraints(2)
+ & QgsFieldConstraints.Constraint.ConstraintUnique
+ )
+ self.assertFalse(
+ vl.dataProvider().fieldConstraints(3)
+ & QgsFieldConstraints.Constraint.ConstraintUnique
+ )
+ self.assertTrue(
+ vl.dataProvider().fieldConstraints(4)
+ & QgsFieldConstraints.Constraint.ConstraintUnique
+ )
# test that constraints have been saved to fields correctly
fields = vl.fields()
- self.assertTrue(fields.at(0).constraints().constraints()
- & QgsFieldConstraints.Constraint.ConstraintUnique)
- self.assertEqual(fields.at(0).constraints().constraintOrigin(QgsFieldConstraints.Constraint.ConstraintUnique),
- QgsFieldConstraints.ConstraintOrigin.ConstraintOriginProvider)
- self.assertFalse(fields.at(1).constraints().constraints()
- & QgsFieldConstraints.Constraint.ConstraintUnique)
- self.assertTrue(fields.at(2).constraints().constraints()
- & QgsFieldConstraints.Constraint.ConstraintUnique)
- self.assertEqual(fields.at(2).constraints().constraintOrigin(QgsFieldConstraints.Constraint.ConstraintUnique),
- QgsFieldConstraints.ConstraintOrigin.ConstraintOriginProvider)
- self.assertFalse(fields.at(3).constraints().constraints()
- & QgsFieldConstraints.Constraint.ConstraintUnique)
- self.assertTrue(fields.at(4).constraints().constraints()
- & QgsFieldConstraints.Constraint.ConstraintUnique)
- self.assertEqual(fields.at(4).constraints().constraintOrigin(QgsFieldConstraints.Constraint.ConstraintUnique),
- QgsFieldConstraints.ConstraintOrigin.ConstraintOriginProvider)
+ self.assertTrue(
+ fields.at(0).constraints().constraints()
+ & QgsFieldConstraints.Constraint.ConstraintUnique
+ )
+ self.assertEqual(
+ fields.at(0)
+ .constraints()
+ .constraintOrigin(QgsFieldConstraints.Constraint.ConstraintUnique),
+ QgsFieldConstraints.ConstraintOrigin.ConstraintOriginProvider,
+ )
+ self.assertFalse(
+ fields.at(1).constraints().constraints()
+ & QgsFieldConstraints.Constraint.ConstraintUnique
+ )
+ self.assertTrue(
+ fields.at(2).constraints().constraints()
+ & QgsFieldConstraints.Constraint.ConstraintUnique
+ )
+ self.assertEqual(
+ fields.at(2)
+ .constraints()
+ .constraintOrigin(QgsFieldConstraints.Constraint.ConstraintUnique),
+ QgsFieldConstraints.ConstraintOrigin.ConstraintOriginProvider,
+ )
+ self.assertFalse(
+ fields.at(3).constraints().constraints()
+ & QgsFieldConstraints.Constraint.ConstraintUnique
+ )
+ self.assertTrue(
+ fields.at(4).constraints().constraints()
+ & QgsFieldConstraints.Constraint.ConstraintUnique
+ )
+ self.assertEqual(
+ fields.at(4)
+ .constraints()
+ .constraintOrigin(QgsFieldConstraints.Constraint.ConstraintUnique),
+ QgsFieldConstraints.ConstraintOrigin.ConstraintOriginProvider,
+ )
def testSkipConstraintCheck(self):
- vl = QgsVectorLayer(f"dbname={self.dbname} table=test_autoincrement", "test_autoincrement",
- "spatialite")
+ vl = QgsVectorLayer(
+ f"dbname={self.dbname} table=test_autoincrement",
+ "test_autoincrement",
+ "spatialite",
+ )
self.assertTrue(vl.isValid())
self.assertTrue(
- vl.dataProvider().skipConstraintCheck(0, QgsFieldConstraints.Constraint.ConstraintUnique, "Autogenerate"))
- self.assertFalse(vl.dataProvider().skipConstraintCheck(
- 0, QgsFieldConstraints.Constraint.ConstraintUnique, 123))
+ vl.dataProvider().skipConstraintCheck(
+ 0, QgsFieldConstraints.Constraint.ConstraintUnique, "Autogenerate"
+ )
+ )
+ self.assertFalse(
+ vl.dataProvider().skipConstraintCheck(
+ 0, QgsFieldConstraints.Constraint.ConstraintUnique, 123
+ )
+ )
# This test would fail. It would require turning on WAL
def XXXXXtestLocking(self):
- temp_dbname = self.dbname + '.locking'
+ temp_dbname = self.dbname + ".locking"
shutil.copy(self.dbname, temp_dbname)
- vl = QgsVectorLayer("dbname=%s table=test_n (geometry)" %
- temp_dbname, "test_n", "spatialite")
+ vl = QgsVectorLayer(
+ "dbname=%s table=test_n (geometry)" % temp_dbname, "test_n", "spatialite"
+ )
self.assertTrue(vl.isValid())
self.assertTrue(vl.startEditing())
- self.assertTrue(vl.changeGeometry(
- 1, QgsGeometry.fromWkt('POLYGON((0 0,1 0,1 1,0 1,0 0))')))
+ self.assertTrue(
+ vl.changeGeometry(1, QgsGeometry.fromWkt("POLYGON((0 0,1 0,1 1,0 1,0 0))"))
+ )
# The iterator will take one extra connection
myiter = vl.getFeatures()
@@ -865,8 +1050,11 @@ def XXXXXtestLocking(self):
def testDefaultValues(self):
- l = QgsVectorLayer("dbname=%s table='test_defaults' key='id'" %
- self.dbname, "test_defaults", "spatialite")
+ l = QgsVectorLayer(
+ "dbname=%s table='test_defaults' key='id'" % self.dbname,
+ "test_defaults",
+ "spatialite",
+ )
self.assertTrue(l.isValid())
self.assertEqual(l.dataProvider().defaultValue(1), "qgis 'is good")
@@ -875,29 +1063,35 @@ def testDefaultValues(self):
self.assertFalse(l.dataProvider().defaultValue(4))
def testVectorLayerUtilsCreateFeatureWithProviderDefaultLiteral(self):
- vl = QgsVectorLayer("dbname=%s table='test_defaults' key='id'" %
- self.dbname, "test_defaults", "spatialite")
+ vl = QgsVectorLayer(
+ "dbname=%s table='test_defaults' key='id'" % self.dbname,
+ "test_defaults",
+ "spatialite",
+ )
self.assertEqual(vl.dataProvider().defaultValue(2), 5)
f = QgsVectorLayerUtils.createFeature(vl)
self.assertEqual(f.attributes(), [None, "qgis 'is good", 5, 5.7, None])
# check that provider default literals do not take precedence over passed attribute values
- f = QgsVectorLayerUtils.createFeature(
- vl, attributes={1: 'qgis is great', 0: 3})
+ f = QgsVectorLayerUtils.createFeature(vl, attributes={1: "qgis is great", 0: 3})
self.assertEqual(f.attributes(), [3, "qgis is great", 5, 5.7, None])
# test that vector layer default value expression overrides provider default literal
vl.setDefaultValueDefinition(3, QgsDefaultValue("4*3"))
- f = QgsVectorLayerUtils.createFeature(
- vl, attributes={1: 'qgis is great', 0: 3})
+ f = QgsVectorLayerUtils.createFeature(vl, attributes={1: "qgis is great", 0: 3})
self.assertEqual(f.attributes(), [3, "qgis is great", 5, 12, None])
def testCreateAttributeIndex(self):
- vl = QgsVectorLayer("dbname=%s table='test_defaults' key='id'" %
- self.dbname, "test_defaults", "spatialite")
- self.assertTrue(vl.dataProvider().capabilities() &
- QgsVectorDataProvider.Capability.CreateAttributeIndex)
+ vl = QgsVectorLayer(
+ "dbname=%s table='test_defaults' key='id'" % self.dbname,
+ "test_defaults",
+ "spatialite",
+ )
+ self.assertTrue(
+ vl.dataProvider().capabilities()
+ & QgsVectorDataProvider.Capability.CreateAttributeIndex
+ )
self.assertFalse(vl.dataProvider().createAttributeIndex(-1))
self.assertFalse(vl.dataProvider().createAttributeIndex(100))
self.assertTrue(vl.dataProvider().createAttributeIndex(1))
@@ -905,19 +1099,21 @@ def testCreateAttributeIndex(self):
con = spatialite_connect(self.dbname, isolation_level=None)
cur = con.cursor()
rs = cur.execute(
- "SELECT * FROM sqlite_master WHERE type='index' AND tbl_name='test_defaults'")
+ "SELECT * FROM sqlite_master WHERE type='index' AND tbl_name='test_defaults'"
+ )
res = [row for row in rs]
self.assertEqual(len(res), 1)
index_name = res[0][1]
rs = cur.execute(f"PRAGMA index_info({index_name})")
res = [row for row in rs]
self.assertEqual(len(res), 1)
- self.assertEqual(res[0][2], 'name')
+ self.assertEqual(res[0][2], "name")
# second index
self.assertTrue(vl.dataProvider().createAttributeIndex(2))
rs = cur.execute(
- "SELECT * FROM sqlite_master WHERE type='index' AND tbl_name='test_defaults'")
+ "SELECT * FROM sqlite_master WHERE type='index' AND tbl_name='test_defaults'"
+ )
res = [row for row in rs]
self.assertEqual(len(res), 2)
indexed_columns = []
@@ -928,100 +1124,102 @@ def testCreateAttributeIndex(self):
self.assertEqual(len(res), 1)
indexed_columns.append(res[0][2])
- self.assertEqual(set(indexed_columns), {'name', 'number'})
+ self.assertEqual(set(indexed_columns), {"name", "number"})
con.close()
def testSubsetStringRegexp(self):
"""Check that the provider supports the REGEXP syntax"""
testPath = f"dbname={self.dbname} table='test_filter' (geometry) key='id'"
- vl = QgsVectorLayer(testPath, 'test', 'spatialite')
+ vl = QgsVectorLayer(testPath, "test", "spatialite")
self.assertTrue(vl.isValid())
- vl.setSubsetString('"name" REGEXP \'[txe]{3}\'')
+ vl.setSubsetString("\"name\" REGEXP '[txe]{3}'")
self.assertEqual(vl.featureCount(), 4)
- del (vl)
+ del vl
def testSubsetStringExtent_bug17863(self):
"""Check that the extent is correct when applied in the ctor and when
- modified after a subset string is set """
+ modified after a subset string is set"""
def _lessdigits(s):
- return re.sub(r'(\d+\.\d{3})\d+', r'\1', s)
+ return re.sub(r"(\d+\.\d{3})\d+", r"\1", s)
testPath = f"dbname={self.dbname} table='test_filter' (geometry) key='id'"
- subSetString = '"name" = \'int\''
- subSet = f' sql={subSetString}'
+ subSetString = "\"name\" = 'int'"
+ subSet = f" sql={subSetString}"
# unfiltered
- vl = QgsVectorLayer(testPath, 'test', 'spatialite')
+ vl = QgsVectorLayer(testPath, "test", "spatialite")
self.assertTrue(vl.isValid())
self.assertEqual(vl.featureCount(), 8)
unfiltered_extent = _lessdigits(vl.extent().toString())
- self.assertNotEqual('Empty', unfiltered_extent)
- del (vl)
+ self.assertNotEqual("Empty", unfiltered_extent)
+ del vl
# filter after construction ...
- subSet_vl2 = QgsVectorLayer(testPath, 'test', 'spatialite')
- self.assertEqual(_lessdigits(
- subSet_vl2.extent().toString()), unfiltered_extent)
+ subSet_vl2 = QgsVectorLayer(testPath, "test", "spatialite")
+ self.assertEqual(_lessdigits(subSet_vl2.extent().toString()), unfiltered_extent)
self.assertEqual(subSet_vl2.featureCount(), 8)
# ... apply filter now!
subSet_vl2.setSubsetString(subSetString)
self.assertEqual(subSet_vl2.featureCount(), 4)
self.assertEqual(subSet_vl2.subsetString(), subSetString)
- self.assertNotEqual(_lessdigits(
- subSet_vl2.extent().toString()), unfiltered_extent)
+ self.assertNotEqual(
+ _lessdigits(subSet_vl2.extent().toString()), unfiltered_extent
+ )
filtered_extent = _lessdigits(subSet_vl2.extent().toString())
- del (subSet_vl2)
+ del subSet_vl2
# filtered in constructor
- subSet_vl = QgsVectorLayer(
- testPath + subSet, 'subset_test', 'spatialite')
+ subSet_vl = QgsVectorLayer(testPath + subSet, "subset_test", "spatialite")
self.assertEqual(subSet_vl.subsetString(), subSetString)
self.assertTrue(subSet_vl.isValid())
# This was failing in bug 17863
self.assertEqual(subSet_vl.featureCount(), 4)
- self.assertEqual(_lessdigits(
- subSet_vl.extent().toString()), filtered_extent)
- self.assertNotEqual(_lessdigits(
- subSet_vl.extent().toString()), unfiltered_extent)
+ self.assertEqual(_lessdigits(subSet_vl.extent().toString()), filtered_extent)
+ self.assertNotEqual(
+ _lessdigits(subSet_vl.extent().toString()), unfiltered_extent
+ )
- self.assertTrue(subSet_vl.setSubsetString(''))
+ self.assertTrue(subSet_vl.setSubsetString(""))
self.assertEqual(subSet_vl.featureCount(), 8)
- self.assertEqual(_lessdigits(
- subSet_vl.extent().toString()), unfiltered_extent)
+ self.assertEqual(_lessdigits(subSet_vl.extent().toString()), unfiltered_extent)
def testDecodeUri(self):
"""Check that the provider URI decoding returns expected values"""
- filename = '/home/to/path/test.db'
- uri = f'dbname=\'{filename}\' table="test" (geometry) key=testkey sql=1=1'
+ filename = "/home/to/path/test.db"
+ uri = f"dbname='{filename}' table=\"test\" (geometry) key=testkey sql=1=1"
registry = QgsProviderRegistry.instance()
- components = registry.decodeUri('spatialite', uri)
- self.assertEqual(components['path'], filename)
- self.assertEqual(components['layerName'], 'test')
- self.assertEqual(components['subset'], '1=1')
- self.assertEqual(components['geometryColumn'], 'geometry')
- self.assertEqual(components['keyColumn'], 'testkey')
+ components = registry.decodeUri("spatialite", uri)
+ self.assertEqual(components["path"], filename)
+ self.assertEqual(components["layerName"], "test")
+ self.assertEqual(components["subset"], "1=1")
+ self.assertEqual(components["geometryColumn"], "geometry")
+ self.assertEqual(components["keyColumn"], "testkey")
def testEncodeUri(self):
"""Check that the provider URI encoding returns expected values"""
- filename = '/home/to/path/test.db'
+ filename = "/home/to/path/test.db"
registry = QgsProviderRegistry.instance()
- parts = {'path': filename,
- 'layerName': 'test',
- 'subset': '1=1',
- 'geometryColumn': 'geometry',
- 'keyColumn': 'testkey'}
- uri = registry.encodeUri('spatialite', parts)
- self.assertEqual(uri, f'dbname=\'{filename}\' key=\'testkey\' table="test" (geometry) sql=1=1')
+ parts = {
+ "path": filename,
+ "layerName": "test",
+ "subset": "1=1",
+ "geometryColumn": "geometry",
+ "keyColumn": "testkey",
+ }
+ uri = registry.encodeUri("spatialite", parts)
+ self.assertEqual(
+ uri, f"dbname='{filename}' key='testkey' table=\"test\" (geometry) sql=1=1"
+ )
def testPKNotInt(self):
- """ Check when primary key is not an integer """
+ """Check when primary key is not an integer"""
# create test db
tmpdir = tempfile.mkdtemp()
self.dirs_to_cleanup.append(tmpdir)
@@ -1030,7 +1228,7 @@ def testPKNotInt(self):
cur = con.cursor()
# try the two different types of index creation
- for index_creation_method in ['CreateSpatialIndex', 'CreateMbrCache']:
+ for index_creation_method in ["CreateSpatialIndex", "CreateMbrCache"]:
table_name = f"pk_is_string_{index_creation_method}"
cur.execute("BEGIN")
@@ -1038,7 +1236,9 @@ def testPKNotInt(self):
cur.execute(sql)
# create table with spatial index and pk is string
- sql = "CREATE TABLE {}(id VARCHAR PRIMARY KEY NOT NULL, name TEXT NOT NULL);"
+ sql = (
+ "CREATE TABLE {}(id VARCHAR PRIMARY KEY NOT NULL, name TEXT NOT NULL);"
+ )
cur.execute(sql.format(table_name))
sql = "SELECT AddGeometryColumn('{}', 'geometry', 4326, 'POINT', 'XY')"
@@ -1053,7 +1253,7 @@ def testPKNotInt(self):
cur.execute("COMMIT")
testPath = f"dbname={dbname} table='{table_name}' (geometry)"
- vl = QgsVectorLayer(testPath, 'test', 'spatialite')
+ vl = QgsVectorLayer(testPath, "test", "spatialite")
self.assertTrue(vl.isValid())
self.assertEqual(vl.featureCount(), 1)
@@ -1084,41 +1284,57 @@ def testLoadStyle(self):
cur.execute(sql)
# simple table with primary key
- sql = "CREATE TABLE test_pg (id INTEGER NOT NULL PRIMARY KEY, name TEXT NOT NULL)"
+ sql = (
+ "CREATE TABLE test_pg (id INTEGER NOT NULL PRIMARY KEY, name TEXT NOT NULL)"
+ )
cur.execute(sql)
sql = "SELECT AddGeometryColumn('test_pg', 'geometry', 4326, 'POLYGON', 'XY')"
cur.execute(sql)
sql = "INSERT INTO test_pg (id, name, geometry) "
- sql += "VALUES (1, 'toto', GeomFromText('POLYGON((0 0,1 0,1 1,0 1,0 0))', 4326))"
+ sql += (
+ "VALUES (1, 'toto', GeomFromText('POLYGON((0 0,1 0,1 1,0 1,0 0))', 4326))"
+ )
cur.execute(sql)
cur.execute("COMMIT")
con.close()
testPath = f"dbname={dbname} table='test_pg' (geometry) key='id'"
- vl = QgsVectorLayer(testPath, 'test', 'spatialite')
+ vl = QgsVectorLayer(testPath, "test", "spatialite")
self.assertTrue(vl.isValid())
self.assertEqual(vl.featureCount(), 1)
err, ok = vl.loadDefaultStyle()
self.assertFalse(ok)
- vl.saveStyleToDatabase('my_style', 'My description', True, '')
+ vl.saveStyleToDatabase("my_style", "My description", True, "")
err, ok = vl.loadDefaultStyle()
self.assertTrue(ok)
def testStyleStorage(self):
# First test with invalid URI
- vl = QgsVectorLayer('/idont/exist.sqlite', 'test', 'spatialite')
+ vl = QgsVectorLayer("/idont/exist.sqlite", "test", "spatialite")
- self.assertEqual(int(vl.dataProvider().styleStorageCapabilities()) & Qgis.ProviderStyleStorageCapability.LoadFromDatabase, 0)
- self.assertEqual(int(vl.dataProvider().styleStorageCapabilities()) & Qgis.ProviderStyleStorageCapability.SaveToDatabase, 0)
+ self.assertEqual(
+ int(vl.dataProvider().styleStorageCapabilities())
+ & Qgis.ProviderStyleStorageCapability.LoadFromDatabase,
+ 0,
+ )
+ self.assertEqual(
+ int(vl.dataProvider().styleStorageCapabilities())
+ & Qgis.ProviderStyleStorageCapability.SaveToDatabase,
+ 0,
+ )
- res, err = QgsProviderRegistry.instance().styleExists('spatialite', '/idont/exist.sqlite', '')
+ res, err = QgsProviderRegistry.instance().styleExists(
+ "spatialite", "/idont/exist.sqlite", ""
+ )
self.assertFalse(res)
self.assertTrue(err)
- res, err = QgsProviderRegistry.instance().styleExists('spatialite', '/idont/exist.sqlite', 'a style')
+ res, err = QgsProviderRegistry.instance().styleExists(
+ "spatialite", "/idont/exist.sqlite", "a style"
+ )
self.assertFalse(res)
self.assertTrue(err)
@@ -1133,7 +1349,7 @@ def testStyleStorage(self):
self.assertFalse(qml)
self.assertTrue(errmsg)
- qml, success = vl.loadNamedStyle('/idont/exist.sqlite')
+ qml, success = vl.loadNamedStyle("/idont/exist.sqlite")
self.assertFalse(success)
errorMsg = vl.saveStyleToDatabase("name", "description", False, "")
@@ -1150,31 +1366,47 @@ def testStyleStorage(self):
cur.execute(sql)
# simple table with primary key
- sql = "CREATE TABLE test_pg (id INTEGER NOT NULL PRIMARY KEY, name TEXT NOT NULL)"
+ sql = (
+ "CREATE TABLE test_pg (id INTEGER NOT NULL PRIMARY KEY, name TEXT NOT NULL)"
+ )
cur.execute(sql)
sql = "SELECT AddGeometryColumn('test_pg', 'geometry', 4326, 'POLYGON', 'XY')"
cur.execute(sql)
sql = "INSERT INTO test_pg (id, name, geometry) "
- sql += "VALUES (1, 'toto', GeomFromText('POLYGON((0 0,1 0,1 1,0 1,0 0))', 4326))"
+ sql += (
+ "VALUES (1, 'toto', GeomFromText('POLYGON((0 0,1 0,1 1,0 1,0 0))', 4326))"
+ )
cur.execute(sql)
cur.execute("COMMIT")
con.close()
testPath = f"dbname={dbname} table='test_pg' (geometry) key='id'"
- vl = QgsVectorLayer(testPath, 'test', 'spatialite')
+ vl = QgsVectorLayer(testPath, "test", "spatialite")
self.assertTrue(vl.isValid())
- self.assertEqual(int(vl.dataProvider().styleStorageCapabilities()) & Qgis.ProviderStyleStorageCapability.LoadFromDatabase, Qgis.ProviderStyleStorageCapability.LoadFromDatabase)
- self.assertEqual(int(vl.dataProvider().styleStorageCapabilities()) & Qgis.ProviderStyleStorageCapability.SaveToDatabase, Qgis.ProviderStyleStorageCapability.SaveToDatabase)
+ self.assertEqual(
+ int(vl.dataProvider().styleStorageCapabilities())
+ & Qgis.ProviderStyleStorageCapability.LoadFromDatabase,
+ Qgis.ProviderStyleStorageCapability.LoadFromDatabase,
+ )
+ self.assertEqual(
+ int(vl.dataProvider().styleStorageCapabilities())
+ & Qgis.ProviderStyleStorageCapability.SaveToDatabase,
+ Qgis.ProviderStyleStorageCapability.SaveToDatabase,
+ )
# style tables don't exist yet
- res, err = QgsProviderRegistry.instance().styleExists('spatialite', vl.source(), '')
+ res, err = QgsProviderRegistry.instance().styleExists(
+ "spatialite", vl.source(), ""
+ )
self.assertFalse(res)
self.assertFalse(err)
- res, err = QgsProviderRegistry.instance().styleExists('spatialite', vl.source(), 'a style')
+ res, err = QgsProviderRegistry.instance().styleExists(
+ "spatialite", vl.source(), "a style"
+ )
self.assertFalse(res)
self.assertFalse(err)
@@ -1189,19 +1421,25 @@ def testStyleStorage(self):
self.assertFalse(qml)
self.assertTrue(errmsg)
- qml, success = vl.loadNamedStyle(f'{dbname}|layerid=0')
+ qml, success = vl.loadNamedStyle(f"{dbname}|layerid=0")
self.assertFalse(success)
errorMsg = vl.saveStyleToDatabase("name", "description", False, "")
self.assertEqual(errorMsg, "")
- res, err = QgsProviderRegistry.instance().styleExists('spatialite', vl.source(), '')
+ res, err = QgsProviderRegistry.instance().styleExists(
+ "spatialite", vl.source(), ""
+ )
self.assertFalse(res)
self.assertFalse(err)
- res, err = QgsProviderRegistry.instance().styleExists('spatialite', vl.source(), 'a style')
+ res, err = QgsProviderRegistry.instance().styleExists(
+ "spatialite", vl.source(), "a style"
+ )
self.assertFalse(res)
self.assertFalse(err)
- res, err = QgsProviderRegistry.instance().styleExists('spatialite', vl.source(), 'name')
+ res, err = QgsProviderRegistry.instance().styleExists(
+ "spatialite", vl.source(), "name"
+ )
self.assertTrue(res)
self.assertFalse(err)
@@ -1212,16 +1450,16 @@ def testStyleStorage(self):
related_count, idlist, namelist, desclist, errmsg = vl.listStylesInDatabase()
self.assertEqual(related_count, 1)
self.assertFalse(errmsg)
- self.assertEqual(idlist, ['1'])
- self.assertEqual(namelist, ['name'])
- self.assertEqual(desclist, ['description'])
+ self.assertEqual(idlist, ["1"])
+ self.assertEqual(namelist, ["name"])
+ self.assertEqual(desclist, ["description"])
qml, errmsg = vl.getStyleFromDatabase("100")
self.assertEqual(qml, "")
self.assertNotEqual(errmsg, "")
qml, errmsg = vl.getStyleFromDatabase("1")
- self.assertTrue(qml.startswith('?layer=ogr:{percent_path_relative}', content)
+ content = "".join(f.readlines())
+ self.assertIn(f"?layer=ogr:{percent_path_relative}", content)
# Check that project is correctly re-read with all layers
QgsProject.instance().setFileName(temp)
@@ -874,17 +1230,19 @@ def test_relative_paths(self):
self.assertEqual(len(QgsProject.instance().mapLayers()), 2)
# Store absolute
- QgsProject.instance().writeEntryBool('Paths', '/Absolute', True)
+ QgsProject.instance().writeEntryBool("Paths", "/Absolute", True)
QgsProject.instance().write()
QgsProject.instance().clear()
self.assertEqual(len(QgsProject.instance().mapLayers()), 0)
# Check that virtual layer source is stored with absolute path
- percent_path_absolute = toPercent(os.path.join(self.testDataDir, "france_parts.shp"))
+ percent_path_absolute = toPercent(
+ os.path.join(self.testDataDir, "france_parts.shp")
+ )
with open(temp) as f:
- content = ''.join(f.readlines())
- self.assertIn(f'?layer=ogr:{percent_path_absolute}', content)
+ content = "".join(f.readlines())
+ self.assertIn(f"?layer=ogr:{percent_path_absolute}", content)
# Check that project is correctly re-read with all layers
QgsProject.instance().setFileName(temp)
@@ -893,10 +1251,14 @@ def test_relative_paths(self):
def test_absolute_relative_uri(self):
context = QgsReadWriteContext()
- context.setPathResolver(QgsPathResolver(os.path.join(self.testDataDir, "project.qgs")))
+ context.setPathResolver(
+ QgsPathResolver(os.path.join(self.testDataDir, "project.qgs"))
+ )
df_abs = QgsVirtualLayerDefinition()
- df_abs.addSource("vtab", os.path.join(self.testDataDir, "france_parts.shp"), "ogr")
+ df_abs.addSource(
+ "vtab", os.path.join(self.testDataDir, "france_parts.shp"), "ogr"
+ )
df_rel = QgsVirtualLayerDefinition()
df_rel.addSource("vtab", "./france_parts.shp", "ogr")
@@ -907,25 +1269,35 @@ def test_absolute_relative_uri(self):
meta = QgsProviderRegistry.instance().providerMetadata("virtual")
assert meta is not None
- self.assertEqual(meta.absoluteToRelativeUri(absolute_uri, context), relative_uri)
- self.assertEqual(meta.relativeToAbsoluteUri(relative_uri, context), absolute_uri)
+ self.assertEqual(
+ meta.absoluteToRelativeUri(absolute_uri, context), relative_uri
+ )
+ self.assertEqual(
+ meta.relativeToAbsoluteUri(relative_uri, context), absolute_uri
+ )
def test_qgisExpressionFunctions(self):
- QgsProject.instance().setTitle('project')
- self.assertEqual(QgsProject.instance().title(), 'project')
+ QgsProject.instance().setTitle("project")
+ self.assertEqual(QgsProject.instance().title(), "project")
df = QgsVirtualLayerDefinition()
df.setQuery(
- "SELECT format('hello %1', 'world') as a, year(todate('2016-01-02')) as b, title('This') as t, var('project_title') as c")
+ "SELECT format('hello %1', 'world') as a, year(todate('2016-01-02')) as b, title('This') as t, var('project_title') as c"
+ )
l = QgsVectorLayer(df.toString(), "testq", "virtual")
self.assertTrue(l.isValid())
for f in l.getFeatures():
- self.assertEqual(f.attributes(), ['hello world', 2016, 'This', 'project'])
+ self.assertEqual(f.attributes(), ["hello world", 2016, "This", "project"])
def test_query_with_accents(self):
# shapefile with accents and latin1 encoding
df = QgsVirtualLayerDefinition()
- df.addSource("vtab", os.path.join(self.testDataDir, "france_parts.shp"), "ogr", "ISO-8859-1")
+ df.addSource(
+ "vtab",
+ os.path.join(self.testDataDir, "france_parts.shp"),
+ "ogr",
+ "ISO-8859-1",
+ )
df.setQuery("SELECT * FROM vtab WHERE TYPE_1 = 'Région'")
vl = QgsVectorLayer(df.toString(), "testq", "virtual")
self.assertTrue(vl.isValid())
@@ -933,7 +1305,9 @@ def test_query_with_accents(self):
self.assertEqual(len(ids), 4)
# the same shapefile with a wrong encoding
- df.addSource("vtab", os.path.join(self.testDataDir, "france_parts.shp"), "ogr", "UTF-8")
+ df.addSource(
+ "vtab", os.path.join(self.testDataDir, "france_parts.shp"), "ogr", "UTF-8"
+ )
df.setQuery("SELECT * FROM vtab WHERE TYPE_1 = 'Région'")
vl2 = QgsVectorLayer(df.toString(), "testq", "virtual")
self.assertTrue(vl2.isValid())
@@ -941,8 +1315,12 @@ def test_query_with_accents(self):
self.assertEqual(ids, [])
def test_layer_with_accents(self):
- l1 = QgsVectorLayer(os.path.join(self.testDataDir, "france_parts.shp"), "françéà", "ogr",
- QgsVectorLayer.LayerOptions(False))
+ l1 = QgsVectorLayer(
+ os.path.join(self.testDataDir, "france_parts.shp"),
+ "françéà",
+ "ogr",
+ QgsVectorLayer.LayerOptions(False),
+ )
self.assertTrue(l1.isValid())
QgsProject.instance().addMapLayer(l1)
@@ -957,8 +1335,12 @@ def test_layer_with_accents(self):
QgsProject.instance().removeMapLayer(l1.id())
def test_lazy(self):
- l1 = QgsVectorLayer(os.path.join(self.testDataDir, "france_parts.shp"), "françéà", "ogr",
- QgsVectorLayer.LayerOptions(False))
+ l1 = QgsVectorLayer(
+ os.path.join(self.testDataDir, "france_parts.shp"),
+ "françéà",
+ "ogr",
+ QgsVectorLayer.LayerOptions(False),
+ )
self.assertTrue(l1.isValid())
QgsProject.instance().addMapLayer(l1)
@@ -978,16 +1360,29 @@ def test_lazy(self):
QgsProject.instance().removeMapLayer(l1.id())
def test_joined_layers_conversion(self):
- v1 = QgsVectorLayer("Point?field=id:integer&field=b_id:integer&field=c_id:integer&field=name:string", "A",
- "memory")
+ v1 = QgsVectorLayer(
+ "Point?field=id:integer&field=b_id:integer&field=c_id:integer&field=name:string",
+ "A",
+ "memory",
+ )
self.assertTrue(v1.isValid())
- v2 = QgsVectorLayer("Point?field=id:integer&field=bname:string&field=bfield:integer", "B", "memory")
+ v2 = QgsVectorLayer(
+ "Point?field=id:integer&field=bname:string&field=bfield:integer",
+ "B",
+ "memory",
+ )
self.assertTrue(v2.isValid())
v3 = QgsVectorLayer("Point?field=id:integer&field=cname:string", "C", "memory")
self.assertTrue(v3.isValid())
- tl1 = QgsVectorLayer("NoGeometry?field=id:integer&field=e_id:integer&field=0name:string", "D", "memory")
+ tl1 = QgsVectorLayer(
+ "NoGeometry?field=id:integer&field=e_id:integer&field=0name:string",
+ "D",
+ "memory",
+ )
self.assertTrue(tl1.isValid())
- tl2 = QgsVectorLayer("NoGeometry?field=id:integer&field=ena me:string", "E", "memory")
+ tl2 = QgsVectorLayer(
+ "NoGeometry?field=id:integer&field=ena me:string", "E", "memory"
+ )
self.assertTrue(tl2.isValid())
QgsProject.instance().addMapLayers([v1, v2, v3, tl1, tl2])
joinInfo = QgsVectorLayerJoinInfo()
@@ -999,9 +1394,12 @@ def test_joined_layers_conversion(self):
self.assertEqual(len(v1.fields()), 6)
df = QgsVirtualLayerDefinitionUtils.fromJoinedLayer(v1)
- self.assertEqual(df.query(),
- 'SELECT t.geometry, t.rowid AS uid, t."id", t."b_id", t."c_id", t."name", j1."bname" AS "B_bname", j1."bfield" AS "B_bfield" FROM "{}" AS t LEFT JOIN "{}" AS j1 ON t."b_id"=j1."id"'.format(
- v1.id(), v2.id()))
+ self.assertEqual(
+ df.query(),
+ 'SELECT t.geometry, t.rowid AS uid, t."id", t."b_id", t."c_id", t."name", j1."bname" AS "B_bname", j1."bfield" AS "B_bfield" FROM "{}" AS t LEFT JOIN "{}" AS j1 ON t."b_id"=j1."id"'.format(
+ v1.id(), v2.id()
+ ),
+ )
# with a field subset
v1.removeJoin(v2.id())
@@ -1009,9 +1407,12 @@ def test_joined_layers_conversion(self):
v1.addJoin(joinInfo)
self.assertEqual(len(v1.fields()), 5)
df = QgsVirtualLayerDefinitionUtils.fromJoinedLayer(v1)
- self.assertEqual(df.query(),
- 'SELECT t.geometry, t.rowid AS uid, t."id", t."b_id", t."c_id", t."name", j1."bname" AS "B_bname" FROM "{}" AS t LEFT JOIN "{}" AS j1 ON t."b_id"=j1."id"'.format(
- v1.id(), v2.id()))
+ self.assertEqual(
+ df.query(),
+ 'SELECT t.geometry, t.rowid AS uid, t."id", t."b_id", t."c_id", t."name", j1."bname" AS "B_bname" FROM "{}" AS t LEFT JOIN "{}" AS j1 ON t."b_id"=j1."id"'.format(
+ v1.id(), v2.id()
+ ),
+ )
joinInfo.setJoinFieldNamesSubset(None)
# add a table prefix to the join
@@ -1020,9 +1421,12 @@ def test_joined_layers_conversion(self):
v1.addJoin(joinInfo)
self.assertEqual(len(v1.fields()), 6)
df = QgsVirtualLayerDefinitionUtils.fromJoinedLayer(v1)
- self.assertEqual(df.query(),
- 'SELECT t.geometry, t.rowid AS uid, t."id", t."b_id", t."c_id", t."name", j1."bname" AS "BB_bname", j1."bfield" AS "BB_bfield" FROM "{}" AS t LEFT JOIN "{}" AS j1 ON t."b_id"=j1."id"'.format(
- v1.id(), v2.id()))
+ self.assertEqual(
+ df.query(),
+ 'SELECT t.geometry, t.rowid AS uid, t."id", t."b_id", t."c_id", t."name", j1."bname" AS "BB_bname", j1."bfield" AS "BB_bfield" FROM "{}" AS t LEFT JOIN "{}" AS j1 ON t."b_id"=j1."id"'.format(
+ v1.id(), v2.id()
+ ),
+ )
joinInfo.setPrefix("")
v1.removeJoin(v2.id())
v1.addJoin(joinInfo)
@@ -1035,10 +1439,14 @@ def test_joined_layers_conversion(self):
v1.addJoin(joinInfo2)
self.assertEqual(len(v1.fields()), 7)
df = QgsVirtualLayerDefinitionUtils.fromJoinedLayer(v1)
- self.assertEqual(df.query(), (
- 'SELECT t.geometry, t.rowid AS uid, t."id", t."b_id", t."c_id", t."name", j1."bname" AS "B_bname", j1."bfield" AS "B_bfield", j2."cname" AS "C_cname" FROM "{}" AS t ' +
- 'LEFT JOIN "{}" AS j1 ON t."b_id"=j1."id" ' +
- 'LEFT JOIN "{}" AS j2 ON t."c_id"=j2."id"').format(v1.id(), v2.id(), v3.id()))
+ self.assertEqual(
+ df.query(),
+ (
+ 'SELECT t.geometry, t.rowid AS uid, t."id", t."b_id", t."c_id", t."name", j1."bname" AS "B_bname", j1."bfield" AS "B_bfield", j2."cname" AS "C_cname" FROM "{}" AS t '
+ + 'LEFT JOIN "{}" AS j1 ON t."b_id"=j1."id" '
+ + 'LEFT JOIN "{}" AS j2 ON t."c_id"=j2."id"'
+ ).format(v1.id(), v2.id(), v3.id()),
+ )
# test NoGeometry joined layers with field names starting with a digit or containing white spaces
joinInfo3 = QgsVectorLayerJoinInfo()
@@ -1048,65 +1456,96 @@ def test_joined_layers_conversion(self):
tl1.addJoin(joinInfo3)
self.assertEqual(len(tl1.fields()), 4)
df = QgsVirtualLayerDefinitionUtils.fromJoinedLayer(tl1)
- self.assertEqual(df.query(),
- 'SELECT t.rowid AS uid, t."id", t."e_id", t."0name", j1."ena me" AS "E_ena me" FROM "{}" AS t LEFT JOIN "{}" AS j1 ON t."e_id"=j1."id"'.format(
- tl1.id(), tl2.id()))
+ self.assertEqual(
+ df.query(),
+ 'SELECT t.rowid AS uid, t."id", t."e_id", t."0name", j1."ena me" AS "E_ena me" FROM "{}" AS t LEFT JOIN "{}" AS j1 ON t."e_id"=j1."id"'.format(
+ tl1.id(), tl2.id()
+ ),
+ )
- QgsProject.instance().removeMapLayers([v1.id(), v2.id(), v3.id(), tl1.id(), tl2.id()])
+ QgsProject.instance().removeMapLayers(
+ [v1.id(), v2.id(), v3.id(), tl1.id(), tl2.id()]
+ )
def testFieldsWithSpecialCharacters(self):
- ml = QgsVectorLayer("Point?srid=EPSG:4326&field=123:int", "mem_with_nontext_fieldnames", "memory")
+ ml = QgsVectorLayer(
+ "Point?srid=EPSG:4326&field=123:int",
+ "mem_with_nontext_fieldnames",
+ "memory",
+ )
self.assertTrue(ml.isValid())
QgsProject.instance().addMapLayer(ml)
ml.startEditing()
- self.assertTrue(ml.addAttribute(QgsField('abc:123', QVariant.String)))
- self.assertTrue(ml.addAttribute(QgsField('map', QVariant.String))) # matches QGIS expression function name
+ self.assertTrue(ml.addAttribute(QgsField("abc:123", QVariant.String)))
+ self.assertTrue(
+ ml.addAttribute(QgsField("map", QVariant.String))
+ ) # matches QGIS expression function name
f1 = QgsFeature(ml.fields())
- f1.setGeometry(QgsGeometry.fromWkt('POINT(0 0)'))
- f1.setAttributes([1, 'a', 'b'])
+ f1.setGeometry(QgsGeometry.fromWkt("POINT(0 0)"))
+ f1.setAttributes([1, "a", "b"])
f2 = QgsFeature(ml.fields())
- f2.setGeometry(QgsGeometry.fromWkt('POINT(1 1)'))
- f2.setAttributes([2, 'c', 'd'])
+ f2.setGeometry(QgsGeometry.fromWkt("POINT(1 1)"))
+ f2.setAttributes([2, "c", "d"])
ml.addFeatures([f1, f2])
ml.commitChanges()
- vl = QgsVectorLayer("?query=select * from mem_with_nontext_fieldnames", "vl", "virtual")
+ vl = QgsVectorLayer(
+ "?query=select * from mem_with_nontext_fieldnames", "vl", "virtual"
+ )
self.assertTrue(vl.isValid())
- self.assertEqual(vl.fields().at(0).name(), '123')
- self.assertEqual(vl.fields().at(1).name(), 'abc:123')
+ self.assertEqual(vl.fields().at(0).name(), "123")
+ self.assertEqual(vl.fields().at(1).name(), "abc:123")
self.assertEqual(vl.featureCount(), 2)
- features = [f for f in vl.getFeatures(QgsFeatureRequest().setFilterExpression('"abc:123"=\'c\''))]
+ features = [
+ f
+ for f in vl.getFeatures(
+ QgsFeatureRequest().setFilterExpression("\"abc:123\"='c'")
+ )
+ ]
self.assertEqual(len(features), 1)
- self.assertEqual(features[0].attributes(), [2, 'c', 'd'])
-
- features = [f for f in vl.getFeatures(QgsFeatureRequest().setFilterExpression('"map"=\'b\''))]
+ self.assertEqual(features[0].attributes(), [2, "c", "d"])
+
+ features = [
+ f
+ for f in vl.getFeatures(
+ QgsFeatureRequest().setFilterExpression("\"map\"='b'")
+ )
+ ]
self.assertEqual(len(features), 1)
- self.assertEqual(features[0].attributes(), [1, 'a', 'b'])
+ self.assertEqual(features[0].attributes(), [1, "a", "b"])
- vl2 = QgsVectorLayer("?query=select * from mem_with_nontext_fieldnames where \"abc:123\"='c'", "vl", "virtual")
+ vl2 = QgsVectorLayer(
+ "?query=select * from mem_with_nontext_fieldnames where \"abc:123\"='c'",
+ "vl",
+ "virtual",
+ )
self.assertTrue(vl2.isValid())
- self.assertEqual(vl2.fields().at(0).name(), '123')
- self.assertEqual(vl2.fields().at(1).name(), 'abc:123')
+ self.assertEqual(vl2.fields().at(0).name(), "123")
+ self.assertEqual(vl2.fields().at(1).name(), "abc:123")
self.assertEqual(vl2.featureCount(), 1)
features = [f for f in vl2.getFeatures()]
self.assertEqual(len(features), 1)
- self.assertEqual(features[0].attributes(), [2, 'c', 'd'])
+ self.assertEqual(features[0].attributes(), [2, "c", "d"])
- vl3 = QgsVectorLayer("?query=select * from mem_with_nontext_fieldnames where \"map\"='b'", "vl", "virtual")
+ vl3 = QgsVectorLayer(
+ "?query=select * from mem_with_nontext_fieldnames where \"map\"='b'",
+ "vl",
+ "virtual",
+ )
self.assertTrue(vl3.isValid())
- self.assertEqual(vl3.fields().at(0).name(), '123')
- self.assertEqual(vl3.fields().at(1).name(), 'abc:123')
+ self.assertEqual(vl3.fields().at(0).name(), "123")
+ self.assertEqual(vl3.fields().at(1).name(), "abc:123")
self.assertEqual(vl3.featureCount(), 1)
features = [f for f in vl3.getFeatures()]
self.assertEqual(len(features), 1)
- self.assertEqual(features[0].attributes(), [1, 'a', 'b'])
+ self.assertEqual(features[0].attributes(), [1, "a", "b"])
QgsProject.instance().removeMapLayer(ml)
@@ -1119,13 +1558,13 @@ def testFiltersWithoutUid(self):
ml.startEditing()
for i in range(10):
f = QgsFeature(ml.fields())
- f.setGeometry(QgsGeometry.fromWkt(f'POINT({i} 0)'))
+ f.setGeometry(QgsGeometry.fromWkt(f"POINT({i} 0)"))
f.setAttributes([i])
ml.addFeatures([f])
ml.commitChanges()
df = QgsVirtualLayerDefinition()
- df.setQuery('select * from mem_no_uid')
+ df.setQuery("select * from mem_no_uid")
vl = QgsVectorLayer(df.toString(), "vl", "virtual")
self.assertTrue(vl.isValid())
@@ -1140,11 +1579,11 @@ def testFiltersWithoutUid(self):
self.assertEqual(fids, [5])
req = QgsFeatureRequest().setFilterFid(5)
- a = [(f.id(), f['a']) for f in vl.getFeatures(req)]
+ a = [(f.id(), f["a"]) for f in vl.getFeatures(req)]
self.assertEqual(a, [(5, 5)])
req = QgsFeatureRequest().setFilterFids([5, 6, 8])
- a = [(f.id(), f['a']) for f in vl.getFeatures(req)]
+ a = [(f.id(), f["a"]) for f in vl.getFeatures(req)]
self.assertEqual(a, [(5, 5), (6, 6), (8, 8)])
QgsProject.instance().removeMapLayer(ml)
@@ -1160,7 +1599,7 @@ def testUpdatedFields(self):
ml.startEditing()
f1 = QgsFeature(ml.fields())
- f1.setGeometry(QgsGeometry.fromWkt('POINT(2 3)'))
+ f1.setGeometry(QgsGeometry.fromWkt("POINT(2 3)"))
ml.addFeatures([f1])
ml.commitChanges()
@@ -1168,7 +1607,7 @@ def testUpdatedFields(self):
self.assertTrue(vl.isValid())
# add one more field
- ml.dataProvider().addAttributes([QgsField('newfield', QVariant.Int)])
+ ml.dataProvider().addAttributes([QgsField("newfield", QVariant.Int)])
ml.updateFields()
self.assertEqual(ml.featureCount(), vl.featureCount())
@@ -1187,7 +1626,9 @@ def test_filter_rect_precise(self):
# Check if don't lost precision when filtering on rect (see https://github.com/qgis/QGIS/issues/36054)
- pl = QgsVectorLayer(os.path.join(self.testDataDir, "points.shp"), "points", "ogr")
+ pl = QgsVectorLayer(
+ os.path.join(self.testDataDir, "points.shp"), "points", "ogr"
+ )
self.assertTrue(pl.isValid())
QgsProject.instance().addMapLayer(pl)
@@ -1198,7 +1639,12 @@ def test_filter_rect_precise(self):
# Take an extent where east farthest point is excluded and second farthest east is on the edge
# and should be returned
- extent = QgsRectangle(-117.23257418909581418, 22.80020703933767834, -85.6521739130433276, 46.87198067632875365)
+ extent = QgsRectangle(
+ -117.23257418909581418,
+ 22.80020703933767834,
+ -85.6521739130433276,
+ 46.87198067632875365,
+ )
r = QgsFeatureRequest(extent)
features = [feature for feature in vl.getFeatures(r)]
self.assertEqual(len(features), 16)
@@ -1212,35 +1658,40 @@ def test_subset_string(self):
project = QgsProject.instance()
project.clear()
- data_layer = QgsVectorLayer('Point?crs=epsg:4326&field=fid:integer&field=value:integer&field=join_pk:integer', 'data', 'memory')
- join_layer = QgsVectorLayer('NoGeometry?field=fid:integer&field=value:string', 'join', 'memory')
+ data_layer = QgsVectorLayer(
+ "Point?crs=epsg:4326&field=fid:integer&field=value:integer&field=join_pk:integer",
+ "data",
+ "memory",
+ )
+ join_layer = QgsVectorLayer(
+ "NoGeometry?field=fid:integer&field=value:string", "join", "memory"
+ )
tempdir = QTemporaryDir()
- gpkg_path = os.path.join(tempdir.path(), 'test_subset.gpkg')
- project_path = os.path.join(tempdir.path(), 'test_subset.qgs')
+ gpkg_path = os.path.join(tempdir.path(), "test_subset.gpkg")
+ project_path = os.path.join(tempdir.path(), "test_subset.qgs")
self.assertTrue(data_layer.isValid())
self.assertTrue(join_layer.isValid())
self.assertFalse(join_layer.isSpatial())
f = QgsFeature(data_layer.fields())
f.setAttributes([1, 20, 2])
- f.setGeometry(QgsGeometry.fromWkt('point(9 45'))
+ f.setGeometry(QgsGeometry.fromWkt("point(9 45"))
self.assertTrue(data_layer.dataProvider().addFeature(f))
f = QgsFeature(data_layer.fields())
f.setAttributes([2, 10, 1])
- f.setGeometry(QgsGeometry.fromWkt('point(9 45'))
+ f.setGeometry(QgsGeometry.fromWkt("point(9 45"))
self.assertTrue(data_layer.dataProvider().addFeature(f))
options = QgsVectorFileWriter.SaveVectorOptions()
- options.driverName = 'GPKG'
- options.actionOnExistingFile = QgsVectorFileWriter.ActionOnExistingFile.CreateOrOverwriteFile
- options.layerName = 'data'
+ options.driverName = "GPKG"
+ options.actionOnExistingFile = (
+ QgsVectorFileWriter.ActionOnExistingFile.CreateOrOverwriteFile
+ )
+ options.layerName = "data"
_, _ = QgsVectorFileWriter.writeAsVectorFormatV2(
- data_layer,
- gpkg_path,
- data_layer.transformContext(),
- options
+ data_layer, gpkg_path, data_layer.transformContext(), options
)
f = QgsFeature(join_layer.fields())
@@ -1249,18 +1700,17 @@ def test_subset_string(self):
f.setAttributes([2, "twenty"])
self.assertTrue(join_layer.dataProvider().addFeature(f))
- options.layerName = 'join'
- options.actionOnExistingFile = QgsVectorFileWriter.ActionOnExistingFile.CreateOrOverwriteLayer
+ options.layerName = "join"
+ options.actionOnExistingFile = (
+ QgsVectorFileWriter.ActionOnExistingFile.CreateOrOverwriteLayer
+ )
_, _ = QgsVectorFileWriter.writeAsVectorFormatV2(
- join_layer,
- gpkg_path,
- join_layer.transformContext(),
- options
+ join_layer, gpkg_path, join_layer.transformContext(), options
)
- gpkg_join_layer = QgsVectorLayer(gpkg_path + '|layername=join', 'join', 'ogr')
- gpkg_data_layer = QgsVectorLayer(gpkg_path + '|layername=data', 'data', 'ogr')
+ gpkg_join_layer = QgsVectorLayer(gpkg_path + "|layername=join", "join", "ogr")
+ gpkg_data_layer = QgsVectorLayer(gpkg_path + "|layername=data", "data", "ogr")
self.assertTrue(gpkg_join_layer.isValid())
self.assertTrue(gpkg_data_layer.isValid())
@@ -1280,8 +1730,8 @@ def test_subset_string(self):
# Reload project
self.assertTrue(project.read(project_path))
- gpkg_data_layer = project.mapLayersByName('data')[0]
- gpkg_join_layer = project.mapLayersByName('join')[0]
+ gpkg_data_layer = project.mapLayersByName("data")[0]
+ gpkg_join_layer = project.mapLayersByName("join")[0]
self.assertEqual(gpkg_data_layer.vectorJoins()[0], joinInfo)
@@ -1292,28 +1742,35 @@ def test_subset_string(self):
project.addMapLayers([virtual])
self.assertEqual(virtual.featureCount(), 2)
- self.assertTrue(virtual.setSubsetString('"join_value" = \'twenty\''))
+ self.assertTrue(virtual.setSubsetString("\"join_value\" = 'twenty'"))
self.assertEqual(virtual.featureCount(), 1)
- self.assertEqual([f.attributes() for f in virtual.getFeatures()], [[1, 20, 2, 'twenty']])
+ self.assertEqual(
+ [f.attributes() for f in virtual.getFeatures()], [[1, 20, 2, "twenty"]]
+ )
# Store and reload the project
self.assertTrue(project.write(project_path))
self.assertTrue(project.read(project_path))
- gpkg_virtual_layer = project.mapLayersByName('virtual_data')[0]
+ gpkg_virtual_layer = project.mapLayersByName("virtual_data")[0]
self.assertEqual(gpkg_virtual_layer.featureCount(), 1)
- self.assertEqual(gpkg_virtual_layer.subsetString(), '"join_value" = \'twenty\'')
+ self.assertEqual(gpkg_virtual_layer.subsetString(), "\"join_value\" = 'twenty'")
def test_feature_count_on_error(self):
"""Test that triggered exception while getting feature count on a badly defined
- virtual layer is correctly caught (see https://github.com/qgis/QGIS/issues/34378)"""
+ virtual layer is correctly caught (see https://github.com/qgis/QGIS/issues/34378)
+ """
- l1 = QgsVectorLayer(os.path.join(self.testDataDir, "france_parts.shp"), "france", "ogr",
- QgsVectorLayer.LayerOptions(False))
+ l1 = QgsVectorLayer(
+ os.path.join(self.testDataDir, "france_parts.shp"),
+ "france",
+ "ogr",
+ QgsVectorLayer.LayerOptions(False),
+ )
self.assertTrue(l1.isValid())
QgsProject.instance().addMapLayer(l1)
df = QgsVirtualLayerDefinition()
- df.setQuery('select error')
+ df.setQuery("select error")
vl = QgsVectorLayer(df.toString(), "testq", "virtual")
self.assertFalse(vl.isValid())
@@ -1331,30 +1788,34 @@ def test_bool_fields(self):
ml.startEditing()
f1 = QgsFeature(ml.fields())
- f1.setAttribute('a', 1)
- f1.setAttribute('b', True)
+ f1.setAttribute("a", 1)
+ f1.setAttribute("b", True)
f2 = QgsFeature(ml.fields())
- f2.setAttribute('a', 2)
- f2.setAttribute('b', False)
+ f2.setAttribute("a", 2)
+ f2.setAttribute("b", False)
ml.addFeatures([f1, f2])
ml.commitChanges()
- self.assertEqual([(f['a'], f['b']) for f in ml.getFeatures()], [(1, True), (2, False)])
+ self.assertEqual(
+ [(f["a"], f["b"]) for f in ml.getFeatures()], [(1, True), (2, False)]
+ )
df = QgsVirtualLayerDefinition()
- df.setQuery('select * from mem')
+ df.setQuery("select * from mem")
vl = QgsVectorLayer(df.toString(), "testq", "virtual")
- self.assertEqual([(f['a'], f['b']) for f in vl.getFeatures()], [(1, True), (2, False)])
+ self.assertEqual(
+ [(f["a"], f["b"]) for f in vl.getFeatures()], [(1, True), (2, False)]
+ )
df = QgsVirtualLayerDefinition()
- df.setQuery('select * from mem where b')
+ df.setQuery("select * from mem where b")
vl = QgsVectorLayer(df.toString(), "testq", "virtual")
- self.assertEqual([(f['a'], f['b']) for f in vl.getFeatures()], [(1, True)])
+ self.assertEqual([(f["a"], f["b"]) for f in vl.getFeatures()], [(1, True)])
df = QgsVirtualLayerDefinition()
- df.setQuery('select * from mem where not b')
+ df.setQuery("select * from mem where not b")
vl = QgsVectorLayer(df.toString(), "testq", "virtual")
- self.assertEqual([(f['a'], f['b']) for f in vl.getFeatures()], [(2, False)])
+ self.assertEqual([(f["a"], f["b"]) for f in vl.getFeatures()], [(2, False)])
QgsProject.instance().removeMapLayer(ml.id())
@@ -1364,32 +1825,35 @@ def test_int64(self):
"""
bigint = 2262000000
- ml = QgsVectorLayer('NoGeometry?crs=epsg:4326&field=fldlonglong:long',
- 'test_bigint', 'memory')
+ ml = QgsVectorLayer(
+ "NoGeometry?crs=epsg:4326&field=fldlonglong:long", "test_bigint", "memory"
+ )
provider = ml.dataProvider()
feat = QgsFeature(ml.fields())
- feat.setAttribute('fldlonglong', bigint)
+ feat.setAttribute("fldlonglong", bigint)
provider.addFeatures([feat])
self.assertTrue(ml.isValid())
QgsProject.instance().addMapLayer(ml)
df = QgsVirtualLayerDefinition()
- df.setQuery('select * from test_bigint')
+ df.setQuery("select * from test_bigint")
vl = QgsVectorLayer(df.toString(), "testq", "virtual")
self.assertEqual(len(vl.fields()), 1)
field = vl.fields()[0]
self.assertEqual(field.type(), QVariant.LongLong)
self.assertTrue(vl.isValid())
feat = next(vl.getFeatures())
- self.assertEqual(feat.attribute('fldlonglong'), bigint)
+ self.assertEqual(feat.attribute("fldlonglong"), bigint)
def test_layer_starting_with_digit(self):
"""Test issue GH #45347"""
project = QgsProject.instance()
project.clear()
- layer = QgsVectorLayer('Point?crs=epsg:4326&field=fid:integer', '1_layer', 'memory')
+ layer = QgsVectorLayer(
+ "Point?crs=epsg:4326&field=fid:integer", "1_layer", "memory"
+ )
project.addMapLayers([layer])
df = QgsVirtualLayerDefinition()
@@ -1402,18 +1866,22 @@ def test_layer_using_joined_fields_from_another_layer(self):
project = QgsProject.instance()
project.clear()
- layer_1 = QgsVectorLayer('Point?crs=epsg:4326&field=fid:integer', 'layer_1', 'memory')
- layer_2 = QgsVectorLayer('Point?crs=epsg:4326&field=fid:integer', 'layer_2', 'memory')
+ layer_1 = QgsVectorLayer(
+ "Point?crs=epsg:4326&field=fid:integer", "layer_1", "memory"
+ )
+ layer_2 = QgsVectorLayer(
+ "Point?crs=epsg:4326&field=fid:integer", "layer_2", "memory"
+ )
project.addMapLayers([layer_1])
# Add a join from 2 to 1
join_info = QgsVectorLayerJoinInfo()
join_info.setJoinLayer(layer_1)
- join_info.setJoinFieldName('layer_1_fid')
- join_info.setTargetFieldName('fid')
+ join_info.setJoinFieldName("layer_1_fid")
+ join_info.setTargetFieldName("fid")
self.assertTrue(layer_2.addJoin(join_info))
- self.assertIn('layer_1_fid', layer_2.fields().names())
+ self.assertIn("layer_1_fid", layer_2.fields().names())
project.addMapLayers([layer_2])
@@ -1426,16 +1894,16 @@ def test_layer_using_joined_fields_from_another_layer(self):
tmp = QTemporaryDir()
path = tmp.path()
- project.write(os.path.join(path, 'test_4683.qgs'))
+ project.write(os.path.join(path, "test_4683.qgs"))
project.clear()
- project.read(os.path.join(path, 'test_4683.qgs'))
+ project.read(os.path.join(path, "test_4683.qgs"))
- layer_2 = project.mapLayersByName('layer_2')[0]
- vl = project.mapLayersByName('virtual')[0]
+ layer_2 = project.mapLayersByName("layer_2")[0]
+ vl = project.mapLayersByName("virtual")[0]
self.assertTrue(vl.isValid())
-if __name__ == '__main__':
+if __name__ == "__main__":
unittest.main()
diff --git a/tests/src/python/test_provider_wfs.py b/tests/src/python/test_provider_wfs.py
index 0108fb823216..1fff943a9bbe 100644
--- a/tests/src/python/test_provider_wfs.py
+++ b/tests/src/python/test_provider_wfs.py
@@ -5,9 +5,10 @@
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
"""
-__author__ = 'Even Rouault'
-__date__ = '2016-03-25'
-__copyright__ = 'Copyright 2016, Even Rouault'
+
+__author__ = "Even Rouault"
+__date__ = "2016-03-25"
+__copyright__ = "Copyright 2016, Even Rouault"
import hashlib
import http.server
@@ -19,7 +20,7 @@
import threading
# Needed on Qt 5 so that the serialization of XML is consistent among all executions
-os.environ['QT_HASH_SEED'] = '1'
+os.environ["QT_HASH_SEED"] = "1"
from providertestbase import ProviderTestCase
from qgis.core import (
@@ -61,7 +62,7 @@
from osgeo import gdal
# Default value is 2 second, which is too short when run under Valgrind
-gdal.SetConfigOption('OGR_GMLAS_XERCES_MAX_TIME', '20')
+gdal.SetConfigOption("OGR_GMLAS_XERCES_MAX_TIME", "20")
TEST_DATA_DIR = unitTestDataPath()
@@ -69,14 +70,17 @@
def sanitize(endpoint, x):
if len(endpoint + x) > 256:
# print('Before: ' + endpoint + x)
- x = x.replace('/', '_').encode()
+ x = x.replace("/", "_").encode()
ret = endpoint + hashlib.md5(x).hexdigest()
# print('After: ' + ret)
return ret
- ret = endpoint + x.replace('?', '_').replace('&', '_').replace('<', '_').replace('>', '_').replace('"',
- '_').replace("'",
- '_').replace(
- ' ', '_').replace(':', '_').replace('/', '_').replace('\n', '_')
+ ret = endpoint + x.replace("?", "_").replace("&", "_").replace("<", "_").replace(
+ ">", "_"
+ ).replace('"', "_").replace("'", "_").replace(" ", "_").replace(":", "_").replace(
+ "/", "_"
+ ).replace(
+ "\n", "_"
+ )
# print('Sanitize: ' + x)
return ret
@@ -97,7 +101,7 @@ def __exit__(self, type, value, traceback):
def logMessage(self, msg, tag, level):
if tag == self.tag or not self.tag:
- self.log.append(msg.encode('UTF-8'))
+ self.log.append(msg.encode("UTF-8"))
def messages(self):
return self.log
@@ -114,7 +118,7 @@ def treat_time_as_string(self):
@classmethod
def setUpClass(cls):
"""Run before all tests"""
- super(TestPyQgsWFSProvider, cls).setUpClass()
+ super().setUpClass()
QCoreApplication.setOrganizationName("QGIS_Test")
QCoreApplication.setOrganizationDomain("TestPyQgsWFSProvider.com")
@@ -124,11 +128,17 @@ def setUpClass(cls):
# On Windows we must make sure that any backslash in the path is
# replaced by a forward slash so that QUrl can process it
- cls.basetestpath = tempfile.mkdtemp().replace('\\', '/')
- endpoint = cls.basetestpath + '/fake_qgis_http_endpoint'
- with open(sanitize(endpoint, '?SERVICE=WFS?REQUEST=GetCapabilities?ACCEPTVERSIONS=2.0.0,1.1.0,1.0.0'),
- 'wb') as f:
- f.write(b"""
+ cls.basetestpath = tempfile.mkdtemp().replace("\\", "/")
+ endpoint = cls.basetestpath + "/fake_qgis_http_endpoint"
+ with open(
+ sanitize(
+ endpoint,
+ "?SERVICE=WFS?REQUEST=GetCapabilities?ACCEPTVERSIONS=2.0.0,1.1.0,1.0.0",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
@@ -142,12 +152,18 @@ def setUpClass(cls):
- """)
+"""
+ )
- with open(sanitize(endpoint,
- '?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAMES=my:typename&TYPENAME=my:typename'),
- 'wb') as f:
- f.write(b"""
+ with open(
+ sanitize(
+ endpoint,
+ "?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAMES=my:typename&TYPENAME=my:typename",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
@@ -173,17 +189,29 @@ def setUpClass(cls):
-""")
+"""
+ )
# Create test layer
- cls.vl = QgsVectorLayer("url='http://" + endpoint + "' typename='my:typename' skipInitialGetFeature='true'", 'test', 'WFS')
+ cls.vl = QgsVectorLayer(
+ "url='http://"
+ + endpoint
+ + "' typename='my:typename' skipInitialGetFeature='true'",
+ "test",
+ "WFS",
+ )
assert cls.vl.isValid()
cls.source = cls.vl.dataProvider()
- with open(sanitize(endpoint,
- '?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&SRSNAME=urn:ogc:def:crs:EPSG::4326'),
- 'wb') as f:
- f.write(b"""
+ with open(
+ sanitize(
+ endpoint,
+ "?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&SRSNAME=urn:ogc:def:crs:EPSG::4326",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
12:13:01
- """)
+"""
+ )
- with open(sanitize(endpoint,
- '?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&RESULTTYPE=hits'),
- 'wb') as f:
- f.write(b"""
+ with open(
+ sanitize(
+ endpoint,
+ "?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&RESULTTYPE=hits",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
- """)
+"""
+ )
- with open(sanitize(endpoint, """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&FILTER=
+ with open(
+ sanitize(
+ endpoint,
+ """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&FILTER=
cnt
@@ -278,15 +316,23 @@ def setUpClass(cls):
-&RESULTTYPE=hits"""), 'wb') as f:
- f.write(b"""
+&RESULTTYPE=hits""",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
- """)
+"""
+ )
- with open(sanitize(endpoint, """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&SRSNAME=urn:ogc:def:crs:EPSG::4326&FILTER=
+ with open(
+ sanitize(
+ endpoint,
+ """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&SRSNAME=urn:ogc:def:crs:EPSG::4326&FILTER=
cnt
@@ -298,8 +344,12 @@ def setUpClass(cls):
-"""), 'wb') as f:
- f.write(b"""
+""",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
3
- """)
+"""
+ )
- with open(sanitize(endpoint, """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&FILTER=
+ with open(
+ sanitize(
+ endpoint,
+ """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&FILTER=
cnt
@@ -350,15 +404,23 @@ def setUpClass(cls):
-&RESULTTYPE=hits"""), 'wb') as f:
- f.write(b"""
+&RESULTTYPE=hits""",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
- """)
+"""
+ )
- with open(sanitize(endpoint, """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&SRSNAME=urn:ogc:def:crs:EPSG::4326&FILTER=
+ with open(
+ sanitize(
+ endpoint,
+ """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&SRSNAME=urn:ogc:def:crs:EPSG::4326&FILTER=
cnt
@@ -370,8 +432,12 @@ def setUpClass(cls):
-"""), 'wb') as f:
- f.write(b"""
+""",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
3
- """)
+"""
+ )
- with open(sanitize(endpoint, """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&FILTER=
+ with open(
+ sanitize(
+ endpoint,
+ """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&FILTER=
name
Apple
-&RESULTTYPE=hits"""), 'wb') as f:
- f.write(b"""
+&RESULTTYPE=hits""",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
- """)
+"""
+ )
- with open(sanitize(endpoint, """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&SRSNAME=urn:ogc:def:crs:EPSG::4326&FILTER=
+ with open(
+ sanitize(
+ endpoint,
+ """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&SRSNAME=urn:ogc:def:crs:EPSG::4326&FILTER=
name
Apple
-"""), 'wb') as f:
- f.write(b"""
+""",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
2
- """)
+"""
+ )
- with open(sanitize(endpoint, """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&FILTER=
+ with open(
+ sanitize(
+ endpoint,
+ """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&FILTER=
name
AppleBearOrangePear
-&RESULTTYPE=hits"""), 'wb') as f:
- f.write(b"""
+&RESULTTYPE=hits""",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
- """)
+"""
+ )
- with open(sanitize(endpoint, """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&SRSNAME=urn:ogc:def:crs:EPSG::4326&FILTER=
+ with open(
+ sanitize(
+ endpoint,
+ """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&SRSNAME=urn:ogc:def:crs:EPSG::4326&FILTER=
name
AppleBearOrangePear
-"""), 'wb') as f:
- f.write(b"""
+""",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
- """)
+"""
+ )
@classmethod
def tearDownClass(cls):
"""Run after all tests"""
QgsSettings().clear()
shutil.rmtree(cls.basetestpath, True)
- cls.vl = None # so as to properly close the provider and remove any temporary file
- super(TestPyQgsWFSProvider, cls).tearDownClass()
+ cls.vl = (
+ None # so as to properly close the provider and remove any temporary file
+ )
+ super().tearDownClass()
def tearDown(self):
"""Run after each test"""
@@ -486,44 +587,62 @@ def testWkbType(self):
pass
def providerCompatibleOfSubsetStringWithStableFID(self):
- """ Return whether the provider is expected to have stable FID when changing subsetString.
- The WFS provider might not always be able to have that guarantee. """
+ """Return whether the provider is expected to have stable FID when changing subsetString.
+ The WFS provider might not always be able to have that guarantee."""
return False
def testInconsistentUri(self):
"""Test a URI with a typename that doesn't match a type of the capabilities"""
- endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_testInconsistentUri'
- with open(sanitize(endpoint, '?SERVICE=WFS?REQUEST=GetCapabilities?ACCEPTVERSIONS=2.0.0,1.1.0,1.0.0'),
- 'wb') as f:
- f.write(b"""
+ endpoint = (
+ self.__class__.basetestpath + "/fake_qgis_http_endpoint_testInconsistentUri"
+ )
+ with open(
+ sanitize(
+ endpoint,
+ "?SERVICE=WFS?REQUEST=GetCapabilities?ACCEPTVERSIONS=2.0.0,1.1.0,1.0.0",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
- """)
+"""
+ )
# Could not find typename my:typename in capabilities
- vl = QgsVectorLayer("url='http://" + endpoint + "' typename='my:typename'", 'test', 'WFS')
+ vl = QgsVectorLayer(
+ "url='http://" + endpoint + "' typename='my:typename'", "test", "WFS"
+ )
self.assertFalse(vl.isValid())
def testMissingTypename(self):
# No typename
- endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_WFS1.0'
- with MessageLogger('WFS') as logger:
- vl = QgsVectorLayer("url='http://" + endpoint + "'", 'test', 'WFS')
+ endpoint = self.__class__.basetestpath + "/fake_qgis_http_endpoint_WFS1.0"
+ with MessageLogger("WFS") as logger:
+ vl = QgsVectorLayer("url='http://" + endpoint + "'", "test", "WFS")
self.assertFalse(vl.isValid())
self.assertEqual(len(logger.messages()), 1, logger.messages())
- self.assertEqual(logger.messages()[0].decode('UTF-8'), "Missing or empty 'typename' URI parameter")
+ self.assertEqual(
+ logger.messages()[0].decode("UTF-8"),
+ "Missing or empty 'typename' URI parameter",
+ )
def testWFS10(self):
"""Test WFS 1.0 read-only"""
# We also test attribute fields in upper-case, and a field named GEOMETRY
- endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_WFS1.0'
+ endpoint = self.__class__.basetestpath + "/fake_qgis_http_endpoint_WFS1.0"
- with open(sanitize(endpoint, '?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=1.0.0'), 'wb') as f:
- f.write(b"""
+ with open(
+ sanitize(endpoint, "?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=1.0.0"),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
@@ -535,11 +654,18 @@ def testWFS10(self):
- """)
+"""
+ )
- with open(sanitize(endpoint, '?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=1.0.0&TYPENAME=my:typename'),
- 'wb') as f:
- f.write(b"""
+ with open(
+ sanitize(
+ endpoint,
+ "?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=1.0.0&TYPENAME=my:typename",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
@@ -559,22 +685,35 @@ def testWFS10(self):
-""")
+"""
+ )
- vl = QgsVectorLayer("url='http://" + endpoint + "' typename='my:typename' version='1.0.0'", 'test', 'WFS')
+ vl = QgsVectorLayer(
+ "url='http://" + endpoint + "' typename='my:typename' version='1.0.0'",
+ "test",
+ "WFS",
+ )
self.assertTrue(vl.isValid())
self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.Point)
self.assertEqual(len(vl.fields()), 5)
self.assertEqual(vl.featureCount(), 0)
- reference = QgsGeometry.fromRect(QgsRectangle(400000.0, 5400000.0, 450000.0, 5500000.0))
+ reference = QgsGeometry.fromRect(
+ QgsRectangle(400000.0, 5400000.0, 450000.0, 5500000.0)
+ )
vl_extent = QgsGeometry.fromRect(vl.extent())
- assert QgsGeometry.compare(vl_extent.asPolygon()[0], reference.asPolygon()[0],
- 0.00001), f'Expected {reference.asWkt()}, got {vl_extent.asWkt()}'
+ assert QgsGeometry.compare(
+ vl_extent.asPolygon()[0], reference.asPolygon()[0], 0.00001
+ ), f"Expected {reference.asWkt()}, got {vl_extent.asWkt()}"
with open(
- sanitize(endpoint, '?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.0.0&TYPENAME=my:typename&SRSNAME=EPSG:32631'),
- 'wb') as f:
- f.write(b"""
+ sanitize(
+ endpoint,
+ "?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.0.0&TYPENAME=my:typename&SRSNAME=EPSG:32631",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
2016-04-10T12:34:56.789Z
- """)
+"""
+ )
# Also test that on file iterator works
- os.environ['QGIS_WFS_ITERATOR_TRANSFER_THRESHOLD'] = '0'
+ os.environ["QGIS_WFS_ITERATOR_TRANSFER_THRESHOLD"] = "0"
- values = [f['INTFIELD'] for f in vl.getFeatures()]
+ values = [f["INTFIELD"] for f in vl.getFeatures()]
self.assertEqual(values, [1])
- del os.environ['QGIS_WFS_ITERATOR_TRANSFER_THRESHOLD']
+ del os.environ["QGIS_WFS_ITERATOR_TRANSFER_THRESHOLD"]
- values = [f['GEOMETRY'] for f in vl.getFeatures()]
+ values = [f["GEOMETRY"] for f in vl.getFeatures()]
self.assertEqual(values, [2])
- values = [f['longfield'] for f in vl.getFeatures()]
+ values = [f["longfield"] for f in vl.getFeatures()]
self.assertEqual(values, [1234567890123])
- values = [f['stringfield'] for f in vl.getFeatures()]
- self.assertEqual(values, ['foo'])
-
- values = [f['datetimefield'] for f in vl.getFeatures()]
- self.assertEqual(values, [QDateTime(QDate(2016, 4, 10), QTime(12, 34, 56, 789), Qt.TimeSpec(Qt.TimeSpec.UTC))])
+ values = [f["stringfield"] for f in vl.getFeatures()]
+ self.assertEqual(values, ["foo"])
+
+ values = [f["datetimefield"] for f in vl.getFeatures()]
+ self.assertEqual(
+ values,
+ [
+ QDateTime(
+ QDate(2016, 4, 10),
+ QTime(12, 34, 56, 789),
+ Qt.TimeSpec(Qt.TimeSpec.UTC),
+ )
+ ],
+ )
got_f = [f for f in vl.getFeatures()]
got = got_f[0].geometry().constGet()
@@ -620,7 +769,10 @@ def testWFS10(self):
self.assertEqual(vl.featureCount(), 1)
- self.assertTrue(vl.dataProvider().capabilities() & QgsVectorDataProvider.Capability.SelectAtId)
+ self.assertTrue(
+ vl.dataProvider().capabilities()
+ & QgsVectorDataProvider.Capability.SelectAtId
+ )
(ret, _) = vl.dataProvider().addFeatures([QgsFeature()])
self.assertFalse(ret)
@@ -632,9 +784,14 @@ def testWFS10(self):
vl.dataProvider().reloadData()
with open(
- sanitize(endpoint, '?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.0.0&TYPENAME=my:typename&SRSNAME=EPSG:32631'),
- 'wb') as f:
- f.write(b"""
+ sanitize(
+ endpoint,
+ "?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.0.0&TYPENAME=my:typename&SRSNAME=EPSG:32631",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
30
- """)
+"""
+ )
features = [f for f in vl.getFeatures()]
self.assertEqual(features[0].id(), 2)
- self.assertEqual(features[0]['INTFIELD'], 20)
+ self.assertEqual(features[0]["INTFIELD"], 20)
self.assertEqual(features[1].id(), 1)
- self.assertEqual(features[1]['INTFIELD'], 30)
+ self.assertEqual(features[1]["INTFIELD"], 30)
# Test with restrictToRequestBBOX=1
- with open(sanitize(endpoint,
- '?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.0.0&TYPENAME=my:typename&SRSNAME=EPSG:32631&BBOX=400000,5400000,450000,5500000'),
- 'wb') as f:
- f.write(b"""
+ with open(
+ sanitize(
+ endpoint,
+ "?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.0.0&TYPENAME=my:typename&SRSNAME=EPSG:32631&BBOX=400000,5400000,450000,5500000",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
100
- """)
+"""
+ )
- uri = "url='http://" + endpoint + "' typename='my:typename' version='1.0.0' restrictToRequestBBOX=1"
- vl = QgsVectorLayer(
- uri, 'test',
- 'WFS')
+ uri = (
+ "url='http://"
+ + endpoint
+ + "' typename='my:typename' version='1.0.0' restrictToRequestBBOX=1"
+ )
+ vl = QgsVectorLayer(uri, "test", "WFS")
extent = QgsRectangle(400000.0, 5400000.0, 450000.0, 5500000.0)
request = QgsFeatureRequest().setFilterRect(extent)
- values = [(f.id(), f['INTFIELD']) for f in vl.getFeatures(request)]
+ values = [(f.id(), f["INTFIELD"]) for f in vl.getFeatures(request)]
self.assertEqual(values[0][1], 100)
# Issue a request by id on a cached feature
request = QgsFeatureRequest(values[0][0])
- values = [(f.id(), f['INTFIELD']) for f in vl.getFeatures(request)]
+ values = [(f.id(), f["INTFIELD"]) for f in vl.getFeatures(request)]
self.assertEqual(values[0][1], 100)
# Check behavior with setLimit(1)
request = QgsFeatureRequest().setLimit(1)
- values = [(f.id(), f['INTFIELD']) for f in vl.getFeatures(request)]
+ values = [(f.id(), f["INTFIELD"]) for f in vl.getFeatures(request)]
self.assertEqual(values[0][1], 100)
- metadata = QgsProviderRegistry.instance().providerMetadata('wfs')
+ metadata = QgsProviderRegistry.instance().providerMetadata("wfs")
sublayers = metadata.querySublayers(uri, Qgis.SublayerQueryFlag.FastScan)
self.assertEqual(len(sublayers), 0)
@@ -711,20 +877,33 @@ def testWFS10(self):
self.assertEqual(sublayers[0].wkbType(), vl.wkbType())
# Unexpected foo parameter key
- with MessageLogger('WFS') as logger:
- vl = QgsVectorLayer("url='http://" + endpoint + "' typename='my:typename' version='1.0.0' foo='bar'", 'test', 'WFS')
+ with MessageLogger("WFS") as logger:
+ vl = QgsVectorLayer(
+ "url='http://"
+ + endpoint
+ + "' typename='my:typename' version='1.0.0' foo='bar'",
+ "test",
+ "WFS",
+ )
self.assertTrue(vl.isValid())
self.assertEqual(len(logger.messages()), 1, logger.messages())
- self.assertEqual(logger.messages()[0].decode('UTF-8'), "The following unknown parameter(s) have been found in the URI: foo")
+ self.assertEqual(
+ logger.messages()[0].decode("UTF-8"),
+ "The following unknown parameter(s) have been found in the URI: foo",
+ )
def testWFS10_outputformat_GML3_2(self):
"""Test WFS 1.0 with OUTPUTFORMAT=GML3"""
# We also test attribute fields in upper-case, and a field named GEOMETRY
- endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_WFS1.0_gml3'
+ endpoint = self.__class__.basetestpath + "/fake_qgis_http_endpoint_WFS1.0_gml3"
- with open(sanitize(endpoint, '?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=1.0.0'), 'wb') as f:
- f.write(b"""
+ with open(
+ sanitize(endpoint, "?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=1.0.0"),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
@@ -746,11 +925,18 @@ def testWFS10_outputformat_GML3_2(self):
- """)
+"""
+ )
- with open(sanitize(endpoint, '?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=1.0.0&TYPENAME=my:typename'),
- 'wb') as f:
- f.write(b"""
+ with open(
+ sanitize(
+ endpoint,
+ "?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=1.0.0&TYPENAME=my:typename",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
@@ -764,15 +950,25 @@ def testWFS10_outputformat_GML3_2(self):
-""")
+"""
+ )
- vl = QgsVectorLayer("url='http://" + endpoint + "' typename='my:typename' version='1.0.0'", 'test', 'WFS')
+ vl = QgsVectorLayer(
+ "url='http://" + endpoint + "' typename='my:typename' version='1.0.0'",
+ "test",
+ "WFS",
+ )
self.assertTrue(vl.isValid())
- with open(sanitize(endpoint,
- '?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.0.0&TYPENAME=my:typename&SRSNAME=EPSG:32631&OUTPUTFORMAT=GML3'),
- 'wb') as f:
- f.write(b"""
+ with open(
+ sanitize(
+ endpoint,
+ "?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.0.0&TYPENAME=my:typename&SRSNAME=EPSG:32631&OUTPUTFORMAT=GML3",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
- """)
+"""
+ )
got_f = [f for f in vl.getFeatures()]
got = got_f[0].geometry().constGet()
self.assertEqual((got.x(), got.y()), (426858.0, 5427937.0))
# Test with explicit OUTPUTFORMAT as parameter
- vl = QgsVectorLayer("url='http://" + endpoint + "' typename='my:typename' version='1.0.0' outputformat='GML2'",
- 'test', 'WFS')
+ vl = QgsVectorLayer(
+ "url='http://"
+ + endpoint
+ + "' typename='my:typename' version='1.0.0' outputformat='GML2'",
+ "test",
+ "WFS",
+ )
self.assertTrue(vl.isValid())
- with open(sanitize(endpoint,
- '?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.0.0&TYPENAME=my:typename&SRSNAME=EPSG:32631&OUTPUTFORMAT=GML2'),
- 'wb') as f:
- f.write(b"""
+ with open(
+ sanitize(
+ endpoint,
+ "?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.0.0&TYPENAME=my:typename&SRSNAME=EPSG:32631&OUTPUTFORMAT=GML2",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
- """)
+"""
+ )
got_f = [f for f in vl.getFeatures()]
got = got_f[0].geometry().constGet()
self.assertEqual((got.x(), got.y()), (1.0, 2.0))
# Test with explicit OUTPUTFORMAT in URL
- vl = QgsVectorLayer("url='http://" + endpoint + "?OUTPUTFORMAT=GML2' typename='my:typename' version='1.0.0'",
- 'test', 'WFS')
+ vl = QgsVectorLayer(
+ "url='http://"
+ + endpoint
+ + "?OUTPUTFORMAT=GML2' typename='my:typename' version='1.0.0'",
+ "test",
+ "WFS",
+ )
self.assertTrue(vl.isValid())
- with open(sanitize(endpoint,
- '?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.0.0&TYPENAME=my:typename&SRSNAME=EPSG:32631&OUTPUTFORMAT=GML2'),
- 'wb') as f:
- f.write(b"""
+ with open(
+ sanitize(
+ endpoint,
+ "?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.0.0&TYPENAME=my:typename&SRSNAME=EPSG:32631&OUTPUTFORMAT=GML2",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
- """)
+"""
+ )
got_f = [f for f in vl.getFeatures()]
got = got_f[0].geometry().constGet()
@@ -848,10 +1067,17 @@ def testWFS10_outputformat_GML3_2(self):
def testWFS10_latlongboundingbox_in_WGS84(self):
"""Test WFS 1.0 with non conformatn LatLongBoundingBox"""
- endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_WFS1.0_latlongboundingbox_in_WGS84'
+ endpoint = (
+ self.__class__.basetestpath
+ + "/fake_qgis_http_endpoint_WFS1.0_latlongboundingbox_in_WGS84"
+ )
- with open(sanitize(endpoint, '?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=1.0.0'), 'wb') as f:
- f.write(b"""
+ with open(
+ sanitize(endpoint, "?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=1.0.0"),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
@@ -864,11 +1090,18 @@ def testWFS10_latlongboundingbox_in_WGS84(self):
- """)
+"""
+ )
- with open(sanitize(endpoint, '?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=1.0.0&TYPENAME=my:typename'),
- 'wb') as f:
- f.write(b"""
+ with open(
+ sanitize(
+ endpoint,
+ "?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=1.0.0&TYPENAME=my:typename",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
@@ -882,27 +1115,45 @@ def testWFS10_latlongboundingbox_in_WGS84(self):
-""")
+"""
+ )
- vl = QgsVectorLayer("url='http://" + endpoint + "' typename='my:typename' version='1.0.0'", 'test', 'WFS')
+ vl = QgsVectorLayer(
+ "url='http://" + endpoint + "' typename='my:typename' version='1.0.0'",
+ "test",
+ "WFS",
+ )
self.assertTrue(vl.isValid())
reference = QgsGeometry.fromRect(
- QgsRectangle(399999.9999999680439942, 5399338.9090830031782389, 449999.9999999987776391,
- 5500658.0448500607162714))
+ QgsRectangle(
+ 399999.9999999680439942,
+ 5399338.9090830031782389,
+ 449999.9999999987776391,
+ 5500658.0448500607162714,
+ )
+ )
vl_extent = QgsGeometry.fromRect(vl.extent())
- assert QgsGeometry.compare(vl_extent.asPolygon()[0], reference.asPolygon()[0],
- 0.00001), f'Expected {reference.asWkt()}, got {vl_extent.asWkt()}'
+ assert QgsGeometry.compare(
+ vl_extent.asPolygon()[0], reference.asPolygon()[0], 0.00001
+ ), f"Expected {reference.asWkt()}, got {vl_extent.asWkt()}"
def testWFST10(self):
"""Test WFS-T 1.0 (read-write)"""
- endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_WFS_T_1.0'
+ endpoint = self.__class__.basetestpath + "/fake_qgis_http_endpoint_WFS_T_1.0"
- transaction_endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_WFS_T_1.0_transaction'
+ transaction_endpoint = (
+ self.__class__.basetestpath
+ + "/fake_qgis_http_endpoint_WFS_T_1.0_transaction"
+ )
- with open(sanitize(endpoint, '?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=1.0.0'), 'wb') as f:
- f.write("""
+ with open(
+ sanitize(endpoint, "?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=1.0.0"),
+ "wb",
+ ) as f:
+ f.write(
+ """
@@ -948,11 +1199,22 @@ def testWFST10(self):
- """.format(transaction_endpoint=transaction_endpoint).encode('UTF-8'))
+""".format(
+ transaction_endpoint=transaction_endpoint
+ ).encode(
+ "UTF-8"
+ )
+ )
- with open(sanitize(endpoint, '?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=1.0.0&TYPENAME=my:typename'),
- 'wb') as f:
- f.write(b"""
+ with open(
+ sanitize(
+ endpoint,
+ "?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=1.0.0&TYPENAME=my:typename",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
@@ -970,18 +1232,25 @@ def testWFST10(self):
-""")
+"""
+ )
- vl = QgsVectorLayer("url='http://" + endpoint + "' typename='my:typename' version='1.0.0'", 'test', 'WFS')
+ vl = QgsVectorLayer(
+ "url='http://" + endpoint + "' typename='my:typename' version='1.0.0'",
+ "test",
+ "WFS",
+ )
self.assertTrue(vl.isValid())
- self.assertEqual(vl.dataProvider().capabilities(),
- QgsVectorDataProvider.Capability.AddFeatures
- | QgsVectorDataProvider.Capability.ChangeAttributeValues
- | QgsVectorDataProvider.Capability.ChangeGeometries
- | QgsVectorDataProvider.Capability.DeleteFeatures
- | QgsVectorDataProvider.Capability.SelectAtId
- | QgsVectorDataProvider.Capability.ReloadData)
+ self.assertEqual(
+ vl.dataProvider().capabilities(),
+ QgsVectorDataProvider.Capability.AddFeatures
+ | QgsVectorDataProvider.Capability.ChangeAttributeValues
+ | QgsVectorDataProvider.Capability.ChangeGeometries
+ | QgsVectorDataProvider.Capability.DeleteFeatures
+ | QgsVectorDataProvider.Capability.SelectAtId
+ | QgsVectorDataProvider.Capability.ReloadData,
+ )
(ret, _) = vl.dataProvider().addFeatures([QgsFeature()])
self.assertFalse(ret)
@@ -992,7 +1261,11 @@ def testWFST10(self):
self.assertEqual(vl.featureCount(), 0)
- self.assertFalse(vl.dataProvider().changeGeometryValues({0: QgsGeometry.fromWkt('Point (3 50)')}))
+ self.assertFalse(
+ vl.dataProvider().changeGeometryValues(
+ {0: QgsGeometry.fromWkt("Point (3 50)")}
+ )
+ )
self.assertFalse(vl.dataProvider().changeAttributeValues({0: {0: 0}}))
@@ -1010,25 +1283,44 @@ def testWFST10(self):
"""
- if int(QT_VERSION_STR.split('.')[0]) >= 6:
+ if int(QT_VERSION_STR.split(".")[0]) >= 6:
attrs = 'xmlns="http://www.opengis.net/wfs" service="WFS" version="1.0.0" xmlns:gml="http://www.opengis.net/gml" xmlns:my="http://my" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://my http://fake_qgis_http_endpoint?REQUEST=DescribeFeatureType&VERSION=1.0.0&TYPENAME=my:typename"'
else:
attrs = 'xmlns="http://www.opengis.net/wfs" service="WFS" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://my http://fake_qgis_http_endpoint?REQUEST=DescribeFeatureType&VERSION=1.0.0&TYPENAME=my:typename" xmlns:my="http://my" xmlns:gml="http://www.opengis.net/gml" version="1.0.0"'
- with open(sanitize(transaction_endpoint,
- f'?SERVICE=WFS&POSTDATA=1 1234567890123 foo 2016-04-10T12:34:56.789Z 2,49 '),
- 'wb') as f:
- f.write(response.encode('UTF-8'))
+ with open(
+ sanitize(
+ transaction_endpoint,
+ f'?SERVICE=WFS&POSTDATA=1 1234567890123 foo 2016-04-10T12:34:56.789Z 2,49 ',
+ ),
+ "wb",
+ ) as f:
+ f.write(response.encode("UTF-8"))
# Qt 4 order ??
- with open(sanitize(transaction_endpoint,
- '?SERVICE=WFS&POSTDATA=1 1234567890123 foo 2016-04-10T12:34:56.789Z 2,49 '),
- 'wb') as f:
- f.write(response.encode('UTF-8'))
+ with open(
+ sanitize(
+ transaction_endpoint,
+ '?SERVICE=WFS&POSTDATA=1 1234567890123 foo 2016-04-10T12:34:56.789Z 2,49 ',
+ ),
+ "wb",
+ ) as f:
+ f.write(response.encode("UTF-8"))
f = QgsFeature()
- f.setAttributes([1, 1234567890123, 'foo', QDateTime(QDate(2016, 4, 10), QTime(12, 34, 56, 789), Qt.TimeSpec(Qt.TimeSpec.UTC))])
- f.setGeometry(QgsGeometry.fromWkt('Point (2 49)'))
+ f.setAttributes(
+ [
+ 1,
+ 1234567890123,
+ "foo",
+ QDateTime(
+ QDate(2016, 4, 10),
+ QTime(12, 34, 56, 789),
+ Qt.TimeSpec(Qt.TimeSpec.UTC),
+ ),
+ ]
+ )
+ f.setGeometry(QgsGeometry.fromWkt("Point (2 49)"))
# def logMessage(msg, tag, level):
# print('--------################----------------')
@@ -1043,17 +1335,26 @@ def testWFST10(self):
self.assertEqual(vl.featureCount(), 1)
- values = [f['intfield'] for f in vl.getFeatures()]
+ values = [f["intfield"] for f in vl.getFeatures()]
self.assertEqual(values, [1])
- values = [f['longfield'] for f in vl.getFeatures()]
+ values = [f["longfield"] for f in vl.getFeatures()]
self.assertEqual(values, [1234567890123])
- values = [f['stringfield'] for f in vl.getFeatures()]
- self.assertEqual(values, ['foo'])
-
- values = [f['datetimefield'] for f in vl.getFeatures()]
- self.assertEqual(values, [QDateTime(QDate(2016, 4, 10), QTime(12, 34, 56, 789), Qt.TimeSpec(Qt.TimeSpec.UTC))])
+ values = [f["stringfield"] for f in vl.getFeatures()]
+ self.assertEqual(values, ["foo"])
+
+ values = [f["datetimefield"] for f in vl.getFeatures()]
+ self.assertEqual(
+ values,
+ [
+ QDateTime(
+ QDate(2016, 4, 10),
+ QTime(12, 34, 56, 789),
+ Qt.TimeSpec(Qt.TimeSpec.UTC),
+ )
+ ],
+ )
got_f = [f for f in vl.getFeatures()]
got = got_f[0].geometry().constGet()
@@ -1070,34 +1371,55 @@ def testWFST10(self):
"""
- with open(sanitize(transaction_endpoint,
- f'?SERVICE=WFS&POSTDATA=my:geometryProperty 3,50 '),
- 'wb') as f:
- f.write(content.encode('UTF-8'))
+ with open(
+ sanitize(
+ transaction_endpoint,
+ f'?SERVICE=WFS&POSTDATA=my:geometryProperty 3,50 ',
+ ),
+ "wb",
+ ) as f:
+ f.write(content.encode("UTF-8"))
# Qt 4 order ??
- with open(sanitize(transaction_endpoint,
- '?SERVICE=WFS&POSTDATA=my:geometryProperty 3,50 '),
- 'wb') as f:
- f.write(content.encode('UTF-8'))
-
- self.assertTrue(vl.dataProvider().changeGeometryValues({1: QgsGeometry.fromWkt('Point (3 50)')}))
+ with open(
+ sanitize(
+ transaction_endpoint,
+ '?SERVICE=WFS&POSTDATA=my:geometryProperty 3,50 ',
+ ),
+ "wb",
+ ) as f:
+ f.write(content.encode("UTF-8"))
+
+ self.assertTrue(
+ vl.dataProvider().changeGeometryValues(
+ {1: QgsGeometry.fromWkt("Point (3 50)")}
+ )
+ )
got_f = [f for f in vl.getFeatures()]
got = got_f[0].geometry().constGet()
self.assertEqual((got.x(), got.y()), (3.0, 50.0))
- values = [f['intfield'] for f in vl.getFeatures()]
+ values = [f["intfield"] for f in vl.getFeatures()]
self.assertEqual(values, [1])
- values = [f['longfield'] for f in vl.getFeatures()]
+ values = [f["longfield"] for f in vl.getFeatures()]
self.assertEqual(values, [1234567890123])
- values = [f['stringfield'] for f in vl.getFeatures()]
- self.assertEqual(values, ['foo'])
-
- values = [f['datetimefield'] for f in vl.getFeatures()]
- self.assertEqual(values, [QDateTime(QDate(2016, 4, 10), QTime(12, 34, 56, 789), Qt.TimeSpec(Qt.TimeSpec.UTC))])
+ values = [f["stringfield"] for f in vl.getFeatures()]
+ self.assertEqual(values, ["foo"])
+
+ values = [f["datetimefield"] for f in vl.getFeatures()]
+ self.assertEqual(
+ values,
+ [
+ QDateTime(
+ QDate(2016, 4, 10),
+ QTime(12, 34, 56, 789),
+ Qt.TimeSpec(Qt.TimeSpec.UTC),
+ )
+ ],
+ )
# Test changeAttributeValues
content = """
@@ -1110,31 +1432,62 @@ def testWFST10(self):
"""
- with open(sanitize(transaction_endpoint,
- f'?SERVICE=WFS&POSTDATA=my:intfield 2 my:longfield 3 my:stringfield bar my:datetimefield 2015-04-10T12:34:56.789Z '),
- 'wb') as f:
- f.write(response.encode('UTF-8'))
+ with open(
+ sanitize(
+ transaction_endpoint,
+ f'?SERVICE=WFS&POSTDATA=my:intfield 2 my:longfield 3 my:stringfield bar my:datetimefield 2015-04-10T12:34:56.789Z ',
+ ),
+ "wb",
+ ) as f:
+ f.write(response.encode("UTF-8"))
# Qt 4 order ??
- with open(sanitize(transaction_endpoint,
- '?SERVICE=WFS&POSTDATA=my:intfield 2 my:longfield 3 my:stringfield bar my:datetimefield 2015-04-10T12:34:56.789Z '),
- 'wb') as f:
- f.write(content.encode('UTF-8'))
-
- self.assertTrue(vl.dataProvider().changeAttributeValues(
- {1: {0: 2, 1: 3, 2: "bar", 3: QDateTime(QDate(2015, 4, 10), QTime(12, 34, 56, 789), Qt.TimeSpec(Qt.TimeSpec.UTC))}}))
-
- values = [f['intfield'] for f in vl.getFeatures()]
+ with open(
+ sanitize(
+ transaction_endpoint,
+ '?SERVICE=WFS&POSTDATA=my:intfield 2 my:longfield 3 my:stringfield bar my:datetimefield 2015-04-10T12:34:56.789Z ',
+ ),
+ "wb",
+ ) as f:
+ f.write(content.encode("UTF-8"))
+
+ self.assertTrue(
+ vl.dataProvider().changeAttributeValues(
+ {
+ 1: {
+ 0: 2,
+ 1: 3,
+ 2: "bar",
+ 3: QDateTime(
+ QDate(2015, 4, 10),
+ QTime(12, 34, 56, 789),
+ Qt.TimeSpec(Qt.TimeSpec.UTC),
+ ),
+ }
+ }
+ )
+ )
+
+ values = [f["intfield"] for f in vl.getFeatures()]
self.assertEqual(values, [2])
- values = [f['longfield'] for f in vl.getFeatures()]
+ values = [f["longfield"] for f in vl.getFeatures()]
self.assertEqual(values, [3])
- values = [f['stringfield'] for f in vl.getFeatures()]
- self.assertEqual(values, ['bar'])
-
- values = [f['datetimefield'] for f in vl.getFeatures()]
- self.assertEqual(values, [QDateTime(QDate(2015, 4, 10), QTime(12, 34, 56, 789), Qt.TimeSpec(Qt.TimeSpec.UTC))])
+ values = [f["stringfield"] for f in vl.getFeatures()]
+ self.assertEqual(values, ["bar"])
+
+ values = [f["datetimefield"] for f in vl.getFeatures()]
+ self.assertEqual(
+ values,
+ [
+ QDateTime(
+ QDate(2015, 4, 10),
+ QTime(12, 34, 56, 789),
+ Qt.TimeSpec(Qt.TimeSpec.UTC),
+ )
+ ],
+ )
got_f = [f for f in vl.getFeatures()]
got = got_f[0].geometry().constGet()
@@ -1151,16 +1504,24 @@ def testWFST10(self):
"""
- with open(sanitize(transaction_endpoint,
- f'?SERVICE=WFS&POSTDATA= '),
- 'wb') as f:
- f.write(response.encode('UTF-8'))
+ with open(
+ sanitize(
+ transaction_endpoint,
+ f'?SERVICE=WFS&POSTDATA= ',
+ ),
+ "wb",
+ ) as f:
+ f.write(response.encode("UTF-8"))
# Qt 4 order ??
- with open(sanitize(transaction_endpoint,
- '?SERVICE=WFS&POSTDATA= '),
- 'wb') as f:
- f.write(content.encode('UTF-8'))
+ with open(
+ sanitize(
+ transaction_endpoint,
+ '?SERVICE=WFS&POSTDATA= ',
+ ),
+ "wb",
+ ) as f:
+ f.write(content.encode("UTF-8"))
self.assertTrue(vl.dataProvider().deleteFeatures([1]))
@@ -1169,11 +1530,19 @@ def testWFST10(self):
def testWFS20Paging(self):
"""Test WFS 2.0 paging"""
- endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_WFS_2.0_paging'
+ endpoint = (
+ self.__class__.basetestpath + "/fake_qgis_http_endpoint_WFS_2.0_paging"
+ )
- with open(sanitize(endpoint, '?SERVICE=WFS?REQUEST=GetCapabilities?ACCEPTVERSIONS=2.0.0,1.1.0,1.0.0'),
- 'wb') as f:
- f.write(b"""
+ with open(
+ sanitize(
+ endpoint,
+ "?SERVICE=WFS?REQUEST=GetCapabilities?ACCEPTVERSIONS=2.0.0,1.1.0,1.0.0",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
@@ -1199,12 +1568,18 @@ def testWFS20Paging(self):
- """)
+"""
+ )
- with open(sanitize(endpoint,
- '?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAMES=my:typename&TYPENAME=my:typename'),
- 'wb') as f:
- f.write(b"""
+ with open(
+ sanitize(
+ endpoint,
+ "?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAMES=my:typename&TYPENAME=my:typename",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
@@ -1219,12 +1594,18 @@ def testWFS20Paging(self):
-""")
+"""
+ )
- with open(sanitize(endpoint,
- '?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&STARTINDEX=0&COUNT=1&SRSNAME=urn:ogc:def:crs:EPSG::4326'),
- 'wb') as f:
- f.write(b"""
+ with open(
+ sanitize(
+ endpoint,
+ "?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&STARTINDEX=0&COUNT=1&SRSNAME=urn:ogc:def:crs:EPSG::4326",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
1
- """)
+"""
+ )
- with open(sanitize(endpoint,
- '?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&STARTINDEX=0&COUNT=1&SRSNAME=urn:ogc:def:crs:EPSG::4326'),
- 'wb') as f:
- f.write(b"""
+ with open(
+ sanitize(
+ endpoint,
+ "?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&STARTINDEX=0&COUNT=1&SRSNAME=urn:ogc:def:crs:EPSG::4326",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
1
- """)
+"""
+ )
# Create test layer
- vl = QgsVectorLayer("url='http://" + endpoint + "' typename='my:typename'", 'test', 'WFS')
+ vl = QgsVectorLayer(
+ "url='http://" + endpoint + "' typename='my:typename'", "test", "WFS"
+ )
self.assertTrue(vl.isValid())
self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.Point)
- with open(sanitize(endpoint,
- '?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&STARTINDEX=1&COUNT=1&SRSNAME=urn:ogc:def:crs:EPSG::4326'),
- 'wb') as f:
- f.write(b"""
+ with open(
+ sanitize(
+ endpoint,
+ "?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&STARTINDEX=1&COUNT=1&SRSNAME=urn:ogc:def:crs:EPSG::4326",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
2
- """)
+"""
+ )
- with open(sanitize(endpoint,
- '?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&STARTINDEX=2&COUNT=1&SRSNAME=urn:ogc:def:crs:EPSG::4326'),
- 'wb') as f:
- f.write(b"""
+ with open(
+ sanitize(
+ endpoint,
+ "?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&STARTINDEX=2&COUNT=1&SRSNAME=urn:ogc:def:crs:EPSG::4326",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
- """)
+"""
+ )
- values = [f['id'] for f in vl.getFeatures()]
+ values = [f["id"] for f in vl.getFeatures()]
self.assertEqual(values, [1, 2])
# Suppress GetFeature responses to demonstrate that the cache is used
- os.unlink(sanitize(endpoint,
- '?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&STARTINDEX=0&COUNT=1&SRSNAME=urn:ogc:def:crs:EPSG::4326'))
- os.unlink(sanitize(endpoint,
- '?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&STARTINDEX=1&COUNT=1&SRSNAME=urn:ogc:def:crs:EPSG::4326'))
- os.unlink(sanitize(endpoint,
- '?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&STARTINDEX=2&COUNT=1&SRSNAME=urn:ogc:def:crs:EPSG::4326'))
-
- values = [f['id'] for f in vl.getFeatures()]
+ os.unlink(
+ sanitize(
+ endpoint,
+ "?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&STARTINDEX=0&COUNT=1&SRSNAME=urn:ogc:def:crs:EPSG::4326",
+ )
+ )
+ os.unlink(
+ sanitize(
+ endpoint,
+ "?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&STARTINDEX=1&COUNT=1&SRSNAME=urn:ogc:def:crs:EPSG::4326",
+ )
+ )
+ os.unlink(
+ sanitize(
+ endpoint,
+ "?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&STARTINDEX=2&COUNT=1&SRSNAME=urn:ogc:def:crs:EPSG::4326",
+ )
+ )
+
+ values = [f["id"] for f in vl.getFeatures()]
self.assertEqual(values, [1, 2])
# No need for hits since the download went to its end
@@ -1309,25 +1723,40 @@ def testWFS20Paging(self):
vl.dataProvider().reloadData()
# Hits working
- with open(sanitize(endpoint,
- '?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&RESULTTYPE=hits'),
- 'wb') as f:
- f.write(b"""
+ with open(
+ sanitize(
+ endpoint,
+ "?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&RESULTTYPE=hits",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
- """)
+"""
+ )
self.assertEqual(vl.featureCount(), 2)
def testWFS20PagingPageSizeOverride(self):
"""Test WFS 2.0 paging"""
- endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_WFS_2.0_paging_override'
+ endpoint = (
+ self.__class__.basetestpath
+ + "/fake_qgis_http_endpoint_WFS_2.0_paging_override"
+ )
- with open(sanitize(endpoint, '?SERVICE=WFS?REQUEST=GetCapabilities?ACCEPTVERSIONS=2.0.0,1.1.0,1.0.0'),
- 'wb') as f:
- f.write(b"""
+ with open(
+ sanitize(
+ endpoint,
+ "?SERVICE=WFS?REQUEST=GetCapabilities?ACCEPTVERSIONS=2.0.0,1.1.0,1.0.0",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
@@ -1353,12 +1782,18 @@ def testWFS20PagingPageSizeOverride(self):
- """)
+"""
+ )
- with open(sanitize(endpoint,
- '?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAMES=my:typename&TYPENAME=my:typename'),
- 'wb') as f:
- f.write(b"""
+ with open(
+ sanitize(
+ endpoint,
+ "?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAMES=my:typename&TYPENAME=my:typename",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
@@ -1373,18 +1808,29 @@ def testWFS20PagingPageSizeOverride(self):
-""")
+"""
+ )
# user pageSize < user maxNumFeatures < server pagesize
- vl = QgsVectorLayer("url='http://" + endpoint + "' typename='my:typename' maxNumFeatures='3' pageSize='2' skipInitialGetFeature='true'",
- 'test', 'WFS')
+ vl = QgsVectorLayer(
+ "url='http://"
+ + endpoint
+ + "' typename='my:typename' maxNumFeatures='3' pageSize='2' skipInitialGetFeature='true'",
+ "test",
+ "WFS",
+ )
self.assertTrue(vl.isValid())
self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.Point)
- with open(sanitize(endpoint,
- '?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&STARTINDEX=0&COUNT=2&SRSNAME=urn:ogc:def:crs:EPSG::4326'),
- 'wb') as f:
- f.write(b"""
+ with open(
+ sanitize(
+ endpoint,
+ "?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&STARTINDEX=0&COUNT=2&SRSNAME=urn:ogc:def:crs:EPSG::4326",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
2
- """)
+"""
+ )
- with open(sanitize(endpoint,
- '?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&STARTINDEX=2&COUNT=1&SRSNAME=urn:ogc:def:crs:EPSG::4326'),
- 'wb') as f:
- f.write(b"""
+ with open(
+ sanitize(
+ endpoint,
+ "?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&STARTINDEX=2&COUNT=1&SRSNAME=urn:ogc:def:crs:EPSG::4326",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
3
- """)
+"""
+ )
- values = [f['id'] for f in vl.getFeatures()]
+ values = [f["id"] for f in vl.getFeatures()]
self.assertEqual(values, [1, 2, 3])
- os.unlink(sanitize(endpoint,
- '?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&STARTINDEX=0&COUNT=2&SRSNAME=urn:ogc:def:crs:EPSG::4326'))
- os.unlink(sanitize(endpoint,
- '?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&STARTINDEX=2&COUNT=1&SRSNAME=urn:ogc:def:crs:EPSG::4326'))
+ os.unlink(
+ sanitize(
+ endpoint,
+ "?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&STARTINDEX=0&COUNT=2&SRSNAME=urn:ogc:def:crs:EPSG::4326",
+ )
+ )
+ os.unlink(
+ sanitize(
+ endpoint,
+ "?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&STARTINDEX=2&COUNT=1&SRSNAME=urn:ogc:def:crs:EPSG::4326",
+ )
+ )
# user maxNumFeatures < user pageSize < server pagesize
- vl = QgsVectorLayer("url='http://" + endpoint + "' typename='my:typename' maxNumFeatures='1' pageSize='2' skipInitialGetFeature='true'",
- 'test', 'WFS')
+ vl = QgsVectorLayer(
+ "url='http://"
+ + endpoint
+ + "' typename='my:typename' maxNumFeatures='1' pageSize='2' skipInitialGetFeature='true'",
+ "test",
+ "WFS",
+ )
self.assertTrue(vl.isValid())
self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.Point)
- with open(sanitize(endpoint,
- '?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&STARTINDEX=0&COUNT=1&SRSNAME=urn:ogc:def:crs:EPSG::4326'),
- 'wb') as f:
- f.write(b"""
+ with open(
+ sanitize(
+ endpoint,
+ "?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&STARTINDEX=0&COUNT=1&SRSNAME=urn:ogc:def:crs:EPSG::4326",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
1
- """)
+"""
+ )
- values = [f['id'] for f in vl.getFeatures()]
+ values = [f["id"] for f in vl.getFeatures()]
self.assertEqual(values, [1])
- os.unlink(sanitize(endpoint,
- '?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&STARTINDEX=0&COUNT=1&SRSNAME=urn:ogc:def:crs:EPSG::4326'))
+ os.unlink(
+ sanitize(
+ endpoint,
+ "?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&STARTINDEX=0&COUNT=1&SRSNAME=urn:ogc:def:crs:EPSG::4326",
+ )
+ )
# user user pageSize > server pagesize
- vl = QgsVectorLayer("url='http://" + endpoint + "' typename='my:typename' pageSize='100' skipInitialGetFeature='true'", 'test', 'WFS')
+ vl = QgsVectorLayer(
+ "url='http://"
+ + endpoint
+ + "' typename='my:typename' pageSize='100' skipInitialGetFeature='true'",
+ "test",
+ "WFS",
+ )
self.assertTrue(vl.isValid())
self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.Point)
- with open(sanitize(endpoint,
- '?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&STARTINDEX=0&COUNT=10&SRSNAME=urn:ogc:def:crs:EPSG::4326'),
- 'wb') as f:
- f.write(b"""
+ with open(
+ sanitize(
+ endpoint,
+ "?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&STARTINDEX=0&COUNT=10&SRSNAME=urn:ogc:def:crs:EPSG::4326",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
1
- """)
+"""
+ )
- values = [f['id'] for f in vl.getFeatures()]
+ values = [f["id"] for f in vl.getFeatures()]
self.assertEqual(values, [1])
- os.unlink(sanitize(endpoint,
- '?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&STARTINDEX=0&COUNT=10&SRSNAME=urn:ogc:def:crs:EPSG::4326'))
+ os.unlink(
+ sanitize(
+ endpoint,
+ "?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&STARTINDEX=0&COUNT=10&SRSNAME=urn:ogc:def:crs:EPSG::4326",
+ )
+ )
vl = QgsVectorLayer(
- "url='http://" + endpoint + "' typename='my:typename' pagingEnabled='false' maxNumFeatures='3' skipInitialGetFeature='true'", 'test',
- 'WFS')
+ "url='http://"
+ + endpoint
+ + "' typename='my:typename' pagingEnabled='false' maxNumFeatures='3' skipInitialGetFeature='true'",
+ "test",
+ "WFS",
+ )
self.assertTrue(vl.isValid())
self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.Point)
- with open(sanitize(endpoint,
- '?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&COUNT=3&SRSNAME=urn:ogc:def:crs:EPSG::4326'),
- 'wb') as f:
- f.write(b"""
+ with open(
+ sanitize(
+ endpoint,
+ "?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&COUNT=3&SRSNAME=urn:ogc:def:crs:EPSG::4326",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
2000
- """)
+"""
+ )
- values = [f['id'] for f in vl.getFeatures()]
+ values = [f["id"] for f in vl.getFeatures()]
self.assertEqual(values, [1000, 2000])
def testWFSGetOnlyFeaturesInViewExtent(self):
- """Test 'get only features in view extent' """
+ """Test 'get only features in view extent'"""
- endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_only_features_in_view_extent'
+ endpoint = (
+ self.__class__.basetestpath
+ + "/fake_qgis_http_endpoint_only_features_in_view_extent"
+ )
- with open(sanitize(endpoint, '?SERVICE=WFS?REQUEST=GetCapabilities?ACCEPTVERSIONS=2.0.0,1.1.0,1.0.0'),
- 'wb') as f:
- f.write(b"""
+ with open(
+ sanitize(
+ endpoint,
+ "?SERVICE=WFS?REQUEST=GetCapabilities?ACCEPTVERSIONS=2.0.0,1.1.0,1.0.0",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
@@ -1541,11 +2052,18 @@ def testWFSGetOnlyFeaturesInViewExtent(self):
- """)
+"""
+ )
- with open(sanitize(endpoint, '?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=1.1.0&TYPENAME=my:typename'),
- 'wb') as f:
- f.write(b"""
+ with open(
+ sanitize(
+ endpoint,
+ "?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=1.1.0&TYPENAME=my:typename",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
@@ -1561,19 +2079,28 @@ def testWFSGetOnlyFeaturesInViewExtent(self):
-""")
+"""
+ )
# Create test layer
- vl = QgsVectorLayer("url='http://" + endpoint + "' typename='my:typename' restrictToRequestBBOX=1 skipInitialGetFeature='true'", 'test',
- 'WFS')
+ vl = QgsVectorLayer(
+ "url='http://"
+ + endpoint
+ + "' typename='my:typename' restrictToRequestBBOX=1 skipInitialGetFeature='true'",
+ "test",
+ "WFS",
+ )
self.assertTrue(vl.isValid())
self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.Point)
return
- last_url = sanitize(endpoint,
- '?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.1.0&TYPENAME=my:typename&MAXFEATURES=2&SRSNAME=urn:ogc:def:crs:EPSG::4326&BBOX=60,-70,80,-60,urn:ogc:def:crs:EPSG::4326')
- with open(last_url, 'wb') as f:
- f.write(b"""
+ last_url = sanitize(
+ endpoint,
+ "?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.1.0&TYPENAME=my:typename&MAXFEATURES=2&SRSNAME=urn:ogc:def:crs:EPSG::4326&BBOX=60,-70,80,-60,urn:ogc:def:crs:EPSG::4326",
+ )
+ with open(last_url, "wb") as f:
+ f.write(
+ b"""
2
- """)
+"""
+ )
extent = QgsRectangle(-70, 60, -60, 80)
request = QgsFeatureRequest().setFilterRect(extent)
- values = [f['ogc_fid'] for f in vl.getFeatures(request)]
+ values = [f["ogc_fid"] for f in vl.getFeatures(request)]
self.assertEqual(values, [2])
# To show that if we zoom-in, we won't issue a new request
- with open(last_url, 'wb') as f:
- f.write(b"""
+ with open(last_url, "wb") as f:
+ f.write(
+ b"""
200
- """)
+"""
+ )
extent = QgsRectangle(-66, 62, -62, 78)
request = QgsFeatureRequest().setFilterRect(extent)
- values = [f['ogc_fid'] for f in vl.getFeatures(request)]
+ values = [f["ogc_fid"] for f in vl.getFeatures(request)]
self.assertEqual(values, [2])
# Move to a neighbouring area, and reach the download limit
- last_url = sanitize(endpoint,
- '?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.1.0&TYPENAME=my:typename&MAXFEATURES=2&SRSNAME=urn:ogc:def:crs:EPSG::4326&BBOX=65,-70,90,-60,urn:ogc:def:crs:EPSG::4326')
- with open(last_url, 'wb') as f:
- f.write(b"""
+ last_url = sanitize(
+ endpoint,
+ "?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.1.0&TYPENAME=my:typename&MAXFEATURES=2&SRSNAME=urn:ogc:def:crs:EPSG::4326&BBOX=65,-70,90,-60,urn:ogc:def:crs:EPSG::4326",
+ )
+ with open(last_url, "wb") as f:
+ f.write(
+ b"""
3
- """)
+"""
+ )
extent = QgsRectangle(-70, 65, -60, 90)
request = QgsFeatureRequest().setFilterRect(extent)
- values = [f['ogc_fid'] for f in vl.getFeatures(request)]
+ values = [f["ogc_fid"] for f in vl.getFeatures(request)]
self.assertEqual(values, [2, 3])
# Zoom-in again, and bring more features
- last_url = sanitize(endpoint,
- '?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.1.0&TYPENAME=my:typename&MAXFEATURES=2&SRSNAME=urn:ogc:def:crs:EPSG::4326&BBOX=66,-69,89,-61,urn:ogc:def:crs:EPSG::4326')
- with open(last_url, 'wb') as f:
- f.write(b"""
+ last_url = sanitize(
+ endpoint,
+ "?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.1.0&TYPENAME=my:typename&MAXFEATURES=2&SRSNAME=urn:ogc:def:crs:EPSG::4326&BBOX=66,-69,89,-61,urn:ogc:def:crs:EPSG::4326",
+ )
+ with open(last_url, "wb") as f:
+ f.write(
+ b"""
4
- """)
+"""
+ )
extent = QgsRectangle(-69, 66, -61, 89)
request = QgsFeatureRequest().setFilterRect(extent)
- values = [f['ogc_fid'] for f in vl.getFeatures(request)]
+ values = [f["ogc_fid"] for f in vl.getFeatures(request)]
self.assertEqual(values, [2, 3, 4])
# Test RESULTTYPE=hits
- last_url = sanitize(endpoint,
- '?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.1.0&TYPENAME=my:typename&RESULTTYPE=hits')
- with open(last_url, 'wb') as f:
- f.write(b"""
+ last_url = sanitize(
+ endpoint,
+ "?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.1.0&TYPENAME=my:typename&RESULTTYPE=hits",
+ )
+ with open(last_url, "wb") as f:
+ f.write(
+ b"""
""")
+ numberOfFeatures="10" timeStamp="2016-03-25T14:51:48.998Z"/>"""
+ )
self.assertEqual(vl.featureCount(), 10)
# Combine BBOX and FILTER
- last_url = sanitize(endpoint, """?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.1.0&TYPENAME=my:typename&MAXFEATURES=2&SRSNAME=urn:ogc:def:crs:EPSG::4326&FILTER=
+ last_url = sanitize(
+ endpoint,
+ """?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.1.0&TYPENAME=my:typename&MAXFEATURES=2&SRSNAME=urn:ogc:def:crs:EPSG::4326&FILTER=
geometryProperty
@@ -1689,9 +2233,11 @@ def testWFSGetOnlyFeaturesInViewExtent(self):
-""")
- with open(last_url, 'wb') as f:
- f.write(b"""
+""",
+ )
+ with open(last_url, "wb") as f:
+ f.write(
+ b"""
101
- """)
+"""
+ )
- vl.dataProvider().setSubsetString('ogc_fid = 101')
+ vl.dataProvider().setSubsetString("ogc_fid = 101")
extent = QgsRectangle(-69, 66, -61, 89)
request = QgsFeatureRequest().setFilterRect(extent)
- values = [f['ogc_fid'] for f in vl.getFeatures(request)]
+ values = [f["ogc_fid"] for f in vl.getFeatures(request)]
self.assertEqual(values, [101])
# Check behavior with setLimit(1)
- with open(sanitize(endpoint,
- "?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.1.0&TYPENAME=my:typename&MAXFEATURES=1&SRSNAME=urn:ogc:def:crs:EPSG::4326"),
- 'wb') as f:
- f.write(b"""
+ with open(
+ sanitize(
+ endpoint,
+ "?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.1.0&TYPENAME=my:typename&MAXFEATURES=1&SRSNAME=urn:ogc:def:crs:EPSG::4326",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
12345
- """)
- vl = QgsVectorLayer("url='http://" + endpoint + "' typename='my:typename' restrictToRequestBBOX=1 skipInitialGetFeature='true'", 'test',
- 'WFS')
+"""
+ )
+ vl = QgsVectorLayer(
+ "url='http://"
+ + endpoint
+ + "' typename='my:typename' restrictToRequestBBOX=1 skipInitialGetFeature='true'",
+ "test",
+ "WFS",
+ )
request = QgsFeatureRequest().setLimit(1)
- values = [f['ogc_fid'] for f in vl.getFeatures(request)]
+ values = [f["ogc_fid"] for f in vl.getFeatures(request)]
self.assertEqual(values, [12345])
# Check that the layer extent is not built from this single feature
reference = QgsGeometry.fromRect(QgsRectangle(-80, 60, -50, 80))
vl_extent = QgsGeometry.fromRect(vl.extent())
- assert QgsGeometry.compare(vl_extent.asPolygon()[0], reference.asPolygon()[0],
- 0.00001), f'Expected {reference.asWkt()}, got {vl_extent.asWkt()}'
+ assert QgsGeometry.compare(
+ vl_extent.asPolygon()[0], reference.asPolygon()[0], 0.00001
+ ), f"Expected {reference.asWkt()}, got {vl_extent.asWkt()}"
def testWFSGetOnlyFeaturesInViewExtentZoomOut(self):
- """Test zoom out outside of declare extent in metadata (#20742) """
+ """Test zoom out outside of declare extent in metadata (#20742)"""
- endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_20742'
+ endpoint = self.__class__.basetestpath + "/fake_qgis_http_endpoint_20742"
- with open(sanitize(endpoint, '?SERVICE=WFS?REQUEST=GetCapabilities?ACCEPTVERSIONS=2.0.0,1.1.0,1.0.0'),
- 'wb') as f:
- f.write(b"""
+ with open(
+ sanitize(
+ endpoint,
+ "?SERVICE=WFS?REQUEST=GetCapabilities?ACCEPTVERSIONS=2.0.0,1.1.0,1.0.0",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
@@ -1767,11 +2332,18 @@ def testWFSGetOnlyFeaturesInViewExtentZoomOut(self):
- """)
+"""
+ )
- with open(sanitize(endpoint, '?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=1.1.0&TYPENAME=my:typename'),
- 'wb') as f:
- f.write(b"""
+ with open(
+ sanitize(
+ endpoint,
+ "?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=1.1.0&TYPENAME=my:typename",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
@@ -1786,10 +2358,13 @@ def testWFSGetOnlyFeaturesInViewExtentZoomOut(self):
-""")
+"""
+ )
- last_url = sanitize(endpoint,
- '?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.1.0&TYPENAME=my:typename&SRSNAME=urn:ogc:def:crs:EPSG::4326&BBOX=60,-80,80,-50,urn:ogc:def:crs:EPSG::4326')
+ last_url = sanitize(
+ endpoint,
+ "?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.1.0&TYPENAME=my:typename&SRSNAME=urn:ogc:def:crs:EPSG::4326&BBOX=60,-80,80,-50,urn:ogc:def:crs:EPSG::4326",
+ )
getfeature_response = b"""
"""
- with open(last_url, 'wb') as f:
+ with open(last_url, "wb") as f:
f.write(getfeature_response)
- last_url = sanitize(endpoint,
- '?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.1.0&TYPENAME=my:typename&SRSNAME=urn:ogc:def:crs:EPSG::4326&BBOX=50,-90,90,-40,urn:ogc:def:crs:EPSG::4326')
- with open(last_url, 'wb') as f:
+ last_url = sanitize(
+ endpoint,
+ "?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.1.0&TYPENAME=my:typename&SRSNAME=urn:ogc:def:crs:EPSG::4326&BBOX=50,-90,90,-40,urn:ogc:def:crs:EPSG::4326",
+ )
+ with open(last_url, "wb") as f:
f.write(getfeature_response)
- vl = QgsVectorLayer("url='http://" + endpoint + "' typename='my:typename' restrictToRequestBBOX=1 skipInitialGetFeature='true'", 'test',
- 'WFS')
+ vl = QgsVectorLayer(
+ "url='http://"
+ + endpoint
+ + "' typename='my:typename' restrictToRequestBBOX=1 skipInitialGetFeature='true'",
+ "test",
+ "WFS",
+ )
# First request with declared extent in metadata
extent = QgsRectangle(-80, 60, -50, 80)
request = QgsFeatureRequest().setFilterRect(extent)
self.assertEqual(len([f for f in vl.getFeatures(request)]), 2)
reference = QgsGeometry.fromRect(QgsRectangle(-65, 70, -64, 71))
vl_extent = QgsGeometry.fromRect(vl.extent())
- assert QgsGeometry.compare(vl_extent.asPolygon()[0], reference.asPolygon()[0],
- 0.00001), f'Expected {reference.asWkt()}, got {vl_extent.asWkt()}'
+ assert QgsGeometry.compare(
+ vl_extent.asPolygon()[0], reference.asPolygon()[0], 0.00001
+ ), f"Expected {reference.asWkt()}, got {vl_extent.asWkt()}"
# Second request: zoomed out
extent = QgsRectangle(-90, 50, -40, 90)
request = QgsFeatureRequest().setFilterRect(extent)
self.assertEqual(len([f for f in vl.getFeatures(request)]), 2)
vl_extent = QgsGeometry.fromRect(vl.extent())
- assert QgsGeometry.compare(vl_extent.asPolygon()[0], reference.asPolygon()[0],
- 0.00001), f'Expected {reference.asWkt()}, got {vl_extent.asWkt()}'
+ assert QgsGeometry.compare(
+ vl_extent.asPolygon()[0], reference.asPolygon()[0], 0.00001
+ ), f"Expected {reference.asWkt()}, got {vl_extent.asWkt()}"
def testWFS20TruncatedResponse(self):
"""Test WFS 2.0 truncatedResponse"""
- endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_WFS_2.0_truncated_response'
+ endpoint = (
+ self.__class__.basetestpath
+ + "/fake_qgis_http_endpoint_WFS_2.0_truncated_response"
+ )
- with open(sanitize(endpoint, '?SERVICE=WFS?REQUEST=GetCapabilities?ACCEPTVERSIONS=2.0.0,1.1.0,1.0.0'),
- 'wb') as f:
- f.write(b"""
+ with open(
+ sanitize(
+ endpoint,
+ "?SERVICE=WFS?REQUEST=GetCapabilities?ACCEPTVERSIONS=2.0.0,1.1.0,1.0.0",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
@@ -1848,12 +2441,18 @@ def testWFS20TruncatedResponse(self):
urn:ogc:def:crs:EPSG::4326
- """)
+"""
+ )
- with open(sanitize(endpoint,
- '?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAMES=my:typename&TYPENAME=my:typename'),
- 'wb') as f:
- f.write(b"""
+ with open(
+ sanitize(
+ endpoint,
+ "?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAMES=my:typename&TYPENAME=my:typename",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
@@ -1867,12 +2466,18 @@ def testWFS20TruncatedResponse(self):
-""")
+"""
+ )
- with open(sanitize(endpoint,
- '?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&SRSNAME=urn:ogc:def:crs:EPSG::4326'),
- 'wb') as f:
- f.write(b"""
+ with open(
+ sanitize(
+ endpoint,
+ "?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&SRSNAME=urn:ogc:def:crs:EPSG::4326",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
-""")
+"""
+ )
# Create test layer
- vl = QgsVectorLayer("url='http://" + endpoint + "' typename='my:typename' skipInitialGetFeature='true'", 'test', 'WFS')
+ vl = QgsVectorLayer(
+ "url='http://"
+ + endpoint
+ + "' typename='my:typename' skipInitialGetFeature='true'",
+ "test",
+ "WFS",
+ )
self.assertTrue(vl.isValid())
# Check that we get a log message
- with MessageLogger('WFS') as logger:
+ with MessageLogger("WFS") as logger:
[f for f in vl.getFeatures()]
# Let signals to be notified to QgsVectorDataProvider
@@ -1896,15 +2508,24 @@ def testWFS20TruncatedResponse(self):
loop.processEvents()
self.assertEqual(len(logger.messages()), 1, logger.messages())
- self.assertGreaterEqual(logger.messages()[0].decode('UTF-8').find('The download limit has been reached'), 0)
+ self.assertGreaterEqual(
+ logger.messages()[0]
+ .decode("UTF-8")
+ .find("The download limit has been reached"),
+ 0,
+ )
def testRetryLogic(self):
- """Test retry logic """
+ """Test retry logic"""
- endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_retry'
+ endpoint = self.__class__.basetestpath + "/fake_qgis_http_endpoint_retry"
- with open(sanitize(endpoint, '?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=1.0.0'), 'wb') as f:
- f.write(b"""
+ with open(
+ sanitize(endpoint, "?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=1.0.0"),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
@@ -1914,11 +2535,18 @@ def testRetryLogic(self):
EPSG:4326
- """)
+"""
+ )
- with open(sanitize(endpoint, '?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=1.0.0&TYPENAME=my:typename'),
- 'wb') as f:
- f.write(b"""
+ with open(
+ sanitize(
+ endpoint,
+ "?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=1.0.0&TYPENAME=my:typename",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
@@ -1932,15 +2560,20 @@ def testRetryLogic(self):
-""")
+"""
+ )
- vl = QgsVectorLayer("url='http://" + endpoint + "' typename='my:typename' version='1.0.0'", 'test', 'WFS')
+ vl = QgsVectorLayer(
+ "url='http://" + endpoint + "' typename='my:typename' version='1.0.0'",
+ "test",
+ "WFS",
+ )
self.assertTrue(vl.isValid())
self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.NoGeometry)
self.assertEqual(len(vl.fields()), 1)
# Failed download: test that error is propagated to the data provider, so as to get application notification
- [f['INTFIELD'] for f in vl.getFeatures()]
+ [f["INTFIELD"] for f in vl.getFeatures()]
# Let signals to be notified to QgsVectorDataProvider
loop = QEventLoop()
@@ -1953,16 +2586,25 @@ def testRetryLogic(self):
vl.reload()
# First retry: Empty response
- with open(sanitize(endpoint,
- '?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.0.0&TYPENAME=my:typename&SRSNAME=EPSG:4326&RETRY=1'),
- 'wb') as f:
- f.write(b'')
+ with open(
+ sanitize(
+ endpoint,
+ "?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.0.0&TYPENAME=my:typename&SRSNAME=EPSG:4326&RETRY=1",
+ ),
+ "wb",
+ ) as f:
+ f.write(b"")
# Second retry: Incomplete response
- with open(sanitize(endpoint,
- '?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.0.0&TYPENAME=my:typename&SRSNAME=EPSG:4326&RETRY=2'),
- 'wb') as f:
- f.write(b"""
+ with open(
+ sanitize(
+ endpoint,
+ "?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.0.0&TYPENAME=my:typename&SRSNAME=EPSG:4326&RETRY=2",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
- 2 """)
+ 2 """
+ )
# Third retry: Valid response
- with open(sanitize(endpoint,
- '?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.0.0&TYPENAME=my:typename&SRSNAME=EPSG:4326&RETRY=3'),
- 'wb') as f:
- f.write(b"""
+ with open(
+ sanitize(
+ endpoint,
+ "?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.0.0&TYPENAME=my:typename&SRSNAME=EPSG:4326&RETRY=3",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
2
- """)
+"""
+ )
- values = [f['INTFIELD'] for f in vl.getFeatures()]
+ values = [f["INTFIELD"] for f in vl.getFeatures()]
self.assertEqual(values, [1, 2])
def testDetachedFeatureSource(self):
- """Test using a feature source after the provider has been destroyed """
+ """Test using a feature source after the provider has been destroyed"""
- endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_detached_source'
+ endpoint = (
+ self.__class__.basetestpath + "/fake_qgis_http_endpoint_detached_source"
+ )
- with open(sanitize(endpoint, '?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=1.0.0'), 'wb') as f:
- f.write(b"""
+ with open(
+ sanitize(endpoint, "?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=1.0.0"),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
@@ -2016,11 +2671,18 @@ def testDetachedFeatureSource(self):
EPSG:4326
- """)
+"""
+ )
- with open(sanitize(endpoint, '?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=1.0.0&TYPENAME=my:typename'),
- 'wb') as f:
- f.write(b"""
+ with open(
+ sanitize(
+ endpoint,
+ "?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=1.0.0&TYPENAME=my:typename",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
@@ -2034,9 +2696,14 @@ def testDetachedFeatureSource(self):
-""")
+"""
+ )
- vl = QgsVectorLayer("url='http://" + endpoint + "' typename='my:typename' version='1.0.0'", 'test', 'WFS')
+ vl = QgsVectorLayer(
+ "url='http://" + endpoint + "' typename='my:typename' version='1.0.0'",
+ "test",
+ "WFS",
+ )
self.assertTrue(vl.isValid())
self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.NoGeometry)
self.assertEqual(len(vl.fields()), 1)
@@ -2046,9 +2713,14 @@ def testDetachedFeatureSource(self):
vl = None
with open(
- sanitize(endpoint, '?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.0.0&TYPENAME=my:typename&SRSNAME=EPSG:4326'),
- 'wb') as f:
- f.write(b"""
+ sanitize(
+ endpoint,
+ "?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.0.0&TYPENAME=my:typename&SRSNAME=EPSG:4326",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
1
- """)
+"""
+ )
- values = [f['INTFIELD'] for f in source.getFeatures(QgsFeatureRequest())]
+ values = [f["INTFIELD"] for f in source.getFeatures(QgsFeatureRequest())]
self.assertEqual(values, [1])
def testLayerConstructionNoPrefix(self):
@@ -2069,12 +2742,14 @@ def testLayerConstructionNoPrefix(self):
without the prefix, when it's safe to do so.
"""
- endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_no_prefix'
+ endpoint = self.__class__.basetestpath + "/fake_qgis_http_endpoint_no_prefix"
- with open(sanitize(endpoint,
- '?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=2.0.0'),
- 'wb') as f:
- f.write(b"""
+ with open(
+ sanitize(endpoint, "?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=2.0.0"),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
@@ -2108,7 +2783,8 @@ def testLayerConstructionNoPrefix(self):
- """)
+"""
+ )
schema = """
@@ -2126,10 +2802,14 @@ def testLayerConstructionNoPrefix(self):
"""
- with open(sanitize(endpoint,
- '?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAMES=my:uniquename&TYPENAME=my:uniquename'),
- 'wb') as f:
- f.write(schema.encode('UTF-8'))
+ with open(
+ sanitize(
+ endpoint,
+ "?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAMES=my:uniquename&TYPENAME=my:uniquename",
+ ),
+ "wb",
+ ) as f:
+ f.write(schema.encode("UTF-8"))
schema = """
@@ -2147,45 +2827,71 @@ def testLayerConstructionNoPrefix(self):
"""
- with open(sanitize(endpoint,
- '?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAMES=my:ambiguousname&TYPENAME=my:ambiguousname'),
- 'wb') as f:
- f.write(schema.encode('UTF-8'))
+ with open(
+ sanitize(
+ endpoint,
+ "?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAMES=my:ambiguousname&TYPENAME=my:ambiguousname",
+ ),
+ "wb",
+ ) as f:
+ f.write(schema.encode("UTF-8"))
# Explicitly stating namespace for unique layer name
vl = QgsVectorLayer(
- "url='http://" + endpoint + "' typename='my:uniquename' version='2.0.0' skipInitialGetFeature='true'",
- 'test', 'WFS')
+ "url='http://"
+ + endpoint
+ + "' typename='my:uniquename' version='2.0.0' skipInitialGetFeature='true'",
+ "test",
+ "WFS",
+ )
self.assertTrue(vl.isValid())
self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.Point)
# excluding namespace for unique layer name
vl = QgsVectorLayer(
- "url='http://" + endpoint + "' typename='uniquename' version='2.0.0' skipInitialGetFeature='true'",
- 'test', 'WFS')
+ "url='http://"
+ + endpoint
+ + "' typename='uniquename' version='2.0.0' skipInitialGetFeature='true'",
+ "test",
+ "WFS",
+ )
self.assertTrue(vl.isValid())
self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.Point)
# Explicitly stating namespace for otherwise ambiguous name
vl = QgsVectorLayer(
- "url='http://" + endpoint + "' typename='my:ambiguousname' version='2.0.0' skipInitialGetFeature='true'",
- 'test', 'WFS')
+ "url='http://"
+ + endpoint
+ + "' typename='my:ambiguousname' version='2.0.0' skipInitialGetFeature='true'",
+ "test",
+ "WFS",
+ )
self.assertTrue(vl.isValid())
self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.Point)
# excluding namespace for ambiguous name -- is not permitted
vl = QgsVectorLayer(
- "url='http://" + endpoint + "' typename='ambiguousname' version='2.0.0' skipInitialGetFeature='true'",
- 'test', 'WFS')
+ "url='http://"
+ + endpoint
+ + "' typename='ambiguousname' version='2.0.0' skipInitialGetFeature='true'",
+ "test",
+ "WFS",
+ )
self.assertFalse(vl.isValid())
def testJoins(self):
- """Test SELECT with joins """
+ """Test SELECT with joins"""
- endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_detached_source'
+ endpoint = (
+ self.__class__.basetestpath + "/fake_qgis_http_endpoint_detached_source"
+ )
- with open(sanitize(endpoint, '?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=2.0.0'), 'wb') as f:
- f.write(b"""
+ with open(
+ sanitize(endpoint, "?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=2.0.0"),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
@@ -2239,7 +2945,8 @@ def testJoins(self):
- """)
+"""
+ )
schema = """
@@ -2269,12 +2976,19 @@ def testJoins(self):
"""
- with open(sanitize(endpoint,
- '?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAMES=my:typename,my:othertypename&TYPENAME=my:typename,my:othertypename'),
- 'wb') as f:
- f.write(schema.encode('UTF-8'))
+ with open(
+ sanitize(
+ endpoint,
+ "?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAMES=my:typename,my:othertypename&TYPENAME=my:typename,my:othertypename",
+ ),
+ "wb",
+ ) as f:
+ f.write(schema.encode("UTF-8"))
- with open(sanitize(endpoint, """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename,my:othertypename&SRSNAME=urn:ogc:def:crs:EPSG::4326&FILTER=
+ with open(
+ sanitize(
+ endpoint,
+ """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename,my:othertypename&SRSNAME=urn:ogc:def:crs:EPSG::4326&FILTER=
my:typename/id
@@ -2286,8 +3000,12 @@ def testJoins(self):
-&SORTBY=id DESC"""), 'wb') as f:
- f.write(b"""
+&SORTBY=id DESC""",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
- """)
+"""
+ )
# * syntax
vl = QgsVectorLayer(
- "url='http://" + endpoint + "' typename='my:typename' version='2.0.0' skipInitialGetFeature='true' sql=SELECT * FROM \"my:typename\" JOIN \"my:othertypename\" o ON \"my:typename\".id = o.main_id WHERE \"my:typename\".id > 0 ORDER BY \"my:typename\".id DESC",
- 'test', 'WFS')
+ "url='http://"
+ + endpoint
+ + '\' typename=\'my:typename\' version=\'2.0.0\' skipInitialGetFeature=\'true\' sql=SELECT * FROM "my:typename" JOIN "my:othertypename" o ON "my:typename".id = o.main_id WHERE "my:typename".id > 0 ORDER BY "my:typename".id DESC',
+ "test",
+ "WFS",
+ )
self.assertTrue(vl.isValid())
self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.Point)
fields = vl.fields()
self.assertEqual(len(fields), 3, fields)
- self.assertEqual(fields[0].name(), 'typename.id')
- self.assertEqual(fields[1].name(), 'o.main_id')
- self.assertEqual(fields[2].name(), 'o.second_id')
-
- values = [(f['typename.id'], f['o.main_id'], f['o.second_id']) for f in vl.getFeatures()]
+ self.assertEqual(fields[0].name(), "typename.id")
+ self.assertEqual(fields[1].name(), "o.main_id")
+ self.assertEqual(fields[2].name(), "o.second_id")
+
+ values = [
+ (f["typename.id"], f["o.main_id"], f["o.second_id"])
+ for f in vl.getFeatures()
+ ]
self.assertEqual(values, [(1, 1, 2)])
# * syntax with unprefixed typenames
vl = QgsVectorLayer(
- "url='http://" + endpoint + "' typename='my:typename' version='2.0.0' sql=SELECT * FROM typename JOIN othertypename o ON typename.id = o.main_id WHERE typename.id > 0 ORDER BY typename.id DESC",
- 'test', 'WFS')
+ "url='http://"
+ + endpoint
+ + "' typename='my:typename' version='2.0.0' sql=SELECT * FROM typename JOIN othertypename o ON typename.id = o.main_id WHERE typename.id > 0 ORDER BY typename.id DESC",
+ "test",
+ "WFS",
+ )
self.assertTrue(vl.isValid())
self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.Point)
fields = vl.fields()
self.assertEqual(len(fields), 3, fields)
- self.assertEqual(fields[0].name(), 'typename.id')
- self.assertEqual(fields[1].name(), 'o.main_id')
- self.assertEqual(fields[2].name(), 'o.second_id')
-
- values = [(f['typename.id'], f['o.main_id'], f['o.second_id']) for f in vl.getFeatures()]
+ self.assertEqual(fields[0].name(), "typename.id")
+ self.assertEqual(fields[1].name(), "o.main_id")
+ self.assertEqual(fields[2].name(), "o.second_id")
+
+ values = [
+ (f["typename.id"], f["o.main_id"], f["o.second_id"])
+ for f in vl.getFeatures()
+ ]
self.assertEqual(values, [(1, 1, 2)])
# main table not appearing in first
- with open(sanitize(endpoint,
- '?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAMES=my:othertypename,my:typename&TYPENAME=my:othertypename,my:typename'),
- 'wb') as f:
- f.write(schema.encode('UTF-8'))
+ with open(
+ sanitize(
+ endpoint,
+ "?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAMES=my:othertypename,my:typename&TYPENAME=my:othertypename,my:typename",
+ ),
+ "wb",
+ ) as f:
+ f.write(schema.encode("UTF-8"))
vl = QgsVectorLayer(
- "url='http://" + endpoint + "' typename='my:typename' version='2.0.0' skipInitialGetFeature='true' sql=SELECT * FROM othertypename o, typename WHERE typename.id = o.main_id AND typename.id > 0 ORDER BY typename.id DESC",
- 'test', 'WFS')
+ "url='http://"
+ + endpoint
+ + "' typename='my:typename' version='2.0.0' skipInitialGetFeature='true' sql=SELECT * FROM othertypename o, typename WHERE typename.id = o.main_id AND typename.id > 0 ORDER BY typename.id DESC",
+ "test",
+ "WFS",
+ )
self.assertTrue(vl.isValid())
self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.Point)
fields = vl.fields()
self.assertEqual(len(fields), 3, fields)
- self.assertEqual(fields[0].name(), 'o.main_id')
- self.assertEqual(fields[1].name(), 'o.second_id')
- self.assertEqual(fields[2].name(), 'typename.id')
+ self.assertEqual(fields[0].name(), "o.main_id")
+ self.assertEqual(fields[1].name(), "o.second_id")
+ self.assertEqual(fields[2].name(), "typename.id")
# main table not appearing in first, not in FROM but in JOIN
vl = QgsVectorLayer(
- "url='http://" + endpoint + "' typename='my:typename' version='2.0.0' skipInitialGetFeature='true' sql=SELECT * FROM othertypename o JOIN typename ON typename.id = o.main_id WHERE typename.id > 0 ORDER BY typename.id DESC",
- 'test', 'WFS')
+ "url='http://"
+ + endpoint
+ + "' typename='my:typename' version='2.0.0' skipInitialGetFeature='true' sql=SELECT * FROM othertypename o JOIN typename ON typename.id = o.main_id WHERE typename.id > 0 ORDER BY typename.id DESC",
+ "test",
+ "WFS",
+ )
self.assertTrue(vl.isValid())
self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.Point)
fields = vl.fields()
self.assertEqual(len(fields), 3, fields)
- self.assertEqual(fields[0].name(), 'o.main_id')
- self.assertEqual(fields[1].name(), 'o.second_id')
- self.assertEqual(fields[2].name(), 'typename.id')
+ self.assertEqual(fields[0].name(), "o.main_id")
+ self.assertEqual(fields[1].name(), "o.second_id")
+ self.assertEqual(fields[2].name(), "typename.id")
# table_alias.*, field alias
vl.setSubsetString(
- "SELECT o.*, m.id AS m_id FROM \"my:typename\" m JOIN \"my:othertypename\" o ON m.id = o.main_id WHERE m.id > 0 ORDER BY m.id DESC")
+ 'SELECT o.*, m.id AS m_id FROM "my:typename" m JOIN "my:othertypename" o ON m.id = o.main_id WHERE m.id > 0 ORDER BY m.id DESC'
+ )
fields = vl.fields()
self.assertEqual(len(fields), 3, fields)
- self.assertEqual(fields[0].name(), 'o.main_id')
- self.assertEqual(fields[1].name(), 'o.second_id')
- self.assertEqual(fields[2].name(), 'm_id')
+ self.assertEqual(fields[0].name(), "o.main_id")
+ self.assertEqual(fields[1].name(), "o.second_id")
+ self.assertEqual(fields[2].name(), "m_id")
- values = [(f['o.main_id'], f['o.second_id'], f['m_id']) for f in vl.getFeatures()]
+ values = [
+ (f["o.main_id"], f["o.second_id"], f["m_id"]) for f in vl.getFeatures()
+ ]
self.assertEqual(values, [(1, 2, 1)])
# table_alias.*, field alias, with unprefixed typenames
vl.setSubsetString(
- "SELECT o.*, m.id AS m_id FROM typename m JOIN othertypename o ON m.id = o.main_id WHERE m.id > 0 ORDER BY m.id DESC")
+ "SELECT o.*, m.id AS m_id FROM typename m JOIN othertypename o ON m.id = o.main_id WHERE m.id > 0 ORDER BY m.id DESC"
+ )
fields = vl.fields()
self.assertEqual(len(fields), 3, fields)
- self.assertEqual(fields[0].name(), 'o.main_id')
- self.assertEqual(fields[1].name(), 'o.second_id')
- self.assertEqual(fields[2].name(), 'm_id')
+ self.assertEqual(fields[0].name(), "o.main_id")
+ self.assertEqual(fields[1].name(), "o.second_id")
+ self.assertEqual(fields[2].name(), "m_id")
- values = [(f['o.main_id'], f['o.second_id'], f['m_id']) for f in vl.getFeatures()]
+ values = [
+ (f["o.main_id"], f["o.second_id"], f["m_id"]) for f in vl.getFeatures()
+ ]
self.assertEqual(values, [(1, 2, 1)])
# Test going back to single layer
vl.setSubsetString(None)
fields = vl.fields()
self.assertEqual(len(fields), 1, fields)
- self.assertEqual(fields[0].name(), 'id')
+ self.assertEqual(fields[0].name(), "id")
- with open(sanitize(endpoint,
- '?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAMES=my:typename&TYPENAME=my:typename'),
- 'wb') as f:
- f.write(schema.encode('UTF-8'))
+ with open(
+ sanitize(
+ endpoint,
+ "?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAMES=my:typename&TYPENAME=my:typename",
+ ),
+ "wb",
+ ) as f:
+ f.write(schema.encode("UTF-8"))
# Duplicate fields
vl = QgsVectorLayer(
- "url='http://" + endpoint + "' typename='my:typename' version='2.0.0' skipInitialGetFeature='true' sql=SELECT id, id FROM \"my:typename\"",
- 'test', 'WFS')
+ "url='http://"
+ + endpoint
+ + "' typename='my:typename' version='2.0.0' skipInitialGetFeature='true' sql=SELECT id, id FROM \"my:typename\"",
+ "test",
+ "WFS",
+ )
self.assertFalse(vl.isValid())
# * syntax with single layer
vl = QgsVectorLayer(
- "url='http://" + endpoint + "' typename='my:typename' version='2.0.0' skipInitialGetFeature='true' sql=SELECT * FROM \"my:typename\"",
- 'test', 'WFS')
+ "url='http://"
+ + endpoint
+ + "' typename='my:typename' version='2.0.0' skipInitialGetFeature='true' sql=SELECT * FROM \"my:typename\"",
+ "test",
+ "WFS",
+ )
self.assertTrue(vl.isValid())
fields = vl.fields()
self.assertEqual(len(fields), 1, fields)
- self.assertEqual(fields[0].name(), 'id')
+ self.assertEqual(fields[0].name(), "id")
# * syntax with single layer, unprefixed
vl = QgsVectorLayer(
- "url='http://" + endpoint + "' typename='my:typename' version='2.0.0' skipInitialGetFeature='true' sql=SELECT * FROM typename", 'test',
- 'WFS')
+ "url='http://"
+ + endpoint
+ + "' typename='my:typename' version='2.0.0' skipInitialGetFeature='true' sql=SELECT * FROM typename",
+ "test",
+ "WFS",
+ )
self.assertTrue(vl.isValid())
fields = vl.fields()
self.assertEqual(len(fields), 1, fields)
- self.assertEqual(fields[0].name(), 'id')
+ self.assertEqual(fields[0].name(), "id")
# test with unqualified field name, and geometry name specified
vl = QgsVectorLayer(
- "url='http://" + endpoint + "' typename='my:typename' version='2.0.0' skipInitialGetFeature='true' sql=SELECT id, geometryProperty FROM typename",
- 'test', 'WFS')
+ "url='http://"
+ + endpoint
+ + "' typename='my:typename' version='2.0.0' skipInitialGetFeature='true' sql=SELECT id, geometryProperty FROM typename",
+ "test",
+ "WFS",
+ )
self.assertTrue(vl.isValid())
fields = vl.fields()
self.assertEqual(len(fields), 1, fields)
- self.assertEqual(fields[0].name(), 'id')
+ self.assertEqual(fields[0].name(), "id")
# Ambiguous typename
vl = QgsVectorLayer(
- "url='http://" + endpoint + "' typename='first_ns:ambiguous' version='2.0.0' skipInitialGetFeature='true' sql=SELECT id FROM ambiguous",
- 'test', 'WFS')
+ "url='http://"
+ + endpoint
+ + "' typename='first_ns:ambiguous' version='2.0.0' skipInitialGetFeature='true' sql=SELECT id FROM ambiguous",
+ "test",
+ "WFS",
+ )
self.assertFalse(vl.isValid())
# main table missing from SQL
vl = QgsVectorLayer(
- "url='http://" + endpoint + "' typename='my:othertypename' version='2.0.0' skipInitialGetFeature='true' sql=SELECT * FROM typename",
- 'test', 'WFS')
+ "url='http://"
+ + endpoint
+ + "' typename='my:othertypename' version='2.0.0' skipInitialGetFeature='true' sql=SELECT * FROM typename",
+ "test",
+ "WFS",
+ )
self.assertFalse(vl.isValid())
def testFunctionValidation(self):
- endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_function_validation'
+ endpoint = (
+ self.__class__.basetestpath + "/fake_qgis_http_endpoint_function_validation"
+ )
- with open(sanitize(endpoint, '?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=1.0.0'), 'wb') as f:
- f.write(b"""
+ with open(
+ sanitize(endpoint, "?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=1.0.0"),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
@@ -2490,10 +3275,15 @@ def testFunctionValidation(self):
- """)
+"""
+ )
- with open(sanitize(endpoint, '?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=1.1.0'), 'wb') as f:
- f.write(b"""
+ with open(
+ sanitize(endpoint, "?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=1.1.0"),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
@@ -2540,10 +3330,15 @@ def testFunctionValidation(self):
- """)
+"""
+ )
- with open(sanitize(endpoint, '?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=2.0.0'), 'wb') as f:
- f.write(b"""
+ with open(
+ sanitize(endpoint, "?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=2.0.0"),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
@@ -2594,7 +3389,8 @@ def testFunctionValidation(self):
- """)
+"""
+ )
schema = """
@@ -2612,84 +3408,144 @@ def testFunctionValidation(self):
"""
- with open(sanitize(endpoint, '?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=1.0.0&TYPENAME=my:typename'),
- 'wb') as f:
- f.write(schema.encode('UTF-8'))
- with open(sanitize(endpoint, '?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=1.1.0&TYPENAME=my:typename'),
- 'wb') as f:
- f.write(schema.encode('UTF-8'))
- with open(sanitize(endpoint,
- '?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAMES=my:typename&TYPENAME=my:typename'),
- 'wb') as f:
- f.write(schema.encode('UTF-8'))
+ with open(
+ sanitize(
+ endpoint,
+ "?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=1.0.0&TYPENAME=my:typename",
+ ),
+ "wb",
+ ) as f:
+ f.write(schema.encode("UTF-8"))
+ with open(
+ sanitize(
+ endpoint,
+ "?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=1.1.0&TYPENAME=my:typename",
+ ),
+ "wb",
+ ) as f:
+ f.write(schema.encode("UTF-8"))
+ with open(
+ sanitize(
+ endpoint,
+ "?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAMES=my:typename&TYPENAME=my:typename",
+ ),
+ "wb",
+ ) as f:
+ f.write(schema.encode("UTF-8"))
# Existing function and validation enabled
vl = QgsVectorLayer(
- "url='http://" + endpoint + "' typename='my:typename' version='1.0.0' validateSQLFunctions=1 sql=SELECT * FROM \"my:typename\" WHERE abs(\"my:typename\".id) > 1",
- 'test', 'WFS')
+ "url='http://"
+ + endpoint
+ + "' typename='my:typename' version='1.0.0' validateSQLFunctions=1 sql=SELECT * FROM \"my:typename\" WHERE abs(\"my:typename\".id) > 1",
+ "test",
+ "WFS",
+ )
self.assertTrue(vl.isValid())
# Existing spatial predicated and validation enabled
vl = QgsVectorLayer(
- "url='http://" + endpoint + "' typename='my:typename' version='1.0.0' validateSQLFunctions=1 sql=SELECT * FROM \"my:typename\" WHERE ST_Intersects(geom, geom)",
- 'test', 'WFS')
+ "url='http://"
+ + endpoint
+ + "' typename='my:typename' version='1.0.0' validateSQLFunctions=1 sql=SELECT * FROM \"my:typename\" WHERE ST_Intersects(geom, geom)",
+ "test",
+ "WFS",
+ )
self.assertTrue(vl.isValid())
# Non existing function and validation enabled
vl = QgsVectorLayer(
- "url='http://" + endpoint + "' typename='my:typename' version='1.0.0' validateSQLFunctions=1 sql=SELECT * FROM \"my:typename\" WHERE non_existing(\"my:typename\".id) > 1",
- 'test', 'WFS')
+ "url='http://"
+ + endpoint
+ + "' typename='my:typename' version='1.0.0' validateSQLFunctions=1 sql=SELECT * FROM \"my:typename\" WHERE non_existing(\"my:typename\".id) > 1",
+ "test",
+ "WFS",
+ )
self.assertFalse(vl.isValid())
# Non existing function, but validation disabled
vl = QgsVectorLayer(
- "url='http://" + endpoint + "' typename='my:typename' version='1.0.0' sql=SELECT * FROM \"my:typename\" WHERE non_existing(\"my:typename\".id) > 1",
- 'test', 'WFS')
+ "url='http://"
+ + endpoint
+ + "' typename='my:typename' version='1.0.0' sql=SELECT * FROM \"my:typename\" WHERE non_existing(\"my:typename\".id) > 1",
+ "test",
+ "WFS",
+ )
self.assertTrue(vl.isValid())
# Existing function and validation enabled
vl = QgsVectorLayer(
- "url='http://" + endpoint + "' typename='my:typename' version='1.1.0' skipInitialGetFeature='true' validateSQLFunctions=1 sql=SELECT * FROM \"my:typename\" WHERE abs(\"my:typename\".id) > 1",
- 'test', 'WFS')
+ "url='http://"
+ + endpoint
+ + "' typename='my:typename' version='1.1.0' skipInitialGetFeature='true' validateSQLFunctions=1 sql=SELECT * FROM \"my:typename\" WHERE abs(\"my:typename\".id) > 1",
+ "test",
+ "WFS",
+ )
self.assertTrue(vl.isValid())
# Existing spatial predicated and validation enabled
vl = QgsVectorLayer(
- "url='http://" + endpoint + "' typename='my:typename' version='1.1.0' skipInitialGetFeature='true' validateSQLFunctions=1 sql=SELECT * FROM \"my:typename\" WHERE ST_Intersects(geom, geom)",
- 'test', 'WFS')
+ "url='http://"
+ + endpoint
+ + "' typename='my:typename' version='1.1.0' skipInitialGetFeature='true' validateSQLFunctions=1 sql=SELECT * FROM \"my:typename\" WHERE ST_Intersects(geom, geom)",
+ "test",
+ "WFS",
+ )
self.assertTrue(vl.isValid())
# Non existing function and validation enabled
vl = QgsVectorLayer(
- "url='http://" + endpoint + "' typename='my:typename' version='1.1.0' skipInitialGetFeature='true' validateSQLFunctions=1 sql=SELECT * FROM \"my:typename\" WHERE non_existing(\"my:typename\".id) > 1",
- 'test', 'WFS')
+ "url='http://"
+ + endpoint
+ + "' typename='my:typename' version='1.1.0' skipInitialGetFeature='true' validateSQLFunctions=1 sql=SELECT * FROM \"my:typename\" WHERE non_existing(\"my:typename\".id) > 1",
+ "test",
+ "WFS",
+ )
self.assertFalse(vl.isValid())
# Existing function and validation enabled
vl = QgsVectorLayer(
- "url='http://" + endpoint + "' typename='my:typename' version='2.0.0' skipInitialGetFeature='true' validateSQLFunctions=1 sql=SELECT * FROM \"my:typename\" WHERE abs(\"my:typename\".id) > 1",
- 'test', 'WFS')
+ "url='http://"
+ + endpoint
+ + "' typename='my:typename' version='2.0.0' skipInitialGetFeature='true' validateSQLFunctions=1 sql=SELECT * FROM \"my:typename\" WHERE abs(\"my:typename\".id) > 1",
+ "test",
+ "WFS",
+ )
self.assertTrue(vl.isValid())
# Existing spatial predicated and validation enabled
vl = QgsVectorLayer(
- "url='http://" + endpoint + "' typename='my:typename' version='2.0.0' skipInitialGetFeature='true' validateSQLFunctions=1 sql=SELECT * FROM \"my:typename\" WHERE ST_Intersects(geom, geom)",
- 'test', 'WFS')
+ "url='http://"
+ + endpoint
+ + "' typename='my:typename' version='2.0.0' skipInitialGetFeature='true' validateSQLFunctions=1 sql=SELECT * FROM \"my:typename\" WHERE ST_Intersects(geom, geom)",
+ "test",
+ "WFS",
+ )
self.assertTrue(vl.isValid())
# Non existing function and validation enabled
vl = QgsVectorLayer(
- "url='http://" + endpoint + "' typename='my:typename' version='2.0.0' skipInitialGetFeature='true' validateSQLFunctions=1 sql=SELECT * FROM \"my:typename\" WHERE non_existing(\"my:typename\".id) > 1",
- 'test', 'WFS')
+ "url='http://"
+ + endpoint
+ + "' typename='my:typename' version='2.0.0' skipInitialGetFeature='true' validateSQLFunctions=1 sql=SELECT * FROM \"my:typename\" WHERE non_existing(\"my:typename\".id) > 1",
+ "test",
+ "WFS",
+ )
self.assertFalse(vl.isValid())
def testSelectDistinct(self):
- """Test SELECT DISTINCT """
+ """Test SELECT DISTINCT"""
- endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_select_distinct'
+ endpoint = (
+ self.__class__.basetestpath + "/fake_qgis_http_endpoint_select_distinct"
+ )
- with open(sanitize(endpoint, '?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=2.0.0'), 'wb') as f:
- f.write(b"""
+ with open(
+ sanitize(endpoint, "?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=2.0.0"),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
@@ -2703,12 +3559,18 @@ def testSelectDistinct(self):
- """)
+"""
+ )
- with open(sanitize(endpoint,
- '?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAMES=my:typename&TYPENAME=my:typename'),
- 'wb') as f:
- f.write(b"""
+ with open(
+ sanitize(
+ endpoint,
+ "?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAMES=my:typename&TYPENAME=my:typename",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
@@ -2725,12 +3587,18 @@ def testSelectDistinct(self):
-""")
+"""
+ )
- with open(sanitize(endpoint,
- """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&SRSNAME=urn:ogc:def:crs:EPSG::4326"""),
- 'wb') as f:
- f.write(b"""
+ with open(
+ sanitize(
+ endpoint,
+ """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&SRSNAME=urn:ogc:def:crs:EPSG::4326""",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
2016-04-10T12:34:56.788Z
- """)
+"""
+ )
vl = QgsVectorLayer(
- "url='http://" + endpoint + "' typename='my:typename' version='2.0.0' skipInitialGetFeature='true' sql=SELECT DISTINCT * FROM \"my:typename\"",
- 'test', 'WFS')
+ "url='http://"
+ + endpoint
+ + "' typename='my:typename' version='2.0.0' skipInitialGetFeature='true' sql=SELECT DISTINCT * FROM \"my:typename\"",
+ "test",
+ "WFS",
+ )
self.assertTrue(vl.isValid())
- values = [(f['intfield'], f['longfield'], f['stringfield'], f['datetimefield']) for f in vl.getFeatures()]
- self.assertEqual(values, [(1, 1234567890, 'foo', QDateTime(QDate(2016, 4, 10), QTime(12, 34, 56, 789), Qt.TimeSpec(Qt.TimeSpec.UTC))),
- (2, 1234567890, 'foo', QDateTime(QDate(2016, 4, 10), QTime(12, 34, 56, 789), Qt.TimeSpec(Qt.TimeSpec.UTC))),
- (1, 1234567891, 'foo', QDateTime(QDate(2016, 4, 10), QTime(12, 34, 56, 789), Qt.TimeSpec(Qt.TimeSpec.UTC))),
- (1, 1234567890, 'fop', QDateTime(QDate(2016, 4, 10), QTime(12, 34, 56, 789), Qt.TimeSpec(Qt.TimeSpec.UTC))),
- (1, 1234567890, 'foo', QDateTime(QDate(2016, 4, 10), QTime(12, 34, 56, 788), Qt.TimeSpec(Qt.TimeSpec.UTC)))])
+ values = [
+ (f["intfield"], f["longfield"], f["stringfield"], f["datetimefield"])
+ for f in vl.getFeatures()
+ ]
+ self.assertEqual(
+ values,
+ [
+ (
+ 1,
+ 1234567890,
+ "foo",
+ QDateTime(
+ QDate(2016, 4, 10),
+ QTime(12, 34, 56, 789),
+ Qt.TimeSpec(Qt.TimeSpec.UTC),
+ ),
+ ),
+ (
+ 2,
+ 1234567890,
+ "foo",
+ QDateTime(
+ QDate(2016, 4, 10),
+ QTime(12, 34, 56, 789),
+ Qt.TimeSpec(Qt.TimeSpec.UTC),
+ ),
+ ),
+ (
+ 1,
+ 1234567891,
+ "foo",
+ QDateTime(
+ QDate(2016, 4, 10),
+ QTime(12, 34, 56, 789),
+ Qt.TimeSpec(Qt.TimeSpec.UTC),
+ ),
+ ),
+ (
+ 1,
+ 1234567890,
+ "fop",
+ QDateTime(
+ QDate(2016, 4, 10),
+ QTime(12, 34, 56, 789),
+ Qt.TimeSpec(Qt.TimeSpec.UTC),
+ ),
+ ),
+ (
+ 1,
+ 1234567890,
+ "foo",
+ QDateTime(
+ QDate(2016, 4, 10),
+ QTime(12, 34, 56, 788),
+ Qt.TimeSpec(Qt.TimeSpec.UTC),
+ ),
+ ),
+ ],
+ )
vl = QgsVectorLayer(
- "url='http://" + endpoint + "' typename='my:typename' version='2.0.0' skipInitialGetFeature='true' sql=SELECT DISTINCT intfield FROM \"my:typename\"",
- 'test', 'WFS')
+ "url='http://"
+ + endpoint
+ + "' typename='my:typename' version='2.0.0' skipInitialGetFeature='true' sql=SELECT DISTINCT intfield FROM \"my:typename\"",
+ "test",
+ "WFS",
+ )
self.assertTrue(vl.isValid())
- values = [(f['intfield']) for f in vl.getFeatures()]
+ values = [(f["intfield"]) for f in vl.getFeatures()]
self.assertEqual(values, [(1), (2)])
def testWrongCapabilityExtent(self):
@@ -2811,10 +3741,17 @@ def testWrongCapabilityExtent(self):
# Note the logic that is tested is purely heuristic, trying to recover from wrong server behavior,
# so it might be legitimate to change that at a later point.
- endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_wrong_capability_extent'
+ endpoint = (
+ self.__class__.basetestpath
+ + "/fake_qgis_http_endpoint_wrong_capability_extent"
+ )
- with open(sanitize(endpoint, '?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=2.0.0'), 'wb') as f:
- f.write(b"""
+ with open(
+ sanitize(endpoint, "?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=2.0.0"),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
@@ -2828,12 +3765,18 @@ def testWrongCapabilityExtent(self):
- """)
+"""
+ )
- with open(sanitize(endpoint,
- '?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAMES=my:typename&TYPENAME=my:typename'),
- 'wb') as f:
- f.write(b"""
+ with open(
+ sanitize(
+ endpoint,
+ "?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAMES=my:typename&TYPENAME=my:typename",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
@@ -2848,12 +3791,18 @@ def testWrongCapabilityExtent(self):
-""")
+"""
+ )
- with open(sanitize(endpoint,
- """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&SRSNAME=urn:ogc:def:crs:EPSG::4326"""),
- 'wb') as f:
- f.write(b"""
+ with open(
+ sanitize(
+ endpoint,
+ """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&SRSNAME=urn:ogc:def:crs:EPSG::4326""",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
49 2
- """)
+"""
+ )
- vl = QgsVectorLayer("url='http://" + endpoint + "' typename='my:typename' version='2.0.0' skipInitialGetFeature='true'", 'test', 'WFS')
+ vl = QgsVectorLayer(
+ "url='http://"
+ + endpoint
+ + "' typename='my:typename' version='2.0.0' skipInitialGetFeature='true'",
+ "test",
+ "WFS",
+ )
self.assertTrue(vl.isValid())
# Download all features
@@ -2875,31 +3831,47 @@ def testWrongCapabilityExtent(self):
reference = QgsGeometry.fromRect(QgsRectangle(2, 49, 2, 49))
vl_extent = QgsGeometry.fromRect(vl.extent())
- assert QgsGeometry.compare(vl_extent.asPolygon()[0], reference.asPolygon()[0],
- 0.00001), f'Expected {reference.asWkt()}, got {vl_extent.asWkt()}'
+ assert QgsGeometry.compare(
+ vl_extent.asPolygon()[0], reference.asPolygon()[0], 0.00001
+ ), f"Expected {reference.asWkt()}, got {vl_extent.asWkt()}"
# Same with restrictToRequestBBOX=1
vl = QgsVectorLayer(
- "url='http://" + endpoint + "' typename='my:typename' version='2.0.0' restrictToRequestBBOX=1 skipInitialGetFeature='true'", 'test',
- 'WFS')
+ "url='http://"
+ + endpoint
+ + "' typename='my:typename' version='2.0.0' restrictToRequestBBOX=1 skipInitialGetFeature='true'",
+ "test",
+ "WFS",
+ )
self.assertTrue(vl.isValid())
# First request that will be attempted
- with open(sanitize(endpoint,
- """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&SRSNAME=urn:ogc:def:crs:EPSG::4326&BBOX=-0.125,-0.125,1.125,1.125,urn:ogc:def:crs:EPSG::4326"""),
- 'wb') as f:
- f.write(b"""
+ with open(
+ sanitize(
+ endpoint,
+ """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&SRSNAME=urn:ogc:def:crs:EPSG::4326&BBOX=-0.125,-0.125,1.125,1.125,urn:ogc:def:crs:EPSG::4326""",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
- """)
+"""
+ )
# And fallback
- with open(sanitize(endpoint,
- """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&COUNT=1"""),
- 'wb') as f:
- f.write(b"""
+ with open(
+ sanitize(
+ endpoint,
+ """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&COUNT=1""",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
49 2
- """)
+"""
+ )
# Download all features in a BBOX that encloses the extent reported by capabilities
extent = QgsRectangle(-0.125, -0.125, 1.125, 1.125)
@@ -2924,10 +3897,14 @@ def testWrongCapabilityExtent(self):
def testGeomedia(self):
"""Test various interoperability specifities that occur with Geomedia Web Server."""
- endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_geomedia'
+ endpoint = self.__class__.basetestpath + "/fake_qgis_http_endpoint_geomedia"
- with open(sanitize(endpoint, '?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=2.0.0'), 'wb') as f:
- f.write(b"""
+ with open(
+ sanitize(endpoint, "?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=2.0.0"),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
@@ -2947,12 +3924,18 @@ def testGeomedia(self):
- """)
+"""
+ )
- with open(sanitize(endpoint,
- '?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAMES=my:typename&TYPENAME=my:typename'),
- 'wb') as f:
- f.write(b"""
+ with open(
+ sanitize(
+ endpoint,
+ "?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAMES=my:typename&TYPENAME=my:typename",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
@@ -2967,12 +3950,18 @@ def testGeomedia(self):
-""")
+"""
+ )
- with open(sanitize(endpoint,
- """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&STARTINDEX=0&COUNT=1&SRSNAME=EPSG:32631"""),
- 'wb') as f:
- f.write(b"""
+ with open(
+ sanitize(
+ endpoint,
+ """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&STARTINDEX=0&COUNT=1&SRSNAME=EPSG:32631""",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
500000 4500000 500000 4510000 510000 4510000 510000 4500000 500000 4500000
- """)
+"""
+ )
# Simulate improper paging support by returning same result set whatever the STARTINDEX is
- with open(sanitize(endpoint,
- """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&STARTINDEX=1&COUNT=1&SRSNAME=EPSG:32631"""),
- 'wb') as f:
- f.write(b"""
+ with open(
+ sanitize(
+ endpoint,
+ """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&STARTINDEX=1&COUNT=1&SRSNAME=EPSG:32631""",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
500000 4500000 500000 4510000 510000 4510000 510000 4500000 500000 4500000
- """)
+"""
+ )
- with open(sanitize(endpoint,
- """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&SRSNAME=EPSG:32631"""),
- 'wb') as f:
- f.write(b"""
+ with open(
+ sanitize(
+ endpoint,
+ """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&SRSNAME=EPSG:32631""",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
500000 4500000 500000 4510000 510000 4510000 510000 4500000 500000 4500000
- """)
+"""
+ )
- QgsSettings().setValue('wfs/max_feature_count_if_not_provided', '1')
+ QgsSettings().setValue("wfs/max_feature_count_if_not_provided", "1")
- vl = QgsVectorLayer("url='http://" + endpoint + "' typename='my:typename' version='2.0.0' skipInitialGetFeature='true'", 'test', 'WFS')
+ vl = QgsVectorLayer(
+ "url='http://"
+ + endpoint
+ + "' typename='my:typename' version='2.0.0' skipInitialGetFeature='true'",
+ "test",
+ "WFS",
+ )
self.assertTrue(vl.isValid())
self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.MultiPolygon)
# Extent before downloading features
reference = QgsGeometry.fromRect(
- QgsRectangle(243900.3520259926444851, 4427769.1559739429503679, 1525592.3040170343592763,
- 5607994.6020106188952923))
+ QgsRectangle(
+ 243900.3520259926444851,
+ 4427769.1559739429503679,
+ 1525592.3040170343592763,
+ 5607994.6020106188952923,
+ )
+ )
vl_extent = QgsGeometry.fromRect(vl.extent())
- assert QgsGeometry.compare(vl_extent.asPolygon()[0], reference.asPolygon()[0],
- 0.05), f'Expected {reference.asWkt()}, got {vl_extent.asWkt()}'
+ assert QgsGeometry.compare(
+ vl_extent.asPolygon()[0], reference.asPolygon()[0], 0.05
+ ), f"Expected {reference.asWkt()}, got {vl_extent.asWkt()}"
# Download all features
features = [f for f in vl.getFeatures()]
@@ -3045,18 +4059,25 @@ def testGeomedia(self):
loop = QEventLoop()
loop.processEvents()
vl_extent = QgsGeometry.fromRect(vl.extent())
- assert QgsGeometry.compare(vl_extent.asPolygon()[0], reference.asPolygon()[0],
- 0.00001), f'Expected {reference.asWkt()}, got {vl_extent.asWkt()}'
- self.assertEqual(features[0]['intfield'], 1)
- self.assertEqual(features[1]['intfield'], 2)
+ assert QgsGeometry.compare(
+ vl_extent.asPolygon()[0], reference.asPolygon()[0], 0.00001
+ ), f"Expected {reference.asWkt()}, got {vl_extent.asWkt()}"
+ self.assertEqual(features[0]["intfield"], 1)
+ self.assertEqual(features[1]["intfield"], 2)
def testMapServerWFS1_1_EPSG_4326(self):
"""Test interoperability with MapServer WFS 1.1."""
- endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_mapserver_wfs_1_1'
+ endpoint = (
+ self.__class__.basetestpath + "/fake_qgis_http_endpoint_mapserver_wfs_1_1"
+ )
- with open(sanitize(endpoint, '?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=1.1.0'), 'wb') as f:
- f.write(b"""
+ with open(
+ sanitize(endpoint, "?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=1.1.0"),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
@@ -3070,11 +4091,18 @@ def testMapServerWFS1_1_EPSG_4326(self):
- """)
+"""
+ )
- with open(sanitize(endpoint, '?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=1.1.0&TYPENAME=my:typename'),
- 'wb') as f:
- f.write(b"""
+ with open(
+ sanitize(
+ endpoint,
+ "?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=1.1.0&TYPENAME=my:typename",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
-""")
+"""
+ )
- with open(sanitize(endpoint,
- """?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.1.0&TYPENAME=my:typename&SRSNAME=urn:ogc:def:crs:EPSG::4326"""),
- 'wb') as f:
- f.write(b"""
+ with open(
+ sanitize(
+ endpoint,
+ """?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.1.0&TYPENAME=my:typename&SRSNAME=urn:ogc:def:crs:EPSG::4326""",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
-""")
+"""
+ )
- vl = QgsVectorLayer("url='http://" + endpoint + "' typename='my:typename' version='1.1.0' skipInitialGetFeature='true'", 'test', 'WFS')
+ vl = QgsVectorLayer(
+ "url='http://"
+ + endpoint
+ + "' typename='my:typename' version='1.1.0' skipInitialGetFeature='true'",
+ "test",
+ "WFS",
+ )
self.assertTrue(vl.isValid())
got_f = [f for f in vl.getFeatures()]
@@ -3144,10 +4185,17 @@ def testMapServerWFS1_1_EPSG_4326(self):
def testDescribeFeatureTypeWithInlineType(self):
"""Test a DescribeFeatureType response with a inline ComplexType (#15395)."""
- endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_testDescribeFeatureTypeWithInlineType'
+ endpoint = (
+ self.__class__.basetestpath
+ + "/fake_qgis_http_endpoint_testDescribeFeatureTypeWithInlineType"
+ )
- with open(sanitize(endpoint, '?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=1.1.0'), 'wb') as f:
- f.write(b"""
+ with open(
+ sanitize(endpoint, "?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=1.1.0"),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
@@ -3161,11 +4209,18 @@ def testDescribeFeatureTypeWithInlineType(self):
- """)
+"""
+ )
- with open(sanitize(endpoint, '?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=1.1.0&TYPENAME=my:typename'),
- 'wb') as f:
- f.write(b"""
+ with open(
+ sanitize(
+ endpoint,
+ "?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=1.1.0&TYPENAME=my:typename",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
-""")
+"""
+ )
- with open(sanitize(endpoint,
- """?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.1.0&TYPENAME=my:typename&SRSNAME=urn:ogc:def:crs:EPSG::4326"""),
- 'wb') as f:
- f.write(b"""
+ with open(
+ sanitize(
+ endpoint,
+ """?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.1.0&TYPENAME=my:typename&SRSNAME=urn:ogc:def:crs:EPSG::4326""",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
-""")
-
- shutil.copyfile(sanitize(endpoint,
- """?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.1.0&TYPENAME=my:typename&SRSNAME=urn:ogc:def:crs:EPSG::4326"""),
- sanitize(endpoint,
- """?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.1.0&TYPENAME=my:typename&MAXFEATURES=1&SRSNAME=urn:ogc:def:crs:EPSG::4326"""))
+"""
+ )
+
+ shutil.copyfile(
+ sanitize(
+ endpoint,
+ """?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.1.0&TYPENAME=my:typename&SRSNAME=urn:ogc:def:crs:EPSG::4326""",
+ ),
+ sanitize(
+ endpoint,
+ """?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.1.0&TYPENAME=my:typename&MAXFEATURES=1&SRSNAME=urn:ogc:def:crs:EPSG::4326""",
+ ),
+ )
- vl = QgsVectorLayer("url='http://" + endpoint + "' typename='my:typename' version='1.1.0' skipInitialGetFeature='true'", 'test', 'WFS')
+ vl = QgsVectorLayer(
+ "url='http://"
+ + endpoint
+ + "' typename='my:typename' version='1.1.0' skipInitialGetFeature='true'",
+ "test",
+ "WFS",
+ )
self.assertTrue(vl.isValid())
got_f = [f for f in vl.getFeatures()]
@@ -3240,11 +4314,20 @@ def testDescribeFeatureTypeWithInlineType(self):
def testWFS20TransactionsDisabled(self):
"""Test WFS 2.0 Transaction disabled"""
- endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_WFS_2.0_transaction_disabled'
+ endpoint = (
+ self.__class__.basetestpath
+ + "/fake_qgis_http_endpoint_WFS_2.0_transaction_disabled"
+ )
- with open(sanitize(endpoint, '?SERVICE=WFS?REQUEST=GetCapabilities?ACCEPTVERSIONS=2.0.0,1.1.0,1.0.0'),
- 'wb') as f:
- f.write(b"""
+ with open(
+ sanitize(
+ endpoint,
+ "?SERVICE=WFS?REQUEST=GetCapabilities?ACCEPTVERSIONS=2.0.0,1.1.0,1.0.0",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
@@ -3270,12 +4353,18 @@ def testWFS20TransactionsDisabled(self):
- """)
+"""
+ )
- with open(sanitize(endpoint,
- '?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAMES=my:typename&TYPENAME=my:typename'),
- 'wb') as f:
- f.write(b"""
+ with open(
+ sanitize(
+ endpoint,
+ "?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAMES=my:typename&TYPENAME=my:typename",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
@@ -3289,23 +4378,41 @@ def testWFS20TransactionsDisabled(self):
-""")
+"""
+ )
# Create test layer
- vl = QgsVectorLayer("url='http://" + endpoint + "' typename='my:typename' skipInitialGetFeature='true'", 'test', 'WFS')
+ vl = QgsVectorLayer(
+ "url='http://"
+ + endpoint
+ + "' typename='my:typename' skipInitialGetFeature='true'",
+ "test",
+ "WFS",
+ )
self.assertTrue(vl.isValid())
- self.assertEqual(vl.dataProvider().capabilities() & vl.dataProvider().EditingCapabilities,
- vl.dataProvider().NoCapabilities)
+ self.assertEqual(
+ vl.dataProvider().capabilities() & vl.dataProvider().EditingCapabilities,
+ vl.dataProvider().NoCapabilities,
+ )
self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.Point)
def testWFS20TransactionsEnabled(self):
"""Test WFS 2.0 Transaction enabled"""
- endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_WFS_2.0_transaction_enabled'
+ endpoint = (
+ self.__class__.basetestpath
+ + "/fake_qgis_http_endpoint_WFS_2.0_transaction_enabled"
+ )
- with open(sanitize(endpoint, '?SERVICE=WFS?REQUEST=GetCapabilities?ACCEPTVERSIONS=2.0.0,1.1.0,1.0.0'),
- 'wb') as f:
- f.write("""
+ with open(
+ sanitize(
+ endpoint,
+ "?SERVICE=WFS?REQUEST=GetCapabilities?ACCEPTVERSIONS=2.0.0,1.1.0,1.0.0",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ """
@@ -3350,12 +4457,22 @@ def testWFS20TransactionsEnabled(self):
- """.format(endpoint=endpoint).encode('UTF-8'))
+""".format(
+ endpoint=endpoint
+ ).encode(
+ "UTF-8"
+ )
+ )
- with open(sanitize(endpoint,
- '?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAMES=my:typename&TYPENAME=my:typename'),
- 'wb') as f:
- f.write(b"""
+ with open(
+ sanitize(
+ endpoint,
+ "?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAMES=my:typename&TYPENAME=my:typename",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
@@ -3373,22 +4490,37 @@ def testWFS20TransactionsEnabled(self):
-""")
+"""
+ )
# Create test layer
- vl = QgsVectorLayer("url='http://" + endpoint + "' typename='my:typename' skipInitialGetFeature='true'", 'test', 'WFS')
+ vl = QgsVectorLayer(
+ "url='http://"
+ + endpoint
+ + "' typename='my:typename' skipInitialGetFeature='true'",
+ "test",
+ "WFS",
+ )
self.assertTrue(vl.isValid())
- self.assertNotEqual(vl.dataProvider().capabilities() & vl.dataProvider().EditingCapabilities,
- vl.dataProvider().NoCapabilities)
+ self.assertNotEqual(
+ vl.dataProvider().capabilities() & vl.dataProvider().EditingCapabilities,
+ vl.dataProvider().NoCapabilities,
+ )
self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.Point)
def testDeprecatedGML2GeometryDeclaration(self):
"""Test ref="gml:pointProperty" """
- endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_deprecated_gml2'
+ endpoint = (
+ self.__class__.basetestpath + "/fake_qgis_http_endpoint_deprecated_gml2"
+ )
- with open(sanitize(endpoint, '?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=1.0.0'), 'wb') as f:
- f.write(b"""
+ with open(
+ sanitize(endpoint, "?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=1.0.0"),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
@@ -3400,11 +4532,18 @@ def testDeprecatedGML2GeometryDeclaration(self):
- """)
+"""
+ )
- with open(sanitize(endpoint, '?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=1.0.0&TYPENAME=my:typename'),
- 'wb') as f:
- f.write(b"""
+ with open(
+ sanitize(
+ endpoint,
+ "?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=1.0.0&TYPENAME=my:typename",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
@@ -3419,17 +4558,27 @@ def testDeprecatedGML2GeometryDeclaration(self):
-""")
+"""
+ )
- vl = QgsVectorLayer("url='http://" + endpoint + "' typename='my:typename' version='1.0.0'", 'test', 'WFS')
+ vl = QgsVectorLayer(
+ "url='http://" + endpoint + "' typename='my:typename' version='1.0.0'",
+ "test",
+ "WFS",
+ )
self.assertTrue(vl.isValid())
self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.Point)
self.assertEqual(len(vl.fields()), 1)
with open(
- sanitize(endpoint, '?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.0.0&TYPENAME=my:typename&SRSNAME=EPSG:32631'),
- 'wb') as f:
- f.write(b"""
+ sanitize(
+ endpoint,
+ "?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.0.0&TYPENAME=my:typename&SRSNAME=EPSG:32631",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
1
- """)
+"""
+ )
- values = [f['INTFIELD'] for f in vl.getFeatures()]
+ values = [f["INTFIELD"] for f in vl.getFeatures()]
self.assertEqual(values, [1])
got_f = [f for f in vl.getFeatures()]
@@ -3453,12 +4603,19 @@ def testDeprecatedGML2GeometryDeclaration(self):
self.assertEqual((got.x(), got.y()), (426858.0, 5427937.0))
def testGetFeatureWithNamespaces(self):
- ''' test https://github.com/qgis/QGIS/issues/22649 '''
+ """test https://github.com/qgis/QGIS/issues/22649"""
- endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_getfeature_with_namespaces'
+ endpoint = (
+ self.__class__.basetestpath
+ + "/fake_qgis_http_endpoint_getfeature_with_namespaces"
+ )
- with open(sanitize(endpoint, '?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=2.0.0'), 'wb') as f:
- f.write(b"""
+ with open(
+ sanitize(endpoint, "?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=2.0.0"),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
@@ -3472,12 +4629,18 @@ def testGetFeatureWithNamespaces(self):
- """)
+"""
+ )
- with open(sanitize(endpoint,
- '?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAMES=my:typename&NAMESPACES=xmlns(my,http://my)&TYPENAME=my:typename&NAMESPACE=xmlns(my,http://my)'),
- 'wb') as f:
- f.write(b"""
+ with open(
+ sanitize(
+ endpoint,
+ "?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAMES=my:typename&NAMESPACES=xmlns(my,http://my)&TYPENAME=my:typename&NAMESPACE=xmlns(my,http://my)",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
@@ -3491,16 +4654,28 @@ def testGetFeatureWithNamespaces(self):
-""")
+"""
+ )
- vl = QgsVectorLayer("url='http://" + endpoint + "' typename='my:typename' version='2.0.0' skipInitialGetFeature='true'", 'test', 'WFS')
+ vl = QgsVectorLayer(
+ "url='http://"
+ + endpoint
+ + "' typename='my:typename' version='2.0.0' skipInitialGetFeature='true'",
+ "test",
+ "WFS",
+ )
self.assertTrue(vl.isValid())
self.assertEqual(len(vl.fields()), 1)
- with open(sanitize(endpoint,
- '?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&SRSNAME=urn:ogc:def:crs:EPSG::32631&NAMESPACES=xmlns(my,http://my)&NAMESPACE=xmlns(my,http://my)'),
- 'wb') as f:
- f.write(b"""
+ with open(
+ sanitize(
+ endpoint,
+ "?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&SRSNAME=urn:ogc:def:crs:EPSG::32631&NAMESPACES=xmlns(my,http://my)&NAMESPACE=xmlns(my,http://my)",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
1
- """)
+"""
+ )
- values = [f['intfield'] for f in vl.getFeatures()]
+ values = [f["intfield"] for f in vl.getFeatures()]
self.assertEqual(values, [1])
def testGetFeatureWithNamespaceAndFilter(self):
- ''' test https://github.com/qgis/QGIS/issues/43957 '''
+ """test https://github.com/qgis/QGIS/issues/43957"""
- endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_getfeature_with_namespace_and_filter'
+ endpoint = (
+ self.__class__.basetestpath
+ + "/fake_qgis_http_endpoint_getfeature_with_namespace_and_filter"
+ )
- with open(sanitize(endpoint, '?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=2.0.0'), 'wb') as f:
- f.write(b"""
+ with open(
+ sanitize(endpoint, "?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=2.0.0"),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
@@ -3535,12 +4718,18 @@ def testGetFeatureWithNamespaceAndFilter(self):
- """)
+"""
+ )
- with open(sanitize(endpoint,
- '?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAMES=my:typename&NAMESPACES=xmlns(my,http://my)&TYPENAME=my:typename&NAMESPACE=xmlns(my,http://my)'),
- 'wb') as f:
- f.write(b"""
+ with open(
+ sanitize(
+ endpoint,
+ "?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAMES=my:typename&NAMESPACES=xmlns(my,http://my)&TYPENAME=my:typename&NAMESPACE=xmlns(my,http://my)",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
@@ -3555,23 +4744,35 @@ def testGetFeatureWithNamespaceAndFilter(self):
-""")
+"""
+ )
# SQL query with type with namespace
- vl = QgsVectorLayer("url='http://" + endpoint + "' typename='my:typename' version='2.0.0' skipInitialGetFeature='true' sql=SELECT * FROM \"my:typename\" WHERE intfield = 1", 'test', 'WFS')
+ vl = QgsVectorLayer(
+ "url='http://"
+ + endpoint
+ + "' typename='my:typename' version='2.0.0' skipInitialGetFeature='true' sql=SELECT * FROM \"my:typename\" WHERE intfield = 1",
+ "test",
+ "WFS",
+ )
self.assertTrue(vl.isValid())
self.assertEqual(len(vl.fields()), 1)
- with open(sanitize(endpoint,
- """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&SRSNAME=urn:ogc:def:crs:EPSG::32631&FILTER=
+ with open(
+ sanitize(
+ endpoint,
+ """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&SRSNAME=urn:ogc:def:crs:EPSG::32631&FILTER=
my:intfield
1
-&NAMESPACES=xmlns(my,http://my)&NAMESPACE=xmlns(my,http://my)"""),
- 'wb') as f:
- f.write(b"""
+&NAMESPACES=xmlns(my,http://my)&NAMESPACE=xmlns(my,http://my)""",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
1
- """)
+"""
+ )
- values = [f['intfield'] for f in vl.getFeatures()]
+ values = [f["intfield"] for f in vl.getFeatures()]
self.assertEqual(values, [1])
# SQL query with type with namespace and bounding box
vl = QgsVectorLayer(
- "url='http://" + endpoint + "' typename='my:typename' version='2.0.0' skipInitialGetFeature='true' restrictToRequestBBOX=1 sql=SELECT * FROM \"my:typename\" WHERE intfield > 0", 'test',
- 'WFS')
+ "url='http://"
+ + endpoint
+ + "' typename='my:typename' version='2.0.0' skipInitialGetFeature='true' restrictToRequestBBOX=1 sql=SELECT * FROM \"my:typename\" WHERE intfield > 0",
+ "test",
+ "WFS",
+ )
extent = QgsRectangle(400000.0, 5400000.0, 450000.0, 5500000.0)
request = QgsFeatureRequest().setFilterRect(extent)
- if int(QT_VERSION_STR.split('.')[0]) >= 6:
+ if int(QT_VERSION_STR.split(".")[0]) >= 6:
filter_attrs = 'xmlns:fes="http://www.opengis.net/fes/2.0" xmlns:gml="http://www.opengis.net/gml/3.2" xmlns:my="http://my"'
else:
filter_attrs = 'xmlns:gml="http://www.opengis.net/gml/3.2" xmlns:my="http://my" xmlns:fes="http://www.opengis.net/fes/2.0"'
- with open(sanitize(endpoint,
- f"""?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&SRSNAME=urn:ogc:def:crs:EPSG::32631&FILTER=
+ with open(
+ sanitize(
+ endpoint,
+ f"""?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&SRSNAME=urn:ogc:def:crs:EPSG::32631&FILTER=
my:geometryProperty
@@ -3615,9 +4823,12 @@ def testGetFeatureWithNamespaceAndFilter(self):
-&NAMESPACES=xmlns(my,http://my)&NAMESPACE=xmlns(my,http://my)"""),
- 'wb') as f:
- f.write(b"""
+&NAMESPACES=xmlns(my,http://my)&NAMESPACE=xmlns(my,http://my)""",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
1
- """)
+"""
+ )
- values = [f['intfield'] for f in vl.getFeatures(request)]
+ values = [f["intfield"] for f in vl.getFeatures(request)]
self.assertEqual(values, [1])
- vl = QgsVectorLayer("url='http://" + endpoint + "' typename='my:typename' version='2.0.0' restrictToRequestBBOX=1", 'test', 'WFS')
+ vl = QgsVectorLayer(
+ "url='http://"
+ + endpoint
+ + "' typename='my:typename' version='2.0.0' restrictToRequestBBOX=1",
+ "test",
+ "WFS",
+ )
self.assertTrue(vl.isValid())
# Test that properties in subset strings are prefixed and the namespace URI
# is included in the filter
- vl.setSubsetString('intfield = 2')
- with open(sanitize(endpoint,
- f"""?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&SRSNAME=urn:ogc:def:crs:EPSG::32631&FILTER=
+ vl.setSubsetString("intfield = 2")
+ with open(
+ sanitize(
+ endpoint,
+ f"""?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&SRSNAME=urn:ogc:def:crs:EPSG::32631&FILTER=
my:geometryProperty
@@ -3654,9 +4874,12 @@ def testGetFeatureWithNamespaceAndFilter(self):
-&NAMESPACES=xmlns(my,http://my)&NAMESPACE=xmlns(my,http://my)"""),
- 'wb') as f:
- f.write(b"""
+&NAMESPACES=xmlns(my,http://my)&NAMESPACE=xmlns(my,http://my)""",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
2
- """)
+"""
+ )
- values = [f['intfield'] for f in vl.getFeatures(request)]
+ values = [f["intfield"] for f in vl.getFeatures(request)]
self.assertEqual(values, [2])
vl.setSubsetString(None)
def testGetFeatureWithServerExpression(self):
- ''' test binary spatial operation expression on server '''
+ """test binary spatial operation expression on server"""
- endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_getfeature_with_server_expression'
+ endpoint = (
+ self.__class__.basetestpath
+ + "/fake_qgis_http_endpoint_getfeature_with_server_expression"
+ )
- with open(sanitize(endpoint, '?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=2.0.0'), 'wb') as f:
- f.write(b"""
+ with open(
+ sanitize(endpoint, "?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=2.0.0"),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
@@ -3693,12 +4924,18 @@ def testGetFeatureWithServerExpression(self):
- """)
+"""
+ )
- with open(sanitize(endpoint,
- '?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAMES=my:typename&TYPENAME=my:typename'),
- 'wb') as f:
- f.write(b"""
+ with open(
+ sanitize(
+ endpoint,
+ "?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAMES=my:typename&TYPENAME=my:typename",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
@@ -3713,18 +4950,30 @@ def testGetFeatureWithServerExpression(self):
-""")
+"""
+ )
- vl = QgsVectorLayer("url='http://" + endpoint + "' typename='my:typename' skipInitialGetFeature='true' version='2.0.0'", 'test', 'WFS')
+ vl = QgsVectorLayer(
+ "url='http://"
+ + endpoint
+ + "' typename='my:typename' skipInitialGetFeature='true' version='2.0.0'",
+ "test",
+ "WFS",
+ )
self.assertTrue(vl.isValid())
self.assertEqual(len(vl.fields()), 1)
self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.Point)
# Simple test
- with open(sanitize(endpoint,
- '?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&SRSNAME=urn:ogc:def:crs:EPSG::4326'),
- 'wb') as f:
- f.write(b"""
+ with open(
+ sanitize(
+ endpoint,
+ "?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&SRSNAME=urn:ogc:def:crs:EPSG::4326",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
1 1
- """)
+"""
+ )
- values = [f['intfield'] for f in vl.getFeatures()]
+ values = [f["intfield"] for f in vl.getFeatures()]
self.assertEqual(values, [1])
# Get feature according to expression
- vl = QgsVectorLayer("url='http://" + endpoint + "' typename='my:typename' skipInitialGetFeature='true' version='2.0.0'", 'test', 'WFS')
+ vl = QgsVectorLayer(
+ "url='http://"
+ + endpoint
+ + "' typename='my:typename' skipInitialGetFeature='true' version='2.0.0'",
+ "test",
+ "WFS",
+ )
self.assertTrue(vl.isValid())
self.assertEqual(len(vl.fields()), 1)
self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.Point)
parent_feature = QgsFeature()
- parent_feature.setGeometry(QgsGeometry.fromWkt('Polygon ((-20 -20, -20 20, 20 20, 20 -20, -20 -20))'))
+ parent_feature.setGeometry(
+ QgsGeometry.fromWkt("Polygon ((-20 -20, -20 20, 20 20, 20 -20, -20 -20))")
+ )
context = QgsExpressionContext()
context.appendScope(QgsExpressionContextUtils.globalScope())
scope = QgsExpressionContextScope()
- scope.setVariable('parent', parent_feature, True)
+ scope.setVariable("parent", parent_feature, True)
context.appendScope(scope)
request = QgsFeatureRequest()
request.setExpressionContext(context)
request.setFilterExpression("intersects( $geometry, geometry(var('parent')))")
- with open(sanitize(endpoint,
- """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&SRSNAME=urn:ogc:def:crs:EPSG::4326&FILTER=
+ with open(
+ sanitize(
+ endpoint,
+ """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&SRSNAME=urn:ogc:def:crs:EPSG::4326&FILTER=
geometryProperty
@@ -3770,9 +5030,12 @@ def testGetFeatureWithServerExpression(self):
-"""),
- 'wb') as f:
- f.write(b"""
+""",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
1 1
- """)
- values = [f['intfield'] for f in vl.getFeatures(request)]
+"""
+ )
+ values = [f["intfield"] for f in vl.getFeatures(request)]
self.assertEqual(values, [1])
# Get feature according to expression and filter
- vl = QgsVectorLayer("url='http://" + endpoint + "' typename='my:typename' skipInitialGetFeature='true' version='2.0.0' sql=SELECT * FROM \"my:typename\" WHERE intfield = 1", 'test', 'WFS')
+ vl = QgsVectorLayer(
+ "url='http://"
+ + endpoint
+ + "' typename='my:typename' skipInitialGetFeature='true' version='2.0.0' sql=SELECT * FROM \"my:typename\" WHERE intfield = 1",
+ "test",
+ "WFS",
+ )
self.assertTrue(vl.isValid())
self.assertEqual(len(vl.fields()), 1)
self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.Point)
parent_feature = QgsFeature()
- parent_feature.setGeometry(QgsGeometry.fromWkt('Polygon ((-20 -20, -20 20, 20 20, 20 -20, -20 -20))'))
+ parent_feature.setGeometry(
+ QgsGeometry.fromWkt("Polygon ((-20 -20, -20 20, 20 20, 20 -20, -20 -20))")
+ )
scope = QgsExpressionContextScope()
- scope.setVariable('parent', parent_feature, True)
+ scope.setVariable("parent", parent_feature, True)
context = QgsExpressionContext()
context.appendScope(QgsExpressionContextUtils.globalScope())
context.appendScope(scope)
@@ -3804,13 +5076,15 @@ def testGetFeatureWithServerExpression(self):
request.setExpressionContext(context)
request.setFilterExpression("intersects( $geometry, geometry(var('parent')))")
- if int(QT_VERSION_STR.split('.')[0]) >= 6:
+ if int(QT_VERSION_STR.split(".")[0]) >= 6:
polygon_attrs = 'xmlns:gml="http://www.opengis.net/gml/3.2" srsName="urn:ogc:def:crs:EPSG::4326" gml:id="qgis_id_geom_1"'
else:
polygon_attrs = 'xmlns:gml="http://www.opengis.net/gml/3.2" gml:id="qgis_id_geom_1" srsName="urn:ogc:def:crs:EPSG::4326"'
- with open(sanitize(endpoint,
- f"""?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&SRSNAME=urn:ogc:def:crs:EPSG::4326&FILTER=
+ with open(
+ sanitize(
+ endpoint,
+ f"""?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&SRSNAME=urn:ogc:def:crs:EPSG::4326&FILTER=
geometryProperty
@@ -3828,8 +5102,12 @@ def testGetFeatureWithServerExpression(self):
-"""), 'wb') as f:
- f.write(b"""
+""",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
1 1
- """)
- values = [f['intfield'] for f in vl.getFeatures(request)]
+ """
+ )
+ values = [f["intfield"] for f in vl.getFeatures(request)]
self.assertEqual(values, [1])
# Get feature according to expression and filter and bounding box
vl = QgsVectorLayer(
- "url='http://" + endpoint + "' typename='my:typename' version='2.0.0' skipInitialGetFeature='true' restrictToRequestBBOX=1 sql=SELECT * FROM \"my:typename\" WHERE intfield = 1", 'test', 'WFS')
+ "url='http://"
+ + endpoint
+ + "' typename='my:typename' version='2.0.0' skipInitialGetFeature='true' restrictToRequestBBOX=1 sql=SELECT * FROM \"my:typename\" WHERE intfield = 1",
+ "test",
+ "WFS",
+ )
self.assertTrue(vl.isValid())
self.assertEqual(len(vl.fields()), 1)
self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.Point)
@@ -3855,22 +5139,26 @@ def testGetFeatureWithServerExpression(self):
request = QgsFeatureRequest().setFilterRect(extent)
parent_feature = QgsFeature()
- parent_feature.setGeometry(QgsGeometry.fromWkt('Polygon ((-20 -20, -20 20, 20 20, 20 -20, -20 -20))'))
+ parent_feature.setGeometry(
+ QgsGeometry.fromWkt("Polygon ((-20 -20, -20 20, 20 20, 20 -20, -20 -20))")
+ )
scope = QgsExpressionContextScope()
- scope.setVariable('parent', parent_feature, True)
+ scope.setVariable("parent", parent_feature, True)
context = QgsExpressionContext()
context.appendScope(QgsExpressionContextUtils.globalScope())
context.appendScope(scope)
request.setExpressionContext(context)
request.setFilterExpression("intersects( $geometry, geometry(var('parent')))")
- if int(QT_VERSION_STR.split('.')[0]) >= 6:
+ if int(QT_VERSION_STR.split(".")[0]) >= 6:
filter_attrs = 'xmlns:fes="http://www.opengis.net/fes/2.0" xmlns:gml="http://www.opengis.net/gml/3.2"'
else:
filter_attrs = 'xmlns:gml="http://www.opengis.net/gml/3.2" xmlns:fes="http://www.opengis.net/fes/2.0"'
- with open(sanitize(endpoint,
- f"""?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&SRSNAME=urn:ogc:def:crs:EPSG::4326&FILTER=
+ with open(
+ sanitize(
+ endpoint,
+ f"""?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&SRSNAME=urn:ogc:def:crs:EPSG::4326&FILTER=
geometryProperty
@@ -3895,8 +5183,12 @@ def testGetFeatureWithServerExpression(self):
-"""), 'wb') as f:
- f.write(b"""
+""",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
1
- """)
+"""
+ )
- values = [f['intfield'] for f in vl.getFeatures(request)]
+ values = [f["intfield"] for f in vl.getFeatures(request)]
self.assertEqual(values, [1])
def testExtentSubsetString(self):
@@ -3919,11 +5212,20 @@ def testExtentSubsetString(self):
def testWFS10DCP(self):
"""Test a server with different DCP endpoints"""
- endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_WFS_DCP_1.0'
- endpoint_alternate = self.__class__.basetestpath + '/fake_qgis_http_endpoint_WFS_DCP_1.0_alternate'
+ endpoint = self.__class__.basetestpath + "/fake_qgis_http_endpoint_WFS_DCP_1.0"
+ endpoint_alternate = (
+ self.__class__.basetestpath
+ + "/fake_qgis_http_endpoint_WFS_DCP_1.0_alternate"
+ )
- with open(sanitize(endpoint, '?FOO=BAR&SERVICE=WFS&REQUEST=GetCapabilities&VERSION=1.0.0'), 'wb') as f:
- f.write("""
+ with open(
+ sanitize(
+ endpoint, "?FOO=BAR&SERVICE=WFS&REQUEST=GetCapabilities&VERSION=1.0.0"
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ """
@@ -3952,12 +5254,22 @@ def testWFS10DCP(self):
- """.format(endpoint_alternate).encode('UTF-8'))
+ """.format(
+ endpoint_alternate
+ ).encode(
+ "UTF-8"
+ )
+ )
- with open(sanitize(endpoint_alternate,
- '?FOO=BAR&SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=1.0.0&TYPENAME=my:typename'),
- 'wb') as f:
- f.write(b"""
+ with open(
+ sanitize(
+ endpoint_alternate,
+ "?FOO=BAR&SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=1.0.0&TYPENAME=my:typename",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
@@ -3977,24 +5289,38 @@ def testWFS10DCP(self):
-""")
+"""
+ )
vl = QgsVectorLayer(
- "url='http://" + endpoint + "?FOO=BAR&SERVICE=WFS&REQUEST=GetCapabilities&VERSION=1.1.0" + "' typename='my:typename' version='1.0.0'",
- 'test', 'WFS')
+ "url='http://"
+ + endpoint
+ + "?FOO=BAR&SERVICE=WFS&REQUEST=GetCapabilities&VERSION=1.1.0"
+ + "' typename='my:typename' version='1.0.0'",
+ "test",
+ "WFS",
+ )
self.assertTrue(vl.isValid())
self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.Point)
self.assertEqual(len(vl.fields()), 5)
self.assertEqual(vl.featureCount(), 0)
- reference = QgsGeometry.fromRect(QgsRectangle(400000.0, 5400000.0, 450000.0, 5500000.0))
+ reference = QgsGeometry.fromRect(
+ QgsRectangle(400000.0, 5400000.0, 450000.0, 5500000.0)
+ )
vl_extent = QgsGeometry.fromRect(vl.extent())
- assert QgsGeometry.compare(vl_extent.asPolygon()[0], reference.asPolygon()[0],
- 0.00001), f'Expected {reference.asWkt()}, got {vl_extent.asWkt()}'
+ assert QgsGeometry.compare(
+ vl_extent.asPolygon()[0], reference.asPolygon()[0], 0.00001
+ ), f"Expected {reference.asWkt()}, got {vl_extent.asWkt()}"
- with open(sanitize(endpoint_alternate,
- '?FOO=BAR&SERVICE=WFS&REQUEST=GetFeature&VERSION=1.0.0&TYPENAME=my:typename&SRSNAME=EPSG:32631'),
- 'wb') as f:
- f.write(b"""
+ with open(
+ sanitize(
+ endpoint_alternate,
+ "?FOO=BAR&SERVICE=WFS&REQUEST=GetFeature&VERSION=1.0.0&TYPENAME=my:typename&SRSNAME=EPSG:32631",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
2016-04-10T12:34:56.789Z
- """)
+ """
+ )
# Also test that on file iterator works
- os.environ['QGIS_WFS_ITERATOR_TRANSFER_THRESHOLD'] = '0'
+ os.environ["QGIS_WFS_ITERATOR_TRANSFER_THRESHOLD"] = "0"
- values = [f['INTFIELD'] for f in vl.getFeatures()]
+ values = [f["INTFIELD"] for f in vl.getFeatures()]
self.assertEqual(values, [1])
- del os.environ['QGIS_WFS_ITERATOR_TRANSFER_THRESHOLD']
+ del os.environ["QGIS_WFS_ITERATOR_TRANSFER_THRESHOLD"]
- values = [f['GEOMETRY'] for f in vl.getFeatures()]
+ values = [f["GEOMETRY"] for f in vl.getFeatures()]
self.assertEqual(values, [2])
- values = [f['longfield'] for f in vl.getFeatures()]
+ values = [f["longfield"] for f in vl.getFeatures()]
self.assertEqual(values, [1234567890123])
- values = [f['stringfield'] for f in vl.getFeatures()]
- self.assertEqual(values, ['foo'])
-
- values = [f['datetimefield'] for f in vl.getFeatures()]
- self.assertEqual(values, [QDateTime(QDate(2016, 4, 10), QTime(12, 34, 56, 789), Qt.TimeSpec(Qt.TimeSpec.UTC))])
+ values = [f["stringfield"] for f in vl.getFeatures()]
+ self.assertEqual(values, ["foo"])
+
+ values = [f["datetimefield"] for f in vl.getFeatures()]
+ self.assertEqual(
+ values,
+ [
+ QDateTime(
+ QDate(2016, 4, 10),
+ QTime(12, 34, 56, 789),
+ Qt.TimeSpec(Qt.TimeSpec.UTC),
+ )
+ ],
+ )
got_f = [f for f in vl.getFeatures()]
got = got_f[0].geometry().constGet()
@@ -4040,7 +5376,10 @@ def testWFS10DCP(self):
self.assertEqual(vl.featureCount(), 1)
- self.assertTrue(vl.dataProvider().capabilities() & QgsVectorDataProvider.Capability.SelectAtId)
+ self.assertTrue(
+ vl.dataProvider().capabilities()
+ & QgsVectorDataProvider.Capability.SelectAtId
+ )
(ret, _) = vl.dataProvider().addFeatures([QgsFeature()])
self.assertFalse(ret)
@@ -4048,10 +5387,15 @@ def testWFS10DCP(self):
self.assertFalse(vl.dataProvider().deleteFeatures([0]))
# Test with restrictToRequestBBOX=1
- with open(sanitize(endpoint_alternate,
- '?FOO=BAR&SERVICE=WFS&REQUEST=GetFeature&VERSION=1.0.0&TYPENAME=my:typename&SRSNAME=EPSG:32631&BBOX=400000,5400000,450000,5500000'),
- 'wb') as f:
- f.write(b"""
+ with open(
+ sanitize(
+ endpoint_alternate,
+ "?FOO=BAR&SERVICE=WFS&REQUEST=GetFeature&VERSION=1.0.0&TYPENAME=my:typename&SRSNAME=EPSG:32631&BBOX=400000,5400000,450000,5500000",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
100
- """)
+ """
+ )
vl = QgsVectorLayer(
- "url='http://" + endpoint + "?FOO=BAR" + "' typename='my:typename' version='1.0.0' restrictToRequestBBOX=1",
- 'test', 'WFS')
+ "url='http://"
+ + endpoint
+ + "?FOO=BAR"
+ + "' typename='my:typename' version='1.0.0' restrictToRequestBBOX=1",
+ "test",
+ "WFS",
+ )
extent = QgsRectangle(400000.0, 5400000.0, 450000.0, 5500000.0)
request = QgsFeatureRequest().setFilterRect(extent)
- values = [f['INTFIELD'] for f in vl.getFeatures(request)]
+ values = [f["INTFIELD"] for f in vl.getFeatures(request)]
self.assertEqual(values, [100])
def testWFS10_outputformat_GML3_1(self):
"""Test WFS 1.0 with OUTPUTFORMAT=GML3"""
# We also test attribute fields in upper-case, and a field named GEOMETRY
- endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_WFS1.0_gml3'
+ endpoint = self.__class__.basetestpath + "/fake_qgis_http_endpoint_WFS1.0_gml3"
- with open(sanitize(endpoint, '?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=1.0.0'), 'wb') as f:
- f.write(b"""
+ with open(
+ sanitize(endpoint, "?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=1.0.0"),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
@@ -4105,11 +5459,18 @@ def testWFS10_outputformat_GML3_1(self):
- """)
+"""
+ )
- with open(sanitize(endpoint, '?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=1.0.0&TYPENAME=my:typename'),
- 'wb') as f:
- f.write(b"""
+ with open(
+ sanitize(
+ endpoint,
+ "?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=1.0.0&TYPENAME=my:typename",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
@@ -4123,15 +5484,25 @@ def testWFS10_outputformat_GML3_1(self):
-""")
+"""
+ )
- vl = QgsVectorLayer("url='http://" + endpoint + "' typename='my:typename' version='1.0.0'", 'test', 'WFS')
+ vl = QgsVectorLayer(
+ "url='http://" + endpoint + "' typename='my:typename' version='1.0.0'",
+ "test",
+ "WFS",
+ )
self.assertTrue(vl.isValid())
- with open(sanitize(endpoint,
- '?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.0.0&TYPENAME=my:typename&SRSNAME=EPSG:32631&OUTPUTFORMAT=GML3'),
- 'wb') as f:
- f.write(b"""
+ with open(
+ sanitize(
+ endpoint,
+ "?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.0.0&TYPENAME=my:typename&SRSNAME=EPSG:32631&OUTPUTFORMAT=GML3",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
- """)
+"""
+ )
got_f = [f for f in vl.getFeatures()]
got = got_f[0].geometry().constGet()
self.assertEqual((got.x(), got.y()), (426858.0, 5427937.0))
# Test with explicit OUTPUTFORMAT as parameter
- vl = QgsVectorLayer("url='http://" + endpoint + "' typename='my:typename' version='1.0.0' outputformat='GML2'",
- 'test', 'WFS')
+ vl = QgsVectorLayer(
+ "url='http://"
+ + endpoint
+ + "' typename='my:typename' version='1.0.0' outputformat='GML2'",
+ "test",
+ "WFS",
+ )
self.assertTrue(vl.isValid())
- with open(sanitize(endpoint,
- '?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.0.0&TYPENAME=my:typename&SRSNAME=EPSG:32631&OUTPUTFORMAT=GML2'),
- 'wb') as f:
- f.write(b"""
+ with open(
+ sanitize(
+ endpoint,
+ "?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.0.0&TYPENAME=my:typename&SRSNAME=EPSG:32631&OUTPUTFORMAT=GML2",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
- """)
+"""
+ )
got_f = [f for f in vl.getFeatures()]
got = got_f[0].geometry().constGet()
self.assertEqual((got.x(), got.y()), (1.0, 2.0))
# Test with explicit OUTPUTFORMAT in URL
- vl = QgsVectorLayer("url='http://" + endpoint + "?OUTPUTFORMAT=GML2' typename='my:typename' version='1.0.0'",
- 'test', 'WFS')
+ vl = QgsVectorLayer(
+ "url='http://"
+ + endpoint
+ + "?OUTPUTFORMAT=GML2' typename='my:typename' version='1.0.0'",
+ "test",
+ "WFS",
+ )
self.assertTrue(vl.isValid())
- with open(sanitize(endpoint,
- '?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.0.0&TYPENAME=my:typename&SRSNAME=EPSG:32631&OUTPUTFORMAT=GML2'),
- 'wb') as f:
- f.write(b"""
+ with open(
+ sanitize(
+ endpoint,
+ "?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.0.0&TYPENAME=my:typename&SRSNAME=EPSG:32631&OUTPUTFORMAT=GML2",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
- """)
+"""
+ )
got_f = [f for f in vl.getFeatures()]
got = got_f[0].geometry().constGet()
@@ -4207,10 +5601,14 @@ def testWFS10_outputformat_GML3_1(self):
def testWfs20SamServer(self):
"""Unknown russian WFS 2.0.0 http://geoportal.samregion.ru/wfs12"""
- endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_sam'
+ endpoint = self.__class__.basetestpath + "/fake_qgis_http_endpoint_sam"
- with open(sanitize(endpoint, '?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=2.0.0'), 'wb') as f:
- f.write(b"""
+ with open(
+ sanitize(endpoint, "?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=2.0.0"),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
EC422
@@ -4219,12 +5617,18 @@ def testWfs20SamServer(self):
urn:ogc:def:crs:EPSG::4326
- """)
+ """
+ )
with open(
- sanitize(endpoint, '?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAMES=EC422&TYPENAME=EC422'),
- 'wb') as f:
- f.write(b"""
-""")
+"""
+ )
feature_content = """
"""
- with open(sanitize(endpoint,
- '?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=EC422&COUNT=1&SRSNAME=urn:ogc:def:crs:EPSG::4326'),
- 'wb') as f:
- f.write(feature_content.encode('UTF-8'))
+ with open(
+ sanitize(
+ endpoint,
+ "?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=EC422&COUNT=1&SRSNAME=urn:ogc:def:crs:EPSG::4326",
+ ),
+ "wb",
+ ) as f:
+ f.write(feature_content.encode("UTF-8"))
- with open(sanitize(endpoint,
- '?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=EC422&SRSNAME=urn:ogc:def:crs:EPSG::4326'),
- 'wb') as f:
- f.write(feature_content.encode('UTF-8'))
+ with open(
+ sanitize(
+ endpoint,
+ "?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=EC422&SRSNAME=urn:ogc:def:crs:EPSG::4326",
+ ),
+ "wb",
+ ) as f:
+ f.write(feature_content.encode("UTF-8"))
- vl = QgsVectorLayer("url='http://" + endpoint + "' version='2.0.0' skipInitialGetFeature='true' typename='EC422'", 'test', 'WFS')
+ vl = QgsVectorLayer(
+ "url='http://"
+ + endpoint
+ + "' version='2.0.0' skipInitialGetFeature='true' typename='EC422'",
+ "test",
+ "WFS",
+ )
self.assertTrue(vl.isValid())
features = list(vl.getFeatures())
self.assertEqual(len(features), 3)
geom = features[0].geometry()
geom_string = geom.asWkt()
- geom_string = re.sub(r'\.\d+', '', geom_string)[:100]
- self.assertEqual(geom_string,
- "LineString (9540051 5997366, 9539934 5997127, 9539822 5996862, 9539504 5996097, 9539529 5996093, 953")
+ geom_string = re.sub(r"\.\d+", "", geom_string)[:100]
+ self.assertEqual(
+ geom_string,
+ "LineString (9540051 5997366, 9539934 5997127, 9539822 5996862, 9539504 5996097, 9539529 5996093, 953",
+ )
def testDescribeFeatureTypeWithSingleInclude(self):
"""Test DescribeFeatureType response which has a single child node"""
- endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_DescribeFeatureTypeWithSingleInclude'
+ endpoint = (
+ self.__class__.basetestpath
+ + "/fake_qgis_http_endpoint_DescribeFeatureTypeWithSingleInclude"
+ )
- with open(sanitize(endpoint, '?SERVICE=WFS?REQUEST=GetCapabilities?ACCEPTVERSIONS=2.0.0,1.1.0,1.0.0'),
- 'wb') as f:
- f.write(b"""
+ with open(
+ sanitize(
+ endpoint,
+ "?SERVICE=WFS?REQUEST=GetCapabilities?ACCEPTVERSIONS=2.0.0,1.1.0,1.0.0",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
@@ -4434,19 +5864,30 @@ def testDescribeFeatureTypeWithSingleInclude(self):
urn:ogc:def:crs:EPSG::4326
- """)
+"""
+ )
- with open(sanitize(endpoint,
- '?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAMES=my:typename&TYPENAME=my:typename'),
- 'wb') as f:
- f.write(("""
+ with open(
+ sanitize(
+ endpoint,
+ "?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAMES=my:typename&TYPENAME=my:typename",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ (
+ """
-""" % ('http://' + endpoint + '?myschema.xsd')).encode('UTF-8'))
+"""
+ % ("http://" + endpoint + "?myschema.xsd")
+ ).encode("UTF-8")
+ )
- with open(sanitize(endpoint, '?myschema.xsd'), 'wb') as f:
- f.write(b"""
+ with open(sanitize(endpoint, "?myschema.xsd"), "wb") as f:
+ f.write(
+ b"""
@@ -4460,19 +5901,30 @@ def testDescribeFeatureTypeWithSingleInclude(self):
-""")
+"""
+ )
# Create test layer
- vl = QgsVectorLayer("url='http://" + endpoint + "' typename='my:typename' skipInitialGetFeature='true'", 'test', 'WFS')
+ vl = QgsVectorLayer(
+ "url='http://"
+ + endpoint
+ + "' typename='my:typename' skipInitialGetFeature='true'",
+ "test",
+ "WFS",
+ )
self.assertTrue(vl.isValid())
def testGeometryCollectionAsMultiLineString(self):
- """Test https://github.com/qgis/QGIS/issues/27398 """
+ """Test https://github.com/qgis/QGIS/issues/27398"""
- endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_gc_as_mls'
+ endpoint = self.__class__.basetestpath + "/fake_qgis_http_endpoint_gc_as_mls"
- with open(sanitize(endpoint, '?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=1.1.0'), 'wb') as f:
- f.write(b"""
+ with open(
+ sanitize(endpoint, "?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=1.1.0"),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
@@ -4486,11 +5938,18 @@ def testGeometryCollectionAsMultiLineString(self):
- """)
+"""
+ )
- with open(sanitize(endpoint, '?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=1.1.0&TYPENAME=my:typename'),
- 'wb') as f:
- f.write(b"""
+ with open(
+ sanitize(
+ endpoint,
+ "?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=1.1.0&TYPENAME=my:typename",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
-""")
+"""
+ )
get_features = """
"""
- with open(sanitize(endpoint,
- """?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.1.0&TYPENAME=my:typename&MAXFEATURES=1&SRSNAME=urn:ogc:def:crs:EPSG::4326"""),
- 'wb') as f:
- f.write(get_features.encode('UTF-8'))
+ with open(
+ sanitize(
+ endpoint,
+ """?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.1.0&TYPENAME=my:typename&MAXFEATURES=1&SRSNAME=urn:ogc:def:crs:EPSG::4326""",
+ ),
+ "wb",
+ ) as f:
+ f.write(get_features.encode("UTF-8"))
- with open(sanitize(endpoint,
- """?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.1.0&TYPENAME=my:typename&SRSNAME=urn:ogc:def:crs:EPSG::4326"""),
- 'wb') as f:
- f.write(get_features.encode('UTF-8'))
+ with open(
+ sanitize(
+ endpoint,
+ """?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.1.0&TYPENAME=my:typename&SRSNAME=urn:ogc:def:crs:EPSG::4326""",
+ ),
+ "wb",
+ ) as f:
+ f.write(get_features.encode("UTF-8"))
- vl = QgsVectorLayer("url='http://" + endpoint + "' typename='my:typename' version='1.1.0'", 'test', 'WFS')
+ vl = QgsVectorLayer(
+ "url='http://" + endpoint + "' typename='my:typename' version='1.1.0'",
+ "test",
+ "WFS",
+ )
self.assertTrue(vl.isValid())
got_f = [f for f in vl.getFeatures()]
geom = got_f[0].geometry().constGet()
geom_string = geom.asWkt()
- geom_string = re.sub(r'\.\d+', '', geom_string)
- self.assertEqual(geom_string, 'MultiLineString ((2 49, 3 50))')
+ geom_string = re.sub(r"\.\d+", "", geom_string)
+ self.assertEqual(geom_string, "MultiLineString ((2 49, 3 50))")
reference = QgsGeometry.fromRect(QgsRectangle(2, 49, 3, 50))
vl_extent = QgsGeometry.fromRect(vl.extent())
- assert QgsGeometry.compare(vl_extent.asPolygon()[0], reference.asPolygon()[0],
- 0.00001), f'Expected {reference.asWkt()}, got {vl_extent.asWkt()}'
+ assert QgsGeometry.compare(
+ vl_extent.asPolygon()[0], reference.asPolygon()[0], 0.00001
+ ), f"Expected {reference.asWkt()}, got {vl_extent.asWkt()}"
def test_NullValues_regression_20961(self):
"""Test that provider handles null values, regression #20961"""
- endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_null_values'
+ endpoint = self.__class__.basetestpath + "/fake_qgis_http_endpoint_null_values"
- with open(sanitize(endpoint, '?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=1.1.0'), 'wb') as f:
- f.write(b"""
+ with open(
+ sanitize(endpoint, "?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=1.1.0"),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
@@ -4588,11 +6065,18 @@ def test_NullValues_regression_20961(self):
- """)
+"""
+ )
- with open(sanitize(endpoint, '?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=1.1.0&TYPENAME=points'),
- 'wb') as f:
- f.write(b"""
+ with open(
+ sanitize(
+ endpoint,
+ "?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=1.1.0&TYPENAME=points",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
@@ -4610,7 +6094,8 @@ def test_NullValues_regression_20961(self):
-""")
+"""
+ )
get_feature_1 = """
@@ -4698,44 +6183,65 @@ def test_NullValues_regression_20961(self):
"""
- with open(sanitize(endpoint,
- """?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.1.0&TYPENAME=points&MAXFEATURES=1&SRSNAME=urn:ogc:def:crs:EPSG::3857"""),
- 'wb') as f:
- f.write(get_feature_1.encode('UTF-8'))
+ with open(
+ sanitize(
+ endpoint,
+ """?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.1.0&TYPENAME=points&MAXFEATURES=1&SRSNAME=urn:ogc:def:crs:EPSG::3857""",
+ ),
+ "wb",
+ ) as f:
+ f.write(get_feature_1.encode("UTF-8"))
- with open(sanitize(endpoint,
- """?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.1.0&TYPENAME=points&SRSNAME=urn:ogc:def:crs:EPSG::3857"""),
- 'wb') as f:
- f.write(get_features.encode('UTF-8'))
+ with open(
+ sanitize(
+ endpoint,
+ """?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.1.0&TYPENAME=points&SRSNAME=urn:ogc:def:crs:EPSG::3857""",
+ ),
+ "wb",
+ ) as f:
+ f.write(get_features.encode("UTF-8"))
- vl = QgsVectorLayer("url='http://" + endpoint + "' typename='points' version='1.1.0' skipInitialGetFeature='true'", 'test', 'WFS')
+ vl = QgsVectorLayer(
+ "url='http://"
+ + endpoint
+ + "' typename='points' version='1.1.0' skipInitialGetFeature='true'",
+ "test",
+ "WFS",
+ )
self.assertTrue(vl.isValid())
got_f = [f for f in vl.getFeatures()]
- self.assertEqual(got_f[0]['type'], NULL)
- self.assertEqual(got_f[0]['elevation'], NULL)
- self.assertEqual(str(got_f[0]['name']), 'Xxx')
- self.assertEqual(str(got_f[1]['type']), '0')
- self.assertEqual(got_f[1]['elevation'], NULL)
- self.assertEqual(str(got_f[1]['name']), 'sdf')
+ self.assertEqual(got_f[0]["type"], NULL)
+ self.assertEqual(got_f[0]["elevation"], NULL)
+ self.assertEqual(str(got_f[0]["name"]), "Xxx")
+ self.assertEqual(str(got_f[1]["type"]), "0")
+ self.assertEqual(got_f[1]["elevation"], NULL)
+ self.assertEqual(str(got_f[1]["name"]), "sdf")
# Now iterate ! Regression #20961
ids = [f.id() for f in got_f]
got_f2 = [vl.getFeature(id) for id in ids]
- self.assertEqual(got_f2[0]['type'], NULL)
- self.assertEqual(got_f2[0]['elevation'], NULL)
- self.assertEqual(str(got_f2[0]['name']), 'Xxx')
- self.assertEqual(str(got_f2[1]['type']), '0')
- self.assertEqual(got_f2[1]['elevation'], NULL)
- self.assertEqual(str(got_f2[1]['name']), 'sdf')
+ self.assertEqual(got_f2[0]["type"], NULL)
+ self.assertEqual(got_f2[0]["elevation"], NULL)
+ self.assertEqual(str(got_f2[0]["name"]), "Xxx")
+ self.assertEqual(str(got_f2[1]["type"]), "0")
+ self.assertEqual(got_f2[1]["elevation"], NULL)
+ self.assertEqual(str(got_f2[1]["name"]), "sdf")
def testFilteredFeatureRequests(self):
- """Test https://github.com/qgis/QGIS/issues/28895 """
+ """Test https://github.com/qgis/QGIS/issues/28895"""
- endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_filtered_feature_requests'
+ endpoint = (
+ self.__class__.basetestpath
+ + "/fake_qgis_http_endpoint_filtered_feature_requests"
+ )
- with open(sanitize(endpoint, '?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=1.1.0'), 'wb') as f:
- f.write(b"""
+ with open(
+ sanitize(endpoint, "?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=1.1.0"),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
@@ -4749,11 +6255,18 @@ def testFilteredFeatureRequests(self):
- """)
+"""
+ )
- with open(sanitize(endpoint, '?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=1.1.0&TYPENAME=points'),
- 'wb') as f:
- f.write(b"""
+ with open(
+ sanitize(
+ endpoint,
+ "?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=1.1.0&TYPENAME=points",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
@@ -4771,7 +6284,8 @@ def testFilteredFeatureRequests(self):
-""")
+"""
+ )
get_feature_1 = """
@@ -4859,29 +6373,47 @@ def testFilteredFeatureRequests(self):
"""
- with open(sanitize(endpoint,
- """?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.1.0&TYPENAME=points&MAXFEATURES=1&SRSNAME=urn:ogc:def:crs:EPSG::3857"""),
- 'wb') as f:
- f.write(get_feature_1.encode('UTF-8'))
+ with open(
+ sanitize(
+ endpoint,
+ """?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.1.0&TYPENAME=points&MAXFEATURES=1&SRSNAME=urn:ogc:def:crs:EPSG::3857""",
+ ),
+ "wb",
+ ) as f:
+ f.write(get_feature_1.encode("UTF-8"))
- with open(sanitize(endpoint,
- """?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.1.0&TYPENAME=points&SRSNAME=urn:ogc:def:crs:EPSG::3857"""),
- 'wb') as f:
- f.write(get_features.encode('UTF-8'))
+ with open(
+ sanitize(
+ endpoint,
+ """?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.1.0&TYPENAME=points&SRSNAME=urn:ogc:def:crs:EPSG::3857""",
+ ),
+ "wb",
+ ) as f:
+ f.write(get_features.encode("UTF-8"))
- vl = QgsVectorLayer("url='http://" + endpoint + "' typename='points' version='1.1.0' skipInitialGetFeature='true'", 'test', 'WFS')
+ vl = QgsVectorLayer(
+ "url='http://"
+ + endpoint
+ + "' typename='points' version='1.1.0' skipInitialGetFeature='true'",
+ "test",
+ "WFS",
+ )
self.assertTrue(vl.isValid())
# Fill the cache
[f for f in vl.getFeatures()]
- qgis_feat = next(vl.getFeatures(QgsFeatureRequest(QgsExpression('"name" = \'qgis\''))))
- other_feat = next(vl.getFeatures(QgsFeatureRequest(QgsExpression('"name" != \'qgis\''))))
- self.assertEqual(qgis_feat['name'], 'qgis')
- self.assertEqual(other_feat['name'], 'Xxx')
+ qgis_feat = next(
+ vl.getFeatures(QgsFeatureRequest(QgsExpression("\"name\" = 'qgis'")))
+ )
+ other_feat = next(
+ vl.getFeatures(QgsFeatureRequest(QgsExpression("\"name\" != 'qgis'")))
+ )
+ self.assertEqual(qgis_feat["name"], "qgis")
+ self.assertEqual(other_feat["name"], "Xxx")
form_scope = QgsExpressionContextUtils.formScope(qgis_feat)
- form_exp = QgsExpression('current_value(\'name\') = "name"')
+ form_exp = QgsExpression("current_value('name') = \"name\"")
ctx = QgsExpressionContext()
ctx.appendScope(form_scope)
ctx.setFeature(qgis_feat)
@@ -4895,12 +6427,19 @@ def testFilteredFeatureRequests(self):
qgis_feat = next(vl.getFeatures(req))
def testWFSFieldWithSameNameButDifferentCase(self):
- """Test a layer with field foo and FOO """
+ """Test a layer with field foo and FOO"""
- endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_FieldWithSameNameButDifferentCase'
+ endpoint = (
+ self.__class__.basetestpath
+ + "/fake_qgis_http_endpoint_FieldWithSameNameButDifferentCase"
+ )
- with open(sanitize(endpoint, '?SERVICE=WFS&REQUEST=GetCapabilities&VERSION=1.0.0'), 'wb') as f:
- f.write(b"""
+ with open(
+ sanitize(endpoint, "?SERVICE=WFS&REQUEST=GetCapabilities&VERSION=1.0.0"),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
@@ -4912,11 +6451,18 @@ def testWFSFieldWithSameNameButDifferentCase(self):
- """)
+"""
+ )
- with open(sanitize(endpoint, '?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=1.0.0&TYPENAME=my:typename'),
- 'wb') as f:
- f.write(b"""
+ with open(
+ sanitize(
+ endpoint,
+ "?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=1.0.0&TYPENAME=my:typename",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
@@ -4933,12 +6479,18 @@ def testWFSFieldWithSameNameButDifferentCase(self):
-""")
+"""
+ )
with open(
- sanitize(endpoint, '?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.0.0&TYPENAME=my:typename&SRSNAME=EPSG:32631'),
- 'wb') as f:
- f.write(b"""
+ sanitize(
+ endpoint,
+ "?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.0.0&TYPENAME=my:typename&SRSNAME=EPSG:32631",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
3
- """)
+ """
+ )
- vl = QgsVectorLayer("url='http://" + endpoint + "' typename='my:typename' version='1.0.0'", 'test', 'WFS')
+ vl = QgsVectorLayer(
+ "url='http://" + endpoint + "' typename='my:typename' version='1.0.0'",
+ "test",
+ "WFS",
+ )
self.assertTrue(vl.isValid())
self.assertEqual(len(vl.fields()), 3)
- values = [f['foo'] for f in vl.getFeatures()]
+ values = [f["foo"] for f in vl.getFeatures()]
self.assertEqual(values, [1])
- values = [f['FOO'] for f in vl.getFeatures()]
+ values = [f["FOO"] for f in vl.getFeatures()]
self.assertEqual(values, [2])
- values = [f['FOO2'] for f in vl.getFeatures()]
+ values = [f["FOO2"] for f in vl.getFeatures()]
self.assertEqual(values, [3])
# Also test that on file iterator works
- os.environ['QGIS_WFS_ITERATOR_TRANSFER_THRESHOLD'] = '0'
+ os.environ["QGIS_WFS_ITERATOR_TRANSFER_THRESHOLD"] = "0"
- vl = QgsVectorLayer("url='http://" + endpoint + "' typename='my:typename' version='1.0.0'", 'test', 'WFS')
- values = [f['foo'] for f in vl.getFeatures()]
+ vl = QgsVectorLayer(
+ "url='http://" + endpoint + "' typename='my:typename' version='1.0.0'",
+ "test",
+ "WFS",
+ )
+ values = [f["foo"] for f in vl.getFeatures()]
self.assertEqual(values, [1])
- values = [f['FOO'] for f in vl.getFeatures()]
+ values = [f["FOO"] for f in vl.getFeatures()]
self.assertEqual(values, [2])
- values = [f['FOO2'] for f in vl.getFeatures()]
+ values = [f["FOO2"] for f in vl.getFeatures()]
self.assertEqual(values, [3])
- del os.environ['QGIS_WFS_ITERATOR_TRANSFER_THRESHOLD']
+ del os.environ["QGIS_WFS_ITERATOR_TRANSFER_THRESHOLD"]
- vl = QgsVectorLayer("url='http://" + endpoint + "' typename='my:typename' version='1.0.0'", 'test', 'WFS')
- request = QgsFeatureRequest().setFilterExpression('FOO = 2')
- values = [f['FOO'] for f in vl.getFeatures(request)]
+ vl = QgsVectorLayer(
+ "url='http://" + endpoint + "' typename='my:typename' version='1.0.0'",
+ "test",
+ "WFS",
+ )
+ request = QgsFeatureRequest().setFilterExpression("FOO = 2")
+ values = [f["FOO"] for f in vl.getFeatures(request)]
self.assertEqual(values, [2])
- vl = QgsVectorLayer("url='http://" + endpoint + "' typename='my:typename' version='1.0.0'", 'test', 'WFS')
- request = QgsFeatureRequest().setSubsetOfAttributes(['FOO'], vl.fields())
- values = [f['FOO'] for f in vl.getFeatures(request)]
+ vl = QgsVectorLayer(
+ "url='http://" + endpoint + "' typename='my:typename' version='1.0.0'",
+ "test",
+ "WFS",
+ )
+ request = QgsFeatureRequest().setSubsetOfAttributes(["FOO"], vl.fields())
+ values = [f["FOO"] for f in vl.getFeatures(request)]
self.assertEqual(values, [2])
def testRetryLogicOnExceptionLackOfPrimaryKey(self):
- """Test retry logic on 'Cannot do natural order without a primary key' server exception (GeoServer) """
+ """Test retry logic on 'Cannot do natural order without a primary key' server exception (GeoServer)"""
- endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_retry'
+ endpoint = self.__class__.basetestpath + "/fake_qgis_http_endpoint_retry"
- with open(sanitize(endpoint, '?SERVICE=WFS&REQUEST=GetCapabilities&VERSION=2.0.0'), 'wb') as f:
- f.write(b"""
+ with open(
+ sanitize(endpoint, "?SERVICE=WFS&REQUEST=GetCapabilities&VERSION=2.0.0"),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
@@ -5023,12 +6596,18 @@ def testRetryLogicOnExceptionLackOfPrimaryKey(self):
- """)
+"""
+ )
- with open(sanitize(endpoint,
- '?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAMES=my:typename&TYPENAME=my:typename'),
- 'wb') as f:
- f.write(b"""
+ with open(
+ sanitize(
+ endpoint,
+ "?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAMES=my:typename&TYPENAME=my:typename",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
@@ -5042,30 +6621,48 @@ def testRetryLogicOnExceptionLackOfPrimaryKey(self):
-""")
+"""
+ )
- vl = QgsVectorLayer("url='http://" + endpoint + "' typename='my:typename' version='2.0.0' skipInitialGetFeature='true'", 'test', 'WFS')
+ vl = QgsVectorLayer(
+ "url='http://"
+ + endpoint
+ + "' typename='my:typename' version='2.0.0' skipInitialGetFeature='true'",
+ "test",
+ "WFS",
+ )
self.assertTrue(vl.isValid())
self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.NoGeometry)
self.assertEqual(len(vl.fields()), 1)
# Initial request: exception
- with open(sanitize(endpoint,
- '?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&STARTINDEX=0&COUNT=1&SRSNAME=urn:ogc:def:crs:EPSG::4326'),
- 'wb') as f:
- f.write(b"""
+ with open(
+ sanitize(
+ endpoint,
+ "?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&STARTINDEX=0&COUNT=1&SRSNAME=urn:ogc:def:crs:EPSG::4326",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
java.lang.RuntimeException: java.lang.RuntimeException: java.io.IOException
java.lang.RuntimeException: java.io.IOException
java.io.IOExceptionCannot do natural order without a primary key, please add it or specify a manual sort over existing attributes
- """)
+ """
+ )
# Retry
- with open(sanitize(endpoint,
- '?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&SRSNAME=urn:ogc:def:crs:EPSG::4326&RETRY=1'),
- 'wb') as f:
- f.write(b"""
+ with open(
+ sanitize(
+ endpoint,
+ "?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&SRSNAME=urn:ogc:def:crs:EPSG::4326&RETRY=1",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
2
- """)
+"""
+ )
- values = [f['INTFIELD'] for f in vl.getFeatures()]
+ values = [f["INTFIELD"] for f in vl.getFeatures()]
self.assertEqual(values, [1, 2])
def testCacheRead(self):
@@ -5091,7 +6689,7 @@ def testCacheRead(self):
QgsSettings().setValue("cache/directory", cache_dir)
# don't retry, http server never fails
- QgsSettings().setValue('qgis/defaultTileMaxRetry', '0')
+ QgsSettings().setValue("qgis/defaultTileMaxRetry", "0")
responses = []
@@ -5102,15 +6700,17 @@ def do_GET(self):
self.send_response(c)
self.send_header("Content-type", "application/xml")
self.send_header("Content-length", len(response))
- self.send_header('Last-Modified', 'Wed, 05 Jun 2019 15:33:27 GMT')
+ self.send_header("Last-Modified", "Wed, 05 Jun 2019 15:33:27 GMT")
self.end_headers()
- self.wfile.write(response.encode('UTF-8'))
+ self.wfile.write(response.encode("UTF-8"))
- httpd = socketserver.TCPServer(('localhost', 0), SequentialHandler)
+ httpd = socketserver.TCPServer(("localhost", 0), SequentialHandler)
port = httpd.server_address[1]
- responses.append((200,
- """
+ responses.append(
+ (
+ 200,
+ """
@@ -5120,10 +6720,14 @@ def do_GET(self):
EPSG:4326
- """))
-
- responses.append((200,
- """
+""",
+ )
+ )
+
+ responses.append(
+ (
+ 200,
+ """
@@ -5137,10 +6741,14 @@ def do_GET(self):
-"""))
-
- responses.append((200,
- """
+""",
+ )
+ )
+
+ responses.append(
+ (
+ 200,
+ """
2
- """))
+""",
+ )
+ )
httpd_thread = threading.Thread(target=httpd.serve_forever)
httpd_thread.daemon = True
httpd_thread.start()
- vl = QgsVectorLayer(f"url='http://localhost:{port}' typename='my:typename' version='1.0.0'", 'test',
- 'WFS')
+ vl = QgsVectorLayer(
+ f"url='http://localhost:{port}' typename='my:typename' version='1.0.0'",
+ "test",
+ "WFS",
+ )
self.assertTrue(vl.isValid())
self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.NoGeometry)
self.assertEqual(len(vl.fields()), 1)
- res = [f['INTFIELD'] for f in vl.getFeatures()]
+ res = [f["INTFIELD"] for f in vl.getFeatures()]
self.assertEqual(sorted(res), [1, 2])
# next response is empty, cache must be used
@@ -5176,7 +6789,7 @@ def do_GET(self):
# Reload
vl.reload()
- res = [f['INTFIELD'] for f in vl.getFeatures()]
+ res = [f["INTFIELD"] for f in vl.getFeatures()]
# self.assertEqual(len(server.errors()), 0, server.errors())
self.assertEqual(sorted(res), [1, 2])
@@ -5187,7 +6800,10 @@ def testWFS20CaseInsensitiveKVP(self):
"""Test an URL with non standard query string arguments where the server exposes
the same parameters with different case: see https://github.com/qgis/QGIS/issues/34148
"""
- endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_WFS_case_insensitive_kvp_2.0'
+ endpoint = (
+ self.__class__.basetestpath
+ + "/fake_qgis_http_endpoint_WFS_case_insensitive_kvp_2.0"
+ )
get_cap = """
@@ -5218,22 +6834,39 @@ def testWFS20CaseInsensitiveKVP(self):
- """.format(endpoint).encode('UTF-8')
+ """.format(
+ endpoint
+ ).encode(
+ "UTF-8"
+ )
- with open(sanitize(endpoint,
- '?PARAMETER1=Value1&PARAMETER2=Value2&FOO=BAR&SERVICE=WFS&REQUEST=GetCapabilities&VERSION=1.0.0'),
- 'wb') as f:
+ with open(
+ sanitize(
+ endpoint,
+ "?PARAMETER1=Value1&PARAMETER2=Value2&FOO=BAR&SERVICE=WFS&REQUEST=GetCapabilities&VERSION=1.0.0",
+ ),
+ "wb",
+ ) as f:
f.write(get_cap)
- with open(sanitize(endpoint,
- '?Parameter1=Value1&Parameter2=Value2&FOO=BAR&SERVICE=WFS&REQUEST=GetCapabilities&VERSION=1.0.0'),
- 'wb') as f:
+ with open(
+ sanitize(
+ endpoint,
+ "?Parameter1=Value1&Parameter2=Value2&FOO=BAR&SERVICE=WFS&REQUEST=GetCapabilities&VERSION=1.0.0",
+ ),
+ "wb",
+ ) as f:
f.write(get_cap)
- with open(sanitize(endpoint,
- '?PARAMETER1=Value1&PARAMETER2=Value2&FOO=BAR&SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=1.0.0&TYPENAME=my:typename'),
- 'wb') as f:
- f.write(b"""
+ with open(
+ sanitize(
+ endpoint,
+ "?PARAMETER1=Value1&PARAMETER2=Value2&FOO=BAR&SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=1.0.0&TYPENAME=my:typename",
+ ),
+ "wb",
+ ) as f:
+ f.write(
+ b"""
@@ -5253,24 +6886,35 @@ def testWFS20CaseInsensitiveKVP(self):
-""")
+"""
+ )
vl = QgsVectorLayer(
- "url='http://" + endpoint + "?Parameter1=Value1&Parameter2=Value2&FOO=BAR&SERVICE=WFS&REQUEST=GetCapabilities&VERSION=1.1.0" + "' typename='my:typename' version='1.0.0'",
- 'test', 'WFS')
+ "url='http://"
+ + endpoint
+ + "?Parameter1=Value1&Parameter2=Value2&FOO=BAR&SERVICE=WFS&REQUEST=GetCapabilities&VERSION=1.1.0"
+ + "' typename='my:typename' version='1.0.0'",
+ "test",
+ "WFS",
+ )
self.assertTrue(vl.isValid())
self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.Point)
self.assertEqual(len(vl.fields()), 5)
self.assertEqual(vl.featureCount(), 0)
- reference = QgsGeometry.fromRect(QgsRectangle(400000.0, 5400000.0, 450000.0, 5500000.0))
+ reference = QgsGeometry.fromRect(
+ QgsRectangle(400000.0, 5400000.0, 450000.0, 5500000.0)
+ )
vl_extent = QgsGeometry.fromRect(vl.extent())
- assert QgsGeometry.compare(vl_extent.asPolygon()[0], reference.asPolygon()[0],
- 0.00001), f'Expected {reference.asWkt()}, got {vl_extent.asWkt()}'
+ assert QgsGeometry.compare(
+ vl_extent.asPolygon()[0], reference.asPolygon()[0], 0.00001
+ ), f"Expected {reference.asWkt()}, got {vl_extent.asWkt()}"
def testGetCapabilitiesReturnWFSException(self):
- """Test parsing of WFS exception
- """
- endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_testGetCapabilitiesReturnWFSException'
+ """Test parsing of WFS exception"""
+ endpoint = (
+ self.__class__.basetestpath
+ + "/fake_qgis_http_endpoint_testGetCapabilitiesReturnWFSException"
+ )
get_cap_response = b"""
"""
- with open(sanitize(endpoint,
- '?SERVICE=WFS&REQUEST=GetCapabilities&VERSION=1.0.0'),
- 'wb') as f:
+ with open(
+ sanitize(endpoint, "?SERVICE=WFS&REQUEST=GetCapabilities&VERSION=1.0.0"),
+ "wb",
+ ) as f:
f.write(get_cap_response)
- with MessageLogger('WFS') as logger:
- vl = QgsVectorLayer("url='http://" + endpoint + "' typename='my:typename' version='1.0.0'", 'test', 'WFS')
+ with MessageLogger("WFS") as logger:
+ vl = QgsVectorLayer(
+ "url='http://" + endpoint + "' typename='my:typename' version='1.0.0'",
+ "test",
+ "WFS",
+ )
self.assertFalse(vl.isValid())
self.assertEqual(len(logger.messages()), 1, logger.messages())
- self.assertIn("foo: bar", logger.messages()[0].decode('UTF-8'))
+ self.assertIn("foo: bar", logger.messages()[0].decode("UTF-8"))
def testGetCapabilitiesReturnWMSException(self):
- """Test fix for https://github.com/qgis/QGIS/issues/29866
- """
- endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_testGetCapabilitiesReturnWMSxception'
+ """Test fix for https://github.com/qgis/QGIS/issues/29866"""
+ endpoint = (
+ self.__class__.basetestpath
+ + "/fake_qgis_http_endpoint_testGetCapabilitiesReturnWMSxception"
+ )
get_cap_response = b"""
@@ -5307,40 +6958,81 @@ def testGetCapabilitiesReturnWMSException(self):
"""
- with open(sanitize(endpoint,
- '?SERVICE=WFS&REQUEST=GetCapabilities&VERSION=1.0.0'),
- 'wb') as f:
+ with open(
+ sanitize(endpoint, "?SERVICE=WFS&REQUEST=GetCapabilities&VERSION=1.0.0"),
+ "wb",
+ ) as f:
f.write(get_cap_response)
- with MessageLogger('WFS') as logger:
- vl = QgsVectorLayer("url='http://" + endpoint + "' typename='my:typename' version='1.0.0'", 'test', 'WFS')
+ with MessageLogger("WFS") as logger:
+ vl = QgsVectorLayer(
+ "url='http://" + endpoint + "' typename='my:typename' version='1.0.0'",
+ "test",
+ "WFS",
+ )
self.assertFalse(vl.isValid())
self.assertEqual(len(logger.messages()), 1, logger.messages())
- self.assertIn("InvalidFormat: Can't recognize service requested.", logger.messages()[0].decode('UTF-8'))
+ self.assertIn(
+ "InvalidFormat: Can't recognize service requested.",
+ logger.messages()[0].decode("UTF-8"),
+ )
def testWFST11(self):
"""Test WFS-T 1.1 (read-write) taken from a geoserver session"""
- endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_WFS_T_1_1_transaction'
-
- shutil.copy(os.path.join(TEST_DATA_DIR, 'provider', 'wfst-1-1', 'getcapabilities.xml'), sanitize(endpoint, '?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=1.1.0'))
- shutil.copy(os.path.join(TEST_DATA_DIR, 'provider', 'wfst-1-1', 'describefeaturetype_polygons.xml'), sanitize(endpoint, '?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=1.1.0&TYPENAME=ws1:polygons'))
+ endpoint = (
+ self.__class__.basetestpath
+ + "/fake_qgis_http_endpoint_WFS_T_1_1_transaction"
+ )
+
+ shutil.copy(
+ os.path.join(TEST_DATA_DIR, "provider", "wfst-1-1", "getcapabilities.xml"),
+ sanitize(endpoint, "?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=1.1.0"),
+ )
+ shutil.copy(
+ os.path.join(
+ TEST_DATA_DIR,
+ "provider",
+ "wfst-1-1",
+ "describefeaturetype_polygons.xml",
+ ),
+ sanitize(
+ endpoint,
+ "?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=1.1.0&TYPENAME=ws1:polygons",
+ ),
+ )
- vl = QgsVectorLayer("url='http://" + endpoint + "' typename='ws1:polygons' version='1.1.0' skipInitialGetFeature='true'", 'test', 'WFS')
+ vl = QgsVectorLayer(
+ "url='http://"
+ + endpoint
+ + "' typename='ws1:polygons' version='1.1.0' skipInitialGetFeature='true'",
+ "test",
+ "WFS",
+ )
self.assertTrue(vl.isValid())
self.assertEqual(vl.featureCount(), 0)
- self.assertEqual(vl.dataProvider().capabilities(),
- QgsVectorDataProvider.Capability.AddFeatures
- | QgsVectorDataProvider.Capability.ChangeAttributeValues
- | QgsVectorDataProvider.Capability.ChangeGeometries
- | QgsVectorDataProvider.Capability.DeleteFeatures
- | QgsVectorDataProvider.Capability.SelectAtId
- | QgsVectorDataProvider.Capability.ReloadData)
+ self.assertEqual(
+ vl.dataProvider().capabilities(),
+ QgsVectorDataProvider.Capability.AddFeatures
+ | QgsVectorDataProvider.Capability.ChangeAttributeValues
+ | QgsVectorDataProvider.Capability.ChangeGeometries
+ | QgsVectorDataProvider.Capability.DeleteFeatures
+ | QgsVectorDataProvider.Capability.SelectAtId
+ | QgsVectorDataProvider.Capability.ReloadData,
+ )
# Transaction response failure (no modifications)
- shutil.copy(os.path.join(TEST_DATA_DIR, 'provider', 'wfst-1-1', 'transaction_response_empty.xml'), sanitize(endpoint, '?SERVICE=WFS&POSTDATA=<_Insert><_Transaction>'))
+ shutil.copy(
+ os.path.join(
+ TEST_DATA_DIR, "provider", "wfst-1-1", "transaction_response_empty.xml"
+ ),
+ sanitize(
+ endpoint,
+ '?SERVICE=WFS&POSTDATA=<_Insert><_Transaction>',
+ ),
+ )
(ret, _) = vl.dataProvider().addFeatures([QgsFeature()])
self.assertFalse(ret)
@@ -5349,51 +7041,109 @@ def testWFST11(self):
# Test add features for real
# Transaction response with 1 feature added
- if int(QT_VERSION_STR.split('.')[0]) >= 6:
+ if int(QT_VERSION_STR.split(".")[0]) >= 6:
attrs = 'xmlns="http:__www.opengis.net_wfs" service="WFS" version="1.1.0" xmlns:gml="http:__www.opengis.net_gml" xmlns:ws1="ws1" xmlns:xsi="http:__www.w3.org_2001_XMLSchema-instance" xsi:schemaLocation="ws1 http:__fake_qgis_http_endpoint?REQUEST=DescribeFeatureType&VERSION=1.0.0&TYPENAME=ws1:polygons"'
else:
attrs = 'xmlns="http:__www.opengis.net_wfs" xmlns:xsi="http:__www.w3.org_2001_XMLSchema-instance" xmlns:gml="http:__www.opengis.net_gml" xmlns:ws1="ws1" xsi:schemaLocation="ws1 http:__fake_qgis_http_endpoint?REQUEST=DescribeFeatureType&VERSION=1.0.0&TYPENAME=ws1:polygons" version="1.1.0" service="WFS"'
- shutil.copy(os.path.join(TEST_DATA_DIR, 'provider', 'wfst-1-1', 'transaction_response_feature_added.xml'), sanitize(endpoint, f'?SERVICE=WFS&POSTDATA=one<_name>1<_value>45 9 45 10 46 10 46 9 45 9<_gml:posList><_gml:LinearRing><_gml:exterior><_gml:Polygon><_geometry><_polygons><_Insert><_Transaction>'))
+ shutil.copy(
+ os.path.join(
+ TEST_DATA_DIR,
+ "provider",
+ "wfst-1-1",
+ "transaction_response_feature_added.xml",
+ ),
+ sanitize(
+ endpoint,
+ f'?SERVICE=WFS&POSTDATA=one<_name>1<_value>45 9 45 10 46 10 46 9 45 9<_gml:posList><_gml:LinearRing><_gml:exterior><_gml:Polygon><_geometry><_polygons><_Insert><_Transaction>',
+ ),
+ )
feat = QgsFeature(vl.fields())
- feat.setAttribute('name', 'one')
- feat.setAttribute('value', 1)
- feat.setGeometry(QgsGeometry.fromWkt('Polygon ((9 45, 10 45, 10 46, 9 46, 9 45))'))
+ feat.setAttribute("name", "one")
+ feat.setAttribute("value", 1)
+ feat.setGeometry(
+ QgsGeometry.fromWkt("Polygon ((9 45, 10 45, 10 46, 9 46, 9 45))")
+ )
(ret, features) = vl.dataProvider().addFeatures([feat])
- self.assertEqual(features[0].attributes(), ['one', 1])
+ self.assertEqual(features[0].attributes(), ["one", 1])
self.assertEqual(vl.featureCount(), 1)
# Test change attributes
# Transaction response with 1 feature changed
- shutil.copy(os.path.join(TEST_DATA_DIR, 'provider', 'wfst-1-1', 'transaction_response_feature_changed.xml'), sanitize(endpoint, f'?SERVICE=WFS&POSTDATA=ws1:name one-one-one ws1:value 111 '))
-
- self.assertTrue(vl.dataProvider().changeAttributeValues({1: {0: 'one-one-one', 1: 111}}))
- self.assertEqual(next(vl.dataProvider().getFeatures()).attributes(), ['one-one-one', 111])
+ shutil.copy(
+ os.path.join(
+ TEST_DATA_DIR,
+ "provider",
+ "wfst-1-1",
+ "transaction_response_feature_changed.xml",
+ ),
+ sanitize(
+ endpoint,
+ f'?SERVICE=WFS&POSTDATA=ws1:name one-one-one ws1:value 111 ',
+ ),
+ )
+
+ self.assertTrue(
+ vl.dataProvider().changeAttributeValues({1: {0: "one-one-one", 1: 111}})
+ )
+ self.assertEqual(
+ next(vl.dataProvider().getFeatures()).attributes(), ["one-one-one", 111]
+ )
# Test change geometry
# Transaction response with 1 feature changed
- shutil.copy(os.path.join(TEST_DATA_DIR, 'provider', 'wfst-1-1', 'transaction_response_feature_changed.xml'), sanitize(endpoint, f'?SERVICE=WFS&POSTDATA=ws1:geometry<_Name>46 10 46 11 47 11 47 10 46 10<_gml:posList><_gml:LinearRing><_gml:exterior><_gml:Polygon><_Value><_Property><_Filter><_Update><_Transaction>'))
-
- new_geom = QgsGeometry.fromWkt('Polygon ((10 46, 11 46, 11 47, 10 47, 10 46))')
+ shutil.copy(
+ os.path.join(
+ TEST_DATA_DIR,
+ "provider",
+ "wfst-1-1",
+ "transaction_response_feature_changed.xml",
+ ),
+ sanitize(
+ endpoint,
+ f'?SERVICE=WFS&POSTDATA=ws1:geometry<_Name>