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.
Related
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
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
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 :)
I'm using GAE, Google App Engine with Webapp using Python.
I've been trying to implement a custom error handler, or template, or along those lines. GAE provides some documentation here however it doesn't provide enough in the example for implementation (for me).
I've also looked at all these wonderful examples on another StackOverflow question here - but cannot understand how to implement it into my current main.py file.
import os
from google.appengine.ext import webapp
from google.appengine.ext.webapp import util
from google.appengine.ext.webapp import template
class MainHandler(webapp.RequestHandler):
def get (self, q):
if q is None:
q = 'static/index.html'
path = os.path.join (os.path.dirname (__file__), q)
self.response.headers ['Content-Type'] = 'text/html'
self.response.out.write (template.render (path, {}))
def main ():
application = webapp.WSGIApplication ([('/(.*html)?', MainHandler)], debug=False)
util.run_wsgi_app (application)
if __name__ == '__main__':
main ()
I've tried making another class, and implementing it before the MainHandler as well as a new def in the MainHandler. The only times I've gotten the 404 to display, it's displayed globally, meaning even the index.html file was a "404".
The last thing I tried was implementing something along the lines of:
if not os.path.exists (_file_):
self.redirect(/static/error/404.html)
My app.yaml file is:
application: appname
version: 1
runtime: python
api_version: 1
error_handlers:
- file: static/error/404.html
- error_code: over_quota
file: static/error/404.html
handlers:
- url: /(.*\.(gif|png|jpg|ico|js|css))
static_files: \1
upload: (.*\.(gif|png|jpg|ico|js|css))
- url: /robots.txt
static_files: robots.txt
upload: robots.txt
- url: /favicon.ico
static_files: favicon.ico
upload: favicon.ico
- url: .*
script: main.py
I cannot find any guides/tutorials to the implementation of the 404 handler, just code extracts.
Much appreciated everyone!
Edit:
As per clarification from Hans below, I want to return a 404 when a file (or directory) is not present in the filesystem.
I've tried:
class ErrorHandler(webapp.RequestHandler):
def get(self):
if not os.path.isfile(_file_):
self.redirect('/static/error/404.html')
to no avail. What's the correct implementation/syntax?
Edit:
To Voscausa
import os
from google.appengine.ext import webapp
from google.appengine.ext.webapp import util
from google.appengine.ext.webapp import template
import logging
import webapp2
def handle_404(request, response, exception):
logging.exception(exception)
response.write('Oops! I could swear this page was here!')
response.set_status(404)
def handle_500(request, response, exception):
logging.exception(exception)
response.write('A server error occurred!')
response.set_status(500)
app = webapp2.WSGIApplication([
webapp2.Route('/', handler='handlers.HomeHandler', name='home')
])
app.error_handlers[404] = handle_404
app.error_handlers[500] = handle_500
class MainHandler(webapp.RequestHandler):
def get (self, q):
if q is None:
q = 'static/index.html'
path = os.path.join (os.path.dirname (__file__), q)
self.response.headers ['Content-Type'] = 'text/html'
self.response.out.write (template.render (path, {}))
def main ():
application = webapp.WSGIApplication ([('/(.*html)?', MainHandler)], debug=True)
util.run_wsgi_app (application)
if __name__ == '__main__':
main ()
Have a look at: http://webapp-improved.appspot.com/guide/exceptions.html for handling 404 and 500 exceptions.
Webapp2 is now the preferred framework for GAE python applications.
SOLUTION 1: Have appengine take care of your static files
You can have GAE handle your static files for you, like this:
application: appname
version: 1
runtime: python
api_version: 1
handlers:
- url: /static
static_dir: static
- url: .*
script: main.py
This is better as serving static files is much easier when it is done for you, and it will also not count as much towards your CPU quota.
There is just one warning. You cannot specify a custom error handled in case a file is not found below /static. As soon as a handler picks up on a url, it will try to finish the request. If the static dir handler cannot find the url, it will not hand control back to main.py, which is now your wildcard solution. It will simply return the default 404 error page from appengine.
SOLUTION 2: Serve static files from your application
If you really must create a custom 404 page for your static you have to do it in your application. (I do not advice you to do so, in case that's not clear.) In that case you were on the right track. You should create an extra handler like in your example. Just rewrite one line:
path = os.path.join(os.path.dirname(__file__), 'static', q)
In you application line, add your handler like this:
('/static/(.*)?', MainHandler),
If the file is not found, you should call self.response.set_status(404) and write whatever custom response message you need.
I'm just now digging into GAE and I see two ways to make a particular URL pull up the right page.
The first way is using handlers:
handlers:
- url: /.*
script: helloworld.py
The other way is using the following:
application = webapp.WSGIApplication(
[('/', MainPage),
('/sign', Guestbook)],
debug=True)
Which is better or which is right? I don't fully understand what the second example is doing exactly.
You need to use both. The section in app.yaml tells App Engine where to look for your WSGI application. application = webapp.WSGIApplication(...) sets up your WSGI application using the webapp framework.
update:
app.yaml:
handlers:
- url: /city.*
script: cityhandler.py
cityhandler.py
application = webapp.WSGIApplication([('/city', ShowCityPage)],
debug=True)