o
    Th                     @   s  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m	Z	m
Z
 d dlmZ d dlmZmZmZmZmZmZmZ ddlmZ dd	lmZmZ dd
lmZ ddlmZ ddlmZmZ zd dl m!Z! W n e"yw   d dl#m$Z! Y nw de%de%dee%ef fddZ&G dd dZ'G dd de'Z(G dd de)Z*dee%ef dee%ef dee%ef fddZ+de,de,de*fd d!Z-d"e,de%fd#d$Z.d%ee%ef dee%ef fd&d'Z/d(ee%ef d)ee%d*f ddfd+d,Z0dee%ef d-ee%ef ddfd.d/Z1dS )0    N)spec_from_loader)PathLike)joinsplitext
expanduser)
ModuleType)AnyDictIteratorOptionalTupleTypeUnion   )Environment)UnknownFileTypeUnpicklableConfigMember)Local)WINDOWS)debugyaml)SourceFileLoader)_SourceFileLoadernamepathreturnc                 C   s@   t j|si S td|}td}td||_|| t|S )Nmod)	osr   existsr   r   r   __spec__exec_modulevars)r   r   loaderr    r#   @/var/www/html/venv/lib/python3.10/site-packages/invoke/config.pyload_source   s   

r%   c                
       s  e Zd ZdZed edd d D  Zede fdee	e
f ded  d	ee	d
f dd fddZde	de
fddZde	de
ddf fddZdeee	e
f  fddZdedefddZdefddZde	de	ddfddZde	de
fddZde	de
fdd Zd!e
d"e
ddfd#d$Zde	fd%d&Zde	defd'd(Zedefd)d*Zedefd+d,Zde	ddfd-d.Z de	de	ddfd/d0Z!de	ddfd1d2Z"d3e	ddfd4d5Z#d@d6d7Z$d!e
de
fd8d9Z%de
fd:d;Z&d!e
de
fd<d=Z'd!e
d"e
ddfd>d?Z(  Z)S )A	DataProxya  
    Helper class implementing nested dict+attr access for `.Config`.

    Specifically, is used both for `.Config` itself, and to wrap any other
    dicts assigned as config values (recursively).

    .. warning::
        All methods (of this object or in subclasses) must take care to
        initialize new attributes via ``self._set(name='value')``, or they'll
        run into recursion errors!

    .. versionadded:: 1.0
    z
        get
        has_key
        items
        iteritems
        iterkeys
        itervalues
        keys
        values
    c                 c   s    | ]}d  |V  qdS )z__{}__N)format.0xr#   r#   r$   	<genexpr>A   s
    
zDataProxy.<genexpr>z>
        cmp
        contains
        iter
        sizeof
    Ndatarootkeypath.r   c                 C   s.   |  }|j |d |j |d |j |d |S )a  
        Alternate constructor for 'baby' DataProxies used as sub-dict values.

        Allows creating standalone DataProxy objects while also letting
        subclasses like `.Config` define their own ``__init__`` without
        muddling the two.

        :param dict data:
            This particular DataProxy's personal data. Required, it's the Data
            being Proxied.

        :param root:
            Optional handle on a root DataProxy/Config which needs notification
            on data updates.

        :param tuple keypath:
            Optional tuple describing the path of keys leading to this
            DataProxy's location inside the ``root`` structure. Required if
            ``root`` was given (and vice versa.)

        .. versionadded:: 1.0
        _config)_root)_keypath_set)clsr,   r-   r.   objr#   r#   r$   	from_dataL   s
   zDataProxy.from_datakeyc              
   C   s   z|  |W S  tyB   || jv rt| j| Y S d|}dd t| jD }|dtt	| j
 7 }|d|7 }t|w )Nz)No attribute or config key found for {!r}c                 S   s   g | ]	}| d s|qS )_)
startswithr(   r#   r#   r$   
<listcomp>|   s    z)DataProxy.__getattr__.<locals>.<listcomp>z

Valid keys: {!r}z

