Convert string to fishy and fishy to string Inspired by this question.

Here's the code:

class FishyError(Exception):
    __module__ = Exception.__module__

def string_to_fishy(string: str) -&gt; str:
    """
    Converts a string to fishy code

    Examples:
        Hello World!
        &gt;&lt;72&gt; &gt;&lt;101&gt; &gt;&lt;108&gt; &gt;&lt;108&gt; &gt;&lt;111&gt; &gt;&lt;32&gt; &gt;&lt;87&gt; &gt;&lt;111&gt; &gt;&lt;114&gt; &gt;&lt;108&gt; &gt;&lt;100&gt; &gt;&lt;33&gt;

        007 James bond
        &gt;&lt;48&gt; &gt;&lt;48&gt; &gt;&lt;55&gt; &gt;&lt;32&gt; &gt;&lt;74&gt; &gt;&lt;97&gt; &gt;&lt;109&gt; &gt;&lt;101&gt; &gt;&lt;115&gt; &gt;&lt;32&gt; &gt;&lt;98&gt; &gt;&lt;111&gt; &gt;&lt;110&gt; &gt;&lt;100&gt;

    """

    l = []

    for char in string:
        l.append(f'&gt;&lt;{ord(char)}&gt;')

    return ' '.join(l)


def fishy_to_string(fishy: str) -&gt; str:
    """
    Converts a fishy code to string

    Examples:
        &gt;&lt;72&gt; &gt;&lt;101&gt; &gt;&lt;108&gt; &gt;&lt;108&gt; &gt;&lt;111&gt; &gt;&lt;32&gt; &gt;&lt;87&gt; &gt;&lt;111&gt; &gt;&lt;114&gt; &gt;&lt;108&gt; &gt;&lt;100&gt; &gt;&lt;33&gt;
        Hello World!

        &gt;&lt;48&gt; &gt;&lt;48&gt; &gt;&lt;55&gt; &gt;&lt;32&gt; &gt;&lt;74&gt; &gt;&lt;97&gt; &gt;&lt;109&gt; &gt;&lt;101&gt; &gt;&lt;115&gt; &gt;&lt;32&gt; &gt;&lt;98&gt; &gt;&lt;111&gt; &gt;&lt;110&gt; &gt;&lt;100&gt;
        007 James bond

    """

    if not fishy:
        return ''

    fishy_chars = fishy.split(' ')

    string = ''

    for char in fishy_chars:
        if not char:
            raise FishyError('Invalid syntax: Extra whitespace')

        if not (char.startswith('&gt;&lt;') and char.endswith('&gt;')):
            raise FishyError('Invalid syntax: ' + char)

        try:
            value = int(char[2:-1])
            string += chr(value)

        except ValueError:
            raise FishyError('Invalid syntax: ' + char)

    return string

while True:
    print(fishy_to_string(input()))


This works well, but doesn't look that great. Any ideas?
I'm not entirely sure why you are not satisfied with your code as it looks quite good. Maybe too many blank lines that seem to stretch the code length. There are also a few things on the Python side that could be changed to reduce the amount of source lines needed for the task:

string_to_fishy

string_to_fishy can be rewritten using a list comprehension:

def string_to_fishy(string: str) -&gt; str:
    """..."""
    return ' '.join(f'&gt;&lt;{ord(char)}&gt;' for char in string)


fishy_to_string

The inverse function could use a similar technique in order to avoid repeated creations of new strings in string += chr(value):

def fishy_to_string(fishy: str) -&gt; str:
    """
    Converts a fishy code to string

    Examples:
        &gt;&lt;72&gt; &gt;&lt;101&gt; &gt;&lt;108&gt; &gt;&lt;108&gt; &gt;&lt;111&gt; &gt;&lt;32&gt; &gt;&lt;87&gt; &gt;&lt;111&gt; &gt;&lt;114&gt; &gt;&lt;108&gt; &gt;&lt;100&gt; &gt;&lt;33&gt;
        Hello World!

        &gt;&lt;48&gt; &gt;&lt;48&gt; &gt;&lt;55&gt; &gt;&lt;32&gt; &gt;&lt;74&gt; &gt;&lt;97&gt; &gt;&lt;109&gt; &gt;&lt;101&gt; &gt;&lt;115&gt; &gt;&lt;32&gt; &gt;&lt;98&gt; &gt;&lt;111&gt; &gt;&lt;110&gt; &gt;&lt;100&gt;
        007 James bond
    """
    if not fishy:
        return ''

    def parse_fish(token):
        if not token:
            raise FishyError('Invalid syntax: Extra whitespace')

        if not (token.startswith('&gt;&lt;') and token.endswith('&gt;')):
            raise FishyError('Invalid syntax: ' + token)

        try:
            value = int(token[2:-1])
            string += chr(value)
        except ValueError:
            raise FishyError('Input cannot be parsed as character: ' + token)

    return ''.join(parse_fish(token) for token in fishy.split(' '))


I also allowed myself to change the variable name char to token, because I find it more appropriate in that context, and also slightly reworded the last error message to make it more expressive.