Data model mappers between Yams and JSON Schema

Module cubicweb_jsonschema.mappers provides appobjects that aims at mapping Yams model definitions to JSON Schema ones.

These appobjects live in the mappers registry and are selectable with context information in Yams/CubicWeb semantics:

  • etype or entity: entity type or entity,
  • rtype: relation type,
  • role: role of etype/entity in rtype relation,
  • target_types: target entity types of rtype relation with etype/entity as role.

The main predicate for these appobjects is yams_match.

Base classes for mappers

Abstract base class JSONSchemaMapper is the main appobject mapping Yams to JSON Schema. Concrete classes should implement schema_and_definitions() to control JSON Schema generation.

class cubicweb_jsonschema.mappers.JSONSchemaMapper(_cw, resource=None, **extra)[source]

Abstract base class for mappers between Yams schema definitions and JSON Schema documents.

__registry__ = 'mappers'
json_schema(schema_role=None)[source]

Return the JSON Schema for bound Yams context.

If schema_role is not None a plain JSON Schema document is returned following specified role (“view”, “creation” or “edition”). Otherwise, a JSON Hyper Schema document with links is returned.

schema_and_definitions(schema_role)[source]

Return the JSON (sub-)Schema for bound Yams context along with a dict of subschemas to be inserted in the main JSON Schema’s “definitions” property.

Yield Link appobjects matching regid and selection context of this mapper.

Extra keyword arguments are used for Link appobjects selection (in addition to mapper’s section context).

Abstract classes JSONSchemaDeserializer, resp. JSONSchemaSerializer, provide interfaces for deserialization, resp. serialization, from/to a JSON instance and are meant to extend JSONSchemaMapper when appropriate.

class cubicweb_jsonschema.mappers.JSONSchemaDeserializer[source]

Abstract mixin class for mappers capable of deserializing a JSON instance valid under mapped JSON Schema and insert respective data into CubicWeb’s database.

values(instance)[source]

Return a dict holding deserialized data from instance suitable for insertion in CubicWeb database for mapped schema element.

Items from instance dictionnary are pop-ed upon processing.

class cubicweb_jsonschema.mappers.JSONSchemaSerializer[source]

Abstract mixin class for mappers capable of serializing data from CubicWeb’s database as a JSON instance valid under mapped JSON Schema.

serialize(*args)[source]

Return the serialized value for mapped schema element.

Mappers for relations

class cubicweb_jsonschema.mappers.BaseRelationMapper(_cw, **kwargs)[source]

Base abstract class to fill the gap between a yams relation and it’s json schema mapping.

They should be selected depending on the relation (etype, rtype, role and optionaly target_types).

__regid__ = 'jsonschema.relation'

To control JSON Schema generation schema_and_definitions() should be defined on concrete classes.

etype

The entity type bound to this mapper.

rtype = None

relation type name

role = None

role of etype in relation

target_types = None

possible target types of the relation (empty for attribute relations)

class cubicweb_jsonschema.mappers.InlinedRelationMapper(_cw, **kwargs)[source]

Map relation as ‘inlined’, i.e. the target of the relation is created/edited along with its original entity.

class cubicweb_jsonschema.mappers.RelationMapper(_cw, **kwargs)[source]

Map relation as ‘generic’, i.e. the target of the relation may be selected in preexisting possible targets.

Final types mappers

Based on relation mappers, AttributeMapper is the base class for mapping Yams final relation type (i.e. attributes).

class cubicweb_jsonschema.mappers.AttributeMapper(_cw, **kwargs)[source]

Abstract base abstract class to map attribute relation.

Concrete class should implement the json_type property.

__regid__ = 'jsonschema.relation'
json_type

JSON primitive type (e.g. “string”, “number”, etc.)

format = None

JSON Schema “format” keyword for semantic validation.

attr

Relation definition for bound attribute.

static _type(json_value)[source]

Return properly typed value for use within a cubicweb’s entity from given JSON value.

Nothing to do by default.

static _value(value)[source]

Return the serializable value from attribute value.

All standard Yams final types have a default mapper:

class cubicweb_jsonschema.mappers.StringMapper(_cw, **kwargs)[source]

Attribute mapper for Yams’ String type.

json_type = 'string'
_type

alias of str

class cubicweb_jsonschema.mappers.BytesMapper(_cw, **kwargs)[source]

Attribute mapper for Yams’ Bytes type.

json_type = 'string'
static _type(value)[source]

Return a Binary containing value.

static _value(value)[source]

Return a unicode string from Binary value.

class cubicweb_jsonschema.mappers.FloatMapper(_cw, **kwargs)[source]

Attribute mapper for Yams’ Float type.

json_type = 'number'
class cubicweb_jsonschema.mappers.IntMapper(_cw, **kwargs)[source]

Attribute mapper for Yams’ Int and BigInt types.

json_type = 'integer'
class cubicweb_jsonschema.mappers.BooleanMapper(_cw, **kwargs)[source]

Attribute mapper for Yams’ Boolean type.

json_type = 'boolean'
class cubicweb_jsonschema.mappers.DateMapper(_cw, **kwargs)[source]

Attribute mapper for Yams’ Date type.

json_type = 'string'
format = 'date'
class cubicweb_jsonschema.mappers.DatetimeMapper(_cw, **kwargs)[source]

Attribute mapper for Yams’ (TZ)Datetime type.

json_type = 'string'
format = 'date-time'
class cubicweb_jsonschema.mappers.PasswordMapper(_cw, **kwargs)[source]

Attribute mapper for Yams’ Password type.

json_type = 'string'
format = 'password'
static _type(json_value)[source]

