12 | 12 |
# - Mac OS X: http://developer.apple.com/documentation/MacOSX/Conceptual/BPFileSystem/index.html
|
13 | 13 |
# - XDG spec for Un*x: http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
|
14 | 14 |
|
15 | |
__version_info__ = (1, 3, 0)
|
|
15 |
__version_info__ = (1, 4, 0)
|
16 | 16 |
__version__ = '.'.join(map(str, __version_info__))
|
17 | 17 |
|
18 | 18 |
|
|
24 | 24 |
if PY3:
|
25 | 25 |
unicode = str
|
26 | 26 |
|
|
27 |
if sys.platform.startswith('java'):
|
|
28 |
import platform
|
|
29 |
os_name = platform.java_ver()[3][0]
|
|
30 |
if os_name.startswith('Windows'): # "Windows XP", "Windows 7", etc.
|
|
31 |
system = 'win32'
|
|
32 |
elif os_name.startswith('Mac'): # "Mac OS X", etc.
|
|
33 |
system = 'darwin'
|
|
34 |
else: # "Linux", "SunOS", "FreeBSD", etc.
|
|
35 |
# Setting this to "linux2" is not ideal, but only Windows or Mac
|
|
36 |
# are actually checked for and the rest of the module expects
|
|
37 |
# *sys.platform* style strings.
|
|
38 |
system = 'linux2'
|
|
39 |
else:
|
|
40 |
system = sys.platform
|
|
41 |
|
|
42 |
|
27 | 43 |
|
28 | 44 |
def user_data_dir(appname=None, appauthor=None, version=None, roaming=False):
|
29 | 45 |
r"""Return full path to the user-specific data dir for this application.
|
30 | 46 |
|
31 | 47 |
"appname" is the name of application.
|
32 | 48 |
If None, just the system directory is returned.
|
33 | |
"appauthor" (only required and used on Windows) is the name of the
|
|
49 |
"appauthor" (only used on Windows) is the name of the
|
34 | 50 |
appauthor or distributing body for this application. Typically
|
35 | |
it is the owning company name. This falls back to appname.
|
|
51 |
it is the owning company name. This falls back to appname. You may
|
|
52 |
pass False to disable it.
|
36 | 53 |
"version" is an optional version path element to append to the
|
37 | 54 |
path. You might want to use this if you want multiple versions
|
38 | 55 |
of your app to be able to run independently. If used, this
|
|
56 | 73 |
For Unix, we follow the XDG spec and support $XDG_DATA_HOME.
|
57 | 74 |
That means, by default "~/.local/share/<AppName>".
|
58 | 75 |
"""
|
59 | |
if sys.platform == "win32":
|
|
76 |
if system == "win32":
|
60 | 77 |
if appauthor is None:
|
61 | 78 |
appauthor = appname
|
62 | 79 |
const = roaming and "CSIDL_APPDATA" or "CSIDL_LOCAL_APPDATA"
|
63 | 80 |
path = os.path.normpath(_get_win_folder(const))
|
64 | 81 |
if appname:
|
65 | |
path = os.path.join(path, appauthor, appname)
|
66 | |
elif sys.platform == 'darwin':
|
|
82 |
if appauthor is not False:
|
|
83 |
path = os.path.join(path, appauthor, appname)
|
|
84 |
else:
|
|
85 |
path = os.path.join(path, appname)
|
|
86 |
elif system == 'darwin':
|
67 | 87 |
path = os.path.expanduser('~/Library/Application Support/')
|
68 | 88 |
if appname:
|
69 | 89 |
path = os.path.join(path, appname)
|
|
81 | 101 |
|
82 | 102 |
"appname" is the name of application.
|
83 | 103 |
If None, just the system directory is returned.
|
84 | |
"appauthor" (only required and used on Windows) is the name of the
|
|
104 |
"appauthor" (only used on Windows) is the name of the
|
85 | 105 |
appauthor or distributing body for this application. Typically
|
86 | |
it is the owning company name. This falls back to appname.
|
|
106 |
it is the owning company name. This falls back to appname. You may
|
|
107 |
pass False to disable it.
|
87 | 108 |
"version" is an optional version path element to append to the
|
88 | 109 |
path. You might want to use this if you want multiple versions
|
89 | 110 |
of your app to be able to run independently. If used, this
|
|
106 | 127 |
|
107 | 128 |
WARNING: Do not use this on Windows. See the Vista-Fail note above for why.
|
108 | 129 |
"""
|
109 | |
if sys.platform == "win32":
|
|
130 |
if system == "win32":
|
110 | 131 |
if appauthor is None:
|
111 | 132 |
appauthor = appname
|
112 | 133 |
path = os.path.normpath(_get_win_folder("CSIDL_COMMON_APPDATA"))
|
113 | 134 |
if appname:
|
114 | |
path = os.path.join(path, appauthor, appname)
|
115 | |
elif sys.platform == 'darwin':
|
|
135 |
if appauthor is not False:
|
|
136 |
path = os.path.join(path, appauthor, appname)
|
|
137 |
else:
|
|
138 |
path = os.path.join(path, appname)
|
|
139 |
elif system == 'darwin':
|
116 | 140 |
path = os.path.expanduser('/Library/Application Support')
|
117 | 141 |
if appname:
|
118 | 142 |
path = os.path.join(path, appname)
|
|
143 | 167 |
|
144 | 168 |
"appname" is the name of application.
|
145 | 169 |
If None, just the system directory is returned.
|
146 | |
"appauthor" (only required and used on Windows) is the name of the
|
|
170 |
"appauthor" (only used on Windows) is the name of the
|
147 | 171 |
appauthor or distributing body for this application. Typically
|
148 | |
it is the owning company name. This falls back to appname.
|
|
172 |
it is the owning company name. This falls back to appname. You may
|
|
173 |
pass False to disable it.
|
149 | 174 |
"version" is an optional version path element to append to the
|
150 | 175 |
path. You might want to use this if you want multiple versions
|
151 | 176 |
of your app to be able to run independently. If used, this
|
|
166 | 191 |
For Unix, we follow the XDG spec and support $XDG_CONFIG_HOME.
|
167 | 192 |
That means, by deafult "~/.config/<AppName>".
|
168 | 193 |
"""
|
169 | |
if sys.platform in ["win32", "darwin"]:
|
|
194 |
if system in ["win32", "darwin"]:
|
170 | 195 |
path = user_data_dir(appname, appauthor, None, roaming)
|
171 | 196 |
else:
|
172 | 197 |
path = os.getenv('XDG_CONFIG_HOME', os.path.expanduser("~/.config"))
|
|
182 | 207 |
|
183 | 208 |
"appname" is the name of application.
|
184 | 209 |
If None, just the system directory is returned.
|
185 | |
"appauthor" (only required and used on Windows) is the name of the
|
|
210 |
"appauthor" (only used on Windows) is the name of the
|
186 | 211 |
appauthor or distributing body for this application. Typically
|
187 | |
it is the owning company name. This falls back to appname.
|
|
212 |
it is the owning company name. This falls back to appname. You may
|
|
213 |
pass False to disable it.
|
188 | 214 |
"version" is an optional version path element to append to the
|
189 | 215 |
path. You might want to use this if you want multiple versions
|
190 | 216 |
of your app to be able to run independently. If used, this
|
|
206 | 232 |
|
207 | 233 |
WARNING: Do not use this on Windows. See the Vista-Fail note above for why.
|
208 | 234 |
"""
|
209 | |
if sys.platform in ["win32", "darwin"]:
|
|
235 |
if system in ["win32", "darwin"]:
|
210 | 236 |
path = site_data_dir(appname, appauthor)
|
211 | 237 |
if appname and version:
|
212 | 238 |
path = os.path.join(path, version)
|
|
232 | 258 |
|
233 | 259 |
"appname" is the name of application.
|
234 | 260 |
If None, just the system directory is returned.
|
235 | |
"appauthor" (only required and used on Windows) is the name of the
|
|
261 |
"appauthor" (only used on Windows) is the name of the
|
236 | 262 |
appauthor or distributing body for this application. Typically
|
237 | |
it is the owning company name. This falls back to appname.
|
|
263 |
it is the owning company name. This falls back to appname. You may
|
|
264 |
pass False to disable it.
|
238 | 265 |
"version" is an optional version path element to append to the
|
239 | 266 |
path. You might want to use this if you want multiple versions
|
240 | 267 |
of your app to be able to run independently. If used, this
|
|
259 | 286 |
OPINION: This function appends "Cache" to the `CSIDL_LOCAL_APPDATA` value.
|
260 | 287 |
This can be disabled with the `opinion=False` option.
|
261 | 288 |
"""
|
262 | |
if sys.platform == "win32":
|
|
289 |
if system == "win32":
|
263 | 290 |
if appauthor is None:
|
264 | 291 |
appauthor = appname
|
265 | 292 |
path = os.path.normpath(_get_win_folder("CSIDL_LOCAL_APPDATA"))
|
266 | 293 |
if appname:
|
267 | |
path = os.path.join(path, appauthor, appname)
|
|
294 |
if appauthor is not False:
|
|
295 |
path = os.path.join(path, appauthor, appname)
|
|
296 |
else:
|
|
297 |
path = os.path.join(path, appname)
|
268 | 298 |
if opinion:
|
269 | 299 |
path = os.path.join(path, "Cache")
|
270 | |
elif sys.platform == 'darwin':
|
|
300 |
elif system == 'darwin':
|
271 | 301 |
path = os.path.expanduser('~/Library/Caches')
|
272 | 302 |
if appname:
|
273 | 303 |
path = os.path.join(path, appname)
|
|
285 | 315 |
|
286 | 316 |
"appname" is the name of application.
|
287 | 317 |
If None, just the system directory is returned.
|
288 | |
"appauthor" (only required and used on Windows) is the name of the
|
|
318 |
"appauthor" (only used on Windows) is the name of the
|
289 | 319 |
appauthor or distributing body for this application. Typically
|
290 | |
it is the owning company name. This falls back to appname.
|
|
320 |
it is the owning company name. This falls back to appname. You may
|
|
321 |
pass False to disable it.
|
291 | 322 |
"version" is an optional version path element to append to the
|
292 | 323 |
path. You might want to use this if you want multiple versions
|
293 | 324 |
of your app to be able to run independently. If used, this
|
|
311 | 342 |
value for Windows and appends "log" to the user cache dir for Unix.
|
312 | 343 |
This can be disabled with the `opinion=False` option.
|
313 | 344 |
"""
|
314 | |
if sys.platform == "darwin":
|
|
345 |
if system == "darwin":
|
315 | 346 |
path = os.path.join(
|
316 | 347 |
os.path.expanduser('~/Library/Logs'),
|
317 | 348 |
appname)
|
318 | |
elif sys.platform == "win32":
|
|
349 |
elif system == "win32":
|
319 | 350 |
path = user_data_dir(appname, appauthor, version)
|
320 | 351 |
version = False
|
321 | 352 |
if opinion:
|
|
357 | 388 |
|
358 | 389 |
@property
|
359 | 390 |
def site_config_dir(self):
|
360 | |
return site_data_dir(self.appname, self.appauthor,
|
|
391 |
return site_config_dir(self.appname, self.appauthor,
|
361 | 392 |
version=self.version, multipath=self.multipath)
|
362 | 393 |
|
363 | 394 |
@property
|
|
447 | 478 |
|
448 | 479 |
return buf.value
|
449 | 480 |
|
450 | |
if sys.platform == "win32":
|
|
481 |
def _get_win_folder_with_jna(csidl_name):
|
|
482 |
import array
|
|
483 |
from com.sun import jna
|
|
484 |
from com.sun.jna.platform import win32
|
|
485 |
|
|
486 |
buf_size = win32.WinDef.MAX_PATH * 2
|
|
487 |
buf = array.zeros('c', buf_size)
|
|
488 |
shell = win32.Shell32.INSTANCE
|
|
489 |
shell.SHGetFolderPath(None, getattr(win32.ShlObj, csidl_name), None, win32.ShlObj.SHGFP_TYPE_CURRENT, buf)
|
|
490 |
dir = jna.Native.toString(buf.tostring()).rstrip("\0")
|
|
491 |
|
|
492 |
# Downgrade to short path name if have highbit chars. See
|
|
493 |
# <http://bugs.activestate.com/show_bug.cgi?id=85099>.
|
|
494 |
has_high_char = False
|
|
495 |
for c in dir:
|
|
496 |
if ord(c) > 255:
|
|
497 |
has_high_char = True
|
|
498 |
break
|
|
499 |
if has_high_char:
|
|
500 |
buf = array.zeros('c', buf_size)
|
|
501 |
kernel = win32.Kernel32.INSTANCE
|
|
502 |
if kernal.GetShortPathName(dir, buf, buf_size):
|
|
503 |
dir = jna.Native.toString(buf.tostring()).rstrip("\0")
|
|
504 |
|
|
505 |
return dir
|
|
506 |
|
|
507 |
if system == "win32":
|
451 | 508 |
try:
|
452 | 509 |
import win32com.shell
|
453 | 510 |
_get_win_folder = _get_win_folder_with_pywin32
|
454 | 511 |
except ImportError:
|
455 | 512 |
try:
|
456 | |
import ctypes
|
|
513 |
from ctypes import windll
|
457 | 514 |
_get_win_folder = _get_win_folder_with_ctypes
|
458 | 515 |
except ImportError:
|
459 | |
_get_win_folder = _get_win_folder_from_registry
|
|
516 |
try:
|
|
517 |
import com.sun.jna
|
|
518 |
_get_win_folder = _get_win_folder_with_jna
|
|
519 |
except ImportError:
|
|
520 |
_get_win_folder = _get_win_folder_from_registry
|
460 | 521 |
|
461 | 522 |
|
462 | 523 |
#---- self test code
|
|
483 | 544 |
dirs = AppDirs(appname)
|
484 | 545 |
for prop in props:
|
485 | 546 |
print("%s: %s" % (prop, getattr(dirs, prop)))
|
|
547 |
|
|
548 |
print("\n-- app dirs (with disabled 'appauthor')")
|
|
549 |
dirs = AppDirs(appname, appauthor=False)
|
|
550 |
for prop in props:
|
|
551 |
print("%s: %s" % (prop, getattr(dirs, prop)))
|