Skip to content

Instantly share code, notes, and snippets.

@plq
Created October 28, 2011 16:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save plq/1322636 to your computer and use it in GitHub Desktop.
Save plq/1322636 to your computer and use it in GitHub Desktop.
sqlalchemy infinite recursion problem.
to get this example running:
1) mysql -u root -p < localhost.sql
2) edit connection string in main_server.py
3) run main_server.py
4) run ws_client.py, witness infinite recursion
-- phpMyAdmin SQL Dump
-- version 3.4.3.1
-- http://www.phpmyadmin.net
--
-- Client: localhost
-- Généré le : Mar 25 Octobre 2011 à 18:23
-- Version du serveur: 5.0.44
-- Version de PHP: 5.2.5-pl1-gentoo
SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO";
SET time_zone = "+00:00";
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8 */;
--
-- Base de données: `idea_iphone`
--
CREATE DATABASE `mybase` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
USE `mybase`;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
#!/usr/bin/python
# -*- coding: UTF-8 -*-
import logging
logging.basicConfig(level=logging.DEBUG)
logging.getLogger('rpclib.protocol.xml').setLevel(logging.DEBUG)
#logging.getLogger('sqlalchemy.engine.base.Engine').setLevel(logging.DEBUG)
from rpclib.application import Application
from rpclib.decorator import rpc
from rpclib.interface.wsdl import Wsdl11
from rpclib.protocol.soap import Soap11
from rpclib.service import ServiceBase
from rpclib.model.table import TableModel
from rpclib.model.primitive import Int
from rpclib.server.wsgi import WsgiApplication
from rpclib.model.complex import Array
import sqlalchemy
from sqlalchemy import create_engine
from sqlalchemy import MetaData
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm.session import sessionmaker
from sqlalchemy.schema import Column
# set client encoding to utf8; all strings come back as unicode
mysqlURL = 'mysql+mysqldb://root:a@localhost:3306/mybase?charset=utf8'
nameSpace = 'com.mydomain.mobile'
myengine = create_engine(mysqlURL, echo=True, pool_recycle=3600)
meta = MetaData(bind=myengine)
DeclarativeBase = declarative_base(metadata=meta)
Session = sessionmaker(bind=myengine)
class Patient(TableModel, DeclarativeBase):
__namespace__ = nameSpace
__tablename__ = 'some_table'
id = Column(sqlalchemy.Integer, primary_key=True)
some_string = Column(sqlalchemy.String(30))
class MyServer(ServiceBase):
@rpc(Array(Patient),
_returns=Int(min_occurs=1, max_occurs=1))
def tpz_setPatients(ctx, patients):
idx = 0
for patient in patients:
idx += 1
ctx.udc.session.add(patient)
return idx
class UserDefinedContext(object):
def __init__(self):
self.session = Session()
def __del__(self):
self.session.close()
def _on_method_call(ctx):
ctx.udc = UserDefinedContext()
def _on_method_return_object(ctx):
# we don't do this in UserDefinedContext.__del__ simply to be able to alert
# the client in case the commit fails.
ctx.udc.session.commit()
application = Application([MyServer], nameSpace,
interface=Wsdl11(), in_protocol=Soap11(), out_protocol=Soap11())
application.event_manager.add_listener('method_call', _on_method_call)
application.event_manager.add_listener('method_return_object', _on_method_return_object)
if __name__ == '__main__':
from wsgiref.simple_server import make_server
wsgi_app = WsgiApplication(application)
server = make_server('localhost', 7789, wsgi_app)
meta.create_all(checkfirst=True)
print "listening to http://127.0.0.1:7789"
print "wsdl is at: http://localhost:7789/?wsdl"
server.serve_forever()
#!/usr/bin/python
URL = 'http://localhost:7789/?wsdl'
from suds.client import Client
client = Client(URL)
patient = client.factory.create('Patient')
patient.id = 888
patient.some_string = 'qwerty'
client.service.tpz_setPatients(patient)
@plq
Copy link
Author

plq commented Oct 28, 2011

DEBUG:rpclib.protocol.xml:Method request_string: '{com.mydomain.mobile}tpz_setPatients'
DEBUG:rpclib.protocol.xml:<SOAP-ENV:Envelope xmlns:ns0="com.mydomain.mobile" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ns1="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
   <SOAP-ENV:Header/>
   <ns1:Body>
      <ns0:tpz_setPatients>
         <ns0:patients>
            <ns0:some_string>qwerty</ns0:some_string>
            <ns0:id>888</ns0:id>
         </ns0:patients>
      </ns0:tpz_setPatients>
   </ns1:Body>
</SOAP-ENV:Envelope>

