2
r5 : make the arguments in the Cmd completable to children keys when user inserts a >
5
will complete to the keys of the #modules node.
6
r6 : implement shell functionalities :
7
r6.1 o ls (with completion) : replace ">" with "/" to simulate directories
8
r6.2 o ls -l : each function,module,classe etc. with its lines of code.
9
Permissions are replaced with the type of the node
10
r6.3 o cd : descend one node
11
r6.4 o cat : display node's code
12
r6.5 o find : search for a node's name
13
r6.6 o grep : look for a string in the code
23
def raise_problem(function):
24
def wrapper(*args,**kw):
26
return function(*args,**kw)
28
print traceback.print_exc()
31
class CodeBrowser(cmd.Cmd):
32
def __init__(self,stat):
33
cmd.Cmd.__init__(self)
34
self.prompt = "root > "
35
self.stat = stat.stats
36
self.current_node = self.stat["#modules"]
38
def path(self,node=None):
40
node = self.current_node
41
parent = node.get("#parent")
43
return node.get("#name","root")
44
parents_path = self.path(parent)
45
parents_type = parent.get("#type")
46
nodes_type = node.get("#type","?")
47
nodes_name = node.get("#name","?")
49
if nodes_type == "class" :
51
elif nodes_type == "function":
52
if parents_type == "class":
56
elif nodes_type == "module":
58
elif nodes_type in ("modules","classes","functions","class_code","module_code","methods"):
60
return "/".join([parents_path,chunk,nodes_name])
62
def change_node(self,dst,error_msg="",node=None):
63
next_node = self.current_node.get(dst)
65
self.current_node = next_node
70
print "this node has no attribute named",dst
71
self.prompt = self.path()+"> "
75
def do_name(self,line="",node=None):
77
node = self.current_node
78
print node.get("#name")
82
def do_path(self,line="",node=None):
84
node = self.current_node
85
print self.path(node=node)
89
def do_show(self,line="",node=None):
91
node = self.current_node
93
self.do_name(node=node)
95
self.do_path(node=node)
97
self.do_keys(node=node)
101
def do_keys(self,line="",node=None):
103
node = self.current_node
106
do_k = do_down = do_keys
108
def do_parent(self,line="",node=None):
110
node = self.current_node
111
self.change_node("#parent","this node has no parent",node=node)
113
do_up = do_u = do_parent
115
## def do_functions(self,line=""):
116
## self.change_node("#functions","this node has no functions")
118
## def do_methods(self,line=""):
119
## self.change_node("#methods","this node has no methods")
121
## def do_modules(self,line=""):
122
## self.change_node("#modules","this node has no modules")
124
## def do_loc(self,line=""):
125
## loc = self.current_node.get("#loc")
129
## print "This node has no #loc key. This is a bug. Please report it"
131
## def do_type(self,line=""):
132
## print self.current_node.get("#type")
134
# def do_select(self,line=""):
135
# node = line.split(":")[0]
136
# self.change_node(node)
138
def default(self,line=""):
139
x = self._get_element(line)
146
def completenames(self,*args):
148
keys = self.current_node.keys()
149
## if user_input.startswith("#"):
150
## user_input = user_input[1:]
151
return [key for key in self.current_node.keys() if key.startswith(user_input)]
154
def completedefault_old(self,*args):
155
#print "completedefault",args
156
user_input = args[1].split(">")
157
node = self.current_node
158
for element in user_input:
159
x = node.get(element)
165
if element.startswith("#"):
166
L = [key[1:] or key for key in keys if key.startswith(element)]
168
L = [key for key in keys if key.startswith(element)]
169
#print "keys are", keys
170
# L = [key.startswith("#") and key[1:] or key for key in keys if key.startswith(element)]
174
def _get_element(self,path):
176
Returns a node or a content, depending on what node.get(element) returns.
178
elements = path.split(">")
179
node = self.current_node
180
for element in elements :
181
x = node.get(element)
188
def do_ls(self,line=""):
189
current_type = self.current_node.get("#type")
190
current_name = self.current_node.get("#name")
191
if current_type == "module":
192
self._list_module(self.current_node)
194
elif current_type == "modules":
195
self._list_modules(self.current_node)
197
elif current_type == "class":
198
self._list_class(self.current_node)
201
def _list_class(self,klass=None):
203
# XXX dangerous assumption
204
klass = self.current_node
206
subclasses_names = [sub for sub in klass.get("#classes",{}).keys() if not sub.startswith("#")]
207
methods_names = [sub for sub in klass.get("#methods",{}).keys() if not sub.startswith("#")]
208
max_length = max(map(lambda x:len(x),subclasses_names+methods_names))
210
for subclass_name in subclasses_names :
211
print "\t".join(("class",subclass_name.ljust(max_length),str(klass["classes"].get(subclass_name).get("#loc")).rjust(6)))
213
for method_name in methods_names :
214
print "\t".join(("method",method_name.ljust(max_length),str(klass["#methods"].get(method_name).get("#loc")).rjust(6)))
216
def _list_modules(self,module=None):
218
module = self.current_node
219
modules_names = [module_name for module_name in module.keys() if not module_name.startswith("#")]
220
max_length = max(map(lambda x:len(x),modules_names+["#modules"]))
222
for module_name in modules_names:
223
print "\t".join(("m",module_name.ljust(max_length),str(module.get(module_name).get("#loc"))))
225
def _list_module(self,module=None):
227
module = self.current_node
229
module_info = module.get("#name"),str(module.get("#loc"))
230
classes = [klass_name for klass_name in module.get("#classes").keys() if not klass_name.startswith("#")]
231
functions = [function_name for function_name in module.get("#functions").keys() if not function_name.startswith("#")]
234
max_name_length = max(map(lambda x:len(x),functions+classes))
236
classes_info = [(klass_name.ljust(max_name_length),
237
str(module.get("#classes").get(klass_name).get("#loc")).rjust(6))
238
for klass_name in classes]
240
functions_info = [(function_name.ljust(max_name_length),
241
str(module.get("#functions").get(function_name).get("#loc")).rjust(6))
242
for function_name in functions]
244
print "Total : "+"\t".join(module_info)
245
for class_info in classes_info:
246
print "class".ljust(8)+"\t"+"\t".join(class_info)
247
for function_info in functions_info:
248
print "function".ljust(8)+"\t"+"\t".join(function_info)
250
def do_cd(self,line=""):
253
self.prompt = self.path()+"> "
256
node = self.get_node(line)
258
self.current_node = node
259
self.prompt = self.path()+"> "
262
def do_cat(self,line):
263
node = self.get_node(line)
266
def get_node(self,path):
267
elements = path.split("/")
268
node = self.current_node
269
for i,element in enumerate(elements):
270
x = self.fetch(element,node)
279
def fetch(self,element,node):
281
return node.get(element)
283
for branch in "#modules","#methods","#functions","#classes" :
284
branch_node = node.get(branch,{})
285
if element in branch_node.keys():
286
return branch_node.get(element)
289
def completedefault(self,*args):
291
# print "user_input",user_input
292
arg = user_input.split(" ")[1]
293
last_arg = arg.split("/")[-1]
294
node = self.get_node(arg)
295
if not node: # de-fense !
296
node = self.current_node
298
for branch in "#modules","#methods","#functions","#classes" :
299
keys += node.get(branch,{}).keys()
300
completions = [key for key in keys if key.startswith(last_arg) and not "#" in key]
302
completions = [completion[1:] for completion in completions]
303
# print "last_arg",last_arg
304
if len(completions) == 1:
305
completions[0] = completions[0] + "/"
309
if len(sys.argv) < 2 :
312
file_path = sys.argv[1]
313
st = tahar.SourceStats(file_path)
315
CodeBrowser(st).cmdloop()
319
print sys.argv[0],"file_path"
323
if __name__ == "__main__":