a
    IDg%                     @   s   d Z ddlZddlZddlZddlZddlZddlZddlZddlm	Z	 e
eZdZdd Zdd Zd	d
 Zdd ZG dd dejZdS )aY  
Support for deprecation warnings when importing names from old locations.

When software evolves, things tend to move around. This is usually detrimental
to backwards compatibility (in Python this primarily manifests itself as
:exc:`~exceptions.ImportError` exceptions).

While backwards compatibility is very important, it should not get in the way
of progress. It would be great to have the agility to move things around
without breaking backwards compatibility.

This is where the :mod:`humanfriendly.deprecation` module comes in: It enables
the definition of backwards compatible aliases that emit a deprecation warning
when they are accessed.

The way it works is that it wraps the original module in an :class:`DeprecationProxy`
object that defines a :func:`~DeprecationProxy.__getattr__()` special method to
override attribute access of the module.
    N)format)DeprecationProxydefine_aliasesdeprecated_argsget_aliases	is_methodc                 K   sr   t j|  }t||}| D ]\}}|t|j |< qdt jv rd| D ]\}}t|||| qFn
|t j| < dS )a  
    Update a module with backwards compatible aliases.

    :param module_name: The ``__name__`` of the module (a string).
    :param aliases: Each keyword argument defines an alias. The values
                    are expected to be "dotted paths" (strings).

    The behavior of this function depends on whether the Sphinx documentation
    generator is active, because the use of :class:`DeprecationProxy` to shadow the
    real module in :data:`sys.modules` has the unintended side effect of
    breaking autodoc support for ``:data:`` members (module variables).

    To avoid breaking Sphinx the proxy object is omitted and instead the
    aliased names are injected into the original module namespace, to make sure
    that imports can be satisfied when the documentation is being rendered.

    If you run into cyclic dependencies caused by :func:`define_aliases()` when
    running Sphinx, you can try moving the call to :func:`define_aliases()` to
    the bottom of the Python module you're working on.
    ZsphinxN)sysmodulesr   itemsREGISTRY__name__setattrresolve)module_namealiasesmoduleproxynametarget r   j/mounts/lovelace/software/anaconda3/envs/paleomix/lib/python3.9/site-packages/humanfriendly/deprecation.pyr   .   s    


r   c                 C   s   t | i S )a  
    Get the aliases defined by a module.

    :param module_name: The ``__name__`` of the module (a string).
    :returns: A dictionary with string keys and values:

              1. Each key gives the name of an alias
                 created for backwards compatibility.

              2. Each value gives the dotted path of
                 the proper location of the identifier.

              An empty dictionary is returned for modules that
              don't define any backwards compatible aliases.
    )r   get)r   r   r   r   r   Q   s    r   c                     s    fdd}|S )a=  
    Deprecate positional arguments without dropping backwards compatibility.

    :param names:

      The positional arguments to :func:`deprecated_args()` give the names of
      the positional arguments that the to-be-decorated function should warn
      about being deprecated and translate to keyword arguments.

    :returns: A decorator function specialized to `names`.

    The :func:`deprecated_args()` decorator function was created to make it
    easy to switch from positional arguments to keyword arguments [#]_ while
    preserving backwards compatibility [#]_ and informing call sites
    about the change.

    .. [#] Increased flexibility is the main reason why I find myself switching
           from positional arguments to (optional) keyword arguments as my code
           evolves to support more use cases.

    .. [#] In my experience positional argument order implicitly becomes part
           of API compatibility whether intended or not. While this makes sense
           for functions that over time adopt more and more optional arguments,
           at a certain point it becomes an inconvenience to code maintenance.

    Here's an example of how to use the decorator::

      @deprecated_args('text')
      def report_choice(**options):
          print(options['text'])

    When the decorated function is called with positional arguments
    a deprecation warning is given::

      >>> report_choice('this will give a deprecation warning')
      DeprecationWarning: report_choice has deprecated positional arguments, please switch to keyword arguments
      this will give a deprecation warning

    But when the function is called with keyword arguments no deprecation
    warning is emitted::

      >>> report_choice(text='this will not give a deprecation warning')
      this will not give a deprecation warning
    c                    sL    fddt  r0t  fdd}nt  fdd}|S )Nc                    sl   t | t kr.ttd jt t | d| rLtjtd jdtdd t| D ]\}}|||< qVd S )Nz6{name} expected at most {limit} arguments, got {count})r   limitcountzN{name} has deprecated positional arguments, please switch to keyword argumentsr      category
stacklevel)len	TypeErrorr   r   warningswarnDeprecationWarningzip)argskwr   value)functionnamesr   r   	translate   s(    		z5deprecated_args.<locals>.decorator.<locals>.translatec                     s,   t | } | d}| |  |fi |S )zWrapper for instance methods.r   )listpop)r%   r&   selfr(   r*   r   r   wrapper   s    

z3deprecated_args.<locals>.decorator.<locals>.wrapperc                     s   | |  f i |S )z#Wrapper for module level functions.r   )r%   r&   r.   r   r   r/      s    
)r   	functoolswraps)r(   r/   r)   r.   r   	decorator   s    z"deprecated_args.<locals>.decoratorr   )r)   r3   r   r2   r   r   d   s    -(r   c                 C   sB   zt | }d|jv W S  ty<   t | }d|jv  Y S 0 dS )zKCheck if the expected usage of the given function is as an instance method.r-   N)inspect	signature
parametersAttributeError
getargspecr%   )r(   r5   metadatar   r   r   r      s    

r   c                       s0   e Zd ZdZ fddZdd Zdd Z  ZS )r   z=Emit deprecation warnings for imports that should be updated.c                    s$   t t| j|jd || _|| _dS )z
        Initialize an :class:`DeprecationProxy` object.

        :param module: The original module object.
        :param aliases: A dictionary of aliases.
        r   N)superr   __init__r   r   r   )r-   r   r   	__class__r   r   r;      s    zDeprecationProxy.__init__c                 C   sn   | j |}|dur<tjtd| jj||tdd | |S t	| j|d}|durV|S t
td| jj|dS )z
        Override module attribute lookup.

        :param name: The name to look up (a string).
        :returns: The attribute value.
        Nz1%s.%s was moved to %s, please update your imports   r   z!module '%s' has no attribute '%s')r   r   r!   r"   r   r   r   r#   r   getattrr7   )r-   r   r   r'   r   r   r   __getattr__   s    
zDeprecationProxy.__getattr__c                 C   s$   | d\}}}t|}t||S )z
        Look up the target of an alias.

        :param target: The fully qualified dotted path (a string).
        :returns: The value of the given target.
        .)
rpartition	importlibimport_moduler?   )r-   r   r   _memberr   r   r   r   r      s    
zDeprecationProxy.resolve)r   
__module____qualname____doc__r;   r@   r   __classcell__r   r   r<   r   r      s   r   )rI   collectionsr0   rC   r4   r   typesr!   Zhumanfriendly.textr   defaultdictdictr   __all__r   r   r   r   
ModuleTyper   r   r   r   r   <module>   s   
#X