<commit_before>#! /usr/bin/env python

"""
Module with utilities.
"""

from __future__ import division, print_function

__author__ = '<NAME>, <NAME>'
__all__ = ['Progressbar']

import os
import sys
import numpy as np

import itertools as itt
from multiprocessing import Pool

from vip_hci import __version__

sep = '-' * 80
vip_figsize = (10, 5)


def print_precision(array, precision=3):
    """ Prints an array with a given floating point precision. 3 by default.
    """
    return print(np.array2string(array.astype(float), precision=precision))


class SaveableEmpty(object):
    """
    Empty object. Used by ``Saveable`` to restore the state of an object wihtout
    calling __init__. Similar to what pickle/copy do.
    """
    pass


class Saveable(object):
    def save(self, filename):
        """
        Save a VIP object to a npz file.


        """

        vip_object = self.__class__.__name__

        if hasattr(self, "_saved_attributes"):

            data = {}

            for a in self._saved_attributes:
                if hasattr(self, a):
                    data[a] = getattr(self, a)

                    # set marker to re-build the original datatype
                    # (for non-np types like float, string, ...)
                    if not isinstance(getattr(self, a), np.ndarray):
                        data["_item_{}".format(a)] = True

                np.savez_compressed(filename, _vip_version=__version__,
                                    _vip_object=vip_object, **data)

        else:
            raise RuntimeError("_saved_attributes not found for class {}"
                               "".format(vip_object))

    @classmethod
    def load(cls, filename):
        if not filename.endswith(".npz"):
            filename += ".npz"

        data = np.load(filename)

        if "_vip_object" not in data:
            raise RuntimeError("The file you specified is not a VIP object.")

        file_vip_object = data["_vip_object"].item()
        if file_vip_object != cls.__name__:
            raise RuntimeError("The object in the file is of type '{}', please "
                               "use that classes 'load()' method instead."
                               "".format(file_vip_object))

        file_vip_version = data["_vip_version"].item()
        if file_vip_version != __version__:
            print("The file was saved with VIP {}. There may be some"
                  "compatibility issues. Use with care."
                  "".format(file_vip_version))

        self = SaveableEmpty()
        self.__class__ = cls

        for k in data:
            if k.startswith("_"):
                continue

            if "_item_{}".format(k) in data:
                setattr(self, k, data[k].item())  # un-pack np array
            else:
                setattr(self, k, data[k])

        return self


class Progressbar(object):
    """ Show progress bars. Supports multiple backends.

    Examples
    --------
    .. code:: python

        from vip_hci.var import Progressbar
        Progressbar.backend = "tqdm"

        from time import sleep<commit_msg>FIX: set non-saved but expected attrs to None<commit_after>#! /usr/bin/env python

"""
Module with utilities.
"""

from __future__ import division, print_function

__author__ = '<NAME>, <NAME>'
__all__ = ['Progressbar']

import os
import sys
import numpy as np

import itertools as itt
from multiprocessing import Pool

from vip_hci import __version__

sep = '-' * 80
vip_figsize = (10, 5)


def print_precision(array, precision=3):
    """ Prints an array with a given floating point precision. 3 by default.
    """
    return print(np.array2string(array.astype(float), precision=precision))


class SaveableEmpty(object):
    """
    Empty object. Used by ``Saveable`` to restore the state of an object wihtout
    calling __init__. Similar to what pickle/copy do.
    """
    pass


class Saveable(object):
    def save(self, filename):
        """
        Save a VIP object to a npz file.


        """

        vip_object = self.__class__.__name__

        if hasattr(self, "_saved_attributes"):

            data = {}

            for a in self._saved_attributes:
                if hasattr(self, a):
                    data[a] = getattr(self, a)

                    # set marker to re-build the original datatype
                    # (for non-np types like float, string, ...)
                    if not isinstance(getattr(self, a), np.ndarray):
                        data["_item_{}".format(a)] = True

                np.savez_compressed(filename, _vip_version=__version__,
                                    _vip_object=vip_object, **data)

        else:
            raise RuntimeError("_saved_attributes not found for class {}"
                               "".format(vip_object))

    @classmethod
    def load(cls, filename):
        if not filename.endswith(".npz"):
            filename += ".npz"

        data = np.load(filename)

        if "_vip_object" not in data:
            raise RuntimeError("The file you specified is not a VIP object.")

        file_vip_object = data["_vip_object"].item()
        if file_vip_object != cls.__name__:
            raise RuntimeError("The object in the file is of type '{}', please "
                               "use that classes 'load()' method instead."
                               "".format(file_vip_object))

        file_vip_version = data["_vip_version"].item()
        if file_vip_version != __version__:
            print("The file was saved with VIP {}. There may be some"
                  "compatibility issues. Use with care."
                  "".format(file_vip_version))

        self = SaveableEmpty()
        self.__class__ = cls

        for k in data:
            if k.startswith("_"):
                continue

            if "_item_{}".format(k) in data:
                setattr(self, k, data[k].item())  # un-pack np array
            else:
                setattr(self, k, data[k])

        # add non-saved, but expected attributes (backwards compatibility)
        for exp_k in self._saved_attributes:
            if exp_k not in data:
                setattr(self, exp_k, None)

        return self


class Progressbar(object):
    """ Show progress bars. Supports multiple backends.

    Examples
    --------
    .. code:: python

        from vip_hci.var import Progressbar
        Progressbar.backend = "tqdm"

        from time import sleep
{'fraction_non_alphanumeric': 0.10105393676379418, 'fraction_numerical': 0.0024798512089274642, 'mean_word_length': 1.8782337198929526, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6582840', 'n_tokens_mistral': 1867, 'n_tokens_neox': 1775, 'n_words': 545}