U
    fP;                     @  s   d dl mZ d dlmZ d dlmZ d dlmZ d dlm  m	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mZ d dlmZ d	d
lmZ dZdd ZG dd de
j	Z	dd ZG dd dZdS )    )annotations)partial)glob)convert_pathN)Path)IterableIterator)unique_everseen   )SetuptoolsDeprecationWarning)z*.pyizpy.typedc                 C  s   t | t | jtjB  d S N)oschmodstatst_modeS_IWRITE)target r   :lib/python3.8/site-packages/setuptools/command/build_py.pymake_writable   s    r   c                      s  e Zd ZU dZdZded< dZded< dd	 Zd? fdd	Zdd Z	dd Z
dd Zdd Zdd Zdd Zdd Zd@dd fddZd dd!d"Zd#dd$d%Zd#dd&d'Zd(d) Zd*d+ Zd,d-d.d/d0d1Zd2d3 Zd4d5 Zd6d7 Zd8d9 Zd:d; ZedAd=d>Z  ZS )Bbuild_pyaX  Enhanced 'build_py' command that includes data files with packages

    The data files are specified via a 'package_data' argument to 'setup()'.
    See 'setuptools.dist.Distribution' for more details.

    Also, this version of the 'build_py' command allows you to specify both
    'py_modules' and 'packages' in the same setup operation.
    Fbooleditable_modeNz
str | Noneexisting_egg_info_dirc                 C  s@   t j|  | jj| _| jjp i | _d| jkr6| jd= g | _d S )N
data_files)origr   finalize_optionsdistributionpackage_dataexclude_package_data__dict___build_py__updated_filesselfr   r   r   r   (   s    

zbuild_py.finalize_optionsT   c                   s:   |r$t t| }t t| }t ||||||S r   )strr   Zresolvesuper	copy_file)r#   ZinfileoutfileZpreserve_modeZpreserve_timeslinklevel	__class__r   r   r'   0   s    
     zbuild_py.copy_filec                 C  sT   | j s| jr| jrdS | j r$|   | jr:|   |   | tjj	| dd dS )z?Build modules, packages, and copy data files to build directoryNF)include_bytecode)
Z
py_modulespackagesr   Zbuild_modulesZbuild_packagesbuild_package_dataZbyte_compiler   r   get_outputsr"   r   r   r   runA   s    zbuild_py.runc                 C  s&   |dkr|   | _| jS tj| |S )zlazily compute data filesr   )_get_data_filesr   r   r   __getattr__)r#   attrr   r   r   r3   Q   s    
zbuild_py.__getattr__c                 C  s.   t j| |||\}}|r&| j| ||fS r   )r   r   build_moduler!   append)r#   modulemodule_filepackager(   Zcopiedr   r   r   r5   X   s    zbuild_py.build_modulec                 C  s   |    tt| j| jpdS )z?Generate list of '(package,src_dir,build_dir,filenames)' tuplesr   )analyze_manifestlistmap_get_pkg_data_filesr.   r"   r   r   r   r2   ^   s    zbuild_py._get_data_filesc                 C  s$   | j di  tt| j| jpdS )z
        Generate list of ``(package,src_dir,build_dir,filenames)`` tuples,
        but without triggering any attempt to analyze or build the manifest.
        manifest_filesr   )r    
setdefaultr;   r<   r=   r.   r"   r   r   r   get_data_files_without_manifestc   s    z(build_py.get_data_files_without_manifestc                   sJ   |  | tjj| jg|d  } fdd| | D }| ||fS )N.c                   s   g | ]}t j| qS r   )r   pathrelpath).0filesrc_dirr   r   
<listcomp>u   s   z0build_py._get_pkg_data_files.<locals>.<listcomp>)get_package_dirr   rB   join	build_libsplitfind_data_files)r#   r9   	build_dir	filenamesr   rF   r   r=   m   s    


zbuild_py._get_pkg_data_filesc                 C  sd   | j | j||td}tttdd|}tj|}t	t
jj|}t| j|g |}| |||S )z6Return filenames for package's data files in 'src_dir')extra_patternsT)	recursive)_get_platform_patternsr   _IMPLICIT_DATA_FILESr<   r   r   	itertoolschainfrom_iterablefilterr   rB   isfiler>   getexclude_data_files)r#   r9   rG   patternsZglobs_expandedZglobs_matchesZ
glob_filesfilesr   r   r   rM   {   s    zbuild_py.find_data_filesz	list[str])returnc                   s"   | j rt|   S t |S )1See :class:`setuptools.commands.build.SubCommand`)r   r;   get_output_mappingkeysr&   r0   )r#   r-   r+   r   r   r0      s    zbuild_py.get_outputszdict[str, str]c                 C  s(   t |  |  }tt|dd dS )r^   c                 S  s   | d S )Nr   r   )xr   r   r   <lambda>       z-build_py.get_output_mapping.<locals>.<lambda>)key)rT   rU    _get_package_data_output_mapping_get_module_mappingdictsorted)r#   mappingr   r   r   r_      s
    zbuild_py.get_output_mappingzIterator[tuple[str, str]]c                 c  s<   |   D ].\}}}|d}| | j||}||fV  qdS )z5Iterate over all modules producing (dest, src) pairs.rA   N)Zfind_all_modulesrL   Zget_module_outfilerK   )r#   r9   r7   r8   filenamer   r   r   rf      s    
