Upgrade to 2.0.x - AttributeError: 'Table' object has no attribute 'permissionid'

705 views
Skip to first unread message

Jim S

unread,
Aug 31, 2012, 9:02:55 AM8/31/12
to web...@googlegroups.com
Getting the following:

Traceback (most recent call last):
File "C:\dev\web2py\gluon\restricted.py", line 209, in restricted
exec ccode in environment
File "C:/dev/web2py/applications/infocenter/models/db.py", line 152, in <module>
format='%(name)s')
File "C:\dev\web2py\gluon\dal.py", line 7047, in define_table
table = self.lazy_define_table(tablename,*fields,**args)
File "C:\dev\web2py\gluon\dal.py", line 7078, in lazy_define_table
polymodel=polymodel)
File "C:\dev\web2py\gluon\dal.py", line 920, in create_table
fake_migrate=fake_migrate)
File "C:\dev\web2py\gluon\dal.py", line 988, in migrate_table
and not isinstance(table[key].type, SQLCustomType) \
File "C:\dev\web2py\gluon\dal.py", line 7559, in __getitem__
return ogetattr(self, str(key))
AttributeError: 'Table' object has no attribute 'permissionid'
Relevant define_table in db.py:

link = db.define_table('link',
   
Field('linkId', 'id', readable=False),
   
Field('name', length=50, required=True, unique=True),
   
Field('parentLinkId', 'reference link', required=True,
          label
='Parent Link'),
   
Field('controller', length=512, required=True),
   
Field('method', length=512, required=True),
   
Field('picture', length=512, required=False),
   
Field('permissionId', db.auth_permission, label='Rqd Permission'),
   
Field('groupId', db.auth_group, label='Rqd Group'),
   
Field('description', 'text', required=True),
    format
='%(name)s')


This is line 152.  If I change it to the following (added .id to definition of permissionId field reference) :

link = db.define_table('link',
 
Field('linkId', 'id', readable=False),
 
Field('name', length=50, required=True, unique=True),
 
Field('parentLinkId', 'reference link', required=True,
 label
='Parent Link'),
 
Field('controller', length=512, required=True),
 
Field('method', length=512, required=True),
 
Field('picture', length=512, required=False),
 
Field('permissionId', db.auth_permission.id, label='Rqd Permission'),  
 
Field('groupId', db.auth_group, label='Rqd Group'),
 
Field('description', 'text', required=True),
 format
='%(name)s')

Then I get the following traceback:

Traceback (most recent call last):
File "C:\dev\web2py\gluon\restricted.py", line 209, in restricted
exec ccode in environment
File "C:/dev/web2py/applications/infocenter/models/db.py", line 152, in <module>
format='%(name)s')
File "C:\dev\web2py\gluon\dal.py", line 7047, in define_table
table = self.lazy_define_table(tablename,*fields,**args)
File "C:\dev\web2py\gluon\dal.py", line 7078, in lazy_define_table
polymodel=polymodel)
File "C:\dev\web2py\gluon\dal.py", line 721, in create_table
elif field_type.startswith('reference'):
File "C:\dev\web2py\gluon\dal.py", line 8122, in startswith
raise SyntaxError, "startswith used with incompatible field type"
SyntaxError: startswith used with incompatible field type
Any ideas where to look for this one?

-Jim

Bruno Rocha

unread,
Aug 31, 2012, 9:20:40 AM8/31/12
to web...@googlegroups.com

did you turned lazy_tables to True on your db definition?

Bruno Rocha
http://rochacbruno.com.br
mobile

--
 
 
 

Jim Steil

unread,
Aug 31, 2012, 9:29:26 AM8/31/12
to web...@googlegroups.com
No, I made no changes to my code what-so-ever.

-Jim

--
 
 
 

Massimo Di Pierro

unread,
Aug 31, 2012, 9:36:51 AM8/31/12
to web...@googlegroups.com
I am using trunk (2.0.3). Your original code is correct.

I cannot reproduce the issue. I tried:

$ python web2py.py -S welcome -M -N
>>> link = db.define_table('link', 
    
Field('linkId', 'id', readable=False),
    
Field('name', length=50, required=True, unique=True),
    
Field('parentLinkId', 'reference link', required=True,
          label
='Parent Link'),
    
Field('controller', length=512, required=True),
    
Field('method', length=512, required=True),
    
Field('picture', length=512, required=False),
    
Field('permissionId', db.auth_permission, label='Rqd Permission'),
    
Field('groupId', db.auth_group, label='Rqd Group'),
    
Field('description', 'text', required=True),
    format
='%(name)s')
>>> link
<Table link (linkId,name,parentLinkId,controller,method,picture,permissionId,groupId,description)>

Could you please perform the same check?

Jim S

unread,
Aug 31, 2012, 9:50:07 AM8/31/12
to web...@googlegroups.com
Yes, that works for me.

-Jim

Jim S

unread,
Aug 31, 2012, 10:37:01 AM8/31/12
to web...@googlegroups.com
FWIW, here is the db.py code up to that point:

from gluon.custom_import import track_changes
track_changes
()

import icUtil
import infoCenterUtil
import logging
from dateutil.relativedelta import *
from dateutil.parser import *
import datetime
import os
from plugin_suggest_widget import suggest_widget

log
= logging.getLogger('InfoCenter')
if len(log.handlers) == 0:
 log
= icUtil.getLog(loggerName='InfoCenter', level='INFO', echo=True)

if infoCenterUtil.migrate():
 db
= DAL(infoCenterUtil.getDalString(), bigint_id=True)
else:
 db
= DAL(infoCenterUtil.getDalString(), migrate=False,
 migrate_enabled
=False, bigint_id=True)

# 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 []

#print request.env.path_info

#########################################################################
## Here is sample code if you need for
## - email capabilities
## - authentication (registration, login, logout, ... )
## - authorization (role based authorization)
## - services (xml, csv, json, xmlrpc, jsonrpc, amf, rss)
## - crud actions
## (more options discussed in gluon/tools.py)
#########################################################################

from gluon.tools import Mail, Auth, Crud, Service, PluginManager, prettydate

mail
= Mail() # mailer
auth
= Auth(db) # authentication/authorization
crud
= Crud(db) # for CRUD helpers using auth
service
= Service() # for json, xml, jsonrpc, xmlrpc, amfrpc
plugins
= PluginManager()

