I have a problem: I don't know how to work with session, in combination with multi-thread, efficiently. Well you can see that I use scoped_session. It will transparently creates a thread-local session - so its threadsafe.
My below and executable example works, as long as the interval of QTimeris 1000, but if you set the value to 1, then there are some problems. On GUI-site, there a 8 QComboBox()-objects, and I will start 8 threads. In this example, I work with one table. When I run this program, not all QComboBox()-objects are filled. Sometimes there is only one QComboBox()-object blank or more. In addition, it happens once in a while that I am told by SQLAlchemy that the connection was closed. For this I have an error message:
Traceback (most recent call last):
File "D:\Dan\Python\Xarphus\xarphus\subclass_master_data_load_data_item.py", line 151, in populate_item
self.populate_item_signal.emit(next(self._element))
File "D:\Dan\Python\Xarphus\xarphus\core\manage_data_manipulation_master_data.py", line 232, in select_all
yield record.id, record.relationship
File "D:\Dan\Python\Xarphus\xarphus\core\manage_db_connection.py", line 245, in __exit__
self.session.commit()
File "C:\Python27\lib\site-packages\sqlalchemy\orm\session.py", line 906, in commit
self.transaction.commit()
File "C:\Python27\lib\site-packages\sqlalchemy\orm\session.py", line 465, in commit
t[1].commit()
File "C:\Python27\lib\site-packages\sqlalchemy\engine\base.py", line 1632, in commit
self._do_commit()
File "C:\Python27\lib\site-packages\sqlalchemy\engine\base.py", line 1663, in _do_commit
self.connection._commit_impl()
File "C:\Python27\lib\site-packages\sqlalchemy\engine\base.py", line 726, in _commit_impl
self.connection._reset_agent is self.__transaction:
File "C:\Python27\lib\site-packages\sqlalchemy\engine\base.py", line 351, in connection
self._handle_dbapi_exception(e, None, None, None, None)
File "C:\Python27\lib\site-packages\sqlalchemy\engine\base.py", line 1405, in _handle_dbapi_exception
util.reraise(*exc_info)
File "C:\Python27\lib\site-packages\sqlalchemy\engine\base.py", line 349, in connection
return self._revalidate_connection()
File "C:\Python27\lib\site-packages\sqlalchemy\engine\base.py", line 429, in _revalidate_connection
raise exc.ResourceClosedError("This Connection is closed")
ResourceClosedError: This Connection is closed
And, if I run my program several times, I get, among other things sometimes the following message:
Traceback (most recent call last):
File "C:\Users\Sophus\Desktop\ver_2_simple_problem.py", line 83, in init_object
self._element = self.master_data_manipulation.select_all()
File "C:\Users\Sophus\Desktop\ver_2_simple_problem.py", line 178, in __exit__
self.session.commit()
File "C:\Python27\lib\site-packages\sqlalchemy\orm\session.py", line 906, in commit
self.transaction.commit()
File "C:\Python27\lib\site-packages\sqlalchemy\orm\session.py", line 459, in commit
self._assert_active(prepared_ok=True)
File "C:\Python27\lib\site-packages\sqlalchemy\orm\session.py", line 258, in _assert_active
"This session is in 'committed' state; no further "
sqlalchemy.exc.InvalidRequestError: This session is in 'committed' state; no further SQL can be emitted within this transaction.
Here is my example code: Is there a better and more elegant source code on how to work with SQLAlchemy in multiple threads? Becaouse I'm not sure if this is the right way.
from PyQt4.QtCore import QObject, QThread, pyqtSignal, pyqtSlot, QTimer
from PyQt4.QtGui import QApplication, QPushButton, QVBoxLayout, QDialog, \
QComboBox, QLabel
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import create_engine
from sqlalchemy.exc import SQLAlchemyError
from sqlalchemy.orm import sessionmaker, scoped_session
from sqlalchemy import Table, Column, Integer, String, MetaData
from traceback import format_exc
from sys import exc_info
''' setting up root class for declarative declaration '''
Base = declarative_base()
class PERSON_SALUTATION(Base):
__tablename__ = "person_salutation"
id = Column(Integer, primary_key=True)
salutation = Column(String(50), nullable=False, unique=True)
class MasterDataManipulation(object):
def __init__(self, session_object=None):
self._session_scope = session_object
def select_all(self):
try:
with self._session_scope as session:
for record in session.query(PERSON_SALUTATION):
yield record.id, record.salutation
except AttributeError:
print "select all, desired_trace", format_exc(exc_info())
return
class Worker(QObject):
finish_progress = pyqtSignal()
populate_item_signal = pyqtSignal(object, object)
def __init__(self,
combo_box=None,
query_data=None,
parent=None):
QObject.__init__(self, parent)
self.query_data = query_data
self.combo_box=combo_box
''' Create attributes '''
self._run_semaphore = 1
def init_object(self):
self._element = self.query_data()
self.timer = QTimer()
self.timer.setSingleShot(False)
self.timer.setInterval(1)
self.timer.timeout.connect(self.populate_item)
self.timer.start()
def populate_item(self):
try:
if self._run_semaphore == 0:
self._run_semaphore = 1
raise StopIteration
else:
self.populate_item_signal.emit(next(self._element), self.combo_box)
except StopIteration:
print "StopIteration is raised"
self.timer.stop()
def stop(self):
self._run_semaphore == 0
self.timer.stop()
class SessionScope(object):
def __init__(self, dbms=None, dbdriver=None,
dbuser=None, dbuser_pwd=None,
db_server_host=None, dbport=None, db_name=None,
admin_database=None):
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
self.admin_database = admin_database
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)
self.session = None
self._session_factory = sessionmaker(bind=self._Engine)
self._Session = scoped_session(sessionmaker(bind=self._Engine, expire_on_commit=False))
''' create tables '''
Base.metadata.create_all(self._Engine)
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()
class MyCustomDialog(QDialog):
finish = pyqtSignal()
def __init__(self, scoped_session=None, parent=None):
QDialog.__init__(self, parent)
self._session_scope = scoped_session
self._list_threads = []
self.init_ui()
self.start_all_selection()
def init_ui(self):
layout = QVBoxLayout(self)
self.combo_person_title = QComboBox(self)
self.combo_person_salutation = QComboBox(self)
self.combo_person_gender = QComboBox(self)
self.combo_person_religion = QComboBox(self)
self.combo_person_relationship_status = QComboBox(self)
self.combo_person_nationality = QComboBox(self)
self.combo_person_eye_color = QComboBox(self)
self.combo_person_hair_color = QComboBox(self)
self.pushButton_populate_combo = QPushButton("Re-populate", self)
self.pushButton_stopp = QPushButton("Stopp", self)
self.pushButton_close = QPushButton("Close", self)
layout.addWidget(self.combo_person_title)
layout.addWidget(self.combo_person_salutation)
layout.addWidget(self.combo_person_gender)
layout.addWidget(self.combo_person_religion)
layout.addWidget(self.combo_person_nationality)
layout.addWidget(self.combo_person_relationship_status)
layout.addWidget(self.combo_person_eye_color)
layout.addWidget(self.combo_person_hair_color)
layout.addWidget(self.pushButton_populate_combo)
layout.addWidget(self.pushButton_stopp)
layout.addWidget(self.pushButton_close)
self.pushButton_stopp.clicked.connect(self.on_finish)
self.pushButton_populate_combo.clicked.connect(self.start_all_selection)
self.pushButton_close.clicked.connect(self.close)
def start_all_selection(self):
list_comboxes = self.findChildren(QComboBox)
for combo_box in list_comboxes:
combo_box.clear()
self.start_thread(combo_box=combo_box)
def fill_combo_boxt(self, item, combo_box):
id, text = item
combo_box.addItem(text)
def on_label(self, i):
self.label.setText("Result: {}".format(i))
def start_thread(self, combo_box=None):
master_data_manipulation = MasterDataManipulation(session_object=self._session_scope)
query_data=master_data_manipulation.select_all
task_thread = QThread(self)
task_thread.work = Worker(query_data=query_data,
combo_box=combo_box,)
''' We need to store threads '''
self._list_threads.append(task_thread)
task_thread.work.moveToThread(task_thread)
task_thread.work.populate_item_signal.connect(self.fill_combo_boxt)
self.finish.connect(task_thread.work.stop)
task_thread.started.connect(task_thread.work.init_object)
task_thread.finished.connect(task_thread.deleteLater)
''' This will emit 'started' and start thread's event loop '''
task_thread.start()
#pyqtSlot()
def abort_workers(self):
self.finish.emit()
for thread in self._list_threads:
''' this will quit **as soon as thread event loop unblocks** '''
thread.quit()
''' so you need to wait for it to *actually* quit'''
thread.wait()
def on_finish(self):
self.finish.emit()
def closeEvent(self, event):
''' Re-implementaate to handle with created threads '''
self.abort_workers()
sys.exit()
def populate_database(sess=None):
try:
with sess as session:
salutations = [PERSON_SALUTATION(salutation="Mister"),
PERSON_SALUTATION(salutation="Miss"),
PERSON_SALUTATION(salutation="Lady"),
PERSON_SALUTATION(salutation="Ma'am"),
PERSON_SALUTATION(salutation="Sir"),
PERSON_SALUTATION(salutation="Queen"),
PERSON_SALUTATION(salutation="Grandma"),]
session.add_all(salutations)
session.commit()
except SQLAlchemyError:
print "SQLAlchemyError", format_exc(exc_info())
def main():
dbms = raw_input('Enter database type: ')
dbdriver = raw_input('Enter database driver: ')
dbuser = raw_input('Enter user name: ')
dbuser_pwd = raw_input('Enter user password: ')
db_server_host = raw_input('Enter server host: ')
dbport = raw_input('Enter port: ')
db_name = raw_input('Enter database name: ')
try:
''' create_engine and scoped_session once per process (per database). '''
session_scope = SessionScope(dbms = dbms,
dbdriver = dbdriver,
dbuser = dbuser,
dbuser_pwd = dbuser_pwd,
db_server_host = db_server_host,
dbport = dbport,
db_name = db_name)
answer = raw_input('Do you want to populate database? Type yes or no: ')
if answer.lower() == 'yes':
populate_database(sess=session_scope)
app = QApplication(sys.argv)
window = MyCustomDialog(scoped_session = session_scope)
window.show()
sys.exit(app.exec_())
except TypeError:
print "ERROR", format_exc(exc_info())
if __name__ == "__main__":
main()
Related
I want to add some extra information into the exists abc file or if its possible while creating alembic cache with some extra information in maya or any cg application using pyhon.
I am appreciate any one can help me to edit the alembic file.
input example
meta_data = {'name': 'Hero', 'tag': 'test_show'}
abc_file = '/show/test_show/scene/hero.abc'
set meta data ?
from alembic import Abc
get meta data
from alembic import Abc
archive = Abc.IArchive(abc_file)
top = archive.getTop()
meta_data = top.getMetaData()
print meta_data__str()
Here's a complete script that does the job of copying the source alembic file and inserting some metadata:
import os
import alembic
def copy_props(i_props, o_props):
'''
Copy properties
'''
for index in range(i_props.getNumProperties()):
header = i_props.getPropertyHeader(index)
if header.isArray():
i_prop = alembic.Abc.IArrayProperty(
i_props,
header.getName())
prop_name = i_prop.getName()
prop_meta = i_prop.getMetaData()
o_prop = alembic.Abc.OArrayProperty(
o_props,
prop_name,
i_prop.getDataType(),
prop_meta,
0)
o_prop.setTimeSampling(i_prop.getTimeSampling())
for i in range(i_prop.getNumSamples()):
o_prop.setValue(i_prop.getValue(i))
elif header.isScalar():
i_prop = alembic.Abc.IScalarProperty(
i_props,
header.getName())
prop_name = i_prop.getName()
prop_meta = i_prop.getMetaData()
o_prop = alembic.Abc.OScalarProperty(
o_props,
prop_name,
i_prop.getDataType(),
prop_meta,
0)
o_prop.setTimeSampling(i_prop.getTimeSampling())
for i in range(i_prop.getNumSamples()):
o_prop.setValue(i_prop.getValue(i))
elif header.isCompound():
i_prop = alembic.Abc.ICompoundProperty(
i_props,
header.getName())
prop_name = i_prop.getName()
prop_meta = i_prop.getMetaData()
o_prop = alembic.Abc.OCompoundProperty(
o_props,
prop_name,
prop_meta)
copy_props(i_prop, o_prop)
def copy_object(i_obj, o_obj):
'''
Recursively copy object data
'''
if o_obj is None:
return
i_props = i_obj.getProperties()
o_props = o_obj.getProperties()
copy_props(i_props, o_props)
for index in range(i_obj.getNumChildren()):
i_child = i_obj.getChild(index)
i_child_name = i_child.getName()
i_child_meta = i_child.getMetaData()
o_child = alembic.Abc.OObject(o_obj, i_child_name, i_child_meta)
copy_object(i_child, o_child)
def copy_abc(i_path, o_path, app, description):
'''
Copy alembic file from i_path to o_path
'''
arc_in = alembic.Abc.IArchive(i_path)
arc_out = alembic.Abc.OArchive(o_path, asOgawa=True)
arc_out = alembic.Abc.CreateArchiveWithInfo(o_path, app, description)
top_in = arc_in.getTop()
top_out = arc_out.getTop()
copy_object(top_in, top_out)
def read(abc_file):
archive = alembic.Abc.IArchive(abc_file)
return alembic.Abc.GetArchiveInfo(archive)
if __name__ == '__main__':
i_path = os.path.join(
os.path.dirname(__file__),
'itest.abc'
)
o_path = os.path.join(
os.path.dirname(__file__),
'otest.abc'
)
copy_abc(i_path, o_path, 'Cool app', 'Cool description')
print('Created archive: ' + o_path)
archive_info = read(o_path)
print('App name: ' + archive_info.get('appName'))
print('Description: ' + archive_info.get('userDescription'))
print('Written: ' + archive_info.get('whenWritten'))
You can't write just arbitrary data but you can set description and application strings:
from alembic import Abc
MY_APP = 'My cool application'
def write(abc_file, description):
archive = Abc.CreateArchiveWithInfo(abc_file, MY_APP, description)
def read(abc_file):
archive = Abc.IArchive(abc_file)
top = archive.getTop()
return Abc.GetArchiveInfo(archive)
abc_file = 'alembic.abc'
write(abc_file, 'An abc file cool description')
archive_info = read(abc_file)
print(archive_info.get('appName'))
print(archive_info.get('userDescription'))
print(archive_info.get('whenWritten'))
I am trying to insert data into my SQLite database, it goes fine until I get the error while creating a function for DB. It sends OperationalError at cursor.
I couldn't find solution for my problem.
Code I'm using:
import sqlite3
from sqlite3 import *
SQL_CREATE_STATEMENT = '''CREATE TABLE password
(id integer PRIMARY KEY NOT NULL,username text, password text, source text)'''
SQL_INSERT_STATEMENT = '''INSERT INTO password (username, password, source)VALUES({},{},{});'''
DATABASE_PATH = 'home/taha/lessons/projects/passStorage/passDB.db'
DATA = dict()
def create_connection(db_file):
try:
conn = sqlite3.connect(db_file)
return conn
except Error as e:
return e
def create_table(connection, sql_commands):
c = connection.cursor()
c.execute(sql_commands)
print('done')
def get_input():
USERNAME = input('username: ')
PASSWORD = input('password: ')
SOURCE = input('source: ')
return USERNAME,PASSWORD,SOURCE
def insert_date(connection, data):
c = connection.cursor()
c.execute(SQL_INSERT_STATEMENT.format(data.values))
def main():
conn = create_connection(DATABASE_PATH)
create_table(conn, SQL_CREATE_STATEMENT)
user_info = get_input()
DATA['username'], DATA['password'], DATA['SOURCE'] = user_info
insert_date(conn, DATA)
if __name__ == '__main__':
main()
I expect no error but it sends this:
c = connection.cursor()
AttributeError: 'OperationalError' object has no attribute 'cursor'
def create_connection(db_file):
try:
conn = sqlite3.connect(db_file)
return conn
except Error as e:
return e # <-- here you return OperationalError instance
AttributeError: 'OperationalError' object has no attribute 'cursor'
Shows that OperationalError has no attribute cursor
Add additional logic that check connection here.
I believe the core of your problem is wrong file path:
DATABASE_PATH = 'home/taha/lessons/projects/passStorage/passDB.db'
But I believe should be
DATABASE_PATH = '/home/taha/lessons/projects/passStorage/passDB.db'
Good day,
I'm getting the following error: is not JSON serializable
but I'm not sure why am I getting it. Everything was working fine until I decided to start making use of sessions to fire up my user cart adding and removal of items
This is my view:
def add_or_update_cart(request, slug):
request.session.set_expiry(180)
new_total = 0.00
try:
# check that session exists
the_cart_id = request.session['cart_id']
except:
new_cart_id = Cart()
new_cart_id.save()
request.session['cart_id'] = new_cart_id
the_cart_id = new_cart_id.id
cart = Cart.objects.get(id=the_cart_id)
try:
product = Product.objects.get(slug=slug)
except Product.DoesNotExist:
pass
except:
pass
if not product in cart.products.all():
cart.products.add(product)
else:
cart.products.remove(product)
for item in cart.products.all():
new_total += float(item.price)
request.session['items_total'] = cart.products.count()
cart.total = new_total
cart.save()
print(cart.products.count())
return HttpResponseRedirect(reverse('cart:cart'))
Models:
class Cart(models.Model):
products = models.ManyToManyField(Product, null=True, blank=True)
total = models.DecimalField(max_digits=100, decimal_places=2, default=0.00)
timestamp = models.DateTimeField(auto_now_add=True, auto_now=False)
updated = models.DateTimeField(auto_now_add=False, auto_now=True)
cart_status = models.BooleanField(default=False)
def __str__(self):
return '%s' % self.id
def item_name(self):
return " ".join([str(p) for p in self.product.all()])
and in my template:
<li role="presentation">Cart <span class="badge">{{ request.session.items_total }}</span></li>
The traceback:
Internal Server Error: /my-cart/puma/
Traceback (most recent call last):
File "/home/drcongo/.virtualenvs/eCommerce/lib/python3.4/site-packages/django/core/handlers/base.py", line 235, in get_response
response = middleware_method(request, response)
File "/home/drcongo/.virtualenvs/eCommerce/lib/python3.4/site-packages/django/contrib/sessions/middleware.py", line 50, in process_response
request.session.save()
File "/home/drcongo/.virtualenvs/eCommerce/lib/python3.4/site-packages/django/contrib/sessions/backends/db.py", line 82, in save
obj = self.create_model_instance(data)
File "/home/drcongo/.virtualenvs/eCommerce/lib/python3.4/site-packages/django/contrib/sessions/backends/db.py", line 68, in create_model_instance
session_data=self.encode(data),
File "/home/drcongo/.virtualenvs/eCommerce/lib/python3.4/site-packages/django/contrib/sessions/backends/base.py", line 88, in encode
serialized = self.serializer().dumps(session_dict)
File "/home/drcongo/.virtualenvs/eCommerce/lib/python3.4/site-packages/django/core/signing.py", line 95, in dumps
return json.dumps(obj, separators=(',', ':')).encode('latin-1')
File "/usr/lib/python3.4/json/__init__.py", line 237, in dumps
**kw).encode(obj)
File "/usr/lib/python3.4/json/encoder.py", line 192, in encode
chunks = self.iterencode(o, _one_shot=True)
File "/usr/lib/python3.4/json/encoder.py", line 250, in iterencode
return _iterencode(o, 0)
File "/usr/lib/python3.4/json/encoder.py", line 173, in default
raise TypeError(repr(o) + " is not JSON serializable")
TypeError: <Cart: 31> is not JSON serializable
I will appreciate any help on this.
The error arises when Django tries to serialize a model instance here
request.session['cart_id'] = new_cart_id
new_cart_id is a model instance and cannot be serialized.
It seems you wanted to assign the primary key of the instance to the key cart_id.
request.session['cart_id'] = new_cart_id.id
I'm confused. It would seem that Client entity should exist because I have 2 locations for it to be created:
I create the requested Entity in the the setUp() of the unittest.TestCase.
I also conditionally create the Client entity in main.py if it doesn't exist already.
I have tried to set a breakpoint where the Client entity is called, but I can't step into the debugger. While the code stops execution, I can't step into the debugger. I'm not even sure how to see the output.
I set the Consistency policy to 1, so the record should exist.
datastore_stub_util.PseudoRandomHRConsistencyPolicy(probability=1)
$ nosetests
INFO 2015-02-24 19:08:56,172 devappserver2.py:726] Skipping SDK update check.
INFO 2015-02-24 19:08:56,242 api_server.py:172] Starting API server at: http://localhost:62049
INFO 2015-02-24 19:08:56,247 dispatcher.py:186] Starting module "default" running at: http://localhost:8080
INFO 2015-02-24 19:08:56,249 admin_server.py:118] Starting admin server at: http://localhost:8000
ERROR 2015-02-24 19:09:00,307 webapp2.py:1552] 'NoneType' object has no attribute 'key'
Traceback (most recent call last):
File "/Users/Bryan/Desktop/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/webapp2-2.5.2/webapp2.py", line 1535, in __call__
rv = self.handle_exception(request, response, e)
File "/Users/Bryan/Desktop/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/webapp2-2.5.2/webapp2.py", line 1529, in __call__
rv = self.router.dispatch(request, response)
File "/Users/Bryan/Desktop/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/webapp2-2.5.2/webapp2.py", line 1278, in default_dispatcher
return route.handler_adapter(request, response)
File "/Users/Bryan/Desktop/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/webapp2-2.5.2/webapp2.py", line 1102, in __call__
return handler.dispatch()
File "/Users/Bryan/work/GoogleAppEngine/dermalfillersecrets/main.py", line 18, in dispatch
webapp2.RequestHandler.dispatch(self)
File "/Users/Bryan/Desktop/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/webapp2-2.5.2/webapp2.py", line 572, in dispatch
return self.handle_exception(e, self.app.debug)
File "/Users/Bryan/Desktop/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/webapp2-2.5.2/webapp2.py", line 570, in dispatch
return method(*args, **kwargs)
File "/Users/Bryan/work/GoogleAppEngine/dermalfillersecrets/main.py", line 95, in get
self.session['client'] = client.key.urlsafe()
AttributeError: 'NoneType' object has no attribute 'key'
INFO 2015-02-24 19:09:00,314 module.py:737] default: "GET / HTTP/1.1" 500 2354
INFO 2015-02-24 19:09:00,377 module.py:737] default: "GET /favicon.ico HTTP/1.1" 200 8348
INFO 2015-02-24 19:09:00,381 module.py:737] default: "GET /favicon.ico HTTP/1.1" 304 -
EINFO 2015-02-24 19:09:08,482 shutdown.py:45] Shutting down.
INFO 2015-02-24 19:09:08,483 api_server.py:588] Applying all pending transactions and saving the datastore
======================================================================
ERROR: test_guest_can_submit_contact_info (dermalfillersecrets.functional_tests.NewVisitorTest)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/Users/Bryan/work/GoogleAppEngine/dermalfillersecrets/functional_tests.py", line 88, in test_guest_can_submit_contact_info
self.browser.find_element_by_name('id_name').send_keys("Kallie Wheelock")
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/selenium/webdriver/remote/webdriver.py", line 302, in find_element_by_name
return self.find_element(by=By.NAME, value=name)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/selenium/webdriver/remote/webdriver.py", line 662, in find_element
{'using': by, 'value': value})['value']
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/selenium/webdriver/remote/webdriver.py", line 173, in execute
self.error_handler.check_response(response)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/selenium/webdriver/remote/errorhandler.py", line 166, in check_response
raise exception_class(message, screen, stacktrace)
NoSuchElementException: Message: Unable to locate element: {"method":"name","selector":"id_name"}
Stacktrace:
at FirefoxDriver.prototype.findElementInternal_ (file:///var/folders/mw/0y88j8_54bjc93d_lg3120qw0000gp/T/tmpSjWZ6W/extensions/fxdriver#googlecode.com/components/driver-component.js:9641:26)
at fxdriver.Timer.prototype.setTimeout/<.notify (file:///var/folders/mw/0y88j8_54bjc93d_lg3120qw0000gp/T/tmpSjWZ6W/extensions/fxdriver#googlecode.com/components/driver-component.js:548:5)
Here is the code in functional_tests.py
import sys, os, subprocess, time, unittest, shlex
sys.path.append("/usr/local/google_appengine")
sys.path.append("/usr/local/google_appengine/lib/yaml/lib")
sys.path.append("/usr/local/google_appengine/lib/webapp2-2.5.2")
sys.path.append("/usr/local/google_appengine/lib/django-1.5")
sys.path.append("/usr/local/google_appengine/lib/cherrypy")
sys.path.append("/usr/local/google_appengine/lib/concurrent")
sys.path.append("/usr/local/google_appengine/lib/docker")
sys.path.append("/usr/local/google_appengine/lib/requests")
sys.path.append("/usr/local/google_appengine/lib/websocket")
sys.path.append("/usr/local/google_appengine/lib/fancy_urllib")
sys.path.append("/usr/local/google_appengine/lib/antlr3")
from selenium import webdriver
from google.appengine.api import memcache, apiproxy_stub, apiproxy_stub_map
from google.appengine.ext import db
from google.appengine.ext import testbed
import dev_appserver
from google.appengine.tools.devappserver2 import devappserver2
class NewVisitorTest(unittest.TestCase):
def setUp(self):
# Start the dev server
cmd = "/usr/local/bin/dev_appserver.py /Users/Bryan/work/GoogleAppEngine/dermalfillersecrets/app.yaml --port 8080 --storage_path /tmp/datastore --clear_datastore --skip_sdk_update_check"
self.dev_appserver = subprocess.Popen(shlex.split(cmd),
stdout=subprocess.PIPE)
time.sleep(2) # Important, let dev_appserver start up
self.testbed = testbed.Testbed()
self.testbed.setup_env(app_id="dev~myapp")
self.testbed.activate()
#self.testbed.setup_env(app_id='dermalfillersecrets')
self.testbed.init_user_stub()
# Create a consistency policy with a probability of 1,
# the datastore should be available.
self.policy = datastore_stub_util.PseudoRandomHRConsistencyPolicy(probability=1)
# Initialize the datastore stub with this policy.
self.testbed.init_datastore_v3_stub(datastore_file="/tmp/datastore/datastore.db", use_sqlite=True, consistency_policy=self.policy)
self.testbed.init_memcache_stub()
self.datastore_stub = apiproxy_stub_map.apiproxy.GetStub('datastore_v3')
# setup the dev_appserver
APP_CONFIGS = ['app.yaml']
# setup client to make sure
from main import Client
if not ( Client.query( Client.name == "Bryan Wheelock").get()):
logging.info("create Admin")
client = Client(
email = "bryan#mail.com",
name = "Bryan Wheelock",
street1 = "555 Main St",
street2 = "unit 1",
city = "Atlanta",
zipcode = 99999,
phone = "(888)555-1212"
).put()
# this sleep is to allow eventual consistency to propogate
time.sleep(2)
self.browser = webdriver.Firefox()
self.browser.implicitly_wait(3)
def tearDown(self):
self.browser.quit()
self.testbed.deactivate()
self.dev_appserver.terminate()
def test_guest_can_submit_contact_info(self):
from main import Client, Customer
client = Client.query( Client.name == "Bryan Wheelock").get()
orig_customer_count = Customer.query(ancestor=client.key).count()
self.browser.get('http://localhost:8080')
time.sleep(5)
self.browser.find_element_by_name('id_name').send_keys("Kallie Wheelock")
self.browser.find_element_by_name('id_street').send_keys("123 main st")
self.browser.find_element_by_name('id_phone').send_keys('(404)555-1212')
self.browser.find_element_by_name('id_zip').send_keys("30306")
self.browser.find_element_by_name('submit').submit()
# the time delay is to allow eventual consisenency to happen.
time.sleep(4)
assert(Customer.query(Customer.name == "Kallie Wheelock").get())
# this should return 1 more record
final_customer_count = Customer.query(ancestor=client.key).count()
self.assertNotEqual(orig_customer_count, final_customer_count)
# Delete the Customer record
Customer.query(Customer.name =="Kallie Wheelock").delete()
Here's the code in main.py:
import os
import urllib
import logging
from google.appengine.api import users
from google.appengine.ext import ndb
import jinja2
import webapp2
from webapp2_extras import sessions
class BaseHandler(webapp2.RequestHandler):
def dispatch(self):
self.session_store = sessions.get_store(request=self.request)
try:
# dispatch the request
webapp2.RequestHandler.dispatch(self)
finally:
# save all sessions
self.session_store.save_sessions(self.response)
#webapp2.cached_property
def session(self):
# Returns a session using the default cookie key.
return self.session_store.get_session()
JINJA_ENVIRONMENT = jinja2.Environment(
loader = jinja2.FileSystemLoader(os.path.dirname(__file__)),
extensions=['jinja2.ext.autoescape'],
autoescape=True)
DEFAULT_LEADBOOK_NAME = 'whatsmyname'
def leadbook_key(leadbook_name=DEFAULT_LEADBOOK_NAME):
"""Constructs a Datastore key for a LeadBook entity with leadbook_name."""
return ndb.Key('LeadBook', leadbook_name)
class Client(ndb.Model):
email = ndb.StringProperty()
name = ndb.StringProperty(indexed=True)
street1 = ndb.StringProperty()
street2 = ndb.StringProperty()
city = ndb.StringProperty()
zipcode = ndb.IntegerProperty()
phone = ndb.StringProperty()
signup = ndb.DateTimeProperty(auto_now_add=True)
# this just creates a Client to use
if not ( Client.query( Client.name == "Bryan Wheelock").get()):
client = Client(
email = "bryan#mail.com",
name = "Bryan Wheelock",
street1 = "555 Main St",
street2 = "unit 1",
city = "Atlanta",
zipcode = 99999,
phone = "(888)555-1212"
).put()
class Customer(ndb.Model):
# I commented out client property because using Ancestor Query( limited to 1 write per second)
#client = ndb.KeyProperty(kind=Client)
#email = ndb.StringProperty(indexed=True)
name = ndb.StringProperty(indexed=True)
street1 = ndb.StringProperty()
street2 = ndb.StringProperty()
city = ndb.StringProperty()
zipcode = ndb.IntegerProperty()
phone = ndb.StringProperty()
signup = ndb.DateTimeProperty(auto_now_add=True)
class MainPage(BaseHandler):
def get(self):
leadbook_name = self.request.get('leadbook_name',
DEFAULT_LEADBOOK_NAME)
# This record should exist because I create in setUP and in main.py
client = Client.query( Client.name == "Bryan Wheelock").get()
###########################################################
########################
# I can't step into the debugger because I don't know how to access debugger shell.
import pdb; pdb.set_trace()
########################
###########################################################
self.session['client'] = client.key.urlsafe()
template_values = {
'client': client,
'leadbook_name': urllib.quote_plus(leadbook_name),
}
template = JINJA_ENVIRONMENT.get_template('index.html')
self.response.write(template.render(template_values))
class LeadBook(BaseHandler):
def post(self):
leadbook_name = self.request.get('leadbook_name',
DEFAULT_LEADBOOK_NAME)
client = ndb.Key(urlsafe=self.session['client']).get()
customer = Customer( parent = client.key)
customer.name = self.request.get('id_name')
customer.street1 = self.request.get('id_street')
customer.phone = self.request.get('id_phone')
customer.zipcode = int(self.request.get('id_zip'))
# show original number of customer to show the code works
starting_customer_count = Customer.query(ancestor=client.key).count()
customer.put()
# This should return the record
assert(Customer.query(Customer.name == "Kallie Wheelock").get())
final_customer_count = Customer.query(ancestor=client.key).count()
#import pdb; pdb.set_trace()
query_params = {'leadbook_name': leadbook_name}
self.redirect('/?' + urllib.urlencode(query_params))
config = {}
config['webapp2_extras.sessions'] = {
'secret_key': 'my-super-secret-key',
}
application = webapp2.WSGIApplication([
('/', MainPage),
('/sign', LeadBook),
], config = config,
debug=True)
Considering you use nosetests, try running it with the pdb option.
nosetests -sv --pdb
The --pdb option will drop the test runner into pdb when it encounters an error.
More info here:
http://nose.readthedocs.org/en/latest/plugins/debug.html
I still can't seem to get Nosetest to run properly.
The dev_appserver runs fine when started from the command line, but when I attempt to start it from the functional_tests.py it fails.
I create a Client entity in the setUp(), but it's not accessable from the test.
How do I step into pdb debugger with dev_appserver starting up in the test?
I have tried to put pdb() breakpoints in the code. While the code stops execution, I can't step into the debugger. I'm not even sure how to see the output.
$ nosetests
INFO 2015-02-24 19:08:56,172 devappserver2.py:726] Skipping SDK update check.
INFO 2015-02-24 19:08:56,242 api_server.py:172] Starting API server at: http://localhost:62049
INFO 2015-02-24 19:08:56,247 dispatcher.py:186] Starting module "default" running at: http://localhost:8080
INFO 2015-02-24 19:08:56,249 admin_server.py:118] Starting admin server at: http://localhost:8000
ERROR 2015-02-24 19:09:00,307 webapp2.py:1552] 'NoneType' object has no attribute 'key'
Traceback (most recent call last):
File "/Users/Bryan/Desktop/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/webapp2-2.5.2/webapp2.py", line 1535, in __call__
rv = self.handle_exception(request, response, e)
File "/Users/Bryan/Desktop/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/webapp2-2.5.2/webapp2.py", line 1529, in __call__
rv = self.router.dispatch(request, response)
File "/Users/Bryan/Desktop/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/webapp2-2.5.2/webapp2.py", line 1278, in default_dispatcher
return route.handler_adapter(request, response)
File "/Users/Bryan/Desktop/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/webapp2-2.5.2/webapp2.py", line 1102, in __call__
return handler.dispatch()
File "/Users/Bryan/work/GoogleAppEngine/dermalfillersecrets/main.py", line 18, in dispatch
webapp2.RequestHandler.dispatch(self)
File "/Users/Bryan/Desktop/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/webapp2-2.5.2/webapp2.py", line 572, in dispatch
return self.handle_exception(e, self.app.debug)
File "/Users/Bryan/Desktop/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/webapp2-2.5.2/webapp2.py", line 570, in dispatch
return method(*args, **kwargs)
File "/Users/Bryan/work/GoogleAppEngine/dermalfillersecrets/main.py", line 95, in get
self.session['client'] = client.key.urlsafe()
AttributeError: 'NoneType' object has no attribute 'key'
INFO 2015-02-24 19:09:00,314 module.py:737] default: "GET / HTTP/1.1" 500 2354
INFO 2015-02-24 19:09:00,377 module.py:737] default: "GET /favicon.ico HTTP/1.1" 200 8348
INFO 2015-02-24 19:09:00,381 module.py:737] default: "GET /favicon.ico HTTP/1.1" 304 -
EINFO 2015-02-24 19:09:08,482 shutdown.py:45] Shutting down.
INFO 2015-02-24 19:09:08,483 api_server.py:588] Applying all pending transactions and saving the datastore
======================================================================
ERROR: test_guest_can_submit_contact_info (dermalfillersecrets.functional_tests.NewVisitorTest)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/Users/Bryan/work/GoogleAppEngine/dermalfillersecrets/functional_tests.py", line 88, in test_guest_can_submit_contact_info
self.browser.find_element_by_name('id_name').send_keys("Kallie Wheelock")
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/selenium/webdriver/remote/webdriver.py", line 302, in find_element_by_name
return self.find_element(by=By.NAME, value=name)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/selenium/webdriver/remote/webdriver.py", line 662, in find_element
{'using': by, 'value': value})['value']
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/selenium/webdriver/remote/webdriver.py", line 173, in execute
self.error_handler.check_response(response)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/selenium/webdriver/remote/errorhandler.py", line 166, in check_response
raise exception_class(message, screen, stacktrace)
NoSuchElementException: Message: Unable to locate element: {"method":"name","selector":"id_name"}
Stacktrace:
at FirefoxDriver.prototype.findElementInternal_ (file:///var/folders/mw/0y88j8_54bjc93d_lg3120qw0000gp/T/tmpSjWZ6W/extensions/fxdriver#googlecode.com/components/driver-component.js:9641:26)
at fxdriver.Timer.prototype.setTimeout/<.notify (file:///var/folders/mw/0y88j8_54bjc93d_lg3120qw0000gp/T/tmpSjWZ6W/extensions/fxdriver#googlecode.com/components/driver-component.js:548:5)
Here is the code in functional_tests.py
import sys, os, subprocess, time, unittest, shlex
sys.path.append("/usr/local/google_appengine")
sys.path.append("/usr/local/google_appengine/lib/yaml/lib")
sys.path.append("/usr/local/google_appengine/lib/webapp2-2.5.2")
sys.path.append("/usr/local/google_appengine/lib/django-1.5")
sys.path.append("/usr/local/google_appengine/lib/cherrypy")
sys.path.append("/usr/local/google_appengine/lib/concurrent")
sys.path.append("/usr/local/google_appengine/lib/docker")
sys.path.append("/usr/local/google_appengine/lib/requests")
sys.path.append("/usr/local/google_appengine/lib/websocket")
sys.path.append("/usr/local/google_appengine/lib/fancy_urllib")
sys.path.append("/usr/local/google_appengine/lib/antlr3")
from selenium import webdriver
from google.appengine.api import memcache, apiproxy_stub, apiproxy_stub_map
from google.appengine.ext import db
from google.appengine.ext import testbed
import dev_appserver
from google.appengine.tools.devappserver2 import devappserver2
class NewVisitorTest(unittest.TestCase):
def setUp(self):
# Start the dev server
cmd = "/usr/local/bin/dev_appserver.py /Users/Bryan/work/GoogleAppEngine/dermalfillersecrets/app.yaml --port 8080 --storage_path /tmp/datastore --clear_datastore --skip_sdk_update_check"
self.dev_appserver = subprocess.Popen(shlex.split(cmd),
stdout=subprocess.PIPE)
time.sleep(2) # Important, let dev_appserver start up
self.testbed = testbed.Testbed()
self.testbed.setup_env(app_id="dev~myapp")
self.testbed.activate()
#self.testbed.setup_env(app_id='dermalfillersecrets')
self.testbed.init_user_stub()
# Create a consistency policy with a probability of 1,
# the datastore should be available.
self.policy = datastore_stub_util.PseudoRandomHRConsistencyPolicy(probability=1)
# Initialize the datastore stub with this policy.
self.testbed.init_datastore_v3_stub(datastore_file="/tmp/datastore/datastore.db", use_sqlite=True, consistency_policy=self.policy)
self.testbed.init_memcache_stub()
self.datastore_stub = apiproxy_stub_map.apiproxy.GetStub('datastore_v3')
# setup the dev_appserver
APP_CONFIGS = ['app.yaml']
# setup client to make sure
from main import Client
if not ( Client.query( Client.name == "Bryan Wheelock").get()):
logging.info("create Admin")
client = Client(
email = "bryan#mail.com",
name = "Bryan Wheelock",
street1 = "555 Main St",
street2 = "unit 1",
city = "Atlanta",
zipcode = 99999,
phone = "(888)555-1212"
).put()
# this sleep is to allow eventual consistency to propogate
time.sleep(2)
self.browser = webdriver.Firefox()
self.browser.implicitly_wait(3)
def tearDown(self):
self.browser.quit()
self.testbed.deactivate()
self.dev_appserver.terminate()
def test_guest_can_submit_contact_info(self):
from main import Client, Customer
client = Client.query( Client.name == "Bryan Wheelock").get()
orig_customer_count = Customer.query(ancestor=client.key).count()
self.browser.get('http://localhost:8080')
time.sleep(5)
self.browser.find_element_by_name('id_name').send_keys("Kallie Wheelock")
self.browser.find_element_by_name('id_street').send_keys("123 main st")
self.browser.find_element_by_name('id_phone').send_keys('(404)555-1212')
self.browser.find_element_by_name('id_zip').send_keys("30306")
self.browser.find_element_by_name('submit').submit()
# the time delay is to allow eventual consisenency to happen.
time.sleep(4)
assert(Customer.query(Customer.name == "Kallie Wheelock").get())
# this should return 1 more record
final_customer_count = Customer.query(ancestor=client.key).count()
self.assertNotEqual(orig_customer_count, final_customer_count)
# Delete the Customer record
Customer.query(Customer.name =="Kallie Wheelock").delete()
Here's the code in main.py:
import os
import urllib
import logging
from google.appengine.api import users
from google.appengine.ext import ndb
import jinja2
import webapp2
from webapp2_extras import sessions
class BaseHandler(webapp2.RequestHandler):
def dispatch(self):
self.session_store = sessions.get_store(request=self.request)
try:
# dispatch the request
webapp2.RequestHandler.dispatch(self)
finally:
# save all sessions
self.session_store.save_sessions(self.response)
#webapp2.cached_property
def session(self):
# Returns a session using the default cookie key.
return self.session_store.get_session()
JINJA_ENVIRONMENT = jinja2.Environment(
loader = jinja2.FileSystemLoader(os.path.dirname(__file__)),
extensions=['jinja2.ext.autoescape'],
autoescape=True)
DEFAULT_LEADBOOK_NAME = 'whatsmyname'
def leadbook_key(leadbook_name=DEFAULT_LEADBOOK_NAME):
"""Constructs a Datastore key for a LeadBook entity with leadbook_name."""
return ndb.Key('LeadBook', leadbook_name)
class Client(ndb.Model):
email = ndb.StringProperty()
name = ndb.StringProperty(indexed=True)
street1 = ndb.StringProperty()
street2 = ndb.StringProperty()
city = ndb.StringProperty()
zipcode = ndb.IntegerProperty()
phone = ndb.StringProperty()
signup = ndb.DateTimeProperty(auto_now_add=True)
# this just creates a Client to use
if not ( Client.query( Client.name == "Bryan Wheelock").get()):
client = Client(
email = "bryan#mail.com",
name = "Bryan Wheelock",
street1 = "555 Main St",
street2 = "unit 1",
city = "Atlanta",
zipcode = 99999,
phone = "(888)555-1212"
).put()
class Customer(ndb.Model):
# I commented out client property because using Ancestor Query( limited to 1 write per second)
#client = ndb.KeyProperty(kind=Client)
#email = ndb.StringProperty(indexed=True)
name = ndb.StringProperty(indexed=True)
street1 = ndb.StringProperty()
street2 = ndb.StringProperty()
city = ndb.StringProperty()
zipcode = ndb.IntegerProperty()
phone = ndb.StringProperty()
signup = ndb.DateTimeProperty(auto_now_add=True)
class MainPage(BaseHandler):
def get(self):
leadbook_name = self.request.get('leadbook_name',
DEFAULT_LEADBOOK_NAME)
# This should be the Client record that shows the info of the owner of the local clinic
# the question is how do I get the site to show the correct Client?
client = Client.query( Client.name == "Bryan Wheelock").get()
self.session['client'] = client.key.urlsafe()
template_values = {
'client': client,
'leadbook_name': urllib.quote_plus(leadbook_name),
}
template = JINJA_ENVIRONMENT.get_template('index.html')
self.response.write(template.render(template_values))
class LeadBook(BaseHandler):
def post(self):
leadbook_name = self.request.get('leadbook_name',
DEFAULT_LEADBOOK_NAME)
client = ndb.Key(urlsafe=self.session['client']).get()
customer = Customer( parent = client.key)
customer.name = self.request.get('id_name')
customer.street1 = self.request.get('id_street')
customer.phone = self.request.get('id_phone')
customer.zipcode = int(self.request.get('id_zip'))
# show original number of customer to show the code works
starting_customer_count = Customer.query(ancestor=client.key).count()
#import pdb; pdb.set_trace()
customer.put()
# This should return the record
assert(Customer.query(Customer.name == "Kallie Wheelock").get())
final_customer_count = Customer.query(ancestor=client.key).count()
#import pdb; pdb.set_trace()
query_params = {'leadbook_name': leadbook_name}
self.redirect('/?' + urllib.urlencode(query_params))
config = {}
config['webapp2_extras.sessions'] = {
'secret_key': 'my-super-secret-key',
}
application = webapp2.WSGIApplication([
('/', MainPage),
('/sign', LeadBook),
], config = config,
debug=True)
The problem is hinted at by your comment:
# this sleep is to allow eventual consistency to propogate
That's really not how it works. Eventual consistency has nothing to do with time, and the way it is emulated in the local datastore has even less; in the tests, the datastore testbed implements a policy whereby the initial read almost always fails. The documentation explains how you can tweak the policy in your test; one shortcut - again, that only works in tests and not in production - is to do an explicit .get() after saving, which will always make the entity visible.