U
    ;g;1                     @   s  d 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
 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 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 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! ddlm"Z" ddlm#Z# ddlm$Z$ erdd  Z!d!d" Z%G d#d$ d$eZ&ej'j(d%d&ej'j)ed'd(ej'j)eoe d)d(G d*d+ d+e&Z*ej'j)ed,d(G d-d. d.e*Z+G d/d0 d0e&Z,dS )1a>	  Notes about unicode handling in psutil
======================================.

Starting from version 5.3.0 psutil adds unicode support, see:
https://github.com/giampaolo/psutil/issues/1040
The notes below apply to *any* API returning a string such as
process exe(), cwd() or username():

* all strings are encoded by using the OS filesystem encoding
  (sys.getfilesystemencoding()) which varies depending on the platform
  (e.g. "UTF-8" on macOS, "mbcs" on Win)
* no API call is supposed to crash with UnicodeDecodeError
* instead, in case of badly encoded data returned by the OS, the
  following error handlers are used to replace the corrupted characters in
  the string:
    * Python 3: sys.getfilesystemencodeerrors() (PY 3.6+) or
      "surrogatescape" on POSIX and "replace" on Windows
    * Python 2: "replace"
* on Python 2 all APIs return bytes (str type), never unicode
* on Python 2, you can go back to unicode by doing:

    >>> unicode(p.exe(), sys.getdefaultencoding(), errors="replace")

For a detailed explanation of how psutil handles unicode see #1040.

Tests
=====

List of APIs returning or dealing with a string:
('not tested' means they are not tested to deal with non-ASCII strings):

* Process.cmdline()
* Process.cwd()
* Process.environ()
* Process.exe()
* Process.memory_maps()
* Process.name()
* Process.net_connections('unix')
* Process.open_files()
* Process.username()             (not tested)

* disk_io_counters()             (not tested)
* disk_partitions()              (not tested)
* disk_usage(str)
* net_connections('unix')
* net_if_addrs()                 (not tested)
* net_if_stats()                 (not tested)
* net_io_counters()              (not tested)
* sensors_fans()                 (not tested)
* sensors_temperatures()         (not tested)
* users()                        (not tested)

* WindowsService.binpath()       (not tested)
* WindowsService.description()   (not tested)
* WindowsService.display_name()  (not tested)
* WindowsService.name()          (not tested)
* WindowsService.status()        (not tested)
* WindowsService.username()      (not tested)

In here we create a unicode path with a funky non-ASCII name and (where
possible) make psutil return it back (e.g. on name(), exe(), open_files(),
etc.) and make sure that:

* psutil never crashes with UnicodeDecodeError
* the returned path matches
    N)closing)BSD)POSIX)WINDOWS)PY3)super)APPVEYOR)ASCII_FS)
CI_TESTING)HAS_ENVIRON)HAS_MEMORY_MAPS)HAS_NET_CONNECTIONS_UNIX)INVALID_UNICODE_SUFFIX)PYPYTESTFN_PREFIX)UNICODE_SUFFIX)PsutilTestCase)bind_unix_socket)chdir)copyload_shared_lib)create_py_exe)
get_testfn)pytest)
safe_mkdirsafe_rmpath)skip_on_access_denied)spawn_testproc)	terminatec                 C   s8   ddl m} z
|| W S  tk
r2   t  Y nX d S )Nr   r   )psutil.testsr   ZWindowsError	traceback	print_exc)pathZrm r$   =/tmp/pip-unpacked-wheel-u0epr1ex/psutil/tests/test_unicode.pyr   q   s
    
