
    =wgq                     b   d dl Z d dlmZ d dlmZ d dlmZmZ d dlmZ d dl	m
Z
 d dlmZmZ d dlmZ  G d	 d
e      Z G d de      Z G d de      Z G d de      Z G d de      Z G d de      Z G d de      Z G d de      Z G d de      Z G d de      Z G d de      Z G d d e      Z G d! d"e      Z G d# d$e      Z G d% d&e      Z G d' d(e      Z  G d) d*e      Z! G d+ d,e      Z" G d- d.e      Z# G d/ d0e      Z$ G d1 d2e      Z% G d3 d4e      Z& G d5 d6e      Z'y)7    N)query)u)	iteritemsxrange)syntax)attach)RegexTaggerFnTagger)rcompilec                       e Zd ZdZd Zd Zy)Pluginz#Base class for parser plugins.
    c                      y)zShould return a list of ``(Tagger, priority)`` tuples to add to the
        syntax the parser understands. Lower priorities run first.
         r   selfparsers     M/var/www/horilla/myenv/lib/python3.12/site-packages/whoosh/qparser/plugins.pytaggerszPlugin.taggers+   s    
     c                      y)zShould return a list of ``(filter_function, priority)`` tuples to
        add to parser. Lower priority numbers run first.

        Filter functions will be called with ``(parser, groupnode)`` and should
        return a group node.
        r   r   r   s     r   filterszPlugin.filters2   s     r   N)__name__
__module____qualname____doc__r   r   r   r   r   r   r   '   s    r   r   c                   .    e Zd ZdZdZddZd Zd Zd Zy)	TaggingPlugina  A plugin that also acts as a Tagger, to avoid having an extra Tagger
    class for simple cases.

    A TaggingPlugin object should have a ``priority`` attribute and either a
    ``nodetype`` attribute or a ``create()`` method. If the subclass doesn't
    override ``create()``, the base class will call ``self.nodetype`` with the
    Match object's named groups as keyword arguments.
    r   Nc                 @    t        |xs | j                        | _        y N)r   exprr   r    s     r   __init__zTaggingPlugin.__init__I   s    T.TYY/	r   c                      | | j                   fgS r   )priorityr   s     r   r   zTaggingPlugin.taggersL   s    t}}%&&r   c                      y)Nr   r   r   s     r   r   zTaggingPlugin.filtersO   s    r   c                 x    t        d t        |j                               D              } | j                  di |S )Nc              3   <   K   | ]  \  }}t        |      |f  y wr   )str.0kvs      r   	<genexpr>z'TaggingPlugin.create.<locals>.<genexpr>U   s     Kdas1vqkKs   r   )dictr   	groupdictnodetype)r   r   matchkwargss       r   createzTaggingPlugin.createR   s4     Ki8I.JKKt}}&v&&r   r   )	r   r   r   r   r$   r"   r   r   r3   r   r   r   r   r   =   s"     H0''r   r   c                   @    e Zd ZdZej
                  ZdZddZd Z	d Z
y)WhitespacePlugina  Tags whitespace and removes it at priority 500. Depending on whether
    your plugin's filter wants to see where whitespace was in the original
    query, it should run with priority lower than 500 (before removal of
    whitespace) or higher than 500 (after removal of whitespace).
    d   c                 0    t         j                  | |       y r   )r   r"   r!   s     r   r"   zWhitespacePlugin.__init__c   s    tT*r   c                      | j                   dfgS )Ni  )remove_whitespacer   s     r   r   zWhitespacePlugin.filtersf   s    ''-..r   c                     |j                         }|D ]`  }t        |t        j                        r"|j	                  | j                  ||             ?|j                         rP|j	                  |       b |S r   )
empty_copy
isinstancer   	GroupNodeappendr9   is_wsr   r   groupnewgroupnodes        r   r9   z"WhitespacePlugin.remove_whitespacei   sd    ##% 	&D$ 0 01 6 6vt DEZZ\%		&
 r   N)z\s+)r   r   r   r   r   
Whitespacer0   r$   r"   r   r9   r   r   r   r5   r5   Y   s(       HH+/r   r5   c                   ,    e Zd ZdZdZej                  Zy)SingleQuotePluginziAdds the ability to specify single "terms" containing spaces by
    enclosing them in single quotes.
    z*(^|(?<=\W))'(?P<text>.*?)'(?=\s|\]|[)}]|$)N)r   r   r   r   r    r   WordNoder0   r   r   r   rF   rF   s   s     9DHr   rF   c                   B    e Zd ZdZ G d dej
                        ZdZeZy)PrefixPlugina  Adds the ability to specify prefix queries by ending a term with an
    asterisk.

    This plugin is useful if you want the user to be able to create prefix but
    not wildcard queries (for performance reasons). If you are including the
    wildcard plugin, you should not include this plugin as well.

    >>> qp = qparser.QueryParser("content", myschema)
    >>> qp.remove_plugin_class(qparser.WildcardPlugin)
    >>> qp.add_plugin(qparser.PrefixPlugin())
    >>> q = qp.parse("pre*")
    c                   *    e Zd Zej                  Zd Zy)PrefixPlugin.PrefixNodec                      d| j                   z  S )Nz%r*textr   s    r   rzPrefixPlugin.PrefixNode.r   s    499$$r   N)r   r   r   r   PrefixqclassrP   r   r   r   
PrefixNoderK      s    	%r   rS   z (?P<text>[^ 	
*]+)[*](?= |$|\))N)	r   r   r   r   r   TextNoderS   r    r0   r   r   r   rI   rI   |   s#    %V__ % 2DHr   rI   c                   `    e Zd Z ed      Zdez  Zd Zd Z G d dej                        Z
e
Zy)WildcardPluginu   ?՞؟፧z(?P<text>[*%s])c                      | j                   dfgS )N2   )do_wildcardsr   s     r   r   zWildcardPlugin.filters   s    ""B'((r   c                    d}|t        |      k  r
||   }t        || j                        r|t        |      dz
  k  rI||dz      j                         r3|j	                  |dz         }|xj
                  |j
                  z  c_        |dkD  rI||dz
     j                         r3|j	                  |dz
        }|j
                  |j
                  z   |_        n7|dz  }n1t        |t        j                        r| j                  ||       |dz  }|t        |      k  r
