U
    (c0                     @   s8  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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% ddlm&Z& erd d! Z"d"d# Z'G d$d% d%eZ(e#e)ed&e)eoe d'G d(d) d)e(Z*e)ed*G d+d, d,e*Z+G d-d. d.e(Z,e-d/kr4dd0l.m/Z/ e/e0 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.connections('unix')
* Process.cwd()
* Process.environ()
* Process.exe()
* Process.memory_maps()
* Process.name()
* 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)OPENBSD)POSIX)WINDOWS)PY3)u)APPVEYOR)ASCII_FS)
CI_TESTING)HAS_CONNECTIONS_UNIX)HAS_ENVIRON)HAS_MEMORY_MAPS)INVALID_UNICODE_SUFFIX)PYPYTESTFN_PREFIX)UNICODE_SUFFIX)PsutilTestCase)bind_unix_socket)chdir)copyload_shared_lib)
create_exe)
get_testfn)
safe_mkdirsafe_rmpath)	serialrun)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-l83rk7k5/psutil/tests/test_unicode.pyr   s   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    
r0   c                   @   s   e Zd ZdZdd ZdS )BaseUnicodeTestNc                 C   s"   | j d k	rt| j s| dd S )Nzcan't handle unicode str)funky_suffixr0   skipTest)selfr%   r%   r&   setUp   s    

zBaseUnicodeTest.setUp)__name__
__module____qualname__r2   r5   r%   r%   r%   r&   r1      s   r1   zASCII fsztoo much trouble on PYPY2c                   @   s   e Zd ZdZeZedd Zedd Zdd Z	dd	 Z
d
d Zdd Zdd ZeeoZeddd Zee ddd Zee dee de dd Zdd Zee dee deeddd Zd S )!
TestFSAPIsz1Test FS APIs with a funky, valid, UTF8 path name.c                 C   s   t | jd| _t| j d S )Nr'   )r   r2   
funky_namer   clsr%   r%   r&   
setUpClass   s    zTestFSAPIs.setUpClassc                 C   s   t | j d S N)r   r:   r;   r%   r%   r&   tearDownClass   s    zTestFSAPIs.tearDownClassc              
   C   sR   t | jtrdntd}t ( td | jt|kW  5 Q R  S Q R X d S )N.ignore)	
isinstancer:   strr   warningscatch_warningssimplefilteroslistdir)r4   herer%   r%   r&   expect_exact_path_match   s    

z"TestFSAPIs.expect_exact_path_matchc                 C   sZ   | j | jgd}t|j}| }| |t |  rV| 	t
j|t
j| j d S Nr)   )r   r:   psutilProcesspidexeassertIsInstancerC   rJ   assertEqualrG   r$   normcase)r4   subpprO   r%   r%   r&   test_proc_exe   s    zTestFSAPIs.test_proc_exec                 C   sN   | j | jgd}t|j }| |t |  rJ| 	|t
j| j d S rK   )r   r:   rL   rM   rN   namerP   rC   rJ   rQ   rG   r$   basename)r4   rS   rV   r%   r%   r&   test_proc_name   s
    zTestFSAPIs.test_proc_namec                 C   sV   | j | jgd}t|j}| }|D ]}| |t q(|  rR| 	|| jg d S rK   )
r   r:   rL   rM   rN   cmdlinerP   rC   rJ   rQ   )r4   rS   rT   rY   partr%   r%   r&   test_proc_cmdline   s    zTestFSAPIs.test_proc_cmdlinec              	   C   sj   | j d }| t| t| t| t }| }W 5 Q R X | | t	 | 
 rf| || d S N2)r:   
addCleanupr   r   r   rL   rM   cwdrP   rC   rJ   rQ   )r4   dnamerT   r_   r%   r%   r&   test_proc_cwd   s    

