Skip to main content

A safe and efficient Python serialization library

Project description

rPickle

A safe and efficient Python serialization library.

Features

  • 🔒 Safety - No arbitrary code execution, unlike pickle
  • 📦 Compact - Small serialized size
  • 🔄 Circular references - Handles self-referential structures
  • 🧩 Extensibility - Custom type support via extensions
  • 🤝 Compatibility - Written in pure Python, works on all platforms
  • ♾️ No recursion limit - Can serialize deeply nested structures
  • 0️⃣ Zero dependencies - No external libraries required

🔒 Safety

rPickle is safe in the sense that it does not execute arbitrary code during deserialization.

Unlike pickle (which can call arbitrary functions during loads()), rPickle only reconstructs data structures.
It does not use __reduce__(), no implicit imports, and no function calls.

rPickle.loads(data) does not execute any code — it only restores data.
pickle.loads(data) may execute arbitrary code defined in __reduce__.

However, safety is not absolute:

  • If you use custom extensions (Extension), you are responsible for the code you provide — the library author is not liable.
  • rPickle does not encrypt data or prevent tampering. If you need integrity or confidentiality, take additional measures.
  • rPickle is not a sandbox. If you load untrusted data with malicious extensions, it can execute arbitrary code.

It is recommended to only load data from trusted sources and review any custom extensions before use.

Requirements

  • Python 3.11+ (all features)
  • Python 3.15+ (all features including frozendict and sentinel)

Installation

pip install rPickle

Why rPickle?

Pickle can't handle truly large integers. rPickle can:

>>> import pickle
>>> import rPickle
>>> big_integer = 1 << (1 << 34)
>>> big_integer == pickle.loads(pickle.dumps(big_integer))
Traceback (most recent call last):
  ...
OverflowError: int too large to pickle
>>> big_integer == rPickle.loads(rPickle.dumps(big_integer))
True

In Python 3.15, sentinel will be added. But pickle cannot handle this case. rPickle can handle it correctly:

>>> import pickle
>>> import rPickle
>>> MISSING = sentinel('MISSING')
>>> S = sentinel('s')

>>> # Pickle: works for one, fails for the other
>>> MISSING is pickle.loads(pickle.dumps(MISSING))
True
>>> S is pickle.loads(pickle.dumps(S))
Traceback (most recent call last):
  ...
_pickle.PicklingError: Can't pickle s: it's not found as __main__.s

>>> # rPickle: works consistently
>>> MISSING is rPickle.loads(rPickle.dumps(MISSING))
True
>>> S is rPickle.loads(rPickle.dumps(S))
True

Quick Start

import rPickle

# Serialize
data = {'name': 'Alice', 'scores': [95, 87, 92]}
packed = rPickle.dumps(data)

# Deserialize
restored = rPickle.loads(packed)
print(restored)  # {'name': 'Alice', 'scores': [95, 87, 92]}

API

Core Function

Function Description
dumps(obj) Serialize object to bytes
loads(data) Deserialize from bytes
dump(obj, file) Serialize to file
load(file) Deserialize from file

Extensions

You can use built-in extensions to support additional types like datetime, Decimal, UUID, etc.

For example, to serialize a dictionary containing a datetime.datetime object:

from datetime import datetime

data = {'created': datetime.now()}
packed = rPickle.dumps(data, extensions=rPickle.ext.datetime_ext)
restored = rPickle.loads(packed, extensions=rPickle.ext.datetime_ext)

# Using more extensions at the same time
exts = rPickle.ext.datetime_ext | rPickle.ext.Path_ext | rPickle.ext.Decimal_ext
packed = rPickle.dumps(data, extensions=exts)

Custom Extensions

Add support for your own types using the extensions parameter. For example, to support datetime.datetime:

import rPickle
from datetime import datetime

# 1. Define dump function (type → bytes)
def dump_datetime(dt: datetime) -> bytes:
    return dt.timestamp().to_bytes(8, 'little')

# 2. Define load function (bytes → type)
def load_datetime(data: bytes) -> datetime:
    timestamp = int.from_bytes(data, 'little')
    return datetime.fromtimestamp(timestamp)

# 3. Register your extension
my_extensions = rPickle.ext.Extension(typ=datetime, load_func=load_datetime, dump_func=dump_datetime)