zbuild_py._get_module_mappingc                 c  sH   | j D ]<\}}}}|D ]*}tj||}tj||}||fV  qqdS )z6Iterate over package data producing (dest, src) pairs.N)r   r   rB   rJ   )r#   r9   rG   rN   rO   rj   r   srcfiler   r   r   re      s
    z)build_py._get_package_data_output_mappingc                 C  s@   |   D ]2\}}| tj| | ||\}}t| qdS )z$Copy data files into build directoryN)re   Zmkpathr   rB   dirnamer'   r   )r#   r   rk   Z_outfZ_copiedr   r   r   r/      s    zbuild_py.build_package_datac                 C  sj  i  | _ }| jjsd S i }| jp"dD ]}||t| |< q$t| dd rzt| jd	 rz| j}t|d}|j
dd }n"| d | d}|j}|jj}t }| ||D ]}	tjt|	\}
}d }|}|
r|
|kr|
|kr|
}tj|
\}
}tj||}q|
|kr||kr.||rNqn |||
 |}|rN|| |||
 g |	 qd S )Nr   r   zSOURCES.txtzutf-8)encodingegg_info)r>   r   Zinclude_package_datar.   assert_relativerI   getattrr   r   existsZ	read_text
splitlinesZrun_commandget_finalized_commandrn   Zfilelistr\   _IncludePackageDataAbuse_filter_build_filesr   rB   rL   rJ   	is_moduleimportable_subpackagewarnr?   r6   )r#   ZmfZsrc_dirsr9   Zegg_info_dirZmanifestr\   Zei_cmdZcheckrB   dfprevZoldfZdf
importabler   r   r   r:      sD    






zbuild_py.analyze_manifestzIterable[str]r%   zIterator[str])r\   rn   r]   c                 #  sl   |  d}|| j|j|jf}dd |D }|D ]8}tj| tj|r`t fdd|D r.|V  q.dS )a}  
        ``build_meta`` may try to create egg_info outside of the project directory,
        and this can be problematic for certain plugins (reported in issue #3500).

        Extensions might also include between their sources files created on the
        ``build_lib`` and ``build_temp`` directories.

        This function should filter this case of invalid files out.
        buildc                 S  s   g | ]}|rt j|qS r   )r   rB   normpath)rD   pr   r   r   rH      s      z0build_py._filter_build_files.<locals>.<listcomp>c                 3  s   | ]}| kV  qd S r   r   )rD   ry   Z	norm_pathr   r   	<genexpr>   s     z/build_py._filter_build_files.<locals>.<genexpr>N)	rs   rK   Z
build_tempZ
build_baser   rB   r~   isabsall)r#   r\   rn   r}   Z
build_dirsZ	norm_dirsrE   r   r   r   ru      s    

"zbuild_py._filter_build_filesc                 C  s   d S r   r   r"   r   r   r   get_data_files   s    zbuild_py.get_data_filesc              	   C  s   z| j | W S  tk
r    Y nX tj| ||}|| j |< |rH| jjsL|S | jjD ]}||ksn||d rT qxqT|S t|d}|	 }W 5 Q R X d|krt
jd|f |S )z8Check namespace packages' __init__ for declare_namespacerA   rbs   declare_namespacezNamespace package problem: %s is a namespace package, but its
__init__.py does not call declare_namespace()! Please fix it.
(See the setuptools manual under "Namespace Packages" for details.)
")packages_checkedKeyErrorr   r   check_packager   Znamespace_packages
startswithopenread	distutilserrorsZDistutilsError)r#   r9   Zpackage_dirZinit_pypkgrz   contentsr   r   r   r      s*    
zbuild_py.check_packagec                 C  s"   i | _ tj|  d| _d | _d S )NF)r   r   r   initialize_optionsr   r   r"   r   r   r   r     s    zbuild_py.initialize_optionsc                 C  s0   t j| |}| jjd k	r,tj| jj|S |S r   )r   r   rI   r   Zsrc_rootr   rB   rJ   )r#   r9   resr   r   r   rI     s    zbuild_py.get_package_dirc                   s\   t | | j||}fdd|D }tj|}t|  fddD }t t|S )z6Filter filenames for package's data files in 'src_dir'c                 3  s   | ]}t  |V  qd S r   )fnmatchrW   rD   pattern)r\   r   r   r   "  s     z.build_py.exclude_data_files.<locals>.<genexpr>c                 3  s   | ]}| kr|V  qd S r   r   )rD   fn)badr   r   r   &  s      )r;   rR   r   rT   rU   rV   setr	   )r#   r9   rG   r\   r[   Zmatch_groupsZmatchesZkeepersr   )r   r\   r   rZ     s    zbuild_py.exclude_data_filesr   c                   s0   t || dg | |g } fdd|D S )z
        yield platform-specific path patterns (suitable for glob
        or fn_match) from a glob-based spec (such as
        self.package_data or self.exclude_package_data)
        matching package in src_dir.
         c                 3  s    | ]}t j t|V  qd S r   )r   rB   rJ   r   r   rF   r   r   r   7  s   z2build_py._get_platform_patterns.<locals>.<genexpr>)rT   rU   rY   )specr9   rG   rP   Zraw_patternsr   rF   r   rR   *  s    