Valid real attributes: {!r})_getKeyError_proxiesgetattrr0   r'   dir	__class__sortedlistkeysAttributeError)selfr8   errattrsr#   r#   r$   __getattr__o   s   

zDataProxy.__getattr__valuec                    s.   |t | v }|s|| |< d S t || d S N)r@   super__setattr__)rF   r8   rJ   has_real_attrrA   r#   r$   rM      s   zDataProxy.__setattr__c                 C   
   t | jS rK   )iterr0   rF   r#   r#   r$   __iter__   s   
zDataProxy.__iter__otherc                 C   s(   t |dd }t|tr|}t| j|kS )Nr0   )r?   
isinstancedictboolr0   )rF   rT   	other_valr#   r#   r$   __eq__   s   
zDataProxy.__eq__c                 C   rP   rK   )lenr0   rR   r#   r#   r$   __len__      
zDataProxy.__len__c                 C   s   || j |< | || d S rK   )r0   _track_modification_of)rF   r8   rJ   r#   r#   r$   __setitem__   s   
zDataProxy.__setitem__c                 C   s
   |  |S rK   )r<   rF   r8   r#   r#   r$   __getitem__   r\   zDataProxy.__getitem__c                 C   s^   |dv rt || j| }t|tr-|f}t| dr| j| }t| d| }tj|||d}|S )N)__setstate__r2   r1   )r,   r-   r.   )	rE   r0   rU   rV   hasattrr2   r?   r&   r7   )rF   r8   rJ   r.   r-   r#   r#   r$   r<      s   



zDataProxy._getargskwargsc                 O   s:   |rt j| g|R   | D ]\}}t | || qdS )a  
        Convenience workaround of default 'attrs are config keys' behavior.

        Uses `object.__setattr__` to work around the class' normal proxying
        behavior, but is less verbose than using that directly.

        Has two modes (which may be combined if you really want):

        - ``self._set('attrname', value)``, just like ``__setattr__``
        - ``self._set(attname=value)`` (i.e. kwargs), even less typing.
        N)objectrM   items)rF   rc   rd   r8   rJ   r#   r#   r$   r4      s
   zDataProxy._setc                 C   s   d | jj| jS )Nz<{}: {}>)r'   rA   __name__r0   rR   r#   r#   r$   __repr__   s   zDataProxy.__repr__c                 C   s
   || j v S rK   r/   r_   r#   r#   r$   __contains__   r\   zDataProxy.__contains__c                 C   
   t | dS )Nr1   rb   rR   r#   r#   r$   _is_leaf      
