o
    حh                     @   s  d dl mZ d dlZd dlZd dl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 ejd	krCejZnd
d Zzd dl	mZmZmZ W n eyf   d dlmZmZmZ Y nw zd dl	mZ W n ey|   dd ZY nw zd dl	mZ W n ey   dd ZY nw zd dl	mZ W n ey   dd ZY nw zd dlmZmZm Z m!Z!m"Z"m#Z#m$Z$ W n	 ey   Y nw ejdk Z%e%sefZ&ne'fZ&e(dZ)												daddZ*dd Z+								dbdd Z,d!d" Z-d#d$ Z.d%d& Z/G d'd( d(Z0d)d* Z1d+d, Z2e3ee4e5fZ6d-d. Z7d/d0 Z8d1d2 Z9d3d4 Z:d5d6 Z;d7d8 Z<d9d: Z=e> Z?dcd;d<Z@	ddd>d?ZAded@dAZB												dfdBdCZCdDdE ZD								dbdFdGZEdHdI ZF	=	=	=	JdgdKdLZGdMdN ZHdOdP ZIe%rG dQdR dRZJeJ ZKndZKdSdT ZLdUdV ZMG dWdX dXeNZOG dYdZ dZePZQG d[d\ d\eRZS		=dhd]d^ZT		=	did_d`ZUdS )j    )print_functionN)OrderedDict)copy)	getsource)	iskeyword)dedent)FunctionType)   r   c                 C   s4   t | dks| d  rdS tdd | dD S )z
        Replacement for `str.isidentifier` when it is not available (e.g. on Python 2).
        :param string:
        :return:
        r   Fc                 S   s    g | ]}t |d kp| qS r   )lenisalnum).0s r   Q/var/www/html/stock_analysis/be/venv/lib/python3.10/site-packages/makefun/main.py
<listcomp>   s     z!is_identifier.<locals>.<listcomp>_)r   isdigitallsplit)stringr   r   r   is_identifier   s   r   )	signature	Signature	Parameter)iscoroutinefunctionc                 C      dS NFr   fr   r   r   r   )      r   )isgeneratorfunctionc                 C   r   r   r   r   r   r   r   r!   0   r    r!   )isasyncgenfunctionc                 C   r   r   r   r   r   r   r   r"   7   r    r"   )CallableAnyUnionIterableDictTupleMapping)r	   z(?s)^\s*(?P<funcname>[_\w][_\w\d]*)?\s*\(\s*(?P<params>.*?)\s*\)\s*(((?P<typed_return_hint>->\s*[^:]+)?(?P<colon>:)?\s*)|:\s*#\s*(?P<comment_return_hint>.+))*$FTc                 K   s.   t | f||||||||	|
|||d||S )z
    Creates a signature-preserving wrapper function.
    `create_wrapper(wrapped, wrapper, **kwargs)` is equivalent to `wraps(wrapped, **kwargs)(wrapper)`.

    See `@makefun.wraps`
    )new_sigprepend_argsappend_argsremove_args	func_nameinject_as_first_arg
add_sourceadd_impldocqualnamemodule_nameco_name)wraps)wrappedwrapperr*   r+   r,   r-   r.   r/   r0   r1   r2   r3   r5   r4   attrsr   r   r   create_wrapperO   s   
r:   c                 G   sR   t | |g|R  }t| tjr'|du s|dkr't|dkr't| j|g|R  S |S )z> Same as getattr but recurses in obj.func if obj is a partial N__dict__r   )getattr
isinstance	functoolspartialr   getattr_partial_awarefunc)objatt_nameatt_defaultvalr   r   r   r@   k   s   
r@   c
                 K   s  z|
 d tdd}W n ty   t }Y nw t|\}}d}|du r-t|dd}d}|du}|s=|du r:d}n|}nt|sKt|sKtd	| d}|du rYt|d
