1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 """The prompt based relax user interface (UI)."""
25
26
27 import dep_check
28
29
30 import ansi
31 from code import InteractiveConsole, softspace
32 from math import pi
33 from os import F_OK, access, chdir, getcwd, path
34 from re import search
35 if dep_check.readline_module:
36 import readline
37 if dep_check.runpy_module:
38 import runpy
39 from string import split
40 import sys
41
42
43 from info import Info_box
44 from prompt.command import Ls, Lh, Ll, system
45 from prompt.gpl import GPL
46 from prompt.help import _Helper, _Helper_python
47 if dep_check.readline_module:
48 from prompt.tab_completion import Tab_completion
49 from prompt.uf_objects import Class_container, Uf_object
50 from relax_errors import AllRelaxErrors, RelaxBinError, RelaxError, RelaxNoneError, RelaxStrError
51 from status import Status; status = Status()
52 from user_functions.data import Uf_info; uf_info = Uf_info()
53
54
55
56
57
58
59 PS1_ORIG = 'relax> '
60 PS2_ORIG = 'relax| '
61 PS3_ORIG = '\n%s' % PS1_ORIG
62
63
64 PS1_COLOUR = "%s%s%s" % (ansi.relax_prompt, PS1_ORIG, ansi.end)
65 PS2_COLOUR = "%s%s%s" % (ansi.relax_prompt, PS2_ORIG, ansi.end)
66 PS3_COLOUR = "\n%s%s%s" % (ansi.relax_prompt, PS1_ORIG, ansi.end)
67
68
70 - def __init__(self, show_script=True, quit=True, raise_relax_error=False):
71 """The interpreter class.
72
73 @param show_script: If true, the relax will print the script contents prior to
74 executing the script.
75 @type show_script: bool
76 @param quit: If true, the default, then relax will exit after running the
77 run() method.
78 @type quit: bool
79 @param raise_relax_error: If false, the default, then relax will print a nice error
80 message to STDERR, without a traceback, when a RelaxError
81 occurs. This is to make things nicer for the user.
82 @type raise_relax_error: bool
83 """
84
85
86 self.__show_script = show_script
87 self.__quit_flag = quit
88 self.__raise_relax_error = raise_relax_error
89
90
91 info = Info_box()
92 self.__intro_string = info.intro_text()
93
94
95 if ansi.enable_control_chars(stream=1):
96 self.prompt_colour_on()
97 else:
98 self.prompt_colour_off()
99
100
101 self._locals = self._setup()
102
103
105 """Private method for executing the given user function.
106
107 @keyword uf_name: The name of the user function.
108 @type uf_name: str
109 """
110
111
112 if 'uf_name' not in kargs:
113 raise RelaxError("The user function name argument 'uf_name' has not been supplied.")
114
115
116 uf_name = kargs.pop('uf_name')
117
118
119 if search('\.', uf_name):
120 class_name, uf_name = split(uf_name, '.')
121 else:
122 class_name = None
123
124
125 if class_name:
126 class_obj = self._locals[class_name]
127
128
129 if class_name:
130 uf = getattr(class_obj, uf_name)
131 else:
132 uf = self._locals[uf_name]
133
134
135 uf(*args, **kargs)
136
137
139 """Set up all the interpreter objects.
140
141 All objects are initialised and placed in a dictionary. These will be later placed in different namespaces such as the run() method local namespace. All the user functions and classes will be auto-generated.
142
143 @return: The dictionary of interpreter objects.
144 @rtype: dict
145 """
146
147
148 objects = {}
149
150
151 objects['pi'] = pi
152
153
154 objects['lh'] = Lh()
155 objects['ll'] = Ll()
156 objects['ls'] = Ls()
157 objects['system'] = system
158
159
160 objects['gpl'] = objects['GPL'] = GPL()
161
162
163 objects['intro_off'] = self.off
164 objects['intro_on'] = self.on
165 objects['exit'] = objects['bye'] = objects['quit'] = objects['q'] = _Exit()
166
167
168 objects['help_python'] = _Helper_python()
169 objects['help'] = _Helper()
170
171
172 for name, data in uf_info.class_loop():
173
174 obj = Class_container(name, data.title)
175
176
177 objects[name] = obj
178
179
180 self._uf_dict = {}
181 for name, data in uf_info.uf_loop():
182
183 if search('\.', name):
184 class_name, uf_name = split(name, '.')
185 else:
186 class_name = None
187
188
189 obj = Uf_object(name, title=data.title, kargs=data.kargs, backend=data.backend, desc=data.desc)
190
191
192 if class_name:
193 class_obj = objects[class_name]
194
195
196 if class_name:
197 setattr(class_obj, uf_name, obj)
198 else:
199 objects[name] = obj
200
201
202 self._uf_dict[name] = obj
203
204
205 return objects
206
207
208 - def off(self, verbose=True):
209 """Turn the user function introductions off."""
210
211 status.uf_intro = False
212
213
214 if verbose:
215 print("Echoing of user function calls has been disabled.")
216
217
218 - def on(self, verbose=True):
219 """Turn the user function introductions on."""
220
221 status.uf_intro = True
222
223
224 if verbose:
225 print("Echoing of user function calls has been enabled.")
226
227
229 """Place all special objects into self."""
230
231
232 for name in self._locals.keys():
233 setattr(self, name, self._locals[name])
234
235
242
243
250
251
252 - def run(self, script_file=None):
253 """Run the python interpreter.
254
255 The namespace of this function is the namespace seen inside the interpreter. All user
256 accessible functions, classes, etc, should be placed in this namespace.
257
258
259 @param script_file: The script file to be executed. For the interpreter mode, this
260 should be left as None.
261 @type script_file: None or str
262 """
263
264
265 for name in self._locals.keys():
266 locals()[name] = self._locals[name]
267
268
269 if dep_check.readline_module:
270 readline.set_completer(Tab_completion(name_space=locals()).finish)
271 readline.set_completer_delims(' \t\n`~!@#$%^&*()=+{}\\|;:",<>/?')
272 readline.parse_and_bind("tab: complete")
273
274
275 if script_file:
276
277 status.uf_intro = True
278
279
280 return run_script(intro=self.__intro_string, local=locals(), script_file=script_file, quit=self.__quit_flag, show_script=self.__show_script, raise_relax_error=self.__raise_relax_error)
281
282
283 else:
284 prompt(intro=self.__intro_string, local=locals())
285
286
287
290 """Exit the program."""
291
292 print("Exiting the program.")
293 sys.exit()
294
295
296
298 """Execute the script."""
299
300
301 status.exec_lock.acquire('script UI', mode='script')
302
303
304 head, tail = path.split(name)
305 script_path = path.join(getcwd(), head)
306 sys.path.append(script_path)
307
308
309 if head:
310 orig_dir = getcwd()
311 chdir(head)
312
313
314 module, ext = path.splitext(tail)
315
316
317 if search('\.', module):
318 raise RelaxError("The relax script must not contain the '.' character (except before the extension '*.py').")
319 if ext != '.py':
320 raise RelaxError("The script must have the extension *.py.")
321
322
323 try:
324
325 sys.path.reverse()
326
327
328 if dep_check.runpy_module:
329 runpy.run_module(module, globals)
330
331
332 else:
333 exec(compile(open(name).read(), name, 'exec'), globals)
334
335 finally:
336
337 if head:
338 chdir(orig_dir)
339
340
341 sys.path.reverse()
342 sys.path.pop(sys.path.index(script_path))
343
344
345 status.exec_lock.release()
346
347
349 """Replacement function for 'code.InteractiveConsole.interact'.
350
351 This will enter into the prompt.
352
353 @param intro: The string to print prior to jumping to the prompt mode.
354 @type intro: str
355 @param local: A namespace which will become that of the prompt (i.e. the namespace visible to
356 the user when in the prompt mode). This should be the output of a function such
357 as locals().
358 @type local: dict
359 """
360
361
362 if intro:
363 sys.stdout.write("%s\n" % intro)
364
365
366
367
368
369 more = False
370 while True:
371 try:
372 if more:
373 prompt = sys.ps2
374 else:
375 prompt = sys.ps1
376 try:
377 line = self.raw_input(prompt)
378 except EOFError:
379 self.write("\n")
380 break
381 else:
382 more = self.push(line)
383 except KeyboardInterrupt:
384 self.write("\nKeyboardInterrupt\n")
385 self.resetbuffer()
386 more = False
387
388
389 -def interact_script(self, intro=None, local={}, script_file=None, quit=True, show_script=True, raise_relax_error=False):
390 """Replacement function for 'code.InteractiveConsole.interact'.
391
392 This will execute the script file.
393
394
395 @param intro: The string to print prior to jumping to the prompt mode.
396 @type intro: str
397 @param local: A namespace which will become that of the prompt (i.e. the namespace
398 visible to the user when in the prompt mode). This should be the
399 output of a function such as locals().
400 @type local: dict
401 @param script_file: The script file to be executed.
402 @type script_file: None or str
403 @param quit: If true, the default, then relax will exit after running the script.
404 @type quit: bool
405 @param show_script: If true, the relax will print the script contents prior to executing
406 the script.
407 @type show_script: bool
408 @param raise_relax_error: If false, the default, then a nice error message will be sent to
409 STDERR, without a traceback, when a RelaxError occurs. This is to
410 make things nicer for the user.
411 @type raise_relax_error: bool
412 """
413
414
415 if intro:
416 sys.stdout.write("%s\n" % intro)
417
418
419 if show_script:
420 try:
421 file = open(script_file, 'r')
422 except IOError, warning:
423 try:
424 raise RelaxError("The script file '" + script_file + "' does not exist.")
425 except AllRelaxErrors, instance:
426 sys.stdout.write(instance.__str__())
427 sys.stdout.write("\n")
428 return
429
430
431 if ansi.enable_control_chars(stream=1):
432 sys.stdout.write(ansi.script)
433
434
435 sys.stdout.write("script = " + repr(script_file) + "\n")
436 sys.stdout.write("----------------------------------------------------------------------------------------------------\n")
437 sys.stdout.write(file.read())
438 sys.stdout.write("----------------------------------------------------------------------------------------------------")
439
440
441 if ansi.enable_control_chars(stream=1):
442 sys.stdout.write(ansi.end)
443
444
445 sys.stdout.write("\n")
446
447
448 file.close()
449
450
451 exec_pass = True
452
453
454 try:
455 exec_script(script_file, local)
456
457
458 except KeyboardInterrupt:
459
460 status.exec_lock.release()
461
462
463 if status.debug:
464 raise
465
466
467 else:
468 sys.stderr.write("\nScript execution cancelled.\n")
469
470
471 exec_pass = False
472
473
474 except AllRelaxErrors, instance:
475
476 status.exec_lock.release()
477
478
479 if raise_relax_error:
480 raise
481
482
483 else:
484
485 if status.debug:
486 self.showtraceback()
487
488
489 else:
490 sys.stderr.write(instance.__str__())
491
492
493 exec_pass = False
494
495
496 except:
497
498 status.exec_lock.release()
499
500
501 raise
502
503
504 if show_script:
505 sys.stdout.write("\n")
506
507
508
509
510
511
512
513 return exec_pass
514
515
516 -def prompt(intro=None, local=None):
517 """Python interpreter emulation.
518
519 This function replaces 'code.interact'.
520
521
522 @param intro: The string to print prior to jumping to the prompt mode.
523 @type intro: str
524 @param local: A namespace which will become that of the prompt (i.e. the namespace visible to
525 the user when in the prompt mode). This should be the output of a function such
526 as locals().
527 @type local: dict
528 """
529
530
531 InteractiveConsole.interact = interact_prompt
532 InteractiveConsole.runcode = runcode
533
534
535 console = InteractiveConsole(local)
536 console.interact(intro, local)
537
538
539 -def run_script(intro=None, local=None, script_file=None, quit=True, show_script=True, raise_relax_error=False):
540 """Python interpreter emulation.
541
542 This function replaces 'code.interact'.
543
544
545 @param intro: The string to print prior to jumping to the prompt mode.
546 @type intro: str
547 @param local: A namespace which will become that of the prompt (i.e. the namespace
548 visible to the user when in the prompt mode). This should be the
549 output of a function such as locals().
550 @type local: dict
551 @param script_file: The script file to be executed.
552 @type script_file: None or str
553 @param quit: If true, the default, then relax will exit after running the script.
554 @type quit: bool
555 @param show_script: If true, the relax will print the script contents prior to executing
556 the script.
557 @type show_script: bool
558 @param raise_relax_error: If false, the default, then a nice error message will be sent to
559 STDERR, without a traceback, when a RelaxError occurs. This is to
560 make things nicer for the user.
561 @type raise_relax_error: bool
562 """
563
564
565 InteractiveConsole.interact = interact_script
566 InteractiveConsole.runcode = runcode
567
568
569 console = InteractiveConsole(local)
570 return console.interact(intro, local, script_file, quit, show_script=show_script, raise_relax_error=raise_relax_error)
571
572
574 """Replacement code for code.InteractiveInterpreter.runcode.
575
576 @param code: The code to execute.
577 @type code: str
578 """
579
580 try:
581 exec(code, self.locals)
582 except SystemExit:
583 raise
584 except AllRelaxErrors, instance:
585 self.write(instance.__str__())
586 self.write("\n")
587 except:
588 self.showtraceback()
589 else:
590 if softspace(sys.stdout, 0):
591 print('')
592