0

I have a number of different objects that I can 'jsonify', these are custom object types:

class Jsonable(ABC):
    @abstractmethod
    def extract_json():
        pass # return json of self

class Organization(Jsonable):
    # implements the abstract method, all good here
    def extract_json():
        return # some json of self, great!

class Feature(Jsonable):
    # implements the abstract method, all good here
    def extract_json():
        return # some json of self, great!

I have a function, where I want to pass in many different types of 'Jsonable' and get the json for them, but theres a catch, the 'str' class is a valid type to this function, and also a List[Jsonable] is also valid, how do I have a clean function for returning the data?

def extract(data: Union[Jsonable, List[Jsonable], str):
    if isinstance(data, str): 
        # do something about string
        # not great but I can live with this, it will never change
    return data.extract_json() # ok for the standard types (Org above)
    # what about List[Jsonable]?
    # I have many types, Organization above is one example

How do I make this extract function not violate the OCP and get a nice clean way to abstract the data from these types? I should be able to get the json from the listed types aswell, cleanly?

The List can't really extend Jsonable, so how do I handle this cleanly?

symon
  • 670
  • 1
  • 7
  • 20

1 Answers1

1

If your signature looks like that, you're basically telling callers they must pass in one of those three types, and you always know Jsonables have .extract_json(), so...

def extract(data: Union[Jsonable, List[Jsonable], str]):
    if isinstance(data, str):
        return ...

    if isinstance(data, list):  # given the signature it's implicit everything is jsonable
        return [item.extract_json() for item in list]

    return item.extract_json()

However, if it's really JSON you're talking about, I'd suggest looking into json.dump()'s default() callback, which is called when there's an object it doesn't know how to deal with:

def handle_object(obj):
    if isinstance(obj, Jsonable):
        return obj.extract_json()  # should really return something that's json encodable now
    raise TypeError(f'Not sure how to JSONify {obj}')

# ...
json.dumps(anything, default=handle_object)
AKX
  • 152,115
  • 15
  • 115
  • 172