def config(self, **kwargs: Union[int, str, bool]) -> None:
        """
        Assign values to self.configuration dictionary.

        :raise ValueError: if type of a dictionary value is wrong.
        """
        if "letter_sequence" in kwargs:
            type_check.type_guard(kwargs["letter_sequence"], str)
            self.configuration["letter_sequence"] = kwargs["letter_sequence"]

        if "key" in kwargs and kwargs["key"] is not None:
            type_check.type_guard(kwargs["key"], int)
            self.configuration["key"] = kwargs["key"]

        if "seed" in kwargs:
            type_check.type_guard(kwargs["seed"], int)
            self.configuration["seed"] = kwargs["seed"]

        if "shuffle" in kwargs:
            type_check.type_guard(kwargs["shuffle"], bool)
            self.configuration["shuffle"] = kwargs["shuffle"]

        if "decrypt" in kwargs:
            type_check.type_guard(kwargs["decrypt"], bool)
            self.configuration["decrypt"] = kwargs["decrypt"]
    def _process_subroutines(
        self, configurations: Dict[str, KWARGS_TYPE], **kwargs: KWARGS_TYPE
    ) -> Dict[str, KWARGS_TYPE]:
        """
        Extend functionality of encrypt and decrypt to accept route lists.

        :raise ValueError: if type of a dictionary value is wrong.
        """
        # flags are all set to False.
        flag_route: bool = False
        flag_replace_route: bool = False

        # get route from kwargs if provided.
        if "route" in kwargs:
            route: List[int] = kwargs["route"]
            type_check.type_guard(route, list)
            flag_route = True

        # get replace route bool from kwargs if provided.
        if "replace_route" in kwargs:
            replace_route: bool = kwargs["replace_route"]
            type_check.type_guard(replace_route, bool)
            flag_replace_route = True

        # if there is a route list, proceed to next steps.
        if flag_route:
            if flag_replace_route:
                # save given route list in configuration dict.
                self.config(route=route)
            # replace route in configurations.
            configurations["route"] = route

        return configurations
Esempio n. 3
0
    def _config_subroutines(self, **kwargs: KWARGS_TYPE) -> None:
        """
        Assign values to self.configuration dictionary.

        :raise ValueError: if type of a dictionary value is wrong.
        """
        if "key" in kwargs and kwargs["key"] is not None:
            type_check.type_guard(kwargs["key"], int)
            self.configuration["key"] = kwargs["key"]
def find_unique_letters(text: str) -> Set[str]:
    """
    Create a set of all letters in a string.

    :param text: string source.
    :return: a set of all unique letters in the string
    :rtype: set
    """
    # check types
    type_check.type_guard(text, str)
    # create and return set
    return set(text)
    def _process(
        self,
        text: str,
        key: Optional[int],
        replace_key: bool,
        decrypt: bool,
        **kwargs: KWARGS_TYPE,
    ) -> str:
        """
        Handle the process for both encryption and decryption.

        This method main job is to fetch configurations and
        modify them if necessary and then feed it into the
        translator method.

        :param text         : string to be processed.
        :param key          : key for encryption/decryption.
        :param decrypt      : switch for encryption/decryption.
        :param replace_key  : replace the old key in self.configuration
                              with new one.
        :return             : encrypted/decrypted string.
        :rtype              : str
        """
        # explicitly switch mode to encryption/decryption.
        self.config(decrypt=decrypt)

        # type annotate.
        configuration: Dict[str, KWARGS_TYPE]
        # deep copy self.configuration dictionary into new dictionary to be used.
        configuration = {i: j for (i, j) in self.configuration.items()}

        if key:
            # check key type to be compatible.
            type_check.type_guard(key, int)

        # fetch configurations based on key and replace key states.
        if key and replace_key:
            # change key in self.configuration.
            self.config(key=key)
            # change the key in the copied dictionary,
            configuration["key"] = key
        elif key and not replace_key:
            # self.configuration key will remain unchanged.
            # change the key in the copied dictionary.
            configuration["key"] = key

        # do sub-process on configuration.
        configuration = self._process_subroutines(configuration, **kwargs)

        # return a call to cipher translator function with
        # configuration dictionary as arguments.
        return self._translator(text, **configuration)
def map_letters_to_indexes(text: str) -> Dict[str, List[int]]:
    """
    Create an index  mapping dictionary.

    Dictionary holds that maps every letter
    to a list of indexes of its occurrence in a given string

    :param text: string source for finding indexes letters in it.
    :return: a dictionary with letter as key and a list of indexes as value.
    :rtype: dict
    """
    # check types
    type_check.type_guard(text, str)

    # return a dictionary with letter as key and a list of indexes as value
    return {
        letter: find_letter_indexes(text, letter)
        for letter in find_unique_letters(text)
    }
def find_letter_indexes(text: str, letter: str) -> List[int]:
    """
    List indexes of a letter in a string.

    This function returns a list of index of every occurrence
    of a letter in a string.

    :param text: string source
    :param letter: the letter to find all of its  occurrence indexes
    :return: list containing letters occurrence indexes
    :rtype: list
    """
    # check types
    type_check.type_guard(text, str)
    type_check.type_guard(letter, str)
    # return index list
    return [
        index for index, character in enumerate(text) if character == letter
    ]
    def _process(self, text: str, key: Optional[int], replace_key: bool,
                 decrypt: bool) -> str:
        """
        Handle the process for both encryption and decryption.

        :param text         : string to be processed.
        :param key          : key for encryption/decryption.
        :param decrypt      : switch for encryption/decryption.
        :param replace_key  : replace the old key in self.configuration
                              with new one.
        :return             : encrypted/decrypted string.
        :rtype              : str
        """
        # explicitly switch mode to encryption/decryption.
        self.config(decrypt=decrypt)

        # replace the old key in self.configuration with new key
        if replace_key:
            self.config(key=key)

        if key and not replace_key:
            # deep copy self.configuration dictionary into new dictionary to be used.
            configuration = {i: j for (i, j) in self.configuration.items()}
            # check key type to be compatible.
            type_check.type_guard(key, int)
            # change the key in the copied dictionary,
            # self.configuration key will remain unchanged.
            configuration["key"] = key
        else:
            # alias self.configuration dictionary to configuration
            # in this case configuration dictionary isn't a copy
            # and is just a pointer to self.configuration
            configuration = self.configuration

        # return a call to affine_cipher_translator function with
        # string and unpacked (prepended "**" is used to unpack the dictionary)
        # configuration dictionary as arguments.
        return self._translator(text, **configuration)
    def config(self, **kwargs: KWARGS_TYPE) -> None:
        """
        Assign values to self.configuration dictionary.

        :raise ValueError: if type of a dictionary value is wrong.
        """
        if "letter_sequence" in kwargs:
            type_check.type_guard(kwargs["letter_sequence"], str)
            self.configuration["letter_sequence"] = kwargs["letter_sequence"]

        if "seed" in kwargs:
            type_check.type_guard(kwargs["seed"], int)
            self.configuration["seed"] = kwargs["seed"]

        if "shuffle" in kwargs:
            type_check.type_guard(kwargs["shuffle"], bool)
            self.configuration["shuffle"] = kwargs["shuffle"]

        if "decrypt" in kwargs:
            type_check.type_guard(kwargs["decrypt"], bool)
            self.configuration["decrypt"] = kwargs["decrypt"]

        # do subroutines.
        self._config_subroutines(**kwargs)
Esempio n. 10
0
 def test_different_types(self):
     with self.assertRaises(TypeError):
         type_guard("Hi this is a str type", int)
     with self.assertRaises(TypeError):
         type_guard(2, float)