From 4fe72f12eea2e4e22075735fd647766af1a8535a Mon Sep 17 00:00:00 2001 From: Lex Berezhny Date: Tue, 19 May 2020 16:21:28 -0400 Subject: [PATCH 1/5] added user_download_dir() --- appdirs.py | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/appdirs.py b/appdirs.py index bd5357e..e0bb39a 100644 --- a/appdirs.py +++ b/appdirs.py @@ -40,6 +40,27 @@ 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 XP (not roaming): C:\Documents and Settings\\Application Data\\ + Win XP (roaming): C:\Documents and Settings\\Local Settings\Application Data\\ + Win 7 (not roaming): C:\Users\\AppData\Local\\ + Win 7 (roaming): C:\Users\\AppData\Roaming\\ + + 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: + 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. @@ -536,6 +557,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 From 6060d804b5502cd07cfe75a27e900365e9bac2c8 Mon Sep 17 00:00:00 2001 From: Lex Berezhny Date: Tue, 19 May 2020 16:48:59 -0400 Subject: [PATCH 2/5] check user-dirs.dirs for download directory on linux --- appdirs.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/appdirs.py b/appdirs.py index e0bb39a..e54074b 100644 --- a/appdirs.py +++ b/appdirs.py @@ -18,6 +18,7 @@ import sys import os +import re PY3 = sys.version_info[0] == 3 @@ -59,6 +60,14 @@ def user_download_dir(): 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', '~') + return os.path.expanduser(cleaned_path) + except Exception: + pass return os.getenv('XDG_DOWNLOAD_DIR', os.path.expanduser("~/Downloads")) @@ -671,3 +680,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()) From 96d8d24a86857fa7483286ca70add3d01f6484c2 Mon Sep 17 00:00:00 2001 From: Lex Berezhny Date: Tue, 19 May 2020 16:53:10 -0400 Subject: [PATCH 3/5] updated changelog to add user_download_dir() --- CHANGES.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES.rst b/CHANGES.rst index a9380b7..9d41fd5 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -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 ------------- From f265412b6196d648562a94721615463a89d0d57c Mon Sep 17 00:00:00 2001 From: Lex Berezhny Date: Tue, 19 May 2020 16:57:30 -0400 Subject: [PATCH 4/5] updated doc for user_download_dir() --- appdirs.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/appdirs.py b/appdirs.py index e54074b..5d04d4a 100644 --- a/appdirs.py +++ b/appdirs.py @@ -45,12 +45,9 @@ 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 XP (not roaming): C:\Documents and Settings\\Application Data\\ - Win XP (roaming): C:\Documents and Settings\\Local Settings\Application Data\\ - Win 7 (not roaming): C:\Users\\AppData\Local\\ - Win 7 (roaming): C:\Users\\AppData\Roaming\\ + Mac OS X: ~/Downloads + Unix: ~/Downloads # or in $XDG_DOWNLOAD_DIR, if defined + Win 7: C:\Users\\Downloads For Unix, we follow the XDG spec and support $XDG_DOWNLOAD_DIR. That means, by default "~/Downloads". From e0176a71a71b16dc5f16dd32268323e4263dcf1d Mon Sep 17 00:00:00 2001 From: Lex Berezhny Date: Tue, 19 May 2020 17:03:22 -0400 Subject: [PATCH 5/5] added user_download_dir property on AppDirs class for convenience --- appdirs.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/appdirs.py b/appdirs.py index 5d04d4a..7942935 100644 --- a/appdirs.py +++ b/appdirs.py @@ -448,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,