On Feb 28, 2006, at 2:55 PM, David Binger wrote: > On Feb 27, 2006, at 3:48 PM, mario ruggier wrote: > >> form.add_password('passwd1', title="Password Confirm", >> required=False, >> hint="Case sensitive. At least 4 chars long. At least 1 >> digit.", >> spec=spec(both( >> spec(equalwidget(form, 'passwd2'), 'not >> equal.'), >> spec(pattern('^\d|^\D+\d'), 'at least 1 >> digit.'), >> spec(length(4, None), 'too short.')), >> 'Password is not OK... ', 'Password is OK.')) > > > What would you think of having the widget itself, instead of the spec > handle the error messages for 1 level AND specifications like this? > I don't see any easy way to produce nice error messages from > any compound spec that is deeper. Yes, I think to me that seems a good way to to about it. And if I get you right I think it is already what I am doing. In my widget parsing loop (i.e. as in an expanded version of qp's current widget._parse() method) I have something like this (where self is the widget being parsed) : if self.spec is not None: value, gfs = self._fs['value'], self.spec if not (value and match(value, gfs)): self._fs['ok'] = False if isinstance(gfs.spec, ConnectiveSpecOperator): self._fs['message'] = gfs.mer + gfs.spec.break_spec.mer or '' else: self._fs['message'] = gfs.mer or '' else: self._fs['message'] = gfs.mok where gfs is therefore the wrapped spec instance, that had been initialised with an error (mer) and an ok (mok) message. The self._fs is a "field status" dict with four keys: name, value, ok, and message. It is a dict because this way I can pass it around on the server-side freely, but can also pass it rather trivially to the client-side, as response to ajax callbacks from specific fields... re-using my own code as much as i can. All the gfs needs to know is which sub-spec gave out... and get its error message from its wrapped instance (the spec.break_out attr, as per the modified connectivespec classes i sent earlier). I would like to repeat that I do not think it is spec's responsibility to produce nice error messages, but it should bubble up as much information as it can, to enable applications to construct the messages as they need. > What if the widget argument is a list > of (spec, error) pairs, all of which must be > satisfied by the value? > > form.add_password('passwd1', > specs=[(pattern('\d+$'), 'must be digits') > (length(4), 'must have length 4')]) Yes, except that in most cases when there will be a spec, it will be just one. So I just thought to use spec itself for the cases where a list of specs must be satisfied. I guess for the generalized case, the shape of what you suggest could be: specs = [ (spec, mer), (spec, mer), ..., mer, mok ] i.e. any number of spec,error pairs, with the last 2 element being an error and an ok message for the top level spec (only top level needs an ok message I think). Each sub-spec can be further compounded, for a hierarchy of compounded specs if necessary (although this should not ever occur hopefully!). As I pointed out previously, I have a wrapper class for this. Doing it with tuples or with a class is more of a stylistic difference though. It does not change the basic issue of whether I know which sub-spec gave out. I do however see your point of doing the "top level spec loop" myself, as opposed to allowing match() to do it... i.e. the code extract above could be turned into something like: if self.spec is not None: value, gfs = self._fs['value'], self.spec if isinstance(gfs.spec, ConnectiveSpecOperator): # need to consider also any otherwise compound spec... for subspec in gfs.spec: ... call match, etc. This can work, but isn't this duplicating some functionality that is already provided by spec.match()? mario