Mercurial > python-cmd2
annotate docs/pycon2010/pycon2010.rst @ 406:cc5c68e15a83
merged
author | Catherine Devlin <catherine.devlin@gmail.com> |
---|---|
date | Sun, 07 Nov 2010 09:20:33 -0500 |
parents | 32b9137577b8 |
children |
rev | line source |
---|---|
351 | 1 ================================================ |
2 Easy command-line interpreters with cmd and cmd2 | |
3 ================================================ | |
4 | |
5 :author: Catherine Devlin | |
6 :date: 2010-02-20 | |
374 | 7 :slides: http://pypi.python.org/pypi/cmd2 |
337 | 8 |
9 Web 2.0 | |
10 ======= | |
11 | |
12 .. image:: web-2-0-logos.gif | |
372 | 13 :height: 350px |
337 | 14 |
15 But first... | |
16 ============ | |
17 | |
18 .. image:: sargon.jpg | |
362 | 19 :height: 250px |
344 | 20 |
351 | 21 .. image:: akkad.png |
362 | 22 :height: 250px |
351 | 23 |
344 | 24 Sargon the Great |
25 Founder of Akkadian Empire | |
26 | |
27 .. twenty-third century BC | |
337 | 28 |
29 In between | |
30 ========== | |
31 | |
32 .. image:: apple.jpg | |
362 | 33 :height: 250px |
337 | 34 |
344 | 35 Command-Line Interface |
36 Unlike the Akkadian Empire, | |
37 the CLI will never die. | |
337 | 38 |
351 | 39 Defining CLI |
40 ============ | |
372 | 41 |
42 Also known as | |
344 | 43 |
44 - "Line-oriented command interpreter" | |
45 - "Command-line interface" | |
46 - "Shell" | |
337 | 47 |
345
6fe1e75e3a67
transcript test wasn't running pre and post cmd hooks
catherine@Drou
parents:
344
diff
changeset
|
48 1. Accepts free text input at prompt |
6fe1e75e3a67
transcript test wasn't running pre and post cmd hooks
catherine@Drou
parents:
344
diff
changeset
|
49 2. Outputs lines of text |
6fe1e75e3a67
transcript test wasn't running pre and post cmd hooks
catherine@Drou
parents:
344
diff
changeset
|
50 3. (repeat) |
337 | 51 |
52 Examples | |
53 ======== | |
54 | |
374 | 55 .. class:: big |
56 | |
57 * Bash, Korn, zsh | |
58 * Python shell | |
59 * screen | |
60 * Zork | |
61 * SQL clients: psql, SQL*\Plus, mysql... | |
62 * ed | |
344 | 63 |
64 .. ``ed`` proves that CLI is sometimes the wrong answer. | |
337 | 65 |
66 != Command Line Utilities | |
67 ========================= | |
68 | |
374 | 69 .. class:: big |
70 | |
71 (``ls``, ``grep``, ``ping``, etc.) | |
362 | 72 |
374 | 73 1. Accept arguments at invocation |
74 2. execute | |
75 3. terminate | |
337 | 76 |
374 | 77 Use ``sys.argv``, ``optparse`` |
337 | 78 |
374 | 79 !="Text User Interface" |
80 ======================= | |
337 | 81 |
344 | 82 * Use entire (session) screen |
83 * I/O is *not* line-by-line | |
372 | 84 * See ``curses``, ``urwid`` |
337 | 85 |
86 .. image:: urwid.png | |
362 | 87 :height: 250px |
337 | 88 |
89 | |
372 | 90 Decide your priorities |
91 ====================== | |
337 | 92 |
351 | 93 .. image:: strategy.png |
372 | 94 :height: 350px |
344 | 95 |
351 | 96 A ``cmd`` app: pirate.py |
97 ======================== | |
337 | 98 |
99 :: | |
100 | |
101 from cmd import Cmd | |
102 | |
103 class Pirate(Cmd): | |
104 pass | |
105 | |
106 pirate = Pirate() | |
107 pirate.cmdloop() | |
108 | |
351 | 109 .. Nothing here... but history and help |
344 | 110 |
111 .. ctrl-r for bash-style history | |
112 | |
113 Fundamental prrrinciple | |
114 ======================= | |
115 | |
351 | 116 .. class:: huge |
117 | |
374 | 118 ``(Cmd) foo a b c`` |
344 | 119 |
374 | 120 becomes |
121 | |
122 ``self.do_foo('a b c')`` | |
344 | 123 |
124 ``do_``-methods: pirate2.py | |
125 =========================== | |
126 | |
127 :: | |
128 | |
129 class Pirate(Cmd): | |
351 | 130 gold = 3 |
344 | 131 def do_loot(self, arg): |
132 'Seize booty frrrom a passing ship.' | |
133 self.gold += 1 | |
374 | 134 print('Now we gots {0} doubloons' |
135 .format(self.gold)) | |
344 | 136 def do_drink(self, arg): |
137 'Drown your sorrrows in rrrum.' | |
138 self.gold -= 1 | |
374 | 139 print('Now we gots {0} doubloons' |
140 .format(self.gold)) | |
344 | 141 |
142 .. do_methods; more help | |
143 | |
144 Hooks | |
145 ===== | |
146 | |
363 | 147 .. image:: hook.jpg |
362 | 148 :height: 250px |
344 | 149 |
374 | 150 :: |
151 | |
152 self.preloop() | |
153 self.postloop() | |
154 self.precmd(line) | |
155 self.postcmd(stop, line) | |
363 | 156 |
344 | 157 Hooks: pirate3.py |
158 ================= | |
159 | |
160 :: | |
337 | 161 |
351 | 162 def do_loot(self, arg): |
163 'Seize booty from a passing ship.' | |
164 self.gold += 1 | |
165 def do_drink(self, arg): | |
166 'Drown your sorrrows in rrrum.' | |
167 self.gold -= 1 | |
168 def precmd(self, line): | |
169 self.initial_gold = self.gold | |
170 return line | |
171 def postcmd(self, stop, line): | |
172 if self.gold != self.initial_gold: | |
374 | 173 print('Now we gots {0} doubloons' |
174 .format(self.gold)) | |
344 | 175 |
176 Arguments: pirate4.py | |
177 ===================== | |
178 | |
179 :: | |
180 | |
181 def do_drink(self, arg): | |
182 '''Drown your sorrrows in rrrum. | |
183 | |
184 drink [n] - drink [n] barrel[s] o' rum.''' | |
185 try: | |
186 self.gold -= int(arg) | |
187 except: | |
188 if arg: | |
345
6fe1e75e3a67
transcript test wasn't running pre and post cmd hooks
catherine@Drou
parents:
344
diff
changeset
|
189 print('''What's "{0}"? I'll take rrrum.''' |
6fe1e75e3a67
transcript test wasn't running pre and post cmd hooks
catherine@Drou
parents:
344
diff
changeset
|
190 .format(arg)) |
344 | 191 self.gold -= 1 |
192 | |
193 quitting: pirate5.py | |
194 ==================== | |
195 | |
196 :: | |
197 | |
351 | 198 def postcmd(self, stop, line): |
199 if self.gold != self.initial_gold: | |
374 | 200 print('Now we gots {0} doubloons' |
201 .format(self.gold)) | |
344 | 202 if self.gold < 0: |
374 | 203 print("Off to debtorrr's prison.") |
204 stop = True | |
344 | 205 return stop |
206 def do_quit(self, arg): | |
207 print("Quiterrr!") | |
351 | 208 return True |
344 | 209 |
374 | 210 prompts, defaults: pirate6.py |
211 ============================= | |
344 | 212 |
213 :: | |
214 | |
215 prompt = 'arrr> ' | |
216 def default(self, line): | |
345
6fe1e75e3a67
transcript test wasn't running pre and post cmd hooks
catherine@Drou
parents:
344
diff
changeset
|
217 print('What mean ye by "{0}"?' |
6fe1e75e3a67
transcript test wasn't running pre and post cmd hooks
catherine@Drou
parents:
344
diff
changeset
|
218 .format(line)) |
372 | 219 |
220 Other CLI packages | |
221 ================== | |
374 | 222 |
223 .. class:: big | |
224 | |
225 * CmdLoop | |
226 * cly | |
227 * CMdO | |
228 * pycopia | |
229 * cmdlin | |
230 * cmd2 | |
372 | 231 |
232 Demo | |
233 ==== | |
234 | |
374 | 235 .. class:: huge |
236 | |
237 Convert ``cmd`` app to ``cmd2`` | |
372 | 238 |
345
6fe1e75e3a67
transcript test wasn't running pre and post cmd hooks
catherine@Drou
parents:
344
diff
changeset
|
239 cmd2 |
6fe1e75e3a67
transcript test wasn't running pre and post cmd hooks
catherine@Drou
parents:
344
diff
changeset
|
240 ==== |
6fe1e75e3a67
transcript test wasn't running pre and post cmd hooks
catherine@Drou
parents:
344
diff
changeset
|
241 |
351 | 242 .. image:: schematic.png |
372 | 243 :height: 350px |
345
6fe1e75e3a67
transcript test wasn't running pre and post cmd hooks
catherine@Drou
parents:
344
diff
changeset
|
244 |
373 | 245 As you wish, Guido |
246 ================== | |
247 | |
374 | 248 .. class:: huge |
249 | |
250 Python 3 compatible | |
373 | 251 |
252 (um, mostly) | |
253 | |
347
432ccab7c6c8
going to try moving output redirection to outside precmd, postcmd hooks
catherine@Drou
parents:
346
diff
changeset
|
254 Absolutely free |
432ccab7c6c8
going to try moving output redirection to outside precmd, postcmd hooks
catherine@Drou
parents:
346
diff
changeset
|
255 =============== |
345
6fe1e75e3a67
transcript test wasn't running pre and post cmd hooks
catherine@Drou
parents:
344
diff
changeset
|
256 |
374 | 257 Script files |
258 | |
259 Commands at invocation | |
260 | |
261 Output redirection | |
262 | |
263 Python | |
264 | |
265 Transcript testing | |
347
432ccab7c6c8
going to try moving output redirection to outside precmd, postcmd hooks
catherine@Drou
parents:
346
diff
changeset
|
266 |
432ccab7c6c8
going to try moving output redirection to outside precmd, postcmd hooks
catherine@Drou
parents:
346
diff
changeset
|
267 But wait, there's more |
432ccab7c6c8
going to try moving output redirection to outside precmd, postcmd hooks
catherine@Drou
parents:
346
diff
changeset
|
268 ====================== |
432ccab7c6c8
going to try moving output redirection to outside precmd, postcmd hooks
catherine@Drou
parents:
346
diff
changeset
|
269 |
432ccab7c6c8
going to try moving output redirection to outside precmd, postcmd hooks
catherine@Drou
parents:
346
diff
changeset
|
270 * Abbreviated commands |
432ccab7c6c8
going to try moving output redirection to outside precmd, postcmd hooks
catherine@Drou
parents:
346
diff
changeset
|
271 * Shell commands |
432ccab7c6c8
going to try moving output redirection to outside precmd, postcmd hooks
catherine@Drou
parents:
346
diff
changeset
|
272 * Quitting |
432ccab7c6c8
going to try moving output redirection to outside precmd, postcmd hooks
catherine@Drou
parents:
346
diff
changeset
|
273 * Timing |
432ccab7c6c8
going to try moving output redirection to outside precmd, postcmd hooks
catherine@Drou
parents:
346
diff
changeset
|
274 * Echo |
432ccab7c6c8
going to try moving output redirection to outside precmd, postcmd hooks
catherine@Drou
parents:
346
diff
changeset
|
275 * Debug |
345
6fe1e75e3a67
transcript test wasn't running pre and post cmd hooks
catherine@Drou
parents:
344
diff
changeset
|
276 |
351 | 277 Minor changes: pirate7.py |
278 ========================= | |
279 | |
280 :: | |
347
432ccab7c6c8
going to try moving output redirection to outside precmd, postcmd hooks
catherine@Drou
parents:
346
diff
changeset
|
281 |
351 | 282 default_to_shell = True |
283 multilineCommands = ['sing'] | |
284 terminators = Cmd.terminators + ['...'] | |
356 | 285 songcolor = 'blue' |
286 settable = Cmd.settable + 'songcolor Color to ``sing`` in (red/blue/green/cyan/magenta, bold, underline)' | |
287 Cmd.shortcuts.update({'~': 'sing'}) | |
351 | 288 def do_sing(self, arg): |
356 | 289 print(self.colorize(arg, self.songcolor)) |
290 | |
291 Now how much would you pay? | |
292 =========================== | |
293 | |
374 | 294 options / flags |
295 | |
296 Quiet (suppress feedback) | |
297 | |
298 BASH-style ``select`` | |
299 | |
300 Parsing: terminators, suffixes | |
351 | 301 |
302 Options: pirate8.py | |
303 =================== | |
304 | |
305 :: | |
347
432ccab7c6c8
going to try moving output redirection to outside precmd, postcmd hooks
catherine@Drou
parents:
346
diff
changeset
|
306 |
375 | 307 @options([make_option('--ho', type='int', default=2, |
308 help="How often to chant 'ho'"), | |
309 make_option('-c', '--commas', | |
310 action="store_true", | |
311 help="Intersperse commas")]) | |
351 | 312 def do_yo(self, arg, opts): |
313 chant = ['yo'] + ['ho'] * opts.ho | |
372 | 314 separator = ', ' if opts.commas else ' ' |
352 | 315 chant = separator.join(chant) |
372 | 316 print('{0} and a bottle of {1}' |
317 .format(chant, arg)) | |
362 | 318 |
319 Serious example: sqlpython | |
320 ========================== | |
321 | |
374 | 322 .. class:: big |
323 | |
324 ``cmd``-based app by Luca Canali @ CERN | |
362 | 325 |
374 | 326 Replacement for Oracle SQL\*Plus |
362 | 327 |
374 | 328 Now ``cmd2``-based; postgreSQL; MySQL |
357 | 329 |
376
32b9137577b8
avoiding 'str doesn't support the buffer api' exception
cat@eee
parents:
375
diff
changeset
|
330 File reporter |
32b9137577b8
avoiding 'str doesn't support the buffer api' exception
cat@eee
parents:
375
diff
changeset
|
331 ============= |
32b9137577b8
avoiding 'str doesn't support the buffer api' exception
cat@eee
parents:
375
diff
changeset
|
332 |
32b9137577b8
avoiding 'str doesn't support the buffer api' exception
cat@eee
parents:
375
diff
changeset
|
333 .. class:: huge |
32b9137577b8
avoiding 'str doesn't support the buffer api' exception
cat@eee
parents:
375
diff
changeset
|
334 |
32b9137577b8
avoiding 'str doesn't support the buffer api' exception
cat@eee
parents:
375
diff
changeset
|
335 Gather info: Python |
32b9137577b8
avoiding 'str doesn't support the buffer api' exception
cat@eee
parents:
375
diff
changeset
|
336 |
32b9137577b8
avoiding 'str doesn't support the buffer api' exception
cat@eee
parents:
375
diff
changeset
|
337 Store: postgresql |
32b9137577b8
avoiding 'str doesn't support the buffer api' exception
cat@eee
parents:
375
diff
changeset
|
338 |
32b9137577b8
avoiding 'str doesn't support the buffer api' exception
cat@eee
parents:
375
diff
changeset
|
339 Report: html |
32b9137577b8
avoiding 'str doesn't support the buffer api' exception
cat@eee
parents:
375
diff
changeset
|
340 |
32b9137577b8
avoiding 'str doesn't support the buffer api' exception
cat@eee
parents:
375
diff
changeset
|
341 fileutil.py |
32b9137577b8
avoiding 'str doesn't support the buffer api' exception
cat@eee
parents:
375
diff
changeset
|
342 =========== |
32b9137577b8
avoiding 'str doesn't support the buffer api' exception
cat@eee
parents:
375
diff
changeset
|
343 |
32b9137577b8
avoiding 'str doesn't support the buffer api' exception
cat@eee
parents:
375
diff
changeset
|
344 :: |
32b9137577b8
avoiding 'str doesn't support the buffer api' exception
cat@eee
parents:
375
diff
changeset
|
345 |
32b9137577b8
avoiding 'str doesn't support the buffer api' exception
cat@eee
parents:
375
diff
changeset
|
346 import glob |
32b9137577b8
avoiding 'str doesn't support the buffer api' exception
cat@eee
parents:
375
diff
changeset
|
347 import os.path |
32b9137577b8
avoiding 'str doesn't support the buffer api' exception
cat@eee
parents:
375
diff
changeset
|
348 |
32b9137577b8
avoiding 'str doesn't support the buffer api' exception
cat@eee
parents:
375
diff
changeset
|
349 for fullfilename in glob.glob('/home/cat/proj/cmd2/*.py'): |
32b9137577b8
avoiding 'str doesn't support the buffer api' exception
cat@eee
parents:
375
diff
changeset
|
350 (dirpath, fname) = os.path.split(fullfilename) |
32b9137577b8
avoiding 'str doesn't support the buffer api' exception
cat@eee
parents:
375
diff
changeset
|
351 stats = os.stat(fullfilename) |
32b9137577b8
avoiding 'str doesn't support the buffer api' exception
cat@eee
parents:
375
diff
changeset
|
352 binds['path'] = dirpath |
32b9137577b8
avoiding 'str doesn't support the buffer api' exception
cat@eee
parents:
375
diff
changeset
|
353 binds['name'] = fname |
32b9137577b8
avoiding 'str doesn't support the buffer api' exception
cat@eee
parents:
375
diff
changeset
|
354 binds['bytes'] = stats.st_size |
32b9137577b8
avoiding 'str doesn't support the buffer api' exception
cat@eee
parents:
375
diff
changeset
|
355 cmd("""INSERT INTO cat.files (path, name, bytes) |
32b9137577b8
avoiding 'str doesn't support the buffer api' exception
cat@eee
parents:
375
diff
changeset
|
356 VALUES (%(path)s, %(name)s, %(bytes)s)""") |
32b9137577b8
avoiding 'str doesn't support the buffer api' exception
cat@eee
parents:
375
diff
changeset
|
357 quit() |
32b9137577b8
avoiding 'str doesn't support the buffer api' exception
cat@eee
parents:
375
diff
changeset
|
358 |
362 | 359 sqlpython features |
360 ================== | |
361 | |
374 | 362 .. class:: big |
363 | |
364 * from ``cmd2``: scripts, redirection, | |
365 py, etc. | |
366 * multiple connections | |
367 * UNIX: ls, cat, grep | |
368 * Special output | |
357 | 369 |
362 | 370 |
372 | 371 Thank you |
372 ========= | |
357 | 373 |
374 | 374 .. class:: big |
375 | |
376 http://pypi.python.org/pypi/cmd2 | |
372 | 377 |
374 | 378 http://catherinedevlin.blogspot.com |
372 | 379 |
374 | 380 http://catherinedevlin.pythoneers.com |
357 | 381 |
363 | 382 |