U
    puf]P                     @   s  d Z ddl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
Z
ddlmZ ddlmZ ddlmZ eded	gZd
dgZdaG dd deZedAddZdBddZdd ZdCedddZdd ZdDddZdd  Zd!d" ZdEd$d%Z dFd&d'Z!dGd(d)Z"d*d+ Z#d,d- Z$d.d/ Z%d0d1 Z&d2d3 Z'd4d5 Z(d6d7 Z)d8d9 Z*d:d; Z+d<d= Z,d>d? Z-e.d@kre-  dS )Ha  pipreqs - Generate pip requirements.txt file based on imports

Usage:
    pipreqs [options] [<path>]

Arguments:
    <path>                The path to the directory containing the application
                          files for which a requirements file should be
                          generated (defaults to the current working
                          directory).

Options:
    --use-local           Use ONLY local package info instead of querying PyPI.
    --pypi-server <url>   Use custom PyPi server.
    --proxy <url>         Use Proxy, parameter will be passed to requests
                          library. You can also just set the environments
                          parameter in your terminal:
                          $ export HTTP_PROXY="http://10.10.1.10:3128"
                          $ export HTTPS_PROXY="https://10.10.1.10:1080"
    --debug               Print debug information
    --ignore <dirs>...    Ignore extra directories, each separated by a comma
    --no-follow-links     Do not follow symbolic links in the project
    --encoding <charset>  Use encoding parameter for file open
    --savepath <file>     Save the list of requirements in the given file
    --print               Output the list of requirements in the standard
                          output
    --force               Overwrite existing requirements.txt
    --diff <file>         Compare modules in requirements.txt to project
                          imports
    --clean <file>        Clean up requirements.txt by removing modules
                          that are not imported in project
    --mode <scheme>       Enables dynamic versioning with <compat>,
                          <gt> or <non-pin> schemes.
                          <compat> | e.g. Flask~=1.1.2
                          <gt>     | e.g. Flask>=1.1.2
                          <no-pin> | e.g. Flask
    --scan-notebooks      Look for imports in jupyter notebook files.
    )contextmanagerN)docopt)json2package)	HTTPError)__version__z^import (.+)$z!^from ((?!\.+).*?) import (?:.*)$z.pyz.pywFc                       s$   e Zd ZdZef fdd	Z  ZS )NbconvertNotInstalledzVIn order to scan jupyter notebooks, please install the nbconvert and ipython librariesc                    s   t  | d S N)super__init__)selfmessage	__class__ 3/tmp/pip-unpacked-wheel-prro_duw/pipreqs/pipreqs.pyr
   A   s    zNbconvertNotInstalled.__init__)__name__
__module____qualname__Zdefault_messager
   __classcell__r   r   r   r   r   <   s   r   rc              	   c   st   | r| dkr@|rd|kr t j}qJd|kr0t j}qJtd|n
t| |}z
|V  W 5 |t jt jfkrn|  X dS )a  Open a file or ``sys.stdout`` depending on the provided filename.

    Args:
        filename (str): The path to the file that should be opened. If
            ``None`` or ``'-'``, ``sys.stdout`` or ``sys.stdin`` is
            returned depending on the desired mode. Defaults to ``None``.
        mode (str): The mode that should be used to open the file.

    Yields:
        A file handle.

    -r   wzInvalid mode for file: {}N)sysstdinstdout
ValueErrorformatopenclose)filenamemodefiler   r   r   _openE   s    

r"   utf-8Tc                    sN  t  }t  }g }d}dddddddd	g|r^g }|D ]}	|tjtj|	 q4| t  tj| |d
}
|
D ]P\}}}fdd|D |d d < |tj| dd |D }|dd |D   fdd|D }|D ]}tj	||}t
||}zdt|}t|D ]J}t|tjrF|jD ]}||j q0nt|tjr||j qW q tk
r } z>|rt| td|  W Y qntd|  |W 5 d }~X Y qX qqvdd |D D ] }|d\}}}|| q|t ||@  }td| tt	dd}dd |D }W 5 Q R X t|| S )NFz.hgz.svnz.gitz.tox__pycache__envvenvz.ipynb_checkpoints)followlinksc                    s   g | ]}| kr|qS r   r   ).0d)ignore_dirsr   r   
<listcomp>~   s      z#get_all_imports.<locals>.<listcomp>c                 S   s   g | ]}t |tr|qS r   )file_ext_is_allowedDEFAULT_EXTENSIONS)r(   r!   r   r   r   r+      s     
 c                 S   s   g | ]}t j|d  qS r   ospathsplitext)r(   r   r   r   r   r+      s     c                    s   g | ]}t | r|qS r   )r,   )r(   fn)
