comparison env/lib/python3.7/site-packages/appdirs.py @ 5:9b1c78e6ba9c draft default tip

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