Search code examples
pythonjsonpython-3.xtry-exceptpython-dataclasses

What is a better way to write multiple try clauses for casting a json string object to a dataclass?


I have a function that receives multiple different json string objects with different structure and/or field names, like so:

event = '{"userId": "TDQIQb2fQaORKvCyepDYoZgsoEE3", "profileIsCreated": true}'

or

event = '{"userId": "TDQIQb2fQaORKvCyepDYoZgsoEE3", "signUpFinished": true}'

And I have data classes like so:

from dataclasses import dataclass, field


@dataclass_json(letter_case=LetterCase.CAMEL)
@dataclass(frozen=True)
class UserId:
    userId: str


@dataclass_json(letter_case=LetterCase.CAMEL)
@dataclass(frozen=True)
class SignUpFinished(UserId):
    signUpFinished: bool


@dataclass_json(letter_case=LetterCase.CAMEL)
@dataclass(frozen=True)
class UserProfileCreated(UserId):
    profileIsCreated: bool

Currently, the way I write my function is like this:

def cast_event(event):
    user_details = None

    try:
        user_details = SignUpFinished.from_json(event)
    except KeyError:
        pass

    try:
        user_details = UserProfileCreated.from_json(event)
    except KeyError:
        pass

    if user_details:
        return "OK"
    else:
        return "UNHANDLED"

The problem is, as I have more and more events to handle, my function will become longer and longer, however, it is only doing the same thing.

Is there a better way to achieve what I want to achieve?


I have checked out some of the SO questions:

but they don't seem to be the best way of trying to achieve what I want.


Solution

  • Since each case is syntactically the same, you can handle them in a single loop. Iterate through a sequence of cases and try to return; this automatically keeps on trying later cases until one succeeds.

    def cast_event(event):
        for case in (UserId , SignUpFinished, UserProfileCreated):
            try:
                return case.from_json(event)
            except KeyError:
                pass
        raise ValueError(f'not a valid event: {event}')