Source code for gemseo.core.grammars.json_schema

# -*- coding: utf-8 -*-
# Copyright 2021 IRT Saint Exupéry, https://www.irt-saintexupery.com
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License version 3 as published by the Free Software Foundation.
#
# 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
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

"""JSON schema handler."""

from gemseo.utils.py23_compat import PY2

if PY2:
    from collections import ItemsView, KeysView, Mapping, ValuesView
else:
    from collections.abc import ItemsView, KeysView, Mapping, ValuesView

from genson import SchemaBuilder
from genson.schema.strategies import Object


class _MergeRequiredStrategy(Object):
    """A genson Object with a modified required attribute handling.

    Genson Object does not merge the required attribute on purpose.
    See :ref:`https://github.com/wolverdude/GenSON#genson`.
    This class will merge the required attributes.
    """

    # Do not merge the name and id properties.
    KEYWORDS = Object.KEYWORDS + ("name", "id")

    def add_schema(self, schema):
        """Add a schema and merge the required attribute.

        Args:
            schema: A schema to be added.
        """
        if "required" not in schema or self._required is None:
            super(_MergeRequiredStrategy, self).add_schema(schema)
        else:
            required = set(self._required)
            super(_MergeRequiredStrategy, self).add_schema(schema)
            self._required = required | set(schema["required"])

    def add_object(self, obj):
        """Add an object and merge the required attribute.

        Args:
            obj: An object to be added.
        """
        if self._required is None:
            super(_MergeRequiredStrategy, self).add_object(obj)
        else:
            required = set(self._required)
            super(_MergeRequiredStrategy, self).add_object(obj)
            self._required = required | set(obj.keys())


[docs]class MutableMappingSchemaBuilder(SchemaBuilder): """A mutable genson SchemaBuilder with a dictionary-like interface. The mutability is provided by the ability to delete a property. """ EXTRA_STRATEGIES = (_MergeRequiredStrategy,)
[docs] def get(self, key, default=None): """Implement the standard mapping getter. Args: key: A key whose mapped value shall be returned. default: The default value returned if the key is missing. Returns: The value mapped to key if it exists, default otherwise. """ try: return self[key] except KeyError: return default
def __contains__(self, key): try: self[key] except KeyError: return False else: return True
[docs] def keys(self): """Return the keys. Returns: The keys. """ return KeysView(self)
[docs] def items(self): """Return the pairs of key and mapped value. Returns: The pairs of key and mapped value. """ return ItemsView(self)
[docs] def values(self): """Return the values. Returns: The values. """ return ValuesView(self)
def __eq__(self, other): if not isinstance(other, Mapping): return NotImplemented return dict(self.items()) == dict(other.items()) __reversed__ = None @property def _properties(self): """Return the properties. Returns: The existing properties, otherwise an empty dictionary. """ try: return self._root_node._active_strategies[0]._properties except AttributeError: return {} def __getitem__(self, key): return self._properties[key] def __iter__(self): return iter(self._properties) def __len__(self): return len(self._properties) def __delitem__(self, key): del self._properties[key] try: self._root_node._active_strategies[0]._required.remove(key) except IndexError: pass # For backward compatibility # TODO: add deprecation warning to_dict = SchemaBuilder.to_schema