Reputation: 608
I have these scripts that perform a lot of expensive computations. One optimization I do is to evaluate the expensive function on a grid, cache the grid, and interpolate for calls within the grid. It is important that the files be written out to disk so that future sessions can benefit from the cache. When this script was just for my own personal use, I could put the cache wherever. Now that I want to incorporate it into a package for wider distribution, I find that I need to have some way to know where is it kosher to store cache files for a package? Do I just need to make some decisions, or are there some procedures I should follow (e.g. let the user modify the directory at install time, at run-time, etc)?
Edit: this code will also have functions based on interpolating data from other sources. So I will need a place to store those, too, but need to know where it is standard to do so and how to detect where that is on a particular install (something hard coded at install time, or can Python modules detect where they're installed at runtime?). Point being, this location needs to be persistent in a way that I understand temporary directories not to be. Therefore, this would ideally be done inside of the package's directory structure or somewhere in the user's home directory. If in the package's directories, it is acceptable if I have to do shenanigans with permissions to make a directory that the user can modify.
Upvotes: 10
Views: 7623
Reputation: 5331
For those who want the awesomeness of Danilia's platformdirs
—so reliable/portable that even Pip uses it—without the suckiness of needless bloat, the full implementation logic of user_cache_dir
reduces to:
# SPDX-License-Id: MIT
# Credit: Jack Giffin and platformdirs: github.com/tox-dev/platformdirs
# Source: https://stackoverflow.com/a/79403791/5601591
def user_cache_dir_from_platformdirs():
from sys import platform, path
from os import getenv, path
if platform == "darwin":
return os.path.expanduser("~/Library/Caches")
elif platform == "win32":
try: # https://learn.microsoft.com/en-us/windows/win32/shell/knownfolderid
from ctypes import windll, wintypes, create_unicode_buffer, c_int
buf, gfpW = create_unicode_buffer(1024), windll.shell32.SHGetFolderPathW
gfpW.argtypes = [wintypes.HWND,c_int,wintypes.HANDLE,wintypes.DWORD,wintypes.LPWSTR]
gfpW.restype = wintypes.HRESULT
if 0 == gfpW(None, 28, None, 0, buf) and buf[0] != 0:
return buf.value # CSIDL_LOCAL_APPDATA = 28
except Exception:
pass
if getenv("LOCALAPPDATA") and path.isdir(getenv("LOCALAPPDATA")):
return getenv("LOCALAPPDATA")
from winreg import OpenKey, QueryValueEx, HKEY_CURRENT_USER
key = OpenKey(HKEY_CURRENT_USER, r"Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders")
return str( QueryValueEx(key, "Local AppData")[1] )
elif getenv("ANDROID_DATA") == "/data" and getenv("ANDROID_ROOT") == "/system" and not getenv("SHELL") and not getenv("PREFIX"):
try:
from android import mActivity
context = cast("android.content.Context", mActivity.getApplicationContext())
return context.getFilesDir().getAbsolutePath() + "/cache"
except Exception:
try:
from jnius import autoclass # noqa: PLC0415
context = autoclass("android.content.Context")
return context.getFilesDir().getAbsolutePath() + "/cache"
except Exception:
from re import match
for dir in path:
if match(r"/data/(data|user/\d+)/(.+)/files", dir):
return path.split("/files")[0] + "/cache"
for dir in path:
if match(r"/mnt/expand/[a-fA-F0-9-]{36}/(data|user/\d+)/(.+)/files", dir):
return path.split("/files")[0] + "/cache"
# For all Linux and *nix including Haiku, OpenIndiana, and the BSDs:
return getenv("XDG_CACHE_HOME","").strip() or path.expanduser("~/.cache")
NOTICE: above differs subtly from platformdirs
in that it attempts to return the generic local-user cache dir, whereas platformdirs
bases its behavior upon the provided name of your software.
Upvotes: 1
Reputation: 9875
I have the same requirements.
It seems like the way to go is storing to ~/.cache/<app name>
(Linux).
For covering different operating systems, getting similar location can be simplified with platformdirs
(src, PyPI, conda-forge), e.g.:
from platformdirs import user_cache_dir
cachedir = user_cache_dir("<app name>", "<app author>")
Upvotes: 13
Reputation: 11
I found some cached files here C:\Users\User_Name\AppData\Local\pip\cache
It is the folder where pip is installed and cache files/libraries are present.
If you uninstall and reinstall python, then these cached libraries will be used, instead of downloading new ones.
Upvotes: 1
Reputation: 16988
I would consider creating a named temporary file with a prefix that can be recognized by your scripts, so that the file can be reopened in a later session. the file creation would look like:
tempfile.NamedTemporaryFile(prefix='myApp', delete=False)
Otherwise, I would default to the current working directory and provide an option to set a folder at run-time with argparse.
Upvotes: 0