widget style: attrs vs. attributes

4 views
Skip to first unread message

Kevin Dangoor

unread,
Feb 7, 2006, 10:28:36 AM2/7/06
to turbo...@googlegroups.com
There are currently 4 people (including myself) actively looking at
the widgets package. I've noticed a little variation in usage that I
wanted to get some consensus on.

Consider this case:
class TextArea(FormField, SimpleWidget):
template = """
<textarea xmlns:py="http://purl.org/kid/ns#"
name="${name}"
class="${field_class}"
id="${field_id}"
rows="${rows}"
cols="${cols}"
py:attrs="attrs"
py:content="value"
/>
"""

template_vars = ["rows", "cols"]

def __init__(self, rows=7, cols=50, **params):
super(TextArea, self).__init__(**params)
self.rows = rows
self.cols = cols

Before I get to my main point, I'd like to mention something I just
noticed: my preference is to have "name" be the first parameter. Like
this:

def __init__(self, name=None, rows=7, cols=50, **params):
super(TextArea, self).__init__(name, **params)

That way, widget users can always do this:

TableForm(widgets = [TextAreaField("foo")])

Is that a bad idea? It's easy to test for.

Now to my main point: the widget above is the way it looks after a
change I made. Previously, it didn't have the template_vars and had an
update_data that looked something like this:

attrs = d["attrs"]
d["rows"] = d[attrs].get(rows, self.rows)
d["cols"] = d[attrs].get(cols, self.cols)

My preference, as you can see above, is for attributes that are
specifically supported in the constructor to be explicitly contained
in the template (as they) and not rely on attrs. With the style that's
committed now, a user can do this:

tf = TextField(rows=5, cols=10)
tf.display(rows=8, cols=39)
or even
tf.display(attrs=dict(rows=10, cols=992))

So, this style is a bit less code (it leverages template_vars), it's
more explicit in the template and it still makes it easy (and
obvious!) for a user to override.

As always, though, I could be missing something, which is why I've
opened it up for discussion.

Kevin

--
Kevin Dangoor
Author of the Zesty News RSS newsreader

email: k...@blazingthings.com
company: http://www.BlazingThings.com
blog: http://www.BlueSkyOnMars.com

Jorge Godoy

unread,
Feb 7, 2006, 11:18:07 AM2/7/06
to turbo...@googlegroups.com
Kevin Dangoor <dan...@gmail.com> writes:

I like it.

> Now to my main point: the widget above is the way it looks after a
> change I made. Previously, it didn't have the template_vars and had an
> update_data that looked something like this:
>
> attrs = d["attrs"]
> d["rows"] = d[attrs].get(rows, self.rows)
> d["cols"] = d[attrs].get(cols, self.cols)

This makes it possible to work around IndexErrors if there's no default... If
every option is going to have a default value, then there's no problem with
the change, but if this isn't the case, some_dict.get('key') returns None if
there's no 'key' in the dictionary. Of course, you know that, but it is
something worth noting.

The above may helps a novice to provide defaults and be a bit more safe than
in your code, but your code is cleaner than this, making it easier to read.

> My preference, as you can see above, is for attributes that are
> specifically supported in the constructor to be explicitly contained
> in the template (as they) and not rely on attrs. With the style that's

I believe attrs should be used just for excetions and not for every
attribute. What is an exception or not is open to debate, but anything
required for making the widget work is essential, plus CSS class, everything
else should be an exception.

So, I'd make it default: id, name and class for all widgets.

> committed now, a user can do this:
>
> tf = TextField(rows=5, cols=10)
> tf.display(rows=8, cols=39)
> or even
> tf.display(attrs=dict(rows=10, cols=992))

If both styles work, I believe we're good with flexibility!

> So, this style is a bit less code (it leverages template_vars), it's more
> explicit in the template and it still makes it easy (and obvious!) for a
> user to override.

I believe that we have to make it easier for the user -- developers using TG
-- not TG developers ;-) As said, one will write a widget once and use it
many times. If we make this "once" a bit (not too much!) harder to make the
"many times" easier, that will be "a good thing"(TM)


--
Jorge Godoy <jgo...@gmail.com>

Alberto

unread,
Feb 7, 2006, 11:22:51 AM2/7/06
to TurboGears
Kevin Dangoor wrote:
> Before I get to my main point, I'd like to mention something I just
> noticed: my preference is to have "name" be the first parameter. Like
> this:
>
> def __init__(self, name=None, rows=7, cols=50, **params):
> super(TextArea, self).__init__(name, **params)
>
> That way, widget users can always do this:
>
> TableForm(widgets = [TextAreaField("foo")])
>
> Is that a bad idea? It's easy to test for.


Just a matter of style... I personally favour named arguments, though
more verbose, for something like this, where we have multiple levels of
inheritance and parameters accepted at various layers.

Anyway, what it's absolutely clear is that we need some consensus as to
avoid the kind of bugs fixed at r660. :)

I also think we should apply Michele's suggestion (#490, try finding
"CalendarDatePicker" at the page if you don't want to get booored... ;)
of listing at the constructor of our Widget subclasses all the
parameters of our superclass (plus the new ones we are taking) to avoid
**kw abuse (and possible bugs). Though if were subclassing more than
one superclass this might not apply... (as most of the widgets at
forms.py which subclass FormWidget and SimpleWidget).

Example (from r694):

class Widget(object):
def __init__self, name=None, template=None, default=None,
validator=None):

class SimpleWidget(Widget):
def __init__(self, name=None, template=None, default=None,
validator=None,
attrs=None, **kw):
super(SimpleWidget, self).__init__(
name, template, default, validator, **kw)

This way it's easier to spot which parameters we have available for
override or to initialize or custom widget.

> Now to my main point: the widget above is the way it looks after a
> change I made. Previously, it didn't have the template_vars and had an
> update_data that looked something like this:
>
> attrs = d["attrs"]
> d["rows"] = d[attrs].get(rows, self.rows)
> d["cols"] = d[attrs].get(cols, self.cols)
>
> My preference, as you can see above, is for attributes that are
> specifically supported in the constructor to be explicitly contained
> in the template (as they) and not rely on attrs. With the style that's
> committed now, a user can do this:
>
> tf = TextField(rows=5, cols=10)
> tf.display(rows=8, cols=39)
> or even
> tf.display(attrs=dict(rows=10, cols=992))
>
> So, this style is a bit less code (it leverages template_vars), it's
> more explicit in the template and it still makes it easy (and
> obvious!) for a user to override.
>

