Home | Trees | Indices | Help |
|
---|
|
1 from lxml.etree import XPath, ElementBase 2 from lxml.html import fromstring, tostring, XHTML_NAMESPACE 3 from lxml.html import _forms_xpath, _options_xpath, _nons, _transform_result 4 from lxml.html import defs 5 try: 6 basestring = __builtins__["basestring"] 7 except (KeyError, NameError): 8 # Python 3 9 basestring = str 10 11 __all__ = ['FormNotFound', 'fill_form', 'fill_form_html', 12 'insert_errors', 'insert_errors_html', 13 'DefaultErrorCreator'] 14 19 20 _form_name_xpath = XPath('descendant-or-self::form[name=$name]|descendant-or-self::x:form[name=$name]', namespaces={'x':XHTML_NAMESPACE}) 21 _input_xpath = XPath('|'.join(['descendant-or-self::'+_tag for _tag in ('input','select','textarea','x:input','x:select','x:textarea')]), 22 namespaces={'x':XHTML_NAMESPACE}) 23 _label_for_xpath = XPath('//label[@for=$for_id]|//x:label[@for=$for_id]', 24 namespaces={'x':XHTML_NAMESPACE}) 25 _name_xpath = XPath('descendant-or-self::*[@name=$name]') 26 3537 result_type = type(html) 38 if isinstance(html, basestring): 39 doc = fromstring(html) 40 else: 41 doc = copy.deepcopy(html) 42 fill_form(doc, values, form_id=form_id, form_index=form_index) 43 return _transform_result(result_type, doc)4446 counts = {} 47 if hasattr(values, 'mixed'): 48 # For Paste request parameters 49 values = values.mixed() 50 inputs = _input_xpath(el) 51 for input in inputs: 52 name = input.get('name') 53 if not name: 54 continue 55 if _takes_multiple(input): 56 value = values.get(name, []) 57 if not isinstance(value, (list, tuple)): 58 value = [value] 59 _fill_multiple(input, value) 60 elif name not in values: 61 continue 62 else: 63 index = counts.get(name, 0) 64 counts[name] = index + 1 65 value = values[name] 66 if isinstance(value, (list, tuple)): 67 try: 68 value = value[index] 69 except IndexError: 70 continue 71 elif index > 0: 72 continue 73 _fill_single(input, value)7476 if _nons(input.tag) == 'select' and input.get('multiple'): 77 # FIXME: multiple="0"? 78 return True 79 type = input.get('type', '').lower() 80 if type in ('radio', 'checkbox'): 81 return True 82 return False8385 type = input.get('type', '').lower() 86 if type == 'checkbox': 87 v = input.get('value') 88 if v is None: 89 if not value: 90 result = False 91 else: 92 result = value[0] 93 if isinstance(value, basestring): 94 # The only valid "on" value for an unnamed checkbox is 'on' 95 result = result == 'on' 96 _check(input, result) 97 else: 98 _check(input, v in value) 99 elif type == 'radio': 100 v = input.get('value') 101 _check(input, v in value) 102 else: 103 assert _nons(input.tag) == 'select' 104 for option in _options_xpath(input): 105 v = option.get('value') 106 if v is None: 107 # This seems to be the default, at least on IE 108 # FIXME: but I'm not sure 109 v = option.text_content() 110 _select(option, v in value)111113 if check: 114 el.set('checked', '') 115 else: 116 if 'checked' in el.attrib: 117 del el.attrib['checked']118120 if select: 121 el.set('selected', '') 122 else: 123 if 'selected' in el.attrib: 124 del el.attrib['selected']125127 if _nons(input.tag) == 'textarea': 128 input.clear() 129 input.text = value 130 else: 131 input.set('value', value)132134 if form_id is None and form_index is None: 135 forms = _forms_xpath(el) 136 for form in forms: 137 return form 138 raise FormNotFound( 139 "No forms in page") 140 if form_id is not None: 141 form = el.get_element_by_id(form_id) 142 if form is not None: 143 return form 144 forms = _form_name_xpath(el, name=form_id) 145 if forms: 146 return forms[0] 147 else: 148 raise FormNotFound( 149 "No form with the name or id of %r (forms: %s)" 150 % (id, ', '.join(_find_form_ids(el)))) 151 if form_index is not None: 152 forms = _forms_xpath(el) 153 try: 154 return forms[form_index] 155 except IndexError: 156 raise FormNotFound( 157 "There is no form with the index %r (%i forms found)" 158 % (form_index, len(forms)))159161 forms = _forms_xpath(el) 162 if not forms: 163 yield '(no forms)' 164 return 165 for index, form in enumerate(forms): 166 if form.get('id'): 167 if form.get('name'): 168 yield '%s or %s' % (form.get('id'), 169 form.get('name')) 170 else: 171 yield form.get('id') 172 elif form.get('name'): 173 yield form.get('name') 174 else: 175 yield '(unnamed form %s)' % index176 177 ############################################################ 178 ## Error filling 179 ############################################################ 180182 insert_before = True 183 block_inside = True 184 error_container_tag = 'div' 185 error_message_class = 'error-message' 186 error_block_class = 'error-block' 187 default_message = "Invalid" 188226 227 default_error_creator = DefaultErrorCreator() 228 229190 for name, value in kw.items(): 191 if not hasattr(self, name): 192 raise TypeError( 193 "Unexpected keyword argument: %s" % name) 194 setattr(self, name, value)195197 error_el = el.makeelement(self.error_container_tag) 198 if self.error_message_class: 199 error_el.set('class', self.error_message_class) 200 if is_block and self.error_block_class: 201 error_el.set('class', error_el.get('class', '')+' '+self.error_block_class) 202 if message is None or message == '': 203 message = self.default_message 204 if isinstance(message, ElementBase): 205 error_el.append(message) 206 else: 207 assert isinstance(message, basestring), ( 208 "Bad message; should be a string or element: %r" % message) 209 error_el.text = message or self.default_message 210 if is_block and self.block_inside: 211 if self.insert_before: 212 error_el.tail = el.text 213 el.text = None 214 el.insert(0, error_el) 215 else: 216 el.append(error_el) 217 else: 218 parent = el.getparent() 219 pos = parent.index(el) 220 if self.insert_before: 221 parent.insert(pos, error_el) 222 else: 223 error_el.tail = el.tail 224 el.tail = None 225 parent.insert(pos+1, error_el)230 -def insert_errors( 231 el, 232 errors, 233 form_id=None, 234 form_index=None, 235 error_class="error", 236 error_creator=default_error_creator, 237 ):238 el = _find_form(el, form_id=form_id, form_index=form_index) 239 for name, error in errors.items(): 240 if error is None: 241 continue 242 for error_el, message in _find_elements_for_name(el, name, error): 243 assert isinstance(message, (basestring, type(None), ElementBase)), ( 244 "Bad message: %r" % message) 245 _insert_error(error_el, message, error_class, error_creator)246248 result_type = type(html) 249 if isinstance(html, basestring): 250 doc = fromstring(html) 251 else: 252 doc = copy.deepcopy(html) 253 insert_errors(doc, values, **kw) 254 return _transform_result(result_type, doc)255257 if _nons(el.tag) in defs.empty_tags or _nons(el.tag) == 'textarea': 258 is_block = False 259 else: 260 is_block = True 261 if _nons(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 Thu Jun 19 18:45:21 2008 | http://epydoc.sourceforge.net |