activestate / appdirs Goto Github PK
View Code? Open in Web Editor NEWA small Python module for determining appropriate platform-specific dirs, e.g. a "user data dir".
Home Page: http://pypi.python.org/pypi/appdirs
License: MIT License
A small Python module for determining appropriate platform-specific dirs, e.g. a "user data dir".
Home Page: http://pypi.python.org/pypi/appdirs
License: MIT License
The convenience wrapper AppDirs requires an appname
parameter, whereas the underlying functions do not. The wrapper should default to None for appname.
hsoft noted on this reddit post http://www.reddit.com/r/Python/comments/cvay0/a_small_python_module_for_determining_appropriate/
hsoft
Looks nice. However, it won't work on python 3 for OS X because it uses the Carbon module :(
What is the development status of this project? The last commit was on Jul 23, 2015, but there seem to be some interest in this project (issues as well as PRs).
Maybe it's possible to find a new maintainer for this project you guys don't want to keep maintaining it.
Please release 1.3.0 to make it easier to use the new user_config_dir function.
In [2]: appdirs.user_data_dir("/foo")
Out[2]: '/foo'
Arguably an incorrect input, but some validation (either bailing out or raising an exception) would be nice.
$ ./test.py
appdirs/doctests/api ... ERROR
appdirs/doctests/internal ... ok
======================================================================
ERROR: appdirs/doctests/api
----------------------------------------------------------------------
Traceback (most recent call last):
File "./test_appdirs.py", line 18, in test_api
test = doctest.DocFileTest("api.doctests")
File "/usr/lib64/python2.7/doctest.py", line 2424, in DocFileTest
doc, path = _load_testfile(path, package, module_relative)
File "/usr/lib64/python2.7/doctest.py", line 219, in _load_testfile
with open(filename) as f:
IOError: [Errno 2] No such file or directory: './api.doctests'
----------------------------------------------------------------------
Ran 2 tests in 0.079s
FAILED (1 error)
It seems that the file should be added to MANIFEST.in
.
https://pypi.python.org/pypi/appdirs/ lists 1.4.0 as the most recent version. Please push the latest version to pypi.
What we do right now is as part of assigning system
we fall back to assigning linux2
if we do not recognize the system.
Most of our functions however, apply the same fallback strategy anew if they encounter none of the recognized strings, but now they dont check againsts sys.platform
but our own system
global.
To me it seems sensible to have only one point where a system (propably better named strategy
) is determined and have all functions just act accordingly.
If a function ends up with going though all supported system
string values without a hit, it should throw an error as it means that for whatever reason system
has been assigned a value that we do not support.
A line of code is propably worth more then words:
elif system == 'darwin':
path = os.path.expanduser('/Library/Application Support')
if appname:
path = os.path.join(path, appname)
else:
# XDG default for $XDG_DATA_DIRS
# only first, if multipath is False](url)
should be:
elif system == 'darwin':
path = os.path.expanduser('/Library/Application Support')
if appname:
path = os.path.join(path, appname)
elif system== 'linux2':
# XDG default for $XDG_DATA_DIRS
# only first, if multipath is False](url)
else:
raise ValueError("Unrecognized system string.")
Hey, this isn't really an issue exactly, but I was wondering if this project was still maintained? I see a handful of commits over the past year but the last release was 3 years ago.
It's OK if it's not :) I just need this functionality and I don't want to rely on an unmaintained library!
I'm getting this error on Python 3.5 on Mac:
>>> appdirs.user_log_dir()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/Users/deil/Library/Python/3.5/lib/python/site-packages/appdirs.py", line 349, in user_log_dir
appname)
File "/opt/local/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/posixpath.py", line 89, in join
genericpath._check_arg_types('join', a, *p)
File "/opt/local/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/genericpath.py", line 143, in _check_arg_types
(funcname, s.__class__.__name__)) from None
TypeError: join() argument must be str or bytes, not 'NoneType'
On Python 2.7 and 3.4 it looks like this:
>>> appdirs.user_log_dir()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/Users/deil/Library/Python/3.4/lib/python/site-packages/appdirs.py", line 349, in user_log_dir
appname)
File "/opt/local/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/posixpath.py", line 79, in join
if b.startswith(sep):
AttributeError: 'NoneType' object has no attribute 'startswith'
All the other functions work for me.
Should appdirs support installation/building without setuptools since setuptools now depends on appdirs? Maybe falling back to distutils?
try:
from setuptools import setup
except ImportError:
from distutils.core import setup
This circular dependency is making building in my environment that checks for this much harder and hackier.
I want to find config paths for my app:
On Linux I can do:
os.environ['XDG_CONFIG_DIRS'] = '/etc:/usr/local/etc'
site_config_dir("foobar", multipath=True)
/etc/foobar:/usr/local/etc/foobar
However, on Mac/darwin we can only every return "/Library/Application Support/" based path. This appears to be entirely compliant by Mac's BPFileSystem spec... but a bunch of applications *do install configs to /usr/local/etc/ (including any python app using setup.cfg->data_files->pip .
site_data_dir's value is actually '~/Library/Application Support'
on Mac, while the function comment says otherwise (/Library/Application Support
)
-- using `AppDirs`
user_data_dir: /Users/sridharr/Library/Application Support/SuperApp/1.0
site_data_dir: /Users/sridharr/Library/Application Support/SuperApp/1.0
We should encourage TDD and having Travis-CI support is The Right Thing™ (despite being locked into one-site API).
_winreg
got renamed to winreg
in python3. Instead of import _winreg
, this should be done:
if PY3:
import winreg as _winreg
else:
import _winreg
Hi,
I just recently discovered your nice appdirs module. Several years ago, I wrote a module with similar functionality, utilia.filesystem.stdpath:
Although, I think we have much overlap, I took a divergent approach to the Windows site data directory and want to share some of my research and code with you, in case you're interested. I noticed in the appdirs code comments, there is some dissatisfaction with the results of using CSIDL_COMMON_APPDATA to get the site data directory on Vista and newer. In my approach, I regarded the path indicated by %ProgramFiles% to be the true equivalent of /usr/local/share and /Library/Application Support. Also, as part of my initial research, I found some newer documentation on Windows standard paths, which indicated that KNOWNFOLDERID is the standard in use, instead of CSIDL, on Vista and beyond:
The second KNOWNFOLDERID URL above contains a trove of information on folder GUIDs as well as environment variables and paths relative to those variables. (If you go the "Remarks" section near the bottom of the page, you will see a thorough discussion about %ProgramFiles% on 32-bit and 64-bit systems.) My implementation, based on that discussion is here:
I would be happy to discuss this more, if you're interested.
P.S. My research links: https://utilia.readthedocs.org/en/latest/modules/filesystem/stdpath.html#references
As suggested in the discussion at
eddyp@9198f6c#commitcomment-2835016
sys.platform.startswith("win")
tests can be safely replaced with sys.platform == "win32"
>>> from appdirs import *
>>> appname = "SuperApp"
>>> appauthor = "Acme"
>>> user_data_dir(appname, appauthor)
'/Users/username/Library/Application Support/SuperApp'
Using appauthor
would make things more organized:
'/Users/username/Library/Application Support/Acme/SuperApp'
Blizzard uses this approach:
/Users/username/Library/Application Support/Blizzard
/Users/username/Library/Application Support/Blizzard/Diablo III
/Users/username/Library/Application Support/Blizzard/Heroes of the Storm
/Users/username/Library/Application Support/Blizzard/Heroes of the Storm/Accounts
/Users/username/Library/Application Support/Blizzard/Heroes of the Storm/Accounts/999999999
/Users/username/Library/Application Support/Blizzard/Heroes of the Storm/Accounts/999999999/1-Hero-1-3384698
/Users/username/Library/Application Support/Blizzard/Heroes of the Storm/Accounts/999999999/1-Hero-1-3384698/Banks
/Users/username/Library/Application Support/Blizzard/Heroes of the Storm/Accounts/999999999/1-Hero-1-3384698/Replays
/Users/username/Library/Application Support/Blizzard/Heroes of the Storm/Accounts/999999999/1-Hero-1-3384698/Replays/Multiplayer
/Users/username/Library/Application Support/Blizzard/Heroes of the Storm/Accounts/999999999/1-Hero-1-3384698/Saves
/Users/username/Library/Application Support/Blizzard/Heroes of the Storm/Accounts/999999999/1-Hero-1-3384698/Saves/Rejoin
/Users/username/Library/Application Support/Blizzard/Heroes of the Storm/GameLogs
/Users/username/Library/Application Support/Blizzard/Heroes of the Storm/ImageUploads
/Users/username/Library/Application Support/Blizzard/Heroes of the Storm/Interfaces
/Users/username/Library/Application Support/Blizzard/System Survey
/Users/username/Library/Application Support/Blizzard/System Survey/Errors
/Users/username/Library/Application Support/Blizzard/System Survey/ProductData
/Users/username/Library/Application Support/Blizzard/System Survey/ProductData/D3
/Users/username/Library/Application Support/Blizzard/System Survey/ProductData/D3/Game
/Users/username/Library/Application Support/Blizzard/System Survey/ProductData/Hero
/Users/username/Library/Application Support/Blizzard/System Survey/ProductData/Hero/Game
If I want to get the path to e.g. the user data directory, I have to pass a phoney app name (or an empty string) to the user_data_dir
function, then clip the string manually. I think it should be possible to just call the function without arguments to get the data directory path. The same should work for the cache dir and log dir functions.
Examples:
>>> user_data_dir() '/Users/tomas/Library/Application Support' >>> user_cache_dir() '/Users/tomas/Library/Caches'
This is an extremely tiny change that would make the library much more user friendly to people in my situation. I would fix it myself, but in this case I think it would be orders of magnitude less work for you to fix this issue than for me to start forking the project and requesting a merge.
Anyway, thanks for making a great library that has saved me a lot of work! :-)
It seems a common use case that one wants to use the paths returned by appdirs
. This usually requires the client to check its existence and maybe creating them.
As this seems to be a general enough situation, do you think it would be feasible to pass appdirs
an otional ensure
or create
argument that will cause appdirs
to implement this kind of logic in one central place?
It would be quite useful to determine directories when working with a windows node from a linux node (e.g. in case of deployment done via ansible).
test_api.py
only tests the type of the return values. we need tests to cover the behaviour of appdirs functions (i.e., return values) on each platform.
hi!
It will be very useful (at least for me), if there would be user_temp_dir
or system_temp_dir
.
Are there any plans to add one?
Thanks!
test_dirs and test_helpers fail on Windows 7 because user_data_dir returns a unicode string.
BTW, @mcepl, the default error reporting verbosity is insufficient. I am not familiar with unittest and used to py.test's default verbose error reporting, how does one increase the verbosity of error reporting to obtain the details of the returned values which were tested?
I had to manually call the function myself in a console to get its type. Py.test does that for you automatically.
(Probably my question isn't clear, I'll provide an this evening an example output to get the gist of it.)
I may be mistaken but isn't there a site cache directory on most systems too? Specifically interested in FHS compliant systems, isn't it /var/cache/ ?
Instead of just extracting the envvar it may be a more robust aproach worth investigating to utilise pyxdg to handle XDG
environments .
Then again, it seems like a relatively heavy dependency. My point was to just put it out here in case you were not aware of it.
appdirs
already has a solid docstring base. Would you be interested in using google-style docstrings to further improve information about arguments, return values and example code? sphinxs extensions like napoleon can easily turn those into proper documentation leveraging the full force of autodocs without loosing out on readability.
If there is interest in this regard, I would be willing to provide a PR.
File "C:\Python31\lib\site-packages\pypm\deps\appdirs.py", line 63, in user_data_dir
path = os.path.join(_get_win_folder(const), appauthor, appname)
File "C:\Python31\lib\site-packages\pypm\deps\appdirs.py", line 267, in _get_win_folder_with_pywin32
dir = unicode(dir)
NameError: global name 'unicode' is not defined
XDG Base Directory Specification says:
All paths set in these environment variables must be absolute. If an implementation encounters a relative path in any of these variables it should consider the path invalid and ignore it.
But appdirs doesn't currently ignore relatives paths in XDG_*
variables.
These lines may need some help (
Lines 23 to 24 in 57f2bc4
Running into issues with appdirs 1.4.1, which appears to have been released today. Am getting the issue below. More details can be found in this log. Issues exist for other Python versions as well.
FileNotFoundError: [Errno 2] No such file or directory: '/home/travis/virtualenv/python3.6.0/lib/python3.6/site-packages/appdirs-1.4.1.dist-info/METADATA'
cc @alimanfoo
Great library, thanks.
I'm using it in one of my projects and recently wanted to migrate it to type hinting with mypy. Unfortunately, I failed, because appdirs doesn't provide type hints.
Could you either add type hints to appdirs.py, or alternatively, add a appdirs.pyi type stub file?
Thank you :)
Need this from applib/base.py
@property
def log_file_path(self):
if sys.platform.startswith('win'):
return join(self.user_cache_dir, self.app.name + '.log')
elif sys.platform.startswith('darwin'):
return join(expanduser('~/Library/Logs'), self.app.name + '.log')
else:
return join(expanduser('~'), '.'+self.app.name.lower() + '.log')
This is where PyPM's log file is stored when latest appdirs (git master) is used:
~/.cache/pypm/1.1/log/1.1/pypm.log
Double version in path? PyPM uses join(user_log_dir, "pypm.log")
(to the effect). Running stock appdirs on Ubuntu:
$ python lib/appdirs.py
[...]
user_log_dir: /home/sridharr/.cache/myapp/1.0/log/1.0
No, that's not good.
Application preferences belong in ~/Library/Preferences or /Library/Preferences to separate them from general application data. The current implementation returns the same location as user_data_dir and site_data_dir, which is ~/Library/Application Support and /Library/Application Support.
eg c:\Users\user\Documents in Windows 7+, /Users/user/Documents in OSX, and ~/Documents in Linux, where applicable (XDG spec doesn't cover this). The "winshell" module does this but only for Windows: https://github.com/tjguk/winshell
The code here doesn't check for XDG_CONFIG_HOME if running macOS.
So I know that XDG is technically not a thing on macOS. But it is not uncommon for people to set up a similar system, using application-specific environment variables and at some level the XDG variables to accomplish the same thing.
For example, Git saves to the XDG_CONFIG_HOME if it is set on my Macbook.
It would be rather helpful for us if you did the same. It makes it easier for me to switch from macOS to Linux, which I want to be able to do easily.
Because logs cannot be regenerated easily (or at all) after removal, they should not be placed in the XDG cache directories. They should be placed instead in one of the XDG data directories.
The *_dir()
methods do not work on Windows or Mac in Jython. In Jython sys.platform
is 'javaX.Y.Z'
which incorrectly causes the paths to treated as Unix/Posix paths. Would you be open to a pull request to fix this?
bash -c "PYTHONPATH=`pwd` /Library/Frameworks/Python.framework/Versions/2.7/bin/mk -v cut_a_release"
* * *
Are you sure you want cut a 1.3.0 release?
This will involved commits and a release to pypi. [y/N] y
* * *
mk: [cut_a_release] cutting a 1.3.0 release
mk: error: [cut_a_release] _changes_parser: change me to .rst (Makefile.py:70 in make)
Traceback (most recent call last):
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/mklib/runner.py", line 313, in main
retval = mk(argv, doc)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/mklib/runner.py", line 281, in mk
master.make(*tasks)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/mklib/taskmaster.py", line 226, in make
self._do_make(targets, run_data, first_pass=True)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/mklib/taskmaster.py", line 346, in _do_make
err_str = self._execute_task(task)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/mklib/taskmaster.py", line 492, in _execute_task
task.make()
File "Makefile.py", line 70, in make
raise NotImplementedError('_changes_parser: change me to .rst')
NotImplementedError: _changes_parser: change me to .rst
The XDG standard says user-specific data files should be written in $XDG_DATA_HOME which defaults to $HOME/.local/share.
Appdirs explicitly breaks XDG_DATA_HOME specification and returns a path based on $XDG_CONFIG_HOME, ~/.config/appname instead of ~/.local/share/appname for user_data_dir.
This is not at all "subject to some interpretation", this is as clear as day in the XDG spec:
http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
Quote:
There is a single base directory relative to which user-specific data files should be written. This directory is defined by the environment variable $XDG_DATA_HOME
and later:
$XDG_DATA_HOME defines the base directory relative to which user specific data files should be stored. If $XDG_DATA_HOME is either not set or empty, a default equal to $HOME/.local/share should be used.
No ifs or buts. It doesn't matter at all if some apps decide not to respect the standard, a library should do the right thing, not break standards for everybody 'just because'.
To fix this, commit 362f390 should be reverted.
Because appdirs is used by setuptools now, when the setup script is run, a different version of appdirs may be in the path ahead of the source distribution, causing the version to be determined indirectly.
It would be great to have a debian package for appdirs so that other packages could depend on it. Would you be open to submitting appdirs as a debian package?
wycliff:appdirs-1.2.0 $ python setup.py nosetests
running nosetests
running egg_info
writing lib/appdirs.egg-info/PKG-INFO
writing top-level names to lib/appdirs.egg-info/top_level.txt
writing dependency_links to lib/appdirs.egg-info/dependency_links.txt
reading manifest file 'lib/appdirs.egg-info/SOURCES.txt'
reading manifest template 'MANIFEST.in'
writing manifest file 'lib/appdirs.egg-info/SOURCES.txt'
running build_ext
E.EEEEEEE
======================================================================
ERROR: test_api (test_appdirs.DocTestsTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/matej/build/BUILD/appdirs-1.2.0/test/test_appdirs.py", line 18, in test_api
test = doctest.DocFileTest("api.doctests")
File "/usr/lib64/python2.7/doctest.py", line 2424, in DocFileTest
doc, path = _load_testfile(path, package, module_relative)
File "/usr/lib64/python2.7/doctest.py", line 219, in _load_testfile
with open(filename) as f:
IOError: [Errno 2] No such file or directory: '/home/matej/build/BUILD/appdirs-1.2.0/test/api.doctests'
======================================================================
ERROR: Failure: TypeError (testmod_paths_from_testdir() takes exactly 1 argument (0 given))
----------------------------------------------------------------------
Traceback (most recent call last):
File "/usr/lib/python2.7/site-packages/nose/loader.py", line 231, in generate
for test in g():
TypeError: testmod_paths_from_testdir() takes exactly 1 argument (0 given)
======================================================================
ERROR: Failure: TypeError (testmods_from_testdir() takes exactly 1 argument (0 given))
----------------------------------------------------------------------
Traceback (most recent call last):
File "/usr/lib/python2.7/site-packages/nose/loader.py", line 231, in generate
for test in g():
TypeError: testmods_from_testdir() takes exactly 1 argument (0 given)
======================================================================
ERROR: Failure: TypeError (testcases_from_testmod() takes exactly 1 argument (0 given))
----------------------------------------------------------------------
Traceback (most recent call last):
File "/usr/lib/python2.7/site-packages/nose/loader.py", line 231, in generate
for test in g():
TypeError: testcases_from_testmod() takes exactly 1 argument (0 given)
======================================================================
ERROR: Failure: TypeError (tests_from_manifest() takes exactly 1 argument (0 given))
----------------------------------------------------------------------
Traceback (most recent call last):
File "/usr/lib/python2.7/site-packages/nose/loader.py", line 231, in generate
for test in g():
TypeError: tests_from_manifest() takes exactly 1 argument (0 given)
======================================================================
ERROR: Failure: TypeError (tests_from_manifest_and_tags() takes exactly 2 arguments (0 given))
----------------------------------------------------------------------
Traceback (most recent call last):
File "/usr/lib/python2.7/site-packages/nose/loader.py", line 231, in generate
for test in g():
TypeError: tests_from_manifest_and_tags() takes exactly 2 arguments (0 given)
======================================================================
ERROR: testlib.test
----------------------------------------------------------------------
Traceback (most recent call last):
File "/usr/lib/python2.7/site-packages/nose/case.py", line 197, in runTest
self.test(*self.arg)
TypeError: test() takes at least 1 argument (0 given)
======================================================================
ERROR: testlib.list_tests
----------------------------------------------------------------------
Traceback (most recent call last):
File "/usr/lib/python2.7/site-packages/nose/case.py", line 197, in runTest
self.test(*self.arg)
TypeError: list_tests() takes exactly 2 arguments (0 given)
----------------------------------------------------------------------
Ran 9 tests in 0.076s
FAILED (errors=8)
wycliff:appdirs-1.2.0 $
Hello there!
We're investigating using appdirs inside of pip over in pypa/pip#1733 and a few issues came up. We were wondering if y'all would be interested in any of these changes at all.
/etc/xdg/<foo>
directory to /etc/<foo>
. Again while it is true that the XDG spec does mandate defaulting to /etc/xdg
looking at a few Linux installs it appears that generally the only things that actually do default to /etc/xdg
instead of /etc
are actual desktop apps and not CLI programs like pip.I don't have a problem submitting these pull requests but I wanted to see if these were things that y'all were willing to have!
We need user_config_dir
. Because, on Unix user_data_dir points to ~/.local/share/<appname>
but we have nothing to use ~/.config/<appname>
.
On Mac? user_config_dir == user_data_dir? ~/Library/Application Support/<appname>
On Windows? user_config_dir == user_data_dir?
When I inspect my Linux VM, all apps tend to use ~/.config for storing stuff instead of ~/.local/share.
Also, ~/.config/pypm.conf
(or ~/.config/pypm/client.conf
) would be the most appropriate place to put the pypm configuration file.
Thoughts?
running the following:
appdirs.user_config_dir('MyApp')
returns:
C:\Documents and Settings\username\Local Settings\Application Data\MyApp\MyApp
expected result:
C:\Documents and Settings\username\Local Settings\Application Data\MyApp
http://www.reddit.com/r/Python/comments/cvay0/a_small_python_module_for_determining_appropriate/c0vk29s
"Configs go in ~/.config and data can go in ~/.local/share/data"
http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
Not an issue, sorry. I ported this to java since it's a library I can't really live without and Java is something you sometimes need: https://github.com/Rendaw/appdirsj
I kept the license of course, but please tell me if I've botched any attributions or other details (if you care).
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.