Repository navigation
Expand file tree
/
Copy pathimport_validate.py
More file actions
executable file
·111 lines (96 loc) · 3.36 KB
/
Copy pathimport_validate.py
File metadata and controls
executable file
·111 lines (96 loc) · 3.36 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
#!/usr/bin/env python3
import os
import sys
import re
def append(data, key, value):
cur = data.get(key, [])
cur.append(value)
data[key] = cur
def add_blank(data):
append(data, "blanks", data["num"])
def comment(data):
append(data, "comment", data["num"])
def blank_import(data):
'''Remove extra blank lines associated with _ imports'''
num = data['num']
if not 'comment' in data:
return
comments = data["comment"]
del data['comment']
while comments:
num -= 1
prev = comments.pop(-1)
if prev < num:
break
# at this point, num == line of first comment
blanks = data.get("blanks", [])
if len(blanks) < 1:
return
if blanks[-1] == num - 1:
blanks.pop(-1)
def check_imports(data):
# We only tolerate blank lines between first and third party imports, as well as blank (_) imports
s_line = data.get('line', '').lstrip()
import_state = data.get('import_state', TPIMPORTS)
# ignore . imports, but recognize 3rd party imports of the form github.com/user/proj;
# dot imports are stripped of their leading dot.
if s_line.startswith('.'):
s_line = s_line[1:]
if '.' in s_line and import_state == FPIMPORTS:
data["import_state"] = TPIMPORTS
check_blanks(data)
def check_blanks(data):
did_run = data.get('check_blanks', False)
blanks = data.get('blanks', [])
import_state = data.get('import_state', FPIMPORTS)
if import_state == FPIMPORTS or did_run:
return # nothing to do here
# If we're in 3rd party imports, we should only ever have one blank separating 1st and 3rd party imports
# keep the last blank, as it's likely the correct one, as we're in the transition to 3rd party imports here
data['blanks'] = blanks[:-1]
data['check_blanks'] = True
def complete(data):
blanks = data.get('blanks', [])
for n in blanks:
print("%s:%d: Too many blank lines in imports" % (data["file"], n))
PREIMPORT, IMPORTS, POSTIMPORT, EXTRACOMMENT, BLANKIMPORT = range(5)
FPIMPORTS, TPIMPORTS = 1, 3 # We differentiate between first party (FPIMPORTS) and third party (TPIMPORTS) imports
TRANSITIONS = [
(PREIMPORT, 'import (', IMPORTS),
(PREIMPORT, '', PREIMPORT),
(IMPORTS, '\t//', IMPORTS, comment),
(IMPORTS, '\t_ ', IMPORTS, blank_import),
(IMPORTS, '\t', IMPORTS, check_imports),
(IMPORTS, '\n', IMPORTS, add_blank),
(IMPORTS, ')', POSTIMPORT, complete),
(POSTIMPORT, '', POSTIMPORT),
]
def main():
ok = True
for gofile in sys.argv[1:]:
fileok = scan(gofile)
ok = ok and fileok
if not ok:
sys.exit(1)
def scan(gofile):
data = {"file": gofile}
state = PREIMPORT
for num, line in enumerate(open(gofile), start = 1):
data["num"] = num
data["line"] = line
data["state"] = state
data["import_state"] = FPIMPORTS # Start with first party imports
matched = False
for t in TRANSITIONS:
if state == t[0] and line.startswith(t[1]):
matched = True
data["newstate"] = t[2]
state = t[2]
if len(t) == 4:
t[3](data)
break
if not matched:
print("Unmatched state: %s, line %s" % (state, repr(line)))
return len(data.get("blanks", [])) <= 1
if __name__ == '__main__':
main()