U
    PeO                     @   s  U d Z ddlZddlmZ ddlmZ ddlmZ ddlmZ ddl	m
Z
 ddlmZ dd	lmZmZmZmZmZ dd
lmZ ddlmZ ddlmZ ddlmZ ddlmZ ddlmZ ddlm Z m!Z! dZ"ej#Z#da$da%G dd deZ&dd Z'dd Z(dd Z)dd Z*dd Z+d-dd Z,G d!d" d"e-Z.ed#e.Z/e.e0d#< e/j1eed$d%d& d'ekrddl2Z2dd(l3m4Z4 d)d* Z5d+d, Z6e27e6 dS ).z_
Builder
======

Class used for the registering and application of rules for specific widgets.
    N)environ)join)copy)CodeType)partial)Factory)ParserParserException	_handlersglobal_idmapParserRuleProperty)Logger)	QueryDict)Cache)kivy_data_dir)register_context)resource_find)
ObservableEventDispatcher)r   BuilderBuilderBaseBuilderExceptionc                   @   s   e Zd ZdZdS )r   zIException raised when the Builder fails to apply a rule on a widget.
    N)__name__
__module____qualname____doc__ r   r   5/tmp/pip-unpacked-wheel-xzebddm3/kivy/lang/builder.pyr   (   s   r   c                 C   s&   z| j W S  tk
r    |  Y S X d S N)	proxy_refAttributeError)widgetr   r   r   	get_proxy.   s    r"   c                 O   s   ||d< t | j| d S )Nargs)execco_value)Z
__kvlang__idmaplargskwargsr   r   r   custom_callback5   s    r)   c           	      C   sZ   | \}}}}}t d||||jf  | jd7  _t||}t d|f  t||| d S )Nz&Lang: call_fn %s, key=%s, value=%r, %r   zLang: call_fn => value=%r)tracevaluecountevalsetattr)	r#   instancevelementkeyr,   ruler&   Ze_valuer   r   r   call_fn:   s       
r5   c                 C   s6   | d d k	rd S t d kr&| a t| d< nt | d< | a d S )N)_delayed_startStopIteration)r#   r0   r1   r   r   r   delayed_call_fnF   s    
r9   c                 C   s  ||d D ]<\}}	}
}|
dkr"qz| |	| W q tk
rF   Y qX q||d= t|d dd  }|dkr||dd dS |d7 }|j}||d D ]}t|ttfr||d}|dk	rt|ddr||t	| |||||}||j
|t	|g n||j
|ddg n|t|d||ddg t||d}|dkrB qL|d7 }qt|ttfr||d ||}|r||j
|d ||g ||dd dS )	aB   Function that is called when an intermediate property is updated
    and `rebind` of that property is True. In that case, we unbind
    all bound funcs that were bound to attrs of the old value of the
    property and rebind them to the new value of the property.

    For example, if the rule is `self.a.b.c.d`, then when b is changed, we
    unbind from `b`, `c` and `d`, if they were bound before (they were not
    None and `rebind` of the respective properties was True) and we rebind
    to the new values of the attrs `b`, `c``, `d` that are not None and
    `rebind` is True.

    :Parameters:
        `base`
            A (proxied) ref to the base widget, `self` in the example
            above.
        `keys`
            A list of the name off the attrs of `base` being watched. In
            the example above it'd be `['a', 'b', 'c', 'd']`.
        `bound`
            A list 4-tuples, each tuple being (widget, attr, callback, uid)
            representing callback functions bound to the attributed `attr`
            of `widget`. `uid` is returned by `fbind` when binding.
            The callback may be None, in which case the attr
            was not bound, but is there to be able to walk the attr tree.
            E.g. in the example above, if `b` was not an eventdispatcher,
            `(_b_ref_, `c`, None)` would be added to the list so we can get
            to `c` and `d`, which may be eventdispatchers and their attrs.
        `s`
            The index in `keys` of the of the attr that needs to be
            updated. That is all the keys from `s` and further will be
            rebound, since the `s` key was changed. In bound, the
            corresponding index is `s - 1`. If `s` is None, we start from
            1 (first attr).
        `fn`
            The function to be called args, `args` on bound callback.
    Nr6      r*   TrebindFr   )
unbind_uidReferenceErrorgetattrappend
isinstancer   r   propertyfbindupdate_intermediatesr   )basekeysboundsfnr#   r0   r,   fkZfunuidr?   valpropr   r   r   rC   T   sP    &
       

rC   Fc                 C   sH  t |}|t | j|d< t| j | }|j}|rJt}	|||||d g}
nt}	|||||f}
|j	d k	r|j	D ]p}|
|d }|d krqnt|d| }}g }d}|j}d}|dd D ]}t|ttfr6||d}|d k	r"t|ddr"||t|||||	|
}||j|t|g d}n||j|d d g n6t|ts\|t|d||d d g n|||d d g t||d }|d kr q|d7 }qt|ttfr||d |	|
}|r||j|d |	|g d}|rn|| qnzt|||fW S  tk
rB } z0t d	 }t|j|jd
|jj||dW 5 d }~X Y nX d S )Nselfr   r   Fr*   r6   Tr;   r:   {}: {}cause)r   updater   r   r
   rK   r?   r9   r5   Zwatched_keysgetr>   r@   r   r   rA   rB   rC   typer.   	Exceptionsysexc_infor   ctxlineformat	__class__r   )Ziselfr2   r3   r,   r4   r&   ZdelayedZ
bound_listZhandler_appendrH   r#   rE   rD   rI   rF   Z	was_boundr?   rJ   rL   rM   rK   etbr   r   r   create_handler   sv    

      



r^   c                       s   e Zd ZdZ fddZedd Zd%ddZd	d
 Zdd Z	dd Z
e ddfddZe ddfddZdd Zde dfddZdd Zdd Zdd Zdd  Zd!d" Zd#d$ Z  ZS )&r   a/  The Builder is responsible for creating a :class:`Parser` for parsing a
    kv file, merging the results into its internal rules, templates, etc.

    By default, :class:`Builder` is a global Kivy instance used in widgets
    that you can use to load other kv files in addition to the default ones.
    c                    s<   t t|   i | _i | _g | _i | _i | _g | _i | _	d S r   )
superr   __init___match_cache_match_name_cachefilesdynamic_classes	templatesrulesrulectxrN   r[   r   r   r`      s    zBuilderBase.__init__c                 C   sh   |  }t |j|_t |j|_t |j|_t |j|_t |j|_t|j|_|jrXt	t
|j|_|S )zCreates a instance of the class, and initializes to the state of
        ``builder``.

        :param builder: The builder to initialize from.
        :return: A new instance of this class.
        )r   ra   rb   rc   rd   re   listrf   rg   AssertionErrordict)clsZbuilderobjr   r   r   create_from
  s    
