On Wed, Oct 18, 2017 at 6:16 PM, Taz Mainiac <tazmain...@gmail.com> wrote: > > I have Postgres DB with a table of pending operations. One column in the > operation in an enum with the status of the enum. I used the standard python > (2.7) enum, with AutoNumber (myenum.py):
the example calls the "myoper" python file in two different contexts, resulting in two different MyStatus enumeration objects. Calling "python myoper.py" invokes "myoper" as a plain Python script, sets up MyStatus and the mapping, then runs some database operations. When it imports myoper_test, myoper_test imports myoper, which runs myoper all over again as a Python module since "myoper" is not in sys.modules. It makes a new MyStatus and then is used against the mappings from the "python myoper.py" script, and fails. Place a print statement below MyStatus like this and you'll see: print "MAKING A MYSTATUS!!! IDENTIFIER IS!! %s" % id(MyStatus) > > > class AutoNumber(enum.Enum): > def __new__(cls): > value = len(cls.__members__) + 1 > obj = object.__new__(cls) > obj._value_ = value > return obj > > class MyStatus(AutoNumber): > INITIAL = () > ACCEPTED = () > DENIED = () > ACK_PENDING = () > AUTHORIZED = () > ACTIVE = () > END = () > DELETED = () > # end enum > > > The table looks like (also in myenum.py): > > > Base = declarative_base() > > class MyOperation(Base): > > __tablename__ = 'operations' > > id = Column( Integer, primary_key=True ) > > status = Column( Enum(MyStatus) ) > status_message = Column( String ) > status_time = Column( DateTime ) > > def __repr__(self): > return "<MyOperation(%s, %s, %s, %s)>" % \ > ( self.id, self.status, self.status_time, self.status_message ) > # end class > > Generally this works fine. In the SAME FILE that defines MyStatus > (myoper.py), I can change the status and save it back to the DB and it works > fine: > > > def checkOper( oper ): > oper.status = MyStatus.DENIED > oper.status_message = "failed check (internal)" > oper.status_time = datetime.datetime.utcnow() > > > Here's how I call it (within myoper.py) > > > checkOper( oper ) > session.add(oper) > session.commit() > > This is all in the same file (myoper.py). > > > However, if I pass an oper instance to an external function, and that > function changes the status, then I get a sqlalchemy.exc.StatementError. > > > Here's the external function (myoper_test.py): > > > import datetime > from myoper import MyStatus > > def extCheckOper( oper ): > oper.status = MyStatus.DENIED > oper.status_message = "failed check (external)" > oper.status_time = datetime.datetime.utcnow() > > > Here's how I call it (from myoper.py): > > > from myoper_test import extCheckOper > extCheckOper( oper ) > session.add(oper) > session.commit() > > Here's the stack trace: > > > Traceback (most recent call last): > File "./myoper.py", line 120, in <module> > session.commit() > File "/usr/local/lib/python2.7/dist-packages/sqlalchemy/orm/session.py", > line 906, in commit > self.transaction.commit() > File "/usr/local/lib/python2.7/dist-packages/sqlalchemy/orm/session.py", > line 461, in commit > self._prepare_impl() > File "/usr/local/lib/python2.7/dist-packages/sqlalchemy/orm/session.py", > line 441, in _prepare_impl > self.session.flush() > File "/usr/local/lib/python2.7/dist-packages/sqlalchemy/orm/session.py", > line 2177, in flush > self._flush(objects) > File "/usr/local/lib/python2.7/dist-packages/sqlalchemy/orm/session.py", > line 2297, in _flush > transaction.rollback(_capture_exception=True) > File > "/usr/local/lib/python2.7/dist-packages/sqlalchemy/util/langhelpers.py", > line 66, in __exit__ > compat.reraise(exc_type, exc_value, exc_tb) > File "/usr/local/lib/python2.7/dist-packages/sqlalchemy/orm/session.py", > line 2261, in _flush > flush_context.execute() > File > "/usr/local/lib/python2.7/dist-packages/sqlalchemy/orm/unitofwork.py", line > 389, in execute > rec.execute(self) > File > "/usr/local/lib/python2.7/dist-packages/sqlalchemy/orm/unitofwork.py", line > 548, in execute > uow > File > "/usr/local/lib/python2.7/dist-packages/sqlalchemy/orm/persistence.py", line > 177, in save_obj > mapper, table, update) > File > "/usr/local/lib/python2.7/dist-packages/sqlalchemy/orm/persistence.py", line > 737, in _emit_update_statements > execute(statement, multiparams) > File "/usr/local/lib/python2.7/dist-packages/sqlalchemy/engine/base.py", > line 945, in execute > return meth(self, multiparams, params) > File "/usr/local/lib/python2.7/dist-packages/sqlalchemy/sql/elements.py", > line 263, in _execute_on_connection > return connection._execute_clauseelement(self, multiparams, params) > File "/usr/local/lib/python2.7/dist-packages/sqlalchemy/engine/base.py", > line 1053, in _execute_clauseelement > compiled_sql, distilled_params > File "/usr/local/lib/python2.7/dist-packages/sqlalchemy/engine/base.py", > line 1121, in _execute_context > None, None) > File "/usr/local/lib/python2.7/dist-packages/sqlalchemy/engine/base.py", > line 1402, in _handle_dbapi_exception > exc_info > File "/usr/local/lib/python2.7/dist-packages/sqlalchemy/util/compat.py", > line 203, in raise_from_cause > reraise(type(exception), exception, tb=exc_tb, cause=cause) > File "/usr/local/lib/python2.7/dist-packages/sqlalchemy/engine/base.py", > line 1116, in _execute_context > context = constructor(dialect, self, conn, *args) > File > "/usr/local/lib/python2.7/dist-packages/sqlalchemy/engine/default.py", line > 639, in _init_compiled > for key in compiled_params > File > "/usr/local/lib/python2.7/dist-packages/sqlalchemy/engine/default.py", line > 639, in <genexpr> > for key in compiled_params > File "/usr/local/lib/python2.7/dist-packages/sqlalchemy/sql/sqltypes.py", > line 1446, in process > value = self._db_value_for_elem(value) > File "/usr/local/lib/python2.7/dist-packages/sqlalchemy/sql/sqltypes.py", > line 1354, in _db_value_for_elem > '"%s" is not among the defined enum values' % elem) > sqlalchemy.exc.StatementError: (exceptions.LookupError) "MyStatus.DENIED" is > not among the defined enum values [SQL: u'UPDATE operations SET > status=%(status)s, status_message=%(status_message)s, > status_time=%(status_time)s WHERE operations.id = %(operations_id)s'] > [parameters: [{'status': <MyStatus.DENIED: 6>, 'status_time': > datetime.datetime(2017, 10, 18, 20, 22, 44, 350035), 'status_message': > 'failed check (external)', 'operations_id': 3}]] > > > I've tried inspecting the type both in the internal file, and external file, > but it's always listed as <enum 'MyStatus'>. > > > I have found, that if I assign the oper.status to the enum .name, then that > DOES work: > > > def extCheckOper( oper ): > oper.status = MyStatus.AUTHORIZED.name > oper.status_message = "authorized check (external)" > oper.status_time = datetime.datetime.utcnow() > > > But that's obviously not a good solution. > > > So - what am I doing wrong? What is different about MyStatus in the > myoper.py, vs an external file (myoper_test.py) that screws up SQL Alchemy? > > > I've attached the files I've been testing with: > > > [~/test] python ./myoper.py drop > dropping table > [~/test] python ./myoper.py > dumping DB > [~/test] python ./myoper.py new > committing oper: <MyOperation(None, MyStatus.ACCEPTED, 2017-10-18 > 22:14:24.027276, Initial)> > after commit: <MyOperation(1, MyStatus.ACCEPTED, 2017-10-18 22:14:24.027276, > Initial)> > [~/test] python ./myoper.py > dumping DB > <MyOperation(1, MyStatus.ACCEPTED, 2017-10-18 22:14:24.027276, Initial)> > [~/test] python ./myoper.py int_check 1 > test for opid 1 > found oper: <MyOperation(1, MyStatus.ACCEPTED, 2017-10-18 22:14:24.027276, > Initial)> > <enum 'MyStatus'> > after compliance check: <MyOperation(1, MyStatus.DENIED, 2017-10-18 > 22:14:32.246124, failed check (internal))> > status: failed check (internal) > after commit: <MyOperation(1, MyStatus.DENIED, 2017-10-18 22:14:32.246124, > failed check (internal))> > [~/test] python ./myoper.py > dumping DB > <MyOperation(1, MyStatus.DENIED, 2017-10-18 22:14:32.246124, failed check > (internal))> > [~/test] python ./myoper.py ext_check 1 > test for opid 1 > found oper: <MyOperation(1, MyStatus.DENIED, 2017-10-18 22:14:32.246124, > failed check (internal))> > <enum 'MyStatus'> > after compliance check: <MyOperation(1, MyStatus.AUTHORIZED, 2017-10-18 > 22:14:40.992209, authorized check (external))> > status: authorized check (external) > Traceback (most recent call last): > File "./myoper.py", line 120, in <module> > session.commit() > ... <stacktrace as above> ... > > [~/test] python ./myoper.py > dumping DB > <MyOperation(1, MyStatus.DENIED, 2017-10-18 22:14:32.246124, failed check > (internal))> > > Ubuntu 16.04, x64 - Python 2.7 - SQL Alchemy 1.1.14 > > > Same thing happens under Cygwin, FWIW. > > > Thanks, > > Taz > > > PS: if there is anything else I'm doing wrong, please let me know - I'm new > to SQL/SQLAlchemy. > > > -- > 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 sqlalchemy+unsubscr...@googlegroups.com. > To post to this group, send email to sqlalchemy@googlegroups.com. > Visit this group at https://groups.google.com/group/sqlalchemy. > For more options, visit https://groups.google.com/d/optout. -- 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 sqlalchemy+unsubscr...@googlegroups.com. To post to this group, send email to sqlalchemy@googlegroups.com. Visit this group at https://groups.google.com/group/sqlalchemy. For more options, visit https://groups.google.com/d/optout.