UtilitiesPython2/Py2SyntaxChecker.py

changeset 805
83ca4d1ff648
parent 802
e8882d16384c
child 915
c1e052773c08
child 1510
e75ecf2bd9dd
equal deleted inserted replaced
804:3465556892de 805:83ca4d1ff648
1 #!/usr/bin/env python2
1 # -*- coding: utf-8 -*- 2 # -*- coding: utf-8 -*-
2 3
3 # Copyright (c) 2011 Detlev Offenbach <detlev@die-offenbachs.de> 4 # Copyright (c) 2011 Detlev Offenbach <detlev@die-offenbachs.de>
4 # 5 #
5 6
8 """ 9 """
9 10
10 import sys 11 import sys
11 import re 12 import re
12 import traceback 13 import traceback
13 from codecs import BOM_UTF8, BOM_UTF16, BOM_UTF32 14
15 from Tools import readEncodedFile, normalizeCode
14 16
15 from py2flakes.checker import Checker 17 from py2flakes.checker import Checker
16 from py2flakes.messages import ImportStarUsed 18 from py2flakes.messages import ImportStarUsed
17 19
18 coding_regexps = [ 20 def compile(file, codestring):
19 (2, re.compile(r'''coding[:=]\s*([-\w_.]+)''')),
20 (1, re.compile(r'''<\?xml.*\bencoding\s*=\s*['"]([-\w_.]+)['"]\?>''')),
21 ]
22
23 def get_coding(text):
24 """
25 Function to get the coding of a text.
26
27 @param text text to inspect (string)
28 @return coding string
29 """
30 lines = text.splitlines()
31 for coding in coding_regexps:
32 coding_re = coding[1]
33 head = lines[:coding[0]]
34 for l in head:
35 m = coding_re.search(l)
36 if m:
37 return m.group(1).lower()
38 return None
39
40 def decode(text):
41 """
42 Function to decode a text.
43
44 @param text text to decode (string)
45 @return decoded text and encoding
46 """
47 try:
48 if text.startswith(BOM_UTF8):
49 # UTF-8 with BOM
50 return unicode(text[len(BOM_UTF8):], 'utf-8'), 'utf-8-bom'
51 elif text.startswith(BOM_UTF16):
52 # UTF-16 with BOM
53 return unicode(text[len(BOM_UTF16):], 'utf-16'), 'utf-16'
54 elif text.startswith(BOM_UTF32):
55 # UTF-32 with BOM
56 return unicode(text[len(BOM_UTF32):], 'utf-32'), 'utf-32'
57 coding = get_coding(text)
58 if coding:
59 return unicode(text, coding), coding
60 except (UnicodeError, LookupError):
61 pass
62
63 # Assume UTF-8
64 try:
65 return unicode(text, 'utf-8'), 'utf-8-guessed'
66 except (UnicodeError, LookupError):
67 pass
68
69 # Assume Latin-1 (behaviour before 3.7.1)
70 return unicode(text, "latin-1"), 'latin-1-guessed'
71
72 def compile(file):
73 """ 21 """
74 Function to compile one Python source file to Python bytecode. 22 Function to compile one Python source file to Python bytecode.
75 23
76 @param file source filename (string) 24 @param file source filename (string)
25 @param codestring source code (string)
77 @return A tuple indicating status (1 = an error was found), the 26 @return A tuple indicating status (1 = an error was found), the
78 filename, the linenumber, the code string, the error message 27 filename, the linenumber, the code string and the error message
79 and the full source code (boolean, string, string, string, 28 (boolean, string, string, string, string). The values are only
80 string, string). The values are only valid, if the status 29 valid, if the status equals 1.
81 equals 1.
82 """ 30 """
83 import __builtin__ 31 import __builtin__
84 try:
85 f = open(file)
86 codestring, encoding = decode(f.read())
87 f.close()
88 except IOError, msg:
89 return (1, file, "1", "", "I/O Error: %s" % unicode(msg), "")
90
91 if type(codestring) == type(u""):
92 codestring = codestring.encode('utf-8')
93 codestring = codestring.replace("\r\n","\n")
94 codestring = codestring.replace("\r","\n")
95
96 if codestring and codestring[-1] != '\n':
97 codestring = codestring + '\n'
98 32
99 try: 33 try:
100 if type(file) == type(u""): 34 if type(file) == type(u""):
101 file = file.encode('utf-8') 35 file = file.encode('utf-8')
102 36
127 else: 61 else:
128 fn = detail.filename 62 fn = detail.filename
129 line = detail.lineno and detail.lineno or 1 63 line = detail.lineno and detail.lineno or 1
130 code = "" 64 code = ""
131 error = detail.msg 65 error = detail.msg
132 return (1, fn, line, code, error, codestring) 66 return (1, fn, line, code, error)
133 except ValueError, detail: 67 except ValueError, detail:
134 try: 68 try:
135 fn = detail.filename 69 fn = detail.filename
136 line = detail.lineno 70 line = detail.lineno
137 error = detail.msg 71 error = detail.msg
138 except AttributeError: 72 except AttributeError:
139 fn = file 73 fn = file
140 line = 1 74 line = 1
141 error = unicode(detail) 75 error = unicode(detail)
142 code = "" 76 code = ""
143 return (1, fn, line, code, error, codestring) 77 return (1, fn, line, code, error)
144 except StandardError, detail: 78 except StandardError, detail:
145 try: 79 try:
146 fn = detail.filename 80 fn = detail.filename
147 line = detail.lineno 81 line = detail.lineno
148 code = "" 82 code = ""
149 error = detail.msg 83 error = detail.msg
150 return (1, fn, line, code, error, codestring) 84 return (1, fn, line, code, error)
151 except: # this catchall is intentional 85 except: # this catchall is intentional
152 pass 86 pass
153 87
154 return (0, None, None, None, None, codestring) 88 return (0, None, None, None, None)
155 89
156 def flakesCheck(fileName, codestring, ignoreStarImportWarnings): 90 def flakesCheck(fileName, codestring, ignoreStarImportWarnings):
157 """ 91 """
158 Function to perform a pyflakes check. 92 Function to perform a pyflakes check.
159 93
196 print "" 130 print ""
197 print "" 131 print ""
198 print "No file name given." 132 print "No file name given."
199 else: 133 else:
200 filename = sys.argv[-1] 134 filename = sys.argv[-1]
201 syntaxerror, fname, line, code, error, codestring = compile(filename) 135 try:
136 codestring = readEncodedFile(filename)[0]
137 codestring = normalizeCode(codestring)
138
139 syntaxerror, fname, line, code, error = compile(filename, codestring)
140 except IOError, msg:
141 # fake a syntax error
142 syntaxerror, fname, line, code, error = \
143 1, filename, "1", "", "I/O Error: %s" % unicode(msg)
202 144
203 if syntaxerror: 145 if syntaxerror:
204 print "ERROR" 146 print "ERROR"
205 else: 147 else:
206 print "NO_ERROR" 148 print "NO_ERROR"

eric ide

mercurial