zDataProxy._is_leafc                 C   rj   )N_modifyrk   rR   r#   r#   r$   _is_root   rm   zDataProxy._is_rootc                 C   sB   d }| j r	| j}n| jr| }|d ur|t| dt | d S d S Nr2   )rl   r1   ro   _remover?   tuple)rF   r8   targetr#   r#   r$   _track_removal_of   s   zDataProxy._track_removal_ofc                 C   sD   d }| j r	| j}n| jr| }|d ur |t| dt || d S d S rp   )rl   r1   ro   rn   r?   rr   )rF   r8   rJ   rs   r#   r#   r$   r]      s   z DataProxy._track_modification_ofc                 C   s   | j |= | | d S rK   )r0   rt   r_   r#   r#   r$   __delitem__   s   zDataProxy.__delitem__r   c                 C   s"   || v r	| |= d S t | | d S rK   )re   __delattr__)rF   r   r#   r#   r$   rv      s   
zDataProxy.__delattr__c                 C   s    t |  }|D ]}| |= qd S rK   )rC   rD   )rF   rD   r8   r#   r#   r$   clear   s   zDataProxy.clearc                 G   s8   |o|d | j v }| j j| }|s|S | |d  |S Nr   )r0   poprt   )rF   rc   key_existedretr#   r#   r$   ry     s   zDataProxy.popc                 C   s   | j  }| |d  |S rx   )r0   popitemrt   )rF   r{   r#   r#   r$   r|     s   
zDataProxy.popitemc                 G   s>   |o|d | j v }| j j| }|r|S |\}}| || |S rx   )r0   
setdefaultr]   )rF   rc   rz   r{   r8   defaultr#   r#   r$   r}     s   zDataProxy.setdefaultc                 O   st   |r|  D ]\}}|| |< qd S |r6|d }t|tr)|D ]}|| | |< qd S |D ]}|d | |d < q+d S d S )Nr   r   )rf   rU   rV   )rF   rc   rd   r8   rJ   argpairr#   r#   r$   update)  s   

zDataProxy.updater   N)*rg   
__module____qualname____doc__rr   splitr>   classmethodr	   strr   r   r   r7   rI   rM   r
   rS   re   rW   rY   intr[   r^   r`   r<   r4   rh   ri   propertyrl   ro   rt   r]   ru   rv   rw   ry   r|   r}   r   __classcell__r#   r#   rO   r$   r&   $   s`    	

"	
r&   c                   @   s  e Zd ZdZdZdZdZedee	e
f fddZ							dHdeee	e
f  d	eee	e
f  d
ee	 dee	 dee dee defddZdIddZdJdee	e
f deddfddZdJdee	e
f deddfddZdJdeddfddZdJdeddfddZdJdeddfddZd ee ddfd!d"ZdJdeddfd#d$ZdId%d&Z	dJdee	e
f deddfd'd(Zd eee	df ddfd)d*Z	dKd+e	d,ededdfd-d.Zd ede
fd/d0ZeZd ede
fd1d2Zd e	dee	e
f fd3d4Z dId5d6Z!d7e	d8e	ddfd9d:Z"dLd;ee#d   dd fd<d=Z$	dLd;ee#d   dee	e
f fd>d?Z%d@e&e	dAf dBe	dCe	ddfdDdEZ'd@e&e	dAf dBe	ddfdFdGZ(dS )MConfigaT  
    Invoke's primary configuration handling class.

    See :doc:`/concepts/configuration` for details on the configuration system
    this class implements, including the :ref:`configuration hierarchy
    <config-hierarchy>`. The rest of this class' documentation assumes
    familiarity with that document.

    **Access**

    Configuration values may be accessed and/or updated using dict syntax::

        config['foo']

    or attribute syntax::

        config.foo

    Nesting works the same way - dict config values are turned into objects
    which honor both the dictionary protocol and the attribute-access method::

       config['foo']['bar']
       config.foo.bar

    **A note about attribute access and methods**

    This class implements the entire dictionary protocol: methods such as
    ``keys``, ``values``, ``items``, ``pop`` and so forth should all function
    as they do on regular dicts. It also implements new config-specific methods
    such as `load_system`, `load_collection`, `merge`, `clone`, etc.

    .. warning::
        Accordingly, this means that if you have configuration options sharing
        names with these methods, you **must** use dictionary syntax (e.g.
        ``myconfig['keys']``) to access the configuration data.

    **Lifecycle**

    At initialization time, `.Config`:

    - creates per-level data structures;
    - stores any levels supplied to `__init__`, such as defaults or overrides,
      as well as the various config file paths/filename patterns;
    - and loads config files, if found (though typically this just means system
      and user-level files, as project and runtime files need more info before
      they can be found and loaded.)

        - This step can be skipped by specifying ``lazy=True``.

    At this point, `.Config` is fully usable - and because it pre-emptively
    loads some config files, those config files can affect anything that
    comes after, like CLI parsing or loading of task collections.

    In the CLI use case, further processing is done after instantiation, using
    the ``load_*`` methods such as `load_overrides`, `load_project`, etc:

    - the result of argument/option parsing is applied to the overrides level;
    - a project-level config file is loaded, as it's dependent on a loaded
      tasks collection;
    - a runtime config file is loaded, if its flag was supplied;
    - then, for each task being executed:

        - per-collection data is loaded (only possible now that we have
          collection & task in hand);
        - shell environment data is loaded (must be done at end of process due
          to using the rest of the config as a guide for interpreting env var
          names.)

    At this point, the config object is handed to the task being executed, as
    part of its execution `.Context`.

    Any modifications made directly to the `.Config` itself after this point
    end up stored in their own (topmost) config level, making it easier to
    debug final values.

    Finally, any *deletions* made to the `.Config` (e.g. applications of
    dict-style mutators like ``pop``, ``clear`` etc) are also tracked in their
    own structure, allowing the config object to honor such method calls
    without mutating the underlying source data.

    **Special class attributes**

    The following class-level attributes are used for low-level configuration
    of the config system itself, such as which file paths to load. They are
    primarily intended for overriding by subclasses.

    - ``prefix``: Supplies the default value for ``file_prefix`` (directly) and
      ``env_prefix`` (uppercased). See their descriptions for details. Its
      default value is ``"invoke"``.
    - ``file_prefix``: The config file 'basename' default (though it is not a
      literal basename; it can contain path parts if desired) which is appended
      to the configured values of ``system_prefix``, ``user_prefix``, etc, to
      arrive at the final (pre-extension) file paths.

      Thus, by default, a system-level config file path concatenates the
      ``system_prefix`` of ``/etc/`` with the ``file_prefix`` of ``invoke`` to
      arrive at paths like ``/etc/invoke.json``.

      Defaults to ``None``, meaning to use the value of ``prefix``.

    - ``env_prefix``: A prefix used (along with a joining underscore) to
      determine which environment variables are loaded as the env var
      configuration level. Since its default is the value of ``prefix``
      capitalized, this means env vars like ``INVOKE_RUN_ECHO`` are sought by
      default.

      Defaults to ``None``, meaning to use the value of ``prefix``.

    .. versionadded:: 1.0
    invokeNr   c               
   C   s   t r
tjdd} nd} i ddddddddd	d
dd
di dd
dddd
dd
dd
ddddddd| dddg idtid
dd
ddddd
dd
ddd
id S )!a  
        Return the core default settings for Invoke.

        Generally only for use by `.Config` internals. For descriptions of
        these values, see :ref:`default-values`.

        Subclasses may choose to override this method, calling
        ``Config.global_defaults`` and applying `.merge_dicts` to the result,
        to add to or modify these values.

        .. versionadded:: 1.0
        COMSPECzcmd.exez	/bin/bashasynchronousFdisowndryecho
