New to python. I am using bottle.py as a web server.
I have a set of static HTML files that need to be rendered on different routes. I am using static_file() function for the same. I also want to set a session based cookie for the page. SO I am using response.set_cookie().
But it turns out that when I am returning a static_file the cookie is never set. However if I change the response to a simple string, set_cookie() works fine. Can anyone explain why? And how can I fix this?
#app.route("/index")
def landingPage():
response.set_cookie("bigUId", "uid12345")
# return "Hello there"
return static_file("/html/index.html", root=config.path_configs['webapp_path'])
Welcome to Bottle and to Python. :)
Looking at the Bottle source code, the problem is readily apparent. Look how static_file ends:
def static_file(...):
...
return HTTPResponse(body, **headers)
static_file creates a new HTTPResponse object--so any headers you've set before then will be discarded.
A very simple way around this is to set the cookies after you call static_file, like this:
#app.route("/index")
def landingPage():
resp = static_file("/html/index.html", root=config.path_configs["webapp_path"])
resp.set_cookie("bigUId", "uid12345")
return resp
I just tried it, and it works perfectly. Good luck!
Well, I just tried, indeed it's not working, I never tried to use cookie with a static_file() before ... However, you can do the following to return a static file as a template, and the cookie will be set :
Your routing function :
#route('/test')
def cookie_test():
response.set_cookie("test", "Yeah")
return template('template/test.html')
And for this to work, you'll need to define a route for /template this way :
#route('/template/<filepath:path>')
def server_static(filepath):
return static_file(filepath, root="./template")
(Obviously, change "/template" to whatever you need according to your project path !)
I'm doing it this way, and it's working fine ! I'm not sure why it doesn't work when you try to set a cookie with static_file(), it might come from the fact that IT IS a static file that you're serving, or whatever, I really don't know.
Also, using the template() function in order to server a "static" html page might not be the right way to do it, but I'm personnaly doing it since a while, and I've never had any issue with this.
Hope it helps !
Related
I am working off of Safari's Pyramid tutorial
WEB APPLICATIONS WITH PYTHON AND THE PYRAMID FRAMEWORK
Inside of my views.py file I having a problem with the following code:
#property
def current(self):
todo_id = self.request.matchdict.get('id')
todo = sample_todos.get(todo_id)
if not todo:
raise HTTPNotFound()
return todo
particularly when the following view function calls this property
#view_config(route_name='view', renderer='templates/view.jinja2')
def view(self):
return dict(todo=self.current)
when I am running the application http://0.0.0.0:6543/5 will not trigger the anticipated HTTPNotFound(), see route below.
config.add_route('view', '/{id}')
the error logs return:
File "/Users/alex/zdev/t-oreilly/mysite/views.py", line 50, in view
return dict(todo=self.current)
File "/Users/alex/zdev/t-oreilly/mysite/views.py", line 25, in current
raise HTTPNotFound()
pyramid.httpexceptions.HTTPNotFound: The resource could not be found.
On the browser waitress returns a default server error.
What is the proper way to remove this error?
I have uploaded this work to github, commit aaf562e
the tutorial link is here, for those eager to help, it can be accessed with their 10 day trial. This problem is from video 17/48.
thank you, if you need additional information please let me know.
This is a different HTTPNotFound exception and it is raised at the route-matching step before your view is even executed. The reason is that you have config.add_route('view', '/{id}'). Note the /{id} NOT /{id}/. Pyramid considers these two different routes and thus the latter does not match. The simplest solution to this is to register all of our canonical routes with a / suffix such as /{id}/ and then pass append_slash=True to your notfound view configuration such as config.add_notfound_view(..., append_slash=True) or #notfound_view_config(append_slash=True). This will trigger a redirect when a user visits the version without the trailing slash.
In two of your Jinja templates you reference the #property view.current. However, since the property throws an HTTPNotFound() exception, your Jinja templates end up hitting that and explode, causing your problem.
Either remove the calls to view.current from your Jinja templates or modify your view.current function so that it doesn't throw.
I'm not sure if this is the solution you are looking for, but it doesn't deviate from the tutorial.
I'm attempting to make a modular pyramid application by including a callable containing several config.add_route functions. In my init.py:
def devices_include(config):
config.add_route("devices.collection", "/")
config.add_route("devices.single", "/{device_id}")
...
def main(global_config, **settings):
...
config.include(devices_include, route_prefix="/devices")
This code works, meaning when I go to /devices/ it runs the devices.collection function and when I go to /devices/1 it runs the devices.single function. However, I would like to be able to run the devices.collection function when going to /devices (no trailing slash). How could I do this?
Feel free to dive into https://github.com/Pylons/pyramid/issues/406 and very many linked issues. The short answer is that you'll need to stop using route_prefix if you want it to work or you can do some hacky internal url rewriting. It's a feature under discussion for Pyramid 2.0.
Currently that is not possible, per Michael Merickel answer.
However there is a workaround:
def main(global_config, **settings):
...
config.include(devices_include, route_prefix="/devices")
config.add_route('devices.collection', '/devices')
Notice the last line.
I was trying to experiment with the loadhook function in web.py, however I am not quite able to make it work. Here is my code:
import web
render = web.template.render('templates/')
urls = (
'/(.*)', 'index'
)
class index:
def GET(self, name):
return render.base(name)
def test():
print "damn"
render.base("test")
if __name__ == "__main__":
app = web.application(urls, globals())
app.run()
app.add_processor(web.loadhook(test))
The base.html template is pretty simple which echoes back the "name" parameter.
What I understood from the documentation was that the loadhook function will be called before every request. But it doesn't seem to work. I have tried going to the homepage, another page etc. Neither do I see a print statement on my CMD, nor does the base template with the name test gets executed.
I tried running the same code with just the add_processor as well, but no luck.
Can anyone help me figure out how to run a function before a request happens on a page?
Also, I am assuming request only encompasses browser level requests. Is there any way to capture more via web.py? (such as call a function on keypress, mouse click etc.)
Any help is much appreciated!
loadhooks are called early in the processing and are used to either set configuration or intercept. For example, I implement a black list similar to the following:
def my_hook():
# If requester's IP is in my blacklist, redirect his browser.
if blacklist.in_blacklist(web.ctx.ip) and web.ctx.path != '/blacklist':
raise web.seeother('/blacklist')
....
app.add_processor(web.loadhook(my_hook))
In your example, your test hook calls render (I'm guessing you're trying to render the test page?) Problem is loadhooks don't return data to the browser, so calling render here doesn't do what you want.
Couple other issues: you need to call app.add_processor(web.loadhook(my_hook)) prior to calling app.run(), because the latter sets your polling loop & never returns.
As for your final question: to capture keypresses, etc. you need your javascript to send something to the server.... Everytime there's a keypress, do an ajax call to the server to log the action.
Python's powerful, but still can't read minds.
I am using webpy framework. I want get current request's url in webpy.
please help me, thanks.
Just try printing web.ctx in your controller method and you will see a bunch of environmental variables.
from pprint import pprint
pprint(web.ctx)
So your url probably should be ctx.home + ctx.path + ctx.query or ctx.home + ctx.fullpath.
UPD: You may also take a look at web.url and web.changequery, find them in api docs: http://webpy.org/docs/0.3/api
Is ctx path what you are after?
Data Found in ctx
Request
path – the path requested by the user, relative to the current
application. If you are using subapplications, any part of the url
matched by the outer application will be trimmed off. E.g. you have a
main app in code.py, and a subapplication called admin.py. In code.py,
you point /admin to admin.app. In admin.py, you point /stories to a
class called stories. Within stories, web.ctx.path will be /stories,
not /admin/stories. E.g. /articles/845
I think this is quite an easy question to answer, I just haven't been able to find anywhere detailing how to do it.
I'm developing a GAE app.
In my main file I have a few request handlers, for example:
class Query(webapp.RequestHandler):
def post(self):
queryDOI = cgi.escape(self.request.get('doiortitle'))
import queryCosine
self.response.out.write(queryCosine.cosine(queryDOI))
In that handler there I'm importing from a queryCosine.py script which is doing all of the work. If something in the queryCosine script fails, I'd like to be able to print a message or do a redirect.
Inside queryCosine.py there is just a normal Python function, so obviously doing things like
self.response.out.write("Done")
doesn't work. What should I use instead of self or what do I need to include within my included file? I've tried using Query.self.response.out.write instead but that doesn't work.
A much better, more modular approach, is to have your queryCosine.cosine function throw an exception if something goes wrong. Then, your handler method can output the appropriate response depending on the return value or exception. This avoids unduly coupling the code that calculates whatever it is you're calculating to the webapp that hosts it.
Pass it to the function.
main file:
import second
...
second.somefunction(self.response.out.write)
second.py:
def somefunction(output):
output('Done')