Hi,

I observed some strange (for me) behavior related to setting query options. 
I am not sure if it works as intended or it is a bug.
It seems to me that options are applied to query in a strange manner. The 
posted below the code that show this behavior:
1) in both tests I am configuring sqlalchemy to raise an exception when 
A.bs relation is accessed
2) but in test number 1, I am not assigning result of running query (i.e. I 
am not reading it as I understand, since it is lazy) and exception is not 
raised.
3) on the other hand in test number 2, I am assigning this result to 
variable 'x' and an exception is raised (this is the only difference 
between tests).
4) It does not matter if I run test_1 prior to test_2.
5) I tested it on current (1.2.12) version of sqlalchemy.

Documentation 
(https://docs.sqlalchemy.org/en/latest/orm/loading_relationships.html#controlling-loading-via-options)
 
suggests that setting this option should be possible in
the way I am doing it in test 1, but I think that my case shows that it 
does not.

Does it work as it is supposed to work and I am missing something or is it 
a bug?

Creating and populating tables:

from sqlalchemy import Column, Integer, String, orm, ForeignKey, create_engine
from sqlalchemy.orm import relationship, Session
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()


class A(Base):
    __tablename__ = 'a'
    id = Column(Integer, primary_key=True)
    name = Column(String)

    def __repr__(self): return '<A id: {}, name: {}>'.format(self.id, self.name)


class B(Base):
    __tablename__ = 'b'
    id = Column(Integer, primary_key=True)

    a_id = Column(Integer, ForeignKey('a.id'), index=True)
    a = relationship('A', backref='bs')

    def __repr__(self): return '<B id: {}, a_id: {}>'.format(self.id, self.a_id)


e = create_engine("sqlite://", echo=True)
Base.metadata.create_all(e)

s = Session(e)
s.add(A(id=1, name='A1', bs=[B()]))
s.add(A(id=2, name='A2', bs=[B(), B()]))
s.commit()



Tests definition:

def test_1():
    # This DOES NOT affect further queries
    print('------------------------ Test 1 ------------------------')
    s.query(A).options(orm.raiseload(A.bs)).filter_by(id=1).all()
    print(s.query(A).filter_by(id=1).all()[0].bs)


def test_2():
    # This DOES affect further queries
    print('------------------------ Test 2 ------------------------')
    x = s.query(A).options(orm.raiseload(A.bs)).filter_by(id=1).all()
    print(s.query(A).filter_by(id=1).all()[0].bs)


test_1()
test_2()


test_1 does not raise any exception, while test_2 raises:

---------------------------------------------------------------------------
InvalidRequestError                       Traceback (most recent call last)
<ipython-input-2-6aad37f5c088> in <module>
     24 create_data()
     25 test_1()
---> 26 test_2()

<ipython-input-2-6aad37f5c088> in test_2()
     19     print('------------------------ Test 2 ------------------------')
     20     x = s.query(A).options(orm.raiseload(A.bs)).filter_by(id=1).all()
---> 21     print(s.query(A).filter_by(id=1).all()[0].bs)
     22 
     23 

~/Envs/importer/lib/python3.6/site-packages/sqlalchemy/orm/attributes.py in 
__get__(self, instance, owner)
    240             return dict_[self.key]
    241         else:
--> 242             return self.impl.get(instance_state(instance), dict_)
    243 
    244 

~/Envs/importer/lib/python3.6/site-packages/sqlalchemy/orm/attributes.py in 
get(self, state, dict_, passive)
    597                 elif key in state.callables:
    598                     callable_ = state.callables[key]
--> 599                     value = callable_(state, passive)
    600                 elif self.callable_:
    601                     value = self.callable_(state, passive)

~/Envs/importer/lib/python3.6/site-packages/sqlalchemy/orm/strategies.py in 
__call__(self, state, passive)
    832         strategy = prop._strategies[self.strategy_key]
    833 
--> 834         return strategy._load_for_state(state, passive)
    835 
    836 

~/Envs/importer/lib/python3.6/site-packages/sqlalchemy/orm/strategies.py in 
_load_for_state(self, state, passive)
    587 
    588         if self._raise_always:
--> 589             self._invoke_raise_load(state, passive, "raise")
    590 
    591         session = _state_session(state)

~/Envs/importer/lib/python3.6/site-packages/sqlalchemy/orm/strategies.py in 
_invoke_raise_load(self, state, passive, lazy)
    562     def _invoke_raise_load(self, state, passive, lazy):
    563         raise sa_exc.InvalidRequestError(
--> 564             "'%s' is not available due to lazy='%s'" % (self, lazy)
    565         )
    566 

InvalidRequestError: 'A.bs' is not available due to lazy='raise'


-- 
SQLAlchemy - 
The Python SQL Toolkit and Object Relational Mapper

http://www.sqlalchemy.org/

To post example code, please provide an MCVE: Minimal, Complete, and Verifiable 
Example.  See  http://stackoverflow.com/help/mcve for a full description.
--- 
You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
Visit this group at https://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/d/optout.

Reply via email to