Agree, this way you don't need to traverse __init__ and update_data at
all the levels of inheritance to see where variables are "picked up"
for insertion in the template.

For example, if you see template_vars = ["name"] at Widget, you'll know
that everything that inherits from Widget (all widgets ;) will have
their name available at the template, same goes for "field_class" and
"field_id" at FormField, etc... You also know that it's the item of
least preference (can be overriden at the constructor OR at display
time). Standard behaviour for all widgets and no need to read
update_data (from potentially a couple of base classes) to see in which
order they are inserted at the template... (well, you still have to
read "template_vars", but that's better than following various ifs,
elifs and elses ;)

my 2 cents,

Regards,
Alberto

Kevin Dangoor

unread,
Feb 7, 2006, 11:29:23 AM2/7/06
to turbo...@googlegroups.com
On 2/7/06, Alberto <alb...@toscat.net> wrote:

>
> Kevin Dangoor wrote:
> > That way, widget users can always do this:
> >
> > TableForm(widgets = [TextAreaField("foo")])
>
> Just a matter of style... I personally favour named arguments, though
> more verbose, for something like this, where we have multiple levels of
> inheritance and parameters accepted at various layers.

To be clear: this is strictly for the "name" parameter. It's used on
every form input field, which is why I think it deserves somewhat
special treatment.

> I also think we should apply Michele's suggestion (#490, try finding
> "CalendarDatePicker" at the page if you don't want to get booored... ;)
> of listing at the constructor of our Widget subclasses all the
> parameters of our superclass (plus the new ones we are taking) to avoid
> **kw abuse (and possible bugs). Though if were subclassing more than
> one superclass this might not apply... (as most of the widgets at
> forms.py which subclass FormWidget and SimpleWidget).

Ideally, there wouldn't be **kw at all... but, realistically, the
subclasses need it, otherwise they can't take advantage of new base
class features easily. Widget no longer has **kw, so at least you'll
get an error if you pass in something invalid and it makes it all the
way up.

Kevin

Kevin Dangoor

unread,
Feb 7, 2006, 11:30:05 AM2/7/06
to turbo...@googlegroups.com
On 2/7/06, Jorge Godoy <jgo...@gmail.com> wrote:
> I believe that we have to make it easier for the user -- developers using TG
> -- not TG developers ;-) As said, one will write a widget once and use it
> many times. If we make this "once" a bit (not too much!) harder to make the
> "many times" easier, that will be "a good thing"(TM)

The nice thing is that this is just easier all around... it's more
just getting a consensus on the style.

Kevin

Alberto

unread,
Feb 7, 2006, 11:51:38 AM2/7/06
to TurboGears

Kevin Dangoor wrote:
> To be clear: this is strictly for the "name" parameter. It's used on
> every form input field, which is why I think it deserves somewhat
> special treatment.
>

In this case, sure, why not... +1

> Ideally, there wouldn't be **kw at all... but, realistically, the
> subclasses need it, otherwise they can't take advantage of new base
> class features easily. Widget no longer has **kw, so at least you'll
> get an error if you pass in something invalid and it makes it all the
> way up.
>

Hmmm, didn't think about that one.... and you're right. But what I
mean is that, if posssible, list explicitly all the parameter we *do*
know that our superclass' constructor needs as to aid people following
the code (and ourselves ;) in knowing what's going on.

If a new parameter is added at the superclass', no problem, **kw takes
care of that (And we have time to update our code). If a former
parameter is removed, our code breaks (with a "TypeError: test() got an
unexpected keyword argument 'spam'", which, IMO, is good, as me might
have depended on that functionality which was removed).

Just let's try to be consistent, at least in favor of our own mental
sanity ;)

Alberto

Michele Cella

unread,
Feb 7, 2006, 12:58:33 PM2/7/06
to TurboGears
Kevin Dangoor wrote:
> snip...

>
> tf = TextField(rows=5, cols=10)
> tf.display(rows=8, cols=39)
> or even
> tf.display(attrs=dict(rows=10, cols=992))
>
> So, this style is a bit less code (it leverages template_vars), it's
> more explicit in the template and it still makes it easy (and
> obvious!) for a user to override.
>
> As always, though, I could be missing something, which is why I've
> opened it up for discussion.

That's also the line I've tried to follow (my initial version of
NewWidgets contained cols and rows, dunno when I removed them). :-/

As a guideline I used the w3school and added to the constructor only
the required attributes, so we have cols and rows for a textarea:

http://www.w3schools.com/tags/tag_textarea.asp

For a form we have only action:

http://www.w3schools.com/tags/tag_form.asp

Any other additional attribute is supported using attrs.

Regarding this I think we should really write some guidelines for our
Widgets to follow and to keep consistency, something like "Zen of TG
Widgets":D.

For example:

1) Keep the programming logic out of templates
2) Use template_vars for trivial case
3) If you need new parameters in the constructor always add name as the
first, then your parameters, then **kw and call the super constructor
with (name, **kw)
4) If you are overriding a method remember to always call the super
method before doing anything (since we want to change it's behavior we
should act after it not before)
5) If your widget is simple use the SimpleWidget as a base class
6) If you need to support HTML attributes support only the required one
in the constructor (reference w3schools.org) and the optionals by using
attrs
...

