flask-restplus icon indicating copy to clipboard operation
flask-restplus copied to clipboard

Swagger input and output models example broken

Open cyounkins opened this issue 8 years ago • 5 comments

flask-restplus==0.9.2

Documentation here: http://flask-restplus.readthedocs.io/en/latest/swagger.html#input-and-output-models

Seems to suggest this should work:

from flask import Blueprint, request
from flask_restplus import Api, Resource, fields

bp = Blueprint('state_machine_api', __name__)
api = Api(bp, version='1.0', title='Labeling State Machines',
          description='Automated tasks associated with labeling')

fields = api.model('MyModel', {
    'name': fields.String(description='The name', required=True),
    'type': fields.String(description='The object type', enum=['A', 'B']),
    'age': fields.Integer(min=0),
})


@api.model(fields={'name': fields.String, 'age': fields.Integer})
class Person(fields.Raw):
    def format(self, value):
        return {'name': value.name, 'age': value.age}


@api.route('/my-resource/<id>', endpoint='my-resource')
@api.doc(params={'id': 'An ID'})
class MyResource(Resource):
    @api.doc(model=fields)
    def get(self, id):
        return {}

    @api.doc(model='MyModel', body=Person)
    def post(self, id):
        return {}

But:

(labeler) localhost% python views/test.py
Traceback (most recent call last):
  File "views/test.py", line 15, in <module>
    @api.model(fields={'name': fields.String, 'age': fields.Integer})
AttributeError: 'Model' object has no attribute 'String'
(labeler) localhost% python -V
Python 2.7.10

Frankly I'm not sure how it's supposed to go. Commenting out the fields = such that the references to fields uses the import:

Traceback (most recent call last):
  File "views/test.py", line 15, in <module>
    @api.model(fields={'name': fields.String, 'age': fields.Integer})
  File "/Users/cyounkins/.virtualenvs/labeler/lib/python2.7/site-packages/flask_restplus/namespace.py", line 137, in model
    model = Model(name, model, mask=mask)
  File "/Users/cyounkins/.virtualenvs/labeler/lib/python2.7/site-packages/flask_restplus/model.py", line 46, in __init__
    super(Model, self).__init__(*args, **kwargs)
TypeError: 'NoneType' object is not iterable

cyounkins avatar Dec 13 '16 23:12 cyounkins

I could reproduce both these errors:

  1. AttributeError: 'Model' object has no attribute 'String'
  2. TypeError: 'NoneType' object is not iterable

Error 1 is clearly happening because of the declaration fields = api.model(... is overriding the reference of the import from flask_restplus import fields. Changing the variable to something like my_model and substituting its references will solve this.

Error 2 is not clear to me. With the usage of the decorator @api.model(fields={'name': fields.String, 'age': fields.Integer}), it tries to instantiate a ModelBase and throws the TypeError when calling super(ModelBase, self).__init__(*args, **kwargs) in the ModelBase.__init__ (don't know why). Following the @api.model definition, if I change the parameter name in the decorator from fields to model (@api.model(model={'name': fields.String, 'age': fields.Integer})) I get the following error:

Traceback (most recent call last):
  File "example.py", line 17, in <module>
    class Person(fields.Raw):
TypeError: 'Model' object is not callable

I'm not sure if the error begins from a possibly wrong parameter name (fields instead of model) or if the usage is right and there is some problem with the model creation. Could anyone clarify this?

hygorxaraujo avatar Nov 30 '18 03:11 hygorxaraujo

Got a little bit further with the second error. Clarifying my own question, it seems the usage of @api.model with the fields parameter is right and the problem is with the creation of the model. Since no model is being passed in @api.model it is by default None and when it gets to the creation of a ModelBase the None value is passed through args (args==(None,)):

class ModelBase(object):
def __init__(self, name, *args, **kwargs):
    super(ModelBase, self).__init__(*args, **kwargs)

Where it gives the TypeError: 'NoneType' object is not iterable. Changing the model function to pass the model argument as a named parameter seems to fix this:

def model(self, name=None, model=None, mask=None, **kwargs):
    cls = OrderedModel if self.ordered else Model
    model = cls(name, model, mask=mask)  # change to: cls(name, model=model, mask=mask)
    model.__apidoc__.update(kwargs)
    return self.add_model(name, model)

The problem is that even after the correct creation of a model we get to this error:

Traceback (most recent call last):
  File "example.py", line 17, in <module>
    class Person(fields.Raw):
TypeError: 'Model' object is not callable

hygorxaraujo avatar Dec 09 '18 22:12 hygorxaraujo

@hygorxaraujo Did you ever make any more headway with this? I am trying to puzzle through the same now and am stumped.

Fail-Safe avatar Aug 23 '19 14:08 Fail-Safe

@Fail-Safe, I stopped working on it, sorry.

hygorxaraujo avatar Sep 07 '19 22:09 hygorxaraujo

I seem to be facing the same issue, has anyone found a workaround for this?

LinHuiqing avatar Jun 10 '20 09:06 LinHuiqing