Security News
Research
Data Theft Repackaged: A Case Study in Malicious Wrapper Packages on npm
The Socket Research Team breaks down a malicious wrapper package that uses obfuscation to harvest credentials and exfiltrate sensitive data.
Models to make easier to deal with structures that are converted to, or read from JSON.
.. image:: https://jazzband.co/static/img/badge.svg :target: https://jazzband.co/ :alt: Jazzband
.. image:: https://badge.fury.io/py/jsonmodels.svg :target: http://badge.fury.io/py/jsonmodels
.. image:: https://github.com/jazzband/jsonmodels/workflows/Test/badge.svg :target: https://github.com/jazzband/jsonmodels/actions :alt: Tests
.. image:: https://img.shields.io/pypi/dm/jsonmodels.svg :target: https://pypi.python.org/pypi/jsonmodels :alt: PyPI
.. image:: https://codecov.io/gh/jazzband/jsonmodels/branch/master/graph/badge.svg :target: https://codecov.io/gh/jazzband/jsonmodels :alt: Coverage
jsonmodels
is library to make it easier for you to deal with structures that
are converted to, or read from JSON.
Fully tested with Python 3.8+.
Support for PyPy 3.9 and 3.10 (see implementation notes in docs for more details).
Create Django-like models:
.. code-block:: python
from jsonmodels import models, fields, errors, validators
class Cat(models.Base):
name = fields.StringField(required=True)
breed = fields.StringField()
love_humans = fields.IntField(nullable=True)
class Dog(models.Base):
name = fields.StringField(required=True)
age = fields.IntField()
class Car(models.Base):
registration_number = fields.StringField(required=True)
engine_capacity = fields.FloatField()
color = fields.StringField()
class Person(models.Base):
name = fields.StringField(required=True)
surname = fields.StringField(required=True)
nickname = fields.StringField(nullable=True)
car = fields.EmbeddedField(Car)
pets = fields.ListField([Cat, Dog], nullable=True)
Access to values through attributes:
.. code-block:: python
cat = Cat() cat.populate(name='Garfield') cat.name 'Garfield' cat.breed = 'mongrel' cat.breed 'mongrel'
Validate models:
.. code-block:: python
person = Person(name='Chuck', surname='Norris') person.validate() None
dog = Dog() dog.validate() *** ValidationError: Field "name" is required!
Cast models to python struct and JSON:
.. code-block:: python
cat = Cat(name='Garfield') dog = Dog(name='Dogmeat', age=9) car = Car(registration_number='ASDF 777', color='red') person = Person(name='Johny', surname='Bravo', pets=[cat, dog]) person.car = car person.to_struct() { 'car': { 'color': 'red', 'registration_number': 'ASDF 777' }, 'surname': 'Bravo', 'name': 'Johny', 'nickname': None, 'pets': [ {'name': 'Garfield'}, {'age': 9, 'name': 'Dogmeat'} ] }
import json person_json = json.dumps(person.to_struct())
You don't like to write JSON Schema? Let jsonmodels
do it for you:
.. code-block:: python
person = Person() person.to_json_schema() { 'additionalProperties': False, 'required': ['surname', 'name'], 'type': 'object', 'properties': { 'car': { 'additionalProperties': False, 'required': ['registration_number'], 'type': 'object', 'properties': { 'color': {'type': 'string'}, 'engine_capacity': {'type': ''}, 'registration_number': {'type': 'string'} } }, 'surname': {'type': 'string'}, 'name': {'type': 'string'}, 'nickname': {'type': ['string', 'null']} 'pets': { 'items': { 'oneOf': [ { 'additionalProperties': False, 'required': ['name'], 'type': 'object', 'properties': { 'breed': {'type': 'string'}, 'name': {'type': 'string'} } }, { 'additionalProperties': False, 'required': ['name'], 'type': 'object', 'properties': { 'age': {'type': 'number'}, 'name': {'type': 'string'} } }, { 'type': 'null' } ] }, 'type': 'array' } } }
Validate models and use validators, that affect generated schema:
.. code-block:: python
class Person(models.Base): ... ... name = fields.StringField( ... required=True, ... validators=[ ... validators.Regex('^[A-Za-z]+$'), ... validators.Length(3, 25), ... ], ... ) ... age = fields.IntField( ... nullable=True, ... validators=[ ... validators.Min(18), ... validators.Max(101), ... ] ... ) ... nickname = fields.StringField( ... required=True, ... nullable=True ... ) ...
person = Person() person.age = 11 person.validate() *** ValidationError: '11' is lower than minimum ('18'). person.age = None person.validate() None
person.age = 19 person.name = 'Scott_' person.validate() *** ValidationError: Value "Scott_" did not match pattern "^[A-Za-z]+$".
person.name = 'Scott' person.validate() None
person.nickname = None person.validate() *** ValidationError: Field is required!
person.to_json_schema() { "additionalProperties": false, "properties": { "age": { "maximum": 101, "minimum": 18, "type": ["number", "null"] }, "name": { "maxLength": 25, "minLength": 3, "pattern": "/^[A-Za-z]+$/", "type": "string" }, "nickname": {, "type": ["string", "null"] } }, "required": [ "nickname", "name" ], "type": "object" }
You can also validate scalars, when needed:
.. code-block:: python
class Person(models.Base): ... ... name = fields.StringField( ... required=True, ... validators=[ ... validators.Regex('^[A-Za-z]+$'), ... validators.Length(3, 25), ... ], ... ) ... age = fields.IntField( ... nullable=True, ... validators=[ ... validators.Min(18), ... validators.Max(101), ... ] ... ) ... nickname = fields.StringField( ... required=True, ... nullable=True ... ) ...
def only_odd_numbers(item): ... if item % 2 != 1: ... raise validators.ValidationError("Only odd numbers are accepted") ... class Person(models.Base): ... lucky_numbers = fields.ListField(int, item_validators=[only_odd_numbers]) ... item_validator_str = fields.ListField( ... str, ... item_validators=[validators.Length(10, 20), validators.Regex(r"\w+")], ... validators=[validators.Length(1, 2)], ... ) ... Person.to_json_schema() { "type": "object", "additionalProperties": false, "properties": { "item_validator_str": { "type": "array", "items": { "type": "string", "minLength": 10, "maxLength": 20, "pattern": "/\w+/" }, "minItems": 1, "maxItems": 2 }, "lucky_numbers": { "type": "array", "items": { "type": "number" } } } }
(Note that only_odd_numbers
did not modify schema, since only class based validators are
able to do that, though it will still work as expected in python. Use class based validators
that can be expressed in json schema if you want to be 100% correct on schema side.)
Lazy loading, best for circular references:
.. code-block:: python
class Primary(models.Base): ... ... name = fields.StringField() ... secondary = fields.EmbeddedField('Secondary')
class Secondary(models.Base): ... ... data = fields.IntField() ... first = fields.EmbeddedField('Primary')
You can use either Model
, full path path.to.Model
or relative imports
.Model
or ...Model
.
Using definitions to generate schema for circular references:
.. code-block:: python
class File(models.Base): ... ... name = fields.StringField() ... size = fields.FloatField()
class Directory(models.Base): ... ... name = fields.StringField() ... children = fields.ListField(['Directory', File])
class Filesystem(models.Base): ... ... name = fields.StringField() ... children = fields.ListField([Directory, File])
Filesystem.to_json_schema() { "type": "object", "properties": { "name": {"type": "string"} "children": { "items": { "oneOf": [ "#/definitions/directory", "#/definitions/file" ] }, "type": "array" } }, "additionalProperties": false, "definitions": { "directory": { "additionalProperties": false, "properties": { "children": { "items": { "oneOf": [ "#/definitions/directory", "#/definitions/file" ] }, "type": "array" }, "name": {"type": "string"} }, "type": "object" }, "file": { "additionalProperties": false, "properties": { "name": {"type": "string"}, "size": {"type": "number"} }, "type": "object" } } }
Dealing with schemaless data
(Plese note that using schemaless fields can cause your models to get out of control - especially if you are the one responsible for data schema. On the other hand there is usually the case when incomming data are with no schema defined and schemaless fields are the way to go.)
.. code-block:: python
>>> class Event(models.Base):
...
... name = fields.StringField()
... size = fields.FloatField()
... extra = fields.DictField()
>>> Event.to_json_schema()
{
"type": "object",
"additionalProperties": false,
"properties": {
"extra": {
"type": "object"
},
"name": {
"type": "string"
},
"size": {
"type": "float"
}
}
}
DictField
allow to pass any dict of values ("type": "object"
), but note, that it will not make any validation
on values except for the dict type.
Compare JSON schemas:
.. code-block:: python
from jsonmodels.utils import compare_schemas schema1 = {'type': 'object'} schema2 = {'type': 'array'} compare_schemas(schema1, schema1) True compare_schemas(schema1, schema2) False
For more examples and better description see full documentation: http://jsonmodels.rtfd.org.
2.7.0 (2023-12-17) ++++++++++++++++++
2.6.0 (2022-10-14) ++++++++++++++++++
2.5.1 (2022-06-16) ++++++++++++++++++
2.5.0 (2021-07-26) ++++++++++++++++++
2.4.1 (2021-02-19) ++++++++++++++++++
2.4 (2018-12-01) ++++++++++++++++
2.3 (2018-02-04) ++++++++++++++++
2.2 (2017-08-21) ++++++++++++++++
2.1.5 (2017-02-01) ++++++++++++++++++
2.1.4 (2017-01-24) ++++++++++++++++++
2.1.3 (2017-01-16) ++++++++++++++++++
2.1.2 (2016-01-06) ++++++++++++++++++
2.1.1 (2015-11-15) ++++++++++++++++++
2.1 (2015-11-02) ++++++++++++++++
2.0.1 (2014-11-15) ++++++++++++++++++
2.0 (2014-11-14) ++++++++++++++++
Backward compatibility breaks
* Renamed _types to types in fields.
* Renamed _items_types to items_types in ListField.
* Removed data transformers.
* Renamed module `error` to `errors`.
* Removed explicit validation - validation occurs at assign time.
* Renamed `get_value_replacement` to `get_default_value`.
* Renamed modules `utils` to `utilities`.
1.4 (2014-07-22)
++++++++++++++++
* Allowed validators to modify generated schema.
* Added validator for maximum value.
* Added utilities to convert regular expressions between Python and ECMA
formats.
* Added validator for regex.
* Added validator for minimum value.
* By default "validators" property of field is an empty list.
1.3.1 (2014-07-13)
++++++++++++++++++
* Fixed generation of schema for BoolField.
1.3 (2014-07-13)
++++++++++++++++
* Added new fields (BoolField, TimeField, DateField and DateTimeField).
* ListField is always not required.
* Schema can be now generated from class itself (not from an instance).
1.2 (2014-06-18)
++++++++++++++++
* Fixed values population, when value is not dictionary.
* Added custom validators.
* Added tool for schema comparison.
1.1.1 (2014-06-07)
++++++++++++++++++
* Added possibility to populate already initialized data to EmbeddedField.
* Added `compare_schemas` utility.
1.1 (2014-05-19)
++++++++++++++++
* Added docs.
* Added json schema generation.
* Added tests for PEP8 and complexity.
* Moved to Python 3.4.
* Added PEP257 compatibility.
* Added help text to fields.
1.0.5 (2014-04-14)
++++++++++++++++++
* Added data transformers.
1.0.4 (2014-04-13)
++++++++++++++++++
* List field now supports simple types.
1.0.3 (2014-04-10)
++++++++++++++++++
* Fixed compatibility with Python 3.
* Fixed `str` and `repr` methods.
1.0.2 (2014-04-03)
++++++++++++++++++
* Added deep data initialization.
1.0.1 (2014-04-03)
++++++++++++++++++
* Added `populate` method.
1.0 (2014-04-02)
++++++++++++++++
* First stable release on PyPI.
0.1.0 (2014-03-17)
++++++++++++++++++
* First release on PyPI.
FAQs
Models to make easier to deal with structures that are converted to, or read from JSON.
We found that jsonmodels demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 2 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Research
The Socket Research Team breaks down a malicious wrapper package that uses obfuscation to harvest credentials and exfiltrate sensitive data.
Research
Security News
Attackers used a malicious npm package typosquatting a popular ESLint plugin to steal sensitive data, execute commands, and exploit developer systems.
Security News
The Ultralytics' PyPI Package was compromised four times in one weekend through GitHub Actions cache poisoning and failure to rotate previously compromised API tokens.