Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 11e7f62

Browse files
committed
Use new, more generic structure for *fix.py scripts.
1 parent b824fc6 commit 11e7f62

1 file changed

Lines changed: 90 additions & 58 deletions

File tree

Tools/scripts/classfix.py

Lines changed: 90 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#! /ufs/guido/bin/sgi/python
12
#! /usr/local/python
23

34
# Fix Python source files to use the new class definition syntax,
@@ -13,19 +14,21 @@
1314
# arguments). Of course, the original file is kept as a back-up
1415
# (with a "~" attached to its name).
1516
#
16-
# Undoubtedly you can do this using find and sed, but this is
17+
# Changes made are reported to stdout in a diff-like format.
18+
#
19+
# Undoubtedly you can do this using find and sed or perl, but this is
1720
# a nice example of Python code that recurses down a directory tree
1821
# and uses regular expressions. Also note several subtleties like
1922
# preserving the file's mode and avoiding to even write a temp file
2023
# when no changes are needed for a file.
2124
#
22-
# Changes made are reported to stdout in a diff-like format.
25+
# NB: by changing only the function fixline() you can turn this
26+
# into a program for a different change to Python programs...
2327

2428
import sys
25-
import regexp
29+
import regex
2630
import posix
2731
import path
28-
import string
2932
from stat import *
3033

3134
err = sys.stderr.write
@@ -35,7 +38,7 @@
3538
def main():
3639
bad = 0
3740
if not sys.argv[1:]: # No arguments
38-
err('usage: classfix file-or-directory ...\n')
41+
err('usage: ' + argv[0] + ' file-or-directory ...\n')
3942
sys.exit(2)
4043
for arg in sys.argv[1:]:
4144
if path.isdir(arg):
@@ -47,7 +50,9 @@ def main():
4750
if fix(arg): bad = 1
4851
sys.exit(bad)
4952

50-
ispython = regexp.compile('^[a-zA-Z0-9_]+\.py$').match # This is a method!
53+
ispythonprog = regex.compile('^[a-zA-Z0-9_]+\.py$')
54+
def ispython(name):
55+
return ispythonprog.match(name) >= 0
5156

5257
def recursedown(dirname):
5358
dbg('recursedown(' + `dirname` + ')\n')
@@ -57,81 +62,66 @@ def recursedown(dirname):
5762
except posix.error, msg:
5863
err(dirname + ': cannot list directory: ' + `msg` + '\n')
5964
return 1
65+
names.sort()
66+
subdirs = []
6067
for name in names:
6168
if name in ('.', '..'): continue
6269
fullname = path.join(dirname, name)
6370
if path.islink(fullname): pass
6471
elif path.isdir(fullname):
65-
if recursedown(fullname): bad = 1
72+
subdirs.append(fullname)
6673
elif ispython(name):
6774
if fix(fullname): bad = 1
75+
for fullname in subdirs:
76+
if recursedown(fullname): bad = 1
6877
return bad
6978

