B
    ¦5¥d¨n  ã               @   sš  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mZm	Z	 d dl
mZmZmZ d dl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mZ d	d
dgZG dd	„ d	eƒZG dd„ deƒZG dd„ deƒZdd„ Zdd„ Z eƒ d)dd„ƒZ!eƒ dd„ ƒZ"dd„ Z#e $d¡Z%e $dej&¡Z'e $dej(ej)B ¡Z*e $d¡Z+e $d ej,¡Z-d!d"d#gZ.G d$d
„ d
e/ƒZ0d*d&d„Z1e2d'kr–d(Ze0eƒZ3e4e3 1¡ ƒ dS )+é    N)ÚOrderedDict)ÚescapeÚunescape)ÚurljoinÚurlparseÚunquote)Úetree)ÚCSSSelector)Úfunction_cache)Úcsstext_to_pairsÚmerge_stylesÚPremailerErrorÚ	PremailerÚ	transformc               @   s   e Zd ZdS )r   N)Ú__name__Ú
__module__Ú__qualname__© r   r   ú7/tmp/pip-unpacked-wheel-am_d5cqw/premailer/premailer.pyr      s   c               @   s   e Zd ZdS )ÚExternalNotFoundErrorN)r   r   r   r   r   r   r   r      s   r   c               @   s   e Zd ZdS )ÚExternalFileLoadingErrorN)r   r   r   r   r   r   r   r      s   r   c             C   s   d  dd„ |  d¡D ƒ¡S )z,makes every property in a string !important.ú;c             s   s$   | ]}|  d ¡sd| n|V  qdS )z
!importantz%s !importantN)Úendswith)Ú.0Úpr   r   r   ú	<genexpr>%   s   z!make_important.<locals>.<genexpr>)ÚjoinÚsplit)Úbulkr   r   r   Úmake_important"   s    r   c             C   sJ   t dƒ| ƒ}|s>t d¡}t dƒ| ƒd }| ¡  d|¡ |S |d S dS )z=Ensures that `root` contains a <head> element and returns it.ÚheadÚbodyr   N)Ú_create_cssselectorr   ÚElementÚ	getparentÚinsert)Úrootr    r!   r   r   r   Úget_or_create_head*   s    
r'   Tc             C   s   t j| |dS )aÆ  
    This function will cache the result from cssutils
    It is a big gain when number of rules is big
    Maximum cache entries are 1000. This is mainly for
    protecting memory leak in case something gone wild.
    Be aware that you can turn the cache off in Premailer

    Args:
        css_body(str): css rules in string format
        validate(bool): if cssutils should validate

    Returns:
        cssutils.css.cssstylesheet.CSSStyleSheet

    )Úvalidate)ÚcssutilsÚparseString)Úcss_bodyr(   r   r   r   Ú_cache_parse_css_string6   s    r,   c             C   s   t | ƒS )N)r	   )Úselectorr   r   r   r"   J   s    r"   c             C   s   dd„ }t  || ¡S )z.Capitalize float and margin CSS property namesc             S   s$   d  |  d¡ ¡ |  d¡|  d¡¡S )Nz
{0}:{1}{2}ÚpropertyÚvalueÚ
terminator)ÚformatÚgroupÚ
capitalize)Úmatchr   r   r   Ú_capitalize_propertyR   s    z5capitalize_float_margin.<locals>._capitalize_property)Ú_lowercase_margin_float_ruleÚsub)r+   r5   r   r   r   Úcapitalize_float_marginO   s    r8   z(^|\s)\wz\<\!\[CDATA\[(.*?)\]\]\>zr(?P<property>margin(-(top|bottom|left|right))?|float)
        :
        (?P<value>.*?)
        (?P<terminator>$|;)z\s*!importantz!^#([0-9a-f])([0-9a-f])([0-9a-f])$z:last-childz:first-childz