Regarding point number 4) if we agree on this (or the other option of
reporting the entire base class signature) we should update the actual
code.
If 4) is Kevin choice we should revert what Alberto has done (ops,
sorry Alberto :D), probably 4) is better if followed by any one since
it's not such a pain as reporting the entire signature, is less error
prone and does not break with every API change in the widget base class
(I'm already hearing Alberto screaming).

Ciao
Michele

Max Ischenko

unread,
Feb 7, 2006, 1:25:47 PM2/7/06
to TurboGears
Kevin,

Speaking of TextArea, it was me who added rows and cols constructor
arguments to that class today in order to get it to work with new
fastdata. I'm pretty new to widgets (except DataGrid class ;-)) so that
explains the [possible] deviation.

I'm not very familiar with the subject to comment on the rest.

Max.

Alberto Valverde

unread,
Feb 7, 2006, 1:33:29 PM2/7/06
to turbo...@googlegroups.com
On Feb 7, 2006, at 6:58 PM, Michele Cella wrote:

> If 4) is Kevin choice we should revert what Alberto has done (ops,
> sorry Alberto :D), probably 4) is better if followed by any one since
> it's not such a pain as reporting the entire signature, is less error
> prone and does not break with every API change in the widget base
> class
> (I'm already hearing Alberto screaming).
>
> Ciao
> Michele
>

Well, fortunately it wasn't much of a chore either, much easier than
porting all the sample stuff for the browser after missing Kevin's
post in which he said he was redoing all the widget-browser stuff... :)

Alberto

Jorge Godoy

unread,
Feb 7, 2006, 1:34:24 PM2/7/06
to turbo...@googlegroups.com
"Max Ischenko" <isch...@gmail.com> writes:

> Speaking of TextArea, it was me who added rows and cols constructor
> arguments to that class today in order to get it to work with new
> fastdata. I'm pretty new to widgets (except DataGrid class ;-)) so that
> explains the [possible] deviation.

Talking about Datagrid, what's its new syntax? All mine stopped working and I
can't find out where to define these new columns attributes. There's no test
for DataGrid so I couldn't check it. :-(

I used to have:

================================================================================


grid_fornecedores = datawidgets.DataGrid(
fields = [
(lazy_gettext('Fornecedor'), 'nomeAbreviado'),
(lazy_gettext('Contrato assinado em'), grid_contrato_assinatura),
(lazy_gettext(u'Contrato válido até'), grid_contrato_vencimento),
(lazy_gettext('Ativo?'), 'isAtivo'),
],
)
================================================================================

How would I convert it to the new format?

I'm getting the following traceback with this:

================================================================================
Traceback (most recent call last):
File "/usr/lib/python2.4/site-packages/CherryPy-2.2.0beta-py2.4.egg/cherrypy/_cphttptools.py", line 99, in _run
self.main()
File "/usr/lib/python2.4/site-packages/CherryPy-2.2.0beta-py2.4.egg/cherrypy/_cphttptools.py", line 247, in main
body = page_handler(*virtual_path, **self.params)
File "<string>", line 3, in index
File "/home/godoy/desenvolvimento/python/TurboGears/trunk/turbogears/controllers.py", line 188, in expose
func, tg_format, html, fragment, *args, **kw)
File "/home/godoy/desenvolvimento/python/TurboGears/trunk/turbogears/database.py", line 193, in run_with_transaction
retval = func(*args, **kw)
File "/home/godoy/desenvolvimento/python/TurboGears/trunk/turbogears/controllers.py", line 200, in _execute_func
output = errorhandling.try_call(func, self, *args, **kw)
File "/home/godoy/desenvolvimento/python/TurboGears/trunk/turbogears/errorhandling.py", line 64, in try_call
output = dispatch_error(func, self, error, *args, **kw)
File "<string>", line 5, in dispatch_error
File "/home/godoy/desenvolvimento/python/TurboGears/trunk/turbogears/errorhandling.py", line 27, in _default_error_handler
return getattr(self, error_source.__name__ )(*args, **kw)
File "<string>", line 3, in index
File "/home/godoy/desenvolvimento/python/TurboGears/trunk/turbogears/controllers.py", line 183, in expose
output = _execute_func(self, func, tg_format, html, fragment,
File "/home/godoy/desenvolvimento/python/TurboGears/trunk/turbogears/controllers.py", line 200, in _execute_func
output = errorhandling.try_call(func, self, *args, **kw)
File "/home/godoy/desenvolvimento/python/TurboGears/trunk/turbogears/errorhandling.py", line 55, in try_call
output = func(self, *args, **kw)
File "/home/godoy/.eclipse/LATAM/site_amostras/site_amostras/clientes.py", line 60, in index
return self.clientes(cliente_id)
File "<string>", line 3, in clientes
File "/home/godoy/desenvolvimento/python/TurboGears/trunk/turbogears/controllers.py", line 183, in expose
output = _execute_func(self, func, tg_format, html, fragment,
File "/home/godoy/desenvolvimento/python/TurboGears/trunk/turbogears/controllers.py", line 205, in _execute_func
return _process_output(tg_format, output, html, fragment)
File "/home/godoy/desenvolvimento/python/TurboGears/trunk/turbogears/controllers.py", line 68, in _process_output
fragment=fragment)
File "/home/godoy/desenvolvimento/python/TurboGears/trunk/turbogears/view.py", line 60, in render
return engine.render(info, format, fragment, template)
File "/usr/lib/python2.4/site-packages/TurboKid-0.9.0-py2.4.egg/turbokid/kidsupport.py", line 136, in render
return t.serialize(encoding=self.defaultencoding, output=format, fragment=fragment)
File "/home/godoy/desenvolvimento/python/TurboGears/trunk/thirdparty/kid/kid/__init__.py", line 236, in serialize
return serializer.serialize(self, encoding, fragment)
File "/home/godoy/desenvolvimento/python/TurboGears/trunk/thirdparty/kid/kid/serialization.py", line 51, in serialize
text = list(self.generate(stream, encoding, fragment))
File "/home/godoy/desenvolvimento/python/TurboGears/trunk/thirdparty/kid/kid/serialization.py", line 327, in generate
for ev, item in self.apply_filters(stream):
File "/home/godoy/desenvolvimento/python/TurboGears/trunk/thirdparty/kid/kid/serialization.py", line 84, in balancing_filter
for ev, item in stream:
File "/home/godoy/desenvolvimento/python/TurboGears/trunk/thirdparty/kid/kid/pull.py", line 206, in _coalesce
for ev, item in stream:
File "/home/godoy/desenvolvimento/python/TurboGears/trunk/thirdparty/kid/kid/filter.py", line 21, in transform_filter
for ev, item in apply_matches(stream, template, templates, apply_func):
File "/home/godoy/desenvolvimento/python/TurboGears/trunk/thirdparty/kid/kid/filter.py", line 31, in apply_matches
item = stream.expand()
File "/home/godoy/desenvolvimento/python/TurboGears/trunk/thirdparty/kid/kid/pull.py", line 95, in expand
for ev, item in self._iter:
File "/home/godoy/desenvolvimento/python/TurboGears/trunk/thirdparty/kid/kid/pull.py", line 164, in _track
for p in stream:
File "/home/godoy/desenvolvimento/python/TurboGears/trunk/thirdparty/kid/kid/pull.py", line 206, in _coalesce
for ev, item in stream:
File "/home/godoy/.eclipse/LATAM/site_amostras/site_amostras/templates/clientes.py", line 86, in _pull
File "/home/godoy/desenvolvimento/python/TurboGears/trunk/thirdparty/kid/kid/filter.py", line 21, in transform_filter
for ev, item in apply_matches(stream, template, templates, apply_func):
File "/home/godoy/desenvolvimento/python/TurboGears/trunk/thirdparty/kid/kid/filter.py", line 25, in apply_matches
for ev, item in stream:
File "/home/godoy/desenvolvimento/python/TurboGears/trunk/thirdparty/kid/kid/pull.py", line 164, in _track
for p in stream:
File "/home/godoy/desenvolvimento/python/TurboGears/trunk/thirdparty/kid/kid/pull.py", line 206, in _coalesce
for ev, item in stream:
File "/home/godoy/desenvolvimento/python/TurboGears/trunk/turbogears/widgets/templates/datagrid.py", line 31, in _pull
NameError: name 'name' is not defined
================================================================================


TIA,
--
Jorge Godoy <jgo...@gmail.com>

Alberto Valverde

unread,
Feb 7, 2006, 1:53:56 PM2/7/06
to turbo...@googlegroups.com
I've you're looking for the former DataGrid, it's been renamed to
FastDataGrid as Datagrid is being refactored out to remove all model
dependancy.

Alberto

Jorge Godoy

unread,
Feb 7, 2006, 2:05:48 PM2/7/06
to turbo...@googlegroups.com
Alberto Valverde <alb...@toscat.net> writes:

> I've you're looking for the former DataGrid, it's been renamed to
> FastDataGrid as Datagrid is being refactored out to remove all model
> dependancy.

And what is its syntax? :-) 'Cause I get the same error with it as well.

