
    oVh7"                        d Z ddlmZ ddlmZ ddlmZ ddlmZmZ er"ddlm	Z	m
Z
mZ  e
d      Z e
d	      Z e
d
      ZdddZddZ	 	 ddZddZd Z G d d      Zy)z
SymPy core decorators.

The purpose of this module is to expose decorators without any other
dependencies, so that they can be easily imported anywhere in sympy/core.
    )annotations)TYPE_CHECKINGwraps   )SympifyErrorsympify)CallableTypeVarUnionT1T2T3Nc                      fd}|S )a  
    decorator to smartly _sympify function arguments

    Explanation
    ===========

    @_sympifyit('other', NotImplemented)
    def add(self, other):
        ...

    In add, other can be thought of as already being a SymPy object.

    If it is not, the code is likely to catch an exception, then other will
    be explicitly _sympified, and the whole code restarted.

    if _sympify(arg) fails, NotImplemented will be returned

    See also
    ========

    __sympifyit
    c                    t        |       S N)__sympifyit)funcargretvals    E/home/dcms/DCMS/lib/python3.12/site-packages/sympy/core/decorators.pydecoz_sympifyit.<locals>.deco.   s    4f--     )r   r   r   s   `` r   
_sympifyitr      s    .. Kr   c                      j                   j                  st        d       j                   j                  d   |k(  sJ t	                fd       }|S t	                fd       }|S )zuDecorator to _sympify `arg` argument for function `func`.

       Do not use directly -- use _sympifyit instead.
    zfunc not foundr   c                ,     | t        |d            S )NTstrict)r	   )abr   s     r   __sympifyit_wrapperz(__sympifyit.<locals>.__sympifyit_wrapper@   s    71T233r   c                l    	 t        |d      st        |d      } | |      S # t        $ r cY S w xY wN_op_priorityTr   )hasattrr	   r   )r    r!   r   r   s     r   r"   z(__sympifyit.<locals>.__sympifyit_wrapperE   s@     q.1$/AAqz! s   !% 33)__code__co_argcountLookupErrorco_varnamesr   )r   r   r   r"   s   ` ` r   r   r   4   s~     ==$$*++==$$Q'3...~	t	4 
	4  
t	 
	 r   c                     d fd}|S )a  A decorator for binary special methods to handle _op_priority.

    Explanation
    ===========

    Binary special methods in Expr and its subclasses use a special attribute
    '_op_priority' to determine whose special method will be called to
    handle the operation. In general, the object having the highest value of
    '_op_priority' will handle the operation. Expr and subclasses that define
    custom binary special methods (__mul__, etc.) should decorate those
    methods with this decorator to add the priority logic.

    The ``method_name`` argument is the name of the method of the other class
    that will be called.  Use this decorator in the following manner::

        # Call other.__rmul__ if other._op_priority > self._op_priority
        @call_highest_priority('__rmul__')
        def __mul__(self, other):
            ...

        # Call other.__mul__ if other._op_priority > self._op_priority
        @call_highest_priority('__mul__')
        def __rmul__(self, other):
        ...
    c                4     t               d fd       }|S )Nc                    t        |d      r0|j                  | j                  kD  rt        |d       }| ||       S  | |      S )Nr%   )r&   r%   getattr)selfotherfr   method_names      r   binary_op_wrapperzLcall_highest_priority.<locals>.priority_decorator.<locals>.binary_op_wrappero   sK    un-%%(9(999@UY9ZA} we$$r   )r/   r   r0   r   returnr   r   )r   r3   r2   s   ` r   priority_decoratorz1call_highest_priority.<locals>.priority_decoratorn   s!    	t	% 
	% ! r   r   Callable[[T1, T2], T3]r4   r7   r   )r2   r5   s   ` r   call_highest_priorityr8   S   s    6	! r   c                    | j                   j                         D ]2  \  }}t        |t              st	        | ||j                  |              4 | S )a	  Decorator for a class with methods that sympify arguments.

    Explanation
    ===========

    The sympify_method_args decorator is to be used with the sympify_return
    decorator for automatic sympification of method arguments. This is
    intended for the common idiom of writing a class like :

    Examples
    ========

    >>> from sympy import Basic, SympifyError, S
    >>> from sympy.core.sympify import _sympify

    >>> class MyTuple(Basic):
    ...     def __add__(self, other):
    ...         try:
    ...             other = _sympify(other)
    ...         except SympifyError:
    ...             return NotImplemented
    ...         if not isinstance(other, MyTuple):
    ...             return NotImplemented
    ...         return MyTuple(*(self.args + other.args))

    >>> MyTuple(S(1), S(2)) + MyTuple(S(3), S(4))
    MyTuple(1, 2, 3, 4)

    In the above it is important that we return NotImplemented when other is
    not sympifiable and also when the sympified result is not of the expected
    type. This allows the MyTuple class to be used cooperatively with other
    classes that overload __add__ and want to do something else in combination
    with instance of Tuple.

    Using this decorator the above can be written as

    >>> from sympy.core.decorators import sympify_method_args, sympify_return

    >>> @sympify_method_args
    ... class MyTuple(Basic):
    ...     @sympify_return([('other', 'MyTuple')], NotImplemented)
    ...     def __add__(self, other):
    ...          return MyTuple(*(self.args + other.args))

    >>> MyTuple(S(1), S(2)) + MyTuple(S(3), S(4))
    MyTuple(1, 2, 3, 4)

    The idea here is that the decorators take care of the boiler-plate code
    for making this happen in each method that potentially needs to accept
    unsympified arguments. Then the body of e.g. the __add__ method can be
    written without needing to worry about calling _sympify or checking the
    type of the resulting object.

    The parameters for sympify_return are a list of tuples of the form
    (parameter_name, expected_type) and the value to return (e.g.
    NotImplemented). The expected_type parameter can be a type e.g. Tuple or a
    string 'Tuple'. Using a string is useful for specifying a Type within its
    class body (as in the above example).

    Notes: Currently sympify_return only works for methods that take a single
    argument (not including self). Specifying an expected_type as a string
    only works for the class in which the method is defined.
    )__dict__items