:nth-childc               @   sl   e Zd ZdZddd„Zddd	„Zd
d„ Zddd„Zdd„ Zdd„ Z	e
dd„ ƒZddd„Zdd„ Zdd„ ZdS )r   zdata-premailerNFTÚhtmlc             C   sð   || _ || _|| _|| _|| _|| _|| _|| _|
| _|| _	|	| _
t|tƒrR|g}|| _t|tƒrh|g}|| _|| _|| _|| _|d krŒg }|| _|| _|| _|| _|| _|| _|| _|| _|| _|pÈt| _|rÜtj |¡ |rìtj  |¡ d S )N)!r9   Úbase_urlÚdisable_link_rewritesÚpreserve_internal_linksÚpreserve_inline_attachmentsÚpreserve_handlebar_syntaxÚexclude_pseudoclassesÚkeep_style_tagsÚremove_classesr8   Úinclude_star_selectorsÚ
isinstanceÚstrÚexternal_stylesÚcss_textÚstrip_importantÚmethodÚ	base_pathÚdisable_basic_attributesÚdisable_validationÚcache_css_parsingÚdisable_leftover_cssÚalign_floating_imagesÚremove_unset_propertiesÚallow_networkÚallow_insecure_sslÚallow_loading_external_filesÚrequestsÚsessionr)   ÚlogÚ
addHandlerÚsetLevel)Úselfr9   r:   r;   r<   r=   r>   r?   r@   rB   rA   r8   rG   rE   rF   rH   rI   rJ   rK   rL   Zcssutils_logging_handlerZcssutils_logging_levelrM   rN   rO   rP   rQ   rR   rT   r   r   r   Ú__init__r   sH    


zPremailer.__init__c             C   s    | j rt||dS tj||dS )N)r(   )rL   r,   r)   r*   )rX   r+   r(   r   r   r   Ú_parse_css_stringÄ   s    zPremailer._parse_css_stringc          
      s¸  ‡fdd„‰ ‡ fdd„}g }g }|s,||fS ˆj |ˆj d}xn|D ]d}|j|jkrd| |¡ qF|j|jkrrqFdd„ |j ¡ D ƒ}dd„ |j ¡ D ƒ}	||ƒ}
||	ƒ}|||	 ƒ}d	d
„ |j 	d¡D ƒ}xÞ|D ]Ö}d|krˆj
rd| 	dd¡d  tkr| ||f¡ qÒn$d|kr*ˆjs*qÒn| d¡r8qÒ| d¡}| d¡}tt |¡ƒ}xLd|fd|
ffD ]8\}}|s~ql|||||t|ƒf}| |||f¡ qlW qÒW qFW ||fS )aA  Returns a list of rules to apply to this doc and a list of rules
        that won't be used because e.g. they are pseudoclasses. Rules
        look like: (specificity, selector, bulk)
        for example: ((0, 1, 0, 0, 0), u'.makeblue', u'color:blue').
        The bulk of the rule should not end in a semicolon.
        c                s4   ˆ j s| jdkr d | j| j¡S d | j| j¡S d S )NÚ	importantz{0}:{1}z{0}:{1} !important)rG   Úpriorityr1   Únamer/   )Úprop)rX   r   r   Úformat_css_propertyÒ   s    z9Premailer._parse_style_rules.<locals>.format_css_propertyc                s   d  ‡ fdd„| D ƒ¡S )z‘Accepts a list of cssutils Property objects and returns
            a semicolon delimitted string like 'color: red; font-size: 12px'
            r   c             3   s   | ]}ˆ |ƒV  qd S )Nr   )r   r^   )r_   r   r   r   Ü   s    zLPremailer._parse_style_rules.<locals>.join_css_properties.<locals>.<genexpr>)r   )Z