t        t        |            D ]  }||   }t        || j                        s|j
                  t              dkD  s:t        fd| j                  D              rYj                  d      t              dz
  k(  szt        j                  d d       }|j                  |_        |j                   |_        |||<    |S )Nr      c              3   &   K   | ]  }|v  
 y wr   r   )r*   qmrN   s     r   r-   z.WildcardPlugin.do_wildcards.<locals>.<genexpr>   s     ,NBR4Z,Ns   *)lenr<   WildcardNodeis_textpoprN   r   r=   rY   r   anyqmarksfindrI   rS   	startcharendchar)	r   r   rA   irC   nextnodeprevnodenewnoderN   s	           @r   rY   zWildcardPlugin.do_wildcards   s   #e*n8D$ 1 12s5zA~%%A,*>*>*@$yyQ/HII.Iq5U1q5\113$yyQ/H (		 9DIFAdF$4$45%%fd3Q #e*n  E
# 		+A8D$ 1 12yyt9q=,N$++,N)Nyy~TQ6"."9"9$s)"D,0NN)*.,,#*a		+ r   c                   *    e Zd Zej                  Zd Zy)WildcardPlugin.WildcardNodec                      d| j                   z  S )NzWild %rrM   rO   s    r   rP   zWildcardPlugin.WildcardNode.r   s    tyy((r   N)r   r   r   r   WildcardrR   rP   r   r   r   ra   rn      s    
 	)r   ra   N)r   r   r   r   re   r    r   rY   r   rT   ra   r0   r   r   r   rV   rV      s:     $%Fv%D)<)v ) Hr   rV   c                   B    e Zd ZdZ G d dej
                        ZdZeZy)RegexPlugina  Adds the ability to specify regular expression term queries.

    The default syntax for a regular expression term is ``r"termexpr"``.

    >>> qp = qparser.QueryParser("content", myschema)
    >>> qp.add_plugin(qparser.RegexPlugin())
    >>> q = qp.parse('foo title:r"bar+"')
    c                   *    e Zd Zej                  Zd Zy)RegexPlugin.RegexNodec                      d| j                   z  S )NzRegex %rrM   rO   s    r   rP   zRegexPlugin.RegexNode.r   s    		))r   N)r   r   r   r   RegexrR   rP   r   r   r   	RegexNodert      s    	*r   rw   zr"(?P<text>[^"]*)"N)	r   r   r   r   r   rT   rw   r    r0   r   r   r   rr   rr      s#    *FOO *  DHr   rr   c                   V    e Zd ZdZdZ G d dej                        Zd Zd Z	d Z
d Zy	)
BoostPluginzAdds the ability to boost clauses of the query using the circumflex.

    >>> qp = qparser.QueryParser("content", myschema)
    >>> q = qp.parse("hello there^2")
    z-\^(?P<boost>[0-9]*(\.[0-9]+)?)($|(?=[ 	
)]))c                       e Zd Zd Zd Zy)BoostPlugin.BoostNodec                      || _         || _        y r   )originalboost)r   r}   r~   s      r   r"   zBoostPlugin.BoostNode.__init__   s    $DMDJr   c                      d| j                   z  S )Nz^ %s)r~   rO   s    r   rP   zBoostPlugin.BoostNode.r   s    DJJ&&r   N)r   r   r   r"   rP   r   r   r   	BoostNoder{      s    		'r   r   c                     |j                  d      }	 t        |j                  d            }| j                  ||      }|S # t        $ r t	        j
                  |      }Y |S w xY w)Nr   r~   )rA   floatr   
ValueErrorr   rG   )r   r   r1   r}   r~   rC   s         r   r3   zBoostPlugin.create   sf    ;;q>	3%++g./E >>(E2D  	- ??8,D 	-s   A A#"A#c                 :    | j                   df| j                  dfgS )Nr     )clean_boostdo_boostr   s     r   r   zBoostPlugin.filters   s!    !!1%s';<<r   c                     | j                   }t        |      D ]?  \  }}t        ||      s|r||dz
     j                  r(t	        j
                  |      ||<   A |S )zThis filter finds any BoostNodes in positions where they can't boost
        the previous node (e.g. at the very beginning, after whitespace, or
        after another BoostNode) and turns them into WordNodes.
        r[   )r   	enumerater<   	has_boostr   to_word)r   r   rA   bnoderi   rC   s         r   r   zBoostPlugin.clean_boost   s[      ' 	4GAt$&q1u!7!7%~~d3E!H	4 r   c                 f   |j                         }|D ]  }t        |t        j                        r| j	                  ||      }n[t        || j
                        rE|r.|d   j                  r|d   j                  |j                         vt        j                  |      }|j                  |        |S )zYThis filter finds BoostNodes and applies the boost to the previous
        node.
        r_   )r;   r<   r   r=   r   r   r   	set_boostr~   r   r>   r@   s        r   r   zBoostPlugin.do_boost  s    
 ##% 	"D$ 0 01}}VT2D$..1"!7!7RL**4::6!>>$/DOOD!	" r   N)r   r   r   r   r    r   
SyntaxNoder   r3   r   r   r   r   r   r   ry   ry      s5     @D'F%% '=r   ry   c                   ~    e Zd ZdZ G d dej
                        Z G d dej
                        ZddZd Z	d Z
d	 Zy
)GroupPluginz9Adds the ability to group clauses using parentheses.
    c                       e Zd Zd Zy)GroupPlugin.OpenBracketc                      y)N(r   rO   s    r   rP   zGroupPlugin.OpenBracket.r)      r   Nr   r   r   rP   r   r   r   OpenBracketr   (      	r   r   c                       e Zd Zd Zy)GroupPlugin.CloseBracketc                      y)N)r   rO   s    r   rP   zGroupPlugin.CloseBracket.r-  r   r   Nr   r   r   r   CloseBracketr   ,  r   r   r   c                      || _         || _        y r   )openexpr	closeexpr)r   r   r   s      r   r"   zGroupPlugin.__init__0       "r   c                     t        | j                  | j                  d      dft        | j                  | j                  d      dfgS )NopenBr   closeB)r
   r   r   r   r   r   s     r   r   zGroupPlugin.taggers4  sD    $--)9)97CQG$..$*;*;XFJL 	Lr   c                      | j                   dfgS Nr   )	do_groupsr   s     r   r   zGroupPlugin.filters8  s    #$$r   c                 H   | j                   | j                  }}|j                         g}|D ]  }t        ||      r |j	                  |j                                /t        ||      r4t        |      dkD  sJ|j                         }|d   j	                  |       o|d   j	                  |        |d   }t        |      dkD  r|dd D ]  }	|j                  |	        t        |      dk(  r5t        |d   t        j                        r|j                  }
|d   }|
|_
        |S )zThis filter finds open and close bracket markers in a flat group
        and uses them to organize the nodes into a hierarchy.
        r[   r_   r   N)r   r   rA   r<   r>   r`   rc   extendr   r=   r~   )r   r   rA   obcbstackrC   lasttoplsr~   s              r   r   zGroupPlugin.do_groups;  s   
 !!4#4#4B  	'D$#V\\^,D"% u:> 99;D"I$$T* b	  &	' Ah u:>ABi 

2 s8q=ZA0@0@AIIEa&CCI
r   N)z[(]z[)])r   r   r   r   r   r   r   r   r"   r   r   r   r   r   r   r   r   "  s@    
f'' v(( #L%#r   r   c                   D    e Zd ZdZdZd Z G d dej                        Zy)EveryPluginz[*]:[*]r_   c                 "    | j                         S r   )	EveryNoder   r   r1   s      r   r3   zEveryPlugin.createe  s    ~~r   c                       e Zd Zd Zd Zy)EveryPlugin.EveryNodec                      y)Nz*:*r   rO   s    r   rP   zEveryPlugin.EveryNode.ri  s    r   c                 *    t        j                         S r   )r   Everyr   s     r   r   zEveryPlugin.EveryNode.queryl  s    ;;= r   N)r   r   r   rP   r   r   r   r   r   r   h  s    		!r   r   N)	r   r   r   r    r$   r3   r   r   r   r   r   r   r   r   a  s#    DH !F%% !r   r   c                   @    e Zd ZdZ G d de      Zd	dZd Zd Zd Z	y)
FieldsPluginz7Adds the ability to specify the field of a clause.
    c                       e Zd Zd Zy)FieldsPlugin.FieldnameTaggerc                 j    t        j                  |j                  d      |j                  d            S )NrN   r   )r   FieldnameNoderA   r   s      r   r3   z#FieldsPlugin.FieldnameTagger.createu  s&    ''F(;U[[^LLr   Nr   r   r   r3   r   r   r   FieldnameTaggerr   t  s    	Mr   r   c                      || _         || _        y)z
        :param expr: the regular expression to use for tagging fields.
        :param remove_unknown: if True, converts field specifications for
            fields that aren't in the schema into regular text.
        N)r    removeunknown)r   r    remove_unknowns      r   r"   zFieldsPlugin.__init__x  s     	+r   c                 >    | j                  | j                        dfgS r   )r   r    r   s     r   r   zFieldsPlugin.taggers  s    %%dii0!455r   c                      | j                   dfgS )Nr6   )do_fieldnamesr   s     r   r   zFieldsPlugin.filters  s    ##S)**r   c                    t         j                  }| j                  r|j                  r|j                  }|j	                         }d}|D ]  }t        ||      r|j                  |vr|} |rQ|j                  r|j                  |j                  z   |_	        n$|j                  t        j                  |             d}|j                  |        |r$|j                  t        j                  |             |}|j	                         }t        |      }|dkD  r|dz  }||   }t        ||      rt        j                  |      }n,t        |t         j                        r| j                  ||      }|dkD  rJ|j                         s:t        ||dz
     |      r(|j!                  ||dz
     j                  d       |dz  }|j                  |       |dkD  r|j#                          |S )zkThis filter finds FieldnameNodes in the tree and applies their
        fieldname to the next node.
        Nr   r[   Foverride)r   r   r   schemar;   r<   	fieldnamehas_textr}   rN   r>   r   r`   r=   r   r?   set_fieldnamereverse)	r   r   rA   fnclassr   rB   prev_field_noderC   ri   s	            r   r   zFieldsPlugin.do_fieldnames  s   
 &&&-- ]]F'')H"O &dG,v1M&*O$ }}$3$<$<tyy$H	 (GH&*O%&  ?@E##% J!eFA8D$( ~~d+D&"2"23))&$71uTZZ\jq1u9@/B""5Q<#9#9E"JQOOD!! !e" 	r   N)z(?P<text>\w+|[*]):T)
