Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.10/site-packages/pyflakes/api.py: 20%

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

90 statements  

1""" 

2API for the command-line I{pyflakes} tool. 

3""" 

4import ast 

5import os 

6import platform 

7import re 

8import sys 

9 

10from pyflakes import checker, __version__ 

11from pyflakes import reporter as modReporter 

12 

13__all__ = ['check', 'checkPath', 'checkRecursive', 'iterSourceCode', 'main'] 

14 

15PYTHON_SHEBANG_REGEX = re.compile(br'^#!.*\bpython(3(\.\d+)?|w)?[dmu]?\s') 

16 

17 

18def check(codeString, filename, reporter=None): 

19 """ 

20 Check the Python source given by C{codeString} for flakes. 

21 

22 @param codeString: The Python source to check. 

23 @type codeString: C{str} 

24 

25 @param filename: The name of the file the source came from, used to report 

26 errors. 

27 @type filename: C{str} 

28 

29 @param reporter: A L{Reporter} instance, where errors and warnings will be 

30 reported. 

31 

32 @return: The number of warnings emitted. 

33 @rtype: C{int} 

34 """ 

35 if reporter is None: 

36 reporter = modReporter._makeDefaultReporter() 

37 # First, compile into an AST and handle syntax errors. 

38 try: 

39 tree = ast.parse(codeString, filename=filename) 

40 except SyntaxError as e: 

41 reporter.syntaxError(filename, e.args[0], e.lineno, e.offset, e.text) 

42 return 1 

43 except Exception: 

44 reporter.unexpectedError(filename, 'problem decoding source') 

45 return 1 

46 # Okay, it's syntactically valid. Now check it. 

47 w = checker.Checker(tree, filename=filename) 

48 w.messages.sort(key=lambda m: m.lineno) 

49 for warning in w.messages: 

50 reporter.flake(warning) 

51 return len(w.messages) 

52 

53 

54def checkPath(filename, reporter=None): 

55 """ 

56 Check the given path, printing out any warnings detected. 

57 

58 @param reporter: A L{Reporter} instance, where errors and warnings will be 

59 reported. 

60 

61 @return: the number of warnings printed 

62 """ 

63 if reporter is None: 

64 reporter = modReporter._makeDefaultReporter() 

65 try: 

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

67 codestr = f.read() 

68 except OSError as e: 

69 reporter.unexpectedError(filename, e.args[1]) 

70 return 1 

71 return check(codestr, filename, reporter) 

72 

73 

74def isPythonFile(filename): 

75 """Return True if filename points to a Python file.""" 

76 if filename.endswith('.py'): 

77 return True 

78 

79 # Avoid obvious Emacs backup files 

80 if filename.endswith("~"): 

81 return False 

82 

83 max_bytes = 128 

84 

85 try: 

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

87 text = f.read(max_bytes) 

88 if not text: 

89 return False 

90 except OSError: 

91 return False 

92 

93 return PYTHON_SHEBANG_REGEX.match(text) 

94 

95 

96def iterSourceCode(paths): 

97 """ 

98 Iterate over all Python source files in C{paths}. 

99 

100 @param paths: A list of paths. Directories will be recursed into and 

101 any .py files found will be yielded. Any non-directories will be 

102 yielded as-is. 

103 """ 

104 for path in paths: 

105 if os.path.isdir(path): 

106 for dirpath, dirnames, filenames in os.walk(path): 

107 for filename in filenames: 

108 full_path = os.path.join(dirpath, filename) 

109 if isPythonFile(full_path): 

110 yield full_path 

111 else: 

112 yield path 

113 

114 

115def checkRecursive(paths, reporter): 

116 """ 

117 Recursively check all source files in C{paths}. 

118 

119 @param paths: A list of paths to Python source files and directories 

120 containing Python source files. 

121 @param reporter: A L{Reporter} where all of the warnings and errors 

122 will be reported to. 

123 @return: The number of warnings found. 

124 """ 

125 warnings = 0 

126 for sourcePath in iterSourceCode(paths): 

127 warnings += checkPath(sourcePath, reporter) 

128 return warnings 

129 

130 

131def _exitOnSignal(sigName, message): 

132 """Handles a signal with sys.exit. 

133 

134 Some of these signals (SIGPIPE, for example) don't exist or are invalid on 

135 Windows. So, ignore errors that might arise. 

136 """ 

137 import signal 

138 

139 try: 

140 sigNumber = getattr(signal, sigName) 

141 except AttributeError: 

142 # the signal constants defined in the signal module are defined by 

143 # whether the C library supports them or not. So, SIGPIPE might not 

144 # even be defined. 

145 return 

146 

147 def handler(sig, f): 

148 sys.exit(message) 

149 

150 try: 

151 signal.signal(sigNumber, handler) 

152 except ValueError: 

153 # It's also possible the signal is defined, but then it's invalid. In 

154 # this case, signal.signal raises ValueError. 

155 pass 

156 

157 

158def _get_version(): 

159 """ 

160 Retrieve and format package version along with python version & OS used 

161 """ 

162 return ('%s Python %s on %s' % 

163 (__version__, platform.python_version(), platform.system())) 

164 

165 

166def main(prog=None, args=None): 

167 """Entry point for the script "pyflakes".""" 

168 import argparse 

169 

170 # Handle "Keyboard Interrupt" and "Broken pipe" gracefully 

171 _exitOnSignal('SIGINT', '... stopped') 

172 _exitOnSignal('SIGPIPE', 1) 

173 

174 parser = argparse.ArgumentParser(prog=prog, 

175 description='Check Python source files for errors') 

176 parser.add_argument('-V', '--version', action='version', version=_get_version()) 

177 parser.add_argument('path', nargs='*', 

178 help='Path(s) of Python file(s) to check. STDIN if not given.') 

179 args = parser.parse_args(args=args).path 

180 reporter = modReporter._makeDefaultReporter() 

181 if args: 

182 warnings = checkRecursive(args, reporter) 

183 else: 

184 warnings = check(sys.stdin.read(), '<stdin>', reporter) 

185 raise SystemExit(warnings > 0)