Python 2.7.6: How do I clean up a class properly? - python-2.7

in the following and executable code you see a SessionScope()-class. In the main()-function the user can log on to his MySQL database server. We take a look in the class. There are two magic methods (__enter__, __exit__),
that allows me to use the object easily with the with-statement. In this statement you also see the program uses session. When the __exit__()-method is
calling then the session is closed. BUT we know that will give the connection back to the connection pool of Engine. That means, its doesn't close the connection directly,
because the connection is pooling. So far so good. On GUI side the user has the option to log off. Well, let us imagine: After a very very very long work with the
database the user wants the connection to be actually closed, but he doesn't wants the program closes itself. Later perhaps the user will log on again and continue working. Until then the program is still running without connection to
the database. The user doesn't need the connection anymore.
That means for python, we don't need the SessionScope()-class anymore. In my case we can remove/clean up this class with del session_scope My idea is to re-implement the __del__()-method. In this method I want to
close all connections of the connection pool. If this class is cleared/removed all connections should be disconnected, that is the reason why I use the del in log_out()-function.
Is this the right way to do this?
TA, your Sophus
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from sqlalchemy.exc import SQLAlchemyError
class SessionScope(object):
def __init__(self, dbms, dbdriver, dbuser, dbuser_pwd, db_server_host, dbport, db_name):
self.dbms = dbms
self.dbdriver = dbdriver
self.dbuser = dbuser
self.dbuser_pwd = dbuser_pwd
self.db_server_host = db_server_host
self.dbport = dbport
self.db_name = db_name
url = '{}+{}://{}:{}#{}:{}/{}'.format(
self.dbms, self.dbdriver, self.dbuser, self.dbuser_pwd, self.db_server_host, self.dbport, self.db_name)
self.engine = create_engine(url, encoding='utf8', echo=True)
# store a sessionmaker for this db connection object
self._Session = sessionmaker(bind=self.engine)
self.session = None
def __enter__(self):
self.session = self._Session()
return self._Session()
def __exit__(self, exception, exc_value, traceback):
try:
if exception:
self.session.rollback()
else:
self.session.commit()
finally:
self.session.close()
self.session = None
def __del__(self):
self.engine.dispose()
def log_out(session_scope):
del session_scope
def main():
dbm_system = raw_input("Which DBMS? (type for e.g. mysql): ")
dbm_driver = raw_input("Which db-driver? (type for e.g. pymysql): ")
db_host = raw_input("Server-Host: ")
db_user = raw_input("Database-user: ")
db_passwd = raw_input("User-Password: ")
db_name = raw_input("Database Name: ")
db_port = raw_input("Port: ")
try:
session_scope = SessionScope(dbm_system, dbm_driver, db_user, \
db_passwd, db_host, db_port, db_name)
with session_scope as session:
# Its just for testing.
print session.execute("SELECT VERSION();")
log_out(session_scope)
except SQLAlchemyError as err:
print "ERROR", err[0]
if __name__ == '__main__':
main()
EDIT #1:
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from sqlalchemy.exc import SQLAlchemyError
class SessionScope(object):
def __init__(self, engine):
self.engine = engine
# store a sessionmaker for this db connection object
self._Session = sessionmaker(bind=self.engine)
self.session = None
def __enter__(self):
self.session = self._Session()
return self._Session()
def __exit__(self, exception, exc_value, traceback):
try:
if exception:
self.session.rollback()
else:
self.session.commit()
finally:
self.session.close()
self.session = None
class Engine(object):
def __init__(self, dbms, dbdriver, dbuser, dbuser_pwd, db_server_host, dbport, db_name):
self.dbms = dbms
self.dbdriver = dbdriver
self.dbuser = dbuser
self.dbuser_pwd = dbuser_pwd
self.db_server_host = db_server_host
self.dbport = dbport
self.db_name = db_name
url = '{}+{}://{}:{}#{}:{}/{}'.format(
self.dbms, self.dbdriver, self.dbuser, self.dbuser_pwd, self.db_server_host, self.dbport, self.db_name)
self._Engine = create_engine(url, encoding='utf8', echo=True)
def __enter__(self):
return self._Engine
def __exit__(self, exception, exc_value, traceback):
'''
Make sure the dbconnection gets closed
'''
self._Engine.dispose()
logged_in = True
def main():
dbm_system = raw_input("Which DBMS? (type for e.g. mysql): ")
dbm_driver = raw_input("Which db-driver? (type for e.g. pymysql): ")
db_host = raw_input("Server-Host: ")
db_user = raw_input("Database-user: ")
db_passwd = raw_input("User-Password: ")
db_name = raw_input("Database Name: ")
db_port = raw_input("Port: ")
try:
with Engine(dbm_system, dbm_driver, db_user, \
db_passwd, db_host, db_port, db_name) as engine:
while logged_in:
with SessionScope(engine) as session:
# Its just for testing.
print session.execute("SELECT VERSION();")
except SQLAlchemyError as err:
print "ERROR", err[0]
if __name__ == '__main__':
main()