extensionsr   r   r+      s     
 zFailed on file: %sc                 S   s   g | ]}|r|qS r   r   )r(   nr   r   r   r+      s      .zFound packages: {0}stdlibr   c                 S   s   h | ]}|  qS r   stripr(   xr   r   r   	<setcomp>   s     z"get_all_imports.<locals>.<setcomp>)setappendr0   r1   basenamerealpathextendget_file_extensionswalkjoinread_file_contentastparse
isinstanceZImportnamesaddnameZ
ImportFrommodule	Exception	traceback	print_excloggingwarnerror	partitiondebugr   r   list)r1   encodingextra_ignore_dirsfollow_linksimportsZraw_imports
candidatesignore_errorsZignore_dirs_parsederC   rootdirsfilespy_files	file_namecontentstreenodeZsubnodeexcrK   Zcleaned_name_packagesfdatar   )r4   r*   r   get_all_importsd   sh    





rj   c                   C   s   t rtdg S tS )N.ipynb)scan_noteboooksr-   r   r   r   r   rB      s    rB   )ra   c              	   C   sN   t | tr.t| d|d}| }W 5 Q R X nt | dgrJtrJt| |d}|S )Nr   rV   rk   )r,   r-   r   readrl   
ipynb_2_py)ra   rV   rh   rb   r   r   r   rE      s    
rE   c                 C   s   t j| d |kS )N   r/   )ra   Z
acceptabler   r   r   r,      s    r,   c                 C   s   t  }|| \}}||S )z

    Args:
        file_name (str): notebook file path to parse as python script
        encoding  (str): encoding of file

    Returns:
        str: parsed string

    )PythonExporterfrom_filenameencode)ra   rV   Zexporterbodyrf   r   r   r   ro      s    ro   c              
      sr   t | d^}tdjt|| ddd |D d d| d  |d	 fd
d|D d	  W 5 Q R X d S )Nr   z/Writing {num} requirements: {imports} to {file}, c                 S   s   g | ]}|d  qS rK   r   r:   r   r   r   r+      s     z.generate_requirements_file.<locals>.<listcomp>)numr!   rY   {name}z	{version}
c                 3   s.   | ]&}|d  r j f |n
dj f |V  qdS )versionrx   N)r   r(   itemfmtr   r   	<genexpr>   s   z-generate_requirements_file.<locals>.<genexpr>)r"   rP   rT   r   lenrD   write)r1   rY   symbolout_filer   r}   r   generate_requirements_file   s       r   c                 C   s   t d| | d S )Nr   )r   )rY   r   r   r   r   output_requirements   s    r   https://pypi.python.org/pypi/c              	   C   s   g }| D ]}zrt d| tjd|||d}|jdkrbt|jdrVt|j	 }q|t|j}n|jdkr|t
|j|jdW n$ t
k
r   t d| Y qY nX t d	||j|j|j |||jd
 q|S )NzMImport named "%s" not found locally. Trying to resolve it at the PyPI server.z{0}{1}/json)proxies   decodei,  )status_codereasonz/Package "%s" does not exist or network problemszImport named "%s" was resolved to "%s:%s" package (%s).
Please, verify manually the final list of requirements.txt to avoid possible dependency confusions.rK   rz   )rP   warningrequestsgetr   r   hasattrcontentr   r   r   r   rK   Zlatest_release_idpypi_urlr>   )rY   pypi_serverproxyresultr|   responseri   r   r   r   get_imports_info   s4    


	r   c                 C   s*  g }dddddg}t jD ]
}t|D ]\}}}|D ]}d|kr6tj||}t|d| d}|tjd	 d
}	z| 	 d}
W n   Y W 5 Q R  q6Y nX t
 }|
