Exemple #1
0
    def test_dumping_schema(self):
        schema = JSONSchema()
        schema.add_property('foo', {'type': 'string'}, required=True)
        expected = dedent("""
        {
            "$schema": "http://json-schema.org/draft-04/schema#",
            "type": "object",
            "properties": {
                "foo": {
                    "type": "string"
                }
            },
            "required": [
                "foo"
            ]
        }
        """).strip()

        dump_path = join(self.tempdir, 'test.schema.json')
        schema.dump(dump_path)

        with open(dump_path) as f:
            actual = f.read()

        self.assertEqual(expected, actual)
Exemple #2
0
    def test_require_any_of(self):
        schema = JSONSchema()
        schema.add_property('foo', {'type': 'string'})
        schema.add_property('bar', {'type': 'string'})
        schema.require_any_of(['foo', 'bar'])

        expected = {
            '$schema': 'http://json-schema.org/draft-04/schema#',
            'type': 'object',
            'properties': {
                'foo': {'type': 'string'},
                'bar': {'type': 'string'},
            },
            'allOf': [
                {
                    'anyOf': [
                        {'required': ['foo']},
                        {'required': ['bar']}
                    ],
                },
            ],

        }
        serialized = schema.serialize()

        self.assertEqual(expected, serialized)
Exemple #3
0
    def test_dropping_last_property_removes_properties_key(self):
        schema = JSONSchema()
        schema.add_property('foo', {'type': 'string'})
        schema.drop_property('foo')

        expected = {
            '$schema': 'http://json-schema.org/draft-04/schema#',
            'type': 'object',
        }
        serialized = schema.serialize()

        self.assertEqual(expected, serialized)
Exemple #4
0
    def test_add_property_supports_required_kwarg(self):
        schema = JSONSchema()
        schema.add_property('foo', {'type': 'string'}, required=True)
        expected = {
            '$schema': 'http://json-schema.org/draft-04/schema#',
            'type': 'object',
            'properties': {
                'foo': {'type': 'string'},
            },
            'required': ['foo'],
        }
        serialized = schema.serialize()

        self.assertEqual(expected, serialized)
Exemple #5
0
    def test_set_not_required_removes_empty_requires_list(self):
        schema = JSONSchema()
        schema.add_property('foo', {'type': 'string'}, required=True)
        schema.set_not_required('foo')

        expected = {
            '$schema': 'http://json-schema.org/draft-04/schema#',
            'type': 'object',
            'properties': {
                'foo': {'type': 'string'},
            },
        }
        serialized = schema.serialize()

        self.assertEqual(expected, serialized)
Exemple #6
0
    def test_add_property(self):
        schema = JSONSchema()
        schema.add_property('foo', {'type': 'string'})
        expected = {
            '$schema': 'http://json-schema.org/draft-04/schema#',
            'type': 'object',
            'properties': {
                'foo': {'type': 'string'},
            },
        }
        serialized = schema.serialize()

        self.assertEqual(expected, serialized)
        self.assertIsInstance(serialized, OrderedDict)
        self.assertIsInstance(serialized['properties'], OrderedDict)
        self.assertIsInstance(serialized['properties']['foo'], OrderedDict)
Exemple #7
0
    def test_set_required_doesnt_add_property_twice_to_requireds(self):
        schema = JSONSchema()
        schema.add_property('foo', {'type': 'string'})
        schema.set_required('foo')
        schema.set_required('foo')

        expected = {
            '$schema': 'http://json-schema.org/draft-04/schema#',
            'type': 'object',
            'properties': {
                'foo': {'type': 'string'},
            },
            'required': ['foo'],
        }
        serialized = schema.serialize()

        self.assertEqual(expected, serialized)
Exemple #8
0
    def test_make_optional_properties_nullable(self):
        schema = JSONSchema()
        schema.add_property('foo', {'type': 'string'}, required=True)
        schema.add_property('bar', {'type': 'string'})
        schema.make_optional_properties_nullable()

        expected = {
            '$schema': 'http://json-schema.org/draft-04/schema#',
            'type': 'object',
            'properties': {
                'foo': {'type': 'string'},
                'bar': {'type': ['null', 'string']},
            },
            'required': ['foo'],
        }
        serialized = schema.serialize()

        self.assertEqual(expected, serialized)
