Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

adds user_download_dir() function to get download directory #147

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ UNRELEASED
----------
- Add Python 3.7 support
- Remove support for end-of-life Pythons 2.6, 3.2, and 3.3
- Add ``user_download_dir()`` function to get user configured download directory.

appdirs 1.4.4
-------------
Expand Down
71 changes: 71 additions & 0 deletions appdirs.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

import sys
import os
import re

PY3 = sys.version_info[0] == 3

Expand All @@ -40,6 +41,32 @@
system = sys.platform


def user_download_dir():
r"""Return full path to the user-specific download dir for this application.

Typical user data directories are:
Mac OS X: ~/Downloads
Unix: ~/Downloads # or in $XDG_DOWNLOAD_DIR, if defined
Win 7: C:\Users\<username>\Downloads

For Unix, we follow the XDG spec and support $XDG_DOWNLOAD_DIR.
That means, by default "~/Downloads".
"""
if system == "win32":
return os.path.normpath(_get_win_download_folder_with_ctypes())
elif system == 'darwin':
return os.path.expanduser('~/Downloads')
else:
try:
config_dirs = os.path.join(user_config_dir(), 'user-dirs.dirs')
with open(config_dirs) as dirs_file:
path_match = re.search(r'XDG_DOWNLOAD_DIR=(.+)', dirs_file.read())
cleaned_path = path_match.group(1).replace('"', '').replace('$HOME', '~')
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I follow correctly this will be more generic if you use os.path.expandvars.

return os.path.expanduser(cleaned_path)
except Exception:
pass
return os.getenv('XDG_DOWNLOAD_DIR', os.path.expanduser("~/Downloads"))


def user_data_dir(appname=None, appauthor=None, version=None, roaming=False):
r"""Return full path to the user-specific data dir for this application.
Expand Down Expand Up @@ -421,6 +448,10 @@ def __init__(self, appname=None, appauthor=None, version=None,
self.roaming = roaming
self.multipath = multipath

@property
def user_download_dir(self):
return user_download_dir()

@property
def user_data_dir(self):
return user_data_dir(self.appname, self.appauthor,
Expand Down Expand Up @@ -536,6 +567,43 @@ def _get_win_folder_with_ctypes(csidl_name):

return buf.value


def _get_win_download_folder_with_ctypes():
import ctypes
from ctypes import windll, wintypes
from uuid import UUID

class GUID(ctypes.Structure):
_fields_ = [
("data1", wintypes.DWORD),
("data2", wintypes.WORD),
("data3", wintypes.WORD),
("data4", wintypes.BYTE * 8)
]

def __init__(self, uuidstr):
ctypes.Structure.__init__(self)
uuid = UUID(uuidstr)
self.data1, self.data2, self.data3, \
self.data4[0], self.data4[1], rest = uuid.fields
for i in range(2, 8):
self.data4[i] = rest >> (8-i-1)*8 & 0xff

SHGetKnownFolderPath = windll.shell32.SHGetKnownFolderPath
SHGetKnownFolderPath.argtypes = [
ctypes.POINTER(GUID), wintypes.DWORD, wintypes.HANDLE, ctypes.POINTER(ctypes.c_wchar_p)
]

FOLDERID_Downloads = '{374DE290-123F-4565-9164-39C4925E467B}'
guid = GUID(FOLDERID_Downloads)
pathptr = ctypes.c_wchar_p()

if SHGetKnownFolderPath(ctypes.byref(guid), 0, 0, ctypes.byref(pathptr)):
raise Exception('Failed to get download directory.')

return pathptr.value


def _get_win_folder_with_jna(csidl_name):
import array
from com.sun import jna
Expand Down Expand Up @@ -613,3 +681,6 @@ def _get_win_folder_with_jna(csidl_name):
dirs = AppDirs(appname, appauthor=False)
for prop in props:
print("%s: %s" % (prop, getattr(dirs, prop)))

print("\n-- download dir")
print(user_download_dir())