D ]"}||kr|	d |kr|| qd }t|	dkr |	d dddd}||	d ||d W 5 Q R X q6q(q|S )NtestsZ_testsZeggZEGGinfoZ	top_levelr   rm   r   ry   r   rp   z.dist z.egg)rK   rz   exports)r   r1   r0   rC   rD   r   splitseprn   r9   rU   r>   r   replace)rV   rg   ignorer1   r]   r^   r_   r|   rh   packageZtop_level_modulesZfiltered_top_level_modulesrL   rz   r   r   r   get_locally_installed_packages  s6    r   c                    sZ   t  }g  | D ]0}|D ]&}||d ks2||d kr | qq fddt D }|S )Nr   rK   c                    s(   g | ] \}}| |d  d kr|qS )rp   Nr   )r(   r5   ir   r   r   r+   ?  s      z$get_import_local.<locals>.<listcomp>)r   r>   	enumerate)rY   rV   localr|   r   Zresult_uniquer   r   r   get_import_local/  s    r   c              	   C   s^   t  }ttdd}tdd |D }W 5 Q R X | D ]}|||| q6t|dd dS )zGet PyPI package names from a list of imports.

    Args:
        pkgs (List[str]): List of import names.

    Returns:
        List[str]: The corresponding PyPI package names.

    mappingr   c                 s   s   | ]}|  d V  qdS ):N)r9   r   r:   r   r   r   r   P  s     z get_pkg_names.<locals>.<genexpr>c                 S   s   |   S r   lower)sr   r   r   <lambda>V      zget_pkg_names.<locals>.<lambda>key)r=   r   rD   dictrJ   r   sorted)pkgsr   rh   ri   pkgr   r   r   get_pkg_namesD  s    
r   c                 C   sH   d| kr,t d |  }|r,|dd } | dd dd  S )Nzimport r   z as r6   )REGEXPmatchr9   groupsrS   )rK   r   r   r   r   get_name_without_aliasY  s
    r   c                 C   s   t jt jt| S r   )r0   r1   rD   dirname__file__)rh   r   r   r   rD   a  s    rD   c           
   
      sH  g }dddddg}zt | d}W nl tk
rN   td|  d td	 Y nb tk
r } z"td
|  dt|  |W 5 d}~X Y n$X zdd |
 D }W 5 |	  X dd |D }|D ] t fdd|D s| dd  D ]P}||kr |}|d }|d dd}	||	d}||kr<||  qqq|S )u9  Parse a requirements formatted file.

    Traverse a string until a delimiter is detected, then split at said
    delimiter, get module name by element index, create a dict consisting of
    module:version, and add dict to list of parsed modules.

    If file ´file_´ is not found in the system, the program will print a
    helpful message and end its execution immediately.

    Args:
        file_: File to parse.

    Raises:
        OSerror: If there's any issues accessing the file.

    Returns:
        list: The contents of the file, excluding comments.
    <>=!~r   zFile z- was not found. Please, fix it and run again.rp   z$There was an error opening the file z: Nc                 S   s   g | ]}|d kr|  qS )ry   r8   r:   r   r   r   r+     s      z&parse_requirements.<locals>.<listcomp>c                 S   s   g | ]}|d    r|qS r.   )isalphar:   r   r   r   r+     s      c                    s   g | ]}| kqS r   r   )r(   yr;   r   r   r+     s     r   r   r   r   )r   FileNotFoundErrorprintr   exitOSErrorrP   rR   strr   	readlinesanyr>   r   r   )
file_modulesdelimrh   rR   ri   r   rL   module_nameZmodule_versionr   r   r   parse_requirementse  s6    




r   c                    sP   t |  fddtt D  fddttD tt  }|S )a>  Compare modules in a file to imported modules in a project.

    Args:
        file_ (str): File to parse for modules to be compared.
        imports (tuple): Modules being imported in the project.

    Returns:
        set: The modules not imported in the project, but do exist in the
            specified file.
    c                    s   g | ]} | d  qS rv   r   r(   r   )rY   r   r   r+     s     z#compare_modules.<locals>.<listcomp>c                    s   g | ]} | d  qS rv   r   r   )r   r   r   r+     s     )r   ranger   r=   r   rY   modules_not_importedr   )rY   r   r   compare_modules  s
    r   c              	   C   s0   t | |}td| ddd |D  dS )zFDisplay the difference between modules in a file and imported modules.zBThe following modules are in {} but do not seem to be imported: {}ru   c                 s   s   | ]
}|V  qd S r   r   r:   r   r   r   r     s     zdiff.<locals>.<genexpr>N)r   rP   r   r   rD   r   r   r   r   diff  s    
 r   c                 C   s   t | |}t|dkr(td|   dS td|}g }zt| d}W n& tk
