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