old version ------------ class MultipleChoice(formless.Typed): """Allow the user to pick from a list of "choices", or a list of choices found by accessing the list in the attribute "choicesAttribute" of the object we 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): formless.Typed.__init__(self, *args, **kw) if choices is None: self.choices = [] else: self.choices = choices self.choicesAttribute = choicesAttribute self.stringify = stringify def coerceWithBinding(self, values, binding): """Coerce a value with the help of an object, which is the object we are configuring. """ int_values = [] try: for val in values: int_values.append(int(val)) except ValueError: raise InputError("%s contains an invalid choice." % str(values)) if self.choicesAttribute is not None: choices = getattr(binding, self.choicesAttribute) else: choices = self.choices return [choices[val] for val in int_values] class MultipleChoiceRenderer(webform.BaseInputRenderer): def input(self, context, slot, data, name, value): tv = data.typedValue if tv.choicesAttribute: choices = getattr(context.locate(formless.IConfigurable), tv.choicesAttribute) else: choices = tv.choices numChoices = len(choices) if numChoices == 0: return None selecter = select(name=name, size=min(5,numChoices), multiple=1) stringify = tv.stringify for index, val in enumerate(choices): if val == value: selecter[option(value=str(index), selected="selected")[stringify(val)]] else: selecter[option(value=str(index))[stringify(val)]] return slot[selecter] class MultipleChoiceInputProcessor(compy.Adapter): implements(iformless.IInputProcessor) def process(self, context, boundTo, data): """data is a list of strings at this point """ typed = self.original if data[0] == '': if typed.required: raise InputError(typed.requiredFailMessage) else: return [] elif hasattr(typed, 'coerceWithBinding'): return typed.coerceWithBinding(data, boundTo) return typed.coerce(data) compy.registerAdapter(MultipleChoiceRenderer, MultipleChoice, iformless.ITypedRenderer) compy.registerAdapter(MultipleChoiceInputProcessor, MultipleChoice, iformless.IInputProcessor) new version ------------ same as above except for below I inherit from object instead of compy.Adapter, and registerAdapter is imported from twisted.python.components. class MultipleChoiceInputProcessor(object): implements(iformless.IInputProcessor) def process(self, context, boundTo, data): """data is a list of strings at this point """ typed = self.original if data[0] == '': if typed.required: raise InputError(typed.requiredFailMessage) else: return [] elif hasattr(typed, 'coerceWithBinding'): return typed.coerceWithBinding(data, boundTo) return typed.coerce(data) registerAdapter(MultipleChoiceRenderer, MultipleChoice, iformless.ITypedRenderer) registerAdapter(MultipleChoiceInputProcessor, MultipleChoice, iformless.IInputProcessor) I'm getting the following long ugly error though. exceptions.TypeError: default __new__ takes no parameters D:\Python24\lib\site-packages\twisted\internet\defer.py, line 107 in maybeDeferred 105 106 try: 107 result = f(*args, **kw) 108 except: Locals args (PageContext(tag=, remembrances={'formless.iformless.IConfigurableFactory': , 'nevow.inevow.ICurrentSegments': (), 'formless.iformless.IBinding': , 'nevow.inevow.IRemainingSegments': ('freeform_post!applytriggers!applytriggers',), 'nevow.inevow.IRequest': , 'nevow.inevow.IResource': , 'formless.iformless.IConfigurable': TypedInterfaceConfigurable()}), 'applytriggers', {'vobs': [''], 'site': ['bangalore'], 'applytriggers': ['applytriggers']}) kw {} f )> D:\Python24\Lib\site-packages\formless\configurable.py, line 116 in postForm 114 115 bindingProcessor = iformless.IInputProcessor(binding) 116 rv = bindingProcessor.process(ctx, binding.boundTo, args) 117 ctx.remember(rv, inevow.IHand) Locals bindingProcessor args {'vobs': [''], 'site': ['bangalore'], 'applytriggers': ['applytriggers']} binding ctx PageContext(tag=, remembrances={'formless.iformless.IConfigurableFactory': , 'nevow.inevow.ICurrentSegments': (), 'formless.iformless.IBinding': , 'nevow.inevow.IRemainingSegments': ('freeform_post!applytriggers!applytriggers',), 'nevow.inevow.IRequest': , 'nevow.inevow.IResource': , 'formless.iformless.IConfigurable': TypedInterfaceConfigurable()}) iformless Globals inevow D:\Python24\Lib\site-packages\formless\processors.py, line 103 in process 101 context = WovenContext(context, faketag) 102 context.remember(binding, iformless.IBinding) 103 results[name] = iformless.IInputProcessor(binding.typedValue).process(context, boundTo, data.get(name, [''])) 104 except formless.InputError, e: Locals e name 'trigger_names' binding boundTo results {'vobs': '', 'request': , 'site': 'bangalore'} context WovenContext(tag=Tag('html'), remembrances={'formless.iformless.IBinding': }) data {'vobs': [''], 'site': ['bangalore'], 'applytriggers': ['applytriggers']} typedValue Globals process faketag Tag('html') formless WovenContext iformless D:\Python24\Lib\site-packages\zope\interface\interface.py, line 676 in __call__ 674 return adapter 675 676 adapter = self.__adapt__(obj) 677 Locals self obj D:\Python24\Lib\site-packages\zope\interface\interface.py, line 744 in __adapt__ 742 743 for hook in adapter_hooks: 744 adapter = hook(self, obj) 745 if adapter is not None: Locals hook self obj Globals adapter_hooks [] D:\Python24\lib\site-packages\twisted\python\components.py, line 96 in _hook 94 return None 95 else: 96 return factory(ob) 97interface.adapter_hooks.append(_hook) Locals factory ob Globals interface _hook exceptions.TypeError: default __new__ takes no parameters