properties)r_   r   r   Újoin_css_propertiesØ   s    z9Premailer._parse_style_rules.<locals>.join_css_properties)r(   c             S   s   g | ]}|j d kr|‘qS )r[   )r\   )r   r^   r   r   r   ú
<listcomp>ï   s   z0Premailer._parse_style_rules.<locals>.<listcomp>c             S   s   g | ]}|j d kr|‘qS )r[   )r\   )r   r^   r   r   r   ra   ô   s   c             s   s,   | ]$}|  ¡ r|  ¡  d ¡s|  ¡ V  qdS )ú@N)ÚstripÚ
startswith)r   Úxr   r   r   r      s   z/Premailer._parse_style_rules.<locals>.<genexpr>ú,ú:é   Ú*ú#Ú.r   )rZ   rK   ÚtypeZ
MEDIA_RULEÚappendZ
STYLE_RULEÚstyleZgetPropertiesZselectorTextr   r?   ÚFILTER_PSEUDOSELECTORSrB   rd   ÚcountÚlenÚ_element_selector_regexÚfindall)rX   r+   Zruleset_indexr`   ÚleftoverÚrulesZsheetÚruleZnormal_propertiesZimportant_propertiesZbulk_normalZbulk_importantZbulk_allÚ	selectorsr-   Zid_countZclass_countZelement_countZis_importantr   Zspecificityr   )r_   rX   r   Ú_parse_style_rulesÊ   s\    





zPremailer._parse_style_rulesc       )      K   sš  |dk	r| j dk	rtdƒ‚n*|dkr8| j dkr8tdƒ‚n|dkrF| j }t|dƒrb| ¡ }|}|}np| jdkr|tjddd}nt ¡ }| ¡ }| j	r¤t
 dd	d
„ |¡}t ||¡ ¡ }| ¡ }| |jj¡rÎ|n|}|dk	sÞt‚| jrêd}	nt|ƒ}	g }
d}dg}| jr| d¡ xˆtd |¡ƒ|ƒD ]p}|j d¡}|rN|dkrNq(|j | j¡}|r|dkr||j| j= q(nt d| j|f ¡ |jdk}|r¨|j}n|j d¡}|  |¡}|   ||¡\}}|d7 }|
 !|¡ | "¡ }|sö| j#r€|r|}nt $d¡}d|jd< | j#r&||_n|  %|¡|_| j&rJt' d|j¡|_| jdkrdt (|j¡|_|s˜| )|¡ | *|¡ n| j#rŽ|s(| *|¡ q(W | j+râ| jrâx2| j+D ](}|  |¡}|  ,|||
|	¡ |d7 }q¶W | j-rx(| j-D ]}|  ,|||
|	¡ |d7 }qòW |
j.t/ 0d¡d i }xê|
D ]â\}}}|}d}d|krft
 1d|d¡\}}d| }|t2ks|| d¡r‚d}n|}|st‚t|ƒ}||ƒ}t3|ƒr0t4|| j5 d}xT|D ]L} t6| ƒ}!|!|kræ| g g dœ||!< ||! d  |¡ ||! d  |¡ qÀW q0W xf| 7¡ D ]Z\}}t8|d j dd¡|d |d | j9d }"|"rd|"|d jd< | j:|d |"d!d" q W | j;r¬x$| <d#¡D ]} |  "¡ }#|#jd$= q’W | j=ràx*| <d%¡D ]} t=| ƒ}$|$|  "¡ jd< qÀW | j>r<xR| <d&¡D ]D} t? @| jd ¡}%|%jAd'kr d'| jd(< n|%jAd)krôd)| jd(< qôW | jBr| jCstD| jBƒjEsbtFd*ƒ‚xªd+D ]¢}&xš| <d,|& ¡D ]ˆ} |  "¡ }#|#j|& }'|&dkr´| jGr´|' d-¡r´q||&d.krÖ| jHrÖ|' d/¡rÖq||&dkrð|' d0¡rðq|tI| jB|'ƒ|#j|&< q|W qhW t|dƒr|S | Jd1| j¡ | Jd2|¡ | Jd3d4¡ tjK|f|Ž L|d3 ¡}(| jdkrxtM d5d
„ |(¡}(| j	r’t
 d6d7d
„ |(¡}(|(S dS )8zUchange the html and return it with CSS turned into style
        attributes.
        NzCan't pass html argument twicez must pass html as first argumentÚgetroottreeÚxmlF)Zns_cleanÚresolve_entitiesz="{{(.*?)}}"c             S   s   dt |  ¡ d ƒ d S )Nz="{{r   z}}")r   Úgroups)r4   r   r   r   Ú<lambda>]  ó    z%Premailer.transform.<locals>.<lambda>r   rn   zlink[rel~=stylesheet]rf   Úmedia)ÚallZscreenÚignorezUnrecognized %s attribute (%r)Úhrefrh   ztext/cssrl   Ú )Úkeyrg   z:%sz
:nth-child)r(   )ÚitemÚclassesrn   r†   r…   )rO   T)Úforcez//@classÚclassz//@stylez//img[@style]ÚrightÚalignÚleftzBase URL must have a scheme)r‚   Úsrcz//@%srj   rŒ   zcid:ztel:rH   Úpretty_printÚencodingzutf-8c             S   s   d|   d¡ S )Nz/*<![CDATA[*/%s/*]]>*/rh   )r2   )Úmr   r   r   r}   0  r~   z="%7B%7B(.+?)%7D%7D"c             S   s   dt t|  ¡ d ƒƒ d S )Nz="{{r   z}}")r   r   r|   )r4   r   r   r   r}   7  r~   )Nr9   Ú	TypeErrorÚhasattrry   rH   r   Ú	XMLParserÚ
HTMLParserrc   r>   Úrer7   Ú
fromstringÚgetrootrd   ZdocinfoÚdoctypeÚAssertionErrorrM   r'   rP   rm   r"   r   ÚattribÚgetÚattribute_nameÚwarningsÚwarnÚtagÚtextÚ_load_externalrx   Úextendr$   r@   r#   Ú_css_rules_to_stringrG   Ú_importantsÚCDATAZaddpreviousÚremoverE   Ú_process_css_textrF   ÚsortÚoperatorÚ
itemgetterr   ro   rq   r   rK   ÚidÚitemsr   rO   Ú_style_to_basic_html_attributesrA   Zxpathr8   rN   r)   Z
parseStyleÚfloatr:   r;   r   ÚschemeÚ
ValueErrorr<   r=   r   Ú
setdefaultÚtostringÚdecodeÚ_cdata_regex))rX   r9   r   Úkwargsr&   ÚpageÚtreeÚparserÚstrippedr    ru   ÚindexZcssselectorÚelementr   Zdata_attributeZis_styler+   r‚   Úthese_rulesÚthese_leftoverZparent_of_elementrn   Ú	stylefileÚelementsÚ_r-   Znew_selectorÚclass_Úselr«   Zprocessed_styler…   Zitem_idZfinal_styleÚparentZmangledZ	image_cssÚattrÚurlÚoutr   r   r   r   +  s>   























zPremailer.transformc             C   s"   | j j|| j d}| ¡  |jS )N)Úverify)rT   rš   rQ   Úraise_for_statusrŸ   )rX   rÄ   Úresponser   r   r   Ú_load_external_url<  s    zPremailer._load_external_urlc          	   C   sô   |  d¡r,| jr$d| jkr$d| }nd| }|  d¡s@|  d¡rL|  |¡}n¤| jsbtd |¡ƒ‚nŽ|}tj | j	pvtj
¡}tj |¡sœtj tj ||¡¡}tj |¡rÌtj|dd}| ¡ }W d	Q R X n$| jrèt| j|ƒ}|  |¡S t|ƒ‚|S )
z<loads an external stylesheet from a remote url or local pathz//zhttps://zhttps:zhttp:zhttp://zEUnable to load external file {!r} because it's explicitly not allowedzutf-8)rŽ   N)rd   r:   rÉ   rR   r   r1   ÚosÚpathÚabspathrI   ÚcurdirÚisabsr   ÚexistsÚcodecsÚopenÚreadr   r    r   )rX   rÄ   r+   r½   rI   Úfr   r   r   r    A  s,    



zPremailer._load_externalc             C   s   t  d| ¡}|S )z°Fix background colors for Lotus Notes

        Notes which fails to handle three character ``bgcolor`` codes well.
        see <https://github.com/peterbe/premailer/issues/114>z#\1\1\2\2\3\3)Ú_short_color_codesr7   )Zcolor_valueÚretvalr   r   r   Ú	six_colora  s    zPremailer.six_colorc             C   s0  |  d¡r4|  d¡|  d¡kr4| d¡d dd… }tƒ }x²dd„ | d¡D ƒD ]š\}}| ¡ }|d	krv| ¡ |d
< qP|dkrŒ| ¡ |d< qP|dkr´d| ¡ kr´|  | ¡ ¡|d< qP|dksÄ|dkrP| ¡ }| d¡râ|dd… }|||< qPW x<| ¡ D ]0\}}||jkr|rø|| j	krqø||j|< qøW dS )a0  given an element and styles like
        'background-color:red; font-family:Arial' turn some of that into HTML
        attributes. like 'bgcolor', etc.

        Note, the style_content can contain pseudoclasses like:
        '{color:red; border:1px solid green} :visited{border:1px solid green}'
        Ú}Ú{r   rh   Nc             S   s(   g | ] }t | d ¡ƒdkr| d ¡‘qS )rg   é   )rq   r   )r   re   r   r   r   ra   {  s    z=Premailer._style_to_basic_html_attributes.<locals>.<listcomp>r   z
text-alignrŠ   zvertical-alignZvalignzbackground-colorZtransparentZbgcolorÚwidthÚheightZpxéþÿÿÿ)
rp   r   r   rc   ÚlowerrÖ   r   r«   r™   rJ   )rX   rº   Zstyle_contentr‡   Ú
attributesr„   r/   r   r   r   r¬   l  s0    
z)Premailer._style_to_basic_html_attributesc             C   sª   g }xš|D ]’}t |tƒr8|\}}| d|t|ƒf ¡ q
xV|jD ]L}t |tjjjtjj	j
fƒr`q@x*|j ¡ D ]}|j |d¡df|j|< qlW q@W | |j¡ q
W d |¡S )z.given a list of css rules returns a css stringz%s {%s}Fz
!importantÚ
)rC   Útuplerm   r   ZcssRulesr)   ÚcssZ
csscommentZ
CSSCommentZcssunknownruleZCSSUnknownRulern   ÚkeysZgetPropertyValueZcssTextr   )rX   ru   Úlinesr…   ÚkÚvrv   r„   r   r   r   r¢   ™  s     

