Setting multiple handlers with Python App Engine - python

I just cannot seem to get multiple handlers working. I'm using Google App Engine with Python. The base URL returns "Hello world!", as expected, but I keep getting a 404 error when I try to visit "/girl".
As far as I can tell I'm doing exactly what is specified in the docs:
https://cloud.google.com/appengine/docs/python/config/appconfig
And in this similar question:
YAML file url and script in GAE python
and yet trying all variants I can think of on these models does not resolve my 404 problem. I am a beginner and don't really understand how the app.yaml file works, thus I'm pretty sure that I'm not specifying the handlers correctly. But I don't know how to fix it.
app.yaml
application: multiapp
version: 1
runtime: python27
api_version: 1
threadsafe: yes
handlers:
- url: ./girl/.*
script: girl.app
- url: .*
script: main.app
libraries:
- name: webapp2
version: "2.5.2"
main.py
import webapp2
class MainHandler(webapp2.RequestHandler):
def get(self):
self.response.write('Hello world!')
app = webapp2.WSGIApplication([
('/', MainHandler)
], debug=True)
girl.py
import webapp2
class MainHandler(webapp2.RequestHandler):
def get(self):
self.response.write('Hey girl!')
app = webapp2.WSGIApplication([
('/',MainHandler),
('/girl/', MainHandler)
], debug=True)
Added: Different organization of the project could definitely avoid having to solve this problem, but I would also like to know why setting these multiple handlers isn't working to begin with.

I know this is an old thread, and that you sort of got your answer, but I want to give a better explanation of what was happening, as I have just found the answer to your fundamental question: How to split handlers into different files?
The key problem is that you are working with regular expressions, both when you declare your WSGIApplication
app = webapp2.WSGIApplication([
('/', MainHandler),
('/girl/', GirlHandler)
], debug=True)
and in your yaml file
handlers:
- url: ./girl/.*
script: girl.app
- url: .*
script: main.app
The path in your yaml url: regex must be the full path from your webapp domain. So if your domain is localhost:8080 then in your yaml file yo should add the url from localhost:8080 onwards. If you type url: /girl/.*
you're asking the browser to match domain+regex: localhost:8080/girl/.*
This means:
match this part exactly: localhost:8080/girl/
match any characters that follow the first part (as that's what ".*"
means in a regex)
So the following yaml statement:
handlers:
- url: /girl/.*
script: girl.app
means that for any url of the form domain/girl/ anything (or nothing) use the the app variable in girl.py file app = webapp2.WSGIApplication(...)
The first implication of this, is there is no purpose in writing a handler for a url that girl.py will never handle, such as when you coded:
girl.py
import webapp2
class MainHandler(webapp2.RequestHandler):
def get(self):
self.response.write('Hey girl!')
app = webapp2.WSGIApplication([
('/',MainHandler),
], debug=True)
You will never use this main handler, as it will only 'activate' when you browse for domain/, but you said in your yaml file that you only wanted girl.py to handler urls of the form domain/girl/something. It's a contradiction
This means that for your setup to work, in girl.py you should only write handlers for urls that match the regex in your yaml. in this case, any regex that is also accepted by /girl/.*.
As a sidenote, if you wanted your girlHandler to work on either domain/girl and domain/girl/ you should use this regex in your yaml file:
handlers:
- url: ./girl(?:/.*)?
script: girl.app
- url: .*
script: main.app
as this makes the /.* part optional
Hope this helps anyone reaching this question, as an insight of how webapp2 calls each handler depending on the url given

You should bundle all your routes together in one file, and have different handlers for different routes.
main.py
import webapp2
class MainHandler(webapp2.RequestHandler):
def get(self):
self.response.write('Hello world!')
class GirlHandler(webapp2.RequestHandler):
def get(self):
self.response.write('Hey Girl!')
app = webapp2.WSGIApplication([
('/', MainHandler),
('/girl/', GirlHandler)
], debug=True)
then in your app.yaml you only have to link to main.app
application: multiapp
version: 1
runtime: python27
api_version: 1
threadsafe: yes
handlers:
- url: .*
script: main.app
libraries:
- name: webapp2
version: "2.5.2"
You don't need multiple webapp2.WSGIApplication instances.

