I'm following along with Architecture Patterns in Python by Harry Percival and Bob Gregory.
Around chapter three (3) they introduce testing the ORM of SQLAlchemy.
A new test that requires a session
fixture, it is throwing AttributeError, FrozenInstanceError
due to cannot assign to field '_sa_instance_state'
It may be important to note that other tests do not fail when creating instances of OrderLine
, but they do fail if I simply include session
into the test parameter(s).
Anyway I'll get straight into the code.
conftest.py
@pytest.fixture
def local_db():
engine = create_engine('sqlite:///:memory:')
metadata.create_all(engine)
return engine
@pytest.fixture
def session(local_db):
start_mappers()
yield sessionmaker(bind=local_db)()
clear_mappers()
model.py
@dataclass(frozen=True)
class OrderLine:
id: str
sku: str
quantity: int
test_orm.py
def test_orderline_mapper_can_load_lines(session):
session.execute(
'INSERT INTO order_lines (order_id, sku, quantity) VALUES '
'("order1", "RED-CHAIR", 12),'
'("order1", "RED-TABLE", 13),'
'("order2", "BLUE-LIPSTICK", 14)'
)
expected = [
model.OrderLine("order1", "RED-CHAIR", 12),
model.OrderLine("order1", "RED-TABLE", 13),
model.OrderLine("order2", "BLUE-LIPSTICK", 14),
]
assert session.query(model.OrderLine).all() == expected
Console error for pipenv run pytest test_orm.py
============================= test session starts =============================
platform linux -- Python 3.7.6, pytest-5.4.1, py-1.8.1, pluggy-0.13.1
rootdir: /home/[redacted]/Documents/architecture-patterns-python
collected 1 item
test_orm.py F [100%]
================================== FAILURES ===================================
____________________ test_orderline_mapper_can_load_lines _____________________
session = <sqlalchemy.orm.session.Session object at 0x7fd919ac5bd0>
def test_orderline_mapper_can_load_lines(session):
session.execute(
'INSERT INTO order_lines (order_id, sku, quantity) VALUES '
'("order1", "RED-CHAIR", 12),'
'("order1", "RED-TABLE", 13),'
'("order2", "BLUE-LIPSTICK", 14)'
)
expected = [
> model.OrderLine("order1", "RED-CHAIR", 12),
model.OrderLine("order1", "RED-TABLE", 13),
model.OrderLine("order2", "BLUE-LIPSTICK", 14),
]
test_orm.py:13:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
<string>:2: in __init__
???
../../.local/share/virtualenvs/architecture-patterns-python-Qi2y0bev/lib64/python3.7/site-packages/sqlalchemy/orm/instrumentation.py:377: in _new_state_if_none
self._state_setter(instance, state)
<string>:1: in set
???
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <[AttributeError("'OrderLine' object has no attribute '_sa_instance_state'") raised in repr()] OrderLine object at 0x7fd919a8cf50>
name = '_sa_instance_state'
value = <sqlalchemy.orm.state.InstanceState object at 0x7fd9198f7490>
> ???
E dataclasses.FrozenInstanceError: cannot assign to field '_sa_instance_state'
<string>:4: FrozenInstanceError
=========================== short test summary info ===========================
FAILED test_orm.py::test_orderline_mapper_can_load_lines - dataclasses.Froze...
============================== 1 failed in 0.06s ==============================
Additional Questions
I understand the overlying logic and what these files are doing, but correct my if my rudimentary understanding is lacking.
conftest.py
(used for all pytest config) is setting up asession
fixture, which basically sets up a temporary database in memory - using start and clear mappers to ensure that the orm model definitions are binding to the db isntance.model.py
simply a dataclass used to represent an atomicOrderLine
object.test_orm.py
class for pytest to supply thesession
fixture, in order tosetup, execute, teardown
a db explicitly for the purpose of running tests.
Issue resolution provided by https://github.com/cosmicpython/code/issues/17