home *** CD-ROM | disk | FTP | other *** search
/ Maximum CD 2011 October / maximum-cd-2011-10.iso / DiscContents / digsby_setup.exe / lib / ClientForm.pyo (.txt) < prev    next >
Encoding:
Python Compiled Bytecode  |  2011-06-22  |  68.2 KB  |  2,433 lines

  1. # Source Generated with Decompyle++
  2. # File: in.pyo (Python 2.6)
  3.  
  4. __all__ = [
  5.     'AmbiguityError',
  6.     'CheckboxControl',
  7.     'Control',
  8.     'ControlNotFoundError',
  9.     'FileControl',
  10.     'FormParser',
  11.     'HTMLForm',
  12.     'HiddenControl',
  13.     'IgnoreControl',
  14.     'ImageControl',
  15.     'IsindexControl',
  16.     'Item',
  17.     'ItemCountError',
  18.     'ItemNotFoundError',
  19.     'Label',
  20.     'ListControl',
  21.     'LocateError',
  22.     'Missing',
  23.     'ParseError',
  24.     'ParseFile',
  25.     'ParseFileEx',
  26.     'ParseResponse',
  27.     'ParseResponseEx',
  28.     'PasswordControl',
  29.     'RadioControl',
  30.     'ScalarControl',
  31.     'SelectControl',
  32.     'SubmitButtonControl',
  33.     'SubmitControl',
  34.     'TextControl',
  35.     'TextareaControl',
  36.     'XHTMLCompatibleFormParser']
  37.  
  38. try:
  39.     True
  40. except NameError:
  41.     True = 1
  42.     False = 0
  43.  
  44.  
  45. try:
  46.     bool
  47. except NameError:
  48.     
  49.     def bool(expr):
  50.         if expr:
  51.             return True
  52.         return False
  53.  
  54.  
  55.  
  56. try:
  57.     import logging
  58.     import inspect
  59. except ImportError:
  60.     
  61.     def debug(msg, *args, **kwds):
  62.         pass
  63.  
  64.  
  65. _logger = logging.getLogger('ClientForm')
  66. OPTIMIZATION_HACK = True
  67.  
  68. def debug(msg, *args, **kwds):
  69.     if OPTIMIZATION_HACK:
  70.         return None
  71.     caller_name = inspect.stack()[1][3]
  72.     extended_msg = '%%s %s' % msg
  73.     extended_args = (caller_name,) + args
  74.     debug = _logger.debug(extended_msg, *extended_args, **kwds)
  75.  
  76.  
  77. def _show_debug_messages():
  78.     global OPTIMIZATION_HACK
  79.     OPTIMIZATION_HACK = False
  80.     _logger.setLevel(logging.DEBUG)
  81.     handler = logging.StreamHandler(sys.stdout)
  82.     handler.setLevel(logging.DEBUG)
  83.     _logger.addHandler(handler)
  84.  
  85. import sys
  86. import urllib
  87. import urllib2
  88. import types
  89. import mimetools
  90. import copy
  91. import urlparse
  92. import htmlentitydefs
  93. import re
  94. import random
  95. from cStringIO import StringIO
  96. import sgmllib
  97. sgmllib.charref = re.compile('&#(x?[0-9a-fA-F]+)[^0-9a-fA-F]')
  98.  
  99. try:
  100.     import HTMLParser
  101. except ImportError:
  102.     HAVE_MODULE_HTMLPARSER = False
  103.  
  104. HAVE_MODULE_HTMLPARSER = True
  105.  
  106. try:
  107.     import warnings
  108. except ImportError:
  109.     
  110.     def deprecation(message, stack_offset = 0):
  111.         pass
  112.  
  113.  
  114.  
  115. def deprecation(message, stack_offset = 0):
  116.     warnings.warn(message, DeprecationWarning, stacklevel = 3 + stack_offset)
  117.  
  118. VERSION = '0.2.9'
  119. CHUNK = 1024
  120. DEFAULT_ENCODING = 'latin-1'
  121.  
  122. class Missing:
  123.     pass
  124.  
  125. _compress_re = re.compile('\\s+')
  126.  
  127. def compress_text(text):
  128.     return _compress_re.sub(' ', text.strip())
  129.  
  130.  
  131. def normalize_line_endings(text):
  132.     return re.sub('(?:(?<!\\r)\\n)|(?:\\r(?!\\n))', '\r\n', text)
  133.  
  134.  
  135. def urlencode(query, doseq = False):
  136.     if hasattr(query, 'items'):
  137.         query = query.items()
  138.     else:
  139.         
  140.         try:
  141.             x = len(query)
  142.             if len(query) and type(query[0]) != types.TupleType:
  143.                 raise TypeError()
  144.             type(query[0]) != types.TupleType
  145.         except TypeError:
  146.             (ty, va, tb) = sys.exc_info()
  147.             raise TypeError('not a valid non-string sequence or mapping object', tb)
  148.  
  149.     l = []
  150.     if not doseq:
  151.         for k, v in query:
  152.             k = urllib.quote_plus(str(k))
  153.             v = urllib.quote_plus(str(v))
  154.             l.append(k + '=' + v)
  155.         
  156.     else:
  157.         for k, v in query:
  158.             k = urllib.quote_plus(str(k))
  159.             if type(v) == types.StringType:
  160.                 v = urllib.quote_plus(v)
  161.                 l.append(k + '=' + v)
  162.                 continue
  163.             if type(v) == types.UnicodeType:
  164.                 v = urllib.quote_plus(v.encode('ASCII', 'replace'))
  165.                 l.append(k + '=' + v)
  166.                 continue
  167.             
  168.             try:
  169.                 x = len(v)
  170.             except TypeError:
  171.                 v = urllib.quote_plus(str(v))
  172.                 l.append(k + '=' + v)
  173.                 continue
  174.  
  175.             for elt in v:
  176.                 l.append(k + '=' + urllib.quote_plus(str(elt)))
  177.             
  178.         
  179.     return '&'.join(l)
  180.  
  181.  
  182. def unescape(data, entities, encoding = DEFAULT_ENCODING):
  183.     if data is None or '&' not in data:
  184.         return data
  185.     
  186.     def replace_entities(match, entities = entities, encoding = encoding):
  187.         ent = match.group()
  188.         if ent[1] == '#':
  189.             return unescape_charref(ent[2:-1], encoding)
  190.         repl = entities.get(ent)
  191.         return repl
  192.  
  193.     return re.sub('&#?[A-Za-z0-9]+?;', replace_entities, data)
  194.  
  195.  
  196. def unescape_charref(data, encoding):
  197.     name = data
  198.     base = 10
  199.     if name.startswith('x'):
  200.         name = name[1:]
  201.         base = 16
  202.     
  203.     uc = unichr(int(name, base))
  204.     if encoding is None:
  205.         return uc
  206.     
  207.     try:
  208.         repl = uc.encode(encoding)
  209.     except UnicodeError:
  210.         encoding is None
  211.         encoding is None
  212.         repl = '&#%s;' % data
  213.     except:
  214.         encoding is None
  215.  
  216.     return repl
  217.  
  218.  
  219. def get_entitydefs():
  220.     import htmlentitydefs
  221.     latin_1_decode = latin_1_decode
  222.     import codecs
  223.     entitydefs = { }
  224.     
  225.     try:
  226.         htmlentitydefs.name2codepoint
  227.     except AttributeError:
  228.         entitydefs = { }
  229.         for name, char in htmlentitydefs.entitydefs.items():
  230.             uc = latin_1_decode(char)[0]
  231.             if uc.startswith('&#') and uc.endswith(';'):
  232.                 uc = unescape_charref(uc[2:-1], None)
  233.             
  234.             entitydefs['&%s;' % name] = uc
  235.         
  236.  
  237.     for name, codepoint in htmlentitydefs.name2codepoint.items():
  238.         entitydefs['&%s;' % name] = unichr(codepoint)
  239.     
  240.     return entitydefs
  241.  
  242.  
  243. def issequence(x):
  244.     
  245.     try:
  246.         x[0]
  247.     except (TypeError, KeyError):
  248.         return False
  249.         except IndexError:
  250.             pass
  251.         except:
  252.             None<EXCEPTION MATCH>IndexError
  253.         
  254.  
  255.     return True
  256.  
  257.  
  258. def isstringlike(x):
  259.     
  260.     try:
  261.         x + ''
  262.     except:
  263.         return False
  264.  
  265.     return True
  266.  
  267.  
  268. def choose_boundary():
  269.     nonce = []([ str(random.randint(0, sys.maxint - 1)) for i in (0, 1, 2) ])
  270.     return '-' * 27 + nonce
  271.  
  272.  
  273. class MimeWriter:
  274.     
  275.     def __init__(self, fp, http_hdrs = None):
  276.         self._http_hdrs = http_hdrs
  277.         self._fp = fp
  278.         self._headers = []
  279.         self._boundary = []
  280.         self._first_part = True
  281.  
  282.     
  283.     def addheader(self, key, value, prefix = 0, add_to_http_hdrs = 0):
  284.         lines = value.split('\r\n')
  285.         while lines and not lines[-1]:
  286.             del lines[-1]
  287.         while lines and not lines[0]:
  288.             del lines[0]
  289.         if add_to_http_hdrs:
  290.             value = ''.join(lines)
  291.             self._http_hdrs.append((key, value))
  292.         else:
  293.             for i in range(1, len(lines)):
  294.                 lines[i] = '    ' + lines[i].strip()
  295.             
  296.             value = '\r\n'.join(lines) + '\r\n'
  297.             line = key + ': ' + value
  298.             if prefix:
  299.                 self._headers.insert(0, line)
  300.             else:
  301.                 self._headers.append(line)
  302.  
  303.     
  304.     def flushheaders(self):
  305.         self._fp.writelines(self._headers)
  306.         self._headers = []
  307.  
  308.     
  309.     def startbody(self, ctype = None, plist = [], prefix = 1, add_to_http_hdrs = 0, content_type = 1):
  310.         if content_type and ctype:
  311.             for name, value in plist:
  312.                 ctype = ctype + ';\r\n %s=%s' % (name, value)
  313.             
  314.             self.addheader('Content-type', ctype, prefix = prefix, add_to_http_hdrs = add_to_http_hdrs)
  315.         
  316.         self.flushheaders()
  317.         if not add_to_http_hdrs:
  318.             self._fp.write('\r\n')
  319.         
  320.         self._first_part = True
  321.         return self._fp
  322.  
  323.     
  324.     def startmultipartbody(self, subtype, boundary = None, plist = [], prefix = 1, add_to_http_hdrs = 0, content_type = 1):
  325.         if not boundary:
  326.             pass
  327.         boundary = choose_boundary()
  328.         self._boundary.append(boundary)
  329.         return self.startbody('multipart/' + subtype, [
  330.             ('boundary', boundary)] + plist, prefix = prefix, add_to_http_hdrs = add_to_http_hdrs, content_type = content_type)
  331.  
  332.     
  333.     def nextpart(self):
  334.         boundary = self._boundary[-1]
  335.         if self._first_part:
  336.             self._first_part = False
  337.         else:
  338.             self._fp.write('\r\n')
  339.         self._fp.write('--' + boundary + '\r\n')
  340.         return self.__class__(self._fp)
  341.  
  342.     
  343.     def lastpart(self):
  344.         if self._first_part:
  345.             self.nextpart()
  346.         
  347.         boundary = self._boundary.pop()
  348.         self._fp.write('\r\n--' + boundary + '--\r\n')
  349.  
  350.  
  351.  
  352. class LocateError(ValueError):
  353.     pass
  354.  
  355.  
  356. class AmbiguityError(LocateError):
  357.     pass
  358.  
  359.  
  360. class ControlNotFoundError(LocateError):
  361.     pass
  362.  
  363.  
  364. class ItemNotFoundError(LocateError):
  365.     pass
  366.  
  367.  
  368. class ItemCountError(ValueError):
  369.     pass
  370.  
  371. if HAVE_MODULE_HTMLPARSER:
  372.     SGMLLIB_PARSEERROR = sgmllib.SGMLParseError
  373.     
  374.     class ParseError(sgmllib.SGMLParseError, HTMLParser.HTMLParseError):
  375.         pass
  376.  
  377. elif hasattr(sgmllib, 'SGMLParseError'):
  378.     SGMLLIB_PARSEERROR = sgmllib.SGMLParseError
  379.     
  380.     class ParseError(sgmllib.SGMLParseError):
  381.         pass
  382.  
  383. else:
  384.     SGMLLIB_PARSEERROR = RuntimeError
  385.     
  386.     class ParseError(RuntimeError):
  387.         pass
  388.  
  389.  
  390. class _AbstractFormParser:
  391.     
  392.     def __init__(self, entitydefs = None, encoding = DEFAULT_ENCODING):
  393.         if entitydefs is None:
  394.             entitydefs = get_entitydefs()
  395.         
  396.         self._entitydefs = entitydefs
  397.         self._encoding = encoding
  398.         self.base = None
  399.         self.forms = []
  400.         self.labels = []
  401.         self._current_label = None
  402.         self._current_form = None
  403.         self._select = None
  404.         self._optgroup = None
  405.         self._option = None
  406.         self._textarea = None
  407.         self._global_form = None
  408.         self.start_form([])
  409.         self.end_form()
  410.         self._current_form = self._global_form = self.forms[0]
  411.  
  412.     
  413.     def do_base(self, attrs):
  414.         debug('%s', attrs)
  415.         for key, value in attrs:
  416.             if key == 'href':
  417.                 self.base = self.unescape_attr_if_required(value)
  418.                 continue
  419.         
  420.  
  421.     
  422.     def end_body(self):
  423.         debug('')
  424.         if self._current_label is not None:
  425.             self.end_label()
  426.         
  427.         if self._current_form is not self._global_form:
  428.             self.end_form()
  429.         
  430.  
  431.     
  432.     def start_form(self, attrs):
  433.         debug('%s', attrs)
  434.         if self._current_form is not self._global_form:
  435.             raise ParseError('nested FORMs')
  436.         self._current_form is not self._global_form
  437.         name = None
  438.         action = None
  439.         enctype = 'application/x-www-form-urlencoded'
  440.         method = 'GET'
  441.         d = { }
  442.         for key, value in attrs:
  443.             if key == 'name':
  444.                 name = self.unescape_attr_if_required(value)
  445.             elif key == 'action':
  446.                 action = self.unescape_attr_if_required(value)
  447.             elif key == 'method':
  448.                 method = self.unescape_attr_if_required(value.upper())
  449.             elif key == 'enctype':
  450.                 enctype = self.unescape_attr_if_required(value.lower())
  451.             
  452.             d[key] = self.unescape_attr_if_required(value)
  453.         
  454.         controls = []
  455.         self._current_form = ((name, action, method, enctype), d, controls)
  456.  
  457.     
  458.     def end_form(self):
  459.         debug('')
  460.         if self._current_label is not None:
  461.             self.end_label()
  462.         
  463.         if self._current_form is self._global_form:
  464.             raise ParseError('end of FORM before start')
  465.         self._current_form is self._global_form
  466.         self.forms.append(self._current_form)
  467.         self._current_form = self._global_form
  468.  
  469.     
  470.     def start_select(self, attrs):
  471.         debug('%s', attrs)
  472.         if self._select is not None:
  473.             raise ParseError('nested SELECTs')
  474.         self._select is not None
  475.         if self._textarea is not None:
  476.             raise ParseError('SELECT inside TEXTAREA')
  477.         self._textarea is not None
  478.         d = { }
  479.         for key, val in attrs:
  480.             d[key] = self.unescape_attr_if_required(val)
  481.         
  482.         self._select = d
  483.         self._add_label(d)
  484.         self._append_select_control({
  485.             '__select': d })
  486.  
  487.     
  488.     def end_select(self):
  489.         debug('')
  490.         if self._select is None:
  491.             raise ParseError('end of SELECT before start')
  492.         self._select is None
  493.         if self._option is not None:
  494.             self._end_option()
  495.         
  496.         self._select = None
  497.  
  498.     
  499.     def start_optgroup(self, attrs):
  500.         debug('%s', attrs)
  501.         if self._select is None:
  502.             raise ParseError('OPTGROUP outside of SELECT')
  503.         self._select is None
  504.         d = { }
  505.         for key, val in attrs:
  506.             d[key] = self.unescape_attr_if_required(val)
  507.         
  508.         self._optgroup = d
  509.  
  510.     
  511.     def end_optgroup(self):
  512.         debug('')
  513.         if self._optgroup is None:
  514.             raise ParseError('end of OPTGROUP before start')
  515.         self._optgroup is None
  516.         self._optgroup = None
  517.  
  518.     
  519.     def _start_option(self, attrs):
  520.         debug('%s', attrs)
  521.         if self._select is None:
  522.             raise ParseError('OPTION outside of SELECT')
  523.         self._select is None
  524.         if self._option is not None:
  525.             self._end_option()
  526.         
  527.         d = { }
  528.         for key, val in attrs:
  529.             d[key] = self.unescape_attr_if_required(val)
  530.         
  531.         self._option = { }
  532.         self._option.update(d)
  533.         if self._optgroup and self._optgroup.has_key('disabled') and not self._option.has_key('disabled'):
  534.             self._option['disabled'] = None
  535.         
  536.  
  537.     
  538.     def _end_option(self):
  539.         debug('')
  540.         if self._option is None:
  541.             raise ParseError('end of OPTION before start')
  542.         self._option is None
  543.         contents = self._option.get('contents', '').strip()
  544.         self._option['contents'] = contents
  545.         if not self._option.has_key('value'):
  546.             self._option['value'] = contents
  547.         
  548.         if not self._option.has_key('label'):
  549.             self._option['label'] = contents
  550.         
  551.         self._option['__select'] = self._select
  552.         self._append_select_control(self._option)
  553.         self._option = None
  554.  
  555.     
  556.     def _append_select_control(self, attrs):
  557.         debug('%s', attrs)
  558.         controls = self._current_form[2]
  559.         name = self._select.get('name')
  560.         controls.append(('select', name, attrs))
  561.  
  562.     
  563.     def start_textarea(self, attrs):
  564.         debug('%s', attrs)
  565.         if self._textarea is not None:
  566.             raise ParseError('nested TEXTAREAs')
  567.         self._textarea is not None
  568.         if self._select is not None:
  569.             raise ParseError('TEXTAREA inside SELECT')
  570.         self._select is not None
  571.         d = { }
  572.         for key, val in attrs:
  573.             d[key] = self.unescape_attr_if_required(val)
  574.         
  575.         self._add_label(d)
  576.         self._textarea = d
  577.  
  578.     
  579.     def end_textarea(self):
  580.         debug('')
  581.         if self._textarea is None:
  582.             raise ParseError('end of TEXTAREA before start')
  583.         self._textarea is None
  584.         controls = self._current_form[2]
  585.         name = self._textarea.get('name')
  586.         controls.append(('textarea', name, self._textarea))
  587.         self._textarea = None
  588.  
  589.     
  590.     def start_label(self, attrs):
  591.         debug('%s', attrs)
  592.         if self._current_label:
  593.             self.end_label()
  594.         
  595.         d = { }
  596.         for key, val in attrs:
  597.             d[key] = self.unescape_attr_if_required(val)
  598.         
  599.         taken = bool(d.get('for'))
  600.         d['__text'] = ''
  601.         d['__taken'] = taken
  602.         if taken:
  603.             self.labels.append(d)
  604.         
  605.         self._current_label = d
  606.  
  607.     
  608.     def end_label(self):
  609.         debug('')
  610.         label = self._current_label
  611.         if label is None:
  612.             return None
  613.         self._current_label = None
  614.         del label['__taken']
  615.  
  616.     
  617.     def _add_label(self, d):
  618.         if self._current_label is not None:
  619.             if not self._current_label['__taken']:
  620.                 self._current_label['__taken'] = True
  621.                 d['__label'] = self._current_label
  622.             
  623.         
  624.  
  625.     
  626.     def handle_data(self, data):
  627.         debug('%s', data)
  628.         if data[0:2] == '\r\n':
  629.             data = data[2:]
  630.         
  631.         if data[0:1] in ('\n', '\r'):
  632.             data = data[1:]
  633.         
  634.         if self._option is not None:
  635.             map = self._option
  636.             key = 'contents'
  637.         elif self._textarea is not None:
  638.             map = self._textarea
  639.             key = 'value'
  640.             data = normalize_line_endings(data)
  641.         elif self._current_label is not None:
  642.             map = self._current_label
  643.             key = '__text'
  644.         else:
  645.             return None
  646.         if not (self._option is not None).has_key(key):
  647.             map[key] = data
  648.         else:
  649.             map[key] = map[key] + data
  650.  
  651.     
  652.     def do_button(self, attrs):
  653.         debug('%s', attrs)
  654.         d = { }
  655.         d['type'] = 'submit'
  656.         for key, val in attrs:
  657.             d[key] = self.unescape_attr_if_required(val)
  658.         
  659.         controls = self._current_form[2]
  660.         type = d['type']
  661.         name = d.get('name')
  662.         type = type + 'button'
  663.         self._add_label(d)
  664.         controls.append((type, name, d))
  665.  
  666.     
  667.     def do_input(self, attrs):
  668.         debug('%s', attrs)
  669.         d = { }
  670.         d['type'] = 'text'
  671.         for key, val in attrs:
  672.             d[key] = self.unescape_attr_if_required(val)
  673.         
  674.         controls = self._current_form[2]
  675.         type = d['type']
  676.         name = d.get('name')
  677.         self._add_label(d)
  678.         controls.append((type, name, d))
  679.  
  680.     
  681.     def do_isindex(self, attrs):
  682.         debug('%s', attrs)
  683.         d = { }
  684.         for key, val in attrs:
  685.             d[key] = self.unescape_attr_if_required(val)
  686.         
  687.         controls = self._current_form[2]
  688.         self._add_label(d)
  689.         controls.append(('isindex', None, d))
  690.  
  691.     
  692.     def handle_entityref(self, name):
  693.         self.handle_data(unescape('&%s;' % name, self._entitydefs, self._encoding))
  694.  
  695.     
  696.     def handle_charref(self, name):
  697.         self.handle_data(unescape_charref(name, self._encoding))
  698.  
  699.     
  700.     def unescape_attr(self, name):
  701.         return unescape(name, self._entitydefs, self._encoding)
  702.  
  703.     
  704.     def unescape_attrs(self, attrs):
  705.         escaped_attrs = { }
  706.         for key, val in attrs.items():
  707.             
  708.             try:
  709.                 val.items
  710.             except AttributeError:
  711.                 escaped_attrs[key] = self.unescape_attr(val)
  712.                 continue
  713.  
  714.             escaped_attrs[key] = self.unescape_attrs(val)
  715.         
  716.         return escaped_attrs
  717.  
  718.     
  719.     def unknown_entityref(self, ref):
  720.         self.handle_data('&%s;' % ref)
  721.  
  722.     
  723.     def unknown_charref(self, ref):
  724.         self.handle_data('&#%s;' % ref)
  725.  
  726.  
  727. if not HAVE_MODULE_HTMLPARSER:
  728.     
  729.     class XHTMLCompatibleFormParser:
  730.         
  731.         def __init__(self, entitydefs = None, encoding = DEFAULT_ENCODING):
  732.             raise ValueError('HTMLParser could not be imported')
  733.  
  734.  
  735. else:
  736.     
  737.     class XHTMLCompatibleFormParser(_AbstractFormParser, HTMLParser.HTMLParser):
  738.         
  739.         def __init__(self, entitydefs = None, encoding = DEFAULT_ENCODING):
  740.             HTMLParser.HTMLParser.__init__(self)
  741.             _AbstractFormParser.__init__(self, entitydefs, encoding)
  742.  
  743.         
  744.         def feed(self, data):
  745.             
  746.             try:
  747.                 HTMLParser.HTMLParser.feed(self, data)
  748.             except HTMLParser.HTMLParseError:
  749.                 exc = None
  750.                 raise ParseError(exc)
  751.  
  752.  
  753.         
  754.         def start_option(self, attrs):
  755.             _AbstractFormParser._start_option(self, attrs)
  756.  
  757.         
  758.         def end_option(self):
  759.             _AbstractFormParser._end_option(self)
  760.  
  761.         
  762.         def handle_starttag(self, tag, attrs):
  763.             
  764.             try:
  765.                 method = getattr(self, 'start_' + tag)
  766.             except AttributeError:
  767.                 
  768.                 try:
  769.                     method = getattr(self, 'do_' + tag)
  770.                 except AttributeError:
  771.                     pass
  772.  
  773.                 method(attrs)
  774.  
  775.             method(attrs)
  776.  
  777.         
  778.         def handle_endtag(self, tag):
  779.             
  780.             try:
  781.                 method = getattr(self, 'end_' + tag)
  782.             except AttributeError:
  783.                 pass
  784.  
  785.             method()
  786.  
  787.         
  788.         def unescape(self, name):
  789.             return self.unescape_attr(name)
  790.  
  791.         
  792.         def unescape_attr_if_required(self, name):
  793.             return name
  794.  
  795.         
  796.         def unescape_attrs_if_required(self, attrs):
  797.             return attrs
  798.  
  799.  
  800.  
  801. class _AbstractSgmllibParser(_AbstractFormParser):
  802.     
  803.     def do_option(self, attrs):
  804.         _AbstractFormParser._start_option(self, attrs)
  805.  
  806.     if sys.version_info[:2] >= (2, 5):
  807.         entity_or_charref = re.compile('&(?:([a-zA-Z][-.a-zA-Z0-9]*)|#(x?[0-9a-fA-F]+))(;?)')
  808.         
  809.         def convert_entityref(self, name):
  810.             return unescape('&%s;' % name, self._entitydefs, self._encoding)
  811.  
  812.         
  813.         def convert_charref(self, name):
  814.             return unescape_charref('%s' % name, self._encoding)
  815.  
  816.         
  817.         def unescape_attr_if_required(self, name):
  818.             return name
  819.  
  820.         
  821.         def unescape_attrs_if_required(self, attrs):
  822.             return attrs
  823.  
  824.     else:
  825.         
  826.         def unescape_attr_if_required(self, name):
  827.             return self.unescape_attr(name)
  828.  
  829.         
  830.         def unescape_attrs_if_required(self, attrs):
  831.             return self.unescape_attrs(attrs)
  832.  
  833.  
  834.  
  835. class FormParser(_AbstractSgmllibParser, sgmllib.SGMLParser):
  836.     
  837.     def __init__(self, entitydefs = None, encoding = DEFAULT_ENCODING):
  838.         sgmllib.SGMLParser.__init__(self)
  839.         _AbstractFormParser.__init__(self, entitydefs, encoding)
  840.  
  841.     
  842.     def feed(self, data):
  843.         
  844.         try:
  845.             sgmllib.SGMLParser.feed(self, data)
  846.         except SGMLLIB_PARSEERROR:
  847.             exc = None
  848.             raise ParseError(exc)
  849.  
  850.  
  851.  
  852.  
  853. def _create_bs_classes(bs, icbinbs):
  854.     
  855.     class _AbstractBSFormParser(_AbstractSgmllibParser):
  856.         bs_base_class = None
  857.         
  858.         def __init__(self, entitydefs = None, encoding = DEFAULT_ENCODING):
  859.             _AbstractFormParser.__init__(self, entitydefs, encoding)
  860.             self.bs_base_class.__init__(self)
  861.  
  862.         
  863.         def handle_data(self, data):
  864.             _AbstractFormParser.handle_data(self, data)
  865.             self.bs_base_class.handle_data(self, data)
  866.  
  867.         
  868.         def feed(self, data):
  869.             
  870.             try:
  871.                 self.bs_base_class.feed(self, data)
  872.             except SGMLLIB_PARSEERROR:
  873.                 exc = None
  874.                 raise ParseError(exc)
  875.  
  876.  
  877.  
  878.     
  879.     class RobustFormParser(_AbstractBSFormParser, bs):
  880.         pass
  881.  
  882.     RobustFormParser.bs_base_class = bs
  883.     
  884.     class NestingRobustFormParser(_AbstractBSFormParser, icbinbs):
  885.         pass
  886.  
  887.     NestingRobustFormParser.bs_base_class = icbinbs
  888.     return (RobustFormParser, NestingRobustFormParser)
  889.  
  890.  
  891. try:
  892.     if sys.version_info[:2] < (2, 2):
  893.         raise ImportError
  894.     sys.version_info[:2] < (2, 2)
  895.     import BeautifulSoup
  896. except ImportError:
  897.     pass
  898.  
  899. (RobustFormParser, NestingRobustFormParser) = _create_bs_classes(BeautifulSoup.BeautifulSoup, BeautifulSoup.ICantBelieveItsBeautifulSoup)
  900. __all__ += [
  901.     'RobustFormParser',
  902.     'NestingRobustFormParser']
  903.  
  904. def ParseResponseEx(response, select_default = False, form_parser_class = FormParser, request_class = urllib2.Request, entitydefs = None, encoding = DEFAULT_ENCODING, _urljoin = urlparse.urljoin, _urlparse = urlparse.urlparse, _urlunparse = urlparse.urlunparse):
  905.     return _ParseFileEx(response, response.geturl(), select_default, False, form_parser_class, request_class, entitydefs, False, encoding, _urljoin = _urljoin, _urlparse = _urlparse, _urlunparse = _urlunparse)
  906.  
  907.  
  908. def ParseFileEx(file, base_uri, select_default = False, form_parser_class = FormParser, request_class = urllib2.Request, entitydefs = None, encoding = DEFAULT_ENCODING, _urljoin = urlparse.urljoin, _urlparse = urlparse.urlparse, _urlunparse = urlparse.urlunparse):
  909.     return _ParseFileEx(file, base_uri, select_default, False, form_parser_class, request_class, entitydefs, False, encoding, _urljoin = _urljoin, _urlparse = _urlparse, _urlunparse = _urlunparse)
  910.  
  911.  
  912. def ParseResponse(response, *args, **kwds):
  913.     return _ParseFileEx(response, response.geturl(), *args, **kwds)[1:]
  914.  
  915.  
  916. def ParseFile(file, base_uri, *args, **kwds):
  917.     return _ParseFileEx(file, base_uri, *args, **kwds)[1:]
  918.  
  919.  
  920. def _ParseFileEx(file, base_uri, select_default = False, ignore_errors = False, form_parser_class = FormParser, request_class = urllib2.Request, entitydefs = None, backwards_compat = False, encoding = DEFAULT_ENCODING, _urljoin = urlparse.urljoin, _urlparse = urlparse.urlparse, _urlunparse = urlparse.urlunparse):
  921.     if backwards_compat:
  922.         deprecation('operating in backwards-compatibility mode', 1)
  923.     
  924.     fp = form_parser_class(entitydefs, encoding)
  925.     while None:
  926.         data = file.read(CHUNK)
  927.         
  928.         try:
  929.             fp.feed(data)
  930.         except ParseError:
  931.             e = None
  932.             e.base_uri = base_uri
  933.             raise 
  934.  
  935.         if len(data) != CHUNK:
  936.             break
  937.             continue
  938.         continue
  939.         if fp.base is not None:
  940.             base_uri = fp.base
  941.         
  942.     labels = []
  943.     id_to_labels = { }
  944.     for l in fp.labels:
  945.         label = Label(l)
  946.         labels.append(label)
  947.         for_id = l['for']
  948.         coll = id_to_labels.get(for_id)
  949.         if coll is None:
  950.             id_to_labels[for_id] = [
  951.                 label]
  952.             continue
  953.         coll.append(label)
  954.     
  955.     forms = []
  956.     for name, action, method, enctype in fp.forms:
  957.         attrs = None
  958.         controls = None
  959.         if action is None:
  960.             action = base_uri
  961.         else:
  962.             action = _urljoin(base_uri, action)
  963.         form = HTMLForm(action, method, enctype, name, attrs, request_class, forms, labels, id_to_labels, backwards_compat)
  964.         form._urlparse = _urlparse
  965.         form._urlunparse = _urlunparse
  966.         for ii in range(len(controls)):
  967.             (type, name, attrs) = controls[ii]
  968.             form.new_control(type, name, attrs, select_default = select_default, index = ii * 10)
  969.         
  970.         forms.append(form)
  971.     
  972.     for form in forms:
  973.         form.fixup()
  974.     
  975.     return forms
  976.  
  977.  
  978. class Label:
  979.     
  980.     def __init__(self, attrs):
  981.         self.id = attrs.get('for')
  982.         self._text = attrs.get('__text').strip()
  983.         self._ctext = compress_text(self._text)
  984.         self.attrs = attrs
  985.         self._backwards_compat = False
  986.  
  987.     
  988.     def __getattr__(self, name):
  989.         if name == 'text':
  990.             if self._backwards_compat:
  991.                 return self._text
  992.             return self._ctext
  993.         name == 'text'
  994.         return getattr(Label, name)
  995.  
  996.     
  997.     def __setattr__(self, name, value):
  998.         if name == 'text':
  999.             raise AttributeError('text attribute is read-only')
  1000.         name == 'text'
  1001.         self.__dict__[name] = value
  1002.  
  1003.     
  1004.     def __str__(self):
  1005.         return '<Label(id=%r, text=%r)>' % (self.id, self.text)
  1006.  
  1007.  
  1008.  
  1009. def _get_label(attrs):
  1010.     text = attrs.get('__label')
  1011.     if text is not None:
  1012.         return Label(text)
  1013.     return None
  1014.  
  1015.  
  1016. class Control:
  1017.     
  1018.     def __init__(self, type, name, attrs, index = None):
  1019.         raise NotImplementedError()
  1020.  
  1021.     
  1022.     def add_to_form(self, form):
  1023.         self._form = form
  1024.         form.controls.append(self)
  1025.  
  1026.     
  1027.     def fixup(self):
  1028.         pass
  1029.  
  1030.     
  1031.     def is_of_kind(self, kind):
  1032.         raise NotImplementedError()
  1033.  
  1034.     
  1035.     def clear(self):
  1036.         raise NotImplementedError()
  1037.  
  1038.     
  1039.     def __getattr__(self, name):
  1040.         raise NotImplementedError()
  1041.  
  1042.     
  1043.     def __setattr__(self, name, value):
  1044.         raise NotImplementedError()
  1045.  
  1046.     
  1047.     def pairs(self):
  1048.         return [ (k, v) for i, k, v in self._totally_ordered_pairs() ]
  1049.  
  1050.     
  1051.     def _totally_ordered_pairs(self):
  1052.         raise NotImplementedError()
  1053.  
  1054.     
  1055.     def _write_mime_data(self, mw, name, value):
  1056.         mw2 = mw.nextpart()
  1057.         mw2.addheader('Content-disposition', 'form-data; name="%s"' % name, 1)
  1058.         f = mw2.startbody(prefix = 0)
  1059.         f.write(value)
  1060.  
  1061.     
  1062.     def __str__(self):
  1063.         raise NotImplementedError()
  1064.  
  1065.     
  1066.     def get_labels(self):
  1067.         res = []
  1068.         if self._label:
  1069.             res.append(self._label)
  1070.         
  1071.         if self.id:
  1072.             res.extend(self._form._id_to_labels.get(self.id, ()))
  1073.         
  1074.         return res
  1075.  
  1076.  
  1077.  
  1078. class ScalarControl(Control):
  1079.     
  1080.     def __init__(self, type, name, attrs, index = None):
  1081.         self._index = index
  1082.         self._label = _get_label(attrs)
  1083.         self.__dict__['type'] = type.lower()
  1084.         self.__dict__['name'] = name
  1085.         self._value = attrs.get('value')
  1086.         self.disabled = attrs.has_key('disabled')
  1087.         self.readonly = attrs.has_key('readonly')
  1088.         self.id = attrs.get('id')
  1089.         self.attrs = attrs.copy()
  1090.         self._clicked = False
  1091.         self._urlparse = urlparse.urlparse
  1092.         self._urlunparse = urlparse.urlunparse
  1093.  
  1094.     
  1095.     def __getattr__(self, name):
  1096.         if name == 'value':
  1097.             return self.__dict__['_value']
  1098.         raise AttributeError("%s instance has no attribute '%s'" % (self.__class__.__name__, name))
  1099.  
  1100.     
  1101.     def __setattr__(self, name, value):
  1102.         if name == 'value':
  1103.             if not isstringlike(value):
  1104.                 raise TypeError('must assign a string')
  1105.             isstringlike(value)
  1106.             if self.readonly:
  1107.                 raise AttributeError("control '%s' is readonly" % self.name)
  1108.             self.readonly
  1109.             if self.disabled:
  1110.                 raise AttributeError("control '%s' is disabled" % self.name)
  1111.             self.disabled
  1112.             self.__dict__['_value'] = value
  1113.         elif name in ('name', 'type'):
  1114.             raise AttributeError('%s attribute is readonly' % name)
  1115.         else:
  1116.             self.__dict__[name] = value
  1117.  
  1118.     
  1119.     def _totally_ordered_pairs(self):
  1120.         name = self.name
  1121.         value = self.value
  1122.         if name is None and value is None or self.disabled:
  1123.             return []
  1124.         return [
  1125.             (self._index, name, value)]
  1126.  
  1127.     
  1128.     def clear(self):
  1129.         if self.readonly:
  1130.             raise AttributeError("control '%s' is readonly" % self.name)
  1131.         self.readonly
  1132.         self.__dict__['_value'] = None
  1133.  
  1134.     
  1135.     def __str__(self):
  1136.         name = self.name
  1137.         value = self.value
  1138.         if name is None:
  1139.             name = '<None>'
  1140.         
  1141.         if value is None:
  1142.             value = '<None>'
  1143.         
  1144.         infos = []
  1145.         if self.disabled:
  1146.             infos.append('disabled')
  1147.         
  1148.         if self.readonly:
  1149.             infos.append('readonly')
  1150.         
  1151.         info = ', '.join(infos)
  1152.         if info:
  1153.             info = ' (%s)' % info
  1154.         
  1155.         return '<%s(%s=%s)%s>' % (self.__class__.__name__, name, value, info)
  1156.  
  1157.  
  1158.  
  1159. class TextControl(ScalarControl):
  1160.     
  1161.     def __init__(self, type, name, attrs, index = None):
  1162.         ScalarControl.__init__(self, type, name, attrs, index)
  1163.         if self.type == 'hidden':
  1164.             self.readonly = True
  1165.         
  1166.         if self._value is None:
  1167.             self._value = ''
  1168.         
  1169.  
  1170.     
  1171.     def is_of_kind(self, kind):
  1172.         return kind == 'text'
  1173.  
  1174.  
  1175.  
  1176. class FileControl(ScalarControl):
  1177.     
  1178.     def __init__(self, type, name, attrs, index = None):
  1179.         ScalarControl.__init__(self, type, name, attrs, index)
  1180.         self._value = None
  1181.         self._upload_data = []
  1182.  
  1183.     
  1184.     def is_of_kind(self, kind):
  1185.         return kind == 'file'
  1186.  
  1187.     
  1188.     def clear(self):
  1189.         if self.readonly:
  1190.             raise AttributeError("control '%s' is readonly" % self.name)
  1191.         self.readonly
  1192.         self._upload_data = []
  1193.  
  1194.     
  1195.     def __setattr__(self, name, value):
  1196.         if name in ('value', 'name', 'type'):
  1197.             raise AttributeError('%s attribute is readonly' % name)
  1198.         name in ('value', 'name', 'type')
  1199.         self.__dict__[name] = value
  1200.  
  1201.     
  1202.     def add_file(self, file_object, content_type = None, filename = None):
  1203.         if not hasattr(file_object, 'read'):
  1204.             raise TypeError('file-like object must have read method')
  1205.         hasattr(file_object, 'read')
  1206.         if content_type is not None and not isstringlike(content_type):
  1207.             raise TypeError('content type must be None or string-like')
  1208.         not isstringlike(content_type)
  1209.         if filename is not None and not isstringlike(filename):
  1210.             raise TypeError('filename must be None or string-like')
  1211.         not isstringlike(filename)
  1212.         if content_type is None:
  1213.             content_type = 'application/octet-stream'
  1214.         
  1215.         self._upload_data.append((file_object, content_type, filename))
  1216.  
  1217.     
  1218.     def _totally_ordered_pairs(self):
  1219.         if self.name is None or self.disabled:
  1220.             return []
  1221.         return [
  1222.             (self._index, self.name, '')]
  1223.  
  1224.     
  1225.     def _write_mime_data(self, mw, _name, _value):
  1226.         if len(self._upload_data) == 1:
  1227.             (file_object, content_type, filename) = self._upload_data[0]
  1228.             mw2 = mw.nextpart()
  1229.             if not filename or '; filename="%s"' % filename:
  1230.                 pass
  1231.             fn_part = ''
  1232.             disp = 'form-data; name="%s"%s' % (self.name, fn_part)
  1233.             mw2.addheader('Content-disposition', disp, prefix = 1)
  1234.             fh = mw2.startbody(content_type, prefix = 0)
  1235.             fh.write(file_object.read())
  1236.         elif len(self._upload_data) != 0:
  1237.             mw2 = mw.nextpart()
  1238.             disp = 'form-data; name="%s"' % self.name
  1239.             mw2.addheader('Content-disposition', disp, prefix = 1)
  1240.             fh = mw2.startmultipartbody('mixed', prefix = 0)
  1241.             for file_object, content_type, filename in self._upload_data:
  1242.                 mw3 = mw2.nextpart()
  1243.                 if not filename or '; filename="%s"' % filename:
  1244.                     pass
  1245.                 fn_part = ''
  1246.                 disp = 'file%s' % fn_part
  1247.                 mw3.addheader('Content-disposition', disp, prefix = 1)
  1248.                 fh2 = mw3.startbody(content_type, prefix = 0)
  1249.                 fh2.write(file_object.read())
  1250.             
  1251.             mw2.lastpart()
  1252.         
  1253.  
  1254.     
  1255.     def __str__(self):
  1256.         name = self.name
  1257.         if name is None:
  1258.             name = '<None>'
  1259.         
  1260.         if not self._upload_data:
  1261.             value = '<No files added>'
  1262.         else:
  1263.             value = []
  1264.             for file, ctype, filename in self._upload_data:
  1265.                 if filename is None:
  1266.                     value.append('<Unnamed file>')
  1267.                     continue
  1268.                 value.append(filename)
  1269.             
  1270.             value = ', '.join(value)
  1271.         info = []
  1272.         if self.disabled:
  1273.             info.append('disabled')
  1274.         
  1275.         if self.readonly:
  1276.             info.append('readonly')
  1277.         
  1278.         info = ', '.join(info)
  1279.         if info:
  1280.             info = ' (%s)' % info
  1281.         
  1282.         return '<%s(%s=%s)%s>' % (self.__class__.__name__, name, value, info)
  1283.  
  1284.  
  1285.  
  1286. class IsindexControl(ScalarControl):
  1287.     
  1288.     def __init__(self, type, name, attrs, index = None):
  1289.         ScalarControl.__init__(self, type, name, attrs, index)
  1290.         if self._value is None:
  1291.             self._value = ''
  1292.         
  1293.  
  1294.     
  1295.     def is_of_kind(self, kind):
  1296.         return kind in ('text', 'clickable')
  1297.  
  1298.     
  1299.     def _totally_ordered_pairs(self):
  1300.         return []
  1301.  
  1302.     
  1303.     def _click(self, form, coord, return_type, request_class = urllib2.Request):
  1304.         parts = self._urlparse(form.action)
  1305.         rest = parts[:-2]
  1306.         (query, frag) = parts[-2:]
  1307.         parts = rest + (urllib.quote_plus(self.value), None)
  1308.         url = self._urlunparse(parts)
  1309.         req_data = (url, None, [])
  1310.         if return_type == 'pairs':
  1311.             return []
  1312.         if return_type == 'request_data':
  1313.             return req_data
  1314.         return request_class(url)
  1315.  
  1316.     
  1317.     def __str__(self):
  1318.         value = self.value
  1319.         if value is None:
  1320.             value = '<None>'
  1321.         
  1322.         infos = []
  1323.         if self.disabled:
  1324.             infos.append('disabled')
  1325.         
  1326.         if self.readonly:
  1327.             infos.append('readonly')
  1328.         
  1329.         info = ', '.join(infos)
  1330.         if info:
  1331.             info = ' (%s)' % info
  1332.         
  1333.         return '<%s(%s)%s>' % (self.__class__.__name__, value, info)
  1334.  
  1335.  
  1336.  
  1337. class IgnoreControl(ScalarControl):
  1338.     
  1339.     def __init__(self, type, name, attrs, index = None):
  1340.         ScalarControl.__init__(self, type, name, attrs, index)
  1341.         self._value = None
  1342.  
  1343.     
  1344.     def is_of_kind(self, kind):
  1345.         return False
  1346.  
  1347.     
  1348.     def __setattr__(self, name, value):
  1349.         if name == 'value':
  1350.             raise AttributeError("control '%s' is ignored, hence read-only" % self.name)
  1351.         name == 'value'
  1352.         if name in ('name', 'type'):
  1353.             raise AttributeError('%s attribute is readonly' % name)
  1354.         name in ('name', 'type')
  1355.         self.__dict__[name] = value
  1356.  
  1357.  
  1358.  
  1359. class Item:
  1360.     
  1361.     def __init__(self, control, attrs, index = None):
  1362.         label = _get_label(attrs)
  1363.         if not label or [
  1364.             label]:
  1365.             pass
  1366.         self.__dict__.update({
  1367.             'name': attrs['value'],
  1368.             '_labels': [],
  1369.             'attrs': attrs,
  1370.             '_control': control,
  1371.             'disabled': attrs.has_key('disabled'),
  1372.             '_selected': False,
  1373.             'id': attrs.get('id'),
  1374.             '_index': index })
  1375.         control.items.append(self)
  1376.  
  1377.     
  1378.     def get_labels(self):
  1379.         res = []
  1380.         res.extend(self._labels)
  1381.         if self.id:
  1382.             res.extend(self._control._form._id_to_labels.get(self.id, ()))
  1383.         
  1384.         return res
  1385.  
  1386.     
  1387.     def __getattr__(self, name):
  1388.         if name == 'selected':
  1389.             return self._selected
  1390.         raise AttributeError(name)
  1391.  
  1392.     
  1393.     def __setattr__(self, name, value):
  1394.         if name == 'selected':
  1395.             self._control._set_selected_state(self, value)
  1396.         elif name == 'disabled':
  1397.             self.__dict__['disabled'] = bool(value)
  1398.         else:
  1399.             raise AttributeError(name)
  1400.         return name == 'selected'
  1401.  
  1402.     
  1403.     def __str__(self):
  1404.         res = self.name
  1405.         if self.selected:
  1406.             res = '*' + res
  1407.         
  1408.         if self.disabled:
  1409.             res = '(%s)' % res
  1410.         
  1411.         return res
  1412.  
  1413.     
  1414.     def __repr__(self):
  1415.         attrs = [
  1416.             ('name', self.name),
  1417.             ('id', self.id)] + self.attrs.items()
  1418.         return ' '.join % ([], []([ '%s=%r' % (k, v) for k, v in attrs ]))
  1419.  
  1420.  
  1421.  
  1422. def disambiguate(items, nr, **kwds):
  1423.     msgs = []
  1424.     for key, value in kwds.items():
  1425.         msgs.append('%s=%r' % (key, value))
  1426.     
  1427.     msg = ' '.join(msgs)
  1428.     if not items:
  1429.         raise ItemNotFoundError(msg)
  1430.     items
  1431.     if nr is None:
  1432.         if len(items) > 1:
  1433.             raise AmbiguityError(msg)
  1434.         len(items) > 1
  1435.         nr = 0
  1436.     
  1437.     if len(items) <= nr:
  1438.         raise ItemNotFoundError(msg)
  1439.     len(items) <= nr
  1440.     return items[nr]
  1441.  
  1442.  
  1443. class ListControl(Control):
  1444.     _label = None
  1445.     
  1446.     def __init__(self, type, name, attrs = { }, select_default = False, called_as_base_class = False, index = None):
  1447.         if not called_as_base_class:
  1448.             raise NotImplementedError()
  1449.         called_as_base_class
  1450.         self.__dict__['type'] = type.lower()
  1451.         self.__dict__['name'] = name
  1452.         self._value = attrs.get('value')
  1453.         self.disabled = False
  1454.         self.readonly = False
  1455.         self.id = attrs.get('id')
  1456.         self._closed = False
  1457.         self.items = []
  1458.         self._form = None
  1459.         self._select_default = select_default
  1460.         self._clicked = False
  1461.  
  1462.     
  1463.     def clear(self):
  1464.         self.value = []
  1465.  
  1466.     
  1467.     def is_of_kind(self, kind):
  1468.         if kind == 'list':
  1469.             return True
  1470.         if kind == 'multilist':
  1471.             return bool(self.multiple)
  1472.         if kind == 'singlelist':
  1473.             return not (self.multiple)
  1474.         return False
  1475.  
  1476.     
  1477.     def get_items(self, name = None, label = None, id = None, exclude_disabled = False):
  1478.         if name is not None and not isstringlike(name):
  1479.             raise TypeError('item name must be string-like')
  1480.         not isstringlike(name)
  1481.         if label is not None and not isstringlike(label):
  1482.             raise TypeError('item label must be string-like')
  1483.         not isstringlike(label)
  1484.         if id is not None and not isstringlike(id):
  1485.             raise TypeError('item id must be string-like')
  1486.         not isstringlike(id)
  1487.         items = []
  1488.         compat = self._form.backwards_compat
  1489.         for o in self.items:
  1490.             if exclude_disabled and o.disabled:
  1491.                 continue
  1492.             
  1493.             if name is not None and o.name != name:
  1494.                 continue
  1495.             
  1496.             if label is not None:
  1497.                 for l in o.get_labels():
  1498.                     if (compat or l.text == label or not compat) and l.text.find(label) > -1:
  1499.                         break
  1500.                         continue
  1501.                 
  1502.             
  1503.             if id is not None and o.id != id:
  1504.                 continue
  1505.             
  1506.             items.append(o)
  1507.         
  1508.         return items
  1509.  
  1510.     
  1511.     def get(self, name = None, label = None, id = None, nr = None, exclude_disabled = False):
  1512.         if nr is None and self._form.backwards_compat:
  1513.             nr = 0
  1514.         
  1515.         items = self.get_items(name, label, id, exclude_disabled)
  1516.         return disambiguate(items, nr, name = name, label = label, id = id)
  1517.  
  1518.     
  1519.     def _get(self, name, by_label = False, nr = None, exclude_disabled = False):
  1520.         if by_label:
  1521.             name = None
  1522.             label = name
  1523.         else:
  1524.             name = name
  1525.             label = None
  1526.         return self.get(name, label, nr, exclude_disabled)
  1527.  
  1528.     
  1529.     def toggle(self, name, by_label = False, nr = None):
  1530.         deprecation('item = control.get(...); item.selected = not item.selected')
  1531.         o = self._get(name, by_label, nr)
  1532.         self._set_selected_state(o, not (o.selected))
  1533.  
  1534.     
  1535.     def set(self, selected, name, by_label = False, nr = None):
  1536.         deprecation('control.get(...).selected = <boolean>')
  1537.         self._set_selected_state(self._get(name, by_label, nr), selected)
  1538.  
  1539.     
  1540.     def _set_selected_state(self, item, action):
  1541.         if self.disabled:
  1542.             raise AttributeError("control '%s' is disabled" % self.name)
  1543.         self.disabled
  1544.         if self.readonly:
  1545.             raise AttributeError("control '%s' is readonly" % self.name)
  1546.         self.readonly
  1547.         action == bool(action)
  1548.         compat = self._form.backwards_compat
  1549.         if not compat and item.disabled:
  1550.             raise AttributeError('item is disabled')
  1551.         item.disabled
  1552.         if compat and item.disabled and action:
  1553.             raise AttributeError('item is disabled')
  1554.         action
  1555.         if self.multiple:
  1556.             item.__dict__['_selected'] = action
  1557.         elif not action:
  1558.             item.__dict__['_selected'] = False
  1559.         else:
  1560.             for o in self.items:
  1561.                 o.__dict__['_selected'] = False
  1562.             
  1563.             item.__dict__['_selected'] = True
  1564.  
  1565.     
  1566.     def toggle_single(self, by_label = None):
  1567.         deprecation('control.items[0].selected = not control.items[0].selected')
  1568.         if len(self.items) != 1:
  1569.             raise ItemCountError("'%s' is not a single-item control" % self.name)
  1570.         len(self.items) != 1
  1571.         item = self.items[0]
  1572.         self._set_selected_state(item, not (item.selected))
  1573.  
  1574.     
  1575.     def set_single(self, selected, by_label = None):
  1576.         deprecation('control.items[0].selected = <boolean>')
  1577.         if len(self.items) != 1:
  1578.             raise ItemCountError("'%s' is not a single-item control" % self.name)
  1579.         len(self.items) != 1
  1580.         self._set_selected_state(self.items[0], selected)
  1581.  
  1582.     
  1583.     def get_item_disabled(self, name, by_label = False, nr = None):
  1584.         deprecation('control.get(...).disabled')
  1585.         return self._get(name, by_label, nr).disabled
  1586.  
  1587.     
  1588.     def set_item_disabled(self, disabled, name, by_label = False, nr = None):
  1589.         deprecation('control.get(...).disabled = <boolean>')
  1590.         self._get(name, by_label, nr).disabled = disabled
  1591.  
  1592.     
  1593.     def set_all_items_disabled(self, disabled):
  1594.         for o in self.items:
  1595.             o.disabled = disabled
  1596.         
  1597.  
  1598.     
  1599.     def get_item_attrs(self, name, by_label = False, nr = None):
  1600.         deprecation('control.get(...).attrs')
  1601.         return self._get(name, by_label, nr).attrs
  1602.  
  1603.     
  1604.     def close_control(self):
  1605.         self._closed = True
  1606.  
  1607.     
  1608.     def add_to_form(self, form):
  1609.         self._form = form
  1610.         if self.name is None:
  1611.             Control.add_to_form(self, form)
  1612.         else:
  1613.             for ii in range(len(form.controls) - 1, -1, -1):
  1614.                 control = form.controls[ii]
  1615.                 if control.name == self.name and control.type == self.type:
  1616.                     if control._closed:
  1617.                         Control.add_to_form(self, form)
  1618.                     else:
  1619.                         control.merge_control(self)
  1620.                     break
  1621.                     continue
  1622.             
  1623.  
  1624.     
  1625.     def merge_control(self, control):
  1626.         self.items.extend(control.items)
  1627.  
  1628.     
  1629.     def fixup(self):
  1630.         for o in self.items:
  1631.             o.__dict__['_control'] = self
  1632.         
  1633.  
  1634.     
  1635.     def __getattr__(self, name):
  1636.         if name == 'value':
  1637.             compat = self._form.backwards_compat
  1638.             if self.name is None:
  1639.                 return []
  1640.             return _[1]
  1641.         raise AttributeError("%s instance has no attribute '%s'" % (self.__class__.__name__, name))
  1642.  
  1643.     
  1644.     def __setattr__(self, name, value):
  1645.         if name == 'value':
  1646.             if self.disabled:
  1647.                 raise AttributeError("control '%s' is disabled" % self.name)
  1648.             self.disabled
  1649.             if self.readonly:
  1650.                 raise AttributeError("control '%s' is readonly" % self.name)
  1651.             self.readonly
  1652.             self._set_value(value)
  1653.         elif name in ('name', 'type', 'multiple'):
  1654.             raise AttributeError('%s attribute is readonly' % name)
  1655.         else:
  1656.             self.__dict__[name] = value
  1657.  
  1658.     
  1659.     def _set_value(self, value):
  1660.         if value is None or isstringlike(value):
  1661.             raise TypeError('ListControl, must set a sequence')
  1662.         isstringlike(value)
  1663.         if not value:
  1664.             compat = self._form.backwards_compat
  1665.             for o in self.items:
  1666.                 if not (o.disabled) or compat:
  1667.                     o.selected = False
  1668.                     continue
  1669.             
  1670.         elif self.multiple:
  1671.             self._multiple_set_value(value)
  1672.         elif len(value) > 1:
  1673.             raise ItemCountError('single selection list, must set sequence of length 0 or 1')
  1674.         else:
  1675.             self._single_set_value(value)
  1676.  
  1677.     
  1678.     def _get_items(self, name, target = 1):
  1679.         all_items = self.get_items(name)
  1680.         items = _[1]
  1681.         if len(items) < target:
  1682.             if len(all_items) < target:
  1683.                 raise ItemNotFoundError('insufficient items with name %r' % name)
  1684.             len(all_items) < target
  1685.             raise AttributeError('insufficient non-disabled items with name %s' % name)
  1686.         len(items) < target
  1687.         on = []
  1688.         off = []
  1689.         for o in items:
  1690.             if o.selected:
  1691.                 on.append(o)
  1692.                 continue
  1693.             []
  1694.             off.append(o)
  1695.         
  1696.         return (on, off)
  1697.  
  1698.     
  1699.     def _single_set_value(self, value):
  1700.         (on, off) = self._get_items(value[0])
  1701.         if not on:
  1702.             off[0].selected = True
  1703.         
  1704.  
  1705.     
  1706.     def _multiple_set_value(self, value):
  1707.         compat = self._form.backwards_compat
  1708.         turn_on = []
  1709.         turn_off = _[1]
  1710.         names = { }
  1711.         for nn in value:
  1712.             if nn in names.keys():
  1713.                 names[nn] += 1
  1714.                 continue
  1715.             []
  1716.             names[nn] = 1
  1717.         
  1718.         for name, count in names.items():
  1719.             (on, off) = self._get_items(name, count)
  1720.             for i in range(count):
  1721.                 if on:
  1722.                     item = on[0]
  1723.                     del on[0]
  1724.                     del turn_off[turn_off.index(item)]
  1725.                     continue
  1726.                 []
  1727.                 item = off[0]
  1728.                 del off[0]
  1729.                 turn_on.append(item)
  1730.             
  1731.         
  1732.         for item in turn_off:
  1733.             item.selected = False
  1734.         
  1735.         for item in turn_on:
  1736.             item.selected = True
  1737.         
  1738.  
  1739.     
  1740.     def set_value_by_label(self, value):
  1741.         if isstringlike(value):
  1742.             raise TypeError(value)
  1743.         isstringlike(value)
  1744.         if not (self.multiple) and len(value) > 1:
  1745.             raise ItemCountError('single selection list, must set sequence of length 0 or 1')
  1746.         len(value) > 1
  1747.         items = []
  1748.         for nn in value:
  1749.             found = self.get_items(label = nn)
  1750.             if len(found) > 1:
  1751.                 if not self._form.backwards_compat:
  1752.                     opt_name = found[0].name
  1753.                     if _[1]:
  1754.                         raise AmbiguityError(nn)
  1755.                     _[1]
  1756.                 else:
  1757.                     found = found[:1]
  1758.             
  1759.             for o in found:
  1760.                 if self._form.backwards_compat or o not in items:
  1761.                     items.append(o)
  1762.                     break
  1763.                     continue
  1764.             else:
  1765.                 raise ItemNotFoundError(nn)
  1766.         
  1767.         self.value = []
  1768.         for o in items:
  1769.             o.selected = True
  1770.         
  1771.  
  1772.     
  1773.     def get_value_by_label(self):
  1774.         res = []
  1775.         compat = self._form.backwards_compat
  1776.         for o in self.items:
  1777.             if (not (o.disabled) or compat) and o.selected:
  1778.                 for l in o.get_labels():
  1779.                     if l.text:
  1780.                         res.append(l.text)
  1781.                         break
  1782.                         continue
  1783.                 
  1784.         
  1785.         return res
  1786.  
  1787.     
  1788.     def possible_items(self, by_label = False):
  1789.         deprecation('[item.name for item in self.items]')
  1790.         if by_label:
  1791.             res = []
  1792.             for o in self.items:
  1793.                 for l in o.get_labels():
  1794.                     if l.text:
  1795.                         res.append(l.text)
  1796.                         break
  1797.                         continue
  1798.                 
  1799.             
  1800.             return res
  1801.         return [ o.name for o in self.items ]
  1802.  
  1803.     
  1804.     def _totally_ordered_pairs(self):
  1805.         if self.disabled or self.name is None:
  1806.             return []
  1807.         return _[1]
  1808.  
  1809.     
  1810.     def __str__(self):
  1811.         name = self.name
  1812.         if name is None:
  1813.             name = '<None>'
  1814.         
  1815.         display = [ str(o) for o in self.items ]
  1816.         infos = []
  1817.         if self.readonly:
  1818.             infos.append('readonly')
  1819.         
  1820.         info = ', '.join(infos)
  1821.         if info:
  1822.             info = ' (%s)' % info
  1823.         
  1824.         return '<%s(%s=[%s])%s>' % (self.__class__.__name__, name, ', '.join(display), info)
  1825.  
  1826.  
  1827.  
  1828. class RadioControl(ListControl):
  1829.     
  1830.     def __init__(self, type, name, attrs, select_default = False, index = None):
  1831.         attrs.setdefault('value', 'on')
  1832.         ListControl.__init__(self, type, name, attrs, select_default, called_as_base_class = True, index = index)
  1833.         self.__dict__['multiple'] = False
  1834.         o = Item(self, attrs, index)
  1835.         o.__dict__['_selected'] = attrs.has_key('checked')
  1836.  
  1837.     
  1838.     def fixup(self):
  1839.         ListControl.fixup(self)
  1840.         found = _[1]
  1841.  
  1842.     
  1843.     def get_labels(self):
  1844.         return []
  1845.  
  1846.  
  1847.  
  1848. class CheckboxControl(ListControl):
  1849.     
  1850.     def __init__(self, type, name, attrs, select_default = False, index = None):
  1851.         attrs.setdefault('value', 'on')
  1852.         ListControl.__init__(self, type, name, attrs, select_default, called_as_base_class = True, index = index)
  1853.         self.__dict__['multiple'] = True
  1854.         o = Item(self, attrs, index)
  1855.         o.__dict__['_selected'] = attrs.has_key('checked')
  1856.  
  1857.     
  1858.     def get_labels(self):
  1859.         return []
  1860.  
  1861.  
  1862.  
  1863. class SelectControl(ListControl):
  1864.     
  1865.     def __init__(self, type, name, attrs, select_default = False, index = None):
  1866.         self.attrs = attrs['__select'].copy()
  1867.         self.__dict__['_label'] = _get_label(self.attrs)
  1868.         self.__dict__['id'] = self.attrs.get('id')
  1869.         self.__dict__['multiple'] = self.attrs.has_key('multiple')
  1870.         contents = attrs.get('contents')
  1871.         attrs = attrs.copy()
  1872.         del attrs['__select']
  1873.         ListControl.__init__(self, type, name, self.attrs, select_default, called_as_base_class = True, index = index)
  1874.         self.disabled = self.attrs.has_key('disabled')
  1875.         self.readonly = self.attrs.has_key('readonly')
  1876.         if attrs.has_key('value'):
  1877.             o = Item(self, attrs, index)
  1878.             o.__dict__['_selected'] = attrs.has_key('selected')
  1879.             label = attrs.get('label')
  1880.             if label:
  1881.                 o._labels.append(Label({
  1882.                     '__text': label }))
  1883.                 if contents and contents != label:
  1884.                     o._labels.append(Label({
  1885.                         '__text': contents }))
  1886.                 
  1887.             elif contents:
  1888.                 o._labels.append(Label({
  1889.                     '__text': contents }))
  1890.             
  1891.         
  1892.  
  1893.     
  1894.     def fixup(self):
  1895.         ListControl.fixup(self)
  1896.         found = _[1]
  1897.         if not found:
  1898.             if not (self.multiple) or self._select_default:
  1899.                 for o in self.items:
  1900.                     if not o.disabled:
  1901.                         was_disabled = self.disabled
  1902.                         self.disabled = False
  1903.                         
  1904.                         try:
  1905.                             o.selected = True
  1906.                         finally:
  1907.                             o.disabled = was_disabled
  1908.  
  1909.                         break
  1910.                         continue
  1911.                     []
  1912.                 
  1913.             
  1914.         elif not self.multiple:
  1915.             for o in found[:-1]:
  1916.                 o.selected = False
  1917.             
  1918.         
  1919.  
  1920.  
  1921.  
  1922. class SubmitControl(ScalarControl):
  1923.     
  1924.     def __init__(self, type, name, attrs, index = None):
  1925.         ScalarControl.__init__(self, type, name, attrs, index)
  1926.         if self.value is None:
  1927.             self.value = ''
  1928.         
  1929.         self.readonly = True
  1930.  
  1931.     
  1932.     def get_labels(self):
  1933.         res = []
  1934.         if self.value:
  1935.             res.append(Label({
  1936.                 '__text': self.value }))
  1937.         
  1938.         res.extend(ScalarControl.get_labels(self))
  1939.         return res
  1940.  
  1941.     
  1942.     def is_of_kind(self, kind):
  1943.         return kind == 'clickable'
  1944.  
  1945.     
  1946.     def _click(self, form, coord, return_type, request_class = urllib2.Request):
  1947.         self._clicked = coord
  1948.         r = form._switch_click(return_type, request_class)
  1949.         self._clicked = False
  1950.         return r
  1951.  
  1952.     
  1953.     def _totally_ordered_pairs(self):
  1954.         if not self._clicked:
  1955.             return []
  1956.         return ScalarControl._totally_ordered_pairs(self)
  1957.  
  1958.  
  1959.  
  1960. class ImageControl(SubmitControl):
  1961.     
  1962.     def __init__(self, type, name, attrs, index = None):
  1963.         SubmitControl.__init__(self, type, name, attrs, index)
  1964.         self.readonly = False
  1965.  
  1966.     
  1967.     def _totally_ordered_pairs(self):
  1968.         clicked = self._clicked
  1969.         if self.disabled or not clicked:
  1970.             return []
  1971.         name = self.name
  1972.         if name is None:
  1973.             return []
  1974.         pairs = [
  1975.             (self._index, '%s.x' % name, str(clicked[0])),
  1976.             (self._index + 1, '%s.y' % name, str(clicked[1]))]
  1977.         value = self._value
  1978.         return pairs
  1979.  
  1980.     get_labels = ScalarControl.get_labels
  1981.  
  1982.  
  1983. class PasswordControl(TextControl):
  1984.     pass
  1985.  
  1986.  
  1987. class HiddenControl(TextControl):
  1988.     pass
  1989.  
  1990.  
  1991. class TextareaControl(TextControl):
  1992.     pass
  1993.  
  1994.  
  1995. class SubmitButtonControl(SubmitControl):
  1996.     pass
  1997.  
  1998.  
  1999. def is_listcontrol(control):
  2000.     return control.is_of_kind('list')
  2001.  
  2002.  
  2003. class HTMLForm:
  2004.     type2class = {
  2005.         'text': TextControl,
  2006.         'password': PasswordControl,
  2007.         'hidden': HiddenControl,
  2008.         'textarea': TextareaControl,
  2009.         'isindex': IsindexControl,
  2010.         'file': FileControl,
  2011.         'button': IgnoreControl,
  2012.         'buttonbutton': IgnoreControl,
  2013.         'reset': IgnoreControl,
  2014.         'resetbutton': IgnoreControl,
  2015.         'submit': SubmitControl,
  2016.         'submitbutton': SubmitButtonControl,
  2017.         'image': ImageControl,
  2018.         'radio': RadioControl,
  2019.         'checkbox': CheckboxControl,
  2020.         'select': SelectControl }
  2021.     
  2022.     def __init__(self, action, method = 'GET', enctype = 'application/x-www-form-urlencoded', name = None, attrs = None, request_class = urllib2.Request, forms = None, labels = None, id_to_labels = None, backwards_compat = True):
  2023.         self.action = action
  2024.         self.method = method
  2025.         self.enctype = enctype
  2026.         self.name = name
  2027.         if attrs is not None:
  2028.             self.attrs = attrs.copy()
  2029.         else:
  2030.             self.attrs = { }
  2031.         self.controls = []
  2032.         self._request_class = request_class
  2033.         self._forms = forms
  2034.         self._labels = labels
  2035.         self._id_to_labels = id_to_labels
  2036.         self.backwards_compat = backwards_compat
  2037.         self._urlunparse = urlparse.urlunparse
  2038.         self._urlparse = urlparse.urlparse
  2039.  
  2040.     
  2041.     def __getattr__(self, name):
  2042.         if name == 'backwards_compat':
  2043.             return self._backwards_compat
  2044.         return getattr(HTMLForm, name)
  2045.  
  2046.     
  2047.     def __setattr__(self, name, value):
  2048.         if name == 'backwards_compat':
  2049.             name = '_backwards_compat'
  2050.             value = bool(value)
  2051.             for cc in self.controls:
  2052.                 
  2053.                 try:
  2054.                     items = cc.items
  2055.                 except AttributeError:
  2056.                     continue
  2057.                     continue
  2058.  
  2059.                 for ii in items:
  2060.                     for ll in ii.get_labels():
  2061.                         ll._backwards_compat = value
  2062.                     
  2063.                 
  2064.             
  2065.         
  2066.         self.__dict__[name] = value
  2067.  
  2068.     
  2069.     def new_control(self, type, name, attrs, ignore_unknown = False, select_default = False, index = None):
  2070.         type = type.lower()
  2071.         klass = self.type2class.get(type)
  2072.         if klass is None:
  2073.             if ignore_unknown:
  2074.                 klass = IgnoreControl
  2075.             else:
  2076.                 klass = TextControl
  2077.         
  2078.         a = attrs.copy()
  2079.         if issubclass(klass, ListControl):
  2080.             control = klass(type, name, a, select_default, index)
  2081.         else:
  2082.             control = klass(type, name, a, index)
  2083.         if type == 'select' and len(attrs) == 1:
  2084.             for ii in range(len(self.controls) - 1, -1, -1):
  2085.                 ctl = self.controls[ii]
  2086.                 if ctl.type == 'select':
  2087.                     ctl.close_control()
  2088.                     break
  2089.                     continue
  2090.             
  2091.         
  2092.         control.add_to_form(self)
  2093.         control._urlparse = self._urlparse
  2094.         control._urlunparse = self._urlunparse
  2095.  
  2096.     
  2097.     def fixup(self):
  2098.         for control in self.controls:
  2099.             control.fixup()
  2100.         
  2101.         self.backwards_compat = self._backwards_compat
  2102.  
  2103.     
  2104.     def __str__(self):
  2105.         if not self.name or self.name + ' ':
  2106.             pass
  2107.         header = '%s%s %s %s' % ('', self.method, self.action, self.enctype)
  2108.         rep = [
  2109.             header]
  2110.         for control in self.controls:
  2111.             rep.append('  %s' % str(control))
  2112.         
  2113.         return '<%s>' % '\n'.join(rep)
  2114.  
  2115.     
  2116.     def __getitem__(self, name):
  2117.         return self.find_control(name).value
  2118.  
  2119.     
  2120.     def __contains__(self, name):
  2121.         return bool(self.find_control(name))
  2122.  
  2123.     
  2124.     def __setitem__(self, name, value):
  2125.         control = self.find_control(name)
  2126.         
  2127.         try:
  2128.             control.value = value
  2129.         except AttributeError:
  2130.             e = None
  2131.             raise ValueError(str(e))
  2132.  
  2133.  
  2134.     
  2135.     def get_value(self, name = None, type = None, kind = None, id = None, nr = None, by_label = False, label = None):
  2136.         if by_label:
  2137.             deprecation('form.get_value_by_label(...)')
  2138.         
  2139.         c = self.find_control(name, type, kind, id, label = label, nr = nr)
  2140.         if by_label:
  2141.             
  2142.             try:
  2143.                 meth = c.get_value_by_label
  2144.             except AttributeError:
  2145.                 raise NotImplementedError("control '%s' does not yet support by_label" % c.name)
  2146.  
  2147.             return meth()
  2148.         by_label
  2149.         return c.value
  2150.  
  2151.     
  2152.     def set_value(self, value, name = None, type = None, kind = None, id = None, nr = None, by_label = False, label = None):
  2153.         if by_label:
  2154.             deprecation('form.get_value_by_label(...)')
  2155.         
  2156.         c = self.find_control(name, type, kind, id, label = label, nr = nr)
  2157.         if by_label:
  2158.             
  2159.             try:
  2160.                 meth = c.set_value_by_label
  2161.             except AttributeError:
  2162.                 raise NotImplementedError("control '%s' does not yet support by_label" % c.name)
  2163.  
  2164.             meth(value)
  2165.         else:
  2166.             c.value = value
  2167.  
  2168.     
  2169.     def get_value_by_label(self, name = None, type = None, kind = None, id = None, label = None, nr = None):
  2170.         c = self.find_control(name, type, kind, id, label = label, nr = nr)
  2171.         return c.get_value_by_label()
  2172.  
  2173.     
  2174.     def set_value_by_label(self, value, name = None, type = None, kind = None, id = None, label = None, nr = None):
  2175.         c = self.find_control(name, type, kind, id, label = label, nr = nr)
  2176.         c.set_value_by_label(value)
  2177.  
  2178.     
  2179.     def set_all_readonly(self, readonly):
  2180.         for control in self.controls:
  2181.             control.readonly = bool(readonly)
  2182.         
  2183.  
  2184.     
  2185.     def clear_all(self):
  2186.         for control in self.controls:
  2187.             control.clear()
  2188.         
  2189.  
  2190.     
  2191.     def clear(self, name = None, type = None, kind = None, id = None, nr = None, label = None):
  2192.         c = self.find_control(name, type, kind, id, label = label, nr = nr)
  2193.         c.clear()
  2194.  
  2195.     
  2196.     def possible_items(self, name = None, type = None, kind = None, id = None, nr = None, by_label = False, label = None):
  2197.         c = self._find_list_control(name, type, kind, id, label, nr)
  2198.         return c.possible_items(by_label)
  2199.  
  2200.     
  2201.     def set(self, selected, item_name, name = None, type = None, kind = None, id = None, nr = None, by_label = False, label = None):
  2202.         self._find_list_control(name, type, kind, id, label, nr).set(selected, item_name, by_label)
  2203.  
  2204.     
  2205.     def toggle(self, item_name, name = None, type = None, kind = None, id = None, nr = None, by_label = False, label = None):
  2206.         self._find_list_control(name, type, kind, id, label, nr).toggle(item_name, by_label)
  2207.  
  2208.     
  2209.     def set_single(self, selected, name = None, type = None, kind = None, id = None, nr = None, by_label = None, label = None):
  2210.         self._find_list_control(name, type, kind, id, label, nr).set_single(selected)
  2211.  
  2212.     
  2213.     def toggle_single(self, name = None, type = None, kind = None, id = None, nr = None, by_label = None, label = None):
  2214.         self._find_list_control(name, type, kind, id, label, nr).toggle_single()
  2215.  
  2216.     
  2217.     def add_file(self, file_object, content_type = None, filename = None, name = None, id = None, nr = None, label = None):
  2218.         self.find_control(name, 'file', id = id, label = label, nr = nr).add_file(file_object, content_type, filename)
  2219.  
  2220.     
  2221.     def click(self, name = None, type = None, id = None, nr = 0, coord = (1, 1), request_class = urllib2.Request, label = None):
  2222.         return self._click(name, type, id, label, nr, coord, 'request', self._request_class)
  2223.  
  2224.     
  2225.     def click_request_data(self, name = None, type = None, id = None, nr = 0, coord = (1, 1), request_class = urllib2.Request, label = None):
  2226.         return self._click(name, type, id, label, nr, coord, 'request_data', self._request_class)
  2227.  
  2228.     
  2229.     def click_pairs(self, name = None, type = None, id = None, nr = 0, coord = (1, 1), label = None):
  2230.         return self._click(name, type, id, label, nr, coord, 'pairs', self._request_class)
  2231.  
  2232.     
  2233.     def find_control(self, name = None, type = None, kind = None, id = None, predicate = None, nr = None, label = None):
  2234.         if name is None and type is None and kind is None and id is None and label is None and predicate is None and nr is None:
  2235.             raise ValueError('at least one argument must be supplied to specify control')
  2236.         nr is None
  2237.         return self._find_control(name, type, kind, id, label, predicate, nr)
  2238.  
  2239.     
  2240.     def _find_list_control(self, name = None, type = None, kind = None, id = None, label = None, nr = None):
  2241.         if name is None and type is None and kind is None and id is None and label is None and nr is None:
  2242.             raise ValueError('at least one argument must be supplied to specify control')
  2243.         nr is None
  2244.         return self._find_control(name, type, kind, id, label, is_listcontrol, nr)
  2245.  
  2246.     
  2247.     def _find_control(self, name, type, kind, id, label, predicate, nr):
  2248.         if name is not None and name is not Missing and not isstringlike(name):
  2249.             raise TypeError('control name must be string-like')
  2250.         not isstringlike(name)
  2251.         if type is not None and not isstringlike(type):
  2252.             raise TypeError('control type must be string-like')
  2253.         not isstringlike(type)
  2254.         if kind is not None and not isstringlike(kind):
  2255.             raise TypeError('control kind must be string-like')
  2256.         not isstringlike(kind)
  2257.         if id is not None and not isstringlike(id):
  2258.             raise TypeError('control id must be string-like')
  2259.         not isstringlike(id)
  2260.         if label is not None and not isstringlike(label):
  2261.             raise TypeError('control label must be string-like')
  2262.         not isstringlike(label)
  2263.         if predicate is not None and not callable(predicate):
  2264.             raise TypeError('control predicate must be callable')
  2265.         not callable(predicate)
  2266.         if nr is not None and nr < 0:
  2267.             raise ValueError('control number must be a positive integer')
  2268.         nr < 0
  2269.         orig_nr = nr
  2270.         found = None
  2271.         ambiguous = False
  2272.         if nr is None and self.backwards_compat:
  2273.             nr = 0
  2274.         
  2275.         for control in self.controls:
  2276.             if name is not None or name != control.name:
  2277.                 if name is not Missing or control.name is not None:
  2278.                     continue
  2279.                 
  2280.             if type is not None and type != control.type:
  2281.                 continue
  2282.             
  2283.             if kind is not None and not control.is_of_kind(kind):
  2284.                 continue
  2285.             
  2286.             if id is not None and id != control.id:
  2287.                 continue
  2288.             
  2289.             if predicate and not predicate(control):
  2290.                 continue
  2291.             
  2292.             if label:
  2293.                 for l in control.get_labels():
  2294.                     if l.text.find(label) > -1:
  2295.                         break
  2296.                         continue
  2297.                 
  2298.             
  2299.             if nr is not None:
  2300.                 if nr == 0:
  2301.                     return control
  2302.                 nr -= 1
  2303.                 continue
  2304.             
  2305.             if found:
  2306.                 ambiguous = True
  2307.                 break
  2308.             
  2309.             found = control
  2310.         
  2311.         if found and not ambiguous:
  2312.             return found
  2313.         description = []
  2314.         if name is not None:
  2315.             description.append('name %s' % repr(name))
  2316.         
  2317.         if type is not None:
  2318.             description.append("type '%s'" % type)
  2319.         
  2320.         if kind is not None:
  2321.             description.append("kind '%s'" % kind)
  2322.         
  2323.         if id is not None:
  2324.             description.append("id '%s'" % id)
  2325.         
  2326.         if label is not None:
  2327.             description.append("label '%s'" % label)
  2328.         
  2329.         if predicate is not None:
  2330.             description.append('predicate %s' % predicate)
  2331.         
  2332.         if orig_nr:
  2333.             description.append('nr %d' % orig_nr)
  2334.         
  2335.         description = ', '.join(description)
  2336.         if ambiguous:
  2337.             raise AmbiguityError('more than one control matching ' + description)
  2338.         ambiguous
  2339.         if not found:
  2340.             raise ControlNotFoundError('no control matching ' + description)
  2341.         found
  2342.  
  2343.     
  2344.     def _click(self, name, type, id, label, nr, coord, return_type, request_class = urllib2.Request):
  2345.         
  2346.         try:
  2347.             control = self._find_control(name, type, 'clickable', id, label, None, nr)
  2348.         except ControlNotFoundError:
  2349.             if name is not None and type is not None and id is not None or nr != 0:
  2350.                 raise 
  2351.             nr != 0
  2352.             return self._switch_click(return_type, request_class)
  2353.  
  2354.         return control._click(self, coord, return_type, request_class)
  2355.  
  2356.     
  2357.     def _pairs(self):
  2358.         return [ (k, v) for i, k, v, c_i in self._pairs_and_controls() ]
  2359.  
  2360.     
  2361.     def _pairs_and_controls(self):
  2362.         pairs = []
  2363.         for control_index in range(len(self.controls)):
  2364.             control = self.controls[control_index]
  2365.             for ii, key, val in control._totally_ordered_pairs():
  2366.                 pairs.append((ii, key, val, control_index))
  2367.             
  2368.         
  2369.         pairs.sort()
  2370.         return pairs
  2371.  
  2372.     
  2373.     def _request_data(self):
  2374.         method = self.method.upper()
  2375.         parts = self._urlparse(self.action)
  2376.         rest = parts[:-2]
  2377.         (query, frag) = parts[-2:]
  2378.         if method == 'GET':
  2379.             if self.enctype != 'application/x-www-form-urlencoded':
  2380.                 raise ValueError("unknown GET form encoding type '%s'" % self.enctype)
  2381.             self.enctype != 'application/x-www-form-urlencoded'
  2382.             parts = rest + (urlencode(self._pairs()), None)
  2383.             uri = self._urlunparse(parts)
  2384.             return (uri, None, [])
  2385.         if method == 'POST':
  2386.             parts = rest + (query, None)
  2387.             uri = self._urlunparse(parts)
  2388.             if self.enctype == 'application/x-www-form-urlencoded':
  2389.                 return (uri, urlencode(self._pairs()), [
  2390.                     ('Content-type', self.enctype)])
  2391.             if self.enctype == 'multipart/form-data':
  2392.                 data = StringIO()
  2393.                 http_hdrs = []
  2394.                 mw = MimeWriter(data, http_hdrs)
  2395.                 f = mw.startmultipartbody('form-data', add_to_http_hdrs = True, prefix = 0)
  2396.                 for ii, k, v, control_index in self._pairs_and_controls():
  2397.                     self.controls[control_index]._write_mime_data(mw, k, v)
  2398.                 
  2399.                 mw.lastpart()
  2400.                 return (uri, data.getvalue(), http_hdrs)
  2401.             raise ValueError("unknown POST form encoding type '%s'" % self.enctype)
  2402.         method == 'POST'
  2403.         raise ValueError("Unknown method '%s'" % method)
  2404.  
  2405.     
  2406.     def _switch_click(self, return_type, request_class = urllib2.Request):
  2407.         if return_type == 'pairs':
  2408.             return self._pairs()
  2409.         if return_type == 'request_data':
  2410.             return self._request_data()
  2411.         req_data = self._request_data()
  2412.         req = request_class(req_data[0], req_data[1])
  2413.         for key, val in req_data[2]:
  2414.             add_hdr = req.add_header
  2415.             if key.lower() == 'content-type':
  2416.                 
  2417.                 try:
  2418.                     add_hdr = req.add_unredirected_header
  2419.                 except AttributeError:
  2420.                     return_type == 'request_data'
  2421.                     return_type == 'request_data'
  2422.                     return_type == 'pairs'
  2423.                 except:
  2424.                     return_type == 'request_data'<EXCEPTION MATCH>AttributeError
  2425.                 
  2426.  
  2427.             return_type == 'request_data'
  2428.             add_hdr(key, val)
  2429.         
  2430.         return req
  2431.  
  2432.  
  2433.