zBuilderBase.create_fromutf8c              
   K   s\   t |p
|}td|| ||d< t|d|d$}| }| j|f|W  5 Q R  S Q R X dS )az  Insert a file into the language builder and return the root widget
        (if defined) of the kv file.

        :parameters:
            `rulesonly`: bool, defaults to False
                If True, the Builder will raise an exception if you have a root
                widget inside the definition.

            `encoding`: File character encoding. Defaults to utf-8,
        z%Lang: load file %s, using %s encodingfilenamerencodingN)r   r+   openreadload_string)rN   rq   rt   r(   fddatar   r   r   	load_file  s    zBuilderBase.load_filec                    s   t  p
   fdd| jD | _|   i }| j D ]\}}|d  kr8|||< q8|| _ | jkrr| j  t  dS )a8  Unload all rules associated with a previously imported file.

        .. versionadded:: 1.0.8

        .. warning::

            This will not remove rules or templates already applied/used on
            current widgets. It will only effect the next widgets creation or
            template invocation.
        c                    s    g | ]}|d  j j kr|qS r*   rX   rq   .0xrq   r   r   
<listcomp>@  s      z+BuilderBase.unload_file.<locals>.<listcomp>r:   N)	r   rf   _clear_matchcachere   itemsrc   remover   Zunregister_from_filename)rN   rq   re   r   yr   r   r   unload_file3  s    

