
2!V6                 @   s^  d  d l  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 d  d l m Z d  d l m Z m Z d  d	 l m Z d  d
 l m Z m Z 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! m" Z" m# Z# d  d l$ m% Z% d \ Z& Z' d \ Z( Z) Gd d   d e*  Z+ d S)    )with_statementunicode_literalsN)import_module)ContentFile)	mark_safe)url2pathname)render_to_string)get_hexdigest	get_mtime)settings)CompressorErrorUncompressableFileErrorFilterDoesNotExist)CachedCompilerFilter)CssAbsoluteFilter)compressor_file_storage)post_compress)	get_classget_mod_funcstaticfiles)cached_propertyinlinefileinputoutputc               @   su  e  Z d  Z d Z d d d d d d  Z e d d    Z d d   Z d	 d
   Z d d   Z	 d d d  Z
 d d   Z d d   Z e d d    Z e d d    Z e d d    Z e d d    Z d d d  Z d d   Z d d  d!  Z d d d d d" d#  Z d$ d%   Z d& d d' d(  Z d d) d*  Z d d d+ d,  Z d d d- d.  Z d d/ d0  Z d S)1
Compressorzi
    Base compressor object to be subclassed for content type
    depending implementations details.
    Nc             O   s   | p	 d |  _  | p d |  _ t j j d  |  _ t j |  _ g  |  _ | pQ i  |  _	 | p` d |  _
 | po g  |  _ i  |  _ t t j  |  _ t j |  _ d  |  _ d  S)N 
compressed/)contentoutput_prefixr   ZCOMPRESS_OUTPUT_DIRstrip
output_dirDEFAULT_CHARSETcharsetZsplit_contentcontexttypefiltersextra_contextdictZCOMPRESS_PRECOMPILERSprecompiler_mimetypesr   findersZ_storage)selfr   r    r%   r'   argskwargs r/   </tmp/pip-build-0sboevxh/django-compressor/compressor/base.py__init__!   s    		zCompressor.__init__c             C   s   d d l  m } | S)Nr   )default_storage)compressor.storager2   )r,   r2   r/   r/   r0   storage0   s    zCompressor.storagec             C   s
   t   d S)z
        To be implemented in a subclass, should return an
        iterable with four values: kind, value, basename, element
        N)NotImplementedError)r,   r/   r/   r0   split_contents5   s    zCompressor.split_contentsc             C   sG   y! t  |  d |  } | r  | SWn t k
 r5 Yn Xd |  j | f S)z?
        Returns the template path for the given mode.
        ztemplate_name_%szcompressor/%s_%s.html)getattrAttributeErrorr&   )r,   modetemplater/   r/   r0   get_template_name<   s    zCompressor.get_template_namec             C   s   y |  j  j } Wn t k
 r- t j } Yn X| j |  sV t d | | f   n  | j | d d  } | j d d  d S)z
        Takes full path to a static file (eg. "/static/css/style.css") and
        returns path with storage's base url removed (eg. "css/style.css").
        zE'%s' isn't accessible via COMPRESS_URL ('%s') and can't be compressedr      ?r   )	r4   base_urlr8   r   ZCOMPRESS_URL
startswithr   replacesplit)r,   urlr>   basenamer/   r/   r0   get_basenameH   s    zCompressor.get_basenamec             C   s   g  } | rB t  j j |  d } | j t  j j |  d  n  | j t | d  |  j g  t  j j |  j	 |  j
 d j |   S)a  
        Returns file path for an output file based on contents.

        Returned path is relative to compressor storage's base url, for
        example "CACHE/css/e41ba2cc6982.css".

        When `basename` argument is provided then file name (without extension)
        will be used as a part of returned file name, for example:

        get_filepath(content, "my_file.css") -> 'CACHE/css/my_file.e41ba2cc6982.css'
        r<   r      .)ospathrA   appendsplitextextendr	   r&   joinr"   r    )r,   r   rC   partsfilenamer/   r/   r0   get_filepathY   s     zCompressor.get_filepathc             C   s   d } t  j sy y1 |  j j |  } |  j j |  s? d } n  Wqy t k
 ru t j |  rq t j |  } n  Yqy Xn  | r |  j r |  j j t	 |   } n  | r | St
 d | t  j |  j r d p d f   d S)z
        Returns full path to a file, for example:

        get_filename('css/one.css') -> '/full/path/to/static/css/one.css'
        Nz3'%s' could not be found in the COMPRESS_ROOT '%s'%sz or with staticfiles.rF   )r   DEBUGr4   rH   existsr5   r   r+   findr   r   ZCOMPRESS_ROOT)r,   rC   rN   r/   r/   r0   get_filenamel   s"    		zCompressor.get_filenamec             C   s   | d k r d } n  t  j | d |   } y | j   SWnx t k
 rx } z t d | | f   WYd d } ~ Xn> t k
 r } z t d | | | f   WYd d } ~ Xn XWd QXd S)zS
        Reads file contents using given `charset` and returns it as text.
        zutf-8z	utf-8-sigrz!IOError while processing '%s': %sNz<UnicodeDecodeError while processing '%s' with charset %s: %s)codecsopenreadIOErrorr   UnicodeDecodeError)r,   rN   r$   fder/   r/   r0   get_filecontent   s    	"zCompressor.get_filecontentc             C   s   t  t j  |  j  S)N)r   r   ZCOMPRESS_PARSERr   )r,   r/   r/   r0   parser   s    zCompressor.parserc             C   s   d d   |  j  D S)Nc             S   s   g  |  ] } t  |   q Sr/   )r   ).0
filter_clsr/   r/   r0   
<listcomp>   s   	 z-Compressor.cached_filters.<locals>.<listcomp>)r'   )r,   r/   r/   r0   cached_filters   s    zCompressor.cached_filtersc             C   s   d d   |  j    D S)Nc             S   s:   g  |  ]0 \ } } } } | t  k r t t |    q Sr/   )SOURCE_FILEstrr
   )r^   kindvaluerC   elemr/   r/   r0   r`      s   	z%Compressor.mtimes.<locals>.<listcomp>)r6   )r,   r/   r/   r0   mtimes   s    	zCompressor.mtimesc             C   s/   t  d j |  j g |  j  j |  j  d  S)Nr   rE   )r	   rL   r   rg   encoder$   )r,   r/   r/   r0   cachekey   s    	zCompressor.cachekeyFc             c   sd  t  j p | } xN|  j   D]@\ } } } } d } |  j j |  } | j d |  j  }	 i t d 6| d 6| d 6| d 6|	 d 6}
 | t k r t	 |
 d | }
 |  j
 | |	  } n  |  j r |  j | |
  \ } } n  | r |  j | |  j |
  Vq | rKt |  j k r+|  j | t g |
  } n  |  j | | d d	 d | Vq |  j j |  Vq Wd
 S)z
        The heart of content parsing, iterates over the
        list of split contents and looks at its kind
        to decide what to do with it. Should yield a
        bunch of precompiled and/or rendered hunks.
        Fr$   methodrf   rd   rC   rN   forcedTN)r   COMPRESS_ENABLEDr6   r]   elem_attribsgetr$   METHOD_INPUTrb   r)   r\   r*   
