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