user1438098
user1438098

Reputation: 2399

Python: Getting AppData folder in a cross-platform way

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.

Upvotes: 33

Views: 15162

Answers (8)

nicbou
nicbou

Reputation: 1056

The platformdirs package serves that purpose. For example, platformdirs.user_cache_dir.

Upvotes: 0

giuliano-macedo
giuliano-macedo

Reputation: 519

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)


Upvotes: 3

proxe
proxe

Reputation: 101

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.

Upvotes: 0

Jason S
Jason S

Reputation: 189656

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.)

Upvotes: 19

voilalex
voilalex

Reputation: 2585

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

Upvotes: 1

Joshua Herr
Joshua Herr

Reputation: 47

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.

Upvotes: 1

Honest Abe
Honest Abe

Reputation: 8758

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".

Upvotes: 17

Harsh
Harsh

Reputation: 57

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')

Upvotes: 1

Related Questions