
    f1                        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rd  Z"d! Z' G d" d#e      Z(e# ejR                  ed$       ejR                  exr e d%       G d& d'e(                           Z* ejR                  ed(       G d) d*e*             Z+ G d+ d,e(      Z,e-d-k(  rdd.l.m/Z/  e/e0       yy)/a:	  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)POSIX)WINDOWS)PY3)super)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_py_exe)
get_testfn)
safe_mkdirsafe_rmpath)	serialrun)skip_on_access_denied)spawn_testproc)	terminatec                 f    ddl m} 	  ||       S # t        $ r t        j                          Y y w xY w)Nr   r   )psutil.testsr   WindowsError	traceback	print_exc)pathrms     ;/usr/lib/python3/dist-packages/psutil/tests/test_unicode.pyr   r   s   s0     	3	"d8O 	"!	"s    00c                 |   d}t        |       }	 t        |       t        |       t        |g      }t	        j
                  ||dz          t        |dz          	 |t        |       t        |       y# t        t        f$ r Y |t        |       t        |       yw xY w# |t        |       t        |       w xY w)z`Return True if both the fs and the subprocess module can
    deal with a unicode file name.
    Nsuffix)cmdz-2TF)	r   r   r   r   shutilcopyfiler    UnicodeEncodeErrorIOError)r+   sproctestfns      r(   try_unicoder3      s     Ev&FFfF8,.FTM" eF (  eF
 eFs$   A
A4 4BB! BB! !B;c                   6     e Zd ZdZe fd       Z fdZ xZS )BaseUnicodeTestNc                    t               j                          d| _        d | _        | j                  Nt        | j                        sd| _        y t        | j                        | _        t        | j                         y y )NFTr*   )r   
setUpClass
skip_tests
funky_namefunky_suffixr3   r   r   )cls	__class__s    r(   r7   zBaseUnicodeTest.setUpClass   sc    's//0!%!+33C3C!Dcnn- (    c                 p    t               j                          | j                  r| j                  d      y )Nzcan't handle unicode str)r   setUpr8   skipTest)selfr<   s    r(   r?   zBaseUnicodeTest.setUp   s*    ??-- :;; r=   )__name__
__module____qualname__r:   classmethodr7   r?   __classcell__)r<   s   @r(   r5   r5      s$    L	. 	.< <r=   r5   zASCII fsztoo much trouble on PYPY2c                      e Zd ZdZeZd Zd Zd Zd Z	d Z
 ej                  exr ed      d        Z ej                  e d	      d
        Z ej                  e d	       ej                  e d       e       d                      Zd Z ej                  e d       ej                  e d       ej                  ed      d                      Zy)
TestFSAPIsz1Test FS APIs with a funky, valid, UTF8 path name.c                    t        | j                  t              rdn
t        d      }t	        j
                         5  t	        j                  d       | j                  t        j                  |      v cd d d        S # 1 sw Y   y xY w)N.ignore)	
isinstancer9   strr	   warningscatch_warningssimplefilteroslistdir)rA   heres     r(   expect_exact_path_matchz"TestFSAPIs.expect_exact_path_match   s`     !#6sAcF$$& 	7!!(+??bjj&66	7 	7 	7s   6A<<Bc                    | j                   ddg}| j                  |      }t        j                  |j                        }|j                         }| j                  |t               | j                         rW| j                  t        j                  j                  |      t        j                  j                  | j                                y y Nz-czimport time; time.sleep(10))r9   r   psutilProcesspidexeassertIsInstancerM   rT   assertEqualrQ   r&   normcase)rA   r,   subpprZ   s        r(   test_proc_exezTestFSAPIs.test_proc_exe   s    &CD""3'NN488$eegc3''')  %rww'7'7'H *r=   c                 ^   | j                   ddg}| j                  |      }t        j                  |j                        j                         }| j                  |t               | j                         r:| j                  |t        j                  j                  | j                                y y rV   )r9   r   rW   rX   rY   namer[   rM   rT   r\   rQ   r&   basename)rA   r,   r^   rb   s       r(   test_proc_namezTestFSAPIs.test_proc_name   s    &CD""3'~~dhh',,.dC('')T277#3#3DOO#DE *r=   c                 "   | j                   ddg}| j                  |      }t        j                  |j                        }|j                         }|D ]  }| j                  |t                | j                         r| j                  ||       y y rV   )
r9   r   rW   rX   rY   cmdliner[   rM   rT   r\   )rA   r,   r^   r_   rf   parts         r(   test_proc_cmdlinezTestFSAPIs.test_proc_cmdline   s    &CD""3'NN488$))+ 	-D!!$,	-'')Wc* *r=   c                 z   | j                   dz   }| j                  t        |       t        |       t	        |      5  t        j                         }|j                         }d d d        | j                  j                         t               | j                         r| j                  |       y y # 1 sw Y   QxY wN2)r9   
addCleanupr   r   r   rW   rX   cwdr[   rM   rT   r\   )rA   dnamer_   rm   s       r(   test_proc_cwdzTestFSAPIs.test_proc_cwd   s    #%U+55\ 	 A%%'C	 	aeegs+'')S%( *		 	s   %B11B:zfails on PYPY + WINDOWSc                 L   t        j                         }t        |j                               }t	        | j
                  d      5  t        |j                               }d d d        |z
  j                         j                  }| j                  |t               t        r|s| j                  d      S | j                         rW| j                  t        j                  j                  |      t        j                  j                  | j
                               y y # 1 sw Y   xY w)Nrbzopen_files on BSD is broken)rW   rX   set
