Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/pip/_vendor/pygments/lexers/__init__.py: 19%

183 statements  

« prev     ^ index     » next       coverage.py v7.2.7, created at 2023-06-07 06:48 +0000

1""" 

2 pygments.lexers 

3 ~~~~~~~~~~~~~~~ 

4 

5 Pygments lexers. 

6 

7 :copyright: Copyright 2006-2022 by the Pygments team, see AUTHORS. 

8 :license: BSD, see LICENSE for details. 

9""" 

10 

11import sys 

12import types 

13from fnmatch import fnmatch 

14from os.path import basename 

15 

16from pip._vendor.pygments.lexers._mapping import LEXERS 

17from pip._vendor.pygments.modeline import get_filetype_from_buffer 

18from pip._vendor.pygments.plugin import find_plugin_lexers 

19from pip._vendor.pygments.util import ClassNotFound, guess_decode 

20 

21COMPAT = { 

22 'Python3Lexer': 'PythonLexer', 

23 'Python3TracebackLexer': 'PythonTracebackLexer', 

24} 

25 

26__all__ = ['get_lexer_by_name', 'get_lexer_for_filename', 'find_lexer_class', 

27 'guess_lexer', 'load_lexer_from_file'] + list(LEXERS) + list(COMPAT) 

28 

29_lexer_cache = {} 

30 

31def _load_lexers(module_name): 

32 """Load a lexer (and all others in the module too).""" 

33 mod = __import__(module_name, None, None, ['__all__']) 

34 for lexer_name in mod.__all__: 

35 cls = getattr(mod, lexer_name) 

36 _lexer_cache[cls.name] = cls 

37 

38 

39def get_all_lexers(plugins=True): 

40 """Return a generator of tuples in the form ``(name, aliases, 

41 filenames, mimetypes)`` of all know lexers. 

42 

43 If *plugins* is true (the default), plugin lexers supplied by entrypoints 

44 are also returned. Otherwise, only builtin ones are considered. 

45 """ 

46 for item in LEXERS.values(): 

47 yield item[1:] 

48 if plugins: 

49 for lexer in find_plugin_lexers(): 

50 yield lexer.name, lexer.aliases, lexer.filenames, lexer.mimetypes 

51 

52 

53def find_lexer_class(name): 

54 """Lookup a lexer class by name. 

55 

56 Return None if not found. 

57 """ 

58 if name in _lexer_cache: 

59 return _lexer_cache[name] 

60 # lookup builtin lexers 

61 for module_name, lname, aliases, _, _ in LEXERS.values(): 

62 if name == lname: 

63 _load_lexers(module_name) 

64 return _lexer_cache[name] 

65 # continue with lexers from setuptools entrypoints 

66 for cls in find_plugin_lexers(): 

67 if cls.name == name: 

68 return cls 

69 

70 

71def find_lexer_class_by_name(_alias): 

72 """Lookup a lexer class by alias. 

73 

74 Like `get_lexer_by_name`, but does not instantiate the class. 

75 

76 .. versionadded:: 2.2 

77 """ 

78 if not _alias: 

79 raise ClassNotFound('no lexer for alias %r found' % _alias) 

80 # lookup builtin lexers 

81 for module_name, name, aliases, _, _ in LEXERS.values(): 

82 if _alias.lower() in aliases: 

83 if name not in _lexer_cache: 

84 _load_lexers(module_name) 

85 return _lexer_cache[name] 

86 # continue with lexers from setuptools entrypoints 

87 for cls in find_plugin_lexers(): 

88 if _alias.lower() in cls.aliases: 

89 return cls 

90 raise ClassNotFound('no lexer for alias %r found' % _alias) 

91 

92 

93def get_lexer_by_name(_alias, **options): 

94 """Get a lexer by an alias. 

95 

96 Raises ClassNotFound if not found. 

97 """ 

98 if not _alias: 

99 raise ClassNotFound('no lexer for alias %r found' % _alias) 

100 

101 # lookup builtin lexers 

102 for module_name, name, aliases, _, _ in LEXERS.values(): 

103 if _alias.lower() in aliases: 

104 if name not in _lexer_cache: 

105 _load_lexers(module_name) 

106 return _lexer_cache[name](**options) 

107 # continue with lexers from setuptools entrypoints 

108 for cls in find_plugin_lexers(): 

109 if _alias.lower() in cls.aliases: 

