def apply(self, hunk, filters, type, kwargs=None):
        """Apply the given list of filters to the hunk, returning a new
        ``MemoryHunk`` object.

        ``kwargs`` are options that should be passed along to the filters.
        If ``hunk`` is a file hunk, a ``source_path`` key will automatically
        be added to ``kwargs``.
        """
        assert type in self.VALID_TRANSFORMS
        log.debug('Need to run method "%s" of filters (%s) on hunk %s with '
                  'kwargs=%s', type, filters, hunk, kwargs)

        filters = [f for f in filters if getattr(f, type, None)]
        if not filters:  # Short-circuit
            log.debug('No filters have "%s" methods, returning hunk '
                      'unchanged' % (type,))
            return hunk

        kwargs_final = self.kwargs.copy()
        kwargs_final.update(kwargs or {})

        def func():
            data = StringIO(hunk.data())
            for filter in filters:
                log.debug('Running method "%s" of  %s with kwargs=%s',
                    type, filter, kwargs_final)
                out = StringIO(u'') # For 2.x, StringIO().getvalue() returns str
                getattr(filter, type)(data, out, **kwargs_final)
                data = out
                data.seek(0)

            return data

        additional_cache_keys = []
        if kwargs_final:
            for filter in filters:
                additional_cache_keys += filter.get_additional_cache_keys(**kwargs_final)

        # Note that the key used to cache this hunk is different from the key
        # the hunk will expose to subsequent merges, i.e. hunk.key() is always
        # based on the actual content, and does not match the cache key. The
        # latter also includes information about for example the filters used.
        #
        # It wouldn't have to be this way. Hunk could subsequently expose their
        # cache key through hunk.key(). This would work as well, but would be
        # an inferior solution: Imagine a source file which receives
        # non-substantial changes, in the sense that they do not affect the
        # filter output, for example whitespace. If a hunk's key is the cache
        # key, such a change would invalidate the caches for all subsequent
        # operations on this hunk as well, even though it didn't actually
        # change after all.
        key = ("hunk", hunk, tuple(filters), type, additional_cache_keys)
        return self._wrap_cache(key, func)
dataset/ETHPy150Open miracle2k/webassets/src/webassets/merge.py/FilterTool.apply/original