web.py roadmap

118 views
Skip to first unread message

Anand

unread,
Sep 20, 2007, 9:33:42 AM9/20/07
to we...@googlegroups.com

Next release of web.py will be version 0.3. As you number suggests it
will be major release. There will be some changes to API, which
breaks the backward compatability. But I promise, it is not going to
change very much.

Major changes will be
* return instead of print
* moving away from globals
* better db api

Apart from these, the existing subversion repository is be migrated
to bazaar.
From now on, the official repository will be

http://webpy.org/bzr/webpy.dev

Please let me know if you have any suggestions, objections or feature
requests.
Some of these changes(application stuff and return instead of print)
are already checked in, I request you to play with it and let me know
if there are any bugs.

Here is how the new API is going to look like.

## Hello world

`print` will be replaced with `return`.

import web

urls = (
'/(.*)', 'hello'
)

# more about this later
app = web.application(urls, globals())

class hello:
def GET(self, name):
if not name: name = 'world'
return 'Hello,' + name + '!'

if __name__ == "__main__":
app.run()

## database

db configuration will not be global any more. Multiple databases can
be used at the same time and no `web.load()` magic required to make
database work.

import web

db = web.database(dbn='postgres', db='todo', user='you', pw='')

db.select('todo')
db.select('todo', where='id=$id', vars={'id': 2})
db.query('SELECT * FROM todo')

## application
Application is a new way of mapping urls to classes, coming in 0.3.
There will be many different kinds of supported applications.

### web.application
Application to delegate requests based on path.

urls = (
"/hello", "hello",
"/magic/.*", "magic")

app = web.application(urls, globals())

### web.auto_application
Application similar to web.application but urls are constructed
automatiacally using metaclasses.

app = web.auto_application()

class hello(app.page):
def GET(self):
return "hello, world!"

### web.subdir_application
Application to delegate requests based on subdir.
This allows reuse of code easily by taking some exiting app and
mounting it at a directory.

import wiki
import blog
import auth

mapping = (
"/wiki", wiki.app,
"/blog", blog.app,
"/auth", auth.app)

app = web.subdir_application(mapping)

### web.subdomain_application
Application to delegate requests based on host.
This makes virtual hosting very easy.

import mainsite
import usersite

mapping = (
"(www\.)?example.com", mainsite.app,
".*\.example.com", usersite.app
)

app = web.subdomain_application(mapping)

## testing

Testing becomes very easy with applications. Both doctest and
unittest can be used to test web applications.

doctest:

urls = ("/hello", "hello")
app = web.application(urls, globals())

class hello:
"""Hello world example.

>>> response = app.request("/hello")
>>> response.data
'hello, world!'
>>> response.status
'200 OK'
>>> response.headers['Content-Type']
'text/plain'
"""
def GET(self):
web.header('Content-Type', 'text/plain')
return "hello, world!"

unittest:

import unittest
from helloworld import app

class HelloWorldTest(unittest.TestCase):
def testHelloWorld(self):
response = app.request('GET', '/')
self.assertEquals(response.data, 'hello, world!')
self.assertEquals(response.headers['Content-Type'],
'text/plain')
self.assertEquals(response.status, '200 OK')

if __name__ == "__main__":
unittest.main()

## templates

* no whitespace magic
* better error reporting
* should allow template reuse
* Probably use Adam Atlas's implementation

## Contrib

* New module, `web.contrib` with contributed utilities, which are not
part of the web.py core. For example, good auth module (port from
django?) and OpenID support.


Tommi Raivio

unread,
Sep 20, 2007, 10:03:38 AM9/20/07
to we...@googlegroups.com
Nice work. What is the planned release date?

Application objects seem a great idea. I think I have seen too many
ad-hoc implementations already.

I don't think the given examples state this, so -- could we also
introduce a response object that could be explicitly used within the
handler methods? For example:

class hello:
def GET(self):
return web.response()

class again:
def POST(self):
return hello.GET(self)

Anand

unread,
Sep 20, 2007, 10:11:10 AM9/20/07
to we...@googlegroups.com

On 20-Sep-07, at 7:33 PM, Tommi Raivio wrote:

>
> Nice work. What is the planned release date?

That depends on the feedback and feature requests.

> I don't think the given examples state this, so -- could we also
> introduce a response object that could be explicitly used within the
> handler methods?

I don't see any additional additional advantage by doing so?

David Terrell