The __del__ method doesn't work like that. It's not called when a user does del some_instance, but when the interpreter's garbage collector sees that there are no live references to the object. Your log_out method does nothing, since the reference it is deleting is an extra one that's created to pass the session to it as an argument (the outside reference still remains).
I suspect you really want to have two different classes that both support the context manager protocol. This lets you have two nested with statements, one which last through an entire login and that only lasts for the length of one per database session. Something like this:
with Engine() as engine:
while logged_in:
with Session(engine) as session:
do_stuff()
You may want another loop around the outer with so that the program doesn't exit after you log out.

Related

Flask SocketI) need to detect duplicate connections on opening new tab

I need to detect the duplicate session when user opens a new tab. Since I am using it for survey, I am not having any of the user's data. I am working on anonymous users.
Reading through documentation and various other thread I understood that I need to send client a session data which will be a uuid and check if the user is already authenticated for new connection.
My code is below -
from flask import Flask, render_template, session
from flask_session import Session
from flask_socketio import SocketIO, send, emit
from flask_login import LoginManager, UserMixin, current_user, login_user, logout_user, AnonymousUserMixin
import time, json, uuid, os
app = Flask(__name__)
app.config['SECRET_KEY'] = 'top-secret!'
app.config['SESSION_TYPE'] = 'filesystem'
login_manager = LoginManager(app)
login_manager.init_app(app)
Session(app)
socketio = SocketIO(app, cors_allowed_origins="*", logger=True, manage_session=False)
class User(UserMixin, object):
def __init__(self, id=None):
self.id = id
#login_manager.user_loader
def load_user(user_id):
return User.get(user_id)
time_now = 0
msg = "Hello User. Please wait other users to join. Survey will start once minimum users will join. Max waiting time " \
"is 5 min "
# connected_msg_json = json.dumps(connected_msg, indent=4)
client_count = 0
#socketio.on('message')
def handle_message(msg):
print("Connected with the client with data " + msg)
#socketio.on('connect')
def test_connect():
print("Connected")
f = open('data.json')
data = json.load(f)
minUserCount = data['minimumNoOfUser']
global client_count, time_now
if current_user.is_authenticated:
pass
else:
client_count += 1
login_user(User(id=uuid.uuid1()))
if client_count == 0:
time_now = int(time.time())
print("Total no of connected client " + str(client_count))
print("About to send the time when first user connected " + str(time_now))
send(time_now)
if client_count > minUserCount:
send("Continue", broadcast=True)
#socketio.on('disconnect')
def test_disconnect():
print('Client disconnected')
logout_user()
global client_count
client_count -= 1
print("Total no of connected client " + str(client_count))
Since I need to make sure that survey opens when there are minimum no of unique users, I decided to login the users upon connection. And if the user is already authenticated then I believe it means it's the new connection via tab.
Now I am not sure if my code is okay but the packages are incorrect or both. I have tried to resolved the error but I am stuck with this error -
ImportError: cannot import name 'ContextVar' from 'werkzeug.local' (/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/werkzeug/local.py)
This appears when I put line
app.config['SESSION_TYPE'] = 'filesystem'
else I get different error about secret key not being set.
My requirements.txt are:
Flask==2.0.2
Flask-Cors==3.0.10
Flask-SocketIO==4.3.1
gevent==21.8.0
gevent-websocket==0.10.1
greenlet==1.1.2
gunicorn==20.1.0
python-engineio==3.13.2
python-socketio==4.6.0
simple-websocket==0.5.0
websocket-client==1.2.1
websockets==10.1
Werkzeug==0.14.1
you need to update werkzeug to 2.0 +

Load Url on Pepper's Tablet

