A tool for light-duty persistent memoization of API calls

Overview

JSON Memoize

What is this?

json_memoize is a straightforward tool for light-duty persistent memoization, created with API calls in mind. It stores the arguments passed to a function and that function call's returned value in a dict, and writes that dict's contents to disk in a .json file.

Arguments at a glance

  • max_age - sets the maximum allowed age in seconds before a cached entry is considered invalid.
  • max_size - sets the maximum number of entries that can be stored in the cache.
  • force_update - overwrites cached values with fresh ones.
  • cache_folder_path - sets the location of the associated .json file.
  • app_name - if no cache_folder_path is provided, app_name is used to create a folder in the default user cache folder.
  • cache_file_name - manually sets the name of the cache file.

Basic Use

Import and add the decorator @memoize to memoize a function.

Warning: json_memoize stores arguments passed to memoized functions in a plain text format. Do not pass your API key, or any other sensitive information, to memoized functions.

Here's a slow api call:

def slow_api_call(arg_1:str, arg_2: str) -> str:
    response = requests.get(f"https://wowthistakesforever.slow/arg-1={arg_1}&arg-2={arg_2}")
    return response.text

Add the @memoize decorator to memoize it.

from json_memoize import memoize

@memoize
def slow_api_call(arg_1:str, arg_2: str) -> str:
    response = requests.get(f"https://wowthistakesforever.slow/arg-1={arg_1}&arg-2={arg_2}")
    return response.text

If the function is called again with the same arguments, the resulting value will be retrieved from the cache without executing the function.

max_age

If you don't want to keep data that's too old, you can set a max age.

@memoize(max_age=600)
def slow_api_call(arg_1:str, arg_2: str) -> str:
    ...

The age of an entry is determined from the time it was first added to the cache. If the difference between that time and the current time exceeds the max_age value, the cached value will be overwritten with a fresh one. Entries that have exceeded max_age will not be written to disk. If max_age is not set, cache entries will not expire. Note: max_age is in seconds. Consider creating variables for measures of time that are inconvenient or unclear when written in seconds, e.g.:

one_week = 604_800
@memoize(max_age=one_week)
    ...

max_size

If you don't want to cache too many entries, you can set a maximum number of entries to store.

@memoize(max_size=10)
def slow_api_call(arg_1:str, arg_2: str) -> str:
    ...

If max_size is set, json_memoize will delete cache entries from oldest to youngest until it meets the specified size limit before it saves the file to disk. As with max_age, the age of an entry is determined by the time at which it was first added to the cache, not when it was most recently used. Note: The size limit is only enforced when the cache file is being written. While the JsonCache object is live in memory, the limit can be exceeded.

force_update

If something in your ecosystem has changed and you want to force the cached values to be updated with fresh information, you can do that too.

@memoize(force_update=True)
def slow_api_call(arg_1:str, arg_2: str) -> str:
    ...

If force_update is True, all entries in the cache will be overwritten, even if they have not yet reached max_age.

Setting the Cache Folder

To reduce the likelihood of name collisions, json_memoize stores its cache files in named folders. There are multiple ways to specify where this folder is located.

Automatic folder creation using app_name

If a value is provided for app_name, json_memoize will use this value to name a new folder within the operating systems preferred user cache folder. e.g.:

@memoize(app_name='my_app') will create a folder structure like ".cache/my_app/"

Manual cache folder assignment

If a cache_folder argument is supplied to the decorator, it will store cache files in that folder. Note: if cache_folder is supplied, it will overrule app_name.

Default folder location

Warning: Not recommended!

If neither cache_folder nor app_name is provided, json_memoize will use its default folder name, yielding a folder structure like ".cache/json_memoize/"

This is not recommended, as intermingling cache files from multiple apps increases the risk of file name collisions, which could cause apps to behave unpredictably.

Naming Cache Files

By default, json_memoize will create each cache file using the name of the function being memoized, e.g.:

@memoize
def slow_api_call():
    ... 

This will create a file called "slow_api_call_cahce.json".

Setting a custom file name with cahce_file_name

If a value is provided for cache_file_name, json_memoize will instead use this value to name the cache file.

Storage and Performance Details

Storage

When a call is made to a memoized function, json_memoize will generate a string from the passed arguments, and use that string as the key in its internal cache dictionary. The value returned by the call is stored as the associated value. Writing this dict to disk is accomplished using json.dump(). Seperate cache files are made for each memoized function.

Warning: It is assumed here that @memoize will be invoked in situations where both the arguments and the returned value of a function have consistent, unambiguous string representations. Passing arguments with unreliable string representation will cause the cache to behave unpredictably. json_memoize will log a warning if it detects something that looks like a repr() output that points to a memory address in an incoming argument. Also, once again, do not pass security-relevant information to memoized functions.

Performance

