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, 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 3 recent versions.
**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**
.. code:: python
# -*- coding: utf-8 -*-
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 it prints:
.. code:: python
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': '€'}
Raw data
{
"_id": null,
"home_page": "https://github.com/irmen/Serpent",
"name": "serpent",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.2",
"maintainer_email": null,
"keywords": "serialization",
"author": "Irmen de Jong",
"author_email": "irmen@razorvine.net",
"download_url": "https://files.pythonhosted.org/packages/06/3c/7ecf39b48121cb6490634bfcb1b1c5cac7d7a216805d889b0676a2e8493f/serpent-1.42.tar.gz",
"platform": "any",
"description": "\nSerpent is a simple serialization library based on ast.literal_eval.\n\nBecause it only serializes literals and recreates the objects using ast.literal_eval(),\nthe serialized data is safe to transport to other machines (over the network for instance)\nand de-serialize it there.\n\n*There is also a Java and a .NET (C#) implementation available. This allows for easy data transfer between the various ecosystems.\nYou can get the full source distribution, a Java .jar file, and a .NET assembly dll.*\nThe java library can be obtained from Maven central (groupid ``net.razorvine`` artifactid ``serpent``),\nand the .NET assembly can be obtained from Nuget.org (package ``Razorvine.Serpent``).\n\n\n**API**\n\n- ``ser_bytes = serpent.dumps(obj, indent=False, module_in_classname=False):`` # serialize obj tree to bytes\n- ``obj = serpent.loads(ser_bytes)`` # deserialize bytes back into object tree\n- You can use ``ast.literal_eval`` yourself to deserialize, but ``serpent.deserialize``\n works around a few corner cases. See source for details.\n\nSerpent is more sophisticated than a simple repr() + literal_eval():\n\n- 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\n- it encodes byte-types as base-64 instead of inefficient escaping notation that repr would use (this does mean you have\n to base-64 decode these strings manually on the receiving side to get your bytes back.\n You can use the serpent.tobytes utility function for this.)\n- it contains a few custom serializers for several additional Python types such as uuid, datetime, array and decimal\n- it tries to serialize unrecognised types as a dict (you can control this with __getstate__ on your own types)\n- it can create a pretty-printed (indented) output for readability purposes\n- it outputs the keys of sets and dicts in alphabetical order (when pretty-printing)\n- it works around a few quirks of ast.literal_eval() on the various Python implementations\n\nSerpent allows comments in the serialized data (because it is just Python source code).\nSerpent can't serialize object graphs (when an object refers to itself); it will then crash with a ValueError pointing out the problem.\n\nWorks with Python 3 recent versions.\n\n**FAQ**\n\n- Why not use XML? Answer: because XML.\n- 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.\n- Why not use pickle? Answer: because pickle has security problems.\n- Why not use ``repr()``/``ast.literal_eval()``? See above; serpent is a superset of this and provides more convenience.\n Serpent provides automatic serialization mappings for types other than the builtin primitive types.\n ``repr()`` can't serialize these to literals that ``ast.literal_eval()`` understands.\n- Why not a binary format? Answer: because binary isn't readable by humans.\n- But I don't care about readability. Answer: doesn't matter, ``ast.literal_eval()`` wants a literal string, so that is what we produce.\n- But I want better performance. Answer: ok, maybe you shouldn't use serpent in this case. Find an efficient binary protocol (protobuf?)\n- Why only Python, Java and C#/.NET, but no bindings for insert-favorite-language-here? Answer: I don't speak that language.\n Maybe you could port serpent yourself?\n- Where is the source? It's on Github: https://github.com/irmen/Serpent\n- Can I use it everywhere? Sure, as long as you keep the copyright and disclaimer somewhere. See the LICENSE file.\n\n**Demo**\n\n.. code:: python\n\n # -*- coding: utf-8 -*-\n import ast\n import uuid\n import datetime\n import pprint\n import serpent\n\n\n class DemoClass:\n def __init__(self):\n self.i=42\n self.b=False\n\n data = {\n \"names\": [\"Harry\", \"Sally\", \"Peter\"],\n \"big\": 2**200,\n \"colorset\": { \"red\", \"green\" },\n \"id\": uuid.uuid4(),\n \"timestamp\": datetime.datetime.now(),\n \"class\": DemoClass(),\n \"unicode\": \"\u20ac\"\n }\n\n # serialize it\n ser = serpent.dumps(data, indent=True)\n open(\"data.serpent\", \"wb\").write(ser)\n\n print(\"Serialized form:\")\n print(ser.decode(\"utf-8\"))\n\n # read it back\n data = serpent.load(open(\"data.serpent\", \"rb\"))\n print(\"Data:\")\n pprint.pprint(data)\n\n # you can also use ast.literal_eval if you like\n ser_string = open(\"data.serpent\", \"r\", encoding=\"utf-8\").read()\n data2 = ast.literal_eval(ser_string)\n\n assert data2==data\n\n\nWhen you run this it prints:\n\n.. code:: python\n\n Serialized form:\n # serpent utf-8 python3.2\n {\n 'big': 1606938044258990275541962092341162602522202993782792835301376,\n 'class': {\n '__class__': 'DemoClass',\n 'b': False,\n 'i': 42\n },\n 'colorset': {\n 'green',\n 'red'\n },\n 'id': 'e461378a-201d-4844-8119-7c1570d9d186',\n 'names': [\n 'Harry',\n 'Sally',\n 'Peter'\n ],\n 'timestamp': '2013-04-02T00:23:00.924000',\n 'unicode': '\u20ac'\n }\n Data:\n {'big': 1606938044258990275541962092341162602522202993782792835301376,\n 'class': {'__class__': 'DemoClass', 'b': False, 'i': 42},\n 'colorset': {'green', 'red'},\n 'id': 'e461378a-201d-4844-8119-7c1570d9d186',\n 'names': ['Harry', 'Sally', 'Peter'],\n 'timestamp': '2013-04-02T00:23:00.924000',\n 'unicode': '\u20ac'}\n \n",
"bugtrack_url": null,
"license": "MIT",
"summary": "Serialization based on ast.literal_eval",
"version": "1.42",
"project_urls": {
"Homepage": "https://github.com/irmen/Serpent"
},
"split_keywords": [
"serialization"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "072473031e6bd25d8f94811b3752b0b217efbdb20a67b65c6838c9af4e50c2e2",
"md5": "1fc098cb61a277367cf05d422a13a01b",
"sha256": "a02f5a4fcf3b41ee6204b36c3cf026bf0433ffe15b6a7fc8a37e0bff74d87575"
},
"downloads": -1,
"filename": "serpent-1.42-py3-none-any.whl",
"has_sig": false,
"md5_digest": "1fc098cb61a277367cf05d422a13a01b",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.2",
"size": 9663,
"upload_time": "2025-10-26T21:58:12",
"upload_time_iso_8601": "2025-10-26T21:58:12.565125Z",
"url": "https://files.pythonhosted.org/packages/07/24/73031e6bd25d8f94811b3752b0b217efbdb20a67b65c6838c9af4e50c2e2/serpent-1.42-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "063c7ecf39b48121cb6490634bfcb1b1c5cac7d7a216805d889b0676a2e8493f",
"md5": "361160793865c5827941d9f0230ea88a",
"sha256": "8ea082b01f8ba07ecd74e34a9118ac4521bc4594938d912b808c89f1da425506"
},
"downloads": -1,
"filename": "serpent-1.42.tar.gz",
"has_sig": false,
"md5_digest": "361160793865c5827941d9f0230ea88a",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.2",
"size": 90352,
"upload_time": "2025-10-26T21:58:13",
"upload_time_iso_8601": "2025-10-26T21:58:13.871206Z",
"url": "https://files.pythonhosted.org/packages/06/3c/7ecf39b48121cb6490634bfcb1b1c5cac7d7a216805d889b0676a2e8493f/serpent-1.42.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-10-26 21:58:13",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "irmen",
"github_project": "Serpent",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"lcname": "serpent"
}