def test_simple_add_rows_with_clear_queue(self): """Test plain old add_rows after clearing the queue.""" all_methods = self._get_unnamed_data_methods() + self._get_named_data_methods() for method in all_methods: # Create a new data-carrying element (e.g. st.dataframe) el = method(DATAFRAME) # Make sure it has 2 rows in it. df_proto = data_frame_proto._get_data_frame(self.get_delta_from_queue()) num_rows = len(df_proto.data.cols[0].int64s.data) self.assertEqual(num_rows, 2) # This is what we're testing: self.report_queue.clear() el.add_rows(NEW_ROWS) # Make sure there are 3 rows in the delta that got appended. ar = self.get_delta_from_queue().add_rows num_rows = len(ar.data.data.cols[0].int64s.data) self.assertEqual(num_rows, 3) # Clear the queue so the next loop is like a brand new test. get_report_ctx().reset() self.report_queue.clear()
def trigger_rerun() -> None: """ Reruns the script from start. it can be used to refresh the program. :return: Doesnt return anything """ report_thread.get_report_ctx()
def test_legacy_add_rows_with_pyarrow_table_data(self): """Test that an error is raised when called with `pyarrow.Table` data.""" all_methods = self._get_unnamed_data_methods() + self._get_named_data_methods() for method in all_methods: with self.assertRaises(StreamlitAPIException): # Create a new data-carrying element (e.g. st._legacy_dataframe) el = method(DATAFRAME) # This is what we're testing: el._legacy_add_rows(pa.Table.from_pandas(NEW_ROWS)) # Clear the queue so the next loop is like a brand new test. get_report_ctx().reset() self.report_queue.clear()
def test_add_rows_fails_when_wrong_shape(self): """Test that add_rows raises error when input has wrong shape.""" all_methods = self._get_unnamed_data_methods() + self._get_named_data_methods() for method in all_methods: # Create a new data-carrying element (e.g. st.dataframe) el = method(DATAFRAME) with self.assertRaises(ValueError): # This is what we're testing: el.add_rows(NEW_ROWS_WRONG_SHAPE) # Clear the queue so the next loop is like a brand new test. get_report_ctx().reset() self.report_queue.clear()
def test_remove_orphaned_files(self, get_file_recs_patch, remove_orphaned_files_patch): """When file_uploader is accessed, it should call UploadedFileManager.remove_orphaned_files. """ ctx = get_report_ctx() ctx.uploaded_file_mgr._file_id_counter = 101 file_recs = [ UploadedFileRec(1, "file1", "type", b"123"), UploadedFileRec(2, "file2", "type", b"456"), ] get_file_recs_patch.return_value = file_recs st.file_uploader("foo", accept_multiple_files=True) args, kwargs = remove_orphaned_files_patch.call_args self.assertEqual(len(args), 0) self.assertEqual(kwargs["session_id"], "test session id") self.assertEqual(kwargs["newest_file_id"], 100) self.assertEqual(kwargs["active_file_ids"], [1, 2]) # Patch _get_file_recs to return [] instead. remove_orphaned_files # should not be called when file_uploader is accessed. get_file_recs_patch.return_value = [] remove_orphaned_files_patch.reset_mock() st.file_uploader("foo") remove_orphaned_files_patch.assert_not_called()
def _get_session_raw(): # Hack to get the session object from Streamlit. ctx = ReportThread.get_report_ctx() this_session = None current_server = Server.get_current() if hasattr(current_server, "_session_infos"): # Streamlit < 0.56 session_infos = Server.get_current()._session_infos.values() else: session_infos = Server.get_current()._session_info_by_id.values() for session_info in session_infos: s = session_info if ( # Streamlit < 0.54.0 (hasattr(s, "_main_dg") and s.session._main_dg == ctx.main_dg) or # Streamlit >= 0.54.0 (not hasattr(s, "_main_dg") and s.session.enqueue == ctx.enqueue) or # Streamlit >= 0.65.2 (not hasattr(s, "_main_dg") and s.session.id == ctx.session_id)): this_session = s if this_session is None: raise RuntimeError( "Oh noes. Couldn't get your Streamlit Session object" "Are you doing something fancy with threads?") return this_session
def send_message(session_id: str, message: str): try: sessions[session_id](args=[get_report_ctx().session_id, message]) except: streamlit.error(f"Session id {session_id} is not in listening state") _check_sessions()
def get(**kwargs): """Gets a SessionState object for the current session. Creates a new object if necessary. Parameters ---------- **kwargs : any Default values you want to add to the session state, if we're creating a new one. Example ------- >>> session_state = get(user_name='', favorite_color='black') >>> session_state.user_name '' >>> session_state.user_name = 'Mary' >>> session_state.favorite_color 'black' Since you set user_name above, next time your script runs this will be the result: >>> session_state = get(user_name='', favorite_color='black') >>> session_state.user_name 'Mary' """ # Hack to get the session object from Streamlit. ctx = ReportThread.get_report_ctx() this_session = None current_server = Server.get_current() if hasattr(current_server, '_session_infos'): # Streamlit < 0.56 session_infos = Server.get_current()._session_infos.values() else: session_infos = Server.get_current()._session_info_by_id.values() for session_info in session_infos: s = session_info.session if ( # Streamlit < 0.54.0 (hasattr(s, '_main_dg') and s._main_dg == ctx.main_dg) or # Streamlit >= 0.54.0 (not hasattr(s, '_main_dg') and s.enqueue == ctx.enqueue) or # Streamlit >= 0.65.2 (not hasattr(s, '_main_dg') and s._uploaded_file_mgr == ctx.uploaded_file_mgr) ): this_session = s if this_session is None: raise RuntimeError( "Oh noes. Couldn't get your Streamlit Session object. " 'Are you doing something fancy with threads?') # Got the session object! Now let's attach some state into it. if not hasattr(this_session, '_custom_session_state'): this_session._custom_session_state = SessionState(**kwargs) return this_session._custom_session_state
def get_saved_session(**kwargs): """Gets a SessionState object for the current session. Creates a new object if necessary. Parameters ---------- **kwargs : any Default values you want to add to the session state, if we're creating a new one. Example ------- >>> session_state = get(user_name='', favorite_color='black') >>> session_state.user_name '' >>> session_state.user_name = 'Mary' >>> session_state.favorite_color 'black' Since you set user_name above, next time your script runs this will be the result: >>> session_state = get(user_name='', favorite_color='black') >>> session_state.user_name 'Mary' """ ctx = get_report_ctx() id = ctx.session_id return get_session(id, **kwargs)
def _current_form( this_dg: "streamlit.delta_generator.DeltaGenerator", ) -> Optional[FormData]: """Find the FormData for the given DeltaGenerator. Forms are blocks, and can have other blocks nested inside them. To find the current form, we walk up the dg_stack until we find a DeltaGenerator that has FormData. """ if not streamlit._is_running_with_streamlit: return None if this_dg._form_data is not None: return this_dg._form_data if this_dg == this_dg._main_dg: # We were created via an `st.foo` call. # Walk up the dg_stack to see if we're nested inside a `with st.form` statement. ctx = get_report_ctx() if ctx is None or len(ctx.dg_stack) == 0: return None for dg in reversed(ctx.dg_stack): if dg._form_data is not None: return dg._form_data else: # We were created via an `dg.foo` call. # Take a look at our parent's form data to see if we're nested inside a form. parent = this_dg._parent if parent is not None and parent._form_data is not None: return parent._form_data return None
def get(**kwargs): # Hack to get the session object from Streamlit. ctx = get_report_ctx() this_session = None current_server = Server.get_current() if hasattr(current_server, '_session_infos'): # Streamlit < 0.56 session_infos = Server.get_current()._session_infos.values() else: session_infos = Server.get_current()._session_info_by_id.values() for session_info in session_infos: s = session_info.session if not hasattr( s, '_main_dg') and s._uploaded_file_mgr == ctx.uploaded_file_mgr: this_session = s if this_session is None: raise RuntimeError( "Oh noes. Couldn't get your Streamlit Session object" 'Are you doing something fancy with threads?') # Got the session object! Now let's attach some state into it. if not hasattr(this_session, '_custom_session_state'): this_session._custom_session_state = SessionState(**kwargs) return this_session._custom_session_state
def serialize_file_uploader( files: SomeUploadedFiles) -> FileUploaderStateProto: state_proto = FileUploaderStateProto() ctx = get_report_ctx() if ctx is None: return state_proto # ctx.uploaded_file_mgr._file_id_counter stores the id to use for # the *next* uploaded file, so the current highest file id is the # counter minus 1. state_proto.max_file_id = ctx.uploaded_file_mgr._file_id_counter - 1 if not files: return state_proto elif not isinstance(files, list): files = [files] for f in files: file_info: UploadedFileInfoProto = state_proto.uploaded_file_info.add( ) file_info.id = f.id file_info.name = f.name file_info.size = f.size return state_proto
def trigger_rerun(): ctx = ReportThread.get_report_ctx() this_session = None current_server = Server.get_current() if hasattr(current_server, '_session_infos'): # Streamlit < 0.56 session_infos = Server.get_current()._session_infos.values() else: session_infos = Server.get_current()._session_info_by_id.values() for session_info in session_infos: s = session_info.session if ( # Streamlit < 0.54.0 (hasattr(s, '_main_dg') and s._main_dg == ctx.main_dg) or # Streamlit >= 0.54.0 (not hasattr(s, '_main_dg') and s._uploaded_file_mgr == ctx.uploaded_file_mgr)): this_session = s if this_session is None: raise RuntimeError( "Oh noes. Couldn't get your Streamlit Session object" 'Are you doing something fancy with threads?') this_session.request_rerun()
def _get_session_object(): # Hack to get the session object from Streamlit. ctx = ReportThread.get_report_ctx() this_session = None session_infos = Server.get_current()._session_infos.values() for session_info in session_infos: s = session_info.session if ( # Streamlit < 0.54.0 (hasattr(s, '_main_dg') and s._main_dg == ctx.main_dg) or # Streamlit >= 0.54.0 (not hasattr(s, '_main_dg') and s.enqueue == ctx.enqueue) or # Streamlit >= 0.65.2 (not hasattr(s, '_main_dg') and s._uploaded_file_mgr == ctx.uploaded_file_mgr)): this_session = s if this_session is None: raise RuntimeError( "Oh noes. Couldn't get your Streamlit Session object" 'Are you doing something fancy with threads?') return this_session
def get(**kwargs): ctx = ReportThread.get_report_ctx() this_session = None current_server = Server.get_current() if hasattr(current_server, '_session_infos'): # Streamlit < 0.56 session_infos = Server.get_current()._session_infos.values() else: session_infos = Server.get_current()._session_info_by_id.values() for session_info in session_infos: s = session_info.session if ( # Streamlit < 0.54.0 (hasattr(s, '_main_dg') and s._main_dg == ctx.main_dg) or # Streamlit >= 0.54.0 (not hasattr(s, '_main_dg') and s.enqueue == ctx.enqueue) or # Streamlit >= 0.65.2 (not hasattr(s, '_main_dg') and s._uploaded_file_mgr == ctx.uploaded_file_mgr)): this_session = s if this_session is None: raise RuntimeError("Could not get session object.") if not hasattr(this_session, '_custom_session_state'): this_session._custom_session_state = SessionState(**kwargs) return this_session._custom_session_state
def _get_session(): session_id = get_report_ctx().session_id session_info = Server.get_current()._get_session_info(session_id) if session_info is None: raise RuntimeError("Couldn't get your Streamlit Session object.") return session_info.session
def _enqueue_message(msg): """Enqueues a ForwardMsg proto to send to the app.""" ctx = get_report_ctx() if ctx is None: raise NoSessionContext() ctx.enqueue(msg)
def on_message(callback: Callable[[str, str], None]): def cb(session, data): if session is not None: callback(session, data) sessions[get_report_ctx().session_id] = _wrapper(cb) _check_sessions()
def __exit__(self, type, value, traceback): # with block ended ctx = get_report_ctx() if ctx: ctx.dg_stack.pop() # Re-raise any exceptions return False
def _wrapper(callback: Optional[Callable[..., None]], uniq_id: Optional[str] = None, need_report: bool = True, delegate_stop: bool = True, at_end: Optional[Callable[[], None]] = None, out_wrapper: Callable[[Callable[..., None]], Callable[..., None]] = lambda i: i): if callback is None: return functools.partial(_wrapper, uniq_id=uniq_id, need_report=need_report, delegate_stop=delegate_stop, at_end=at_end, out_wrapper=out_wrapper) report_ctx = get_report_ctx() report_session: ReportSession = _SessionState.get_report_session_from_ctx( report_ctx) if report_session is None: raise StopException("No report session") callback_session_state = getattr(report_session, '_callback_session_state', None) if callback_session_state is None: callback_session_state = _SessionState(report_session) setattr(report_session, '_callback_session_state', callback_session_state) else: callback_session_state.refresh_ctx() if uniq_id is not None: pre_callback = callback_session_state.callbacks.get(uniq_id) callback_session_state.callbacks[uniq_id] = (callback, weakref.ref(report_ctx)) if pre_callback is None: callback_session_state.regist_at_end(at_end, session=True) return out_wrapper( functools.partial( _wrapped, session_state_ref=weakref.ref(callback_session_state), cb_ref=uniq_id, need_report=need_report, delegate_stop=delegate_stop)) else: def raise_(*args, **kwargs): if delegate_stop: raise StopException("Already running") return raise_ callback_session_state.regist_at_end(at_end, session=False) return out_wrapper( functools.partial( _wrapped, session_state_ref=weakref.ref(callback_session_state), cb_ref=[(callback, weakref.ref(report_ctx))], need_report=need_report, delegate_stop=delegate_stop))
def get_session_id(): import streamlit.report_thread as ReportThread from streamlit.server.server import Server session_id = get_report_ctx().session_id session_info = Server.get_current()._get_session_info(session_id) if session_info is None: raise RuntimeError("Couldn't get your Streamlit Session object.") return session_info.session.id
def sync(): session_id = ReportThread.get_report_ctx().session_id session_info = Server.get_current()._get_session_info(session_id) if session_info is None: raise RuntimeError('Could not get Streamlit session object.') this_session = session_info.session this_session.request_rerun()
def _active_dg(self): if self == self._main_dg: # `st.button`: Use the current `with` dg (aka the top of the stack) ctx = get_report_ctx() if ctx and len(ctx.dg_stack) > 0: return ctx.dg_stack[-1] # `st.sidebar.button`: Ignore the `with` dg return self
def test_add_rows_works_when_new_name(self): """Test add_rows with new named datasets.""" for method in self._get_named_data_methods(): # Create a new data-carrying element (e.g. st.dataframe) el = method(DATAFRAME) self.report_queue.clear() # This is what we're testing: el.add_rows(new_name=NEW_ROWS) # Make sure there are 3 rows in the delta that got appended. ar = self.get_delta_from_queue().add_rows num_rows = len(ar.data.data.cols[0].int64s.data) self.assertEqual(num_rows, 3) # Clear the queue so the next loop is like a brand new test. get_report_ctx().reset() self.report_queue.clear()
def _get_session_id(): """Semantic wrapper to retrieve current ReportSession ID.""" ctx = get_report_ctx() if ctx is None: # This is only None when running "python myscript.py" rather than # "streamlit run myscript.py". In which case the session ID doesn't # matter and can just be a constant, as there's only ever "session". return "dontcare" else: return ctx.session_id
def clear(): """ Register this run to the callback thread. This call is important, when it may no other callback register function call happens this run :return: None """ refresh_ctx = _getattrs(get_report_ctx(), '_enqueue', '__self__', '_callback_session_state', 'refresh_ctx') if callable(refresh_ctx): refresh_ctx()
def register_widget( element_type: str, element_proto: Any, user_key: Optional[str] = None, widget_func_name: Optional[str] = None, ) -> Any: """Register a widget with Streamlit, and return its current ui_value. NOTE: This function should be called after the proto has been filled. Parameters ---------- element_type : str The type of the element as stored in proto. element_proto : proto The proto of the specified type (e.g. Button/Multiselect/Slider proto) user_key : str Optional user-specified string to use as the widget ID. If this is None, we'll generate an ID by hashing the element. widget_func_name : str or None The widget's DeltaGenerator function name, if it's different from its element_type. Custom components are a special case: they all have the element_type "component_instance", but are instantiated with dynamically-named functions. Returns ------- ui_value : any The value of the widget set by the client or the default value passed. If the report context doesn't exist, None will be returned. """ widget_id = _get_widget_id(element_type, element_proto, user_key) element_proto.id = widget_id ctx = get_report_ctx() if ctx is None: # Early-out if we're not running inside a ReportThread (which # probably means we're running as a "bare" Python script, and # not via `streamlit run`). return None # Register the widget, and ensure another widget with the same id hasn't # already been registered. added = ctx.widget_ids_this_run.add(widget_id) if not added: raise DuplicateWidgetID( _build_duplicate_widget_message( widget_func_name if widget_func_name is not None else element_type, user_key, )) # Return the widget's current value. return ctx.widgets.get_widget_value(widget_id)
def _get_report_session() -> ReportSession: try: session_id: str = get_report_ctx().session_id except AttributeError: raise RuntimeError("Couldn't start Streamlit application.") session_info = Server.get_current()._get_session_info(session_id) if session_info is None: raise RuntimeError("Couldn't get your Streamlit Session object.") return session_info.session
def test_no_index_no_data_add_rows(self): """Test plain old add_rows.""" all_methods = self._get_unnamed_data_methods() for method in all_methods: # Create a new data-carrying element (e.g. st.dataframe) el = method(None) data_frame_proto._get_data_frame(self.get_delta_from_queue()) # This is what we're testing: el.add_rows(DATAFRAME) # Make sure there are 2 rows in it now. df_proto = data_frame_proto._get_data_frame(self.get_delta_from_queue()) num_rows = len(df_proto.data.cols[0].int64s.data) self.assertEqual(num_rows, 2) # Clear the queue so the next loop is like a brand new test. get_report_ctx().reset() self.report_queue.clear()
def get_container_cursor(container): ctx = get_report_ctx() if ctx is None: return None if container in ctx.cursors: return ctx.cursors[container] cursor = RunningCursor() ctx.cursors[container] = cursor return cursor