d}d}|du rct|dd}|	du rmt|dd}	t	| t
rt| |\}} }|dur|s|}|s|}|s|}t| }|r|rt|nd}||d d }n*|du r|| }n!t	| trt| }|rt| |}nt|| |}ntdt|  t| }t| }t| \}}}dd | D }d|}|rd||f }t|rtjdkrd||f }n2ddlm} | ||f }n$t|rd||f }n|r1|r,d||f }nd| }nd||f }t|rDd| dd}t ||| ||d< |rYt!d|||}nt!||||}|rg||
d < |rn||
d!< t"|||||t#|||	|
d"	 |S )#a  
    Creates a function with signature `func_signature` that will call `func_impl` when called. All arguments received
    by the generated function will be propagated as keyword-arguments to `func_impl` when it is possible (so all the
    time, except for var-positional or positional-only arguments that get passed as *args. Note that positional-only
    does not yet exist in python but this case is already covered because it is supported by `Signature` objects).

    `func_signature` can be provided in different formats:

     - as a string containing the name and signature without 'def' keyword, such as `'foo(a, b: int, *args, **kwargs)'`.
       In which case the name in the string will be used for the `__name__` and `__qualname__` of the created function
       by default
     - as a `Signature` object, for example created using `signature(f)` or handcrafted. Since a `Signature` object
       does not contain any name, in this case the `__name__` and `__qualname__` of the created function will be copied
       from `func_impl` by default.

    All the other metadata of the created function are defined as follows:

     - default `__name__` attribute (see above) can be overridden by providing a non-None `func_name`
     - default `__qualname__` attribute (see above) can be overridden by providing a non-None `qualname`
     - `__annotations__` attribute is created to match the annotations in the signature.
     - `__doc__` attribute is copied from `func_impl.__doc__` except if overridden using `doc`
     - `__module__` attribute is copied from `func_impl.__module__` except if overridden using `module_name`
     - `__code__.co_name` (see above) defaults to the same value as the above `__name__` attribute, except when that
       value is not a valid Python identifier, in which case it will be `<lambda>`. It can be  overridden by providing
       a `co_name` that is either a valid Python identifier or `<lambda>`.

    Finally two new attributes are optionally created

     - `__source__` attribute: set if `add_source` is `True` (default), this attribute contains the source code of the
     generated function
     - `__func_impl__` attribute: set if `add_impl` is `True` (default), this attribute contains a pointer to
     `func_impl`

    A lambda function will be created in the following cases:

     - when `func_signature` is a `Signature` object and `func_impl` is itself a lambda function,
     - when the function name, either derived from a `func_signature` string, or given explicitly with `func_name`,
       is not a valid Python identifier, or
     - when the provided `co_name` is `<lambda>`.

    :param func_signature: either a string without 'def' such as "foo(a, b: int, *args, **kwargs)" or "(a, b: int)",
        or a `Signature` object, for example from the output of `inspect.signature` or from the `funcsigs.signature`
        backport. Note that these objects can be created manually too. If the signature is provided as a string and
        contains a non-empty name, this name will be used instead of the one of the decorated function.
    :param func_impl: the function that will be called when the generated function is executed. Its signature should
        be compliant with (=more generic than) `func_signature`
    :param inject_as_first_arg: if `True`, the created function will be injected as the first positional argument of
        `func_impl`. This can be handy in case the implementation is shared between several facades and needs
        to know from which context it was called. Default=`False`
    :param func_name: provide a non-`None` value to override the created function `__name__` and `__qualname__`. If this
        is `None` (default), the `__name__` will default to the one of `func_impl` if `func_signature` is a `Signature`,
        or to the name defined in `func_signature` if `func_signature` is a `str` and contains a non-empty name.
    :param add_source: a boolean indicating if a '__source__' annotation should be added to the generated function
        (default: True)
    :param add_impl: a boolean indicating if a '__func_impl__' annotation should be added to the generated function
        (default: True)
    :param doc: a string representing the docstring that will be used to set the __doc__ attribute on the generated
        function. If None (default), the doc of func_impl will be used.
    :param qualname: a string representing the qualified name to be used. If None (default), the `__qualname__` will
        default to the one of `func_impl` if `func_signature` is a `Signature`, or to the name defined in
        `func_signature` if `func_signature` is a `str` and contains a non-empty name.
    :param co_name: a string representing the name to be used in the compiled code of the function. If None (default),
        the `__code__.co_name` will default to the one of `func_impl` if `func_signature` is a `Signature`, or to the
        name defined in `func_signature` if `func_signature` is a `str` and contains a non-empty name.
    :param module_name: the name of the module to be set on the function (under __module__ ). If None (default),
        `func_impl.__module__` will be used.
    :param attrs: other keyword attributes that should be set on the function. Note that `func_impl.__dict__` is not
        automatically copied.
    :return:
    
_with_sig_   offsetTN__name__Fz<lambda>zlInvalid co_name %r for created function. It is not possible to declare a function with the provided co_name.__qualname____doc__
__module__r   z%Invalid type for `func_signature`: %sc                 S   s$   g | ]\}}|rd ||f n|qS )z%s=%sr   )r   kis_kwr   r   r   r   %  s   $ z#create_function.<locals>.<listcomp>, z%s, %sr	   r	   z&def %s
    yield from _func_impl_(%s)
)%get_legacy_py_generator_body_templatezAasync def %s
    async for y in _func_impl_(%s):
        yield y
z%lambda_ = lambda %s: _func_impl_(%s)
z"lambda_ = lambda: _func_impl_(%s)
z"def %s
    return _func_impl_(%s)
zasync zreturn _func_impl_zreturn await _func_impl__func_impl_lambda_
__source____func_impl__)namer3   r2   annotationsdefaultskwonlydefaultsmodulekw)$pop_get_callerframeKeyErrorextract_module_and_evaldictr@   _is_valid_func_def_name_is_lambda_func_name
ValueErrorr<   r=   strget_signature_from_stringr   r   get_lambda_argument_stringget_signature_string	TypeErrortypeget_signature_paramslistkeysget_signature_detailsitemsjoin_is_generator_funcsysversion_infomakefun._main_legacy_pyrS   r"   r   replaceprotect_eval_dict_make_update_fieldstuple)func_signature	func_implr.   r/   r0   r1   r2   r3   r5   r4   r9   frameevaldictr   user_provided_nameuser_provided_co_nameuser_provided_qnamefunc_name_from_strfunc_signature_strcreate_lambdaname_lenparams_to_kw_assignment_modeparams_namesrY   rZ   r[   assignments
params_strbodyrS   r   r   r   r   create_functionv   s   R