unread,
Sep 20, 2007, 10:49:36 AM9/20/07
to we...@googlegroups.com
On Thu, Sep 20, 2007 at 07:03:42PM +0530, Anand wrote:
>
>
> Next release of web.py will be version 0.3.
>
> Please let me know if you have any suggestions, objections or feature
> requests.
> Some of these changes(application stuff and return instead of print)
> are already checked in, I request you to play with it and let me know
> if there are any bugs.
>
> Here is how the new API is going to look like.
>
> ## Hello world
>
> `print` will be replaced with `return`.

awesome.

> db = web.database(dbn='postgres', db='todo', user='you', pw='')

awesome.

> ## application
> Application is a new way of mapping urls to classes, coming in 0.3.
> There will be many different kinds of supported applications.
>
> ### web.application
> Application to delegate requests based on path.

awesome.

> ### web.auto_application
> Application similar to web.application but urls are constructed
> automatiacally using metaclasses.

awesome.

> mapping = (
> "/wiki", wiki.app,
> "/blog", blog.app,
> "/auth", auth.app)
>
> app = web.subdir_application(mapping)

SUPER awesome.

> Testing becomes very easy with applications. Both doctest and
> unittest can be used to test web applications.
>
> doctest:

Do I need to say it? Awesome.

> ## templates

I don't use web.template, but I might have to reconsider that now.

> * New module, `web.contrib` with contributed utilities, which are not
> part of the web.py core. For example, good auth module (port from
> django?) and OpenID support.

This is all really great stuff. Stays within the web.py model
of doing things, but makes things much easier to use. Seriously,
I'm excited about this release.

--
David Terrell
d...@meat.net
((meatspace)) http://meat.net/

Aaron Swartz

unread,
Sep 20, 2007, 10:50:29 AM9/20/07
to we...@googlegroups.com
> >>> response.data
> 'hello, world!'

Why'd you change this to .data from .output?

Anand

unread,
Sep 20, 2007, 10:57:48 AM9/20/07
to we...@googlegroups.com

I just though response data/response body sounds better then response
output.
I don't mind changing that to output, if you wish.

Aaron Swartz

unread,
Sep 20, 2007, 11:07:12 AM9/20/07
to we...@googlegroups.com
> I just though response data/response body sounds better then response
> output.
> I don't mind changing that to output, if you wish.

No, I like data; just curious.

bubblboy

unread,
Sep 20, 2007, 11:18:52 AM9/20/07
to we...@googlegroups.com
Anand wrote:
> ## templates
>
> * no whitespace magic
> * better error reporting
> * should allow template reuse
> * Probably use Adam Atlas's implementation

So, I am not exactly familiar with Adam Atlas's implementation, but does
it allow templates to import ("include") other templates?

Aside from that, hurray! Especially the new URL handling looks promising.

b^4

Adam Atlas

unread,
Sep 20, 2007, 11:29:03 AM9/20/07
to we...@googlegroups.com

On 20 Sep 2007, at 09:33, Anand wrote:
> * no whitespace magic

What does that mean?

Just removing the four-space indentation style restriction and any
other whitespace sensitivity where there shouldn't be?

Adam Atlas

unread,
Sep 20, 2007, 11:35:32 AM9/20/07
to we...@googlegroups.com

On 20 Sep 2007, at 11:18, bubblboy wrote:
> So, I am not exactly familiar with Adam Atlas's implementation, but
> does
> it allow templates to import ("include") other templates?

It's not "inclusion" in the style of PHP (where it's treated as
though the included template was placed inline in the containing
template), but it does make the `render` object an automatic global
for templates, so you can use that to easily call other templates.

It currently also supports a sort of inheritance by way of $return. I
think Aaron doesn't like that; I'm still open to other ideas. I was
thinking of adding support for decorators ($@... at the top of the
template, before any $def line), and including an `inherit` decorator
which would also be an automatic global, and would look something
like this:
def inherit(parent, *args, **kwargs):
def dec(func):
def _f(*_args, **kwargs):
return parent(func(*_args, **kwargs), *args, **kwargs)
return _f
return dec

For example, if you have these templates:

#base.html
$def with (body, title)
<title>$title</title>
$:body

#index.html
Hello

Then adding $@inherit(render.base, 'Hi') to the top of index.html
would make it equivalent to calling render.base(render.body(), 'Hi').
(Also equivalent would be adding `$return render.base(self, 'Hi')` to
the bottom.) I suppose we should narrow this down (or at least
standardize on one preferred style) on the principle of "There should
be one -- and preferably only one -- obvious way to do it."

Anand

