Metadata-Version: 1.1
Name: anyblok_marshmallow
Version: 1.0.1
Summary: Add validator, serializer and deserializer to AnyBlok
Home-page: https://anyblok-marshmallow.readthedocs.io/en/1.0.1
Author: Jean-Sébastien SUZANNE
Author-email: jssuzanne@anybox.fr
License: UNKNOWN
Description: .. This file is a part of the AnyBlok Marshmallow project
        ..
        ..    Copyright (C) 2017 Jean-Sebastien SUZANNE <jssuzanne@anybox.fr>
        ..
        .. This Source Code Form is subject to the terms of the Mozilla Public License,
        .. v. 2.0. If a copy of the MPL was not distributed with this file,You can
        .. obtain one at http://mozilla.org/MPL/2.0/.
        
        .. image:: https://travis-ci.org/AnyBlok/AnyBlok_Marshmallow.svg?branch=master
            :target: https://travis-ci.org/AnyBlok/AnyBlok_Marshmallow
            :alt: Build status
        
        .. image:: https://coveralls.io/repos/github/AnyBlok/AnyBlok_Marshmallow/badge.svg?branch=master
            :target: https://coveralls.io/github/AnyBlok/AnyBlok_Marshmallow?branch=master
            :alt: Coverage
        
        .. image:: https://img.shields.io/pypi/v/AnyBlok_Marshmallow.svg
           :target: https://pypi.python.org/pypi/AnyBlok_Marshmallow/
           :alt: Version status
                 
        .. image:: https://readthedocs.org/projects/AnyBlok_Marshmallow/badge/?version=latest
            :alt: Documentation Status
            :scale: 100%
            :target: https://doc.anyblok-marshmallow.anyblok.org/?badge=latest
        
        
        AnyBlok Marshmallow
        ===================
        
        Improve AnyBlok `AnyBlok <http://doc.anyblok.org>`_ to add validator, serializer and 
        deserializer schema with `marshmallow <https://marshmallow.readthedocs.io/en/latest/>`_.
        
        This module is a wrapper of `marshmallow-sqlalchemy <https://marshmallow-sqlalchemy.readthedocs.io/en/latest/>`_,
        the goal is to give the SQLAlchemy Model build by AnyBlok to this librairy
        
        AnyBlok Marshmallow is released under the terms of the `Mozilla Public License`.
        
        See the `latest documentation <http://doc.anyblok-marshmallow.anyblok.org/>`_
        
        .. This file is a part of the AnyBlok / Marshmallow project
        ..
        ..    Copyright (C) 2017 Jean-Sebastien SUZANNE <jssuzanne@anybox.fr>
        ..
        .. This Source Code Form is subject to the terms of the Mozilla Public License,
        .. v. 2.0. If a copy of the MPL was not distributed with this file,You can
        .. obtain one at http://mozilla.org/MPL/2.0/.
        
        .. contents::
        
        Front Matter
        ============
        
        Information about the AnyBlok / Marshmallow project.
        
        Project Homepage
        ----------------
        
        AnyBlok is hosted on `github <http://github.com>`_ - the main project
        page is at https://githusb.com/AnyBlok/AnyBlok_Marshmallow. Source code is
        tracked here using `GIT <https://git-scm.com>`_.
        
        Releases and project status are available on Pypi at
        http://pypi.python.org/pypi/anyblok_marshmallow.
        
        The most recent published version of this documentation should be at
        http://doc.anyblok-marshmallow.anyblok.org.
        
        Project Status
        --------------
        
        AnyBlok with Marshmallow is currently in beta status and is expected to be fairly
        stable.   Users should take care to report bugs and missing features on an as-needed
        basis.  It should be expected that the development version may be required
        for proper implementation of recently repaired issues in between releases;
        
        Installation
        ------------
        
        Install released versions of AnyBlok from the Python package index with
        `pip <http://pypi.python.org/pypi/pip>`_ or a similar tool::
        
            pip install anyblok_marshmallow
        
        Installation via source distribution is via the ``setup.py`` script::
        
            python setup.py install
        
        Installation will add the ``anyblok`` commands to the environment.
        
        Unit Test
        ---------
        
        Run the test with ``nose``::
        
            pip install nose
            nosetests anyblok_marshmallow/tests
        
        Dependencies
        ------------
        
        AnyBlok works with **Python 3.3** and later. The install process will
        ensure that `AnyBlok <http://doc.anyblok.org>`_,
        `marshmallow <https://marshmallow.readthedocs.io/en/latest/>`_ and 
        `marshmallow-sqlalchemy <https://marshmallow-sqlalchemy.readthedocs.io/en/latest/>`_ 
        are installed, in addition to other dependencies. 
        The latest version of them is strongly recommended.
        
        
        Contributing (hackers needed!)
        ------------------------------
        
        Anyblok / Marshmallow is at a very early stage, feel free to fork, talk with core
        dev, and spread the word!
        
        Author
        ------
        
        Jean-Sébastien Suzanne
        
        Contributors
        ------------
        
        `Anybox <http://anybox.fr>`_ team:
        
        * Jean-Sébastien Suzanne
        
        `Sensee <http://sensee.com>`_ team:
        
        * Franck Bret
        
        Bugs
        ----
        
        Bugs and feature enhancements to AnyBlok should be reported on the `Issue
        tracker <https://github.com/AnyBlok/AnyBlok_Marshmallow/issues>`_.
        
        .. This file is a part of the AnyBlok / Marshmallow project
        ..
        ..    Copyright (C) 2017 Jean-Sebastien SUZANNE <jssuzanne@anybox.fr>
        ..
        .. This Source Code Form is subject to the terms of the Mozilla Public License,
        .. v. 2.0. If a copy of the MPL was not distributed with this file,You can
        .. obtain one at http://mozilla.org/MPL/2.0/.
        
        .. contents::
        
        Memento
        =======
        
        Declare your **AnyBlok model**
        ------------------------------
        
        ::
        
            from anyblok.column import Integer, String
            from anyblok.relationship import Many2One, Many2Many
            from anyblok import Declarations
        
        
            @Declarations.register(Declarations.Model)
            class City:
        
                id = Integer(primary_key=True)
                name = String(nullable=False)
                zipcode = String(nullable=False)
        
                def __repr__(self):
                    return '<City(name={self.name!r})>'.format(self=self)
        
        
            @Declarations.register(Declarations.Model)
            class Tag:
        
                id = Integer(primary_key=True)
                name = String(nullable=False)
        
                def __repr__(self):
                    return '<Tag(name={self.name!r})>'.format(self=self)
        
        
            @Declarations.register(Declarations.Model)
            class Customer:
                id = Integer(primary_key=True)
                name = String(nullable=False)
                tags = Many2Many(model=Declarations.Model.Tag)
        
                def __repr__(self):
                    return '<Customer(name={self.name!r}, '
                           'tags={self.tags!r})>'.format(self=self)
        
        
            @Declarations.register(Declarations.Model)
            class Address:
        
                id = Integer(primary_key=True)
                street = String(nullable=False)
                city = Many2One(model=Declarations.Model.City, nullable=False)
                customer = Many2One(
                    model=Declarations.Model.Customer, nullable=False,
                    one2many="addresses")
        
        
        .. warning::
        
            The **AnyBlok model** must be declared in a blok
        
        
        Declare your schema
        -------------------
        
        ::
        
            from anyblok_marshmallow import ModelSchema
            from marshmallow import fields
        
            class CitySchema(ModelSchema):
        
                class Meta:
                    model = 'Model.City'
        
        
            class TagSchema(ModelSchema):
        
                class Meta:
                    model = 'Model.Tag'
        
        
            class AddressSchema(ModelSchema):
        
                # follow the relationship Many2One and One2One
                city = fields.Nested(CitySchema)
        
                class Meta:
                    model = 'Model.Address'
        
        
            class CustomerSchema(ModelSchema):
        
                # follow the relationship One2Many and Many2Many
                # - the many=True is required because it is *2Many
                # - exclude is used to forbid the recurse loop
                addresses = fields.Nested(AddressSchema, many=True, exclude=('customer', ))
                tags = fields.Nested(TagSchema, many=True)
        
                class Meta:
                    model = 'Model.Customer'
                    # optionally attach an AnyBlok registry
                    # to use for serialization, desarialization and validation
                    registry = registry
                    # optionally return an AnyBlok model instance
                    post_load_return_instance = True
        
        
            customer_schema = CustomerSchema()
        
        
        (De)serialize your data and validate it
        ---------------------------------------
        
        ::
        
            customer = registry.Customer.insert(name="JS Suzanne")
            tag1 = registry.Tag.insert(name="tag 1")
            customer.tags.append(tag1)
            tag2 = registry.Tag.insert(name="tag 2")
            customer.tags.append(tag2)
            rouen = registry.City.insert(name="Rouen", zipcode="76000")
            paris = registry.City.insert(name="Paris", zipcode="75000")
            registry.Address.insert(customer=customer, street="Somewhere", city=rouen)
            registry.Address.insert(customer=customer, street="Another place", city=paris)
        
            dump_data = customer_schema.dump(customer).data
            # {
            #     'id': 1,
            #     'name': 'JS Suzanne',
            #     'tags': [
            #         {
            #             'id': 1,
            #             'name': 'tag 1',
            #         },
            #         {
            #             'id': 2,
            #             'name': 'tag 2',
            #         },
            #     ],
            #     'addresses': [
            #         {
            #             'id': 1
            #             'street': 'Somewhere'
            #             'city': {
            #                 'id': 1,
            #                 'name': 'Rouen',
            #                 'zipcode': '76000',
            #             },
            #         },
            #         {
            #             'id': 2
            #             'street': 'Another place'
            #             'city': {
            #                 'id': 2,
            #                 'name': 'Paris',
            #                 'zipcode': '75000',
            #             },
            #         },
            #     ],
            # }
        
            customer_schema.load(dump_data).data
            # <Customer(name='JS Suzanne' tags=[<Tag(name='tag 1')>, <Tag (name='tag 2')>])>
        
            errors = customer_schema.validate(dump_data)
            # dict with all the validating errors
        
        
        .. note::
            By default: the deserialization return a dict with deserialized data, here we get an
            instance of the model because the ``CustomerSchema`̀` add **post_load_return_instance = True**
            in their Meta
        
        
        Give the registry
        -----------------
        
        The schema need to have the registry.
        
        If no registry found when the de(serialization) or validation then the 
        **RegistryNotFound** exception will be raised.
        
        Add the **registry** by the Meta
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        
        This is the solution given in the main exemple::
        
            class CustomerSchema(ModelSchema):
        
                class Meta:
                    model = 'Model.Customer'
                    registry = registry
        
        
        Add the **registry** during init
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        
        This solution is use during the instanciation
        
        ::
        
            customer_schema = CustomerSchema(registry=registry)
        
        
        Add the **registry** by the context
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        
        This solution is use during the instanciation or after
        
        ::
        
            customer_schema = CustomerSchema(context={'registry': registry})
        
        or
        
        ::
        
            customer_schema = CustomerSchema()
            customer_schema.context['registry'] = registry
        
        
        Add the **registry** when the de(serialization or validatoris called
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        
        ::
        
            customer_schema.dump(customer, registry=registry)
            customer_schema.load(dump_data, registry=registry)
            customer_schema.validate(dump_data, registry=registry)
        
        
        **post_load_return_instance** option
        ------------------------------------
        
        As the registry this option can be passed by initialization of the schema, by the
        context or during the call of methods
        
        The value of this options can be:
        
        * False: **default**, the output is a dict
        * True: the output is an instance of the model. The primary keys must be in value
        * array of string: the output is an instance of the model, each str entry must be an existing column
        
        .. warning::
        
            If the option is not False, and the instance can no be found, then the **instance** error will be added
            in the errors dict of the method
        
        .. warning::
        
            The post load is only for load method!!!
        
        
        Overriding Generated Fields
        ---------------------------
        
        :: 
        
            from anyblok_marshmallow import ModelSchema
            from marshmallow import fields
        
            class Customer(ModelSchema):
        
                date_created = field_for(Author, 'date_created', dump_only=True)
        
                class Meta:
                    model = 'Model.Customer'
        
        .. This file is a part of the AnyBlok / Marshmallow project
        ..
        ..    Copyright (C) 2017 Jean-Sebastien SUZANNE <jssuzanne@anybox.fr>
        ..
        .. This Source Code Form is subject to the terms of the Mozilla Public License,
        .. v. 2.0. If a copy of the MPL was not distributed with this file,You can
        .. obtain one at http://mozilla.org/MPL/2.0/.
        
        .. contents::
        
        CHANGELOG
        =========
        
        1.0.0 (2017-10-24)
        ------------------
        
        * Add marshmallow schema for AnyBlok for:
        
          - Serialization
          - Deserialization
          - Validation
        
Keywords: anyblok_marshmallow
Platform: UNKNOWN
Classifier: Development Status :: 2 - Pre-Alpha
Classifier: Intended Audience :: Developers
Classifier: Natural Language :: English
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.3
Classifier: Programming Language :: Python :: 3.4
Classifier: Programming Language :: Python :: 3.5
Classifier: Programming Language :: Python :: 3.6
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0)