zbuild_py._get_platform_patterns)TTNr$   )T)r   )__name__
__module____qualname____doc__r   __annotations__r   r   r'   r1   r3   r5   r2   r@   r=   rM   r0   r_   rf   re   r/   r:   ru   r   r   r   rI   rZ   staticmethodrR   __classcell__r   r   r+   r   r      s<   
	    
)r   c                 C  s:   t j| s| S ddlm} td |  }||d S )Nr   )DistutilsSetupErrorz
        Error: setup script specifies an absolute path:

            %s

        setup() arguments must *always* be /-separated paths relative to the
        setup.py directory, *never* absolute paths.
        )r   rB   r   distutils.errorsr   textwrapdedentlstrip)rB   r   msgr   r   r   ro   >  s    
ro   c                   @  s@   e Zd ZdZG dd deZdd Zdd Zdd	 Zd
d Z	dS )rt   z>Inform users that package or module is included as 'data file'c                   @  s   e Zd ZdZdZdS )z!_IncludePackageDataAbuse._WarningzU
        Package {importable!r} is absent from the `packages` configuration.
        a|  
        ############################
        # Package would be ignored #
        ############################
        Python recognizes {importable!r} as an importable package[^1],
        but it is absent from setuptools' `packages` configuration.

        This leads to an ambiguous overall configuration. If you want to distribute this
        package, please make sure that {importable!r} is explicitly added
        to the `packages` configuration field.

        Alternatively, you can also rely on setuptools' discovery methods
        (for example by using `find_namespace_packages(...)`/`find_namespace:`
        instead of `find_packages(...)`/`find:`).

        You can read more about "package discovery" on setuptools documentation page:

        - https://setuptools.pypa.io/en/latest/userguide/package_discovery.html

        If you don't want {importable!r} to be distributed and are
        already explicitly excluding {importable!r} via
        `find_namespace_packages(...)/find_namespace` or `find_packages(...)/find`,
        you can try to use `exclude_package_data`, or `include-package-data=False` in
        combination with a more fine grained `package-data` configuration.

        You can read more about "package data files" on setuptools documentation page:

        - https://setuptools.pypa.io/en/latest/userguide/datafiles.html


        [^1]: For Python, any directory (with suitable naming) can be imported,
              even if it does not contain any `.py` files.
              On the other hand, currently there is no concept of package data
              directory, all directories are treated like packages.
        N)r   r   r   Z_SUMMARYZ_DETAILSr   r   r   r   _WarningV  s   r   c                 C  s   t  | _d S r   )r   _already_warnedr"   r   r   r   __init__  s    z!_IncludePackageDataAbuse.__init__c                 C  s    | do|d td   S )Nz.py)endswithlenisidentifier)r#   rE   r   r   r   rv     s    z"_IncludePackageDataAbuse.is_modulec                 C  s6   t |j}tttj|j}|r2d|f|S d S )NrA   )	r   parentr;   rT   	takewhiler%   r   partsrJ   )r#   r   rE   r   r   r   r   r   rw     s
    
z._IncludePackageDataAbuse.importable_subpackagec                 C  s(   || j kr$| jj|d | j | d S )N)r|   )r   r   emitadd)r#   r|   r   r   r   rx     s    
z_IncludePackageDataAbuse.warnN)
r   r   r   r   r   r   r   rv   rw   rx   r   r   r   r   rt   S  s   +rt   )Z
__future__r   	functoolsr   r   Zdistutils.utilr   Zdistutils.command.build_pyZcommandr   r   r   r   r   r   r   rT   r   pathlibr   typingr   r   Zmore_itertoolsr	   warningsr   rS   r   ro   rt   r   r   r   r   <module>   s*     %