a
    mzfR                     @   s  d Z ddlZddlZddlmZmZ ddlmZ d<ddZG dd	 d	e	Z
G d
d de	ZG dd deZG dd deZG dd deZG dd deZG dd deZG dd deZG dd deZG dd deZG dd deZG dd deZG d d! d!eZG d"d# d#eZG d$d% d%eZG d&d' d'eZG d(d) d)eZG d*d+ d+eZG d,d- d-eZG d.d/ d/eZG d0d1 d1eZG d2d3 d3eZ G d4d5 d5eZ!G d6d7 d7Z"e"d8e#Z$G d9d: d:e"Z%e&d;krddl'Z'e'(  dS )=z
HTML forms
(part of web.py)
    N   )netutils)webapic                 C   sf   z t | dr|| v r| | W S W n ty2   Y n0 t | drN|| v rN| | S t | |rbt| |S |S )NZhas_keykeys)hasattr	TypeErrorgetattr)objattrvalue r   6/var/www/media/lib/python3.9/site-packages/web/form.pyattrget   s    

r   c                   @   s   e Zd ZdZdd ZdddZdd Zd	d
 Zdd ZdddZ	dd Z
dddZdd Zdd ZdddZdd ZeeZdS ) Forma  
    HTML form.

        >>> f = Form(Textbox("x"))
        >>> f.render()
        u'<table>\n    <tr><th><label for="x">x</label></th><td><input id="x" name="x" type="text"/></td></tr>\n</table>'
        >>> f.fill(x="42")
        True
        >>> f.render()
        u'<table>\n    <tr><th><label for="x">x</label></th><td><input id="x" name="x" type="text" value="42"/></td></tr>\n</table>'
    c                 O   s$   || _ d| _d | _|dg | _d S )NT
validators)inputsvalidnotepopr   )selfr   kwr   r   r   __init__+   s    zForm.__init__Nc                 C   s   t | }|r|| |S N)copydeepcopy	validates)r   xor   r   r   __call__1   s    

zForm.__call__c                 C   s   d}||  | j7 }|d7 }| jD ]h}t|j|  |  |j t|j }| rh|d| 7 }q"|dt	
|jt	
|j|f 7 }q"|d7 }|S )N z<table>
z9    <tr style="display: none;"><th></th><td>%s</td></tr>
z<    <tr><th><label for="%s">%s</label></th><td>%s</td></tr>
z</table>)
rendernoter   r   r   Zsafeunicodeprerenderpost	is_hiddenr   websafeiddescription)r   outihtmlr   r   r   r#   7   s.    



zForm.renderc                 C   s   g }| | | j | jD ]p}| sJ| dt|jt|jf  | |j	 | |
  | | |j | |j | d qd|S )Nz<label for="%s">%s</label>
r    )appendr!   r   r   r%   r   r&   r'   r(   r"   r#   r$   join)r   r)   r*   r   r   r   
render_cssO   s    
zForm.render_cssc                 C   s   |rdt | S dS d S Nz!<strong class="wrong">%s</strong>r    r   r&   r   r   r   r   r   r!   _   s    zForm.rendernoteTc                 K   sf   |p|pt  }d}| jD ].}t||j}|r>||o:|}q|| q|rb|oZ| |}|| _|S NT)	webinputr   r   namevalidate	set_value	_validater   )r   sourcer9   r   r)   r*   vr   r   r   r   e   s    
zForm.validatesc                 C   s.   || _ | jD ]}||s|j| _ dS qdS NFT)r   r   r   msgr   r   r   r;   r   r   r   r9   s   s    

zForm._validatec                 K   s   | j |fddi|S )Nr9   F)r   )r   r:   r   r   r   r   fill{   s    z	Form.fillc                 C   s*   | j D ]}|j|kr|  S qt|d S r   )r   r6   KeyError)r   r*   r   r   r   r   __getitem__~   s    


zForm.__getitem__c                 C   s8   | j dpg }|D ]}|j|kr|  S qt|d S )Nr   )__dict__getr6   AttributeError)r   r6   r   r   r   r   r   __getattr__   s
    

