App Engine throws 404 Not Found for any path but root
<p>I want to split my App Engine implementation into several files. So I wrote in my app.yaml file:</p>

<pre><code>runtime: python27
api_version: 1
threadsafe: true

handlers:

- url: /imageuploader
  script: imageuploader.app

- url: /search
  script: main.app

- url: /
  static_files: index.html
  upload: index.html

libraries:
- name: MySQLdb
  version: "latest"
</code></pre>

<p>Basically I search and image upload to be on different paths and root path to have index file.</p>

<p>Here are my handlers:</p>

<p>main.py:</p>

<pre><code>class MainPage(webapp2.RequestHandler):

    def get(self):
        #Implementation

app = webapp2.WSGIApplication([
    ('/', MainPage),
], debug=True)
</code></pre>

<p>imageuploader.py:</p>

<pre><code>class UserPhoto(ndb.Model):
    blob_key = ndb.BlobKeyProperty()


class PhotoUploadFormHandler(webapp2.RequestHandler):
    def get(self):
        # [START upload_url]
        upload_url = blobstore.create_upload_url('/upload_photo')
        # [END upload_url]
        # [START upload_form]
        # To upload files to the blobstore, the request method must be "POST"
        # and enctype must be set to "multipart/form-data".
        self.response.out.write("""
&lt;html&gt;&lt;body&gt;
&lt;form action="{0}" method="POST" enctype="multipart/form-data"&gt;
  Upload File: &lt;input type="file" name="file"&gt;&lt;br&gt;
  &lt;input type="submit" name="submit" value="Submit"&gt;
&lt;/form&gt;
&lt;/body&gt;&lt;/html&gt;""".format(upload_url))
        # [END upload_form]


# [START upload_handler]
class PhotoUploadHandler(blobstore_handlers.BlobstoreUploadHandler):
    def post(self):
        try:
            upload = self.get_uploads()[0]
            user_photo = UserPhoto(
                user=users.get_current_user().user_id(),
                blob_key=upload.key())
            user_photo.put()

            self.redirect('/view_photo/%s' % upload.key())

        except:
            self.error(500)
# [END upload_handler]


# [START download_handler]
class ViewPhotoHandler(blobstore_handlers.BlobstoreDownloadHandler):
    def get(self, photo_key):
        if not blobstore.get(photo_key):
            self.error(404)
        else:
            self.send_blob(photo_key)
# [END download_handler]


app = webapp2.WSGIApplication([
    ('/', PhotoUploadFormHandler),
    ('/upload_photo', PhotoUploadHandler),
    ('/view_photo/([^/]+)?', ViewPhotoHandler),
], debug=True)
# [END all]
</code></pre>

<p>Now, the weird thing is that if I set </p>

<pre><code>-url: /.*
    script: main.app
</code></pre>

<p>It all works. I also tried <code>/search/.+</code> and <code>/imageuploader/.+</code>. I must have forgotten something completely obvious but I cant figure out what is it.</p>

<p>Each <code>app.yaml</code> route script config (like <code>script: imageuploader.app</code>) requires a python file with a matching name (<code>imageuploader.py</code> in this case) which is defining an app called <code>app</code> (just like the <code>main.py</code> does) with app routes being, of course, a subset of (or equal to) the corresponding path from the <code>app.yaml</code> file (<code>/imageuploader</code> in this case).</p>

<p>So, problems with your implementation:</p>

<ul>
<li>the <code>main.py</code> app path is <code>/</code> - doesn't match the corresponding <code>/search</code> path in <code>app.yaml</code></li>
<li>none of the 3 app path patterns in <code>imageuploader.py</code> matches the corresponding <code>/imageuploader</code> path in <code>app.yaml</code></li>
<li>the <code>/</code> path in <code>app.yaml</code> is actually mapped to the static resource <code>index.html</code>, so it'll be served by GAE directly - no point adding a handler for it as that handler should never be invoked (you may want to revisit the static resources mapping).</li>
</ul>

<p>Your attempt using <code>/.*</code> mapped to <code>main.app</code> could only have worked <strong>before</strong> you removed the handler code now in <code>imageuploader.py</code>, but should not be working with the <code>main.py</code> content from your question.</p>

<p>Assuming your patterns in the <code>app.yaml</code> are the ones you desire, these would be the app configs you'd need (to continue with your approach):</p>

<p>main.py:</p>

<pre><code>app = webapp2.WSGIApplication([
    ('/search', MainPage),
], debug=True)
</code></pre>

<p>imageuploader.py:</p>

<pre><code>app = webapp2.WSGIApplication([
    ('/imageuploader', ...),  # TODO: revisit mappings
], debug=True)
</code></pre>

<p>But I'd suggest a simpler to manage approach, using <a href="http://webapp2.readthedocs.io/en/latest/guide/routing.html#guide-routing-lazy-handlers" rel="nofollow">webapp2's lazy loading</a> of the handler code.</p>

<p>You keep a single, generic mapping in the <code>app.yaml</code>, which would match <strong>any url pattern</strong> in the <code>main.py</code> file:</p>

<pre><code>- url: /.*
  script: main.app
</code></pre>

<p>You have a single app route mapping definition in <code>main.py</code>, but which can lazy-load handlers from both <code>main.py</code> as well as other modules/files. For example something like this:</p>

<pre><code>app = webapp2.WSGIApplication([    
    ('/upload', 'imageuploader.PhotoUploadFormHandler'),
    ('/upload_photo', 'imageuploader.PhotoUploadHandler'),
    ('/view_photo/([^/]+)?', 'imageuploader.ViewPhotoHandler'),
    ('/main_page', MainPage),
], debug=True)
</code></pre>

<p>A middle-ground approach is also possible, allowing you to completely de-couple <code>imageuploader.py</code> from <code>main.py</code> but with a slightly more careful url pattern choice.</p>

<p>You could have in <code>app.yaml</code>:</p>

<pre><code>- url: /photo.*
  script: imageuploader.app
</code></pre>

<p>And in <code>imageuploader.py</code> have url patterns matching that <code>/photo.*</code> one:</p>

<pre><code>app = webapp2.WSGIApplication([
    ('/photo_upload_form', PhotoUploadFormHandler),
    ('/photo_upload', PhotoUploadHandler),
    ('/photo_view/([^/]+)?', ViewPhotoHandler),
], debug=True)
</code></pre>

python google-app-engine app.yaml