Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/xdg/BaseDirectory.py: 24%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

78 statements  

1""" 

2This module is based on a rox module (LGPL): 

3 

4http://cvs.sourceforge.net/viewcvs.py/rox/ROX-Lib2/python/rox/basedir.py?rev=1.9&view=log 

5 

6The freedesktop.org Base Directory specification provides a way for 

7applications to locate shared data and configuration: 

8 

9 http://standards.freedesktop.org/basedir-spec/ 

10 

11(based on version 0.6) 

12 

13This module can be used to load and save from and to these directories. 

14 

15Typical usage: 

16 

17 from rox import basedir 

18  

19 for dir in basedir.load_config_paths('mydomain.org', 'MyProg', 'Options'): 

20 print "Load settings from", dir 

21 

22 dir = basedir.save_config_path('mydomain.org', 'MyProg') 

23 print >>file(os.path.join(dir, 'Options'), 'w'), "foo=2" 

24 

25Note: see the rox.Options module for a higher-level API for managing options. 

26""" 

27 

28import os, stat 

29 

30_home = os.path.expanduser('~') 

31xdg_data_home = os.environ.get('XDG_DATA_HOME') or \ 

32 os.path.join(_home, '.local', 'share') 

33 

34xdg_data_dirs = [xdg_data_home] + \ 

35 (os.environ.get('XDG_DATA_DIRS') or '/usr/local/share:/usr/share').split(':') 

36 

37xdg_config_home = os.environ.get('XDG_CONFIG_HOME') or \ 

38 os.path.join(_home, '.config') 

39 

40xdg_config_dirs = [xdg_config_home] + \ 

41 (os.environ.get('XDG_CONFIG_DIRS') or '/etc/xdg').split(':') 

42 

43xdg_cache_home = os.environ.get('XDG_CACHE_HOME') or \ 

44 os.path.join(_home, '.cache') 

45 

46xdg_state_home = os.environ.get('XDG_STATE_HOME') or \ 

47 os.path.join(_home, '.local', 'state') 

48 

49xdg_data_dirs = [x for x in xdg_data_dirs if x] 

50xdg_config_dirs = [x for x in xdg_config_dirs if x] 

51 

52def save_config_path(*resource): 

53 """Ensure ``$XDG_CONFIG_HOME/<resource>/`` exists, and return its path. 

54 'resource' should normally be the name of your application. Use this 

55 when saving configuration settings. 

56 """ 

57 resource = os.path.join(*resource) 

58 assert not resource.startswith('/') 

59 path = os.path.join(xdg_config_home, resource) 

60 if not os.path.isdir(path): 

61 os.makedirs(path, 0o700) 

62 return path 

63 

64def save_data_path(*resource): 

65 """Ensure ``$XDG_DATA_HOME/<resource>/`` exists, and return its path. 

66 'resource' should normally be the name of your application or a shared 

67 resource. Use this when saving or updating application data. 

68 """ 

69 resource = os.path.join(*resource) 

70 assert not resource.startswith('/') 

71 path = os.path.join(xdg_data_home, resource) 

72 if not os.path.isdir(path): 

73 os.makedirs(path) 

74 return path 

75 

76def save_cache_path(*resource): 

77 """Ensure ``$XDG_CACHE_HOME/<resource>/`` exists, and return its path. 

78 'resource' should normally be the name of your application or a shared 

79 resource.""" 

80 resource = os.path.join(*resource) 

81 assert not resource.startswith('/') 

82 path = os.path.join(xdg_cache_home, resource) 

83 if not os.path.isdir(path): 

84 os.makedirs(path) 

85 return path 

86 

87def save_state_path(*resource): 

88 """Ensure ``$XDG_STATE_HOME/<resource>/`` exists, and return its path. 

89 'resource' should normally be the name of your application or a shared 

90 resource.""" 

91 resource = os.path.join(*resource) 

92 assert not resource.startswith('/') 

93 path = os.path.join(xdg_state_home, resource) 

94 if not os.path.isdir(path): 

95 os.makedirs(path) 

96 return path 

97 

98def load_config_paths(*resource): 

99 """Returns an iterator which gives each directory named 'resource' in the 

100 configuration search path. Information provided by earlier directories should 

101 take precedence over later ones, and the user-specific config dir comes 

102 first.""" 

103 resource = os.path.join(*resource) 

104 for config_dir in xdg_config_dirs: 

105 path = os.path.join(config_dir, resource) 

106 if os.path.exists(path): yield path 

107 

108def load_first_config(*resource): 

109 """Returns the first result from load_config_paths, or None if there is nothing 

110 to load.""" 

111 for x in load_config_paths(*resource): 

112 return x 

113 return None 

114 

115def load_data_paths(*resource): 

116 """Returns an iterator which gives each directory named 'resource' in the 

117 application data search path. Information provided by earlier directories 

118 should take precedence over later ones.""" 

119 resource = os.path.join(*resource) 

120 for data_dir in xdg_data_dirs: 

121 path = os.path.join(data_dir, resource) 

122 if os.path.exists(path): yield path 

123 

124def get_runtime_dir(strict=True): 

125 """Returns the value of $XDG_RUNTIME_DIR, a directory path. 

126  

127 This directory is intended for 'user-specific non-essential runtime files 

128 and other file objects (such as sockets, named pipes, ...)', and 

129 'communication and synchronization purposes'. 

130  

131 As of late 2012, only quite new systems set $XDG_RUNTIME_DIR. If it is not 

132 set, with ``strict=True`` (the default), a KeyError is raised. With  

133 ``strict=False``, PyXDG will create a fallback under /tmp for the current 

134 user. This fallback does *not* provide the same guarantees as the 

135 specification requires for the runtime directory. 

136  

137 The strict default is deliberately conservative, so that application 

138 developers can make a conscious decision to allow the fallback. 

139 """ 

140 try: 

141 return os.environ['XDG_RUNTIME_DIR'] 

142 except KeyError: 

143 if strict: 

144 raise 

145 

146 import getpass 

147 fallback = '/tmp/pyxdg-runtime-dir-fallback-' + getpass.getuser() 

148 create = False 

149 

150 try: 

151 # This must be a real directory, not a symlink, so attackers can't 

152 # point it elsewhere. So we use lstat to check it. 

153 st = os.lstat(fallback) 

154 except OSError as e: 

155 import errno 

156 if e.errno == errno.ENOENT: 

157 create = True 

158 else: 

159 raise 

160 else: 

161 # The fallback must be a directory 

162 if not stat.S_ISDIR(st.st_mode): 

163 os.unlink(fallback) 

164 create = True 

165 # Must be owned by the user and not accessible by anyone else 

166 elif (st.st_uid != os.getuid()) \ 

167 or (st.st_mode & (stat.S_IRWXG | stat.S_IRWXO)): 

168 os.rmdir(fallback) 

169 create = True 

170 

171 if create: 

172 os.mkdir(fallback, 0o700) 

173 

174 return fallback