r   r   r   r   r	   r   r"   r   r   r   r   r   r   r   r   p  s)    M+ M,6+6r   r   c                       e Zd ZdZ edd      Z G d dej                        Z G d dej                        Z
d	 Zd
 Zd Zy)FuzzyTermPlugina  Adds syntax to the query parser to create "fuzzy" term queries, which
    match any term within a certain "edit distance" (number of inserted,
    deleted, or transposed characters) by appending a tilde (``~``) and an
    optional maximum edit distance to a term. If you don't specify an explicit
    maximum edit distance, the default is 1.

    >>> qp = qparser.QueryParser("content", myschema)
    >>> qp.add_plugin(qparser.FuzzyTermPlugin())
    >>> q = qp.parse("Stephen~2 Colbert")

    For example, the following query creates a :class:`whoosh.query.FuzzyTerm`
    query with a maximum edit distance of 1::

        bob~

    The following creates a fuzzy term query with a maximum edit distance of
    2::

        bob~2

    The maximum edit distance can only be a single digit. Note that edit
    distances greater than 2 can take an extremely long time and are generally
    not useful.

    You can specify a prefix length using ``~n/m``. For example, to allow a
    maximum edit distance of 2 and require a prefix match of 3 characters::

        johannson~2/3

    To specify a prefix with the default edit distance::

        johannson~/3
    ad  
    (?<=\S)                          # Only match right after non-space
    ~                                 # Initial tilde
    (?P<maxdist>[0-9])?               # Optional maxdist
    (/                                # Optional prefix slash
        (?P<prefix>[1-9][0-9]*)       # prefix
    )?                                # (end prefix group)
    Tverbosec                       e Zd Zd Zd Zy)FuzzyTermPlugin.FuzzinessNodec                 .    || _         || _        || _        y r   )maxdistprefixlengthr}   )r   r   r   r}   s       r   r"   z&FuzzyTermPlugin.FuzzinessNode.__init__  s    "DL ,D$DMr   c                 8    d| j                   | j                  fz  S )Nz<~%d/%d>)r   r   rO   s    r   __repr__z&FuzzyTermPlugin.FuzzinessNode.__repr__  s    t/@/@ AAAr   Nr   r   r   r"   r   r   r   r   FuzzinessNoder     s    	%
	Br   r   c                   6    e Zd Zej                  Zd Zd Zd Zy)FuzzyTermPlugin.FuzzyTermNodec                     |j                   | _         |j                  | _        |j                  | _        |j                  | _        |j                  | _        || _        || _        y r   )r   rN   r~   rg   rh   r   r   )r   wordnoder   r   s       r   r"   z&FuzzyTermPlugin.FuzzyTermNode.__init__  sN    %//DN DI!DJ%//DN#++DL"DL ,Dr   c                 N    d| j                   | j                  | j                  fz  S )Nz	%r ~%d/%d)rN   r   r   rO   s    r   rP   zFuzzyTermPlugin.FuzzyTermNode.r  s"    $))T\\4;L;L!MMMr   c                     t         j                  j                  | |      }| j                  |_        | j                  |_        |S r   )r   rT   r   r   r   )r   r   qs      r   r   z#FuzzyTermPlugin.FuzzyTermNode.query  s7     %%dF3AAI!..ANHr   N)r   r   r   r   	FuzzyTermrR   r"   rP   r   r   r   FuzzyTermNoder     s    	-	N	r   r   c                     |j                  d      }|rt        |      nd}|j                  d      }|rt        |      nd}| j                  |||j                  d            S )Nr   r[   prefixr   )rA   intr   )r   r   r1   mdstrr   pstrr   s          r   r3   zFuzzyTermPlugin.create  sU    I& %#e*1{{8$$(s4ya!!'<QHHr   c                      | j                   dfgS r   )do_fuzzytermsr   s     r   r   zFuzzyTermPlugin.filters  s    ##Q'((r   c                 2   |j                         }d}|t        |      k  r||   }|t        |      dz
  k  rdt        |t        j                        rJ||dz      }t        || j
                        r,| j                  ||j                  |j                        }|dz  }t        || j
                        rt        j                  |      }t        |t        j                        r| j                  ||      }|j                  |       |dz  }|t        |      k  r|S Nr   r[   )r;   r`   r<   r   rG   r   r   r   r   r   r=   r   r>   r   r   rA   rB   ri   rC   rj   s          r   r   zFuzzyTermPlugin.do_fuzzyterms  s    ##%#e*n8D3u:>!jv&G Q<h(:(:;--dH4D4D.6.C.CEDFA$ 2 23~~d+$ 0 01))&$7OOD!FA #e*n r   N)r   r   r   r   r   r    r   r   r   rT   r   r3   r   r   r   r   r   r   r     sR     D   DB)) B 2I)r   r   c                   l    e Zd ZdZ edd      Z G d dej                        Zd Z	d Z
d	 Zd
 Zd Zy)FunctionPluginzAdds an abitrary "function call" syntax to the query parser to allow
    advanced and extensible query functionality.

    This is unfinished and experimental.
    z
    [#](?P<name>[A-Za-z_][A-Za-z0-9._]*)  # function name
    (                                     # optional args
        \[                               # inside square brackets
        (?P<args>.*?)
        \]
    )?
    Tr   c                   *    e Zd ZdZdZdZd Zd Zd Zy)FunctionPlugin.FunctionNodeFTc                 X    || _         || _        || _        || _        g | _        d | _        y r   )namefnargsr2   nodesr~   )r   r   r   r   r2   s        r   r"   z$FunctionPlugin.FunctionNode.__init__E  s,    DIDGDI DKDJDJr   c                 V    d| j                   d| j                  d| j                  dS )N#<z>(r   )r   r   r   rO   s    r   r   z$FunctionPlugin.FunctionNode.__repr__M  s    $(IItyy$**EEr   c                    | j                   D cg c]  }|j                  |       }}| j                  }d|vr| j                  | j                  |d<    | j                  |g| j
                  i | j                  S c c}w )Nr~   )r   r   r2   r~   r   r   )r   r   nqsr2   s        r   r   z!FunctionPlugin.FunctionNode.queryP  sp    +/::6a!''&/6B6[[Ff$)?"&**w47729		9T[[99 7s   A>N)	r   r   r   has_fieldnamer   mergingr"   r   r   r   r   r   FunctionNoder   @  s!    			F	:r   r  c                     || _         y)zf
        :param fns: a dictionary mapping names to functions that return a
            query.
        N)fns)r   r  s     r   r"   zFunctionPlugin.__init__X  s     r   c                     |j                  d      }|| j                  v rO| j                  |   }|j                  d      }|r| j                  |      \  }}nd}i }| j                  ||||      S y )Nr   r   r   )rA   r  _parse_argsr  )r   r   r1   r   r   	argstringr   r2   s           r   r3   zFunctionPlugin.create`  st    {{6"488$BF+I#//	:f$$T2tV<< r   c                 P   g }i }|j                  d      }|D ]  }d|v r/|j                  dd      \  }}t        |j                               }nd }|}|j                         }|j                  d      r|j	                  d      r|dd }|r|||<   y|j                  |        ||fS )N,=r[   'r_   )splitr(   strip
startswithendswithr>   )r   r	  r   r2   partspartr   values           r   r  zFunctionPlugin._parse_argsl  s    $ 	#Dd{"jja0e4::<(KKME$)<a$tE"!	#$ V|r   c                      | j                   dfgS NiX  )do_functionsr   s     r   r   zFunctionPlugin.filters      ""C())r   c                 0   |j                         }d}|t        |      k  r||   }t        || j                        r|t        |      dz
  k  rxt        ||dz      t        j
                        rX||dz      }t        | j                  ||            |_        |j                  dk7  r|j                  |j                         |dz  }n,t        |t        j
                        r| j                  ||      }|j                  |       |dz  }|t        |      k  r|S r   )r;   r`   r<   r  r   r=   listr  r   r~   r   r>   r   s          r   r  zFunctionPlugin.do_functions  s    ##%#e*n8D4!2!23E
Q&uQU|V-=-=> Q<!$"3"3FH"EF
>>Q&NN8>>2QD&"2"23((6OOD!FA! #e*n" r   N)r   r   r   r   r   r    r   r   r  r"   r3   r  r   r  r   r   r   r   r   0  sH       D:v(( :0
=2*r   r   c                   n    e Zd ZdZ ed      Z G d dej                        Z G d de	      Z
d
dZd Zy	)PhrasePluginzEAdds the ability to specify phrase queries inside double quotes.
    z\S+c                   &    e Zd ZddZd Zd Zd Zy)PhrasePlugin.PhraseNodec                 `    t         j                  j                  | |       || _        || _        y r   )r   rT   r"   textstartcharslop)r   rN   r   r!  s       r   r"   z PhrasePlugin.PhraseNode.__init__  s%    OO$$T40!.DDIr   c                 f    | j                   j                  d| j                  d| j                  S )N ~)	__class__r   rN   r!  rO   s    r   rP   zPhrasePlugin.PhraseNode.r  s!    !%!8!8$))TYYOOr   c           	          | j                  | j                  | j                  D cg c]
  } ||       c}| j                  | j                        S c c}w )N)r!  r~   )r%  typer   r!  r~   )r   r   rC   s      r   applyzPhrasePlugin.PhraseNode.apply  sE    >>$))4::-N4bh-N'+yy

 " D D-Ns   A
