Skip to content

Commit cd058a9

Browse files
committed
Add tab 2 spaces script
1 parent 4bf8027 commit cd058a9

File tree

1 file changed

+140
-0
lines changed

1 file changed

+140
-0
lines changed

tab2spaces.py

+140
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
#!/usr/bin/env python
2+
import argparse
3+
import glob
4+
import logging
5+
import os
6+
import fnmatch
7+
import shutil
8+
import StringIO
9+
10+
11+
class Tabs2SpaceConverter(object):
12+
""" Convert tabs to spaces in text/source files. """
13+
def __init__(self, path=('.',), tab_stop=4, extension='*.py', pretend=False, log_level='DEBUG'):
14+
self.files_processed = 0
15+
16+
self.path = path
17+
self.tab_stop = tab_stop
18+
self.pretend = pretend
19+
self.extension = extension
20+
self.log_level = log_level
21+
22+
self._set_log()
23+
24+
def _set_log(self):
25+
logger = logging.getLogger()
26+
logger.setLevel(self.log_level)
27+
28+
fm = logging.Formatter('%(filename)s [LINE:%(lineno)d]# %(levelname)-8s [%(asctime)s] %(message)s')
29+
30+
console = logging.StreamHandler()
31+
console.setLevel(self.log_level)
32+
console.setFormatter(fm)
33+
34+
logger.addHandler(console)
35+
36+
def _prepare_path_list(self):
37+
logging.debug('path_arg: %s' % self.path)
38+
self.path_list = []
39+
40+
for path in self.path:
41+
self.path_list.extend(glob.glob(path))
42+
43+
logging.info('PATH: %s' % self.path_list)
44+
45+
def _process_paths(self):
46+
for path in self.path_list:
47+
48+
if os.path.isfile(path):
49+
self._process(path)
50+
51+
elif os.path.isdir(path):
52+
for root, dirs, files in os.walk(path):
53+
for filename in fnmatch.filter(files, self.extension):
54+
self._process(os.path.join(root, filename))
55+
else:
56+
raise TypeError('%s should be either dir or file' % path)
57+
58+
if self.pretend:
59+
logging.info('No actual changes was done, run without \'-p\' to overwrite source files')
60+
61+
logging.info('%d files processed' % self.files_processed)
62+
63+
def _process(self, path_):
64+
filepath = os.path.abspath(path_)
65+
changed = self._tabs_to_spaces(filepath)
66+
67+
if changed:
68+
self.files_processed += 1
69+
70+
def _tabs_to_spaces(self, file_name):
71+
def process_line(line_):
72+
return line_.replace('\t', ' ' * self.tab_stop)
73+
74+
logging.debug('Processing file: %s' % file_name)
75+
76+
was_changed = False
77+
temp_file = StringIO.StringIO()
78+
79+
with open(file_name) as f:
80+
for line in f:
81+
newline = process_line(line)
82+
83+
if newline != line:
84+
was_changed = True
85+
86+
temp_file.write(newline)
87+
88+
if was_changed:
89+
try:
90+
logging.debug('Replacing file %s' % file_name)
91+
92+
if not self.pretend:
93+
temp_file.seek(0)
94+
95+
with open(file_name, 'w') as f:
96+
shutil.copyfileobj(temp_file, f)
97+
except IOError:
98+
import traceback
99+
traceback.print_exc()
100+
101+
return was_changed
102+
103+
def run(self):
104+
self._prepare_path_list()
105+
self._process_paths()
106+
107+
108+
def parse_args():
109+
parser = argparse.ArgumentParser(description='Convert tabs to spaces in text/source files')
110+
111+
parser.add_argument('path', type=str, nargs='+', help='Path to scan')
112+
parser.add_argument('--tabstop', '-t', type=int, help='Number of spaces to replace tab symbol', default=4)
113+
parser.add_argument('--pretend', '-p', action='store_true', help='Don\'t actually change anything')
114+
parser.add_argument('--extension', '-e', type=str, help='File extension to replace tab symbol', default='*.py')
115+
parser.add_argument('--loglevel', '-l', type=str, help='Logging level', default='DEBUG')
116+
117+
return parser.parse_args()
118+
119+
120+
if __name__ == '__main__':
121+
config = parse_args()
122+
123+
t2sc = Tabs2SpaceConverter(path=config.path,
124+
tab_stop=config.tabstop,
125+
pretend=config.pretend,
126+
extension=config.extension,
127+
log_level=config.loglevel)
128+
t2sc.run()
129+
130+
# Example of output (converting 2 folders with 6 python scripts):
131+
# C:\Anaconda2\python.exe tab2spaces.py C:\site\123 C:\site\123_1
132+
# tab2spaces.py[LINE:37] # DEBUG [2016-12-29 17:24:36,234] path_arg: ['C:\\site\\123', 'C:\\site\\123_1']
133+
# tab2spaces.py[LINE:43] # INFO [2016-12-29 17:24:36,244] PATH: ['C:\\site\\123', 'C:\\site\\123_1']
134+
# tab2spaces.py[LINE:73] # DEBUG [2016-12-29 17:24:36,244] Processing file: C:\site\123\1 - (2).py
135+
# tab2spaces.py[LINE:73] # DEBUG [2016-12-29 17:24:36,244] Processing file: C:\site\123\1.py
136+
# tab2spaces.py[LINE:89] # DEBUG [2016-12-29 17:24:36,244] Replacing file C:\site\123\1.py
137+
# tab2spaces.py[LINE:73] # DEBUG [2016-12-29 17:24:36,244] Processing file: C:\site\123_1\1 - (2).py
138+
# tab2spaces.py[LINE:73] # DEBUG [2016-12-29 17:24:36,244] Processing file: C:\site\123_1\1.py
139+
# tab2spaces.py[LINE:89] # DEBUG [2016-12-29 17:24:36,244] Replacing file C:\site\123_1\1.py
140+
# tab2spaces.py[LINE:60] # INFO [2016-12-29 17:24:36,244] 6 files processed

0 commit comments

Comments
 (0)