GithubHelp home page GithubHelp logo

rossmacarthur / serde Goto Github PK

View Code? Open in Web Editor NEW
53.0 3.0 5.0 1.12 MB

:monorail: (unmaintained) A framework for defining, serializing, deserializing, and validating data structures

Home Page: https://rossmacarthur.github.io/serde

License: Apache License 2.0

Python 100.00%
python serialization deserialization validation schema python3 serde

serde's Introduction

Unmaintained

I will personally not be contributing any features or bug fixes to this project, but I am happy to accept pull requests. If you would like to maintain this project please let me know. If you are using this project please consider alternatives like:

Serde

PyPI Version Documentation Status Build Status Code Coverage Code Style

Serde is a lightweight, general-purpose framework for defining, serializing, deserializing, and validating data structures in Python.

Getting started

Installation

Serde is available on PyPI, you can install it using

pip install serde

Extended features can be installed with the ext feature.

pip install serde[ext]

Introduction

In Serde models are containers for fields. Data structures are defined by subclassing Model and assigning Field instances as class annotations. These fields handle serialization, deserialization, normalization, and validation for the corresponding model attributes.

from datetime import date
from serde import Model, fields

class Artist(Model):
    name: fields.Str()

class Album(Model):
    title: fields.Str()
    release_date: fields.Optional(fields.Date)
    artist: fields.Nested(Artist)

album = Album(
    title='Dangerously in Love',
    release_date=date(2003, 6, 23),
    artist=Artist(name='Beyoncé')
)
assert album.to_dict() == {
    'title': 'Dangerously in Love',
    'release_date': '2003-06-23',
    'artist': {
        'name': 'Beyoncé'
    }
}

album = Album.from_json("""{
    "title": "Lemonade",
    "artist": {"name": "Beyoncé"}}"
""")
assert album == Album(title='Lemonade', artist=Artist(name='Beyoncé'))

Basic usage

Below we create a User model by subclassing Model and adding the name and email fields.

>>> from datetime import datetime
>>> from serde import Model, fields
>>>
>>> class User(Model):
...     name: fields.Str(rename='username')
...     email: fields.Email()

The corresponding attribute names are used to instantiate the model object and access the values on the model instance.

>>> user = User(name='Linus Torvalds', email='[email protected]')
>>> user.name
'Linus Torvalds'
>>> user.email
'[email protected]'

Models are validated when they are instantiated and a ValidationError is raised if you provide invalid values.

>>> User(name='Linus Torvalds', email='not an email')
Traceback (most recent call last):
...
serde.exceptions.ValidationError: {'email': 'invalid email'}

Models are serialized into primitive Python types using the to_dict() method on the model instance.

>>> user.to_dict()
OrderedDict([('username', 'Linus Torvalds'), ('email', '[email protected]')])

Or to JSON using the to_json() method.

>>> user.to_json()
'{"username": "Linus Torvalds", "email": "[email protected]"}'

Models are also validated when they are deserialized. Models are deserialized from primitive Python types using the reciprocal from_dict() class method.

>>> user = User.from_dict({
...     'username': 'Donald Knuth',
...     'email': '[email protected]'
... })

Or from JSON using the from_json() method.

>>> user = User.from_json('''{
...     "username": "Donald Knuth",
...     "email": "[email protected]"
... }''')

Attempting to deserialize invalid data will result in a ValidationError.

>>> User.from_dict({'username': 'Donald Knuth'})
Traceback (most recent call last):
...
serde.exceptions.ValidationError: {'email': "missing data, expected field 'email'"}

Models

Models can be nested and used in container-like fields. Below we create a Blog with an author and a list of subscribers which must all be User instances.

>>> class Blog(Model):
...     title: fields.Str()
...     author: fields.Nested(User)
...     subscribers: fields.List(User)

When instantiating you have to supply instances of the nested models.

>>> blog = Blog(
...     title="sobolevn's personal blog",
...     author=User(name='Nikita Sobolev', email='[email protected]'),
...     subscribers=[
...         User(name='Ned Batchelder', email='[email protected]')
...     ]
... )

Serializing a Blog would serialize the entire nested structure.