zPremailer._css_rules_to_stringc             C   sh   |   ||¡\}}| |¡ |dk	rd|s,| jrdt d¡}d|jd< | jrN||_n|  |¡|_| |¡ dS )z¸processes the given css_text by adding rules that can be
        in-lined to the given rules list and adding any that cannot
        be in-lined to the given `<head>` element.
        Nrn   ztext/cssrl   )	rx   r¡   r@   r   r#   r™   rŸ   r¢   rm   )rX   rF   r¹   ru   r    r»   r¼   rn   r   r   r   r¦   ³  s    


zPremailer._process_css_text)NNFFTFTFFFFTNNr9   NNFTNNFTTTFFN)T)NT)F)r   r   r   r›   rY   rZ   rx   r   rÉ   r    ÚstaticmethodrÖ   r¬   r¢   r¦   r   r   r   r   r   n   sP                              
5
a
   
-Fc             K   s   t f |Žj| |dS )N)r   )r   r   )r9   r   r´   r   r   r   r   Ä  s    Ú__main__a  <html>
        <head>
        <title>Test</title>
        <style>
        h1, h2 { color:red; }
        strong {
          text-decoration:none
          }
        p { font-size:2px }
        p.footer { font-size: 1px}
        </style>
        </head>
        <body>
        <h1>Hi!</h1>
        <p><strong>Yes!</strong></p>
        <p class="footer" style="color:red">Feetnuts</p>
        </body>
        </html>)T)F)5rÐ   r¨   rÊ   r”   rœ   Úcollectionsr   r9   r   r   Úurllib.parser   r   r   r)   rS   Úlxmlr   Zlxml.cssselectr	   Zpremailer.cacher
   Zpremailer.merge_styler   r   Ú__all__Ú	Exceptionr   r¯   r   r   r   r'   r,   r"   r8   Úcompilerr   ÚDOTALLr³   Ú
IGNORECASEÚVERBOSEr6   r£   ÚIrÔ   ro   Úobjectr   r   r   r   Úprintr   r   r   r   Ú<module>   sR   



    Z

