ATLAS Offline Software
Interactive.py
Go to the documentation of this file.
1 # Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
2 
3 """Utilities for the interactive athena prompt."""
4 
5 import os
6 import sys
7 import re
8 import AthenaCommon.Utils.unixtools as unixtools
9 from AthenaCommon.Logging import log
10 
11 _shellCommands = [ 'echo', 'emacs', 'env', 'ls', 'less', 'more', 'pico', 'vi' ]
12 _unacceptable = [ 'false', 'true', 'sys' ]
13 _NAME = 'name'
14 _NAMEREX = re.compile( r"named? '?(?P<%s>[\w\d]+)'?" % _NAME )
15 
16 
17 
19  """Provide shell escapes from the prompt by catching name and syntax errors."""
20 
21  def __init__( self ):
22  self._orig_ehook = sys.excepthook
23  log.debug( 'shell short-cuts enabled' )
24 
25  def uninstall( self ):
26  sys.excepthook = self._orig_ehook
27  log.debug( 'shell short-cuts disabled' )
28 
29  def __call__( self, exctype, value, traceb ):
30  global _shellCommands
31 
32  cmd = None
33 
34  # catch name and syntax errors to perform shell escapes if known
35  if isinstance( value, NameError ):
36  res = _NAMEREX.search( str(value) )
37  if res:
38  cmd = res.group( _NAME )
39 
40  # disallow selected commands/executables
41  if cmd in _unacceptable:
42  cmd = None
43 
44  elif isinstance( value, SyntaxError ):
45  cmd = value.text[:-1]
46 
47  # execute command, if any
48  if cmd is not None:
49  args = cmd.split()
50  exe = args[0]
51 
52  # special cases
53  if exe == 'cd' and len(args) == 2:
54  os.chdir( args[1] )
55  log.info( 'new directory: %s', os.getcwd() )
56  return
57 
58  if exe == 'help' and len(args) == 2:
59  import __main__
60  exec ('help( %s )' % args[1] in __main__.__dict__, __main__.__dict__)
61  return
62 
63  # cache shell command
64  if exe not in _shellCommands:
65  log.debug( 'accepting executable "%s"', exe )
66  if unixtools.which( exe ):
67  _shellCommands.append( exe )
68  else:
69  exe = None
70 
71  if exe is not None:
72  log.debug( 'executing shell command "%s"', cmd )
73  os.system( cmd )
74  return
75 
76  # nothing recognizable: normal exception processing
77  self._orig_ehook( exctype, value, traceb )
78 
79 
80 def configureInteractivePrompt(completionDict = None):
81  """Configure interactive prompt. The optional completionDict is used to
82  configure the readline completer."""
83 
84  # Athena-specific command history
85  import atexit
86  import readline
87  import rlcompleter # noqa: F401 (needed for completion)
88 
89  fhistory = os.path.expanduser( '~/.athena.history' )
90 
91  if completionDict is not None:
92  readline.set_completer(rlcompleter.Completer(completionDict).complete)
93 
94  readline.parse_and_bind( 'tab: complete' )
95  readline.parse_and_bind( 'set show-all-if-ambiguous On' )
96 
97  if os.path.exists( fhistory ):
98  readline.read_history_file( fhistory )
99 
100  readline.set_history_length( 1024 )
101 
102  # save history on exit
103  atexit.register( readline.write_history_file, fhistory )
104 
105  # enable shell commands in interactive prompt
106  sys.excepthook = ShellEscapes()
python.Interactive.ShellEscapes
LazyPython based hook for shell commands ====================================.
Definition: Interactive.py:18
python.Interactive.ShellEscapes.__init__
def __init__(self)
Definition: Interactive.py:21
python.Interactive.configureInteractivePrompt
def configureInteractivePrompt(completionDict=None)
Definition: Interactive.py:80
python.Interactive.ShellEscapes.uninstall
def uninstall(self)
Definition: Interactive.py:25
python.Interactive.ShellEscapes.__call__
def __call__(self, exctype, value, traceb)
Definition: Interactive.py:29
python.Interactive.ShellEscapes._orig_ehook
_orig_ehook
Definition: Interactive.py:22
str
Definition: BTagTrackIpAccessor.cxx:11