>>> print(blog.to_json(indent=2))
{
  "title": "sobolevn's personal blog",
  "author": {
    "username": "Nikita Sobolev",
    "email": "[email protected]"
  },
  "subscribers": [
    {
      "username": "Ned Batchelder",
      "email": "[email protected]"
    }
  ]
}

Similiarly deserializing a Blog would deserialize the entire nested structure, and create instances of all the submodels.

Subclassed models

Models can be subclassed. The subclass will have all the fields of the parent and any additional ones. Consider the case where we define a SuperUser model which is a subclass of a User. Simply a User that has an extra level field.

>>> class SuperUser(User):
...     # inherits name and email fields from User
...     level: fields.Choice(['admin', 'read-only'])

We instantiate a subclassed model as normal by passing in each field value.

>>> superuser = SuperUser(
...     name='Linus Torvalds',
...     email='[email protected]',
...     level='admin'
... )

This is great for many cases, however, a commonly desired paradigm is to be able to have the User.from_dict() class method be able to deserialize a SuperUser as well. This can be made possible through model tagging.

Model tagging

Model tagging is a way to mark serialized data in order to show that it is a particular variant of a model. Serde provides three types of model tagging, but you can also define you own custom Tag. A Tag can be thought of in the same way as a Field but instead of deserializing data into an attribute on a model instance, it deserializes data into a model class.

Internally tagged

Internally tagged data stores a tag value inside the serialized data.

Let us consider an example where we define a Pet model with a tag. We can then subclass this model and deserialize arbitrary subclasses using the tagged model.

>>> from serde import Model, fields, tags
>>>
>>> class Pet(Model):
...     name: fields.Str()
...
...     class Meta:
...         tag = tags.Internal(tag='species')
...
>>> class Dog(Pet):
...     hates_cats: fields.Bool()
...
>>> class Cat(Pet):
...     hates_dogs: fields.Bool()

We refer to the Dog and Cat subclasses as variants of Pet. When serializing all parent model tag serialization is done after field serialization.

>>> Cat(name='Fluffy', hates_dogs=True).to_dict()
OrderedDict([('name', 'Fluffy'), ('hates_dogs', True), ('species', '__main__.Cat')])

When deserializing, tag deserialization is done first to determine which model to use for the deserialization.

>>> milo = Pet.from_dict({
...     'name': 'Milo',
...     'hates_cats': False,
...     'species': '__main__.Dog'
... })
>>> milo.__class__
<class '__main__.Dog'>
>>> milo.name
'Milo'
>>> milo.hates_cats
False

An invalid or missing tag will raise a ValidationError.

>>> Pet.from_dict({'name': 'Milo', 'hates_cats': False})
Traceback (most recent call last):
...
serde.exceptions.ValidationError: missing data, expected tag 'species'
>>>
>>> Pet.from_dict({'name': 'Duke', 'species': '__main__.Horse'})
Traceback (most recent call last):
...
serde.exceptions.ValidationError: no variant found

Externally tagged

Externally tagged data uses the tag value as a key and nests the content underneath that key. All other processes behave similarly to the internally tagged example above.

>>> class Pet(Model):
...     name: fields.Str()
...
...     class Meta:
...         tag = tags.External()
...
>>> class Dog(Pet):
...     hates_cats: fields.Bool()
...
>>> Dog(name='Max', hates_cats=True).to_dict()
OrderedDict([('__main__.Dog', OrderedDict([('name', 'Max'), ('hates_cats', True)]))])

Adjacently tagged

Adjacently tagged data data stores the tag value and the content underneath two separate keys. All other processes behave similarly to the internally tagged example.

>>> class Pet(Model):
...     name: fields.Str()
...
...     class Meta:
...         tag = tags.Adjacent(tag='species', content='data')
...
>>> class Dog(Pet):
...     hates_cats: fields.Bool()
...
>>> Dog(name='Max', hates_cats=True).to_dict()
OrderedDict([('species', '__main__.Dog'), ('data', OrderedDict([('name', 'Max'), ('hates_cats', True)]))])

Abstract models

By default model tagging still allows deserialization of the base model. It is common to have this model be abstract. You can do this by setting the abstract Meta field to True. This will make it uninstantiatable and it won't be included in the variant list during deserialization.

>>> class Fruit(Model):
...     class Meta:
...         abstract = True
...
>>> Fruit()
Traceback (most recent call last):
...
TypeError: unable to instantiate abstract model 'Fruit'

Custom tags

It is possible to create your own custom tag class by subclassing any of tags.External, tags.Internal, tags.Adjacent or even the base tags.Tag. This will allow customization of how the variants are looked up, how the tag values are generated for variants, and how the data is serialized.

Consider an example where we use a class attribute code as the tag value.

>>> class Custom(tags.Internal):
...     def lookup_tag(self, variant):
...         return variant.code
...
>>> class Pet(Model):
...     name: fields.Str()
...
...     class Meta:
...         abstract = True
...         tag = Custom(tag='code')
...
>>> class Dog(Pet):
...     code = 1
...     hates_cats: fields.Bool()
...
>>> Dog(name='Max', hates_cats=True).to_dict()
OrderedDict([('name', 'Max'), ('hates_cats', True), ('code', 1)])
>>> max = Pet.from_dict({'name': 'Max', 'hates_cats': True, 'code': 1})
>>> max.__class__
<class '__main__.Dog'>
>>> max.name
'Max'
>>> max.hates_cats
True

Fields

Fields do the work of serializing, deserializing, normalizing, and validating the input values. Fields are always assigned to a model as instances , and they support extra serialization, deserialization, normalization, and validation of values without having to subclass Field. For example

from serde import Model, fields, validators

class Album(Model):
    title: fields.Str(normalizers=[str.strip])
    released: fields.Date(
        rename='release_date',
        validators=[validators.Min(datetime.date(1912, 4, 15))]
    )

In the above example we define an Album class. The title field is of type str , and we apply the str.strip normalizer to automatically strip the input value when instantiating or deserializing the Album. The released field is of type datetime.date and we apply an extra validator to only accept dates after 15th April 1912. Note: the rename argument only applies to the serializing and deserializing of the data, the Album class would still be instantiated using Album(released=...).

If these methods of creating custom Field classes are not satisfactory, you can always subclass a Field and override the relevant methods.

>>> class Percent(fields.Float):
...     def validate(self, value):
...         super().validate(value)
...         validators.Between(0.0, 100.0)(value)

Model states and processes

In Serde, there are two states that the data can be in:

  • Serialized data
  • Model instance

There are five different processes that the data structure can go through when moving between these two states.

  • Deserialization happens when you create a model instance from a serialized version using from_dict() or similar.
  • Instantiation happens when you construct a model instance in Python using the __init__() constructor.
  • Normalization happens after instantiation and after deserialization. This is usually a way to transform things before they are validated. For example: this is where an Optional field sets default values.
  • Validation is where the model and fields values are validated. This happens after normalization.
  • Serialization is when you serialize a model instance to a supported serialization format using to_dict() or similar.

The diagram below shows how the stages (uppercase) and processes (lowercase) fit in with each other.

                    +---------------+
                    | Instantiation |
                    +---------------+
                            |
                            v
+---------------+   +---------------+
|Deserialization|-->| Normalization |
+---------------+   +---------------+
        ^                   |
        |                   v
        |           +---------------+
        |           |   Validation  |
        |           +---------------+
        |                   |
        |                   v
+-------+-------+   +---------------+
|SERIALIZED DATA|   | MODEL INSTANCE|
+---------------+   +---------------+
        ^                   |
        |                   |
+-------+-------+           |
| Serialization |<----------+
+---------------+

License

Serde is licensed under either of

at your option.

serde's People

Contributors

nomad010 avatar rossmacarthur avatar vyrzdev avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

serde's Issues

First-class support for containers

Storing collections of objects in various containers is an everyday job. However, currently there is no obvious way to have a field that is just a top-level container by itself.

Let's say we have the following structure:

{
    "Hello": {
        "name": "World",
        "id": 123,
    },
    "Foo": {
        "name": "Bar",
        "id": 42,
    }
}

In this case one could write the User type as the following:

class User(Model):
    name: fields.Str()
    id: fields.Int()

but representing the outer dictionary is hard and cumbersome.

Of course it is possible to wrap it in a new type that has a dict field, but that will create a new layer in the output and the user has to dispatch the functions being used (or use the field directly, also not very nice).
The other solution I found is to serialize the User type into a dict and serialize the whole data structure using the json module, but that also feels cumbersome.