zBuilderBase.unload_filec                 K   s  | dd |dd | _}|| jkr8td| zHt||d}| j	|j | 
  |jD ]4\}}}|||f| j|< tj|t| j|ddd qd|j D ]\}}tj|||dd	 q|d r|jr|dd
}	td|	 |r|js|js|jr| j| |jrt|jjdd}
g }|
j|
|d | j|
|j|j|d |D ]}|d|
 qX|
d|
 |
W S W 5 d| _X dS )aK  Insert a string into the Language Builder and return the root widget
        (if defined) of the kv string.

        :Parameters:
            `rulesonly`: bool, defaults to False
                If True, the Builder will raise an exception if you have a root
                widget inside the definition.
            `filename`: str, defaults to None
                If specified, the filename used to index the kv rules.

        The filename parameter can be used to unload kv strings in the same way
        as you unload kv files. This can be achieved using pseudo file names
        e.g.::

            Build.load_string("""
                <MyRule>:
                    Label:
                        text="Hello"
            """, filename="myrule.kv")

        can be unloaded via::

            Build.unload_file("myrule.kv")

        	rulesonlyFrq   NzOLang: The file {} is loaded multiples times, you might have unwanted behaviors.)contentrq   T)rm   is_templatewarn)baseclassesrq   r   z<string>z/The file <%s> contain also non-rules directivesZ__no_builderrootrule_childrenr   
on_kv_post)
setdefaultrS   Z_current_filenamerc   r   warningrZ   r   rf   extendr   re   r   registerr   templaterd   r   r   rU   r?   nameapply_class_lang_rules_apply_ruledispatch)rN   stringr(   rH   parserr   rm   r   r   rq   r!   r   childr   r   r   rw   N  sh    

 
   zBuilderBase.load_stringc                 O   s   |d }|| j krtd| | j | \}}}d||f }td|}|dkrg }	|dD ]}
|	t|
 q\t|t|	i }td|| | }dd |	 D }| j
||||d	 |S )
a  Create a specialized template using a specific context.

        .. versionadded:: 1.0.5

        With templates, you can construct custom widgets from a kv lang
        definition by giving them a context. Check :ref:`Template usage
        <template_usage>`.
        r   zUnknown <%s> template namez%s|%szkv.langN+c                 S   s   i | ]\}}|t |qS r   )r"   )r~   rJ   r1   r   r   r   