open_filesopenr9   popr&   r[   rM   r   r@   rT   r\   rQ   r]   )rA   r_   startnewr&   s        r(   test_proc_open_fileszTestFSAPIs.test_proc_open_files   s    NNALLN#$//4( 	&alln%C	&e  "''dC(t==!>??'')  &(8(8(I *	& 	&s   DD#z
POSIX onlyc                    | j                  | j                        }	 t        |      }t        |      5  t        j                         j                  d      d   }| j                  |j                  t               | j                  |j                  |       d d d        y # t        $ r t        r t        j                  d      w xY w# 1 sw Y   y xY w)Nr*   not supportedunixr   )r   r:   r   r/   r   unittestSkipTestr   rW   rX   connectionsr[   laddrrM   r\   )rA   rb   sockconns       r(   test_proc_connectionsz TestFSAPIs.test_proc_connections   s    d&7&78	9#D)D T] 	/>>#//7:D!!$**c2TZZ.	/ 	/ " 	9''88		9
	/ 	/s   B  A#C	 &C	Czcan't list UNIX socketsc                    d }| j                  | j                        }	 t        |      }t        |      5  t        j                  d      } ||      }| j                  |j                  t               | j                  |j                  |       d d d        y # t        $ r t        r t        j                  d      w xY w# 1 sw Y   y xY w)Nc                     | D ]B  }t         j                  j                  |j                        j	                  t
              s@|c S  t        d      )Nzconnection not found)rQ   r&   rc   r   
startswithr   
ValueError)consr   s     r(   	find_sockz2TestFSAPIs.test_net_connections.<locals>.find_sock  sE      77##DJJ/::=IK  344r=   r*   rz   r{   )kind)r   r:   r   r/   r   r|   r}   r   rW   net_connectionsr[   r   rM   r\   )rA   r   rb   r   r   r   s         r(   test_net_connectionszTestFSAPIs.test_net_connections  s    	5 d&7&78	9#D)D T] 	/))v6DT?D!!$**c2TZZ.		/ 	/ " 	9''88		9
	/ 	/s   B AC&CCc                     | j                   dz   }| j                  t        |       t        |       t	        j
                  |       y rj   )r9   rl   r   r   rW   
disk_usage)rA   rn   s     r(   test_disk_usagezTestFSAPIs.test_disk_usage'  s4    #%U+5% r=   rz   z&ctypes does not support unicode on PY2zunstable on PYPYc                    t        | j                        5 }d }t        j                         j	                         D cg c]  } ||j
                         }}|D cg c]  }t        |v s| }}| j                   ||      |       |D ]  }| j                  |t                	 d d d        y c c}w c c}w # 1 sw Y   y xY w)Nr*   c                 z    t         j                  j                  t         j                  j                  |             S )N)rQ   r&   realpathr]   )r_   s    r(   normpathz-TestFSAPIs.test_memory_maps.<locals>.normpath5  s&    ww''(8(8(;<<r=   )
r   r:   rW   rX   memory_mapsr&   r   assertInr[   rM   )rA   
funky_pathr   xlibpathsr&   s         r(   test_memory_mapszTestFSAPIs.test_memory_maps-  s     !(9(9: 	1j= +1..*:*F*F*H%& H  $,Ba}/ABHBMM(:.9  1%%dC01	1 	1
 C	1 	1s.   (B;B1B;B6,B607B;1
B;;CN)rB   rC   rD   __doc__r   r:   rT   r`   rd   rh   ro   r|   skipIfr   r   rx   r   r   r   r   r   r   r   r   r    r=   r(   rH   rH      s    <!L7	F+	) X__T%g'@A B X__Y-/ ./ X__Y-X__--/HI/  J ./*! X__(/:X__WFGX__T-.1 / H ;1r=   rH   zunreliable on CIc                       e Zd ZdZeZd Zy)TestFSAPIsWithInvalidPathz-Test FS APIs with a funky, invalid path name.c                      y)NTr   )rA   s    r(   rT   z1TestFSAPIsWithInvalidPath.expect_exact_path_matchH  s    r=   N)rB   rC   rD   r   r   r:   rT   r   r=   r(   r   r   B  s    7)Lr=   r   c                       e Zd ZdZerendZ ej                  e	 d       ej                  e
xr ed      d               Zy)TestNonFSAPISz&Unicode tests for non fs-related APIs.   èrz   zsegfaults on PYPY + WINDOWSc                    t         j                  j                         }| j                  |d<   | j	                  |      }t        j                  |j                        }|j                         }|j                         D ]1  \  }}| j                  |t               | j                  |t               3 | j                  |d   | j                         y )N	FUNNY_ARG)env)rQ   environcopyr:   r   rW   rX   rY   itemsr[   rM   r\   )rA   r   r1   r_   kvs         r(   test_proc_environzTestNonFSAPIS.test_proc_environW  s     jjoo,,K###,NN599%iikIIK 	*DAq!!!S)!!!S)	* 	[)4+<+<=r=   N)rB   rC   rD   r   r   r   r:   r|   r   r   r   r   r   r   r=   r(   r   r   R  sK    0%(>dLX___o6X__T%g'DE> F 7>r=   r   __main__)run_from_name)1r   rQ   r-   r$   r|   rN   
contextlibr   rW   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    r3   r5   r   rH   r   r   rB   psutil.tests.runnerr   __file__r   r=   r(   <module>r      s3  AF 
              ! ! # - $ ( /  & ' ' )  , & # # $ " . ' " "&6<n <* :&!c'#>?F1 F1 @ ' F1R /0
  1>O >0 z1( r=   