I'm trying to load a website on Pepper like "www.google.com"
I'm sure we are connected on the same network. I've tried doing "http://www.google.com" too on the ShowApp Dialog.
I've seen this guide: http://kokorobot.com/2016/08/08/how-to-use-pepper-tablet
class MyClass(GeneratedClass):
def __init__(self):
GeneratedClass.__init__(self)
def onLoad(self):
self.isRunning = False
def onUnload(self):
self.isRunning = False
def _getTabletService(self):
tabletService = None
try:
tabletService = self.session().service("ALTabletService")
except Exception as e:
self.logger.error(e)
return tabletService
def onInput_onStart(self):
if self.isRunning:
return # already running, nothing to do
self.isRunning = True
# We create TabletService here in order to avoid
# problems with connections and disconnections of the tablet during the life of the application
tabletService = self._getTabletService()
appName = self.packageUid()
state = False
if appName:
if tabletService:
if tabletService.loadApplication(appName):
tabletService.loadUrl("www.google.com") self.logger.info("Successfully set application: %s" % appName)
tabletService.showWebview()
state = True
else:
self.logger.warning("Got tablet service, but failed to set application: %s" % appName)
else:
self.logger.warning("Couldn't find tablet service, so can't set application: %s" % appName)
if state:
self.onSuccess()
else:
self.onFailure()
If you want to show a web consider using the box "Show Web View" instead. I've found that Show App gives more trouble than it's worth it.
class MyClass(GeneratedClass):
def __init__(self):
GeneratedClass.__init__(self)
def onLoad(self):
pass
def onUnload(self):
pass
def _getTabletService(self):
tabletService = None
try:
tabletService = self.session().service("ALTabletService")
except Exception as e:
self.logger.error(e)
return tabletService
def _getAbsoluteUrl(self, partial_url):
import os
subPath = os.path.join(self.packageUid(), os.path.normpath(partial_url).lstrip("\\/"))
# We create TabletService here in order to avoid
# problems with connections and disconnections of the tablet during the life of the application
return "http://%s/apps/%s" %(self._getTabletService().robotIp(), subPath.replace(os.path.sep, "/"))
def onInput_onStart(self):
# We create TabletService here in order to avoid
# problems with connections and disconnections of the tablet during the life of the application
tabletService = self._getTabletService()
if tabletService:
try:
url = "http://www.google.com/"
if url == '':
self.logger.error("URL of the image is empty")
if not url.startswith('http'):
url = self._getAbsoluteUrl(url)
self.logger.info(url)
tabletService.showWebview(url)
except Exception as err:
self.logger.error("Error during ShowImage : %s " % err)
self.onStopped()
self.onStopped()

unable to use session variables outside view function

I have login page where the user inputs the username and password. I have made the username as session variable in the /login view function and would like to use this variable outside the view function in the main body of the code in a if-else block.
session['username'] = request.form['username'].lower()
How do I do this?
Here is part of the code for this:
import os
import csv
import pymysql
import pymysql.cursors
from datetime import date
import calendar
import ssl
from ldap3 import Connection, Server, ANONYMOUS, SIMPLE, SYNC, ASYNC,ALL
from flask import Flask, make_response,render_template,url_for,redirect,request,session,escape
from validusers import users
app = Flask(__name__)
IT = pymysql.connect(host='xx.xx.xx.xx', user='xxxxx', password='xxxxx',
db='xxxx')#Connect to the IT database
Others = pymysql.connect(host='xxxxx', user='xxxxxx', password='xxxxxx',
db='xxxxx')#Connect to the non IT database
a=IT.cursor() # Open Cursor for IT database
b=Others.cursor()#Open Cursor for non-IT database
**#app.route('/')
#app.route('/login',methods=['GET', 'POST'])
def login():
error=None
if request.method =='POST':
#if not request.form['username']:
#error='You forgot to enter "Username", please try again'
#return render_template('login.html',error=error)
if request.form['username'].lower() not in users:
error='You are not authorized to view this page !!'
return render_template('login.html',error=error)
#if not request.form['password']:
#error='You forgot to enter "Password", please try again'
#return render_template('login.html',error=error)
#else:
#s = Server('appauth.corp.domain.com:636', use_ssl=True, get_info=ALL)
#c = Connection(s,user=request.form['username'],password=request.form['password'],check_names=True, lazy=False,raise_exceptions=False)
#c.open()
#c.bind()
#if (c.bind() != True) is True:
#error='Invalid credentials. Please try again'
#else:
#session['username'] = request.form['username'].lower()
#return redirect(url_for('index'))
return render_template('login.html',error=error)**
#app.route('/index',methods=['GET','POST'])
def index():
if 'username' in session:
return render_template('index.html')
Filename = os.getenv("HOMEDRIVE") + os.getenv("HOMEPATH") + "\\Desktop\RosterUnified.csv" # Create/write a CSV file in the user's desktop
Filename1=os.getenv("HOMEDRIVE") + os.getenv("HOMEPATH") + "\\Desktop\RosterCurrentMonth.csv"
d=open(Filename, 'w',newline='\n') #Format for CSV input
c = csv.writer(d)
c.writerow(["Manager NT ID"," Vertical Org","Employee ID" ]+ dayssl)# Write the header list of strings in the first row
for row in result_IT:
c.writerow(row)#Write output for IT to csv
d.close()
#result_IT and result_Oters part of code is ommitted
e=open(Filename, 'a',newline='\n')
f= csv.writer(e)
for row in result_Others:
f.writerow(row)# Append to the existing CSV file with non IT data
e.close()
x=session['username']
sql="select verticalorg from tbl_employeedetails where empntid=(%s)"
args=x
a.execute(sql,args)
b.execute(sql,args)
c=a.fetchall()
d1=b.fetchall()
s=c+d1
q=[x[0] for x in s]
sql1="select role from tbl_employeedetails where empntid=(%s)"
a.execute(sql1,args)
b.execute(sql1,args)
c1=a.fetchall()
d2=b.fetchall()
Role=c1+d2
r=[x[0] for x in Role]
if r=='O':
if q==27:
f1=open(Filename,'r',newline='\n')
f2=open(Filename1,'w',newline='\n')
reader = csv.DictReader(f1)
writer = csv.writer(f2)
writer.writerow(["Manager NT ID"," Vertical Org","Employee ID" ]+ dayssl)
rows = [row for row in reader if row['Vertical Org'] == 'HR']
writer.writerow[row in rows]
elif q==2:
f1=open(Filename,'r',newline='\n')
f2=open(Filename1,'w',newline='\n')
reader = csv.DictReader(f1)
writer = csv.writer(f2)
writer.writerow(["Manager NT ID"," Vertical Org","Employee ID" ]+ dayssl)
f2.close()
z=open(Filename1)
with z as f:
p = f.read()
else:
z=open(Filename)
with z as f:
p = f.read()
#app.route('/csv/')
def download_csv():
csv = p
response = make_response(csv)
cd = 'attachment; filename=RosterCurrentMonth.csv'
response.headers['Content-Disposition'] = cd
response.mimetype='text/csv'
return response
z.close()
os.remove(Filename)
#app.route('/logout')
def logout():
# remove the username from the session if it's there
session.pop('username', None)
return redirect(url_for('login'))
app.secret_key ='secret key generated'
if __name__=='__main__':
context=('RosterWeb.crt','RosterWeb.key')
app.run(ssl_context=context, threaded=True, debug=True)
getting the error:
Traceback (most recent call last):
File "roster.py", line 175, in <module>
x=session['username']
File "C:\Users\dasa17\Envs\r_web\lib\site-packages\werkzeug\local.py", line 37
3, in <lambda>
__getitem__ = lambda x, i: x._get_current_object()[i]
File "C:\Users\dasa17\Envs\r_web\lib\site-packages\werkzeug\local.py", line 30
2, in _get_current_object
return self.__local()
File "C:\Users\dasa17\Envs\r_web\lib\site-packages\flask\globals.py", line 37,
in _lookup_req_object
raise RuntimeError(_request_ctx_err_msg)
RuntimeError: Working outside of request context.
This typically means that you attempted to use functionality that needed
an active HTTP request. Consult the documentation on testing for
information about how to avoid this problem.
You need to place the code you want to run before any routing is done in a function and use the before_first_request decorator on it. It will be executed before your first request is done and you can make use of your session variable from there.
#app.route('/')
def index():
# ... index route here ...
pass
#app.before_first_request
def init_app():
# ... do some preparation here ...
session['username'] = 'me'

How to get the "full" async result in Celery link_error callback

