Home | Trees | Indices | Help |
|
---|
|
1 from lxml.etree import XPath, ElementBase 2 from lxml.html import fromstring, XHTML_NAMESPACE 3 from lxml.html import _forms_xpath, _options_xpath, _nons, _transform_result 4 from lxml.html import defs 5 import copy 6 7 try: 8 basestring 9 except NameError: 10 # Python 3 11 basestring = str 12 13 __all__ = ['FormNotFound', 'fill_form', 'fill_form_html', 14 'insert_errors', 'insert_errors_html', 15 'DefaultErrorCreator'] 16 21 22 _form_name_xpath = XPath('descendant-or-self::form[name=$name]|descendant-or-self::x:form[name=$name]', namespaces={'x':XHTML_NAMESPACE}) 23 _input_xpath = XPath('|'.join(['descendant-or-self::'+_tag for _tag in ('input','select','textarea','x:input','x:select','x:textarea')]), 24 namespaces={'x':XHTML_NAMESPACE}) 25 _label_for_xpath = XPath('//label[@for=$for_id]|//x:label[@for=$for_id]', 26 namespaces={'x':XHTML_NAMESPACE}) 27 _name_xpath = XPath('descendant-or-self::*[@name=$name]') 28 3739 result_type = type(html) 40 if isinstance(html, basestring): 41 doc = fromstring(html) 42 else: 43 doc = copy.deepcopy(html) 44 fill_form(doc, values, form_id=form_id, form_index=form_index) 45 return _transform_result(result_type, doc)4648 counts = {} 49 if hasattr(values, 'mixed'): 50 # For Paste request parameters 51 values = values.mixed() 52 inputs = _input_xpath(el) 53 for input in inputs: 54 name = input.get('name') 55 if not name: 56 continue 57 if _takes_multiple(input): 58 value = values.get(name, []) 59 if not isinstance(value, (list, tuple)): 60 value = [value] 61 _fill_multiple(input, value) 62 elif name not in values: 63 continue 64 else: 65 index = counts.get(name, 0) 66 counts[name] = index + 1 67 value = values[name] 68 if isinstance(value, (list, tuple)): 69 try: 70 value = value[index] 71 except IndexError: 72 continue 73 elif index > 0: 74 continue 75 _fill_single(input, value)7678 if _nons(input.tag) == 'select' and input.get('multiple'): 79 # FIXME: multiple="0"? 80 return True 81 type = input.get('type', '').lower() 82 if type in ('radio', 'checkbox'): 83 return True 84 return False8587 type = input.get('type', '').lower() 88 if type == 'checkbox': 89 v = input.get('value') 90 if v is None: 91 if not value: 92 result = False 93 else: 94 result = value[0] 95 if isinstance(value, basestring): 96 # The only valid "on" value for an unnamed checkbox is 'on' 97 result = result == 'on' 98 _check(input, result) 99 else: 100 _check(input, v in value) 101 elif type == 'radio': 102 v = input.get('value') 103 _check(input, v in value) 104 else: 105 assert _nons(input.tag) == 'select' 106 for option in _options_xpath(input): 107 v = option.get('value') 108 if v is None: 109 # This seems to be the default, at least on IE 110 # FIXME: but I'm not sure 111 v = option.text_content() 112 _select(option, v in value)113115 if check: 116 el.set('checked', '') 117 else: 118 if 'checked' in el.attrib: 119 del el.attrib['checked']120122 if select: 123 el.set('selected', '') 124 else: 125 if 'selected' in el.attrib: 126 del el.attrib['selected']127129 if _nons(input.tag) == 'textarea': 130 input.text = value 131 else: 132 input.set('value', value)133135 if form_id is None and form_index is None: 136 forms = _forms_xpath(el) 137 for form in forms: 138 return form 139 raise FormNotFound( 140 "No forms in page") 141 if form_id is not None: 142 form = el.get_element_by_id(form_id) 143 if form is not None: 144 return form 145 forms = _form_name_xpath(el, name=form_id) 146 if forms: 147 return forms[0] 148 else: 149 raise FormNotFound( 150 "No form with the name or id of %r (forms: %s)" 151 % (id, ', '.join(_find_form_ids(el)))) 152 if form_index is not None: 153 forms = _forms_xpath(el) 154 try: 155 return forms[form_index] 156 except IndexError: 157 raise FormNotFound( 158 "There is no form with the index %r (%i forms found)" 159 % (form_index, len(forms)))160162 forms = _forms_xpath(el) 163 if not forms: 164 yield '(no forms)' 165 return 166 for index, form in enumerate(forms): 167 if form.get('id'): 168 if form.get('name'): 169 yield '%s or %s' % (form.get('id'), 170 form.get('name')) 171 else: 172 yield form.get('id') 173 elif form.get('name'): 174 yield form.get('name') 175 else: 176 yield '(unnamed form %s)' % index177 178 ############################################################ 179 ## Error filling 180 ############################################################ 181183 insert_before = True 184 block_inside = True 185 error_container_tag = 'div' 186 error_message_class = 'error-message' 187 error_block_class = 'error-block' 188 default_message = "Invalid" 189227 228 default_error_creator = DefaultErrorCreator() 229 230191 for name, value in kw.items(): 192 if not hasattr(self, name): 193 raise TypeError( 194 "Unexpected keyword argument: %s" % name) 195 setattr(self, name, value)196198 error_el = el.makeelement(self.error_container_tag) 199 if self.error_message_class: 200 error_el.set('class', self.error_message_class) 201 if is_block and self.error_block_class: 202 error_el.set('class', error_el.get('class', '')+' '+self.error_block_class) 203 if message is None or message == '': 204 message = self.default_message 205 if isinstance(message, ElementBase): 206 error_el.append(message) 207 else: 208 assert isinstance(message, basestring), ( 209 "Bad message; should be a string or element: %r" % message) 210 error_el.text = message or self.default_message 211 if is_block and self.block_inside: 212 if self.insert_before: 213 error_el.tail = el.text 214 el.text = None 215 el.insert(0, error_el) 216 else: 217 el.append(error_el) 218 else: 219 parent = el.getparent() 220 pos = parent.index(el) 221 if self.insert_before: 222 parent.insert(pos, error_el) 223 else: 224 error_el.tail = el.tail 225 el.tail = None 226 parent.insert(pos+1, error_el)231 -def insert_errors( 232 el, 233 errors, 234 form_id=None, 235 form_index=None, 236 error_class="error", 237 error_creator=default_error_creator, 238 ):239 el = _find_form(el, form_id=form_id, form_index=form_index) 240 for name, error in errors.items(): 241 if error is None: 242 continue 243 for error_el, message in _find_elements_for_name(el, name, error): 244 assert isinstance(message, (basestring, type(None), ElementBase)), ( 245 "Bad message: %r" % message) 246 _insert_error(error_el, message, error_class, error_creator)247249 result_type = type(html) 250 if isinstance(html, basestring): 251 doc = fromstring(html) 252 else: 253 doc = copy.deepcopy(html) 254 insert_errors(doc, values, **kw) 255 return _transform_result(result_type, doc)256258 if _nons(el.tag) in defs.empty_tags or _nons(el.tag) == 'textarea': 259 is_block = False 260 else: 261 is_block = True 262 if _nons(el.tag) != 'form' and error_class: 263 _add_class(el, error_class) 264 if el.get('id'): 265 labels = _label_for_xpath(el, for_id=el.get('id')) 266 if labels: 267 for label in labels: 268 _add_class(label, error_class) 269 error_creator(el, is_block, error)270272 if el.get('class'): 273 el.set('class', el.get('class')+' '+class_name) 274 else: 275 el.set('class', class_name)276278 if name is None: 279 # An error for the entire form 280 yield form, error 281 return 282 if name.startswith('#'): 283 # By id 284 el = form.get_element_by_id(name[1:]) 285 if el is not None: 286 yield el, error 287 return 288 els = _name_xpath(form, name=name) 289 if not els: 290 # FIXME: should this raise an exception? 291 return 292 if not isinstance(error, (list, tuple)): 293 yield els[0], error 294 return 295 # FIXME: if error is longer than els, should it raise an error? 296 for el, err in zip(els, error): 297 if err is None: 298 continue 299 yield el, err300
Home | Trees | Indices | Help |
|
---|
Generated by Epydoc 3.0.1 on Thu Jul 9 18:29:53 2020 | http://epydoc.sourceforge.net |