rp   t	d
|   Y n^X zP| D ]}||dkr||| q||d |  |D ]}|| qW 5 |  X td|   dS )z9Remove modules that aren't imported in project from file.r   zNothing to clean in N|zr+zFailed on file: {}z(Successfully cleaned up requirements in )r   r   rP   r   recompilerD   r   r   rR   r   r   r   r   r>   seektruncater   )r   rY   r   Z	re_removeZto_writerh   r   r   r   r   clean  s*    


r   c                 C   s>   | dkrdd |D }d}n| dkr*d}n| dkr6d}||fS )	zDEnables dynamic versioning with <compat>, <gt> or <non-pin> schemes.no-pinc                 S   s   g | ]}|d  ddqS )rK   r   r   r   r{   r   r   r   r+     s     z&dynamic_versioning.<locals>.<listcomp>r   gtz>=compatz~=r   )schemerY   r   r   r   r   dynamic_versioning  s    r   c                   C   sB   t std d S zddlma W n tk
r<   t Y nX d S )Nz#Not scanning for jupyter notebooks.r   )rq   )rl   rP   r   Z	nbconvertrq   ImportErrorr   r   r   r   r   handle_scan_noteboooks  s    
r   c                    s8  |  d}|  d}|  d }|  ddat  | d }|d krFd}|d kr\tjtj}|rj|d}| d	 rz| d	 ntj|d
}| d s| d	 s| d stj	|rt
d d S t||||d}t|}t
dd|  d}d }| d r| d }| d r| d | d d}| d r<t
d t||d}	n:t
d t||d  fdd|D }
 t|
||d }	t|	dd d}	| d rt| d |	 d S | d  rt| d  |	 d S | d! r|  d!}|d"krt||	\}	}ntd#nd$}| d rt|	| t
d% nt||	| t
d&|  d S )'Nz
--encodingz--ignorez--no-follow-linksz--scan-notebooksFz<path>r#   ,z
--savepathzrequirements.txtz--printz--forcez<requirements.txt already exists, use --force to overwrite it)rV   rW   rX   zFound imports: ru   r   z--pypi-serverz--proxy)httphttpsz--use-localz9Getting package information ONLY from local installation.rm   z,Getting packages information from Local/PyPIc                    s<   g | ]4}|  d d  D kr|  dd  D kr|qS )c                 S   s   g | ]}|d  D ]}|qqS )r   r   )r(   r;   r   r   r   r   r+   7  s     
  z#init.<locals>.<listcomp>.<listcomp>c                 S   s   g | ]}|d  qS rv   r   r:   r   r   r   r+   9  s     r   r:   r   r   r   r+   0  s   zinit.<locals>.<listcomp>)r   r   c                 S   s   | d   S )NrK   r   r   r   r   r   r   >  r   zinit.<locals>.<lambda>r   z--diffz--cleanz--mode)r   r   r   zFInvalid argument for mode flag, use 'compat', 'gt' or 'no-pin' insteadz==z Successfully output requirementsz(Successfully saved requirements file in )r   rl   r   r0   r1   abspathcurdirr   rD   existsrP   r   rj   r   rT   r   r   r   r   r   r   r   r   r   r   )argsrV   rW   rX   Z
input_pathr1   rZ   r   r   rY   
differencer   r   r   r   r   init  s    
















r   c                  C   s^   t ttd} | d rtjntj}tj|dd zt|  W n tk
rX   t	
d Y nX d S )N)rz   z--debugz%(levelname)s: %(message)s)levelr   r   )r   __doc__r   rP   DEBUGINFObasicConfigr   KeyboardInterruptr   r   )r   Z	log_levelr   r   r   main[  s    r   __main__)Nr   )r#   NT)r#   )r#   )r   N)r#   )r#   )/r   
contextlibr   r0   r   r   rP   rF   rN   r   r   Zyargr   Zyarg.exceptionsr   Zpipreqsr   r   r   r-   rl   r   r   r"   rj   rB   r   rE   r,   ro   r   r   r   r   r   r   r   rD   r   r   r   r   r   r   r   r   r   r   r   r   r   <module>   sR   &	
J	

!
)
;
 e