Exemple #9
0
    def test_set_field_order(self):
        schema = JSONSchema()
        schema.add_property('foo', {'type': 'string'})
        schema.add_property('bar', {'type': 'string'})
        schema.set_field_order(['foo', 'bar'])

        expected = {
            '$schema': 'http://json-schema.org/draft-04/schema#',
            'type': 'object',
            'properties': {
                'foo': {'type': 'string'},
                'bar': {'type': 'string'},
            },
            'field_order': ['foo', 'bar'],
        }
        serialized = schema.serialize()

        self.assertEqual(expected, serialized)
Exemple #10
0
    def test_add_definition(self):
        schema = JSONSchema()
        subschema = JSONSchema()
        subschema.add_property('subfoo', {'type': 'string'})
        schema.add_definition('sub', subschema)

        expected = {
            '$schema': 'http://json-schema.org/draft-04/schema#',
            'type': 'object',
            'definitions': {
                'sub': {
                    'type': 'object',
                    'properties': {
                        'subfoo': {'type': 'string'},
                    },
                }
            }
        }
        serialized = schema.serialize()

        self.assertDictEqual(expected, serialized)
    def _build_permission_subschema(self):
        subschema = JSONSchema(additional_properties=False)
        string_array = {
            "type": "array",
            "items": {
                "type": "string"
            },
        }

        subschema.add_property('block_inheritance', {"type": "boolean"})
        subschema.add_property('read', string_array)
        subschema.add_property('add', string_array)
        subschema.add_property('edit', string_array)
        subschema.add_property('close', string_array)
        subschema.add_property('reactivate', string_array)

        if self.portal_type in [
                'opengever.repository.repositoryroot',
                'opengever.repository.repositoryfolder'
        ]:
            subschema.add_property('manage_dossiers', string_array)
        return subschema
class JSONSchemaBuilder(object):
    """Builds a JSON Schema representation of a single GEVER type.
    """
    def __init__(self, portal_type):
        self.portal_type = portal_type
        self.schema = None

        if portal_type in GEVER_TYPES:
            self.type_dumper = TypeDumper()
        elif portal_type in GEVER_SQL_TYPES:
            self.type_dumper = SQLTypeDumper()
        else:
            raise Exception("Unmapped type: %r" % portal_type)

    def build_schema(self):
        type_dump = self.type_dumper.dump(self.portal_type)

        self.schema = JSONSchema(
            title=type_dump['title'],
            additional_properties=False,
        )
        field_order = []
        # Collect field info from all schemas (base schema + behaviors)
        for _schema in type_dump['schemas']:
            # Note: This is not the final / "correct" field order as displayed
            # in the user interface (which should eventually honor fieldsets
            # and plone.autoform directives).
            # The intent here is rather to keep a *consistent* order for now.
            field_order.extend([field['name'] for field in _schema['fields']])

            translated_title_fields = []
            for field in _schema['fields']:
                prop_def = self._property_definition_from_field(field)
                self.schema.add_property(field['name'], prop_def)

                if field['name'] in TRANSLATED_TITLE_NAMES:
                    translated_title_fields.append(field['name'])

            if translated_title_fields:
                self.schema.require_any_of(translated_title_fields)

        self.schema.set_field_order(field_order)
        return self.schema

    def _property_definition_from_field(self, field):
        """Create a JSON Schema property definition from a field info dump.
        """
        prop_def = self._js_type_from_zope_type(field['type'])

        prop_def['title'] = field['title']
        prop_def['description'] = field['description']
        prop_def['_zope_schema_type'] = field['type']

        self._process_choice(prop_def, field)
        self._process_max_length(prop_def, field)
        self._process_default(prop_def, field)
        self._process_vocabulary(prop_def, field)
        self._process_required(prop_def, field)

        return prop_def

    def _js_type_from_zope_type(self, zope_type):
        """Map a zope.schema type to a JSON schema (JavaScript) type.

        Returns a minimal property definition dict including at least a
        'type', and possibly a 'format' as well.
        """
        if zope_type not in JSON_SCHEMA_FIELD_TYPES:
            raise Exception(
                "Don't know what JS type to map %r to. Please map it in "
                "JSON_SCHEMA_FIELD_TYPES first." % zope_type)

        type_spec = JSON_SCHEMA_FIELD_TYPES[zope_type].copy()
        return type_spec

    def _process_choice(self, prop_def, field):
        if field['type'] == 'Choice':
            prop_def['type'] = field['value_type']

    def _process_max_length(self, prop_def, field):
        if field.get('max_length') is not None:
            prop_def['maxLength'] = field['max_length']

    def _process_default(self, prop_def, field):
        if 'default' in field:
            prop_def['default'] = field['default']

    def _process_vocabulary(self, prop_def, field):
        if field.get('vocabulary'):
            vocab = field['vocabulary']
            if isinstance(vocab, basestring) and vocab.startswith('<'):
                # Placeholder vocabulary (like <Any valid user> )
                prop_def['_vocabulary'] = vocab
            else:
                prop_def['enum'] = vocab

    def _process_required(self, prop_def, field):
        if field.get('required', False):
            if field['name'] not in TRANSLATED_TITLE_NAMES:
                self.schema.set_required(field['name'])
