22# -*- coding: utf-8 -*-
33
44import os
5- import re
65from collections import defaultdict
76from code_counter .conf .config import Config
7+ from code_counter .core .countable .iterator import CountableFileIterator
88
99
1010class CodeCounter :
@@ -20,7 +20,6 @@ def __init__(self):
2020
2121 self .search_args = None
2222 self .lines_of_language = {}
23- self .pattern = None
2423
2524 self .result = {
2625 'total' : {
@@ -43,35 +42,50 @@ def setSearchArgs(self, args):
4342
4443 self .lines_of_language = {suffix : 0 for suffix in self .config .suffix }
4544
46- regex = r'.*\.({})$' .format ('|' .join (self .config .suffix ))
47- self .pattern = re .compile (regex )
48-
4945 def search (self ):
50- if not self .search_args :
51- raise Exception ('search_args is None, please invoke setSearchArgs first.' )
46+ if self .search_args is None :
47+ raise Exception ('search_args is None, please invoke the ` setSearchArgs` function first.' )
5248
5349 input_path = self .search_args .input_path
54- output_path = self .search_args .output_path
50+ if not input_path :
51+ print ('{} is not a validate path.' .format (input_path ))
52+ return
5553
54+ output_path = self .search_args .output_path
5655 output_file = open (output_path , 'w' ) if output_path else None
5756
5857 if self .search_args .verbose :
59- print ('\n \t {}' .format ("SEARCHING" ), file = output_file )
60- print ("\t {}" .format ('=' * 20 ), file = output_file )
61- print ('\t {:>10} |{:>10} |{:>10} |{:>10} |{:>10} | {}'
62- .format ("File Type" , "Lines" , "Code" , "Blank" , "Comment" , "File Path" ), file = output_file )
63- print ("\t {}" .format ('-' * 90 ), file = output_file )
64-
65- if not input_path :
66- print ('{} is not a validate path.' .format (input_path ))
67- return
58+ self .print_searching_verbose_info (output_file )
6859
6960 for path in input_path :
7061 if os .path .exists (path ):
71- self .__search (path , output_file )
62+ for cf in CountableFileIterator (path ):
63+ cf .count ()
64+ if self .search_args .verbose :
65+ print (cf , file = output_file )
66+ self .files_of_language [cf .file_type ] += 1
67+ self .total_file_lines += cf .file_lines
68+ self .total_code_lines += cf .code_lines
69+ self .total_blank_lines += cf .blank_lines
70+ self .total_comment_lines += cf .comment_lines
71+ self .lines_of_language [cf .file_type ] += cf .code_lines
7272 else :
7373 print ('{} is not a validate path.' .format (path ))
74+ exit (1 )
75+
76+ self .print_result_info (output_file )
77+
78+ if output_file :
79+ output_file .close ()
80+
81+ def print_searching_verbose_info (self , output_file = None ):
82+ print ('\n \t {}' .format ("SEARCHING" ), file = output_file )
83+ print ("\t {}" .format ('=' * 20 ), file = output_file )
84+ print ('\t {:>10} |{:>10} |{:>10} |{:>10} |{:>10} | {}'
85+ .format ("File Type" , "Lines" , "Code" , "Blank" , "Comment" , "File Path" ), file = output_file )
86+ print ("\t {}" .format ('-' * 90 ), file = output_file )
7487
88+ def print_result_info (self , output_file = None ):
7589 print ('\n \t {}' .format ("RESULT" ), file = output_file )
7690 print ("\t {}" .format ('=' * 20 ), file = output_file )
7791 print ("\t {:<20}:{:>8} ({:>7})"
@@ -109,106 +123,11 @@ def search(self):
109123
110124 for tp , cnt in self .files_of_language .items ():
111125 code_line = self .lines_of_language [tp ]
126+ self .result ['code' ][tp ] = code_line
127+ self .result ['file' ][tp ] = cnt
112128 print ("\t {:>10} |{:>10} |{:>10} |{:>10} |{:>10}" .format (
113129 tp , cnt , '%.2f%%' % (cnt / total_files * 100 ),
114130 code_line , '%.2f%%' % (code_line / self .total_code_lines * 100 )), file = output_file )
115- self .result ['code' ][tp ] = code_line
116- self .result ['file' ][tp ] = cnt
117-
118- if output_file :
119- output_file .close ()
120-
121- def __search (self , input_path , output_file = None ):
122- """
123- :param input_path: input file path
124- :param output_file: output file path
125- :return:
126- """
127- if os .path .isdir (input_path ):
128- files = os .listdir (input_path )
129- for file in files :
130- file_path = os .path .join (input_path , file )
131- if os .path .isdir (file_path ):
132- if os .path .split (file_path )[- 1 ] in self .config .ignore :
133- continue
134- self .__search (file_path , output_file )
135- elif os .path :
136- file_path = os .path .join (input_path , file )
137- self .__format_output (file_path , output_file )
138- elif os .path .isfile (input_path ):
139- self .__format_output (input_path , output_file )
140-
141- def __format_output (self , file_path , output_file = None ):
142- """
143- :param file_path: input file path
144- :param output_file: output file path
145- :return:
146- """
147- try :
148- res = re .match (self .pattern , file_path )
149- if res :
150- single = self .count_single (file_path , output_file )
151- file_lines = single ['file_lines' ]
152- code_lines = single ['code_lines' ]
153- blank_lines = single ['blank_lines' ]
154- comment_lines = single ['comment_lines' ]
155-
156- file_type = os .path .splitext (file_path )[1 ][1 :]
157- self .files_of_language [file_type ] += 1
158-
159- if self .search_args .verbose :
160- print ('\t {:>10} |{:>10} |{:>10} |{:>10} |{:>10} | {}'
161- .format (file_type , file_lines , code_lines , blank_lines , comment_lines , file_path ),
162- file = output_file )
163-
164- self .total_file_lines += file_lines
165- self .total_code_lines += code_lines
166- self .total_blank_lines += blank_lines
167- self .total_comment_lines += comment_lines
168- self .lines_of_language [file_type ] += code_lines
169- except AttributeError as e :
170- print (e )
171-
172- def count_single (self , file_path , output_file = None ):
173- """
174- :param file_path: the file you want to count
175- :param output_file: output file path
176- :return: single { file_lines, code_lines, blank_lines, comment_lines }
177- """
178- assert os .path .isfile (file_path ), "Function: 'code_counter' need a file path, but {} is not." .format (file_path )
179-
180- single = {
181- 'file_lines' : 0 ,
182- 'code_lines' : 0 ,
183- 'blank_lines' : 0 ,
184- 'comment_lines' : 0 ,
185- }
186-
187- with open (file_path , 'rb' ) as handle :
188- for line_number , raw_line in enumerate (handle ):
189- try :
190- line = raw_line .strip ().decode ('utf8' )
191- except UnicodeDecodeError :
192- try :
193- # If the code line contain Chinese string, decode it as gbk
194- line = raw_line .strip ().decode ('gbk' )
195- except UnicodeDecodeError :
196- if self .search_args .verbose :
197- print ('\n \t {:>10} | decode line occurs a problem, non-count it, at File "{}", line {}:'
198- .format ('WARN' , file_path , line_number ),
199- file = output_file )
200- print ('\t {:>10} | {}\n '
201- .format (' ' , raw_line ))
202- continue
203-
204- single ['file_lines' ] += 1
205- if not line :
206- single ['blank_lines' ] += 1
207- elif line .startswith (tuple (self .config .comment )):
208- single ['comment_lines' ] += 1
209- else :
210- single ['code_lines' ] += 1
211- return single
212131
213132 def visualize (self ):
214133 from matplotlib import pyplot as plt
0 commit comments