Python: Getting AppData folder in a cross-platform way
Asked Answered
F

7

32

I'd like a code snippet that gets the proper directory for app data (config files, etc) on all platforms (Win/Mac/Linux at least). For example: %APPDATA%/ on Windows.

Fleece answered 29/9, 2013 at 14:7 Comment(0)
A
20

If you don't mind using the appdirs module, it should solve your problem. (cost = you either need to install the module or include it directly in your Python application.)

Ardelia answered 25/3, 2014 at 19:35 Comment(5)
@Taylor D Edmiston please add your own answerArdelia
Why revert the edit adding usage examples from the readme to make this answer complete?! As you know good answers are complete vs just "click this link". Removing highly relevant and valuable usage info feels a bit passive aggressive... Per stackoverflow.com/help/how-to-answer: "Links to external resources are encouraged, but please add context around the link so your fellow users will have some idea what it is and why it’s there. Always quote the most relevant part of an important link, in case the external resource is unreachable or goes permanently offline."Foucquet
You add your own answer, please. By editing my answer to make it better, but significantly different, it is no longer my answer. You are welcome to suggest this, but please don't reach in and do the edit for me.Ardelia
It does make it significantly different, and conflicts with the author's intent. This is not Wikipedia. All I'm saying is if you want to improve, post your own answer; I'll even upvote it.Ardelia
Point taken but FWIW SO specifically mentions "All contributions are licensed under Creative Commons, and this site is collaboratively edited, like Wikipedia." in the guide to editing posts - stackoverflow.com/help/editing.Foucquet
H
17

Qt's QStandardPaths documentation lists paths like this.

Using Python 3.8

import sys
import pathlib

def get_datadir() -> pathlib.Path:

    """
    Returns a parent directory path
    where persistent application data can be stored.

    # linux: ~/.local/share
    # macOS: ~/Library/Application Support
    # windows: C:/Users/<USER>/AppData/Roaming
    """

    home = pathlib.Path.home()

    if sys.platform == "win32":
        return home / "AppData/Roaming"
    elif sys.platform == "linux":
        return home / ".local/share"
    elif sys.platform == "darwin":
        return home / "Library/Application Support"

# create your program's directory

my_datadir = get_datadir() / "program-name"

try:
    my_datadir.mkdir(parents=True)
except FileExistsError:
    pass

The Python documentation recommends the sys.platform.startswith('linux') "idiom" for compatibility with older versions of Python that returned things like "linux2" or "linux3".

Huskey answered 19/5, 2020 at 22:17 Comment(2)
I would recommend following the $XDG_DATA_HOME spec for Linux and %APPDATA% or %LOCALAPPDATA% for Windows instead of hardcoding. The Qt paths are actually fallback to rely on in case those variables are not set. I'll add a link to sample code tomorrow, once my PR is merged.Lingerie
^can't edit anymore but here you go: github.com/SwagLyrics/SwagLyrics-For-Spotify/blob/master/…Lingerie
W
3

You can use the following function to get user data dir, tested in linux and w10 (returning AppData/Local dir) it's adapted from the appdirs package:

import sys
from pathlib import Path
from os import getenv


def get_user_data_dir(appname: str) -> Path:
    if sys.platform == "win32":
        import winreg

        key = winreg.OpenKey(
            winreg.HKEY_CURRENT_USER,
            r"Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders",
        )
        dir_, _ = winreg.QueryValueEx(key, "Local AppData")
        ans = Path(dir_).resolve(strict=False)
    elif sys.platform == "darwin":
        ans = Path("~/Library/Application Support/").expanduser()
    else:
        ans = Path(getenv("XDG_DATA_HOME", "~/.local/share")).expanduser()
    return ans.joinpath(appname)


Wily answered 4/10, 2020 at 14:15 Comment(0)
G
1

I recommend researching the locations of 'appdata' in the operating systems that you want to use this program on. Once you know the locations you could simple use if statements to detect the os and do_something().

import sys
if sys.platform == "platform_value":
    do_something()
elif sys.platform == "platform_value":
    do_something()
  • System: platform_value
  • Linux (2.x and 3.x): 'linux2'
  • Windows: 'win32'
  • Windows/Cygwin: 'cygwin'
  • Mac OS X: 'darwin'
  • OS/2: 'os2'
  • OS/2 EMX: 'os2emx'
  • RiscOS: 'riscos'
  • AtheOS: 'atheos'

List is from the official Python docs. (Search for 'sys.platform')

Grous answered 29/9, 2013 at 14:9 Comment(2)
Pretty sure that only works on Windows. I want cross platform :)Fleece
Python is all about abstracting things into common libraries; why isn't there a common function to do this?Ardelia
F
1

You can use module called appdata:

pip install appdata
from appdata import AppDataPaths
app_paths = AppDataPaths()
app_paths.app_data_path  # cross-platform path to AppData folder
Frolic answered 22/12, 2021 at 18:39 Comment(2)
how does the appdata package differ from appdirs?Foucquet
@TaylorD.Edmiston Yeah, essentially there is no difference as I can see. I had no idea about appdirs when I developed appdataFrolic
K
0

I came across a similar problem and I wanted to dynamically resolve all of the Windows % paths without knowing about them prior. You can use os.path.expandvars to resolve the paths dynamically. Something like this:

from os import path

appdatapath = '%APPDATA%\MyApp'
if '%' in appdatapath:
    appdatapath = path.expandvars(appdatapath)
print(appdatapath)

The line at the end will print: C:\Users\\{user}\AppData\Roaming\MyApp This works for windows however I have not tested on Linux. So long as the paths are defined by the environment than expandvars should be able to find it. You can read more about expand vars here.

Kizzee answered 20/9, 2021 at 19:1 Comment(0)
R
0

If you are after the config directory here is a solution that defaults to ~/.config unless a platform specific (sys.platform) entry is available in the method's local platforms: dict

from sys import platform
from os.path import expandvars, join


def platform_config_directory() -> str:
    '''
    Platform config directory
      Entries available in local platforms dict use the current
      "best practice" location for config directories.
      
    Default: $HOME/.config (XDG Base Directory Specification)
      https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html
    '''
    home: str = expandvars('$HOME')

    platforms: dict = {
        "win32": expandvars('%AppData%'),
        "darwin": join(home, 'Library', 'Application Support'),
    }

    if platform in platforms:
        return platforms[platform]

    return join(home, '.config')

This works on windows, mac and linux, however allows for easier expansion given the need.

Retiarius answered 11/12, 2022 at 5:6 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.