Giter Club home page Giter Club logo

platformdirs's Introduction

The problem

image

When writing desktop application, finding the right location to store user data and configuration varies per platform. Even for single-platform apps, there may by plenty of nuances in figuring out the right location.

For example, if running on macOS, you should use:

~/Library/Application Support/<AppName>

If on Windows (at least English Win) that should be:

C:\Documents and Settings\<User>\Application Data\Local Settings\<AppAuthor>\<AppName>

or possibly:

C:\Documents and Settings\<User>\Application Data\<AppAuthor>\<AppName>

for roaming profiles but that is another story.

On Linux (and other Unices), according to the XDG Basedir Spec, it should be:

~/.local/share/<AppName>

platformdirs to the rescue

This kind of thing is what the platformdirs package is for. platformdirs will help you choose an appropriate:

  • user data dir (user_data_dir)
  • user config dir (user_config_dir)
  • user cache dir (user_cache_dir)
  • site data dir (site_data_dir)
  • site config dir (site_config_dir)
  • user log dir (user_log_dir)
  • user documents dir (user_documents_dir)
  • user downloads dir (user_downloads_dir)
  • user pictures dir (user_pictures_dir)
  • user videos dir (user_videos_dir)
  • user music dir (user_music_dir)
  • user desktop dir (user_desktop_dir)
  • user runtime dir (user_runtime_dir)

And also:

  • Is slightly opinionated on the directory names used. Look for "OPINION" in documentation and code for when an opinion is being applied.

Example output

On macOS:

>>> from platformdirs import *
>>> appname = "SuperApp"
>>> appauthor = "Acme"
>>> user_data_dir(appname, appauthor)
'/Users/trentm/Library/Application Support/SuperApp'
>>> site_data_dir(appname, appauthor)
'/Library/Application Support/SuperApp'
>>> user_cache_dir(appname, appauthor)
'/Users/trentm/Library/Caches/SuperApp'
>>> user_log_dir(appname, appauthor)
'/Users/trentm/Library/Logs/SuperApp'
>>> user_documents_dir()
'/Users/trentm/Documents'
>>> user_downloads_dir()
'/Users/trentm/Downloads'
>>> user_pictures_dir()
'/Users/trentm/Pictures'
>>> user_videos_dir()
'/Users/trentm/Movies'
>>> user_music_dir()
'/Users/trentm/Music'
>>> user_desktop_dir()
'/Users/trentm/Desktop'
>>> user_runtime_dir(appname, appauthor)
'/Users/trentm/Library/Caches/TemporaryItems/SuperApp'

On Windows:

>>> from platformdirs import *
>>> appname = "SuperApp"
>>> appauthor = "Acme"
>>> user_data_dir(appname, appauthor)
'C:\\Users\\trentm\\AppData\\Local\\Acme\\SuperApp'
>>> user_data_dir(appname, appauthor, roaming=True)
'C:\\Users\\trentm\\AppData\\Roaming\\Acme\\SuperApp'
>>> user_cache_dir(appname, appauthor)
'C:\\Users\\trentm\\AppData\\Local\\Acme\\SuperApp\\Cache'
>>> user_log_dir(appname, appauthor)
'C:\\Users\\trentm\\AppData\\Local\\Acme\\SuperApp\\Logs'
>>> user_documents_dir()
'C:\\Users\\trentm\\Documents'
>>> user_downloads_dir()
'C:\\Users\\trentm\\Downloads'
>>> user_pictures_dir()
'C:\\Users\\trentm\\Pictures'
>>> user_videos_dir()
'C:\\Users\\trentm\\Videos'
>>> user_music_dir()
'C:\\Users\\trentm\\Music'
>>> user_desktop_dir()
'C:\\Users\\trentm\\Desktop'
>>> user_runtime_dir(appname, appauthor)
'C:\\Users\\trentm\\AppData\\Local\\Temp\\Acme\\SuperApp'

On Linux:

>>> from platformdirs import *
>>> appname = "SuperApp"
>>> appauthor = "Acme"
>>> user_data_dir(appname, appauthor)
'/home/trentm/.local/share/SuperApp'
>>> site_data_dir(appname, appauthor)
'/usr/local/share/SuperApp'
>>> site_data_dir(appname, appauthor, multipath=True)
'/usr/local/share/SuperApp:/usr/share/SuperApp'
>>> user_cache_dir(appname, appauthor)
'/home/trentm/.cache/SuperApp'
>>> user_log_dir(appname, appauthor)
'/home/trentm/.local/state/SuperApp/log'
>>> user_config_dir(appname)
'/home/trentm/.config/SuperApp'
>>> user_documents_dir()
'/home/trentm/Documents'
>>> user_downloads_dir()
'/home/trentm/Downloads'
>>> user_pictures_dir()
'/home/trentm/Pictures'
>>> user_videos_dir()
'/home/trentm/Videos'
>>> user_music_dir()
'/home/trentm/Music'
>>> user_desktop_dir()
'/home/trentm/Desktop'
>>> user_runtime_dir(appname, appauthor)
'/run/user/{os.getuid()}/SuperApp'
>>> site_config_dir(appname)
'/etc/xdg/SuperApp'
>>> os.environ["XDG_CONFIG_DIRS"] = "/etc:/usr/local/etc"
>>> site_config_dir(appname, multipath=True)
'/etc/SuperApp:/usr/local/etc/SuperApp'

On Android:

>>> from platformdirs import *
>>> appname = "SuperApp"
>>> appauthor = "Acme"
>>> user_data_dir(appname, appauthor)
'/data/data/com.myApp/files/SuperApp'
>>> user_cache_dir(appname, appauthor)
'/data/data/com.myApp/cache/SuperApp'
>>> user_log_dir(appname, appauthor)
'/data/data/com.myApp/cache/SuperApp/log'
>>> user_config_dir(appname)
'/data/data/com.myApp/shared_prefs/SuperApp'
>>> user_documents_dir()
'/storage/emulated/0/Documents'
>>> user_downloads_dir()
'/storage/emulated/0/Downloads'
>>> user_pictures_dir()
'/storage/emulated/0/Pictures'
>>> user_videos_dir()
'/storage/emulated/0/DCIM/Camera'
>>> user_music_dir()
'/storage/emulated/0/Music'
>>> user_desktop_dir()
'/storage/emulated/0/Desktop'
>>> user_runtime_dir(appname, appauthor)
'/data/data/com.myApp/cache/SuperApp/tmp'

Note: Some android apps like Termux and Pydroid are used as shells. These apps are used by the end user to emulate Linux environment. Presence of SHELL environment variable is used by Platformdirs to differentiate between general android apps and android apps used as shells. Shell android apps also support XDG_* environment variables.

PlatformDirs for convenience

>>> from platformdirs import PlatformDirs
>>> dirs = PlatformDirs("SuperApp", "Acme")
>>> dirs.user_data_dir
'/Users/trentm/Library/Application Support/SuperApp'
>>> dirs.site_data_dir
'/Library/Application Support/SuperApp'
>>> dirs.user_cache_dir
'/Users/trentm/Library/Caches/SuperApp'
>>> dirs.user_log_dir
'/Users/trentm/Library/Logs/SuperApp'
>>> dirs.user_documents_dir
'/Users/trentm/Documents'
>>> dirs.user_downloads_dir
'/Users/trentm/Downloads'
>>> dirs.user_pictures_dir
'/Users/trentm/Pictures'
>>> dirs.user_videos_dir
'/Users/trentm/Movies'
>>> dirs.user_music_dir
'/Users/trentm/Music'
>>> dirs.user_desktop_dir
'/Users/trentm/Desktop'
>>> dirs.user_runtime_dir
'/Users/trentm/Library/Caches/TemporaryItems/SuperApp'

Per-version isolation

If you have multiple versions of your app in use that you want to be able to run side-by-side, then you may want version-isolation for these dirs:

>>> from platformdirs import PlatformDirs
>>> dirs = PlatformDirs("SuperApp", "Acme", version="1.0")
>>> dirs.user_data_dir
'/Users/trentm/Library/Application Support/SuperApp/1.0'
>>> dirs.site_data_dir
'/Library/Application Support/SuperApp/1.0'
>>> dirs.user_cache_dir
'/Users/trentm/Library/Caches/SuperApp/1.0'
>>> dirs.user_log_dir
'/Users/trentm/Library/Logs/SuperApp/1.0'
>>> dirs.user_documents_dir
'/Users/trentm/Documents'
>>> dirs.user_downloads_dir
'/Users/trentm/Downloads'
>>> dirs.user_pictures_dir
'/Users/trentm/Pictures'
>>> dirs.user_videos_dir
'/Users/trentm/Movies'
>>> dirs.user_music_dir
'/Users/trentm/Music'
>>> dirs.user_desktop_dir
'/Users/trentm/Desktop'
>>> dirs.user_runtime_dir
'/Users/trentm/Library/Caches/TemporaryItems/SuperApp/1.0'

Be wary of using this for configuration files though; you'll need to handle migrating configuration files manually.

Why this Fork?

This repository is a friendly fork of the wonderful work started by ActiveState who created appdirs, this package's ancestor.

Maintaining an open source project is no easy task, particularly from within an organization, and the Python community is indebted to appdirs (and to Trent Mick and Jeff Rouse in particular) for creating an incredibly useful simple module, as evidenced by the wide number of users it has attracted over the years.

Nonetheless, given the number of long-standing open issues and pull requests, and no clear path towards ensuring that maintenance of the package would continue or grow, this fork was created.

Contributions are most welcome.

platformdirs's People

Contributors

adamjstewart avatar bdrung avatar carlwgeorge avatar cpburnz avatar dependabot[bot] avatar deronnax avatar domdfcoding avatar eddyp avatar efiop avatar freed-wu avatar gaborbernat avatar graingert avatar hugovk avatar jackenmen avatar jdufresne avatar joeyespo avatar julian avatar jwilk avatar keller00 avatar kemzeb avatar ofek avatar papr avatar pradyunsg avatar pre-commit-ci[bot] avatar rayyanansari avatar rexkerr avatar sir-sigurd avatar srid avatar trentm avatar zoofood avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

platformdirs's Issues

Document the intention of the fork

It would be useful to have a section in the README, or elsewhere in the documentation, that describes why this fork exists and its benefits/differences compared to the appdirs library.

Support more environments with platformdirs (variations within an OS)

I am working on projects to adapt Python development to environment variations, such as using git-bash on Windows, using WSL and others. Virtualenv had some issues which led me to discover that it is using platformdirs which I didn't even know existed.

I don't know what all environment variations exist, but I will mention a few that I am aware of: cmd.exe on Windows, powershell on windows, cygwin on Windows, mingw on windows, git-bash on Windows, and GOW on windows. (I run Windows and use VMs and other methods to produce cross-platform code.)

There are multiple issues with running Windows and using various command line shells. One is that Python works with paths in normal Linux "/" form just fine on Windows, but any of the os.path functions that try to normalize or convert paths tend to turn them into Windows "" form. I don't think platformdirs can fix this, but suggestions would be welcome.

The other issue is that each of the above Windows environment variations caused by running a command "shell" produces some variation in how directories are laid out and and how paths are presented.

If platformdirs supported XDG env variables on all platforms and gave them priority the problems could be mostly configured away. This is noted in #4.

The other part of the solution is to recognize environment variations and modify the default paths appropriately.
I want to specifically note git-bash which is extremely common on Windows as it is part of Git for Windows. Unlike cygwin it isn't a complete Linux tool distribution. I have Python installed on Windows and that is the python I run in git-bash. I believe that cygwin has its own python installed. I am currently successfully running full Python with virtualenv and virtualenvwrapper with Git-bash and Windows python with environment modifications.

I am trying to submit pull requests to the various Python packages to support these environment variations more easily.

Document _path API

I was looking at the README wondering if you'd add a pathlib API, but then found it was done so in #27. The README could mention this :)

Add release dates to changelog

Usually, changelogs include the release date along with the release's changelog which makes it much easier to follow IMO.

missing metadata in `setup.py`

When packaging this for MacPorts I realized that it is installed under /opt/local/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/platformdirs-0.0.0-py3.9.egg-info/.

Please note the 0.0.0 in the directory name, which is causing issues when dependents check the installed version, which is now reported as being 0.0.0 instead of 2.2.0 (see, for example, this report). Indeed, checking the setup.py/setup.cfg files shows:

% platformdirs-2.2.0 % python setup.py check
running check
warning: check: missing required meta-data: version

can you please add this required meta-data?

wrong site_data_dir

In README, on Linux:

from platformdirs import *
appname = "SuperApp"
appauthor = "Acme"
site_data_dir(appname, appauthor)
'/usr/local/share/SuperApp'

However, I get

In [16]: site_data_dir(appname, appauthor)
Out[16]: "/home/wzy/.local/share/SuperApp"

Is it a bug?

Does not work with Nuitka

Nuitka creates a single executable out of your python code.

I've used platformdirs in a project of mine called mcrpc. The code itself runs fine, but the executable created with Nuitka spits out this error:

λ ./mcrpc-linux                                                                  
Traceback (most recent call last):
  File "/tmp/.mount_mcrpc-h4h3HH/mcrpc.py", line 14, in <module>
  File "/tmp/.mount_mcrpc-h4h3HH/platformdirs/__init__.py", line 33, in <module platformdirs>
  File "/tmp/.mount_mcrpc-h4h3HH/platformdirs/__init__.py", line 29, in _set_platform_dir_class
  File "importlib.py", line 127, in import_module
ModuleNotFoundError: No module named 'platformdirs.unix'

It spits out a similar error on windows:
ModuleNotFoundError: No module named 'platformdirs.windows'

Is there anything that can be done on platformdirs' side to help it work well with Nuitka? You can try using the executables from v1.2.

Support XDG directories on Windows

By support I don't mean put in all the Linux defaults, but rather if XDG environment variables are set then use them. If not use the Windows defined directories.

This won't affect anyone who has not set XDG variables in their environment.

This provides maximum flexibility and allows for consistency for developers.

I share my HOME directory tree and dot files between Windows and WSL Ubuntu. For any program that provides a way to configure directories I use the typical XDG directories with platform qualifiers as necessary. This provides a very consistent and convenient development environment.

Support XDG env variables on Android or use default XDG directories on Android/Termux

Previous issue #62 with fix #63 messes up all config directories.

Related:

mborsetti/webchanges#28
pypa/pip#10887

The fixed config directory on Termux:

-- platformdirs 2.4.2.dev4+gbd70a11 --
-- app dirs (with optional 'version')
user_data_dir: /data/data/com.termux/files/MyApp/1.0
user_config_dir: /data/data/com.termux/shared_prefs/MyApp/1.0
user_cache_dir: /data/data/com.termux/cache/MyApp/1.0
user_state_dir: /data/data/com.termux/files/MyApp/1.0
user_log_dir: /data/data/com.termux/cache/MyApp/1.0/log
user_documents_dir: /storage/emulated/0/Documents
user_runtime_dir: /data/data/com.termux/cache/MyApp/1.0/tmp
site_data_dir: /data/data/com.termux/files/MyApp/1.0
site_config_dir: /data/data/com.termux/shared_prefs/MyApp/1.0

No app should ever store anything outside $HOME. The correct config directory should reference $HOME first and then the config directory:

$HOME: /data/data/com.termux/files/home
$PREFIX: /data/data/com.termux/files/usr
Config: /data/data/com.termux/files/home/.config

Data structure official reference:

https://github.com/termux/termux-packages/wiki/Termux-file-system-layout

So, Termux dirs should be:

-- platformdirs 2.4.2.dev4+gbd70a11 --
-- app dirs (with optional 'version')
user_data_dir: /data/data/com.termux/files/home/.local/share/MyApp/1.0
user_config_dir: /data/data/com.termux/files/home/.config/MyApp/1.0
user_cache_dir: /data/data/com.termux/files/home/.cache/MyApp/1.0
user_state_dir: /data/data/com.termux/files/home/.local/state/MyApp/1.0
user_log_dir: /data/data/com.termux/files/home/.cache/MyApp/1.0/log
user_documents_dir: /data/data/com.termux/files/home/storage/Documents
user_runtime_dir: /data/data/com.termux/files/usr/var/run/MyApp/1.0/tmp
site_data_dir: /data/data/com.termux/files/usr/share/MyApp/1.0
site_config_dir: /data/data/com.termux/files/usr/etc/MyApp/1.0

Release 2.6.1 fails on import on Python < 3.8 w/o typing extensions

If you import platformdirs on python < 3.8, it now fails with release 2.6.1 unless you have the typing-extensions package already installed.

I think the issue is this change in release 2.6.1: 2.6.0...2.6.1#diff-e6813e0402941ad4943c8261f1ecfe5e1f9ccd55cb009b996fd785f3637fc7c2

I would suggest it should be:

from typing import TYPE_CHECKING

if TYPE_CHECKING:
    if sys.version_info >= (3, 8):  # pragma: no cover (py38+)
        from typing import Literal
    else:  # pragma: no cover (py38+)
        from typing_extensions import Literal

Alternatively, typing_extensions should be added as a dependency

Please consider switching the build-system to flit_core or removing hatch-vcs to ease setuptools bootstrap

Could you please consider switching the build system from setuptools to flit_core, or at least removing the hatch-vcs requirement? This would help Linux distributions such as Gentoo avoid cyclic dependencies that cause bootstrapping unbundled setuptools a real pain. If you agree, I can submit a pull request doing one or the other.

The problem is that the most recent release of setuptools (66.0.0) started using platformdirs. Hatchling has a number of dependencies using setuptools themselves, that are effectively creating a dependency cycle for us — we need platformdirs to install setuptools, platformdirs need hatchling but hatchling needs setuptools first (because of its dependencies). On top of that, hatch-vcs needs setuptools_scm which invariably needs setuptools.

flit_core is a "no dependencies [except for tomli, on Python < 3.11]" by design, so it makes bootstrapping packages much easier. Alternatively, I'm also trying to get hatchling's dependencies not to use setuptools (feels like asking a lot of favors just to get things working again…).

Unfortunately, I don't think it's possible to retain setuptools_scm-style logic. Both hatch-vcs and flit_scm packages use setuptools_scm which invariably means a cyclic dependency with setuptools.

macOS `user_config_dir` goes against OS guidelines

config_dir points to ~/Library/Preferences on macOS:

def user_config_dir(self) -> str:
""":return: config directory tied to the user, e.g. ``~/Library/Preferences/$appname/$version``"""
return self._append_app_name_and_version(os.path.expanduser("~/Library/Preferences/"))
@property
def site_config_dir(self) -> str:
""":return: config directory shared by the users, e.g. ``/Library/Preferences/$appname``"""
return self._append_app_name_and_version("/Library/Preferences")

This goes against macOS guidelines:

Preferences

Contains the user’s preferences. You should never create files in this directory yourself. To get or set preference values, you should always use the NSUserDefaults class or an equivalent system-provided interface.

Requires users to configure hidden imports when used in a PyInstaller project.

appdirs does not suffer from this issue because all the source code is in one file appdirs.py

For example with app.py:

from platformdirs import user_data_dir

print(user_data_dir("appname"))

building this and running it gives an error due to the conditional imports PyInstaller can't detect.

> pyinstaller app.py
> .\dist\app\app.exe
Traceback (most recent call last):
  File "app.py", line 1, in <module>
  File "PyInstaller\loader\pyimod03_importers.py", line 546, in exec_module
  File "platformdirs\__init__.py", line 31, in <module>
  File "platformdirs\__init__.py", line 27, in _set_platform_dir_class
  File "importlib\__init__.py", line 127, in import_module
ModuleNotFoundError: No module named 'platformdirs.windows'
[1348] Failed to execute script 'app' due to unhandled exception!

Users can fix this themselves by configuring a hidden import.

> pyinstaller app.py --hidden-import platformdirs.windows
> .\dist\app\app.exe
C:\Users\<User>\AppData\Local\appname\appname

However it would be nice if platformdirs provided a hook specifying the hidden imports.
PyInstaller provides a mechanism for doing this https://pyinstaller.readthedocs.io/en/stable/hooks.html#provide-hooks-with-package
Especially since I imagine the hidden import would be different depending on the platform.

No module named 'platformdirs.version'

DEBUG: File "/usr/lib/python3.8/site-packages/platformdirs/init.py", line 15, in
DEBUG: from .version import version, version_info
DEBUG: ModuleNotFoundError: No module named 'platformdirs.version'

I build RPM pkg, in generated PKG-INFO i see Version: 0.0.0

revert changes that remove python3.6 support from 2.x

