예제 #1
0
    def update_typedef(self, **kwargs):
        r"""Update the current typedef with new values.

        Args:
            **kwargs: All keyword arguments are considered to be new type
                definitions. If they are a valid definition property, they
                will be copied to the typedef associated with the instance.

        Returns:
            dict: A dictionary of keyword arguments that were not added to the
                type definition.

        Raises:
            MetaschemaTypeError: If the current type does not match the type being
                updated to.

        """
        types = kwargs.pop('type', [])
        if self.type_instances:
            if set(types) != set(self.type_instances.keys()):
                raise MetaschemaTypeError(
                    "New types (%s) do not match old (%s)." %
                    (set(types), set(self.type_instances.keys())))
            for tcls in self.type_instances.values():
                tcls.update_typedef(**copy.deepcopy(kwargs))
        else:
            if set(types) != set(self.type_classes.keys()):
                raise MetaschemaTypeError(
                    "New types (%s) do not match class's (%s)." %
                    (set(types), set(self.type_classes.keys())))
            for t, tcls in self.type_classes.items():
                self.type_instances[t] = tcls(**copy.deepcopy(kwargs))
        return super(MultiMetaschemaType, self).update_typedef(type=types,
                                                               **kwargs)
예제 #2
0
    def update_typedef(self, **kwargs):
        r"""Update the current typedef with new values.

        Args:
            **kwargs: All keyword arguments are considered to be new type
                definitions. If they are a valid definition property, they
                will be copied to the typedef associated with the instance.

        Returns:
            dict: A dictionary of keyword arguments that were not added to the
                type definition.

        Raises:
            MetaschemaTypeError: If the current type does not match the type being
                updated to.

        """
        typename0 = self._typedef.get('type', None)
        typename1 = kwargs.get('type', None)
        # Check typename to make sure this is possible
        if typename1 and typename0 and (typename1 != typename0):
            raise MetaschemaTypeError(
                "Cannot update typedef for type '%s' to be '%s'."
                % (typename0, typename1))  # pragma: debug
        # Copy over valid properties
        all_keys = [k for k in kwargs.keys()]
        # req_keys = self.definition_schema().get('required', [])
        for k in all_keys:
            # if k in req_keys:
            self._typedef[k] = kwargs.pop(k)
        # Validate
        self.validate_definition(self._typedef)
        return kwargs
 def encode(cls, instance, typedef=None):
     r"""Encoder for the 'subtype' scalar property."""
     dtype = data2dtype(instance)
     out = None
     for k, v in _valid_types.items():
         if dtype.name.startswith(v):
             out = k
             break
     if out is None:
         raise MetaschemaTypeError(
             'Cannot find subtype string for dtype %s' % dtype)
     return out
예제 #4
0
    def get_type_class(cls, typedef=None, obj=None):
        r"""Get the type class from the provided typedef.

        """
        if (typedef is not None) and isinstance(typedef['type'], (str, bytes)):
            type_name = typedef['type']
        else:
            type_name = TypeMetaschemaProperty.encode(obj)
        if type_name not in cls.type_classes:
            raise MetaschemaTypeError(
                "Type '%s' not in set of supported types (%s)." %
                (type_name, list(cls.type_classes.keys())))
        return cls.type_classes[type_name]
예제 #5
0
    def instance2args(cls, instance):
        r"""Get input arguments from a class instance.

        Args:
            instance (object): Instance of a Python class.

        Returns:
            dict: Input arguments for re-creating the instance.

        """
        for k in cls._instance_dict_attr:
            if hasattr(instance, k):
                return getattr(instance, k)
            elif hasattr(instance, 'get_' + k):
                return getattr(instance, 'get_' + k)()
            elif hasattr(instance, '_' + k):
                return getattr(instance, '_' + k)
        raise MetaschemaTypeError('Could not locate dictionary of arguments.')
예제 #6
0
    def encode(cls, instance, typedef=None):
        r"""Method to encode the property given the object.

        Args:
            instance (object): Object to get property for.
            typedef (object, None): Template value in type definition to use
                for initializing encoding some cases. Defaults to None and
                is ignored.

        Returns:
            object: Encoded property for instance.

        """
        type_registry = get_registered_types()
        for t, cls in sorted(type_registry.items(), key=_specificity_sort_key):
            if (t != 'any') and cls.validate(instance):
                return t
        raise MetaschemaTypeError(
            "Could not encode 'type' property for Python type: %s" %
            type(instance))
    def instance2args(cls, instance):
        r"""Get input arguments from a class instance.

        Args:
            instance (object): Instance of a Python class.

        Returns:
            dict: Input arguments for re-creating the instance.

        """
        out = None
        for k in cls._instance_dict_attr:
            if out is not None:
                break
            if hasattr(instance, k):
                out = getattr(instance, k)
            elif hasattr(instance, 'get_' + k):
                out = getattr(instance, 'get_' + k)()
            elif hasattr(instance, '_' + k):
                out = getattr(instance, '_' + k)
        if isinstance(out, (list, tuple)):
            out_real = []
            for x in out:
                if isinstance(x, weakref.ReferenceType):
                    out_real.append(x())
                else:
                    out_real.append(x)
            return out_real
        elif isinstance(out, dict):
            out_real = {}
            for k, v in out.items():
                if isinstance(v, weakref.ReferenceType):
                    out_real[k] = v()
                else:
                    out_real[k] = v
            return out_real
        else:
            raise MetaschemaTypeError(
                'Could not locate dictionary of arguments.')
예제 #8
0
    def encode_type(cls, obj, typedef=None, is_validated=False, **kwargs):
        r"""Encode an object's type definition.

        Args:
            obj (object): Object to encode.
            typedef (dict, optional): Type properties that should be used to
                initialize the encoded type definition in certain cases.
                Defaults to None and is ignored.
            **kwargs: Additional keyword arguments are treated as additional
                schema properties.

        Raises:
            MetaschemaTypeError: If the object is not the correct type.

        Returns:
            dict: Encoded type definition.

        """
        obj = cls.coerce_type(obj, typedef=typedef)
        if typedef is None:
            typedef = {}
        if not is_validated:
            if not cls.validate(obj):
                raise MetaschemaTypeError(("Object could not be encoded as "
                                           "'%s' type.") % cls.name)
        out = copy.deepcopy(kwargs)
        for x in cls.properties:
            itypedef = typedef.get(x, out.get(x, None))
            if x == 'type':
                out['type'] = cls.name
            elif x == 'title':
                if itypedef is not None:
                    out[x] = itypedef
            else:
                prop_cls = get_metaschema_property(x)
                out[x] = prop_cls.encode(obj, typedef=itypedef)
        return out