================================================================================
from turbogears.fastdata import datawidgets

grid_clientes = datawidgets.FastDataGrid(
fields = [
(lazy_gettext('Cliente'), 'nomeAbreviado'),


(lazy_gettext('Contrato assinado em'), grid_contrato_assinatura),
(lazy_gettext(u'Contrato válido até'), grid_contrato_vencimento),
(lazy_gettext('Ativo?'), 'isAtivo'),
],
)
================================================================================

and the Traceback:

File "/home/godoy/desenvolvimento/python/TurboGears/trunk/turbogears/fastdata/templates/datagrid.py", line 31, in _pull


NameError: name 'name' is not defined
================================================================================


--
Jorge Godoy <jgo...@gmail.com>

Kevin Dangoor

unread,
Feb 7, 2006, 2:12:58 PM2/7/06
to turbo...@googlegroups.com
On 2/7/06, Alberto <alb...@toscat.net> wrote:
> Hmmm, didn't think about that one.... and you're right. But what I
> mean is that, if posssible, list explicitly all the parameter we *do*
> know that our superclass' constructor needs as to aid people following
> the code (and ourselves ;) in knowing what's going on.

I think that listing all of the superclass' parameters would get quite
tedious very quickly, and is probably not very useful it we can get
PythonDoc to create a link to the superclass __init__.

> Just let's try to be consistent, at least in favor of our own mental
> sanity ;)

That and also to help provide good example code for people writing
their own widgets.

Kevin

Alberto Valverde

unread,
Feb 7, 2006, 2:18:08 PM2/7/06
to turbo...@googlegroups.com
I'm not really sure, but try passing in a name parameter... (which
you really shouldn't, but try, maybe there's a bug...)

Alberto

> turbogears/errorhandling.py", line 55, in try_call
> output = func(self, *args, **kw)
> File "/home/godoy/.eclipse/LATAM/site_amostras/site_amostras/
> clientes.py", line 60, in index
> return self.clientes(cliente_id)
> File "<string>", line 3, in clientes
> File "/home/godoy/desenvolvimento/python/TurboGears/trunk/

> turbogears/controllers.py", line 183, in expose
> output = _execute_func(self, func, tg_format, html, fragment,
> File "/home/godoy/desenvolvimento/python/TurboGears/trunk/

> File "/home/godoy/.eclipse/LATAM/site_amostras/site_amostras/

> templates/clientes.py", line 86, in _pull
> File "/home/godoy/desenvolvimento/python/TurboGears/trunk/

> thirdparty/kid/kid/filter.py", line 21, in transform_filter
> for ev, item in apply_matches(stream, template, templates,
> apply_func):
> File "/home/godoy/desenvolvimento/python/TurboGears/trunk/

> thirdparty/kid/kid/filter.py", line 25, in apply_matches
> for ev, item in stream:
> File "/home/godoy/desenvolvimento/python/TurboGears/trunk/

> thirdparty/kid/kid/pull.py", line 164, in _track
> for p in stream:
> File "/home/godoy/desenvolvimento/python/TurboGears/trunk/

> thirdparty/kid/kid/pull.py", line 206, in _coalesce
> for ev, item in stream:
> File "/home/godoy/desenvolvimento/python/TurboGears/trunk/

Kevin Dangoor

unread,
Feb 7, 2006, 2:22:59 PM2/7/06
to turbo...@googlegroups.com
On 2/7/06, Michele Cella <michel...@gmail.com> wrote:
> As a guideline I used the w3school and added to the constructor only
> the required attributes, so we have cols and rows for a textarea:
>
> http://www.w3schools.com/tags/tag_textarea.asp

I'd actually go farther than that. I think the constructor should
include the "most commonly used" attributes. This will prove helpful
for documentation and is easier for widget users (they'll have to
resort to attrs less).

These seem like a good start to guidelines (except #6, which I talked
about above).

As for #4, I think we can be more explicit that than in suggestions
about overrides. It'd be nice to document how people should override
__init__, display and update_data which are really the main things
that people will need to override.

Kevin

Alberto Valverde

unread,
Feb 7, 2006, 2:23:19 PM2/7/06
to turbo...@googlegroups.com
You're right... forget all that nonsense I was blabbering then
(except the template_vars stuff)... :)

