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.2.tar.gz (9.0 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.2-py3-none-any.whl (9.9 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: packify-0.3.2.tar.gz
  • Upload date:
  • Size: 9.0 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.2.tar.gz
Algorithm Hash digest
SHA256 c7eb50e749c2af8d03875eb4d9915c3c19af406371021db260d43c1c9a848df5
MD5 dc29cbb068f8768b886ab218c50cfdbe
BLAKE2b-256 ef4531376434693c72a69d28d08dd23dcf744d8de679a9aa8f313b46333b8903

See more details on using hashes here.

File details

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

File metadata

  • Download URL: packify-0.3.2-py3-none-any.whl
  • Upload date:
  • Size: 9.9 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.2-py3-none-any.whl
Algorithm Hash digest
SHA256 047291ee5c7bc4d65dc6ecbd54b763b165094a2102a5bd07ae82ce8619930959
MD5 17762e19b203aebb3b4aee1d31842434
BLAKE2b-256 265432431681ea237ab62ae8e758c5da19f1c7c59b45b6ca5a452eda5553660a

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