
    d=                         d Z ddlZddlZddlmZ ddlmZ  ej        d          Z	d Z
d Zed	             Zd
 Zd Zd Z G d d          Zd Zd ZddZdS )a&  Utility functions and classes for supporting query conditions.

Classes:

`CompileCondition`
    Container for a compiled condition.

Functions:

`compile_condition`
    Compile a condition and extract usable index conditions.
`call_on_recarr`
    Evaluate a function over a structured array.

    N   )get_nested_field)lazyattrz[^a-z]([a-z]+)_([a-z]+)[^a-z]c                    | j         d         }t                              |                                          \  }}d|z  }|d                    d |dd         D                       z  }|                     |          S )zvMake the "no matching opcode" Numexpr `exception` more clear.

    A new exception of the same kind is returned.

    r   z$unsupported operand types for *%s*: z, c              3   D   K   | ]}t           j        j        |         V  d S N)ne
necompilertypecode_to_kind).0ts     1lib/python3.11/site-packages/tables/conditions.py	<genexpr>z/_unsupported_operation_error.<locals>.<genexpr>&   s=       > >./&q)> > > > > >    r   N)args_no_matching_opcodesearchgroupsjoin	__class__)	exceptionmessageoptypes
newmessages        r   _unsupported_operation_errorr      s     nQG#**733::<<IB7"<J$)) > >389> > > > > >Jz***r   c                 B      fd} j         |_          j        |_        |S )zDecorate `getidxcmp` to check the returned indexable comparison.

    This does some extra checking that Numexpr would perform later on
    the comparison if it was compiled within a complete condition.

    c                      | |          }|d         _	 t           j                            t           j                            |                      n!# t          $ r}t          |          d }~ww xY w|S )Nr   )r	   r
   typeCompileAstexpressionToASTNotImplementedErrorr   )exprnodeindexedcolsresultnie	getidxcmps       r   newfuncz%_check_indexable_cmp.<locals>.newfunc3   s    8[11!9 8,,M11(;;= = = =& 8 8 8237778 s   <A 
A2A--A2)__name____doc__)r&   r'   s   ` r   _check_indexable_cmpr*   +   s8    	 	 	 	 	 !)G'GONr   c                    d}dddddd}fd}fd	} ||           r
| j         dd
fS | j        dk    r=| j         dk    r2| j        d         } ||          r
|j         ddfS |j        dk    r|ddfS | j        dk    r|S | j         }||vr|S | j        \  }}	 |||	|          }
|
r|
S  ||	|||                   }
|
r|
S |S )a  Get the indexable variable-constant comparison in `exprnode`.

    A tuple of (variable, operation, constant) is returned if
    `exprnode` is a variable-constant (or constant-variable)
    comparison, and the variable is in `indexedcols`.  A normal
    variable can also be used instead of a constant: a tuple with its
    name will appear instead of its value.

    Otherwise, the values in the tuple are ``None``.
    )NNNgtgeeqlelt)r0   r/   r.   r-   r,   c                 z    | j         |j         }}| j        dk    r |v r|j        dv r|j        dk    r|f}|||fS d S )Nvariable)constantr2   )valueastType)varconstr   	var_valueconst_valuer#   s        r   get_cmpz#_get_indexable_cmp.<locals>.get_cmpV   s[    !$EK;	K:%%){*B*B} 888}
***or;//tr   c                 B    | j         dk    o| j        dk    o| j        v S )Nr2   bool)r5   astKindr4   )noder#   s    r   is_indexed_booleanz._get_indexable_cmp.<locals>.is_indexed_boolean_   s0    
* .LF*.J+-	/r   Tr   invertr   Fr<   N)r4   r5   childrenr=   )r"   r#   not_indexableturncmpr:   r?   childcmpopleftrightcmp_s    `         r   _get_indexable_cmprI   B   sf    'M	 G    / / / / / (## ,d++4HNh$>$>!!$e$$ 	.Ku-- =F""8T** 4NEG #KD%74&&D 75$//D r   c                 D   t          | t          j        j                  s%t          |t          j        j                  s| |k    S t	          |           t	          |          ust          | t          j        j                  rit          |t          j        j                  rJ| j        |j        k    s:| j        |j        k    s*t          | j                  t          |j                  k    rdS t          | j        |j                  D ]\  }}t          ||          s dS dS )zReturns whether two ExpressionNodes are equivalent.

    This is needed because '==' is overridden on ExpressionNode to
    return a new ExpressionNode.

    FT)
