Skip to content

Commit

Permalink
Merge pull request #374 from chrstnbwnkl/add_logical_operators_to_pro…
Browse files Browse the repository at this point in the history
…cessing_algos

Add logical operators to processing algos
  • Loading branch information
Gustry authored Aug 7, 2024
2 parents dff9d11 + 2878a6c commit 7aa852f
Show file tree
Hide file tree
Showing 6 changed files with 90 additions and 1 deletion.
39 changes: 39 additions & 0 deletions QuickOSM/core/query_factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,8 @@ def __init__(
"""
if isinstance(type_multi_request, list):
self._type_multi_request = [x for x in type_multi_request if x]
elif isinstance(type_multi_request, str):
self._type_multi_request = self._convert_to_multitypes(type_multi_request)
else:
self._type_multi_request = []

Expand Down Expand Up @@ -154,6 +156,32 @@ def area(self) -> list:
"""
return self._area

@staticmethod
def _convert_to_multitypes(type_multi_request: str) -> List[MultiType]:
"""Converts a string of comma separated 'AND'/'OR's to a list of MultiType equivalents.
:param type_multi_request: A string of comma separated 'AND'/'OR's provided from input of processing
algorithms
:type type_multi_request: str
:return: list of MultiType
:rtype: list
:raise QueryFactoryException:
"""
types = []
if type_multi_request:
for type_ in type_multi_request.split(','):
type_ = type_.strip()
if type_ == 'AND':
types.append(MultiType.AND)
elif type_ == 'OR':
types.append(MultiType.OR)
else:
raise QueryFactoryException(
tr('Only values "AND"/"OR" are allowed as logical operators.'))
return types

def _check_parameters(self) -> bool:
"""Internal function to check that the query can be built.
Expand Down Expand Up @@ -214,6 +242,17 @@ def _check_parameters(self) -> bool:
raise QueryFactoryException(
tr(f'Key "{key}" contains leading or trailing whitespace.'))

if len(self._key) != 0:
if len(self._type_multi_request) > len(self._key) - 1:
raise QueryFactoryException(
tr('Too many logical operators were provided.')
)

if len(self._type_multi_request) < len(self._key) - 1:
raise QueryFactoryException(
tr('Not enough logical operators were provided.')
)

self._checked = True
return True

Expand Down
1 change: 1 addition & 0 deletions QuickOSM/quick_osm_processing/advanced/build_query.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ def initAlgorithm(self, config=None):
def build_query(self) -> Dict[str, str]:
"""Build the query requested."""
query_factory = QueryFactory(
type_multi_request=self.type_multi_request,
query_type=self.QUERY_TYPE,
key=self.key,
value=self.value,
Expand Down
16 changes: 16 additions & 0 deletions QuickOSM/quick_osm_processing/build_input.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,18 +141,21 @@ class BuildBasedQuery(BuildBased):

KEY = 'KEY'
VALUE = 'VALUE'
TYPE_MULTI_REQUEST = 'TYPE_MULTI_REQUEST'

def __init__(self):
super().__init__()
self.key = None
self.value = None
self.type_multi_request = None
self.distance = None

def fetch_based_parameters(self, parameters, context):
"""Get the parameters."""
super().fetch_based_parameters(parameters, context)
self.key = self.parameterAsString(parameters, self.KEY, context)
self.value = self.parameterAsString(parameters, self.VALUE, context)
self.type_multi_request = self.parameterAsString(parameters, self.TYPE_MULTI_REQUEST, context)

def add_top_parameters(self):
"""Set up the parameters."""
Expand Down Expand Up @@ -180,6 +183,19 @@ def add_top_parameters(self):
param.setHelp(help_string)
self.addParameter(param)

param = QgsProcessingParameterString(
self.TYPE_MULTI_REQUEST,
tr('Operator types to combine multiple keys and values with'),
optional=True
)

# TODO: expand help string
help_string = tr(
'The logical operators used to combine keys and values, if there are multiple.'
)
param.setHelp(help_string)
self.addParameter(param)


class BuildBasedNotSpatialQuery(BuildBasedQuery):
"""Set up the parameters for a not spatial query."""
Expand Down
4 changes: 4 additions & 0 deletions QuickOSM/quick_osm_processing/quickosm_process.py
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,7 @@ def processAlgorithm(self, parameters, context, feedback):
'KEY': self.key,
'SERVER': self.server,
'TIMEOUT': self.timeout,
'TYPE_MULTI_REQUEST': self.type_multi_request,
'VALUE': self.value
},
feedback=self.feedback
Expand Down Expand Up @@ -342,6 +343,7 @@ def processAlgorithm(self, parameters, context, feedback):
'KEY': self.key,
'SERVER': self.server,
'TIMEOUT': self.timeout,
'TYPE_MULTI_REQUEST': self.type_multi_request,
'VALUE': self.value
},
feedback=self.feedback
Expand Down Expand Up @@ -389,6 +391,7 @@ def processAlgorithm(self, parameters, context, feedback):
'KEY': self.key,
'SERVER': self.server,
'TIMEOUT': self.timeout,
'TYPE_MULTI_REQUEST': self.type_multi_request,
'VALUE': self.value
},
feedback=self.feedback
Expand Down Expand Up @@ -435,6 +438,7 @@ def processAlgorithm(self, parameters, context, feedback):
'KEY': self.key,
'SERVER': self.server,
'TIMEOUT': self.timeout,
'TYPE_MULTI_REQUEST': self.type_multi_request,
'VALUE': self.value
},
feedback=self.feedback
Expand Down
29 changes: 29 additions & 0 deletions QuickOSM/test/test_processing.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,35 @@ def test_build_in_extent_query(self):

self.assertEqual(result_expected, result)

def test_build_in_extent_query_with_multitypes(self):
"""Test for the build of an in extent algorithm that uses the multitypes parameter."""
result = processing.run(
'quickosm:buildqueryextent',
{
'EXTENT': '8.71679,8.79689,51.70687,51.72602 [EPSG:4326]',
'KEY': 'highway,footway',
'SERVER': 'https://lz4.overpass-api.de/api/interpreter',
'TIMEOUT': 25,
'TYPE_MULTI_REQUEST': 'AND',
'VALUE': 'footway,sidewalk'
}
)
result_expected = {
'OUTPUT_OQL_QUERY':
'[out:xml] [timeout:25];\n(\n node["highway"="footway"]["footway"="sidewalk"]'
'( 51.70687,8.71679,51.72602,8.79689);\n way["highway"="footway"]["footway"="sidewalk"]'
'( 51.70687,8.71679,51.72602,8.79689);\n relation["highway"="footway"]'
'["footway"="sidewalk"]( 51.70687,8.71679,51.72602,8.79689);\n);\n(._;>;);\nout body;',
'OUTPUT_URL':
'https://lz4.overpass-api.de/api/interpreter?data=[out:xml] [timeout:25];%0A(%0A'
' node[%22highway%22%3D%22footway%22][%22footway%22%3D%22sidewalk%22]'
'( 51.70687,8.71679,51.72602,8.79689);%0A way[%22highway%22%3D%22footway%22]'
'[%22footway%22%3D%22sidewalk%22]( 51.70687,8.71679,51.72602,8.79689);%0A '
'relation[%22highway%22%3D%22footway%22][%22footway%22%3D%22sidewalk%22]'
'( 51.70687,8.71679,51.72602,8.79689);%0A);%0A(._;%3E;);%0Aout body;&info=QgisQuickOSMPlugin'
}
self.assertEqual(result_expected, result)

def test_build_raw_query(self):
"""Test for the build of a raw query algorithm."""
result = processing.run(
Expand Down
2 changes: 1 addition & 1 deletion QuickOSM/test/test_query_factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ def test_impossible_queries(self):
"""Test queries which are not possible and must raise an exception."""
# Query type
# noinspection PyTypeChecker
query = QueryFactory('fake_query_type', area='foo')
query = QueryFactory(query_type='fake_query_type', area='foo')
msg = 'Wrong query type.'
with self.assertRaisesRegex(QueryFactoryException, msg):
query._check_parameters()
Expand Down

0 comments on commit 7aa852f

Please sign in to comment.