2

I am going through an App Engine tutorial from the Google Developers Academy on this page: https://developers.google.com/appengine/training/cloud-sql/application_with_local_mysql

It's about building a guestbook application with the local MySQL instance. I run the dev_appserver command given at the end of the tutorial $ app_engine_sdk_path/dev_appserver.py --mysql_socket=mysql_socket_path . replacing the two paths with the actual paths from my computer. After that, the terminal output looks good:

INFO     2013-10-16 05:30:54,815 sdk_update_checker.py:245] Checking for updates to the     SDK.
INFO     2013-10-16 05:30:55,025 sdk_update_checker.py:273] The SDK is up to date.
WARNING  2013-10-16 05:30:55,066 api_server.py:332] Could not initialize images API; you are likely missing the Python "PIL" module.
INFO     2013-10-16 05:30:55,072 api_server.py:139] Starting API server at: http://localhost:50138
INFO     2013-10-16 05:30:55,076 dispatcher.py:171] Starting module "default" running at: http://localhost:8080
INFO     2013-10-16 05:30:55,081 admin_server.py:117] Starting admin server at: http://localhost:8000

But after going to localhost:8080 in my browser, I get a large error message in the terminal, with many lines of it referencing webapp2.py:

ERROR    2013-10-16 05:31:04,828 webapp2.py:1528] connect() got an unexpected keyword argument 'user'
Traceback (most recent call last):
File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine
default.bundle/Contents/Resources/google_appengine/lib/webapp2-2.3/webapp2.py", line 1511, in __call__
rv = self.handle_exception(request, response, e)
File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/webapp2-2.3/webapp2.py", line 1505, in __call__
rv = self.router.dispatch(request, response)
File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/webapp2-2.3/webapp2.py", line 1253, in default_dispatcher
return route.handler_adapter(request, response)
File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/webapp2-2.3/webapp2.py", line 1077, in __call__
return handler.dispatch()
File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/webapp2-2.3/webapp2.py", line 547, in dispatch
return self.handle_exception(e, self.app.debug)
File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/webapp2-2.3/webapp2.py", line 545, in dispatch
return method(*args, **kwargs)
File "/Users/patneedham/Documents/AppEngine/mysql-demo/main.py", line 29, in get
conn = get_connection()
File "/Users/patneedham/Documents/AppEngine/mysql-demo/main.py", line 23, in get_connection
user=USER_NAME, password=PASSWORD, charset='utf8')
TypeError: connect() got an unexpected keyword argument 'user'
ERROR    2013-10-16 05:31:04,830 wsgi.py:278] 
Traceback (most recent call last):
File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/runtime/wsgi.py", line 266, in Handle
result = handler(dict(self._environ), self._StartResponse)
File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/webapp2-2.3/webapp2.py", line 1519, in __call__
response = self._internal_error(e)
File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/webapp2-2.3/webapp2.py", line 1511, in __call__
rv = self.handle_exception(request, response, e)
File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/webapp2-2.3/webapp2.py", line 1505, in __call__
rv = self.router.dispatch(request, response)
File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/webapp2-2.3/webapp2.py", line 1253, in default_dispatcher
return route.handler_adapter(request, response)
File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/webapp2-2.3/webapp2.py", line 1077, in __call__
return handler.dispatch()
File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/webapp2-2.3/webapp2.py", line 547, in dispatch
return self.handle_exception(e, self.app.debug)
File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/webapp2-2.3/webapp2.py", line 545, in dispatch
return method(*args, **kwargs)
File "/Users/patneedham/Documents/AppEngine/mysql-demo/main.py", line 29, in get
conn = get_connection()
File "/Users/patneedham/Documents/AppEngine/mysql-demo/main.py", line 23, in get_connection
user=USER_NAME, password=PASSWORD, charset='utf8')
TypeError: connect() got an unexpected keyword argument 'user'
INFO     2013-10-16 05:31:04,837 module.py:608] default: "GET / HTTP/1.1" 500 -

The last error message line doesn't make any sense: TypeError: connect() got an unexpected keyword argument 'user'

It is complaining about this:

return rdbms.connect(instance=CLOUDSQL_INSTANCE, database=DATABASE_NAME,
                     user=USER_NAME, password=PASSWORD, charset='utf8')

rdbms is from the import statement from google.appengine.api import rdbms. I found the rdbms code hosted by Google on this site: https://code.google.com/p/googleappengine/source/browse/trunk/python/google/appengine/api/rdbms.py

The connect method from that is:

def connect(instance=None, database=None, **kwargs):
  global _instance
  if not instance and _instance:
    instance = _instance

  if 'db' in kwargs and not database:
    database = kwargs.pop('db')

  user = None
  if 'user' in kwargs:
    user = kwargs.pop('user')

  password = None
  if 'password' in kwargs:
    password = kwargs.pop('password')

  if kwargs:
    logging.info('Ignoring extra kwargs to connect(): %r', kwargs)

  return rdbms_apiproxy.connect('unused_address',
                                instance,
                                database=database,
                                user=user,
                                password=password)

It definitely IS expecting the keyword argument 'user', which is what makes this whole thing very frustrating. I also checked to make sure the rdbms file I have locally is the same, and it is, so this isn't caused by having an older version of it.

I found another case of someone else with this same problem here: (https://code.google.com/p/googleappengine/issues/detail?can=2&start=0&num=100&q=&colspec=ID%20Type%20Component%20Status%20Stars%20Summary%20Language%20Priority%20Owner%20Log&groupby=&sort=&id=10102), but it is unanswered.

Pat Needham
  • 5,698
  • 7
  • 43
  • 63
  • Have you tried looking at the source code of the file as installed on your system? It should be at `/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/api/rdbms.py` according to the paths in your example. It's possible the version you found online and the version on your system are different. – Amber Oct 16 '13 at 06:24
  • @Amber that's what I thought at first, but the version on my computer is the same. I'll add that to my question to make that clear. – Pat Needham Oct 16 '13 at 06:33
  • Hm. Did you see the comment in it? `Note that rdbms_mysqldb is the module used in dev_appserver.` The code in `rdbms_mysqldb` doesn't have the user-popping bit (though that shouldn't matter, since MySQLdb.connect takes a user arg...) – Amber Oct 16 '13 at 06:47
  • That's definitely odd. It's almost like you're getting to some other `connect()`. If you're willing to edit the SDK source, find rdbms.py and add a logging.info('in the right connect') right at the top of connect(). – Dave W. Smith Oct 20 '13 at 00:56
  • @DaveW.Smith you're right, I must be getting to some other `connect()`. I added both a logging.info and print statement inside `rdbms.py` but didn't see either of the messages after running it again. – Pat Needham Oct 21 '13 at 01:42
  • Thanks. That's useful info, since I'm not able to duplicate that error. What version of OSX are you running, and what version of Python? – Dave W. Smith Oct 21 '13 at 02:29
  • Python 2.7.5 and OSX 10.8.5; I left a link to the same App Engine issue at the end of my question - luckily I'm not the only one with this problem – Pat Needham Oct 21 '13 at 02:40
  • A bit surprised to hear that google is supporting relational database on top of their big data table. – zinking Oct 23 '13 at 12:48

3 Answers3

3

I think the document may be out-dated.

It will be easier to solve the issue by remove the user and password parameters in connect and move them while you start dev_appserver. Since rdbms doesn't really use these two parameters in runtime, it is better to let them only exist in development environment.

def get_connection():
    # remove user / password
    return rdbms.connect(instance=CLOUDSQL_INSTANCE, database=DATABASE_NAME)

# start the dev server with user/password
$ app_engine_sdk_path/dev_appserver.py --mysql_socket=mysql_socket_path --mysql_user=[MYSQL_USER] --mysql_password=[MYSQL_PASSWORD] . 

# some other variables available.
[--mysql_host MYSQL_HOST] [--mysql_port MYSQL_PORT]
[--mysql_user MYSQL_USER]
[--mysql_password MYSQL_PASSWORD]
[--mysql_socket MYSQL_SOCKET]

Google App Engine also provided a MySQLdb interface.

https://developers.google.com/appengine/docs/python/cloud-sql/#Python_complete_python_example

if (os.getenv('SERVER_SOFTWARE') and
  os.getenv('SERVER_SOFTWARE').startswith('Google App Engine/')):
  db = MySQLdb.connect(unix_socket='/cloudsql/your-project-id:your-instance-name', user='root')
else:
  db = MySQLdb.connect(host='localhost', user='root')
lucemia
  • 6,349
  • 5
  • 42
  • 75
1

While I try to duplicate the symptoms you're seeing, try giving MySQLdb a try. See https://developers.google.com/appengine/docs/python/cloud-sql/#Python_Connect_to_your_database

Dave W. Smith
  • 24,318
  • 4
  • 40
  • 46
  • I created the Cloud SQL instance and enabled billing, but where is the SQL prompt within the dashboard? According to the 'Using the SQL Prompt' page (https://developers.google.com/cloud-sql/docs/sql_prompt), it says there is a SQL Prompt tab on top of the dashboard pane, but I cannot find that. I was able to find the Data Store viewer and its query page, but I believe that is different from Cloud SQL. – Pat Needham Oct 21 '13 at 21:28
  • I've been stuck on a `ImportError: No module named MySQLdb` and it's been frustrating the daylights out of me. I'll try at it again tomorrow – Pat Needham Oct 22 '13 at 03:49
  • Maybe http://stackoverflow.com/questions/5531958/installing-mysqldb-on-mac-os-x will help. – Dave W. Smith Oct 22 '13 at 04:23
1

Looking at the code you linked to, in rdbms.py:

"""Relational database API for production.

Note that rdbms_mysqldb is the module used in dev_appserver.
"""

Then, in rbdms_mysqldb.py:

try:
    import google
    import MySQLdb

    from MySQLdb import *



    __import__('MySQLdb.constants', globals(), locals(), ['*'])
except ImportError:

    def connect(instance=None, database=None):
        logging.error('The rdbms API (Google Cloud SQL) is not available because '
                      'the MySQLdb library could not be loaded. Please see the SDK '
                      'documentation for installation instructions.')

        raise NotImplementedError('Unable to find the MySQLdb library')

else:


    def connect(instance=None, database=None, **kwargs):

So, it looks like the only way you could define connect without a user or **kwargs argument is if you don't have MySQLdb installed

pip install mysql-python
John Spong
  • 1,361
  • 7
  • 8
  • I ran that command and got back: `Requirement already satisfied (use --upgrade to upgrade): mysql-python in /usr/local/lib/python2.7/site-packages/MySQL_python-1.2.4b4-py2.7-macosx-10.8-x86_64.egg Cleaning up...`. I ran it with the `--upgrade` option, and said successfully installed. But after starting the `dev_appserver` and going to the localhost page for the project, I still get that `Unable to find the MySQLdb library` error – Pat Needham Oct 25 '13 at 04:43