<dictcomp>  s      z(BuilderBase.template.<locals>.<dictcomp>)template_ctx)re   rU   r   rS   splitr?   r   rT   tupler   r   )rN   r#   rX   r   r   r4   rH   r3   rm   ZrootwidgetsZbaseclsr!   Z	proxy_ctxr   r   r   r     s     
zBuilderBase.templateNFc           	      C   sv   |  |}tdt||f  |s&dS |r:|dk	r6|ng }|D ]}| j|||||d q>|rr|D ]}|d| q`dS )a  Search all the rules that match the name `rule_name`
        and apply them to `widget`.

        .. versionadded:: 1.10.0

        :Parameters:

            `widget`: :class:`~kivy.uix.widget.Widget`
                The widget to whom the matching rules should be applied to.
            `ignored_consts`: set
                A set or list type whose elements are property names for which
                constant KV rules (i.e. those that don't create bindings) of
                that widget will not be applied. This allows e.g. skipping
                constant rules that overwrite a value initialized in python.
            `rule_children`: list
                If not ``None``, it should be a list that will be populated
                with all the widgets created by the kv rules being applied.

                .. versionchanged:: 1.11.0

            `dispatch_kv_post`: bool
                Normally the class `Widget` dispatches the `on_kv_post` event
                to widgets created during kv rule application.
                But if the rules are manually applied by calling :meth:`apply`,
                that may not happen, so if this is `True`, we will dispatch the
                `on_kv_post` event where needed after applying the rules to
                `widget` (we won't dispatch it for `widget` itself).

                Defaults to False.

                .. versionchanged:: 1.11.0
        Lang: Found %d rules for %sNignored_constsr   r   )match_rule_namer+   lenr   r   )	rN   r!   	rule_namer   r   dispatch_kv_postrf   r4   wr   r   r   apply_rules  s"    #
   zBuilderBase.apply_rulesc                 C   sv   |  |}tdt||f  |s&dS |r:|dk	r6|ng }|D ]}| j|||||d q>|rr|D ]}|d| q`dS )aP  Search all the rules that match the widget and apply them.

        :Parameters:

            `widget`: :class:`~kivy.uix.widget.Widget`
                The widget whose class rules should be applied to this widget.
            `ignored_consts`: set
                A set or list type whose elements are property names for which
                constant KV rules (i.e. those that don't create bindings) of
                that widget will not be applied. This allows e.g. skipping
                constant rules that overwrite a value initialized in python.
            `rule_children`: list
                If not ``None``, it should be a list that will be populated
                with all the widgets created by the kv rules being applied.

                .. versionchanged:: 1.11.0

            `dispatch_kv_post`: bool
                Normally the class `Widget` dispatches the `on_kv_post` event
                to widgets created during kv rule application.
                But if the rules are manually applied by calling :meth:`apply`,
                that may not happen, so if this is `True`, we will dispatch the
                `on_kv_post` event where needed after applying the rules to
                `widget` (we won't dispatch it for `widget` itself).

                Defaults to False.

                .. versionchanged:: 1.11.0
        r   Nr   r   )matchr+   r   r   r   )rN   r!   r   r   r   rf   r4   r   r   r   r   apply  s"    
   zBuilderBase.applyc                 C   s   | j   | j  d S r   )ra   clearrb   rh   r   r   r   r   #  s    
zBuilderBase._clear_matchcachec                 C   s  || j kstd|jig g d | j |< }|| j ks8t| j | }|d k	rZt||d d< |jr|jddd  |_|j|d |j< t|d }|d}	|	j	}
|
 D ]\}}||	krq||
|< q|
|	_	|| |jr
|jj | |jj||j| W 5 Q R X |jr8|j | |j||j| W 5 Q R X |jrj|jj | |jj||j| W 5 Q R X tj}tj}|jD ]}|j}|dkrt|j|jd	||}||ri }tt}|d|d d i d|d kr|d|d d i zb|j D ].}|j }t!|t"kr(t#||}|||j< q|j$D ]}t#|j%|}|||j< q<W nP t&k
r } z0t'( d
 }t)|j|jd*|j+j,||dW 5 d }~X Y nX |f |}|-| |jr*||d |j< nP|dd}|-| |j.|d d |d | j/||||d |d k	r||0| q||jr~|d 0|jt1|j f |j
 D ]\}}|j2r^t34|| q^|j$r|d 0|j|j$f ||k	r| j |= d S zd }t5|d D ]\}}|D ]}t6|t7st|j}|j }t!|t"kr@t8||||||d \}}||ks2|s2||kr`t9||| n ||ksT||krt9||| qАqW n^ t&k
r } z>|d k	rt'( d
 }t)|j|jd*|j+j,||d|W 5 d }~X Y nX zd }|d D ]\}}|D ]}t6|t7st|j:ds
t|j}|;|s(|dd  }tt}||d  |j|d< |<|t=||sbt>||jdkrtj?j@A|jB qqW n^ t&k
r } z>|d k	rt'( d
 }t)|j|jd*|j+j,||d|W 5 d }~X Y nX | j |= d S )Nr   )idssethdlr   rX   #r*   r   )canvaszcanvas.beforezcanvas.afterzFCanvas instructions added in kv must be declared before child widgets.r:   rO   rP   Tr   r   r   r   r   Zon_   rN   Z	on_parent)Crg   rk   r   r   idr   striprl   popr   r   Zcreate_missingcanvas_beforer   before_build_canvascanvas_rootcanvas_afterafterr   rS   r   childrenr   r	   rX   rY   r   r   rR   
