Home | Trees | Indices | Help |
|
---|
|
1 from lxml.etree import XPath, ElementBase 2 from lxml.html import fromstring, tostring 3 from lxml.html import defs 4 5 __all__ = ['FormNotFound', 'fill_form', 'fill_form_html', 6 'insert_errors', 'insert_errors_html', 7 'DefaultErrorCreator'] 8 13 14 _form_name_xpath = XPath('descendant-or-self::form[name=$name]') 15 _input_xpath = XPath('descendant-or-self::input | descendant-or-self::select | descendant-or-self::textarea') 16 _label_for_xpath = XPath('//label[@for=$for_id]') 17 _name_xpath = XPath('descendant-or-self::*[@name=$name]') 18 2729 if isinstance(html, basestring): 30 doc = fromstring(html) 31 return_string = True 32 else: 33 doc = copy.deepcopy(html) 34 return_string = False 35 fill_form(doc, values, form_id=form_id, form_index=form_index) 36 if return_string: 37 return tostring(doc) 38 else: 39 return doc4042 counts = {} 43 if hasattr(values, 'mixed'): 44 # For Paste request parameters 45 values = values.mixed() 46 inputs = _input_xpath(el) 47 for input in inputs: 48 name = input.get('name') 49 if not name: 50 continue 51 if _takes_multiple(input): 52 value = values.get(name, []) 53 if not isinstance(value, (list, tuple)): 54 value = [value] 55 _fill_multiple(input, value) 56 elif name not in values: 57 continue 58 else: 59 index = counts.get(name, 0) 60 counts[name] = index + 1 61 value = values[name] 62 if isinstance(value, (list, tuple)): 63 try: 64 value = value[index] 65 except IndexError: 66 continue 67 elif index > 0: 68 continue 69 _fill_single(input, value)7072 if input.tag == 'select' and input.get('multiple'): 73 # FIXME: multiple="0"? 74 return True 75 type = input.get('type', '').lower() 76 if type in ('radio', 'checkbox'): 77 return True 78 return False7981 type = input.get('type', '').lower() 82 if type == 'checkbox': 83 v = input.get('value') 84 if v is None: 85 if not value: 86 result = False 87 else: 88 result = value[0] 89 if isinstance(value, basestring): 90 # The only valid "on" value for an unnamed checkbox is 'on' 91 result = result == 'on' 92 _check(input, result) 93 else: 94 _check(input, v in value) 95 elif type == 'radio': 96 v = input.get('value') 97 _check(input, v in value) 98 else: 99 assert input.tag == 'select' 100 for option in input.findall('option'): 101 v = option.get('value') 102 if v is None: 103 # This seems to be the default, at least on IE 104 # FIXME: but I'm not sure 105 v = option.text_content() 106 _select(option, v in value)107109 if check: 110 el.set('checked', '') 111 else: 112 if 'checked' in el.attrib: 113 del el.attrib['checked']114116 if select: 117 el.set('selected', '') 118 else: 119 if 'selected' in el.attrib: 120 del el.attrib['selected']121123 if input.tag == 'textarea': 124 input.clear() 125 input.text = value 126 else: 127 input.set('value', value)128130 if form_id is None and form_index is None: 131 forms = el.getiterator('form') 132 for form in forms: 133 return form 134 raise FormNotFound( 135 "No forms in page") 136 if form_id is not None: 137 form = el.get_element_by_id(form_id) 138 if form is not None: 139 return form 140 forms = _form_name_xpath(el, name=form_id) 141 if forms: 142 return forms[0] 143 else: 144 raise FormNotFound( 145 "No form with the name or id of %r (forms: %s)" 146 % (id, ', '.join(_find_form_ids(el)))) 147 if form_index is not None: 148 forms = el.getiterator('form') 149 try: 150 return forms[form_index] 151 except IndexError: 152 raise FormNotFound( 153 "There is no form with the index %r (%i forms found)" 154 % (form_index, len(forms)))155157 forms = el.getiterator('form') 158 if not forms: 159 yield '(no forms)' 160 return 161 for index, form in enumerate(forms): 162 if form.get('id'): 163 if form.get('name'): 164 yield '%s or %s' % (form.get('id'), 165 form.get('name')) 166 else: 167 yield form.get('id') 168 elif form.get('name'): 169 yield form.get('name') 170 else: 171 yield '(unnamed form %s)' % index172 173 ############################################################ 174 ## Error filling 175 ############################################################ 176178 insert_before = True 179 block_inside = True 180 error_container_tag = 'div' 181 error_message_class = 'error-message' 182 error_block_class = 'error-block' 183 default_message = "Invalid" 184222 223 default_error_creator = DefaultErrorCreator() 224 225186 for name, value in kw.items(): 187 if not hasattr(self, name): 188 raise TypeError( 189 "Unexpected keyword argument: %s" % name) 190 setattr(self, name, value)191193 error_el = el.makeelement(self.error_container_tag) 194 if self.error_message_class: 195 error_el.set('class', self.error_message_class) 196 if is_block and self.error_block_class: 197 error_el.set('class', error_el.get('class', '')+' '+self.error_block_class) 198 if message is None or message == '': 199 message = self.default_message 200 if isinstance(message, ElementBase): 201 error_el.append(message) 202 else: 203 assert isinstance(message, basestring), ( 204 "Bad message; should be a string or element: %r" % message) 205 error_el.text = message or self.default_message 206 if is_block and self.block_inside: 207 if self.insert_before: 208 error_el.tail = el.text 209 el.text = None 210 el.insert(0, error_el) 211 else: 212 el.append(error_el) 213 else: 214 parent = el.getparent() 215 pos = parent.index(el) 216 if self.insert_before: 217 parent.insert(pos, error_el) 218 else: 219 error_el.tail = el.tail 220 el.tail = None 221 parent.insert(pos+1, error_el)226 -def insert_errors( 227 el, 228 errors, 229 form_id=None, 230 form_index=None, 231 error_class="error", 232 error_creator=default_error_creator, 233 ):234 el = _find_form(el, form_id=form_id, form_index=form_index) 235 for name, error in errors.iteritems(): 236 if error is None: 237 continue 238 for error_el, message in _find_elements_for_name(el, name, error): 239 assert isinstance(message, (basestring, type(None), ElementBase)), ( 240 "Bad message: %r" % message) 241 _insert_error(error_el, message, error_class, error_creator)242244 if isinstance(html, basestring): 245 doc = fromstring(html) 246 return_string = True 247 else: 248 doc = copy.deepcopy(html) 249 return_string = False 250 insert_errors(doc, values, **kw) 251 if return_string: 252 return tostring(doc) 253 else: 254 return doc255257 if el.tag in defs.empty_tags or el.tag == 'textarea': 258 is_block = False 259 else: 260 is_block = True 261 if el.tag != 'form' and error_class: 262 _add_class(el, error_class) 263 if el.get('id'): 264 labels = _label_for_xpath(el, for_id=el.get('id')) 265 if labels: 266 for label in labels: 267 _add_class(label, error_class) 268 error_creator(el, is_block, error)269271 if el.get('class'): 272 el.set('class', el.get('class')+' '+class_name) 273 else: 274 el.set('class', class_name)275277 if name is None: 278 # An error for the entire form 279 yield form, error 280 return 281 if name.startswith('#'): 282 # By id 283 el = form.get_element_by_id(name[1:]) 284 if el is not None: 285 yield el, error 286 return 287 els = _name_xpath(form, name=name) 288 if not els: 289 # FIXME: should this raise an exception? 290 return 291 if not isinstance(error, (list, tuple)): 292 yield els[0], error 293 return 294 # FIXME: if error is longer than els, should it raise an error? 295 for el, err in zip(els, error): 296 if err is None: 297 continue 298 yield el, err299
Home | Trees | Indices | Help |
|
---|
Generated by Epydoc 3.0 on Fri Dec 12 22:47:07 2008 | http://epydoc.sourceforge.net |