| """ | |
| Composite Transformation | |
| ============================================ | |
| Multiple transformations can be used by providing a list of ``Transformation`` to ``CompositeTransformation`` | |
| """ | |
| from textattack.shared import utils | |
| from textattack.transformations import Transformation | |
| class CompositeTransformation(Transformation): | |
| """A transformation which applies each of a list of transformations, | |
| returning a set of all optoins. | |
| Args: | |
| transformations: The list of ``Transformation`` to apply. | |
| """ | |
| def __init__(self, transformations): | |
| if not ( | |
| isinstance(transformations, list) or isinstance(transformations, tuple) | |
| ): | |
| raise TypeError("transformations must be list or tuple") | |
| elif not len(transformations): | |
| raise ValueError("transformations cannot be empty") | |
| self.transformations = transformations | |
| def _get_transformations(self, *_): | |
| """Placeholder method that would throw an error if a user tried to | |
| treat the CompositeTransformation as a 'normal' transformation.""" | |
| raise RuntimeError( | |
| "CompositeTransformation does not support _get_transformations()." | |
| ) | |
| def __call__(self, *args, **kwargs): | |
| new_attacked_texts = set() | |
| for transformation in self.transformations: | |
| new_attacked_texts.update(transformation(*args, **kwargs)) | |
| return list(new_attacked_texts) | |
| def __repr__(self): | |
| main_str = "CompositeTransformation" + "(" | |
| transformation_lines = [] | |
| for i, transformation in enumerate(self.transformations): | |
| transformation_lines.append(utils.add_indent(f"({i}): {transformation}", 2)) | |
| transformation_lines.append(")") | |
| main_str += utils.add_indent("\n" + "\n".join(transformation_lines), 2) | |
| return main_str | |
| __str__ = __repr__ | |