json_memoize is intended to be performant relative to a slow API call, and has not been optimized further than that. If max_size is exceeded, the entries in the dict are sorted so the oldest ones can be dropped. Setting aside hard drive performance, this sorting operation is the most costly step of the process, and it occurs every time the cahce file is saved.

CMPE 204 Modelling Project

CISC/CMPE 204 Modelling Project Welcome to the major project for CISC/CMPE 204 (Fall 2021)! Change this README.md file to summarize your project (few

totallyrin 2 May 16, 2022
Traditionally, there is considerable friction for developers when setting up development environments

This self-led, half-day training will teach participants the patterns and best practices for working with GitHub Codespaces

CSE Labs at Spark 12 Dec 02, 2022
Batch Python Program Verify

Batch Python Program Verify About As a TA(teaching assistant) of Programming Class, it is very annoying to test students' homework assignments one by

Han-Wei Li 7 Dec 20, 2022
This repository provides a set of easy to understand and tested Python samples for using Acronis Cyber Platform API.

Base Acronis Cyber Platform API operations with Python !!! info Copyright © 2019-2021 Acronis International GmbH. This is distributed under MIT licens

Acronis International GmbH 3 Aug 11, 2022
Sequence clustering and database creation using mmseqs, from local fasta files

Sequence clustering and database creation using mmseqs, from local fasta files

Ana Julia Velez Rueda 3 Oct 27, 2022
Test reproducibility of leiden/umap on different systems

Demonstrate that UMAP and Leiden analysis is not reproducible between different cpu architectures.

Gregor Sturm 2 Oct 16, 2021
A python program, imitating functionalities of a banking system

A python program, imitating functionalities of a banking system, in order for users to perform certain operations in a bank.

Moyosore Weke 1 Nov 26, 2021
Rates how pog a word or user is. Not random and does have *some* kind of algorithm to it.

PogRater :D Rates how pogchamp a word is :D A fun project coded by JBYT27 using Python3 Have you ever wondered how pog a word is? Well, congrats, you

an aspirin 2 Jun 25, 2022
A dog facts python module

A dog facts python module

Fayas Noushad 3 Nov 28, 2021
The repository is about 100+ python programming exercise problem discussed, explained, and solved in different ways

Break The Ice With Python A journey of 100+ simple yet interesting problems which are explained, solved, discussed in different pythonic ways Introduc

Abdullah Al Masud Tushar 2.2k Jan 04, 2023
ERPNext Easy Letterhead

ERPNext Easy Letterhead Intro Quality letterheads are a problem for non-technical users. So we've built (really hacked together) a slightly easier sol

Bantoo 3 Jan 02, 2023
Class and mathematical functions for quaternion numbers.

Quaternions Class and mathematical functions for quaternion numbers. Installation Python This is a Python 3 module. If you don't have Python installed

3 Nov 08, 2022
Repository voor verhalen over de woningbouw-opgave in Nederland

Analyse plancapaciteit woningen In deze notebook zetten we cijfers op een rij om de woningbouwplannen van Nederlandse gemeenten in kaart te kunnen bre

Follow the Money 10 Jun 30, 2022
An assistant to guess your pip dependencies from your code, without using a requirements file.

Pip Sala Bim is an assistant to guess your pip dependencies from your code, without using a requirements file. Pip Sala Bim will tell you which packag

Collage Labs 15 Nov 19, 2022
Shopping-card - Shopping Card Project With Python

Shopping Card Project this application was built to handle problems with saving

moein98 1 May 06, 2022
Platform Tree for Xiaomi Redmi Note 7/7S (lavender)

The Xiaomi Redmi Note 7 (codenamed "lavender") is a mid-range smartphone from Xiaomi announced in January 2019. Device specifications Device Xiaomi Re

MUHAMAD KHOIRON 2 Dec 20, 2021
A software dedicated to automaticaly select the agent of your desire in Valorant

AUTOPICKER A software dedicated to automaticaly select the agent of your desire in Valorant GUIDE Before stariting to use this program check if you ha

p1n00 0 Sep 24, 2022
Python scripts to interact with Upper Deck ePack online trading card platform

This script should connect to the Upper Deck ePack API using your browser cookies and download a list of your current collection and save it as a CSV.

Adrian Kent 1 Nov 22, 2021
Um sistema de llogin feito em uma interface grafica.

Interface-para-login Um sistema de login feito com JSON. Utilizando a biblioteca Tkinter, eu criei um sistema de login, onde guarda a informações de l

Mobben 1 Nov 28, 2021
XHacks 2021 Startup Track Winner: Be Heard. Educate, Enact, Empower. No voice left behind. (backend)

Be Heard: X Hacks 2021 Submission Educate, Enact, Empower. No voice left behind. Inspiration To say 2020 was an eventful year would be an understateme

3 Jul 14, 2022