xref: /aosp_15_r20/external/pytorch/torch/_appdirs.py (revision da0073e96a02ea20f0ac840b70461e3646d07c45)
1*da0073e9SAndroid Build Coastguard Worker#!/usr/bin/env python3
2*da0073e9SAndroid Build Coastguard Worker# -*- coding: utf-8 -*-
3*da0073e9SAndroid Build Coastguard Worker# Copyright (c) 2005-2010 ActiveState Software Inc.
4*da0073e9SAndroid Build Coastguard Worker# Copyright (c) 2013 Eddy Petrișor
5*da0073e9SAndroid Build Coastguard Worker
6*da0073e9SAndroid Build Coastguard Worker# flake8: noqa
7*da0073e9SAndroid Build Coastguard Worker
8*da0073e9SAndroid Build Coastguard Worker"""
9*da0073e9SAndroid Build Coastguard WorkerThis file is directly from
10*da0073e9SAndroid Build Coastguard Workerhttps://github.com/ActiveState/appdirs/blob/3fe6a83776843a46f20c2e5587afcffe05e03b39/appdirs.py
11*da0073e9SAndroid Build Coastguard Worker
12*da0073e9SAndroid Build Coastguard WorkerThe license of https://github.com/ActiveState/appdirs copied below:
13*da0073e9SAndroid Build Coastguard Worker
14*da0073e9SAndroid Build Coastguard Worker
15*da0073e9SAndroid Build Coastguard Worker# This is the MIT license
16*da0073e9SAndroid Build Coastguard Worker
17*da0073e9SAndroid Build Coastguard WorkerCopyright (c) 2010 ActiveState Software Inc.
18*da0073e9SAndroid Build Coastguard Worker
19*da0073e9SAndroid Build Coastguard WorkerPermission is hereby granted, free of charge, to any person obtaining a
20*da0073e9SAndroid Build Coastguard Workercopy of this software and associated documentation files (the
21*da0073e9SAndroid Build Coastguard Worker"Software"), to deal in the Software without restriction, including
22*da0073e9SAndroid Build Coastguard Workerwithout limitation the rights to use, copy, modify, merge, publish,
23*da0073e9SAndroid Build Coastguard Workerdistribute, sublicense, and/or sell copies of the Software, and to
24*da0073e9SAndroid Build Coastguard Workerpermit persons to whom the Software is furnished to do so, subject to
25*da0073e9SAndroid Build Coastguard Workerthe following conditions:
26*da0073e9SAndroid Build Coastguard Worker
27*da0073e9SAndroid Build Coastguard WorkerThe above copyright notice and this permission notice shall be included
28*da0073e9SAndroid Build Coastguard Workerin all copies or substantial portions of the Software.
29*da0073e9SAndroid Build Coastguard Worker
30*da0073e9SAndroid Build Coastguard WorkerTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
31*da0073e9SAndroid Build Coastguard WorkerOR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
32*da0073e9SAndroid Build Coastguard WorkerMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
33*da0073e9SAndroid Build Coastguard WorkerIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
34*da0073e9SAndroid Build Coastguard WorkerCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
35*da0073e9SAndroid Build Coastguard WorkerTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
36*da0073e9SAndroid Build Coastguard WorkerSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
37*da0073e9SAndroid Build Coastguard Worker"""
38*da0073e9SAndroid Build Coastguard Worker
39*da0073e9SAndroid Build Coastguard Worker"""Utilities for determining application-specific dirs.
40*da0073e9SAndroid Build Coastguard Worker
41*da0073e9SAndroid Build Coastguard WorkerSee <https://github.com/ActiveState/appdirs> for details and usage.
42*da0073e9SAndroid Build Coastguard Worker"""
43*da0073e9SAndroid Build Coastguard Worker# Dev Notes:
44*da0073e9SAndroid Build Coastguard Worker# - MSDN on where to store app data files:
45*da0073e9SAndroid Build Coastguard Worker#   http://support.microsoft.com/default.aspx?scid=kb;en-us;310294#XSLTH3194121123120121120120
46*da0073e9SAndroid Build Coastguard Worker# - Mac OS X: http://developer.apple.com/documentation/MacOSX/Conceptual/BPFileSystem/index.html
47*da0073e9SAndroid Build Coastguard Worker# - XDG spec for Un*x: https://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
48*da0073e9SAndroid Build Coastguard Worker
49*da0073e9SAndroid Build Coastguard Worker__version__ = "1.4.4"
50*da0073e9SAndroid Build Coastguard Worker__version_info__ = tuple(int(segment) for segment in __version__.split("."))
51*da0073e9SAndroid Build Coastguard Worker
52*da0073e9SAndroid Build Coastguard Worker
53*da0073e9SAndroid Build Coastguard Workerimport os
54*da0073e9SAndroid Build Coastguard Workerimport sys
55*da0073e9SAndroid Build Coastguard Worker
56*da0073e9SAndroid Build Coastguard Worker
57*da0073e9SAndroid Build Coastguard Workerunicode = str
58*da0073e9SAndroid Build Coastguard Worker
59*da0073e9SAndroid Build Coastguard Workerif sys.platform.startswith("java"):
60*da0073e9SAndroid Build Coastguard Worker    import platform
61*da0073e9SAndroid Build Coastguard Worker
62*da0073e9SAndroid Build Coastguard Worker    os_name = platform.java_ver()[3][0]
63*da0073e9SAndroid Build Coastguard Worker    if os_name.startswith("Windows"):  # "Windows XP", "Windows 7", etc.
64*da0073e9SAndroid Build Coastguard Worker        system = "win32"
65*da0073e9SAndroid Build Coastguard Worker    elif os_name.startswith("Mac"):  # "Mac OS X", etc.
66*da0073e9SAndroid Build Coastguard Worker        system = "darwin"
67*da0073e9SAndroid Build Coastguard Worker    else:  # "Linux", "SunOS", "FreeBSD", etc.
68*da0073e9SAndroid Build Coastguard Worker        # Setting this to "linux2" is not ideal, but only Windows or Mac
69*da0073e9SAndroid Build Coastguard Worker        # are actually checked for and the rest of the module expects
70*da0073e9SAndroid Build Coastguard Worker        # *sys.platform* style strings.
71*da0073e9SAndroid Build Coastguard Worker        system = "linux2"
72*da0073e9SAndroid Build Coastguard Workerelse:
73*da0073e9SAndroid Build Coastguard Worker    system = sys.platform
74*da0073e9SAndroid Build Coastguard Worker
75*da0073e9SAndroid Build Coastguard Worker
76*da0073e9SAndroid Build Coastguard Workerdef user_data_dir(appname=None, appauthor=None, version=None, roaming=False):
77*da0073e9SAndroid Build Coastguard Worker    r"""Return full path to the user-specific data dir for this application.
78*da0073e9SAndroid Build Coastguard Worker
79*da0073e9SAndroid Build Coastguard Worker        "appname" is the name of application.
80*da0073e9SAndroid Build Coastguard Worker            If None, just the system directory is returned.
81*da0073e9SAndroid Build Coastguard Worker        "appauthor" (only used on Windows) is the name of the
82*da0073e9SAndroid Build Coastguard Worker            appauthor or distributing body for this application. Typically
83*da0073e9SAndroid Build Coastguard Worker            it is the owning company name. This falls back to appname. You may
84*da0073e9SAndroid Build Coastguard Worker            pass False to disable it.
85*da0073e9SAndroid Build Coastguard Worker        "version" is an optional version path element to append to the
86*da0073e9SAndroid Build Coastguard Worker            path. You might want to use this if you want multiple versions
87*da0073e9SAndroid Build Coastguard Worker            of your app to be able to run independently. If used, this
88*da0073e9SAndroid Build Coastguard Worker            would typically be "<major>.<minor>".
89*da0073e9SAndroid Build Coastguard Worker            Only applied when appname is present.
90*da0073e9SAndroid Build Coastguard Worker        "roaming" (boolean, default False) can be set True to use the Windows
91*da0073e9SAndroid Build Coastguard Worker            roaming appdata directory. That means that for users on a Windows
92*da0073e9SAndroid Build Coastguard Worker            network setup for roaming profiles, this user data will be
93*da0073e9SAndroid Build Coastguard Worker            sync'd on login. See
94*da0073e9SAndroid Build Coastguard Worker            <http://technet.microsoft.com/en-us/library/cc766489(WS.10).aspx>
95*da0073e9SAndroid Build Coastguard Worker            for a discussion of issues.
96*da0073e9SAndroid Build Coastguard Worker
97*da0073e9SAndroid Build Coastguard Worker    Typical user data directories are:
98*da0073e9SAndroid Build Coastguard Worker        Mac OS X:               ~/Library/Application Support/<AppName>
99*da0073e9SAndroid Build Coastguard Worker        Unix:                   ~/.local/share/<AppName>    # or in $XDG_DATA_HOME, if defined
100*da0073e9SAndroid Build Coastguard Worker        Win XP (not roaming):   C:\Documents and Settings\<username>\Application Data\<AppAuthor>\<AppName>
101*da0073e9SAndroid Build Coastguard Worker        Win XP (roaming):       C:\Documents and Settings\<username>\Local Settings\Application Data\<AppAuthor>\<AppName>
102*da0073e9SAndroid Build Coastguard Worker        Win 7  (not roaming):   C:\Users\<username>\AppData\Local\<AppAuthor>\<AppName>
103*da0073e9SAndroid Build Coastguard Worker        Win 7  (roaming):       C:\Users\<username>\AppData\Roaming\<AppAuthor>\<AppName>
104*da0073e9SAndroid Build Coastguard Worker
105*da0073e9SAndroid Build Coastguard Worker    For Unix, we follow the XDG spec and support $XDG_DATA_HOME.
106*da0073e9SAndroid Build Coastguard Worker    That means, by default "~/.local/share/<AppName>".
107*da0073e9SAndroid Build Coastguard Worker    """
108*da0073e9SAndroid Build Coastguard Worker    if system == "win32":
109*da0073e9SAndroid Build Coastguard Worker        if appauthor is None:
110*da0073e9SAndroid Build Coastguard Worker            appauthor = appname
111*da0073e9SAndroid Build Coastguard Worker        const = roaming and "CSIDL_APPDATA" or "CSIDL_LOCAL_APPDATA"
112*da0073e9SAndroid Build Coastguard Worker        path = os.path.normpath(_get_win_folder(const))
113*da0073e9SAndroid Build Coastguard Worker        if appname:
114*da0073e9SAndroid Build Coastguard Worker            if appauthor is not False:
115*da0073e9SAndroid Build Coastguard Worker                path = os.path.join(path, appauthor, appname)
116*da0073e9SAndroid Build Coastguard Worker            else:
117*da0073e9SAndroid Build Coastguard Worker                path = os.path.join(path, appname)
118*da0073e9SAndroid Build Coastguard Worker    elif system == "darwin":
119*da0073e9SAndroid Build Coastguard Worker        path = os.path.expanduser("~/Library/Application Support/")
120*da0073e9SAndroid Build Coastguard Worker        if appname:
121*da0073e9SAndroid Build Coastguard Worker            path = os.path.join(path, appname)
122*da0073e9SAndroid Build Coastguard Worker    else:
123*da0073e9SAndroid Build Coastguard Worker        path = os.getenv("XDG_DATA_HOME", os.path.expanduser("~/.local/share"))
124*da0073e9SAndroid Build Coastguard Worker        if appname:
125*da0073e9SAndroid Build Coastguard Worker            path = os.path.join(path, appname)
126*da0073e9SAndroid Build Coastguard Worker    if appname and version:
127*da0073e9SAndroid Build Coastguard Worker        path = os.path.join(path, version)
128*da0073e9SAndroid Build Coastguard Worker    return path
129*da0073e9SAndroid Build Coastguard Worker
130*da0073e9SAndroid Build Coastguard Worker
131*da0073e9SAndroid Build Coastguard Workerdef site_data_dir(appname=None, appauthor=None, version=None, multipath=False):
132*da0073e9SAndroid Build Coastguard Worker    r"""Return full path to the user-shared data dir for this application.
133*da0073e9SAndroid Build Coastguard Worker
134*da0073e9SAndroid Build Coastguard Worker        "appname" is the name of application.
135*da0073e9SAndroid Build Coastguard Worker            If None, just the system directory is returned.
136*da0073e9SAndroid Build Coastguard Worker        "appauthor" (only used on Windows) is the name of the
137*da0073e9SAndroid Build Coastguard Worker            appauthor or distributing body for this application. Typically
138*da0073e9SAndroid Build Coastguard Worker            it is the owning company name. This falls back to appname. You may
139*da0073e9SAndroid Build Coastguard Worker            pass False to disable it.
140*da0073e9SAndroid Build Coastguard Worker        "version" is an optional version path element to append to the
141*da0073e9SAndroid Build Coastguard Worker            path. You might want to use this if you want multiple versions
142*da0073e9SAndroid Build Coastguard Worker            of your app to be able to run independently. If used, this
143*da0073e9SAndroid Build Coastguard Worker            would typically be "<major>.<minor>".
144*da0073e9SAndroid Build Coastguard Worker            Only applied when appname is present.
145*da0073e9SAndroid Build Coastguard Worker        "multipath" is an optional parameter only applicable to *nix
146*da0073e9SAndroid Build Coastguard Worker            which indicates that the entire list of data dirs should be
147*da0073e9SAndroid Build Coastguard Worker            returned. By default, the first item from XDG_DATA_DIRS is
148*da0073e9SAndroid Build Coastguard Worker            returned, or '/usr/local/share/<AppName>',
149*da0073e9SAndroid Build Coastguard Worker            if XDG_DATA_DIRS is not set
150*da0073e9SAndroid Build Coastguard Worker
151*da0073e9SAndroid Build Coastguard Worker    Typical site data directories are:
152*da0073e9SAndroid Build Coastguard Worker        Mac OS X:   /Library/Application Support/<AppName>
153*da0073e9SAndroid Build Coastguard Worker        Unix:       /usr/local/share/<AppName> or /usr/share/<AppName>
154*da0073e9SAndroid Build Coastguard Worker        Win XP:     C:\Documents and Settings\All Users\Application Data\<AppAuthor>\<AppName>
155*da0073e9SAndroid Build Coastguard Worker        Vista:      (Fail! "C:\ProgramData" is a hidden *system* directory on Vista.)
156*da0073e9SAndroid Build Coastguard Worker        Win 7:      C:\ProgramData\<AppAuthor>\<AppName>   # Hidden, but writeable on Win 7.
157*da0073e9SAndroid Build Coastguard Worker
158*da0073e9SAndroid Build Coastguard Worker    For Unix, this is using the $XDG_DATA_DIRS[0] default.
159*da0073e9SAndroid Build Coastguard Worker
160*da0073e9SAndroid Build Coastguard Worker    WARNING: Do not use this on Windows. See the Vista-Fail note above for why.
161*da0073e9SAndroid Build Coastguard Worker    """
162*da0073e9SAndroid Build Coastguard Worker    if system == "win32":
163*da0073e9SAndroid Build Coastguard Worker        if appauthor is None:
164*da0073e9SAndroid Build Coastguard Worker            appauthor = appname
165*da0073e9SAndroid Build Coastguard Worker        path = os.path.normpath(_get_win_folder("CSIDL_COMMON_APPDATA"))
166*da0073e9SAndroid Build Coastguard Worker        if appname:
167*da0073e9SAndroid Build Coastguard Worker            if appauthor is not False:
168*da0073e9SAndroid Build Coastguard Worker                path = os.path.join(path, appauthor, appname)
169*da0073e9SAndroid Build Coastguard Worker            else:
170*da0073e9SAndroid Build Coastguard Worker                path = os.path.join(path, appname)
171*da0073e9SAndroid Build Coastguard Worker    elif system == "darwin":
172*da0073e9SAndroid Build Coastguard Worker        path = os.path.expanduser("/Library/Application Support")
173*da0073e9SAndroid Build Coastguard Worker        if appname:
174*da0073e9SAndroid Build Coastguard Worker            path = os.path.join(path, appname)
175*da0073e9SAndroid Build Coastguard Worker    else:
176*da0073e9SAndroid Build Coastguard Worker        # XDG default for $XDG_DATA_DIRS
177*da0073e9SAndroid Build Coastguard Worker        # only first, if multipath is False
178*da0073e9SAndroid Build Coastguard Worker        path = os.getenv(
179*da0073e9SAndroid Build Coastguard Worker            "XDG_DATA_DIRS", os.pathsep.join(["/usr/local/share", "/usr/share"])
180*da0073e9SAndroid Build Coastguard Worker        )
181*da0073e9SAndroid Build Coastguard Worker        pathlist = [
182*da0073e9SAndroid Build Coastguard Worker            os.path.expanduser(x.rstrip(os.sep)) for x in path.split(os.pathsep)
183*da0073e9SAndroid Build Coastguard Worker        ]
184*da0073e9SAndroid Build Coastguard Worker        if appname:
185*da0073e9SAndroid Build Coastguard Worker            if version:
186*da0073e9SAndroid Build Coastguard Worker                appname = os.path.join(appname, version)
187*da0073e9SAndroid Build Coastguard Worker            pathlist = [os.sep.join([x, appname]) for x in pathlist]
188*da0073e9SAndroid Build Coastguard Worker
189*da0073e9SAndroid Build Coastguard Worker        if multipath:
190*da0073e9SAndroid Build Coastguard Worker            path = os.pathsep.join(pathlist)
191*da0073e9SAndroid Build Coastguard Worker        else:
192*da0073e9SAndroid Build Coastguard Worker            path = pathlist[0]
193*da0073e9SAndroid Build Coastguard Worker        return path
194*da0073e9SAndroid Build Coastguard Worker
195*da0073e9SAndroid Build Coastguard Worker    if appname and version:
196*da0073e9SAndroid Build Coastguard Worker        path = os.path.join(path, version)
197*da0073e9SAndroid Build Coastguard Worker    return path
198*da0073e9SAndroid Build Coastguard Worker
199*da0073e9SAndroid Build Coastguard Worker
200*da0073e9SAndroid Build Coastguard Workerdef user_config_dir(appname=None, appauthor=None, version=None, roaming=False):
201*da0073e9SAndroid Build Coastguard Worker    r"""Return full path to the user-specific config dir for this application.
202*da0073e9SAndroid Build Coastguard Worker
203*da0073e9SAndroid Build Coastguard Worker        "appname" is the name of application.
204*da0073e9SAndroid Build Coastguard Worker            If None, just the system directory is returned.
205*da0073e9SAndroid Build Coastguard Worker        "appauthor" (only used on Windows) is the name of the
206*da0073e9SAndroid Build Coastguard Worker            appauthor or distributing body for this application. Typically
207*da0073e9SAndroid Build Coastguard Worker            it is the owning company name. This falls back to appname. You may
208*da0073e9SAndroid Build Coastguard Worker            pass False to disable it.
209*da0073e9SAndroid Build Coastguard Worker        "version" is an optional version path element to append to the
210*da0073e9SAndroid Build Coastguard Worker            path. You might want to use this if you want multiple versions
211*da0073e9SAndroid Build Coastguard Worker            of your app to be able to run independently. If used, this
212*da0073e9SAndroid Build Coastguard Worker            would typically be "<major>.<minor>".
213*da0073e9SAndroid Build Coastguard Worker            Only applied when appname is present.
214*da0073e9SAndroid Build Coastguard Worker        "roaming" (boolean, default False) can be set True to use the Windows
215*da0073e9SAndroid Build Coastguard Worker            roaming appdata directory. That means that for users on a Windows
216*da0073e9SAndroid Build Coastguard Worker            network setup for roaming profiles, this user data will be
217*da0073e9SAndroid Build Coastguard Worker            sync'd on login. See
218*da0073e9SAndroid Build Coastguard Worker            <http://technet.microsoft.com/en-us/library/cc766489(WS.10).aspx>
219*da0073e9SAndroid Build Coastguard Worker            for a discussion of issues.
220*da0073e9SAndroid Build Coastguard Worker
221*da0073e9SAndroid Build Coastguard Worker    Typical user config directories are:
222*da0073e9SAndroid Build Coastguard Worker        Mac OS X:               ~/Library/Preferences/<AppName>
223*da0073e9SAndroid Build Coastguard Worker        Unix:                   ~/.config/<AppName>     # or in $XDG_CONFIG_HOME, if defined
224*da0073e9SAndroid Build Coastguard Worker        Win *:                  same as user_data_dir
225*da0073e9SAndroid Build Coastguard Worker
226*da0073e9SAndroid Build Coastguard Worker    For Unix, we follow the XDG spec and support $XDG_CONFIG_HOME.
227*da0073e9SAndroid Build Coastguard Worker    That means, by default "~/.config/<AppName>".
228*da0073e9SAndroid Build Coastguard Worker    """
229*da0073e9SAndroid Build Coastguard Worker    if system == "win32":
230*da0073e9SAndroid Build Coastguard Worker        path = user_data_dir(appname, appauthor, None, roaming)
231*da0073e9SAndroid Build Coastguard Worker    elif system == "darwin":
232*da0073e9SAndroid Build Coastguard Worker        path = os.path.expanduser("~/Library/Preferences/")
233*da0073e9SAndroid Build Coastguard Worker        if appname:
234*da0073e9SAndroid Build Coastguard Worker            path = os.path.join(path, appname)
235*da0073e9SAndroid Build Coastguard Worker    else:
236*da0073e9SAndroid Build Coastguard Worker        path = os.getenv("XDG_CONFIG_HOME", os.path.expanduser("~/.config"))
237*da0073e9SAndroid Build Coastguard Worker        if appname:
238*da0073e9SAndroid Build Coastguard Worker            path = os.path.join(path, appname)
239*da0073e9SAndroid Build Coastguard Worker    if appname and version:
240*da0073e9SAndroid Build Coastguard Worker        path = os.path.join(path, version)
241*da0073e9SAndroid Build Coastguard Worker    return path
242*da0073e9SAndroid Build Coastguard Worker
243*da0073e9SAndroid Build Coastguard Worker
244*da0073e9SAndroid Build Coastguard Workerdef site_config_dir(appname=None, appauthor=None, version=None, multipath=False):
245*da0073e9SAndroid Build Coastguard Worker    r"""Return full path to the user-shared data dir for this application.
246*da0073e9SAndroid Build Coastguard Worker
247*da0073e9SAndroid Build Coastguard Worker        "appname" is the name of application.
248*da0073e9SAndroid Build Coastguard Worker            If None, just the system directory is returned.
249*da0073e9SAndroid Build Coastguard Worker        "appauthor" (only used on Windows) is the name of the
250*da0073e9SAndroid Build Coastguard Worker            appauthor or distributing body for this application. Typically
251*da0073e9SAndroid Build Coastguard Worker            it is the owning company name. This falls back to appname. You may
252*da0073e9SAndroid Build Coastguard Worker            pass False to disable it.
253*da0073e9SAndroid Build Coastguard Worker        "version" is an optional version path element to append to the
254*da0073e9SAndroid Build Coastguard Worker            path. You might want to use this if you want multiple versions
255*da0073e9SAndroid Build Coastguard Worker            of your app to be able to run independently. If used, this
256*da0073e9SAndroid Build Coastguard Worker            would typically be "<major>.<minor>".
257*da0073e9SAndroid Build Coastguard Worker            Only applied when appname is present.
258*da0073e9SAndroid Build Coastguard Worker        "multipath" is an optional parameter only applicable to *nix
259*da0073e9SAndroid Build Coastguard Worker            which indicates that the entire list of config dirs should be
260*da0073e9SAndroid Build Coastguard Worker            returned. By default, the first item from XDG_CONFIG_DIRS is
261*da0073e9SAndroid Build Coastguard Worker            returned, or '/etc/xdg/<AppName>', if XDG_CONFIG_DIRS is not set
262*da0073e9SAndroid Build Coastguard Worker
263*da0073e9SAndroid Build Coastguard Worker    Typical site config directories are:
264*da0073e9SAndroid Build Coastguard Worker        Mac OS X:   same as site_data_dir
265*da0073e9SAndroid Build Coastguard Worker        Unix:       /etc/xdg/<AppName> or $XDG_CONFIG_DIRS[i]/<AppName> for each value in
266*da0073e9SAndroid Build Coastguard Worker                    $XDG_CONFIG_DIRS
267*da0073e9SAndroid Build Coastguard Worker        Win *:      same as site_data_dir
268*da0073e9SAndroid Build Coastguard Worker        Vista:      (Fail! "C:\ProgramData" is a hidden *system* directory on Vista.)
269*da0073e9SAndroid Build Coastguard Worker
270*da0073e9SAndroid Build Coastguard Worker    For Unix, this is using the $XDG_CONFIG_DIRS[0] default, if multipath=False
271*da0073e9SAndroid Build Coastguard Worker
272*da0073e9SAndroid Build Coastguard Worker    WARNING: Do not use this on Windows. See the Vista-Fail note above for why.
273*da0073e9SAndroid Build Coastguard Worker    """
274*da0073e9SAndroid Build Coastguard Worker    if system == "win32":
275*da0073e9SAndroid Build Coastguard Worker        path = site_data_dir(appname, appauthor)
276*da0073e9SAndroid Build Coastguard Worker        if appname and version:
277*da0073e9SAndroid Build Coastguard Worker            path = os.path.join(path, version)
278*da0073e9SAndroid Build Coastguard Worker    elif system == "darwin":
279*da0073e9SAndroid Build Coastguard Worker        path = os.path.expanduser("/Library/Preferences")
280*da0073e9SAndroid Build Coastguard Worker        if appname:
281*da0073e9SAndroid Build Coastguard Worker            path = os.path.join(path, appname)
282*da0073e9SAndroid Build Coastguard Worker    else:
283*da0073e9SAndroid Build Coastguard Worker        # XDG default for $XDG_CONFIG_DIRS
284*da0073e9SAndroid Build Coastguard Worker        # only first, if multipath is False
285*da0073e9SAndroid Build Coastguard Worker        path = os.getenv("XDG_CONFIG_DIRS", "/etc/xdg")
286*da0073e9SAndroid Build Coastguard Worker        pathlist = [
287*da0073e9SAndroid Build Coastguard Worker            os.path.expanduser(x.rstrip(os.sep)) for x in path.split(os.pathsep)
288*da0073e9SAndroid Build Coastguard Worker        ]
289*da0073e9SAndroid Build Coastguard Worker        if appname:
290*da0073e9SAndroid Build Coastguard Worker            if version:
291*da0073e9SAndroid Build Coastguard Worker                appname = os.path.join(appname, version)
292*da0073e9SAndroid Build Coastguard Worker            pathlist = [os.sep.join([x, appname]) for x in pathlist]
293*da0073e9SAndroid Build Coastguard Worker
294*da0073e9SAndroid Build Coastguard Worker        if multipath:
295*da0073e9SAndroid Build Coastguard Worker            path = os.pathsep.join(pathlist)
296*da0073e9SAndroid Build Coastguard Worker        else:
297*da0073e9SAndroid Build Coastguard Worker            path = pathlist[0]
298*da0073e9SAndroid Build Coastguard Worker    return path
299*da0073e9SAndroid Build Coastguard Worker
300*da0073e9SAndroid Build Coastguard Worker
301*da0073e9SAndroid Build Coastguard Workerdef user_cache_dir(appname=None, appauthor=None, version=None, opinion=True):
302*da0073e9SAndroid Build Coastguard Worker    r"""Return full path to the user-specific cache dir for this application.
303*da0073e9SAndroid Build Coastguard Worker
304*da0073e9SAndroid Build Coastguard Worker        "appname" is the name of application.
305*da0073e9SAndroid Build Coastguard Worker            If None, just the system directory is returned.
306*da0073e9SAndroid Build Coastguard Worker        "appauthor" (only used on Windows) is the name of the
307*da0073e9SAndroid Build Coastguard Worker            appauthor or distributing body for this application. Typically
308*da0073e9SAndroid Build Coastguard Worker            it is the owning company name. This falls back to appname. You may
309*da0073e9SAndroid Build Coastguard Worker            pass False to disable it.
310*da0073e9SAndroid Build Coastguard Worker        "version" is an optional version path element to append to the
311*da0073e9SAndroid Build Coastguard Worker            path. You might want to use this if you want multiple versions
312*da0073e9SAndroid Build Coastguard Worker            of your app to be able to run independently. If used, this
313*da0073e9SAndroid Build Coastguard Worker            would typically be "<major>.<minor>".
314*da0073e9SAndroid Build Coastguard Worker            Only applied when appname is present.
315*da0073e9SAndroid Build Coastguard Worker        "opinion" (boolean) can be False to disable the appending of
316*da0073e9SAndroid Build Coastguard Worker            "Cache" to the base app data dir for Windows. See
317*da0073e9SAndroid Build Coastguard Worker            discussion below.
318*da0073e9SAndroid Build Coastguard Worker
319*da0073e9SAndroid Build Coastguard Worker    Typical user cache directories are:
320*da0073e9SAndroid Build Coastguard Worker        Mac OS X:   ~/Library/Caches/<AppName>
321*da0073e9SAndroid Build Coastguard Worker        Unix:       ~/.cache/<AppName> (XDG default)
322*da0073e9SAndroid Build Coastguard Worker        Win XP:     C:\Documents and Settings\<username>\Local Settings\Application Data\<AppAuthor>\<AppName>\Cache
323*da0073e9SAndroid Build Coastguard Worker        Vista:      C:\Users\<username>\AppData\Local\<AppAuthor>\<AppName>\Cache
324*da0073e9SAndroid Build Coastguard Worker
325*da0073e9SAndroid Build Coastguard Worker    On Windows the only suggestion in the MSDN docs is that local settings go in
326*da0073e9SAndroid Build Coastguard Worker    the `CSIDL_LOCAL_APPDATA` directory. This is identical to the non-roaming
327*da0073e9SAndroid Build Coastguard Worker    app data dir (the default returned by `user_data_dir` above). Apps typically
328*da0073e9SAndroid Build Coastguard Worker    put cache data somewhere *under* the given dir here. Some examples:
329*da0073e9SAndroid Build Coastguard Worker        ...\Mozilla\Firefox\Profiles\<ProfileName>\Cache
330*da0073e9SAndroid Build Coastguard Worker        ...\Acme\SuperApp\Cache\1.0
331*da0073e9SAndroid Build Coastguard Worker    OPINION: This function appends "Cache" to the `CSIDL_LOCAL_APPDATA` value.
332*da0073e9SAndroid Build Coastguard Worker    This can be disabled with the `opinion=False` option.
333*da0073e9SAndroid Build Coastguard Worker    """
334*da0073e9SAndroid Build Coastguard Worker    if system == "win32":
335*da0073e9SAndroid Build Coastguard Worker        if appauthor is None:
336*da0073e9SAndroid Build Coastguard Worker            appauthor = appname
337*da0073e9SAndroid Build Coastguard Worker        path = os.path.normpath(_get_win_folder("CSIDL_LOCAL_APPDATA"))
338*da0073e9SAndroid Build Coastguard Worker        if appname:
339*da0073e9SAndroid Build Coastguard Worker            if appauthor is not False:
340*da0073e9SAndroid Build Coastguard Worker                path = os.path.join(path, appauthor, appname)
341*da0073e9SAndroid Build Coastguard Worker            else:
342*da0073e9SAndroid Build Coastguard Worker                path = os.path.join(path, appname)
343*da0073e9SAndroid Build Coastguard Worker            if opinion:
344*da0073e9SAndroid Build Coastguard Worker                path = os.path.join(path, "Cache")
345*da0073e9SAndroid Build Coastguard Worker    elif system == "darwin":
346*da0073e9SAndroid Build Coastguard Worker        path = os.path.expanduser("~/Library/Caches")
347*da0073e9SAndroid Build Coastguard Worker        if appname:
348*da0073e9SAndroid Build Coastguard Worker            path = os.path.join(path, appname)
349*da0073e9SAndroid Build Coastguard Worker    else:
350*da0073e9SAndroid Build Coastguard Worker        path = os.getenv("XDG_CACHE_HOME", os.path.expanduser("~/.cache"))
351*da0073e9SAndroid Build Coastguard Worker        if appname:
352*da0073e9SAndroid Build Coastguard Worker            path = os.path.join(path, appname)
353*da0073e9SAndroid Build Coastguard Worker    if appname and version:
354*da0073e9SAndroid Build Coastguard Worker        path = os.path.join(path, version)
355*da0073e9SAndroid Build Coastguard Worker    return path
356*da0073e9SAndroid Build Coastguard Worker
357*da0073e9SAndroid Build Coastguard Worker
358*da0073e9SAndroid Build Coastguard Workerdef user_state_dir(appname=None, appauthor=None, version=None, roaming=False):
359*da0073e9SAndroid Build Coastguard Worker    r"""Return full path to the user-specific state dir for this application.
360*da0073e9SAndroid Build Coastguard Worker
361*da0073e9SAndroid Build Coastguard Worker        "appname" is the name of application.
362*da0073e9SAndroid Build Coastguard Worker            If None, just the system directory is returned.
363*da0073e9SAndroid Build Coastguard Worker        "appauthor" (only used on Windows) is the name of the
364*da0073e9SAndroid Build Coastguard Worker            appauthor or distributing body for this application. Typically
365*da0073e9SAndroid Build Coastguard Worker            it is the owning company name. This falls back to appname. You may
366*da0073e9SAndroid Build Coastguard Worker            pass False to disable it.
367*da0073e9SAndroid Build Coastguard Worker        "version" is an optional version path element to append to the
368*da0073e9SAndroid Build Coastguard Worker            path. You might want to use this if you want multiple versions
369*da0073e9SAndroid Build Coastguard Worker            of your app to be able to run independently. If used, this
370*da0073e9SAndroid Build Coastguard Worker            would typically be "<major>.<minor>".
371*da0073e9SAndroid Build Coastguard Worker            Only applied when appname is present.
372*da0073e9SAndroid Build Coastguard Worker        "roaming" (boolean, default False) can be set True to use the Windows
373*da0073e9SAndroid Build Coastguard Worker            roaming appdata directory. That means that for users on a Windows
374*da0073e9SAndroid Build Coastguard Worker            network setup for roaming profiles, this user data will be
375*da0073e9SAndroid Build Coastguard Worker            sync'd on login. See
376*da0073e9SAndroid Build Coastguard Worker            <http://technet.microsoft.com/en-us/library/cc766489(WS.10).aspx>
377*da0073e9SAndroid Build Coastguard Worker            for a discussion of issues.
378*da0073e9SAndroid Build Coastguard Worker
379*da0073e9SAndroid Build Coastguard Worker    Typical user state directories are:
380*da0073e9SAndroid Build Coastguard Worker        Mac OS X:  same as user_data_dir
381*da0073e9SAndroid Build Coastguard Worker        Unix:      ~/.local/state/<AppName>   # or in $XDG_STATE_HOME, if defined
382*da0073e9SAndroid Build Coastguard Worker        Win *:     same as user_data_dir
383*da0073e9SAndroid Build Coastguard Worker
384*da0073e9SAndroid Build Coastguard Worker    For Unix, we follow this Debian proposal <https://wiki.debian.org/XDGBaseDirectorySpecification#state>
385*da0073e9SAndroid Build Coastguard Worker    to extend the XDG spec and support $XDG_STATE_HOME.
386*da0073e9SAndroid Build Coastguard Worker
387*da0073e9SAndroid Build Coastguard Worker    That means, by default "~/.local/state/<AppName>".
388*da0073e9SAndroid Build Coastguard Worker    """
389*da0073e9SAndroid Build Coastguard Worker    if system in ["win32", "darwin"]:
390*da0073e9SAndroid Build Coastguard Worker        path = user_data_dir(appname, appauthor, None, roaming)
391*da0073e9SAndroid Build Coastguard Worker    else:
392*da0073e9SAndroid Build Coastguard Worker        path = os.getenv("XDG_STATE_HOME", os.path.expanduser("~/.local/state"))
393*da0073e9SAndroid Build Coastguard Worker        if appname:
394*da0073e9SAndroid Build Coastguard Worker            path = os.path.join(path, appname)
395*da0073e9SAndroid Build Coastguard Worker    if appname and version:
396*da0073e9SAndroid Build Coastguard Worker        path = os.path.join(path, version)
397*da0073e9SAndroid Build Coastguard Worker    return path
398*da0073e9SAndroid Build Coastguard Worker
399*da0073e9SAndroid Build Coastguard Worker
400*da0073e9SAndroid Build Coastguard Workerdef user_log_dir(appname=None, appauthor=None, version=None, opinion=True):
401*da0073e9SAndroid Build Coastguard Worker    r"""Return full path to the user-specific log dir for this application.
402*da0073e9SAndroid Build Coastguard Worker
403*da0073e9SAndroid Build Coastguard Worker        "appname" is the name of application.
404*da0073e9SAndroid Build Coastguard Worker            If None, just the system directory is returned.
405*da0073e9SAndroid Build Coastguard Worker        "appauthor" (only used on Windows) is the name of the
406*da0073e9SAndroid Build Coastguard Worker            appauthor or distributing body for this application. Typically
407*da0073e9SAndroid Build Coastguard Worker            it is the owning company name. This falls back to appname. You may
408*da0073e9SAndroid Build Coastguard Worker            pass False to disable it.
409*da0073e9SAndroid Build Coastguard Worker        "version" is an optional version path element to append to the
410*da0073e9SAndroid Build Coastguard Worker            path. You might want to use this if you want multiple versions
411*da0073e9SAndroid Build Coastguard Worker            of your app to be able to run independently. If used, this
412*da0073e9SAndroid Build Coastguard Worker            would typically be "<major>.<minor>".
413*da0073e9SAndroid Build Coastguard Worker            Only applied when appname is present.
414*da0073e9SAndroid Build Coastguard Worker        "opinion" (boolean) can be False to disable the appending of
415*da0073e9SAndroid Build Coastguard Worker            "Logs" to the base app data dir for Windows, and "log" to the
416*da0073e9SAndroid Build Coastguard Worker            base cache dir for Unix. See discussion below.
417*da0073e9SAndroid Build Coastguard Worker
418*da0073e9SAndroid Build Coastguard Worker    Typical user log directories are:
419*da0073e9SAndroid Build Coastguard Worker        Mac OS X:   ~/Library/Logs/<AppName>
420*da0073e9SAndroid Build Coastguard Worker        Unix:       ~/.cache/<AppName>/log  # or under $XDG_CACHE_HOME if defined
421*da0073e9SAndroid Build Coastguard Worker        Win XP:     C:\Documents and Settings\<username>\Local Settings\Application Data\<AppAuthor>\<AppName>\Logs
422*da0073e9SAndroid Build Coastguard Worker        Vista:      C:\Users\<username>\AppData\Local\<AppAuthor>\<AppName>\Logs
423*da0073e9SAndroid Build Coastguard Worker
424*da0073e9SAndroid Build Coastguard Worker    On Windows the only suggestion in the MSDN docs is that local settings
425*da0073e9SAndroid Build Coastguard Worker    go in the `CSIDL_LOCAL_APPDATA` directory. (Note: I'm interested in
426*da0073e9SAndroid Build Coastguard Worker    examples of what some windows apps use for a logs dir.)
427*da0073e9SAndroid Build Coastguard Worker
428*da0073e9SAndroid Build Coastguard Worker    OPINION: This function appends "Logs" to the `CSIDL_LOCAL_APPDATA`
429*da0073e9SAndroid Build Coastguard Worker    value for Windows and appends "log" to the user cache dir for Unix.
430*da0073e9SAndroid Build Coastguard Worker    This can be disabled with the `opinion=False` option.
431*da0073e9SAndroid Build Coastguard Worker    """
432*da0073e9SAndroid Build Coastguard Worker    if system == "darwin":
433*da0073e9SAndroid Build Coastguard Worker        path = os.path.join(os.path.expanduser("~/Library/Logs"), appname)
434*da0073e9SAndroid Build Coastguard Worker    elif system == "win32":
435*da0073e9SAndroid Build Coastguard Worker        path = user_data_dir(appname, appauthor, version)
436*da0073e9SAndroid Build Coastguard Worker        version = False
437*da0073e9SAndroid Build Coastguard Worker        if opinion:
438*da0073e9SAndroid Build Coastguard Worker            path = os.path.join(path, "Logs")
439*da0073e9SAndroid Build Coastguard Worker    else:
440*da0073e9SAndroid Build Coastguard Worker        path = user_cache_dir(appname, appauthor, version)
441*da0073e9SAndroid Build Coastguard Worker        version = False
442*da0073e9SAndroid Build Coastguard Worker        if opinion:
443*da0073e9SAndroid Build Coastguard Worker            path = os.path.join(path, "log")
444*da0073e9SAndroid Build Coastguard Worker    if appname and version:
445*da0073e9SAndroid Build Coastguard Worker        path = os.path.join(path, version)
446*da0073e9SAndroid Build Coastguard Worker    return path
447*da0073e9SAndroid Build Coastguard Worker
448*da0073e9SAndroid Build Coastguard Worker
449*da0073e9SAndroid Build Coastguard Workerclass AppDirs(object):
450*da0073e9SAndroid Build Coastguard Worker    """Convenience wrapper for getting application dirs."""
451*da0073e9SAndroid Build Coastguard Worker
452*da0073e9SAndroid Build Coastguard Worker    def __init__(
453*da0073e9SAndroid Build Coastguard Worker        self, appname=None, appauthor=None, version=None, roaming=False, multipath=False
454*da0073e9SAndroid Build Coastguard Worker    ):
455*da0073e9SAndroid Build Coastguard Worker        self.appname = appname
456*da0073e9SAndroid Build Coastguard Worker        self.appauthor = appauthor
457*da0073e9SAndroid Build Coastguard Worker        self.version = version
458*da0073e9SAndroid Build Coastguard Worker        self.roaming = roaming
459*da0073e9SAndroid Build Coastguard Worker        self.multipath = multipath
460*da0073e9SAndroid Build Coastguard Worker
461*da0073e9SAndroid Build Coastguard Worker    @property
462*da0073e9SAndroid Build Coastguard Worker    def user_data_dir(self):
463*da0073e9SAndroid Build Coastguard Worker        return user_data_dir(
464*da0073e9SAndroid Build Coastguard Worker            self.appname, self.appauthor, version=self.version, roaming=self.roaming
465*da0073e9SAndroid Build Coastguard Worker        )
466*da0073e9SAndroid Build Coastguard Worker
467*da0073e9SAndroid Build Coastguard Worker    @property
468*da0073e9SAndroid Build Coastguard Worker    def site_data_dir(self):
469*da0073e9SAndroid Build Coastguard Worker        return site_data_dir(
470*da0073e9SAndroid Build Coastguard Worker            self.appname, self.appauthor, version=self.version, multipath=self.multipath
471*da0073e9SAndroid Build Coastguard Worker        )
472*da0073e9SAndroid Build Coastguard Worker
473*da0073e9SAndroid Build Coastguard Worker    @property
474*da0073e9SAndroid Build Coastguard Worker    def user_config_dir(self):
475*da0073e9SAndroid Build Coastguard Worker        return user_config_dir(
476*da0073e9SAndroid Build Coastguard Worker            self.appname, self.appauthor, version=self.version, roaming=self.roaming
477*da0073e9SAndroid Build Coastguard Worker        )
478*da0073e9SAndroid Build Coastguard Worker
479*da0073e9SAndroid Build Coastguard Worker    @property
480*da0073e9SAndroid Build Coastguard Worker    def site_config_dir(self):
481*da0073e9SAndroid Build Coastguard Worker        return site_config_dir(
482*da0073e9SAndroid Build Coastguard Worker            self.appname, self.appauthor, version=self.version, multipath=self.multipath
483*da0073e9SAndroid Build Coastguard Worker        )
484*da0073e9SAndroid Build Coastguard Worker
485*da0073e9SAndroid Build Coastguard Worker    @property
486*da0073e9SAndroid Build Coastguard Worker    def user_cache_dir(self):
487*da0073e9SAndroid Build Coastguard Worker        return user_cache_dir(self.appname, self.appauthor, version=self.version)
488*da0073e9SAndroid Build Coastguard Worker
489*da0073e9SAndroid Build Coastguard Worker    @property
490*da0073e9SAndroid Build Coastguard Worker    def user_state_dir(self):
491*da0073e9SAndroid Build Coastguard Worker        return user_state_dir(self.appname, self.appauthor, version=self.version)
492*da0073e9SAndroid Build Coastguard Worker
493*da0073e9SAndroid Build Coastguard Worker    @property
494*da0073e9SAndroid Build Coastguard Worker    def user_log_dir(self):
495*da0073e9SAndroid Build Coastguard Worker        return user_log_dir(self.appname, self.appauthor, version=self.version)
496*da0073e9SAndroid Build Coastguard Worker
497*da0073e9SAndroid Build Coastguard Worker
498*da0073e9SAndroid Build Coastguard Worker# ---- internal support stuff
499*da0073e9SAndroid Build Coastguard Worker
500*da0073e9SAndroid Build Coastguard Worker
501*da0073e9SAndroid Build Coastguard Workerdef _get_win_folder_from_registry(csidl_name):
502*da0073e9SAndroid Build Coastguard Worker    """This is a fallback technique at best. I'm not sure if using the
503*da0073e9SAndroid Build Coastguard Worker    registry for this guarantees us the correct answer for all CSIDL_*
504*da0073e9SAndroid Build Coastguard Worker    names.
505*da0073e9SAndroid Build Coastguard Worker    """
506*da0073e9SAndroid Build Coastguard Worker    import winreg as _winreg
507*da0073e9SAndroid Build Coastguard Worker
508*da0073e9SAndroid Build Coastguard Worker    shell_folder_name = {
509*da0073e9SAndroid Build Coastguard Worker        "CSIDL_APPDATA": "AppData",
510*da0073e9SAndroid Build Coastguard Worker        "CSIDL_COMMON_APPDATA": "Common AppData",
511*da0073e9SAndroid Build Coastguard Worker        "CSIDL_LOCAL_APPDATA": "Local AppData",
512*da0073e9SAndroid Build Coastguard Worker    }[csidl_name]
513*da0073e9SAndroid Build Coastguard Worker
514*da0073e9SAndroid Build Coastguard Worker    key = _winreg.OpenKey(
515*da0073e9SAndroid Build Coastguard Worker        _winreg.HKEY_CURRENT_USER,
516*da0073e9SAndroid Build Coastguard Worker        r"Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders",
517*da0073e9SAndroid Build Coastguard Worker    )
518*da0073e9SAndroid Build Coastguard Worker    dir, type = _winreg.QueryValueEx(key, shell_folder_name)
519*da0073e9SAndroid Build Coastguard Worker    return dir
520*da0073e9SAndroid Build Coastguard Worker
521*da0073e9SAndroid Build Coastguard Worker
522*da0073e9SAndroid Build Coastguard Workerdef _get_win_folder_with_pywin32(csidl_name):
523*da0073e9SAndroid Build Coastguard Worker    from win32com.shell import shell, shellcon
524*da0073e9SAndroid Build Coastguard Worker
525*da0073e9SAndroid Build Coastguard Worker    dir = shell.SHGetFolderPath(0, getattr(shellcon, csidl_name), 0, 0)
526*da0073e9SAndroid Build Coastguard Worker    # Try to make this a unicode path because SHGetFolderPath does
527*da0073e9SAndroid Build Coastguard Worker    # not return unicode strings when there is unicode data in the
528*da0073e9SAndroid Build Coastguard Worker    # path.
529*da0073e9SAndroid Build Coastguard Worker    try:
530*da0073e9SAndroid Build Coastguard Worker        dir = unicode(dir)
531*da0073e9SAndroid Build Coastguard Worker
532*da0073e9SAndroid Build Coastguard Worker        # Downgrade to short path name if have highbit chars. See
533*da0073e9SAndroid Build Coastguard Worker        # <http://bugs.activestate.com/show_bug.cgi?id=85099>.
534*da0073e9SAndroid Build Coastguard Worker        has_high_char = False
535*da0073e9SAndroid Build Coastguard Worker        for c in dir:
536*da0073e9SAndroid Build Coastguard Worker            if ord(c) > 255:
537*da0073e9SAndroid Build Coastguard Worker                has_high_char = True
538*da0073e9SAndroid Build Coastguard Worker                break
539*da0073e9SAndroid Build Coastguard Worker        if has_high_char:
540*da0073e9SAndroid Build Coastguard Worker            try:
541*da0073e9SAndroid Build Coastguard Worker                import win32api
542*da0073e9SAndroid Build Coastguard Worker
543*da0073e9SAndroid Build Coastguard Worker                dir = win32api.GetShortPathName(dir)
544*da0073e9SAndroid Build Coastguard Worker            except ImportError:
545*da0073e9SAndroid Build Coastguard Worker                pass
546*da0073e9SAndroid Build Coastguard Worker    except UnicodeError:
547*da0073e9SAndroid Build Coastguard Worker        pass
548*da0073e9SAndroid Build Coastguard Worker    return dir
549*da0073e9SAndroid Build Coastguard Worker
550*da0073e9SAndroid Build Coastguard Worker
551*da0073e9SAndroid Build Coastguard Workerdef _get_win_folder_with_ctypes(csidl_name):
552*da0073e9SAndroid Build Coastguard Worker    import ctypes
553*da0073e9SAndroid Build Coastguard Worker
554*da0073e9SAndroid Build Coastguard Worker    csidl_const = {
555*da0073e9SAndroid Build Coastguard Worker        "CSIDL_APPDATA": 26,
556*da0073e9SAndroid Build Coastguard Worker        "CSIDL_COMMON_APPDATA": 35,
557*da0073e9SAndroid Build Coastguard Worker        "CSIDL_LOCAL_APPDATA": 28,
558*da0073e9SAndroid Build Coastguard Worker    }[csidl_name]
559*da0073e9SAndroid Build Coastguard Worker
560*da0073e9SAndroid Build Coastguard Worker    buf = ctypes.create_unicode_buffer(1024)
561*da0073e9SAndroid Build Coastguard Worker    ctypes.windll.shell32.SHGetFolderPathW(None, csidl_const, None, 0, buf)
562*da0073e9SAndroid Build Coastguard Worker
563*da0073e9SAndroid Build Coastguard Worker    # Downgrade to short path name if have highbit chars. See
564*da0073e9SAndroid Build Coastguard Worker    # <http://bugs.activestate.com/show_bug.cgi?id=85099>.
565*da0073e9SAndroid Build Coastguard Worker    has_high_char = False
566*da0073e9SAndroid Build Coastguard Worker    for c in buf:
567*da0073e9SAndroid Build Coastguard Worker        if ord(c) > 255:
568*da0073e9SAndroid Build Coastguard Worker            has_high_char = True
569*da0073e9SAndroid Build Coastguard Worker            break
570*da0073e9SAndroid Build Coastguard Worker    if has_high_char:
571*da0073e9SAndroid Build Coastguard Worker        buf2 = ctypes.create_unicode_buffer(1024)
572*da0073e9SAndroid Build Coastguard Worker        if ctypes.windll.kernel32.GetShortPathNameW(buf.value, buf2, 1024):
573*da0073e9SAndroid Build Coastguard Worker            buf = buf2
574*da0073e9SAndroid Build Coastguard Worker
575*da0073e9SAndroid Build Coastguard Worker    return buf.value
576*da0073e9SAndroid Build Coastguard Worker
577*da0073e9SAndroid Build Coastguard Worker
578*da0073e9SAndroid Build Coastguard Workerdef _get_win_folder_with_jna(csidl_name):
579*da0073e9SAndroid Build Coastguard Worker    import array
580*da0073e9SAndroid Build Coastguard Worker
581*da0073e9SAndroid Build Coastguard Worker    from com.sun import jna
582*da0073e9SAndroid Build Coastguard Worker    from com.sun.jna.platform import win32
583*da0073e9SAndroid Build Coastguard Worker
584*da0073e9SAndroid Build Coastguard Worker    buf_size = win32.WinDef.MAX_PATH * 2
585*da0073e9SAndroid Build Coastguard Worker    buf = array.zeros("c", buf_size)
586*da0073e9SAndroid Build Coastguard Worker    shell = win32.Shell32.INSTANCE
587*da0073e9SAndroid Build Coastguard Worker    shell.SHGetFolderPath(
588*da0073e9SAndroid Build Coastguard Worker        None,
589*da0073e9SAndroid Build Coastguard Worker        getattr(win32.ShlObj, csidl_name),
590*da0073e9SAndroid Build Coastguard Worker        None,
591*da0073e9SAndroid Build Coastguard Worker        win32.ShlObj.SHGFP_TYPE_CURRENT,
592*da0073e9SAndroid Build Coastguard Worker        buf,
593*da0073e9SAndroid Build Coastguard Worker    )
594*da0073e9SAndroid Build Coastguard Worker    dir = jna.Native.toString(buf.tostring()).rstrip("\0")
595*da0073e9SAndroid Build Coastguard Worker
596*da0073e9SAndroid Build Coastguard Worker    # Downgrade to short path name if have highbit chars. See
597*da0073e9SAndroid Build Coastguard Worker    # <http://bugs.activestate.com/show_bug.cgi?id=85099>.
598*da0073e9SAndroid Build Coastguard Worker    has_high_char = False
599*da0073e9SAndroid Build Coastguard Worker    for c in dir:
600*da0073e9SAndroid Build Coastguard Worker        if ord(c) > 255:
601*da0073e9SAndroid Build Coastguard Worker            has_high_char = True
602*da0073e9SAndroid Build Coastguard Worker            break
603*da0073e9SAndroid Build Coastguard Worker    if has_high_char:
604*da0073e9SAndroid Build Coastguard Worker        buf = array.zeros("c", buf_size)
605*da0073e9SAndroid Build Coastguard Worker        kernel = win32.Kernel32.INSTANCE
606*da0073e9SAndroid Build Coastguard Worker        if kernel.GetShortPathName(dir, buf, buf_size):
607*da0073e9SAndroid Build Coastguard Worker            dir = jna.Native.toString(buf.tostring()).rstrip("\0")
608*da0073e9SAndroid Build Coastguard Worker
609*da0073e9SAndroid Build Coastguard Worker    return dir
610*da0073e9SAndroid Build Coastguard Worker
611*da0073e9SAndroid Build Coastguard Worker
612*da0073e9SAndroid Build Coastguard Workerif system == "win32":
613*da0073e9SAndroid Build Coastguard Worker    try:
614*da0073e9SAndroid Build Coastguard Worker        import win32com.shell
615*da0073e9SAndroid Build Coastguard Worker
616*da0073e9SAndroid Build Coastguard Worker        _get_win_folder = _get_win_folder_with_pywin32
617*da0073e9SAndroid Build Coastguard Worker    except ImportError:
618*da0073e9SAndroid Build Coastguard Worker        try:
619*da0073e9SAndroid Build Coastguard Worker            from ctypes import windll
620*da0073e9SAndroid Build Coastguard Worker
621*da0073e9SAndroid Build Coastguard Worker            _get_win_folder = _get_win_folder_with_ctypes
622*da0073e9SAndroid Build Coastguard Worker        except ImportError:
623*da0073e9SAndroid Build Coastguard Worker            try:
624*da0073e9SAndroid Build Coastguard Worker                import com.sun.jna
625*da0073e9SAndroid Build Coastguard Worker
626*da0073e9SAndroid Build Coastguard Worker                _get_win_folder = _get_win_folder_with_jna
627*da0073e9SAndroid Build Coastguard Worker            except ImportError:
628*da0073e9SAndroid Build Coastguard Worker                _get_win_folder = _get_win_folder_from_registry
629*da0073e9SAndroid Build Coastguard Worker
630*da0073e9SAndroid Build Coastguard Worker
631*da0073e9SAndroid Build Coastguard Worker# ---- self test code
632*da0073e9SAndroid Build Coastguard Worker
633*da0073e9SAndroid Build Coastguard Workerif __name__ == "__main__":
634*da0073e9SAndroid Build Coastguard Worker    appname = "MyApp"
635*da0073e9SAndroid Build Coastguard Worker    appauthor = "MyCompany"
636*da0073e9SAndroid Build Coastguard Worker
637*da0073e9SAndroid Build Coastguard Worker    props = (
638*da0073e9SAndroid Build Coastguard Worker        "user_data_dir",
639*da0073e9SAndroid Build Coastguard Worker        "user_config_dir",
640*da0073e9SAndroid Build Coastguard Worker        "user_cache_dir",
641*da0073e9SAndroid Build Coastguard Worker        "user_state_dir",
642*da0073e9SAndroid Build Coastguard Worker        "user_log_dir",
643*da0073e9SAndroid Build Coastguard Worker        "site_data_dir",
644*da0073e9SAndroid Build Coastguard Worker        "site_config_dir",
645*da0073e9SAndroid Build Coastguard Worker    )
646*da0073e9SAndroid Build Coastguard Worker
647*da0073e9SAndroid Build Coastguard Worker    print(f"-- app dirs {__version__} --")
648*da0073e9SAndroid Build Coastguard Worker
649*da0073e9SAndroid Build Coastguard Worker    print("-- app dirs (with optional 'version')")
650*da0073e9SAndroid Build Coastguard Worker    dirs = AppDirs(appname, appauthor, version="1.0")
651*da0073e9SAndroid Build Coastguard Worker    for prop in props:
652*da0073e9SAndroid Build Coastguard Worker        print(f"{prop}: {getattr(dirs, prop)}")
653*da0073e9SAndroid Build Coastguard Worker
654*da0073e9SAndroid Build Coastguard Worker    print("\n-- app dirs (without optional 'version')")
655*da0073e9SAndroid Build Coastguard Worker    dirs = AppDirs(appname, appauthor)
656*da0073e9SAndroid Build Coastguard Worker    for prop in props:
657*da0073e9SAndroid Build Coastguard Worker        print(f"{prop}: {getattr(dirs, prop)}")
658*da0073e9SAndroid Build Coastguard Worker
659*da0073e9SAndroid Build Coastguard Worker    print("\n-- app dirs (without optional 'appauthor')")
660*da0073e9SAndroid Build Coastguard Worker    dirs = AppDirs(appname)
661*da0073e9SAndroid Build Coastguard Worker    for prop in props:
662*da0073e9SAndroid Build Coastguard Worker        print(f"{prop}: {getattr(dirs, prop)}")
663*da0073e9SAndroid Build Coastguard Worker
664*da0073e9SAndroid Build Coastguard Worker    print("\n-- app dirs (with disabled 'appauthor')")
665*da0073e9SAndroid Build Coastguard Worker    dirs = AppDirs(appname, appauthor=False)
666*da0073e9SAndroid Build Coastguard Worker    for prop in props:
667*da0073e9SAndroid Build Coastguard Worker        print(f"{prop}: {getattr(dirs, prop)}")
668