[Twisted-web] Re: [Nevow-commits] r962 - One billion times better
Choice...
Alex Levy
mesozoic at polynode.com
Tue Dec 21 08:30:14 MST 2004
I'm a little behind on Nevow changes, and I just came across this change to
the Choice interface. It looks cool (deferred support is a big plus), but so
far all the examples I've seen involve declaring the available choices as
part of the interface definition, e.g.:
class MyInterface(TypedInterface):
pickOne = Choice(lambda c,d: [1,2,3,4])
What I do (fairly regularly) with my application involves declaring the
available choices as part of the _implementing_ class, not as part of the
interface. I typically used choicesAttribute to do this, and was working on
something along the lines of a choicesMethod, but now it seems that this
behavior has been deprecated.
So, what is the new recommended syntax for a Choice where the implementing
class can change the choices dynamically?
On Thu, Dec 16, 2004 at 01:49:29PM -0500, Donovan Preston wrote:
> MIME-Version: 1.0
> Content-Type: text/plain; charset=UTF-8
>
> Author: dp
> Date: Thu Dec 16 13:49:28 2004
> New Revision: 962
>
> Modified:
> trunk/examples/formbuilder.py
> trunk/examples/formpost2.py
> trunk/formless/annotate.py
> trunk/formless/webform.py
> Log:
> One billion times better Choice implementation; supports lazy choices from a function, a deferred, etc. Has valueToKey and keyToValue methods which are used to serialize/unserialize the choice instead of the index into the list.
>
>
> Modified: trunk/examples/formbuilder.py
> ==============================================================================
> --- trunk/examples/formbuilder.py (original)
> +++ trunk/examples/formbuilder.py Thu Dec 16 13:49:28 2004
> @@ -10,6 +10,9 @@
> from formless import webform
> from formless import configurable
>
> +from twisted.python import reflect
> +
> +
> class BuilderCore(configurable.Configurable):
> def __init__(self):
> configurable.Configurable.__init__(self, None)
> @@ -32,10 +35,11 @@
>
>
> allTypes = [annotate.String, annotate.Text, annotate.Integer, annotate.Real, annotate.Password]
> +typeChoice = annotate.Choice(choices=allTypes, valueToKey=reflect.qual, keyToValue=reflect.namedAny, stringify=lambda x: x.__name__)
>
>
> class IFormBuilder(annotate.TypedInterface):
> - def addElement(self, name=annotate.String(required=True), type=annotate.Choice(choices=allTypes)):
> + def addElement(self, name=annotate.String(required=True), type=typeChoice):
> """Add Element
>
> Add an element to this form.
>
> Modified: trunk/examples/formpost2.py
> ==============================================================================
> --- trunk/examples/formpost2.py (original)
> +++ trunk/examples/formpost2.py Thu Dec 16 13:49:28 2004
> @@ -3,15 +3,24 @@
> from nevow import loaders
> from nevow import rend
> from nevow import tags
> +from nevow import inevow
>
> from formless import annotate
> from formless import webform
>
> +from twisted.internet import defer
> +
> +
> +oldChoicesWay = annotate.Choice(choicesAttribute='theChoices') # Doing this gives you a DeprecationWarning now
> +# If you still want to use an attribute or method of some other object, you should use a function as shown below,
> +# but look up IResource(ctx) or IConfigurable(ctx), whichever is more appropriate.
> +newChoicesWay = annotate.Choice(lambda c, d: range(30))
> +deferChoicesWay = annotate.Choice(lambda c, d: defer.succeed(['abcd', 'efgh', 'ijkl']))
>
> class IMyForm(annotate.TypedInterface):
> foo = annotate.Integer()
>
> - def bar(self, baz=annotate.Integer()):
> + def bar(self, baz=annotate.Integer(), bamf=oldChoicesWay, slam=newChoicesWay, ham=deferChoicesWay):
> pass
> bar = annotate.autocallable(bar)
>
> @@ -21,8 +30,10 @@
>
> foo = 5
>
> - def bar(self, baz):
> - print "baz!", baz
> + def bar(self, baz, bamf, slam, ham):
> + return "You called bar! %s %s %s %s" % (baz, bamf, slam, ham)
> +
> + theChoices = [1, 2, 3]
>
>
> class FormPage(rend.Page):
> @@ -31,12 +42,19 @@
>
> child_webform_css = webform.defaultCSS
>
> + def render_hand(self, ctx, data):
> + hand = inevow.IHand(ctx, default=None)
> + if hand is not None:
> + return ctx.tag[hand]
> + return ''
> +
> docFactory = loaders.stan(
> tags.html[
> tags.head[
> tags.link(rel='stylesheet', type='text/css', href='/webform_css'),
> ],
> tags.body[
> + tags.h3(render=render_hand, style="color: red; font-size: xx-large"),
> "Hello! Here is a form:",
>
> # We want to render forms defined by the Implementation instance.
>
> Modified: trunk/formless/annotate.py
> ==============================================================================
> --- trunk/formless/annotate.py (original)
> +++ trunk/formless/annotate.py Thu Dec 16 13:49:28 2004
> @@ -10,6 +10,7 @@
> import copy
> import inspect
> import types
> +import warnings
>
> from nevow import inevow
> from nevow import util
> @@ -238,28 +239,29 @@
> are configuring. The elements of the list will be rendered by calling the
> function passed to stringify, which is by default "str".
> """
> - def __init__(self, choices=None, choicesAttribute=None, stringify=str, *args, **kw):
> + def __init__(self, choices=None, choicesAttribute=None, stringify=str, valueToKey=str, keyToValue=str, *args, **kw):
> Typed.__init__(self, *args, **kw)
> - if choices is None:
> - self.choices = []
> - else:
> - self.choices = choices
> - self.choicesAttribute = choicesAttribute
> + self.choices = choices
> + if choicesAttribute:
> + self.choicesAttribute = choicesAttribute
> + if getattr(self, 'choicesAttribute', None):
> + warnings.warn(
> + "Choice.choicesAttribute is deprecated. Please pass a function to choices instead.",
> + DeprecationWarning,
> + stacklevel=2)
> + def findTheChoices(ctx, data):
> + return getattr(iformless.IConfigurable(ctx).original, self.choicesAttribute)
> + self.choices = findTheChoices
> +
> self.stringify = stringify
> + self.valueToKey=valueToKey
> + self.keyToValue=keyToValue
>
> def coerce(self, val, binding):
> """Coerce a value with the help of an object, which is the object
> we are configuring.
> """
> - try:
> - val = int(val)
> - except ValueError:
> - raise InputError("%r is an invalid choice." % val)
> - if self.choicesAttribute is not None:
> - choices = getattr(binding, self.choicesAttribute)
> - else:
> - choices = self.choices
> - return choices[val]
> + return self.keyToValue(val)
>
>
> class Any(object):
>
> Modified: trunk/formless/webform.py
> ==============================================================================
> --- trunk/formless/webform.py (original)
> +++ trunk/formless/webform.py Thu Dec 16 13:49:28 2004
> @@ -62,6 +62,7 @@
> def rend(self, context, data):
> defaults = context.locate(iformless.IFormDefaults)
> value = defaults.getDefault(context.key, context)
> + context.remember(data.typedValue, iformless.ITyped)
>
> if data.typedValue.getAttribute('immutable'):
> inp = span(id=keyToXMLID(context.key))[value]
> @@ -145,32 +146,45 @@
> _class='freeform-input-file')]
>
>
> +class ICurrentlySelectedValue(compy.Interface):
> + """The currently-selected-value for the ITypedRenderer being rendered.
> + """
> +
> +
> +csv = ICurrentlySelectedValue
> +def valToKey(c, d):
> + return iformless.ITyped(c).valueToKey(d)
> +
> +
> +def isSelected(c, d):
> + if csv(c) == valToKey(c, d):
> + return c.tag(selected='selected')
> + return c.tag
> +
> +
> +default_select = select(id=slot('id'), name=slot('name'), render=directive('sequence'), foo="bar")[
> + option(pattern="item",
> + value=valToKey,
> + render=isSelected)[
> + lambda c, d: iformless.ITyped(c).stringify(d)]]
> +
> +
> class ChoiceRenderer(BaseInputRenderer):
> def input(self, context, slot, data, name, value):
> tv = data.typedValue
> - if tv.choicesAttribute:
> - choices = getattr(context.locate(iformless.IConfigurable).boundTo, tv.choicesAttribute)
> - else:
> - choices = tv.choices
> + choices = tv.choices
>
> - numChoices = len(choices)
> - if numChoices == 0:
> - return None
> + if value:
> + context.remember(self.original.valueToKey(value), csv)
> + else:
> + context.remember('', csv)
>
> try:
> selector = context.tag.patternGenerator( 'selector' )
> except NodeNotFound:
> - selector = select
> -
> - selector = selector(id=keyToXMLID(context.key), name=name)
> - stringify = tv.stringify
> + selector = default_select
>
> - for index, val in enumerate(choices):
> - if val == value:
> - selector[option(value=str(index), selected="selected")[stringify(val)]]
> - else:
> - selector[option(value=str(index))[stringify(val)]]
> - return slot[selector]
> + return selector(data=choices)
>
>
> class ObjectRenderer(compy.Adapter):
> @@ -259,6 +273,7 @@
> class PropertyBindingRenderer(BaseBindingRenderer):
> def rend(self, context, data):
> context.remember(data, iformless.IBinding)
> + context.remember(data.typedValue, iformless.ITyped)
> typedRenderer = iformless.ITypedRenderer(data.typedValue, defaultBindingRenderer, persist=False)
> if typedRenderer.complexType:
> return invisible(data=data, render=typedRenderer)
> @@ -337,11 +352,13 @@
> except NodeNotFound:
> default_content_pattern = freeformDefaultContentPattern
> content_pattern = default_content_pattern
> + renderer = iformless.ITypedRenderer(
> + argument.typedValue, defaultBindingRenderer, persist=False)
> pat = content_pattern(
> key=argument.name,
> data=argument,
> - render= iformless.ITypedRenderer(
> - argument.typedValue, defaultBindingRenderer, persist=False))
> + render=renderer,
> + remember={iformless.ITyped: argument.typedValue})
> context.fillSlots( 'argument!!%s' % argument.name, pat )
> yield pat
>
>
> _______________________________________________
> Nevow-commits mailing list
> Nevow-commits at divmod.org
> http://divmod.org/users/mailman.twistd/listinfo/nevow-commits
--
Alex Levy
WWW: http://mesozoic.geecs.org/
"Never let your sense of morals prevent you from doing what is right."
-- Salvor Hardin, Isaac Asimov's _Foundation_
More information about the Twisted-web
mailing list