Move description file parsing out to separate class

This commit is contained in:
Nyall Dawson 2023-12-05 11:42:24 +10:00
parent 16ad840d63
commit 83d6ea461b
2 changed files with 127 additions and 63 deletions

View File

@ -74,9 +74,10 @@ with warnings.catch_warnings():
from processing.core.ProcessingConfig import ProcessingConfig
from processing.core.parameters import getParameterFromString
from grassprovider.Grass7Utils import Grass7Utils
from grassprovider.Grass7Utils import (
Grass7Utils,
ParsedDescription
)
from processing.tools.system import isWindows, getTempFilename
@ -103,7 +104,7 @@ class Grass7Algorithm(QgsProcessingAlgorithm):
QgsProcessing.TypeVectorLine: 'line',
QgsProcessing.TypeVectorPolygon: 'area'}
def __init__(self, descriptionfile):
def __init__(self, descriptionfile: Path):
super().__init__()
self._name = ''
self._display_name = ''
@ -119,7 +120,7 @@ class Grass7Algorithm(QgsProcessingAlgorithm):
self.outputCommands = []
self.exportedLayers = {}
self.fileOutputs = {}
self.descriptionFile = descriptionfile
self.descriptionFile: Path = descriptionfile
# Default GRASS parameters
self.region = None
@ -207,54 +208,17 @@ class Grass7Algorithm(QgsProcessingAlgorithm):
"""
Create algorithm parameters and outputs from a text file.
"""
with self.descriptionFile.open() as lines:
# First line of the file is the Grass algorithm name
line = lines.readline().strip('\n').strip()
self.grass7Name = line
# Second line if the algorithm name in Processing
line = lines.readline().strip('\n').strip()
self._short_description = line
if " - " not in line:
self._name = self.grass7Name
else:
self._name = line[:line.find(' ')].lower()
self._short_description = QCoreApplication.translate("GrassAlgorithm", line)
self._display_name = self._name
# Read the grass group
line = lines.readline().strip('\n').strip()
self._group = QCoreApplication.translate("GrassAlgorithm", line)
self._groupId = self.groupIdRegex.search(line).group(0).lower()
hasRasterOutput = False
hasRasterInput = False
hasVectorInput = False
vectorOutputs = False
# Then you have parameters/output definition
line = lines.readline().strip('\n').strip()
while line != '':
try:
line = line.strip('\n').strip()
if line.startswith('Hardcoded'):
self.hardcodedStrings.append(line[len('Hardcoded|'):])
parameter = getParameterFromString(line, "GrassAlgorithm")
if parameter is not None:
self.params.append(parameter)
if isinstance(parameter, (QgsProcessingParameterVectorLayer, QgsProcessingParameterFeatureSource)):
hasVectorInput = True
elif isinstance(parameter, QgsProcessingParameterRasterLayer):
hasRasterInput = True
elif isinstance(parameter, QgsProcessingParameterMultipleLayers):
if parameter.layerType() < 3 or parameter.layerType() == 5:
hasVectorInput = True
elif parameter.layerType() == 3:
hasRasterInput = True
elif isinstance(parameter, QgsProcessingParameterVectorDestination):
vectorOutputs = True
elif isinstance(parameter, QgsProcessingParameterRasterDestination):
hasRasterOutput = True
line = lines.readline().strip('\n').strip()
except Exception as e:
QgsMessageLog.logMessage(self.tr('Could not open GRASS GIS 7 algorithm: {0}\n{1}').format(self.descriptionFile, line), self.tr('Processing'), Qgis.Critical)
raise e
results = ParsedDescription.parse_description_file(
self.descriptionFile)
self.grass7Name = results.grass_command
self._name = results.name
self._short_description = results.short_description
self._display_name = results.display_name
self._group = results.group
self._groupId = results.group_id
self.hardcodedStrings = results.hardcoded_strings[:]
self.params = results.params
param = QgsProcessingParameterExtent(
self.GRASS_REGION_EXTENT_PARAMETER,
@ -264,7 +228,7 @@ class Grass7Algorithm(QgsProcessingAlgorithm):
param.setFlags(param.flags() | QgsProcessingParameterDefinition.FlagAdvanced)
self.params.append(param)
if hasRasterOutput or hasRasterInput:
if results.has_raster_output or results.has_raster_input:
# Add a cellsize parameter
param = QgsProcessingParameterNumber(
self.GRASS_REGION_CELLSIZE_PARAMETER,
@ -275,7 +239,7 @@ class Grass7Algorithm(QgsProcessingAlgorithm):
param.setFlags(param.flags() | QgsProcessingParameterDefinition.FlagAdvanced)
self.params.append(param)
if hasRasterOutput:
if results.has_raster_output:
# Add a createopt parameter for format export
param = QgsProcessingParameterString(
self.GRASS_RASTER_FORMAT_OPT,
@ -296,7 +260,7 @@ class Grass7Algorithm(QgsProcessingAlgorithm):
param.setHelp(self.tr('Metadata options should be comma separated'))
self.params.append(param)
if hasVectorInput:
if results.has_vector_input:
param = QgsProcessingParameterNumber(self.GRASS_SNAP_TOLERANCE_PARAMETER,
self.tr('v.in.ogr snap tolerance (-1 = no snap)'),
type=QgsProcessingParameterNumber.Double,
@ -312,7 +276,7 @@ class Grass7Algorithm(QgsProcessingAlgorithm):
param.setFlags(param.flags() | QgsProcessingParameterDefinition.FlagAdvanced)
self.params.append(param)
if vectorOutputs:
if results.has_vector_outputs:
# Add an optional output type
param = QgsProcessingParameterEnum(self.GRASS_OUTPUT_TYPE_PARAMETER,
self.tr('v.out.ogr output type'),

View File

@ -23,19 +23,119 @@ import stat
import shutil
import subprocess
import os
import re
import sys
from dataclasses import (
dataclass,
field
)
from pathlib import Path
from typing import (
Optional,
List
)
from qgis.core import (Qgis,
QgsApplication,
QgsProcessingUtils,
QgsMessageLog,
QgsCoordinateReferenceSystem,
QgsProcessingContext)
from qgis.core import (
Qgis,
QgsApplication,
QgsProcessingUtils,
QgsMessageLog,
QgsCoordinateReferenceSystem,
QgsProcessingContext,
QgsProcessingParameterDefinition,
QgsProcessingParameterVectorLayer,
QgsProcessingParameterFeatureSource,
QgsProcessingParameterRasterLayer,
QgsProcessingParameterMultipleLayers,
QgsProcessingParameterVectorDestination,
QgsProcessingParameterRasterDestination
)
from qgis.PyQt.QtCore import QCoreApplication
from processing.core.ProcessingConfig import ProcessingConfig
from processing.tools.system import userFolder, isWindows, isMac, mkdir
from processing.algs.gdal.GdalUtils import GdalUtils
from processing.core.parameters import getParameterFromString
@dataclass
class ParsedDescription:
"""
Results of parsing a description file
"""
GROUP_ID_REGEX = re.compile(r'^[^\s\(]+')
grass_command: Optional[str] = None
short_description: Optional[str] = None
name: Optional[str] = None
display_name: Optional[str] = None
group: Optional[str] = None
group_id: Optional[str] = None
has_raster_input: bool = False
has_vector_input: bool = False
has_raster_output: bool = False
has_vector_outputs: bool = False
hardcoded_strings: List[str] = field(default_factory=list)
params: List[QgsProcessingParameterDefinition] = field(default_factory=list)
@staticmethod
def parse_description_file(description_file: Path) -> 'ParsedDescription':
"""
Parses a description file and returns the result
"""
result = ParsedDescription()
with description_file.open() as lines:
# First line of the file is the Grass algorithm name
line = lines.readline().strip('\n').strip()
result.grass_command = line
# Second line if the algorithm name in Processing
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.short_description = QCoreApplication.translate("GrassAlgorithm", line)
result.display_name = result.name
# Read the grass group
line = lines.readline().strip('\n').strip()
result.group = QCoreApplication.translate("GrassAlgorithm", line)
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 != '':
try:
line = line.strip('\n').strip()
if line.startswith('Hardcoded'):
result.hardcoded_strings.append(line[len('Hardcoded|'):])
parameter = getParameterFromString(line, "GrassAlgorithm")
if parameter is not None:
result.params.append(parameter)
if isinstance(parameter, (QgsProcessingParameterVectorLayer, QgsProcessingParameterFeatureSource)):
result.has_vector_input = True
elif isinstance(parameter, QgsProcessingParameterRasterLayer):
result.has_raster_input = True
elif isinstance(parameter, QgsProcessingParameterMultipleLayers):
if parameter.layerType() < 3 or parameter.layerType() == 5:
result.has_vector_input = True
elif parameter.layerType() == 3:
result.has_raster_input = True
elif isinstance(parameter, QgsProcessingParameterVectorDestination):
result.has_vector_outputs = True
elif isinstance(parameter, QgsProcessingParameterRasterDestination):
result.has_raster_output = True
line = lines.readline().strip('\n').strip()
except Exception as e:
QgsMessageLog.logMessage(
QCoreApplication.translate("GrassAlgorithm", 'Could not open GRASS GIS 7 algorithm: {0}\n{1}').format(description_file, line),
QCoreApplication.translate("GrassAlgorithm", 'Processing'), Qgis.Critical)
raise e
return result
class Grass7Utils: