|
""" |
|
Transformation Abstract Class |
|
============================================ |
|
|
|
""" |
|
|
|
from abc import ABC, abstractmethod |
|
|
|
from textattack.shared.utils import ReprMixin |
|
|
|
|
|
class Transformation(ReprMixin, ABC): |
|
"""An abstract class for transforming a sequence of text to produce a |
|
potential adversarial example.""" |
|
|
|
def __call__( |
|
self, |
|
current_text, |
|
pre_transformation_constraints=[], |
|
indices_to_modify=None, |
|
shifted_idxs=False, |
|
return_indices=False, |
|
): |
|
"""Returns a list of all possible transformations for ``current_text``. |
|
Applies the ``pre_transformation_constraints`` then calls |
|
``_get_transformations``. |
|
|
|
Args: |
|
current_text: The ``AttackedText`` to transform. |
|
pre_transformation_constraints: The ``PreTransformationConstraint`` to apply before |
|
beginning the transformation. |
|
indices_to_modify: Which word indices should be modified as dictated by the |
|
``SearchMethod``. |
|
shifted_idxs (bool): Whether indices could have been shifted from |
|
their original position in the text. |
|
return_indices (bool): Whether the function returns indices_to_modify |
|
instead of the transformed_texts. |
|
""" |
|
if indices_to_modify is None: |
|
indices_to_modify = set(range(len(current_text.words))) |
|
|
|
shifted_idxs = False |
|
else: |
|
indices_to_modify = set(indices_to_modify) |
|
|
|
if shifted_idxs: |
|
indices_to_modify = set( |
|
current_text.convert_from_original_idxs(indices_to_modify) |
|
) |
|
|
|
for constraint in pre_transformation_constraints: |
|
indices_to_modify = indices_to_modify & constraint(current_text, self) |
|
|
|
if return_indices: |
|
return indices_to_modify |
|
|
|
transformed_texts = self._get_transformations(current_text, indices_to_modify) |
|
for text in transformed_texts: |
|
text.attack_attrs["last_transformation"] = self |
|
return transformed_texts |
|
|
|
@abstractmethod |
|
def _get_transformations(self, current_text, indices_to_modify): |
|
"""Returns a list of all possible transformations for ``current_text``, |
|
only modifying ``indices_to_modify``. Must be overridden by specific |
|
transformations. |
|
|
|
Args: |
|
current_text: The ``AttackedText`` to transform. |
|
indicies_to_modify: Which word indices can be modified. |
|
""" |
|
raise NotImplementedError() |
|
|
|
@property |
|
def deterministic(self): |
|
return True |
|
|