propertiesvaluesr%   rT   r   r.   handlersr,   rU   rV   rW   r   rZ   r[   r   Z
add_widgetr   r   r?   rj   Zignore_prevr   unbind_propertyreversedr@   r   r^   r/   
startswithZis_event_typerB   r)   r    ZWidgetparentr   __self__)rN   r!   r4   rootruler   r   r   ZrctxZ_ids_rootZ_new_ids_key_valueZFactory_getZFactory_is_templatecrulecnamerm   rX   r&   pruler,   r\   r]   r   r3   Z
widget_setrf   rF   r   r   r   r   '  sL    




 
 
 
 


  




    

    






  zBuilderBase._apply_rulec                 C   sj   | j }|jt|jf}||kr&|| S g }| jD ],\}}||r0|jrR|dd= || q0|||< |S zJReturn a list of :class:`ParserRule` objects matching the widget.
        N)ra   r[   r   rm   rf   r   avoid_previous_rulesr?   )rN   r!   cacherJ   rf   selectorr4   r   r   r   r     s    

zBuilderBase.matchc                 C   sj   | j }t|}| }||kr&|| S g }| jD ],\}}||r0|jrR|dd= || q0|||< |S r   )rb   strlowerrf   r   r   r?   )rN   r   r   rJ   rf   r   r4   r   r   r   r     s    

zBuilderBase.match_rule_namec                 C   sd   t }|dkrdS |tk	r\zt|dd dd W n tk
rD   Y nX |}|d }d|d< qda dS )zExecute all the waiting operations, such as the execution of all the
        expressions related to the canvas.

        .. versionadded:: 1.7.0
        Nr6   )r7   r8   r5   r=   )rN   Z	next_argsr#   r   r   r   sync	  s    
zBuilderBase.syncc                 C   st   |t krdS t |  D ]P}|D ]F}|D ]<\}}}}|dkr>q(z||| W q( tk
rb   Y q(X q(q qt |= dS )a  Unbind all the handlers created by the KV rules of the
        widget. The :attr:`kivy.uix.widget.Widget.uid` is passed here
        instead of the widget itself, because Builder is using it in the
        widget destructor.

        This effectively clears all the KV rules associated with this widget.
        For example:

        .. code-block:: python

            >>> w = Builder.load_string('''
            ... Widget:
            ...     height: self.width / 2. if self.disabled else self.width
            ...     x: self.y + 50
            ... ''')
            >>> w.size
            [100, 100]
            >>> w.pos
            [50, 0]
            >>> w.width = 500
            >>> w.size
            [500, 500]
            >>> Builder.unbind_widget(w.uid)
            >>> w.width = 222
            >>> w.y = 500
            >>> w.size
            [222, 500]
            >>> w.pos
            [50, 500]

        .. versionadded:: 1.7.2
        N)r
   r   r<   r=   )rN   rK   Zprop_callbacks	callbacksrI   rJ   rH   	bound_uidr   r   r   unbind_widget   s    !zBuilderBase.unbind_widgetc           
   
   C   s   |j }|tkrdS t| }||kr&dS || D ]F}|D ]<\}}}}	|dkrLq6z|||	 W q6 tk
rp   Y q6X q6q.||= |st|= dS )aQ  Unbind the handlers created by all the rules of the widget that set
        the name.

        This effectively clears all the rules of widget that take the form::

            name: rule

        For example:

        .. code-block:: python

            >>> w = Builder.load_string('''
            ... Widget:
            ...     height: self.width / 2. if self.disabled else self.width
            ...     x: self.y + 50
            ... ''')
            >>> w.size
            [100, 100]
            >>> w.pos
            [50, 0]
            >>> w.width = 500
            >>> w.size
            [500, 500]
            >>> Builder.unbind_property(w, 'height')
            >>> w.width = 222
            >>> w.size
            [222, 500]
            >>> w.y = 500
            >>> w.pos
            [550, 500]

        .. versionadded:: 1.9.1
        N)rK   r
   r<   r=   )