Alberto

P.S.

Grrr... Michele, where are you?!?.... :-D

Jorge Godoy

unread,
Feb 7, 2006, 2:26:00 PM2/7/06
to turbo...@googlegroups.com
Alberto Valverde <alb...@toscat.net> writes:

> I'm not really sure, but try passing in a name parameter... (which you really
> shouldn't, but try, maybe there's a bug...)

Same thing.


grid_clientes = datawidgets.FastDataGrid(
name = 'clientes',


fields = [
(lazy_gettext('Cliente'), 'nomeAbreviado'),
(lazy_gettext('Contrato assinado em'), grid_contrato_assinatura),
(lazy_gettext(u'Contrato válido até'), grid_contrato_vencimento),
(lazy_gettext('Ativo?'), 'isAtivo'),
],
)


--
Jorge Godoy <jgo...@gmail.com>

Kevin Dangoor

unread,
Feb 7, 2006, 2:34:20 PM2/7/06
to turbo...@googlegroups.com
On 2/7/06, Alberto Valverde <alb...@toscat.net> wrote:
> Grrr... Michele, where are you?!?.... :-D

According to #490, he's studying. (Hmm... tracking someone's
whereabouts via Trac seems like a new use case :)

Kevin

Jorge Godoy

unread,
Feb 7, 2006, 2:48:19 PM2/7/06
to turbo...@googlegroups.com
Kevin Dangoor <dan...@gmail.com> writes:

Michele is a 'he' or a 'she'? :-) In pt_BR it is a woman's name.

--
Jorge Godoy <jgo...@gmail.com>

Kevin Dangoor

unread,
Feb 7, 2006, 2:55:57 PM2/7/06
to turbo...@googlegroups.com
On 2/7/06, Jorge Godoy <jgo...@gmail.com> wrote:
>

I think that Michele is a man's name in Europe ("Michelle" is a
woman's name here).

My apologies if I got it wrong...

Kevin

Alberto

unread,
Feb 7, 2006, 3:00:44 PM2/7/06
to TurboGears
Another thing that pops up to my mind is that, as template_vars get
computed using a set (there cannot be duplicates), it wouldn't hurt to
list all the variables which are pulled from the widget instance into
the widget's template, regardless if they're already listed at one of
the bases. Just to be more explicit.

What do you think? (I'm probably smoking crack again on this one...)

Jorge Godoy wrote:
> Michele is a 'he' or a 'she'? :-) In pt_BR it is a woman's name.

I think that in it_IT, he's a 'he' :)

Alberto

Alberto

unread,
Feb 7, 2006, 3:01:32 PM2/7/06
to TurboGears
Well, in fr_FR she'd be a she :)

Leandro Lucarella

unread,
Feb 7, 2006, 3:11:44 PM2/7/06
to turbo...@googlegroups.com
Kevin Dangoor, el martes 7 de febrero a las 14:55 me escribiste:

In general, french names ended by 'e' are for women (I might be wrong,
this is what I recall from my highschool french class =)

And about Michelle, ask the beatles if they were gay ;)

Anyway, I think Michele (one 'l') Cella is italian (because of the "Ciao"
in his mails), so I don't know, (s)he can be a guy...

--
Leandro Lucarella (luca) | Blog colectivo: http://www.mazziblog.com.ar/blog/
.------------------------------------------------------------------------,
\ GPG: 5F5A8D05 // F8CD F9A7 BF00 5431 4145 104C 949E BFB6 5F5A 8D05 /
'--------------------------------------------------------------------'
Oiganmen ñatos de corazón, es más posible que un potus florezca en
primavera a que un ángel pase con una remera.
-- Peperino Pómoro

Kevin Dangoor

unread,
Feb 7, 2006, 3:39:52 PM2/7/06
to turbo...@googlegroups.com
On 2/7/06, Alberto <alb...@toscat.net> wrote:
>
> Another thing that pops up to my mind is that, as template_vars get
> computed using a set (there cannot be duplicates), it wouldn't hurt to
> list all the variables which are pulled from the widget instance into
> the widget's template, regardless if they're already listed at one of
> the bases. Just to be more explicit.
>
> What do you think? (I'm probably smoking crack again on this one...)

Nope, no crack there. You're right... this should more properly be a set.

Kevin

Kevin Dangoor

unread,
Feb 7, 2006, 4:07:23 PM2/7/06
to turbo...@googlegroups.com
On 2/7/06, Kevin Dangoor <dan...@gmail.com> wrote:
> On 2/7/06, Alberto <alb...@toscat.net> wrote:
> > Hmmm, didn't think about that one.... and you're right. But what I
> > mean is that, if posssible, list explicitly all the parameter we *do*
> > know that our superclass' constructor needs as to aid people following
> > the code (and ourselves ;) in knowing what's going on.
>
> I think that listing all of the superclass' parameters would get quite
> tedious very quickly, and is probably not very useful it we can get
> PythonDoc to create a link to the superclass __init__.

By the way, I don't see any need to change the __init__s that
currently explicitly list out parameters. I was just saying that i
don't think it's necessary.

Kevin

Michele Cella

unread,
Feb 7, 2006, 4:24:42 PM2/7/06
to TurboGears

Leandro Lucarella wrote:
> Kevin Dangoor, el martes 7 de febrero a las 14:55 me escribiste:
> >
> > On 2/7/06, Jorge Godoy <jgo...@gmail.com> wrote:
> > >
> > > Kevin Dangoor <dan...@gmail.com> writes:
> > >
> > > > On 2/7/06, Alberto Valverde <alb...@toscat.net> wrote:
> > > >> Grrr... Michele, where are you?!?.... :-D
> > > >
> > > > According to #490, he's studying. (Hmm... tracking someone's
> > > > whereabouts via Trac seems like a new use case :)
> > >
> > > Michele is a 'he' or a 'she'? :-) In pt_BR it is a woman's name.
> >
> > I think that Michele is a man's name in Europe ("Michelle" is a
> > woman's name here).
>
> In general, french names ended by 'e' are for women (I might be wrong,
> this is what I recall from my highschool french class =)
>
> And about Michelle, ask the beatles if they were gay ;)
>
> Anyway, I think Michele (one 'l') Cella is italian (because of the "Ciao"
> in his mails), so I don't know, (s)he can be a guy...
>

