home *** CD-ROM | disk | FTP | other *** search
/ Maximum CD 2010 November / maximum-cd-2010-11.iso / DiscContents / calibre-0.7.13.msi / file_1501 (.txt) < prev    next >
Encoding:
Python Compiled Bytecode  |  2010-08-06  |  78.7 KB  |  2,454 lines

  1. # Source Generated with Decompyle++
  2. # File: in.pyc (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.10'
  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.capitalize(), 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.title() + ': ' + 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 self._option is not None:
  629.             map = self._option
  630.             key = 'contents'
  631.         elif self._textarea is not None:
  632.             map = self._textarea
  633.             key = 'value'
  634.             data = normalize_line_endings(data)
  635.         elif self._current_label is not None:
  636.             map = self._current_label
  637.             key = '__text'
  638.         else:
  639.             return None
  640.         if self._option is not None and not map.has_key(key):
  641.             if data[0:2] == '\r\n':
  642.                 data = data[2:]
  643.             elif data[0:1] in ('\n', '\r'):
  644.                 data = data[1:]
  645.             
  646.             map[key] = data
  647.         else:
  648.             map[key] = map[key] + data
  649.  
  650.     
  651.     def do_button(self, attrs):
  652.         debug('%s', attrs)
  653.         d = { }
  654.         d['type'] = 'submit'
  655.         for key, val in attrs:
  656.             d[key] = self.unescape_attr_if_required(val)
  657.         
  658.         controls = self._current_form[2]
  659.         type = d['type']
  660.         name = d.get('name')
  661.         type = type + 'button'
  662.         self._add_label(d)
  663.         controls.append((type, name, d))
  664.  
  665.     
  666.     def do_input(self, attrs):
  667.         debug('%s', attrs)
  668.         d = { }
  669.         d['type'] = 'text'
  670.         for key, val in attrs:
  671.             d[key] = self.unescape_attr_if_required(val)
  672.         
  673.         controls = self._current_form[2]
  674.         type = d['type']
  675.         name = d.get('name')
  676.         self._add_label(d)
  677.         controls.append((type, name, d))
  678.  
  679.     
  680.     def do_isindex(self, attrs):
  681.         debug('%s', attrs)
  682.         d = { }
  683.         for key, val in attrs:
  684.             d[key] = self.unescape_attr_if_required(val)
  685.         
  686.         controls = self._current_form[2]
  687.         self._add_label(d)
  688.         controls.append(('isindex', None, d))
  689.  
  690.     
  691.     def handle_entityref(self, name):
  692.         self.handle_data(unescape('&%s;' % name, self._entitydefs, self._encoding))
  693.  
  694.     
  695.     def handle_charref(self, name):
  696.         self.handle_data(unescape_charref(name, self._encoding))
  697.  
  698.     
  699.     def unescape_attr(self, name):
  700.         return unescape(name, self._entitydefs, self._encoding)
  701.  
  702.     
  703.     def unescape_attrs(self, attrs):
  704.         escaped_attrs = { }
  705.         for key, val in attrs.items():
  706.             
  707.             try:
  708.                 val.items
  709.             except AttributeError:
  710.                 escaped_attrs[key] = self.unescape_attr(val)
  711.                 continue
  712.  
  713.             escaped_attrs[key] = self.unescape_attrs(val)
  714.         
  715.         return escaped_attrs
  716.  
  717.     
  718.     def unknown_entityref(self, ref):
  719.         self.handle_data('&%s;' % ref)
  720.  
  721.     
  722.     def unknown_charref(self, ref):
  723.         self.handle_data('&#%s;' % ref)
  724.  
  725.  
  726. if not HAVE_MODULE_HTMLPARSER:
  727.     
  728.     class XHTMLCompatibleFormParser:
  729.         
  730.         def __init__(self, entitydefs = None, encoding = DEFAULT_ENCODING):
  731.             raise ValueError('HTMLParser could not be imported')
  732.  
  733.  
  734. else:
  735.     
  736.     class XHTMLCompatibleFormParser(_AbstractFormParser, HTMLParser.HTMLParser):
  737.         
  738.         def __init__(self, entitydefs = None, encoding = DEFAULT_ENCODING):
  739.             HTMLParser.HTMLParser.__init__(self)
  740.             _AbstractFormParser.__init__(self, entitydefs, encoding)
  741.  
  742.         
  743.         def feed(self, data):
  744.             
  745.             try:
  746.                 HTMLParser.HTMLParser.feed(self, data)
  747.             except HTMLParser.HTMLParseError:
  748.                 exc = None
  749.                 raise ParseError(exc)
  750.  
  751.  
  752.         
  753.         def start_option(self, attrs):
  754.             _AbstractFormParser._start_option(self, attrs)
  755.  
  756.         
  757.         def end_option(self):
  758.             _AbstractFormParser._end_option(self)
  759.  
  760.         
  761.         def handle_starttag(self, tag, attrs):
  762.             
  763.             try:
  764.                 method = getattr(self, 'start_' + tag)
  765.             except AttributeError:
  766.                 
  767.                 try:
  768.                     method = getattr(self, 'do_' + tag)
  769.                 except AttributeError:
  770.                     pass
  771.  
  772.                 method(attrs)
  773.  
  774.             method(attrs)
  775.  
  776.         
  777.         def handle_endtag(self, tag):
  778.             
  779.             try:
  780.                 method = getattr(self, 'end_' + tag)
  781.             except AttributeError:
  782.                 pass
  783.  
  784.             method()
  785.  
  786.         
  787.         def unescape(self, name):
  788.             return self.unescape_attr(name)
  789.  
  790.         
  791.         def unescape_attr_if_required(self, name):
  792.             return name
  793.  
  794.         
  795.         def unescape_attrs_if_required(self, attrs):
  796.             return attrs
  797.  
  798.         
  799.         def close(self):
  800.             HTMLParser.HTMLParser.close(self)
  801.             self.end_body()
  802.  
  803.  
  804.  
  805. class _AbstractSgmllibParser(_AbstractFormParser):
  806.     
  807.     def do_option(self, attrs):
  808.         _AbstractFormParser._start_option(self, attrs)
  809.  
  810.     if sys.version_info[:2] >= (2, 5):
  811.         entity_or_charref = re.compile('&(?:([a-zA-Z][-.a-zA-Z0-9]*)|#(x?[0-9a-fA-F]+))(;?)')
  812.         
  813.         def convert_entityref(self, name):
  814.             return unescape('&%s;' % name, self._entitydefs, self._encoding)
  815.  
  816.         
  817.         def convert_charref(self, name):
  818.             return unescape_charref('%s' % name, self._encoding)
  819.  
  820.         
  821.         def unescape_attr_if_required(self, name):
  822.             return name
  823.  
  824.         
  825.         def unescape_attrs_if_required(self, attrs):
  826.             return attrs
  827.  
  828.     else:
  829.         
  830.         def unescape_attr_if_required(self, name):
  831.             return self.unescape_attr(name)
  832.  
  833.         
  834.         def unescape_attrs_if_required(self, attrs):
  835.             return self.unescape_attrs(attrs)
  836.  
  837.  
  838.  
  839. class FormParser(_AbstractSgmllibParser, sgmllib.SGMLParser):
  840.     
  841.     def __init__(self, entitydefs = None, encoding = DEFAULT_ENCODING):
  842.         sgmllib.SGMLParser.__init__(self)
  843.         _AbstractFormParser.__init__(self, entitydefs, encoding)
  844.  
  845.     
  846.     def feed(self, data):
  847.         
  848.         try:
  849.             sgmllib.SGMLParser.feed(self, data)
  850.         except SGMLLIB_PARSEERROR:
  851.             exc = None
  852.             raise ParseError(exc)
  853.  
  854.  
  855.     
  856.     def close(self):
  857.         sgmllib.SGMLParser.close(self)
  858.         self.end_body()
  859.  
  860.  
  861.  
  862. def _create_bs_classes(bs, icbinbs):
  863.     
  864.     class _AbstractBSFormParser(_AbstractSgmllibParser):
  865.         bs_base_class = None
  866.         
  867.         def __init__(self, entitydefs = None, encoding = DEFAULT_ENCODING):
  868.             _AbstractFormParser.__init__(self, entitydefs, encoding)
  869.             self.bs_base_class.__init__(self)
  870.  
  871.         
  872.         def handle_data(self, data):
  873.             _AbstractFormParser.handle_data(self, data)
  874.             self.bs_base_class.handle_data(self, data)
  875.  
  876.         
  877.         def feed(self, data):
  878.             
  879.             try:
  880.                 self.bs_base_class.feed(self, data)
  881.             except SGMLLIB_PARSEERROR:
  882.                 exc = None
  883.                 raise ParseError(exc)
  884.  
  885.  
  886.         
  887.         def close(self):
  888.             self.bs_base_class.close(self)
  889.             self.end_body()
  890.  
  891.  
  892.     
  893.     class RobustFormParser(_AbstractBSFormParser, bs):
  894.         pass
  895.  
  896.     RobustFormParser.bs_base_class = bs
  897.     
  898.     class NestingRobustFormParser(_AbstractBSFormParser, icbinbs):
  899.         pass
  900.  
  901.     NestingRobustFormParser.bs_base_class = icbinbs
  902.     return (RobustFormParser, NestingRobustFormParser)
  903.  
  904.  
  905. try:
  906.     if sys.version_info[:2] < (2, 2):
  907.         raise ImportError
  908.     sys.version_info[:2] < (2, 2)
  909.     import BeautifulSoup
  910. except ImportError:
  911.     pass
  912.  
  913. (RobustFormParser, NestingRobustFormParser) = _create_bs_classes(BeautifulSoup.BeautifulSoup, BeautifulSoup.ICantBelieveItsBeautifulSoup)
  914. __all__ += [
  915.     'RobustFormParser',
  916.     'NestingRobustFormParser']
  917.  
  918. 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):
  919.     return _ParseFileEx(response, response.geturl(), select_default, False, form_parser_class, request_class, entitydefs, False, encoding, _urljoin = _urljoin, _urlparse = _urlparse, _urlunparse = _urlunparse)
  920.  
  921.  
  922. 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):
  923.     return _ParseFileEx(file, base_uri, select_default, False, form_parser_class, request_class, entitydefs, False, encoding, _urljoin = _urljoin, _urlparse = _urlparse, _urlunparse = _urlunparse)
  924.  
  925.  
  926. def ParseResponse(response, *args, **kwds):
  927.     return _ParseFileEx(response, response.geturl(), *args, **kwds)[1:]
  928.  
  929.  
  930. def ParseFile(file, base_uri, *args, **kwds):
  931.     return _ParseFileEx(file, base_uri, *args, **kwds)[1:]
  932.  
  933.  
  934. def _ParseFileEx(file, base_uri, select_default = False, ignore_errors = False, form_parser_class = FormParser, request_class = urllib2.Request, entitydefs = None, backwards_compat = True, encoding = DEFAULT_ENCODING, _urljoin = urlparse.urljoin, _urlparse = urlparse.urlparse, _urlunparse = urlparse.urlunparse):
  935.     if backwards_compat:
  936.         deprecation('operating in backwards-compatibility mode', 1)
  937.     
  938.     fp = form_parser_class(entitydefs, encoding)
  939.     while None:
  940.         data = file.read(CHUNK)
  941.         
  942.         try:
  943.             fp.feed(data)
  944.         except ParseError:
  945.             e = None
  946.             e.base_uri = base_uri
  947.             raise 
  948.  
  949.         if len(data) != CHUNK:
  950.             break
  951.             continue
  952.         continue
  953.         fp.close()
  954.         if fp.base is not None:
  955.             base_uri = fp.base
  956.         
  957.     labels = []
  958.     id_to_labels = { }
  959.     for l in fp.labels:
  960.         label = Label(l)
  961.         labels.append(label)
  962.         for_id = l['for']
  963.         coll = id_to_labels.get(for_id)
  964.         if coll is None:
  965.             id_to_labels[for_id] = [
  966.                 label]
  967.             continue
  968.         coll.append(label)
  969.     
  970.     forms = []
  971.     for name, action, method, enctype in fp.forms:
  972.         attrs = None
  973.         controls = None
  974.         if action is None:
  975.             action = base_uri
  976.         else:
  977.             action = _urljoin(base_uri, action)
  978.         form = HTMLForm(action, method, enctype, name, attrs, request_class, forms, labels, id_to_labels, backwards_compat)
  979.         form._urlparse = _urlparse
  980.         form._urlunparse = _urlunparse
  981.         for ii in range(len(controls)):
  982.             (type, name, attrs) = controls[ii]
  983.             form.new_control(type, name, attrs, select_default = select_default, index = ii * 10)
  984.         
  985.         forms.append(form)
  986.     
  987.     for form in forms:
  988.         form.fixup()
  989.     
  990.     return forms
  991.  
  992.  
  993. class Label:
  994.     
  995.     def __init__(self, attrs):
  996.         self.id = attrs.get('for')
  997.         self._text = attrs.get('__text').strip()
  998.         self._ctext = compress_text(self._text)
  999.         self.attrs = attrs
  1000.         self._backwards_compat = False
  1001.  
  1002.     
  1003.     def __getattr__(self, name):
  1004.         if name == 'text':
  1005.             if self._backwards_compat:
  1006.                 return self._text
  1007.             return self._ctext
  1008.         name == 'text'
  1009.         return getattr(Label, name)
  1010.  
  1011.     
  1012.     def __setattr__(self, name, value):
  1013.         if name == 'text':
  1014.             raise AttributeError('text attribute is read-only')
  1015.         name == 'text'
  1016.         self.__dict__[name] = value
  1017.  
  1018.     
  1019.     def __str__(self):
  1020.         return '<Label(id=%r, text=%r)>' % (self.id, self.text)
  1021.  
  1022.  
  1023.  
  1024. def _get_label(attrs):
  1025.     text = attrs.get('__label')
  1026.     if text is not None:
  1027.         return Label(text)
  1028.     return None
  1029.  
  1030.  
  1031. class Control:
  1032.     
  1033.     def __init__(self, type, name, attrs, index = None):
  1034.         raise NotImplementedError()
  1035.  
  1036.     
  1037.     def add_to_form(self, form):
  1038.         self._form = form
  1039.         form.controls.append(self)
  1040.  
  1041.     
  1042.     def fixup(self):
  1043.         pass
  1044.  
  1045.     
  1046.     def is_of_kind(self, kind):
  1047.         raise NotImplementedError()
  1048.  
  1049.     
  1050.     def clear(self):
  1051.         raise NotImplementedError()
  1052.  
  1053.     
  1054.     def __getattr__(self, name):
  1055.         raise NotImplementedError()
  1056.  
  1057.     
  1058.     def __setattr__(self, name, value):
  1059.         raise NotImplementedError()
  1060.  
  1061.     
  1062.     def pairs(self):
  1063.         return [ (k, v) for i, k, v in self._totally_ordered_pairs() ]
  1064.  
  1065.     
  1066.     def _totally_ordered_pairs(self):
  1067.         raise NotImplementedError()
  1068.  
  1069.     
  1070.     def _write_mime_data(self, mw, name, value):
  1071.         mw2 = mw.nextpart()
  1072.         mw2.addheader('Content-Disposition', 'form-data; name="%s"' % name, 1)
  1073.         f = mw2.startbody(prefix = 0)
  1074.         f.write(value)
  1075.  
  1076.     
  1077.     def __str__(self):
  1078.         raise NotImplementedError()
  1079.  
  1080.     
  1081.     def get_labels(self):
  1082.         res = []
  1083.         if self._label:
  1084.             res.append(self._label)
  1085.         
  1086.         if self.id:
  1087.             res.extend(self._form._id_to_labels.get(self.id, ()))
  1088.         
  1089.         return res
  1090.  
  1091.  
  1092.  
  1093. class ScalarControl(Control):
  1094.     
  1095.     def __init__(self, type, name, attrs, index = None):
  1096.         self._index = index
  1097.         self._label = _get_label(attrs)
  1098.         self.__dict__['type'] = type.lower()
  1099.         self.__dict__['name'] = name
  1100.         self._value = attrs.get('value')
  1101.         self.disabled = attrs.has_key('disabled')
  1102.         self.readonly = attrs.has_key('readonly')
  1103.         self.id = attrs.get('id')
  1104.         self.attrs = attrs.copy()
  1105.         self._clicked = False
  1106.         self._urlparse = urlparse.urlparse
  1107.         self._urlunparse = urlparse.urlunparse
  1108.  
  1109.     
  1110.     def __getattr__(self, name):
  1111.         if name == 'value':
  1112.             return self.__dict__['_value']
  1113.         raise AttributeError("%s instance has no attribute '%s'" % (self.__class__.__name__, name))
  1114.  
  1115.     
  1116.     def __setattr__(self, name, value):
  1117.         if name == 'value':
  1118.             if not isstringlike(value):
  1119.                 raise TypeError('must assign a string')
  1120.             isstringlike(value)
  1121.             if self.readonly:
  1122.                 raise AttributeError("control '%s' is readonly" % self.name)
  1123.             self.readonly
  1124.             if self.disabled:
  1125.                 raise AttributeError("control '%s' is disabled" % self.name)
  1126.             self.disabled
  1127.             self.__dict__['_value'] = value
  1128.         elif name in ('name', 'type'):
  1129.             raise AttributeError('%s attribute is readonly' % name)
  1130.         else:
  1131.             self.__dict__[name] = value
  1132.  
  1133.     
  1134.     def _totally_ordered_pairs(self):
  1135.         name = self.name
  1136.         value = self.value
  1137.         if name is None and value is None or self.disabled:
  1138.             return []
  1139.         return [
  1140.             (self._index, name, value)]
  1141.  
  1142.     
  1143.     def clear(self):
  1144.         if self.readonly:
  1145.             raise AttributeError("control '%s' is readonly" % self.name)
  1146.         self.readonly
  1147.         self.__dict__['_value'] = None
  1148.  
  1149.     
  1150.     def __str__(self):
  1151.         name = self.name
  1152.         value = self.value
  1153.         if name is None:
  1154.             name = '<None>'
  1155.         
  1156.         if value is None:
  1157.             value = '<None>'
  1158.         
  1159.         infos = []
  1160.         if self.disabled:
  1161.             infos.append('disabled')
  1162.         
  1163.         if self.readonly:
  1164.             infos.append('readonly')
  1165.         
  1166.         info = ', '.join(infos)
  1167.         if info:
  1168.             info = ' (%s)' % info
  1169.         
  1170.         return '<%s(%s=%s)%s>' % (self.__class__.__name__, name, value, info)
  1171.  
  1172.  
  1173.  
  1174. class TextControl(ScalarControl):
  1175.     
  1176.     def __init__(self, type, name, attrs, index = None):
  1177.         ScalarControl.__init__(self, type, name, attrs, index)
  1178.         if self.type == 'hidden':
  1179.             self.readonly = True
  1180.         
  1181.         if self._value is None:
  1182.             self._value = ''
  1183.         
  1184.  
  1185.     
  1186.     def is_of_kind(self, kind):
  1187.         return kind == 'text'
  1188.  
  1189.  
  1190.  
  1191. class FileControl(ScalarControl):
  1192.     
  1193.     def __init__(self, type, name, attrs, index = None):
  1194.         ScalarControl.__init__(self, type, name, attrs, index)
  1195.         self._value = None
  1196.         self._upload_data = []
  1197.  
  1198.     
  1199.     def is_of_kind(self, kind):
  1200.         return kind == 'file'
  1201.  
  1202.     
  1203.     def clear(self):
  1204.         if self.readonly:
  1205.             raise AttributeError("control '%s' is readonly" % self.name)
  1206.         self.readonly
  1207.         self._upload_data = []
  1208.  
  1209.     
  1210.     def __setattr__(self, name, value):
  1211.         if name in ('value', 'name', 'type'):
  1212.             raise AttributeError('%s attribute is readonly' % name)
  1213.         name in ('value', 'name', 'type')
  1214.         self.__dict__[name] = value
  1215.  
  1216.     
  1217.     def add_file(self, file_object, content_type = None, filename = None):
  1218.         if not hasattr(file_object, 'read'):
  1219.             raise TypeError('file-like object must have read method')
  1220.         hasattr(file_object, 'read')
  1221.         if content_type is not None and not isstringlike(content_type):
  1222.             raise TypeError('content type must be None or string-like')
  1223.         not isstringlike(content_type)
  1224.         if filename is not None and not isstringlike(filename):
  1225.             raise TypeError('filename must be None or string-like')
  1226.         not isstringlike(filename)
  1227.         if content_type is None:
  1228.             content_type = 'application/octet-stream'
  1229.         
  1230.         self._upload_data.append((file_object, content_type, filename))
  1231.  
  1232.     
  1233.     def _totally_ordered_pairs(self):
  1234.         if self.name is None or self.disabled:
  1235.             return []
  1236.         return [
  1237.             (self._index, self.name, '')]
  1238.  
  1239.     
  1240.     def _write_mime_data(self, mw, _name, _value):
  1241.         if len(self._upload_data) < 2:
  1242.             if len(self._upload_data) == 0:
  1243.                 file_object = StringIO()
  1244.                 content_type = 'application/octet-stream'
  1245.                 filename = ''
  1246.             else:
  1247.                 (file_object, content_type, filename) = self._upload_data[0]
  1248.                 if filename is None:
  1249.                     filename = ''
  1250.                 
  1251.             mw2 = mw.nextpart()
  1252.             fn_part = '; filename="%s"' % filename
  1253.             disp = 'form-data; name="%s"%s' % (self.name, fn_part)
  1254.             mw2.addheader('Content-Disposition', disp, prefix = 1)
  1255.             fh = mw2.startbody(content_type, prefix = 0)
  1256.             fh.write(file_object.read())
  1257.         else:
  1258.             mw2 = mw.nextpart()
  1259.             disp = 'form-data; name="%s"' % self.name
  1260.             mw2.addheader('Content-Disposition', disp, prefix = 1)
  1261.             fh = mw2.startmultipartbody('mixed', prefix = 0)
  1262.             for file_object, content_type, filename in self._upload_data:
  1263.                 mw3 = mw2.nextpart()
  1264.                 if filename is None:
  1265.                     filename = ''
  1266.                 
  1267.                 fn_part = '; filename="%s"' % filename
  1268.                 disp = 'file%s' % fn_part
  1269.                 mw3.addheader('Content-Disposition', disp, prefix = 1)
  1270.                 fh2 = mw3.startbody(content_type, prefix = 0)
  1271.                 fh2.write(file_object.read())
  1272.             
  1273.             mw2.lastpart()
  1274.  
  1275.     
  1276.     def __str__(self):
  1277.         name = self.name
  1278.         if name is None:
  1279.             name = '<None>'
  1280.         
  1281.         if not self._upload_data:
  1282.             value = '<No files added>'
  1283.         else:
  1284.             value = []
  1285.             for file, ctype, filename in self._upload_data:
  1286.                 if filename is None:
  1287.                     value.append('<Unnamed file>')
  1288.                     continue
  1289.                 value.append(filename)
  1290.             
  1291.             value = ', '.join(value)
  1292.         info = []
  1293.         if self.disabled:
  1294.             info.append('disabled')
  1295.         
  1296.         if self.readonly:
  1297.             info.append('readonly')
  1298.         
  1299.         info = ', '.join(info)
  1300.         if info:
  1301.             info = ' (%s)' % info
  1302.         
  1303.         return '<%s(%s=%s)%s>' % (self.__class__.__name__, name, value, info)
  1304.  
  1305.  
  1306.  
  1307. class IsindexControl(ScalarControl):
  1308.     
  1309.     def __init__(self, type, name, attrs, index = None):
  1310.         ScalarControl.__init__(self, type, name, attrs, index)
  1311.         if self._value is None:
  1312.             self._value = ''
  1313.         
  1314.  
  1315.     
  1316.     def is_of_kind(self, kind):
  1317.         return kind in ('text', 'clickable')
  1318.  
  1319.     
  1320.     def _totally_ordered_pairs(self):
  1321.         return []
  1322.  
  1323.     
  1324.     def _click(self, form, coord, return_type, request_class = urllib2.Request):
  1325.         parts = self._urlparse(form.action)
  1326.         rest = parts[:-2]
  1327.         (query, frag) = parts[-2:]
  1328.         parts = rest + (urllib.quote_plus(self.value), None)
  1329.         url = self._urlunparse(parts)
  1330.         req_data = (url, None, [])
  1331.         if return_type == 'pairs':
  1332.             return []
  1333.         if return_type == 'request_data':
  1334.             return req_data
  1335.         return request_class(url)
  1336.  
  1337.     
  1338.     def __str__(self):
  1339.         value = self.value
  1340.         if value is None:
  1341.             value = '<None>'
  1342.         
  1343.         infos = []
  1344.         if self.disabled:
  1345.             infos.append('disabled')
  1346.         
  1347.         if self.readonly:
  1348.             infos.append('readonly')
  1349.         
  1350.         info = ', '.join(infos)
  1351.         if info:
  1352.             info = ' (%s)' % info
  1353.         
  1354.         return '<%s(%s)%s>' % (self.__class__.__name__, value, info)
  1355.  
  1356.  
  1357.  
  1358. class IgnoreControl(ScalarControl):
  1359.     
  1360.     def __init__(self, type, name, attrs, index = None):
  1361.         ScalarControl.__init__(self, type, name, attrs, index)
  1362.         self._value = None
  1363.  
  1364.     
  1365.     def is_of_kind(self, kind):
  1366.         return False
  1367.  
  1368.     
  1369.     def __setattr__(self, name, value):
  1370.         if name == 'value':
  1371.             raise AttributeError("control '%s' is ignored, hence read-only" % self.name)
  1372.         name == 'value'
  1373.         if name in ('name', 'type'):
  1374.             raise AttributeError('%s attribute is readonly' % name)
  1375.         name in ('name', 'type')
  1376.         self.__dict__[name] = value
  1377.  
  1378.  
  1379.  
  1380. class Item:
  1381.     
  1382.     def __init__(self, control, attrs, index = None):
  1383.         label = _get_label(attrs)
  1384.         if not label or [
  1385.             label]:
  1386.             pass
  1387.         self.__dict__.update({
  1388.             'name': attrs['value'],
  1389.             '_labels': [],
  1390.             'attrs': attrs,
  1391.             '_control': control,
  1392.             'disabled': attrs.has_key('disabled'),
  1393.             '_selected': False,
  1394.             'id': attrs.get('id'),
  1395.             '_index': index })
  1396.         control.items.append(self)
  1397.  
  1398.     
  1399.     def get_labels(self):
  1400.         res = []
  1401.         res.extend(self._labels)
  1402.         if self.id:
  1403.             res.extend(self._control._form._id_to_labels.get(self.id, ()))
  1404.         
  1405.         return res
  1406.  
  1407.     
  1408.     def __getattr__(self, name):
  1409.         if name == 'selected':
  1410.             return self._selected
  1411.         raise AttributeError(name)
  1412.  
  1413.     
  1414.     def __setattr__(self, name, value):
  1415.         if name == 'selected':
  1416.             self._control._set_selected_state(self, value)
  1417.         elif name == 'disabled':
  1418.             self.__dict__['disabled'] = bool(value)
  1419.         else:
  1420.             raise AttributeError(name)
  1421.         return name == 'selected'
  1422.  
  1423.     
  1424.     def __str__(self):
  1425.         res = self.name
  1426.         if self.selected:
  1427.             res = '*' + res
  1428.         
  1429.         if self.disabled:
  1430.             res = '(%s)' % res
  1431.         
  1432.         return res
  1433.  
  1434.     
  1435.     def __repr__(self):
  1436.         attrs = [
  1437.             ('name', self.name),
  1438.             ('id', self.id)] + self.attrs.items()
  1439.         return ' '.join % ([], []([ '%s=%r' % (k, v) for k, v in attrs ]))
  1440.  
  1441.  
  1442.  
  1443. def disambiguate(items, nr, **kwds):
  1444.     msgs = []
  1445.     for key, value in kwds.items():
  1446.         msgs.append('%s=%r' % (key, value))
  1447.     
  1448.     msg = ' '.join(msgs)
  1449.     if not items:
  1450.         raise ItemNotFoundError(msg)
  1451.     items
  1452.     if nr is None:
  1453.         if len(items) > 1:
  1454.             raise AmbiguityError(msg)
  1455.         len(items) > 1
  1456.         nr = 0
  1457.     
  1458.     if len(items) <= nr:
  1459.         raise ItemNotFoundError(msg)
  1460.     len(items) <= nr
  1461.     return items[nr]
  1462.  
  1463.  
  1464. class ListControl(Control):
  1465.     _label = None
  1466.     
  1467.     def __init__(self, type, name, attrs = { }, select_default = False, called_as_base_class = False, index = None):
  1468.         if not called_as_base_class:
  1469.             raise NotImplementedError()
  1470.         called_as_base_class
  1471.         self.__dict__['type'] = type.lower()
  1472.         self.__dict__['name'] = name
  1473.         self._value = attrs.get('value')
  1474.         self.disabled = False
  1475.         self.readonly = False
  1476.         self.id = attrs.get('id')
  1477.         self._closed = False
  1478.         self.items = []
  1479.         self._form = None
  1480.         self._select_default = select_default
  1481.         self._clicked = False
  1482.  
  1483.     
  1484.     def clear(self):
  1485.         self.value = []
  1486.  
  1487.     
  1488.     def is_of_kind(self, kind):
  1489.         if kind == 'list':
  1490.             return True
  1491.         if kind == 'multilist':
  1492.             return bool(self.multiple)
  1493.         if kind == 'singlelist':
  1494.             return not (self.multiple)
  1495.         return False
  1496.  
  1497.     
  1498.     def get_items(self, name = None, label = None, id = None, exclude_disabled = False):
  1499.         if name is not None and not isstringlike(name):
  1500.             raise TypeError('item name must be string-like')
  1501.         not isstringlike(name)
  1502.         if label is not None and not isstringlike(label):
  1503.             raise TypeError('item label must be string-like')
  1504.         not isstringlike(label)
  1505.         if id is not None and not isstringlike(id):
  1506.             raise TypeError('item id must be string-like')
  1507.         not isstringlike(id)
  1508.         items = []
  1509.         compat = self._form.backwards_compat
  1510.         for o in self.items:
  1511.             if exclude_disabled and o.disabled:
  1512.                 continue
  1513.             
  1514.             if name is not None and o.name != name:
  1515.                 continue
  1516.             
  1517.             if label is not None:
  1518.                 for l in o.get_labels():
  1519.                     if (compat or l.text == label or not compat) and l.text.find(label) > -1:
  1520.                         break
  1521.                         continue
  1522.                 
  1523.             
  1524.             if id is not None and o.id != id:
  1525.                 continue
  1526.             
  1527.             items.append(o)
  1528.         
  1529.         return items
  1530.  
  1531.     
  1532.     def get(self, name = None, label = None, id = None, nr = None, exclude_disabled = False):
  1533.         if nr is None and self._form.backwards_compat:
  1534.             nr = 0
  1535.         
  1536.         items = self.get_items(name, label, id, exclude_disabled)
  1537.         return disambiguate(items, nr, name = name, label = label, id = id)
  1538.  
  1539.     
  1540.     def _get(self, name, by_label = False, nr = None, exclude_disabled = False):
  1541.         if by_label:
  1542.             name = None
  1543.             label = name
  1544.         else:
  1545.             name = name
  1546.             label = None
  1547.         return self.get(name, label, nr, exclude_disabled)
  1548.  
  1549.     
  1550.     def toggle(self, name, by_label = False, nr = None):
  1551.         deprecation('item = control.get(...); item.selected = not item.selected')
  1552.         o = self._get(name, by_label, nr)
  1553.         self._set_selected_state(o, not (o.selected))
  1554.  
  1555.     
  1556.     def set(self, selected, name, by_label = False, nr = None):
  1557.         deprecation('control.get(...).selected = <boolean>')
  1558.         self._set_selected_state(self._get(name, by_label, nr), selected)
  1559.  
  1560.     
  1561.     def _set_selected_state(self, item, action):
  1562.         if self.disabled:
  1563.             raise AttributeError("control '%s' is disabled" % self.name)
  1564.         self.disabled
  1565.         if self.readonly:
  1566.             raise AttributeError("control '%s' is readonly" % self.name)
  1567.         self.readonly
  1568.         action == bool(action)
  1569.         compat = self._form.backwards_compat
  1570.         if not compat and item.disabled:
  1571.             raise AttributeError('item is disabled')
  1572.         item.disabled
  1573.         if compat and item.disabled and action:
  1574.             raise AttributeError('item is disabled')
  1575.         action
  1576.         if self.multiple:
  1577.             item.__dict__['_selected'] = action
  1578.         elif not action:
  1579.             item.__dict__['_selected'] = False
  1580.         else:
  1581.             for o in self.items:
  1582.                 o.__dict__['_selected'] = False
  1583.             
  1584.             item.__dict__['_selected'] = True
  1585.  
  1586.     
  1587.     def toggle_single(self, by_label = None):
  1588.         deprecation('control.items[0].selected = not control.items[0].selected')
  1589.         if len(self.items) != 1:
  1590.             raise ItemCountError("'%s' is not a single-item control" % self.name)
  1591.         len(self.items) != 1
  1592.         item = self.items[0]
  1593.         self._set_selected_state(item, not (item.selected))
  1594.  
  1595.     
  1596.     def set_single(self, selected, by_label = None):
  1597.         deprecation('control.items[0].selected = <boolean>')
  1598.         if len(self.items) != 1:
  1599.             raise ItemCountError("'%s' is not a single-item control" % self.name)
  1600.         len(self.items) != 1
  1601.         self._set_selected_state(self.items[0], selected)
  1602.  
  1603.     
  1604.     def get_item_disabled(self, name, by_label = False, nr = None):
  1605.         deprecation('control.get(...).disabled')
  1606.         return self._get(name, by_label, nr).disabled
  1607.  
  1608.     
  1609.     def set_item_disabled(self, disabled, name, by_label = False, nr = None):
  1610.         deprecation('control.get(...).disabled = <boolean>')
  1611.         self._get(name, by_label, nr).disabled = disabled
  1612.  
  1613.     
  1614.     def set_all_items_disabled(self, disabled):
  1615.         for o in self.items:
  1616.             o.disabled = disabled
  1617.         
  1618.  
  1619.     
  1620.     def get_item_attrs(self, name, by_label = False, nr = None):
  1621.         deprecation('control.get(...).attrs')
  1622.         return self._get(name, by_label, nr).attrs
  1623.  
  1624.     
  1625.     def close_control(self):
  1626.         self._closed = True
  1627.  
  1628.     
  1629.     def add_to_form(self, form):
  1630.         self._form = form
  1631.         if self.name is None:
  1632.             Control.add_to_form(self, form)
  1633.         else:
  1634.             for ii in range(len(form.controls) - 1, -1, -1):
  1635.                 control = form.controls[ii]
  1636.                 if control.name == self.name and control.type == self.type:
  1637.                     if control._closed:
  1638.                         Control.add_to_form(self, form)
  1639.                     else:
  1640.                         control.merge_control(self)
  1641.                     break
  1642.                     continue
  1643.             
  1644.  
  1645.     
  1646.     def merge_control(self, control):
  1647.         self.items.extend(control.items)
  1648.  
  1649.     
  1650.     def fixup(self):
  1651.         for o in self.items:
  1652.             o.__dict__['_control'] = self
  1653.         
  1654.  
  1655.     
  1656.     def __getattr__(self, name):
  1657.         if name == 'value':
  1658.             compat = self._form.backwards_compat
  1659.             if self.name is None:
  1660.                 return []
  1661.             return _[1]
  1662.         raise AttributeError("%s instance has no attribute '%s'" % (self.__class__.__name__, name))
  1663.  
  1664.     
  1665.     def __setattr__(self, name, value):
  1666.         if name == 'value':
  1667.             if self.disabled:
  1668.                 raise AttributeError("control '%s' is disabled" % self.name)
  1669.             self.disabled
  1670.             if self.readonly:
  1671.                 raise AttributeError("control '%s' is readonly" % self.name)
  1672.             self.readonly
  1673.             self._set_value(value)
  1674.         elif name in ('name', 'type', 'multiple'):
  1675.             raise AttributeError('%s attribute is readonly' % name)
  1676.         else:
  1677.             self.__dict__[name] = value
  1678.  
  1679.     
  1680.     def _set_value(self, value):
  1681.         if value is None or isstringlike(value):
  1682.             raise TypeError('ListControl, must set a sequence')
  1683.         isstringlike(value)
  1684.         if not value:
  1685.             compat = self._form.backwards_compat
  1686.             for o in self.items:
  1687.                 if not (o.disabled) or compat:
  1688.                     o.selected = False
  1689.                     continue
  1690.             
  1691.         elif self.multiple:
  1692.             self._multiple_set_value(value)
  1693.         elif len(value) > 1:
  1694.             raise ItemCountError('single selection list, must set sequence of length 0 or 1')
  1695.         else:
  1696.             self._single_set_value(value)
  1697.  
  1698.     
  1699.     def _get_items(self, name, target = 1):
  1700.         all_items = self.get_items(name)
  1701.         items = _[1]
  1702.         if len(items) < target:
  1703.             if len(all_items) < target:
  1704.                 raise ItemNotFoundError('insufficient items with name %r' % name)
  1705.             len(all_items) < target
  1706.             raise AttributeError('insufficient non-disabled items with name %s' % name)
  1707.         len(items) < target
  1708.         on = []
  1709.         off = []
  1710.         for o in items:
  1711.             if o.selected:
  1712.                 on.append(o)
  1713.                 continue
  1714.             []
  1715.             off.append(o)
  1716.         
  1717.         return (on, off)
  1718.  
  1719.     
  1720.     def _single_set_value(self, value):
  1721.         (on, off) = self._get_items(value[0])
  1722.         if not on:
  1723.             off[0].selected = True
  1724.         
  1725.  
  1726.     
  1727.     def _multiple_set_value(self, value):
  1728.         compat = self._form.backwards_compat
  1729.         turn_on = []
  1730.         turn_off = _[1]
  1731.         names = { }
  1732.         for nn in value:
  1733.             if nn in names.keys():
  1734.                 names[nn] += 1
  1735.                 continue
  1736.             []
  1737.             names[nn] = 1
  1738.         
  1739.         for name, count in names.items():
  1740.             (on, off) = self._get_items(name, count)
  1741.             for i in range(count):
  1742.                 if on:
  1743.                     item = on[0]
  1744.                     del on[0]
  1745.                     del turn_off[turn_off.index(item)]
  1746.                     continue
  1747.                 []
  1748.                 item = off[0]
  1749.                 del off[0]
  1750.                 turn_on.append(item)
  1751.             
  1752.         
  1753.         for item in turn_off:
  1754.             item.selected = False
  1755.         
  1756.         for item in turn_on:
  1757.             item.selected = True
  1758.         
  1759.  
  1760.     
  1761.     def set_value_by_label(self, value):
  1762.         if isstringlike(value):
  1763.             raise TypeError(value)
  1764.         isstringlike(value)
  1765.         if not (self.multiple) and len(value) > 1:
  1766.             raise ItemCountError('single selection list, must set sequence of length 0 or 1')
  1767.         len(value) > 1
  1768.         items = []
  1769.         for nn in value:
  1770.             found = self.get_items(label = nn)
  1771.             if len(found) > 1:
  1772.                 if not self._form.backwards_compat:
  1773.                     opt_name = found[0].name
  1774.                     if _[1]:
  1775.                         raise AmbiguityError(nn)
  1776.                     _[1]
  1777.                 else:
  1778.                     found = found[:1]
  1779.             
  1780.             for o in found:
  1781.                 if self._form.backwards_compat or o not in items:
  1782.                     items.append(o)
  1783.                     break
  1784.                     continue
  1785.             else:
  1786.                 raise ItemNotFoundError(nn)
  1787.         
  1788.         self.value = []
  1789.         for o in items:
  1790.             o.selected = True
  1791.         
  1792.  
  1793.     
  1794.     def get_value_by_label(self):
  1795.         res = []
  1796.         compat = self._form.backwards_compat
  1797.         for o in self.items:
  1798.             if (not (o.disabled) or compat) and o.selected:
  1799.                 for l in o.get_labels():
  1800.                     if l.text:
  1801.                         res.append(l.text)
  1802.                         break
  1803.                         continue
  1804.                 
  1805.         
  1806.         return res
  1807.  
  1808.     
  1809.     def possible_items(self, by_label = False):
  1810.         deprecation('[item.name for item in self.items]')
  1811.         if by_label:
  1812.             res = []
  1813.             for o in self.items:
  1814.                 for l in o.get_labels():
  1815.                     if l.text:
  1816.                         res.append(l.text)
  1817.                         break
  1818.                         continue
  1819.                 
  1820.             
  1821.             return res
  1822.         return [ o.name for o in self.items ]
  1823.  
  1824.     
  1825.     def _totally_ordered_pairs(self):
  1826.         if self.disabled or self.name is None:
  1827.             return []
  1828.         return _[1]
  1829.  
  1830.     
  1831.     def __str__(self):
  1832.         name = self.name
  1833.         if name is None:
  1834.             name = '<None>'
  1835.         
  1836.         display = [ str(o) for o in self.items ]
  1837.         infos = []
  1838.         if self.readonly:
  1839.             infos.append('readonly')
  1840.         
  1841.         info = ', '.join(infos)
  1842.         if info:
  1843.             info = ' (%s)' % info
  1844.         
  1845.         return '<%s(%s=[%s])%s>' % (self.__class__.__name__, name, ', '.join(display), info)
  1846.  
  1847.  
  1848.  
  1849. class RadioControl(ListControl):
  1850.     
  1851.     def __init__(self, type, name, attrs, select_default = False, index = None):
  1852.         attrs.setdefault('value', 'on')
  1853.         ListControl.__init__(self, type, name, attrs, select_default, called_as_base_class = True, index = index)
  1854.         self.__dict__['multiple'] = False
  1855.         o = Item(self, attrs, index)
  1856.         o.__dict__['_selected'] = attrs.has_key('checked')
  1857.  
  1858.     
  1859.     def fixup(self):
  1860.         ListControl.fixup(self)
  1861.         found = _[1]
  1862.  
  1863.     
  1864.     def get_labels(self):
  1865.         return []
  1866.  
  1867.  
  1868.  
  1869. class CheckboxControl(ListControl):
  1870.     
  1871.     def __init__(self, type, name, attrs, select_default = False, index = None):
  1872.         attrs.setdefault('value', 'on')
  1873.         ListControl.__init__(self, type, name, attrs, select_default, called_as_base_class = True, index = index)
  1874.         self.__dict__['multiple'] = True
  1875.         o = Item(self, attrs, index)
  1876.         o.__dict__['_selected'] = attrs.has_key('checked')
  1877.  
  1878.     
  1879.     def get_labels(self):
  1880.         return []
  1881.  
  1882.  
  1883.  
  1884. class SelectControl(ListControl):
  1885.     
  1886.     def __init__(self, type, name, attrs, select_default = False, index = None):
  1887.         self.attrs = attrs['__select'].copy()
  1888.         self.__dict__['_label'] = _get_label(self.attrs)
  1889.         self.__dict__['id'] = self.attrs.get('id')
  1890.         self.__dict__['multiple'] = self.attrs.has_key('multiple')
  1891.         contents = attrs.get('contents')
  1892.         attrs = attrs.copy()
  1893.         del attrs['__select']
  1894.         ListControl.__init__(self, type, name, self.attrs, select_default, called_as_base_class = True, index = index)
  1895.         self.disabled = self.attrs.has_key('disabled')
  1896.         self.readonly = self.attrs.has_key('readonly')
  1897.         if attrs.has_key('value'):
  1898.             o = Item(self, attrs, index)
  1899.             o.__dict__['_selected'] = attrs.has_key('selected')
  1900.             label = attrs.get('label')
  1901.             if label:
  1902.                 o._labels.append(Label({
  1903.                     '__text': label }))
  1904.                 if contents and contents != label:
  1905.                     o._labels.append(Label({
  1906.                         '__text': contents }))
  1907.                 
  1908.             elif contents:
  1909.                 o._labels.append(Label({
  1910.                     '__text': contents }))
  1911.             
  1912.         
  1913.  
  1914.     
  1915.     def fixup(self):
  1916.         ListControl.fixup(self)
  1917.         found = _[1]
  1918.         if not found:
  1919.             if not (self.multiple) or self._select_default:
  1920.                 for o in self.items:
  1921.                     if not o.disabled:
  1922.                         was_disabled = self.disabled
  1923.                         self.disabled = False
  1924.                         
  1925.                         try:
  1926.                             o.selected = True
  1927.                         finally:
  1928.                             o.disabled = was_disabled
  1929.  
  1930.                         break
  1931.                         continue
  1932.                     []
  1933.                 
  1934.             
  1935.         elif not self.multiple:
  1936.             for o in found[:-1]:
  1937.                 o.selected = False
  1938.             
  1939.         
  1940.  
  1941.  
  1942.  
  1943. class SubmitControl(ScalarControl):
  1944.     
  1945.     def __init__(self, type, name, attrs, index = None):
  1946.         ScalarControl.__init__(self, type, name, attrs, index)
  1947.         if self.value is None:
  1948.             self.value = ''
  1949.         
  1950.         self.readonly = True
  1951.  
  1952.     
  1953.     def get_labels(self):
  1954.         res = []
  1955.         if self.value:
  1956.             res.append(Label({
  1957.                 '__text': self.value }))
  1958.         
  1959.         res.extend(ScalarControl.get_labels(self))
  1960.         return res
  1961.  
  1962.     
  1963.     def is_of_kind(self, kind):
  1964.         return kind == 'clickable'
  1965.  
  1966.     
  1967.     def _click(self, form, coord, return_type, request_class = urllib2.Request):
  1968.         self._clicked = coord
  1969.         r = form._switch_click(return_type, request_class)
  1970.         self._clicked = False
  1971.         return r
  1972.  
  1973.     
  1974.     def _totally_ordered_pairs(self):
  1975.         if not self._clicked:
  1976.             return []
  1977.         return ScalarControl._totally_ordered_pairs(self)
  1978.  
  1979.  
  1980.  
  1981. class ImageControl(SubmitControl):
  1982.     
  1983.     def __init__(self, type, name, attrs, index = None):
  1984.         SubmitControl.__init__(self, type, name, attrs, index)
  1985.         self.readonly = False
  1986.  
  1987.     
  1988.     def _totally_ordered_pairs(self):
  1989.         clicked = self._clicked
  1990.         if self.disabled or not clicked:
  1991.             return []
  1992.         name = self.name
  1993.         if name is None:
  1994.             return []
  1995.         pairs = [
  1996.             (self._index, '%s.x' % name, str(clicked[0])),
  1997.             (self._index + 1, '%s.y' % name, str(clicked[1]))]
  1998.         value = self._value
  1999.         return pairs
  2000.  
  2001.     get_labels = ScalarControl.get_labels
  2002.  
  2003.  
  2004. class PasswordControl(TextControl):
  2005.     pass
  2006.  
  2007.  
  2008. class HiddenControl(TextControl):
  2009.     pass
  2010.  
  2011.  
  2012. class TextareaControl(TextControl):
  2013.     pass
  2014.  
  2015.  
  2016. class SubmitButtonControl(SubmitControl):
  2017.     pass
  2018.  
  2019.  
  2020. def is_listcontrol(control):
  2021.     return control.is_of_kind('list')
  2022.  
  2023.  
  2024. class HTMLForm:
  2025.     type2class = {
  2026.         'text': TextControl,
  2027.         'password': PasswordControl,
  2028.         'hidden': HiddenControl,
  2029.         'textarea': TextareaControl,
  2030.         'isindex': IsindexControl,
  2031.         'file': FileControl,
  2032.         'button': IgnoreControl,
  2033.         'buttonbutton': IgnoreControl,
  2034.         'reset': IgnoreControl,
  2035.         'resetbutton': IgnoreControl,
  2036.         'submit': SubmitControl,
  2037.         'submitbutton': SubmitButtonControl,
  2038.         'image': ImageControl,
  2039.         'radio': RadioControl,
  2040.         'checkbox': CheckboxControl,
  2041.         'select': SelectControl }
  2042.     
  2043.     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):
  2044.         self.action = action
  2045.         self.method = method
  2046.         self.enctype = enctype
  2047.         self.name = name
  2048.         if attrs is not None:
  2049.             self.attrs = attrs.copy()
  2050.         else:
  2051.             self.attrs = { }
  2052.         self.controls = []
  2053.         self._request_class = request_class
  2054.         self._forms = forms
  2055.         self._labels = labels
  2056.         self._id_to_labels = id_to_labels
  2057.         self.backwards_compat = backwards_compat
  2058.         self._urlunparse = urlparse.urlunparse
  2059.         self._urlparse = urlparse.urlparse
  2060.  
  2061.     
  2062.     def __getattr__(self, name):
  2063.         if name == 'backwards_compat':
  2064.             return self._backwards_compat
  2065.         return getattr(HTMLForm, name)
  2066.  
  2067.     
  2068.     def __setattr__(self, name, value):
  2069.         if name == 'backwards_compat':
  2070.             name = '_backwards_compat'
  2071.             value = bool(value)
  2072.             for cc in self.controls:
  2073.                 
  2074.                 try:
  2075.                     items = cc.items
  2076.                 except AttributeError:
  2077.                     continue
  2078.                     continue
  2079.  
  2080.                 for ii in items:
  2081.                     for ll in ii.get_labels():
  2082.                         ll._backwards_compat = value
  2083.                     
  2084.                 
  2085.             
  2086.         
  2087.         self.__dict__[name] = value
  2088.  
  2089.     
  2090.     def new_control(self, type, name, attrs, ignore_unknown = False, select_default = False, index = None):
  2091.         type = type.lower()
  2092.         klass = self.type2class.get(type)
  2093.         if klass is None:
  2094.             if ignore_unknown:
  2095.                 klass = IgnoreControl
  2096.             else:
  2097.                 klass = TextControl
  2098.         
  2099.         a = attrs.copy()
  2100.         if issubclass(klass, ListControl):
  2101.             control = klass(type, name, a, select_default, index)
  2102.         else:
  2103.             control = klass(type, name, a, index)
  2104.         if type == 'select' and len(attrs) == 1:
  2105.             for ii in range(len(self.controls) - 1, -1, -1):
  2106.                 ctl = self.controls[ii]
  2107.                 if ctl.type == 'select':
  2108.                     ctl.close_control()
  2109.                     break
  2110.                     continue
  2111.             
  2112.         
  2113.         control.add_to_form(self)
  2114.         control._urlparse = self._urlparse
  2115.         control._urlunparse = self._urlunparse
  2116.  
  2117.     
  2118.     def fixup(self):
  2119.         for control in self.controls:
  2120.             control.fixup()
  2121.         
  2122.         self.backwards_compat = self._backwards_compat
  2123.  
  2124.     
  2125.     def __str__(self):
  2126.         if not self.name or self.name + ' ':
  2127.             pass
  2128.         header = '%s%s %s %s' % ('', self.method, self.action, self.enctype)
  2129.         rep = [
  2130.             header]
  2131.         for control in self.controls:
  2132.             rep.append('  %s' % str(control))
  2133.         
  2134.         return '<%s>' % '\n'.join(rep)
  2135.  
  2136.     
  2137.     def __getitem__(self, name):
  2138.         return self.find_control(name).value
  2139.  
  2140.     
  2141.     def __contains__(self, name):
  2142.         return bool(self.find_control(name))
  2143.  
  2144.     
  2145.     def __setitem__(self, name, value):
  2146.         control = self.find_control(name)
  2147.         
  2148.         try:
  2149.             control.value = value
  2150.         except AttributeError:
  2151.             e = None
  2152.             raise ValueError(str(e))
  2153.  
  2154.  
  2155.     
  2156.     def get_value(self, name = None, type = None, kind = None, id = None, nr = None, by_label = False, label = None):
  2157.         if by_label:
  2158.             deprecation('form.get_value_by_label(...)')
  2159.         
  2160.         c = self.find_control(name, type, kind, id, label = label, nr = nr)
  2161.         if by_label:
  2162.             
  2163.             try:
  2164.                 meth = c.get_value_by_label
  2165.             except AttributeError:
  2166.                 raise NotImplementedError("control '%s' does not yet support by_label" % c.name)
  2167.  
  2168.             return meth()
  2169.         by_label
  2170.         return c.value
  2171.  
  2172.     
  2173.     def set_value(self, value, name = None, type = None, kind = None, id = None, nr = None, by_label = False, label = None):
  2174.         if by_label:
  2175.             deprecation('form.get_value_by_label(...)')
  2176.         
  2177.         c = self.find_control(name, type, kind, id, label = label, nr = nr)
  2178.         if by_label:
  2179.             
  2180.             try:
  2181.                 meth = c.set_value_by_label
  2182.             except AttributeError:
  2183.                 raise NotImplementedError("control '%s' does not yet support by_label" % c.name)
  2184.  
  2185.             meth(value)
  2186.         else:
  2187.             c.value = value
  2188.  
  2189.     
  2190.     def get_value_by_label(self, name = None, type = None, kind = None, id = None, label = None, nr = None):
  2191.         c = self.find_control(name, type, kind, id, label = label, nr = nr)
  2192.         return c.get_value_by_label()
  2193.  
  2194.     
  2195.     def set_value_by_label(self, value, name = None, type = None, kind = None, id = None, label = None, nr = None):
  2196.         c = self.find_control(name, type, kind, id, label = label, nr = nr)
  2197.         c.set_value_by_label(value)
  2198.  
  2199.     
  2200.     def set_all_readonly(self, readonly):
  2201.         for control in self.controls:
  2202.             control.readonly = bool(readonly)
  2203.         
  2204.  
  2205.     
  2206.     def clear_all(self):
  2207.         for control in self.controls:
  2208.             control.clear()
  2209.         
  2210.  
  2211.     
  2212.     def clear(self, name = None, type = None, kind = None, id = None, nr = None, label = None):
  2213.         c = self.find_control(name, type, kind, id, label = label, nr = nr)
  2214.         c.clear()
  2215.  
  2216.     
  2217.     def possible_items(self, name = None, type = None, kind = None, id = None, nr = None, by_label = False, label = None):
  2218.         c = self._find_list_control(name, type, kind, id, label, nr)
  2219.         return c.possible_items(by_label)
  2220.  
  2221.     
  2222.     def set(self, selected, item_name, name = None, type = None, kind = None, id = None, nr = None, by_label = False, label = None):
  2223.         self._find_list_control(name, type, kind, id, label, nr).set(selected, item_name, by_label)
  2224.  
  2225.     
  2226.     def toggle(self, item_name, name = None, type = None, kind = None, id = None, nr = None, by_label = False, label = None):
  2227.         self._find_list_control(name, type, kind, id, label, nr).toggle(item_name, by_label)
  2228.  
  2229.     
  2230.     def set_single(self, selected, name = None, type = None, kind = None, id = None, nr = None, by_label = None, label = None):
  2231.         self._find_list_control(name, type, kind, id, label, nr).set_single(selected)
  2232.  
  2233.     
  2234.     def toggle_single(self, name = None, type = None, kind = None, id = None, nr = None, by_label = None, label = None):
  2235.         self._find_list_control(name, type, kind, id, label, nr).toggle_single()
  2236.  
  2237.     
  2238.     def add_file(self, file_object, content_type = None, filename = None, name = None, id = None, nr = None, label = None):
  2239.         self.find_control(name, 'file', id = id, label = label, nr = nr).add_file(file_object, content_type, filename)
  2240.  
  2241.     
  2242.     def click(self, name = None, type = None, id = None, nr = 0, coord = (1, 1), request_class = urllib2.Request, label = None):
  2243.         return self._click(name, type, id, label, nr, coord, 'request', self._request_class)
  2244.  
  2245.     
  2246.     def click_request_data(self, name = None, type = None, id = None, nr = 0, coord = (1, 1), request_class = urllib2.Request, label = None):
  2247.         return self._click(name, type, id, label, nr, coord, 'request_data', self._request_class)
  2248.  
  2249.     
  2250.     def click_pairs(self, name = None, type = None, id = None, nr = 0, coord = (1, 1), label = None):
  2251.         return self._click(name, type, id, label, nr, coord, 'pairs', self._request_class)
  2252.  
  2253.     
  2254.     def find_control(self, name = None, type = None, kind = None, id = None, predicate = None, nr = None, label = None):
  2255.         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:
  2256.             raise ValueError('at least one argument must be supplied to specify control')
  2257.         nr is None
  2258.         return self._find_control(name, type, kind, id, label, predicate, nr)
  2259.  
  2260.     
  2261.     def _find_list_control(self, name = None, type = None, kind = None, id = None, label = None, nr = None):
  2262.         if name is None and type is None and kind is None and id is None and label is None and nr is None:
  2263.             raise ValueError('at least one argument must be supplied to specify control')
  2264.         nr is None
  2265.         return self._find_control(name, type, kind, id, label, is_listcontrol, nr)
  2266.  
  2267.     
  2268.     def _find_control(self, name, type, kind, id, label, predicate, nr):
  2269.         if name is not None and name is not Missing and not isstringlike(name):
  2270.             raise TypeError('control name must be string-like')
  2271.         not isstringlike(name)
  2272.         if type is not None and not isstringlike(type):
  2273.             raise TypeError('control type must be string-like')
  2274.         not isstringlike(type)
  2275.         if kind is not None and not isstringlike(kind):
  2276.             raise TypeError('control kind must be string-like')
  2277.         not isstringlike(kind)
  2278.         if id is not None and not isstringlike(id):
  2279.             raise TypeError('control id must be string-like')
  2280.         not isstringlike(id)
  2281.         if label is not None and not isstringlike(label):
  2282.             raise TypeError('control label must be string-like')
  2283.         not isstringlike(label)
  2284.         if predicate is not None and not callable(predicate):
  2285.             raise TypeError('control predicate must be callable')
  2286.         not callable(predicate)
  2287.         if nr is not None and nr < 0:
  2288.             raise ValueError('control number must be a positive integer')
  2289.         nr < 0
  2290.         orig_nr = nr
  2291.         found = None
  2292.         ambiguous = False
  2293.         if nr is None and self.backwards_compat:
  2294.             nr = 0
  2295.         
  2296.         for control in self.controls:
  2297.             if name is not None or name != control.name:
  2298.                 if name is not Missing or control.name is not None:
  2299.                     continue
  2300.                 
  2301.             if type is not None and type != control.type:
  2302.                 continue
  2303.             
  2304.             if kind is not None and not control.is_of_kind(kind):
  2305.                 continue
  2306.             
  2307.             if id is not None and id != control.id:
  2308.                 continue
  2309.             
  2310.             if predicate and not predicate(control):
  2311.                 continue
  2312.             
  2313.             if label:
  2314.                 for l in control.get_labels():
  2315.                     if l.text.find(label) > -1:
  2316.                         break
  2317.                         continue
  2318.                 
  2319.             
  2320.             if nr is not None:
  2321.                 if nr == 0:
  2322.                     return control
  2323.                 nr -= 1
  2324.                 continue
  2325.             
  2326.             if found:
  2327.                 ambiguous = True
  2328.                 break
  2329.             
  2330.             found = control
  2331.         
  2332.         if found and not ambiguous:
  2333.             return found
  2334.         description = []
  2335.         if name is not None:
  2336.             description.append('name %s' % repr(name))
  2337.         
  2338.         if type is not None:
  2339.             description.append("type '%s'" % type)
  2340.         
  2341.         if kind is not None:
  2342.             description.append("kind '%s'" % kind)
  2343.         
  2344.         if id is not None:
  2345.             description.append("id '%s'" % id)
  2346.         
  2347.         if label is not None:
  2348.             description.append("label '%s'" % label)
  2349.         
  2350.         if predicate is not None:
  2351.             description.append('predicate %s' % predicate)
  2352.         
  2353.         if orig_nr:
  2354.             description.append('nr %d' % orig_nr)
  2355.         
  2356.         description = ', '.join(description)
  2357.         if ambiguous:
  2358.             raise AmbiguityError('more than one control matching ' + description)
  2359.         ambiguous
  2360.         if not found:
  2361.             raise ControlNotFoundError('no control matching ' + description)
  2362.         found
  2363.  
  2364.     
  2365.     def _click(self, name, type, id, label, nr, coord, return_type, request_class = urllib2.Request):
  2366.         
  2367.         try:
  2368.             control = self._find_control(name, type, 'clickable', id, label, None, nr)
  2369.         except ControlNotFoundError:
  2370.             if name is not None and type is not None and id is not None or nr != 0:
  2371.                 raise 
  2372.             nr != 0
  2373.             return self._switch_click(return_type, request_class)
  2374.  
  2375.         return control._click(self, coord, return_type, request_class)
  2376.  
  2377.     
  2378.     def _pairs(self):
  2379.         return [ (k, v) for i, k, v, c_i in self._pairs_and_controls() ]
  2380.  
  2381.     
  2382.     def _pairs_and_controls(self):
  2383.         pairs = []
  2384.         for control_index in range(len(self.controls)):
  2385.             control = self.controls[control_index]
  2386.             for ii, key, val in control._totally_ordered_pairs():
  2387.                 pairs.append((ii, key, val, control_index))
  2388.             
  2389.         
  2390.         pairs.sort()
  2391.         return pairs
  2392.  
  2393.     
  2394.     def _request_data(self):
  2395.         method = self.method.upper()
  2396.         parts = self._urlparse(self.action)
  2397.         rest = parts[:-2]
  2398.         (query, frag) = parts[-2:]
  2399.         if method == 'GET':
  2400.             if self.enctype != 'application/x-www-form-urlencoded':
  2401.                 raise ValueError("unknown GET form encoding type '%s'" % self.enctype)
  2402.             self.enctype != 'application/x-www-form-urlencoded'
  2403.             parts = rest + (urlencode(self._pairs()), None)
  2404.             uri = self._urlunparse(parts)
  2405.             return (uri, None, [])
  2406.         if method == 'POST':
  2407.             parts = rest + (query, None)
  2408.             uri = self._urlunparse(parts)
  2409.             if self.enctype == 'application/x-www-form-urlencoded':
  2410.                 return (uri, urlencode(self._pairs()), [
  2411.                     ('Content-Type', self.enctype)])
  2412.             if self.enctype == 'multipart/form-data':
  2413.                 data = StringIO()
  2414.                 http_hdrs = []
  2415.                 mw = MimeWriter(data, http_hdrs)
  2416.                 f = mw.startmultipartbody('form-data', add_to_http_hdrs = True, prefix = 0)
  2417.                 for ii, k, v, control_index in self._pairs_and_controls():
  2418.                     self.controls[control_index]._write_mime_data(mw, k, v)
  2419.                 
  2420.                 mw.lastpart()
  2421.                 return (uri, data.getvalue(), http_hdrs)
  2422.             raise ValueError("unknown POST form encoding type '%s'" % self.enctype)
  2423.         method == 'POST'
  2424.         raise ValueError("Unknown method '%s'" % method)
  2425.  
  2426.     
  2427.     def _switch_click(self, return_type, request_class = urllib2.Request):
  2428.         if return_type == 'pairs':
  2429.             return self._pairs()
  2430.         if return_type == 'request_data':
  2431.             return self._request_data()
  2432.         req_data = self._request_data()
  2433.         req = request_class(req_data[0], req_data[1])
  2434.         for key, val in req_data[2]:
  2435.             add_hdr = req.add_header
  2436.             if key.lower() == 'content-type':
  2437.                 
  2438.                 try:
  2439.                     add_hdr = req.add_unredirected_header
  2440.                 except AttributeError:
  2441.                     return_type == 'request_data'
  2442.                     return_type == 'request_data'
  2443.                     return_type == 'pairs'
  2444.                 except:
  2445.                     return_type == 'request_data'<EXCEPTION MATCH>AttributeError
  2446.                 
  2447.  
  2448.             return_type == 'request_data'
  2449.             add_hdr(key, val)
  2450.         
  2451.         return req
  2452.  
  2453.  
  2454.