DefinetlyNotAI/AlgoPy

View on GitHub
algopy/convert.py

Summary

Maintainability
A
0 mins
Test Coverage
class Convert:
    class Binary:
        @staticmethod
        def __check_input_type(value, expected_type) -> bool:
            """
            Check if the input value is of the expected type.

            :param value: The value to check.
            :param expected_type: The expected type of the value.
            :return: True if the value is of the expected type, otherwise raises an Exception.
            """
            if not isinstance(value, expected_type):
                raise Exception(
                    f"Expected {expected_type.__name__}, got {type(value).__name__}"
                )
            return True

        @classmethod
        def to_hex(cls, Binary_Number: int) -> str:
            """
            Convert a binary number to its hexadecimal representation.

            :param Binary_Number: The binary number to convert.
            :return: The hexadecimal representation of the binary number.
            """
            if Binary_Number is None:
                raise Exception("No binary number provided")
            cls.__check_input_type(str(Binary_Number), str)
            return hex(int(str(Binary_Number), 2))[2:].upper()

        @classmethod
        def to_dec(cls, Binary_Number: int) -> int:
            """
            Convert a binary number to its decimal representation.

            :param Binary_Number: The binary number to convert.
            :return: The decimal representation of the binary number.
            """
            if Binary_Number is None:
                raise Exception("No binary number provided")
            cls.__check_input_type(str(Binary_Number), str)
            return int(str(Binary_Number), 2)

    class Decimal:
        @staticmethod
        def __check_input_type(value, expected_type) -> bool:
            """
            Check if the input value is of the expected type.

            :param value: The value to check.
            :param expected_type: The expected type of the value.
            :return: True if the value is of the expected type, otherwise raises an Exception.
            """
            if not isinstance(value, expected_type):
                raise Exception(
                    f"Expected {expected_type.__name__}, got {type(value).__name__}"
                )
            return True

        @staticmethod
        def to_roman(Number: int) -> str:
            """
            Convert a decimal number to its Roman numeral representation.

            :param Number: The decimal number to convert.
            :return: The Roman numeral representation of the decimal number.
            """
            mapping = {
                1000: "M",
                900: "CM",
                500: "D",
                400: "CD",
                100: "C",
                90: "XC",
                50: "L",
                40: "XL",
                10: "X",
                9: "IX",
                5: "V",
                4: "IV",
                1: "I",
            }
            if Number is None or Number < 1:
                raise Exception("Invalid input.")
            result = ""
            for num, roman in sorted(mapping.items(), reverse=True):
                while Number >= num:
                    result += roman
                    Number -= num
            return result

        @staticmethod
        def to_ascii(Number: int | str) -> str:
            """
            Convert a decimal number to its ASCII art representation.

            :param Number: The decimal number to convert.
            :return: The ASCII art representation of the decimal number.
            """
            digits = [
                [
                    "  ***  ",
                    " *   * ",
                    "*     *",
                    "*     *",
                    "*     *",
                    " *   * ",
                    "  ***  ",
                ],
                [" * ", "** ", " * ", " * ", " * ", " * ", "***"],
                [" *** ", "*   *", "*  * ", "  *  ", " *   ", "*    ", "*****"],
                [" *** ", "*   *", "    *", "  ** ", "    *", "*   *", " *** "],
                ["   *  ", "  **  ", " * *  ", "*  *  ", "******", "   *  ", "   *  "],
                ["*****", "*    ", "*    ", " *** ", "    *", "*   *", " *** "],
                [" *** ", "*    ", "*    ", "**** ", "*   *", "*   *", " *** "],
                ["*****", "    *", "   * ", "  *  ", " *   ", "*    ", "*    "],
                [" *** ", "*   *", "*   *", " *** ", "*   *", "*   *", " *** "],
                [" ****", "*   *", "*   *", " ****", "    *", "    *", "    *"],
            ]
            Number = str(Number)
            if Number is None:
                raise Exception("No input given.")
            ascii_art_lines = [
                "".join(digits[int(digit)][i] + "  " for digit in Number)
                for i in range(7)
            ]
            return "\n".join(ascii_art_lines)

        @classmethod
        def to_hex(cls, Decimal_Number: int) -> str:
            """
            Convert a decimal number to its hexadecimal representation.

            :param Decimal_Number: The decimal number to convert.
            :return: The hexadecimal representation of the decimal number.
            """
            if Decimal_Number is None:
                raise Exception("No decimal number provided")
            cls.__check_input_type(Decimal_Number, (int, str))
            return hex(Decimal_Number)[2:].upper()

        @classmethod
        def to_bin(cls, Decimal_Number: int) -> int:
            """
            Convert a decimal number to its binary representation.

            :param Decimal_Number: The decimal number to convert.
            :return: The binary representation of the decimal number.
            """
            if Decimal_Number is None:
                raise Exception("No decimal number provided")
            cls.__check_input_type(Decimal_Number, (int, str))
            return int(bin(Decimal_Number)[2:])

    class Hexadecimal:
        @staticmethod
        def __check_input_type(value, expected_type) -> bool:
            """
            Check if the input value is of the expected type.

            :param value: The value to check.
            :param expected_type: The expected type of the value.
            :return: True if the value is of the expected type, otherwise raises an Exception.
            """
            if not isinstance(value, expected_type):
                raise Exception(
                    f"Expected {expected_type.__name__}, got {type(value).__name__}"
                )
            return True

        @classmethod
        def to_bin(cls, Hexadecimal_Number: str) -> int:
            """
            Convert a hexadecimal number to its binary representation.

            :param Hexadecimal_Number: The hexadecimal number to convert.
            :return: The binary representation of the hexadecimal number.
            """
            if Hexadecimal_Number is None:
                raise Exception("No hexadecimal number provided")
            cls.__check_input_type(Hexadecimal_Number, str)
            return int(bin(int(Hexadecimal_Number, 16))[2:])

        @classmethod
        def to_dec(cls, Hexadecimal_Number: str) -> int:
            """
            Convert a hexadecimal number to its decimal representation.

            :param Hexadecimal_Number: The hexadecimal number to convert.
            :return: The decimal representation of the hexadecimal number.
            """
            if Hexadecimal_Number is None:
                raise Exception("No hexadecimal number provided")
            cls.__check_input_type(Hexadecimal_Number, str)
            return int(Hexadecimal_Number, 16)

    class Roman:
        @classmethod
        def __init__(cls):
            """
            Initialize the Roman numeral dictionary.
            """
            cls.roman_dict = {
                "I": 1,
                "V": 5,
                "X": 10,
                "L": 50,
                "C": 100,
                "D": 500,
                "M": 1000,
                "IV": 4,
                "IX": 9,
                "XL": 40,
                "XC": 90,
                "CD": 400,
                "CM": 900,
            }

        @classmethod
        def to_dec(cls, Roman: str) -> int:
            """
            Convert a Roman numeral to its decimal representation.

            :param Roman: The Roman numeral to convert.
            :return: The decimal representation of the Roman numeral.
            """
            if getattr(cls, "roman_dict", None) is None:
                cls.__init__()
            if not isinstance(Roman, str):
                raise Exception("Input must be a string.")
            elif not Roman.isupper():
                raise Exception("Input must be uppercase.")
            elif Roman is None:
                raise Exception("Input cannot be None.")

            roman_to_numerical = cls.roman_dict
            return cls.__convert_roman_to_decimal(Roman, roman_to_numerical)

        @staticmethod
        def __convert_roman_to_decimal(Roman: str, roman_to_numerical: dict) -> int:
            """
            Convert a Roman numeral string to its decimal representation.

            :param Roman: The Roman numeral string to convert.
            :param roman_to_numerical: A dictionary mapping Roman numeral strings to their decimal values.
            :return: The decimal representation of the Roman numeral.
            """
            i, num = 0, 0
            while i < len(Roman):
                if i + 1 < len(Roman) and Roman[i: i + 2] in roman_to_numerical:
                    num += roman_to_numerical[Roman[i: i + 2]]
                    i += 2
                else:
                    num += roman_to_numerical[Roman[i]]
                    i += 1
            return num

    class Celsius:
        @staticmethod
        def to_fahrenheit(celsius: float | int) -> float:
            """
            Convert a temperature from Celsius to Fahrenheit.

            :param celsius: The temperature in Celsius.
            :return: The temperature in Fahrenheit.
            """
            if celsius is None:
                raise Exception("No temperature provided")
            return (celsius * 9 / 5) + 32

        @staticmethod
        def to_kelvin(celsius: float | int) -> float:
            """
            Convert a temperature from Celsius to Kelvin.

            :param celsius: The temperature in Celsius.
            :return: The temperature in Kelvin.
            """
            if celsius is None:
                raise Exception("No temperature provided")
            return celsius + 273.15

    class Kelvin:
        @staticmethod
        def to_celsius(kelvin: float | int) -> float:
            """
            Convert a temperature from Kelvin to Celsius.

            :param kelvin: The temperature in Kelvin.
            :return: The temperature in Celsius.
            """
            if kelvin is None:
                raise Exception("No temperature provided")
            return kelvin - 273.15

        @staticmethod
        def to_fahrenheit(kelvin: float | int) -> float:
            """
            Convert a temperature from Kelvin to Fahrenheit.

            :param kelvin: The temperature in Kelvin.
            :return: The temperature in Fahrenheit.
            """
            if kelvin is None:
                raise Exception("No temperature provided")
            return (kelvin - 273.15) * 9 / 5 + 32

    class Fahrenheit:
        @staticmethod
        def to_kelvin(fahrenheit: float | int) -> float:
            """
            Convert a temperature from Fahrenheit to Kelvin.

            :param fahrenheit: The temperature in Fahrenheit.
            :return: The temperature in Kelvin.
            """
            if fahrenheit is None:
                raise Exception("No temperature provided")
            return (fahrenheit - 32) * 5 / 9 + 273.15

        @staticmethod
        def to_celsius(fahrenheit: float | int) -> float:
            """
            Convert a temperature from Fahrenheit to Celsius.

            :param fahrenheit: The temperature in Fahrenheit.
            :return: The temperature in Celsius.
            """
            if fahrenheit is None:
                raise Exception("No temperature provided")
            return (fahrenheit - 32) * 5 / 9

    @classmethod
    def memory(cls, number: int, input_unit: str, output_unit: str) -> str:
        """
        Convert a memory size from one unit to another.

        :param number: The memory size to convert.
        :param input_unit: The unit of the input memory size.
        :param output_unit: The unit of the output memory size.
        :return: The converted memory size in the output unit.
        """
        mem_values = {
            "bit": 1,
            "byte": 8,
            "kilobyte": 8000,
            "megabyte": 8 * (1000 ** 2),
            "gigabyte": 8 * (1000 ** 3),
            "terrabyte": 8 * (1000 ** 4),
            "petabyte": 8 * (1000 ** 5),
            "kibibyte": 8192,
            "mebibyte": 8 * (1024 ** 2),
            "gibibyte": 8 * (1024 ** 3),
            "tebibyte": 8 * (1024 ** 4),
            "pebibyte": 8 * (1024 ** 5),
            "kilobit": 1000,
            "megabit": 1000 ** 2,
            "gigabit": 1000 ** 3,
            "terrabit": 1000 ** 4,
            "petabit": 1000 ** 5,
            "kibibit": 1024,
            "mebibit": 1024 ** 2,
            "gibibit": 1024 ** 3,
            "tebibit": 1024 ** 4,
            "pebibit": 1024 ** 5,
            "KB": 8000,
            "MB": 8 * (1000 ** 2),
            "GB": 8 * (1000 ** 3),
            "TB": 8 * (1000 ** 4),
            "PB": 8 * (1000 ** 5),
            "KiB": 8192,
            "MiB": 8 * (1024 ** 2),
            "GiB": 8 * (1024 ** 3),
            "TiB": 8 * (1024 ** 4),
            "PiB": 8 * (1024 ** 5),
            "Kb": 1000,
            "Mb": 1000 ** 2,
            "Gb": 1000 ** 3,
            "Tb": 1000 ** 4,
            "Pb": 1000 ** 5,
            "Kib": 1024,
            "Mib": 1024 ** 2,
            "Gib": 1024 ** 3,
            "Tib": 1024 ** 4,
            "Pib": 1024 ** 5,
        }
        cls.__validate_memory_input(number, input_unit, output_unit, mem_values)
        if input_unit == output_unit:
            return f"{number} {output_unit}"
        final_number = cls.__convert_memory_size(number, input_unit, output_unit, mem_values)
        return f"{final_number:.15f}".rstrip("0").rstrip(".") + f" {output_unit}"

    @classmethod
    def __validate_memory_input(cls, number: int, input_unit: str, output_unit: str, memory_dict: dict):
        """
        Validate the input parameters for memory conversion.

        :param number: The memory size to convert.
        :param input_unit: The unit of the input memory size.
        :param output_unit: The unit of the output memory size.
        :param memory_dict: The dictionary mapping memory units to their bit equivalents.
        :raises Exception: If any input is invalid.
        """
        if not all([number, input_unit, output_unit]):
            raise Exception(f"Invalid input: {number} {input_unit} -> {output_unit}")
        input_unit = cls.__normalize_unit(input_unit)
        output_unit = cls.__normalize_unit(output_unit)
        if not isinstance(number, int) or input_unit not in memory_dict or output_unit not in memory_dict:
            raise Exception(f"Invalid input: {number} {input_unit} -> {output_unit}")

    @staticmethod
    def __normalize_unit(unit: str) -> str:
        """
        Normalize the memory unit to a standard format.

        :param unit: The memory unit to normalize.
        :return: The normalized memory unit.
        """
        return unit.lower() if len(unit) > 3 and unit.lower() != "bit" else unit

    @classmethod
    def __convert_memory_size(cls, number: int, input_unit: str, output_unit: str, memory_dict: dict) -> float:
        """
        Convert a memory size from one unit to another.

        :param number: The memory size to convert.
        :param input_unit: The unit of the input memory size.
        :param output_unit: The unit of the output memory size.
        :param memory_dict: The dictionary mapping memory units to their bit equivalents.
        :return: The converted memory size in the output unit.
        """
        input_unit = cls.__normalize_unit(input_unit)
        output_unit = cls.__normalize_unit(output_unit)
        return (number * memory_dict[input_unit]) / memory_dict[output_unit]