##// END OF EJS Templates
%tasks shows elapsed time in min:sec
vivainio -
Show More
@@ -1,161 +1,162 b''
1 1 """ Preliminary "job control" extensions for IPython
2 2
3 3 requires python 2.4 (or separate 'subprocess' module
4 4
5 5 This provides 2 features, launching background jobs and killing foreground jobs from another IPython instance.
6 6
7 7 Launching background jobs:
8 8
9 9 Usage:
10 10
11 11 [ipython]|2> import jobctrl
12 12 [ipython]|3> &ls
13 13 <3> <jobctrl.IpyPopen object at 0x00D87FD0>
14 14 [ipython]|4> _3.go
15 15 -----------> _3.go()
16 16 ChangeLog
17 17 IPython
18 18 MANIFEST.in
19 19 README
20 20 README_Windows.txt
21 21
22 22 ...
23 23
24 24 Killing foreground tasks:
25 25
26 26 Launch IPython instance, run a blocking command:
27 27
28 28 [Q:/ipython]|1> import jobctrl
29 29 [Q:/ipython]|2> cat
30 30
31 31 Now launch a new IPython prompt and kill the process:
32 32
33 33 IPython 0.8.3.svn.r2919 [on Py 2.5]
34 34 [Q:/ipython]|1> import jobctrl
35 35 [Q:/ipython]|2> %tasks
36 36 6020: 'cat ' (Q:\ipython)
37 37 [Q:/ipython]|3> %kill
38 38 SUCCESS: The process with PID 6020 has been terminated.
39 39 [Q:/ipython]|4>
40 40
41 41 (you don't need to specify PID for %kill if only one task is running)
42 42 """
43 43
44 44 from subprocess import Popen,PIPE
45 45 import os,shlex,sys,time
46 46
47 47 from IPython import genutils
48 48
49 49 import IPython.ipapi
50 50
51 51 if os.name == 'nt':
52 52 def kill_process(pid):
53 53 os.system('taskkill /F /PID %d' % pid)
54 54 else:
55 55 def kill_process(pid):
56 56 os.system('kill -9 %d' % pid)
57 57
58 58
59 59
60 60 class IpyPopen(Popen):
61 61 def go(self):
62 62 print self.communicate()[0]
63 63 def __repr__(self):
64 64 return '<IPython job "%s" PID=%d>' % (self.line, self.pid)
65 65
66 66 def kill(self):
67 67 kill_process(self.pid)
68 68
69 69 def startjob(job):
70 70 p = IpyPopen(shlex.split(job), stdout=PIPE, shell = False)
71 71 p.line = job
72 72 return p
73 73
74 74 def jobctrl_prefilter_f(self,line):
75 75 if line.startswith('&'):
76 76 pre,fn,rest = self.split_user_input(line[1:])
77 77
78 78 line = ip.IP.expand_aliases(fn,rest)
79 79 return '_ip.startjob(%s)' % genutils.make_quoted_expr(line)
80 80
81 81 raise IPython.ipapi.TryNext
82 82
83 83
84 84 def job_list(ip):
85 85 keys = ip.db.keys('tasks/*')
86 86 ents = [ip.db[k] for k in keys]
87 87 return ents
88 88
89 89 def magic_tasks(self,line):
90 90 """ Show a list of tasks.
91 91
92 92 A 'task' is a process that has been started in IPython when 'jobctrl' extension is enabled.
93 93 Tasks can be killed with %kill.
94 94 """
95 95 ip = self.getapi()
96 96 ents = job_list(ip)
97 97 if not ents:
98 98 print "No tasks running"
99 99 for pid,cmd,cwd,t in ents:
100 print "%d: '%s' (%s)" % (pid,cmd,cwd)
100 dur = int(time.time()-t)
101 print "%d: '%s' (%s) %d:%02d" % (pid,cmd,cwd, dur / 60,dur%60)
101 102
102 103 def magic_kill(self,line):
103 104 """ Kill a task
104 105
105 106 Without args, either kill one task (if only one running) or show list (if many)
106 107 With arg, assume it's the process id.
107 108
108 109 %kill is typically (much) more powerful than trying to terminate a process with ctrl+C.
109 110 """
110 111 ip = self.getapi()
111 112 jobs = job_list(ip)
112 113
113 114 if not line.strip():
114 115 if len(jobs) == 1:
115 116 kill_process(jobs[0][0])
116 117 else:
117 118 magic_tasks(self,line)
118 119 return
119 120
120 121 try:
121 122 pid = int(line)
122 123 kill_process(pid)
123 124 except ValueError:
124 125 magic_tasks(self,line)
125 126
126 127 if sys.platform == 'win32':
127 128 shell_internal_commands = 'break chcp cls copy ctty date del erase dir md mkdir path prompt rd rmdir time type ver vol'.split()
128 129 else:
129 130 # todo linux commands
130 131 shell_internal_commands = []
131 132
132 133
133 134 def jobctrl_shellcmd(ip,cmd):
134 135 """ os.system replacement that stores process info to db['tasks/t1234'] """
135 136 cmdname = cmd.split(None,1)[0]
136 137 if cmdname in shell_internal_commands:
137 138 use_shell = True
138 139 else:
139 140 use_shell = False
140 141
141 142 p = Popen(cmd,shell = use_shell)
142 143 jobentry = 'tasks/t' + str(p.pid)
143 144
144 145 try:
145 146 ip.db[jobentry] = (p.pid,cmd,os.getcwd(),time.time())
146 147 p.communicate()
147 148 finally:
148 149 del ip.db[jobentry]
149 150
150 151
151 152 def install():
152 153 global ip
153 154 ip = IPython.ipapi.get()
154 155 # needed to make startjob visible as _ip.startjob('blah')
155 156 ip.startjob = startjob
156 157 ip.set_hook('input_prefilter', jobctrl_prefilter_f)
157 158 ip.set_hook('shell_hook', jobctrl_shellcmd)
158 159 ip.expose_magic('kill',magic_kill)
159 160 ip.expose_magic('tasks',magic_tasks)
160 161
161 162 install()
General Comments 0
You need to be logged in to leave comments. Login now