zTestFSAPIs.test_proc_cwdzfails on PYPY + WINDOWSc              	   C   s   t  }t| }t| jd t| }W 5 Q R X ||  j}| |t	 t
rd|sd| dS |  r| tj|tj| j d S )Nrbzopen_files on BSD is broken)rL   rM   setZ
open_filesopenr:   popr$   rP   rC   r   r3   rJ   rQ   rG   rR   )r4   rT   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|8 t	 
dd }| |jt ts~| |j| W 5 Q R X d S )Nr'   not supportedunixr   )r   r2   r   r-   r   unittestSkipTestr   rL   rM   connectionsrP   laddrrC   r   rQ   )r4   rV   sockconnr%   r%   r&   test_proc_connections   s    
z TestFSAPIs.test_proc_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|: tj	dd}t
s||}| |jt | |j| 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)rG   r$   rW   rn   
startswithr   
ValueError)consrp   r%   r%   r&   	find_sock  s    
z2TestFSAPIs.test_net_connections.<locals>.find_sockr'   ri   rj   )kind)r   r2   r   r-   r   rk   rl   r   rL   Znet_connectionsr   rP   rn   rC   rQ   )r4   ru   rV   ro   rt   rp   r%   r%   r&   test_net_connections  s    
zTestFSAPIs.test_net_connectionsc                 C   s,   | j d }| t| t| t| d S r\   )r:   r^   r   r   rL   
disk_usage)r4   r`   r%   r%   r&   test_disk_usage"  s    
zTestFSAPIs.test_disk_usageri   z&ctypes does not support unicode on PY2zunstable on PYPYc              	      sr   t | jd\}dd   fddt  D }dd |D }|  || |D ]}| |t qRW 5 Q R X d S )Nr'   c                 S   s   t jt j| S r>   )rG   r$   realpathrR   )rT   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>1  s   z/TestFSAPIs.test_memory_maps.<locals>.<listcomp>c                 S   s   g | ]}t |kr|qS r%   r   r|   r%   r%   r&   r   4  s      )r   r2   rL   rM   Zmemory_mapsZassertInrP   rC   )r4   Z
funky_pathZlibpathsr$   r%   r   r&   test_memory_maps(  s    

zTestFSAPIs.test_memory_mapsN)r6   r7   r8   __doc__r   r2   classmethodr=   r?   rJ   rU   rX   r[   ra   rk   skipIfr   r   rh   r   rq   r   r   rw   ry   r   r   r   r%   r%   r%   r&   r9      s0   


		


r9   zunreliable on CIc                   @   s    e Zd ZdZeZedd ZdS )TestFSAPIsWithInvalidPathz-Test FS APIs with a funky, invalid path name.c                 C   s   dS )NTr%   r;   r%   r%   r&   rJ   ?  s    z1TestFSAPIsWithInvalidPath.expect_exact_path_matchN)r6   r7   r8   r   r   r2   r   rJ   r%   r%   r%   r&   r   :  s   r   c                   @   sB   e Zd ZdZerendZee	 dee
o.eddd ZdS )TestNonFSAPISz&Unicode tests for non fs-related APIs.   èri   zsegfaults on PYPY + WINDOWSc                 C   st   t j }| j|d< | j|d}t|j}| }| D ] \}}| 	|t
 | 	|t
 q<| |d | j d S )NZ	FUNNY_ARG)env)rG   environcopyr2   r   rL   rM   rN   itemsrP   rC   rQ   )r4   r   r/   rT   kvr%   r%   r&   test_proc_environN  s    

zTestNonFSAPIS.test_proc_environN)r6   r7   r8   r   r   r   r2   rk   r   r   r   r   r   r%   r%   r%   r&   r   J  s
   r   __main__)run_from_name)1r   rG   r+   r"   rk   rD   
contextlibr   rL   r   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    r0   r1   r   r9   r   r   r6   Zpsutil.tests.runnerr   __file__r%   r%   r%   r&   <module>   sd   D	
 