I have Celery 3.1.18 running with Django 1.6.11 and RabbitMQ 3.5.4, and trying to test my async task in a failure state (CELERY_ALWAYS_EAGER=True). However, I cannot get the proper "result" in the error callback. The example in the Celery docs shows:
#app.task(bind=True)
def error_handler(self, uuid):
result = self.app.AsyncResult(uuid)
print('Task {0} raised exception: {1!r}\n{2!r}'.format(
uuid, result.result, result.traceback))
When I do this, my result is still "PENDING", result.result = '', and result.traceback=''. But the actual result returned by my .apply_async call has the right "FAILURE" state and traceback.
My code (basically a Django Rest Framework RESTful endpoint that parses a .tar.gz file, and then sends a notification back to the user, when the file is done parsing):
views.py:
from producer_main.celery import app as celery_app
#celery_app.task()
def _upload_error_simple(uuid):
print uuid
result = celery_app.AsyncResult(uuid)
print result.backend
print result.state
print result.result
print result.traceback
msg = 'Task {0} raised exception: {1!r}\n{2!r}'.format(uuid,
result.result,
result.traceback)
class UploadNewFile(APIView):
def post(self, request, repository_id, format=None):
try:
uploaded_file = self.data['files'][self.data['files'].keys()[0]]
self.path = default_storage.save('{0}/{1}'.format(settings.MEDIA_ROOT,
uploaded_file.name),
uploaded_file)
print type(import_file)
self.async_result = import_file.apply_async((self.path, request.user),
link_error=_upload_error_simple.s())
print 'results from self.async_result:'
print self.async_result.id
print self.async_result.backend
print self.async_result.state
print self.async_result.result
print self.async_result.traceback
return Response()
except (PermissionDenied, InvalidArgument, NotFound, KeyError) as ex:
gutils.handle_exceptions(ex)
tasks.py:
from producer_main.celery import app
from utilities.general import upload_class
#app.task
def import_file(path, user):
"""Asynchronously import a course."""
upload_class(path, user)
celery.py:
"""
As described in
http://celery.readthedocs.org/en/latest/django/first-steps-with-django.html
"""
from __future__ import absolute_import
import os
import logging
from celery import Celery
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'producer_main.settings')
from django.conf import settings
log = logging.getLogger(__name__)
app = Celery('producer') # pylint: disable=invalid-name
# Using a string here means the worker will not have to
# pickle the object when using Windows.
app.config_from_object('django.conf:settings')
app.autodiscover_tasks(lambda: settings.INSTALLED_APPS) # pragma: no cover
#app.task(bind=True)
def debug_task(self):
print('Request: {0!r}'.format(self.request))
My backend is configured as such:
CELERY_ALWAYS_EAGER = True
CELERY_EAGER_PROPAGATES_EXCEPTIONS = False
BROKER_URL = 'amqp://'
CELERY_RESULT_BACKEND = 'redis://localhost'
CELERY_RESULT_PERSISTENT = True
CELERY_IGNORE_RESULT = False
When I run my unittest for the link_error state, I get:
Creating test database for alias 'default'...
<class 'celery.local.PromiseProxy'>
130ccf13-c2a0-4bde-8d49-e17eeb1b0115
<celery.backends.redis.RedisBackend object at 0x10aa2e110>
PENDING
None
None
results from self.async_result:
130ccf13-c2a0-4bde-8d49-e17eeb1b0115
None
FAILURE
Non .zip / .tar.gz file passed in.
Traceback (most recent call last):
So the task results are not available in my _upload_error_simple() method, but they are available from the self.async_result returned variable...
I could not get the link and link_error callbacks to work, so I finally had to use the on_failure and on_success task methods described in the docs and this SO question. My tasks.py then looks like:
class ErrorHandlingTask(Task):
abstract = True
def on_failure(self, exc, task_id, targs, tkwargs, einfo):
msg = 'Import of {0} raised exception: {1!r}'.format(targs[0].split('/')[-1],
str(exc))
def on_success(self, retval, task_id, targs, tkwargs):
msg = "Upload successful. You may now view your course."
#app.task(base=ErrorHandlingTask)
def import_file(path, user):
"""Asynchronously import a course."""
upload_class(path, user)
You appear to have _upload_error() as a bound method of your class - this is probably not what you want. try making it a stand-along task:
#celery_app.task(bind=True)
def _upload_error(self, uuid):
result = celery_app.AsyncResult(uuid)
msg = 'Task {0} raised exception: {1!r}\n{2!r}'.format(uuid,
result.result,
result.traceback)
class Whatever(object):
....
self.async_result = import_file.apply_async((self.path, request.user),
link=self._upload_success.s(
"Upload finished."),
link_error=_upload_error.s())
in fact there's no need for the self paramater since it's not used so you could just do this:
#celery_app.task()
def _upload_error(uuid):
result = celery_app.AsyncResult(uuid)
msg = 'Task {0} raised exception: {1!r}\n{2!r}'.format(uuid,
result.result,
result.traceback)
note the absence of bind=True and self
Be careful with UUID instance!
If you will try to get status of a task with id not string type but UUID type, you will only get PENDING status.
from uuid import UUID
from celery.result import AsyncResult
task_id = UUID('d4337c01-4402-48e9-9e9c-6e9919d5e282')
print(AsyncResult(task_id).state)
# PENDING
print(AsyncResult(str(task_id)).state)
# SUCCESS