from gluon.contrib.login_methods.email_auth import email_auth
#auth.settings.login_methods.append((email_auth('smtp.sdfgsdg.com:321, '@sdfgs.com')))
auth
.settings.login_methods.append((email_auth('mail.sdfgsd.com:6548, '@sdfg.com')))

mail.settings.server = '
mail.sdfgsd.com:9875 # your SMTP server
mail
.settings.sender = 'i...@sdfgs.com' # your email
mail
.settings.login = sdfgs:dfgsdg # your credentials or None

auth
.settings.hmac_key = 'sha512:9d8d83af-4769-6546-9cf5-e01a163b498d' # before define_tables()

auth_user
= db.define_table(
 auth
.settings.table_user_name,
 
Field('first_name', length=128, default='', required=True),
 
Field('last_name', length=128, default='', required=True),
 
Field('email', length=128, unique=True, required=True),
 
Field('password', 'password', length=512,
 readable
=True, writable=True, label='Password'),
 
Field('registration_key', length=512,
 writable
=False, readable=False, default=''),
 
Field('reset_password_key', length=512,
 writable
=False, readable=False, default=''),
 
Field('registration_id', length=512,
 writable
=False, readable=False, default=''),
 
Field('brillLogon', length=10, default='', label='Brill Logon'),
 
Field('technician', 'boolean', default=False),
 
Field('dispatcher', 'boolean', default=False),
 
Field('lastFirst', compute=lambda u: '%s, %s' % (u['last_name'], u['first_name']), label='Name'),
 
Field('firstLast', compute=lambda u: '%s %s' % (u['first_name'], u['last_name']), label='Name'),
 format
='%(last_name)s, %(first_name)s')

auth_user
.first_name.requires = IS_NOT_EMPTY(error_message=auth.messages.is_empty)
auth_user
.last_name.requires = IS_NOT_EMPTY(error_message=auth.messages.is_empty)
auth_user
.password.requires = [CRYPT()]
auth_user
.email.requires = [IS_EMAIL(error_message=auth.messages.invalid_email),
 IS_NOT_IN_DB
(db, auth_user.email),
 IS_NOT_EMPTY
(error_message=auth.messages.is_empty)]
auth_user
.id.readable = False
auth_user
._plural = 'Users'

auth
.settings.table_user = auth_user

auth
.define_tables() # creates all needed tables
auth
.settings.mailer = mail # for user email verification
auth
.settings.registration_requires_verification = False
auth
.settings.registration_requires_approval = False
auth
.messages.verify_email = 'Click on the link http://'+request.env.http_host+URL('default','user',args=['verify_email'])+'/%(key)s to verify your email'
auth
.settings.reset_password_requires_verification = True
auth
.messages.reset_password = 'Click on the link http://'+request.env.http_host+URL('default','user',args=['reset_password'])+'/%(key)s to reset your password'

#########################################################################
## If you need to use OpenID, Facebook, MySpace, Twitter, Linkedin, etc.
## register with janrain.com, uncomment and customize following
# from gluon.contrib.login_methods.rpx_account import RPXAccount
# auth.settings.actions_disabled = \
# ['register','change_password','request_reset_password']
# auth.settings.login_form = RPXAccount(request, api_key='...',domain='...',
# url = "http://localhost:8000/%s/default/user/login" % request.application)
## other login methods are in gluon/contrib/login_methods
#########################################################################

crud
.settings.auth = None # =auth to enforce authorization on crud

#########################################################################
## Define your tables below (or better in another model file) for example
##
## >>> db.define_table('mytable',Field('myfield','string'))
##
## Fields can be 'string','text','password','integer','double','boolean'
## 'date','time','datetime','blob','upload', 'reference TABLENAME'
## There is an implicit 'id integer autoincrement' field
## Consult manual for more options, validators, etc.
##
## More API examples for controllers:
##
## >>> db.mytable.insert(myfield='value')
## >>> rows=db(db.mytable.myfield=='value').select(db.mytable.ALL)
## >>> for row in rows: print row.id, row.myfield
#########################################################################
warehouse
= db.define_table('warehouse',
 
Field('warehouseId', 'id'),
 
Field('warehouseNumber', 'integer', required=True, unique=True, label='Warehouse #'),

 
Field('name', length=50, required=True, unique=True),

 
Field('allowPricesToFall', 'boolean', default=False,
 label
='Allow Prices to Fall'),
 
Field('hin', length=10),
 
Field('active', 'boolean', default=True),
 format
='%(warehouseNumber)s - %(name)s')

warehouse
.warehouseNumber.requires = [IS_NOT_EMPTY(error_message=auth.messages.is_empty),
 IS_NOT_IN_DB
(db, warehouse.warehouseNumber)]
warehouse
.name.requires = [IS_NOT_IN_DB(db, warehouse.name),
 IS_NOT_EMPTY
(error_message=auth.messages.is_empty)]
warehouse
._plural = 'Warehouses'


link
= db.define_table('link',
 
Field('linkId', 'id', readable=False),
 
Field('name', length=50, required=True, unique=True),
 
Field('parentLinkId', 'reference link', required=True,
 label
='Parent Link'),
 
Field('controller', length=512, required=True),
 
Field('method', length=512, required=True),
 
Field('picture', length=512, required=False),
 
Field('permissionId', db.auth_permission, label='Rqd Permission'),
 
Field('groupId', db.auth_group, label='Rqd Group'),
 
Field('description', 'text', required=True),
 format
='%(name)s')



-Jim

Jim S

unread,
Aug 31, 2012, 10:47:34 AM8/31/12
to web...@googlegroups.com
Also, if I try this app on an empty db, it can't create the 'link' table. Here is the SQL generated:

CREATE TABLE link(
 linkId BIGINT AUTO_INCREMENT NOT NULL
,
 NAME VARCHAR
(50) UNIQUE,
 parentLinkId BIGINT
, INDEX parentLinkId__idx (parentLinkId), FOREIGN KEY (parentLinkId) REFERENCES link (id) ON DELETE CASCADE,
 controller VARCHAR
(255),
 method VARCHAR
(255),
 picture VARCHAR
(255),
 permissionId BIGINT
, INDEX permissionId__idx (permissionId), FOREIGN KEY (permissionId) REFERENCES auth_permission (id) ON DELETE CASCADE,
 groupId BIGINT
, INDEX groupId__idx (groupId), FOREIGN KEY (groupId) REFERENCES auth_group (id) ON DELETE CASCADE,
 description LONGTEXT
,
 PRIMARY KEY
(linkId)
) ENGINE=INNODB CHARACTER SET utf8;




and here is the result in MySQL:

Query: CREATE TABLE link( linkId BIGINT AUTO_INCREMENT NOT NULL, name VARCHAR(50) UNIQUE, parentLinkId BIGINT, INDEX parentLinkId__idx ...

Error Code: 1005
Can't create table 'ictest.link' (errno: 150)

Execution Time : 0 sec
Transfer Time : 0 sec
Total Time : 0.075 sec
---------------------------------------------------

-Jim

Jim S

unread,
Aug 31, 2012, 10:57:43 AM8/31/12
to web...@googlegroups.com
I just did a test in my MySQL tool and changed this line in the CREATE TABLE sql:

parentLinkId BIGINT, INDEX parentLinkId__idx (parentLinkId), FOREIGN KEY (parentLinkId) REFERENCES link (id) ON DELETE CASCADE,

...to this:

parentLinkId BIGINT, INDEX parentLinkId__idx (parentLinkId), FOREIGN KEY (parentLinkId) REFERENCES link (linkId) ON DELETE CASCADE,

And, now the create works.  Could it be an issue with a reference field referring to the same table not using the proper key when the default key of 'id' is not used?

-Jim

Massimo Di Pierro

unread,
Aug 31, 2012, 11:21:56 AM8/31/12
to web...@googlegroups.com
I think this is now fixed in trunk. Can you give it a try?

Jim S

unread,
Aug 31, 2012, 11:51:08 AM8/31/12
to web...@googlegroups.com
Ok, that fixed the problem with the empty db, but still getting the original traceback on my populated db:

Traceback (most recent call last):
File "C:\dev\web2py\gluon\restricted.py", line 209, in restricted
exec ccode in environment
File "C:/dev/web2py/applications/infocenter/models/db.py", line 152, in <module>
format='%(name)s'
)
File "C:\dev\web2py\gluon\dal.py", line 7052, in define_table
table = self.lazy_define_table(tablename,*fields,**args)
File "C:\dev\web2py\gluon\dal.py", line 7083, in lazy_define_table
polymodel=polymodel)
File "C:\dev\web2py\gluon\dal.py", line 925, in create_table
fake_migrate=fake_migrate)
File "C:\dev\web2py\gluon\dal.py", line 993, in migrate_table

and not isinstance(table[key].type, SQLCustomType) \
  File "C:\dev\web2py\gluon\dal.py", line 7564, in __getitem__

return ogetattr(self, str(key))
AttributeError: 'Table' object has no attribute 'permissionid'
Is lazy table definition on by default?

-Jim

Jim S

unread,
Aug 31, 2012, 2:18:17 PM8/31/12
to web...@googlegroups.com
I don't have any idea what is causing this, but I can get past it by just creating a new db and copying the data over.  This can be closed as far as I'm concerned.

-Jim

Massimo Di Pierro

unread,
Aug 31, 2012, 2:34:04 PM8/31/12
to web...@googlegroups.com
Can you check the latest trunk? I think this is fixed. The problem is wich case and migrations.
This is not a 2.0.x issue but something in your code is triggering a migration and web2py gets confused by the mixed case of the field.

Jim S

unread,
Aug 31, 2012, 3:50:58 PM8/31/12
to web...@googlegroups.com
Yes, working now.  Thanks again Massimo.  Boy, I need to buy you a drink some day!

-Jim

Massimo Di Pierro

unread,
Aug 31, 2012, 4:24:45 PM8/31/12
to web...@googlegroups.com
Look forward to that. :-)

Jim Steil

unread,
Aug 31, 2012, 4:26:24 PM8/31/12
to web...@googlegroups.com
If you ever get up just west of Madison, WI, let me know!


--
 
 
 

Reply all
Reply to author
Forward
0 new messages