I'm working on a Google AppEngine project that uses the legacy Python 2.7 runtime - my team is migrating away from this, however we're still using it for the time being. Local development has worked fine for me for the last ~6 months, and no one else on my team is affected by the following issue.
I'm getting an ImportError
when starting dev_appserver.py
, as well as during handling of any requests:
09:36:59 dev_server.1 | ERROR 2021-05-13 13:36:59,470 wsgi.py:269]
09:36:59 dev_server.1 | Traceback (most recent call last):
09:36:59 dev_server.1 | File "/Users/me/google-cloud-sdk/platform/google_appengine/google/appengine/runtime/wsgi.py", line 240, in Handle
09:36:59 dev_server.1 | handler = _config_handle.add_wsgi_middleware(self._LoadHandler())
09:36:59 dev_server.1 | File "/Users/me/google-cloud-sdk/platform/google_appengine/google/appengine/runtime/wsgi.py", line 311, in _LoadHandler
09:36:59 dev_server.1 | handler, path, err = LoadObject(self._handler)
09:36:59 dev_server.1 | File "/Users/me/google-cloud-sdk/platform/google_appengine/google/appengine/runtime/wsgi.py", line 85, in LoadObject
09:36:59 dev_server.1 | obj = __import__(path[0])
09:36:59 dev_server.1 | File "/Users/me/Source/myproject/main.py", line 5, in <module>
09:36:59 dev_server.1 | import webapp2
09:36:59 dev_server.1 | File "/Users/me/google-cloud-sdk/platform/google_appengine/lib/webapp2-2.5.2/webapp2.py", line 25, in <module>
09:36:59 dev_server.1 | import webob
09:36:59 dev_server.1 | File "/private/var/folders/qs/2qn9hbhn3k77wbhgsg77w6tm0000gn/T/pip-target-etkWjd/lib/python/webob/__init__.py", line 1, in <module>
09:36:59 dev_server.1 | File "/Users/me/google-cloud-sdk/platform/google_appengine/google/appengine/tools/devappserver2/python/runtime/sandbox.py", line 1168, in load_module
09:36:59 dev_server.1 | raise ImportError('No module named %s' % fullname)
09:36:59 dev_server.1 | ImportError: No module named webob.datetime_utils
As you can see, the error happens on importing webapp2
, which calls import webob
. webob
is installed both in my virtualenv:
(myenv) me@pegasus site % pip list | grep WebOb
WebOb 1.8.7
As well as specified in app.yaml
:
libraries:
...
- name: webob
version: "1.2.3"
...
I've ensured that my virtualenv is active at the time I start dev_appserver.py
.
The curious thing to me is this line of the traceback:
09:36:59 dev_server.1 | File "/private/var/folders/qs/2qn9hbhn3k77wbhgsg77w6tm0000gn/T/pip-target-etkWjd/lib/python/webob/__init__.py", line 1, in <module>
I have no idea why code in /private/var/folders
is being executed - shouldn't it be calling the code in my virtualenv or the code provided with the Google Cloud SDK?
It appears to be in the SDK - the caller is google-cloud-sdk/platform/google_appengine/lib/webapp2-2.5.2/webapp2.py
, however I can find no reason as to why the resolved path for webob
is in /private/var/folders
as opposed to my virtualenv or, more sensibly, the webob-1.2.3
package also located in google-cloud-sdk/platform/google_appengine/lib/
!
In fact, in ~6 years of developing Python full time, I've never seen such a filepath in a traceback - I'd always expect executed code to be in either my own files or site-packages
of the associated virtualenv.
Additionally, the file in the traceback doesn't exist (or isn't visible to me, at least): attempting to ls
the /private/var/folders/qs/2qn9hbhn3k77wbhgsg77w6tm0000gn/T/pip-target-etkWjd/
directory results in No such file or directory
.
What I've tried:
pip
installed instance of webob
.webob
with the same version that comes with the SDK (1.2.3).pyenv
and used it to remove & re-create my virtualenv.PATH
to see if some entry was causing the import system to resolve webob
in an unexpected way.None of this has worked. Ultimately, I'm still not sure how an import can ever fail if the package is installed in the active virtualenv - I'd expect that the webapp2
module in the Google Cloud SDK would resolve the import via the virtualenv, but I'm definitely not an expert on the import system.
I ended up adding the following code to /Users/me/google-cloud-sdk/platform/google_appengine/lib/webapp2-2.5.2/webapp2.py
before the attempted import of webob
:
import imp
fp, pathname, description = imp.find_module('webob')
print '--------------------------'
print fp
print pathname
print description
print '--------------------------'
Which printed out:
14:03:13 dev_server.1 |--------------------------
14:03:13 dev_server.1 | None
14:03:13 dev_server.1 | /Users/me/Source/myproject/lib/webob
14:03:13 dev_server.1 | ('', '', 5)
14:03:13 dev_server.1 | --------------------------
This webob
directory in lib
was unexpected - it's included with the python2 runtime on GAE as well as in the SDK, and thus doesn't need to be vendored in lib
. It was also empty, and so I hadn't noticed it because git
didn't report any new untracked files.
I'm not quite sure of the mechanism, but this was causing the import issue - as soon as I removed the empty directory, the issue was resolved.