r   c                 C   s:   dt j  krdk rn t| S t| ot|  S t| S )zX
    Return True if the func_impl is a generator
    :param func_impl:
    :return:
    r	      r	      )rr   rs   r!   r   )r{   r   r   r   rq   U  s   rq   c                 C   s   | dd j jkS )z]
    Return True if func_name is the name of a lambda
    :param func_name:
    :return:
    c                   S   s   d S Nr   r   r   r   r   <lambda>j      z&_is_lambda_func_name.<locals>.<lambda>)__code__r5   r.   r   r   r   rc   d  s   rc   c                 C   s   t | ot|  S )zh
    Return True if func_name is valid in a function definition.
    :param func_name:
    :return:
    )r   r   r   r   r   r   rb   m  s   rb   c                   @   s$   e Zd ZdZdZdd Zdd ZdS )
_SymbolRefaC  
    A class used to protect signature default values and type hints when the local context would not be able
    to evaluate them properly when the new function is created. In this case we store them under a known name,
    we add that name to the locals(), and we use this symbol that has a repr() equal to the name.
    varnamec                 C   s
   || _ d S r   r   )selfr   r   r   r   __init__~  s   
z_SymbolRef.__init__c                 C   s   | j S r   r   r   r   r   r   __repr__  s   z_SymbolRef.__repr__N)rJ   rM   rK   rL   	__slots__r   r   r   r   r   r   r   v  s
    r   c                 C   s   t jdk }g }d}|j D ]D\}}t|j|}t|j|d| |}	|r-tj}
|
|j	u}nt|j	|}t|j	|d| |}
|sA|rMt|j
|j|	|
d}d}|| q|r^tj}||ju}nt|j|}t|j|d|}|sp|rwt||d}n|}d	| |f S )
z
    Returns the string to be used as signature.
    If there is a non-native symbol in the defaults, it is created as a variable in the evaldict
    :param func_name:
    :param func_signature:
    :return:
    r   Fz
DEFAULT_%szHINT_%s)kinddefault
annotationT
RETURNHINT
parametersreturn_annotationz%s%s:)rr   rs   r   ro   "_signature_symbol_needs_protectionr   _protect_signature_symbolr   emptyr   rX   r   appendr   r   )r.   rz   r}   no_type_hints_allowed
new_paramsparams_changedp_namepdefault_needs_protectionnew_defaultnew_annotationannotation_needs_protectionnew_return_annotationreturn_needs_protectionr   r   r   r   rh     s8   
rh   c                 C   s   t d| |dd S )z
    Returns the string to be used as arguments in a lambda function definition.
    If there is a non-native symbol in the defaults, it is created as a variable in the evaldict
    :param func_name:
    :param func_signature:
    :return:
     rG   rN   )rh   )rz   r}   r   r   r   rg     s   rg   c                 C   sL   | dur$| t jur$t| tvr$z
tt| || kW S  ty#   Y dS w dS )a   
    Helper method for signature symbols (defaults, type hints) protection.

    Returns True if the given symbol needs to be protected - that is, if its repr() can not be correctly evaluated with
    current evaldict.

    :param symbol:
    :return:
    NTF)r   r   rj   TYPES_WITH_SAFE_REPRevalrepr	Exception)symbolr}   r   r   r   r     s   
r   c                 C   s   |r
| ||< t |S | S )aJ  
    Helper method for signature symbols (defaults, type hints) protection.

    Returns either `val`, or a protection symbol. In that case the protection symbol
    is created with name `varname` and inserted into `evaldict`

    :param val:
    :param needs_protection:
    :param varname:
    :param evaldict:
    :return:
    )r   )rE   needs_protectionr   r}   r   r   r   r     s   r   c                 C   s   |  dr| dd } t| }|du rtd| tjf | }|d }|du s-|dkr2d}d}n|}|d }|d	 }|du sFt|d
krT|du sPt|d
krT| d } |du r\||  n| }d| }	t|g |	|}
|t|
| fS )z
    Creates a `Signature` object from the given function signature string.

    :param func_sig_str:
    :return: (func_name, func_sig, func_sig_str). func_sig_str is guaranteed to contain the ':' symbol already
    
rG   NzThe provided function template is not valid: "%s" does not match "<func_name>(<func_args>)[ -> <return-hint>]".
 For information the regex used is: "%s"funcnamer   dummycoloncomment_return_hintr   :zdef %s
    pass
)	
startswithFUNC_DEFmatchSyntaxErrorpattern	groupdictr   rw   r   )func_sig_strr}   	def_matchgroupsr.   
func_name_	colon_endcmt_return_hintfunc_sig_str_r   dummy_fr   r   r   rf     s2   