echo_stdinNencodingenv
err_streamfallbackThide	in_stream
out_streamecho_formatz[1;37m{command}[0mptyreplace_envshellwarnwatcherslocalz[sudo] password: )passwordpromptusertasks)auto_dash_namescollection_namededupeexecutor_classignore_unknown_helpsearch_rootcommand)runrunnerssudor   timeouts)r   r   environgetr   )r   r#   r#   r$   global_defaults  sl   	
zConfig.global_defaultsF	overridesdefaultssystem_prefixuser_prefixproject_locationruntime_pathlazyc           	      C   sV  | j i d | j dd |du rt|  }| j |d | j i d |du r*ts*d}| j |d | j dd	 | j dd
 | j i d |du rHd}| j |d | j dd | j dd | j i d | | | j}|du ro| j}d| }| j |d | j i d | 	| |du ri }| j |d | j i d | j i d |s| 
  |   dS )a  
        Creates a new config object.

        :param dict defaults:
            A dict containing default (lowest level) config data. Default:
            `global_defaults`.

        :param dict overrides:
            A dict containing override-level config data. Default: ``{}``.

        :param str system_prefix:
            Base path for the global config file location; combined with the
            prefix and file suffixes to arrive at final file path candidates.

            Default: ``/etc/`` (thus e.g. ``/etc/invoke.yaml`` or
            ``/etc/invoke.json``).

        :param str user_prefix:
            Like ``system_prefix`` but for the per-user config file. These
            variables are joined as strings, not via path-style joins, so they
            may contain partial file paths; for the per-user config file this
            often means a leading dot, to make the final result a hidden file
            on most systems.

            Default: ``~/.`` (e.g. ``~/.invoke.yaml``).

        :param str project_location:
            Optional directory path of the currently loaded `.Collection` (as
            loaded by `.Loader`). When non-empty, will trigger seeking of
            per-project config files in this directory.

        :param str runtime_path:
            Optional file path to a runtime configuration file.

            Used to fill the penultimate slot in the config hierarchy. Should
            be a full file path to an existing file, not a directory path or a
            prefix.

        :param bool lazy:
            Whether to automatically load some of the lower config levels.

            By default (``lazy=False``), ``__init__`` automatically calls
            `load_system` and `load_user` to load system and user config files,
            respectively.

            For more control over what is loaded when, you can say
            ``lazy=True``, and no automatic loading is done.

            .. note::
                If you give ``defaults`` and/or ``overrides`` as ``__init__``
                kwargs instead of waiting to use `load_defaults` or
                `load_overrides` afterwards, those *will* still end up 'loaded'
                immediately.
        r/   )r   ymljsonpy)_file_suffixesN	_defaults_collectionz/etc/)_system_prefix)_system_path)_system_found)_systemz~/.)_user_prefix)
