1# Copyright 2016 The TensorFlow Authors. All Rights Reserved. 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14# ============================================================================== 15"""Base Class of TensorFlow Debugger (tfdbg) Command-Line Interface.""" 16from __future__ import absolute_import 17from __future__ import division 18from __future__ import print_function 19 20import argparse 21 22from tensorflow.python.debug.cli import cli_config 23from tensorflow.python.debug.cli import command_parser 24from tensorflow.python.debug.cli import debugger_cli_common 25 26 27class BaseUI(object): 28 """Base class of tfdbg user interface.""" 29 30 CLI_PROMPT = "tfdbg> " 31 CLI_EXIT_COMMANDS = ["exit", "quit"] 32 ERROR_MESSAGE_PREFIX = "ERROR: " 33 INFO_MESSAGE_PREFIX = "INFO: " 34 35 def __init__(self, on_ui_exit=None, config=None): 36 """Constructor of the base class. 37 38 Args: 39 on_ui_exit: (`Callable`) the callback to be called when the UI exits. 40 config: An instance of `cli_config.CLIConfig()` carrying user-facing 41 configurations. 42 """ 43 44 self._on_ui_exit = on_ui_exit 45 46 self._command_handler_registry = ( 47 debugger_cli_common.CommandHandlerRegistry()) 48 49 self._tab_completion_registry = debugger_cli_common.TabCompletionRegistry() 50 51 # Create top-level tab-completion context and register the exit and help 52 # commands. 53 self._tab_completion_registry.register_tab_comp_context( 54 [""], self.CLI_EXIT_COMMANDS + 55 [debugger_cli_common.CommandHandlerRegistry.HELP_COMMAND] + 56 debugger_cli_common.CommandHandlerRegistry.HELP_COMMAND_ALIASES) 57 58 self._config = config or cli_config.CLIConfig() 59 self._config_argparser = argparse.ArgumentParser( 60 description="config command", usage=argparse.SUPPRESS) 61 subparsers = self._config_argparser.add_subparsers() 62 set_parser = subparsers.add_parser("set") 63 set_parser.add_argument("property_name", type=str) 64 set_parser.add_argument("property_value", type=str) 65 set_parser = subparsers.add_parser("show") 66 self.register_command_handler( 67 "config", 68 self._config_command_handler, 69 self._config_argparser.format_help(), 70 prefix_aliases=["cfg"]) 71 72 def set_help_intro(self, help_intro): 73 """Set an introductory message to the help output of the command registry. 74 75 Args: 76 help_intro: (RichTextLines) Rich text lines appended to the beginning of 77 the output of the command "help", as introductory information. 78 """ 79 80 self._command_handler_registry.set_help_intro(help_intro=help_intro) 81 82 def register_command_handler(self, 83 prefix, 84 handler, 85 help_info, 86 prefix_aliases=None): 87 """A wrapper around CommandHandlerRegistry.register_command_handler(). 88 89 In addition to calling the wrapped register_command_handler() method, this 90 method also registers the top-level tab-completion context based on the 91 command prefixes and their aliases. 92 93 See the doc string of the wrapped method for more details on the args. 94 95 Args: 96 prefix: (str) command prefix. 97 handler: (callable) command handler. 98 help_info: (str) help information. 99 prefix_aliases: (list of str) aliases of the command prefix. 100 """ 101 102 self._command_handler_registry.register_command_handler( 103 prefix, handler, help_info, prefix_aliases=prefix_aliases) 104 105 self._tab_completion_registry.extend_comp_items("", [prefix]) 106 if prefix_aliases: 107 self._tab_completion_registry.extend_comp_items("", prefix_aliases) 108 109 def register_tab_comp_context(self, *args, **kwargs): 110 """Wrapper around TabCompletionRegistry.register_tab_comp_context().""" 111 112 self._tab_completion_registry.register_tab_comp_context(*args, **kwargs) 113 114 def run_ui(self, 115 init_command=None, 116 title=None, 117 title_color=None, 118 enable_mouse_on_start=True): 119 """Run the UI until user- or command- triggered exit. 120 121 Args: 122 init_command: (str) Optional command to run on CLI start up. 123 title: (str) Optional title to display in the CLI. 124 title_color: (str) Optional color of the title, e.g., "yellow". 125 enable_mouse_on_start: (bool) Whether the mouse mode is to be enabled on 126 start-up. 127 128 Returns: 129 An exit token of arbitrary type. Can be None. 130 """ 131 132 raise NotImplementedError("run_ui() is not implemented in BaseUI") 133 134 def _parse_command(self, command): 135 """Parse a command string into prefix and arguments. 136 137 Args: 138 command: (str) Command string to be parsed. 139 140 Returns: 141 prefix: (str) The command prefix. 142 args: (list of str) The command arguments (i.e., not including the 143 prefix). 144 output_file_path: (str or None) The path to save the screen output 145 to (if any). 146 """ 147 command = command.strip() 148 if not command: 149 return "", [], None 150 151 command_items = command_parser.parse_command(command) 152 command_items, output_file_path = command_parser.extract_output_file_path( 153 command_items) 154 155 return command_items[0], command_items[1:], output_file_path 156 157 def _analyze_tab_complete_input(self, text): 158 """Analyze raw input to tab-completer. 159 160 Args: 161 text: (str) the full, raw input text to be tab-completed. 162 163 Returns: 164 context: (str) the context str. For example, 165 If text == "print_tensor softmax", returns "print_tensor". 166 If text == "print", returns "". 167 If text == "", returns "". 168 prefix: (str) the prefix to be tab-completed, from the last word. 169 For example, if text == "print_tensor softmax", returns "softmax". 170 If text == "print", returns "print". 171 If text == "", returns "". 172 except_last_word: (str) the input text, except the last word. 173 For example, if text == "print_tensor softmax", returns "print_tensor". 174 If text == "print_tensor -a softmax", returns "print_tensor -a". 175 If text == "print", returns "". 176 If text == "", returns "". 177 """ 178 text = text.lstrip() 179 if not text: 180 # Empty (top-level) context. 181 context = "" 182 prefix = "" 183 except_last_word = "" 184 else: 185 items = text.split(" ") 186 if len(items) == 1: 187 # Single word: top-level context. 188 context = "" 189 prefix = items[0] 190 except_last_word = "" 191 else: 192 # Multiple words. 193 context = items[0] 194 prefix = items[-1] 195 except_last_word = " ".join(items[:-1]) + " " 196 197 return context, prefix, except_last_word 198 199 @property 200 def config(self): 201 """Obtain the CLIConfig of this `BaseUI` instance.""" 202 return self._config 203 204 def _config_command_handler(self, args, screen_info=None): 205 """Command handler for the "config" command.""" 206 del screen_info # Currently unused. 207 208 parsed = self._config_argparser.parse_args(args) 209 if hasattr(parsed, "property_name") and hasattr(parsed, "property_value"): 210 # set. 211 self._config.set(parsed.property_name, parsed.property_value) 212 return self._config.summarize(highlight=parsed.property_name) 213 else: 214 # show. 215 return self._config.summarize() 216