r   c              	   C   s   d}t | d}zhz<t| t| t|gd}t||d  t|d  W n ttfk
rj   Y W dS X W dS W 5 |dk	rt| t| X dS )z`Return True if both the fs and the subprocess module can
    deal with a unicode file name.
    Nsuffix)cmdz-2FT)	r   r   r   r   r   shutilcopyfileUnicodeEncodeErrorIOError)r'   sprocZtestfnr$   r$   r%   try_unicode   s    
r.   c                       s0   e Zd ZdZe fddZ fddZ  ZS )BaseUnicodeTestNc                    sN   t    d| _d | _| jd k	rJt| js2d| _nt| jd| _t| j d S )NFTr&   )r   
setUpClass
skip_tests
funky_namefunky_suffixr.   r   r   )cls	__class__r$   r%   r0      s    


zBaseUnicodeTest.setUpClassc                    s   t    | jrtdd S )Nzcan't handle unicode str)r   setUpr1   r   skipselfr5   r$   r%   r7      s    
zBaseUnicodeTest.setUp)__name__
__module____qualname__r3   classmethodr0   r7   __classcell__r$   r$   r5   r%   r/      s   r/   serial)namezASCII fsreasonztoo much trouble on PYPY2c                   @   s   e Zd ZdZeZdd Zdd Zdd Zdd	 Z	d
d Z
ejjeoDedddd Zejje dddd Zejje ddejje dde dd Zdd Zejje ddejje ddejjedddd ZdS )
TestFSAPIsz1Test FS APIs with a funky, valid, UTF8 path name.c              
   C   sN   t | jtrdnd}t ( td | jt|kW  5 Q R  S Q R X d S )N.ignore)
isinstancer2   strwarningscatch_warningssimplefilteroslistdir)r:   herer$   r$   r%   expect_exact_path_match   s    

z"TestFSAPIs.expect_exact_path_matchc                 C   sb   | j ddg}| |}t|j}| }t|ts8t| 	 r^t
j|t
j| j ks^td S Nz-cz2import time; [time.sleep(0.1) for x in range(100)])r2   r   psutilProcesspidexerG   rH   AssertionErrorrO   rL   r#   normcase)r:   r(   subpprT   r$   r$   r%   test_proc_exe   s    
zTestFSAPIs.test_proc_exec                 C   sV   | j ddg}| |}t|j }t|ts4t| 	 rR|t
j| j ksRtd S rP   )r2   r   rQ   rR   rS   rA   rG   rH   rU   rO   rL   r#   basename)r:   r(   rW   rA   r$   r$   r%   test_proc_name   s    
zTestFSAPIs.test_proc_namec                 C   sZ   | j ddg}| |}t|j}| }|D ]}t|ts.tq.| 	 rV||ksVtd S rP   )
r2   r   rQ   rR   rS   cmdlinerG   rH   rU   rO   )r:   r(   rW   rX   r\   partr$   r$   r%   test_proc_cmdline   s    
zTestFSAPIs.test_proc_cmdlinec              	   C   sl   | j d }| t| t| t| t }| }W 5 Q R X t| t	sTt
|  rh||ksht
d S N2)r2   
addCleanupr   r   r   rQ   rR   cwdrG   rH   rU   rO   )r:   dnamerX   rb   r$   r$   r%   test_proc_cwd   s    

zTestFSAPIs.test_proc_cwdzfails on PYPY + WINDOWSrB   c              	   C   s   t  }t| }t| jd t| }W 5 Q R X ||  j}t|t	sTt
trf|sftd|  rtj|tj| jkst
d S )Nrbzopen_files on BSD is broken)rQ   rR   setZ
open_filesopenr2   popr#   rG   rH   rU   r   r   r8   rO   rL   rV   )r:   rX   startnewr#   r$   r$   r%   test_proc_open_files   s    
zTestFSAPIs.test_proc_open_filesz
POSIX onlyc              	   C   s   | j | jd}zt|}W n& tk
r@   tr2 n
tdY nX t|6 t	 
dd }t|jtsnt|j|ks|tW 5 Q R X d S )Nr&   not supportedunixr   )r   r3   r   r+   r   r   r8   r   rQ   rR   net_connectionsrG   laddrrH   rU   )r:   rA   sockconnr$   r$   r%   test_proc_net_connections  s    
z$TestFSAPIs.test_proc_net_connectionszcan't list UNIX socketsc              	   C   s   dd }| j | jd}zt|}W n& tk
rH   tr: n
tdY nX t|8 tj	dd}||}t
|jtsxt|j|kstW 5 Q R X d S )Nc                 S   s2   | D ] }t j|jtr|  S qtdd S )Nzconnection not found)rL   r#   rZ   ro   
startswithr   
ValueError)consrq   r$   r$   r%   	find_sock  s    
z2TestFSAPIs.test_net_connections.<locals>.find_sockr&   rl   rm   )kind)r   r3   r   r+   r   r   r8   r   rQ   rn   rG   ro   rH   rU   )r:   rv   rA   rp   ru   rq   r$   r$   r%   test_net_connections  s    
zTestFSAPIs.test_net_connectionsc                 C   s,   | j d }| t| t| t| d S r_   )r2   ra   r   r   rQ   
disk_usage)r:   rc   r$   r$   r%   test_disk_usage/  s    
zTestFSAPIs.test_disk_usagerl   z&ctypes does not support unicode on PY2zunstable on PYPYc              	      st   t | jd^}dd   fddt  D }dd |D } ||ksNt|D ]}t|tsRtqRW 5 Q R X d S )Nr&   c                 S   s   t jt j| S )N)rL   r#   realpathrV   )rX   r$   r$   r%   normpath?  s    z-TestFSAPIs.test_memory_maps.<locals>.normpathc                    s   g | ]} |j qS r$   )r#   .0xr|   r$   r%   
<listcomp>B  s    z/TestFSAPIs.test_memory_maps.<locals>.<listcomp>c                 S   s   g | ]}t |kr|qS r$   r   r}   r$   r$   r%   r   F  s      )r   r3   rQ   rR   Zmemory_mapsrU   rG   rH   )r:   Z
funky_pathZlibpathsr#   r$   r   r%   test_memory_maps5  s    

zTestFSAPIs.test_memory_mapsN)r;   r<   r=   __doc__r   r3   rO   rY   r[   r^   rd   r   markskipifr   r   rk   r   rr   r   r   rx   rz   r   r   r   r$   r$   r$   r%   rD      s4   


  rD   zunreliable on CIc                   @   s   e Zd ZdZeZdd ZdS )TestFSAPIsWithInvalidPathz-Test FS APIs with a funky, invalid path name.c                 C   s   dS )NTr$   r9   r$   r$   r%   rO   R  s    z1TestFSAPIsWithInvalidPath.expect_exact_path_matchN)r;   r<   r=   r   r   r3   rO   r$   r$   r$   r%   r   L  s   r   c                   @   sJ   e Zd ZdZerendZejj	e
 ddejj	eo4edddd ZdS )	TestNonFSAPISz&Unicode tests for non fs-related APIs.   èrl   rB   zsegfaults on PYPY + WINDOWSc                 C   sx   t j }| j|d< | j|d}t|j}| }| D ]$\}}t	|t
sRtt	|t
s<tq<|d | jksttd S )NZ	FUNNY_ARG)env)rL   environcopyr3   r   rQ   rR   rS   itemsrG   rH   rU   )r:   r   r-   rX   kvr$   r$   r%   test_proc_environa  s    

zTestNonFSAPIS.test_proc_environN)r;   r<   r=   r   r   r   r3   r   r   r   r   r   r   r   r$   r$   r$   r%   r   \  s
   r   )-r   rL   r)   r!   rI   
contextlibr   rQ   r   r   r   Zpsutil._compatr   r   r    r   r	   r
   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r.   r/   r   Zxdist_groupr   rD   r   r   r$   r$   r$   r%   <module>   sZ   C 