isinstancer	   expressionsExpressionNodetyper4   r=   lenrA   zip_equiv_expr_node)xyxchildychilds       r   rQ   rQ      s    q".788 	q"."?@@	Av
q''a
 
 Ar~<== !Ar~<== ! WY!)##__AJ//uaj!*55  // 	55	4r   c                 6   g dgf}dddddddd	d
}d }t          | |          } ||| |          \  }} }|d         rF|r(|\  }	}
dk    r
|
dv r|
dz  }
n|         |	f|
ff}d}n|d         |d         f|d         ff}|gS |r|S | j        dk    s	| j        dvr|S | j        \  }}t          ||          \  }}}t          ||          \  }}}| j        |@|>t	          ||          r.dk    r(|dv r|dv r|||f||ff}|gS |dv r|dv r|||f||ff}|gS t          ||||          }t          ||||          }fd}||k    r0dk    s||k    r$ ||||           ||k    r ||||           ||fS ||k    rdk    r ||||           ||fS |S )a
  Here lives the actual implementation of the get_idx_expr() wrapper.

    'idxexprs' is a list of expressions in the form ``(var, (ops),
    (limits))``. 'strexpr' is the indexable expression in string format.
    These parameters will be received empty (i.e. [], ['']) for the
    first time and populated during the different recursive calls.
    Finally, they are returned in the last level to the original
    wrapper.  If 'exprnode' is not indexable, it will return the tuple
    ([], ['']) so as to signal this.

     &|~)andornotr-   r,   r0   r/   )r0   r/   r-   r,   c                 z    d}| d         dk    r)|dz  }| d         }t          ||          } | d         dk    )| ||fS )NFr   r@   Tr   )rI   )idxcmpr"   r#   r@   s       r   
fix_invertz)_get_idx_expr_recurse.<locals>.fix_invert   sW    Qi8##dNFayH'+>>F	 Qi8##
 x''r   r   r.   )TFTFr      r   )r[   r\   Nr[   )r,   r-   )r0   r/   c                     t          | t                    rY|                    | d                    t          |          }|dk    r
dg|dd<   dS d|d                  |dz
  fz  g|dd<   dS dS )z$Add a single expression to the list.r   r   e0Nz(%s %s e%d))rK   listappendrO   )expridxexprsstrexprlenexprsr   op_convs       r   add_exprz'_get_idx_expr_recurse.<locals>.add_expr   s     dD!! 		MOODG$$$8}}H1}}"V


 "WQZhl$KKM


		M 		Mr   )rI   r5   r4   rA   rQ   _get_idx_expr_recurse)r"   r#   rg   rh   rB   negcmpr`   r_   r@   r6   r4   rf   rF   rG   lcolvarlopllimrcolvarroprlimlexprrexprrk   r   rj   s                          @@r   rl   rl      s    "JM G 	 F( ( (  +66F)z&(KHHFHfay  
	;#NCUTzze}44BZ")DFF1Iq	|fQi\:Dv
   48>#F#F#KD%+D+>>GS$+E;??GS$
 
B 3 '22 !479U{{,3,#6#6c3Z$6D6M,3,#6#6c3Z$6D6M "$XwGGE!%hHHEM M M M M M  2;;%=2H2H'***M!!HUHg...'"""++'***'"" r   c                 (    t          | |g dg          S )a  Extract an indexable expression out of `exprnode`.

    Looks for variable-constant comparisons in the expression node
    `exprnode` involving variables in `indexedcols`.

    It returns a tuple of (idxexprs, strexpr) where 'idxexprs' is a
    list of expressions in the form ``(var, (ops), (limits))`` and
    'strexpr' is the indexable expression in string format.

    Expressions such as ``0 < c1 <= 1`` do not work as expected.

    Right now only some of the *indexable comparisons* are considered:

    * ``a <[=] x``, ``a == x`` and ``a >[=] x``
    * ``(a <[=] x) & (y <[=] b)`` and ``(a == x) | (b == y)``
    * ``~(~c_bool)``, ``~~c_bool`` and ``~(~c_bool) & (c_extra != 2)``

    (where ``a``, ``b`` and ``c_bool`` are indexed columns, but
    ``c_extra`` is not)

    Particularly, the ``!=`` operator and negations of complex boolean
    expressions are *not considered* as valid candidates:

    * ``a != 1`` and  ``c_bool != False``
    * ``~((a > 0) & (c_bool))``

    rW   )rl   )rf   r#   s     r   _get_idx_exprrw     s    : !{B===r   c                   :    e Zd ZdZed             Zd Zd Zd ZdS )CompiledConditionz#Container for a compiled condition.c                 ~    | j         }g }|D ]#}|d         }||vr|                    |           $t          |          S )z2The columns participating in the index expression.r   )index_expressionsre   	frozenset)selfrg   idxvarsrf   idxvars        r   index_variablesz!CompiledCondition.index_variables2  sU     ) 	' 	'D!WFW$$v&&&!!!r   c                 T    || _         	 || _        	 || _        	 || _        	 || _        d S r   )function
parametersr{   string_expressionkwargs)r}   funcparamsrg   rh   r   s         r   __init__zCompiledCondition.__init__>  s9    K ;!)K!(8BBr   c                 6    d| j         d| j        d| j        S )Nz
idxexprs: z