110 return cls(**options) 

111 raise ClassNotFound('no lexer for alias %r found' % _alias) 

112 

113 

114def load_lexer_from_file(filename, lexername="CustomLexer", **options): 

115 """Load a lexer from a file. 

116 

117 This method expects a file located relative to the current working 

118 directory, which contains a Lexer class. By default, it expects the 

119 Lexer to be name CustomLexer; you can specify your own class name 

120 as the second argument to this function. 

121 

122 Users should be very careful with the input, because this method 

123 is equivalent to running eval on the input file. 

124 

125 Raises ClassNotFound if there are any problems importing the Lexer. 

126 

127 .. versionadded:: 2.2 

128 """ 

129 try: 

130 # This empty dict will contain the namespace for the exec'd file 

131 custom_namespace = {} 

132 with open(filename, 'rb') as f: 

133 exec(f.read(), custom_namespace) 

134 # Retrieve the class `lexername` from that namespace 

135 if lexername not in custom_namespace: 

136 raise ClassNotFound('no valid %s class found in %s' % 

137 (lexername, filename)) 

138 lexer_class = custom_namespace[lexername] 

139 # And finally instantiate it with the options 

140 return lexer_class(**options) 

141 except OSError as err: 

142 raise ClassNotFound('cannot read %s: %s' % (filename, err)) 

143 except ClassNotFound: 

144 raise 

145 except Exception as err: 

146 raise ClassNotFound('error when loading custom lexer: %s' % err) 

147 

148 

149def find_lexer_class_for_filename(_fn, code=None): 

150 """Get a lexer for a filename. 

151 

152 If multiple lexers match the filename pattern, use ``analyse_text()`` to 

153 figure out which one is more appropriate. 

154 

155 Returns None if not found. 

156 """ 

157 matches = [] 

158 fn = basename(_fn) 

159 for modname, name, _, filenames, _ in LEXERS.values(): 

160 for filename in filenames: 

161 if fnmatch(fn, filename): 

162 if name not in _lexer_cache: 

163 _load_lexers(modname) 

164 matches.append((_lexer_cache[name], filename)) 

165 for cls in find_plugin_lexers(): 

166 for filename in cls.filenames: 

167 if fnmatch(fn, filename): 

168 matches.append((cls, filename)) 

169 

170 if isinstance(code, bytes): 

171 # decode it, since all analyse_text functions expect unicode 

172 code = guess_decode(code) 

173 

174 def get_rating(info): 

175 cls, filename = info 

176 # explicit patterns get a bonus 

177 bonus = '*' not in filename and 0.5 or 0 

178 # The class _always_ defines analyse_text because it's included in 

179 # the Lexer class. The default implementation returns None which 

180 # gets turned into 0.0. Run scripts/detect_missing_analyse_text.py 

181 # to find lexers which need it overridden. 

182 if code: 

183 return cls.analyse_text(code) + bonus, cls.__name__ 

184 return cls.priority + bonus, cls.__name__ 

185 

186 if matches: 

187 matches.sort(key=get_rating) 

188 # print "Possible lexers, after sort:", matches 

189 return matches[-1][0] 

190 

191 

192def get_lexer_for_filename(_fn, code=None, **options): 

193 """Get a lexer for a filename. 

194 

195 If multiple lexers match the filename pattern, use ``analyse_text()`` to 

196 figure out which one is more appropriate. 

197 

198 Raises ClassNotFound if not found. 

199 """ 

200 res = find_lexer_class_for_filename(_fn, code) 

201 if not res: 

202 raise ClassNotFound('no lexer for filename %r found' % _fn) 

203 return res(**options) 

204 

205 

206def get_lexer_for_mimetype(_mime, **options): 

207 """Get a lexer for a mimetype. 

208 

209 Raises ClassNotFound if not found. 

210 """ 

211 for modname, name, _, _, mimetypes in LEXERS.values(): 

212 if _mime in mimetypes: 

213 if name not in _lexer_cache: 

214 _load_lexers(modname) 

215 return _lexer_cache[name](**options) 

216 for cls in find_plugin_lexers(): 

217 if _mime in cls.mimetypes: 

218 return cls(**options) 

219 raise ClassNotFound('no lexer for mimetype %r found' % _mime) 

220 

221 

222def _iter_lexerclasses(plugins=True): 

223 """Return an iterator over all lexer classes.""" 

