Setting a default route in bottle?

1,922 views
Skip to first unread message

pgoetz

unread,
Sep 27, 2011, 2:28:25 PM9/27/11
to bottlepy
In order to facilitate graceful recovery from both bugs and bad user
input, I usually set up a default route for a given URL:

http://xxx.yyy.com/widget-finger[&/]garbage -->
http://xxx.yyy.com/widget-finger/index.html

How would you do this in bottle?

Juan Carlos Ojeda

unread,
Sep 27, 2011, 2:50:22 PM9/27/11
to bott...@googlegroups.com

--
You are member of the "bottlepy" group at google groups.
See http://groups.google.de/group/bottlepy for mailing list options.
See http://bottlepy.org/ for news and documentation.

a wildcard * ?, i think i dont understand...

--
.

pgoetz

unread,
Sep 27, 2011, 3:12:10 PM9/27/11
to bottlepy


On Sep 27, 1:50 pm, Juan Carlos Ojeda <juancarlosp...@gmail.com>
wrote:
> a wildcard * ?, i think i dont understand...
>

This would be OK if I know that the routes are looked at in order.
Suppose

http://xxx.yyy.com/widget-finder/index.html is the default screen for
this application.

I want

http://xxx.yyy.com/widget-finder/retrieve/1298
http://xxx.yyy.com/widget-finder/display&id=146
http:/xxx.yyy.com/widget-finder/help
http:/xxx.yyy.com/widget-finder/display&id=146;partno=15
http:/xxx.yyy.com/widget-finder/search&string=large%20purple%20widget

to do some specific useful things and return relevant content.

If the browser sends something like

http:/xxx.yyy.com/widget-finder/random_junk&xyz=123

which doesn't match any other route decorator, then I want the
application to respond as if the browser had sent a request for

http://xxx.yyy.com/widget-finder/index.html

Does this make sense?

Michael P. Soulier

unread,
Sep 27, 2011, 3:59:25 PM9/27/11
to bott...@googlegroups.com
On 27/09/11 pgoetz said:

> I want
>
> http://xxx.yyy.com/widget-finder/retrieve/1298
> http://xxx.yyy.com/widget-finder/display&id=146
> http:/xxx.yyy.com/widget-finder/help
> http:/xxx.yyy.com/widget-finder/display&id=146;partno=15
> http:/xxx.yyy.com/widget-finder/search&string=large%20purple%20widget
>
> to do some specific useful things and return relevant content.
>
> If the browser sends something like
>
> http:/xxx.yyy.com/widget-finder/random_junk&xyz=123
>
> which doesn't match any other route decorator, then I want the
> application to respond as if the browser had sent a request for
>
> http://xxx.yyy.com/widget-finder/index.html
>
> Does this make sense?

Can you put a catch-all pattern last to do this?

Mike

Iuri

unread,
Sep 27, 2011, 4:04:51 PM9/27/11
to bott...@googlegroups.com
If url doesn't any route, you just need to catch it with an error route:

@error(404)
def error_route(code):
    redirect('/index')

It is a route to any 404 error, redirecting to /index. Just use it how you want.

cheers,
iuri

pgoetz

unread,
Oct 4, 2011, 6:02:32 PM10/4/11
to bottlepy
On Sep 27, 3:04 pm, Iuri <iurisil...@gmail.com> wrote:
> If url doesn't any route, you just need to catch it with an error route:
>
> @error(404)
> def error_route(code):
>     redirect('/index')
>

Except that ... this doesn't appear to work?

Below is my code:
========================
import bottle

@bottle.route('/')
@bottle.route('/index')
def hello():
return("Welcome to Rolodex3000")

@bottle.error(404)
def error_route(code):
bottle.redirect('/index')


bottle.debug(True)
bottle.run(reloader=True)
========================

This is what I get when I enter the URL: http://localhost:8080/foo

Critical error while processing request: /foo
Error:

HTTPResponse('HTTP Response 303',)

Traceback:

Traceback (most recent call last):
File "/local/lib/python2.6/bottle-0.9.6-py2.6.egg/bottle.py", line
736, in wsgi
out = self._cast(out, request, response)
File "/local/lib/python2.6/bottle-0.9.6-py2.6.egg/bottle.py", line
688, in _cast
out = self.error_handler.get(out.status, repr)(out)
File "r.py", line 10, in error_route
bottle.redirect('/index')
File "/local/lib/python2.6/bottle-0.9.6-py2.6.egg/bottle.py", line
1430, in redirect
raise HTTPResponse("", status=code,
header=dict(Location=location))
HTTPResponse: HTTP Response 303

Iuri

unread,
Oct 4, 2011, 6:23:00 PM10/4/11
to bott...@googlegroups.com
Wow! It is a huge bug. =)

I'm sure it should not happen. I reported it here: https://github.com/defnull/bottle/issues/236

[]s
iuri

pgoetz

unread,
Oct 5, 2011, 1:17:30 PM10/5/11
to bottlepy
On Oct 4, 5:23 pm, Iuri <iurisil...@gmail.com> wrote:
> Wow! It is a huge bug. =)
>
> I'm sure it should not happen. I reported it here:https://github.com/defnull/bottle/issues/236
>

I found this in the release notes for 0.8:

o The default redirect() code changed from 307 to 303.
o Removed support for @default. Use @error(404) instead.

However, if I run ipython
import bottle
app = bottle.Bottle()

help app

redirect doesn't show up in the list of methods.

If I use
app.redirect('/index')

I get this error:
AttributeError("'Bottle' object has no attribute 'redirect'",)

If however I use
bottle.redirect('/index')
(in the same application)
I get:
HTTPResponse('HTTP Response 303',)

not sure what to make of all this, but having a default route is a
critical feature for most apps.

Marcel Hellkamp

unread,
Oct 5, 2011, 5:00:26 PM10/5/11
to bott...@googlegroups.com
Am 05.10.2011 19:17, schrieb pgoetz:
> On Oct 4, 5:23 pm, Iuri <iurisil...@gmail.com> wrote:
>> Wow! It is a huge bug. =)
>>
>> I'm sure it should not happen. I reported it here:https://github.com/defnull/bottle/issues/236

Raising exceptions in an error handler is currently not allowed. It is
an implementation detail and we might/should get rid of it, but
currently there is no way to use redirect() (which raises HTTPResponse)
within an error handler. You can, however, manually set the location
header and status code for a redirect (as a workaround):

response.set_header('location', '...')
response.status = 303

> I found this in the release notes for 0.8:
>
> o The default redirect() code changed from 307 to 303.
> o Removed support for @default. Use @error(404) instead.
>
> However, if I run ipython
> import bottle
> app = bottle.Bottle()
>
> help app
>
> redirect doesn't show up in the list of methods.

redirect() is a module-level helper (see static_file() and abort() for
other examples). These are relicts from very early versions of bottle
and might seem counter-intuitive to new users. I'll keep that in mind
and try to find a better, more intuitive API.

> not sure what to make of all this, but having a default route is a
> critical feature for most apps.

The order of routes is significant. They are checked in order. If you
want a catchall route, just add it last. For example: @route('/:#.*#',
method='ANY') matches any request that is not handled by a previous route.

pgoetz

unread,
Oct 5, 2011, 5:48:57 PM10/5/11
to bottlepy
On Oct 5, 4:00 pm, Marcel Hellkamp <m...@gsites.de> wrote:
> The order of routes is significant. They are checked in order. If you
> want a catchall route, just add it last. For example: @route('/:#.*#',
> method='ANY') matches any request that is not handled by a previous route.

Thanks! This the answer I was looking for when I first posted this
question.... and it works.

