spyne icon indicating copy to clipboard operation
spyne copied to clipboard

can't adapt type 'EnumValue'

Open warvariuc opened this issue 12 years ago • 9 comments

I have a SQLAlchemy model with this column:

    status = Column(
        Enum('SUBSCRIBED', 'UNSUBSCRIBED', 'UNCONFIRMED',
             name='status_choices', native_enum=False),

Then spyne.model.complex.TableModel around that model is used for a service.

When a value for that column comes from a SOAP client i get this:

ProgrammingError: (ProgrammingError) can't adapt type 'EnumValue' 'INSERT INTO ...

I tried to register a psycopg2 adapter for spyne.model.enum.Enum.EnumValue but it's a dynamically created class...

warvariuc avatar Jul 15 '13 13:07 warvariuc

Hi,

There's no test for it, so I'm not surprised.... Can you provide a test case? It'd make my job much easier.

Best,

plq avatar Jul 15 '13 18:07 plq

I looked in the tests, but where can i find tests that test Spyne+SQLAlchemy+Postgres?

warvariuc avatar Jul 16 '13 05:07 warvariuc

So, if this is not enough for you, I think you can take it from here.

plq avatar Jul 16 '13 12:07 plq

I could not check the changes - i pulled the repo but could not find commit d4697752568bd80db02e1dd6bac9de1641c67a7a

But i found another bug with enums:

     62         def __cmp__(self, other):
     63             import ipdb; import pprint; ipdb.set_trace()
---> 64             return isinstance(self, type(other)) and cmp(self.__value, other.__value)
     65 
     66         def __invert__(self):
     67             return values[maximum - self.__value]
     68 
     69         def __nonzero__(self):

ipdb> self
SUBSCRIBED
ipdb> other
u'UNSUBSCRIBED'
ipdb> isinstance(self, type(other)) and cmp(self.__value, other.__value)
False
ipdb> isinstance(self, type(other))
False
ipdb> cmp(self.__value, other.__value)
*** AttributeError: 'EnumValue' object has no attribute '__value'
ipdb> 

warvariuc avatar Jul 17 '13 09:07 warvariuc

I.e. when SQLAlchemy pulls current data from database and compares value from db with value of the field from SOAP request, it will always say it's not equal:

  /home/vic/projects/.venv/apilib/local/lib/python2.7/site-packages/sqlalchemy/orm/attributes.py(1278)from_scalar_attribute()
   1276                 return cls((), [current], ())
   1277         # don't let ClauseElement expressions here trip things up
-> 1278         elif attribute.is_equal(current, original) is True:
   1279             return cls((), [current], ())
   1280         else:

  /home/vic/projects/.venv/apilib/local/lib/python2.7/site-packages/sqlalchemy/types.py(203)compare_values()
    201         """Compare two values for equality."""
    202 
--> 203         return x == y
    204 
    205     def get_dbapi_type(self, dbapi):

> /home/vic/projects/apigateway/apigateway/spyne_injection.py(64)__cmp__()
     62         def __cmp__(self, other):
     63             import ipdb; import pprint; ipdb.set_trace()
---> 64             return isinstance(self, type(other)) and cmp(self.__value, other.__value)
     65 
     66         def __invert__(self):

warvariuc avatar Jul 17 '13 10:07 warvariuc

Also, using __cmp__ is wrong here:

> /home/vic/projects/apigateway/apigateway/spyne_injection.py(64)__cmp__()
     62         def __cmp__(self, other):
     63             import ipdb; import pprint; ipdb.set_trace()
---> 64             return isinstance(self, type(other)) and cmp(self.__value, other.__value)
     65 
     66         def __invert__(self):

ipdb> n
--Return--
False
> /home/vic/projects/apigateway/apigateway/spyne_injection.py(64)__cmp__()
     63             import ipdb; import pprint; ipdb.set_trace()
---> 64             return isinstance(self, type(other)) and cmp(self.__value, other.__value)
     65 

ipdb> 
--Return--
True
> /home/vic/projects/.venv/apilib/local/lib/python2.7/site-packages/sqlalchemy/types.py(203)compare_values()
    202 
--> 203         return x == y
    204 

because if types differ, it returns False which is 0, which means that values are equal (http://docs.python.org/2/reference/datamodel.html#object.cmp)

warvariuc avatar Jul 17 '13 10:07 warvariuc

you're right that __cmp__ implementation has always been wrong here. can you please write tests for these so I can fix this?

Thanks

plq avatar Jul 18 '13 19:07 plq

@plq , hi Burak!

Sorry, I don't have time for this (got a lot of urgent work to do) and the unittests look quite complex to me. I removed all ENums from my SQLALchemy models and replaced them with strings with check constraints.

I would suggest removing enum support from Spyne, as it looks like no one used it anyway - this is what i did in our monkey-patching code for spyne.

warvariuc avatar Jul 19 '13 03:07 warvariuc

would you now?

enums are there because they're there in the Xml schema standard. so they work just fine. just apparently not with sqlalchemy. I'll eventually fix this.

thanks for your time

plq avatar Jul 19 '13 16:07 plq