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)
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 = self.create_input_buffer_for(hunk.data()) for filter in filters: data = self.convert_input_buffer_for(filter, data) out = self.create_output_buffer_for(filter) log.debug('Running method "%s" of %s with kwargs=%s', type, filter, kwargs_final) 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)
def apply_func(self, filters, type, args, kwargs=None, cache_key=None): """Apply a filter that is not a "stream in, stream out" transform (i.e. like the input() and output() filter methods). Instead, the filter method is given the arguments in ``args`` and should then produce an output stream. This is used, e.g., for the concat() and open() filter methods. Only one such filter can run per operation. ``cache_key`` may be a list of additional values to use as the cache key, in addition to the default key (the filter and arguments). """ assert type in self.VALID_FUNCS log.debug( 'Need to run method "%s" of one of the filters (%s) ' 'with args=%s, kwargs=%s', type, filters, args, kwargs) filters = [f for f in filters if getattr(f, type, None)] if not filters: # Short-circuit log.debug('No filters have a "%s" method' % type) raise NoFilters() if len(filters) > 1: raise MoreThanOneFilterError( 'These filters cannot be combined: %s' % (', '.join([f.name for f in filters])), filters) kwargs_final = self.kwargs.copy() kwargs_final.update(kwargs or {}) def func(): filter = filters[0] out = StringIO(u'') # For 2.x, StringIO().getvalue() returns str log.debug('Running method "%s" of %s with args=%s, kwargs=%s', type, filter, args, kwargs) getattr(filter, type)(out, *args, **kwargs_final) return out additional_cache_keys = [] if kwargs_final: for filter in filters: additional_cache_keys += filter.get_additional_cache_keys( **kwargs_final) key = ("hunk", args, tuple(filters), type, cache_key or [], additional_cache_keys) return self._wrap_cache(key, func)
def apply_func(self, filters, type, args, kwargs=None, cache_key=None): """Apply a filter that is not a "stream in, stream out" transform (i.e. like the input() and output() filter methods). Instead, the filter method is given the arguments in ``args`` and should then produce an output stream. This is used, e.g., for the concat() and open() filter methods. Only one such filter can run per operation. ``cache_key`` may be a list of additional values to use as the cache key, in addition to the default key (the filter and arguments). """ assert type in self.VALID_FUNCS log.debug('Need to run method "%s" of one of the filters (%s) ' 'with args=%s, kwargs=%s', type, filters, args, kwargs) filters = [f for f in filters if getattr(f, type, None)] if not filters: # Short-circuit log.debug('No filters have a "%s" method' % type) raise NoFilters() if len(filters) > 1: raise MoreThanOneFilterError( 'These filters cannot be combined: %s' % ( ', '.join([f.name for f in filters])), filters) kwargs_final = self.kwargs.copy() kwargs_final.update(kwargs or {}) def func(): filter = filters[0] out = StringIO(u'') # For 2.x, StringIO().getvalue() returns str log.debug('Running method "%s" of %s with args=%s, kwargs=%s', type, filter, args, kwargs) getattr(filter, type)(out, *args, **kwargs_final) return out additional_cache_keys = [] if kwargs_final: for filter in filters: additional_cache_keys += filter.get_additional_cache_keys(**kwargs_final) key = ("hunk", args, tuple(filters), type, cache_key or [], additional_cache_keys) return self._wrap_cache(key, func)