o
    0ήcy                  
   @   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	 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mZmZmZmZmZmZmZmZmZ dd
lm Z m!Z!m"Z"m#Z# ddl$m%Z& ddl'm(Z( ddl)m*Z* erddl+m,Z, ej-dkrddlm.Z. nerddl/m.Z. nddl0m1Z. ee2ef Z3ede3dZ4e5e6Z7G dd deZ8dZ9dZ:G dd de Z;G dd de.Z<G dd dZ=G dd de=Z>G d d! d!Z?d"ed#e@fd$d%ZAd&ee2 d'ee2e2f d(ed#e@fd)d*ZBd+d, ZCd-e*d#ee2 fd.d/ZDd-e*d#ee2 fd0d1ZEd&ee2 d'ee2e2f d2e3d#ee2e2f fd3d4ZFd5e3d#e2fd6d7ZGd8ee2e2f d#ee2 fd9d:ZHd&ee2 d8ee2e2f d#eee2ee2 f  fd;d<ZId8ee2e2f d#ee2e2f fd=d>ZJd?e2d@e2dAe2dBe2d#e@f
dCdDZKdEe3d#e2fdFdGZLdHe4d#e4fdIdJZMdKe2d#e2fdLdMZNG dNdO dOe#jOZPdPZQdKe2dQee2e2f dRee2ee2 f d#e2fdSdTZRG dUdV dVeSZTG dWdX dXe"jUZVdS )Ya  
Create a wheel that, when installed, will make the source package 'editable'
(add it to the interpreter's path, including metadata) per PEP 660. Replaces
'setup.py develop'.

.. note::
   One of the mechanisms briefly mentioned in PEP 660 to implement editable installs is
   to create a separated directory inside ``build`` and use a .pth file to point to that
   directory. In the context of this file such directory is referred as
   *auxiliary build directory* or ``auxiliary_dir``.
    N)suppress)Enum)cleandoc)chain)Path)TemporaryDirectory)
TYPE_CHECKINGDictIterableIteratorListMappingOptionalTupleTypeVarUnion)CommandSetuptoolsDeprecationWarningerrors
namespaces)build_pyfind_package_path)Distribution	WheelFile)      )Protocol)ABC_P)boundc                   @   s6   e Zd ZdZdZdZdZedee	 dd fddZ
d	S )
_EditableModea  
    Possible editable installation modes:
    `lenient` (new files automatically added to the package - DEFAULT);
    `strict` (requires a new installation when files are added/removed); or
    `compat` (attempts to emulate `python setup.py develop` - DEPRECATED).
    strictlenientcompatmodereturnc                 C   sN   |st jS | }|t jvrtd|d|dkr#d}t|t t | S )NzInvalid editable mode: z. Try: 'strict'.COMPATax  
            The 'compat' editable mode is transitional and will be removed
            in future versions of `setuptools`.
            Please adapt your code accordingly to use either the 'strict' or the
            'lenient' modes.

            For more information, please check:
            https://setuptools.pypa.io/en/latest/userguide/development_mode.html
            )	r"   LENIENTupper__members__r   OptionErrorwarningswarnr   )clsr&   _modemsg r2   H/tmp/pip-target-vg8gfxp4/lib/python/setuptools/command/editable_wheel.pyconvertG   s   
	z_EditableMode.convertN)__name__
__module____qualname____doc__STRICTr)   r(   classmethodr   strr4   r2   r2   r2   r3   r"   ;   s    r"   zU
New or renamed files may not be automatically picked up without a new installation.
zt
Options like `package-data`, `include/exclude-package-data` or
`packages.find.exclude/include` may have no effect.
c                   @   s$  e Zd ZdZdZddddeejpdfgZdd	 Zd
d Z	dd Z
dd Zdd Zdee fddZdedededefddZdd Zdeee eeef f fddZdededededeee eeef f f
d d!Zd"d# Zd$efd%d&Zd'd( Zd)efd*d+Zded,ededd-fd.d/ZdS )0editable_wheelzkBuild 'editable' wheel for development.
    (This command is reserved for internal use of setuptools).
    z!create a PEP 660 'editable' wheel)z	dist-dir=dz-directory to put final built distributions in)zdist-info-dir=Iz(path to a pre-build .dist-info directoryzmode=N c                 C   s   d | _ d | _d | _d | _d S N)dist_dirdist_info_dirproject_dirr&   selfr2   r2   r3   initialize_optionsv   s   