Exemple #13
0
    def _build_permission_subschema(self):
        subschema = JSONSchema(additional_properties=False)
        string_array = {
            "type": "array",
            "items": {"type": "string"},
        }

        subschema.add_property('block_inheritance', {"type": "boolean"})
        subschema.add_property('read', string_array)
        subschema.add_property('add', string_array)
        subschema.add_property('edit', string_array)
        subschema.add_property('close', string_array)
        subschema.add_property('reactivate', string_array)

        if self.portal_type in ['opengever.repository.repositoryroot',
                                'opengever.repository.repositoryfolder']:
            subschema.add_property('manage_dossiers', string_array)
        return subschema
Exemple #14
0
class JSONSchemaBuilder(object):
    """Builds a JSON Schema representation of a single GEVER type.
    """

    def __init__(self, portal_type):
        self.portal_type = portal_type
        self.schema = None

        if portal_type in GEVER_TYPES:
            self.type_dumper = TypeDumper()
        elif portal_type in GEVER_SQL_TYPES:
            self.type_dumper = SQLTypeDumper()
        else:
            raise Exception("Unmapped type: %r" % portal_type)

    def build_schema(self):
        type_dump = self.type_dumper.dump(self.portal_type)

        self.schema = JSONSchema(
            title=type_dump['title'],
            additional_properties=False,
        )
        field_order = []
        # Collect field info from all schemas (base schema + behaviors)
        for _schema in type_dump['schemas']:
            # Note: This is not the final / "correct" field order as displayed
            # in the user interface (which should eventually honor fieldsets
            # and plone.autoform directives).
            # The intent here is rather to keep a *consistent* order for now.
            field_order.extend([field['name'] for field in _schema['fields']])

            translated_title_fields = []
            for field in _schema['fields']:
                prop_def = self._property_definition_from_field(field)
                self.schema.add_property(field['name'], prop_def)

                if field['name'] in TRANSLATED_TITLE_NAMES:
                    translated_title_fields.append(field['name'])

            if translated_title_fields:
                self.schema.require_any_of(translated_title_fields)

        self.schema.set_field_order(field_order)
        return self.schema

    def _property_definition_from_field(self, field):
        """Create a JSON Schema property definition from a field info dump.
        """
        prop_def = self._js_type_from_zope_type(field['type'])

        prop_def['title'] = field['title']
        prop_def['description'] = field['description']
        prop_def['_zope_schema_type'] = field['type']

        self._process_choice(prop_def, field)
        self._process_max_length(prop_def, field)
        self._process_default(prop_def, field)
        self._process_vocabulary(prop_def, field)
        self._process_required(prop_def, field)

        return prop_def

    def _js_type_from_zope_type(self, zope_type):
        """Map a zope.schema type to a JSON schema (JavaScript) type.

        Returns a minimal property definition dict including at least a
        'type', and possibly a 'format' as well.
        """
        if zope_type not in JSON_SCHEMA_FIELD_TYPES:
            raise Exception(
                "Don't know what JS type to map %r to. Please map it in "
                "JSON_SCHEMA_FIELD_TYPES first." % zope_type)

        type_spec = JSON_SCHEMA_FIELD_TYPES[zope_type].copy()
        return type_spec

    def _process_choice(self, prop_def, field):
        if field['type'] == 'Choice':
            prop_def['type'] = field['value_type']

    def _process_max_length(self, prop_def, field):
        if field.get('max_length') is not None:
            prop_def['maxLength'] = field['max_length']

    def _process_default(self, prop_def, field):
        if 'default' in field:
            prop_def['default'] = field['default']

    def _process_vocabulary(self, prop_def, field):
        if field.get('vocabulary'):
            vocab = field['vocabulary']
            if isinstance(vocab, basestring) and vocab.startswith('<'):
                # Placeholder vocabulary (like <Any valid user> )
                prop_def['_vocabulary'] = vocab
            else:
                prop_def['enum'] = vocab

    def _process_required(self, prop_def, field):
        if field.get('required', False):
            if field['name'] not in TRANSLATED_TITLE_NAMES:
                self.schema.set_required(field['name'])