o
    ˆ¶¹a«0  ã                   @   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$ ddlm%Z% dd lm&Z& erÐd!d"„ Z!d#d$„ Z'G d%d&„ d&eƒZ(e"e& )ed'¡e& )eoèe d(¡G d)d*„ d*e(ƒƒƒƒZ*e& )ed+¡G d,d-„ d-e*ƒƒZ+G d.d/„ d/e(ƒZ,e-d0k�rdd1l.m/Z/ e/e0ƒ dS dS )2a:	  
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)Ú	terminate)Úunittestc                 C   s4   ddl m} z|| ƒW S  ty   t ¡  Y d S w )Nr   r   )Úpsutil.testsr   ÚWindowsErrorÚ	tracebackÚ	print_exc)ÚpathÚrm© r(   ú;/usr/lib/python3/dist-packages/psutil/tests/test_unicode.pyr   s   s   
ÿr   c              	   C   s¸   d}t | d�}zGzt|ƒ t|ƒ t|gd�}t ||d ¡ t|d ƒ W n ttfy?   Y W |dur9t|ƒ t|ƒ dS w W |durIt|ƒ t|ƒ dS |durWt|ƒ t|ƒ w )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   ÚshutilÚcopyfileÚUnicodeEncodeErrorÚIOErrorr    )r+   ÚsprocÚtestfnr(   r(   r)   Útry_unicode…   s*   
ùþ
r4   c                   @   s   e Zd ZdZdd„ ZdS )ÚBaseUnicodeTestNc                 C   s&   | j d urt| j ƒs|  d¡‚d S d S )Nzcan't handle unicode str)Úfunky_suffixr4   ÚskipTest)Úselfr(   r(   r)   ÚsetUp£   s
   


