B
    ]t\D                 @   sd  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Zddl	Z	ddl
Z
ddlmZ ddlZddlZddlmZ ddlmZmZ ddd	gZd
d Zedd-ddZdd Zd.ddZdd ZedjZdd ZG dd deZ G dd de!Z"G dd de"Z#G dd de"Z$d d! Z%i Z&e%  d"d	 Z'd#d$ Z(d%d& Z)d'd( Z*d/d*dZ+d+d, Z,dS )0zD
Provides a collection of utilities for comparing (image) results.

    N)Path)TemporaryFile)ImageComparisonFailure)_pngcbookcompare_floatcompare_imagescomparable_formatsc             C   s   t j| \}}d|||f S )zU
    Make a new filename by inserting `purpose` before the file's
    extension.
    z%s-%s%s)ospathsplitext)fnameZpurposebaseZext r   9lib/python3.7/site-packages/matplotlib/testing/compare.pymake_test_filename   s    r   z3.0c             C   s   |dkr|dkrt dd}|dk	r^t| | }||k r^dddddg}|dd	d
 |D 7 }|dk	rt| | }| r|t|  }||k rdddddg}|ddd
 |D 7 }|pdS )z
    Fail if the floating point values are not close enough, with
    the given message.

    You can specify a relative tolerance, absolute tolerance, or both.

    Nz}You haven't specified a 'relTol' relative tolerance or a 'absTol' absolute tolerance function argument. You must specify one. zExpected: {expected}zActual:   {actual}zAbs diff: {absDiff}zAbs tol:  {absTol}z
  c             S   s   g | ]}|j f t qS r   )formatlocals).0liner   r   r   
<listcomp>:   s    z!compare_float.<locals>.<listcomp>zRel diff: {relDiff}zRel tol:  {relTol}c             S   s   g | ]}|j f t qS r   )r   r   )r   r   r   r   r   r   J   s    )
ValueErrorabsjoin)expectedactualZrelTolZabsTolmsgZabsDifftemplateZrelDiffr   r   r   r   #   s0    	c              C   sh   t  } | d krtdtj| d}yt|jddd W n tk
rP   d S X t	|tj
sdd S |S )Nz1Could not find a suitable configuration directoryZ
test_cacheT)parentsexist_ok)
matplotlibZget_cachedirRuntimeErrorr
   r   r   r   mkdirIOErroraccessW_OK)Zcachedir	cache_dirr   r   r   get_cache_dirO   s    r(      c          	   C   s   t  }t| d&}x||}|s&P || qW W d Q R X | drlddlm} || d d n(| drddlm	} || d |
 S )	Nrbz.pdfr   )checkdep_ghostscript   zutf-8z.svg)checkdep_inkscape)hashlibmd5openreadupdateendswithr!   r+   encoder-   Z	hexdigest)r   Z
block_sizer/   fddatar+   r-   r   r   r   get_file_hash]   s    


r7   c                s    fdd}|S )Nc                s~    | |}t j|dt jt jd}| \}}| }tj|rD|rzdd| }|rb|d| 7 }|rr|d| 7 }t	|d S )NT)Zuniversal_newlinesstdoutstderrzConversion command failed:
%s
 zStandard output:
%s
zStandard error:
%s
)

subprocessPopenPIPEZcommunicatewaitr
   r   existsr   r$   )oldnewZcmdlinepiper8   r9   Zerrcoder   )cmdr   r   convertq   s    
z1make_external_conversion_command.<locals>.convertr   )rC   rD   r   )rC   r    make_external_conversion_commandp   s    rE   s   [^a-zA-Z0-9_@%+=:,./-]c             C   s$   t | d kr| S d| dd d S )N   's   '"'"')_find_unsafe_bytesreplace)br   r   r   _shlex_quote_bytes   s    rJ   c               @   s   e Zd ZdS )_ConverterErrorN)__name__
__module____qualname__r   r   r   r   rK      s   rK   c               @   s$   e Zd Zdd Zdd Zdd ZdS )
_Converterc             C   s   d | _ t| j d S )N)_procatexitregister__del__)selfr   r   r   __init__   s    z_Converter.__init__c             C   sR   | j rN| j   | j   x,td | j j| j j| j jgD ]}|  q8W d | _ d S )N)rP   killr>   filterstdinr8   r9   close)rT   streamr   r   r   rS      s    