SQLAlchemy query not retrieving committed data in alternate session

I have a problem where I insert a database item using a SQLAlchemy / Tastypie REST interface, but the item is missing when subsequently get the list of items. It shows up only after I get the list of items a second time.
I am using SQLAlchemy with Tastypie/Django running on Apache via mod_wsgi. I use a singleton Database Manager class to hold my engine and declarative_base, and with Tastypie, a separate class to get the session and make sure I roll-back if there is a problem with the commit. As in the update below, the problem occurs when I don't close my session after inserting. Why is this necessary?
My original code was like this:
Session = scoped_session(sessionmaker(autoflush=True))
# Singleton Database Manager class for managing session
class DatabaseManager():
engine = None
base = None
def ready(self):
host='mysql+mysqldb://etc...'
if self.engine and self.base:
return True
else:
try:
self.engine = create_engine(host, pool_recycle=3600)
self.base = declarative_base(bind=self.engine)
return True
except:
return False
def getSession(self):
if self.ready():
session = Session()
session.configure(bind=self.engine)
return session
else:
return None
DM = DatabaseManager()
# A session class I use with Tastypie to ensure the session is destroyed at the
# end of the transaction, because Tastypie creates singleton Resources used for
# all threads
class MySession:
def __init__(self):
self.s = DM.getSession()
def safeCommit(self):
try:
self.s.commit()
except:
self.s.rollback()
raise
def __del__(self):
try:
self.s.commit()
except:
self.s.rollback()
raise
# ... Then ... when I get requests through Apache/mod_wsgi/Django/Tastypie
# First Request
obj_create():
db = MySession()
print db.s.query(DBClass).count() # returns 4
newItem = DBClass()
db.s.add(newItem)
db.s.safeCommit()
print db.s.query(DBClass).count() # returns 5
# Second Request after First Request returns
obj_get_list():
db = MySession()
print db.s.query(DBClass).count() # returns 4 ... should be 5
# Third Request is okay
obj_get_list():
db = MySession()
print db.s.query(DBClass).count() # returns 5
UPDATE
After further digging, it appears that the problem is my session needed to be closed after creating. Perhaps because Tastypie's object_create() adds the SQLAlchemy object to it's bundle, and I don't know what happens after it leaves the function's scope:
obj_create():
db = MySession()
newItem = DBClass()
db.s.add(newItem)
db.s.safeCommit()
copiedObj = copyObj(newItem) # copy SQLAlchemy record into non-sa object (see below)
db.s.close()
return copiedObj
If someone cares to explain this in an answer, I can close the question. Also, for those who are curious, I copy my object out of SQLAlchemy like this:
class Struct:
def __init__(self, **entries):
self.__dict__.update(entries)
class MyTastypieResource(Resource):
...
def copyObject(self, object):
base = {}
# self._meta is part of my tastypie resource
for p in class_mapper(self._meta.object_class).iterate_properties:
if p.key not in base and p.key not in self._meta.excludes:
base[p.key] = getattr(object,p.key)
return Struct(**base)
The problem was resolved by closing my session. The update in the answer didn't solve the problem fully - I ended up adding a middleware class to close the session at the end of a transaction. This ensured everything was written to the database. The middleware looks a bit like this:
class SQLAlchemySessionMiddleWare(object):
def process_response(self, request, response):
try:
session = MyDatabaseManger.getSession()
session.commit()
session.close()
except Exception, err:
pass
return response
def process_exception(self, request, exception):
try:
session = MyDatabaseManger.getSession()
session.rollback()
session.close()
except Exception, err:
pass