zForm.__getattr__c                 C   s&   z
| | W S  t y    | Y S 0 d S r   )r@   )r   r*   defaultr   r   r   rC      s    
zForm.getc                 C   s   t dd | jD S )Nc                 S   s   g | ]}|j | fqS r   )r6   	get_value).0r*   r   r   r   
<listcomp>       zForm._get_d.<locals>.<listcomp>)r   Zstorager   r   r   r   r   _get_d   s    zForm._get_d)N)NT)N)N)__name__
__module____qualname____doc__r   r   r#   r/   r!   r   r9   r?   rA   rE   rC   rL   propertydr   r   r   r   r      s   



r   c                   @   s`   e Zd ZdZdd Zdd Zdd Zdd	 Zd
d Zdd Z	dd Z
dd Zdd Zdd ZdS )Inputa  Generic input. Type attribute must be specified when called directly.

    See also: <https://www.w3.org/TR/html52/sec-forms.html#the-input-element>

    Currently only types which can be written inside one `<input />` tag are
    supported.

    - For checkbox, please use `Checkbox` class for better control.
    - For radiobox, please use `Radio` class for better control.

        >>> Input(name='foo', type='email', value="user@domain.com").render()
        u'<input id="foo" name="foo" type="email" value="user@domain.com"/>'
        >>> Input(name='foo', type='number', value="bar").render()
        u'<input id="foo" name="foo" type="number" value="bar"/>'
        >>> Input(name='num', type="number", min='0', max='10', step='2', value='5').render()
        u'<input id="num" max="10" min="0" name="num" step="2" type="number" value="5"/>'
        >>> Input(name='foo', type="tel", value='55512345').render()
        u'<input id="foo" name="foo" type="tel" value="55512345"/>'
        >>> Input(name='search', type="search", value='Search').render()
        u'<input id="search" name="search" type="search" value="Search"/>'
        >>> Input(name='search', type="search", value='Search', required='required', pattern='[a-z0-9]{2,30}', placeholder='Search...').render()
        u'<input id="search" name="search" pattern="[a-z0-9]{2,30}" placeholder="Search..." required="required" type="search" value="Search"/>'
        >>> Input(name='url', type="url", value='url').render()
        u'<input id="url" name="url" type="url" value="url"/>'
        >>> Input(name='range', type="range", min='0', max='10', step='2', value='5').render()
        u'<input id="range" max="10" min="0" name="range" step="2" type="range" value="5"/>'
        >>> Input(name='color', type="color").render()
        u'<input id="color" name="color" type="color"/>'
        >>> Input(name='f', type="file", accept=".doc,.docx,.xml").render()
        u'<input accept=".doc,.docx,.xml" id="f" name="f" type="file"/>'
    c                 O   s   || _ || _t| | _}|dd | _|d|| _|dd | _|dd| _|dd| _	d | _
|d|  | _d|v r|d |d	< |d= d S )
Ntyper(   r   r"   r    r$   r'   class_class)r6   r   AttributeListattrsr   rT   r(   r   r"   r$   r   
setdefaultget_default_idr'   r   r6   r   rX   r   r   r   r      s    zInput.__init__c                 C   s   dS NFr   rK   r   r   r   r%      s    zInput.is_hiddenc                 C   s   | j d ur| j S tdd S )Nzmissing attribute 'type')rT   rD   rK   r   r   r   get_type   s    
zInput.get_typec                 C   s   | j S r   )r6   rK   r   r   r   rZ      s    zInput.get_default_idc                 C   s2   |  | | jD ]}||s|j| _ dS qdS r<   )r8   r   r   r=   r   r>   r   r   r   r7      s    


zInput.validatec                 C   s
   || _ d S r   r   r   r   r   r   r   r8      s    zInput.set_valuec                 C   s   | j S r   r^   rK   r   r   r   rG      s    zInput.get_valuec                 C   sF   | j  }|  |d< | jd ur*| j|d< | j|d< | j|d< d| S )NrT   r   r6   r'   <input %s/>)rX   r   r]   r   r6   r'   r   rX   r   r   r   r#      s    




zInput.renderc                 C   s   |rdt | S dS d S r0   r1   r2   r   r   r   r!      s    zInput.rendernotec                 C   s   dt | j S )N )strrX   rK   r   r   r   addatts   s    zInput.addattsN)rM   rN   rO   rP   r   r%   r]   rZ   r7   r8   rG   r#   r!   rd   r   r   r   r   rS      s    		rS   c                   @   s(   e Zd ZdZdd Zdd Zdd ZdS )	rW   zList of attributes of input.

    >>> a = AttributeList(type='text', name='x', value=20)
    >>> a
    <attrs: 'name="x" type="text" value="20"'>
    c                 C   s   t | S r   )rW   rK   r   r   r   r     s    zAttributeList.copyc                 C   s   d dd t|  D S )Nrb   c                 S   s"   g | ]\}}d |t |f qS )z%s="%s"r1   )rH   kr;   r   r   r   rI     rJ   z)AttributeList.__str__.<locals>.<listcomp>)r.   sorteditemsrK   r   r   r   __str__  s    zAttributeList.__str__c                 C   s   dt t|  S )Nz<attrs: %s>)reprrc   rK   r   r   r   __repr__
  s    zAttributeList.__repr__N)rM   rN   rO   rP   r   rh   rj   r   r   r   r   rW      s   rW   c                   @   s   e Zd ZdZdd ZdS )TextboxzTextbox input.

    >>> Textbox(name='foo', value='bar').render()
    u'<input id="foo" name="foo" type="text" value="bar"/>'
    >>> Textbox(name='foo', value=0).render()
    u'<input id="foo" name="foo" type="text" value="0"/>'
    c                 C   s   dS )Ntextr   rK   r   r   r   r]     s    zTextbox.get_typeNrM   rN   rO   rP   r]   r   r   r   r   rk     s   rk   c                   @   s   e Zd ZdZdd ZdS )PasswordzPassword input.

    >>> Password(name='password', value='secret').render()
    u'<input id="password" name="password" type="password" value="secret"/>'
    c                 C   s   dS )Npasswordr   rK   r   r   r   r]   "  s    zPassword.get_typeNrm   r   r   r   r   rn     s   rn   c                   @   s   e Zd ZdZdd ZdS )Textareaz|Textarea input.

    >>> Textarea(name='foo', value='bar').render()
    u'<textarea id="foo" name="foo">bar</textarea>'
    c                 C   s0   | j  }| j|d< t| jp d}d||f S )Nr6   r    z<textarea %s>%s</textarea>)rX   r   r6   r   r&   r   )r   rX   r   r   r   r   r#   -  s    

zTextarea.renderN)rM   rN   rO   rP   r#   r   r   r   r   rp   &  s   rp   c                       s2   e Zd ZdZ fddZdd Zd	ddZ  ZS )
Dropdowna  Dropdown/select input.

    >>> Dropdown(name='foo', args=['a', 'b', 'c'], value='b').render()
    u'<select id="foo" name="foo">\n  <option value="a">a</option>\n  <option selected="selected" value="b">b</option>\n  <option value="c">c</option>\n</select>\n'
    >>> Dropdown(name='foo', args=[('a', 'aa'), ('b', 'bb'), ('c', 'cc')], value='b').render()
    u'<select id="foo" name="foo">\n  <option value="a">aa</option>\n  <option selected="selected" value="b">bb</option>\n  <option value="c">cc</option>\n</select>\n'
    c                    s(   || _ tt| j|g|R i | d S r   argssuperrq   r   r   r6   rs   r   rX   	__class__r   r   r   =  s    zDropdown.__init__c                 C   sB   | j  }| j|d< d| }| jD ]}|| |7 }q"|d7 }|S )Nr6   <select %s>

</select>
)rX   r   r6   rs   _render_option)r   rX   r   argr   r   r   r#   A  s    


zDropdown.render  c                 C   s   t |ttfr|\}}n
|| }}t|}t | jttfrNdd | jD }nt| j}||kstt |trz||v rzd}nd}|d|t|t|f  S )Nc                 S   s   g | ]}t |qS r   )r   safestr)rH   r   r   r   r   rI   U  rJ   z+Dropdown._render_option.<locals>.<listcomp>z selected="selected"r    z!<option%s value="%s">%s</option>
)
isinstancetuplelistr   r}   r   r   r&   )r   r{   indentr   descZs_valueZselect_pr   r   r   rz   M  s    


zDropdown._render_option)r|   )rM   rN   rO   rP   r   r#   rz   __classcell__r   r   rv   r   rq   4  s   rq   c                       s(   e Zd ZdZ fddZdd Z  ZS )GroupedDropdowna  Grouped Dropdown/select input.

    >>> GroupedDropdown(name='car_type', args=(('Swedish Cars', ('Volvo', 'Saab')), ('German Cars', ('Mercedes', 'Audi'))), value='Audi').render()
    u'<select id="car_type" name="car_type">\n  <optgroup label="Swedish Cars">\n    <option value="Volvo">Volvo</option>\n    <option value="Saab">Saab</option>\n  </optgroup>\n  <optgroup label="German Cars">\n    <option value="Mercedes">Mercedes</option>\n    <option selected="selected" value="Audi">Audi</option>\n  </optgroup>\n</select>\n'
    >>> GroupedDropdown(name='car_type', args=(('Swedish Cars', (('v', 'Volvo'), ('s', 'Saab'))), ('German Cars', (('m', 'Mercedes'), ('a', 'Audi')))), value='a').render()
    u'<select id="car_type" name="car_type">\n  <optgroup label="Swedish Cars">\n    <option value="v">Volvo</option>\n    <option value="s">Saab</option>\n  </optgroup>\n  <optgroup label="German Cars">\n    <option value="m">Mercedes</option>\n    <option selected="selected" value="a">Audi</option>\n  </optgroup>\n</select>\n'

    c                    s(   || _ tt| j|g|R i | d S r   rr   ru   rv   r   r   r   n  s    zGroupedDropdown.__init__c                 C   sn   | j  }| j|d< d| }| jD ]>\}}|dt| 7 }|D ]}|| j|dd7 }q@|d7 }q"|d7 }|S )Nr6   rx   z  <optgroup label="%s">
z    )r   z  </optgroup>
ry   )rX   r   r6   rs   r   r&   rz   )r   rX   r   labeloptionsr{   r   r   r   r#   r  s    


zGroupedDropdown.renderrM   rN   rO   rP   r   r#   r   r   r   rv   r   r   d  s   	r   c                       s$   e Zd Z fddZdd Z  ZS )Radioc                    s(   || _ tt| j|g|R i | d S r   )rs   rt   r   r   ru   rv   r   r   r     s    zRadio.__init__c                 C   s   d}t | jddD ]\}}t|ttfr2|\}}n
|| }}| j }| j|d< d|d< ||d< | jt| |d< | j	|krd	|d	< |d
|t
|f 7 }q|d7 }|S )Nz<span>r   )startr6   ZradiorT   r   r'   checkedz<input %s/> %sz</span>)	enumeraters   r~   r   r   rX   r   r6   rc   r   r   r&   )r   r   idxr{   r   r   rX   r   r   r   r#     s    




zRadio.render)rM   rN   rO   r   r#   r   r   r   rv   r   r     s   r   c                   @   s8   e Zd ZdZdd Zdd Zdd Zdd	 Zd
d ZdS )Checkboxa  Checkbox input.

    >>> Checkbox('foo', value='bar', checked=True).render()
    u'<input checked="checked" id="foo_bar" name="foo" type="checkbox" value="bar"/>'
    >>> Checkbox('foo', value='bar').render()
    u'<input id="foo_bar" name="foo" type="checkbox" value="bar"/>'
    >>> c = Checkbox('foo', value='bar')
    >>> c.validate('on')
    True
    >>> c.render()
    u'<input checked="checked" id="foo_bar" name="foo" type="checkbox" value="bar"/>'
    c                 O   s,   | dd| _tj| |g|R i | d S )Nr   F)r   r   rS   r   r[   r   r   r   r     s    zCheckbox.__init__c                 C   s&   t | jpd}| jd |dd S )Nr    _rb   )r   r}   r   r6   replacer_   r   r   r   rZ     s    zCheckbox.get_default_idc                 C   s<   | j  }d|d< | j|d< | j|d< | jr4d|d< d| S )NZcheckboxrT   r6   r   r   r`   )rX   r   r6   r   r   ra   r   r   r   r#     s    


