123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216 |
- ########################################################################
- # Searx-Qt - Lightweight desktop application for Searx.
- # Copyright (C) 2020-2022 CYBERDEViL
- #
- # This file is part of Searx-Qt.
- #
- # Searx-Qt is free software: you can redistribute it and/or modify
- # it under the terms of the GNU General Public License as published by
- # the Free Software Foundation, either version 3 of the License, or
- # (at your option) any later version.
- #
- # Searx-Qt is distributed in the hope that it will be useful,
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- # GNU General Public License for more details.
- #
- # You should have received a copy of the GNU General Public License
- # along with this program. If not, see <https://www.gnu.org/licenses/>.
- #
- ########################################################################
- from searxqt.core import log
- class ValueBase:
- """ Base for evaluatable data type(s).
- """
- def evaluate(self, valueType):
- return False
- class Value(ValueBase):
- """ Evaluatable data type.
- """
- def __init__(self, dataType):
- """
- @param dataType: The data type this should match.
- @type dataType: type
- """
- self.__dataType = dataType
- def __repr__(self):
- return str(self)
- def __str__(self):
- return str(self.__dataType)
- def evaluate(self, valueType):
- if valueType is self.__dataType:
- return True
- return False
- class MultiValue(ValueBase):
- """ For when multiple data types may be valid.
- """
- def __init__(self, dataTypes):
- """
- @param dataTypes: A tuple with one or more acceptable data types.
- @type dataTypes: tuple(type, ..)
- """
- self.__dataTypes = dataTypes
- def __repr__(self):
- return str(self)
- def __str__(self):
- return "({0})".format(
- ", ".join([str(dataType) for dataType in self.__dataTypes])
- )
- def evaluate(self, valueType):
- if valueType in self.__dataTypes:
- return True
- return False
- class IgnoreValue:
- """ Use a instance of this class to ignore a value.
- """
- pass
- NoneType = type(None)
- def verifyStructure(structure, data, path="root"):
- """
- - Verify data types of defined data structure.
- - Warn on unknown keys in dict.
- @param structure: Expected data structure
- @type structure: any
- @param data: Data to compare with the expected structure.
- @type data: any
- @param path: This is only used to keep track of where a issue occured.
- @type path: str
- @return: Verification status and error message.
- @rtype: tuple(bool, str)
- """
- dataType = type(data)
- structureType = type(structure)
- # Verify if the current data has the expected type.
- if isinstance(structure, ValueBase):
- # Multiple types may be valid.
- if not structure.evaluate(dataType):
- error = (
- f"Mismatched! (1) Expected a `{str(structure)}` but got"
- f" `{str(dataType)}` for {path}"
- )
- return (False, error)
- elif structureType is IgnoreValue:
- # Struct says ignore this check.
- return (True, "")
- elif dataType != structureType:
- # Data value isn't of expected type.
- error = (
- f"Mismatched! (2) Expected a `{structureType}` but got"
- f" `{dataType}` for {path}"
- )
- return (False, error)
- # Recurse iterable objects.
- if dataType is dict:
- if not data:
- # Empty data dict, nothing to evaluate.
- return (True, "")
- elif not structure:
- # Empty dict structure; skip check.
- return (True, "")
- if "" in structure:
- # The key is variabble
- for key in data:
- verified, error = verifyStructure(
- structure[""],
- data[key],
- path=f"{path}['{key}']"
- )
- if not verified:
- return (False, error)
- else:
- # Constant key
- for key in data:
- if key not in structure:
- log.warning(
- f"Unknown key '{key}' '{type(data[key])}' '{path}'"
- )
- continue
- verified, error = verifyStructure(
- structure[key],
- data[key],
- path=f"{path}['{key}']"
- )
- if not verified:
- return (False, error)
- elif dataType is list:
- if not data:
- # Empty data list, nothing to evaluate.
- return (True, "")
- elif not structure:
- # Empty list structure; skip check.
- return (True, "")
- structLen = len(structure)
- if structLen == 1:
- # Repeated match
- index = 0
- for value in data:
- verified, error = verifyStructure(
- structure[0],
- value,
- path=f"{path}['{index}']"
- )
- if not verified:
- return (False, error)
- index += 1
- elif structLen != len(data):
- # Mismatch!
- return (
- False,
- (
- f"Expected a fixed length of {structLen} elements but got"
- f" a length of {len(data)} elements instead for path:"
- f" {path}"
- )
- )
- else:
- # Structure within list (fixed length)
- index = 0
- for value in structure:
- verified, error = verifyStructure(
- value,
- data[index],
- path=f"{path}['{index}']"
- )
- if not verified:
- return (False, error)
- index += 1
- return (True, "")
|