unread,
Sep 20, 2007, 11:47:49 AM9/20/07
to we...@googlegroups.com
> It currently also supports a sort of inheritance by way of $return. I
> think Aaron doesn't like that; I'm still open to other ideas. I was
> thinking of adding support for decorators ($@... at the top of the
> template, before any $def line), and including an `inherit` decorator
> which would also be an automatic global, and would look something
> like this:
> def inherit(parent, *args, **kwargs):
> def dec(func):
> def _f(*_args, **kwargs):
> return parent(func(*_args, **kwargs), *args, **kwargs)
> return _f
> return dec
>
> For example, if you have these templates:
>
> #base.html
> $def with (body, title)
> <title>$title</title>
> $:body
>
> #index.html
> Hello


The new way to handle this is:

def rendersite(handle):
page = handle()
return render.site(page)

app.add_processor(rendersite)

This passes output of every request through site template.

Adam Atlas, is your implementation available online? Can you share
the url?

Adam Atlas

unread,
Sep 20, 2007, 12:46:28 PM9/20/07
to we...@googlegroups.com

On 20 Sep 2007, at 11:47, Anand wrote:
> The new way to handle this is:
>
> def rendersite(handle):
> page = handle()
> return render.site(page)
>
> app.add_processor(rendersite)
>
> This passes output of every request through site template.

What if you don't want every request to go through the template? (I
can think of many, many instances where that would be the case. AJAX
handlers, API type things, dynamically generated images, and pretty
much anything else that's non-HTML.) And what if you want to pass
some argument to the base template (a page title for instance)?

I've always found it much more natural to handle inheritance on a per-
template basis.

> Adam Atlas, is your implementation available online? Can you share
> the url?

I can't remember where I uploaded the last release. But the svn is
<http://svn.adamatlas.org/TTwain>.

dou...@gmail.com

unread,
Sep 20, 2007, 1:07:36 PM9/20/07
to web.py
Wow, this looks excellent! I look forward to trying it out!

-Dougal

Tommi Raivio

unread,
Sep 20, 2007, 4:24:26 PM9/20/07
to we...@googlegroups.com
Anand wrote:
>> I don't think the given examples state this, so -- could we also
>> introduce a response object that could be explicitly used within the
>> handler methods?
>>
> I don't see any additional additional advantage by doing so?
>
I think I'm just challenging myself to think whether we should reserve
the names `request` and `response` to describe most of what is currently
stuffed in web.ctx. This might make the web.py code itself even more
readable. For example seeing things like

web.request.headers
web.request.body

web.response.headers
web.response.body

within the implementation might be a nice touch.

YMMV.

Green

unread,
Sep 20, 2007, 5:41:26 PM9/20/07
to web.py
Prints become returns
what about web.render using cheetah? does that break too ?

Werner Hartnagel

unread,
Sep 22, 2007, 10:48:07 AM9/22/07
to web.py
Really nice changes.

I just did a checkout of the new code and it seems web.loadhocks
disappear?

web.loadhooks['sessionc'] = connect_storm

AttributeError: 'module' object has no attribute 'loadhooks'

Anand

unread,
Sep 22, 2007, 11:20:37 AM9/22/07
to we...@googlegroups.com

On 22-Sep-07, at 8:18 PM, Werner Hartnagel wrote:
> I just did a checkout of the new code and it seems web.loadhocks
> disappear?
>

We are moving away from using globals.
new way to do that is like this:

app.add_processor(web.loadhook(connect_storm))


Werner Hartnagel

unread,
Sep 22, 2007, 11:53:09 AM9/22/07
to web.py
Thank you for the fast response.

I found already out how to use loadhook now, the new Code is really
good documented - Docstrings everywhere (only still miss it for
forms), great!

My Website still don't run, it seems it isn't Unicode aware?

mod_wsgi (pid=7118): Exception occurred within WSGI script '/home/www/
wpy/main.wsgi'.
[Sat Sep 22 17:46:41 2007] [error] [client 127.0.0.1] Traceback (most
recent call last):
[Sat Sep 22 17:46:41 2007] [error] [client 127.0.0.1] File "/usr/lib/
python2.5/site-packages/web/application.py", line 131, in wsgi
[Sat Sep 22 17:46:41 2007] [error] [client 127.0.0.1] result =
[str(result)]
[Sat Sep 22 17:46:41 2007] [error] [client 127.0.0.1]
UnicodeEncodeError: 'ascii' codec can't encode character u'\\u2192' in
position 203: ordinal not in range(128)

Anand

unread,
Sep 22, 2007, 12:41:39 PM9/22/07
to we...@googlegroups.com

>
> My Website still don't run, it seems it isn't Unicode aware?

