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.

Backup dc registry - A simple POC that abuses Backup Operator privileges to remote dump SAM, SYSTEM, and SECURITY

Backup Operator Registry Backup to Domain Compromise A simple POC that abuses Ba

Horizon 3 AI Inc 57 Dec 18, 2022
A normal phoneNumber tracker made with python.

A normal phoneNumber tracker made with python.

CLAYZANE 2 Dec 30, 2021
Python Script to add OpenGapps, Magisk, libhoudini translation library and libndk translation library to waydroid !

Waydroid Extras Script Script to add gapps and other stuff to waydroid ! Installation/Usage "lzip" is required for this script to work, install it usi

Casu Al Snek 331 Jan 02, 2023
BMI-Calculator: Program to Calculate Body Mass Index (BMI)

The Body Mass Index (BMI) or Quetelet index is a value derived from the mass (weight) and height of an individual, male or female.

PyLaboratory 0 Feb 07, 2022
An educational platform for students

Watch N Learn About Watch N Learn is an educational platform for students. Watch N Learn incentivizes students to learn with fun activities and reward

Brian Law 3 May 04, 2022
Flow control is the order in which statements or blocks of code are executed at runtime based on a condition. Learn Conditional statements, Iterative statements, and Transfer statements

03_Python_Flow_Control Introduction 👋 The control flow statements are an essential part of the Python programming language. A control flow statement

Milaan Parmar / Милан пармар / _米兰 帕尔马 209 Oct 31, 2022
Robotic hamster to give you financial advice

hampp Robotic hamster to give you financial advice. I am not liable for any advice that the hamster gives. Follow at your own peril. Description Hampp

1 Nov 17, 2021
CPLib is the abbreviation of Competitive Programming Library.

CPLib CPLib is the abbreviation of Competitive Programming Library. It aims to be a general template and optimization library for competitive programm

12 Oct 16, 2021
CNKD - Minimalistic Windows ransomware written in Python

CNKD Minimalistic Windows ransomware written in Python (Still a work in progress

Alex 2 May 27, 2022
A short course on Julia and open-source software development

Advanced Scientific Computing: producing better code This course is taught as a 6-session "nanocourse" at Washington University in St. Louis. See the

Tim Holy 230 Jan 07, 2023
Script for resizing MTD partitions on a QNAP device in order to be available to upgrade from buster to bullseye

QNAP partitions resize for kirkwood devices. As explained by Marin Michlmayr, Debian bullseye support on kirkwood QNAP devices was dropped due to [mai

Arnaud Mouiche 26 Jan 05, 2023
The last walk-through project in code institute diploma course

Welcome Rocky.C, This is the Code Institute student template for Gitpod. We have preinstalled all of the tools you need to get started. It's perfectly

Rocky.C 1 Jan 31, 2022
A command line interface tool converting starknet warp transpiled outputs into readable cairo contracts.

warp-to-cairo warp-to-cairo is a simple tool converting starknet warp outputs (NethermindEth/warp) outputs into readable cairo contracts. The warp out

Michael K 5 Jun 10, 2022
Python library for creating PEG parsers

PyParsing -- A Python Parsing Module Introduction The pyparsing module is an alternative approach to creating and executing simple grammars, vs. the t

Pyparsing 1.7k Jan 03, 2023
TinyBar - Tiny MacOS menu bar utility to track price dynamics for assets on TinyMan.org

📃 About A simple MacOS menu bar app to display current coins from most popular

Al 8 Dec 23, 2022
Purge all transformation orientations addon for Blender 2.8 and newer versions

CTO Purge This add-on adds a new button to Blender's Transformation Orientation panel which empowers the user to purge all of his/her custom transform

MMMrqs 10 Dec 29, 2022
Python library to natively send files to Trash (or Recycle bin) on all platforms.

Send2Trash -- Send files to trash on all platforms Send2Trash is a small package that sends files to the Trash (or Recycle Bin) natively and on all pl

Andrew Senetar 224 Jan 04, 2023
Larvamatch - Find your larva or punk match.

LarvaMatch Find your larva or punk match. UI TBD API (not started) The API will allow you to specify a punk by token id to find a larva match, and vic

1 Jan 02, 2022
Python most simple|stupid programming language (MSPL)

Most Simple|Stupid Programming language. (MSPL) Stack - Based programming language "written in Python" Features: Interpretate code (Run). Generate gra

Kirill Zhosul 14 Nov 03, 2022
A bunch of codes for procedurally modeling and texturing futuristic cities.

Procedural Futuristic City This is our final project for CPSC 479. We created a procedural futuristic city complete with Worley noise procedural textu

1 Dec 22, 2021