~yacinechaouche/+junk/BZR

« back to all changes in this revision

Viewing changes to PROG/TAHAR/ARCHIVES/naive_tahar_r9.1.py

  • Committer: yacinechaouche at yahoo
  • Date: 2015-01-14 22:23:03 UTC
  • Revision ID: yacinechaouche@yahoo.com-20150114222303-6gbtqqxii717vyka
Ajout de CODE et PROD. Il faudra ensuite ajouter ce qu'il y avait dan TMP

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#-*-encoding:utf-8-*-
 
2
"""
 
3
r1   : Première version très naïve, poc.
 
4
r2   : Traitement des modules n'étant pas dans le dossier courant
 
5
r3   : Traitement des dossiers (tous les fichiers python d'un dossier).
 
6
r4   : ? 
 
7
r5   : ? 
 
8
r6   : docstrings handling
 
9
r7   : correct handling of directories
 
10
r8   : correct handling of single files (bug probably introduced in r7)
 
11
r9.0 : gle stats
 
12
 
 
13
Nb of modules : 12
 
14
+ Module : mod1 => 102 loc
 
15
`--+ 306 functions => 3940 loc
 
16
   `-- function 1 : 20 loc
 
17
`--+ 49 classes => 2048 loc
 
18
   `--+ class MyClass => 92 loc
 
19
      `-- method1 : 30 loc
 
20
      `-- method2 : 38 loc
 
21
 
 
22
r9.1  : printing by + module
 
23
                 |
 
24
                 `-- functions
 
25
                 |
 
26
                 `-- classes
 
27
                  |
 
28
                  `-- methods
 
29
 
 
30
r10 : accept a --verbose option to enable/disable info prints
 
31
"""
 
32
 
 
33
import inspect
 
34
import sys
 
35
import os
 
36
import dircache
 
37
import pprint
 
38
 
 
39
class Inspector(object):
 
40
 
 
41
    def __init__(self,modules_names,max_length=25,stop_at_warning=False):
 
42
        self.modules_names        = modules_names
 
43
        self.max_length           = max_length
 
44
        self.loc                  = 0
 
45
        self.all_ok               = True
 
46
        self.stop_at_warning      = stop_at_warning
 
47
        self.stats                = {} # {module_name : {classes : {nb_methods:NBM,#loc=LOC}, nb_functions:NBF, #loc=LOC}, #loc : N}
 
48
        self.stats["#loc"]         = 0
 
49
 
 
50
 
 
51
    def print_stats(self):
 
52
        self.print_modules_stats()
 
53
        self.print_gl_stats()
 
54
        self.print_avg_stats()
 
55
        self.print_max_stats()
 
56
 
 
57
    def print_gl_stats(self):
 
58
        nb_modules        = len(self.stats) - 1
 
59
        self.nb_modules   = nb_modules
 
60
        total_loc         = self.stats["#loc"]
 
61
        nb_functions      = sum(map(lambda x: x!="#loc" and len(self.stats[x]["functions"] or 0),self.stats.keys()))
 
62
        self.nb_functions = nb_functions
 
63
        classes_stats     = filter(lambda x:x != {},
 
64
                               map(lambda module_name:module_name!="#loc" and self.stats[module_name]["classes"] or {},
 
65
                                   self.stats.keys()
 
66
                                   )
 
67
                               )
 
68
        pprint.pprint(classes_stats)
 
69
 
 
70
# [{'#loc': 134,
 
71
#   'Inspector': {'#loc': 134,
 
72
#                 'methods': {'__init__': 8,
 
73
#                             'print_class_stats': 28,
 
74
#                             'print_functions_stats': 14,
 
75
#                             'print_module_stats': 17,
 
76
#                             'print_modules_stats': 5,
 
77
#                             'print_stats': 28,
 
78
#                             'process_callables': 4,
 
79
#                             'process_modules': 30},
 
80
#                 'nb_methods': 8}}]
 
81
 
 
82
        extract_methods   = lambda tup:map(lambda class_name: class_name != "#loc" and tup[0][class_name]["methods"] or {},tup[1])
 
83
        extract_nbmethods = lambda tup:map(lambda class_name: class_name != "#loc" and tup[0][class_name]["nb_methods"] or 0,tup[1])
 
84
        methods_stats     = map(extract_methods,zip(classes_stats,map(lambda x:x.keys(),classes_stats)))
 
85
        pprint.pprint(methods_stats)
 