70-
# This expression doesn't catch *all* class definition headers,
71-
# but it's darn pretty close.
72-
classexpr = '^([ \t]*class +[a-zA-Z0-9_]+) *\( *\) *((=.*)?):'
73-
findclass = regexp.compile(classexpr).match # This is a method!
74-
75-
baseexpr = '^ *(.*) *\( *\) *$'
76-
findbase = regexp.compile(baseexpr).match # This is a method, too!
77-
7879
def fix(filename):
79-
## dbg('fix(' + `filename` + ')\n')
80+
dbg('fix(' + `filename` + ')\n')
8081
try:
8182
f = open(filename, 'r')
8283
except IOError, msg:
8384
err(filename + ': cannot open: ' + `msg` + '\n')
8485
return 1
8586
head, tail = path.split(filename)
8687
tempname = path.join(head, '@' + tail)
87-
tf = None
88+
g = None
8889
# If we find a match, we rewind the file and start over but
8990
# now copy everything to a temp file.
91+
lineno = 0
9092
while 1:
9193
line = f.readline()
9294
if not line: break
93-
res = findclass(line)
94-
if not res:
95-
if tf: tf.write(line)
96-
continue
97-
if not tf:
98-
try:
99-
tf = open(tempname, 'w')
100-
except IOError, msg:
101-
f.close()
102-
err(tempname+': cannot create: '+`msg`+'\n')
103-
return 1
104-
rep(filename + ':\n')
105-
# Rewind the input file and start all over:
106-
f.seek(0)
107-
continue
108-
a0, b0 = res[0] # Whole match (up to ':')
109-
a1, b1 = res[1] # First subexpression (up to classname)
110-
a2, b2 = res[2] # Second subexpression (=.*)
111-
head = line[:b1]
112-
tail = line[b0:] # Unmatched rest of line
113-
if a2 = b2: # No base classes -- easy case
114-
newline = head + ':' + tail
115-
else:
116-
# Get rid of leading '='
117-
basepart = line[a2+1:b2]
118-
# Extract list of base expressions
119-
bases = string.splitfields(basepart, ',')
120-
# Strip trailing '()' from each base expression
121-
for i in range(len(bases)):
122-
res = findbase(bases[i])
123-
if res:
124-
(x0, y0), (x1, y1) = res
125-
bases[i] = bases[i][x1:y1]
126-
# Join the bases back again and build the new line
127-
basepart = string.joinfields(bases, ', ')
128-
newline = head + '(' + basepart + '):' + tail
129-
rep('< ' + line)
130-
rep('> ' + newline)
131-
tf.write(newline)
95+
lineno = lineno + 1
96+
while line[-2:] == '\\\n':
97+
nextline = f.readline()
98+
if not nextline: break
99+
line = line + nextline
100+
lineno = lineno + 1
101+
newline = fixline(line)
102+
if newline != line:
103+
if g is None:
104+
try:
105+
g = open(tempname, 'w')
106+
except IOError, msg:
107+
f.close()
108+
err(tempname+': cannot create: '+\
109+
`msg`+'\n')
110+
return 1
111+
f.seek(0)
112+
lineno = 0
113+
rep(filename + ':\n')
114+
continue # restart from the beginning
115+
rep(`lineno` + '\n')
116+
rep('< ' + line)
117+
rep('> ' + newline)
118+
if g is not None:
119+
g.write(newline)
120+
121+
# End of file
132122
f.close()
133-
if not tf: return 0 # No changes
134-
123+
if not g: return 0 # No changes
124+
135125
# Finishing touch -- move files
136126

137127
# First copy the file's mode to the temp file
@@ -154,4 +144,46 @@ def fix(filename):
154144
# Return succes
155145
return 0
156146

147+
# This expression doesn't catch *all* class definition headers,
148+
# but it's pretty darn close.
149+
classexpr = '^\([ \t]*class +[a-zA-Z0-9_]+\) *( *) *\(\(=.*\)?\):'
150+
classprog = regex.compile(classexpr)
151+
152+
# Expressions for finding base class expressions.
153+
baseexpr = '^ *\(.*\) *( *) *$'
154+
baseprog = regex.compile(baseexpr)
155+
156+
import string
157+
158+
def fixline(line):
159+
if classprog.match(line) < 0: # No 'class' keyword -- no change
160+
return line
161+
162+
(a0, b0), (a1, b1), (a2, b2) = classprog.regs[:3]
163+
# a0, b0 = Whole match (up to ':')
164+
# a1, b1 = First subexpression (up to classname)
165+
# a2, b2 = Second subexpression (=.*)
166+
head = line[:b1]
167+
tail = line[b0:] # Unmatched rest of line
168+
169+
if a2 == b2: # No base classes -- easy case
170+
return head + ':' + tail
171+
172+
# Get rid of leading '='
173+
basepart = line[a2+1:b2]
174+
175+
# Extract list of base expressions
176+
bases = string.splitfields(basepart, ',')
177+
178+
# Strip trailing '()' from each base expression
179+
for i in range(len(bases)):
180+
if baseprog.match(bases[i]) >= 0:
181+
x1, y1 = baseprog.regs[1]
182+
bases[i] = bases[i][x1:y1]
183+
184+
# Join the bases back again and build the new line
185+
basepart = string.joinfields(bases, ', ')
186+
187+
return head + '(' + basepart + '):' + tail
188+
157189
main()

0 commit comments

Comments
 (0)