I could imagine something like this (but probably now the brightest solution):

MyUsersDict = serde.collections.Dict(serde.fields.Str(), User)

users = MyUsersDict()
users["Hello"] = User(...)

Use `simplejson` package if available

This can be as simple as

try:
    import simplejson as json
except ImportError:
    import json

I think we can add a json feature that will install simplejson as well.

Automated publishing of docs to `gh-pages` branch

At the moment I have to do the following:

pip install sphinx
just docs
cd docs/_build/html
git init
git remote add origin [email protected]:rossmacarthur/serde.git
git fetch
git reset origin/gh-pages
git add .
git commit -m "publish docs for $(git -C ../../.. rev-parse --short HEAD)"
git push origin HEAD:gh-pages

Model tagging when serializing and deserializing

It is very common to want to have an abstract Model that can will be automatically deserialized into the correct subclass.

Example

from serde import Model, fields

class Abstract(Model):
    x = fields.Str()

class A(Abstract):
    a = fields.Int()

class B(Abstract):
    b = fields.Float()


a = Abstract.from_dict({
    'x': 'test',
    'a': 5
}) 

b = Abstract.from_dict({
    'x': 'test',
    'b': 5.0
}) 

The current easiest way to do this is through tagging, and then overriding the from_dict and to_dict methods of the Abstract model to serialize and deserialize the tag field.

class Abstract(Model):
    x = fields.Str()

    @classmethod
    def from_dict(cls, d, **kwargs):
        if cls is Abstract:  # this is the key part that makes this all work
            tag = d.pop('tag')
            subcls = {c.__name__: c for c in cls.__subclasses__()}[tag]
            return subcls.from_dict(d, **kwargs)

        return super(Abstract, cls).from_dict(d, **kwargs)

    def to_dict(self, **kwargs):
        d = self.to_dict(**kwargs)
        d['tag'] = self.__class__.__name__
        return d

You can even create a subclass-able Tagged Model.

class Tagged(Model):

    @classmethod
    def from_dict(cls, d, **kwargs):
        if Tagged in cls.__bases__:  # this is the key part that makes this all work
            tag = d.pop('tag')
            subcls = {c.__name__: c for c in cls.__subclasses__()}[tag]
            return subcls.from_dict(d, **kwargs)

        return super(Tagged, cls).from_dict(d, **kwargs)

    def to_dict(self, **kwargs):
        d = self.to_dict(**kwargs)
        d['tag'] = self.__class__.__name__
        return d

But it might be better to do this with decorators? We would also want to have the tag field be configurable. Maybe this is the time to add a Meta inner class, that can be used by the ModelType metaclass to adjust Model settings.

Perhaps we should move away from metaclasses completely and use decorators like attrs.

Integration with mypy

I'm not sure if the serde field type annotations are compatible with MyPy. For example, with this code:

from serde import Model, fields
class Artist(Model):
    name: fields.Str()

