Skip to main content

Schema based JSON Parser/Serializer

Project description

jsonbp

jsonbp (JSON BluePrint) is a library to validate and deserialize JSON into Python data based on a schema. There is json-schema and its implementations already if you want a more mature and more widely used technique, but I needed some features that were not easily available by just patching json-schema, so this library is the result.

jsonbp's design main goals were:

  • schema reuse through import / type system
  • support for enums
  • built in numeric fixed precision type (which deserializes directly into Python's Decimal)
  • built in datetime type (which deserializes directly into Python's datetime)
  • error reporting with support for localization
  • easy to integrate and use

Contents

Schema definition

jsonbp uses its own (very simple) domain language to define a schema. The only mandatory declaration is the "root" entry, which determines the expected JSON contents. Here's a simple hypothetical example:

root {
  x: float (min=0.0),
  y: float (min=0.0, max=1.0),
  
  optional color: {
    RED,
    GOLD,
    GREEN
  }
} [minLength=2]

This defines a schema that represents an array of minimum length 2 whose elements contain the fields 'x' and 'y' (where both 'x' and 'y' are not allowed to be negative and 'y' is not allowed to be greater than 1.0) and an optional field 'color' that can be either "RED", "GOLD" or "GREEN". A JSON instance that obeys this schema is:

[
  {
    "x": 2.0,
    "y", 0.004,
    "color": "RED"
  },
  
  {
    "x": 3.0,
    "y", 0.009
  },
  
  {
    "x": 4.0,
    "y", 0.016,
    "color": "GREEN"
  }
]

Besides "root", in jsonbp the following optional directives can be used to organize a schema:

  • "type" -> to define specialized (restricted) simple types
  • "node" -> to specify the contents of compound types (Objetcs)
  • "enum" -> to define a list of allowed values for given fields
  • "import" -> to reuse directives from existing blueprints

One can then make use of these features to simplify and make the schema more modular. In the above example schema, we could split the definitions and get something more reusable, like the following:

type non_negative : float (min=0.0)
type normalized : non_negative (max=1.0)

node coordinates {
  x: non_negative,
  y: normalized
}

include "color.jbp"
node colored_coordinates extends coordinates {
  optional color: color
}

root colored_coordinates[minLength=2]

where the contents of file "color.jbp" would then be:

enum color {
  RED,
  GOLD,
  GREEN
}

(For detailed information using these directives, see the Documentation section)

Usage

All of jsonbp can be summarized in 2 functionalities:

Schema parsing

  • jsonbp.load(<schema file path>) => <blueprint object>
  • jsonbp.loads(<schema string>) => <blueprint object>

These functions are used for schema/blueprint loading. Both do the same thing, the only difference is that the former expects a path to a file storing the schema content while the latter expects a string with the schema content itself. When there's a problem with the supplied schema, an exception is thrown. More on this can be read on Error handling and error localization. These functions, when succeed loading the schema, return a blueprint instance that can then be used to deserialize JSON strings.

When loading a file, the blueprint is stored in a cache and associated with the absolute path of that file. Thus, loading the same file twice won't make jsonbp parse it a second time. To force the parsing of posterior calls to load(), call jsonbp.invalidateCache().

JSON deserialization

  • <blueprint object>.deserialize(<JSON string>) => (success, outcome)

This is the only method that is intended to be invoked from the blueprint object returned by load()/loads(). It expects a string holding the JSON contents to be deserialized. It returns a tuple in the form (success, outcome). success being a boolean signalizing if the deserialization was successful or not. If successful, outcome will hold the Python data obtained from the JSON string. Otherwise (success is false) outcome will have a message explaining what was not compliant according to the schema.

Example

Here's how one uses these functions in code:

import jsonbp

blueprint = jsonbp.loads('''
root {
  success: {
    YES,
    NO
  }
}
''')

jsonInstance = '{ "success": "YES" }'
success, outcome = blueprint.deserialize(jsonInstance)
print(f'Success: {success}')
print(f'Outcome: {outcome}')

Requirements and Dependencies

jsonbp requires Python 3.6+, that's it.
Under the hood, jsonbp uses PLY for its schema parsing. PLY comes included with jsonbp already, there's no need to download it separately.

Installation

jsonbp is available at PyPI: https://pypi.org/project/jsonbp/

To install through pip:

pip install jsonbp

Documentation

That was just an introduction, if you are interested in using jsonbp here are some more detailed information:

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

jsonbp-1.0.2.tar.gz (53.2 kB view hashes)

Uploaded Source

Built Distribution

jsonbp-1.0.2-py3-none-any.whl (53.0 kB view hashes)

Uploaded Python 3

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page