Open havok2063 opened 2 years ago
On closer inspection, it looks like it might have something to do with factory-boy
and SQL Server identity key columns. See https://docs.sqlalchemy.org/en/14/dialects/mssql.html#auto-increment-behavior. I tried removing the Sequence column from my factory:
class MissionFactory(factory.alchemy.SQLAlchemyModelFactory):
class Meta:
model = Base.classes.Mission
sqlalchemy_session = Session
label = factory.Faker('name')
When I run this manually in a terminal with my session, it does successfully create and save an object to the db with an auto-incremented column. However when I run my test with the same factory, I now get the following error:
def do_execute(self, cursor, statement, parameters, context=None):
> cursor.execute(statement, parameters)
E sqlalchemy.exc.DataError: (raised as a result of Query-invoked autoflush; consider using a session.no_autoflush block if this flush is occurring prematurely)
E (pyodbc.DataError) ('22001', '[22001] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]String or binary data would be truncated. (8152) (SQLExecDirectW)')
E [SQL: INSERT INTO [Mission] (label) OUTPUT inserted.[missionID] VALUES (?)]
E [parameters: ('NEW_MISSION',)]
E (Background on this error at: http://sqlalche.me/e/13/9h9h)
with full traceback
session = <sqlalchemy.orm.session.Session object at 0x7fa768c54580>, mission_factory = <class 'tests.factories.MissionFactory'>
def test_mission(session, mission_factory):
missions = session.query(Base.classes.Mission.label).all()
assert missions == [('JWST',)]
#breakpoint()
mission = mission_factory(label="NEW_MISSION")
assert isinstance(mission, Base.classes.Mission)
#breakpoint()
> missions = session.query(Base.classes.Mission.label).all()
test_factories.py:17:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
/Users/bcherinka/anaconda3/envs/jwstdb/lib/python3.8/site-packages/sqlalchemy/orm/query.py:3373: in all
return list(self)
/Users/bcherinka/anaconda3/envs/jwstdb/lib/python3.8/site-packages/sqlalchemy/orm/query.py:3534: in __iter__
self.session._autoflush()
/Users/bcherinka/anaconda3/envs/jwstdb/lib/python3.8/site-packages/sqlalchemy/orm/session.py:1633: in _autoflush
util.raise_(e, with_traceback=sys.exc_info()[2])
/Users/bcherinka/anaconda3/envs/jwstdb/lib/python3.8/site-packages/sqlalchemy/util/compat.py:182: in raise_
raise exception
/Users/bcherinka/anaconda3/envs/jwstdb/lib/python3.8/site-packages/sqlalchemy/orm/session.py:1622: in _autoflush
self.flush()
/Users/bcherinka/anaconda3/envs/jwstdb/lib/python3.8/site-packages/sqlalchemy/orm/session.py:2540: in flush
self._flush(objects)
/Users/bcherinka/anaconda3/envs/jwstdb/lib/python3.8/site-packages/sqlalchemy/orm/session.py:2682: in _flush
transaction.rollback(_capture_exception=True)
/Users/bcherinka/anaconda3/envs/jwstdb/lib/python3.8/site-packages/sqlalchemy/util/langhelpers.py:68: in __exit__
compat.raise_(
/Users/bcherinka/anaconda3/envs/jwstdb/lib/python3.8/site-packages/sqlalchemy/util/compat.py:182: in raise_
raise exception
/Users/bcherinka/anaconda3/envs/jwstdb/lib/python3.8/site-packages/sqlalchemy/orm/session.py:2642: in _flush
flush_context.execute()
/Users/bcherinka/anaconda3/envs/jwstdb/lib/python3.8/site-packages/sqlalchemy/orm/unitofwork.py:422: in execute
rec.execute(self)
/Users/bcherinka/anaconda3/envs/jwstdb/lib/python3.8/site-packages/sqlalchemy/orm/unitofwork.py:586: in execute
persistence.save_obj(
/Users/bcherinka/anaconda3/envs/jwstdb/lib/python3.8/site-packages/sqlalchemy/orm/persistence.py:239: in save_obj
_emit_insert_statements(
/Users/bcherinka/anaconda3/envs/jwstdb/lib/python3.8/site-packages/sqlalchemy/orm/persistence.py:1135: in _emit_insert_statements
result = cached_connections[connection].execute(
/Users/bcherinka/anaconda3/envs/jwstdb/lib/python3.8/site-packages/sqlalchemy/engine/base.py:1011: in execute
return meth(self, multiparams, params)
/Users/bcherinka/anaconda3/envs/jwstdb/lib/python3.8/site-packages/sqlalchemy/sql/elements.py:298: in _execute_on_connection
return connection._execute_clauseelement(self, multiparams, params)
/Users/bcherinka/anaconda3/envs/jwstdb/lib/python3.8/site-packages/sqlalchemy/engine/base.py:1124: in _execute_clauseelement
ret = self._execute_context(
/Users/bcherinka/anaconda3/envs/jwstdb/lib/python3.8/site-packages/sqlalchemy/engine/base.py:1316: in _execute_context
self._handle_dbapi_exception(
/Users/bcherinka/anaconda3/envs/jwstdb/lib/python3.8/site-packages/sqlalchemy/engine/base.py:1510: in _handle_dbapi_exception
util.raise_(
/Users/bcherinka/anaconda3/envs/jwstdb/lib/python3.8/site-packages/sqlalchemy/util/compat.py:182: in raise_
raise exception
/Users/bcherinka/anaconda3/envs/jwstdb/lib/python3.8/site-packages/sqlalchemy/engine/base.py:1276: in _execute_context
self.dialect.do_execute(
Description
Edit - title to reflect possible updated problem
Does
factory-boy
do anything internally with the db user connecting to the database? I'm getting strange errors when trying to set this up for a new project, when the factory tries to create the object, that looks like permissions errors. But the user I connect with in my db connection string for the test suite is the same as in my regular code. The user has the correct permissions, and can successfully write to the database.Trying to set up
factory-boy
withpytest-factoryboy
for a new project to test a SQL Server database. I've previously usedfactory-boy
successfully on other projects, with other dbs, e.g. postgres. This is the first project with a SQL Server db. I can't for the life of me get this working correctly for a single table test.To Reproduce
Running the
test_mission
pytest below with the setup below results in the errorModel / Factory code
I'm auto-reflecting my models with
automap_base
.but I also tried a declarative base model. The model only has two columns, an auto-incrementing identity unique key
missionID
, and a string columnlabel
.Factory
The issue
I tried the simple
test_mission
and get the error above, with full traceback below. The table already has an existing row in it (id=1, label="A").pytest fixtures
Simple test that fails
I thought it was a flushing issue, so I turned off
autoflush
insession_factory = sessionmaker(bind=engine, expire_on_commit=True, autocommit=True, autoflush=False)
. When I do that, I don't get the error but the object is not saved to the database, probably since only asession.add
is happening. I also tried setting onMissionFactory
thesqlalchemy_session_persistence
to bothflush
andcommit
, and I get a similar error.Notes
Full traceback