_user_path)_user_found)_userz{}_)_env_prefix_env
_overrides)_modifications)
_deletions)r4   	copy_dictr   r   set_project_location
env_prefixprefixr'   upperset_runtime_pathload_base_conf_filesmerge)	rF   r   r   r   r   r   r   r   r   r#   r#   r$   __init__   sD   B

zConfig.__init__c                 C   s   | j dd | jdd d S )NF)r   )load_system	load_userrR   r#   r#   r$   r     s   zConfig.load_base_conf_filesTr,   r   c                 C       | j |d |r|   dS dS )aZ  
        Set or replace the 'defaults' configuration level, from ``data``.

        :param dict data: The config data to load as the defaults level.

        :param bool merge:
            Whether to merge the loaded data into the central config. Default:
            ``True``.

        :returns: ``None``.

        .. versionadded:: 1.0
        r   Nr4   r   rF   r,   r   r#   r#   r$   load_defaults     zConfig.load_defaultsc                 C   r   )a\  
        Set or replace the 'overrides' configuration level, from ``data``.

        :param dict data: The config data to load as the overrides level.

        :param bool merge:
            Whether to merge the loaded data into the central config. Default:
            ``True``.

        :returns: ``None``.

        .. versionadded:: 1.0
        r   Nr   r   r#   r#   r$   load_overrides  r   zConfig.load_overridesc                 C      | j d|d dS )a  
        Load a system-level config file, if possible.

        Checks the configured ``_system_prefix`` path, which defaults to
        ``/etc``, and will thus load files like ``/etc/invoke.yml``.

        :param bool merge:
            Whether to merge the loaded data into the central config. Default:
            ``True``.

        :returns: ``None``.

        .. versionadded:: 1.0
        systemr   r   N