# 4. Use it
data = {'created': datetime.now()}
packed = rPickle.dumps(data, extensions=my_extensions)
restored = rPickle.loads(packed, extensions=my_extensions)

You can also combine your extension with built-in ones or custom ones using |=. For example, to combine your datetime.datetime extension with the built-in one:

import rPickle
from datetime import datetime

def dump_datetime(dt: datetime) -> bytes:
    return dt.timestamp().to_bytes(8, 'little')

def load_datetime(data: bytes) -> datetime:
    timestamp = int.from_bytes(data, 'little')
    return datetime.fromtimestamp(timestamp)

my_extensions = rPickle.ext.Extension(typ=datetime, load_func=load_datetime, dump_func=dump_datetime)

# Add a built-in extension or others
my_extensions |= rPickle.ext.datetime_ext

packed = rPickle.dumps(data, extensions=my_extensions)
restored = rPickle.loads(packed, extensions=my_extensions)

⚠️Note: For safety, avoid using eval(), exec(), or __import__() in your custom extensions.

Overriding Built-in Types With Custom Extensions

You can override built-in types with your own extensions. For example, if you want to change how list is serialized:

import rPickle
from rPickle.ext import Extension

def dump_list_plus(lst: list) -> bytes:
    return bytes(lst)

def load_list_plus(data: bytes) -> list:
    return list(data)

list_plus = Extension(typ=list, load_func=load_list_plus, dump_func=dump_list_plus)

data = [1, 2, 5, 3, 4, 5, 8, 9, 7, 5, 9, 5]
packed = rPickle.dumps(data, extensions=list_plus)
restored = rPickle.loads(packed, extensions=list_plus)

⚠️Note: For safety, avoid using eval(), exec(), or __import__() in your enhancement extensions

Supported Types

  • None, bool, int, float, complex, str
  • bytes, bytearray
  • list, tuple, set, frozenset
  • dict, frozendict (Python 3.15+)
  • range, slice
  • Ellipsis, NotImplemented
  • sentinel (Python 3.15+)
  • Custom types

Sentinel Support

Python 3.15 introduced sentinel for creating unique marker objects. rPickle supports sentinel natively with identity preservation:

import rPickle

MISSING = sentinel('MISSING')
packed = rPickle.dumps(MISSING)
restored = rPickle.loads(packed)

assert restored is MISSING  # True

That makes rPickle more correct.

Built-in Extensions

rPickle comes with ready-to-use extensions for common types: see the list below.

Name Type
datetime_ext datetime.datetime
Decimal_ext decimal.Decimal
UUID_ext uuid.UUID
Fraction_ext fractions.Fraction
Path_ext pathlib.Path
defaultdict_ext collections.defaultdict
date_ext datetime.date
time_ext datetime.time

Links

License

MIT License.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

rpickle-0.11.0.tar.gz (18.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

rpickle-0.11.0-py3-none-any.whl (18.5 kB view details)

Uploaded Python 3

File details

Details for the file rpickle-0.11.0.tar.gz.

File metadata

  • Download URL: rpickle-0.11.0.tar.gz
  • Upload date:
  • Size: 18.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.6

File hashes

Hashes for rpickle-0.11.0.tar.gz
Algorithm Hash digest
SHA256 d7b62e466e776c7319814dfa965e8656767b461e38759e5633fe5b62cdcf4aa3
MD5 1ef41bab637f1babf4a5a355836eea84
BLAKE2b-256 98c49a151b09e6b8769cdff3df69a6ed126b36ff0a90cb0e9b4f31238f5e4b42

See more details on using hashes here.

File details

Details for the file rpickle-0.11.0-py3-none-any.whl.

File metadata

  • Download URL: rpickle-0.11.0-py3-none-any.whl
  • Upload date:
  • Size: 18.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.6

File hashes

Hashes for rpickle-0.11.0-py3-none-any.whl
Algorithm Hash digest
SHA256 929dc8738e23e1c8c5e8a3c90186030c95eb4b783d6df6c7e561ef1c52ed455c
MD5 e05f5d89f3eef2028e1046af67cb382e
BLAKE2b-256 f9860c1f7193e99e1da0ca5eaaed721a532cbf04b5c35e5c60a57e60f25810bd

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page