Skip to main content

A simple decorator to make your classes hickle-able

Project description

https://codecov.io/gh/steven-murray/hickleable/branch/main/graph/badge.svg?token=7TRaE5cJzZ PyPI - License https://img.shields.io/badge/code%20style-black-000000.svg Documentation Status

A simple decorator to make your classes hickle-able.

What is this?

hickleable provides a simple decorator for your classes that will almost always make them serilalize well using the excellent hickle package. By default, custom classes are not supported by hickle – instead, they are written to the HDF5 file as a binary dataset that is serialized using the standard Python pickle. This obviously negates much of the benefit of hickle, for example, the fact that pickle-serialized data is only readable using Python.

hickle provides a way to serialize your custom classes using the HDF5 format, via defining a few hooks for loading/dumping. However, it can be a little tricky to implement these hooks, as they are quite general.

hickleable provides a “default implementation” of these hooks that should satisfy the requirements of most custom classes, and can be applied as a simple decorator. This makes it a one-liner to transform your class into a well-supported data format.

Check out the docs at ReadTheDocs.

Installation

Simply pip install hickleable. Conda-installable dependencies include h5py.

Usage

Simply:

from hickleable import hickleable

@hickleable()
class MyClass:
   def __init__(self, a=1, b='foo', c={'a': 'dict'}):
       self.a = a
       self.b = b
       self.c = c

Now, MyClass can be hickled without any pickling:

import hickle

my_obj = MyClass()
hickle.dump(my_obj, 'temporary_file.h5')  # Note: no warnings about having to pickle
new_obj = hickle.load('temporary_file.h5')

One super cool thing is that @cached_property attributes are respected, and dataclasses are also supported:

from dataclass import dataclass
from functools import cached_property

@hickleable()
@dataclass
class CachedClass:
    foo: str
    bar: int

    @cached_property
    def foobar(self) -> str:
        print("Obtaining foobar...")
        return foo*bar

c = CachedClass('baz', 50000)

foobar = c.foobar  # prints "Obtaining foobar..."
foobar = c.foobar  # prints nothing, since it's returning cached value.

hickle.dump(c, 'foobar.h5')
d = hickle.load('foobar.h5')

d_foobar = d.foobar  # prints nothing! The value is cached in the hickle file.

One thing to note is that the cached properties are only saved in the hickle file if they have already been evaluated. To force hickle to write out all cached properties, use the evaluate_cached_properties=True parameter in the call to hickleable().

Customizing Dumping/Loading

While hickleable will automatically render most classes hickle-able, there are bound to be corner cases in which constituent attributes are not themselves hickleable, or other concerns that you will want to customize. While all of this is of course totally customizable by using the dumping/loading hooks from hickle, the hickleable decorator also respects the magic methods __gethstate__ and __sethstate__, which act exactly like __getstate__ and __setstate__ do for pickling. In fact, if the latter exist and the former don’t, the latter will be used to serialize the object in hickle. For instance, let’s say you have a class that keeps track of the number of times it is called in its lifecycle:

@hickleable()
class Counter:
    def __init__(self, a):
        self.a = a
        self._counts = 0

    def __call__(self, b):
        self._counts += 1
        self.a *= b

If we make an instance and call it a few times, the _counts attribute is larger than zero. If we save the object to a hickle file and load it back up somewhere else, it will start with _counts > 0. We can avoid this as follows:

def ignore_counts(self, state: dict):
    state['_counts'] = 0
    self.__dict__.update(state)

Counter.__setstate__ = ignore_counts

We could also have removed _counts entirely from the hickle file:

def remove_counts(self) -> dict:
    return {k: v for k, v in self.__dict__.items() if k != '_counts'}

Counter.__gethstate__ = remove_counts

Note that since we set ignore_counts to be the __setstate__ method, it will be respected both for hickle and pickle. We set remove_counts as the __gethstate__ method, which means it will only be respected for hickle.

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

hickleable-0.1.1.tar.gz (21.0 kB view details)

Uploaded Source

Built Distribution

hickleable-0.1.1-py2.py3-none-any.whl (7.2 kB view details)

Uploaded Python 2 Python 3

File details

Details for the file hickleable-0.1.1.tar.gz.

File metadata

  • Download URL: hickleable-0.1.1.tar.gz
  • Upload date:
  • Size: 21.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.1 CPython/3.10.6

File hashes

Hashes for hickleable-0.1.1.tar.gz
Algorithm Hash digest
SHA256 893df5e47fa256242b1375c3cb86f4b1051fe4718be03794660e33c7a807b014
MD5 623be018bd97a8ef395335de9c603ae7
BLAKE2b-256 29c0a0cbae3d34c07ac29178cc2c529942b8e073c2cfa86d286377260b45cd95

See more details on using hashes here.

File details

Details for the file hickleable-0.1.1-py2.py3-none-any.whl.

File metadata

  • Download URL: hickleable-0.1.1-py2.py3-none-any.whl
  • Upload date:
  • Size: 7.2 kB
  • Tags: Python 2, Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.1 CPython/3.10.6

File hashes

Hashes for hickleable-0.1.1-py2.py3-none-any.whl
Algorithm Hash digest
SHA256 049fea4edd3067210b5c706a108b2d59cf43efce40b7ae6a76fd9dbabf8297de
MD5 02595eb28098aa74df10512b54d9181c
BLAKE2b-256 226a0dc14b732d171899113dbb2954cd4bb91e78546426f58d4c306c3b7e75bb

See more details on using hashes here.

Supported by

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