_load_filerF   r   r#   r#   r$   r        zConfig.load_systemc                 C   r   )a  
        Load a user-level config file, if possible.

        Checks the configured ``_user_prefix`` path, which defaults to ``~/.``,
        and will thus load files like ``~/.invoke.yml``.

        :param bool merge:
            Whether to merge the loaded data into the central config. Default:
            ``True``.

        :returns: ``None``.

        .. versionadded:: 1.0
        r   r   Nr   r   r#   r#   r$   r     r   zConfig.load_userc                 C   r   )a  
        Load a project-level config file, if possible.

        Checks the configured ``_project_prefix`` value derived from the path
        given to `set_project_location`, which is typically set to the
        directory containing the loaded task collection.

        Thus, if one were to run the CLI tool against a tasks collection
        ``/home/myuser/code/tasks.py``, `load_project` would seek out files
        like ``/home/myuser/code/invoke.yml``.

        :param bool merge:
            Whether to merge the loaded data into the central config. Default:
            ``True``.

        :returns: ``None``.

        .. versionadded:: 1.0
        projectr   Nr   r   r#   r#   r$   load_project  s   zConfig.load_projectr   c                 C   s(   | j |d | j i d | j dd dS )zR
        Set the runtime config file path.

        .. versionadded:: 1.0
        )_runtime_path)_runtimeN)_runtime_foundr3   )rF   r   r#   r#   r$   r     s   zConfig.set_runtime_pathc                 C   s   | j dd|d dS )a  
        Load a runtime-level config file, if one was specified.

        When the CLI framework creates a `Config`, it sets ``_runtime_path``,
        which is a full path to the requested config file. This method attempts
        to load that file.

        :param bool merge:
            Whether to merge the loaded data into the central config. Default:
            ``True``.

        :returns: ``None``.

        .. versionadded:: 1.0
        runtimeT)r   absoluter   Nr   r   r#   r#   r$   load_runtime   s   zConfig.load_runtimec                 C   sL   t d |   t d t| j| jd}| j| d t d |   dS )a  
        Load values from the shell environment.

        `.load_shell_env` is intended for execution late in a `.Config`
        object's lifecycle, once all other sources (such as a runtime config
        file or per-collection configurations) have been loaded. Loading from
        the shell is not terrifically expensive, but must be done at a specific
        point in time to ensure the "only known config keys are loaded from the
        env" behavior works correctly.

        See :ref:`env-vars` for details on this design decision and other info
        re: how environment variables are scanned and loaded.

        .. versionadded:: 1.0
        z*Running pre-merge for shell env loading...zDone with pre-merge.)configr   r   z0Loaded shell environment, triggering final mergeN)r   r   r   r0   r   r4   load)rF   r"   r#   r#   r$   load_shell_env  s   zConfig.load_shell_envc                 C   s(   t d | j|d |r|   dS dS )a(  
        Update collection-driven config data.

        `.load_collection` is intended for use by the core task execution
        machinery, which is responsible for obtaining collection-driven data.
        See :ref:`collection-configuration` for details.

        .. versionadded:: 1.0
        z Loading collection configurationr   N)r   r4   r   r   r#   r#   r$   load_collection+  s
   zConfig.load_collectionc                 C   sJ   d}|durt |d}| j|d | jdd | jdd | ji d dS )z
        Set the directory path where a project-level config file may be found.

        Does not do any file loading on its own; for that, see `load_project`.

        .. versionadded:: 1.0
        N )_project_prefix)_project_path)_project_found)_project)r   r4   )rF   r   project_prefixr#   r#   r$   r   <  s   	
zConfig.set_project_locationr   r   c                    s  d |}d |}d |}| j  d u r| j t| |d ur"d S |r3t| |}|d u r/d S |g}nt| d |d u rAd S  fdd| jD }|D ]f}	t|	}	z>zt|	d d}
t| d	 |
}W n ty{   d
}t	| |
|	| jw | 
|||	 | 
||	 | 
|d W  n" ty } z|jdkrd}t| |	 n W Y d }~qNd }~ww t| |d u r| 
|d d S |r|   d S d S )N	_{}_found_{}_path_{}z
_{}_prefixc                    s   g | ]}d    |fqS ).)r   r(   midfixpath_prefixr#   r$   r;   l  s    z%Config._load_file.<locals>.<listcomp>r   r   z_load_{}zUConfig files of type {!r} (from file {!r}) are not supported! Please use one of: {!r}T   zDidn't see any {}, skipping.F)r'   file_prefixr   r?   r   r   r   lstriprE   r   r4   IOErrorerrnor   r   )rF   r   r   r   foundr   r,   absolute_pathpathsfilepathtype_r"   msgerG   r#   r   r$   r   R  s`   




zConfig._load_filec                 C   6   t |}t|W  d    S 1 sw   Y  d S rK   )openr   	safe_loadrF   r   fdr#   r#   r$   
_load_yaml     
$zConfig._load_yamlc                 C   r  rK   )r  r   r   r  r#   r#   r$   
_load_json  r  zConfig._load_jsonc                 C   sR   i }t d| D ]\}}|drq	t|tjr"d}t|||||< q	|S )Nr   __z'{}' is a module, which can't be used as a config value. (Are you perhaps giving a tasks file instead of a config file by mistake?))r%   rf   r:   rU   typesr   r   r'   )rF   r   r,   r8   rJ   rG   r#   r#   r$   _load_py  s   

