Skip to main content

Serialize and deserialize almost anything easily.

Project description

Packify

This is a simple package that allows one to serialize and deserialize practically any data structure to and from bytes.

Installation

pip install packify

Status

Primary development is complete. Further development will be tracked in the issues. Historical changes can be found in the changelog.

Usage

Usage is simple: import the package and call the pack/unpack functions.

from packify import pack, unpack
from decimal import Decimal

data = {
    123: 432.1,
    "abc": "cba",
    b"abc": b"cba",
    "None": None,
    "true": True,
    "false": False,
    'list': [
        '123',
        123,
        b'123',
        True,
    ],
    'tuple': (
        '123',
        123,
        b'123',
        False,
    ),
    'set': {
        '123',
        123,
        b'123',
    },
    'Decimal': Decimal('123.321'),
}

packed = pack(data)
unpacked = unpack(packed)
assert type(packed) is bytes
assert unpacked == data

The following types are supported:

  • int
  • bool
  • float
  • Decimal
  • str
  • bytes
  • bytearray
  • NoneType
  • list
  • tuple
  • set
  • dict
Using with named tuples

If you want to use named tuples, you can do so by packing as a regular tuple and then unpacking it into the named tuple class.

from packify import pack, unpack
from collections import namedtuple

Point = namedtuple('Point', ['x', 'y'])

original = Point(1, 2)
packed = pack(tuple(original))
unpacked = Point(*unpack(packed))
assert unpacked == original

The recursive features of pack and unpack will not work with named tuples nested within data structures. Using a Packable implementation is a better approach if you need custom data types nested within data structures (see below).


Additionally, a simple duck-type interface/protocol, Packable, is included. Any more complex data structure can be handled if it implements the Packable interface. Packable is defined as follows:

@runtime_checkable
class Packable(Protocol):
    def pack(self) -> bytes:
        """Packs the instance into bytes."""
        ...

    @classmethod
    def unpack(cls, data: bytes, /, *, inject: dict = {}) -> Packable:
        """Unpacks an instance from bytes. Must accept dependency
            injection to unpack other Packable types.
        """
        ...

If a class that implements Packable is used, then it needs to be included in the inject parameter for calls to unpack.

Example
from dataclasses import dataclass, field
from packify import pack, unpack

@dataclass
class Thing:
    data: str = field()
    amount: int = field()
    fraction: float = field()
    parts: list = field()
    def __eq__(self, other) -> bool:
        return type(self) is type(other) and self.pack() == other.pack()
    def pack(self) -> bytes:
        return pack((self.data, self.amount, self.fraction, self.parts))
    @classmethod
    def unpack(cls, data: bytes, /, *, inject: dict = {}):
        return cls(*unpack(data, inject={**globals(), **inject}))

thing = Thing("hello world", 123, 420.69, ['a', b'b', 3])
packed = pack(thing)
unpacked = unpack(packed, inject={'Thing': Thing})
assert unpacked == thing
# alternately, the easier but less specific method is to copy globals
unpacked = unpack(packed, inject={**globals()})
assert unpacked == thing

As long as the class implements the Packable protocol, it can be included in lists, sets, tuples, and dicts (assuming it is hashable for set or to be used as a dict key), and it will just work.

The pack function will raise a UsageError if the data is not serializable, and the unpack function will raise a UsageError if it is unable to find a Packable class to unpack the relevant item.

For convenience/use in annotations, a SerializableType is exported which includes the above type information.

Additional documentation can be found in dox.md, which was generated automagically by autodox.

CLI

The packify package includes a CLI for exporting the agent skill to various AI coding environments:

# Print skill to stdout
packify skill

# Save skill to a specific directory
packify skill --output path/to/skills

# Install skill for specific AI tools
packify opencode   # .opencode/skills/packify/SKILL.md
packify claude     # .claude/skills/packify/SKILL.md
packify cursor     # .cursor/skills/packify/SKILL.md
packify codex      # .agents/skills/packify/SKILL.md

This makes the packify skill available to AI agents so they can understand and use the library effectively.

More Resources

Check out the Pycelium discord server. If you experience a problem, please discuss it on the Discord server. All suggestions for improvement are also welcome, and the best place for that is also Discord. If you experience a bug and do not use Discord, open an issue on Github.

Tests

Since it is a focused package, there are only 15 tests, and they consist of e2e tests of both the pack and unpack functions, a few tests covering reported bugs, and 2 fuzz tests to broaden the coverage of the test suite added after the v0.3.0 refactor. To run the tests, clone the repository and use the following:

python tests/test_serialization.py
python tests/test_fuzzy.py

License

Copyright (c) 2026 Jonathan Voss (k98kurz)

Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.

THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

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

packify-0.3.3.tar.gz (9.2 kB view details)

Uploaded Source

Built Distribution

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

packify-0.3.3-py3-none-any.whl (10.2 kB view details)

Uploaded Python 3

File details

Details for the file packify-0.3.3.tar.gz.

File metadata

  • Download URL: packify-0.3.3.tar.gz
  • Upload date:
  • Size: 9.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.0.1 CPython/3.11.15

File hashes

Hashes for packify-0.3.3.tar.gz
Algorithm Hash digest
SHA256 49746701fde5d3552c88fb524508ec2be6a38f0dbb890933ae7893b4aac76a27
MD5 7d8a404e9597cc362fbaa457ae08354f
BLAKE2b-256 f526b8a82f871c9b55bb5a2294e69f541f5f2de5ffa5406ab75ef6478d7d927f

See more details on using hashes here.

File details

Details for the file packify-0.3.3-py3-none-any.whl.

File metadata

  • Download URL: packify-0.3.3-py3-none-any.whl
  • Upload date:
  • Size: 10.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.0.1 CPython/3.11.15

File hashes

Hashes for packify-0.3.3-py3-none-any.whl
Algorithm Hash digest
SHA256 cee79febbe493a5acffcbcf6ded9ed62765ad3bff1d7d62111ffeaecef8b6897
MD5 97e428939e50876ac15400b313b5c266
BLAKE2b-256 55bef6bee9715b331579d2cb09c1b11bcb6cd3da581a31ea788270baebd2f14d

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