You could have central routing while keeping handlers in separate files with something along these lines in main.py:
app = webapp2.WSGIApplication([
('/girl/.*', "girl.MainHandler")
('/.*', MainHandler),
], debug=True)
Another possibility of running largely independent "apps" while still be able to share some info across them (like authentication) would be to make them modules of the main app. While offering more flexibility in the long run they do have a non-neglijible learning curve (and docs aren't always up2date for them)

Organizational issues aside, the reason this wasn't working was that I didn't include a trailing slash.
"/girl" (no slash) returns 404;
"/girl/" (with slash) renders the page.
Also the lines in app.yaml should be:
handlers:
- url: /girl/.*
script: girl.app

Related

GAE app.yaml Script Handling for scripts in subdirectories (python)

I am setting up a new GAE project, and I can't get my scripts in sub-directories to work.
EDIT: If I go to localhost:8080/testing_desc.html I don't any errors, just a blank page (view-source is blank, too). Scripts in my root dir work normally. There is a __init__.py in both the root and sub-dir.
Python script example ("/testing/testing_desc.py"):
import webapp2 as webapp
class DescTstPage(webapp.RequestHandler):
def get(self):
html = 'This should work.'
self.response.out.write(html)
app = webapp.WSGIApplication([('/.*', DescTstPage)], debug=True)
app.yaml:
application: blah
version: blah
runtime: python27
api_version: 1
default_expiration: "5d 12h"
threadsafe: false
libraries:
- name: webapp2
version: latest
handlers:
- url: / <-- This one works
script: main.app
- url: /index.html <-- This does NOT work (??)
script: main.app
- url: /(.*?)_desc.html <-- Also does NOT work
script: \1/\1_desc.app
#file not found
- url: /.*
script: file_not_found.app
I have also tried a simpler version of the yaml:
-url: /testing_desc.html
script: /testing/testing_desc.app
When you use WSGI Pyhon27 this will work. Use a dot for the seperator :
-url: /testing_desc.html
script: /testing.testing_desc.app
You are passing a list of routes to your WSGIApplicaiton call. Those routes must match whatever URL is being handled.
('/', DescTstPage) just matches the '/' URL to your handler. /.* matches all routes.
What routes are you setting in testing/testing_desc.app? They must match /testing_desc.html.
To get my scripts working in sub-dir, I changed the app.yaml and /testing/testing_desc.py to this:
app.yaml:
- url: /testing.html
script: testing/testing_desc.py
/testing/testing_desc.py:
app = webapp.WSGIApplication([('/.*', DescTstPage),], debug=True)
def main():
run_wsgi_app(app)
if __name__ == '__main__':
main()
ATM I do not understand how to make the routing work with sub-dir, so I will use this.
The answer is here:
How can i use script in sub folders on gae?
Its not explicitly stated, but in the answer you must change /foo/ to /foo in the WSGIApplication call, which maps to www.bar.com/foo. If you want to map to www.bar.com/foo.html you need to change /foo to /foo.* in the WSGIApplication call AND the url handler in app.yaml to - url: /foo\.html

The url "/web" does not match any handlers

I've been trying to do a simple webapp on appengine, but I got an issue with handlers.
This is my code:
My app.yaml file:
application: test-app
version: 1
runtime: python27
api_version: 1
threadsafe: true
handlers:
- url: /web/.*
script: AppWebInterface.application
My AppWebInterface.py file:
import webapp2
class MainPage(webapp2.RequestHandler):
def get(self):
self.response.headers['Content-Type'] = 'text/plain'
self.response.write('Hello, World!')
application = webapp2.WSGIApplication([
('/', MainPage),
], debug=True)
When I run the dev_server and visit localhost:8080/web , I get this error:
The url "/web" does not match any handlers.
I see two problems, one masking the other.
First, /web/.* will match /web/, /web/foo, but not /web. There are a few approaches. One is to use
- url: /web.*
But this will also match /webelos. Many that's not a problem for you, because the next step will catch it.
The next problem is that, having passed /web/foo through to the application, there's nothing mapping that url pattern to a class. The WSGIAppliction is set up to handle /, though no such URL will make it to the app given the handler in app.yaml.
If you're stuck getting started, try changing the handler in app.yaml to - url: /. Get something simple working, then add handlers from there.
It is because your pattern only match url which contains /web/ (need to have a '/' after /weg)
modify the pattern and see the result.
handlers:
- url: /web.*
script: AppWebInterface.application

Is there any difference between splitting application in app.yaml or webapp2 URI router

Consider the two following scenarios:
There are two url handlers in app.yaml
handlers:
- url: /main
script: main.app1
- url: /secondary
script: secondary.app2
and URI router in main.py
app1 = webapp2.WSGIApplication([('/main', MainHandler)])
and another in secondary.py
app2 = webapp2.WSGIApplication([('/secondary', SecondaryHandler)])
vs
There is one url handler in app.yaml
handlers:
- url: /.*
script: main.app
and the URI router decides the handler
app = webapp2.WSGIApplication([
('/main', MainHandler),
('/secondary', SecondaryHandler)
])
Is there any difference in how the App Engine imports the two scenarios? If all requests are for MainHandler, does the App Engine import the files associated with SecondaryHandler at all in the first scenario or does an instance always import each handler when it is first initialized?
Obviously these are different ways to partition the application logically, but I'm asking if there are any associated performance considerations.
You can use a lazy handler in webapp2 to optimize loading and use a single app.
See this link : https://webapp2.readthedocs.io/en/latest/guide/routing.html#lazy-handlers

First iussue about GAE

I'm approaching to Google App Engine.
I want to implement some handlers, but I get a "Oops! This link appears to be broken." error for each of them:
from google.appengine.ext import webapp
from google.appengine.ext.webapp.util import run_wsgi_app
class MainPage(webapp.RequestHandler):
def get(self):
self.response.headers['Content-Type'] = 'text/plain'
self.response.out.write('Hello, webapp World!')
application = webapp.WSGIApplication([('/', MainPage)], debug=True)
def main():
run_wsgi_app(application)
if __name__ == "__main__":
main()
if I used a simple print function (i.e. print "2gf"), all would work perfectly.
This is my app.yaml file:
application: sample-app
version: 1
runtime: python
api_version: 1
handlers:
- url: /aaa/aaa
script: helloworld.py
- url: /bbb/bbb
script: helloworld2.py
Suggestions?
Your code is old, and the yaml file is pointing the python scripts/apps at the wrong urls. Try the code below:
import webapp2
class HomePageHandler(webapp2.RequestHandler):
def get(self):
self.response.headers['Content-Type'] = 'text/plain'
self.response.write('Hello appengine!')
app = webapp2.WSGIApplication([('/', MainPage)],
debug=True)
And the app.yaml file should contain something like this:
application: helloworld
version: 1
runtime: python27
api_version: 1
threadsafe: true
handlers:
- url: /.*
script: helloworld.py
Also, go through the following App Engine python tutorial. It explains the main concepts of coding for App Engine really well. It helped me greatly when I got started.
In your app.yaml you do not have any routing instructions for /. Therefore when you hit a URL that does not match one of those already in your YAML, your app doesn't know what to do and shows you that error. In order to fix that you need to provide a 'default' handler for anything else that isn't specified in your app.yaml. As mentioned by #Tkingovr (+1 to him), you want to point the default (/.*) to your script. Add that handler at the bottom of your app.yaml and point it to your main script. However I agree with #Tkingovr - switching over to 2.7 now (when you're first learning) will make things easier in the long run :)

Configuring Script Handlers Google App Engine

I am trying to make a simple application using Google App Engine.
Below is my code
helloworld.py
print "hello"
class helloworld():
def myfunc(self):
st = "inside class"
return st
test.py
import helloworld
hw_object = helloworld.helloworld()
print hw_object.myfunc()
app.yaml
handlers:
- url: /.*
script: helloworld.py
- url: /.*
script: test.py
When I run my application via http://localhost:10000 it prints only hello whereas my expected output is hello and inside class.
My directory structure
E:\helloworld>dir
app.yaml helloworld.py test.py
I am pretty sure this has something to do with Script Handlers.So, what is the correct way to define handlers and what is wrong in my way of defining them.
When your first handler pattern /.* matches http://localhost:10000, the remaining handlers are all ignored.
You can updated your app.yaml
handlers:
- url: /hello
script: helloworld.py
- url: /test
script: test.py
And browse http://localhost:10000/test
Please walk through the Getting Started guide from the appengine documentation. It will help you get through the initial setup problems like this.
http://code.google.com/appengine/docs/python/gettingstarted/helloworld.html
Here is the sample Handler from that documentation.
from google.appengine.ext import webapp
from google.appengine.ext.webapp.util import run_wsgi_app
class MainPage(webapp.RequestHandler):
def get(self):
self.response.headers['Content-Type'] = 'text/plain'
self.response.out.write('Hello, webapp World!')
application = webapp.WSGIApplication(
[('/', MainPage)],
debug=True)
def main():
run_wsgi_app(application)
if __name__ == "__main__":
main()
Note that the class extends webapp.RequestHandler, the method name is get (or post if you are responding to a http post request) Also the extra code at the bottom for setting up the application. You can add extra URL's to the application by adding arguments to the WSGIApplication. For example:
application = webapp.WSGIApplication(
[('/', MainPage)],
[('/help/', HelpPage)],
debug=True)
Also note that in your app.yaml as both scripts refer to the same url pattern, there is no way that any request will ever get to test.py. The normal pattern is to have specific url patterns at the top and a catch-all patter last.
Good Luck.
I had a similar problem too. Expanding on Hamish's answer, and correcting the last part where the square brackets are:
application = webapp.WSGIApplication([
('/', MainPage),
('/help/', HelpPage)],
debug=True)
Reference:
https://webapp-improved.appspot.com/guide/routing.html
** Edit I also had an extra closing bracket in my code above. Changed that now.

Categories

Resources