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.

Reply via email to