Oh my god! LOL

Let's make some points clear:
0- I'm Michele ;-)
1- I'm a "he"
2- I'm italian
3- I will admit that during this delirium (what have you smoked guys?)
I was not studying (as Kevin said) but having fun while playing calcio
AKA football (AKA soccer for Americans, right? even if they suck at
this game :P)
4- I never forced or putted any pressure on Alberto (who started
seeking me) to do any work on the widgets __init__ method. :D

I will add that until now I was a "he" (at least here in Italy) but now
(thanks to you) I'm under and identity crisis for foreign countries.
:-)

>>> Michael (Jordan) is Michele
True
>>> Miguel is Michele
True
>>> Michelle is Michele
False

Let me add that all you guys (as I've already suggested to Alberto on
#490) should use some "good" coffee, that's an italian coffee AKA
"espresso". :P

LOL

Ciao
Michele

Alberto

unread,
Feb 7, 2006, 4:26:45 PM2/7/06
to TurboGears

Kevin Dangoor wrote:
> Nope, no crack there. You're right... this should more properly be a set.
>
> Kevin

I think I haven't explained myself well, I think template_vars should
be remain a list (just to avoid the try/except NameError idiom for 2.3
in every module that implements widgets). The internal implementation
for finding the union of all template_vars from all bases (which uses
set) will take care of removing duplicates...

What I was trying to say is that, being this safety-net in place, maybe
a little extra redundancy when defining template_vars on a custom
widget would not hurt. Ok, maybe a little code will disambiguate my
spaninglish :)

class MyWidget(Widget):
template = """
<tag xmlns:py="http://purl.org/kid/ns#" name="${name}">
<p py:for="i in xrange(count)">I will not repeat myself!</p>
</tag>
""""
template_vars = ["name", "count"]


As "name" is already listed as a template_var at Widget, there's no
real need to list it at this subclass, but, as it's template uses it,
listing it here makes clearer that the variable comes from the widget
instance and that it can be overriden via display() (without even
looking at the template).

The thing is, the more I explain it, the less sure I am about it... :/
Better let the design-gurus decide...

Alberto

Kevin Dangoor

unread,
Feb 7, 2006, 4:31:17 PM2/7/06
to turbo...@googlegroups.com
On 2/7/06, Michele Cella <michel...@gmail.com> wrote:
> 3- I will admit that during this delirium (what have you smoked guys?)
> I was not studying (as Kevin said) but having fun while playing calcio
> AKA football (AKA soccer for Americans, right? even if they suck at
> this game :P)

We actually suck so bad at it, that we took the name "football" and
applied it to a completely different game (the biggest event of which,
for me at least, is a set of commercials shown around the bits of
game).

http://video.google.com/superbowl.html

Well, I'm glad we've all cleared up the relative genders of the
various Michele/Michelles of the world :)

Kevin

Alberto

unread,
Feb 7, 2006, 4:49:51 PM2/7/06
to TurboGears
No, no pressure was put on me... I was just applying a suggestion which
i first thought to be good but then changed my mind and saw it
not-that-good... anyway... please, let's us stop this delirium now and
get to the point... :)

Alberto.

P.S Michele, you should be studying more and playing less Calcio! :D
(BTW: who am I to say *this* to anyone.. ;)

Mike Orr

unread,
Feb 7, 2006, 5:30:42 PM2/7/06
to turbo...@googlegroups.com
On 2/7/06, Leandro Lucarella <lu...@luca.homeip.net> wrote:
>
> Kevin Dangoor, el martes 7 de febrero a las 14:55 me escribiste:
> >
> > On 2/7/06, Jorge Godoy <jgo...@gmail.com> wrote:
> > > Michele is a 'he' or a 'she'? :-) In pt_BR it is a woman's name.
> >
> > I think that Michele is a man's name in Europe ("Michelle" is a
> > woman's name here).
>
> In general, french names ended by 'e' are for women (I might be wrong,
> this is what I recall from my highschool french class =)

Michel is the French male form. Jean-Michel Jarre.

Michelle is the French female form.
Michelle, ma belle, sont des mots qui donc tres bien ensemble.
(No subject there, but I don't hear a subject in the song. Maybe a
dropped "ce" or "c,a"?)

--
Mike Orr <slugg...@gmail.com>
(m...@oz.net address is semi-reliable)

Jorge Godoy

unread,
Feb 7, 2006, 6:51:24 PM2/7/06
to turbo...@googlegroups.com
"Michele Cella" <michel...@gmail.com> writes:

> Oh my god! LOL
>
> Let's make some points clear:
> 0- I'm Michele ;-)

OK. That we know.

> 1- I'm a "he"

Ah! That's the answer for the question! ;-)

> 2- I'm italian

I guessed that. :-)

> 3- I will admit that during this delirium (what have you smoked guys?)

(Wanna have some? ;-))

> I was not studying (as Kevin said) but having fun while playing calcio
> AKA football (AKA soccer for Americans, right? even if they suck at
> this game :P)

(We're going to win the world cup again this year... Six times champions ;-))

> I will add that until now I was a "he" (at least here in Italy) but now
> (thanks to you) I'm under and identity crisis for foreign countries.
> :-)

LOL.

>>>> Michael (Jordan) is Michele
> True
>>>> Miguel is Michele
> True
>>>> Michelle is Michele
> False

:-)