z!editable_wheel.initialize_optionsc                 C   s@   | j }|jptj| _|jpi | _t| jptj	| jd| _d S )Ndist)
distributionsrc_rootoscurdirrC   package_dirr   rA   pathjoin)rE   rG   r2   r2   r3   finalize_options|   s    zeditable_wheel.finalize_optionsc              
   C   s|   z#| j jdd |   | d | d}|| j | | W d S  ty= } zt	
  d}tt||d }~ww )NT)exist_okbdist_wheela  
            Support for editable installs via PEP 660 was recently introduced
            in `setuptools`. If you are seeing this error, please report to:

            https://github.com/pypa/setuptools/issues

            Meanwhile you can try the legacy behavior by setting an
            environment variable and trying to install again:

            SETUPTOOLS_ENABLE_FEATURES="legacy-editable"
            )rA   mkdir_ensure_dist_inforeinitialize_commandget_finalized_commandwrite_wheelfilerB   _create_wheel_file	Exception	traceback	print_excr   InternalErrorr   )rE   rQ   exr1   r2   r2   r3   run   s   

zeditable_wheel.runc                 C   sd   | j d u r| d}| j|_|  |  |j | _ d S t| j ds&J t| j d	 s0J d S )N	dist_infoz
.dist-infoMETADATA)
rB   rT   rA   
output_dirensure_finalizedr]   r;   endswithr   exists)rE   r^   r2   r2   r3   rS      s   

z editable_wheel._ensure_dist_infoc                 C   sD   | j }|jsd S t| j| jdd }t||||}|  d S )Nr?   .)	rH   namespace_packagesr   rC   rL   getresolve_NamespaceInstallerinstall_namespaces)rE   installation_dir
pth_prefixrG   rI   	installerr2   r2   r3   _install_namespaces   s   z"editable_wheel._install_namespacesr'   c                 C   s2   | j r	t| j jnt }tt|d}t|d S )Nz
*.egg-info)rB   r   parentmapr;   globnext)rE   
parent_dir
candidatesr2   r2   r3   _find_egg_info_dir   s   
z!editable_wheel._find_egg_info_dirnameunpacked_wheel	build_libtmp_dirc                 C   s  | j }t|}t|}tt|| dd}tt|| dd}tt|| dd}	|jddd}
t||
_d|
_|jddd}|jd	dd}| |_ |_|_| |_	 |_
|_|	 |_|_||_||_|d
}d|_t||_|d}d|_|  |_|   |  |  dS )a  Configure commands to behave in the following ways:

        - Build commands can write to ``build_lib`` if they really want to...
          (but this folder is expected to be ignored and modules are expected to live
          in the project directory...)
        - Binary extensions should be built in-place (editable_mode = True)
        - Data/header/script files are not part of the "editable" specification
          so they are written directly to the unpacked_wheel directory.
        z.datadataheadersscriptsegg_infoT)reinit_subcommandsbuildinstallinstall_scriptsr   FN)rH   r;   r   rT   egg_baseignore_egg_info_in_manifestbuild_platlibbuild_purelibrw   install_purelibinstall_platlibinstall_libr   build_scriptsinstall_headersinstall_dataget_command_objno_ep
build_tempcompilert   existing_egg_info_dir_set_editable_modera   )rE   ru   rv   rw   rx   rG   wheelry   rz   r{   r|   r~   r   r   r   r2   r2   r3   _configure_build   s2   




zeditable_wheel._configure_buildc                 C   sN   | j }|d}| D ]}||}t|drd|_qt|dr$d|_qdS )z8Set the ``editable_mode`` flag in the build sub-commandsr~   editable_modeTinplaceN)rH   r   get_sub_commandshasattrr   r   )rE   rG   r~   cmd_namecmdr2   r2   r3   r      s   



