over the last couple of days (during the odd hour that I can spend on this project), I struggled to start using the Google Drive API with a service account in python GAE for local debugging.
My setup:
- Eclipse 4.4
- Google App Engine SDK for Python 1.8.0
- Google Python API Client GAE 1.1
I activated (among others) these third-party libraries in app.yaml:
- name: pycrypto version: latest - name: ssl version: latest
This is what I understand about setting up sofar, in a few statements:
- because my application doesn’t need to access user files, but the application-specific file, the application must use the “service account” to own and access the file in Google Drive.
- service accounts can be authenticated in two ways: (1) an API key and (2) private key credentials
- When developing a GAE application using the SDK, two environments must be considered: the local system (for debugging) and the GAE server (for deployment)
- API key authentication does not work (and will never work) when launched on the local system due to two-way authentication (do not fully understand this ... but it seems true).
I really need a local debugging function because I am learning python and learning the interface of the Google interface, so debugging on the server is a big load.
Therefore, I need to get the secret key credentials running on the local system. But then I ran into the problem "ImportError: I can not import the name SignedJwtAssertionCredentials". Tried almost everything I found on the Internet:
- using python 2.7 runtime and including pycrypto library
- update google-api-python-client-gae to 1.1 (which includes this fix)
- OpenSSL is installed on my system (but probably failed to set the correct paths)
- read the installation instructions for pycrypto locally, but suggested they are outdated.
=> My first question is just to understand: is it even possible to authenticate your local system from SDE GAE to the Google Drive API using Python? Maybe the answer is very simple no.
=> if the answer is yes, then will there be an example example and code sample to show how to achieve this local authentication?
=> The error log (below) seems to indicate that there is still a problem with pycrypto inaccessibility, but the docs explicitly state that it is included in the Python 2.7 GAE runtime.
=> possible (please confirm). I am confused by the difference between local and server python configuration. When I look at Eclipse's “Run Local” PYTHONPATH, it includes (1) my project folders, (2) google-api-client-python-gae folders (which don't seem to include pycrypto !!), whereas GAE runtime - what's the difference? and (3) my local deployment of Python 2.7. So, what is missing in this local configuration, what do I need to emulate server configurations to start debugging?
This is my code for authentication using private key credentials:
from oauth2client.client import SignedJwtAssertionCredentials f = file(SERVICE_ACCOUNT_PKCS12_FILE_PATH, 'rb') key = f.read() f.close() credentials = SignedJwtAssertionCredentials(SERVICE_ACCOUNT_EMAIL, key, scope=OAUTH_SCOPE) http = httplib2.Http() http = credentials.authorize(http) return build('drive', 'v2', http=http)
This error log is:
ERROR 2013-06-18 00:59:57,562 dev_appserver_import_hook.py:1251] Third party package Crypto was enabled in app.yaml but not found on import. You may have to download and install it. ERROR 2013-06-18 00:59:59,255 dev_appserver_import_hook.py:1251] Third party package Crypto was enabled in app.yaml but not found on import. You may have to download and install it. ERROR 2013-06-18 00:59:59,289 webapp2.py:1552] import_string() failed for 'illustrations.SyncHandler'. Possible reasons are: - missing __init__.py in a package; - package or module path not included in sys.path; - duplicated package or module name taking precedence in sys.path; - missing module, class, function or variable; Original exception: ImportError: cannot import name SignedJwtAssertionCredentials Debugged import: - 'illustrations' not found. Traceback (most recent call last): File "C:\Program Files (x86)\Google\google_appengine\lib\webapp2-2.5.2\webapp2.py", line 1535, in __call__ rv = self.handle_exception(request, response, e) File "C:\Program Files (x86)\Google\google_appengine\lib\webapp2-2.5.2\webapp2.py", line 1529, in __call__ rv = self.router.dispatch(request, response) File "C:\Program Files (x86)\Google\google_appengine\lib\webapp2-2.5.2\webapp2.py", line 1272, in default_dispatcher self.handlers[handler] = handler = import_string(handler) File "C:\Program Files (x86)\Google\google_appengine\lib\webapp2-2.5.2\webapp2.py", line 1850, in import_string return getattr(__import__(module, None, None, [obj]), obj) File "C:\Program Files (x86)\Google\google_appengine\google\appengine\tools\dev_appserver_import_hook.py", line 692, in Decorate return func(self, *args, **kwargs) File "C:\Program Files (x86)\Google\google_appengine\google\appengine\tools\dev_appserver_import_hook.py", line 1766, in load_module return self.FindAndLoadModule(submodule, fullname, search_path) File "C:\Program Files (x86)\Google\google_appengine\google\appengine\tools\dev_appserver_import_hook.py", line 692, in Decorate return func(self, *args, **kwargs) File "C:\Program Files (x86)\Google\google_appengine\google\appengine\tools\dev_appserver_import_hook.py", line 1630, in FindAndLoadModule description) File "C:\Program Files (x86)\Google\google_appengine\google\appengine\tools\dev_appserver_import_hook.py", line 692, in Decorate return func(self, *args, **kwargs) File "C:\Program Files (x86)\Google\google_appengine\google\appengine\tools\dev_appserver_import_hook.py", line 1577, in LoadModuleRestricted description) File "C:\Users\vic\Dropbox\Development\Eclipse-juno-workspace\Missale\src\illustrations.py", line 6, in <module> import drive File "C:\Program Files (x86)\Google\google_appengine\google\appengine\tools\dev_appserver_import_hook.py", line 692, in Decorate return func(self, *args, **kwargs) File "C:\Program Files (x86)\Google\google_appengine\google\appengine\tools\dev_appserver_import_hook.py", line 1766, in load_module return self.FindAndLoadModule(submodule, fullname, search_path) File "C:\Program Files (x86)\Google\google_appengine\google\appengine\tools\dev_appserver_import_hook.py", line 692, in Decorate return func(self, *args, **kwargs) File "C:\Program Files (x86)\Google\google_appengine\google\appengine\tools\dev_appserver_import_hook.py", line 1630, in FindAndLoadModule description) File "C:\Program Files (x86)\Google\google_appengine\google\appengine\tools\dev_appserver_import_hook.py", line 692, in Decorate return func(self, *args, **kwargs) File "C:\Program Files (x86)\Google\google_appengine\google\appengine\tools\dev_appserver_import_hook.py", line 1577, in LoadModuleRestricted description) File "C:\Users\vic\Dropbox\Development\Eclipse-juno-workspace\Missale\src\drive.py", line 6, in <module> from oauth2client.client import SignedJwtAssertionCredentials ImportStringError: import_string() failed for 'illustrations.SyncHandler'. Possible reasons are: - missing __init__.py in a package; - package or module path not included in sys.path; - duplicated package or module name taking precedence in sys.path; - missing module, class, function or variable; Original exception: ImportError: cannot import name SignedJwtAssertionCredentials Debugged import: - 'illustrations' not found.
[update], considering my question, I think I will need to get a closer look at installing pycrypto locally. If this is a fix, I will send feedback on this article to request a note on inconsistencies between the GAE runtime libraries and the local SDK libraries. And I will also add installation instructions.
[update2] The import problem of SignedJwtAssertionCredentials has disappeared, but another import problem has appeared in the tlslite package. I had no idea how to fix this, because the import looked completely healthy, and I resorted to reconfiguring the entire IDE from scratch. I installed another pre-compiled pycrypto library and I followed the prompt in the error message and converted the private key file .p12 to the .pem file. Note that the .pem file created by openssl contained 4 lines of text before "----- BEGIN", which I had to delete manually so that the .pem file was recognized by oauth2client!
[update3] when reconfiguring the IDE from scratch, I missed the opportunity to use "old_dev_appserver.py" to run the application locally, rather than "dev_appserver.py". The latter will not turn on breakpoints! But it seems that this has something to do with the import problem of SignedJwtAssertionCredentials. Using "dev_appserver.py", I have no import problem (but no breakpoints) and using "old_dev_appserver.py", I can reproduce the import problem. Thus, "old_dev_appserver.py" can be part of the problem all the time!