IvanShpotenko
6/26/2018 - 3:45 PM

Decorator to pickle function results

Decorator to pickle function results

#!/usr/bin/python3.6
import pickle
import re
from os.path import join, exists
from typing import Callable

from decorator import decorator


def slugify(s: str):
    """ Helper function.
    Simplifies ugly strings into something URL-friendly.
    https://blog.dolphm.com/slugify-a-string-in-python/
    >>> print(slugify("[Some] _ Article's Title--"))
    some-articles-title
    """

    # "[Some] _ Article's Title--"
    # "[some] _ article's title--"
    s = s.lower()

    # "[some] _ article's_title--"
    # "[some]___article's_title__"
    for c in [' ', '-', '.', '/']:
        s = s.replace(c, '_')

    # "[some]___article's_title__"
    # "some___articles_title__"
    s = re.sub('\W', '', s)

    # "some___articles_title__"
    # "some   articles title  "
    s = s.replace('_', ' ')

    # "some   articles title  "
    # "some articles title "
    s = re.sub('\s+', ' ', s)

    # "some articles title "
    # "some articles title"
    s = s.strip()

    # "some articles title"
    # "some-articles-title"
    s = s.replace(' ', '-')

    return s


@decorator
def cache_pickle(func: Callable, path_to_cache: str = None, *args, **kwargs):
    ''' Caches function result to pickle file in directory provided in path_to_cache.
    Args:
        func: computationally heavy function
        path_to_cache: path to cached pickle
    '''
    key = slugify(f'{func.__name__}_{args}_{kwargs}')
    filename = f'_cached_{key}.pickle'
    cache_filepath = join(path_to_cache, filename) if path_to_cache else key
    if exists(cache_filepath):
        with open(cache_filepath, 'rb') as fh:
            result = pickle.load(fh)
    else:
        result = func(*args, **kwargs)
        with open(cache_filepath, 'wb') as fh:
            pickle.dump(result, fh)
    return result