pythonsqlalchemypyramidcolanderalchemycornice

Cornice schema validation with colanderalchemy


Cornice's documentation mentions how to validate your schema using a colander's MappingSchema subclass. How should we use a colanderalchemy schema for the same purpose? Because if we create a schema using colanderalchemy as stated in the documentation, the schema object has already instantiated the colander's class, and I think that this results in an error.

To be more precise, here is my sample code:

from sqlalchemy.ext.declarative import declarative_base
from cornice.resource import resource, view
from colanderalchemy import SQLAlchemySchemaNode
from sqlalchemy import (
    Column,
    Integer,
    Unicode,
    )

Base = declarative_base()

'''
SQLAlchemy part
'''

class DBTable(Base):
    __tablename__ = 'mytable'

    id = Column(Integer, primary_key=True,
                info={'colanderalchemy': {'exclude': True}})
    name = Column(Unicode(70), nullable=False)
    description = Column(Unicode(256))


'''
ColanderAlchemy part
'''

ClndrTable = SQLAlchemySchemaNode(DBTable)


'''
Cornice part
'''

PRF='api'

@resource(collection_path='%s/' % PRF, path='%s/{fid}' % PRF)
class TableApi(object):
    def __init__(self, request):
        self.request = request

    @view(schema=ClndrTable, renderer='json')
    def put(self):
        # do my stuff here
        pass

Where ClndrTable is my auto-generated schema. Now, when trying to deploy this code, I get the following error:

NotImplementedError: Schema node construction without a typ argument or a schema_type() callable present on the node class

As I've mentioned earlier, I am suspecting that the problem is that ClndrTable (given as an argument to the view decorator) is an instantiation of the automatically generated schema by colanderalchemy.

Anyone knowing how to resolve this?

Thanks all in advance!


Solution

  • This appears to be due to the issue of colander having both a typ property and a schema_type property. They're both supposed to tell you the schema's type, but they can actually be different values. I filed an issue with colander, but if there's a fix it'll likely not make it to pypi any time soon.

    So what's happing is: ColanderAlchemy ignores schema_type and uses typ while Cornice ignores typ and uses schema_type.

    You can hack a fix with the following: ClndrTable.schema_type = lambda: ClndrTable.typ

    However, that just leads you to the next exception:

    cornice.schemas.SchemaError: schema is not a MappingSchema: <class 'colanderalchemy.schema.SQLAlchemySchemaNode'>
    

    This is due to Cornice not duck typing but expecting all Schema to be a subclass of MappingSchema. However, MappingSchema is just a Schema with typ/schema_type being Mapping (which is what ColanderAlchemy returns).

    I'll see if I can enact some changes to fix this.

    Update

    Despite the names, 'typ' and 'schema_type' have two different purposes. 'typ' always tells you the type of a schema instance. 'schema_type' is a method that's called to give a SchemaNode a default type when it's instantiated (so it's called in the __init__ if you don't pass a typ in, but other than that it's not supposed to be used).

    Cornice has been patched to properly use typ now (though, as of this message, it's not part of the latest release).