rf   c                 C   s   t  }| j D ]P\}}|jtju rd||< q|jtju r"d||< q|jtju r-d||< q|jtju rE|	 D ]}d||< q7d|d| < q|jtj
u rRd|d| < qtd|j |S )z
    Utility method to return the parameter names in the provided `Signature` object, by group of kind

    :param s:
    :return:
    FT*z**zUnknown kind: %s)r   r   ro   r   r   POSITIONAL_ONLYKEYWORD_ONLYPOSITIONAL_OR_KEYWORDVAR_POSITIONALrm   VAR_KEYWORDrd   )r   params_to_assignment_moder   r   rO   r   r   r   rk   J  s    



rk   c                 C   s   t  }g }t  }| j| jur| j|d< | j D ]'\}}|j| jur'|j||< |j| jur?|jtj	ur:|
|j q|j||< q|||fS )z
    Utility method to extract the annotations, defaults and kwdefaults from a `Signature` object

    :param s:
    :return:
    return)dictr   r   r   ro   r   r   r   r   r   r   )r   rY   rZ   r[   r   r   r   r   r   rn   g  s   



rn   c                 C   sR   z| j dd}t| j }|| j W ||fS  ty(   d}t }Y ||fS w )z
    Utility function to extract the module name from the given frame,
    and to return a dictionary containing globals and locals merged together

    :param frame:
    :return:
    rJ   ?)	f_globalsgetr   updatef_localsAttributeErrorr   )r|   r4   r}   r   r   r   ra     s   
