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