everything is broken with 2.4.1 for python3.6 users
Consider example:
pip3.6 install virtualenv
requires platformdirs<3,>=2 in /usr/local/lib/python3.6/site-packages (from virtualenv)

could you please revert 2.4.1 changes and drop python3.6. support e.g. in 3.0 release. This is major change anyway.

What is the purpose of using app name as author name

I would like to understand the use case for no author, but using the app name as the author name. (I did see the disable option.)

-- app dirs (without optional 'appauthor')
user_data_dir: C:\Users\julie\AppData\Local\MyApp\MyApp

Does not work on Arch Linux subsystem in Termux: `OSError: Cannot find path to android app folder`

Description

Unable to use platformdirs in virtual environment created in Termux's Arch Linux subsystem. It will be raise: OSError: Cannot find path to android app folder.

The Arch Linux subsystem is deployed by install script from SDRausty/TermuxArch.

This problem also breaks the functionality of pip because it embeds this module: pypa/pip#10887

A reddit page reported a similar problem: https://www.reddit.com/r/termux/comments/p6l3yh/i_cant_use_python_virtualenv_on_termux_proot/

Python version

3.10.2

platformdirs version

2.4.1

OS

Android 11, Arch Linux subsystem in Termux

How to Reproduce

  1. Deploy a Arch Linux subsystem environment by install script from SDRausty/TermuxArch. Don't add any parameters. The specific link for install script: https://raw.githubusercontent.com/TermuxArch/TermuxArch/master/setupTermuxArch
  2. Install package python and python-platformdirs in the subsystem. (The latest version of python-platformdirs in the Arch Linux arm repositories: 2.4.1-1, python: 3.10.2-1)
  3. Execute python -m platformdirs or from platformdirs import * in python interpreter. You can see the full screen of error messages.

Output

Shell:

# (Skip the part about deploying the subsystem)

u0_a398@localhost:pts/0->/data/data/com.termux/files/home (0)
> startarch

Welcome to Arch Linux in Termux PRoot!
Install a package: pacman -S package
More  information: pacman -[D|F|Q|R|S|T|U]h
Search   packages: pacman -Ss query
Upgrade  packages: pacman -Syu

Chat:   wiki.termux.com/wiki/Community
GitHub: github.com/archlinuxarm
Help:   help man and info man
IRC:    archlinuxarm.org/about/contact

root09:27~$ pacman -Qi python-platformdirs
名字           : python-platformdirs
版本           : 2.4.1-1
描述           : A small Python module for
                 determining appropriate platform-specific dirs, e.g. a "user
                 data dir"
架构           : any
URL            : https://github.com/platformdirs/platformdirs
软件许可       : MIT
组             : 无
提供           : 无
依赖于         : python
可选依赖       : 无
依赖它         : python-virtualenv
被可选依赖     : 无
与它冲突       : 无
取代           : 无
安装后大小     : 121.81 KiB
打包者         : Arch Linux ARM Build System
                 <[email protected]>
编译日期       : 2021年12月28日 星期二 00时30分09秒
安装日期       : 2022年02月07日 星期一 23时25分34秒
安装原因       : 作为其他软件包的依赖关系安装
安装脚本       : 否
验证者         : 数字签名

root09:27~$ python -m platformdirs
-- platformdirs 2.4.1 --
-- app dirs (with optional 'version')
Traceback (most recent call last):
  File "/usr/lib/python3.10/site-packages/platformdirs/android.py", line 85, in _android_folder
    from jnius import autoclass