z_Converter.__del__c             C   sP   t  }xD| jjd}|st|| ||rt|dt|  S qW dS )z!Read until the prompt is reached.r,   N)		bytearrayrP   r8   r1   rK   extendr3   byteslen)rT   
terminatorZbufcr   r   r   _read_until   s    

z_Converter._read_untilN)rL   rM   rN   rU   rS   ra   r   r   r   r   rO      s   
rO   c               @   s   e Zd Zdd ZdS )_GSConverterc             C   s  | j sZt | _tjtjjddgtjtjd| _ y| 	d W n t
k
rX   tdY nX dd }| j jd|| d	 || d
  | j j  | 	d}| 	d}|stj|s|rt|dd  nd}| j jd|  t|d | d t dd S )Nz	-dNOPAUSEz-sDEVICE=png16m)rX   r8   s   
GSzFailed to start Ghostscriptc             S   s"   t | ddddddS )N   \s   \\   (s   \(   )s   \))r
   fsencoderH   )namer   r   r   encode_and_escape   s    
z0_GSConverter.__call__.<locals>.encode_and_escapes   << /OutputFile (s   ) >> setpagedevice (s   ) run flush
s   GS   >r,   r   s   pop
rH   )rP   r   Z_stdoutr;   r<   r!   r+   
executabler=   ra   rK   OSErrorrX   writeflushr
   r   r?   intr   decodesysgetfilesystemencoding)rT   origdestrh   errstack
stack_sizer   r   r   __call__   s,    

z_GSConverter.__call__N)rL   rM   rN   rw   r   r   r   r   rb      s   rb   c               @   s   e Zd Zdd ZdS )_SVGConverterc             C   s@  | j r| j  d k	rtj }|dd  tj|d< t }tj	dddgtj
tj
||d| _ || j _y| d W n tk
r   tdY nX ttttj||g\}}d	|ksd	|krtd
d ||S | j j|d | d	  | j j  y| d W n< tk
r:   | jd t| j t dY nX d S )NZDISPLAYZINKSCAPE_PROFILE_DIRinkscapez--without-guiz--shell)rX   r8   r9   envs   
>z,Failed to start Inkscape in interactive mode   
c             S   s   dd| d|gS )Nry   z-zz--export-pngr   )r@   rA   r   r   r   <lambda>   s    z(_SVGConverter.__call__.<locals>.<lambda>s    --export-png=r   rH   )rP   Zpollr
   environcopypopdevnullr   r;   r<   r=   r9   ra   rK   rk   maprJ   rf   rE   rX   rl   rm   Z_stderrseekr   r1   ro   rp   rq   )rT   rr   rs   rz   r9   Zorig_bZdest_br   r   r   rw      s:    



z_SVGConverter.__call__N)rL   rM   rN   rw   r   r   r   r   rx      s   rx   c              C   s@   t  \} }|d k	r&t  td< td< t  d k	r<t td< d S )NpdfepsZsvg)r!   r+   rb   	converterr-   rx   )ZgsZgs_vr   r   r   _update_converter  s
    r   c               C   s   dt S )z_
    Returns the list of file formats that compare_images can compare
    on this system.

    png)r   )r   r   r   r   r   r	     s    c             C   s2  |  dd\}}|tkrZd| }ddlm} | rFddl}|| nddlm} |||d | d	 }tj	
| std
|  tj	
|rt|jt| jk r.|rt }	nd}	|	dk	r
t| }
tj	|d }tj	|	|
| }tj	
|r
t|| |S t| | | |	dk	r.t|| |S )at  
    Convert the named file to png; return the name of the created file.

    If *cache* is True, the result of the conversion is cached in
    `matplotlib.get_cachedir() + '/test_cache/'`.  The caching is based on a
    hash of the exact contents of the input file.  There is no limit on the
    size of the cache, so it may need to be manually cleared periodically.
    .r,   z)Don't know how to convert %s files to png)is_called_from_pytestr   N)SkipTest_z.pngz'%s' does not exist)rsplitr   r   r   pytestskipZnoser   r
   r   r?   r$   statst_mtimer(   r7   r   r   shutilZcopyfile)filenamecacher   	extensionreasonr   r   r   Znewnamer'   Z