> Let me add that all you guys (as I've already suggested to Alberto on
> #490) should use some "good" coffee, that's an italian coffee AKA
> "espresso". :P

I like espressos. But I just asked if you were "he" or "she"... :-) And it
was before making my coffee. ;-) Now, after the coffee and 2 hours at the
gym, I'm back. ;-)

--
Jorge Godoy <jgo...@gmail.com>

Jorge Godoy

unread,
Feb 7, 2006, 6:52:51 PM2/7/06
to turbo...@googlegroups.com
Kevin Dangoor <dan...@gmail.com> writes:

> We actually suck so bad at it, that we took the name "football" and

I see... You also have problems with English since you play FOOTball with
your HANDS.

> Well, I'm glad we've all cleared up the relative genders of the
> various Michele/Michelles of the world :)

:-) There's this girl at the gym named Michele... She was gorgeous today...
Ops! OK, I won't start it again... ;-)

--
Jorge Godoy <jgo...@gmail.com>

Kevin Dangoor

unread,
Feb 7, 2006, 11:07:08 PM2/7/06
to turbo...@googlegroups.com
On 2/7/06, Alberto <alb...@toscat.net> wrote:
> class MyWidget(Widget):
> template = """
> <tag xmlns:py="http://purl.org/kid/ns#" name="${name}">
> <p py:for="i in xrange(count)">I will not repeat myself!</p>
> </tag>
> """"
> template_vars = ["name", "count"]
>
>
> As "name" is already listed as a template_var at Widget, there's no
> real need to list it at this subclass, but, as it's template uses it,
> listing it here makes clearer that the variable comes from the widget
> instance and that it can be overriden via display() (without even
> looking at the template).

I think I like the way you implemented it, and the lack of a need to
repeat this. This is something to keep in mind for the widget browser:
let *it* figure out which variables are available.

Kevin

Max Ischenko

unread,
Feb 8, 2006, 2:25:27 PM2/8/06
to TurboGears
Hi Jorge,

> Talking about Datagrid, what's its new syntax? All mine stopped working and I
> can't find out where to define these new columns attributes. There's no test
> for DataGrid so I couldn't check it. :-(

There are tests now.

> I used to have:
>
> ================================================================================
>
> grid_fornecedores = datawidgets.DataGrid(
> fields = [
> (lazy_gettext('Fornecedor'), 'nomeAbreviado'),
> (lazy_gettext('Contrato assinado em'), grid_contrato_assinatura),

> (lazy_gettext(u'Contrato valido ate'), grid_contrato_vencimento),


> (lazy_gettext('Ativo?'), 'isAtivo'),
> ],
> )
> ================================================================================
>
> How would I convert it to the new format?

The 'new' syntax is fully compatible with the old one so you don't have
to make any changes unless you're willing to use DataGrid.Column.

> I'm getting the following traceback with this:

> File "/home/godoy/desenvolvimento/python/TurboGears/trunk/turbogears/widgets/templates/datagrid.py", line 31, in _pull


> NameError: name 'name' is not defined

Looks like 'name' is not injected in the template's namespace. Are you
sure
you're using new widgets codebase? Does the tests in widgets/tests/
runs
without errors on your machine?

Jorge Godoy

unread,
Feb 9, 2006, 2:07:50 PM2/9/06
to turbo...@googlegroups.com
"Max Ischenko" <isch...@gmail.com> writes:

> The 'new' syntax is fully compatible with the old one so you don't have
> to make any changes unless you're willing to use DataGrid.Column.

Are there any advantages on that? If not, then I prefer using the simplest
approach.

>> File "/home/godoy/desenvolvimento/python/TurboGears/trunk/turbogears/widgets/templates/datagrid.py", line 31, in _pull
>> NameError: name 'name' is not defined
>
> Looks like 'name' is not injected in the template's namespace. Are you sure
> you're using new widgets codebase? Does the tests in widgets/tests/ runs

There's no call to "oldwidgets" on my code...

> without errors on your machine?

Yes, they do.

================================================================================
godoy@jupiter ~/desenvolvimento/python/TurboGears/trunk/turbogears/widgets % nosetests
................................
----------------------------------------------------------------------
Ran 32 tests in 1.020s

OK
godoy@jupiter ~/desenvolvimento/python/TurboGears/trunk/turbogears/widgets %
================================================================================


But not all tests are OK:

================================================================================
godoy@jupiter ~/desenvolvimento/python/TurboGears/trunk % nosetests
.................../home/godoy/desenvolvimento/python/TurboGears/trunk/turbogears/errorhandling.py:81: DeprecationWarning: Use decorator error_handler on per-method base rather than defining a validation_error method.
DeprecationWarning, 1)
...............................E..E/home/godoy/desenvolvimento/python/TurboGears/trunk/turbogears/tests/form.kid:39: DeprecationWarning: widget.insert should be replaced with widget.display
/home/godoy/desenvolvimento/python/TurboGears/trunk/turbogears/tests/form.kid:50: DeprecationWarning: widget.insert should be replaced with widget.display
/home/godoy/desenvolvimento/python/TurboGears/trunk/turbogears/tests/form.kid:63: DeprecationWarning: widget.insert should be replaced with widget.display
..........................................................
======================================================================
ERROR: test module turbogears.tests.test_i18n in /home/godoy/desenvolvimento/python/TurboGears/trunk
----------------------------------------------------------------------


Traceback (most recent call last):

