Esempio n. 1
0
def add_type_from_schema(path_to_schema, **kwargs):
    r"""Add a type from a schema in a file.

    Args:
        path_to_schema (string): Full path to the location of a schema file that
            can be loaded.
        target_globals (dict, optional): Globals dictionary for module where the
            fixed class should be added. If None, the new class is returned.
            Defaults to local globals.
        **kwargs: Additional keyword arguments are assumed to be attributes for
            the new class.

    """
    from yggdrasil.metaschema.datatypes.FixedMetaschemaType import (
        create_fixed_type_class)
    if 'target_globals' not in kwargs:
        kwargs['target_globals'] = globals()
    if not os.path.isfile(path_to_schema):
        raise ValueError("The 'path_to_schema' attribute is not a valid path: "
                         + "'%s'" % path_to_schema)
    with open(path_to_schema, 'r') as fd:
        out = decode_json(fd)
    jsonschema.validate(out, {'type': 'object',
                              'required': ['title', 'description', 'type']})
    name = out['title']
    if _type_registry.has_entry(name):
        assert(kwargs['target_globals'] is not None)
        return name
    description = out['description']
    base = get_type_class(out['type'])
    fixed_properties = out
    return create_fixed_type_class(name, description, base, fixed_properties,
                                   loaded_schema_file=path_to_schema, **kwargs)
Esempio n. 2
0
    def func_deserialize(self, msg):
        r"""Deserialize a message.

        Args:
            msg (str, bytes): Message to be deserialized.

        Returns:
            obj: Deserialized Python object.

        """
        return decode_json(msg)
Esempio n. 3
0
def get_schema():
    r"""Return the Obj schema, initializing it if necessary.

    Returns:
        dict: Obj schema.
    
    """
    if not os.path.isfile(_schema_file):
        create_schema()
    with open(_schema_file, 'r') as fd:
        out = decode_json(fd)
    return out
Esempio n. 4
0
    def func_deserialize(self, msg):
        r"""Deserialize a message.

        Args:
            msg (str, bytes): Message to be deserialized.

        Returns:
            obj: Deserialized Python object.

        """
        out = decode_json(msg)
        if backwards.PY2:  # pragma: Python 2
            out = backwards.as_str(out, recurse=True, allow_pass=True)
        return out
Esempio n. 5
0
def decode(msg):
    r"""Decode an object from a message.

    Args:
        msg (bytes): Bytes encoded message.

    Returns:
        object: Decoded Python object.

    """
    cls = guess_type_from_msg(msg)
    metadata = decode_json(msg.split(YGG_MSG_HEAD, 2)[1])
    typedef = cls.extract_typedef(metadata.get('datatype', {}))
    cls_inst = cls(**typedef)
    obj = cls_inst.deserialize(msg)[0]
    return obj
Esempio n. 6
0
def guess_type_from_msg(msg):
    r"""Guess the type class from a message.

    Args:
        msg (str, bytes): Message containing metadata.

    Raises:
        ValueError: If a type class cannot be determined.

    Returns:
        MetaschemaType: Instance of the appropriate type class.

    """
    try:
        if YGG_MSG_HEAD in msg:
            _, metadata, data = msg.split(YGG_MSG_HEAD, 2)
            metadata = decode_json(metadata)
            cls = _type_registry[metadata['datatype']['type']]
        else:
            raise Exception
        return cls
    except BaseException:
        raise ValueError("Could not guess type.")
Esempio n. 7
0
    def deserialize(self,
                    msg,
                    no_data=False,
                    metadata=None,
                    dont_decode=False,
                    dont_check=False):
        r"""Deserialize a message.

        Args:
            msg (str, bytes): Message to be deserialized.
            no_data (bool, optional): If True, only the metadata is returned.
                Defaults to False.
            metadata (dict, optional): Metadata that should be used to deserialize
                the message instead of the current header content. Defaults to
                None and is not used.
            dont_decode (bool, optional): If True, type specific and JSON
                decoding will not be used to decode the message. Defaults to
                False.
            dont_check (bool, optional): If True, the metadata will not be
                checked against the type definition. Defaults to False.

        Returns:
            tuple(obj, dict): Deserialized message and header information.

        Raises:
            TypeError: If msg is not bytes type (str on Python 2).
            ValueError: If msg does not contain the header separator.

        """
        if not isinstance(msg, bytes):
            raise TypeError("Message to be deserialized is not bytes type.")
        # Check for header
        if msg.startswith(constants.YGG_MSG_HEAD):
            if metadata is not None:
                raise ValueError("Metadata in header and provided by keyword.")
            _, metadata, data = msg.split(constants.YGG_MSG_HEAD, 2)
            if len(metadata) == 0:
                metadata = dict(size=len(data))
            else:
                metadata = encoder.decode_json(metadata)
        elif isinstance(metadata, dict) and metadata.get(
                'type_in_data', False):
            assert (msg.count(constants.YGG_MSG_HEAD) == 1)
            typedef, data = msg.split(constants.YGG_MSG_HEAD, 1)
            if len(typedef) > 0:
                metadata.update(encoder.decode_json(typedef))
            metadata.pop('type_in_data')
            metadata['size'] = len(data)
        else:
            data = msg
            if metadata is None:
                metadata = dict(size=len(msg))
                if (((len(msg) > 0) and (msg != constants.YGG_MSG_EOF)
                     and (not is_default_typedef(self._typedef))
                     and (not dont_decode))):
                    raise ValueError("Header marker not in message.")
        # Set flags based on data
        metadata['incomplete'] = (len(data) < metadata['size'])
        if (data == constants.YGG_MSG_EOF):
            metadata['raw'] = True
        # Return based on flags
        if no_data:
            return metadata
        elif len(data) == 0:
            return self._empty_msg, metadata
        elif (metadata['incomplete'] or metadata.get('raw', False)
              or (metadata.get('type', None) == 'direct') or dont_decode):
            return data, metadata
        else:
            data = encoder.decode_json(data)
            obj = self.decode(metadata['datatype'],
                              data,
                              self._typedef,
                              typedef_validated=True,
                              dont_check=dont_check)
        return obj, metadata
Esempio n. 8
0
import yggdrasil
from yggdrasil import constants, units
from yggdrasil.metaschema.encoder import encode_json, decode_json
from yggdrasil.metaschema.properties import get_registered_properties
from yggdrasil.metaschema.datatypes import get_registered_types

_metaschema_fbase = '.ygg_metaschema.json'
_metaschema_fname = os.path.abspath(
    os.path.join(os.path.dirname(yggdrasil.__file__), _metaschema_fbase))
_metaschema = None
_validator = None
_base_schema = {u'$schema': u'http://json-schema.org/draft-04/schema'}

if os.path.isfile(_metaschema_fname):
    with open(_metaschema_fname, 'r') as fd:
        _metaschema = decode_json(fd)
    schema_id = _metaschema.get('id', _metaschema.get('$id', None))
    assert (schema_id is not None)
    _metaschema.setdefault('$schema', schema_id)
    _base_schema['$schema'] = _metaschema.get('$schema', schema_id)

_base_validator = jsonschema.validators.validator_for(_base_schema)


class MetaschemaTypeError(TypeError):
    r"""Error that should be raised when a class encounters a type it cannot handle."""
    pass


def create_metaschema(overwrite=False):
    r"""Create the meta schema for validating ygg schema.