mirror of
https://github.com/pypa/pip
synced 2023-12-13 21:30:23 +01:00
Merge pull request #7501 from uranusjr/appdirs-patch
This commit is contained in:
commit
0292938f89
0
news/050cda98-2240-11ea-9951-00e04c3600d8.trivial
Normal file
0
news/050cda98-2240-11ea-9951-00e04c3600d8.trivial
Normal file
|
@ -1,19 +1,17 @@
|
||||||
"""
|
"""
|
||||||
This code was taken from https://github.com/ActiveState/appdirs and modified
|
This code wraps the vendored appdirs module to so the return values are
|
||||||
to suit our purposes.
|
compatible for the current pip code base.
|
||||||
"""
|
|
||||||
|
|
||||||
# The following comment should be removed at some point in the future.
|
The intention is to rewrite current usages gradually, keeping the tests pass,
|
||||||
# mypy: disallow-untyped-defs=False
|
and eventually drop this after all usages are changed.
|
||||||
|
"""
|
||||||
|
|
||||||
from __future__ import absolute_import
|
from __future__ import absolute_import
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import sys
|
|
||||||
|
|
||||||
from pip._vendor.six import PY2, text_type
|
from pip._vendor import appdirs as _appdirs
|
||||||
|
|
||||||
from pip._internal.utils.compat import WINDOWS, expanduser
|
|
||||||
from pip._internal.utils.typing import MYPY_CHECK_RUNNING
|
from pip._internal.utils.typing import MYPY_CHECK_RUNNING
|
||||||
|
|
||||||
if MYPY_CHECK_RUNNING:
|
if MYPY_CHECK_RUNNING:
|
||||||
|
@ -22,255 +20,22 @@ if MYPY_CHECK_RUNNING:
|
||||||
|
|
||||||
def user_cache_dir(appname):
|
def user_cache_dir(appname):
|
||||||
# type: (str) -> str
|
# type: (str) -> str
|
||||||
r"""
|
return _appdirs.user_cache_dir(appname, appauthor=False)
|
||||||
Return full path to the user-specific cache dir for this application.
|
|
||||||
|
|
||||||
"appname" is the name of application.
|
|
||||||
|
|
||||||
Typical user cache directories are:
|
|
||||||
macOS: ~/Library/Caches/<AppName>
|
|
||||||
Unix: ~/.cache/<AppName> (XDG default)
|
|
||||||
Windows: C:\Users\<username>\AppData\Local\<AppName>\Cache
|
|
||||||
|
|
||||||
On Windows the only suggestion in the MSDN docs is that local settings go
|
|
||||||
in the `CSIDL_LOCAL_APPDATA` directory. This is identical to the
|
|
||||||
non-roaming app data dir (the default returned by `user_data_dir`). Apps
|
|
||||||
typically put cache data somewhere *under* the given dir here. Some
|
|
||||||
examples:
|
|
||||||
...\Mozilla\Firefox\Profiles\<ProfileName>\Cache
|
|
||||||
...\Acme\SuperApp\Cache\1.0
|
|
||||||
|
|
||||||
OPINION: This function appends "Cache" to the `CSIDL_LOCAL_APPDATA` value.
|
|
||||||
"""
|
|
||||||
if WINDOWS:
|
|
||||||
# Get the base path
|
|
||||||
path = os.path.normpath(_get_win_folder("CSIDL_LOCAL_APPDATA"))
|
|
||||||
|
|
||||||
# When using Python 2, return paths as bytes on Windows like we do on
|
|
||||||
# other operating systems. See helper function docs for more details.
|
|
||||||
if PY2 and isinstance(path, text_type):
|
|
||||||
path = _win_path_to_bytes(path)
|
|
||||||
|
|
||||||
# Add our app name and Cache directory to it
|
|
||||||
path = os.path.join(path, appname, "Cache")
|
|
||||||
elif sys.platform == "darwin":
|
|
||||||
# Get the base path
|
|
||||||
path = expanduser("~/Library/Caches")
|
|
||||||
|
|
||||||
# Add our app name to it
|
|
||||||
path = os.path.join(path, appname)
|
|
||||||
else:
|
|
||||||
# Get the base path
|
|
||||||
path = os.getenv("XDG_CACHE_HOME", expanduser("~/.cache"))
|
|
||||||
|
|
||||||
# Add our app name to it
|
|
||||||
path = os.path.join(path, appname)
|
|
||||||
|
|
||||||
return path
|
|
||||||
|
|
||||||
|
|
||||||
def user_data_dir(appname, roaming=False):
|
|
||||||
# type: (str, bool) -> str
|
|
||||||
r"""
|
|
||||||
Return full path to the user-specific data dir for this application.
|
|
||||||
|
|
||||||
"appname" is the name of application.
|
|
||||||
If None, just the system directory is returned.
|
|
||||||
"roaming" (boolean, default False) can be set True to use the Windows
|
|
||||||
roaming appdata directory. That means that for users on a Windows
|
|
||||||
network setup for roaming profiles, this user data will be
|
|
||||||
sync'd on login. See
|
|
||||||
<http://technet.microsoft.com/en-us/library/cc766489(WS.10).aspx>
|
|
||||||
for a discussion of issues.
|
|
||||||
|
|
||||||
Typical user data directories are:
|
|
||||||
macOS: ~/Library/Application Support/<AppName>
|
|
||||||
if it exists, else ~/.config/<AppName>
|
|
||||||
Unix: ~/.local/share/<AppName> # or in
|
|
||||||
$XDG_DATA_HOME, if defined
|
|
||||||
Win XP (not roaming): C:\Documents and Settings\<username>\ ...
|
|
||||||
...Application Data\<AppName>
|
|
||||||
Win XP (roaming): C:\Documents and Settings\<username>\Local ...
|
|
||||||
...Settings\Application Data\<AppName>
|
|
||||||
Win 7 (not roaming): C:\\Users\<username>\AppData\Local\<AppName>
|
|
||||||
Win 7 (roaming): C:\\Users\<username>\AppData\Roaming\<AppName>
|
|
||||||
|
|
||||||
For Unix, we follow the XDG spec and support $XDG_DATA_HOME.
|
|
||||||
That means, by default "~/.local/share/<AppName>".
|
|
||||||
"""
|
|
||||||
if WINDOWS:
|
|
||||||
const = roaming and "CSIDL_APPDATA" or "CSIDL_LOCAL_APPDATA"
|
|
||||||
path = os.path.join(os.path.normpath(_get_win_folder(const)), appname)
|
|
||||||
elif sys.platform == "darwin":
|
|
||||||
path = os.path.join(
|
|
||||||
expanduser('~/Library/Application Support/'),
|
|
||||||
appname,
|
|
||||||
) if os.path.isdir(os.path.join(
|
|
||||||
expanduser('~/Library/Application Support/'),
|
|
||||||
appname,
|
|
||||||
)
|
|
||||||
) else os.path.join(
|
|
||||||
expanduser('~/.config/'),
|
|
||||||
appname,
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
path = os.path.join(
|
|
||||||
os.getenv('XDG_DATA_HOME', expanduser("~/.local/share")),
|
|
||||||
appname,
|
|
||||||
)
|
|
||||||
|
|
||||||
return path
|
|
||||||
|
|
||||||
|
|
||||||
def user_config_dir(appname, roaming=True):
|
def user_config_dir(appname, roaming=True):
|
||||||
# type: (str, bool) -> str
|
# type: (str, bool) -> str
|
||||||
"""Return full path to the user-specific config dir for this application.
|
return _appdirs.user_config_dir(appname, appauthor=False, roaming=roaming)
|
||||||
|
|
||||||
"appname" is the name of application.
|
|
||||||
If None, just the system directory is returned.
|
def user_data_dir(appname, roaming=False):
|
||||||
"roaming" (boolean, default True) can be set False to not use the
|
# type: (str, bool) -> str
|
||||||
Windows roaming appdata directory. That means that for users on a
|
return _appdirs.user_data_dir(appname, appauthor=False, roaming=roaming)
|
||||||
Windows network setup for roaming profiles, this user data will be
|
|
||||||
sync'd on login. See
|
|
||||||
<http://technet.microsoft.com/en-us/library/cc766489(WS.10).aspx>
|
|
||||||
for a discussion of issues.
|
|
||||||
|
|
||||||
Typical user data directories are:
|
|
||||||
macOS: same as user_data_dir
|
|
||||||
Unix: ~/.config/<AppName>
|
|
||||||
Win *: same as user_data_dir
|
|
||||||
|
|
||||||
For Unix, we follow the XDG spec and support $XDG_CONFIG_HOME.
|
|
||||||
That means, by default "~/.config/<AppName>".
|
|
||||||
"""
|
|
||||||
if WINDOWS:
|
|
||||||
path = user_data_dir(appname, roaming=roaming)
|
|
||||||
elif sys.platform == "darwin":
|
|
||||||
path = user_data_dir(appname)
|
|
||||||
else:
|
|
||||||
path = os.getenv('XDG_CONFIG_HOME', expanduser("~/.config"))
|
|
||||||
path = os.path.join(path, appname)
|
|
||||||
|
|
||||||
return path
|
|
||||||
|
|
||||||
|
|
||||||
# for the discussion regarding site_config_dirs locations
|
|
||||||
# see <https://github.com/pypa/pip/issues/1733>
|
|
||||||
def site_config_dirs(appname):
|
def site_config_dirs(appname):
|
||||||
# type: (str) -> List[str]
|
# type: (str) -> List[str]
|
||||||
r"""Return a list of potential user-shared config dirs for this application.
|
dirval = _appdirs.site_config_dir(appname, appauthor=False, multipath=True)
|
||||||
|
if _appdirs.system not in ["win32", "darwin"]:
|
||||||
"appname" is the name of application.
|
return dirval.split(os.pathsep)
|
||||||
|
return [dirval]
|
||||||
Typical user config directories are:
|
|
||||||
macOS: /Library/Application Support/<AppName>/
|
|
||||||
Unix: /etc or $XDG_CONFIG_DIRS[i]/<AppName>/ for each value in
|
|
||||||
$XDG_CONFIG_DIRS
|
|
||||||
Win XP: C:\Documents and Settings\All Users\Application ...
|
|
||||||
...Data\<AppName>\
|
|
||||||
Vista: (Fail! "C:\ProgramData" is a hidden *system* directory
|
|
||||||
on Vista.)
|
|
||||||
Win 7: Hidden, but writeable on Win 7:
|
|
||||||
C:\ProgramData\<AppName>\
|
|
||||||
"""
|
|
||||||
if WINDOWS:
|
|
||||||
path = os.path.normpath(_get_win_folder("CSIDL_COMMON_APPDATA"))
|
|
||||||
pathlist = [os.path.join(path, appname)]
|
|
||||||
elif sys.platform == 'darwin':
|
|
||||||
pathlist = [os.path.join('/Library/Application Support', appname)]
|
|
||||||
else:
|
|
||||||
# try looking in $XDG_CONFIG_DIRS
|
|
||||||
xdg_config_dirs = os.getenv('XDG_CONFIG_DIRS', '/etc/xdg')
|
|
||||||
if xdg_config_dirs:
|
|
||||||
pathlist = [
|
|
||||||
os.path.join(expanduser(x), appname)
|
|
||||||
for x in xdg_config_dirs.split(os.pathsep)
|
|
||||||
]
|
|
||||||
else:
|
|
||||||
pathlist = []
|
|
||||||
|
|
||||||
# always look in /etc directly as well
|
|
||||||
pathlist.append('/etc')
|
|
||||||
|
|
||||||
return pathlist
|
|
||||||
|
|
||||||
|
|
||||||
# -- Windows support functions --
|
|
||||||
|
|
||||||
def _get_win_folder_from_registry(csidl_name):
|
|
||||||
# type: (str) -> str
|
|
||||||
"""
|
|
||||||
This is a fallback technique at best. I'm not sure if using the
|
|
||||||
registry for this guarantees us the correct answer for all CSIDL_*
|
|
||||||
names.
|
|
||||||
"""
|
|
||||||
import _winreg
|
|
||||||
|
|
||||||
shell_folder_name = {
|
|
||||||
"CSIDL_APPDATA": "AppData",
|
|
||||||
"CSIDL_COMMON_APPDATA": "Common AppData",
|
|
||||||
"CSIDL_LOCAL_APPDATA": "Local AppData",
|
|
||||||
}[csidl_name]
|
|
||||||
|
|
||||||
key = _winreg.OpenKey(
|
|
||||||
_winreg.HKEY_CURRENT_USER,
|
|
||||||
r"Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders"
|
|
||||||
)
|
|
||||||
directory, _type = _winreg.QueryValueEx(key, shell_folder_name)
|
|
||||||
return directory
|
|
||||||
|
|
||||||
|
|
||||||
def _get_win_folder_with_ctypes(csidl_name):
|
|
||||||
# type: (str) -> str
|
|
||||||
# On Python 2, ctypes.create_unicode_buffer().value returns "unicode",
|
|
||||||
# which isn't the same as str in the annotation above.
|
|
||||||
csidl_const = {
|
|
||||||
"CSIDL_APPDATA": 26,
|
|
||||||
"CSIDL_COMMON_APPDATA": 35,
|
|
||||||
"CSIDL_LOCAL_APPDATA": 28,
|
|
||||||
}[csidl_name]
|
|
||||||
|
|
||||||
buf = ctypes.create_unicode_buffer(1024)
|
|
||||||
windll = ctypes.windll # type: ignore
|
|
||||||
windll.shell32.SHGetFolderPathW(None, csidl_const, None, 0, buf)
|
|
||||||
|
|
||||||
# Downgrade to short path name if have highbit chars. See
|
|
||||||
# <http://bugs.activestate.com/show_bug.cgi?id=85099>.
|
|
||||||
has_high_char = False
|
|
||||||
for c in buf:
|
|
||||||
if ord(c) > 255:
|
|
||||||
has_high_char = True
|
|
||||||
break
|
|
||||||
if has_high_char:
|
|
||||||
buf2 = ctypes.create_unicode_buffer(1024)
|
|
||||||
if windll.kernel32.GetShortPathNameW(buf.value, buf2, 1024):
|
|
||||||
buf = buf2
|
|
||||||
|
|
||||||
# The type: ignore is explained under the type annotation for this function
|
|
||||||
return buf.value # type: ignore
|
|
||||||
|
|
||||||
|
|
||||||
if WINDOWS:
|
|
||||||
try:
|
|
||||||
import ctypes
|
|
||||||
_get_win_folder = _get_win_folder_with_ctypes
|
|
||||||
except ImportError:
|
|
||||||
_get_win_folder = _get_win_folder_from_registry
|
|
||||||
|
|
||||||
|
|
||||||
def _win_path_to_bytes(path):
|
|
||||||
"""Encode Windows paths to bytes. Only used on Python 2.
|
|
||||||
|
|
||||||
Motivation is to be consistent with other operating systems where paths
|
|
||||||
are also returned as bytes. This avoids problems mixing bytes and Unicode
|
|
||||||
elsewhere in the codebase. For more details and discussion see
|
|
||||||
<https://github.com/pypa/pip/issues/3463>.
|
|
||||||
|
|
||||||
If encoding using ASCII and MBCS fails, return the original Unicode path.
|
|
||||||
"""
|
|
||||||
for encoding in ('ASCII', 'MBCS'):
|
|
||||||
try:
|
|
||||||
return path.encode(encoding)
|
|
||||||
except (UnicodeEncodeError, LookupError):
|
|
||||||
pass
|
|
||||||
return path
|
|
||||||
|
|
|
@ -37,6 +37,10 @@ if sys.platform.startswith('java'):
|
||||||
# are actually checked for and the rest of the module expects
|
# are actually checked for and the rest of the module expects
|
||||||
# *sys.platform* style strings.
|
# *sys.platform* style strings.
|
||||||
system = 'linux2'
|
system = 'linux2'
|
||||||
|
elif sys.platform == 'cli' and os.name == 'nt':
|
||||||
|
# Detect Windows in IronPython to match pip._internal.utils.compat.WINDOWS
|
||||||
|
# Discussion: <https://github.com/pypa/pip/pull/7501>
|
||||||
|
system = 'win32'
|
||||||
else:
|
else:
|
||||||
system = sys.platform
|
system = sys.platform
|
||||||
|
|
||||||
|
@ -64,7 +68,7 @@ def user_data_dir(appname=None, appauthor=None, version=None, roaming=False):
|
||||||
for a discussion of issues.
|
for a discussion of issues.
|
||||||
|
|
||||||
Typical user data directories are:
|
Typical user data directories are:
|
||||||
Mac OS X: ~/Library/Application Support/<AppName>
|
Mac OS X: ~/Library/Application Support/<AppName> # or ~/.config/<AppName>, if the other does not exist
|
||||||
Unix: ~/.local/share/<AppName> # or in $XDG_DATA_HOME, if defined
|
Unix: ~/.local/share/<AppName> # or in $XDG_DATA_HOME, if defined
|
||||||
Win XP (not roaming): C:\Documents and Settings\<username>\Application Data\<AppAuthor>\<AppName>
|
Win XP (not roaming): C:\Documents and Settings\<username>\Application Data\<AppAuthor>\<AppName>
|
||||||
Win XP (roaming): C:\Documents and Settings\<username>\Local Settings\Application Data\<AppAuthor>\<AppName>
|
Win XP (roaming): C:\Documents and Settings\<username>\Local Settings\Application Data\<AppAuthor>\<AppName>
|
||||||
|
@ -88,6 +92,10 @@ def user_data_dir(appname=None, appauthor=None, version=None, roaming=False):
|
||||||
path = os.path.expanduser('~/Library/Application Support/')
|
path = os.path.expanduser('~/Library/Application Support/')
|
||||||
if appname:
|
if appname:
|
||||||
path = os.path.join(path, appname)
|
path = os.path.join(path, appname)
|
||||||
|
if not os.path.isdir(path):
|
||||||
|
path = os.path.expanduser('~/.config/')
|
||||||
|
if appname:
|
||||||
|
path = os.path.join(path, appname)
|
||||||
else:
|
else:
|
||||||
path = os.getenv('XDG_DATA_HOME', os.path.expanduser("~/.local/share"))
|
path = os.getenv('XDG_DATA_HOME', os.path.expanduser("~/.local/share"))
|
||||||
if appname:
|
if appname:
|
||||||
|
@ -150,7 +158,7 @@ def site_data_dir(appname=None, appauthor=None, version=None, multipath=False):
|
||||||
if appname:
|
if appname:
|
||||||
if version:
|
if version:
|
||||||
appname = os.path.join(appname, version)
|
appname = os.path.join(appname, version)
|
||||||
pathlist = [os.sep.join([x, appname]) for x in pathlist]
|
pathlist = [os.path.join(x, appname) for x in pathlist]
|
||||||
|
|
||||||
if multipath:
|
if multipath:
|
||||||
path = os.pathsep.join(pathlist)
|
path = os.pathsep.join(pathlist)
|
||||||
|
@ -203,6 +211,8 @@ def user_config_dir(appname=None, appauthor=None, version=None, roaming=False):
|
||||||
return path
|
return path
|
||||||
|
|
||||||
|
|
||||||
|
# for the discussion regarding site_config_dir locations
|
||||||
|
# see <https://github.com/pypa/pip/issues/1733>
|
||||||
def site_config_dir(appname=None, appauthor=None, version=None, multipath=False):
|
def site_config_dir(appname=None, appauthor=None, version=None, multipath=False):
|
||||||
r"""Return full path to the user-shared data dir for this application.
|
r"""Return full path to the user-shared data dir for this application.
|
||||||
|
|
||||||
|
@ -238,14 +248,17 @@ def site_config_dir(appname=None, appauthor=None, version=None, multipath=False)
|
||||||
if appname and version:
|
if appname and version:
|
||||||
path = os.path.join(path, version)
|
path = os.path.join(path, version)
|
||||||
else:
|
else:
|
||||||
# XDG default for $XDG_CONFIG_DIRS
|
# XDG default for $XDG_CONFIG_DIRS (missing or empty)
|
||||||
|
# see <https://github.com/pypa/pip/pull/7501#discussion_r360624829>
|
||||||
# only first, if multipath is False
|
# only first, if multipath is False
|
||||||
path = os.getenv('XDG_CONFIG_DIRS', '/etc/xdg')
|
path = os.getenv('XDG_CONFIG_DIRS') or '/etc/xdg'
|
||||||
pathlist = [os.path.expanduser(x.rstrip(os.sep)) for x in path.split(os.pathsep)]
|
pathlist = [os.path.expanduser(x.rstrip(os.sep)) for x in path.split(os.pathsep) if x]
|
||||||
if appname:
|
if appname:
|
||||||
if version:
|
if version:
|
||||||
appname = os.path.join(appname, version)
|
appname = os.path.join(appname, version)
|
||||||
pathlist = [os.sep.join([x, appname]) for x in pathlist]
|
pathlist = [os.path.join(x, appname) for x in pathlist]
|
||||||
|
# always look in /etc directly as well
|
||||||
|
pathlist.append('/etc')
|
||||||
|
|
||||||
if multipath:
|
if multipath:
|
||||||
path = os.pathsep.join(pathlist)
|
path = os.pathsep.join(pathlist)
|
||||||
|
@ -291,6 +304,10 @@ def user_cache_dir(appname=None, appauthor=None, version=None, opinion=True):
|
||||||
if appauthor is None:
|
if appauthor is None:
|
||||||
appauthor = appname
|
appauthor = appname
|
||||||
path = os.path.normpath(_get_win_folder("CSIDL_LOCAL_APPDATA"))
|
path = os.path.normpath(_get_win_folder("CSIDL_LOCAL_APPDATA"))
|
||||||
|
# When using Python 2, return paths as bytes on Windows like we do on
|
||||||
|
# other operating systems. See helper function docs for more details.
|
||||||
|
if not PY3 and isinstance(path, unicode):
|
||||||
|
path = _win_path_to_bytes(path)
|
||||||
if appname:
|
if appname:
|
||||||
if appauthor is not False:
|
if appauthor is not False:
|
||||||
path = os.path.join(path, appauthor, appname)
|
path = os.path.join(path, appauthor, appname)
|
||||||
|
@ -567,6 +584,24 @@ if system == "win32":
|
||||||
_get_win_folder = _get_win_folder_from_registry
|
_get_win_folder = _get_win_folder_from_registry
|
||||||
|
|
||||||
|
|
||||||
|
def _win_path_to_bytes(path):
|
||||||
|
"""Encode Windows paths to bytes. Only used on Python 2.
|
||||||
|
|
||||||
|
Motivation is to be consistent with other operating systems where paths
|
||||||
|
are also returned as bytes. This avoids problems mixing bytes and Unicode
|
||||||
|
elsewhere in the codebase. For more details and discussion see
|
||||||
|
<https://github.com/pypa/pip/issues/3463>.
|
||||||
|
|
||||||
|
If encoding using ASCII and MBCS fails, return the original Unicode path.
|
||||||
|
"""
|
||||||
|
for encoding in ('ASCII', 'MBCS'):
|
||||||
|
try:
|
||||||
|
return path.encode(encoding)
|
||||||
|
except (UnicodeEncodeError, LookupError):
|
||||||
|
pass
|
||||||
|
return path
|
||||||
|
|
||||||
|
|
||||||
#---- self test code
|
#---- self test code
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|
|
@ -4,6 +4,7 @@ import posixpath
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
import pretend
|
import pretend
|
||||||
|
from pip._vendor import appdirs as _appdirs
|
||||||
|
|
||||||
from pip._internal.utils import appdirs
|
from pip._internal.utils import appdirs
|
||||||
|
|
||||||
|
@ -16,12 +17,12 @@ class TestUserCacheDir:
|
||||||
return "C:\\Users\\test\\AppData\\Local"
|
return "C:\\Users\\test\\AppData\\Local"
|
||||||
|
|
||||||
monkeypatch.setattr(
|
monkeypatch.setattr(
|
||||||
appdirs,
|
_appdirs,
|
||||||
"_get_win_folder",
|
"_get_win_folder",
|
||||||
_get_win_folder,
|
_get_win_folder,
|
||||||
raising=False,
|
raising=False,
|
||||||
)
|
)
|
||||||
monkeypatch.setattr(appdirs, "WINDOWS", True)
|
monkeypatch.setattr(_appdirs, "system", "win32")
|
||||||
monkeypatch.setattr(os, "path", ntpath)
|
monkeypatch.setattr(os, "path", ntpath)
|
||||||
|
|
||||||
assert (appdirs.user_cache_dir("pip") ==
|
assert (appdirs.user_cache_dir("pip") ==
|
||||||
|
@ -29,7 +30,7 @@ class TestUserCacheDir:
|
||||||
assert _get_win_folder.calls == [pretend.call("CSIDL_LOCAL_APPDATA")]
|
assert _get_win_folder.calls == [pretend.call("CSIDL_LOCAL_APPDATA")]
|
||||||
|
|
||||||
def test_user_cache_dir_osx(self, monkeypatch):
|
def test_user_cache_dir_osx(self, monkeypatch):
|
||||||
monkeypatch.setattr(appdirs, "WINDOWS", False)
|
monkeypatch.setattr(_appdirs, "system", "darwin")
|
||||||
monkeypatch.setattr(os, "path", posixpath)
|
monkeypatch.setattr(os, "path", posixpath)
|
||||||
monkeypatch.setenv("HOME", "/home/test")
|
monkeypatch.setenv("HOME", "/home/test")
|
||||||
monkeypatch.setattr(sys, "platform", "darwin")
|
monkeypatch.setattr(sys, "platform", "darwin")
|
||||||
|
@ -37,7 +38,7 @@ class TestUserCacheDir:
|
||||||
assert appdirs.user_cache_dir("pip") == "/home/test/Library/Caches/pip"
|
assert appdirs.user_cache_dir("pip") == "/home/test/Library/Caches/pip"
|
||||||
|
|
||||||
def test_user_cache_dir_linux(self, monkeypatch):
|
def test_user_cache_dir_linux(self, monkeypatch):
|
||||||
monkeypatch.setattr(appdirs, "WINDOWS", False)
|
monkeypatch.setattr(_appdirs, "system", "linux2")
|
||||||
monkeypatch.setattr(os, "path", posixpath)
|
monkeypatch.setattr(os, "path", posixpath)
|
||||||
monkeypatch.delenv("XDG_CACHE_HOME", raising=False)
|
monkeypatch.delenv("XDG_CACHE_HOME", raising=False)
|
||||||
monkeypatch.setenv("HOME", "/home/test")
|
monkeypatch.setenv("HOME", "/home/test")
|
||||||
|
@ -46,7 +47,7 @@ class TestUserCacheDir:
|
||||||
assert appdirs.user_cache_dir("pip") == "/home/test/.cache/pip"
|
assert appdirs.user_cache_dir("pip") == "/home/test/.cache/pip"
|
||||||
|
|
||||||
def test_user_cache_dir_linux_override(self, monkeypatch):
|
def test_user_cache_dir_linux_override(self, monkeypatch):
|
||||||
monkeypatch.setattr(appdirs, "WINDOWS", False)
|
monkeypatch.setattr(_appdirs, "system", "linux2")
|
||||||
monkeypatch.setattr(os, "path", posixpath)
|
monkeypatch.setattr(os, "path", posixpath)
|
||||||
monkeypatch.setenv("XDG_CACHE_HOME", "/home/test/.other-cache")
|
monkeypatch.setenv("XDG_CACHE_HOME", "/home/test/.other-cache")
|
||||||
monkeypatch.setenv("HOME", "/home/test")
|
monkeypatch.setenv("HOME", "/home/test")
|
||||||
|
@ -55,7 +56,7 @@ class TestUserCacheDir:
|
||||||
assert appdirs.user_cache_dir("pip") == "/home/test/.other-cache/pip"
|
assert appdirs.user_cache_dir("pip") == "/home/test/.other-cache/pip"
|
||||||
|
|
||||||
def test_user_cache_dir_linux_home_slash(self, monkeypatch):
|
def test_user_cache_dir_linux_home_slash(self, monkeypatch):
|
||||||
monkeypatch.setattr(appdirs, "WINDOWS", False)
|
monkeypatch.setattr(_appdirs, "system", "linux2")
|
||||||
monkeypatch.setattr(os, "path", posixpath)
|
monkeypatch.setattr(os, "path", posixpath)
|
||||||
# Verify that we are not affected by https://bugs.python.org/issue14768
|
# Verify that we are not affected by https://bugs.python.org/issue14768
|
||||||
monkeypatch.delenv("XDG_CACHE_HOME", raising=False)
|
monkeypatch.delenv("XDG_CACHE_HOME", raising=False)
|
||||||
|
@ -71,7 +72,7 @@ class TestUserCacheDir:
|
||||||
def my_get_win_folder(csidl_name):
|
def my_get_win_folder(csidl_name):
|
||||||
return u"\u00DF\u00E4\u03B1\u20AC"
|
return u"\u00DF\u00E4\u03B1\u20AC"
|
||||||
|
|
||||||
monkeypatch.setattr(appdirs, "_get_win_folder", my_get_win_folder)
|
monkeypatch.setattr(_appdirs, "_get_win_folder", my_get_win_folder)
|
||||||
|
|
||||||
# Do not use the isinstance expression directly in the
|
# Do not use the isinstance expression directly in the
|
||||||
# assert statement, as the Unicode characters in the result
|
# assert statement, as the Unicode characters in the result
|
||||||
|
@ -92,19 +93,19 @@ class TestSiteConfigDirs:
|
||||||
return "C:\\ProgramData"
|
return "C:\\ProgramData"
|
||||||
|
|
||||||
monkeypatch.setattr(
|
monkeypatch.setattr(
|
||||||
appdirs,
|
_appdirs,
|
||||||
"_get_win_folder",
|
"_get_win_folder",
|
||||||
_get_win_folder,
|
_get_win_folder,
|
||||||
raising=False,
|
raising=False,
|
||||||
)
|
)
|
||||||
monkeypatch.setattr(appdirs, "WINDOWS", True)
|
monkeypatch.setattr(_appdirs, "system", "win32")
|
||||||
monkeypatch.setattr(os, "path", ntpath)
|
monkeypatch.setattr(os, "path", ntpath)
|
||||||
|
|
||||||
assert appdirs.site_config_dirs("pip") == ["C:\\ProgramData\\pip"]
|
assert appdirs.site_config_dirs("pip") == ["C:\\ProgramData\\pip"]
|
||||||
assert _get_win_folder.calls == [pretend.call("CSIDL_COMMON_APPDATA")]
|
assert _get_win_folder.calls == [pretend.call("CSIDL_COMMON_APPDATA")]
|
||||||
|
|
||||||
def test_site_config_dirs_osx(self, monkeypatch):
|
def test_site_config_dirs_osx(self, monkeypatch):
|
||||||
monkeypatch.setattr(appdirs, "WINDOWS", False)
|
monkeypatch.setattr(_appdirs, "system", "darwin")
|
||||||
monkeypatch.setattr(os, "path", posixpath)
|
monkeypatch.setattr(os, "path", posixpath)
|
||||||
monkeypatch.setenv("HOME", "/home/test")
|
monkeypatch.setenv("HOME", "/home/test")
|
||||||
monkeypatch.setattr(sys, "platform", "darwin")
|
monkeypatch.setattr(sys, "platform", "darwin")
|
||||||
|
@ -113,7 +114,7 @@ class TestSiteConfigDirs:
|
||||||
["/Library/Application Support/pip"]
|
["/Library/Application Support/pip"]
|
||||||
|
|
||||||
def test_site_config_dirs_linux(self, monkeypatch):
|
def test_site_config_dirs_linux(self, monkeypatch):
|
||||||
monkeypatch.setattr(appdirs, "WINDOWS", False)
|
monkeypatch.setattr(_appdirs, "system", "linux2")
|
||||||
monkeypatch.setattr(os, "path", posixpath)
|
monkeypatch.setattr(os, "path", posixpath)
|
||||||
monkeypatch.delenv("XDG_CONFIG_DIRS", raising=False)
|
monkeypatch.delenv("XDG_CONFIG_DIRS", raising=False)
|
||||||
monkeypatch.setattr(sys, "platform", "linux2")
|
monkeypatch.setattr(sys, "platform", "linux2")
|
||||||
|
@ -124,7 +125,7 @@ class TestSiteConfigDirs:
|
||||||
]
|
]
|
||||||
|
|
||||||
def test_site_config_dirs_linux_override(self, monkeypatch):
|
def test_site_config_dirs_linux_override(self, monkeypatch):
|
||||||
monkeypatch.setattr(appdirs, "WINDOWS", False)
|
monkeypatch.setattr(_appdirs, "system", "linux2")
|
||||||
monkeypatch.setattr(os, "path", posixpath)
|
monkeypatch.setattr(os, "path", posixpath)
|
||||||
monkeypatch.setattr(os, "pathsep", ':')
|
monkeypatch.setattr(os, "pathsep", ':')
|
||||||
monkeypatch.setenv("XDG_CONFIG_DIRS", "/spam:/etc:/etc/xdg")
|
monkeypatch.setenv("XDG_CONFIG_DIRS", "/spam:/etc:/etc/xdg")
|
||||||
|
@ -137,6 +138,14 @@ class TestSiteConfigDirs:
|
||||||
'/etc'
|
'/etc'
|
||||||
]
|
]
|
||||||
|
|
||||||
|
def test_site_config_dirs_linux_empty(self, monkeypatch):
|
||||||
|
monkeypatch.setattr(_appdirs, "system", "linux2")
|
||||||
|
monkeypatch.setattr(os, "path", posixpath)
|
||||||
|
monkeypatch.setattr(os, "pathsep", ':')
|
||||||
|
monkeypatch.setenv("XDG_CONFIG_DIRS", "")
|
||||||
|
monkeypatch.setattr(sys, "platform", "linux2")
|
||||||
|
assert appdirs.site_config_dirs("pip") == ['/etc/xdg/pip', '/etc']
|
||||||
|
|
||||||
|
|
||||||
class TestUserDataDir:
|
class TestUserDataDir:
|
||||||
|
|
||||||
|
@ -146,12 +155,12 @@ class TestUserDataDir:
|
||||||
return "C:\\Users\\test\\AppData\\Local"
|
return "C:\\Users\\test\\AppData\\Local"
|
||||||
|
|
||||||
monkeypatch.setattr(
|
monkeypatch.setattr(
|
||||||
appdirs,
|
_appdirs,
|
||||||
"_get_win_folder",
|
"_get_win_folder",
|
||||||
_get_win_folder,
|
_get_win_folder,
|
||||||
raising=False,
|
raising=False,
|
||||||
)
|
)
|
||||||
monkeypatch.setattr(appdirs, "WINDOWS", True)
|
monkeypatch.setattr(_appdirs, "system", "win32")
|
||||||
monkeypatch.setattr(os, "path", ntpath)
|
monkeypatch.setattr(os, "path", ntpath)
|
||||||
|
|
||||||
assert (appdirs.user_data_dir("pip") ==
|
assert (appdirs.user_data_dir("pip") ==
|
||||||
|
@ -164,12 +173,12 @@ class TestUserDataDir:
|
||||||
return "C:\\Users\\test\\AppData\\Roaming"
|
return "C:\\Users\\test\\AppData\\Roaming"
|
||||||
|
|
||||||
monkeypatch.setattr(
|
monkeypatch.setattr(
|
||||||
appdirs,
|
_appdirs,
|
||||||
"_get_win_folder",
|
"_get_win_folder",
|
||||||
_get_win_folder,
|
_get_win_folder,
|
||||||
raising=False,
|
raising=False,
|
||||||
)
|
)
|
||||||
monkeypatch.setattr(appdirs, "WINDOWS", True)
|
monkeypatch.setattr(_appdirs, "system", "win32")
|
||||||
monkeypatch.setattr(os, "path", ntpath)
|
monkeypatch.setattr(os, "path", ntpath)
|
||||||
|
|
||||||
assert (
|
assert (
|
||||||
|
@ -179,7 +188,7 @@ class TestUserDataDir:
|
||||||
assert _get_win_folder.calls == [pretend.call("CSIDL_APPDATA")]
|
assert _get_win_folder.calls == [pretend.call("CSIDL_APPDATA")]
|
||||||
|
|
||||||
def test_user_data_dir_osx(self, monkeypatch):
|
def test_user_data_dir_osx(self, monkeypatch):
|
||||||
monkeypatch.setattr(appdirs, "WINDOWS", False)
|
monkeypatch.setattr(_appdirs, "system", "darwin")
|
||||||
monkeypatch.setattr(os, "path", posixpath)
|
monkeypatch.setattr(os, "path", posixpath)
|
||||||
monkeypatch.setenv("HOME", "/home/test")
|
monkeypatch.setenv("HOME", "/home/test")
|
||||||
monkeypatch.setattr(sys, "platform", "darwin")
|
monkeypatch.setattr(sys, "platform", "darwin")
|
||||||
|
@ -192,7 +201,7 @@ class TestUserDataDir:
|
||||||
"/home/test/.config/pip")
|
"/home/test/.config/pip")
|
||||||
|
|
||||||
def test_user_data_dir_linux(self, monkeypatch):
|
def test_user_data_dir_linux(self, monkeypatch):
|
||||||
monkeypatch.setattr(appdirs, "WINDOWS", False)
|
monkeypatch.setattr(_appdirs, "system", "linux2")
|
||||||
monkeypatch.setattr(os, "path", posixpath)
|
monkeypatch.setattr(os, "path", posixpath)
|
||||||
monkeypatch.delenv("XDG_DATA_HOME", raising=False)
|
monkeypatch.delenv("XDG_DATA_HOME", raising=False)
|
||||||
monkeypatch.setenv("HOME", "/home/test")
|
monkeypatch.setenv("HOME", "/home/test")
|
||||||
|
@ -201,7 +210,7 @@ class TestUserDataDir:
|
||||||
assert appdirs.user_data_dir("pip") == "/home/test/.local/share/pip"
|
assert appdirs.user_data_dir("pip") == "/home/test/.local/share/pip"
|
||||||
|
|
||||||
def test_user_data_dir_linux_override(self, monkeypatch):
|
def test_user_data_dir_linux_override(self, monkeypatch):
|
||||||
monkeypatch.setattr(appdirs, "WINDOWS", False)
|
monkeypatch.setattr(_appdirs, "system", "linux2")
|
||||||
monkeypatch.setattr(os, "path", posixpath)
|
monkeypatch.setattr(os, "path", posixpath)
|
||||||
monkeypatch.setenv("XDG_DATA_HOME", "/home/test/.other-share")
|
monkeypatch.setenv("XDG_DATA_HOME", "/home/test/.other-share")
|
||||||
monkeypatch.setenv("HOME", "/home/test")
|
monkeypatch.setenv("HOME", "/home/test")
|
||||||
|
@ -210,7 +219,7 @@ class TestUserDataDir:
|
||||||
assert appdirs.user_data_dir("pip") == "/home/test/.other-share/pip"
|
assert appdirs.user_data_dir("pip") == "/home/test/.other-share/pip"
|
||||||
|
|
||||||
def test_user_data_dir_linux_home_slash(self, monkeypatch):
|
def test_user_data_dir_linux_home_slash(self, monkeypatch):
|
||||||
monkeypatch.setattr(appdirs, "WINDOWS", False)
|
monkeypatch.setattr(_appdirs, "system", "linux2")
|
||||||
monkeypatch.setattr(os, "path", posixpath)
|
monkeypatch.setattr(os, "path", posixpath)
|
||||||
# Verify that we are not affected by https://bugs.python.org/issue14768
|
# Verify that we are not affected by https://bugs.python.org/issue14768
|
||||||
monkeypatch.delenv("XDG_DATA_HOME", raising=False)
|
monkeypatch.delenv("XDG_DATA_HOME", raising=False)
|
||||||
|
@ -228,12 +237,12 @@ class TestUserConfigDir:
|
||||||
return "C:\\Users\\test\\AppData\\Local"
|
return "C:\\Users\\test\\AppData\\Local"
|
||||||
|
|
||||||
monkeypatch.setattr(
|
monkeypatch.setattr(
|
||||||
appdirs,
|
_appdirs,
|
||||||
"_get_win_folder",
|
"_get_win_folder",
|
||||||
_get_win_folder,
|
_get_win_folder,
|
||||||
raising=False,
|
raising=False,
|
||||||
)
|
)
|
||||||
monkeypatch.setattr(appdirs, "WINDOWS", True)
|
monkeypatch.setattr(_appdirs, "system", "win32")
|
||||||
monkeypatch.setattr(os, "path", ntpath)
|
monkeypatch.setattr(os, "path", ntpath)
|
||||||
|
|
||||||
assert (
|
assert (
|
||||||
|
@ -248,12 +257,12 @@ class TestUserConfigDir:
|
||||||
return "C:\\Users\\test\\AppData\\Roaming"
|
return "C:\\Users\\test\\AppData\\Roaming"
|
||||||
|
|
||||||
monkeypatch.setattr(
|
monkeypatch.setattr(
|
||||||
appdirs,
|
_appdirs,
|
||||||
"_get_win_folder",
|
"_get_win_folder",
|
||||||
_get_win_folder,
|
_get_win_folder,
|
||||||
raising=False,
|
raising=False,
|
||||||
)
|
)
|
||||||
monkeypatch.setattr(appdirs, "WINDOWS", True)
|
monkeypatch.setattr(_appdirs, "system", "win32")
|
||||||
monkeypatch.setattr(os, "path", ntpath)
|
monkeypatch.setattr(os, "path", ntpath)
|
||||||
|
|
||||||
assert (appdirs.user_config_dir("pip") ==
|
assert (appdirs.user_config_dir("pip") ==
|
||||||
|
@ -261,7 +270,7 @@ class TestUserConfigDir:
|
||||||
assert _get_win_folder.calls == [pretend.call("CSIDL_APPDATA")]
|
assert _get_win_folder.calls == [pretend.call("CSIDL_APPDATA")]
|
||||||
|
|
||||||
def test_user_config_dir_osx(self, monkeypatch):
|
def test_user_config_dir_osx(self, monkeypatch):
|
||||||
monkeypatch.setattr(appdirs, "WINDOWS", False)
|
monkeypatch.setattr(_appdirs, "system", "darwin")
|
||||||
monkeypatch.setattr(os, "path", posixpath)
|
monkeypatch.setattr(os, "path", posixpath)
|
||||||
monkeypatch.setenv("HOME", "/home/test")
|
monkeypatch.setenv("HOME", "/home/test")
|
||||||
monkeypatch.setattr(sys, "platform", "darwin")
|
monkeypatch.setattr(sys, "platform", "darwin")
|
||||||
|
@ -274,7 +283,7 @@ class TestUserConfigDir:
|
||||||
"/home/test/.config/pip")
|
"/home/test/.config/pip")
|
||||||
|
|
||||||
def test_user_config_dir_linux(self, monkeypatch):
|
def test_user_config_dir_linux(self, monkeypatch):
|
||||||
monkeypatch.setattr(appdirs, "WINDOWS", False)
|
monkeypatch.setattr(_appdirs, "system", "linux2")
|
||||||
monkeypatch.setattr(os, "path", posixpath)
|
monkeypatch.setattr(os, "path", posixpath)
|
||||||
monkeypatch.delenv("XDG_CONFIG_HOME", raising=False)
|
monkeypatch.delenv("XDG_CONFIG_HOME", raising=False)
|
||||||
monkeypatch.setenv("HOME", "/home/test")
|
monkeypatch.setenv("HOME", "/home/test")
|
||||||
|
@ -283,7 +292,7 @@ class TestUserConfigDir:
|
||||||
assert appdirs.user_config_dir("pip") == "/home/test/.config/pip"
|
assert appdirs.user_config_dir("pip") == "/home/test/.config/pip"
|
||||||
|
|
||||||
def test_user_config_dir_linux_override(self, monkeypatch):
|
def test_user_config_dir_linux_override(self, monkeypatch):
|
||||||
monkeypatch.setattr(appdirs, "WINDOWS", False)
|
monkeypatch.setattr(_appdirs, "system", "linux2")
|
||||||
monkeypatch.setattr(os, "path", posixpath)
|
monkeypatch.setattr(os, "path", posixpath)
|
||||||
monkeypatch.setenv("XDG_CONFIG_HOME", "/home/test/.other-config")
|
monkeypatch.setenv("XDG_CONFIG_HOME", "/home/test/.other-config")
|
||||||
monkeypatch.setenv("HOME", "/home/test")
|
monkeypatch.setenv("HOME", "/home/test")
|
||||||
|
@ -292,7 +301,7 @@ class TestUserConfigDir:
|
||||||
assert appdirs.user_config_dir("pip") == "/home/test/.other-config/pip"
|
assert appdirs.user_config_dir("pip") == "/home/test/.other-config/pip"
|
||||||
|
|
||||||
def test_user_config_dir_linux_home_slash(self, monkeypatch):
|
def test_user_config_dir_linux_home_slash(self, monkeypatch):
|
||||||
monkeypatch.setattr(appdirs, "WINDOWS", False)
|
monkeypatch.setattr(_appdirs, "system", "linux2")
|
||||||
monkeypatch.setattr(os, "path", posixpath)
|
monkeypatch.setattr(os, "path", posixpath)
|
||||||
# Verify that we are not affected by https://bugs.python.org/issue14768
|
# Verify that we are not affected by https://bugs.python.org/issue14768
|
||||||
monkeypatch.delenv("XDG_CONFIG_HOME", raising=False)
|
monkeypatch.delenv("XDG_CONFIG_HOME", raising=False)
|
||||||
|
|
|
@ -1,9 +1,91 @@
|
||||||
diff --git a/src/pip/_vendor/appdirs.py b/src/pip/_vendor/appdirs.py
|
diff --git a/src/pip/_vendor/appdirs.py b/src/pip/_vendor/appdirs.py
|
||||||
index ae67001a..2bd39110 100644
|
index ae67001a..3a52b758 100644
|
||||||
--- a/src/pip/_vendor/appdirs.py
|
--- a/src/pip/_vendor/appdirs.py
|
||||||
+++ b/src/pip/_vendor/appdirs.py
|
+++ b/src/pip/_vendor/appdirs.py
|
||||||
@@ -557,18 +557,14 @@ def _get_win_folder_with_jna(csidl_name):
|
@@ -37,6 +37,10 @@ if sys.platform.startswith('java'):
|
||||||
|
# are actually checked for and the rest of the module expects
|
||||||
|
# *sys.platform* style strings.
|
||||||
|
system = 'linux2'
|
||||||
|
+elif sys.platform == 'cli' and os.name == 'nt':
|
||||||
|
+ # Detect Windows in IronPython to match pip._internal.utils.compat.WINDOWS
|
||||||
|
+ # Discussion: <https://github.com/pypa/pip/pull/7501>
|
||||||
|
+ system = 'win32'
|
||||||
|
else:
|
||||||
|
system = sys.platform
|
||||||
|
|
||||||
|
@@ -64,7 +68,7 @@ def user_data_dir(appname=None, appauthor=None, version=None, roaming=False):
|
||||||
|
for a discussion of issues.
|
||||||
|
|
||||||
|
Typical user data directories are:
|
||||||
|
- Mac OS X: ~/Library/Application Support/<AppName>
|
||||||
|
+ Mac OS X: ~/Library/Application Support/<AppName> # or ~/.config/<AppName>, if the other does not exist
|
||||||
|
Unix: ~/.local/share/<AppName> # or in $XDG_DATA_HOME, if defined
|
||||||
|
Win XP (not roaming): C:\Documents and Settings\<username>\Application Data\<AppAuthor>\<AppName>
|
||||||
|
Win XP (roaming): C:\Documents and Settings\<username>\Local Settings\Application Data\<AppAuthor>\<AppName>
|
||||||
|
@@ -88,6 +92,10 @@ def user_data_dir(appname=None, appauthor=None, version=None, roaming=False):
|
||||||
|
path = os.path.expanduser('~/Library/Application Support/')
|
||||||
|
if appname:
|
||||||
|
path = os.path.join(path, appname)
|
||||||
|
+ if not os.path.isdir(path):
|
||||||
|
+ path = os.path.expanduser('~/.config/')
|
||||||
|
+ if appname:
|
||||||
|
+ path = os.path.join(path, appname)
|
||||||
|
else:
|
||||||
|
path = os.getenv('XDG_DATA_HOME', os.path.expanduser("~/.local/share"))
|
||||||
|
if appname:
|
||||||
|
@@ -150,7 +158,7 @@ def site_data_dir(appname=None, appauthor=None, version=None, multipath=False):
|
||||||
|
if appname:
|
||||||
|
if version:
|
||||||
|
appname = os.path.join(appname, version)
|
||||||
|
- pathlist = [os.sep.join([x, appname]) for x in pathlist]
|
||||||
|
+ pathlist = [os.path.join(x, appname) for x in pathlist]
|
||||||
|
|
||||||
|
if multipath:
|
||||||
|
path = os.pathsep.join(pathlist)
|
||||||
|
@@ -203,6 +211,8 @@ def user_config_dir(appname=None, appauthor=None, version=None, roaming=False):
|
||||||
|
return path
|
||||||
|
|
||||||
|
|
||||||
|
+# for the discussion regarding site_config_dir locations
|
||||||
|
+# see <https://github.com/pypa/pip/issues/1733>
|
||||||
|
def site_config_dir(appname=None, appauthor=None, version=None, multipath=False):
|
||||||
|
r"""Return full path to the user-shared data dir for this application.
|
||||||
|
|
||||||
|
@@ -238,14 +248,17 @@ def site_config_dir(appname=None, appauthor=None, version=None, multipath=False)
|
||||||
|
if appname and version:
|
||||||
|
path = os.path.join(path, version)
|
||||||
|
else:
|
||||||
|
- # XDG default for $XDG_CONFIG_DIRS
|
||||||
|
+ # XDG default for $XDG_CONFIG_DIRS (missing or empty)
|
||||||
|
+ # see <https://github.com/pypa/pip/pull/7501#discussion_r360624829>
|
||||||
|
# only first, if multipath is False
|
||||||
|
- path = os.getenv('XDG_CONFIG_DIRS', '/etc/xdg')
|
||||||
|
- pathlist = [os.path.expanduser(x.rstrip(os.sep)) for x in path.split(os.pathsep)]
|
||||||
|
+ path = os.getenv('XDG_CONFIG_DIRS') or '/etc/xdg'
|
||||||
|
+ pathlist = [os.path.expanduser(x.rstrip(os.sep)) for x in path.split(os.pathsep) if x]
|
||||||
|
if appname:
|
||||||
|
if version:
|
||||||
|
appname = os.path.join(appname, version)
|
||||||
|
- pathlist = [os.sep.join([x, appname]) for x in pathlist]
|
||||||
|
+ pathlist = [os.path.join(x, appname) for x in pathlist]
|
||||||
|
+ # always look in /etc directly as well
|
||||||
|
+ pathlist.append('/etc')
|
||||||
|
|
||||||
|
if multipath:
|
||||||
|
path = os.pathsep.join(pathlist)
|
||||||
|
@@ -291,6 +304,10 @@ def user_cache_dir(appname=None, appauthor=None, version=None, opinion=True):
|
||||||
|
if appauthor is None:
|
||||||
|
appauthor = appname
|
||||||
|
path = os.path.normpath(_get_win_folder("CSIDL_LOCAL_APPDATA"))
|
||||||
|
+ # When using Python 2, return paths as bytes on Windows like we do on
|
||||||
|
+ # other operating systems. See helper function docs for more details.
|
||||||
|
+ if not PY3 and isinstance(path, unicode):
|
||||||
|
+ path = _win_path_to_bytes(path)
|
||||||
|
if appname:
|
||||||
|
if appauthor is not False:
|
||||||
|
path = os.path.join(path, appauthor, appname)
|
||||||
|
@@ -557,18 +574,32 @@ def _get_win_folder_with_jna(csidl_name):
|
||||||
|
|
||||||
if system == "win32":
|
if system == "win32":
|
||||||
try:
|
try:
|
||||||
- import win32com.shell
|
- import win32com.shell
|
||||||
|
@ -23,6 +105,24 @@ index ae67001a..2bd39110 100644
|
||||||
- except ImportError:
|
- except ImportError:
|
||||||
- _get_win_folder = _get_win_folder_from_registry
|
- _get_win_folder = _get_win_folder_from_registry
|
||||||
+ _get_win_folder = _get_win_folder_from_registry
|
+ _get_win_folder = _get_win_folder_from_registry
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+def _win_path_to_bytes(path):
|
||||||
|
+ """Encode Windows paths to bytes. Only used on Python 2.
|
||||||
|
+
|
||||||
|
+ Motivation is to be consistent with other operating systems where paths
|
||||||
|
+ are also returned as bytes. This avoids problems mixing bytes and Unicode
|
||||||
|
+ elsewhere in the codebase. For more details and discussion see
|
||||||
|
+ <https://github.com/pypa/pip/issues/3463>.
|
||||||
|
+
|
||||||
|
+ If encoding using ASCII and MBCS fails, return the original Unicode path.
|
||||||
|
+ """
|
||||||
|
+ for encoding in ('ASCII', 'MBCS'):
|
||||||
|
+ try:
|
||||||
|
+ return path.encode(encoding)
|
||||||
|
+ except (UnicodeEncodeError, LookupError):
|
||||||
|
+ pass
|
||||||
|
+ return path
|
||||||
|
|
||||||
|
|
||||||
#---- self test code
|
#---- self test code
|
||||||
|
|
Loading…
Reference in a new issue