Seite 1 von 1

Vermeidung verschachtelter try...except Blöcke

Verfasst: Freitag 10. März 2017, 13:57
von skirnir
Hallo,

ich versuche gerade, JSON-Objekte, die als Email-Attachments ankommen, zu dekodieren. Diese können in unterschiedlichen Kodierungen ankommen, so dass nicht jeder Versuch von Erfolg gekrönt ist. Derzeit sieht das so aus:

Code: Alles auswählen

try:
    # plain text?
    myvar = json.loads(mystring)
except ValueError:
    # base64?
    try:
        myvar = json.loads(base64.decode(mystring))
    except ValueError:
        try:
            # quoted-printable?
            myvar = json.loads(quopri.decodestring(mystring))
        except ValueError:
            logger.error("None of the above.")
Ist häßlich und kann ggf. zu einer beliebigen Tiefe der Verschachtelung führen, was dann irgendwann unlesbar wird.

Als Alternative fällt mir bisher nur so was ein (ungetestet):

Code: Alles auswählen

def decode_string(source_string, mydecoders=None):
    if mydecoders is None:
        mydecoders = iter((lambda x: x, base64.decode, quopri.decodestring))

    try:
        current_decoder = next(mydecoders)
        return json.loads(current_decoder(source_string))
    except ValueError:
        return decode_string(source_string, mydecoders)
    except StopIteration:
        return None
Das würde zwar nicht zu weiterer Verschachtelung führen, ist aber vielleicht auch nicht intuitiv für jeden zu lesen.

Gibt es eine einfachere (und lesbarere) Möglichkeit, so was auszudrücken?

Re: Vermeidung verschachtelter try...except Blöcke

Verfasst: Freitag 10. März 2017, 14:27
von Sirius3
@skirnir: ist in den Email-Anhängen denn kein Encoding angegeben?

Rekursion ist in diesem Fall ein Fehler, weil es kein rekursives Problem ist. Nimm einfach eine for-Schleife:

Code: Alles auswählen

def decode_string(source_string, decoders=(lambda x: x, base64.decode, quopri.decodestring)):
    for decoder in decoders:
        try:
            return json.loads(decoder(source_string))
        except ValueError:
            pass

Re: Vermeidung verschachtelter try...except Blöcke

Verfasst: Freitag 10. März 2017, 14:32
von kbr
skirnir hat geschrieben:Gibt es eine einfachere (und lesbarere) Möglichkeit, so was auszudrücken?
Klar, das geht.

Code: Alles auswählen

class MyDecoderException(Exception): pass

def decode_string(source, decoders):
    for decoder in decoders:
        try:
            return json.loads(decoder(source))
        except ValueError:
            continue
    raise MyDecoderException('no matching decoder')

Re: Vermeidung verschachtelter try...except Blöcke

Verfasst: Freitag 10. März 2017, 14:35
von skirnir
Sirius3 hat geschrieben:@skirnir: ist in den Email-Anhängen denn kein Encoding angegeben?
Ich arbeite mit einer email.message.Message Instanz. `get_content_type` liefert "application/octet-stream", was ja im Prinzip alles sein kann. Hab' ich evtl. übersehen, wie ich das Encoding rausfinden kann?
Rekursion ist in diesem Fall ein Fehler, weil es kein rekursives Problem ist. Nimm einfach eine for-Schleife:

Code: Alles auswählen

def decode_string(source_string, decoders=(lambda x: x, base64.decode, quopri.decodestring)):
    for decoder in decoders:
        try:
            return json.loads(decoder(source_string))
        except ValueError:
            pass
Ja, das ergibt mehr Sinn. Danke!

Re: Vermeidung verschachtelter try...except Blöcke

Verfasst: Freitag 10. März 2017, 15:36
von skirnir
skirnir hat geschrieben: Ich arbeite mit einer email.message.Message Instanz. `get_content_type` liefert "application/octet-stream", was ja im Prinzip alles sein kann. Hab' ich evtl. übersehen, wie ich das Encoding rausfinden kann?
Falls mal jemand diesen Thread findet:
Das Objekt hat einen key 'Content-Transfer-Encoding', in dem das Encoding drin steht (duh!):

Code: Alles auswählen

mail_part.get('Content-Transfer-Encoding')

Re: Vermeidung verschachtelter try...except Blöcke

Verfasst: Freitag 10. März 2017, 16:25
von BlackJack
@skirnir: Vielleicht ist selbst das uninteressant wenn Du bei der `get_payload()`-Methode für das `decode`-Argument `True` übergibst. :-)

Re: Vermeidung verschachtelter try...except Blöcke

Verfasst: Freitag 10. März 2017, 16:30
von skirnir
BlackJack hat geschrieben:@skirnir: Vielleicht ist selbst das uninteressant wenn Du bei der `get_payload()`-Methode für das `decode`-Argument `True` übergibst. :-)
:oops: Mal wieder zu früh aufgehört zu lesen. Danke!

Aber immerhin habe ich was über Exception-Handling gelernt.