rN   r!   r   rK   Zprop_handlersr   rI   rJ   rH   r   r   r   r   r   O  s"    "
zBuilderBase.unbind_propertyc                 C   s  t d krtda t| j| d }|jD ]}|j}|dkrF|  q*t| }t|t slt	|j
|jdzR|j D ]B}	|	j}
|	j}t|tkrt||j|
||	|d\}}t||
| qxW q* tk
r } z0t d }t	|	j
|	jd|jj||dW 5 d }~X Y q*X q*d S )	NInstructionr   ZClearz0You can add only graphics Instruction in canvas.Tr:   rO   rP   )r   r   rS   r   rg   r   r   r   r@   r   rX   rY   r   r   r%   rT   r   r^   r   r/   rU   rV   rW   rZ   r[   r   )rN   r   r!   r4   r   r&   r   r   instrr   r3   r,   _r\   r]   r   r   r   r     sL    


        zBuilderBase._build_canvas)rp   )r   r   r   r   r`   classmethodro   rz   r   rw   r   r   r   r   r   r   r   r   r   r   r   r   __classcell__r   r   ri   r   r      s6   


T  
3
/ 
 B/7r   r   zstyle.kvT)r   ZKIVY_PROFILE_LANG)escapec                 c   s   |j j| krd S |j D ]\}}|j|kr.q|V  q|jD ]}t| ||D ]
}|V  qLq<|jrzt| ||jD ]
}|V  qn|jrt| ||jD ]
}|V  q|j	rt| ||j	D ]
}|V  qd S r   )
rX   rq   r   r   rY   r   
match_ruler   r   r   )rH   indexr4   rM   Zprpr   rr   r   r   r   r     s$    


r   c                  C   sl  ddddg} dd t jD }|D ]}z t|}| }W 5 Q R X W n. ttfk
rt } zW Y q W 5 d }~X Y nX | d|dd	g7 } d
}t|D ]\}}| }t|}g }	t jD ]\}
}|		t
||| qtdd |	D }|rdnd}| d|dt|d ddt|dd|ddg7 } q| dg7 } q | dg7 } tdddd}|d|  W 5 Q R X td d S )Nz<!doctype html><html><body>z<style type="text/css">
zpre { margin: 0; }
z</style>c                 S   s   h | ]}|d  j jqS r{   r|   r}   r   r   r   	<setcomp>  s     z%dump_builder_stats.<locals>.<setcomp>z<h2>z</h2>z<table>r   c                 S   s   h | ]
}|j qS r   )r-   r}   r   r   r   r     s     )      r   )r   r   r   z$<tr style="background-color: rgb{}">z<td>r*   z</td>z	<td><pre>z</pre></td>z</tr>z</table>z</body></html>zbuilder_stats.htmlr   zutf-8rs    z'Profiling written at builder_stats.html)r   rf   ru   	readlinesIOError	TypeError	enumeraterstripr   r   r   sumrZ   r   writer   print)htmlrc   rH   rI   linesr\   r-   r   rY   Zmatched_prpZpsnr4   colorrx   r   r   r   dump_builder_stats  sN    


 
     
r   )F)8r   rV   osr   os.pathr   r   typesr   	functoolsr   Zkivy.factoryr   Zkivy.lang.parserr   r	   r
   r   r   Zkivy.loggerr   Z
kivy.utilsr   Z
kivy.cacher   Zkivyr   Zkivy.contextr   Zkivy.resourcesr   Zkivy._eventr   r   __all__r+   r   r7   r   r"   r)   r5   r9   rC   r^   objectr   r   __annotations__rz   atexitr   r   r   r   r   r   r   r   r   <module>   sP   [
I     3
&