86
        nb_classes      = sum(map(lambda x:x != "#loc" and self.stats[x]["nb_classes"] or 0,self.stats.keys()))
 
87
        self.nb_classes = nb_classes
 
88
        nb_methods      = map(extract_nbmethods,zip(classes_stats,map(lambda x:x.keys(),classes_stats)))
 
89
        nb_methods      = len(nb_methods) > 1 and reduce(lambda x,y:sum(x)+sum(y) ,nb_methods) or sum(nb_methods[0])
 
90
        self.nb_methods = nb_methods
 
91
        
 
92
        print "Number of modules %s" % nb_modules        
 
93
        output     =  "Total : %s loc across %s modules containing %s functions, %s classes and %s methods."
 
94
        print output % (total_loc,nb_modules,nb_functions,nb_classes,nb_methods)
 
95
 
 
96
    def print_avg_stats(self):
 
97
        self.print_avg_functions_stats()
 
98
        self.print_avg_methods_stats()
 
99
        self.print_avg_classes_stats()
 
100
        self.print_avg_modules_stats()
 
101
 
 
102
    def print_avg_functions_stats(self):
 
103
        functions_loc = lambda x,y: x != "#loc" and y!="#loc" and self.stats[x]["functions"]["#loc"]+self.stats[y]['functions']["#loc"] or 0
 
104
        functions_loc = len(self.stats) > 1 and reduce(functions_loc,self.stats.keys()) or self.stats.values()[0]["functions"]["#loc"]
 
105
        func_avg_loc  = functions_loc * 1.0 / self.nb_functions
 
106
        print "avg loc per function : %s" % func_avg_loc
 
107
 
 
108
    def print_avg_methods_stats(self):
 
109
        methods_loc = sum([self.stats[module]["classes"]["#loc"] for module in self.stats.keys() if module != "#loc"])
 
110
        methods_loc_avg = 1.0 * methods_loc / self.nb_methods
 
111
        print "avg loc per method   : %s" % methods_loc_avg
 
112
 
 
113
    def print_avg_classes_stats(self):
 
114
        class_loc = sum([self.stats[module]["classes"][classname]["#loc"]
 
115
                         for module in self.stats.keys()
 
116
                         if module != "#loc"
 
117
                         for classname in self.stats[module]["classes"].keys()
 
118
                         if classname != "#loc"
 
119
                         ])
 
120
        
 
121
        class_avg_loc = 1.0 * class_loc / self.nb_classes
 
122
        print "avg loc per class    : %s" % class_avg_loc
 
123
 
 
124
    def print_avg_modules_stats(self):
 
125
        module_loc = 1.0 * self.stats["#loc"] / self.nb_modules
 
126
        print "avg loc per module   : %s" % module_loc
 
127
 
 
128
    def print_max_stats(self):
 
129
        print "longest function     : %s with %s loc"
 
130
        print "longest method       : %s with %s loc"
 
131
        print "longest class        : %s with %s loc"
 
132
        print "longest module       : %s with %s loc"
 
133
        
 
134
    def print_modules_stats(self):
 
135
        for module_name in self.stats.keys():
 
136
            if module_name == '#loc' :
 
137
                continue
 
138
            self.print_module_stats(module_name)
 
139
        
 
140
    def print_module_stats(self,module_name):
 
141
        output       = "+ Module %s => %s loc"
 
142
        module_dict  = self.stats[module_name]
 
143
        loc          = 0
 
144
        
 
145
        for function_name in module_dict["functions"]:
 
146
            if function_name == "#loc":
 
147
                continue
 
148
            
 
149
            loc += module_dict["functions"][function_name]
 
150
 
 
151
        for class_name in module_dict["classes"].keys():
 
152
            if class_name == '#loc':
 
153
                continue
 
154
            for method_name in module_dict["classes"][class_name]["methods"].keys():
 
155
                loc += module_dict["classes"][class_name]["methods"][method_name]
 
156
 
 
157
        output %= (module_name,loc)
 
158
        print output
 
159
        self.print_functions_stats(module_name)
 
160
        self.print_class_stats(module_name)
 
161
 
 
162
    def print_functions_stats(self,module_name):
 
163
        delayed_output      = []
 
164
        total_loc           = 0
 
165
        functions_names     = self.stats[module_name]["functions"].keys()
 
166
        longest_name_length = max(map(lambda x:len(x),functions_names))
 