This raises another question that probably just speaks to the fact
that I am a python neophyte. Suppose I set up this route first:

@bottle.route('/')
@bottle.route('/index.html')
def intro_interface():
stuff
more stuff
goodies

... some other routes here ....

Can I then end the file containing the routes like this?

@bottle.route('/:#.*#',method='ANY')
intro_interface()

In particular, I guess the question is are all the route methods
compiled and available each time the application is accessed? Not
sure yet how useful this is, but this would then also allow stuff like
this:

@bottle.route(/foo)
def func(a,b,c):
stuff
etc

@bottle.route(/bar)
func(a/2,x,y)




Branko Vukelić

unread,
Oct 5, 2011, 6:08:40 PM10/5/11
to bott...@googlegroups.com
On 2011-10-05 14:48 -0700, pgoetz wrote:

It's been a while, but, can't you do this instead?

> @bottle.route('/')
> @bottle.route('/index.html')

> @bottle.route('/:#.*#',method='ANY')

> def intro_interface():
> stuff
> more stuff
> goodies

Also I believe the proper way is to say:


> @bottle.route('/:#.*#',method='ANY')

> intro_interface # w/o the `()`

The short version of what decorator (i.e., `@blah` thingy) does in
Python is this:

def myfunc():
# blah

def mydecorator(func):
# do something to func
return decorated_func

myfunc = mydecorator(myfunc)

So, instead of a function call `myfunc()`, you pass the function object
`myfunc`, and the decorator returns a function object. When using the
decorator syntax, the above looks like this:

@mydecorator
def myfunc():
# blah

and it does the exact same thing (unless I forgot how to Python).


--
Branko Vukelic
bra...@brankovukelic.com
bra...@herdhound.com

IDEA MACHINE
www.brankovukelic.com

Lead Developer
Herd Hound (tm) - Travel that doesn't bite
www.herdhound.com

Love coffee? You might love Loveffee, too.
loveffee.appspot.com

Peter Froehlich

unread,
Oct 5, 2011, 6:12:56 PM10/5/11
to bott...@googlegroups.com
On Wed, Oct 5, 2011 at 5:00 PM, Marcel Hellkamp <ma...@gsites.de> wrote:
> redirect() is a module-level helper (see static_file() and abort() for
> other examples). These are relicts from very early versions of bottle
> and might seem counter-intuitive to new users. I'll keep that in mind
> and try to find a better, more intuitive API.

I plan on using bottle.py as a web framework for an intro-level
programming course. I like the fact that I don't have to use classes
at all and can do simple apps just with functions. So keeping the
"module-level helpers" would be much appreciated. Just my $0.02 of
course. :-D Oh, and note that I wouldn't mind if they were put into a
different module/namespace, I can explain *that* to the students just
fine.
--
Peter H. Froehlich <http://www.cs.jhu.edu/~phf/>
Senior Lecturer | Director, Johns Hopkins Gaming Lab

Marcel Hellkamp

unread,
Oct 5, 2011, 6:20:42 PM10/5/11
to bott...@googlegroups.com
Am 06.10.2011 00:08, schrieb Branko Vukelić:
> On 2011-10-05 14:48 -0700, pgoetz wrote:
>
> It's been a while, but, can't you do this instead?
>
>> @bottle.route('/')
>> @bottle.route('/index.html')
>> @bottle.route('/:#.*#',method='ANY')
>> def intro_interface():
>> stuff
>> more stuff
>> goodies

Be careful: Decorators are applied in reverse order and the catch-all
route is created first in your example.

> Also I believe the proper way is to say:
>> @bottle.route('/:#.*#',method='ANY')
>> intro_interface # w/o the `()`

No, decorators only work with def-blocks. But you can do this:

bottle.route('/:#.*#', method='ANY', callback=intro_interface)
or shorter: bottle.route('/:#.*#', 'ANY', intro_interface)

Greg Stein

