# ------------------------------------------------------------------------------
#
# Project: pyows <http://eoxserver.org>
# Authors: Fabian Schindler <fabian.schindler@eox.at>
#
# ------------------------------------------------------------------------------
# Copyright (C) 2019 EOX IT Services GmbH
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies of this Software or works derived from this Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
# ------------------------------------------------------------------------------
""" This module contains facilities to help decoding KVP strings.
"""
from urllib.parse import parse_qs
from typing import Iterable
from .decoder import BaseParameter, BaseDecoder, NO_DEFAULT
[docs]class Parameter(BaseParameter):
""" Parameter for KVP values.
:param key: the lookup key; defaults to the property name of the
:class:`Decoder`
:param type: the type to parse the raw value; by default the raw
string is returned
:param num: defines how many times the key can be present; use any
numeric value to set it to a fixed count, "*" for any
number, "?" for zero or one time or "+" for one or more
times
:param default: the default value
:param default_factory: the default value factory
:param locator: override the locator in case of exceptions
"""
key = None
def __init__(self, key=None, type=None, num=1, default=NO_DEFAULT,
default_factory=None, locator=None):
super().__init__(type, num, default, default_factory)
self.key = key.lower() if key is not None else None
self._locator = locator
[docs] def select(self, decoder, decoder_class=None):
return [
value for value in decoder._query_dict.get(self.key, [])
if value != ""
]
@property
def locator(self):
return self._locator or self.key
[docs]class MultiParameter(Parameter):
""" Class for selecting different KVP parameters at once.
:param selector: a function to determine if a key is used for the multi
parameter selection
:param num: defines how many times the key can be present; use any
numeric value to set it to a fixed count, "*" for any
number, "?" for zero or one time or "+" for one or more
times
:param default: the default value
:param locator: override the locator in case of exceptions
"""
def __init__(self, selector, num=1, default=None, locator=None):
super(MultiParameter, self).__init__(
"", lambda s: s, num, default, locator
)
self.key = selector
[docs] def select(self, decoder):
result = []
for key, values in decoder._query_dict.items():
if self.key(key):
result.append((key, values))
return result
[docs]class Decoder(BaseDecoder, metaclass=DecoderMetaclass):
""" Base class for KVP decoders.
:param params: an instance of either :class:`dict`,
:class:`django.http.QueryDict` or :class:`basestring` (which
will be parsed using :func:`cgi.parse_qs`)
Decoders should be used as such:
::
from ows import kvp, typelist
class ExampleDecoder(kvp.Decoder):
mandatory_param = kvp.Parameter(num=1)
list_param = kvp.Parameter(type=typelist(separator=","))
multiple_param = kvp.Parameter("multi", num="+")
optional_param = kvp.Parameter(num="?", default="default_value")
decoder = ExampleDecoder(
"mandatory_param=value"
"&list_param=a,b,c"
"&multi=a&multi=b&multi=c"
)
print(decoder.mandatory_param)
print(decoder.list_param)
print(decoder.multiple_param)
print(decoder.optional_param)
"""
def __init__(self, params):
query_dict = {}
if isinstance(params, str):
tmp = parse_qs(params)
for key, values in tmp.items():
query_dict[key.lower()] = values
elif isinstance(params, dict):
for key, value in params.items():
query_dict[key.lower()] = [value]
elif isinstance(params, Iterable):
for key, value in params:
value = value if isinstance(value, (tuple, list)) else [value]
query_dict[key.lower()] = value
else:
raise ValueError(
"Decoder input '%s' not supported." % type(params).__name__
)
self.kvp = params
self._query_dict = query_dict