Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ docs/site
/.coverage
/.coverage.xml
/.profile/
/tests/resources/.process_output
1 change: 1 addition & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
services:
qgis-server-light:
image: local/opengisch/qgis-server-light-dev:latest
platform: linux/amd64
build:
context: .
dockerfile: ./Dockerfile
Expand Down
1 change: 1 addition & 0 deletions requirements.test.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ pillow
pixelmatch
mypy
pytest-cov
pillow
34 changes: 32 additions & 2 deletions src/qgis_server_light/exporter/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,19 @@
import os.path

import click
from qgis.analysis import QgsNativeAlgorithms
from qgis.core import QgsApplication
from xsdata.formats.dataclass.serializers import JsonSerializer, XmlSerializer
from xsdata.formats.dataclass.serializers import (
DictEncoder,
JsonSerializer,
XmlSerializer,
)
from xsdata.formats.dataclass.serializers.config import SerializerConfig

from qgis_server_light.exporter.common import create_full_pg_service_conf
from qgis_server_light.exporter.extract import Exporter
from qgis_server_light.interface.exporter.extract import Process
from qgis_server_light.worker.runner.process import algorithm_from_qgs_definition

os.environ["QT_QPA_PLATFORM"] = "offscreen"
QgsApplication.setPrefixPath("/usr", True)
Expand Down Expand Up @@ -93,5 +100,28 @@ def export(
raise AttributeError("Project file does not exist")


@cli.command("export-processes")
def export_processes():
registry = qgs.processingRegistry()
qgs.setTranslation("en")
registry.addProvider(QgsNativeAlgorithms())
process = Process(
algorithms=[
algorithm_from_qgs_definition(registry.algorithmById(alg))
for alg in [
"native:buffer",
"native:centroids",
"native:concavehull",
"native:rasterlayerproperties",
"native:rescaleraster",
"native:collect",
"native:rasterize",
"native:affinetransform",
]
]
)
click.echo(DictEncoder().encode(process))


if __name__ == "__main__":
export()
cli()
191 changes: 190 additions & 1 deletion src/qgis_server_light/exporter/extract.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import logging
import re
import sys
import unicodedata
import zlib
from base64 import urlsafe_b64encode
Expand All @@ -11,6 +12,7 @@
from PyQt5.QtCore import QMetaType
from PyQt5.QtXml import QDomDocument
from qgis.core import (
Qgis,
QgsCoordinateReferenceSystem,
QgsCoordinateTransform,
QgsDataSourceUri,
Expand All @@ -24,6 +26,36 @@
QgsMapLayer,
QgsMeshLayer,
QgsPointCloudLayer,
QgsProcessingAlgorithm,
QgsProcessingOutputBoolean,
QgsProcessingOutputDefinition,
QgsProcessingOutputFile,
QgsProcessingOutputHtml,
QgsProcessingOutputMapLayer,
QgsProcessingOutputNumber,
QgsProcessingOutputRasterLayer,
QgsProcessingOutputString,
QgsProcessingOutputVectorLayer,
QgsProcessingParameterBand,
QgsProcessingParameterBoolean,
QgsProcessingParameterCrs,
QgsProcessingParameterDefinition,
QgsProcessingParameterEnum,
QgsProcessingParameterExpression,
QgsProcessingParameterExtent,
QgsProcessingParameterFeatureSink,
QgsProcessingParameterFeatureSource,
QgsProcessingParameterField,
QgsProcessingParameterFile,
QgsProcessingParameterLayout,
QgsProcessingParameterMapTheme,
QgsProcessingParameterMultipleLayers,
QgsProcessingParameterNumber,
QgsProcessingParameterRasterDestination,
QgsProcessingParameterRasterLayer,
QgsProcessingParameterString,
QgsProcessingParameterVectorDestination,
QgsProcessingParameterVectorLayer,
QgsProject,
QgsProviderRegistry,
QgsRasterLayer,
Expand All @@ -36,6 +68,7 @@

from qgis_server_light.interface.common import BBox, Style
from qgis_server_light.interface.exporter.extract import (
Algorithm,
Config,
Crs,
Custom,
Expand All @@ -46,7 +79,27 @@
Group,
MetaData,
OgrSource,
Output,
Parameter,
PostgresSource,
ProcessingParameterType,
ProcessingParameterTypeAnyLayer,
ProcessingParameterTypeBand,
ProcessingParameterTypeBoolean,
ProcessingParameterTypeCrs,
ProcessingParameterTypeEnum,
ProcessingParameterTypeExpression,
ProcessingParameterTypeExtent,
ProcessingParameterTypeField,
ProcessingParameterTypeFile,
ProcessingParameterTypeFloat,
ProcessingParameterTypeInt,
ProcessingParameterTypeLayout,
ProcessingParameterTypeMapLayer,
ProcessingParameterTypeMapTheme,
ProcessingParameterTypeRasterLayer,
ProcessingParameterTypeString,
ProcessingParameterTypeVectorLayer,
Project,
Raster,
Service,
Expand Down Expand Up @@ -934,7 +987,10 @@ def collect(acc, pair):
acc.append((our_scope_name, list_as_text))
else:
acc.append(
(our_scope_name, project.readEntry(qgis_scope_name, key)[0])
(
our_scope_name,
project.readEntry(qgis_scope_name, key)[0],
)
)

return acc
Expand All @@ -958,3 +1014,136 @@ def create_style_list(qgs_layer: QgsMapLayer) -> List[Style]:
)
)
return style_list


def parameter_type_from_qgs_definition(
param: QgsProcessingParameterDefinition,
) -> ProcessingParameterType:
if isinstance(param, QgsProcessingParameterFeatureSource):
return ProcessingParameterTypeVectorLayer()
if isinstance(param, QgsProcessingParameterVectorLayer):
return ProcessingParameterTypeVectorLayer()
if isinstance(param, QgsProcessingParameterRasterLayer):
return ProcessingParameterTypeRasterLayer()
if isinstance(param, QgsProcessingParameterFile):
return ProcessingParameterTypeFile()
if isinstance(param, QgsProcessingParameterFeatureSink):
return ProcessingParameterTypeVectorLayer()
if isinstance(param, QgsProcessingParameterVectorDestination):
return ProcessingParameterTypeVectorLayer()
if isinstance(param, QgsProcessingParameterRasterDestination):
return ProcessingParameterTypeRasterLayer()
if isinstance(param, QgsProcessingParameterMultipleLayers):
minimum = param.minimumNumberInputs()
match param.layerType():
case Qgis.ProcessingSourceType.MapLayer:
layer_type = ProcessingParameterTypeMapLayer()
case Qgis.ProcessingSourceType.Raster:
layer_type = ProcessingParameterTypeRasterLayer()
case (
Qgis.ProcessingSourceType.Vector
| Qgis.ProcessingSourceType.VectorAnyGeometry
| Qgis.ProcessingSourceType.VectorPoint
| Qgis.ProcessingSourceType.VectorLine
| Qgis.ProcessingSourceType.VectorPolygon
):
layer_type = ProcessingParameterTypeVectorLayer()
case unsupported:
raise ValueError(f"unsupported ProcessingSourceType: {unsupported}")
return ProcessingParameterTypeAnyLayer(
layer_type=layer_type,
minimum=minimum,
)
if isinstance(param, QgsProcessingParameterBand):
return ProcessingParameterTypeBand(allow_multiple=param.allowMultiple())
if isinstance(param, QgsProcessingParameterNumber):
if (maximum := param.maximum()) >= sys.float_info.max:
maximum = None
if (minimum := param.minimum()) <= sys.float_info.min:
minimum = None
match param.dataType():
case Qgis.ProcessingNumberParameterType.Double:
return ProcessingParameterTypeFloat(minimum=minimum, maximum=maximum)
case Qgis.ProcessingNumberParameterType.Integer:
minimum = None if minimum is None else int(minimum)
maximum = None if maximum is None else int(maximum)
return ProcessingParameterTypeInt(minimum=minimum, maximum=maximum)
if isinstance(param, QgsProcessingParameterString):
return ProcessingParameterTypeString()
if isinstance(param, QgsProcessingParameterExpression):
return ProcessingParameterTypeExpression()
if isinstance(param, QgsProcessingParameterCrs):
return ProcessingParameterTypeCrs()
if isinstance(param, QgsProcessingParameterLayout):
return ProcessingParameterTypeLayout()
if isinstance(param, QgsProcessingParameterField):
return ProcessingParameterTypeField(allow_multiple=param.allowMultiple())
if isinstance(param, QgsProcessingParameterEnum):
return ProcessingParameterTypeEnum(
options=param.options(), allow_multiple=param.allowMultiple()
)
if isinstance(param, QgsProcessingParameterBoolean):
return ProcessingParameterTypeBoolean()
if isinstance(param, QgsProcessingParameterExtent):
return ProcessingParameterTypeExtent()
if isinstance(param, QgsProcessingParameterMapTheme):
return ProcessingParameterTypeMapTheme()
else:
logging.error(f"invalid parameter: {param.name()}, {param.type()}, {param}")
raise ValueError(f"parameter: {param}")


def parameter_from_qgs_definition(param: QgsProcessingParameterDefinition) -> Parameter:
return Parameter(
name=param.name(),
type=parameter_type_from_qgs_definition(param),
description=param.description(),
optional=bool(param.flags() & Qgis.ProcessingParameterFlag.Optional),
default=param.defaultValue(),
is_destination=param.isDestination(),
)


def output_type_from_qgs_definition(output: QgsProcessingOutputDefinition) -> Output:
if isinstance(output, QgsProcessingOutputMapLayer):
return ProcessingParameterTypeMapLayer()
elif isinstance(output, QgsProcessingOutputRasterLayer):
return ProcessingParameterTypeRasterLayer()
elif isinstance(output, QgsProcessingOutputVectorLayer):
return ProcessingParameterTypeVectorLayer()
elif isinstance(output, QgsProcessingOutputFile):
return ProcessingParameterTypeFile()
elif isinstance(output, QgsProcessingOutputHtml):
return ProcessingParameterTypeString()
elif isinstance(output, QgsProcessingOutputNumber):
return ProcessingParameterTypeFloat()
elif isinstance(output, QgsProcessingOutputString):
return ProcessingParameterTypeString()
elif isinstance(output, QgsProcessingOutputBoolean):
return ProcessingParameterTypeBoolean()
else:
logging.error(f"invalid output: {output.name()}, {output.type()}, {output}")
raise ValueError(f"output: {output}")


def output_from_qgs_definition(output: QgsProcessingOutputDefinition) -> Output:
return Output(
name=output.name(),
description=output.description(),
type=output_type_from_qgs_definition(output),
)


def algorithm_from_qgs_definition(alg: QgsProcessingAlgorithm) -> Algorithm:
algorithm = Algorithm(
id=alg.id(),
name=alg.name(),
display_name=alg.displayName(),
short_help_string=alg.shortHelpString(),
short_description=alg.shortDescription(),
)
for param in alg.parameterDefinitions():
algorithm.parameters.append(parameter_from_qgs_definition(param))
for output in alg.outputDefinitions():
algorithm.outputs.append(output_from_qgs_definition(output))
return algorithm
9 changes: 9 additions & 0 deletions src/qgis_server_light/interface/dispatcher/redis_asio.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@
QslJobInfoLegend,
QslJobParameterLegend,
)
from qgis_server_light.interface.job.process.input import (
QslJobInfoExecuteProcess,
QslJobParameterExecuteProcess,
)
from qgis_server_light.interface.job.render.input import (
QslJobInfoRender,
QslJobParameterRender,
Expand Down Expand Up @@ -83,6 +87,7 @@ async def post(
| QslJobParameterFeatureInfo
| QslJobParameterLegend
| QslJobParameterFeature
| QslJobParameterExecuteProcess
),
to: float = 10.0,
) -> tuple[JobResult, str]:
Expand Down Expand Up @@ -113,6 +118,10 @@ async def post(
job_info = QslJobInfoFeature(
id=job_id, type=QslJobInfoFeature.__name__, job=job_parameter
)
elif isinstance(job_parameter, QslJobParameterExecuteProcess):
job_info = QslJobInfoExecuteProcess(
id=job_id, type=QslJobInfoExecuteProcess.__name__, job=job_parameter
)
else:
return (
JobResult(
Expand Down
Loading
Loading