File "/usr/lib/python2.4/site-packages/nose-0.8.4-py2.4.egg/nose/core.py", line 409, in run
self.setUp()
File "/usr/lib/python2.4/site-packages/nose-0.8.4-py2.4.egg/nose/core.py", line 588, in setUp
self.module = self.loader._import(self.module_name, self.path)
File "/usr/lib/python2.4/site-packages/nose-0.8.4-py2.4.egg/nose/core.py", line 263, in _import
module = nose.importer._import(name, [path])
File "/usr/lib/python2.4/site-packages/nose-0.8.4-py2.4.egg/nose/importer.py", line 64, in _import
mod = load_module(fqname, fh, filename, desc)
File "/home/godoy/desenvolvimento/python/TurboGears/trunk/turbogears/tests/test_i18n.py", line 31, in ?
sogettext.create_so_catalog(["en","fi"], "messages")
File "/home/godoy/desenvolvimento/python/TurboGears/trunk/turbogears/i18n/sogettext/__init__.py", line 58, in create_so_catalog
TG_Message.dropTable(ifExists=True)
File "/home/godoy/desenvolvimento/python/TurboGears/trunk/thirdparty/sqlobject/sqlobject/main.py", line 1308, in dropTable
conn = connection or cls._connection
File "/home/godoy/desenvolvimento/python/TurboGears/trunk/thirdparty/sqlobject/sqlobject/dbconnection.py", line 880, in __get__
return self.getConnection()
File "/home/godoy/desenvolvimento/python/TurboGears/trunk/turbogears/database.py", line 46, in getConnection
raise AttributeError(
AttributeError: No connection has been defined for this thread or process


======================================================================
ERROR: turbogears.tests.test_form_controllers.test_invalid_form_with_error_handling
----------------------------------------------------------------------


Traceback (most recent call last):

File "/usr/lib/python2.4/site-packages/nose-0.8.4-py2.4.egg/nose/core.py", line 113, in runTest
self.testFunc()
File "/home/godoy/desenvolvimento/python/TurboGears/trunk/turbogears/tests/test_form_controllers.py", line 68, in test_invalid_form_with_error_handling
assert root.has_errors
AttributeError: 'MyRoot' object has no attribute 'has_errors'
-------------------- >> begin captured stdout << ---------------------
09/Feb/2006:17:03:30 HTTP INFO Page handler: <bound method MyRoot.testform of <turbogears.tests.test_form_controllers.MyRoot object at 0x40a4e32c>>


Traceback (most recent call last):
File "/usr/lib/python2.4/site-packages/CherryPy-2.2.0beta-py2.4.egg/cherrypy/_cphttptools.py", line 99, in _run
self.main()
File "/usr/lib/python2.4/site-packages/CherryPy-2.2.0beta-py2.4.egg/cherrypy/_cphttptools.py", line 247, in main
body = page_handler(*virtual_path, **self.params)

File "<string>", line 3, in testform
File "/home/godoy/desenvolvimento/python/TurboGears/trunk/turbogears/controllers.py", line 189, in expose


func, tg_format, html, fragment, *args, **kw)
File "/home/godoy/desenvolvimento/python/TurboGears/trunk/turbogears/database.py", line 193, in run_with_transaction
retval = func(*args, **kw)

File "/home/godoy/desenvolvimento/python/TurboGears/trunk/turbogears/controllers.py", line 201, in _execute_func


output = errorhandling.try_call(func, self, *args, **kw)

File "/home/godoy/desenvolvimento/python/TurboGears/trunk/turbogears/errorhandling.py", line 69, in try_call


output = dispatch_error(func, self, error, *args, **kw)
File "<string>", line 5, in dispatch_error

File "/home/godoy/desenvolvimento/python/TurboGears/trunk/turbogears/errorhandling.py", line 28, in _implicit_error_handler


return getattr(self, error_source.__name__ )(*args, **kw)

File "<string>", line 3, in testform
File "/home/godoy/desenvolvimento/python/TurboGears/trunk/turbogears/controllers.py", line 184, in expose


output = _execute_func(self, func, tg_format, html, fragment,

File "/home/godoy/desenvolvimento/python/TurboGears/trunk/turbogears/controllers.py", line 201, in _execute_func


output = errorhandling.try_call(func, self, *args, **kw)

File "/home/godoy/desenvolvimento/python/TurboGears/trunk/turbogears/errorhandling.py", line 58, in try_call


output = func(self, *args, **kw)

File "<string>", line 3, in testform
File "/home/godoy/desenvolvimento/python/TurboGears/trunk/turbogears/controllers.py", line 127, in validate
return errorhandling.run_with_errors(errors, func, self, *args, **kw)
File "/home/godoy/desenvolvimento/python/TurboGears/trunk/turbogears/errorhandling.py", line 88, in run_with_errors
output = dispatch_error(func, self, errors, *args, **kw)


File "<string>", line 5, in dispatch_error

File "/home/godoy/desenvolvimento/python/TurboGears/trunk/turbogears/errorhandling.py", line 28, in _implicit_error_handler


return getattr(self, error_source.__name__ )(*args, **kw)

TypeError: testform() takes at least 4 non-keyword arguments (3 given)

Request Headers:
Host: localhost
localhost - - [09/Feb/2006:17:03:30] "GET /testform?name=ed&age=edalso&date=11/05/2005 HTTP/1.1" 500 3459

--------------------- >> end captured stdout << ----------------------


----------------------------------------------------------------------
Ran 111 tests in 20.685s

FAILED (errors=2)
================================================================================

And I'm using

================================================================================
godoy@jupiter ~/desenvolvimento/python/TurboGears/trunk % LANG= svn info .
Path: .
URL: http://www.turbogears.org/svn/turbogears/trunk
Repository UUID: 77541ad4-5f01-0410-9ede-a1b63cd9a898
Revision: 715
Node Kind: directory
Schedule: normal
Last Changed Author: alberto
Last Changed Rev: 715
Last Changed Date: 2006-02-09 13:35:06 -0200 (Thu, 09 Feb 2006)
Properties Last Updated: 2006-02-08 23:58:51 -0200 (Wed, 08 Feb 2006)

Max Ischenko

unread,
Feb 11, 2006, 5:04:12 AM2/11/06
to TurboGears
Hi Jorge,

Sorry for slow replies.


> > The 'new' syntax is fully compatible with the old one so you don't have
> > to make any changes unless you're willing to use DataGrid.Column.
>
> Are there any advantages on that? If not, then I prefer using the simplest
> approach.

You free to use 'old' syntax, it remain fully legible and not
'obsoleted' in any way. New syntax is useful if you want to make use of
options attribute of DataGrid.Column -- there is no way to specify
those with old syntax.

As for the error you get when using DataGrid -- sorry, have no idea.

Please try to find the minimum amount of code needed to reproduce it.

Max.

Reply all
Reply to author
Forward
0 new messages