Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AttributeError: type object '<model>' has no attribute '' #8

Open
hroncok opened this issue Apr 25, 2016 · 2 comments
Open

AttributeError: type object '<model>' has no attribute '' #8

hroncok opened this issue Apr 25, 2016 · 2 comments

Comments

@hroncok
Copy link

hroncok commented Apr 25, 2016

Given the following example (search for HERE IS THE PROBLEM):

from flask import Flask
from flask.ext.sqlalchemy import SQLAlchemy
from flask_ripozo import FlaskDispatcher
from ripozo import restmixins, ListRelationship, Relationship, adapters, apimethod
from ripozo_sqlalchemy import AlchemyManager, SessionHandler
from sqlalchemy.engine.url import URL
from sqlalchemy.orm import relationship

app = Flask(__name__)
url = URL('mysql', query={'read_default_file': './mysql.cnf'})
app.config['SQLALCHEMY_DATABASE_URI'] = url
db = SQLAlchemy(app)


session_handler = SessionHandler(db.session)

class Sport(db.Model):
    __tablename__ = 'v_sports'

    id_sport = db.Column(db.Integer, primary_key=True)
    description = db.Column(db.String)


class Course(db.Model):
    __tablename__ = 'v_subjects'

    id_course = db.Column('id_subjects', db.Integer, primary_key=True)
    _sport = db.Column('sport', db.Integer, db.ForeignKey('v_sports.id_sport'))
    sport = relationship(Sport, foreign_keys=(_sport,))     # <--- HERE IS THE PROBLEM


class SportManager(AlchemyManager):
    fields = ('id_sport', 'description',)
    model = Sport


class CourseManager(AlchemyManager):
    fields = ('id_course', 'sport',)
    model = Course


class SportResource(restmixins.RetrieveRetrieveList):
    manager = SportManager(session_handler)
    resource_name = 'sports'
    pks = ('id_sport',)


class CourseResource(restmixins.RetrieveRetrieveList):
    manager = CourseManager(session_handler)
    resource_name = 'courses'
    pks = ('id_course',)

dispatcher = FlaskDispatcher(app, url_prefix='/')
dispatcher.register_resources(SportResource, CourseResource)
dispatcher.register_adapters(adapters.BasicJSONAdapter)

if __name__ == '__main__':
    app.run(debug=True)

If I GET /courses/1/, I get a nasty exception:


type object 'Sport' has no attribute ''
Traceback (most recent call last):
  File "venv/lib64/python3.4/site-packages/ripozo_sqlalchemy/alchemymanager.py", line 102, in _get_field_python_type
    return getattr(model, name).property.columns[0].type.python_type
  File "venv/lib64/python3.4/site-packages/sqlalchemy/util/langhelpers.py", line 840, in __getattr__
    return self._fallback_getattr(key)
  File "venv/lib64/python3.4/site-packages/sqlalchemy/util/langhelpers.py", line 818, in _fallback_getattr
    raise AttributeError(key)
AttributeError: columns

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "venv/lib64/python3.4/site-packages/ripozo_sqlalchemy/alchemymanager.py", line 102, in _get_field_python_type
    return getattr(model, name).property.columns[0].type.python_type