zConfig._load_pyc                 C   s   t d | ji d t d| j t| j| j t d| j t| j| j | dd | dd | d	d
 t d| j t| j| j | dd t d| j	 t| j| j	 t d| j
 t| j| j
 t d| j t| j| j dS )zT
        Merge all config sources, in order.

        .. versionadded:: 1.0
        z9Merging config sources in order onto new empty _config...r/   zDefaults: {!r}zCollection-driven: {!r}r   zSystem-wider   zPer-userr   zPer-projectz!Environment variable config: {!r}r   RuntimezOverrides: {!r}zModifications: {!r}zDeletions: {!r}N)r   r4   r'   r   merge_dictsr0   r   _merge_filer   r   r   r   
obliteraterR   r#   r#   r$   r     s$   zConfig.merger   descc                 C   s   |d7 }t | d|}t | d|}t | d|}|d u r)td| d S |r<td||| t| j| d S td| d S )Nz config filer   r   r   z${} has not been loaded yet, skippingz{} ({}): {!r}z{} not found, skipping)r?   r'   r   r  r0   )rF   r   r  r  r   r,   r#   r#   r$   r    s   zConfig._merge_fileintoc                 C   s   |du r| j n|}|di | j|d}d D ]#}d|}t| |}t|ts3||t| qt	t||| q|
  |  |S )a  
        Return a copy of this configuration object.

        The new object will be identical in terms of configured sources and any
        loaded (or user-manipulated) data, but will be a distinct object with
        as little shared mutable state as possible.

        Specifically, all `dict` values within the config are recursively
        recreated, with non-dict leaf values subjected to `copy.copy` (note:
        *not* `copy.deepcopy`, as this can cause issues with various objects
        such as compiled regexen or threading locks, often found buried deep
        within rich aggregates like API or DB clients).

        The only remaining config values that may end up shared between a
        config and its clone are thus those 'rich' objects that do not
        `copy.copy` cleanly, or compound non-dict objects (such as lists or
        tuples).

        :param into:
            A `.Config` subclass that the new clone should be "upgraded" to.

            Used by client libraries which have their own `.Config` subclasses
            that e.g. define additional defaults; cloning "into" one of these
            subclasses ensures that any new keys/subtrees are added gracefully,
            without overwriting anything that may have been pre-defined.

            Default: ``None`` (just clone into another regular `.Config`).

        :returns:
            A `.Config`, or an instance of the class given to ``into``.

        .. versionadded:: 1.0
        N)r  a  
            collection
            system_prefix
            system_path
            system_found
            system
            user_prefix
            user_path
            user_found
            user
            project_prefix
            project_path
            project_found
            project
            env_prefix
            env
            runtime_path
            runtime_found
            runtime
            overrides
            modifications
        r   r#   )rA   _clone_init_kwargsr   r'   r?   rU   rV   r4   copyr  r   r   )rF   r  klassnewr   my_datar#   r#   r$   clone  s   #



zConfig.clonec                 C   s,   t | j}|durt||  t|ddS )a  
        Supply kwargs suitable for initializing a new clone of this object.

        Note that most of the `.clone` process involves copying data between
        two instances instead of passing init kwargs; however, sometimes you
        really do want init kwargs, which is why this method exists.

        :param into: The value of ``into`` as passed to the calling `.clone`.

        :returns: A `dict`.
        NT)r   r   )r   r   r  r   rV   )rF   r  new_defaultsr#   r#   r$   r   1  s   
zConfig._clone_init_kwargsr.   .r8   rJ   c                 C   s^   t | j||f  | j}t|}|r%|d}||vri ||< || }|s|||< |   dS )a  
        Update our user-modifications config level with new data.

        :param tuple keypath:
            The key path identifying the sub-dict being updated. May be an
            empty tuple if the update is occurring at the topmost level.

        :param str key:
            The actual key receiving an update.

        :param value:
            The value being written.
        r   N)exciser   r   rC   ry   r   )rF   r.   r8   rJ   r,   keypath_listsubkeyr#   r#   r$   rn   N  s   