ra   c              	   C   sH   z| |= W n	 t y   Y nw |D ]}z| |= W q t y!   Y qw | S )z
    remove all symbols that could be harmful in evaldict

    :param evaldict:
    :param func_name:
    :param params_names:
    :return:
    )r`   )r}   r.   r   nr   r   r   rv     s   	

rv   c                 C   s   |pi }|D ]}|dv rt d||f q|dstddttf }zt||d}t|| W n tyH   tdt	j
d t|t	j
d  w ||  }|S )	z
    Make a new function from a given template and update the signature

    :param func_name:
    :param params_names:
    :param body:
    :param evaldict:
    :param add_source:
    :return:
    )_func_rT   z%s is overridden in
%sr   zbody should end with a newlinez<makefun-gen-%d>singlezError in generated code:)file)	NameErrorendswithrd   next_compile_countcompileexecBaseExceptionprintrr   stderr)r   r   r   r}   r   filenamecoderA   r   r   r   rw     s$   
rw   r   c	           	      C   sZ   |du rt  }|| _|dur|| _|| _|| _|| _t|dkr"d}|| _|| _|| _	dS )z
    Update the signature of func with the provided information

    This method merely exists to remind which field have to be filled.

    :param func:
    :param name:
    :param qualname:
    :param kw:
    :return:
    Nr   )
r   rJ   rK   rL   r;   __defaults__r   __kwdefaults____annotations__rM   )	rA   rX   r3   r2   rY   rZ   r[   r\   r]   r   r   r   rx     s   
rx   c                 C   s.   z
t d|  }W |S  ty   d }Y |S w )N   )rr   	_getframer   )rI   r|   r   r   r   r_     s   r_   c                 K   sL   t | ||||||
||||\}}}
}}}}t|f||||	|
|||d|S )a  
    A decorator to create a signature-preserving wrapper function.

    It is similar to `functools.wraps`, but

     - relies on a proper dynamically-generated function. Therefore as opposed to `functools.wraps`,

        - the wrapper body will not be executed if the arguments provided are not compliant with the signature -
          instead a `TypeError` will be raised before entering the wrapper body.
        - the arguments will always be received as keywords by the wrapper, when possible. See
          [documentation](./index.md#signature-preserving-function-wrappers) for details.

     - you can modify the signature of the resulting function, by providing a new one with `new_sig` or by providing a
       list of arguments to remove in `remove_args`, to prepend in `prepend_args`, or to append in `append_args`.
       See [documentation](./index.md#editing-a-signature) for details.

    Comparison with `@with_signature`:`@wraps(f)` is equivalent to

        `@with_signature(signature(f),
                         func_name=f.__name__,
                         doc=f.__doc__,
                         module_name=f.__module__,
                         qualname=f.__qualname__,
                         __wrapped__=f,
                         **f.__dict__,
                         **attrs)`

    In other words, as opposed to `@with_signature`, the metadata (doc, module name, etc.) is provided by the wrapped
    `wrapped_fun`, so that the created function seems to be identical (except possibly for the signature).
    Note that all options in `with_signature` can still be overridden using parameters of `@wraps`.

    The additional `__wrapped__` attribute is set on the created function, to stay consistent
    with the `functools.wraps` behaviour. If the signature is modified through `new_sig`,
    `remove_args`, `append_args` or `prepend_args`, the additional
    `__signature__` attribute will be set so that `inspect.signature` and related functionality
    works as expected. See PEP 362 for more detail on `__wrapped__` and `__signature__`.

    See also [python documentation on @wraps](https://docs.python.org/3/library/functools.html#functools.wraps)

    :param wrapped_fun: the function that you intend to wrap with the decorated function. As in `functools.wraps`,
        `wrapped_fun` is used as the default reference for the exposed signature, `__name__`, `__qualname__`, `__doc__`
        and `__dict__`.
    :param new_sig: the new signature of the decorated function. By default it is `None` and means "same signature as
        in `wrapped_fun`" (similar behaviour as in `functools.wraps`). If you wish to modify the exposed signature
        you can either use `remove/prepend/append_args`, or pass a non-None `new_sig`. It can be either a string
        without 'def' such as "foo(a, b: int, *args, **kwargs)" of "(a, b: int)", or a `Signature` object, for example
        from the output of `inspect.signature` or from the `funcsigs.signature` backport. Note that these objects can
        be created manually too. If the signature is provided as a string and contains a non-empty name, this name
        will be used instead of the one of `wrapped_fun`.
    :param prepend_args: a string or list of strings to prepend to the signature of `wrapped_fun`. These extra arguments
        should not be passed to `wrapped_fun`, as it does not know them. This is typically used to easily create a
        wrapper with additional arguments, without having to manipulate the signature objects.
    :param append_args: a string or list of strings to append to the signature of `wrapped_fun`. These extra arguments
        should not be passed to `wrapped_fun`, as it does not know them. This is typically used to easily create a
        wrapper with additional arguments, without having to manipulate the signature objects.
    :param remove_args: a string or list of strings to remove from the signature of `wrapped_fun`. These arguments
        should be injected in the received `kwargs` before calling `wrapped_fun`, as it requires them. This is typically
        used to easily create a wrapper with less arguments, without having to manipulate the signature objects.
    :param func_name: provide a non-`None` value to override the created function `__name__` and `__qualname__`. If this
        is `None` (default), the `__name__` will default to the ones of `wrapped_fun` if `new_sig` is `None` or is a
        `Signature`, or to the name defined in `new_sig` if `new_sig` is a `str` and contains a non-empty name.
    :param inject_as_first_arg: if `True`, the created function will be injected as the first positional argument of
        the decorated function. This can be handy in case the implementation is shared between several facades and needs
        to know from which context it was called. Default=`False`
    :param add_source: a boolean indicating if a '__source__' annotation should be added to the generated function
        (default: True)
    :param add_impl: a boolean indicating if a '__func_impl__' annotation should be added to the generated function
        (default: True)
    :param doc: a string representing the docstring that will be used to set the __doc__ attribute on the generated
        function. If None (default), the doc of `wrapped_fun` will be used. If `wrapped_fun` is an instance of
        `functools.partial`, a special enhanced doc will be generated.
    :param qualname: a string representing the qualified name to be used. If None (default), the `__qualname__` will
        default to the one of `wrapped_fun`, or the one in `new_sig` if `new_sig` is provided as a string with a
        non-empty function name.
    :param co_name: a string representing the name to be used in the compiled code of the function. If None (default),
        the `__code__.co_name` will default to the one of `func_impl` if `func_signature` is a `Signature`, or to the
        name defined in `func_signature` if `func_signature` is a `str` and contains a non-empty name.
    :param module_name: the name of the module to be set on the function (under __module__ ). If None (default), the
        `__module__` attribute of `wrapped_fun` will be used.
    :param attrs: other keyword attributes that should be set on the function. Note that the full `__dict__` of
        `wrapped_fun` is automatically copied.
    :return: a decorator
    )r.   r/   r0   r1   r2   r3   r5   r4   )_get_args_for_wrappingwith_signature)wrapped_funr*   r+   r,   r-   r.   r5   r/   r0   r1   r2   r3   r4   r9   func_sig	all_attrsr   r   r   r6     s&   br6   c                 C   s  d}|dur|dus|dus|durt d|}d}n?t| }|r3t|tr)|f}t|g|R  }d}|r>t|tr=|f}nd}|rKt|trJ|f}nd}|sQ|rZd}t|||d}|du rdt| dd}|du rt| dd}t| tj	r|s|t	d	d
 j
krt| j}tt| jddt| jdd||| j}|du rt| dd}|	du rt| dd}	|du rt| dd}|dur|j}tt| d}| |d< |rt|tr||d< ntdd}t|\}}t||\}}}||d< ||
 ||||||	|fS )a3  
    Internal method used by @wraps and create_wrapper

    :param wrapped:
    :param new_sig:
    :param remove_args:
    :param prepend_args:
    :param append_args:
    :param func_name:
    :param doc:
    :param qualname:
    :param co_name:
    :param module_name:
    :param attrs:
    :return:
    FNzJOnly one of `[remove/prepend/append]_args` or `new_sig` should be providedTr   )firstlastrJ   rL   c                   S   r   )NTr   r   r   r   r   r     r   z(_get_args_for_wrapping.<locals>.<lambda>rK   rM   r   r;   __wrapped____signature__rG   rH   )rd   r   r=   string_typesremove_signature_parametersadd_signature_parametersr@   r<   r>   r?   rL   rA   gen_partial_docargsr5   r   r   r_   ra   rf   r   )r7   r*   r-   r+   r,   r.   r2   r3   r5   r4   r9   has_new_sigr   orig_sigr   r   r|   r}   r   
_func_namefunc_sig_as_sigr   r   r   r   }  sp   







r   c	              
      s^   du rdu rsr st d	fdd}
|
S  	f
dd}
|
S )a  
    A decorator for functions, to change their signature. The new signature should be compliant with the old one.

    ```python
    @with_signature(<arguments>)
    def impl(...):
        ...
    ```

    is totally equivalent to `impl = create_function(<arguments>, func_impl=impl)` except for one additional behaviour:

     - If `func_signature` is set to `None`, there is no `TypeError` as in create_function. Instead, this simply
     applies the new metadata (name, doc, module_name, attrs) to the decorated function without creating a wrapper.
     `add_source`, `add_impl` and `inject_as_first_arg` should not be set in this case.

    :param func_signature: the new signature of the decorated function. Either a string without 'def' such as
        "foo(a, b: int, *args, **kwargs)" of "(a, b: int)", or a `Signature` object, for example from the output of
        `inspect.signature` or from the `funcsigs.signature` backport. Note that these objects can be created manually
        too. If the signature is provided as a string and contains a non-empty name, this name will be used instead
        of the one of the decorated function. Finally `None` can be provided to indicate that user wants to only change
        the medatadata (func_name, doc, module_name, attrs) of the decorated function, without generating a new
        function.
    :param inject_as_first_arg: if `True`, the created function will be injected as the first positional argument of
        the decorated function. This can be handy in case the implementation is shared between several facades and needs
        to know from which context it was called. Default=`False`
    :param func_name: provide a non-`None` value to override the created function `__name__` and `__qualname__`. If this
        is `None` (default), the `__name__` will default to the ones of the decorated function if `func_signature` is a
        `Signature`, or to the name defined in `func_signature` if `func_signature` is a `str` and contains a non-empty
        name.
    :param add_source: a boolean indicating if a '__source__' annotation should be added to the generated function
        (default: True)
    :param add_impl: a boolean indicating if a '__func_impl__' annotation should be added to the generated function
        (default: True)
    :param doc: a string representing the docstring that will be used to set the __doc__ attribute on the generated
        function. If None (default), the doc of the decorated function will be used.
    :param qualname: a string representing the qualified name to be used. If None (default), the `__qualname__` will
        default to the one of `func_impl` if `func_signature` is a `Signature`, or to the name defined in
        `func_signature` if `func_signature` is a `str` and contains a non-empty name.
    :param co_name: a string representing the name to be used in the compiled code of the function. If None (default),
        the `__code__.co_name` will default to the one of `func_impl` if `func_signature` is a `Signature`, or to the
        name defined in `func_signature` if `func_signature` is a `str` and contains a non-empty name.
    :param module_name: the name of the module to be set on the function (under __module__ ). If None (default), the
        `__module__` attribute of the decorated function will be used.
    :param attrs: other keyword attributes that should be set on the function. Note that the full `__dict__` of the
        decorated function is not automatically copied.
    NzIf `func_signature=None` no new signature will be generated so only `func_name`, `module_name`, `doc` and `attrs` should be provided, to modify the metadata.c                    sZ   d ur| _ d ur| _d ur| _d ur| _  D ]
\}}t| || q | S r   )rJ   rL   rK   rM   ro   setattr)r   rO   v)r9   r2   r.   r4   r3   r   r   	replace_f  s   z!with_signature.<locals>.replace_fc                    s&   t d|  	ddS )NT)rz   r{   r.   r/   r0   r1   r2   r3   r5   r4   rF   r   )r   r   
r1   r0   r9   r5   r2   r.   rz   r/   r4   r3   r   r   r  %  s   )rd   )rz   r.   r/   r0   r1   r2   r3   r5   r4   r9   r  r   r  r   r     s   9r   c                 G   s.   t | j }|D ]}||= q	| j| dS )z
    Removes the provided parameters from the signature `s` (returns a new `Signature` instance).

    :param s:
    :param param_names: a list of parameter names to remove
    :return:
    r   )r   r   ro   ru   values)r   param_namesparams
param_namer   r   r   r   7  s   	r   c           
   	   C   sL  t | j }t| }zt|D ]}|j|v r td|j ||| qW n t	yC   |j|v r;td|j ||| Y nw d}zQt|D ]J}t
|tr|du rntj}ztt| j}W n	 tym   Y nw |tjtjfv rytj}t||d}n|j}|j|v rtd|j |d| qKW n t	y   |j|v rtd|j |d| Y nw d}	zN|D ]I}t
|tr|	du rtj}	ztt| j}	W n	 ty   Y nw |	tjtjfv rtj}	t||	d}n|j}	|j|v rtd|j || qW n t	y   |j|v rtd|j || Y nw | j|dS )a  
    Adds the provided parameters to the signature `s` (returns a new `Signature` instance).

    :param s: the original signature to edit
    :param first: a single element or a list of `Parameter` instances to be added at the beginning of the parameter's
        list. Strings can also be provided, in which case the parameter kind will be created based on best guess.
    :param last: a single element or a list of `Parameter` instances to be added at the end of the parameter's list.
        Strings can also be provided, in which case the parameter kind will be created based on best guess.
    :param custom: a single element or a list of `Parameter` instances to be added at a custom position in the list.
        That position is determined with `custom_idx`
    :param custom_idx: the custom position to insert the `custom` parameters to.
    :return: a new signature created from the original one by adding the specified parameters.
    zDParameter with name '%s' is present twice in the signature to createN)rX   r   r   r  )r   r   ro   rl   r  reversedrX   rd   insertri   r=   r   r   r   r   iterr   StopIterationr   r   r   r   r   ru   )
r   r   r   custom
custom_idxr	  lstparamfirst_param_kindlast_param_kindr   r   r   r   F  s|   






r   c                     s    fdd}|S )z
    Decorator to 'partialize' a function using `partial`

    :param preset_pos_args:
    :param preset_kwargs:
    :return:
    c                    s   t | gR i  S r   )r?   r   preset_kwargspreset_pos_argsr   r   apply_decorator  s   z%with_partial.<locals>.apply_decoratorr   )r  r  r  r   r  r   with_partial  s   r  c           	         s   t  }srt| }nd}t rAtjdkr.ddlm} || gR i }n=ddlm} || gR i }n*t	 r]tjdkr]ddl
m} || gR i }nt |d fd	d
}|durzt|j|j|||_ |_|S )aK  
    Equivalent of `functools.partial` but relies on a dynamically-created function. As a result the function
    looks nicer to users in terms of apparent documentation, name, etc.

    See [documentation](./index.md#removing-parameters-easily) for details.

    :param preset_pos_args:
    :param preset_kwargs:
    :return:
    NrR   r   )make_partial_using_yield_from)make_partial_using_yieldr   )%make_partial_using_async_for_in_yield)r*   c                     s    |   t| i |S r   )r   	itertoolschain)r   kwargsr   r  r  r   r   	partial_f  s   
zpartial.<locals>.partial_f)r   gen_partial_sigrq   rr   rs   makefun._main_py35_and_higherr  rt   r  r"   makefun._main_py36_and_higherr  r6   r   rJ   rL   rA   )	r   r  r  r   r*   r  r"  r  r  r   r!  r   r?     s&   

r?   c                   @   s   e Zd Zdd Zdd ZdS )KwOnlyc                 C   s   t | S r   )r   r   r   r   r   __str__  s   zKwOnly.__str__c                 C   r   )NzKW_ONLY_ARG!r   r   r   r   r   r     r    zKwOnly.__repr__N)rJ   rM   rK   r'  r   r   r   r   r   r&    s    r&  c              
   C   s~  t |}t| jt|k rtdt|t|d|t| jf g }d}t| j D ]w\}\}}|t|k r7q*z||}	W n5 tys   |rq|j	t
jt
jfvrqtra|j	}
|jt
jur^|jnt}nt
j}
|j}t
|j|
||jd}Y n)w |j	t
ju r~tdts|j	t
jt
jfvrt
j}
n|j	}
t
|j|
|	|jd}d}|| q*tt|| jd}t|dkrtd	t|d||f |S )
a  
    Returns the signature of partial(f, *preset_pos_args, **preset_kwargs)
    Raises explicit errors in case of non-matching argument names.

    By default the behaviour is the same as `functools.partial`:

     - partialized positional arguments disappear from the signature
     - partialized keyword arguments remain in the signature in the same order, but all keyword arguments after them
       in the parameters order become keyword-only (if python 2, they do not become keyword-only as this is not allowed
       in the compiler, but we pass them a bad default value "KEYWORD_ONLY")

    :param orig_sig:
    :param preset_pos_args:
    :param preset_kwargs:
    :param f: used in error messages only
    :return:
    z?Cannot preset %s positional args, function %s has only %s args.rJ   F)rX   r   r   r   zPredefining a positional-only argument using keyword is not supported as in python 3.8.8, 'signature()' does not support such functions and raises aValueError. Please report this issue if support needs to be added in the future.Tr   r   zICannot preset keyword argument(s), not present in the signature of %s: %s)r   r   r   rd   r<   	enumeratero   r^   r`   r   r   r   r   PY2r   r   KW_ONLYrX   r   r   NotImplementedErrorr   r   ry   r   )r   r  r  r   r   kwonly_flagir   r   overridden_p_defaultnew_kindr   r*   r   r   r   r#    sL   r#  c                 C   s   g }d}t |j D ]E\}\}}	|t|k r!|t||  q|j| }
