o
    ,wi@                     @  s   d Z ddlmZ ddlZddlZddlZddlmZmZm	Z	m
Z
 e	dZdd Zdd	 Zefd
dZdd ZG dd dZdd ZejG dd dZdd Zdd Ze
dddZd ddZdS )!a
  Functions that generate callable arguments each time they are called.

The `arg_factory` package provides two function wrappers that can be used
to generate parameter values each time a wrapped function is called:

  * `@arg_factory.supply_defaults` is a decorator that defines a "default
    factory" for one or more parameters.  Each time the decorated function
    is called, any missing parameter with a default factory has its value
    filled in by calling the factory.  For example, this can be used to define
    mutable default values for functions, that are created each time the
    function is called.

  * `arg_factory.partial` is a specialized version of `functools.partial`
    that binds parameters to factories rather than values.  These factories
    are used to compute the parameter values each time the partial function
    is called.

## Differences between `supply_defaults` and `partial`

These two wrappers have similar behavior for keyword arguments, but differ in
how they handle factories for positional arguments:

  * When `arg_factory.partial` binds an argument positionally, that argument is
    removed from the signature.  I.e., the wrapper function no longer expects
    that argument.

  * In contrast, `@arg_factory.supply_defaults` does not remove any
    arguments from the signature of the wrapped function.

The wrappers also differ in their restrictions for positional-only
arguments.  Consider a function with signature `f(x, y, /)`:

  * `arg_factory.partial` may be used to define a factory for
    `x` without defining one for `y` (and doing so will "consume" the argument
    `x`); but `@arg_factory.supply_defaults` can not (since non-default
    arguments may not follow default arguments).

  * Conversely, `@arg_factory.supply_defaults` may be used to define a
    factory for `y` without defining one for `x` (and doing so will make `y`
    an optional argument); but `arg_factory.partial` can not (since `y` is a
    positional-only argument, so there's no way to bind it without also binding
    `x`).