z!editable_wheel._set_editable_modec                 C   sj   g }i }|  d}| D ]#}|  |}t|dr"|| p g  t|dr0|| p.i  q||fS )Nr~   get_outputsget_output_mapping)rU   r   r   extendr   updater   )rE   filesmappingr~   r   r   r2   r2   r3   _collect_build_outputs   s   



z%editable_wheel._collect_build_outputs	dist_namec                 C   sJ   |  |||| |   |  \}}| d | d | d ||fS )Nrz   r{   ry   )r   _run_build_subcommandsr   _run_install)rE   r   rv   rw   rx   r   r   r2   r2   r3   _run_build_commands  s   


z"editable_wheel._run_build_commandsc                 C   sP   |  d}| D ]}|  |}|dkr t|tkr | | q	| | q	dS )a}  
        Issue #3501 indicates that some plugins/customizations might rely on:

        1. ``build_py`` not running
        2. ``build_py`` always copying files to ``build_lib``

        However both these assumptions may be false in editable_wheel.
        This method implements a temporary workaround to support the ecosystem
        while the implementations catch up.
        r~   r   N)rU   r   typebuild_py_cls_safely_runrun_command)rE   r~   ru   r   r2   r2   r3   r     s   

z%editable_wheel._run_build_subcommandsr   c              	   C   sL   z|  |W S  ty%   t  d| d| d}tj|tdd Y d S w )Nz

            If you are seeing this warning it is very likely that a setuptools
            plugin or customization overrides the `z` command, without
            taking into consideration how editable installs run build steps
            starting from v64.0.0.

            Plugin authors and developers relying on custom build steps are encouraged
            to update their `aO  ` implementation considering the information in
            https://setuptools.pypa.io/en/latest/userguide/extension.html
            about editable installs.

            For the time being `setuptools` will silence this error and ignore
            the faulty command, but this behaviour will change in future versions.

               )
stacklevel)r   rX   rY   
format_excr-   r.   r   )rE   r   r1   r2   r2   r3   r   "  s   
zeditable_wheel._safely_runc                 C   s  ddl m} | d}|j}d| }d}| d| d| d}t| j|}| r0|	  t
|d}	t
dd}
t
d	d}|	}|
t}|b}t|t| jj}t| j| | ||j | ||||\}}| |||}|( ||d
}|||| || W d    n1 sw   Y  W d    n1 sw   Y  W d    n1 sw   Y  W d    n1 sw   Y  W d    |S W d    |S 1 sw   Y  |S )Nr   r   r^   -z
0.editablez.whl)suffixz
.build-libz.build-tempw)wheel.wheelfiler   rU   ru   rN   get_tagr   rA   rc   unlinkr   rB   shutilcopytreerm   r   _select_strategywrite_files)rE   rQ   r   r^   r   tag	build_tagarchive_name
wheel_pathrv   rw   	build_tmpunpackedlibtmpunpacked_dist_infor   r   strategy	wheel_objr2   r2   r3   rW   6  sB   



 ( 


z!editable_wheel._create_wheel_filecategoryc                 C   sL   t | jd| d }|r"| r$td| d | d|  d S d S d S )Nhas_zInstalling z as non editableinstall_)getattrrH   _loggerinfor   )rE   r   has_categoryr2   r2   r3   r   R  s
   
zeditable_wheel._run_installr   EditableStrategyc                 C   s   d| d| }t | j}t| j}|tju r)tt | jd|}t| j|||S t	| j}t
|| j|}	|tju }
t| jdhkrD|	sF|
rX| jdd}t| j|t ||gS t| j|S )zDDecides which strategy to use to implement an editable installation.__editable__.r   r~   r?   rd   )r   rC   r"   r4   r&   r9   
_empty_dir	_LinkTreerH   _find_packages_simple_layoutrL   r(   setrf   
_StaticPth_TopLevelFinder)rE   ru   r   rw   
build_namerC   r&   auxiliary_dirpackageshas_simple_layoutis_compat_modesrc_dirr2   r2   r3   r   X  s   