c                 d   | j                   }| j                  xs |j                  }| j                  }|j                  r||j                  v r|j                  |   }|j                  rh|j                  |dd      }g }g }|D ]J  }	|j                  |	j                          |j                  ||	j                  z   ||	j                  z   f       L nt        |j                  |d            }dgt        |      z  }n}g }g }t        j                  j                  |      D ]W  }
|j                  |
j                  d             |j                  ||
j!                         z   ||
j#                         z   f       Y |j$                  } |||| j&                  | j(                  |      }t+        ||       S )Nr   T)modechars)r*  )NNr   )r!  r~   char_ranges)rN   r   r   r   analyzertokenizer>   rg   rh   r  process_textr`   r  wordexprfinditerrA   startendphraseclassr!  r~   r   )r   r   rN   r   scfieldtokenswordsr,  tr1   rR   r   s                r   r   zPhrasePlugin.PhraseNode.query  s   99D:&*:*:I
 ##B}}fmm!;i0>> #^^Dwd^KFE"$K# OQVV,#**B,<b199n+MNO !!3!3Dw!3!GHE#/.3u:"=K  )22;;DA OELLQ0&&U[[](:B<L'MNO ''Fy%diitzz#.0A!T?"r   N)r[   )r   r   r   r"   rP   r(  r   r   r   r   
PhraseNoder    s    	
	P	D%	#r   r:  c                       e Zd Zd Zy)PhrasePlugin.PhraseTaggerc                     |j                  d      }|j                  d      }|j                  d      }|rt        |      nd}t        j	                  |||      S )NrN   r!  r[   )rA   r2  r   r  r:  )r   r   r1   rN   r   slopstrr!  s          r   r3   z PhrasePlugin.PhraseTagger.create  sN    ;;v&D!KK/Mkk&)G#*3w<D**4EEr   Nr   r   r   r   PhraseTaggerr<    s    	Fr   r?  c                     || _         y r   r    r!   s     r   r"   zPhrasePlugin.__init__  s	    	r   c                 >    | j                  | j                        dfgS r   )r?  r    r   s     r   r   zPhrasePlugin.taggers  s    ""499-q122r   N)z("(?P<text>.*?)"(~(?P<slop>[1-9][0-9]*))?)r   r   r   r   r   r0  r   rT   r:  r	   r?  r"   r   r   r   r   r  r    s<     H2#V__ 2#hF{ F3r   r  c                   ~    e Zd ZdZddZ G d dej                        Z G d dej                        Z	d Z
d Zd	 Zy
)SequencePlugina  Adds the ability to group arbitrary queries inside double quotes to
    produce a query matching the individual sub-queries in sequence.

    To enable this plugin, first remove the default PhrasePlugin, then add
    this plugin::

        qp = qparser.QueryParser("field", my_schema)
        qp.remove_plugin_class(qparser.PhrasePlugin)
        qp.add_plugin(qparser.SequencePlugin())

    This enables parsing "phrases" such as::

        "(jon OR john OR jonathan~1) smith*"
    c                     || _         y)z
        :param expr: a regular expression for the marker at the start and end
            of a phrase. The default is the double-quotes character.
        NrA  r!   s     r   r"   zSequencePlugin.__init__  s     	r   c                   $    e Zd Zej                  Zy)SequencePlugin.SequenceNodeN)r   r   r   r   SequencerR   r   r   r   SequenceNoderG    s    r   rI  c                       e Zd ZddZy)SequencePlugin.QuoteNodeNc                 8    |rt        |      | _        y d| _        y Nr[   )r   r!  )r   r!  s     r   r"   z!SequencePlugin.QuoteNode.__init__  s    %)D	DIqDIr   r   )r   r   r   r"   r   r   r   	QuoteNoderK    s    	1r   rN  c                 J    t        | j                  | j                  d      dfgS )Nquoter   )r
   r    rN  r   s     r   r   zSequencePlugin.taggers  s!    $))T^^W=qABBr   c                      | j                   dfgS )Ni&  )	do_quotesr   s     r   r   zSequencePlugin.filters  s    %&&r   c                    |j                         }d }|D ]  }t        |t        j                        r| j	                  ||      }t        || j
                        r6|g }J| j                  ||j                        }|j                  |       d }{||j                  |       |j                  |        ||j                  |       |S )N)r!  )
r;   r<   r   r=   rR  rN  rI  r!  r>   r   )r   r   rA   rB   seqrC   sns          r   rR  zSequencePlugin.do_quotes  s    ##%   	!D$ 0 01~~fd3$/;C **3TYY*?BOOB'C% 

4 '	!. ?OOC r   N)z["](~(?P<slop>[1-9][0-9]*))?)r   r   r   r   r"   r   r=   rI  
MarkerNoderN  r   r   rR  r   r   r   rD  rD    s@     v''  1F%% 1C'%r   rD  c                   H    e Zd ZdZ edd      Z G d de      Zd
dZd	 Z	y)RangePluginz-Adds the ability to specify term ranges.
    a  
    (?P<open>\{|\[)               # Open paren
    (?P<start>
        ('[^']*?'\s+)             # single-quoted
        |                         # or
        ([^\]}]+?(?=[Tt][Oo]))    # everything until "to"
    )?
    [Tt][Oo]                      # "to"
    (?P<end>
        (\s+'[^']*?')             # single-quoted
        |                         # or
        ([^\]}]+?)                # everything until "]" or "}"
    )?
    (?P<close>}|])                # Close paren
    Tr   c                       e Zd Zd Zd Zy)RangePlugin.RangeTaggerc                 .    || _         || _        || _        y r   r    