strexpr: z

idxvars: )r{   r   r   )r}   s    r   __repr__zCompiledCondition.__repr__J  s.     )))4+A+A+A'') 	*r   c                 v   | j         }g }|D ]}|d         }g }|D ]N}t          |t                    r"||d                  }|                                }|                    |           O|\  }}	}
|                    ||	t          |          f           t          | j        | j        || j        fi | j	        }|S )zReplace index limit variables with their values in-place.

        A new compiled condition is returned.  Values are taken from
        the `condvars` mapping and converted to Python scalars.
        ra   r   )
r{   rK   tupletolistre   ry   r   r   r   r   )r}   condvarsexprsexprs2rf   idxlimslimit_valuesidxlimr6   ops_newccs               r   with_replaced_varsz$CompiledCondition.with_replaced_varsO  s     & 
	; 
	;D1gGL! , ,fe,, -%fQi0F#]]__F##F++++KCaMM3U<%8%89::::!M4?FD4J k  r   N)	r(   
__module____qualname__r)   r   r   r   r   r    r   r   ry   ry   /  sc        --	" 	" X	"
C 
C 
C* * *
    r   ry   c                    g }| g}|rf|                                 }|j        dk    r|                    |j                   n*t	          |d          r|                    |j                   |ft          t          |                    S )z>Return the list of variable names in the Numexpr `expression`.r2   rA   )	popr5   re   r4   hasattrextendrA   rd   set)
expressionnamesstackr>   s       r   _get_variable_namesr   j  s     ELE
 (yy{{<:%%LL$$$$T:&& 	(LL'''  ( E

r   c                    t           j                            | i           }|j        dk    rt	          d| z            t          ||          }t          |t                    rdg}n|\  }}|d         }t          |          }fd|D             }	 t           j        	                    ||          }n!# t          $ r}	t          |	          d}	~	ww xY wt           j                            | i           \  }
}d|i}|}t          ||||fi |S )a  Compile a condition and extract usable index conditions.

    Looks for variable-constant comparisons in the `condition` string
    involving the indexed columns whose variable names appear in
    `indexedcols`.  The part of `condition` having usable indexes is
    returned as a compiled condition in a `CompiledCondition` container.

    Expressions such as '0 < c1 <= 1' do not work as expected.  The
    Numexpr types of *all* variables must be given in the `typemap`
    mapping.  The ``function`` of the resulting `CompiledCondition`
    instance is a Numexpr function object, and the ``parameters`` list
    indicates the order of its parameters.

    r<   z-condition ``%s`` does not have a boolean typerc   r   c                 $    g | ]}||         fS r   r   )r   r6   typemaps     r   
<listcomp>z%compile_condition.<locals>.<listcomp>  s"    999#ws|$999r   Nex_uses_vml)r	   r
   stringToExpressionr=   	TypeErrorrw   rK   rd   r   NumExprr!   r   getExprNamesry   )	conditionr   r#   rf   rg   rh   varnames	signaturer   r%   r   r   r   r   s    `            r   compile_conditionr   x  sD   " =++IwCCD|vG#$ % % 	%T;//H(D!! %& %'ajG #4((H9999999I0 }$$T955 0 0 0*3///0 ]//	2>>NA{[)FFT68WGGGGGs    B5 5
C?CCc                     g }|D ]L}|r ||          }n|}t          |d          rt          ||j                  }|                    |           M | |i |S )a3  Call `func` with `params` over `recarr`.

    The `param2arg` function, when specified, is used to get an argument
    given a parameter name; otherwise, the parameter itself is used as
    an argument.  When the argument is a `Column` object, the proper
    column from `recarr` is used as its value.

    pathname)r   r   r   re   )r   r   recarr	param2argr   r   paramargs           r   call_on_recarrr     s     D   	)E""CCC3
## 	9"63<88CC4    r   r   )r)   renumexprr	   utilsextensionr   utilsr   compiler   r   r*   rI   rQ   rl   rw   ry   r   r   r   r   r   r   <module>r      s5     
			     , , , , , ,       !bj!ABB + + +  . > > >B  .q q qh> > >@8 8 8 8 8 8 8 8v  2H 2H 2Hj! ! ! ! ! !r   