zeditable_wheel._select_strategy)r5   r6   r7   r8   descriptionr   r"   user_optionsrF   rO   r]   rS   rm   r   r;   rt   _Pathr   r   r   r   r	   r   r   r   r   rW   r   r   r2   r2   r2   r3   r<   i   s`    

2"
r<   c                   @   s>   e Zd Zdddee deeef fddZdd Zd	d
 ZdS )r   r   r   r   r   c                 C      d S r@   r2   rE   r   r   r   r2   r2   r3   __call__t     zEditableStrategy.__call__c                 C   r   r@   r2   rD   r2   r2   r3   	__enter__w  r   zEditableStrategy.__enter__c                 C   r   r@   r2   rE   	_exc_type
_exc_value
_tracebackr2   r2   r3   __exit__z  r   zEditableStrategy.__exit__N)	r5   r6   r7   r   r;   r	   r   r   r   r2   r2   r2   r3   r   s  s    "r   c                   @   sX   e Zd Zdededee fddZdddee d	eeef fd
dZ	dd Z
dd ZdS )r   rG   ru   path_entriesc                 C   s   || _ || _|| _d S r@   )rG   ru   r   )rE   rG   ru   r   r2   r2   r3   __init__  s   
z_StaticPth.__init__r   r   r   r   c                 C   s@   d dd | jD }t| dd}|d| j d| d S )N
c                 s   s    | ]	}t | V  qd S r@   )r;   rg   ).0pr2   r2   r3   	<genexpr>      z&_StaticPth.__call__.<locals>.<genexpr>utf-8r   .pth)rN   r   byteswritestrru   )rE   r   r   r   entriescontentsr2   r2   r3   r     s   z_StaticPth.__call__c                 C   s,   dt ttj| jd}t|t  | S )Nz_
        Editable install will be performed using .pth file to extend `sys.path` with:
        z	
        )listro   rJ   fspathr   r   warning_LENIENT_WARNINGrE   r1   r2   r2   r3   r     s
   z_StaticPth.__enter__c                 C   r   r@   r2   r   r2   r2   r3   r     r   z_StaticPth.__exit__N)r5   r6   r7   r   r;   r   r   r   r	   r   r   r   r2   r2   r2   r3   r   ~  s
    "r   c                       s   e Zd ZdZdedededef fddZdd	d