Yes it was a bug. Fixed now.

Also to make database work, the following processor must be added to
the application.

def loaddb():
web.db.connect(**web.config.db_parameters)

app.add_processor(web.loadhook(loaddb))


Werner Hartnagel

unread,
Sep 23, 2007, 6:50:19 AM9/23/07
to web.py
Great, its works like a charm now.
Only Sessions don't work, they aren't port to the new codebase, right?

I miss one point on the Roadmap - the date when it may be ready :)

Regarding the docs, it would be great if the docs on the Website
are managed by Version (just like on the Django Website).
That would allow everyone to prepare the docs for upcoming releases.

Anand

unread,
Sep 23, 2007, 11:05:24 AM9/23/07
to we...@googlegroups.com

On 23-Sep-07, at 4:20 PM, Werner Hartnagel wrote:

> Great, its works like a charm now.
> Only Sessions don't work, they aren't port to the new codebase, right?

Not yet. Session code depends on loadhooks, which are now replaced
with app processors.

> I miss one point on the Roadmap - the date when it may be ready :)

I think, the database and application stuff may be ready with in
couple of weeks.
But I am not sure how much the other things.

> Regarding the docs, it would be great if the docs on the Website
> are managed by Version (just like on the Django Website).
> That would allow everyone to prepare the docs for upcoming releases.

Thats a good point.
How about having docs at docs/$version?

bubblboy

unread,
Sep 23, 2007, 11:13:43 AM9/23/07
to we...@googlegroups.com
Anand wrote:
>> Regarding the docs, it would be great if the docs on the Website
>> are managed by Version (just like on the Django Website).
>> That would allow everyone to prepare the docs for upcoming releases.
>
> Thats a good point.
> How about having docs at docs/$version?

I vote aye.

Tzury

unread,
Sep 25, 2007, 4:30:48 AM9/25/07
to web.py
Yet another suggestion,
Today's web.select() returns itterBetter object which behave as
forward-only. This behaviour has advantages and disadvantages (e.g.
accessing the database more than once for the same record-set such as
calling len(list(we.select(...))) for a counter).

May that behaviour can be customized upon function call:
web.select(view_name, where = x, order = y, autoDispose=False)

{
PS
current.web.select() == new.db.select()
}

Tom Berger

unread,
Sep 25, 2007, 4:43:04 AM9/25/07
to we...@googlegroups.com
On 25/09/2007, Tzury <Afro.S...@gmail.com> wrote:

Yet another suggestion,
Today's web.select() returns itterBetter object which behave as
forward-only. This behaviour has advantages and disadvantages (e.g.
accessing the database more than once for the same record-set such as
calling len(list(we.select(...))) for a counter).

May that behaviour can be customized upon function call:
web.select(view_name, where = x, order = y, autoDispose=False)

Why not just do:

results = list(select(...)) in those few cases where you want to have all the items in any order?

--
Tom Berger
http://intellectronica.net/

Tzury

unread,
Sep 25, 2007, 6:02:35 AM9/25/07
to web.py
> Why not just do:
>
> results = list(select(...)) in those few cases where you want to have all
> the items in any order?

I guess my example was bad.

Here is a better one: (real world) case of a result set, which contain
262144 records.
In that case what I do is caching the list(select), and adding
pagination mechanism at client side.

While web.select takes no time,
Calling list(select(...)) means running over all the records just for
casting itterBetter to list.

On new powerful laptop just list(select)) takes about 10 seconds!!

Whereas end user may only use first 2 or 3 pages.

bubblboy

unread,
Sep 25, 2007, 1:44:46 PM9/25/07
to we...@googlegroups.com

Hey,

Perhaps I am a little late with this, perhaps it has already been
mentioned (I could not find it on the list right away, but OK):
something just crossed my mind regarding those returns. Will there still
be yield? That is pretty useful for large HTML pages especially if it is
a collection of smaller parts that each take quite some time to
generate. Anyway, I was just wondering about it.

Greetings,
b^4

Tzury

unread,
Sep 25, 2007, 7:19:06 PM9/25/07
to web.py
> > Why not just do:
>
> > results = list(select(...)) in those few cases where you want to have all
> > the items in any order?
>
> I guess my example was bad.

@Tom + Anand

here is my version:
added self.store[] so instead of raising IndexError, it returns
self.store[i]

# ItterBetter with reverse capabilities

class IterBetter2:
def __init__(self, iterator):
self.i, self.c = iterator, 0
self.store = []