hash_valueZnew_extZcached_filer   r   r   rD   $  s8    	

rD   c       
      C   s   | dd dkr|dd dkr|j \}}}|j \}}}	|t|d |d  t|d |d  t|d |d  t|d |d  f }||fS )Nir   r      )shapern   )
Zactual_pathZactual_imageZexpected_pathZexpected_imageZawZahZadZewZehZedr   r   r   crop_to_sameT  s     >r   c             C   s<   | j |j kr td| j |j t| | td  S )zHCalculate the per-pixel errors, then compute the root mean square error.z9Image sizes do not match expected size: {} actual size {}r   )r   r   r   npZsqrtastypefloatZmean)expectedImageactualImager   r   r   calculate_rms_  s
    r   Fc       
         s~  t j|std| t |jdkr4td| | dd }t j| sZtd|  |dkrvt|d}t| d	} t	
| }t	
|}|d
d
d
d
d
df }|d
d
d
d
d
df }t||| |\}}t|d}|dkrt||rd
S |tj}|tj}t||}||kr"d
S t| || t|t| t|t||d |szddddddg}	d fdd|	D   S )a]  
    Compare two "image" files checking differences within a tolerance.

    The two given filenames may point to files which are convertible to
    PNG via the `.converter` dictionary. The underlying RMS is calculated
    with the `.calculate_rms` function.

    Parameters
    ----------
    expected : str
        The filename of the expected image.
    actual :str
        The filename of the actual image.
    tol : float
        The tolerance (a color value difference, where 255 is the
        maximal difference).  The test fails if the average pixel
        difference is greater than this value.
    in_decorator : bool
        If called from image_comparison decorator, this should be
        True. (default=False)

    Examples
    --------
    img1 = "./baseline/plot.png"
    img2 = "./output/plot.png"
    compare_images(img1, img2, 0.001):

    zOutput image %s does not exist.r   zOutput image file %s is empty.r   z!Baseline image %r does not exist.r   FTN   zfailed-diff)rmsr   r   Zdifftolz!Error: Image files did not match.zRMS Value: {rms}zExpected:  
    {expected}zActual:    
    {actual}zDifference:
    {diff}zTolerance: 
    {tol}z
  c                s   g | ]}|j f  qS r   )r   )r   r   )resultsr   r   r     s    z"compare_images.<locals>.<listcomp>)r
   r   r?   	Exceptionr   st_sizesplitr$   rD   r   Zread_png_intr   r   r   Zarray_equalr   Zint16r   save_diff_imagedictstrr   )
r   r   r   Zin_decoratorr   r   r   Z
diff_imager   r   r   )r   r   r   i  sJ    







c             C   s  t | dddf }t |dddf }t||| |\}}t|t}t|t}|j|jkr~td	|j|jt
|| }|d9 }t|ddtj}|j\}}}	|	dkrtj||dftjd	}
||
ddddddf< |
}d|dddddf< t || dS )
z
    Parameters
    ----------
    expected : str
        File path of expected image.
    actual : str
        File path of actual image.
    output : str
        File path to save difference image to.
    .Nr   z9Image sizes do not match expected size: {} actual size {}i	  r         )Zdtype)r   Zread_pngr   r   Zarrayr   r   r   r   r   r   ZclipZuint8emptyZ	write_png)r   r   outputr   r   ZabsDiffImageZsave_image_npZheightwidthZdepthZ
with_alphar   r   r   r     s(    r   )NN)r)   )F)-__doc__rQ   	functoolsr.   r
   Zpathlibr   rer   r;   rp   Ztempfiler   Znumpyr   r!   Zmatplotlib.testing.exceptionsr   r   r   __all__r   Z
deprecatedr   r(   r7   rE   compilesearchrG   rJ   r   rK   objectrO   rb   rx   r   r   r	   rD   r   r   r   r   r   r   r   r   <module>   sH   
	+
'6	0

W