Traceback (most recent call last):
  File "/usr/lib64/python2.7/wsgiref/handlers.py", line 85, in run
    self.result = application(self.environ, self.start_response)
  File "/home/plq/src/github/plq/rpclib/src/rpclib/server/wsgi.py", line 168, in __call__
    return self.__handle_rpc(req_env, start_response)
  File "/home/plq/src/github/plq/rpclib/src/rpclib/server/wsgi.py", line 235, in __handle_rpc
    self.get_in_object(ctx, in_string_charset)
  File "/home/plq/src/github/plq/rpclib/src/rpclib/server/_base.py", line 59, in get_in_object
    self.app.in_protocol.deserialize(ctx, message='request')
  File "/home/plq/src/github/plq/rpclib/src/rpclib/protocol/soap/soap11.py", line 209, in deserialize
    ctx.in_object = self.from_element(body_class, ctx.in_body_doc)
  File "/home/plq/src/github/plq/rpclib/src/rpclib/protocol/xml/_base.py", line 112, in from_element
    return handler(self, cls, element)
  File "/home/plq/src/github/plq/rpclib/src/rpclib/protocol/xml/model/_base.py", line 50, in wrapper
    return func(prot, cls, element)
  File "/home/plq/src/github/plq/rpclib/src/rpclib/protocol/xml/model/complex.py", line 112, in complex_from_element
    value = prot.from_element(member, c)
  File "/home/plq/src/github/plq/rpclib/src/rpclib/protocol/xml/_base.py", line 112, in from_element
    return handler(self, cls, element)
  File "/home/plq/src/github/plq/rpclib/src/rpclib/protocol/xml/model/_base.py", line 50, in wrapper
    return func(prot, cls, element)
  File "/home/plq/src/github/plq/rpclib/src/rpclib/protocol/xml/model/complex.py", line 134, in array_from_element
    retval.append(prot.from_element(serializer, child))
  File "/home/plq/src/github/plq/rpclib/src/rpclib/protocol/xml/_base.py", line 112, in from_element
    return handler(self, cls, element)
  File "/home/plq/src/github/plq/rpclib/src/rpclib/protocol/xml/model/_base.py", line 50, in wrapper
    return func(prot, cls, element)
  File "/home/plq/src/github/plq/rpclib/src/rpclib/protocol/xml/model/complex.py", line 73, in complex_from_element
    inst = cls.get_deserialization_instance()
  File "/home/plq/src/github/plq/rpclib/src/rpclib/model/complex.py", line 180, in get_deserialization_instance
    return cls()
  File "<string>", line 2, in __init__
  File "/home/plq/src/sqlalchemy/lib/sqlalchemy/orm/instrumentation.py", line 308, in _new_state_if_none
    _new_state_if_none(instance)
  File "/home/plq/src/sqlalchemy/lib/sqlalchemy/orm/instrumentation.py", line 308, in _new_state_if_none
    _new_state_if_none(instance)
  File "/home/plq/src/sqlalchemy/lib/sqlalchemy/orm/instrumentation.py", line 308, in _new_state_if_none
    _new_state_if_none(instance)
  File "/home/plq/src/sqlalchemy/lib/sqlalchemy/orm/instrumentation.py", line 308, in _new_state_if_none
    _new_state_if_none(instance)
  File "/home/plq/src/sqlalchemy/lib/sqlalchemy/orm/instrumentation.py", line 308, in _new_state_if_none
    _new_state_if_none(instance)
  File "/home/plq/src/sqlalchemy/lib/sqlalchemy/orm/instrumentation.py", line 308, in _new_state_if_none
    _new_state_if_none(instance)
  File "/home/plq/src/sqlalchemy/lib/sqlalchemy/orm/instrumentation.py", line 308, in _new_state_if_none
    _new_state_if_none(instance)
  File "/home/plq/src/sqlalchemy/lib/sqlalchemy/orm/instrumentation.py", line 308, in _new_state_if_none
    _new_state_if_none(instance)

(...)


  File "/home/plq/src/sqlalchemy/lib/sqlalchemy/orm/instrumentation.py", line 308, in _new_state_if_none
    _new_state_if_none(instance)
  File "/home/plq/src/sqlalchemy/lib/sqlalchemy/orm/instrumentation.py", line 307, in _new_state_if_none
    return self._subclass_manager(instance.__class__).\
  File "/home/plq/src/sqlalchemy/lib/sqlalchemy/orm/instrumentation.py", line 135, in _subclass_manager
    manager = manager_of_class(cls)
  File "/home/plq/src/sqlalchemy/lib/sqlalchemy/orm/instrumentation.py", line 610, in manager_of_class
    return cls.__dict__.get(ClassManager.MANAGER_ATTR, None)
RuntimeError: maximum recursion depth exceeded while calling a Python object

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment