I am generating some GAE endpoints library. When running endpoints tool(endpointscfg.py get_client_lib ... ), gcloud import fails.
Third party libraries are bundled with GAE project, and oauth2client-2.0.1 is actually exists in library directory.
Affecting versions: 0.10 and above
Traceback (most recent call last):
File "/usr/local/bin/endpointscfg.py", line 133, in <module>
run_file(__file__, globals())
File "/usr/local/bin/endpointscfg.py", line 129, in run_file
execfile(_PATHS.script_file(script_name), globals_)
File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/tools/endpointscfg.py", line 561, in <module>
main(sys.argv)
File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/tools/endpointscfg.py", line 557, in main
args.callback(args)
File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/tools/endpointscfg.py", line 426, in _GetClientLibCallback
hostname=args.hostname, application_path=args.application)
File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/tools/endpointscfg.py", line 388, in _GetClientLib
application_path=application_path)
File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/tools/endpointscfg.py", line 187, in GenApiConfig
module = __import__(module_name, fromlist=base_service_class_name)
File "/Users/kang/jackend/main.py", line 10, in <module>
from auth.services import JackEndAuthAPI
File "/Users/kang/jackend/auth/services.py", line 12, in <module>
from . import (
File "/Users/kang/jackend/auth/storage.py", line 9, in <module>
from ext import cloudstorage as storage
File "/Users/kang/jackend/ext/cloudstorage.py", line 9, in <module>
from gcloud import (
File "/Users/kang/jackend/lib/gcloud/storage/__init__.py", line 45, in <module>
from gcloud.storage.client import Client
File "/Users/kang/jackend/lib/gcloud/storage/client.py", line 19, in <module>
from gcloud.client import JSONClient
File "/Users/kang/jackend/lib/gcloud/client.py", line 17, in <module>
from oauth2client.service_account import ServiceAccountCredentials
ImportError: cannot import name ServiceAccountCredentials
I'm guessing that maybe App Engine provides a different version of oauth2client somehow?
Can you add a line in your code that does:
import oauth2client
print oauth2client.__version__
It should show '2.0.1' if you're using the one in the library directory. (the variable is defined here: https://github.com/google/oauth2client/blob/master/oauth2client/__init__.py)
@jgeewax You are right. App Engine serves oauth2client 1.4.12.
To add detail:
"""
`appengine_config.py` is automatically loaded when Google App Engine
starts a new instance of your application. This runs before any
WSGI applications specified in app.yaml are loaded.
"""
from google.appengine.ext import vendor
# Third-party libraries are stored in "lib", vendoring will make
# sure that they are importable by the application.
vendor.add('lib')
import oauth2client
print oauth2client.__version__
This prints 1.4.12.
BTW App Engine SDK version is 1.9.35.
OK -- if you have oauthclient 2.0.1 in your directory, then all you'd need to do is put it first in the PYTHONPATH environment variable and then it'll use that one.
But is that what google.appengine.ext.vendor.add does? Printing sys.path right after vendor.add('lib') gives the following paths, that vendor directory comes earlier than App Engine oauth2client.
[
'/Users/kang/jackend', '/Users/kang/jackend/lib',
'/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine', ...,
'/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/oauth2client',
...
]
I actually don't know for sure, but all you need is to make sure the oauth2client that you have (which is the right version) is the one used by your code... I'd assume you'd need to vendor.add('path/to/oauth2client')
@jonparrott is the author of vendor he can chime in?
@jgeewax Sure. I have all my bundled libraries under <project root>/lib directory. There is <project root>/lib/oauth2client directory too. And vendor.add('lib') adds <my project root>/lib path to sys.path list.
The problem is that endpointscfg.py doesn't load appengine_config.py. I'm actually the one who reported this issue.
A workaround is to just import appengine_config yourself as soon as possible in your code.
@cyluss LMK if this doesn't work for you and we can re-open and discuss.
@dhermes Still no luck. I moved import appengine_config very first line of my code. Something like:
"""`main` is the top level module for your API application."""
try:
appengine_config
except NameError:
import appengine_config
import endpoints
app = endpoints.api_server([<my_service object>], restricted=False)
GAE Issue 11232 is equivalent to setting --application option as app directory(which defaults to current working directory) when runningendpointscfg.py. I always run the tool in my app directory so I don't think it is effective.
Should we notify App Engine team this issue?
Can you print sys.path after importing appengine_config and oauth2client.__version__?
@jonparrott
[
'/Users/kang/jackend',
'/Users/kang/jackend/lib',
'/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine',
'/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/antlr3',
'/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/django-0.96',
'/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/fancy_urllib',
'/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/ipaddr',
'/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/jinja2-2.6',
'/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/protorpc-1.0',
'/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/webob_0_9',
'/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/webapp2-2.5.2',
'/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/yaml/lib',
'/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/simplejson',
'/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/rsa',
'/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/pyasn1',
'/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/pyasn1_modules',
'/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/httplib2',
'/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/oauth2client',
'/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/six',
'/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/cherrypy',
'/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/concurrent',
'/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/endpoints-1.0',
'/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine',
'/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python27.zip',
'/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7',
'/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/plat-darwin',
'/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/plat-mac',
'/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/plat-mac/lib-scriptpackages',
'/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python',
'/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/lib-tk',
'/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/lib-old',
'/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/lib-dynload',
'/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/PyObjC',
'/Library/Python/2.7/site-packages'
]
@cyluss sorry for the delay, can you tell me what oauth2client.__version__ and oauth2client.__file__ is after import appengine_config?
@jonparrott Thank you for your attention!
1.4.12
/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/oauth2client/oauth2client/__init__.pyc
Can you try doing this nonsense in appengine_config.py after the vendor call?
import sys
if 'oauth2client' in sys.modules:
del sys.modules['oauth2client']
@jonparrott Looks good. After unloading and reloading module, the script loads vendored 2.0.1 oauth2client. It only reloaded toplevel module, so I reloaded all the submodules in oauth2client -- Like this:
import sys
def unload_module(module_name):
target_modules = [m for m in sys.modules if m.startswith(module_name)]
for m in target_modules:
if m in sys.modules:
del sys.modules[m]
unload_module('oauth2client')
And then other module is failing:
Traceback (most recent call last):
File "/usr/local/bin/endpointscfg.py", line 133, in <module>
run_file(__file__, globals())
...
...
...
File "/Users/kang/jackend/lib/gcloud/storage/__init__.py", line 45, in <module>
from gcloud.storage.client import Client
File "/Users/kang/jackend/lib/gcloud/storage/client.py", line 19, in <module>
from gcloud.client import JSONClient
File "/Users/kang/jackend/lib/gcloud/client.py", line 17, in <module>
from oauth2client.service_account import ServiceAccountCredentials
File "/Users/kang/jackend/lib/oauth2client/service_account.py", line 32, in <module>
from oauth2client import crypt
File "/Users/kang/jackend/lib/oauth2client/crypt.py", line 27, in <module>
from oauth2client._pure_python_crypt import RsaSigner
File "/Users/kang/jackend/lib/oauth2client/_pure_python_crypt.py", line 23, in <module>
from pyasn1_modules import pem
ImportError: cannot import name pem
I will try reimporting other subsequent modules. Thank you again!
After reimporting pyasn1_modules and its submodules, endpoint tool works like charm! 馃憤
My appengine_config.py looks like this now:
"""
`appengine_config.py` is automatically loaded when Google App Engine
starts a new instance of your application. This runs before any
WSGI applications specified in app.yaml are loaded.
"""
import sys
from google.appengine.ext import vendor
# Third-party libraries are stored in "lib", vendoring will make
# sure that they are importable by the application.
vendor.add('lib')
def unload_module(module_name):
target_modules = [m for m in sys.modules if m.startswith(module_name)]
for m in target_modules:
if m in sys.modules:
del sys.modules[m]
unload_module('oauth2client')
unload_module('pyasn1_modules')
This workaround would be useful for swapping GAE provided libraries.
Great.
The long and short is that app engine is barrels of fun when it comes to user-provided newer versions of bundled libraries.
Most helpful comment
My
appengine_config.pylooks like this now:This workaround would be useful for swapping GAE provided libraries.