Return an encoded string suitable for Password type.

There are several ways to override default attribute mappers.

  • One define a custom JSON Schema format through the format class attribute:

    class EmailMapper(StringMapper):
        __select__ = yams_match(etype='EmailAddress',
                                rtype='address', role='subject')
        format = 'email'
    

    and get the following schema for the address property of EmailAddress entity type:

    {
      "title": "EmailAddress",
      "type": "object",
      "properties": {
        "address": {
          "format": "email",
          "title": "address",
          "type": "string"
        },
        "alias": {
          "title": "alias",
          "type": "string"
        }
      }
    }
    
  • Another possibility is to override _type and/or _value methods of an attribute mapper to control serialization and deserialization:

    class Base64BytesMapper(BytesMapper):
        """A mapper for Bytes attribute encoded in base64."""
        __select__ = yams_match(etype='File',
                                rtype='data', role='subject',
                                target_types='Bytes')
    
        @staticmethod
        def _type(value):
            return Binary(b64decode(value))
    
        @staticmethod
        def _value(value):
            return b64encode(value.getvalue()).decode('ascii')
    

Compound mappers

CompoundMapper can be used to define a JSON Schema sub-document gathering a set of relations of a given entity type.

For example, consider the following Yams entity type definition:

class Photo(EntityType):
    longitude = Float()
    latitude = Float()
    taken_at = Datetime()

the following class defines a “geo” property to be inserted in the JSON Schema document for “Photo” entity type:

class geo(CompoundMapper):
    etype = 'Photo'
    relations = ('longitude', 'latitude')
    title = _('Geographic Coordinates')

thus leading to the following JSON Schema:

{
  "type": "object",
  "title": "Photo",
  "properties": {
    "geo": {
      "$ref": "#/definitions/Geographic Coordinates"
    },
    "take_at": {
      "type": "string",
      "format": "date-time"
    }
  },
  "definitions": {
    "Geographic Coordinates": {
      "type": "object",
      "title": "Geographic Coordinates",
      "properties": {
        "longitude": {
          "type": "float"
        },
        "latitude": {
          "type": "float"
        }
      }
    }
  }
}
class cubicweb_jsonschema.mappers.CompoundMapper(_cw, resource=None, **extra)[source]

Mapper for a “compound” field gathering Yams relations into a dedicated JSON “object” to be inserted in “definitions” key of the JSON Schema document.

The compound “object” will appear in the main JSON Schema document’s properties under the name class attribute (defaults to class name).

__regid__ = 'jsonschema.object'
etype

entity type holding this compound field

relations

sequence of relations gathered in this compound field

title

title of the field

required(schema_role)[source]

Return False by default.

Mappers for entity types and entities

class cubicweb_jsonschema.mappers.ETypeMapper(_cw, resource=None, **extra)[source]

JSON Schema mapper for entity types.

__regid__ = 'jsonschema.entity'
entity

Entity bound to this mapper, None for ETypeMapper.

Yield Link appobjects matching regid and selection context of this entity mapper along with selectable “jsonschema.relation” links for “subject” relations.

values(instance)[source]

Return a dict with deserialized data from instance suitable for insertion in CubicWeb database.

relations(schema_role, section='inlined')[source]

Yield relation information tuple (rtype, role, targettypes) for given schema role in the context of bound entity type.

Keyword argument section controls uicfg section to select relations in.

class cubicweb_jsonschema.mappers.TargetETypeMapper(_cw, resource=None, **extra)[source]

Specialized version of ETypeMapper selectable for an entity type as target of (rtype, role) relation.

__regid__ = 'jsonschema.entity'
class cubicweb_jsonschema.mappers.EntityMapper(_cw, resource=None, **extra)[source]

JSON Schema mapper for an entity.

__regid__ = 'jsonschema.entity'
entity

Live entity from selection context.

serialize()[source]

Return the serialized value entity bound to this mapper.

Mappers for entities as collections and items

The following mapper classes are used to represent entities as collections and items of a collection. These are selected for entity types collection as well as for targets of relation.

class cubicweb_jsonschema.mappers.EntityCollectionMapper(_cw, resource=None, **extra)[source]

Mapper for a collection of entities.

__regid__ = 'jsonschema.collection'
title

Title of the collection, plural form of entity type.

Yield Link appobjects matching regid and selection context of this mapper if schema_role is None.

serialize(entities)[source]

Return a list of collection item representing each entity in entities.

class cubicweb_jsonschema.mappers.RelatedCollectionMapper(_cw, resource=None, **extra)[source]

Mapper for a collection of entities through an inlined relation.

__regid__ = 'jsonschema.collection'
title

Title of the collection, name of the relation.

class cubicweb_jsonschema.mappers.CollectionItemMapper(_cw, resource=None, **extra)[source]

Mapper for an item of a collection.

__regid__ = 'jsonschema.item'
schema_and_definitions(schema_role=None)[source]

Return either a string schema or an object with “type”, “id and “title” properties.

static serialize(entity)[source]

Return a dictionary with entity represented as a collection item.

Predicates

class cubicweb_jsonschema.mappers.yams_match(etype=None, rtype=None, role=None, target_types=())[source]

Predicate that returns a positive value when the supplied relation match parameters given as predicate argument.

The more __call__ arguments match __init__’s ones, the higher the score is.

class cubicweb_jsonschema.mappers.yams_final_rtype

Predicate that returns 1 when the supplied rtype is not final.

class cubicweb_jsonschema.mappers.yams_component_target

Predicate that returns 1 when the target entity types are component of the relation defined by rtype and role (i.e. the relation has composite set to role).