isinstance_SympifyWrappersetattrmake_wrapped)clsattrnameobjs      r   sympify_method_argsrC   {   sM    F ++- :#c?+C3#3#3C#89: Jr   c                      d fd}|S )zFunction/method decorator to sympify arguments automatically

    See the docstring of sympify_method_args for explanation.
    c                    t        |       S r   )r=   r   argss    r   wrapperzsympify_return.<locals>.wrapper   s    tT**r   r6   r   )rG   rH   s   ` r   sympify_returnrI      s    +Nr   c                      e Zd ZdZd Zd Zy)r=   z=Internal class used by sympify_return and sympify_method_argsc                     || _         || _        y r   rF   )r/   r   rG   s      r   __init__z_SympifyWrapper.__init__   s    		r   c                V   | j                   | j                  \  }|\  \  }|j                  k(  r|j                  j                  }|dk7  rt        d      j                  j                  d   |k7  rt        d|dj                        t              fd       }|S )N   z9sympify_return can only be used with 2 argument functionsr   zparameter name mismatch "z" in c                    t        |d      s	 t        |d      }t        |      sS  | |      S # t        $ r cY S w xY wr$   )r&   r	   r   r<   )r/   r0   expectedclsr   r   s     r   _funcz+_SympifyWrapper.make_wrapped.<locals>._func   sT    
 5.1"#E$7E e[1e$$	 $ "!M"s   3 A A)r   rG   __name__r'   r(   RuntimeErrorr*   r   )	r/   r@   
parameters	parameternargsrQ   rP   r   r   s	         @@@r   r?   z_SympifyWrapper.make_wrapped   s    yy!YY
F &0"	!)[ #,,&K ))A:Z[[==$$Q'94 / 0 0 
t	% 
	% r   N)rR   
__module____qualname____doc__rL   r?   r   r   r   r=   r=      s    G$r   r=   r   )r4   :Callable[[Callable[[T1, T2], T3]], Callable[[T1, T2], T3]])r2   strr4   rZ   )r@   type[T1]r4   r\   )rY   
__future__r   typingr   	functoolsr   r	   r   r
   r   r   r   r   r   r   r   r8   rC   rI   r=   r   r   r   <module>r`      sl    #    * //	B	B	B:>%	C%PFR+ +r   