ee de	eef f fddZ
dedee fddZddedefddZdd Zdd Zdd Z  ZS )r   a`  
    Creates a ``.pth`` file that points to a link tree in the ``auxiliary_dir``.

    This strategy will only link files (not dirs), so it can be implemented in
    any OS, even if that means using hardlinks instead of symlinks.

    By collocating ``auxiliary_dir`` and the original source code, limitations
    with hardlinks should be avoided.
    rG   ru   r   rw   c                    s>   t || _t | | _|dj| _t ||| jg d S )Nr   )	r   r   rg   rw   r   	copy_file_filesuperr   )rE   rG   ru   r   rw   	__class__r2   r3   r     s   
z_LinkTree.__init__r   r   r   r   c                    s    |  || t ||| d S r@   )_create_linksr   r   r   r   r2   r3   r     s   z_LinkTree.__call__filer'   c                 C   sR   t t t| | j}t|tj	dW  d    S 1 s"w   Y  d S )N/)
r   
ValueErrorr   rg   relative_torw   r;   replacerJ   sep)rE   r   rM   r2   r2   r3   _normalize_output  s
   
 z_LinkTree._normalize_outputNrelative_outputsrc_filec                 C   s6   | j | }|j s|jjdd | j|||d d S )NT)parentslink)r   rn   is_dirrR   r   )rE   r  r  r  destr2   r2   r3   _create_file  s   

z_LinkTree._create_filec                    s    j jddd t j rdnd} fdd| D }|d d  |D ]} |}|r7||vr7 || q$| D ]\}} j|||d q<d S )NT)r  rP   symhardc                    s   i | ]
\}}  ||qS r2   )r  r   kvrD   r2   r3   
<dictcomp>  s    
z+_LinkTree._create_links.<locals>.<dictcomp>r  )r   rR   _can_symlink_filesitemspopr  r	  )rE   outputsoutput_mapping	link_typemappingsoutputrelativesrcr2   rD   r3   r     s   

z_LinkTree._create_linksc                 C      d}t |t  | S )Nz=Strict editable install will be performed using a link tree.
)r   r   _STRICT_WARNINGr   r2   r2   r3   r        z_LinkTree.__enter__c                 C   s   d| j  d}t|t d S )Nz\

        Strict editable installation performed using the auxiliary directory:
            z

        Please be careful to not remove this directory, otherwise you might not be able
        to import/use your package.
        )r   r-   r.   InformationOnlyrE   r   r   r   r1   r2   r2   r3   r     s   z_LinkTree.__exit__r@   )r5   r6   r7   r8   r   r;   r   r   r   r	   r   r   r  r	  r   r   r   __classcell__r2   r2   r   r3   r     s"    	&r   c                   @   sP   e Zd ZdedefddZdddee deeef fd	d
Zdd Z	dd Z
dS )r   rG   ru   c                 C   s   || _ || _d S r@   )rG   ru   )rE   rG   ru   r2   r2   r3   r     s   
z_TopLevelFinder.__init__r   r   r   r   c                 C   s   | j jptj}tt| j t| j }| j jpi }t|||}t	tt
| j jp&g |dd t|D }d| j d}	t|	}
tt|	||d}||
 d| td|
 d|
 d	d}|d| j d
| d S )Nc                 s   s    | ]}|g fV  qd S r@   r2   )r   nsr2   r2   r3   r     s    z+_TopLevelFinder.__call__.<locals>.<genexpr>r   z.finderr   z.pyzimport z; z
.install()r   )rG   rI   rJ   rK   r   r   _find_top_level_modulesrL   _find_package_rootsdict_find_namespacesr   _find_virtual_namespacesru   _make_identifierr   _finder_templater   )rE   r   r   r   rI   	top_levelrL   rootsnamespaces_ru   findercontentr2   r2   r3   r     s   z_TopLevelFinder.__call__c                 C   r  )Nz=Editable install will be performed using a meta path finder.
)r   r   r   r   r2   r2   r3   r     r  z_TopLevelFinder.__enter__c                 C   s   d}t |t d S )Nz

        Please be careful with folders in your working directory with the same
        name as your package as they may take precedence during imports.
        )r-   r.   r  r  r2   r2   r3   r     s   z_TopLevelFinder.__exit__N)r5   r6   r7   r   r;   r   r   r	   r   r   r   r2   r2   r2   r3   r     s
    "r   base_dirr'   c                 C   s  t t|  do}t|dt|d}}|jddd tttt) t	
|| | rD|jdddkrD	 W d    W d    dS W d    n1 sNw   Y  zt	|| W n tyn } zd}t||d }~ww 	 W d    d	S 1 s{w   Y  d S )
N)dirz	file1.txtz	file2.txtfile1r   )encodingTzFile system does not seem to support either symlinks or hard links. Strict editable installs require one of them to be supported.F)r   r;   rg   r   
write_textr   AttributeErrorNotImplementedErrorOSErrorrJ   symlink
is_symlink	read_textr  rX   LinksNotSupported)r-  r   path1path2r\   r1   r2   r2   r3   r    s*   
$r  r   rL   rC   c                    s^    fdd| D }|st  i dhfv S tjdd | D tfdd| D S )a[  Return ``True`` if:
    - all packages are contained by the same parent directory, **and**
    - all packages become importable if the parent directory is added to ``sys.path``.

    >>> _simple_layout(['a'], {"": "src"}, "/tmp/myproj")
    True
    >>> _simple_layout(['a', 'a.b'], {"": "src"}, "/tmp/myproj")
    True
    >>> _simple_layout(['a', 'a.b'], {}, "/tmp/myproj")
    True
    >>> _simple_layout(['a', 'a.a1', 'a.a1.a2', 'b'], {"": "src"}, "/tmp/myproj")
    True
    >>> _simple_layout(['a', 'a.a1', 'a.a1.a2', 'b'], {"a": "a", "b": "b"}, ".")
    True
    >>> _simple_layout(['a', 'a.a1', 'a.a1.a2', 'b'], {"a": "_a", "b": "_b"}, ".")
    False
    >>> _simple_layout(['a', 'a.a1', 'a.a1.a2', 'b'], {"a": "_a"}, "/tmp/myproj")
    False
    >>> _simple_layout(['a', 'a.a1', 'a.a1.a2', 'b'], {"a.a1.a2": "_a2"}, ".")
    False
    >>> _simple_layout(['a', 'a.b'], {"": "src", "a.b": "_ab"}, "/tmp/myproj")
    False
    >>> # Special cases, no packages yet:
    >>> _simple_layout([], {"": "src"}, "/tmp/myproj")
    True
    >>> _simple_layout([], {"a": "_a", "": "src"}, "/tmp/myproj")
    False
    c                    s   i | ]	}|t | qS r2   r   r   pkg)rL   rC   r2   r3   r  4  s    z"_simple_layout.<locals>.<dictcomp>r?   c                 S   s   g | ]	\}}t ||qS r2   )_parent_pathr  r2   r2   r3   
<listcomp>:  s    z"_simple_layout.<locals>.<listcomp>c                 3   s6    | ]\}}t t g|d R  t |kV  qdS rd   N)_normalize_pathr   split)r   keyvalue)rn   r2   r3   r   ;  s
     
z!_simple_layout.<locals>.<genexpr>)r   rJ   rM   
commonpathr  all)r   rL   rC   layoutr2   )rL   rn   rC   r3   r     s   r   c                 C   s0   | | r|dt|   n|}|dtj S )a7  Infer the parent path containing a package, that if added to ``sys.path`` would
    allow importing that package.
    When ``pkg`` is directly mapped into a directory with a different name, return its
    own path.
    >>> _parent_path("a", "src/a")
    'src'
    >>> _parent_path("b", "src/c")
    'src/c'
    Nr   )rb   lenrstriprJ   r   )r<  pkg_pathrn   r2   r2   r3   r=  A  s    
r=  rG   c                 c   s~    t | jpg E d H  | jpg }dd |D }| jr| jV  n| jp#g }|dd |D 7 }|D ]}|d\}}}|V  q/d S )Nc                 S   s   g | ]}d |v r|qS rd   r2   r   modr2   r2   r3   r>  S  s    z"_find_packages.<locals>.<listcomp>c                 S   s   g | ]
}d |j v r|j qS rJ  ru   r   xr2   r2   r3   r>  X  s    rd   )iterr   
py_modulesext_packageext_modules
rpartition)rG   rQ  nested_modulesrS  modulepackage_r2   r2   r3   r   O  s   


r   c                 c   sL    | j pg }dd |D E d H  | js$| jpg }dd |D E d H  d S d S )Nc                 s   s    | ]	}d |vr|V  qdS r?  r2   rK  r2   r2   r3   r   a  r   z*_find_top_level_modules.<locals>.<genexpr>c                 s   s     | ]}d |j vr|j V  qdS r?  rM  rN  r2   r2   r3   r   e  s    )rQ  rR  rS  )rG   rQ  rS  r2   r2   r3   r!  _  s   

r!  rI   c                    s     fddt | D }t|S )Nc                    s   i | ]}|t t| qS r2   )_absolute_rootr   r;  rL   rI   r2   r3   r  m  s    z'_find_package_roots.<locals>.<dictcomp>)sorted_remove_nested)r   rL   rI   	pkg_rootsr2   rZ  r3   r"  h  s   r"  rM   c                 C   s4   t | }|j}| rt| S t| |j S )z(Works for packages and top-level modules)r   rn   rc   r;   rg   ru   )rM   path_rn   r2   r2   r3   rY  u  s
   rY  r]  c                 c   sv    | D ]5}d|vr
q| d}tt|d ddD ]}d|d| }tt|| d}| r4|| vr7|V  qqdS )a8  By carefully designing ``package_dir``, it is possible to implement the logical
    structure of PEP 420 in a package without the corresponding directories.

    Moreover a parent package can be purposefully/accidentally skipped in the discovery
    phase (e.g. ``find_packages(include=["mypkg.*"])``, when ``mypkg.foo`` is included
    by ``mypkg`` itself is not).
    We consider this case to also be a virtual namespace (ignoring the original
    directory) to emulate a non-editable installation.

    This function will try to find these kinds of namespaces.
    rd      r   Nr?   )rA  rangerG  rN   r   r   rc   )r]  r<  partsipartial_namerM   r2   r2   r3   r%    s   
r%  c                 c   sB    | D ]}t ||d}t| rt|d s||gfV  qd S )Nr?   z__init__.py)r   r   rc   )r   r]  r<  rM   r2   r2   r3   r$    s   r$  c                    sP   t |  }tt|  D ]\ t fdd|  D r%| q|S )Nc                 3   s*    | ]\}}|kot  ||V  qd S r@   )
_is_nested)r   other
other_pathrM   r<  r2   r3   r     s
    
z!_remove_nested.<locals>.<genexpr>)r#  copyreversedr   r  anyr  )r]  r  r2   rh  r3   r\    s   
r\  r<  rI  rn   parent_pathc                 C   sD   t |}| |dddd}| |o!|t t|g|R  kS )a  
    Return ``True`` if ``pkg`` is nested inside ``parent`` both logically and in the
    file system.
    >>> _is_nested("a.b", "path/a/b", "a", "path/a")
    True
    >>> _is_nested("a.b", "path/a/b", "a", "otherpath/a")
    False
    >>> _is_nested("a.b", "path/a/b", "c", "path/c")
    False
    >>> _is_nested("a.a", "path/a/a", "a", "path/a")
    True
    >>> _is_nested("b.a", "path/b/a", "a", "path/a")
    False
    r?   r_  rd   )r@  r   striprA  
startswithr   )r<  rI  rn   rl  norm_pkg_pathrestr2   r2   r3   re    s
   
re  filenamec                 C   s6   t jdkrtj| n| }tjtjtj|S )z1Normalize a file/dir name for comparison purposescygwin)sysplatformrJ   rM   abspathnormcaserealpathnormpath)rq  r   r2   r2   r3   r@    s   r@  dir_c                 C   s   t j| dd t|  | S )zFCreate a directory ensured to be empty. Existing files may be removed.T)ignore_errors)r   rmtreerJ   makedirs)ry  r2   r2   r3   r     s   
r   ru   c                 C   s   t dd| }| sJ |S )zMake a string safe to be used as Python identifier.
    >>> _make_identifier("12abc")
    '_12abc'
    >>> _make_identifier("__editable__.myns.pkg-78.9.3_local")
    '__editable___myns_pkg_78_9_3_local'
    z
\W|^(?=\d)rX  )resubisidentifier)ru   safer2   r2   r3   r&    s   r&  c                   @   s$   e Zd Zdd Zdd Zdd ZdS )rh   c                 C   s(   || _ || _|| _|| _g | _d| _d S )NF)rH   rI   rj   editable_namer  dry_run)rE   rH   rj   r  rI   r2   r2   r3   r     s   
z_NamespaceInstaller.__init__c                 C   s   t j| j| jS )zInstallation target.)rJ   rM   rN   rj   r  rD   r2   r2   r3   _get_target  s   z_NamespaceInstaller._get_targetc                 C   s   t t| jS )z1Where the modules/packages should be loaded from.)reprr;   rI   rD   r2   r2   r3   	_get_root  s   z_NamespaceInstaller._get_rootN)r5   r6   r7   r   r  r  r2   r2   r2   r3   rh     s    rh   a<	  import sys
from importlib.machinery import ModuleSpec
from importlib.machinery import all_suffixes as module_suffixes
from importlib.util import spec_from_file_location
from itertools import chain
from pathlib import Path

MAPPING = {mapping!r}
NAMESPACES = {namespaces!r}
PATH_PLACEHOLDER = {name!r} + ".__path_hook__"


class _EditableFinder:  # MetaPathFinder
    @classmethod
    def find_spec(cls, fullname, path=None, target=None):
        for pkg, pkg_path in reversed(list(MAPPING.items())):
            if fullname == pkg or fullname.startswith(f"{{pkg}}."):
                rest = fullname.replace(pkg, "", 1).strip(".").split(".")
                return cls._find_spec(fullname, Path(pkg_path, *rest))

        return None

    @classmethod
    def _find_spec(cls, fullname, candidate_path):
        init = candidate_path / "__init__.py"
        candidates = (candidate_path.with_suffix(x) for x in module_suffixes())
        for candidate in chain([init], candidates):
            if candidate.exists():
                return spec_from_file_location(fullname, candidate)


class _EditableNamespaceFinder:  # PathEntryFinder
    @classmethod
    def _path_hook(cls, path):
        if path == PATH_PLACEHOLDER:
            return cls
        raise ImportError

    @classmethod
    def _paths(cls, fullname):
        # Ensure __path__ is not empty for the spec to be considered a namespace.
        return NAMESPACES[fullname] or MAPPING.get(fullname) or [PATH_PLACEHOLDER]

    @classmethod
    def find_spec(cls, fullname, target=None):
        if fullname in NAMESPACES:
            spec = ModuleSpec(fullname, None, is_package=True)
            spec.submodule_search_locations = cls._paths(fullname)
            return spec
        return None

    @classmethod
    def find_module(cls, fullname):
        return None


def install():
    if not any(finder == _EditableFinder for finder in sys.meta_path):
        sys.meta_path.append(_EditableFinder)

    if not NAMESPACES:
        return

    if not any(hook == _EditableNamespaceFinder._path_hook for hook in sys.path_hooks):
        # PathEntryFinder is needed to create NamespaceSpec without private APIS
        sys.path_hooks.append(_EditableNamespaceFinder._path_hook)
    if PATH_PLACEHOLDER not in sys.path:
        sys.path.append(PATH_PLACEHOLDER)  # Used just to trigger the path hook
r   r   c                 C   s(   t t| dd d}tj| ||dS )z_Create a string containing the code for the``MetaPathFinder`` and
    ``PathEntryFinder``.
    c                 S   s   | d S )Nr   r2   )r   r2   r2   r3   <lambda>?  s    z"_finder_template.<locals>.<lambda>)rB  ru   r   r   )r#  r[  r  _FINDER_TEMPLATEformatr  r2   r2   r3   r'  9  s   r'  c                   @      e Zd ZdZdS )r  zCurrently there is no clear way of displaying messages to the users
    that use the setuptools backend directly via ``pip``.
    The only thing that might work is a warning, although it is not the
    most appropriate tool for the job...
    Nr5   r6   r7   r8   r2   r2   r2   r3   r  C      r  c                   @   r  )r8  zCFile system does not seem to support either symlinks or hard links.Nr  r2   r2   r2   r3   r8  K  r  r8  )Wr8   loggingrJ   r}  r   rs  rY   r-   
contextlibr   enumr   inspectr   	itertoolsr   pathlibr   tempfiler   typingr   r	   r
   r   r   r   r   r   r   r   
setuptoolsr   r   r   r   setuptools.command.build_pyr   r   setuptools.discoveryr   setuptools.distr   r   r   version_infor   typing_extensionsabcr   r;   r   r    	getLoggerr5   r   r"   r  r   r<   r   r   r   r   boolr  r   r=  r   r!  r"  rY  r%  r$  r\  re  r@  r   r&  	Installerrh   r  r'  UserWarningr  	FileErrorr8  r2   r2   r2   r3   <module>   s    0

$  G%

,	




"	H


