[twill] Spurious parse error when processing <select> tag without a <form> tag

Barry Hart barry.hart at predictix.com
Tue Aug 5 13:30:51 PDT 2008

At my company, we are starting to use Twill for server monitoring and load
We noticed a problem recently where Twill would report a "nested SELECTs"
parse error on a page which looked fine to us. On further investigation,
this was the HTML causing the problem. It is a 'quick links' drop-down
which we include at the top of every page:
      <select py:if="not tg.identity.anonymous" id="quick_link_menu">  
        <option value="">Quick links</option>  
        <option value="/promotion/list/create_new">Create a new
a planned promotion</option>

Because events on this select tag control are processed on the browser
side by JavaScript, it is not enclosed in a <form> tag. This HTML
uncovered an apparent bug in twill/other_packages/_mechanize_dist. The
problem stems from the following function in ClientForm.py. Because
end_select() exits immediately if self._current_form is self._global_form,
it leaves self._select set if there is a <select> tag outside of a <form>
    def end_select(self):
        if self._current_form is self._global_form:
        if self._select is None:
            raise ParseError("end of SELECT before start")
        if self._option is not None:
        self._select = None

 Thus, any subsequent <select> tag will cause a parse error in
    def start_select(self, attrs):
        debug("%s", attrs)
        if self._select is not None:
            raise ParseError("nested SELECTs")
        if self._textarea is not None:
            raise ParseError("SELECT inside TEXTAREA")
        d = {}
        for key, val in attrs:
            d[key] = val
        self._select = d
        self._append_select_control({"__select": d})

A possible fix is to to clear self._select here:
        if self._current_form is self._global_form:
            self._select = None # NEW CODE

or you can monkeypatch around it, as I'm doing:
# Patch the form parser class to ensure end select tags are processed
from twill.other_packages._mechanize_dist import ClientForm
form_parser_class =
old_end_select = form_parser_class.end_select
def end_select(self):
    result = old_end_select(self)
    self._select = None
    return result
form_parser_class.end_select = end_select

Either of these fixes works but with one apparent side effect - now all
the form indices are shifted by 1, e.g. form 1 becomes form 2.
If either of these changes looks okay, could one of them be incorporated
in Twill or mechanize?
Barry Hart
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.idyll.org/pipermail/twill/attachments/20080805/2afabd95/attachment.htm 

More information about the twill mailing list