def __iter__(self):
while 1:
x = self.i.next()
self.store.append(x)
yield x
self.c += 1
def __getitem__(self, i):
#todo: slices
if i < self.c:
return self.store[i]
try:
while i > self.c:
x = self.i.next()
self.c += 1
# if this item not in store, add it
if self.c > len(self.store):
self.store.append(x)
# now self.c == i
self.c += 1
self.store.append(self.i.next())
return self.store[i]
except StopIteration:
raise IndexError, str(i)

if __name__ == '__main__':
itr = IterBetter2(iter([x for x in range(12)]))

print itr[3], itr[2], itr[1], itr[0], itr.store

for i in itr:
print i
print itr.store

dou...@gmail.com

unread,
Sep 26, 2007, 12:41:42 AM9/26/07
to web.py
I agree that this would be useful. I know that I have a lot of cases
where I have to list(select( and it would be nice to be able to skip
that step in a lot of cases.

ambre

unread,
Sep 28, 2007, 3:48:52 AM9/28/07
to web.py

Do you think reading that much data into memory ist good practise.
I don't know which database your are using, but when I need paging,
I'm using OFFSET and LIMIT for the selects. The user can choose how
much rows per page and each request for the next page ist doing like:

web.select('the_table', offset=25, limit=25)

In this case the user has choosen to get 25 rows per page and has
requested the 2'nd page.
Of course you have to pass the offset along with the HTTP-Requests.

RedStalker_Mike

unread,
Sep 28, 2007, 10:05:10 AM9/28/07
to web.py
And what about quoting of SQL queries and results? Will it be added?

Mike Grozak

unread,
Sep 28, 2007, 5:52:05 PM9/28/07
to web.py
Sorry ) I want to know about escaping, not about quoting...

2007/9/28, RedStalker_Mike <mgr...@gmail.com>:

And what about quoting of SQL queries and results? Will it be added?



--
WBR, Mike Grozak

Bjorn Tipling

unread,
Sep 28, 2007, 7:15:04 PM9/28/07
to we...@googlegroups.com
Anyone in here use Berkely DB much? I use that instead of an SQL database. If there were a web.py interface to it, how would you imagine it would be implemented? I've sort of created my own abstraction layer, and I store serialized objects for the most part. Is there any interest in that?

Angelo Gladding

unread,
Sep 28, 2007, 11:40:38 PM9/28/07
to we...@googlegroups.com
My suggestion for the doc versioning hierarchy would be to branch modules & methods while updating their descriptions with deprecations and/or changes. The resulting doc namespace could look something like this:

/
doc/
book
ref/
abridged
db
db/
...
query
#.3
#.22
#.21
select
update
...
forms
utils
utils/
...
dateify
numify
storify
...

borrowed from Python's docs (note the change mentioned for Try: functionality in Python 2.5; http://docs.python.org/ref/try.html)

`/doc/ref/abridged` would be the current doc page. `/doc/ref/db` would be a summary page with link for direct download of module, link for browsing source code directly, a short summary, a list of supported DBMSes, the methods found within, etc. `/doc/book` would be a table of contents for a readable walkthrough of web.py. I believe Anand mentioned wanting a book of some sort. Branching into `/doc/ref` allows for the book to contain non-referential material maintained within the wiki that are sure not to have a name conflict. Examples would be tutorials or common idioms.

Let me know what you guys think. I'll do the grunt work if this reaches consensus.

Angelo

Sam

unread,
Oct 18, 2007, 6:57:21 AM10/18/07
to web.py
I couldn't find this anywhere obvious so I put it here:
http://webpy.org/roadmap

Helpful?

Sam.

Berwyn Hoyt

unread,
Oct 18, 2007, 5:12:02 PM10/18/07
to we...@googlegroups.com
Yes, very helpful, thank you. You might want to link it from the
sidebar or docs page.

Gopnic

unread,
Oct 30, 2007, 6:15:51 PM10/30/07
to web.py
Pardon me for my english.

What about some kind of page controller's arguments processor?
For example something like that:

from myproj.models import ArticleModel

class Home:

@process_arguments (Error404OnFail (ArticleModel), UseDefaultOnFail
(int, 0), str, int)
def GET (s, article, page_number, foo, bar):
...

ArticleModel constructor:
def __init__ (s, row_id=None)

Doing so we initially have in GET method of Home class instance:
article = ArticleModel object that keeps row that was finded by it's
id that was specifed in url
page_number = some integer that was specifed in url or 0 if
transformation of url segment to int raised exception
and so on

Sorry if this is a lame idea, i'm newbie in python programming

Reply all
Reply to author
Forward
0 new messages