167
        lnl                 = longest_name_length
 
168
        for function_name in functions_names:
 
169
            if function_name == '#loc':
 
170
                continue
 
171
 
 
172
            loc            = self.stats[module_name]["functions"][function_name]
 
173
            total_loc      += loc
 
174
            delayed_output.append(format_branch(3," "+function_name.ljust(lnl) + " => %s loc" %loc))
 
175
            
 
176
        print_branch(0,"+ %s functions => %s loc" % (len(self.stats[module_name]["functions"]),total_loc))
 
177
        print "\n".join(delayed_output)
 
178
        
 
179
    def print_class_stats(self,module_name):
 
180
        delayed_output = []
 
181
        total_loc = 0
 
182
        if not self.stats[module_name]["classes"]:
 
183
            return
 
184
        for class_name in self.stats[module_name]["classes"]:
 
185
            if class_name == '#loc':
 
186
                continue
 
187
            total_class_loc = 0
 
188
            nb_methods      = len(self.stats[module_name]["classes"][class_name]["methods"])
 
189
            methods_output  = []
 
190
            methods_names   = self.stats[module_name]["classes"][class_name]["methods"].keys()
 
191
            if not methods_names :
 
192
                continue
 
193
            longest_name_length = max(map(lambda x:len(x),methods_names))
 
194
            lnl                 = longest_name_length
 
195
            for method_name in methods_names :
 
196
                if method_name == '#loc':
 
197
                    continue
 
198
                methods_dict    = self.stats[module_name]["classes"][class_name]["methods"]
 
199
                loc             = methods_dict[method_name]
 
200
                total_class_loc += loc
 
201
                total_loc       += loc
 
202
                methods_output.append(format_branch(6," "+method_name.ljust(lnl) + " => %s loc" %loc))                
 
203
                
 
204
            delayed_output.append(format_branch(3,"+ class %s => %s loc over %s methods" % (class_name,total_class_loc,nb_methods)))
 
205
            delayed_output += methods_output
 
206
            
 
207
        print_branch(0,"+ %s classes => %s loc" % (len(self.stats[module_name]["classes"]),total_loc))
 
208
        print "\n".join(delayed_output)
 
209
            
 
210
    def process_modules(self):
 
211
        """
 
212
        main function of this class
 
213
        """
 
214
        for module_name in self.modules_names:
 
215
            # module_name could be a directory_name, therefor, we loop.
 
216
            for module in get_module(module_name):
 
217
                functions                                        = get_functions(module)
 
218
                classes                                          = get_classes(module)
 
219
                self.stats[module.__name__]                      = {}
 
220
                self.stats[module.__name__]["#loc"]              = 0
 
221
                self.stats[module.__name__]["functions"]         = {}
 
222
                self.stats[module.__name__]["functions"]["#loc"] = 0
 
223
                self.stats[module.__name__]["nb_functions"]      = len(functions)
 
224
                
 
225
                for function_name, loc in self.process_callables(functions):
 
226
                    self.stats[module.__name__]["functions"][function_name] = loc
 
227
                    self.stats[module.__name__]["functions"]["#loc"]        += loc
 
228
                    self.stats[module.__name__]["#loc"]                     += loc
 
229
                    self.stats["#loc"]                                      += loc
 
230
                    
 
231
                self.stats[module.__name__]["classes"]         = {}
 
232
                self.stats[module.__name__]["classes"]["#loc"] = 0
 
233
                self.stats[module.__name__]["nb_classes"]      = len(classes)
 
234
                
 
235
                for klass in classes :
 
236
                    methods                                                              = get_methods(klass)
 
237
                    self.stats[module.__name__]["classes"][klass.__name__]               = {}
 
238
                    self.stats[module.__name__]["classes"][klass.__name__]["#loc"]       = 0
 
239
                    self.stats[module.__name__]["classes"][klass.__name__]["methods"]    = {}
 
240
                    self.stats[module.__name__]["classes"][klass.__name__]["nb_methods"] = len(methods)
 
241
                    
 
242
                    for method_name,loc  in self.process_callables(methods):
 
243
                        self.stats[module.__name__]["classes"][klass.__name__]["methods"][method_name] = loc
 
244
                        self.stats[module.__name__]["classes"][klass.__name__]["#loc"]                 += loc
 
245
                        self.stats[module.__name__]["classes"]["#loc"]                                 += loc
 
