Path: blob/master/venv/Lib/site-packages/pip/_vendor/appdirs.py
811 views
#!/usr/bin/env python1# -*- coding: utf-8 -*-2# Copyright (c) 2005-2010 ActiveState Software Inc.3# Copyright (c) 2013 Eddy Petrișor45"""Utilities for determining application-specific dirs.67See <http://github.com/ActiveState/appdirs> for details and usage.8"""9# Dev Notes:10# - MSDN on where to store app data files:11# http://support.microsoft.com/default.aspx?scid=kb;en-us;310294#XSLTH319412112312012112012012# - Mac OS X: http://developer.apple.com/documentation/MacOSX/Conceptual/BPFileSystem/index.html13# - XDG spec for Un*x: http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html1415__version_info__ = (1, 4, 3)16__version__ = '.'.join(map(str, __version_info__))171819import sys20import os2122PY3 = sys.version_info[0] == 32324if PY3:25unicode = str2627if sys.platform.startswith('java'):28import platform29os_name = platform.java_ver()[3][0]30if os_name.startswith('Windows'): # "Windows XP", "Windows 7", etc.31system = 'win32'32elif os_name.startswith('Mac'): # "Mac OS X", etc.33system = 'darwin'34else: # "Linux", "SunOS", "FreeBSD", etc.35# Setting this to "linux2" is not ideal, but only Windows or Mac36# are actually checked for and the rest of the module expects37# *sys.platform* style strings.38system = 'linux2'39elif sys.platform == 'cli' and os.name == 'nt':40# Detect Windows in IronPython to match pip._internal.utils.compat.WINDOWS41# Discussion: <https://github.com/pypa/pip/pull/7501>42system = 'win32'43else:44system = sys.platform45464748def user_data_dir(appname=None, appauthor=None, version=None, roaming=False):49r"""Return full path to the user-specific data dir for this application.5051"appname" is the name of application.52If None, just the system directory is returned.53"appauthor" (only used on Windows) is the name of the54appauthor or distributing body for this application. Typically55it is the owning company name. This falls back to appname. You may56pass False to disable it.57"version" is an optional version path element to append to the58path. You might want to use this if you want multiple versions59of your app to be able to run independently. If used, this60would typically be "<major>.<minor>".61Only applied when appname is present.62"roaming" (boolean, default False) can be set True to use the Windows63roaming appdata directory. That means that for users on a Windows64network setup for roaming profiles, this user data will be65sync'd on login. See66<http://technet.microsoft.com/en-us/library/cc766489(WS.10).aspx>67for a discussion of issues.6869Typical user data directories are:70Mac OS X: ~/Library/Application Support/<AppName> # or ~/.config/<AppName>, if the other does not exist71Unix: ~/.local/share/<AppName> # or in $XDG_DATA_HOME, if defined72Win XP (not roaming): C:\Documents and Settings\<username>\Application Data\<AppAuthor>\<AppName>73Win XP (roaming): C:\Documents and Settings\<username>\Local Settings\Application Data\<AppAuthor>\<AppName>74Win 7 (not roaming): C:\Users\<username>\AppData\Local\<AppAuthor>\<AppName>75Win 7 (roaming): C:\Users\<username>\AppData\Roaming\<AppAuthor>\<AppName>7677For Unix, we follow the XDG spec and support $XDG_DATA_HOME.78That means, by default "~/.local/share/<AppName>".79"""80if system == "win32":81if appauthor is None:82appauthor = appname83const = roaming and "CSIDL_APPDATA" or "CSIDL_LOCAL_APPDATA"84path = os.path.normpath(_get_win_folder(const))85if appname:86if appauthor is not False:87path = os.path.join(path, appauthor, appname)88else:89path = os.path.join(path, appname)90elif system == 'darwin':91path = os.path.expanduser('~/Library/Application Support/')92if appname:93path = os.path.join(path, appname)94else:95path = os.getenv('XDG_DATA_HOME', os.path.expanduser("~/.local/share"))96if appname:97path = os.path.join(path, appname)98if appname and version:99path = os.path.join(path, version)100return path101102103def site_data_dir(appname=None, appauthor=None, version=None, multipath=False):104r"""Return full path to the user-shared data dir for this application.105106"appname" is the name of application.107If None, just the system directory is returned.108"appauthor" (only used on Windows) is the name of the109appauthor or distributing body for this application. Typically110it is the owning company name. This falls back to appname. You may111pass False to disable it.112"version" is an optional version path element to append to the113path. You might want to use this if you want multiple versions114of your app to be able to run independently. If used, this115would typically be "<major>.<minor>".116Only applied when appname is present.117"multipath" is an optional parameter only applicable to *nix118which indicates that the entire list of data dirs should be119returned. By default, the first item from XDG_DATA_DIRS is120returned, or '/usr/local/share/<AppName>',121if XDG_DATA_DIRS is not set122123Typical site data directories are:124Mac OS X: /Library/Application Support/<AppName>125Unix: /usr/local/share/<AppName> or /usr/share/<AppName>126Win XP: C:\Documents and Settings\All Users\Application Data\<AppAuthor>\<AppName>127Vista: (Fail! "C:\ProgramData" is a hidden *system* directory on Vista.)128Win 7: C:\ProgramData\<AppAuthor>\<AppName> # Hidden, but writeable on Win 7.129130For Unix, this is using the $XDG_DATA_DIRS[0] default.131132WARNING: Do not use this on Windows. See the Vista-Fail note above for why.133"""134if system == "win32":135if appauthor is None:136appauthor = appname137path = os.path.normpath(_get_win_folder("CSIDL_COMMON_APPDATA"))138if appname:139if appauthor is not False:140path = os.path.join(path, appauthor, appname)141else:142path = os.path.join(path, appname)143elif system == 'darwin':144path = os.path.expanduser('/Library/Application Support')145if appname:146path = os.path.join(path, appname)147else:148# XDG default for $XDG_DATA_DIRS149# only first, if multipath is False150path = os.getenv('XDG_DATA_DIRS',151os.pathsep.join(['/usr/local/share', '/usr/share']))152pathlist = [os.path.expanduser(x.rstrip(os.sep)) for x in path.split(os.pathsep)]153if appname:154if version:155appname = os.path.join(appname, version)156pathlist = [os.path.join(x, appname) for x in pathlist]157158if multipath:159path = os.pathsep.join(pathlist)160else:161path = pathlist[0]162return path163164if appname and version:165path = os.path.join(path, version)166return path167168169def user_config_dir(appname=None, appauthor=None, version=None, roaming=False):170r"""Return full path to the user-specific config dir for this application.171172"appname" is the name of application.173If None, just the system directory is returned.174"appauthor" (only used on Windows) is the name of the175appauthor or distributing body for this application. Typically176it is the owning company name. This falls back to appname. You may177pass False to disable it.178"version" is an optional version path element to append to the179path. You might want to use this if you want multiple versions180of your app to be able to run independently. If used, this181would typically be "<major>.<minor>".182Only applied when appname is present.183"roaming" (boolean, default False) can be set True to use the Windows184roaming appdata directory. That means that for users on a Windows185network setup for roaming profiles, this user data will be186sync'd on login. See187<http://technet.microsoft.com/en-us/library/cc766489(WS.10).aspx>188for a discussion of issues.189190Typical user config directories are:191Mac OS X: same as user_data_dir192Unix: ~/.config/<AppName> # or in $XDG_CONFIG_HOME, if defined193Win *: same as user_data_dir194195For Unix, we follow the XDG spec and support $XDG_CONFIG_HOME.196That means, by default "~/.config/<AppName>".197"""198if system in ["win32", "darwin"]:199path = user_data_dir(appname, appauthor, None, roaming)200else:201path = os.getenv('XDG_CONFIG_HOME', os.path.expanduser("~/.config"))202if appname:203path = os.path.join(path, appname)204if appname and version:205path = os.path.join(path, version)206return path207208209# for the discussion regarding site_config_dir locations210# see <https://github.com/pypa/pip/issues/1733>211def site_config_dir(appname=None, appauthor=None, version=None, multipath=False):212r"""Return full path to the user-shared data dir for this application.213214"appname" is the name of application.215If None, just the system directory is returned.216"appauthor" (only used on Windows) is the name of the217appauthor or distributing body for this application. Typically218it is the owning company name. This falls back to appname. You may219pass False to disable it.220"version" is an optional version path element to append to the221path. You might want to use this if you want multiple versions222of your app to be able to run independently. If used, this223would typically be "<major>.<minor>".224Only applied when appname is present.225"multipath" is an optional parameter only applicable to *nix226which indicates that the entire list of config dirs should be227returned. By default, the first item from XDG_CONFIG_DIRS is228returned, or '/etc/xdg/<AppName>', if XDG_CONFIG_DIRS is not set229230Typical site config directories are:231Mac OS X: same as site_data_dir232Unix: /etc/xdg/<AppName> or $XDG_CONFIG_DIRS[i]/<AppName> for each value in233$XDG_CONFIG_DIRS234Win *: same as site_data_dir235Vista: (Fail! "C:\ProgramData" is a hidden *system* directory on Vista.)236237For Unix, this is using the $XDG_CONFIG_DIRS[0] default, if multipath=False238239WARNING: Do not use this on Windows. See the Vista-Fail note above for why.240"""241if system in ["win32", "darwin"]:242path = site_data_dir(appname, appauthor)243if appname and version:244path = os.path.join(path, version)245else:246# XDG default for $XDG_CONFIG_DIRS (missing or empty)247# see <https://github.com/pypa/pip/pull/7501#discussion_r360624829>248# only first, if multipath is False249path = os.getenv('XDG_CONFIG_DIRS') or '/etc/xdg'250pathlist = [os.path.expanduser(x.rstrip(os.sep)) for x in path.split(os.pathsep) if x]251if appname:252if version:253appname = os.path.join(appname, version)254pathlist = [os.path.join(x, appname) for x in pathlist]255256if multipath:257path = os.pathsep.join(pathlist)258else:259path = pathlist[0]260return path261262263def user_cache_dir(appname=None, appauthor=None, version=None, opinion=True):264r"""Return full path to the user-specific cache dir for this application.265266"appname" is the name of application.267If None, just the system directory is returned.268"appauthor" (only used on Windows) is the name of the269appauthor or distributing body for this application. Typically270it is the owning company name. This falls back to appname. You may271pass False to disable it.272"version" is an optional version path element to append to the273path. You might want to use this if you want multiple versions274of your app to be able to run independently. If used, this275would typically be "<major>.<minor>".276Only applied when appname is present.277"opinion" (boolean) can be False to disable the appending of278"Cache" to the base app data dir for Windows. See279discussion below.280281Typical user cache directories are:282Mac OS X: ~/Library/Caches/<AppName>283Unix: ~/.cache/<AppName> (XDG default)284Win XP: C:\Documents and Settings\<username>\Local Settings\Application Data\<AppAuthor>\<AppName>\Cache285Vista: C:\Users\<username>\AppData\Local\<AppAuthor>\<AppName>\Cache286287On Windows the only suggestion in the MSDN docs is that local settings go in288the `CSIDL_LOCAL_APPDATA` directory. This is identical to the non-roaming289app data dir (the default returned by `user_data_dir` above). Apps typically290put cache data somewhere *under* the given dir here. Some examples:291...\Mozilla\Firefox\Profiles\<ProfileName>\Cache292...\Acme\SuperApp\Cache\1.0293OPINION: This function appends "Cache" to the `CSIDL_LOCAL_APPDATA` value.294This can be disabled with the `opinion=False` option.295"""296if system == "win32":297if appauthor is None:298appauthor = appname299path = os.path.normpath(_get_win_folder("CSIDL_LOCAL_APPDATA"))300# When using Python 2, return paths as bytes on Windows like we do on301# other operating systems. See helper function docs for more details.302if not PY3 and isinstance(path, unicode):303path = _win_path_to_bytes(path)304if appname:305if appauthor is not False:306path = os.path.join(path, appauthor, appname)307else:308path = os.path.join(path, appname)309if opinion:310path = os.path.join(path, "Cache")311elif system == 'darwin':312path = os.path.expanduser('~/Library/Caches')313if appname:314path = os.path.join(path, appname)315else:316path = os.getenv('XDG_CACHE_HOME', os.path.expanduser('~/.cache'))317if appname:318path = os.path.join(path, appname)319if appname and version:320path = os.path.join(path, version)321return path322323324def user_state_dir(appname=None, appauthor=None, version=None, roaming=False):325r"""Return full path to the user-specific state dir for this application.326327"appname" is the name of application.328If None, just the system directory is returned.329"appauthor" (only used on Windows) is the name of the330appauthor or distributing body for this application. Typically331it is the owning company name. This falls back to appname. You may332pass False to disable it.333"version" is an optional version path element to append to the334path. You might want to use this if you want multiple versions335of your app to be able to run independently. If used, this336would typically be "<major>.<minor>".337Only applied when appname is present.338"roaming" (boolean, default False) can be set True to use the Windows339roaming appdata directory. That means that for users on a Windows340network setup for roaming profiles, this user data will be341sync'd on login. See342<http://technet.microsoft.com/en-us/library/cc766489(WS.10).aspx>343for a discussion of issues.344345Typical user state directories are:346Mac OS X: same as user_data_dir347Unix: ~/.local/state/<AppName> # or in $XDG_STATE_HOME, if defined348Win *: same as user_data_dir349350For Unix, we follow this Debian proposal <https://wiki.debian.org/XDGBaseDirectorySpecification#state>351to extend the XDG spec and support $XDG_STATE_HOME.352353That means, by default "~/.local/state/<AppName>".354"""355if system in ["win32", "darwin"]:356path = user_data_dir(appname, appauthor, None, roaming)357else:358path = os.getenv('XDG_STATE_HOME', os.path.expanduser("~/.local/state"))359if appname:360path = os.path.join(path, appname)361if appname and version:362path = os.path.join(path, version)363return path364365366def user_log_dir(appname=None, appauthor=None, version=None, opinion=True):367r"""Return full path to the user-specific log dir for this application.368369"appname" is the name of application.370If None, just the system directory is returned.371"appauthor" (only used on Windows) is the name of the372appauthor or distributing body for this application. Typically373it is the owning company name. This falls back to appname. You may374pass False to disable it.375"version" is an optional version path element to append to the376path. You might want to use this if you want multiple versions377of your app to be able to run independently. If used, this378would typically be "<major>.<minor>".379Only applied when appname is present.380"opinion" (boolean) can be False to disable the appending of381"Logs" to the base app data dir for Windows, and "log" to the382base cache dir for Unix. See discussion below.383384Typical user log directories are:385Mac OS X: ~/Library/Logs/<AppName>386Unix: ~/.cache/<AppName>/log # or under $XDG_CACHE_HOME if defined387Win XP: C:\Documents and Settings\<username>\Local Settings\Application Data\<AppAuthor>\<AppName>\Logs388Vista: C:\Users\<username>\AppData\Local\<AppAuthor>\<AppName>\Logs389390On Windows the only suggestion in the MSDN docs is that local settings391go in the `CSIDL_LOCAL_APPDATA` directory. (Note: I'm interested in392examples of what some windows apps use for a logs dir.)393394OPINION: This function appends "Logs" to the `CSIDL_LOCAL_APPDATA`395value for Windows and appends "log" to the user cache dir for Unix.396This can be disabled with the `opinion=False` option.397"""398if system == "darwin":399path = os.path.join(400os.path.expanduser('~/Library/Logs'),401appname)402elif system == "win32":403path = user_data_dir(appname, appauthor, version)404version = False405if opinion:406path = os.path.join(path, "Logs")407else:408path = user_cache_dir(appname, appauthor, version)409version = False410if opinion:411path = os.path.join(path, "log")412if appname and version:413path = os.path.join(path, version)414return path415416417class AppDirs(object):418"""Convenience wrapper for getting application dirs."""419def __init__(self, appname=None, appauthor=None, version=None,420roaming=False, multipath=False):421self.appname = appname422self.appauthor = appauthor423self.version = version424self.roaming = roaming425self.multipath = multipath426427@property428def user_data_dir(self):429return user_data_dir(self.appname, self.appauthor,430version=self.version, roaming=self.roaming)431432@property433def site_data_dir(self):434return site_data_dir(self.appname, self.appauthor,435version=self.version, multipath=self.multipath)436437@property438def user_config_dir(self):439return user_config_dir(self.appname, self.appauthor,440version=self.version, roaming=self.roaming)441442@property443def site_config_dir(self):444return site_config_dir(self.appname, self.appauthor,445version=self.version, multipath=self.multipath)446447@property448def user_cache_dir(self):449return user_cache_dir(self.appname, self.appauthor,450version=self.version)451452@property453def user_state_dir(self):454return user_state_dir(self.appname, self.appauthor,455version=self.version)456457@property458def user_log_dir(self):459return user_log_dir(self.appname, self.appauthor,460version=self.version)461462463#---- internal support stuff464465def _get_win_folder_from_registry(csidl_name):466"""This is a fallback technique at best. I'm not sure if using the467registry for this guarantees us the correct answer for all CSIDL_*468names.469"""470if PY3:471import winreg as _winreg472else:473import _winreg474475shell_folder_name = {476"CSIDL_APPDATA": "AppData",477"CSIDL_COMMON_APPDATA": "Common AppData",478"CSIDL_LOCAL_APPDATA": "Local AppData",479}[csidl_name]480481key = _winreg.OpenKey(482_winreg.HKEY_CURRENT_USER,483r"Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders"484)485dir, type = _winreg.QueryValueEx(key, shell_folder_name)486return dir487488489def _get_win_folder_with_pywin32(csidl_name):490from win32com.shell import shellcon, shell491dir = shell.SHGetFolderPath(0, getattr(shellcon, csidl_name), 0, 0)492# Try to make this a unicode path because SHGetFolderPath does493# not return unicode strings when there is unicode data in the494# path.495try:496dir = unicode(dir)497498# Downgrade to short path name if have highbit chars. See499# <http://bugs.activestate.com/show_bug.cgi?id=85099>.500has_high_char = False501for c in dir:502if ord(c) > 255:503has_high_char = True504break505if has_high_char:506try:507import win32api508dir = win32api.GetShortPathName(dir)509except ImportError:510pass511except UnicodeError:512pass513return dir514515516def _get_win_folder_with_ctypes(csidl_name):517import ctypes518519csidl_const = {520"CSIDL_APPDATA": 26,521"CSIDL_COMMON_APPDATA": 35,522"CSIDL_LOCAL_APPDATA": 28,523}[csidl_name]524525buf = ctypes.create_unicode_buffer(1024)526ctypes.windll.shell32.SHGetFolderPathW(None, csidl_const, None, 0, buf)527528# Downgrade to short path name if have highbit chars. See529# <http://bugs.activestate.com/show_bug.cgi?id=85099>.530has_high_char = False531for c in buf:532if ord(c) > 255:533has_high_char = True534break535if has_high_char:536buf2 = ctypes.create_unicode_buffer(1024)537if ctypes.windll.kernel32.GetShortPathNameW(buf.value, buf2, 1024):538buf = buf2539540return buf.value541542def _get_win_folder_with_jna(csidl_name):543import array544from com.sun import jna545from com.sun.jna.platform import win32546547buf_size = win32.WinDef.MAX_PATH * 2548buf = array.zeros('c', buf_size)549shell = win32.Shell32.INSTANCE550shell.SHGetFolderPath(None, getattr(win32.ShlObj, csidl_name), None, win32.ShlObj.SHGFP_TYPE_CURRENT, buf)551dir = jna.Native.toString(buf.tostring()).rstrip("\0")552553# Downgrade to short path name if have highbit chars. See554# <http://bugs.activestate.com/show_bug.cgi?id=85099>.555has_high_char = False556for c in dir:557if ord(c) > 255:558has_high_char = True559break560if has_high_char:561buf = array.zeros('c', buf_size)562kernel = win32.Kernel32.INSTANCE563if kernel.GetShortPathName(dir, buf, buf_size):564dir = jna.Native.toString(buf.tostring()).rstrip("\0")565566return dir567568if system == "win32":569try:570from ctypes import windll571_get_win_folder = _get_win_folder_with_ctypes572except ImportError:573try:574import com.sun.jna575_get_win_folder = _get_win_folder_with_jna576except ImportError:577_get_win_folder = _get_win_folder_from_registry578579580def _win_path_to_bytes(path):581"""Encode Windows paths to bytes. Only used on Python 2.582583Motivation is to be consistent with other operating systems where paths584are also returned as bytes. This avoids problems mixing bytes and Unicode585elsewhere in the codebase. For more details and discussion see586<https://github.com/pypa/pip/issues/3463>.587588If encoding using ASCII and MBCS fails, return the original Unicode path.589"""590for encoding in ('ASCII', 'MBCS'):591try:592return path.encode(encoding)593except (UnicodeEncodeError, LookupError):594pass595return path596597598#---- self test code599600if __name__ == "__main__":601appname = "MyApp"602appauthor = "MyCompany"603604props = ("user_data_dir",605"user_config_dir",606"user_cache_dir",607"user_state_dir",608"user_log_dir",609"site_data_dir",610"site_config_dir")611612print("-- app dirs %s --" % __version__)613614print("-- app dirs (with optional 'version')")615dirs = AppDirs(appname, appauthor, version="1.0")616for prop in props:617print("%s: %s" % (prop, getattr(dirs, prop)))618619print("\n-- app dirs (without optional 'version')")620dirs = AppDirs(appname, appauthor)621for prop in props:622print("%s: %s" % (prop, getattr(dirs, prop)))623624print("\n-- app dirs (without optional 'appauthor')")625dirs = AppDirs(appname)626for prop in props:627print("%s: %s" % (prop, getattr(dirs, prop)))628629print("\n-- app dirs (with disabled 'appauthor')")630dirs = AppDirs(appname, appauthor=False)631for prop in props:632print("%s: %s" % (prop, getattr(dirs, prop)))633634635