excl_startexcl_endr   r    r]  r^  s       r   r"   z RangePlugin.RangeTagger.__init__N  s    DI(DO$DMr   c                    |j                  d      }|j                  d      }|r7|j                         }|j                  d      r|j                  d      r|dd }|r7|j	                         }|j                  d      r|j                  d      r|dd }|j                  d      | j
                  k(  }|j                  d      | j                  k(  }t        j                  ||||      }|S )Nr2  r3  r  r[   r_   openclose)	rA   rstripr  r  lstripr]  r^  r   	RangeNode)r   r   r1   r2  r3  	startexclendexclrns           r   r3   zRangePlugin.RangeTagger.createS  s    KK(E++e$C##C(U^^C-@!!BKEjjl>>#&3<<+<a)CF+t>Ikk'*dmm;G!!%iABIr   N)r   r   r   r"   r3   r   r   r   RangeTaggerrZ  M  s    	%
	r   ri  Nc                 J    |xs | j                   | _         || _        || _        y r   r\  r_  s       r   r"   zRangePlugin.__init__i  s     %DII	$ r   c                 n    | j                  | j                  | j                  | j                        }|dfgS rM  )ri  r    r]  r^  )r   r   taggers      r   r   zRangePlugin.taggersn  s.    !!$))T__dmmL}r   )N{})
r   r   r   r   r   r    r	   ri  r"   r   r   r   r   rX  rX  9  s3       D k 8!
r   rX  c                   N    e Zd ZdZ G d de      Z	 	 	 	 	 	 	 d	dZd Zd Zd Z	y)
OperatorsPlugina  By default, adds the AND, OR, ANDNOT, ANDMAYBE, and NOT operators to
    the parser syntax. This plugin scans the token stream for subclasses of
    :class:`Operator` and calls their :meth:`Operator.make_group` methods
    to allow them to manipulate the stream.

    There are two levels of configuration available.

    The first level is to change the regular expressions of the default
    operators, using the ``And``, ``Or``, ``AndNot``, ``AndMaybe``, and/or
    ``Not`` keyword arguments. The keyword value can be a pattern string or
    a compiled expression, or None to remove the operator::

        qp = qparser.QueryParser("content", schema)
        cp = qparser.OperatorsPlugin(And="&", Or="\|", AndNot="&!",
                                     AndMaybe="&~", Not=None)
        qp.replace_plugin(cp)

    You can also specify a list of ``(OpTagger, priority)`` pairs as the first
    argument to the initializer to use custom operators. See :ref:`custom-op`
    for more information on this.
    c                   :    e Zd Zej                  ddfdZd Zd Zy)OperatorsPlugin.OpTaggerT c                 h    t        j                  | |       || _        || _        || _        || _        y r   )r	   r"   	grouptypeoptype	leftassocmemo)r   r    ru  rv  rw  rx  s         r   r"   z!OperatorsPlugin.OpTagger.__init__  s.      t,&DN DK&DNDIr   c                 ~    d| j                   j                  d| j                  j                  d| j                  dS )Nr   r#  z (z)>)r%  r   r    patternrx  rO   s    r   r   z!OperatorsPlugin.OpTagger.__repr__  s.    %)^^%<%<%)YY%6%6		C Cr   c                 n    | j                  |j                  d      | j                  | j                        S r   )rv  rA   ru  rw  r   s      r   r3   zOperatorsPlugin.OpTagger.create  s%    ;;u{{1~t~~t~~NNr   N)r   r   r   r   InfixOperatorr"   r   r3   r   r   r   OpTaggerrr    s!    393G3G#"		C	Or   r}  Nc	                 ~   |rt        |      }ng }|s#| j                  }	|r9|j                   |	|t        j                  t        j
                  d      df       |r*|j                   |	|t        j                  d      df       |r*|j                   |	|t        j                  d      df       |r*|j                   |	|t        j                  d      df       |r*|j                   |	|t        j                  d      df       |r*|j                   |	|t        j                  d	      df       || _        y )
Nnot)rx  r   andoranotamaybereq)r  r}  r>   r   NotGroupPrefixOperatorAndGroupOrGroupAndNotGroupAndMaybeGroupRequireGroupops)
r   r  cleanAndOrAndNotAndMaybeNotRequireots
             r   r"   zOperatorsPlugin.__init__  s    s)CCB

BsFOOV5J5J$)+,-/ 0

BsFOO%@!DE

Br6>>=qAB

Bvv'9'9$*,-/1 2

Bx)=)=$,./13 4

Bw(;(;$)+,-/ 0 r   c                     | j                   S r   )r  r   s     r   r   zOperatorsPlugin.taggers  s    xxr   c                      | j                   dfgS r  )do_operatorsr   s     r   r   zOperatorsPlugin.filters  r  r   c                 4   | j                   D ]  \  }}|j                  }|j                  }|j                  rYd}|t	        |      k  s;||   }t        ||      r"|j                  |u r|j                  |||      }n|dz  }|t	        |      k  rGt	        |      dz
  }|dk\  s||   }t        ||      r|j                  |||      }|dz  }|dk\  r/ t        |      D ]5  \  }}t        |t        j                        s!| j                  ||      ||<   7 |S )zThis filter finds PrefixOperator, PostfixOperator, and InfixOperator
        nodes in the tree and calls their logic to rearrange the nodes.
        r   r[   )r  rv  ru  rw  r`   r<   replace_selfr   r   r=   r  )	r   r   rA   rl  _rv  gtyperi   r9  s	            r   r  zOperatorsPlugin.do_operators  s$   
  	IFA]]F$$E #e*naA!!V,1ENN65!<Q #e*n JN1faA!!V,NN65!<FA	 1f'	4 e$ 	8DAq!V--.,,VQ7a	8 r   )NFz(?<=\s)AND(?=\s)z(?<=\s)OR(?=\s)z(?<=\s)ANDNOT(?=\s)z(?<=\s)ANDMAYBE(?=\s)z(^|(?<=(\s|[()])))NOT(?=\s)z(^|(?<=\s))REQUIRE(?=\s))
r   r   r   r   r	   r}  r"   r   r   r  r   r   r   rp  rp  s  sA    ,O; O  (-(&.234B*#r   rp  c                   ~    e Zd ZdZ G d dej
                        Z G d dej
                        ZddZd Z	d Z
d	 Zy
)PlusMinusPluginzAdds the ability to use + and - in a flat OR query to specify required
    and prohibited terms.

    This is the basis for the parser configuration returned by
    ``SimpleParser()``.
    c                       e Zd Zy)PlusMinusPlugin.PlusNr   r   r   r   r   r   Plusr        r   r  c                       e Zd Zy)PlusMinusPlugin.MinusNr  r   r   r   Minusr    r  r   r  c                      || _         || _        y r   )plusexpr	minusexpr)r   r  r  s      r   r"   zPlusMinusPlugin.__init__  r   r   c                     t        | j                  | j                  d      dft        | j                  | j                  d      dfgS )Nplusr   minus)r
   r  r  r  r  r   s     r   r   zPlusMinusPlugin.taggers  s@    $--F;Q?$..$**g>BD 	Dr   c                      | j                   dfgS )Nr   )do_plusminusr   s     r   r   zPlusMinusPlugin.filters  r  r   c                    t        j                         }t        j                         }t        j                         }t        |t         j                        rt        j                         }|}|D ]G  }t        || j                        r|}t        || j
                        r|}5|j                  |       |}I |}|rt        j                  ||g      }|rt        j                  ||g      }|S )zThis filter sorts nodes in a flat group into "required", "optional",
        and "banned" subgroups based on the presence of plus and minus nodes.
        )	r   r  r  r<   r  r  r>   r  r  )r   r   rA   requiredoptionalbannednextrC   s           r   r  zPlusMinusPlugin.do_plusminus  s    
 ??$>>#! eV__-(H  	 D$		*D$**- D!	  (((E):;E&&v7Er   N)z\+-)r   r   r   r   r   rV  r  r  r"   r   r   r  r   r   r   r  r    s@    v   !! #D*!r   r  c                   T    e Zd ZdZ G d dej
                        ZdZeZd Z	d Z
d Zy)	
GtLtPlugina  Allows the user to use greater than/less than symbols to create range
    queries::

        a:>100 b:<=z c:>=-1.4 d:<mz

    This is the equivalent of::

        a:{100 to] b:[to z] c:[-1.4 to] d:[to mz}

    The plugin recognizes ``>``, ``<``, ``>=``, ``<=``, ``=>``, and ``=<``
    after a field specifier. The field specifier is required. You cannot do the
    following::

        >100

    This plugin requires the FieldsPlugin and RangePlugin to work.
    c                       e Zd Zd Zd Zy)GtLtPlugin.GtLtNodec                     || _         y r   rel)r   r  s     r   r"   zGtLtPlugin.GtLtNode.__init__<  s	    DHr   c                      d| j                   z  S )Nz(%s)r  rO   s    r   r   zGtLtPlugin.GtLtNode.__repr__?  s    DHH$$r   Nr   r   r   r   GtLtNoder  ;  s    		%r   r  z(?P<rel>(<=|>=|<|>|=<|=>))c                      | j                   dfgS Nc   )do_gtltr   s     r   r   zGtLtPlugin.filtersE  s    r"##r   c                    t         j                  }|j                         }d}t        |      dz
  }|t        |      k  r||   }t	        || j
                        r[||k  rg|d   }||dz      }	t	        ||      rN|	j                  rB|j                  | j                  |	|j                               |dz  }n|j                  |       |dz  }|t        |      k  r|S )zLThis filter translate FieldnameNode/GtLtNode pairs into RangeNodes.
        r   r[   r_   )
r   r   r;   r`   r<   r  r   r>   
make_ranger  )
r   r   rA   fnamerB   ri   lastirC   rk   rj   s
             r   r  zGtLtPlugin.do_gtltI  s     $$##%E