zConfig._modifyc                 C   sb   | j }t|}|r'|d}||v r|| }|du rdS ni ||< || }|s	d||< |   dS )z3
        Like `._modify`, but for removal.
        r   N)r   rC   ry   r   )rF   r.   r8   r,   r(  r)  r#   r#   r$   rq   l  s   
zConfig._remove)NNNNNNFr   )T)FTrK   ))rg   r   r   r   r   r  r   staticmethodr	   r   r   r   r   r   rW   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r  	_load_ymlr  r  r   r  r   r%  r   r   rn   rq   r#   r#   r#   r$   r   9  s    oT
 
  



?
Y


""r   c                   @   s   e Zd ZdS )AmbiguousMergeErrorN)rg   r   r   r#   r#   r#   r$   r,    s    r,  baseupdatesc                 C   s   |pi   D ]`\}}|| v rIt|tr)t| | tr"t| | | qt| | |t| | tr7t| | |t|drA|| |< qt|| |< qt|trUt|| |< qt|dr_|| |< qt|| |< q| S )aA  
    Recursively merge dict ``updates`` into dict ``base`` (mutating ``base``.)

    * Values which are themselves dicts will be recursed into.
    * Values which are a dict in one input and *not* a dict in the other input
      (e.g. if our inputs were ``{'foo': 5}`` and ``{'foo': {'bar': 5}}``) are
      irreconciliable and will generate an exception.
    * Non-dict leaf values are run through `copy.copy` to avoid state bleed.

    .. note::
        This is effectively a lightweight `copy.deepcopy` which offers
        protection from mismatched types (dict vs non-dict) and avoids some
        core deepcopy problems (such as how it explodes on certain object
        types).

    :returns:
        The value of ``base``, which is mostly useful for wrapper functions
        like `copy_dict`.

    .. versionadded:: 1.0
    fileno)rf   rU   rV   r  _merge_errorrb   r!  r   )r-  r.  r8   rJ   r#   r#   r$   r    s"   





r  origr#  c                 C   s   t dt| t|S )NzCan't cleanly merge {} with {})r,  r'   _format_mismatch)r1  r#  r#   r#   r$   r0    s
   r0  r*   c                 C   s   d t| | S )Nz	{} ({!r}))r'   type)r*   r#   r#   r$   r2    s   r2  sourcec                 C   s
   t i | S )z
    Return a fresh copy of ``source`` with as little shared state as possible.

    Uses `merge_dicts` under the hood, with an empty ``base`` dict; see its
    documentation for details on behavior.

    .. versionadded:: 1.0
    )r  )r4  r#   r#   r$   r     s   
	r   dict_r.   .c                 C   sP   | }t |}| }|r|d}||vrdS || }|s||v r&||= dS dS )zp
    Remove key pointed at by ``keypath`` from nested dict ``dict_``, if exists.

    .. versionadded:: 1.0
    r   N)rC   ry   )r5  r.   r,   r(  leaf_keyr8   r#   r#   r$   r'    s   

r'  	deletionsc                 C   s:   |  D ]\}}t|trt| | ||  q| |= qdS )zh
    Remove all (nested) keys mentioned in ``deletions``, from ``base``.

    .. versionadded:: 1.0
    N)rf   rU   rV   r  )r-  r7  r8   rJ   r#   r#   r$   r    s
   
r  )2r!  r   r   r  importlib.utilr   r   os.pathr   r   r   r   typingr   r	   r
   r   r   r   r   r   r   
exceptionsr   r   r   r   	terminalsr   utilr   r   importlib.machineryr   ImportErrorimportlib._bootstrapr   r   r%   r&   r   
ValueErrorr,  r  re   r0  r2  r   r'  r  r#   r#   r#   r$   <module>   sV    $
        Y



;"&*