def echo(): """Use in a `with` block to draw some code on the app, then execute it. Example ------- >>> with st.echo(): >>> st.write('This code will be printed') """ code = empty() # noqa: F821 try: frame = _traceback.extract_stack()[-3] filename, start_line = frame.filename, frame.lineno yield frame = _traceback.extract_stack()[-3] end_line = frame.lineno lines_to_display = [] # type: List[str] with _source_util.open_python_file(filename) as source_file: source_lines = source_file.readlines() lines_to_display.extend(source_lines[start_line:end_line]) match = _SPACES_RE.match(lines_to_display[0]) initial_spaces = match.end() if match else 0 for line in source_lines[end_line:]: match = _SPACES_RE.match(line) indentation = match.end() if match else 0 # The != 1 is because we want to allow '\n' between sections. if indentation != 1 and indentation < initial_spaces: break lines_to_display.append(line) line_to_display = _textwrap.dedent("".join(lines_to_display)) code.code(line_to_display, "python") except FileNotFoundError as err: code.warning("Unable to display code. %s" % err)
def echo(code_location="above"): """Use in a `with` block to draw some code on the app, then execute it. Parameters ---------- code_location : "above" or "below" Whether to show the echoed code before or after the results of the executed code block. Example ------- >>> with st.echo(): >>> st.write('This code will be printed') """ if code_location == "below": show_code = code show_warning = warning else: placeholder = empty() show_code = placeholder.code show_warning = placeholder.warning try: frame = _traceback.extract_stack()[-3] filename, start_line = frame.filename, frame.lineno yield frame = _traceback.extract_stack()[-3] end_line = frame.lineno lines_to_display = [] # type: List[str] with _source_util.open_python_file(filename) as source_file: source_lines = source_file.readlines() lines_to_display.extend(source_lines[start_line:end_line]) match = _SPACES_RE.match(lines_to_display[0]) initial_spaces = match.end() if match else 0 for line in source_lines[end_line:]: match = _SPACES_RE.match(line) indentation = match.end() if match else 0 # The != 1 is because we want to allow '\n' between sections. if indentation != 1 and indentation < initial_spaces: break lines_to_display.append(line) line_to_display = _textwrap.dedent("".join(lines_to_display)) show_code(line_to_display, "python") except FileNotFoundError as err: show_warning("Unable to display code. %s" % err)
def end_code_block(display=True): """Ends the current code block and sends it to streamlit output. Args: display: whether to show this code block in the output """ global _current_end_line global _space_for_code frame = traceback.extract_stack()[ -2] # stack[-1] would be this frame itself # stack[-2] is the frame in the user's "notebook" calling us # (as long as the user is calling us directly) filename, lineno = frame.filename, frame.lineno with open_python_file(filename) as source_file: source_lines = source_file.readlines() lines_to_display = source_lines[_current_end_line:( lineno - 1)] # `lineno-1` means we skip showing the call to us _current_end_line = lineno if display: _space_for_code.code(''.join(lines_to_display), 'python') _space_for_code = st.empty()
def end_code_block(display=True): """Ends the current code block and sends it to streamlit output. Keyword Arguments: display: whether to show this code block in the output """ global _CURRENT_END_LINE # pylint: disable=global-statement global _SPACE_FOR_CODE # pylint: disable=global-statement frame = traceback.extract_stack()[ -2] # stack[-1] would be this frame itself # stack[-2] is the frame in the user's "notebook" calling us # (as long as the user is calling us directly) filename, lineno = frame.filename, frame.lineno filename = awesome_streamlit_hack(filename) with open_python_file(filename) as source_file: source_lines = source_file.readlines() # `lineno-1` means we skip showing the call to us lines_to_display = source_lines[_CURRENT_END_LINE:(lineno - 1)] _CURRENT_END_LINE = lineno if display: _SPACE_FOR_CODE.code("".join(lines_to_display), "python") _SPACE_FOR_CODE = st.empty()
def echo(): """Use in a `with` block to draw some code on the app, then execute it. Example ------- >>> with st.echo(): >>> st.write('This code will be printed') """ code = empty() # noqa: F821 try: frame = _traceback.extract_stack()[-3] if _is_running_py3(): filename, start_line = frame.filename, frame.lineno else: filename, start_line = frame[:2] yield frame = _traceback.extract_stack()[-3] if _is_running_py3(): end_line = frame.lineno else: end_line = frame[1] lines_to_display = [] with _source_util.open_python_file(filename) as source_file: source_lines = source_file.readlines() lines_to_display.extend(source_lines[start_line:end_line]) initial_spaces = _SPACES_RE.match(lines_to_display[0]).end() for line in source_lines[end_line:]: if _SPACES_RE.match(line).end() < initial_spaces: break lines_to_display.append(line) lines_to_display = _textwrap.dedent("".join(lines_to_display)) code.code(lines_to_display, "python") except FileNotFoundError as err: # noqa: F821 code.warning("Unable to display code. %s" % err)
def _run_script(self, rerun_data): """Run our script. Parameters ---------- rerun_data: RerunData The RerunData to use. """ assert self._is_in_script_thread() LOGGER.debug("Running script %s", rerun_data) # Reset DeltaGenerators, widgets, media files. media_file_manager.clear_session_files() ctx = get_report_ctx() if ctx is None: # This should never be possible on the script_runner thread. raise RuntimeError( "ScriptRunner thread has a null ReportContext. Something has gone very wrong!" ) ctx.reset(query_string=rerun_data.query_string) self.on_event.send(ScriptRunnerEvent.SCRIPT_STARTED) # Compile the script. Any errors thrown here will be surfaced # to the user via a modal dialog in the frontend, and won't result # in their previous report disappearing. try: with source_util.open_python_file(self._report.script_path) as f: filebody = f.read() if config.get_option("runner.magicEnabled"): filebody = magic.add_magic(filebody, self._report.script_path) code = compile( filebody, # Pass in the file path so it can show up in exceptions. self._report.script_path, # We're compiling entire blocks of Python, so we need "exec" # mode (as opposed to "eval" or "single"). mode="exec", # Don't inherit any flags or "future" statements. flags=0, dont_inherit=1, # Use the default optimization options. optimize=-1, ) except BaseException as e: # We got a compile error. Send an error event and bail immediately. LOGGER.debug("Fatal script error: %s" % e) self.on_event.send( ScriptRunnerEvent.SCRIPT_STOPPED_WITH_COMPILE_ERROR, exception=e) return # If we get here, we've successfully compiled our script. The next step # is to run it. Errors thrown during execution will be shown to the # user as ExceptionElements. # Update the Widget object with the new widget_states. # (The ReportContext has a reference to this object, so we just update it in-place) if rerun_data.widget_states is not None: self._widgets.set_state(rerun_data.widget_states) if config.get_option("runner.installTracer"): self._install_tracer() # This will be set to a RerunData instance if our execution # is interrupted by a RerunException. rerun_with_data = None try: # Create fake module. This gives us a name global namespace to # execute the code in. module = _new_module("__main__") # Install the fake module as the __main__ module. This allows # the pickle module to work inside the user's code, since it now # can know the module where the pickled objects stem from. # IMPORTANT: This means we can't use "if __name__ == '__main__'" in # our code, as it will point to the wrong module!!! sys.modules["__main__"] = module # Add special variables to the module's globals dict. # Note: The following is a requirement for the CodeHasher to # work correctly. The CodeHasher is scoped to # files contained in the directory of __main__.__file__, which we # assume is the main script directory. module.__dict__["__file__"] = self._report.script_path with modified_sys_path(self._report), self._set_execing_flag(): exec(code, module.__dict__) except RerunException as e: rerun_with_data = e.rerun_data except StopException: pass except BaseException as e: handle_uncaught_app_exception(e) finally: self._widgets.reset_triggers() self._widgets.cull_nonexistent(ctx.widget_ids_this_run.items()) self.on_event.send(ScriptRunnerEvent.SCRIPT_STOPPED_WITH_SUCCESS) # delete expired files now that the script has run and files in use # are marked as active media_file_manager.del_expired_files() # Use _log_if_error() to make sure we never ever ever stop running the # script without meaning to. _log_if_error(_clean_problem_modules) if rerun_with_data is not None: self._run_script(rerun_with_data)
def echo(code_location="above"): """Use in a `with` block to draw some code on the app, then execute it. Parameters ---------- code_location : "above" or "below" Whether to show the echoed code before or after the results of the executed code block. Example ------- >>> with st.echo(): >>> st.write('This code will be printed') """ from streamlit import code, warning, empty, source_util if code_location == "below": show_code = code show_warning = warning else: placeholder = empty() show_code = placeholder.code show_warning = placeholder.warning try: # Get stack frame *before* running the echoed code. The frame's # line number will point to the `st.echo` statement we're running. frame = traceback.extract_stack()[-3] filename, start_line = frame.filename, frame.lineno # Read the file containing the source code of the echoed statement. with source_util.open_python_file(filename) as source_file: source_lines = source_file.readlines() # Get the indent of the first line in the echo block, skipping over any # empty lines. initial_indent = _get_initial_indent(source_lines[start_line:]) # Iterate over the remaining lines in the source file # until we find one that's indented less than the rest of the # block. That's our end line. # # Note that this is *not* a perfect strategy, because # de-denting is not guaranteed to signal "end of block". (A # triple-quoted string might be dedented but still in the # echo block, for example.) # TODO: rewrite this to parse the AST to get the *actual* end of the block. lines_to_display: List[str] = [] for line in source_lines[start_line:]: indent = _get_indent(line) if indent is not None and indent < initial_indent: break lines_to_display.append(line) code_string = textwrap.dedent("".join(lines_to_display)) # Run the echoed code... yield # And draw the code string to the app! show_code(code_string, "python") except FileNotFoundError as err: show_warning("Unable to display code. %s" % err)
def _run_script(self, rerun_data: RerunData) -> None: """Run our script. Parameters ---------- rerun_data: RerunData The RerunData to use. """ assert self._is_in_script_thread() LOGGER.debug("Running script %s", rerun_data) # Reset DeltaGenerators, widgets, media files. in_memory_file_manager.clear_session_files() ctx = self._get_script_run_ctx() ctx.reset(query_string=rerun_data.query_string) self.on_event.send(ScriptRunnerEvent.SCRIPT_STARTED) # Compile the script. Any errors thrown here will be surfaced # to the user via a modal dialog in the frontend, and won't result # in their previous script elements disappearing. try: with source_util.open_python_file( self._session_data.script_path) as f: filebody = f.read() if config.get_option("runner.magicEnabled"): filebody = magic.add_magic(filebody, self._session_data.script_path) code = compile( filebody, # Pass in the file path so it can show up in exceptions. self._session_data.script_path, # We're compiling entire blocks of Python, so we need "exec" # mode (as opposed to "eval" or "single"). mode="exec", # Don't inherit any flags or "future" statements. flags=0, dont_inherit=1, # Use the default optimization options. optimize=-1, ) except BaseException as e: # We got a compile error. Send an error event and bail immediately. LOGGER.debug("Fatal script error: %s" % e) self._session_state[SCRIPT_RUN_WITHOUT_ERRORS_KEY] = False self.on_event.send( ScriptRunnerEvent.SCRIPT_STOPPED_WITH_COMPILE_ERROR, exception=e) return # If we get here, we've successfully compiled our script. The next step # is to run it. Errors thrown during execution will be shown to the # user as ExceptionElements. if config.get_option("runner.installTracer"): self._install_tracer() # This will be set to a RerunData instance if our execution # is interrupted by a RerunException. rerun_with_data = None try: # Create fake module. This gives us a name global namespace to # execute the code in. module = _new_module("__main__") # Install the fake module as the __main__ module. This allows # the pickle module to work inside the user's code, since it now # can know the module where the pickled objects stem from. # IMPORTANT: This means we can't use "if __name__ == '__main__'" in # our code, as it will point to the wrong module!!! sys.modules["__main__"] = module # Add special variables to the module's globals dict. # Note: The following is a requirement for the CodeHasher to # work correctly. The CodeHasher is scoped to # files contained in the directory of __main__.__file__, which we # assume is the main script directory. module.__dict__["__file__"] = self._session_data.script_path with modified_sys_path( self._session_data), self._set_execing_flag(): # Run callbacks for widgets whose values have changed. if rerun_data.widget_states is not None: # Update the WidgetManager with the new widget_states. # The old states, used to skip callbacks if values # haven't changed, are also preserved in the # WidgetManager. self._session_state.compact_state() self._session_state.set_widgets_from_proto( rerun_data.widget_states) self._session_state.call_callbacks() ctx.on_script_start() exec(code, module.__dict__) self._session_state[SCRIPT_RUN_WITHOUT_ERRORS_KEY] = True except RerunException as e: rerun_with_data = e.rerun_data except StopException: pass except BaseException as e: self._session_state[SCRIPT_RUN_WITHOUT_ERRORS_KEY] = False handle_uncaught_app_exception(e) finally: self._on_script_finished(ctx) # Use _log_if_error() to make sure we never ever ever stop running the # script without meaning to. _log_if_error(_clean_problem_modules) if rerun_with_data is not None: self._run_script(rerun_with_data)
def _run_script(self, rerun_data): """Run our script. Parameters ---------- rerun_data: RerunData The RerunData to use. """ assert self._is_in_script_thread() LOGGER.debug("Running script %s", rerun_data) # Reset delta generator so it starts from index 0. import streamlit as st st._reset(self._main_dg, self._sidebar_dg) self.on_event.send(ScriptRunnerEvent.SCRIPT_STARTED) # Compile the script. Any errors thrown here will be surfaced # to the user via a modal dialog in the frontend, and won't result # in their previous report disappearing. try: # Python 3 got rid of the native execfile() command, so we read # the file, compile it, and exec() it. This implementation is # compatible with both 2 and 3. with source_util.open_python_file(self._report.script_path) as f: filebody = f.read() if config.get_option("runner.magicEnabled"): filebody = magic.add_magic(filebody, self._report.script_path) code = compile( filebody, # Pass in the file path so it can show up in exceptions. self._report.script_path, # We're compiling entire blocks of Python, so we need "exec" # mode (as opposed to "eval" or "single"). mode="exec", # Don't inherit any flags or "future" statements. flags=0, dont_inherit=1, # Parameter not supported in Python2: # optimize=-1, ) except BaseException as e: # We got a compile error. Send an error event and bail immediately. LOGGER.debug("Fatal script error: %s" % e) self.on_event.send( ScriptRunnerEvent.SCRIPT_STOPPED_WITH_COMPILE_ERROR, exception=e) return # If we get here, we've successfully compiled our script. The next step # is to run it. Errors thrown during execution will be shown to the # user as ExceptionElements. # Update the Widget singleton with the new widget_state if rerun_data.widget_state is not None: self._widgets.set_state(rerun_data.widget_state) if config.get_option("runner.installTracer"): self._install_tracer() # This will be set to a RerunData instance if our execution # is interrupted by a RerunException. rerun_with_data = None try: # Create fake module. This gives us a name global namespace to # execute the code in. module = _new_module("__main__") # Install the fake module as the __main__ module. This allows # the pickle module to work inside the user's code, since it now # can know the module where the pickled objects stem from. # IMPORTANT: This means we can't use "if __name__ == '__main__'" in # our code, as it will point to the wrong module!!! sys.modules["__main__"] = module # Add special variables to the module's globals dict. # Note: The following is a requirement for the CodeHasher to # work correctly. The CodeHasher is scoped to # files contained in the directory of __main__.__file__, which we # assume is the main script directory. module.__dict__["__file__"] = self._report.script_path with modified_sys_path(self._report), self._set_execing_flag(): exec(code, module.__dict__) except RerunException as e: rerun_with_data = e.rerun_data except StopException: pass except BaseException as e: # Show exceptions in the Streamlit report. LOGGER.debug(e) import streamlit as st st.exception(e) # This is OK because we're in the script thread. # TODO: Clean up the stack trace, so it doesn't include # ScriptRunner. finally: self._widgets.reset_triggers() self.on_event.send(ScriptRunnerEvent.SCRIPT_STOPPED_WITH_SUCCESS) # Use _log_if_error() to make sure we never ever ever stop running the # script without meaning to. _log_if_error(_clean_problem_modules) if rerun_with_data is not None: self._run_script(rerun_with_data)