A final difference is that `@arg_factory.supply_defaults` may only be used
to provide default factories for positional and keyword parameters in the
wrapped function's signature; it may not be used to add factories for functions
with var-positional (`*args`) or var-keyword (**kwargs`) parameters. But
`arg_factory.partial` *can* be used to provide a default for a var-positional or
var-keyword argument.  E.g.:

>>> def f(**kwargs):
...   print(kwargs)
>>> p = arg_factory.partial(f, x=list)
>>> p(y=3)
{'x': [], y: 3}
    )annotationsN)AnyCallableTypeVaroverloadTc                  O  D   | ^}} dd | D } dd |  D }tjt|g| R i |S )a$  A specialized version of `functools.partial` that binds args to factories.

  `arg_factory.partial` is similar to `functools.partial`, except that it binds
  arguments to *factory functions* rather than *values*.  These factory
  functions are used to construct a value for an argument each time the partial
  is called.

  Example:

  Consider the following code.

  >>> def f(x, noise): return x + noise
  >>> g = functools.partial(f, noise=random.random())
  >>> g(5) == g(5)  # noise has the same value for each call to `g`.
  True

  Here, the value for the `noise` parameter is set when the partial object is
  created, so each call to `g` will use the same value.  If we want a new
  value for each call to the partial, we can use `arg_factory.partial`:

  >>> g = arg_factory.partial(f, noise=random.random)
  >>> g(5) == g(5)  # noise has a new value for each call to g.
  False

  Since we used `arg_factory.partial`, each call to `g` will call the
  `random.random`, and so will use a different value for `noise`.

  If you need to define a partial function that specifies some parameters using
  values and other parameters using factories, then you should do so by
  composing `functools.partial` with `arg_factory.partial`.  E.g.:

  >>> h = functools.partial(arg_factory.partial(f, noise=random.random), x=4)

  Args:
    *args: The function whose arguments should be bound to factories, followed
      by factories for positional arguments to `func`.
    **kwargs: Factories for keyword arguments to `func`.

  Returns:
    A `functools.partial` object.
  c                 S     g | ]}t |qS  
ArgFactory.0argr
   r
   T/home/ubuntu/sommelier/.venv/lib/python3.10/site-packages/fiddle/_src/arg_factory.py
<listcomp>       zpartial.<locals>.<listcomp>c                 S     i | ]	\}}|t |qS r
   r   r   namer   r
   r
   r   
<dictcomp>       zpartial.<locals>.<dictcomp>)items	functoolspartial_InvokeArgFactoryWrapperargskwargsfuncr
   r
   r   r   U   s   *r   c                  O  r   )a@  Version of `functools.partialmethod` that supports binds args to factories.

  `arg_factory.partialmethod` behaves like `arg_factory.partial`, except that it
  is designed to be used as a method definition rather than being directly
  callable.

  See `functools.partialmethod` and `arg_factory.partial` for more details.

  Args:
    *args: The function whose arguments should be bound to factories, followed
      by factories for positional arguments to `func`.
    **kwargs: Factories for keyword arguments to `func`.

  Returns:
    A `functools.partialmethod` object.
  c                 S  r	   r
   r   r   r
   r
   r   r      r   z!partialmethod.<locals>.<listcomp>c                 S  r   r
   r   r   r
   r
   r   r      r   z!partialmethod.<locals>.<dictcomp>)r   r   partialmethodr   r   r
   r
   r   r       s   r    c                 C  s.   t | dt | dt| }|d| d| d)zFRaises a ValueError for an ArgFactory operation that is not supported.__qualname____name__zarg_factory.default_factory(z) does not support z.
`arg_factory.default_factory(...)` should only be used as a default value for a function wrapped with `arg_factory.supply_defaults`; or as an argument to `arg_factory.partial`.
Did you forget to apply the `@arg_factory.supply_defaults` decorator?)getattrrepr)factoryop_type
error_typer   r
   r
   r   _raise_unsupported_op_error   s   r(   c                   s    fdd}|S )z:Returns a function that calls _raise_unsupported_op_error.c                   s   ~~| j }t|  d S N)_factoryr(   )arg_factoryr   r   r%   r&   r
   r   unsupported_op_handler   s   z,_unsupported.<locals>.unsupported_op_handlerr
   )r&   r-   r
   r,   r   _unsupported   s   r.   c                      s  e Zd ZU dZded< ed$dd	Z fd
d	Zd% fddZedd Z	dd Z
dd Zdd ZedZedZedZedZedZedZedZedZedZedZedZedZedZedZedZedZedZedZedZ edZ!edZ"edZ#edZ$edZ%edZ&edZ'edZ(edZ)edZ*edZ+edZ,edZ-edZ.edZ/edZ0edZ1edZ2edZ3edZ4edZ5edZ6edZ7edZ8edZ9edZ:edZ;edZ<edZ=edZ>edZ?edZ@edZAedZBedZCedZDedZEedZFedZGedZHedZIedZJedZKedZLedZMedZNedZOedZPedZQdd ZRd d! ZSd"d# ZT  ZUS )&r   aR  A wrapper indicating that an argument should be computed with a factory.

  This wrapper is used by `arg_factory.partial` to define arguments whose
  value should should be built each time the partial is called.  It is also
  used in as the default value in the signatures for `arg_factory.partial`
  and `arg_factory.supply_defaults`.
  Callable[..., Any]r*   r%   Callable[..., T]returnr   c                 C     d S r)   r
   )clsr%   r
   r
   r   __new__      zArgFactory.__new__c                   s   ~~t  | S r)   )superr4   )r3   r   r   	__class__r
   r   r4      s   c                   s*   t |std|dt d| d S )Nz@Expected arguments to `arg_factory.partial` to be callable. Got .r*   )callable	TypeErrorr6   __setattr__)selfr%   r7   r
   r   __init__   s   zArgFactory.__init__c                 C  s   | j S r)   )r*   r=   r
   r
   r   <lambda>   s    zArgFactory.<lambda>c                 C  s*   t | jdt | jdt| j}d| dS )Nr!   r"   z<built by: z()>)r#   r*   r$   r=   r   r
   r
   r   __repr__   s   zArgFactory.__repr__c                 C  s   t |to
| j|jkS r)   )
isinstancer   r*   )r=   otherr
   r
   r   __eq__      zArgFactory.__eq__c                 C  s
   t | jS r)   )hashr*   r?   r
   r
   r   __hash__   s   
zArgFactory.__hash__zmath operations	iterationlenreversedcontainscallinggetitemsetitemdelitemc                 C  s(   |dkrt n| j}t|d| t d S )Nr*   the attribute )Ellipsisr*   r(   AttributeError)r=   r   r%   r
   r
   r   __getattr__/  s   zArgFactory.__getattr__c                 C  s   t | jd d S )Nzsetting attributesr(   r*   )r=   r   valuer
   r
   r   r<   6  s   zArgFactory.__setattr__c                 C  s   t | jd|  d S )NrQ   rU   rA   r
   r
   r   __delattr__9  rF   zArgFactory.__delattr__r%   r0   r1   r   )r%   r/   )Vr"   
__module__r!   __doc____annotations__r   r4   r>   propertyr%   rB   rE   rH   r.   __ge____gt____le____lt____add____and__
__divmod____floordiv__
__lshift__
__matmul____mod____mul____or____pow__
__rshift____sub____truediv____xor____radd____rand____rdiv____rdivmod____rfloordiv____rlshift____rmatmul____rmod____rmul____ror____rpow____rrshift____rsub____rtruediv____rxor____iadd____iand____ifloordiv____ilshift____imatmul____imod____imul____ior____ipow____irshift____isub____itruediv____ixor____abs____neg____pos__
__invert__	__trunc__	__floor____ceil__	__round____int____bool____nonzero____complex__	__float____iter____next____len____reversed____contains____call____getitem____setitem____delitem__rT   r<   rW   __classcell__r
   r
   r7   r   r      s   
 r   c                 C  s   t | tjtjfot | jtS )zHReturns True if `partial_fn` was constructed with `arg_factory.partial`.)rC   r   r   r    r   r   )
partial_fnr
   r
   r   is_arg_factory_partial=  s
   

r   c                   @  s.   e Zd ZU dZded< dd Zedd ZdS )	r   a   Function wrapper that invokes the factories of ArgFactory args.

  When called, this wrapper transforms the arguments by replacing each
  `ArgFactory` argument `x` with `x.factory()`; and then calls the wrapped
  function with the transformed arguments.
  r/   r   c                 O  s4   t dd |D }dd | D }| j|i |S )Nc                 s  s    | ]}t |V  qd S r)   _arg_factory_valuer   r
   r
   r   	<genexpr>P  s    z4_InvokeArgFactoryWrapper.__call__.<locals>.<genexpr>c                 S  r   r
   r   )r   keyr   r
   r
   r   r   Q  r   z5_InvokeArgFactoryWrapper.__call__.<locals>.<dictcomp>)tupler   r   )r=   r   r   r
   r
   r   r   O  s   z!_InvokeArgFactoryWrapper.__call__c                 C  s   t | jS r)   )inspect	signaturer   r?   r
   r
   r   __signature__T  s   z&_InvokeArgFactoryWrapper.__signature__N)r"   rY   r!   rZ   r[   r   r\   r   r
   r
   r
   r   r   D  s   
 r   c                 C  s   t | tr	|  S | S r)   )rC   r   r%   )rV   r
   r
   r   r   Y  rF   r   c                   sH   t dd j D   stdt fdd}|S )a  Decorator that defines default factories for a function's parameters.

  Each time the decorated function is called, any missing parameter with a
  default factory has its value filled in by calling the factory.  Default
  factories are specified by setting the default value of a parameter to
  `arg_factory.default_factory(<factory>)`.

  For example, this can be used to define mutable default values for functions,
  that are created each time the function is called:

  >>> @arg_factory.supply_defaults
  ... def append(elt, seq: list[Any] = arg_factory.default_factory(list)):
  ...   seq.append(elt)
  ...   return seq

  This decorator can also be used in other contexts where the default value
  for a parameter should be computed each time the function is called.  E.g.:

  >>> @arg_factory.supply_defaults
  ... def add_noise(value, noise = arg_factory.default_factory(random.random)):
  ...   return value + noise**2

  This decorator uses `functools.wraps` to copy fields such as `__name__` and
  `__doc__` from the wrapped function to the wrapper function.

  Args:
    wrapped_func: The function that should be decorated.

  Returns:
    The decorated function.
  c                 S  s$   i | ]}t |jtr|j|jjqS r
   )rC   defaultr   r   r%   )r   paramr
   r
   r   r   ~  s    

z#supply_defaults.<locals>.<dictcomp>zi@supply_defaults expected at least one argument to have a default value constructed with default_factory.c                    sJ   j | i |}  D ]\}}||jvr| |j|< q|ji |jS r)   )bindr   	argumentsr   r   )r   r   
bound_argsr   r%   	factoriesr   wrapped_funcr
   r   wrapper  s   
z supply_defaults.<locals>.wrapper)r   r   
parametersvalues
ValueErrorr   wraps)r   r   r
   r   r   supply_defaults]  s   
 r   r%   r0   r1   c                 C  r2   r)   r
   r%   r
   r
   r   default_factory  r5   r   r/   c                 C  s   t | S )a  Returns a value used to declare the default factory for a parameter.

  `default_factory` should be used in conjuction with the `@supply_defaults`
  decorator to declare default factories for a function's parameters.  See
  the documentation for `supply_defaults` for more information.

  Args:
    factory: The factory that should be used to construct the value for a
      parameter.  This factory is called each time the function is called.
  r   r   r
   r
   r   r     s   rX   )r%   r/   r1   r   )rZ   
__future__r   dataclassesr   r   typingr   r   r   r   r   r   r    r   r(   r.   r   r   	dataclassr   r   r   r   r
   r
   r
   r   <module>   s*   90 ;