zCheckbox.renderc                 C   s   t || _d S r   )boolr   r_   r   r   r   r8     s    zCheckbox.set_valuec                 C   s   | j S r   )r   rK   r   r   r   rG     s    zCheckbox.get_valueN)	rM   rN   rO   rP   r   rZ   r#   r8   rG   r   r   r   r   r     s   
r   c                       s(   e Zd ZdZ fddZdd Z  ZS )Buttona  HTML Button.

    >>> Button("save").render()
    u'<button id="save" name="save">save</button>'
    >>> Button("action", value="save", html="<b>Save Changes</b>").render()
    u'<button id="action" name="action" value="save"><b>Save Changes</b></button>'
    c                    s(   t t| j|g|R i | d| _d S )Nr    )rt   r   r   r(   r[   rv   r   r   r     s    zButton.__init__c                 C   sL   | j  }| j|d< | jd ur(| j|d< |dd p>t| j}d||f S )Nr6   r   r+   z<button %s>%s</button>)rX   r   r6   r   r   r   r&   )r   rX   r+   r   r   r   r#     s    



zButton.renderr   r   r   rv   r   r     s   r   c                   @   s    e Zd ZdZdd Zdd ZdS )HiddenzHidden Input.

    >>> Hidden(name='foo', value='bar').render()
    u'<input id="foo" name="foo" type="hidden" value="bar"/>'
    c                 C   s   dS r3   r   rK   r   r   r   r%     s    zHidden.is_hiddenc                 C   s   dS )Nhiddenr   rK   r   r   r   r]     s    zHidden.get_typeN)rM   rN   rO   rP   r%   r]   r   r   r   r   r     s   r   c                   @   s   e Zd ZdZdd ZdS )FilezFile input.

    >>> File(name='f', accept=".doc,.docx,.xml").render()
    u'<input accept=".doc,.docx,.xml" id="f" name="f" type="file"/>'
    c                 C   s   dS )Nfiler   rK   r   r   r   r]     s    zFile.get_typeNrm   r   r   r   r   r     s   r   c                   @   s   e Zd ZdZdd ZdS )	TelephonezTelephone input.

    See: <https://html.spec.whatwg.org/#telephone-state-(type=tel)>

    >>> Telephone(name='tel', value='55512345').render()
    u'<input id="tel" name="tel" type="tel" value="55512345"/>'
    c                 C   s   dS )Ntelr   rK   r   r   r   r]     s    zTelephone.get_typeNrm   r   r   r   r   r     s   r   c                   @   s   e Zd ZdZdd ZdS )EmailzEmail input.

    See: <https://html.spec.whatwg.org/#e-mail-state-(type=email)>

    >>> Email(name='email', value='me@example.org').render()
    u'<input id="email" name="email" type="email" value="me@example.org"/>'

    c                 C   s   dS )Nemailr   rK   r   r   r   r]     s    zEmail.get_typeNrm   r   r   r   r   r     s   	r   c                   @   s   e Zd ZdZdd ZdS )Datea  Date input.

    Note: Not supported by desktop Safari, Internet Explorer, or Opera Mini

    See: <https://html.spec.whatwg.org/#date-state-(type=date)>

    >>> Date(name='date', value='2020-04-01').render()
    u'<input id="date" name="date" type="date" value="2020-04-01"/>'

    c                 C   s   dS )Ndater   rK   r   r   r   r]     s    zDate.get_typeNrm   r   r   r   r   r     s   r   c                   @   s   e Zd ZdZdd ZdS )Timea  Time input.

    Note: Not supported by desktop Safari, Internet Explorer, or Opera Mini

    See: <https://html.spec.whatwg.org/#time-state-(type=time)>

    >>> Time(name='time', value='07:00').render()
    u'<input id="time" name="time" type="time" value="07:00"/>'

    c                 C   s   dS )Ntimer   rK   r   r   r   r]   '  s    zTime.get_typeNrm   r   r   r   r   r     s   r   c                   @   s   e Zd ZdZdd ZdS )Searcha  Search input.

    See: <https://html.spec.whatwg.org/#text-(type=text)-state-and-search-state-(type=search)>

    >> Search(name='search', value='Search').render()
    u'<input id="search" name="search" type="search" value="Search"/>'
    >>> Search(name='search', value='Search', required='required', pattern='[a-z0-9]{2,30}', placeholder='Search...').render()
    u'<input id="search" name="search" pattern="[a-z0-9]{2,30}" placeholder="Search..." required="required" type="search" value="Search"/>'

    c                 C   s   dS )Nsearchr   rK   r   r   r   r]   7  s    zSearch.get_typeNrm   r   r   r   r   r   +  s   r   c                   @   s   e Zd ZdZdd ZdS )UrlzURL input.

    See: <https://html.spec.whatwg.org/#url-state-(type=url)>

    >>> Url(name='url', value='url').render()
    u'<input id="url" name="url" type="url" value="url"/>'
    c                 C   s   dS )Nurlr   rK   r   r   r   r]   D  s    zUrl.get_typeNrm   r   r   r   r   r   ;  s   r   c                   @   s   e Zd ZdZdd ZdS )NumberzNumber input.

    See: <https://html.spec.whatwg.org/#number-state-(type=number)>

    >>> Number(name='num', min='0', max='10', step='2', value='5').render()
    u'<input id="num" max="10" min="0" name="num" step="2" type="number" value="5"/>'
    c                 C   s   dS )Nnumberr   rK   r   r   r   r]   Q  s    zNumber.get_typeNrm   r   r   r   r   r   H  s   r   c                   @   s   e Zd ZdZdd ZdS )RangezRange input.

    See: <https://html.spec.whatwg.org/#range-state-(type=range)>

    >>> Range(name='range', min='0', max='10', step='2', value='5').render()
    u'<input id="range" max="10" min="0" name="range" step="2" type="range" value="5"/>'
    c                 C   s   dS )Nranger   rK   r   r   r   r]   ^  s    zRange.get_typeNrm   r   r   r   r   r   U  s   r   c                   @   s   e Zd ZdZdd ZdS )Colora  Color input.

    Note: Not supported by Internet Explorer or Opera Mini

    See: <https://html.spec.whatwg.org/#color-stat://html.spec.whatwg.org/#color-state-(type=color)>

    >>> Color(name='color').render()
    u'<input id="color" name="color" type="color"/>'
    c                 C   s   dS )Ncolorr   rK   r   r   r   r]   m  s    zColor.get_typeNrm   r   r   r   r   r   b  s   