224 for key in sorted(LEXERS): 

225 module_name, name = LEXERS[key][:2] 

226 if name not in _lexer_cache: 

227 _load_lexers(module_name) 

228 yield _lexer_cache[name] 

229 if plugins: 

230 yield from find_plugin_lexers() 

231 

232 

233def guess_lexer_for_filename(_fn, _text, **options): 

234 """ 

235 Lookup all lexers that handle those filenames primary (``filenames``) 

236 or secondary (``alias_filenames``). Then run a text analysis for those 

237 lexers and choose the best result. 

238 

239 usage:: 

240 

241 >>> from pygments.lexers import guess_lexer_for_filename 

242 >>> guess_lexer_for_filename('hello.html', '<%= @foo %>') 

243 <pygments.lexers.templates.RhtmlLexer object at 0xb7d2f32c> 

244 >>> guess_lexer_for_filename('hello.html', '<h1>{{ title|e }}</h1>') 

245 <pygments.lexers.templates.HtmlDjangoLexer object at 0xb7d2f2ac> 

246 >>> guess_lexer_for_filename('style.css', 'a { color: <?= $link ?> }') 

247 <pygments.lexers.templates.CssPhpLexer object at 0xb7ba518c> 

248 """ 

249 fn = basename(_fn) 

250 primary = {} 

251 matching_lexers = set() 

252 for lexer in _iter_lexerclasses(): 

253 for filename in lexer.filenames: 

254 if fnmatch(fn, filename): 

255 matching_lexers.add(lexer) 

256 primary[lexer] = True 

257 for filename in lexer.alias_filenames: 

258 if fnmatch(fn, filename): 

259 matching_lexers.add(lexer) 

260 primary[lexer] = False 

261 if not matching_lexers: 

262 raise ClassNotFound('no lexer for filename %r found' % fn) 

263 if len(matching_lexers) == 1: 

264 return matching_lexers.pop()(**options) 

265 result = [] 

266 for lexer in matching_lexers: 

267 rv = lexer.analyse_text(_text) 

268 if rv == 1.0: 

269 return lexer(**options) 

270 result.append((rv, lexer)) 

271 

272 def type_sort(t): 

273 # sort by: 

274 # - analyse score 

275 # - is primary filename pattern? 

276 # - priority 

277 # - last resort: class name 

278 return (t[0], primary[t[1]], t[1].priority, t[1].__name__) 

279 result.sort(key=type_sort) 

280 

281 return result[-1][1](**options) 

282 

283 

284def guess_lexer(_text, **options): 

285 """Guess a lexer by strong distinctions in the text (eg, shebang).""" 

286 

287 if not isinstance(_text, str): 

288 inencoding = options.get('inencoding', options.get('encoding')) 

289 if inencoding: 

290 _text = _text.decode(inencoding or 'utf8') 

291 else: 

292 _text, _ = guess_decode(_text) 

293 

294 # try to get a vim modeline first 

295 ft = get_filetype_from_buffer(_text) 

296 

297 if ft is not None: 

298 try: 

299 return get_lexer_by_name(ft, **options) 

300 except ClassNotFound: 

301 pass 

302 

303 best_lexer = [0.0, None] 

304 for lexer in _iter_lexerclasses(): 

305 rv = lexer.analyse_text(_text) 

306 if rv == 1.0: 

307 return lexer(**options) 

308 if rv > best_lexer[0]: 

309 best_lexer[:] = (rv, lexer) 

310 if not best_lexer[0] or best_lexer[1] is None: 

311 raise ClassNotFound('no lexer matching the text found') 

312 return best_lexer[1](**options) 

313 

314 

315class _automodule(types.ModuleType): 

316 """Automatically import lexers.""" 

317 

318 def __getattr__(self, name): 

319 info = LEXERS.get(name) 

320 if info: 

321 _load_lexers(info[0]) 

322 cls = _lexer_cache[info[1]] 

323 setattr(self, name, cls) 

324 return cls 

325 if name in COMPAT: 

326 return getattr(self, COMPAT[name]) 

327 raise AttributeError(name) 

328 

329 

330oldmod = sys.modules[__name__] 

331newmod = _automodule(__name__) 

332newmod.__dict__.update(oldmod.__dict__) 

333sys.modules[__name__] = newmod 

334del newmod.newmod, newmod.oldmod, newmod.sys, newmod.types