246
                        self.stats[module.__name__]["#loc"]                                            += loc
 
247
                        self.stats["#loc"]                                                             += loc
 
248
 
 
249
    def process_callables(self,callables):
 
250
        for kallable in callables:
 
251
            loc = count_loc(inspect.getsourcelines(kallable)[0])
 
252
            yield kallable.__name__,loc
 
253
        
 
254
def print_branch(depth,s):
 
255
    print (depth != 0 and '|' or '') + " "*depth+"`--"+s
 
256
 
 
257
def format_branch(depth,s):
 
258
    return (depth != 0 and '|' or '') + " "*depth+"`--"+s
 
259
 
 
260
def repeat(kallable,times):
 
261
    for i in xrange(times):
 
262
        kallable()
 
263
 
 
264
def pretty_box(string):
 
265
    l = len(string)
 
266
    print "##"+"#"*l+"##"
 
267
    print "#",string,"#"
 
268
    print "##"+"#"*l+"##"
 
269
 
 
270
def add_to_path(dir_name):
 
271
    if dir_name not in sys.path:
 
272
        sys.path.append(dir_name)
 
273
        print "added '%s' to the path" % (dir_name)
 
274
    
 
275
def get_module(file_name):
 
276
    # if it's a directory return all modules and submodules recursively
 
277
    if os.path.isdir(file_name):
 
278
        dir_name = file_name
 
279
        add_to_path(dir_name)
 
280
        files = dircache.listdir(dir_name)
 
281
        for one_file in files:
 
282
            complete_file_name = os.path.join(dir_name,one_file)
 
283
            for module in get_module(complete_file_name):
 
284
                yield module
 
285
        
 
286
    elif file_name.endswith(".py"):
 
287
        exploded_path = file_name.split(".py")[0].split(os.sep)
 
288
        module_name   = exploded_path[-1]
 
289
        if "/" in file_name :
 
290
            dir_name = os.path.join(*exploded_path[:-1])
 
291
            add_to_path(dir_name)
 
292
 
 
293
        yield __import__(module_name)
 
294
 
 
295
def count_loc(lines):
 
296
    nb_lines  = 0
 
297
    docstring = False
 
298
    i         = 0
 
299
    for line in lines:
 
300
        line = line.strip()
 
301
 
 
302
        if line == "" \
 
303
           or line.startswith("#") \
 
304
           or docstring and not (line.startswith('"""') or line.startswith("'''"))\
 
305
           or (line.startswith("'''") and line.endswith("'''") and len(line) >3)  \
 
306
           or (line.startswith('"""') and line.endswith('"""') and len(line) >3) :
 
307
            continue
 
308
        
 
309
        # this is either a starting or ending docstring
 
310
        elif line.startswith('"""') or line.startswith("'''"):
 
311
            docstring = not docstring
 
312
            continue
 
313
 
 
314
        else:
 
315
            nb_lines += 1
 
316
        i+=1
 
317
 
 
318
    return nb_lines
 
319
 
 
320
def print_module_separator():
 
321
    print "#"*72
 
322
 
 
323
def print_class_separator():
 
324
    print "-"*36
 
325
 
 
326
print_functions_separator = print_class_separator
 
327
    
 
328
def print_module(module_name):
 
329
    pretty_box("Module :"+module_name)
 
330
    
 
331
def print_class(class_name):
 
332
    print "Class :",class_name
 
333
 
 
334
def get_functions(module):
 
335
    return get_callables(module,inspect.isfunction)
 
336
 
 
337
def get_methods(module):
 
338
    return get_callables(module,inspect.ismethod)
 
339
 
 
340
def get_callables(module,type_filter):
 
341
    return map(lambda x:x[1],inspect.getmembers(module,type_filter))
 
342
 
 
343
def get_classes(module):
 
344
    return map(lambda x:x[1],inspect.getmembers(module,inspect.isclass))
 
345
 
 
346
def main():
 
347
    modules_names = sys.argv[1:]
 
348
    if not modules_names:
 
349
        print "usage : %s FILE_OR_DIRECTORY ... " % sys.argv[0]
 
350
        exit(0)
 
351
 
 
352
    tahar = Inspector(modules_names)
 
353
    tahar.process_modules()
 
354
    tahar.print_stats()
 
355
        
 
356
def test_get_module():
 
357
    for module in get_module("."):
 
358
        print module
 
359
    
 
360
if __name__ == "__main__":
 
361
    main()
 
362