Contributed code that converts Python source files to any combination of tabs/spaces for indenting.
diff --git a/Mac/Contrib/Tabcleaner/Tabcleaner.py b/Mac/Contrib/Tabcleaner/Tabcleaner.py
new file mode 100644
index 0000000..c6d3223
--- /dev/null
+++ b/Mac/Contrib/Tabcleaner/Tabcleaner.py
@@ -0,0 +1,160 @@
+#!/usr/bin/python
+
+import tokenize
+import string
+
+TABSONLY = 'TABSONLY'
+SPACESONLY = 'SPACESONLY'
+MIXED = 'MIXED'
+
+class PyText:
+	def __init__(self, fnm, optdict):
+		self.optdict = optdict
+		self.fnm = fnm
+		self.txt = open(self.fnm, 'r').readlines()
+		self.indents = [(0, 0, )]
+		self.lnndx = 0
+		self.indentndx = 0
+	def getline(self):
+		if self.lnndx < len(self.txt):
+			txt = self.txt[self.lnndx]
+			self.lnndx = self.lnndx + 1
+		else:
+			txt = ''
+		return txt
+	def tokeneater(self, type, token, start, end, line):
+		if type == tokenize.INDENT:
+			(lvl, s) = self.indents[-1]
+			self.indents[-1] = (lvl, s, start[0]-1)
+			self.indents.append((lvl+1, start[0]-1,))
+		elif type == tokenize.DEDENT:
+			(lvl, s) = self.indents[-1]
+			self.indents[-1] = (lvl, s, start[0]-1)
+			self.indents.append((lvl-1, start[0]-1,))
+		elif type == tokenize.ENDMARKER:
+			(lvl, s) = self.indents[-1]
+			self.indents[-1] = (lvl, s, len(self.txt))
+	def split(self, ln):
+		content = string.lstrip(ln)
+		if not content:
+			return ('', '\n')
+		lead = ln[:len(ln) - len(content)]
+		lead = string.expandtabs(lead)
+		return (lead, content)
+		
+	def process(self):
+		style = self.optdict.get('style', TABSONLY)
+		indent = string.atoi(self.optdict.get('indent', '4'))
+		tabsz = string.atoi(self.optdict.get('tabs', '8'))
+		print 'file %s -> style %s, tabsize %d, indent %d' % (self.fnm, style, tabsz, indent)
+		tokenize.tokenize(self.getline, self.tokeneater)
+		#import pprint
+		#pprint.pprint(self.indents)
+		new = []
+		for (lvl, s, e) in self.indents:
+			if s >= len(self.txt):
+				break
+			if s == e:
+				continue
+			oldlead, content = self.split(self.txt[s])
+			#print "oldlead", len(oldlead), `oldlead`
+			if style == TABSONLY:
+				newlead = '\t'*lvl
+			elif style == SPACESONLY:
+				newlead = ' '*(indent*lvl)
+			else:
+				sz = indent*lvl
+				t,spcs = divmod(sz, tabsz)
+				newlead = '\t'*t + ' '*spcs
+			new.append(newlead + content)
+			for ln in self.txt[s+1:e]:
+				lead, content = self.split(ln)
+				#print "lead:", len(lead)
+				new.append(newlead + lead[len(oldlead):] + content)
+		self.save(new)
+		#print "---", self.fnm
+		#for ln in new:
+		#    print ln,
+		#print
+		
+	def save(self, txt):
+		bakname = os.path.splitext(self.fnm)[0]+'.bak'
+		print "backing up", self.fnm, "to", bakname
+		#print os.getcwd()
+		try:
+			os.rename(self.fnm, bakname)
+		except os.error:
+			os.remove(bakname)
+			os.rename(self.fnm, bakname)
+		open(self.fnm, 'w').writelines(txt)
+		
+def test():
+	tc = PyText('test1.py')
+	tc.process()
+	tc = PyText('test1.py')
+	tc.process(style=TABSONLY)
+	tc = PyText('test1.py')
+	tc.process(style=MIXED, indent=4, tabs=8)
+	tc = PyText('test1.py')
+	tc.process(style=MIXED, indent=2, tabs=8)
+	
+def cleanfile(fnm, d):
+	if os.path.isdir(fnm) and not os.path.islink(fnm):
+		names = os.listdir(fnm)
+		for name in names:
+			fullnm = os.path.join(fnm, name)
+			if (os.path.isdir(fullnm) and not os.path.islink(fullnm)) or \
+			    os.path.normcase(fullnm[-3:]) == ".py":
+				cleanfile(fullnm, d)
+		return
+	tc = PyText(fnm, d)
+	tc.process()
+	
+usage="""\
+%s [options] [path...]
+ options
+  -T : reformat to TABS ONLY
+  -S : reformat to SPACES ONLY ( -i option is important)
+  -M : reformat to MIXED SPACES / TABS ( -t and -i options important)
+  -t<n> : tab is worth <n> characters
+  -i<n> : indents should be <n> characters 
+  -h : print this text
+ path is file or directory
+"""
+if __name__ == '__main__':
+	import sys, getopt, os
+	opts, args = getopt.getopt(sys.argv[1:], "TSMht:i:")
+	d = {}
+	print `opts`
+	for opt in opts:
+		if opt[0] == '-T':
+			d['style'] = TABSONLY
+		elif opt[0] == '-S':
+			d['style'] = SPACESONLY
+		elif opt[0] == '-M':
+			d['style'] = MIXED
+		elif opt[0] == '-t':
+			d['tabs'] = opt[1]
+		elif opt[0] == '-i':
+			d['indent'] = opt[1]
+		elif opt[0] == '-h':
+			print usage % sys.argv[0]
+			sys.exit(0)
+	if not args:
+		print usage % sys.argv[0]
+	for arg in args:
+		cleanfile(arg, d)
+		
+		
+		
+		
+		
+		
+		
+		
+		
+		
+		
+		
+		
+