There shouldn't be issue specific to SQLite (I mean it should work properly), though there is maybe a specific unnoticed issue with it as there has been a big refactoring of pyDAL, I don't recall it the refactored pyDAL was present in 2.14.5
On Thu, Jun 16, 2016 at 12:22 PM, Marty Jones <murtin.jo...@gmail.com> wrote: > Done - no change. > > Is it possible that the issue is SQLite specific and I need to migrate to > MySQL or some other db? > > On Thursday, June 16, 2016 at 12:14:51 PM UTC-4, Richard wrote: >> >> Can you comment out the part of the scheduler, the db lock file may come >> from there... >> >> On Thu, Jun 16, 2016 at 12:05 PM, Marty Jones <murtin...@gmail.com> >> wrote: >> >>> Controller logic is below. Error 1 is occuring under the "dashboard" >>> function. Errors 2/3 under the user function. >>> >>> # -*- coding: utf-8 -*- >>> # this file is released under public domain and you can use without >>> limitations >>> >>> >>> ############################################################################### >>> ## Launch with all settings via "sudo python run_server.py" >>> >>> ############################################################################### >>> >>> import operator # needed for manager_status variable >>> >>> response.title = 'nolabills' >>> >>> def jspage(): >>> link = URL('static', 'main.js') >>> return dict(link=link) >>> >>> def index(): >>> """ >>> For registered users, redirects to the requests page >>> For unregistered users, displays intro message >>> """ >>> >>> signup = URL(a=request.application, c='default', f='user/register') >>> >>> return dict(is_logged_in=auth.is_logged_in(), signup=signup) >>> >>> @auth.requires_membership('manager') >>> def manage(): >>> """ >>> This page, accessible by only managers, shows the current employees >>> of a company as well as any users who are registering themselves as >>> employees of the company. >>> From this page a manager can approve a pending user's membership, >>> as well as revoke the membership of a user on the current employee >>> list. >>> """ >>> pending_list = [] >>> approved_list = [] >>> if request.post_vars: >>> for each in request.post_vars: >>> key = request.post_vars.keys()[0] >>> underscore = key.find('_') >>> id = key[0:underscore] >>> change = key[underscore+1:len(key)] >>> change = None if change == "approve" else "unapproved" >>> # modify db accordingly >>> record = db(db.auth_user.id==id).select().first() >>> record.registration_key=change >>> record.update_record() >>> >>> for row in db().select(): >>> #for row in db(db.auth_user.company==auth.user.company).select(): >>> if row.registration_key: # if pending approval by manager >>> pending_list.append({row.id: >>> {"first":row.first_name,"last":row.last_name}}) >>> else: >>> manager_status = auth.has_membership('manager', row.id) >>> approved_list.append({row.id: >>> {"first":row.first_name,"last":row.last_name,"manager_status":manager_status}}) >>> return dict(pending_list=pending_list, approved_list=approved_list) >>> >>> @auth.requires_login() >>> def dashboard(): >>> """ >>> This page allows a user to send an email to >>> a potential customer, requesting access to bill data >>> """ >>> i = 0 >>> already_submitted = False # default is false; can only be changed if >>> request.post_vars == True >>> >>> # SQLFORM version >>> data_requests = >>> SQLFORM.grid(db(db.data_requests.company==auth.user.company), >>> fields=[db.data_requests.last_name, \ >>> db.data_requests.first_name, \ >>> db.data_requests.email, \ >>> db.data_requests.status, \ >>> db.data_requests.bill_1, >>> ], >>> headers={'data_requests.bill_1':'Most >>> Recent Bill'}, >>> sortable=False, >>> create=False, >>> editable=False, >>> deletable=True, >>> details=False, >>> maxtextlength=30, >>> csv=False, >>> upload=URL('download'), >>> ) >>> >>> pending_list = db().select(db.data_requests.email) >>> # if a new request has been made, update the database >>> if request.post_vars: >>> >>> while not already_submitted and i <= len(data_requests): >>> already_submitted = [True for row in pending_list if >>> row.email == request.post_vars.email] >>> i += 1 >>> >>> from entergy_scraper import download >>> from mailer import send_request >>> >>> if not already_submitted: >>> # generate token >>> import random, base64, sha >>> token = >>> base64.b64encode(sha.sha(str(random.random())).hexdigest())[:8] >>> db.tokens.insert(token = token, >>> first_name = request.post_vars.first_name, >>> last_name = request.post_vars.last_name, >>> email = request.post_vars.email, >>> company = auth.user.company, >>> ) >>> >>> # send request to user >>> db.scheduler_task.insert(status = 'QUEUED', >>> application_name = >>> request.application+'/default', >>> task_name = 'request', >>> group_name = 'email', >>> function_name = 'send_request', >>> args = '["{0}", "{1}", "{2}", >>> "{3}"]'.format( \ >>> request.post_vars.first, >>> request.post_vars.last, request.post_vars.email, token), >>> vars = '{}', >>> enabled = True, >>> start_time = request.now, >>> timeout = 500, # should take less >>> than 500 secs >>> ) >>> # update data_requests to show that the task is >>> AWAITING_CUSTOMER >>> db.data_requests.insert(first_name = >>> request.post_vars.first_name, >>> last_name = >>> request.post_vars.last_name, >>> email = request.post_vars.email, >>> company = auth.user.company, >>> status = 'AWAITING_CUSTOMER', >>> ) >>> >>> >>> return dict(already_submitted=already_submitted, >>> data_requests=data_requests, pending_list=pending_list) >>> >>> def approve_request(): >>> """ >>> Allows a customer to approve a data request >>> """ >>> submitted = 'submitted' >>> valid_token = 'valid_token' >>> invalid_token = 'invalid_token' >>> >>> >>> # if the user has submitted their data and it's not already in the >>> database, let them know we'll get their data >>> if request.post_vars: >>> status = submitted >>> >>> token_submitted = True if db(db.data_requests.email == >>> request.post_vars.email).select(db.tokens.submitted).first() else False >>> >>> if token_submitted == False: >>> # download data >>> db.data_requests.insert(first_name = >>> request.post_vars.first_name, >>> last_name = >>> request.post_vars.last_name, >>> email = request.post_vars.email, >>> company = auth.user.company, >>> energy_username = >>> request.post_vars.energy_username, >>> energy_password = >>> request.post_vars.energy_password, >>> ) >>> >>> # if no submission of info, try to give them the option to do so >>> else: >>> try: >>> status = valid_token >>> token = request.get_vars.token >>> token_row = db(db.tokens.token == token).select().first() >>> first_name = token_row.first_name >>> last_name = token_row.last_name >>> email = token_row.email >>> except: >>> status = invalid_token >>> >>> if status == submitted or status == invalid_token: >>> return dict(status=status, submitted=submitted, >>> invalid_token=invalid_token, token_submitted=token_submitted) >>> else: >>> return dict(status=status, first_name=first_name, >>> last_name=last_name, email=email, submitted=False, invalid_token=False, >>> token_submitted=False) >>> >>> def user(): >>> """ >>> exposes: >>> http://..../[app]/default/user/login >>> http://..../[app]/default/user/logout >>> http://..../[app]/default/user/register >>> http://..../[app]/default/user/profile >>> http://..../[app]/default/user/retrieve_password >>> http://..../[app]/default/user/change_password >>> http://..../[app]/default/user/bulk_register >>> use @auth.requires_login() >>> @auth.requires_membership('group name') >>> @auth.requires_permission('read','table name',record_id) >>> to decorate functions that need access control >>> also notice there is http://..../[app]/appadmin/manage/auth to >>> allow administrator to manage users >>> """ >>> return dict(form=auth()) >>> >>> @cache.action() >>> def download(): >>> """ >>> allows downloading of uploaded files >>> http://..../[app]/default/download/[filename] >>> """ >>> return response.download(request, db) >>> >>> def call(): >>> """ >>> exposes services. for example: >>> http://..../[app]/default/call/jsonrpc >>> decorate with @services.jsonrpc the functions to expose >>> supports xml, json, xmlrpc, jsonrpc, amfrpc, rss, csv >>> """ >>> return service() >>> >>> >>> >>> On Thursday, June 16, 2016 at 9:36:18 AM UTC-4, Marty Jones wrote: >>> >>>> I uploaded a local application to my DigitalOcean droplet and have been >>>> having a nightmare of a time with the databases. I get this variety of >>>> errors on various pages: >>>> >>>> *Error 1:* >>>> >>>> Traceback (most recent call last): >>>> File "/home/murtyjones/app/gluon/restricted.py", line 227, in restricted >>>> exec ccode in environment >>>> File >>>> "/home/murtyjones/app/applications/nolabills/controllers/default.py" >>>> <https://nolabills.com/admin/default/edit/nolabills/controllers/default.py>, >>>> line 230, in <module> >>>> File "/home/murtyjones/app/gluon/globals.py", line 417, in <lambda> >>>> self._caller = lambda f: f() >>>> File "/home/murtyjones/app/gluon/tools.py", line 4241, in f >>>> return action(*a, **b) >>>> File >>>> "/home/murtyjones/app/applications/nolabills/controllers/default.py" >>>> <https://nolabills.com/admin/default/edit/nolabills/controllers/default.py>, >>>> line 73, in dashboard >>>> data_requests = >>>> SQLFORM.grid(db(db.data_requests.company==auth.user.company), >>>> File "/home/murtyjones/app/gluon/packages/dal/pydal/objects.py", line >>>> 91, in __getattr__ >>>> raise AttributeError >>>> AttributeError >>>> >>>> >>>> *Error 2 (trying to apply changes as a user to own profile):* >>>> >>>> Traceback (most recent call last): >>>> File "/home/murtyjones/app/gluon/restricted.py", line 227, in restricted >>>> exec ccode in environment >>>> File >>>> "/home/murtyjones/app/applications/nolabills/controllers/default.py" >>>> <https://nolabills.com/admin/default/edit/nolabills/controllers/default.py>, >>>> line 230, in <module> >>>> File "/home/murtyjones/app/gluon/globals.py", line 417, in <lambda> >>>> self._caller = lambda f: f() >>>> File >>>> "/home/murtyjones/app/applications/nolabills/controllers/default.py" >>>> <https://nolabills.com/admin/default/edit/nolabills/controllers/default.py>, >>>> line 211, in user >>>> return dict(form=auth()) >>>> File "/home/murtyjones/app/gluon/tools.py", line 1941, in __call__ >>>> return getattr(self, args[0])() >>>> File "/home/murtyjones/app/gluon/tools.py", line 4026, in profile >>>> hideerror=self.settings.hideerror): >>>> File "/home/murtyjones/app/gluon/sqlhtml.py", line 1744, in accepts >>>> self.id_field_name]).update(**fields) >>>> File "/home/murtyjones/app/gluon/packages/dal/pydal/objects.py", line >>>> 2041, in update >>>> ret = db._adapter.update("%s" % table._tablename, self.query, fields) >>>> File "/home/murtyjones/app/gluon/packages/dal/pydal/adapters/base.py", >>>> line 519, in update >>>> raise e >>>> OperationalError: attempt to write a readonly database >>>> >>>> >>>> *Error 3 (trying to logout as a user):* >>>> >>>> Traceback (most recent call last): >>>> File "/home/murtyjones/app/gluon/restricted.py", line 227, in restricted >>>> exec ccode in environment >>>> File >>>> "/home/murtyjones/app/applications/nolabills/controllers/default.py" >>>> <https://nolabills.com/admin/default/edit/nolabills/controllers/default.py>, >>>> line 230, in <module> >>>> File "/home/murtyjones/app/gluon/globals.py", line 417, in <lambda> >>>> self._caller = lambda f: f() >>>> File >>>> "/home/murtyjones/app/applications/nolabills/controllers/default.py" >>>> <https://nolabills.com/admin/default/edit/nolabills/controllers/default.py>, >>>> line 211, in user >>>> return dict(form=auth()) >>>> File "/home/murtyjones/app/gluon/tools.py", line 1941, in __call__ >>>> return getattr(self, args[0])() >>>> File "/home/murtyjones/app/gluon/tools.py", line 3235, in logout >>>> self.log_event(log, self.user) >>>> File "/home/murtyjones/app/gluon/tools.py", line 2530, in log_event >>>> self.table_event().insert(description=str(description % vars), >>>> origin=origin, user_id=user_id) >>>> File "/home/murtyjones/app/gluon/packages/dal/pydal/objects.py", line >>>> 740, in insert >>>> ret = self._db._adapter.insert(self, self._listify(fields)) >>>> File "/home/murtyjones/app/gluon/packages/dal/pydal/adapters/base.py", >>>> line 482, in insert >>>> raise e >>>> IntegrityError: FOREIGN KEY constraint failed >>>> >>>> >>>> *db.py* >>>> ## app configuration made easy. Look inside private/appconfig.ini >>>> from gluon.contrib.appconfig import AppConfig >>>> ## import current for current.db = db line >>>> from gluon import current >>>> >>>> ## once in production, remove reload=True to gain full speed >>>> myconf = AppConfig(reload=True) >>>> >>>> ## if NOT running on Google App Engine use SQLite or other DB >>>> db = DAL(myconf.take('db.uri'), pool_size=myconf.take('db.pool_size', >>>> cast=int), migrate_enabled = myconf.get('db.migrate'), >>>> check_reserved=['all']) >>>> >>>> ## define current.db for module usage >>>> current.db = db >>>> >>>> ## by default give a view/generic.extension to all actions from >>>> localhost >>>> ## none otherwise. a pattern can be 'controller/function.extension' >>>> response.generic_patterns = ['*'] if request.is_local else [] >>>> ## choose a style for forms >>>> response.formstyle = myconf.take('forms.formstyle') # or >>>> 'bootstrap3_stacked' or 'bootstrap2' or other >>>> response.form_label_separator = myconf.take('forms.separator') >>>> >>>> from gluon.tools import Auth, Service, PluginManager >>>> >>>> auth = Auth(db) >>>> service = Service() >>>> plugins = PluginManager() >>>> >>>> auth.settings.extra_fields['auth_user']= [ >>>> Field('company'), >>>> ] >>>> >>>> ## create all tables needed by auth if not custom tables >>>> auth.define_tables(username=False, signature=False, migrate=True, >>>> fake_migrate=True) >>>> >>>> ## configure email >>>> mail = auth.settings.mailer >>>> mail.settings.server = 'smtp.gmail.com' >>>> mail.settings.sender = 'em...@gmail.com' >>>> mail.settings.login = 'em...@gmail.com:password' >>>> >>>> ## configure auth policy >>>> auth.settings.registration_requires_verification = True >>>> auth.settings.registration_requires_approval = True >>>> auth.settings.reset_password_requires_verification = True >>>> >>>> ## after defining tables, uncomment below to enable auditing >>>> # auth.enable_record_versioning(db) >>>> >>>> >>>> ## create list of companies for which this is available >>>> db.define_table('company_info', >>>> Field('name'), >>>> Field('street_address'), >>>> ) >>>> >>>> ## create a table for the queue of not yet fulfilled data requests >>>> db.define_table('data_requests', >>>> Field('first_name'), >>>> Field('last_name'), >>>> Field('entergy_username'), >>>> Field('entergy_password'), >>>> Field('email'), >>>> Field('company'), >>>> Field('status', default='QUEUED'), >>>> Field('runs', 'integer', default=0), >>>> Field('bill_1', 'upload', uploadfield='bill_1_file'), >>>> Field('bill_1_file', 'blob'), >>>> ) >>>> >>>> >>>> ## create a table for generating tokens >>>> db.define_table('tokens', >>>> Field('first_name'), >>>> Field('last_name'), >>>> Field('email'), >>>> Field('company'), >>>> Field('token'), >>>> Field('submitted', default=False), >>>> ) >>>> >>>> >>>> >>>> *sql.log* >>>> timestamp: 2016-06-15T14:20:52.811948 >>>> CREATE TABLE auth_user( >>>> id INTEGER PRIMARY KEY AUTOINCREMENT, >>>> first_name CHAR(128), >>>> last_name CHAR(128), >>>> email CHAR(512), >>>> password CHAR(512), >>>> registration_key CHAR(512), >>>> reset_password_key CHAR(512), >>>> registration_id CHAR(512) >>>> ); >>>> success! >>>> timestamp: 2016-06-15T14:20:52.856816 >>>> CREATE TABLE auth_group( >>>> id INTEGER PRIMARY KEY AUTOINCREMENT, >>>> role CHAR(512), >>>> description TEXT >>>> ); >>>> success! >>>> timestamp: 2016-06-15T14:20:52.899975 >>>> CREATE TABLE auth_membership( >>>> id INTEGER PRIMARY KEY AUTOINCREMENT, >>>> user_id INTEGER REFERENCES auth_user (id) ON DELETE CASCADE , >>>> group_id INTEGER REFERENCES auth_group (id) ON DELETE CASCADE >>>> ); >>>> success! >>>> timestamp: 2016-06-15T14:20:53.040386 >>>> CREATE TABLE auth_permission( >>>> id INTEGER PRIMARY KEY AUTOINCREMENT, >>>> group_id INTEGER REFERENCES auth_group (id) ON DELETE CASCADE , >>>> name CHAR(512), >>>> table_name CHAR(512), >>>> record_id INTEGER >>>> ); >>>> success! >>>> timestamp: 2016-06-15T14:20:53.092848 >>>> CREATE TABLE auth_event( >>>> id INTEGER PRIMARY KEY AUTOINCREMENT, >>>> time_stamp TIMESTAMP, >>>> client_ip CHAR(512), >>>> user_id INTEGER REFERENCES auth_user (id) ON DELETE CASCADE , >>>> origin CHAR(512), >>>> description TEXT >>>> ); >>>> success! >>>> timestamp: 2016-06-15T14:20:53.223004 >>>> CREATE TABLE auth_cas( >>>> id INTEGER PRIMARY KEY AUTOINCREMENT, >>>> user_id INTEGER REFERENCES auth_user (id) ON DELETE CASCADE , >>>> created_on TIMESTAMP, >>>> service CHAR(512), >>>> ticket CHAR(512), >>>> renew CHAR(1) >>>> ); >>>> success! >>>> timestamp: 2016-06-15T14:22:53.166163 >>>> ALTER TABLE auth_user ADD company CHAR(512); >>>> success! >>>> timestamp: 2016-06-15T14:22:53.554653 >>>> CREATE TABLE company_info( >>>> id INTEGER PRIMARY KEY AUTOINCREMENT, >>>> name CHAR(512), >>>> street_address CHAR(512) >>>> ); >>>> success! >>>> timestamp: 2016-06-15T14:22:53.604055 >>>> CREATE TABLE data_requests( >>>> id INTEGER PRIMARY KEY AUTOINCREMENT, >>>> first_name CHAR(512), >>>> last_name CHAR(512), >>>> entergy_username CHAR(512), >>>> entergy_password CHAR(512), >>>> email CHAR(512), >>>> company CHAR(512), >>>> status CHAR(512), >>>> runs INTEGER, >>>> bill_1 CHAR(512), >>>> bill_1_file BLOB >>>> ); >>>> success! >>>> timestamp: 2016-06-15T14:22:53.645905 >>>> CREATE TABLE tokens( >>>> id INTEGER PRIMARY KEY AUTOINCREMENT, >>>> first_name CHAR(512), >>>> last_name CHAR(512), >>>> email CHAR(512), >>>> company CHAR(512), >>>> token CHAR(512), >>>> submitted CHAR(512) >>>> ); >>>> success! >>>> timestamp: 2016-06-15T14:22:56.435830 >>>> CREATE TABLE scheduler_task( >>>> id INTEGER PRIMARY KEY AUTOINCREMENT, >>>> application_name CHAR(512), >>>> task_name CHAR(512), >>>> group_name CHAR(512), >>>> status CHAR(512), >>>> function_name CHAR(512), >>>> uuid CHAR(255) UNIQUE, >>>> args TEXT, >>>> vars TEXT, >>>> enabled CHAR(1), >>>> start_time TIMESTAMP, >>>> next_run_time TIMESTAMP, >>>> stop_time TIMESTAMP, >>>> repeats INTEGER, >>>> retry_failed INTEGER, >>>> period INTEGER, >>>> prevent_drift CHAR(1), >>>> timeout INTEGER, >>>> sync_output INTEGER, >>>> times_run INTEGER, >>>> times_failed INTEGER, >>>> last_run_time TIMESTAMP, >>>> assigned_worker_name CHAR(512) >>>> ); >>>> success! >>>> timestamp: 2016-06-15T14:22:56.501649 >>>> CREATE TABLE scheduler_run( >>>> id INTEGER PRIMARY KEY AUTOINCREMENT, >>>> task_id INTEGER REFERENCES scheduler_task (id) ON DELETE CASCADE , >>>> status CHAR(512), >>>> start_time TIMESTAMP, >>>> stop_time TIMESTAMP, >>>> run_output TEXT, >>>> run_result TEXT, >>>> traceback TEXT, >>>> worker_name CHAR(512) >>>> ); >>>> success! >>>> timestamp: 2016-06-15T14:22:56.546304 >>>> CREATE TABLE scheduler_worker( >>>> id INTEGER PRIMARY KEY AUTOINCREMENT, >>>> worker_name CHAR(255) UNIQUE, >>>> first_heartbeat TIMESTAMP, >>>> last_heartbeat TIMESTAMP, >>>> status CHAR(512), >>>> is_ticker CHAR(1), >>>> group_names TEXT, >>>> worker_stats TEXT >>>> ); >>>> success! >>>> timestamp: 2016-06-15T14:22:56.589493 >>>> CREATE TABLE scheduler_task_deps( >>>> id INTEGER PRIMARY KEY AUTOINCREMENT, >>>> job_name CHAR(512), >>>> task_parent INTEGER, >>>> task_child INTEGER REFERENCES scheduler_task (id) ON DELETE CASCADE >>>> , >>>> can_visit CHAR(1) >>>> ); >>>> success! >>>> >>>> No idea where to even start with this and would appreciate help. >>>> >>>> -- >>> Resources: >>> - http://web2py.com >>> - http://web2py.com/book (Documentation) >>> - http://github.com/web2py/web2py (Source code) >>> - https://code.google.com/p/web2py/issues/list (Report Issues) >>> --- >>> You received this message because you are subscribed to the Google >>> Groups "web2py-users" group. >>> To unsubscribe from this group and stop receiving emails from it, send >>> an email to web2py+un...@googlegroups.com. >>> For more options, visit https://groups.google.com/d/optout. >>> >> >> -- > Resources: > - http://web2py.com > - http://web2py.com/book (Documentation) > - http://github.com/web2py/web2py (Source code) > - https://code.google.com/p/web2py/issues/list (Report Issues) > --- > You received this message because you are subscribed to the Google Groups > "web2py-users" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to web2py+unsubscr...@googlegroups.com. > For more options, visit https://groups.google.com/d/optout. > -- Resources: - http://web2py.com - http://web2py.com/book (Documentation) - http://github.com/web2py/web2py (Source code) - https://code.google.com/p/web2py/issues/list (Report Issues) --- You received this message because you are subscribed to the Google Groups "web2py-users" group. To unsubscribe from this group and stop receiving emails from it, send an email to web2py+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.