Skip to content

Instantly share code, notes, and snippets.

@Hardtack
Created January 23, 2016 09:32
Show Gist options
  • Select an option

  • Save Hardtack/8baeba02bd509e489f38 to your computer and use it in GitHub Desktop.

Select an option

Save Hardtack/8baeba02bd509e489f38 to your computer and use it in GitHub Desktop.

Revisions

  1. Hardtack created this gist Jan 23, 2016.
    111 changes: 111 additions & 0 deletions formencode_jsonschema.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,111 @@
    import datetime
    import decimal
    import uuid

    from marshmallow import Schema, fields
    from formencode import validators as v
    from formencode.api import Validator as FormencodeValidator, NoDefault
    from formencode.schema import Schema as FormencodeSchema

    # From https://github.com/fuhrysteve/marshmallow-jsonschema/blob/master/marshmallow_jsonschema/base.py
    TYPE_MAP = {
    dict: {
    'type': 'object',
    },
    list: {
    'type': 'array',
    },
    datetime.time: {
    'type': 'string',
    'format': 'time',
    },
    datetime.timedelta: {
    # TODO explore using 'range'?
    'type': 'string',
    },
    datetime.datetime: {
    'type': 'string',
    'format': 'date-time',
    },
    datetime.date: {
    'type': 'string',
    'format': 'date',
    },
    uuid.UUID: {
    'type': 'string',
    'format': 'uuid',
    },
    str: {
    'type': 'string',
    },
    bytes: {
    'type': 'string',
    },
    decimal.Decimal: {
    'type': 'number',
    'format': 'decimal',
    },
    set: {
    'type': 'array',
    },
    tuple: {
    'type': 'array',
    },
    float: {
    'type': 'number',
    'format': 'float',
    },
    int: {
    'type': 'number',
    'format': 'integer',
    },
    bool: {
    'type': 'boolean',
    },
    }


    class JSONSchema(Schema):
    type = fields.Constant('object')
    properties = fields.Method('get_properties')
    required = fields.Method('get_required')

    _type_mapping = {
    v.ByteString: bytes,
    v.StringBool: str,
    v.Bool: bool,
    v.Int: int,
    v.Number: float,
    v.UnicodeString: str,
    v.Regex: str,
    }

    def get_properties(self, schema: FormencodeSchema):
    fields = schema.fields
    properties = {}
    for name, validator in fields.items():
    properties[name] = self._convert_validator(validator)
    return properties

    def _convert_type(self, python_type):
    return TYPE_MAP[python_type]

    def _convert_validator(self, validator: FormencodeValidator):
    for validator_class, python_type in self._type_mapping.items():
    if isinstance(validator, validator_class):
    return self._convert_type(python_type)

    def get_required(self, schema: FormencodeSchema):
    fields = schema.fields
    required = []
    for name, validator in fields.items():
    if self._is_required(validator):
    required.append(name)
    return required

    def _is_required(self, validator: FormencodeValidator):
    if validator.not_empty:
    return True
    if validator.if_missing is NoDefault:
    return True
    return False