1 """
2 Support functions for parsing command-line arguments and providing
3 the Topographica command prompt. Typically called from the
4 './topographica' script, but can be called directly if using
5 Topographica files within a separate Python.
6
7 $Id: commandline.py 11301 2010-07-27 16:19:54Z ceball $
8 """
9 __version__='$Revision: 11301 $'
10
11
12 from optparse import OptionParser
13
14 import sys, __main__, math, os, re
15
16 import topo
17 from param.parameterized import Parameterized,OptionalSingleton
18
19
20 try:
21
22 from matplotlib import rcParams
23 rcParams['backend']='Agg'
24 matplotlib_imported=True
25 except ImportError:
26 matplotlib_imported=False
27
28
29 try:
30 import IPython.Shell
31 ipython_imported=True
32 except ImportError:
33 ipython_imported=False
34 print "Note: IPython is not available; using basic interactive Python prompt instead."
35
36
37
38
39 BANNER = """
40 Welcome to Topographica!
41
42 Type help() for interactive help with python, help(topo) for general
43 information about Topographica, help(commandname) for info on a
44 specific command, or topo.about() for info on this release, including
45 licensing information.
46 """
50 """
51 A Parameterized class providing script-level parameters.
52
53 Script-level parameters can be set from the commandline by passing
54 via -p, e.g. ./topographica -p retina_density=10
55
56 Within scripts, parameters can be declared by using the add()
57 method.
58
59
60 Example usage in a script:
61
62 from topo.misc.commandline import global_params as p
63 p.add(
64 retina_density=param.Number(default=24.0,bounds=(0,None),
65 inclusive_bounds=(False,True),doc=\"""
66 The nominal_density to use for the retina.\"""))
67 ...
68 topo.sim['Retina']=sheet.GeneratorSheet(
69 nominal_density=p.retina_density)
70
71
72 Further information:
73
74 'context' is usually set to __main__.__dict__ and is used to find
75 the value of a parameter as it is add()ed to this object
76 (i.e. add() has access to values set via the commandline or in
77 scripts).
78
79 Values set via set_in_context() or exec_in_context() (used by -p)
80 are tracked: warnings are issued for overwritten values, and
81 unused values can be warned about via check_for_unused_names().
82
83 The context is not saved in snapshots, but parameter values are
84 saved.
85 """
86 context = None
87
90
91 - def __init__(self,context=None,**params):
96
104
105 - def set_in_context(self,**params):
106 """
107 Set in self.context all name=val pairs specified in **params,
108 tracking new names and warning of any replacements.
109 """
110 for name,val in params.items():
111 if name in self.context:
112 self.warning("Replacing previous value of '%s' with '%s'"%(name,val))
113 self.context[name]=val
114 self.unused_names.add(name)
115
116 - def exec_in_context(self,arg):
117 """
118 exec arg in self.context, tracking new names and
119 warning of any replacements.
120 """
121
122
123 current_ids = dict([(k,id(v)) for k,v in self.context.items()])
124
125 exec arg in self.context
126
127 for k,v in self.context.items():
128 if k in self.unused_names and id(v)!=current_ids[k]:
129 self.warning("Replacing previous value of '%s' with '%s'"%(k,v))
130
131 new_names = set(self.context.keys()).difference(set(current_ids.keys()))
132 for k in new_names:
133 self.unused_names.add(k)
134
151
152
153 - def add(self,**kw):
154 """
155 For each parameter_name=parameter_object specified in kw:
156 * adds the parameter_object to this object's class
157 * if there is an entry in context that has the same name as the parameter,
158 sets the value of the parameter in this object to that value, and then removes
159 the name from context
160 """
161 for p_name,p_obj in kw.items():
162 self._add_parameter(p_name,p_obj)
163 if p_name in self.context:
164 setattr(self,p_name,self.context[p_name])
165 if p_name in self.unused_names:
166
167 del self.context[p_name]
168 self.unused_names.remove(p_name)
169
170
171 global_params=GlobalParams(context=__main__.__dict__)
178 """
179 Allows control over IPython's dynamic command prompts.
180 """
181 _format = ''
182 _prompt = ''
183
184 @classmethod
195
196 @classmethod
202
205 """
206 Control over input prompt.
207
208 Several predefined formats are provided, and any of these (or any
209 arbitrary string) can be used by calling set_format() with their
210 values.
211
212 See the IPython manual for details:
213 http://ipython.scipy.org/doc/manual/html/config/index.html
214
215 Examples:
216 # Use one of the predefined formats:
217 CommandPrompt.set_format(CommandPrompt.basic_format)
218 # Just print the command number:
219 CommandPrompt.set_format('\# ')
220 # Print the command number but don't use color:
221 CommandPrompt.set_format('\N ')
222 # Print the value of my_var at each prompt:
223 CommandPrompt.set_format('${my_var}>>> ')
224 """
225 _prompt = 'prompt1'
226
227
228 basic_format = 'Topographica>>> '
229 simtime_format = 'topo_t${topo.sim.timestr()}>>> '
230 simtimecmd_format = 'topo_t${topo.sim.timestr()}_c\\#>>> '
231
232 _format = simtimecmd_format
233
244
255
256
257
258
259
260
261 global_constants = {'pi':math.pi}
262
263
264 usage = "usage: topographica ([<option>]:[<filename>])*\n\
265 where any combination of options and Python script filenames will be\n\
266 processed in order left to right."
267 topo_parser = OptionParser(usage=usage)
271 """
272 Set the simulation title from the given filename, if none has been
273 set already.
274 """
275 if topo.sim.name is None:
276 topo.sim.name=re.sub('.ty$','',os.path.basename(filename))
277
280 """Callback function for boolean-valued options that apply to the entire run."""
281
282 setattr(parser.values,option.dest,True)
283
286 os.environ['PYTHONINSPECT']='1'
287
288
289
290 -def i_action(option,opt_str,value,parser):
294
295 topo_parser.add_option("-i","--interactive",action="callback",callback=i_action,
296 dest="interactive",default=False,
297 help="provide an interactive prompt even if stdin does not appear to be a terminal.")
298
299
300 -def v_action(option,opt_str,value,parser):
305
306 topo_parser.add_option("-v","--verbose",action="callback",callback=v_action,dest="verbose",default=False,help="""\
307 enable verbose messaging output.""")
308
309
310 -def d_action(option,opt_str,value,parser):
315
316 topo_parser.add_option("-d","--debug",action="callback",callback=d_action,dest="debug",default=False,help="""\
317 enable debugging message output (implies --verbose).""")
318
319
320
321 -def l_action(option,opt_str,value,parser):
327
328 topo_parser.add_option("-l","--legacy",action="callback",callback=l_action,dest="legacy",default=False,help="""\
329 launch Topographica with legacy support enabled.""")
330
331
332 -def gui(start=True):
340
341
342
343
344 -def g_action(option,opt_str,value,parser):
349
350
351 topo_parser.add_option("-g","--gui",action="callback",callback=g_action,dest="gui",default=False,help="""\
352 launch an interactive graphical user interface; \
353 equivalent to -c 'from topo.misc.commandline import gui ; gui()'. \
354 Implies -a.""")
355
356
357
358 something_executed=False
359
360 -def c_action(option,opt_str,value,parser):
366
367 topo_parser.add_option("-c","--command",action = "callback",callback=c_action,type="string",
368 default=[],dest="commands",metavar="\"<command>\"",
369 help="string of arbitrary Python code to be executed in the main namespace.")
370
371
372
373 -def p_action(option,opt_str,value,parser):
378
379 topo_parser.add_option("-p","--set-parameter",action = "callback",callback=p_action,type="string",
380 default=[],dest="commands",metavar="\"<command>\"",
381 help="command specifying value(s) of script-level (global) Parameter(s).")
385 """Import the contents of all files in the topo/command/ directory."""
386 import re,os
387 import topo
388 import __main__
389
390
391
392 topo_path = os.path.join(os.path.split(topo.__file__)[0],"command")
393 for f in os.listdir(topo_path):
394 if re.match('^[^_.].*\.py$',f):
395 modulename = re.sub('\.py$','',f)
396 exec "from topo.command."+modulename+" import *" in __main__.__dict__
397
398 -def a_action(option,opt_str,value,parser):
401
402 topo_parser.add_option("-a","--auto-import-commands",action="callback",callback=a_action,help="""\
403 import everything from commands/*.py into the main namespace, for convenience; \
404 equivalent to -c 'from topo.misc.commandline import auto_import_commands ; auto_import_commands()'.""")
409 """
410 Execute startup files, looking at appropriate locations for many different platforms.
411 """
412 home = os.path.expanduser("~")
413 appdata = os.path.expandvars("$APPDATA")
414 appsupport = os.path.join(home,"Library","Application Support")
415
416 rcpath = os.path.join(home,'.topographicarc')
417 inipath = os.path.join(appdata,'Topographica','topographica.ini')
418 configpath = os.path.join(appsupport,'Topographica','topographica.config')
419
420 for startup_file in (rcpath,configpath,inipath):
421 if os.path.exists(startup_file):
422 print "Executing user startup file %s" % (startup_file)
423 execfile(startup_file,__main__.__dict__)
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455 -def process_argv(argv):
456 """
457 Process command-line arguments (minus argv[0]!), rearrange and execute.
458 """
459
460 import __main__
461 for (k,v) in global_constants.items():
462 exec '%s = %s' % (k,v) in __main__.__dict__
463
464 exec_startup_files()
465
466
467 topo_parser.disable_interspersed_args()
468 args=argv
469 option=None
470 global something_executed
471 while True:
472
473 (option,args) = topo_parser.parse_args(args,option)
474
475
476 if args:
477 filename=args.pop(0)
478
479 filedir = os.path.dirname(os.path.abspath(filename))
480 sys.path.insert(0,filedir)
481 sim_name_from_filename(filename)
482
483 execfile(filename,__main__.__dict__)
484 something_executed=True
485
486 if not args:
487 break
488
489 global_params.check_for_unused_names()
490
491
492 if not something_executed: interactive()
493
494 if option.gui: topo.guimain.title(topo.sim.name)
495
496
497
498 if os.environ.get('PYTHONINSPECT'):
499 print BANNER
500
501
502
503
504 if ipython_imported:
505
506
507 __main__.__name__="__mynamespace__"
508
509 IPython.Shell.IPShell(
510 ['-noconfirm_exit','-nobanner',
511 '-pi1',CommandPrompt.get_format(),
512 '-pi2',CommandPrompt2.get_format(),
513 '-po',OutputPrompt.get_format()],
514 user_ns=__main__.__dict__).mainloop(sys_exit=1)
515