Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/pygments/formatters/__init__.py: 42%

84 statements  

« prev     ^ index     » next       coverage.py v7.4.4, created at 2024-04-20 06:09 +0000

1""" 

2 pygments.formatters 

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

4 

5 Pygments formatters. 

6 

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

8 :license: BSD, see LICENSE for details. 

9""" 

10 

11import re 

12import sys 

13import types 

14import fnmatch 

15from os.path import basename 

16 

17from pygments.formatters._mapping import FORMATTERS 

18from pygments.plugin import find_plugin_formatters 

19from pygments.util import ClassNotFound 

20 

21__all__ = ['get_formatter_by_name', 'get_formatter_for_filename', 

22 'get_all_formatters', 'load_formatter_from_file'] + list(FORMATTERS) 

23 

24_formatter_cache = {} # classes by name 

25_pattern_cache = {} 

26 

27 

28def _fn_matches(fn, glob): 

29 """Return whether the supplied file name fn matches pattern filename.""" 

30 if glob not in _pattern_cache: 

31 pattern = _pattern_cache[glob] = re.compile(fnmatch.translate(glob)) 

32 return pattern.match(fn) 

33 return _pattern_cache[glob].match(fn) 

34 

35 

36def _load_formatters(module_name): 

37 """Load a formatter (and all others in the module too).""" 

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

39 for formatter_name in mod.__all__: 

40 cls = getattr(mod, formatter_name) 

41 _formatter_cache[cls.name] = cls 

42 

43 

44def get_all_formatters(): 

45 """Return a generator for all formatter classes.""" 

46 # NB: this returns formatter classes, not info like get_all_lexers(). 

47 for info in FORMATTERS.values(): 

48 if info[1] not in _formatter_cache: 

49 _load_formatters(info[0]) 

50 yield _formatter_cache[info[1]] 

51 for _, formatter in find_plugin_formatters(): 

52 yield formatter 

53 

54 

55def find_formatter_class(alias): 

56 """Lookup a formatter by alias. 

57 

58 Returns None if not found. 

59 """ 

60 for module_name, name, aliases, _, _ in FORMATTERS.values(): 

61 if alias in aliases: 

62 if name not in _formatter_cache: 

63 _load_formatters(module_name) 

64 return _formatter_cache[name] 

65 for _, cls in find_plugin_formatters(): 

66 if alias in cls.aliases: 

67 return cls 

68 

69 

70def get_formatter_by_name(_alias, **options): 

71 """ 

72 Return an instance of a :class:`.Formatter` subclass that has `alias` in its 

73 aliases list. The formatter is given the `options` at its instantiation. 

74 

75 Will raise :exc:`pygments.util.ClassNotFound` if no formatter with that 

76 alias is found. 

77 """ 

78 cls = find_formatter_class(_alias) 

79 if cls is None: 

80 raise ClassNotFound("no formatter found for name %r" % _alias) 

81 return cls(**options) 

82 

83 

84def load_formatter_from_file(filename, formattername="CustomFormatter", **options): 

85 """ 

86 Return a `Formatter` subclass instance loaded from the provided file, relative 

87 to the current directory. 

88 

89 The file is expected to contain a Formatter class named ``formattername`` 

90 (by default, CustomFormatter). Users should be very careful with the input, because 

91 this method is equivalent to running ``eval()`` on the input file. The formatter is 

92 given the `options` at its instantiation. 

93 

94 :exc:`pygments.util.ClassNotFound` is raised if there are any errors loading 

95 the formatter. 

96 

97 .. versionadded:: 2.2 

98 """ 

99 try: 

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

101 custom_namespace = {} 

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

103 exec(f.read(), custom_namespace) 

104 # Retrieve the class `formattername` from that namespace 

105 if formattername not in custom_namespace: 

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

107 (formattername, filename)) 

108 formatter_class = custom_namespace[formattername] 

109 # And finally instantiate it with the options 

110 return formatter_class(**options) 

111 except OSError as err: 

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

113 except ClassNotFound: 

114 raise 

115 except Exception as err: 

116 raise ClassNotFound('error when loading custom formatter: %s' % err) 

117 

118 

119def get_formatter_for_filename(fn, **options): 

120 """ 

121 Return a :class:`.Formatter` subclass instance that has a filename pattern 

122 matching `fn`. The formatter is given the `options` at its instantiation. 

123 

124 Will raise :exc:`pygments.util.ClassNotFound` if no formatter for that filename 

125 is found. 

126 """ 

127 fn = basename(fn) 

128 for modname, name, _, filenames, _ in FORMATTERS.values(): 

129 for filename in filenames: 

130 if _fn_matches(fn, filename): 

131 if name not in _formatter_cache: 

132 _load_formatters(modname) 

133 return _formatter_cache[name](**options) 

134 for _name, cls in find_plugin_formatters(): 

135 for filename in cls.filenames: 

136 if _fn_matches(fn, filename): 

137 return cls(**options) 

138 raise ClassNotFound("no formatter found for file name %r" % fn) 

139 

140 

141class _automodule(types.ModuleType): 

142 """Automatically import formatters.""" 

143 

144 def __getattr__(self, name): 

145 info = FORMATTERS.get(name) 

146 if info: 

147 _load_formatters(info[0]) 

148 cls = _formatter_cache[info[1]] 

149 setattr(self, name, cls) 

150 return cls 

151 raise AttributeError(name) 

152 

153 

154oldmod = sys.modules[__name__] 

155newmod = _automodule(__name__) 

156newmod.__dict__.update(oldmod.__dict__) 

157sys.modules[__name__] = newmod 

158del newmod.newmod, newmod.oldmod, newmod.sys, newmod.types