Skip to content
Snippets Groups Projects
validate.py 4.38 KiB
Newer Older
##############################################################################
#
#    Converter Odoo module
Vincent Hatakeyama's avatar
Vincent Hatakeyama committed
#    Copyright © 2020, 2024 XCG Consulting <https://xcg-consulting.fr>
#
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU Affero General Public License as
#    published by the Free Software Foundation, either version 3 of the
#    License, or (at your option) any later version.
#
#    This program 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 Affero General Public License for more details.
#
#    You should have received a copy of the GNU Affero General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from enum import StrEnum
Vincent Hatakeyama's avatar
Vincent Hatakeyama committed
from typing import Any, LiteralString
from odoo.exceptions import UserError  # type: ignore[import-untyped]

_fastjsonschema: None | Exception = None
try:
    import fastjsonschema  # type: ignore[import-untyped]
except ImportError as e:
    _fastjsonschema = e


Vincent Hatakeyama's avatar
Vincent Hatakeyama committed

class Validation(StrEnum):
Vincent Hatakeyama's avatar
Vincent Hatakeyama committed
    """Type of validation"""

    SKIP = "skip"
    SOFT = "soft"
    STRICT = "strict"
def _add_schema(schemas, schema):
    if "$id" in schema:
        schemas[schema["$id"]] = schema
    else:
        _logger.warning("Schema without $id (schema ignored)")


        """
        :param package_name: Package where the schema can be found
        :param default_url_pattern: pattern for url ({} will be replaced by $id)
        :param directory: directory to search for json, not used if a get_schema is
        provided in the package.
        """
        self.package_name = package_name
        # exemple "https://annonces-legales.fr/xbus/schemas/v1/{}.schema.json"
        self.default_url_pattern = default_url_pattern
        self.initialized = False
        self.encoding = "UTF-8"
        if self.initialized:
            return
        schemas: dict[LiteralString, Any] = {}
        module = import_module(self.package_name)
        if hasattr(module, "get_schemas"):
            for schema in module.get_schemas():
                _add_schema(schemas, schema)
        else:
            if module.__file__ is None:
                # XXX maybe not the best type of error
                raise UserError("Module %s has no file", self.package_name)
            # Fallback on searching schema json files
            schema_search_path = os.path.dirname(module.__file__)
            schema_search_path = os.path.abspath(
                os.path.join(schema_search_path, self.directory)
                if self.directory is not None
                else schema_search_path
            )
            for root, _dirs, files in os.walk(schema_search_path):
                for fname in files:
                    fpath = os.path.join(root, fname)
                    if fpath.endswith((".json",)):
                        with open(fpath, encoding=self.encoding) as schema_fd:
                            schema = json.load(schema_fd)
                            _add_schema(schemas, schema)

        # Prepare validators for each schema. We add an HTTPS handler that
        # points back to our schema definition cache built above.
        for schema_id, schema in schemas.items():
            if _fastjsonschema is not None:
                raise _fastjsonschema
            self.validators[schema_id] = fastjsonschema.compile(
                schema,
                handlers={"https": lambda uri: schemas[uri]},
                use_default=False,
            )
Vincent Hatakeyama's avatar
Vincent Hatakeyama committed
    def validate(self, schema_id: str, payload) -> None:
        if not self.initialized:
            raise NotInitialized("please call the initialize() method")
        self.validators[self.default_url_pattern.format(schema_id)](payload)