def _ask_command(command): if not console_utils.stdin_is_interactive(): return None if platform.system() == 'Windows': other = 'windows' else: other = 'unix' choices = {'b': 'bokeh_app', 'c': other, 'n': 'notebook'} while True: data = console_utils.console_input( "Is `{}` a (B)okeh app, (N)otebook, or (C)ommand line? ".format( command)) data = data.lower().strip() if len(data) == 0 or data[0] not in choices: print("Please enter 'b', 'n', or 'c'.") print( " A Bokeh app is the project-relative path to a Bokeh script or app directory." ) print( " A notebook file is the project-relative path to a .ipynb file." ) print( " A command line is any command you might type at the command prompt." ) continue return choices[data]
def load_project(dirname): """Load a Project, fixing it if needed and possible.""" project = Project(dirname, frontend=CliFrontend(), must_exist=True) # No sense in engaging the user if we cannot achieve a fixed state. if project.unfixable_problems: return project if console_utils.stdin_is_interactive(): regressions = 0 problems = project.fixable_problems while problems and regressions < 3: # Instead of looping through the problems in the list, we # fix only the first one and refresh the list. This allows # us to detect when fixing one problem impacts another, # positively or negatively. problem = problems[0] print(problem.text) should_fix = console_utils.console_ask_yes_or_no(problem.fix_prompt, default=False) if not should_fix: break problem.fix(project) project.use_changes_without_saving() o_problems, problems = problems, project.fixable_problems # If the number of problems doesn't decrease as a result of # fixing a problem, it suggests some sort of negative cycle. # We can't reliably detect a cycle, so instead we simply let # this happen 3 times before we give up. regressions += (len(problems) >= len(o_problems)) if not problems: project.save() return project
def _interactively_fix_missing_variables(project, result): """Return True if we need to re-prepare.""" if project.problems: return False if not console_utils.stdin_is_interactive(): return False # We don't ask the user to manually enter CONDA_PREFIX # (CondaEnvRequirement) because it's a bizarre/confusing # thing to ask. can_ask_about = [ status for status in result.statuses if (not status and isinstance(status.requirement, EnvVarRequirement) and not isinstance(status.requirement, CondaEnvRequirement)) ] if can_ask_about: print("(Use Ctrl+C to quit.)") start_over = False values = dict() for status in can_ask_about: reply = console_utils.console_input( "Value for " + status.requirement.env_var + ": ", encrypted=status.requirement.encrypted) if reply is None: return False # EOF reply = reply.strip() if reply == '': start_over = True break values[status.requirement.env_var] = reply if len(values) > 0: status = project_ops.set_variables(project, result.env_spec_name, values.items(), result) if status: return True else: console_utils.print_status_errors(status) return False else: return start_over
def load_project(dirname): """Load a Project, fixing it if needed and possible.""" project = Project(dirname, frontend=CliFrontend()) if console_utils.stdin_is_interactive(): had_fixable = len(project.fixable_problems) > 0 for problem in project.fixable_problems: print(problem.text) should_fix = console_utils.console_ask_yes_or_no(problem.fix_prompt, default=False) if should_fix: problem.fix(project) else: problem.no_fix(project) # both fix() and no_fix() can modify project_file, if no changes # were made this is a no-op. if had_fixable: project.save() return project
def test_stdin_is_interactive(monkeypatch): result = console_utils.stdin_is_interactive() assert result is True or result is False
def handle_bugs(main_func, program_name, details_dict): """Invoke main entry point, handling uncaught exceptions. Args: main_func (function): a main()-style function returning an exit status program_name (str): name of the app details_dict (dict): dictionary of stuff to include in the bug report file Returns: an exit status code from main_func or 1 on uncaught exception """ slugified_program_name = slugify(program_name) try: return main_func() except KeyboardInterrupt: # KeyboardInterrupt doesn't derive from Exception, but the default handler # prints a stack trace which is sort of ugly, so we replace the default # with this. print("%s was interrupted." % program_name, file=sys.stderr) return 1 except Exception: (exception_type, exception_value, exception_trace) = sys.exc_info() try: import datetime import pprint import tempfile import traceback print("An unexpected error occurred, most likely a bug in %s." % program_name, file=sys.stderr) print(" (The error was: %s: %s)" % (exception_type.__name__, str(exception_value)), file=sys.stderr) # so batch jobs have the details in their logs output_to_console = not console_utils.stdin_is_interactive() when = datetime.date.today().isoformat() prefix = "bug_details_%s_%s_" % (slugified_program_name, when) with tempfile.NamedTemporaryFile(prefix=prefix, suffix=".txt", delete=False) as bugfile: report_name = bugfile.name def output(s): bugfile.write(s.encode('utf-8')) bugfile.write("\n".encode('utf-8')) if output_to_console: print(s, file=sys.stderr) output("Bug details for %s error on %s" % (program_name, when)) output("") output("sys.argv: %r" % sys.argv) output("") output(pprint.pformat(details_dict)) output("") output("\n".join( traceback.format_exception(exception_type, exception_value, exception_trace))) if output_to_console: print("Above details were also saved to %s" % report_name, file=sys.stderr) else: print("Details about the error were saved to %s" % report_name, file=sys.stderr) except Exception: # re-raise the original exception, which is probably more useful # than reporting whatever was broken about our bug handling code # above. raise exception_value # exit code return 1