precompilefilterra   r   handle_outputZelem_str)r,   rk   enabledrd   re   rC   rf   ZprecompiledZattribsr$   optionsr/   r/   r0   hunks   s0    
	zCompressor.hunksc             C   s   |  j  | |  j d t S)zl
        Passes the concatenated content to the 'output' methods
        of the compressor filters.
        rj   )rq   ra   METHOD_OUTPUT)r,   r   r/   r/   r0   filter_output   s    zCompressor.filter_outputc             C   s1   g  } x$ |  j  |  D] } | j |  q W| S)zk
        Passes each hunk (file or code) to the 'input' methods
        of the compressor filters.
        )ru   rI   )r,   rk   r   Zhunkr/   r/   r0   filter_input   s    zCompressor.filter_inputc             K   s  | s d | f S|  j  j |  } | j d d  } | d k rJ d | f S|  j j |  }	 |	 d k r | d k r~ d | f St d |   n  t |	  \ }
 } y t |
  } Wn[ t t f k
 rt	 d | d |  j
 d	 | d
 | d |	 d |  } d | j |   f SYn Xy t | |  } Wn" t k
 rHt d |	   Yn X| | d | d |  j
 d
 | d	 | } d | j |   f S)z
        Processes file using a pre compiler.

        This is the place where files like coffee script are processed.
        Fr&   Ntext/csstext/javascriptzQCouldn't find any precompiler in COMPRESS_PRECOMPILERS setting for mimetype '%s'.r   filter_typerN   r$   commandmimetypeTzCould not find "%s".attrs)ry   rz   )r]   rm   rn   r*   r   r   r   ImportError	TypeErrorr   r&   r   r7   r8   r   )r,   r   rd   rf   rN   r$   r.   r~   r}   Zfilter_or_commandmod_nameZcls_namemodrq   Zprecompiler_classr/   r/   r0   rp      s8    


	zCompressor.precompilec             K   sg   x` | D]X } t  | | d |  j |  } y t |  rI | |   } n  Wq t k
 r^ Yq Xq W| S)Nr{   )r7   r&   callabler5   )r,   r   r'   rj   r.   r_   Zfilter_funcr/   r/   r0   rq     s    	zCompressor.filterr   c             C   sW   d j  |  j |   } | s" d St j s1 | rS |  j |  } |  j | | |  S| S)z
        The general output method, override in subclass if you need to do
        any custom modification. Calls other mode specific methods or simply
        returns the content directly.
        
r   )rL   rx   r   rl   rw   rr   )r,   r9   rk   r   Zfiltered_outputr/   r/   r0   r     s    zCompressor.outputc             C   sI   t  |  d | d   } t |  r5 | | | | |  St d |   d  S)Nz	output_%sz)Couldn't find output method for mode '%s')r7   r   r   )r,   r9   r   rk   rC   Zoutput_funcr/   r/   r0   rr   /  s
    zCompressor.handle_outputc             C   s   |  j  | d | } |  j j |  s. | rV |  j j | t | j |  j    n  t |  j j |   } |  j	 | i | d 6 S)z
        The output method that saves the content to a file and renders
        the appropriate template with the file's URL.
        rC   rB   )
rO   r4   rQ   saver   rh   r$   r   rB   render_output)r,   r9   r   rk   rC   Znew_filepathrB   r/   r/   r0   output_file8  s
    (zCompressor.output_filec             C   s   |  j  | i | d 6 S)za
        The output method that directly returns the content for inline
        display.
        r   )r   )r,   r9   r   rk   rC   r/   r/   r0   output_inlineC  s    zCompressor.output_inlinec          	   C   s   d |  j  k r i  |  j  d <n  |  j  d j | p5 i   |  j  d j |  j  t |  j  d  rt |  j  j   } n	 |  j  } t j d |  j d |  j d | d |  |  j	 |  } t
 | d | S)z~
        Renders the compressor output with the appropriate template for
        the given mode and template context.
        r   flattenZsenderr&   r9   r%   )r%   updater(   hasattrr   r   send	__class__r&   r;   r   )r,   r9   r%   Zfinal_contextZtemplate_namer/   r/   r0   r   J  s    	zCompressor.render_output)__name__
__module____qualname____doc__r1   r   r4   r6   r;   rD   rO   rS   r\   r]   ra   rg   ri   ru   rw   rx   rp   rq   r   rr   r   r   r   r/   r/   r/   r0   r      s2    )
	&	r   )zinlinezfile)zinputzoutput),
__future__r   r   rG   rU   	importlibr   Zdjango.core.files.baser   Zdjango.utils.safestringr   Z%django.utils.six.moves.urllib.requestr   Zdjango.template.loaderr   Zcompressor.cacher	   r
   Zcompressor.confr   Zcompressor.exceptionsr   r   r   Zcompressor.filtersr   Zcompressor.filters.css_defaultr   r3   r   Zcompressor.signalsr   Zcompressor.utilsr   r   r   Zcompressor.utils.decoratorsr   ZSOURCE_HUNKrb   ro   rv   objectr   r/   r/   r/   r0   <module>   s&   