Define custom JSON encoders and decoders¶
When calling mytask.defer()
to create a job, the task arguments are serialized into
a JSON string for storing into the PostgreSQL database.
And after fetching a job from the database Procrastinate workers need to deserialize the task arguments before calling the task.
By default Procrastinate relies on the JSON dumps and loads functions used by psycopg2. (See the psycopg2 documentation.) Procrastinate makes it possible to specify custom encoders and decoders.
Here is an example involving serializing/deserializing datetime
objects:
import functools
import json
from procrastinate import App, AiopgConnector
# Function used for encoding datetime objects
def encode(obj):
if isinstance(obj, datetime.datetime):
return obj.isoformat()
raise TypeError()
# Function used for decoding datetime objects
def decode(dict_):
if "dt" in dict_:
dict_["dt"] = datetime.datetime.fromisoformat(dict_["dt"])
return dict_
json_dumps = functools.partial(json.dumps, default=encode)
json_loads = functools.partial(json.loads, object_hook=decode)
app = App(connector=AiopgConnector(json_dumps=json_dumps, json_loads=json_loads))
In this example the custom JSON dumps and loads functions are based on the standard
json
module’s dumps
and loads
functions, with specific default
and
object_hook
for serializing and deserializing datetime
objects, respectively.
(See the Python 3 json documentation for more detail.)
This mechanism even makes it possible to use a different JSON implementation than
json
, such as UltraJSON for example.
Also, if your encoding function starts resembling a long list of if isinstance
calls, you may want to have a look at functools.singledispatch
for a cleaner
way. (See the Python 3 functools documentation for more detail.)