Q#e*n8D$.u9'|H$QU|H!(E2x7H7H $(((KLQ %FA# #e*n& r   c                 h   |j                   }|dk(  rt        j                  d |dd      }nc|dk(  rt        j                  |d dd      }nE|dk(  s|dk(  rt        j                  d |dd      }n"|dk(  s|dk(  rt        j                  |d dd      }j                  |j                  |j
                        S )	Nr   FT>z<=z=<z>=z=>)rN   r   re  	set_rangerg   rh   )r   rC   r  rN   r   s        r   r  zGtLtPlugin.make_rangef  s    yy#:  tUD9ACZ  tT59AD[C4K  tUE:AD[C4K  tUE:A{{4>>4<<88r   N)r   r   r   r   r   r   r  r    r0   r   r  r  r   r   r   r  r  (  s4    $%6$$ % )DH$:
9r   r  c                   <    e Zd ZdZdej
                  fdZd Zd Zy)MultifieldPlugina  Converts any unfielded terms into OR clauses that search for the
    term in a specified list of fields.

    >>> qp = qparser.QueryParser(None, myschema)
    >>> qp.add_plugin(qparser.MultifieldPlugin(["a", "b"])
    >>> qp.parse("alfa c:bravo")
    And([Or([Term("a", "alfa"), Term("b", "alfa")]), Term("c", "bravo")])

    This plugin is the basis for the ``MultifieldParser``.
    Nc                 6    || _         |xs i | _        || _        y)a  
        :param fieldnames: a list of fields to search.
        :param fieldboosts: an optional dictionary mapping field names to
            a boost to use for that field.
        :param group: the group to use to relate the fielded terms to each
            other.
        N)
fieldnamesboostsrA   )r   r  fieldboostsrA   s       r   r"   zMultifieldPlugin.__init__  s     %!'R
r   c                      | j                   dfgS )Nn   )do_multifieldr   s     r   r   zMultifieldPlugin.filters  s     ##S)**r   c                    t        |      D ]  \  }}t        |t        j                        r| j	                  ||      ||<   6|j
                  sC|j                  Pg }| j                  D ]d  }t        j                  |      }|j                  |       |j                  | j                  j                  |d             |j                  |       f | j                  |      ||<    |S )Ng      ?)r   r<   r   r=   r  r  r   r  copyr   r   r  getr>   rA   )r   r   rA   ri   rC   newnodesr  rl   s           r   r  zMultifieldPlugin.do_multifield  s     ' 	0GAt$ 0 01--fd;a##(> !__ -E"iioG))%0%%dkkooeS&ABOOG,	-
  ::h/a	0 r   )	r   r   r   r   r   r  r"   r   r  r   r   r   r  r  s  s!    	 046>> +
r   r  c                   "    e Zd ZdZd Zd Zd Zy)FieldAliasPlugina  Adds the ability to use "aliases" of fields in the query string.

    This plugin is useful for allowing users of languages that can't be
    represented in ASCII to use field names in their own language, and
    translate them into the "real" field names, which must be valid Python
    identifiers.

    >>> # Allow users to use 'body' or 'text' to refer to the 'content' field
    >>> parser.add_plugin(FieldAliasPlugin({"content": ["body", "text"]}))
    >>> parser.parse("text:hello")
    Term("content", "hello")
    c                 r    || _         i | _        t        |      D ]  \  }}|D ]  }|| j                  |<     y r   )fieldmapr   r   )r   r  keyvaluesr  s        r   r"   zFieldAliasPlugin.__init__  sE     $X. 	*KC *&)U#*	*r   c                      | j                   dfgS )NZ   )
do_aliasesr   s     r   r   zFieldAliasPlugin.filters  s    "%&&r   c                 6   t        |      D ]  \  }}t        |t        j                        r| j	                  ||      ||<   6|j
                  sC|j                  P|j                  }|| j                  v sk|j                  | j                  |   d        |S NTr   )	r   r<   r   r=   r  r  r   r   r   )r   r   rA   ri   rC   r  s         r   r  zFieldAliasPlugin.do_aliases  s     ' 	KGAt$ 0 01??648a##(BDLL(&&t||E':T&J	K r   N)r   r   r   r   r"   r   r  r   r   r   r  r    s    *'r   r  c                   <    e Zd ZdZej
                  dfdZd Zd Zy)CopyFieldPlugina+  Looks for basic syntax nodes (terms, prefixes, wildcards, phrases, etc.)
    occurring in a certain field and replaces it with a group (by default OR)
    containing the original token and the token copied to a new field.

    For example, the query::

        hello name:matt

    could be automatically converted by ``CopyFieldPlugin({"name", "author"})``
    to::

        hello (name:matt OR author:matt)

    This is useful where one field was indexed with a differently-analyzed copy
    of another, and you want the query to search both fields.

    You can specify a different group type with the ``group`` keyword. You can
    also specify ``group=None``, in which case the copied node is inserted
    "inline" next to the original, instead of in a new group::

        hello name:matt author:matt
    Fc                 z    || _         || _        |r+|j                  t        d t	        |      D                     yy)a  
        :param map: a dictionary mapping names of fields to copy to the
            names of the destination fields.
        :param group: the type of group to create in place of the original
            token. You can specify ``group=None`` to put the copied node
            "inline" next to the original node instead of in a new group.
        :param two_way: if True, the plugin copies both ways, so if the user
            specifies a query in the 'toname' field, it will be copied to
            the 'fromname' field.
        c              3   *   K   | ]  \  }}||f  y wr   r   r)   s      r   r-   z+CopyFieldPlugin.__init__.<locals>.<genexpr>  s     >tq!QF>s   N)maprA   updater.   r   )r   r  rA   mirrors       r   r"   zCopyFieldPlugin.__init__  s5     
