thesayhey
thesayhey

Reputation: 958

Inheritance Issue: AttributeError: 'str' object has no attribute '_sa_instance_state'

Issue: inheritance class is not checking for strings because it is being passed as None.

The parent class (object.py) of the retrieve method was designed to retrieve objects from the database (e.g. id or user/assessment combo). The child class (convenience.py) is designed to accept the strs of those objects.

object.py

def retrieve_assessment_result(self, *args):
    id, owner, assessment = None, None, None
    if len(args) == 1:
        id, = args # or id = args[0]
    elif len(args) == 2:
        owner, assessment = args
        print 'testa', owner, assessment, id
    else:
        raise ValueError('Value being passed is an object')
    if id is not None:
        print 'testi', id
        return self.session.query(Assessment_Result).\
        filter(Assessment_Result.id == id).one()
    elif owner is not None:
        print 'testo', owner
        return self.session.query(Assessment_Result).\
        filter(Assessment_Result.owner == owner).one()
    elif assessment is not None:
        print 'testa', assessment
        return self.session.query(Assessment_Result).\
        filter(Assessment_Result.assessment == assessment).one()

convenience.py

def retrieve_assessment_result(self, *args):
    id, owner, assessment = None, None, None
    if len(args) == 1:
        id, = args # or id = args[0]
        print " args = ", args
    elif len(args) == 2:
        username, name = args
        print "api args = ", args
        print 'type args', type(args)
        print 'owner: ', owner
        print 'assessment: ', assessment
    if owner is not None:
        owner = self.retrieve_user(username)
    if assessment is not None:
        assessment = self.retrieve_assessment(name)
    return super(ConvenienceAPI, self).retrieve_assessment_result(*args)

test.py

api.retrieve_assessment_result('baseball', 'Becoming a Leader')

Traceback Error:

Traceback (most recent call last):
  File "/usr/local/lib/python2.7/site-packages/nose/case.py", line 197, in runTest
    self.test(*self.arg)
  File "/Users/ack/code/venv/NotssDB/notssdb/test/test.py", line 133, in test1
    api.retrieve_assessment_result('baseball', 'Becoming a Leader')
  File "/Users/ack/code/venv/NotssDB/notssdb/api/convenience.py", line 42, in retrieve_assessment_result
    return super(ConvenienceAPI, self).retrieve_assessment_result(*args)
  File "/Users/ack/code/venv/NotssDB/notssdb/api/object.py", line 327, in retrieve_assessment_result
    filter(Assessment_Result.owner == owner).one()
  File "/usr/local/lib/python2.7/site-packages/sqlalchemy/sql/operators.py", line 301, in __eq__
    return self.operate(eq, other)
  File "/usr/local/lib/python2.7/site-packages/sqlalchemy/orm/attributes.py", line 175, in operate
    return op(self.comparator, *other, **kwargs)
  File "/usr/local/lib/python2.7/site-packages/sqlalchemy/orm/relationships.py", line 1011, in __eq__
    other, adapt_source=self.adapter))
  File "/usr/local/lib/python2.7/site-packages/sqlalchemy/orm/relationships.py", line 1338, in _optimized_compare
    state = attributes.instance_state(state)
AttributeError: 'str' object has no attribute '_sa_instance_state'
------output--------
<Assessment_Result(owner='<User(username ='bambam', firstname ='Sean', lastname ='Cargo', email='[email protected]')>', assessment='<Assessment(name='Foo', text='this is foo')>')>
api args =  ('baseball', 'Becoming a Leader')
type args <type 'tuple'>
owner:  None
assessment:  None
testa baseball Becoming a Leader None
testo baseball

-----updates after comment/suggestions:
object.py Updated:

def retrieve_assessment_result(self, id=None, owner=None, assessment=None):
    print 'test_all_objects', owner, assessment, id
    if id is not None:
        print 'test_id_object', id
        return self.session.query(Assessment_Result).\
        filter(Assessment_Result.id == id).one()
    elif owner is not None:
        print 'test_owner_object', owner
        return self.session.query(Assessment_Result).\
        filter(Assessment_Result.owner.has(User.username == username)).one()
    elif assessment is not None:
        print 'test_assessment_object', assessment
        return self.session.query(Assessment_Result).\
        filter(Assessment_Result.assessment.has(Assessment.name == name)).one()

Convenience.py (inherited from object.py) change:

def retrieve_assessment_result(self, id=None, owner=username, assessment=name):
    if owner is not None:
        owner = self.retrieve_user(username)
    if assessment is not None:
        assessment = self.retrieve_assessment(name)
    return super(ConvenienceAPI, self).retrieve_assessment_result(id=None, owner=owner, assessment=assessment)

Traceback:

  File ".../api/convenience.py", line 6, in <module>
    class ConvenienceAPI(BaseAPI):
  File "../api/convenience.py", line 37, in ConvenienceAPI
    def retrieve_assessment_result(self, id=None, owner=username, assessment=name):
NameError: name 'username' is not defined

Upvotes: 2

Views: 3145

Answers (1)

pi.
pi.

Reputation: 21562

In my experience, the error '???' object has no attribute '_sa_instance_state almost always indicates that you assigned something which is not a SQLAlchemy object (i.e. some basic type, as int, str, etc.) to a relationship or dynamic_loader.

relationship example

>>> result = db.query(Assessment_Result).first()
>>> # owner only accepts Owner objects
>>> result.owner = "Mr. Harvey Example"
Traceback (most recent call last):
...
AttributeError: 'str' object has no attribute '_sa_instance_state'

Furthermore, filtering with other types on a relationship will also lead to this error:

filtering example

>>> Assessment_Result.owner == "baseball"
Traceback (most recent call last):
...
AttributeError: 'str' object has no attribute '_sa_instance_state'

In your case the error is caused by having the string "baseball" as the first entry in the 2-tuple args which you pass on to Object.retrieve_assessment_result, which in turn will be put in the variable owner in the second if block.

>>>         owner, assessment = args

As owner now contains a str this will fail when you filter with it.

I'd like to take this opportunity to point out that this code is not very readable and could be improved by the use of keyword arguments and generally making it more concise.

Upvotes: 3

Related Questions