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