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 import copy 6 try: 7 basestring = __builtins__["basestring"] 8 except (KeyError, NameError): 9 # Python 3 10 basestring = str 11 12 __all__ = ['FormNotFound', 'fill_form', 'fill_form_html', 13 'insert_errors', 'insert_errors_html', 14 'DefaultErrorCreator'] 15 20 21 _form_name_xpath = XPath('descendant-or-self::form[name=$name]|descendant-or-self::x:form[name=$name]', namespaces={'x':XHTML_NAMESPACE}) 22 _input_xpath = XPath('|'.join(['descendant-or-self::'+_tag for _tag in ('input','select','textarea','x:input','x:select','x:textarea')]), 23 namespaces={'x':XHTML_NAMESPACE}) 24 _label_for_xpath = XPath('//label[@for=$for_id]|//x:label[@for=$for_id]', 25 namespaces={'x':XHTML_NAMESPACE}) 26 _name_xpath = XPath('descendant-or-self::*[@name=$name]') 27 3638 result_type = type(html) 39 if isinstance(html, basestring): 40 doc = fromstring(html) 41 else: 42 doc = copy.deepcopy(html) 43 fill_form(doc, values, form_id=form_id, form_index=form_index) 44 return _transform_result(result_type, doc)4547 counts = {} 48 if hasattr(values, 'mixed'): 49 # For Paste request parameters 50 values = values.mixed() 51 inputs = _input_xpath(el) 52 for input in inputs: 53 name = input.get('name') 54 if not name: 55 continue 56 if _takes_multiple(input): 57 value = values.get(name, []) 58 if not isinstance(value, (list, tuple)): 59 value = [value] 60 _fill_multiple(input, value) 61 elif name not in values: 62 continue 63 else: 64 index = counts.get(name, 0) 65 counts[name] = index + 1 66 value = values[name] 67 if isinstance(value, (list, tuple)): 68 try: 69 value = value[index] 70 except IndexError: 71 continue 72 elif index > 0: 73 continue 74 _fill_single(input, value)7577 if _nons(input.tag) == 'select' and input.get('multiple'): 78 # FIXME: multiple="0"? 79 return True 80 type = input.get('type', '').lower() 81 if type in ('radio', 'checkbox'): 82 return True 83 return False8486 type = input.get('type', '').lower() 87 if type == 'checkbox': 88 v = input.get('value') 89 if v is None: 90 if not value: 91 result = False 92 else: 93 result = value[0] 94 if isinstance(value, basestring): 95 # The only valid "on" value for an unnamed checkbox is 'on' 96 result = result == 'on' 97 _check(input, result) 98 else: 99 _check(input, v in value) 100 elif type == 'radio': 101 v = input.get('value') 102 _check(input, v in value) 103 else: 104 assert _nons(input.tag) == 'select' 105 for option in _options_xpath(input): 106 v = option.get('value') 107 if v is None: 108 # This seems to be the default, at least on IE 109 # FIXME: but I'm not sure 110 v = option.text_content() 111 _select(option, v in value)112114 if check: 115 el.set('checked', '') 116 else: 117 if 'checked' in el.attrib: 118 del el.attrib['checked']119121 if select: 122 el.set('selected', '') 123 else: 124 if 'selected' in el.attrib: 125 del el.attrib['selected']126128 if _nons(input.tag) == 'textarea': 129 input.clear() 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 Sun Feb 6 20:30:25 2011 | http://epydoc.sourceforge.net |