Running mypy on the code gives the following result (in addition to an error about the fact that serde doesn't have a type definition module):

serdetest.py:7: error: Invalid type comment or annotation
serdetest.py:7: note: Suggestion: use fields.Str[...] instead of fields.Str(...)

So, on the surface, it seems that this library is incompatible with MyPy. Is this true, or is there a way to get them to work together?

serialising sets to json fails

since serializing sets to dict is supported for sets, i expected serialising sets to json to work.
serializing to dict gives "('attribute_name', set())" which then fails to serialise to json giving the error "TypeError: Object of type set is not JSON serializable"

Container types not handled properly in `ValidationError` output

Consider the example below:

from serde import Model, fields

class Nested(Model):
    number = fields.Int()

class Example(Model):
    group = fields.List(Nested)

Example.from_dict({'group': [{'number': 5}, {'number': None}]})
#^ serde.exceptions.ValidationError: {'group': {'number': "invalid type, expected 'int'"}}

In the output of the ValidationError {'group': {'number': "invalid type, expected 'int'"}} doesn't give context to the List

Unix Timestamp for datetime field

I don't know whether this makes sense, but since I needed this, it just might.
Could you have unix timestamp as a format for datetime?

Continuous fuzzing by way of OSS-Fuzz

Hi,

I was wondering if you would like to integrate continuous fuzzing by way of OSS-Fuzz? Fuzzing is a way to automate test-case generation and has been heavily used for memory unsafe languages. Recently efforts have been put into fuzzing memory safe languages and Python, and the bugs fuzzing can currently help find is uncaught exceptions. Down the line more bug oracles will hopefully come.

In this PR google/oss-fuzz#8139 I did an initial integration into OSS-Fuzz. The first fuzzer checks if from_dict can ever raise any exceptions other than ValidationError. OSS-Fuzz is a free service run by Google that performs continuous fuzzing of important open source projects.

If you would like to integrate, the only thing I need is a list of email(s) that will get access to the data produced by OSS-Fuzz, such as bug reports, coverage reports and more stats. Notice the emails affiliated with the project will be public in the OSS-Fuzz repo, as they will be part of a configuration file.

Add Support for Transparent and Alias Fields

Compared to the comparable library in Rust, this package lacks support for Transparent and Alias fields. Adding support for these two features would increase interoperability with serialized data from projects written in Rust.

I would be happy to implement these myself and submit a PR, but at the moment my free time is rather limited. Here's an untested stab at what an implementation of these two features may look like (but certainly needs validation):

from serde import fields
from serde.exceptions import ValidationError

class Transparent(fields.Field):
    """Serialize and deserialize a newtype struct or a braced struct with one
       field exactly the same as if its one field were serialized and
       deserialized by itself."""

    def _deserialize_with(self, model, d):
        if len(d) != 1:
            raise ValidationError(
                'Transparent Fields {!r} must be only field in class'.format(
                    self._serde_name)
            )
        setattr(model, self._attr_name, self._deserialize(d[next(iter(d))]))
        return model, d

    def _serialize_with(self, model, d):
        return self._serialize(getattr(model, self._attr_name))


class Alias(fields.Field):
    """Allows the specification of an alternate deserialization field name for
       the contained field. Alias should not be the name of another field
       within the same model."""
    
    def __init__(self, aliases: str, *args, **kwargs):
        self.aliases = aliases
        super(Alias, self).__init__(*args, **kwargs)
    
    def _deserialize_with(self, model, d):
        for alias in self.aliases:
            if alias in self._model_cls._fields:
                raise ValidationError(
                    'Alias cannot contain existing field name {!r}'.format(
                        alias
                ))
        if self._attr_name in d:
            value = d[self._attr_name]
            setattr(model, self._attr_name, self._deserialize(value))
        else:
            for alias in self.aliases:
                if alias in d:
                    value = d[alias]
                    d[self._attr_name] = d.pop(alias)
                    setattr(model, self._attr_name, self._deserialize(value))
                    break
        return model, d

Add 'Auto' field or something more appropriately named

It would be nice to have a field that must be present in deserialization but has a default when instantiated.

Currently the way this has to be done is by overriding the __init__ method.

from serde import Model, fields

class Example(Model):
    name = fields.Str()
    
    def __init__(self, **kwargs):
        kwargs.setdefault('a', 'a default value')
        super().__init__(**kwargs)

Add Text field

It would be nice to have a field that can handle bytes and strings (strings and unicode in Py2). It could take an encoding value as well, otherwise defaulting to UTF-8.

Example:

from serde import Model, fields

class Example(Model):
    text = fields.Text(encoding='utf-8-sig')

assert Example(text=b'test') == Example(text=u'test')
assert Example(text=u'test') == Example(text=u'test')

Add Enum Field

It might be nice to have a Field that is serialized as an integer, but deserialized as a something else.

Example:

result = Enum('Ok', 'Err')

assert result.serialize('Ok') == 0
assert result.serialize('Err') == 1

assert result.deserialize(0) == 'Ok'
assert result.deserialize(1) == 'Err'

Add Optional Field

Instead of having the required and default options on Fields this could be a seperate Field class.

Example:

from serde import Model, field

class Example(Model):
    a = field.Optional(field.Int)
    b = field.Optional(field.Str, default='Hello World!')

An Optional would not be be required to be present when deserializing and instantiating. If not present the value on the Model will be None.

Doing this removes the following case from Fields:
required = True
default = xxxxx

which is probably fine because this was confusing anyway. It meant that instantiation was possible but deserialization was not.

Use `inspect` to determine parameters for serialize, deserialize, and validate methods

This would allow variable arguments for serialize, deserialize, and validate methods. This is to faciliate cases where Field serialization, deserialization, and validation is dependent for example on the parent model.

We could either do it based on the number of arguments (1) or based on the argument names (2).

For example (1):

# If there is only a single parameter then pass the value
validate(value)

# If there is two parameters pass the value and the current model
validate(value, model)

# If there is three parameters pass the value, the current model, and the parent model?
validate(value, model, parent_model)

For example (2):

# Detect the argument names so all the above would be possible, as well as
validate(value, parent_model)
validate(model, value)
# etc...

The more important question is perhaps what we would like to be passed. Is it the Model instance that is in the process of being deserialized (pre normalization). Or the Model class, or perhaps either or?

Removing one level of nesting

Hi, thanks for the library! (glad to find it, coming from Rust 🦀)

I have a following json for which I'd like to remove one level of nesting:

{
    "id": 256,
    "title": "Super Album",
    "release_date": "2000-01-02",
    "artist": {
        "id": 42,
        "name": "Some Name"
    },
    "tracks": {
        "data": [
            {
                "id": 123,
                "title": "Track Title"
            }
        ]
    }
}

Deserialization uses following classes it with following classes:

class Artist(Model):
    name: fields.Str()


class Track(Model):
    id: fields.Int()
    title: fields.Str()


class TracksData(Model):
    data: fields.List(Track)


class Album(Model):
    title: fields.Str()
    release_date: fields.Optional(fields.Date)
    artist: fields.Nested(Artist)
    tracks: fields.Nested(TracksData)

Is it possible to get tracks as a list of tracks? In the docs there is fields.Flatten and it's possible to specify deserializers for a field, but I struggle with it and ask for some help. Thanks 😃

Ability to access parent model

It would be nice on a Model instance to be able to access the parent model instance. For example

from serde import Model, fields

class SubExample(Model):
    a = fields.Int()
    
    @property
    def parent_id(self):
        return self._parent.id

class Example(Model):
    id = fields.Int()
    b = fields.Nested(SubExample)


e = Example(id=10, b=SubExample(a=5))
assert e.b.parent_id == 10

Allow install without `validators` package

This would make a bunch of Fields optional, but wouldn't require the validators package. This would reduce the size of the default package. This would obviously be a breaking change.

We need to decide whether this should be a separate package like serde-ext, or should simply be a feature in the current package e.g. pip install serde[extended]

Need to bump chardet dependencies

Chardet is in major release 5. It is unknown what will happen if not installing the extra ext while chardet==5.1.0 is in the module path.

Provides-Extra: ext
Requires-Dist: chardet (==3.*) ; extra == 'ext'
Requires-Dist: validators (>=0.12.0) ; extra == 'ext'

Having it so far behind keeps chardet quite behind when installing a list of pip requirements where various libraries use this tool. It also restricts direct usage of chardet to an old API.

Add Number Field

It would be nice to have a Field that can handle all types of Numbers. Floats, integers, (longs in Python 2). Perhaps Decimals, and complex numbers too.

from serde import Model, fields

class Example(Model):
    number = fields.Number()

assert Example(number=5.0) == Example(number=5)
assert Example(number=5 + 0j) == Example(number=5)

Add length validate methods

Example

from serde import Model, fields, validate

class Example(Model):
    a = fields.Field(validators=[validate.length(10)])
    b = fields.Field(validators=[validate.length_between(10, 20, inclusive=False)])
    c = fields.Field(validators=[validate.length_min(10, inclusive=True)])
    d = fields.Field(validators=[validate.length_max(10)])

Can't set attribute error, when trying to use the same name as a Field

How to replicate:

from serde import Model, field

class A(Model):
    derp = field.Field()

class B(A):
    @property
    def derp(self):
        return 'something else'

B()  # does not work

Exception is

serde/model.py", line 284, in __init__
    setattr(self, name, value)
AttributeError: can't set attribute

Store Model and Field chain in SerdeErrors

If there is a serialization, deserialization, or validation failure on some nested Model, it would be nice to traverse the Model and Field objects that the failure occurred in.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.