r   c                       s(   e Zd ZdZ fddZdd Z  ZS )DatalistaP  Datalist input.

    This is currently supported by Chrome, Firefox, Edge, and Opera. It is not
    supported on Safari or Internet Explorer. Use it with caution.

    Datalist cannot be used separately. It must be bound to an input.

    <https://html.spec.whatwg.org/#the-datalist-element>

    >>> Datalist(name='list', args=[('a', 'b'), ('c', 'd')]).render()
    u'<datalist id="list" name="list"><option label="a" value="b"/><option label="c" value="d"/></datalist>'
    >>> Datalist(name='list', args=[['a', 'b'], ['c', 'd']]).render()
    u'<datalist id="list" name="list"><option label="a" value="b"/><option label="c" value="d"/></datalist>'
    >>> Datalist(name='list', args=['a', 'b', 'c', 'd']).render()
    u'<datalist id="list" name="list"><option value="a"/><option value="b"/><option value="c"/><option value="d"/></datalist>'
    c                    s(   || _ tt| j|g|R i | d S r   )rs   rt   r   r   )r   r6   rs   r   kwargsrv   r   r   r     s    zDatalist.__init__c                 C   s   | j  }| j|d< d}d| }| jD ]N}t|ttfrZdt|d  }t|d }n
t|}|d||f 7 }q&|d7 }|S )	Nr6   r    z<datalist %s>z label="%s"r   r   z<option%s value="%s"/>z</datalist>)	rX   r   r6   rs   r~   r   r   r   r&   )r   rX   Zlabel_pr   r{   r   r   r   r   r#     s    



zDatalist.renderr   r   r   rv   r   r   q  s   r   c                   @   s&   e Zd Zdd ZdddZdd ZdS )		Validatorc                 C   s
   t  | S r   )r   )r   memor   r   r   __deepcopy__  s    zValidator.__deepcopy__Nc                 C   s   t | t  d S r   )r   Z
autoassignlocals)r   r=   testZjstestr   r   r   r     s    zValidator.__init__c                 C   s    z|  |W S    Y dS 0 d S r\   )r   r_   r   r   r   r     s    zValidator.valid)N)rM   rN   rO   r   r   r   r   r   r   r   r     s   
r   ZRequiredc                   @   s   e Zd Zdd Zdd ZdS )regexpc                 C   s   t || _|| _d S r   )recompilerexpr=   )r   r   r=   r   r   r   r     s    zregexp.__init__c                 C   s   t | j|S r   )r   r   matchr_   r   r   r   r     s    zregexp.validN)rM   rN   rO   r   r   r   r   r   r   r     s   r   __main__)N))rP   r   r   r    r   r   r   r4   r   objectr   rS   dictrW   rk   rn   rp   rq   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   Znotnullr   rM   doctesttestmodr   r   r   r   <module>   sD   
zb0'&
	