|s7tr/|
jtu s5|
j	t
jkr7d}trI|rI|t|
dt d q|t|
 qd|}|du s`t|dkrhd| |f }|S d	| || f }|| }|S )
a6  
    Generate a documentation indicating which positional arguments and keyword arguments are set in this
    partial implementation, and appending the wrapped function doc.

    :param wrapped_name:
    :param wrapped_doc:
    :param orig_sig:
    :param new_sig:
    :param preset_pos_args:
    :return:
    FTz=%sr   rQ   Nr   z+<This function is equivalent to '%s(%s)'.>
zH<This function is equivalent to '%s(%s)', see original '%s' doc below.>
)r(  r   ro   r   r   r   r)  r   r*  r   r   r   re   ru   rp   )wrapped_namewrapped_docr   r*   r  all_strskw_onlyr-  r   _ppnew	argstringpartial_docnew_liner   r   r   r   Z  s*   

r   c                   @      e Zd ZdZdS )UnsupportedForCompilationzQ
    Exception raised by @compile_fun when decorated target is not supported
    NrJ   rM   rK   rL   r   r   r   r   r:        r:  c                   @   r9  )UndefinedSymbolErrorz\
    Exception raised by @compile_fun when the function requires a name not yet defined
    Nr;  r   r   r   r   r=    r<  r=  c                   @   r9  )SourceUnavailablezx
    Exception raised by @compile_fun when the function source is not available (inspect.getsource raises an error)
    Nr;  r   r   r   r   r>    r<  r>  c                    s*   t r}t|ddS  fdd}|S )a  
    A draft decorator to `compile` any existing function so that users cant
    debug through it. It can be handy to mask some code from your users for
    convenience (note that this does not provide any obfuscation, people can
    still reverse engineer your code easily. Actually the source code even gets
    copied in the function's `__source__` attribute for convenience):

    ```python
    from makefun import compile_fun

    @compile_fun
    def foo(a, b):
        return a + b

    assert foo(5, -5.0) == 0
    print(foo.__source__)
    ```

    yields

    ```
    @compile_fun
    def foo(a, b):
        return a + b
    ```

    If the function closure includes functions, they are recursively replaced with compiled versions too (only for
    this closure, this does not modify them otherwise).

    **IMPORTANT** this decorator is a "goodie" in early stage and has not been extensively tested. Feel free to
    contribute !

    Note that according to [this post](https://stackoverflow.com/a/471227/7262247) compiling does not make the code
    run any faster.

    Known issues: `NameError` will appear if your function code depends on symbols that have not yet been defined.
    Make sure all symbols exist first ! See https://github.com/smarie/python-makefun/issues/47

    :param recurse: a boolean (default `True`) indicating if referenced symbols should be compiled too
    :param except_names: an optional list of symbols to exclude from compilation when `recurse=True`
    :return:
    T)	_evaldictc                    s   t |  ddS )NTrecurseexcept_namesr?  )compile_fun_manually)targetrB  rA  r   r   apply_compile_fun  s   z&compile_fun.<locals>.apply_compile_fun)callablerC  )rA  rB  rD  rF  r   rE  r   compile_fun  s
   -rH  c              
   C   s  t | ts	td|du s|du r$|du rtdd}nt }t|\}}zt| }W n ttfyD } zdt|v r?t	| | d}~ww z| j
}| j}	W n ty\   | j}| j}	Y nw |r|durt|	j|D ]9\}
}|
|v rrqi|
|vr|td|
 z|j}W n	 ty   Y qiw zt||||d||
< W qi tt	fy   Y qiw t|}|}|d	rd
| dd }d	|v rtd|d d
kr|d
7 }t| jd||}||_|S )z&

    :param target:
    :return:
    z0Only functions can be compiled by this decoratorNTrG   rH   zcould not get source codez|Symbol %s does not seem to be defined yet. Make sure you apply `compile_fun` *after* all required symbols have been defined.r@  z@compile_funr   zA@compile_fun seems to appear several times in the function sourcer  r   )r=   r   r:  r_   ra   r   OSErrorIOErrorre   r>  __closure__r   r   func_closure	func_codezipco_freevarsr=  cell_contentsrd   rC  r   r   rp   
splitlinesrw   rJ   rV   )rD  rA  rB  r?  r|   r   lineserL  rM  rX   cellvaluesource_linesnew_fr   r   r   rC    sl   






rC  )NNNNNFTTNNNN)NFTTNNNNr   )NNNr   NNNr
   )NNNNNNFTTNNN)r   r   r   r  )Tr   )Tr   N)V
__future__r   r>   rerr   r  collectionsr   r   inspectr   keywordr   textwrapr   typesr   rs   re   isidentifierr   r   r   r   ImportErrorfuncsigsr   r!   r"   typingr#   r$   r%   r&   r'   r(   r)   r)  r   
basestringr   r   r:   r@   r   rq   rc   rb   r   rh   rg   intbytesboolr   r   r   rf   rk   rn   ra   rv   countr   rw   rx   r_   r6   r   r   r   r   r  r?   r&  r*  r#  r   ri   r:  r   r=  rI  r>  rH  rC  r   r   r   r   <module>   s  

(
	

 `		6U
&

"
u\
_
k3X-
;