• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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