unread,
Oct 5, 2011, 8:26:57 PM10/5/11
to bott...@googlegroups.com
On Wed, Oct 5, 2011 at 18:12, Peter Froehlich
<peter.hans...@gmail.com> wrote:
> On Wed, Oct 5, 2011 at 5:00 PM, Marcel Hellkamp <ma...@gsites.de> wrote:
>> redirect() is a module-level helper (see static_file() and abort() for
>> other examples). These are relicts from very early versions of bottle
>> and might seem counter-intuitive to new users. I'll keep that in mind
>> and try to find a better, more intuitive API.
>
> I plan on using bottle.py as a web framework for an intro-level
> programming course. I like the fact that I don't have to use classes
> at all and can do simple apps just with functions. So keeping the
> "module-level helpers" would be much appreciated. Just my $0.02 of
> course. :-D Oh, and note that I wouldn't mind if they were put into a
> different module/namespace, I can explain *that* to the students just
> fine.

Hmm? They're already in the "bottle" namespace. You have to do extra
work to bring them into your own namespace.

ie. the difference between:

import bottle
...
bottle.redirect(...)

and:

from bottle import redirect
...
redirect(...)


In my experience, the "from MOD import NAME" syntax is problematic for
various reasons. I always stick to pure "import MOD".

Cheers,
-g

Peter Froehlich

unread,
Oct 5, 2011, 9:04:55 PM10/5/11
to bott...@googlegroups.com
On Wed, Oct 5, 2011 at 8:26 PM, Greg Stein <gst...@gmail.com> wrote:
> Hmm? They're already in the "bottle" namespace. You have to do extra
> work to bring them into your own namespace.

LOL, sorry for the confusion. I meant "if you are about to rip them
out, maybe put them into another namespace instead because I like
using bottle without having to explain classes/objects to my
students". That's all. And yes, I don't teach "from X import Y" at
all. :-D

Marcel Hellkamp

unread,
Oct 6, 2011, 4:34:11 AM10/6/11
to bott...@googlegroups.com
Am 06.10.2011 03:04, schrieb Peter Froehlich:
> On Wed, Oct 5, 2011 at 8:26 PM, Greg Stein <gst...@gmail.com> wrote:
>> Hmm? They're already in the "bottle" namespace. You have to do extra
>> work to bring them into your own namespace.
>
> LOL, sorry for the confusion. I meant "if you are about to rip them
> out, maybe put them into another namespace instead because I like
> using bottle without having to explain classes/objects to my
> students". That's all. And yes, I don't teach "from X import Y" at
> all. :-D

Bottle is fully backwards compatible for at least one release. Don't
worry :) And I don't plan to remove them, just turn them into shortcuts
for more suitable methods on BaseRequest or Bottle. We'll see.

pgoetz

unread,
Oct 6, 2011, 1:08:54 PM10/6/11
to bottlepy
On Oct 5, 5:08 pm, Branko Vukelić <bra...@brankovukelic.com> wrote:
> It's been a while, but, can't you do this instead?
>
> > @bottle.route('/')
> > @bottle.route('/index.html')
> > @bottle.route('/:#.*#',method='ANY')
> > def intro_interface():
> >     stuff
> >     more stuff
> >     goodies
>

The problem with this is you won't ever get to any other subsequent
routes, since the @bottle.route('/:#.*#',method='ANY') will swallow
every other possible route; this is why I had it using the same
function at the end of the list of all route decorators/function def-
blocks.

Also, I'm taking this comment

On Oct 5, 5:20 pm, Marcel Hellkamp <m...@gsites.de> wrote:
> No, decorators only work with def-blocks. But you can do this:
>

to mean that this:

@route(/foo)
def func(a,b,c):

@route(/bar)
func(x,y,z)

does NOT work. I guess this means that part of the application design
is making sure you choose URL's that do not require repeating function
def-blocks with different routes.



Reply all
Reply to author
Forward
0 new messages