ModuleNotFoundError: No module named 'jnius'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/lib/python3.10/runpy.py", line 196, in _run_module_as_main
    return _run_code(code, main_globals, None,
  File "/usr/lib/python3.10/runpy.py", line 86, in _run_code
    exec(code, run_globals)
  File "/usr/lib/python3.10/site-packages/platformdirs/__main__.py", line 46, in <module>
    main()
  File "/usr/lib/python3.10/site-packages/platformdirs/__main__.py", line 27, in main
    print(f"{prop}: {getattr(dirs, prop)}")
  File "/usr/lib/python3.10/site-packages/platformdirs/android.py", line 21, in user_data_dir
    return self._append_app_name_and_version(_android_folder(), "files")
  File "/usr/lib/python3.10/site-packages/platformdirs/android.py", line 97, in _android_folder
    raise OSError("Cannot find path to android app folder")
OSError: Cannot find path to android app folder
root09:27~$ 

Python:

>>> from platformdirs import *
>>> user_data_dir()
Traceback (most recent call last):
  File "/usr/lib/python3.10/site-packages/platformdirs/android.py", line 85, in _android_folder
    from jnius import autoclass
ModuleNotFoundError: No module named 'jnius'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python3.10/site-packages/platformdirs/__init__.py", line 50, in user_data_dir
    return PlatformDirs(appname=appname, appauthor=appauthor, version=version, roaming=roaming).user_data_dir
  File "/usr/lib/python3.10/site-packages/platformdirs/android.py", line 21, in user_data_dir
    return self._append_app_name_and_version(_android_folder(), "files")
  File "/usr/lib/python3.10/site-packages/platformdirs/android.py", line 97, in _android_folder
    raise OSError("Cannot find path to android app folder")
OSError: Cannot find path to android app folder
>>> site_data_
site_data_dir(   site_data_path(
>>> site_data_dir()
Traceback (most recent call last):
  File "/usr/lib/python3.10/site-packages/platformdirs/android.py", line 85, in _android_folder
    from jnius import autoclass
ModuleNotFoundError: No module named 'jnius'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python3.10/site-packages/platformdirs/__init__.py", line 66, in site_data_dir
    return PlatformDirs(appname=appname, appauthor=appauthor, version=version, multipath=multipath).site_data_dir
  File "/usr/lib/python3.10/site-packages/platformdirs/android.py", line 26, in site_data_dir
    return self.user_data_dir
  File "/usr/lib/python3.10/site-packages/platformdirs/android.py", line 21, in user_data_dir
    return self._append_app_name_and_version(_android_folder(), "files")
  File "/usr/lib/python3.10/site-packages/platformdirs/android.py", line 97, in _android_folder
    raise OSError("Cannot find path to android app folder")
OSError: Cannot find path to android app folder
>>>

Linux: Empty environment variables should use defaults

This was originally reported in the appdirs tracker: ActiveState/appdirs#130

The gist is that, per the XDG spec, platformdirs should treat environment variables that are set but empty as if they were unset.


I came across this as part of pypa/pip#10202

pip patches appdirs to work around this: https://github.com/pypa/pip/blob/867bbb00ccb0506095e19a0e111ce06ce71a2495/tools/vendoring/patches/appdirs.patch#L47-L54

There is some prior discussion in pypa/pip#7501 (comment)

Allow XDG_CONFIG_HOME on macOS

For many tools, especially those designed for use across Linux/Unix/Mac, it makes sense to use XDG as a common standard. This especially applies to command line tools, for which ~/Library/* breaks inherited convention (and thus breaks interop).

I have previously submitted PRs to resolve this in several applications on macOS, but it would be easier to establish good defaults here instead of sending PRs to patch around it downstream. (This also makes this a blocker for personal usage – at least without vendoring and modifying the module, which isn't ideal.)

Appdirs issue: ActiveState/appdirs#78

No module named 'platformdirs.version'

DEBUG: File "/usr/lib/python3.8/site-packages/platformdirs/init.py", line 15, in
DEBUG: from .version import version, version_info
DEBUG: ModuleNotFoundError: No module named 'platformdirs.version'

I build RPM pkg, in generated PKG-INFO i see Version: 0.0.0

Could not find a version that satisfies the requirement platformdirs==2.4.1

Just got this message while installing black==21.12b0 on my CI/CD:

$ pip install platformdirs==2.4.1

ERROR: Could not find a version that satisfies the requirement platformdirs==2.4.1 (from versions: 2.0.0a1, 2.0.0a2, 2.0.0a3, 2.0.0, 2.0.2, 2.1.0, 2.2.0, 2.3.0, 2.4.0)
ERROR: No matching distribution found for platformdirs==2.4.1

I checked manually with fresh virtualenv for python 3.9 and 3.8 and the problem persists. Version 2.4.0 works.
Pip version I used: 20.0.2

Python from the Windows store alias paths

Not sure if this a bug in platformdirs, but users will hit this issue so I'll share my observations

Platform dirs will return the environment variable path for things like data dir, log dir for the Python from the Windows Store.

Python in the Windows store uses app execution aliases, so the actual path is something else.

For example:

>>> import platformdirs, os
>>> d = platformdirs.user_data_dir(appname="foo", appauthor="bar")
>>> os.makedirs(d)
>>> d
'C:\\Users\\anthonyshaw\\AppData\\Local\\bar\\foo\\'
>>> test_file = os.path.join(d, 'test.txt')
>>> test_file
'C:\\Users\\anthonyshaw\\AppData\\Local\\bar\\foo\\test.txt'
>>> os.path.realpath(test_file)
'C:\\Users\\anthonyshaw\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.8_qbz5n2kfra8p0\\LocalCache\\Local\\bar\\foo\\test.txt'

This causes issues when you launch a process and use that path for something (e.g. where you created a file), but the process will resolve to a different path.

This can be disabled in apps > advanced app settings > app execution aliases in Windows.

NB: os.path.realpath only resolves this redirection in Python 3.8+ and it only works for files, not directories.

Returning `Path` instead of `str` instances

As mentioned in ActiveState/appdirs#79, I've been working on another fork of appdirs, but would rather hold off on publishing that and focus all efforts in one place.

I mostly have two changes in places:

  • Drop support for ancient python versions (there's little point in a new library supporting Pythons that re long past their EOL, and that just holds back on keeping the library alive).
  • Change the return type of directories to Path instance, to make usage on consumer libraries easier. This kinda means it's not a 100% drop-in replacement, but rather an upgrade (e.g.: like a major).

Maybe it would make sense to have a platformdirs==1.0.0 release, which is functionally identical to appdirs (to allow seamless switching), and then start merging in any non-backwards-compatible changes. Thoughts?

pyproject.toml: license field is incorrectly formatted

Currently, pyproject.toml lists the license as follows:

[project]
license = "MIT"

It should be formatted as follows: (see e.g. https://setuptools.pypa.io/en/latest/userguide/pyproject_config.html)

[project]
license = {text = "MIT"}

Setuptools complains as follows:

ValueError: invalid pyproject.toml config: `project.license`.
configuration error: `project.license` must be valid exactly by one definition (2 matches found):

    - keys:
        'file': {type: string}
      required: ['file']
    - keys:
        'text': {type: string}
      required: ['text']

Add type hints

What are your thoughts on adding type hints (or standalone type stubs)? There's a PR for adding them to appdirs (ActiveState/appdirs#75), but it seems to have stalled. It's a feature I'd like, and I'd consider switching to platformdirs if it had them.

The hints for the function signatures are really simple: Optional[str] or bool for the arguments and str for the return type.

Happy to submit a PR

follow up on #31

I am happy to provide more information, but you locked the Issue. Here it is:

We download the source file from PyPI and use the typical python setup.py install mechanism to install the package. You can confirm this yourself by just doing python setup.py --user from the source directory and you'll see that it is installed as "Installed /Users//Library/Python/3.9/lib/python/site-packages/platformdirs-0.0.0-py3.9.egg"

The missing a required metadata field in setup.cfg (see above) is causing this as it is resolved when you add a version field with the correct specifier? To me this doesn't seem like a packaging issue on our side, but just an oversight of not defining the version number correctly.

I'd appreciate if you'd considering fixing this on your side; otherwise we'd have to carry this simple patch forward ourselves.

list using alternative to multipath

i took note that the multipath variants will use a joined string instead of a list of strings

this would be a pain to support for a Path Type

Issue detecting app data dir on Android (when running in chroot)

When running in a Debian chroot, on Android, platformdirs detects the system as Android, but it can't detect the user data dir. I think this is because the environment is more like a regular Debian system than an Android one

Looking at the code, in _android_folder, it appears the logic is to fimd the first entry in sys.path that starts with /data/data or /data/user/# and ends with /files, then strip off the /files suffix.

Traceback (most recent call last):
  File "/usr/local/lib/python3.9/dist-packages/pip/_vendor/platformdirs/android.py", line 83, in _android_folder
    from jnius import autoclass  # noqa: SC200
ModuleNotFoundError: No module named 'jnius'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/lib/python3.9/dist-packages/pip/_vendor/platformdirs/__init__.py", line 48, in user_data_dir
    return PlatformDirs(appname=appname, appauthor=appauthor, version=version, roaming=roaming).user_data_dir
  File "/usr/local/lib/python3.9/dist-packages/pip/_vendor/platformdirs/android.py", line 19, in user_data_dir
    return self._append_app_name_and_version(_android_folder(), "files")
  File "/usr/local/lib/python3.9/dist-packages/pip/_vendor/platformdirs/android.py", line 95, in _android_folder
    raise OSError("Cannot find path to android app folder")
OSError: Cannot find path to android app folder

Thoughts? It would be nice if it could be detected as a regular Linux (unix?) system

Also the problem occurs in both the standalone platformdirs package and the one pip has a vendored copy of, probably not a big surprise but wanted to mention it.
Thanks, --David

[advice] add check of PREFIX for termux-widget

Now in android, when $SHELL exists, it will use linux config, such as ~/.config/XXX, else it will use android config.

However, for termux-widget, it will not set $SHELL.

Such as create a /data/data/com.termux/files/home/.shortcuts/test

echo $SHELL

return nothing.

Why not add a check not only for $SHELL but also for $PREFIX? the latter is all programs running in termux will set. Thanks.

https://github.com/termux/termux-widget

'env LANG=C python3.6 setup.py build' fails

platformdirs-2.4.0 fails when running setup.py with LANG=C and python3.6 (noticed with python 3.6.15):

Traceback (most recent call last):
  File "setup.py", line 3, in <module>
    setup()
  File "/usr/local/lib/python3.6/site-packages/setuptools/__init__.py", line 153, in setup
    return distutils.core.setup(**attrs)
  File "/usr/local/lib/python3.6/distutils/core.py", line 108, in setup
    _setup_distribution = dist = klass(attrs)
  File "/usr/local/lib/python3.6/site-packages/setuptools/dist.py", line 456, in __init__
    k: v for k, v in attrs.items()
  File "/usr/local/lib/python3.6/distutils/dist.py", line 281, in __init__
    self.finalize_options()
  File "/usr/local/lib/python3.6/site-packages/setuptools/dist.py", line 801, in finalize_options
    ep(self)
  File "/usr/local/lib/python3.6/site-packages/setuptools_scm/integration.py", line 90, in infer_version
    config = Configuration.from_file(dist_name=dist_name)
  File "/usr/local/lib/python3.6/site-packages/setuptools_scm/config.py", line 199, in from_file
    dist_name = _read_dist_name_from_setup_cfg()
  File "/usr/local/lib/python3.6/site-packages/setuptools_scm/config.py", line 210, in _read_dist_name_from_setup_cfg
    parser.read(["setup.cfg"])
  File "/usr/local/lib/python3.6/configparser.py", line 697, in read
    self._read(fp, filename)
  File "/usr/local/lib/python3.6/configparser.py", line 1015, in _read
    for lineno, line in enumerate(fp, start=1):
  File "/usr/local/lib/python3.6/encodings/ascii.py", line 26, in decode
    return codecs.ascii_decode(input, self.errors)[0]
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 306: ordinal not in range(128)

No error when running with LANG=en_US.UTF-8 or de_DE.UTF-8.

This is likely a bug in python3.6, but setup.cfg asserts that platformdirs works with python3.6.

Perhaps the fix is to change setup.cfg to make python_requires = >=3.7

Android support

How about android (termux, beeware, p4a, pydriod, qpython etc) support? Now appdirs has linux-style behavior and defines wrong derictories, e.g.: /etc/xdg, /usr/local/share etc. Check out my fork, I would like to make my own changes to platformdirs, maybe with pathlib.
appdirs: ActiveState#95

How to create user_data_dir roaming folder without appauthor directory?

I would like to generate a user data dir without the appauthor directory.

My code looks like this:

from platformdirs import *


path = user_data_dir("TestApp", appauthor=None, roaming=True)
print(path)

And prints out: C:\Users\Clemens\AppData\Roaming\TestApp\TestApp

I would like it to omit the "TestApp" directory so that it prints out: C:\Users\Clemens\AppData\Roaming\TestApp

How can I achieve this?

I could simply manually remove the last subdirectory but that doesn't really seem like a good solution to me

Auto-create the dirs

The app_paths project supports an additional interface (property) that will ensure the directory exists before returning it (alongside the classic interface where it's the caller's responsibility to create it). Having this interface is very convenient. Could platformdirs implement something similar?

Mac: Could not find METADATA file when installing

For some reason, when running pip install -U pip, or even trying to upgrade platformsdirs directly, it fails during the installation due METADATA missing. Initially, I thought it was a permission flaw on my side (missing write permission on that folder), however, I noted that Metadata was changed on the latest release.

It may be related to #75

System information

OS: MacOS
Arch: amd64
Python version: 3.8.12 (but occurs on Python 3.9 too)
Platformdirs version: 2.5.2

Steps to reproduce

PYVER=py38
TEST_FOLDER="${TMPDIR}/${PYVER}"
mkdir -p ${TEST_FOLDER} || echo "ok"
python -m pip install tox==3.7.0 tox-venv==0.3.1 requests
python -m venv ${TEST_FOLDER}
source ${TEST_FOLDER}/bin/activate
python --version
which python
python -m pip install --upgrade platformdirs
python -m pip install --upgrade pip

Logs

+ python --version
Python 3.8.12
+ python -m pip install --upgrade platformdirs
Requirement already satisfied: platformdirs in /private/var/folders/c2/vd5y5mfs33q84hyzmxvqmyjm0000gp/T/py38/lib/python3.8/site-packages (2.5.2)
ERROR: Could not install packages due to an OSError: [Errno 2] No such file or directory: '/private/var/folders/c2/vd5y5mfs33q84hyzmxvqmyjm0000gp/T/py38/lib/python3.8/site-packages/platformdirs-2.5.2.dist-info/METADATA'

You can obtain the full log here: https://ci.conan.io/blue/organizations/jenkins/Hooks/detail/PR-419/2/pipeline/

2.5.0: sphinx is failing

in docs/copy.py is missing path to platformdirs. After fixing that sphinx still is failing with:

+ SETUPTOOLS_SCM_PRETEND_VERSION=2.5.0
+ /usr/bin/python3 setup.py build_sphinx -b man --build-dir build/sphinx
running build_sphinx
Running Sphinx v4.3.2

Configuration error:
There is a syntax error in your configuration file: from __future__ imports must occur at the beginning of the file (conf.py, line 5)

Here is patch which fixes those two issues:

--- a/docs/conf.py~     2022-02-09 15:53:14.000000000 +0000
+++ b/docs/conf.py      2022-02-09 16:18:10.283191607 +0000
@@ -1,4 +1,6 @@
-from __future__ import annotations
+import os
+import sys
+sys.path.append(os.path.abspath('../src'))

 from platformdirs.version import __version__

Continuous fuzzing by way of OSS-Fuzz

Hi,

I was wondering if you would like to integrate continuous fuzzing by way of OSS-Fuzz? Fuzzing is a way to automate test-case generation and can be used to find unexpected exceptions in Python. In this PR google/oss-fuzz#8244 I did an initial integration into OSS-Fuzz, and the first overall goal is to extend the fuzzer to achieve optimal code coverage. Since platformdirs is relatively small in comparison to other Python projects being fuzzed I think we should be able to cover the code fairly easily.

OSS-Fuzz is a service run by Google for important open source projects. If you would like to integrate, the only thing I need is a list of email(s) that will get access to the data produced by OSS-Fuzz, such as bug reports, coverage reports and more stats. Notice the emails affiliated with the project will be public in the OSS-Fuzz repo, as they will be part of a configuration file.

convert from fork to normal repo

GitHub's search does not include forks by default.

https://github.com/search?q=platformdirs

This hurts the discoverability of this repository. I'm not aware of a way to remove the fork designation in place. This is the work around I've used before.

  1. clone the fork repo locally
  2. rename the fork repo
  3. create a new non-fork repo in GitHub with the original name
  4. push the local clone to the new repo
  5. transfer issues from the renamed fork repo to the new repo
  6. delete the fork repo

Support `XDG_RUNTIME_DIR`

Copied from ActiveState/appdirs#156:

The XDG specification includes $XDG_RUNTIME_DIR for user-specific runtime files that should be cleaned up on reboot. It would be nice if platformdirs supported this with a user_runtime_dir function that checks this environment variable and falls back to a default like tempfile.gettempdir.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.