From a5201c1709124259b63ca15426c23d2130704cbc Mon Sep 17 00:00:00 2001 From: Mark Pilgrim Date: Wed, 2 Sep 2009 15:25:13 -0400 Subject: [PATCH] raise TypeError at end of to_json custom serializer function --- examples/customserializer.py | 1 + serializing.html | 7 +++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/examples/customserializer.py b/examples/customserializer.py index cc7c75a..19cae8f 100644 --- a/examples/customserializer.py +++ b/examples/customserializer.py @@ -9,6 +9,7 @@ def to_json(python_object): if isinstance(python_object, bytes): return {'__class__': 'bytes', '__value__': list(python_object)} + raise TypeError def from_json(json_object): if '__class__' in json_object: diff --git a/serializing.html b/serializing.html index d18ef40..64f542f 100644 --- a/serializing.html +++ b/serializing.html @@ -458,11 +458,13 @@ def protocol_version(file_object): def to_json(python_object): if isinstance(python_object, bytes): return {'__class__': 'bytes', - '__value__': list(python_object)} + '__value__': list(python_object)} + raise TypeError
  1. To define your own “mini-serialization format” for a datatype that JSON doesn’t support natively, just define a function that takes a Python object as a parameter. This Python object will be the actual object that the json.dump() function is unable to serialize by itself — in this case, the bytes object b'\xDE\xD5\xB4\xF8'.
  2. Your custom serialization function should check the type of the Python object that the json.dump() function passed to it. This is not strictly necessary if your function only serializes one datatype, but it makes it crystal clear what case your function is covering, and it makes it easier to extend if you need to add serializations for more datatypes later.
  3. In this case, I’ve chosen to convert a bytes object into a dictionary. The __class__ key will hold the original datatype (as a string, 'bytes'), and the __value__ key will hold the actual value. Of course this can’t be a bytes object; the entire point is to convert it into something that can be serialized in JSON! A bytes object is just a sequence of integers; each integer is somewhere in the range 0–255. We can use the list() function to convert the bytes object into a list of integers. So b'\xDE\xD5\xB4\xF8' becomes [222, 213, 180, 248]. (Do the math! It works! The byte \xDE in hexadecimal is 222 in decimal, \xD5 is 213, and so on.) +
  4. This line is important. The data structure you’re serializing may contain types that neither the built-in JSON serializer nor your custom serializer can handle. In this case, your custom serializer must raise a TypeError so that the json.dump() function knows that your custom serializer did not recognize the type.

That’s it; you don’t need to do anything else. In particular, this custom serialization function returns a Python dictionary, not a string. You’re not doing the entire serializing-to-JSON yourself; you’re only doing the converting-to-a-supported-datatype part. The json.dump() function will do the rest. @@ -506,7 +508,8 @@ def to_json(python_object): '__value__': time.asctime(python_object)} if isinstance(python_object, bytes): return {'__class__': 'bytes', - '__value__': list(python_object)} + '__value__': list(python_object)} + raise TypeError

  1. Adding to our existing customserializer.to_json() function, we need to check whether the Python object (that the json.dump() function is having trouble with) is a time.struct_time.
  2. If so, we’ll do something similar to the conversion we did with the bytes object: convert the time.struct_time object to a dictionary that only contains JSON-serializable values. In this case, the easiest way to convert a datetime into a JSON-serializable value is to convert it to a string with the time.asctime() function. The time.asctime() function will convert that nasty-looking time.struct_time into the string 'Fri Mar 27 22:20:42 2009'.