JJt>y~>>? r   c                      | j                   dfgS )Nm   )do_copyfieldr   s     r   r   zCopyFieldPlugin.filters  s    ""C())r   c                    | j                   }|j                         }|D ]  }t        |t        j                        r| j                  ||      }n|j                  r|j                  xs |j                  }||v r}t        j                  |      }|j                  ||   d       | j                  #|j                  |       |j                  |       n"|j                  | j                  ||g             |j                  |        |S r  )r  r;   r<   r   r=   r  r  r   r  r   rA   r>   )r   r   rA   r  rB   rC   r  rl   s           r   r  zCopyFieldPlugin.do_copyfield  s    hh##% 	"D$ 0 01((6##:&*:*:C<"iioG))#e*t)Dzz) - 0 

D'?(CDOOD!	"  r   N)	r   r   r   r   r   r  r"   r   r  r   r   r   r  r    s"    . #).. @$*r   r  c                   "    e Zd ZdZd Zd Zd Zy)PseudoFieldPlugina  This is an advanced plugin that lets you define "pseudo-fields" the user
    can use in their queries. When the parser encounters one of these fields,
    it runs a given function on the following node in the abstract syntax tree.

    Unfortunately writing the transform function(s) requires knowledge of the
    parser's abstract syntax tree classes. A transform function takes a
    :class:`whoosh.qparser.SyntaxNode` and returns a
    :class:`~whoosh.qparser.SyntaxNode` (or None if the node should be removed
    instead of transformed).

    Some things you can do in the transform function::

        from whoosh import qparser

        def my_xform_fn(node):
            # Is this a text node?
            if node.has_text:
                # Change the node's text
                node.text = node.text + "foo"

                # Change the node into a prefix query
                node = qparser.PrefixPlugin.PrefixNode(node.text)

                # Set the field the node should search in
                node.set_fieldname("title")

                return node
            else:
                # If the pseudo-field wasn't applied to a text node (e.g.
                # it preceded a group, as in ``pfield:(a OR b)`` ), remove the
                # node. Alternatively you could just ``return node`` here to
                # leave the non-text node intact.
                return None

    In the following example, if the user types ``regex:foo.bar``, the function
    transforms the text in the pseudo-field "regex" into a regular expression
    query in the "content" field::

        from whoosh import qparser

        def regex_maker(node):
            if node.has_text:
                node = qparser.RegexPlugin.RegexNode(node.text)
                node.set_fieldname("content")
                return node

        qp = qparser.QueryParser("content", myindex.schema)
        qp.add_plugin(qparser.PseudoFieldPlugin({"regex": regex_maker}))
        q = qp.parse("alfa regex:br.vo")

    The name of the "pseudo" field can be the same as an actual field. Imagine
    the schema has a field named ``reverse``, and you want the user to be able
    to type ``reverse:foo`` and transform it to ``reverse:(foo OR oof)``::

        def rev_text(node):
            if node.has_text:
                # Create a word node for the reversed text
                revtext = node.text[::-1]  # Reverse the text
                rnode = qparser.WordNode(revtext)

                # Put the original node and the reversed node in an OrGroup
                group = qparser.OrGroup([node, rnode])

                # Need to set the fieldname here because the PseudoFieldPlugin
                # removes the field name syntax
                group.set_fieldname("reverse")

                return group

        qp = qparser.QueryParser("content", myindex.schema)
        qp.add_plugin(qparser.PseudoFieldPlugin({"reverse": rev_text}))
        q = qp.parse("alfa reverse:bravo")

    Note that transforming the query like this can potentially really confuse
    the spell checker!

    This plugin works as a filter, so it can only operate on the query after it
    has been parsed into an abstract syntax tree. For parsing control (i.e. to
    give a pseudo-field its own special syntax), you would need to write your
    own parsing plugin.
    c                     || _         y)aZ  
        :param xform_map: a dictionary mapping psuedo-field names to transform
            functions. The function should take a
            :class:`whoosh.qparser.SyntaxNode` as an argument, and return a
            :class:`~whoosh.qparser.SyntaxNode`. If the function returns None,
            the node will be removed from the query.
        N)	xform_map)r   r  s     r   r"   zPseudoFieldPlugin.__init__^  s     #r   c                      | j                   dfgS r  )do_pseudofieldr   s     r   r   zPseudoFieldPlugin.filtersi  s    $$b)**r   c                    | j                   }|j                         }d }|D ]  }t        |t        j                        r| j                  ||      }n8t        |t        j                        r|j                  |v r||j                     }h|r5 ||      }d }|w|j                  |j                  |j                         |}|j                  |        |S r   )r  r;   r<   r   r=   r  r   r   r  rg   rh   r>   )r   r   rA   r  rB   
xform_nextrC   rl   s           r   r  z PseudoFieldPlugin.do_pseudofieldm  s    NN	##%
 	"D$ 0 01**648T6#7#78nn	1&t~~6
$T*!
?%%dnndllC"DOOD!#	"& r   N)r   r   r   r   r"   r   r  r   r   r   r  r    s    Pd	#+r   r  )(r  whooshr   whoosh.compatr   r   r   whoosh.qparserr   whoosh.qparser.commonr   whoosh.qparser.taggersr	   r
   whoosh.util.textr   objectr   r   r5   rF   rI   rV   rr   ry   r   r   r   r   r   r  rD  rX  rp  r  r  r  r  r  r  r   r   r   <module>r     sV  8    + ! ( 8 %V ,'K '8} 4 = 03] 3l- (A- AH<& <~!- !N= Nblm l^l] l^J36 J3ZJV JZ7& 7tqf ql<f <~H9 H9V-v -`!v !HAf AHz zr   