þzBaseUnicodeTest.setUp)Ú__name__Ú
__module__Ú__qualname__r6   r9   r(   r(   r(   r)   r5       s    r5   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o-e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   r6   Ú
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   s^   t | jtƒrdntdƒ}t ¡ � t d¡ | jt |¡v W  d   ƒ S 1 s(w   Y  d S )NÚ.Úignore)	Ú
isinstancer>   Ústrr   ÚwarningsÚcatch_warningsÚsimplefilterÚosÚlistdir)r8   Úherer(   r(   r)   Úexpect_exact_path_matchº   s
   

$þz"TestFSAPIs.expect_exact_path_matchc                 C   s^   | j | jgd�}t |j¡}| ¡ }|  |t¡ |  ¡ r-|  	t
j |¡t
j | j¡¡ d S d S ©Nr,   )r   r>   ÚpsutilÚProcessÚpidÚexeÚassertIsInstancerG   rN   ÚassertEqualrK   r&   Únormcase)r8   ÚsubpÚprS   r(   r(   r)   Útest_proc_exeÄ   s   ÿÿzTestFSAPIs.test_proc_exec                 C   sR   | j | jgd�}t |j¡ ¡ }|  |t¡ |  ¡ r'|  	|t
j | j¡¡ d S d S rO   )r   r>   rP   rQ   rR   ÚnamerT   rG   rN   rU   rK   r&   Úbasename)r8   rW   rZ   r(   r(   r)   Útest_proc_nameÍ   s   ÿzTestFSAPIs.test_proc_namec                 C   sZ   | j | jgd�}t |j¡}| ¡ }|D ]}|  |t¡ q|  ¡ r+|  	|| jg¡ d S d S rO   )
r   r>   rP   rQ   rR   ÚcmdlinerT   rG   rN   rU   )r8   rW   rX   r]   Úpartr(   r(   r)   Útest_proc_cmdlineÔ   s   ÿzTestFSAPIs.test_proc_cmdlinec                 C   s‚   | j d }|  t|¡ t|ƒ t|ƒ� t ¡ }| ¡ }W d   ƒ n1 s&w   Y  |  | ¡ t	¡ |  
¡ r?|  ||¡ d S d S ©NÚ2)r>   Ú
addCleanupr   r   r   rP   rQ   ÚcwdrT   rG   rN   rU   )r8   ÚdnamerX   rc   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 d   ƒ n1 s!w   Y  ||  ¡ j}|  |t	¡ t
r<|s<|  d¡S |  ¡ rQ|  tj |¡tj | j¡¡ d S d S )NÚrbzopen_files on BSD is broken)rP   rQ   ÚsetÚ
open_filesÚopenr>   Úpopr&   rT   rG   r   r7   rN   rU   rK   rV   )r8   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y   tr‚ t d¡‚w t|ƒ�* t 	¡  
d¡d }|  |jt¡ tsC|  |j|¡ W d   ƒ d S W d   ƒ d S 1 sNw   Y  d S )Nr*   únot supportedÚunixr   )r   r6   r   r0   r   r!   ÚSkipTestr   rP   rQ   ÚconnectionsrT   ÚladdrrG   r   rU   )r8   rZ   Ú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y    tr‚ t d¡‚w t|ƒ�+ tj	dd�}t
sH||ƒ}|  |jt¡ |  |j|¡ W d   ƒ d S W d   ƒ d S 1 sSw   Y  d S )Nc                 S   s.   | D ]}t j |j¡ t¡r|  S qtdƒ‚)Nzconnection not found)rK   r&   r[   rr   Ú
startswithr   Ú
ValueError)Úconsrt   r(   r(   r)   Ú	find_sock  s
   ÿz2TestFSAPIs.test_net_connections.<locals>.find_sockr*   rn   ro   )Úkind)r   r6   r   r0   r   r!   rp   r   rP   Únet_connectionsr   rT   rr   rG   rU   )r8   ry   rZ   rs   rx   rt   r(   r(   r)   Útest_net_connections  s$   
ü
ú"ýzTestFSAPIs.test_net_connectionsc                 C   s,   | j d }|  t|¡ t|ƒ t |¡ d S r`   )r>   rb   r   r   rP   Ú
disk_usage)r8   rd   r(   r(   r)   Útest_disk_usage"  s   
zTestFSAPIs.test_disk_usagern   z&ctypes does not support unicode on PY2zunstable on PYPYc                    sˆ   t | jd��4}dd„ ‰ ‡ fdd„t ¡  ¡ D ƒ}dd„ |D ƒ}|  ˆ |ƒ|¡ |D ]}|  |t¡ q)W d   ƒ d S 1 s=w   Y  d S )Nr*   c                 S   s   t j t j | ¡¡S rB   )rK   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>1  s    ÿz/TestFSAPIs.test_memory_maps.<locals>.<listcomp>c                 S   s   g | ]}t |v r|‘qS r(   r   r�   r(   r(   r)   r…   4  s    )r   r6   rP   rQ   Úmemory_mapsÚassertInrT   rG   )r8   Ú
funky_pathÚlibpathsr&   r(   r„   r)   Útest_memory_maps(  s   

ÿÿ"øzTestFSAPIs.test_memory_mapsN)r:   r;   r<   Ú__doc__r   r6   ÚclassmethodrA   rC   rN   rY   r\   r_   re   r!   ÚskipIfr   r   rm   r   ru   r   r   r|   r~   r   r   rŠ   r(   r(   r(   r)   r=   ©   s2    


		


r=   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)   rN   ?  s   z1TestFSAPIsWithInvalidPath.expect_exact_path_matchN)r:   r;   r<   r‹   r   r6   rŒ   rN   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.õ   Ã¨rn   zsegfaults on PYPY + WINDOWSc                 C   st   t j ¡ }| j|d< | j|d�}t |j¡}| ¡ }| ¡ D ]\}}|  	|t
¡ |  	|t
¡ q|  |d | j¡ d S )NÚ	FUNNY_ARG)Úenv)rK   ÚenvironÚcopyr6   r   rP   rQ   rR   ÚitemsrT   rG   rU   )r8   r’   r2   rX   ÚkÚvr(   r(   r)   Útest_proc_environN  s   

zTestNonFSAPIS.test_proc_environN)r:   r;   r<   r‹   r   r   r6   r!   r�   r   r   r   r˜   r(   r(   r(   r)   r�   J  s    r�   Ú__main__)Úrun_from_name)1r‹   rK   r.   r$   rH   Ú
contextlibr   rP   r   r   r   r   Ú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!   r4   r5   r�   r=   rŽ   r�   r:   Úpsutil.tests.runnerrš   Ú__file__r(   r(   r(   r)   Ú<module>   sh   D	
 

þ