AttributeError: type object 'Sport' has no attribute ''

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "venv/lib64/python3.4/site-packages/flask_ripozo/dispatcher.py", line 213, in flask_dispatch
    adapter = dispatcher.dispatch(f, accepted_mimetypes, ripozo_request)
  File "venv/lib64/python3.4/site-packages/ripozo/dispatch_base.py", line 212, in dispatch
    result = endpoint_func(request, *args, **kwargs)
  File "venv/lib64/python3.4/site-packages/ripozo/decorators.py", line 103, in newfunc
    return self.func(klass, *args)
  File "venv/lib64/python3.4/site-packages/ripozo/decorators.py", line 197, in wrapped
    resource = func(cls, request, *args, **kwargs)
  File "venv/lib64/python3.4/site-packages/ripozo/decorators.py", line 111, in __call__
    return self.__get__(None, klass=cls)(*args, **kwargs)
  File "venv/lib64/python3.4/site-packages/ripozo/decorators.py", line 103, in newfunc
    return self.func(klass, *args)
  File "venv/lib64/python3.4/site-packages/ripozo/decorators.py", line 367, in action
    translate_fields(request, self.fields(cls.manager),
  File "venv/lib64/python3.4/site-packages/ripozo/decorators.py", line 382, in fields
    for field in manager.field_validators:
  File "venv/lib64/python3.4/site-packages/ripozo/decorators.py", line 33, in __get__
    return self.fget.__get__(obj, klass)()
  File "venv/lib64/python3.4/site-packages/ripozo/manager_base.py", line 208, in field_validators
    cls._field_validators[field_name] = cls.get_field_type(field_name)
  File "venv/lib64/python3.4/site-packages/ripozo_sqlalchemy/alchemymanager.py", line 123, in get_field_type
    python_type = cls._get_field_python_type(cls.model, name)
  File "venv/lib64/python3.4/site-packages/ripozo_sqlalchemy/alchemymanager.py", line 106, in _get_field_python_type
    return AlchemyManager._get_field_python_type(model, '.'.join(parts))
  File "venv/lib64/python3.4/site-packages/ripozo_sqlalchemy/alchemymanager.py", line 105, in _get_field_python_type
    model = getattr(model, parts.pop(0)).comparator.mapper.class_
AttributeError: type object 'Sport' has no attribute ''
127.0.0.1 - - [25/Apr/2016 20:24:18] "GET /courses/117/ HTTP/1.1" 500 -
Traceback (most recent call last):
  File "venv/lib/python3.4/site-packages/flask/app.py", line 1836, in __call__
    return self.wsgi_app(environ, start_response)
  File "venv/lib/python3.4/site-packages/flask/app.py", line 1820, in wsgi_app
    response = self.make_response(self.handle_exception(e))
  File "venv/lib/python3.4/site-packages/flask/app.py", line 1403, in handle_exception
    reraise(exc_type, exc_value, tb)
  File "venv/lib/python3.4/site-packages/flask/_compat.py", line 33, in reraise
    raise value
  File "venv/lib/python3.4/site-packages/flask/app.py", line 1817, in wsgi_app
    response = self.full_dispatch_request()
  File "venv/lib/python3.4/site-packages/flask/app.py", line 1477, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "venv/lib/python3.4/site-packages/flask/app.py", line 1381, in handle_user_exception
    reraise(exc_type, exc_value, tb)
  File "venv/lib/python3.4/site-packages/flask/_compat.py", line 33, in reraise
    raise value
  File "venv/lib/python3.4/site-packages/flask/app.py", line 1475, in full_dispatch_request
    rv = self.dispatch_request()
  File "venv/lib/python3.4/site-packages/flask/app.py", line 1461, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "venv/lib/python3.4/site-packages/flask_ripozo/dispatcher.py", line 216, in flask_dispatch
    return dispatcher.error_handler(dispatcher, accepted_mimetypes, e)
  File "venv/lib/python3.4/site-packages/flask_ripozo/dispatcher.py", line 51, in exception_handler
    raise exc
  File "venv/lib/python3.4/site-packages/flask_ripozo/dispatcher.py", line 213, in flask_dispatch
    adapter = dispatcher.dispatch(f, accepted_mimetypes, ripozo_request)
  File "venv/lib/python3.4/site-packages/ripozo/dispatch_base.py", line 212, in dispatch
    result = endpoint_func(request, *args, **kwargs)
  File "venv/lib/python3.4/site-packages/ripozo/decorators.py", line 103, in newfunc
    return self.func(klass, *args)
  File "venv/lib/python3.4/site-packages/ripozo/decorators.py", line 197, in wrapped
    resource = func(cls, request, *args, **kwargs)
  File "venv/lib/python3.4/site-packages/ripozo/decorators.py", line 111, in __call__
    return self.__get__(None, klass=cls)(*args, **kwargs)
  File "venv/lib/python3.4/site-packages/ripozo/decorators.py", line 103, in newfunc
    return self.func(klass, *args)
  File "venv/lib/python3.4/site-packages/ripozo/decorators.py", line 367, in action
    translate_fields(request, self.fields(cls.manager),
  File "venv/lib/python3.4/site-packages/ripozo/decorators.py", line 382, in fields
    for field in manager.field_validators:
  File "venv/lib/python3.4/site-packages/ripozo/decorators.py", line 33, in __get__
    return self.fget.__get__(obj, klass)()
  File "venv/lib/python3.4/site-packages/ripozo/manager_base.py", line 208, in field_validators
    cls._field_validators[field_name] = cls.get_field_type(field_name)
  File "venv/lib/python3.4/site-packages/ripozo_sqlalchemy/alchemymanager.py", line 123, in get_field_type
    python_type = cls._get_field_python_type(cls.model, name)
  File "venv/lib/python3.4/site-packages/ripozo_sqlalchemy/alchemymanager.py", line 106, in _get_field_python_type
    return AlchemyManager._get_field_python_type(model, '.'.join(parts))
  File "venv/lib/python3.4/site-packages/ripozo_sqlalchemy/alchemymanager.py", line 105, in _get_field_python_type
    model = getattr(model, parts.pop(0)).comparator.mapper.class_
AttributeError: type object 'Sport' has no attribute ''

The problem is here: https://github.com/vertical-knowledge/ripozo-sqlalchemy/blob/master/ripozo_sqlalchemy/alchemymanager.py#L106

The joined part is empty string.

But even when I remove that and return just object, as it was previously before 4445a19 I still get weird errors.

Traceback (most recent call last):
  File "venv/lib/python3.4/site-packages/flask/app.py", line 1836, in __call__
    return self.wsgi_app(environ, start_response)
  File "venv/lib/python3.4/site-packages/flask/app.py", line 1820, in wsgi_app
    response = self.make_response(self.handle_exception(e))
  File "venv/lib/python3.4/site-packages/flask/app.py", line 1403, in handle_exception
    reraise(exc_type, exc_value, tb)
  File "venv/lib/python3.4/site-packages/flask/_compat.py", line 33, in reraise
    raise value
  File "venv/lib/python3.4/site-packages/flask/app.py", line 1817, in wsgi_app
    response = self.full_dispatch_request()
  File "venv/lib/python3.4/site-packages/flask/app.py", line 1477, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "venv/lib/python3.4/site-packages/flask/app.py", line 1381, in handle_user_exception
    reraise(exc_type, exc_value, tb)
  File "venv/lib/python3.4/site-packages/flask/_compat.py", line 33, in reraise
    raise value
  File "venv/lib/python3.4/site-packages/flask/app.py", line 1475, in full_dispatch_request
    rv = self.dispatch_request()
  File "venv/lib/python3.4/site-packages/flask/app.py", line 1461, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "venv/lib/python3.4/site-packages/flask_ripozo/dispatcher.py", line 218, in flask_dispatch
    return Response(response=adapter.formatted_body, headers=adapter.extra_headers,
  File "venv/lib/python3.4/site-packages/ripozo/adapters/basic_json.py", line 59, in formatted_body
    return json.dumps({self.resource.resource_name: response})
  File "/usr/lib64/python3.4/json/__init__.py", line 230, in dumps
    return _default_encoder.encode(obj)
  File "/usr/lib64/python3.4/json/encoder.py", line 192, in encode
    chunks = self.iterencode(o, _one_shot=True)
  File "/usr/lib64/python3.4/json/encoder.py", line 250, in iterencode
    return _iterencode(o, 0)
  File "/usr/lib64/python3.4/json/encoder.py", line 173, in default
    raise TypeError(repr(o) + " is not JSON serializable")
TypeError: <__main__.Sport object at 0x7f0079dc62e8> is not JSON serializable

What am I doing wrong? I've spend couple of hours trying and I'm clueless.

Thanks for any help.

@hroncok
Copy link
Author

hroncok commented Apr 25, 2016

Oh, it seems the problem is here:

class CourseManager(AlchemyManager):
    fields = ('id_course', 'sport',)  # <-- sport should not be here!
    model = Course

My bad :(

Still, perhaps issue a different kind of exception?

@timmartin19
Copy link
Member

You can include 'sport.id' in which case it'll return something like {'sport': {'id': 1}} You're right that it should be a more explicit exception though.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants