Skip to content

Instantly share code, notes, and snippets.

@Et7f3
Forked from simonw/gist:7000493
Last active August 27, 2024 18:13
Show Gist options
  • Save Et7f3/922260074697e585bb492b5f2e7e1166 to your computer and use it in GitHub Desktop.
Save Et7f3/922260074697e585bb492b5f2e7e1166 to your computer and use it in GitHub Desktop.
How to use custom Python JSON serializers and deserializers to automatically roundtrip complex types.
import json, datetime
class RoundTripEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, datetime.datetime):
return "$dt$" + str(obj.isoformat())
return super().default(obj)
data = {
"name": "Silent Bob",
"dt": datetime.datetime(2013, 11, 11, 10, 40, 32)
}
s = json.dumps(data, cls=RoundTripEncoder, indent=2)
print(s)
class RoundTripDecoder(json.JSONDecoder):
def __init__(self, *args, **kwargs):
json.JSONDecoder.__init__(self, object_hook=self.object_hook, *args, **kwargs)
def object_hook(self, obj):
for k, v in obj.items():
if isinstance(v, str) and v[0:4] == "$dt$":
obj[k] = datetime.datetime.fromisoformat(v[4:])
return obj
print (json.loads(s, cls=RoundTripDecoder))
@Et7f3
Copy link
Author

Et7f3 commented Aug 27, 2024

Output:

{
  "name": "Silent Bob",
  "dt": "$dt$2013-11-11T10:40:32"
}
{'name': 'Silent Bob', 'dt': datetime.datetime(2013, 11, 11, 10, 40, 32)}

The trick is to use $dt$ to at the beginning of datetime like $6$ for password hash. If it might be possible this string is legally in the json serialized string: you can rewrite line 23 with a try catch:

-            if isinstance(v, str) and v[0:4] == "$dt$":
+            try:
+                if isinstance(v, str):
-                obj[k] = datetime.datetime.fromisoformat(v[4:])
+                    obj[k] = datetime.datetime.fromisoformat(v[4:])
+            except ValueError: pass

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment