Serpent is a simple serialization library based on ast.literal_eval.
Because it only serializes literals and recreates the objects using ast.literal_eval(), the serialized data is safe to transport to other machines (over the network for instance) and de-serialize it there.
There is also a Java and a .NET (C#) implementation available. This allows for easy data transfer between the various ecosystems. You can get the full source distribution, a Java .jar file, and a .NET assembly dll. The java library can be obtained from Maven central (groupid net.razorvine artifactid serpent), and the .NET assembly can be obtained from Nuget.org (package Razorvine.Serpent).
API
ser_bytes = serpent.dumps(obj, indent=False, set_literals=True, module_in_classname=False): # serialize obj tree to bytes
obj = serpent.loads(ser_bytes) # deserialize bytes back into object tree
You can use ast.literal_eval yourself to deserialize, but serpent.deserialize works around a few corner cases. See source for details.
Serpent is more sophisticated than a simple repr() + literal_eval():
it serializes directly to bytes (utf-8 encoded), instead of a string, so it can immediately be saved to a file or sent over a socket
it encodes byte-types as base-64 instead of inefficient escaping notation that repr would use (this does mean you have to base-64 decode these strings manually on the receiving side to get your bytes back. You can use the serpent.tobytes utility function for this.)
it contains a few custom serializers for several additional Python types such as uuid, datetime, array and decimal
it tries to serialize unrecognised types as a dict (you can control this with __getstate__ on your own types)
it can create a pretty-printed (indented) output for readability purposes
it outputs the keys of sets and dicts in alphabetical order (when pretty-printing)
it works around a few quirks of ast.literal_eval() on the various Python implementations
Serpent allows comments in the serialized data (because it is just Python source code). Serpent can’t serialize object graphs (when an object refers to itself); it will then crash with a ValueError pointing out the problem.
Works with Python 2.7+ (including 3.x), IronPython 2.7+, Jython 2.7+.
FAQ
Why not use XML? Answer: because XML.
Why not use JSON? Answer: because JSON is quite limited in the number of datatypes it supports, and you can’t use comments in a JSON file.
Why not use pickle? Answer: because pickle has security problems.
Why not use repr()/ast.literal_eval()? See above; serpent is a superset of this and provides more convenience. Serpent provides automatic serialization mappings for types other than the builtin primitive types. repr() can’t serialize these to literals that ast.literal_eval() understands.
Why not a binary format? Answer: because binary isn’t readable by humans.
But I don’t care about readability. Answer: doesn’t matter, ast.literal_eval() wants a literal string, so that is what we produce.
But I want better performance. Answer: ok, maybe you shouldn’t use serpent in this case. Find an efficient binary protocol (protobuf?)
Why only Python, Java and C#/.NET, but no bindings for insert-favorite-language-here? Answer: I don’t speak that language. Maybe you could port serpent yourself?
Where is the source? It’s on Github: https://github.com/irmen/Serpent
Can I use it everywhere? Sure, as long as you keep the copyright and disclaimer somewhere. See the LICENSE file.
Demo
# This demo script is written for Python 3.2+
# -*- coding: utf-8 -*-
from __future__ import print_function
import ast
import uuid
import datetime
import pprint
import serpent
class DemoClass:
def __init__(self):
self.i=42
self.b=False
data = {
"names": ["Harry", "Sally", "Peter"],
"big": 2**200,
"colorset": { "red", "green" },
"id": uuid.uuid4(),
"timestamp": datetime.datetime.now(),
"class": DemoClass(),
"unicode": "€"
}
# serialize it
ser = serpent.dumps(data, indent=True)
open("data.serpent", "wb").write(ser)
print("Serialized form:")
print(ser.decode("utf-8"))
# read it back
data = serpent.load(open("data.serpent", "rb"))
print("Data:")
pprint.pprint(data)
# you can also use ast.literal_eval if you like
ser_string = open("data.serpent", "r", encoding="utf-8").read()
data2 = ast.literal_eval(ser_string)
assert data2==data
When you run this (with python 3.2+) it prints:
Serialized form:
# serpent utf-8 python3.2
{
'big': 1606938044258990275541962092341162602522202993782792835301376,
'class': {
'__class__': 'DemoClass',
'b': False,
'i': 42
},
'colorset': {
'green',
'red'
},
'id': 'e461378a-201d-4844-8119-7c1570d9d186',
'names': [
'Harry',
'Sally',
'Peter'
],
'timestamp': '2013-04-02T00:23:00.924000',
'unicode': '€'
}
Data:
{'big': 1606938044258990275541962092341162602522202993782792835301376,
'class': {'__class__': 'DemoClass', 'b': False, 'i': 42},
'colorset': {'green', 'red'},
'id': 'e461378a-201d-4844-8119-7c1570d9d186',
'names': ['Harry', 'Sally', 'Peter'],
'timestamp': '2013-04-02T00:23:00.924000',
'unicode': '€'}
Release files for serpent 1.18
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| serpent-1.18.tar.gz | 11.7 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| serpent-1.18-py2.py3-none-any.whl | Python 3, Python 2 | none | any | Details |
Total release size: 24.9 kB
Release files / serpent-1.18.tar.gz
| Download URL | serpent-1.18.tar.gz |
|---|---|
| Size | 11.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
cc4e1aff3a38a0d438526bede81480776fa8c33fa6d5059412988b0754c9af6d
|
|
BLAKE2b-256 checksum How to use checksums |
1253e972a2f270da04ba4e913f0d14fe0f770f8d13aeb5f1f161015d14739629
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
Release files / serpent-1.18-py2.py3-none-any.whl
| Download URL | serpent-1.18-py2.py3-none-any.whl |
|---|---|
| Size | 13.2 kB |
| Tags | Python 2 Python 3 |
|
SHA-256 checksum How to use checksums |
69c43ee4b6d4069b3ff57443b8a39adfdaf69210f584b91f7806abec717686d2
|
|
BLAKE2b-256 checksum How to use checksums |
c48920e2a96c8c666131371e3f025670ec8246a0a85613756867c6328ba1d4b6
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |