class_docstr: Thread-safe wrapper around SessionState.
  
  When AppSession gets a re-run request, it can interrupt its existing
  ScriptRunner and spin up a new ScriptRunner to handle the request.
  When this happens, the existing ScriptRunner will continue executing
  its script until it reaches a yield point - but during this time, it
  must not mutate its SessionState.
class_docstr_tok: ["Thread-safe","wrapper","around","SessionState",".","When","AppSession","gets","a","re-run","request",",","it","can","interrupt","its","existing","ScriptRunner","and","spin","up","a","new","ScriptRunner","to","handle","the","request",".","When","this","happens",",","the","existing","ScriptRunner","will","continue","executing","its","script","until","it","reaches","a","yield","point","-","but","during","this","time",",","it","must","not","mutate","its","SessionState","."]
code: def __init__(
      self, state: SessionState, yield_callback: Callable[[], None]
  ):
      # Fields must be set using the object's setattr method to avoid
      # infinite recursion from trying to look up the fields we're setting.
      object.__setattr__(self, "_state", state)
      # TODO: we'd prefer this be a threading.Lock instead of RLock -
      #  but `call_callbacks` first needs to be rewritten.
      object.__setattr__(self, "_lock", threading.RLock())
      object.__setattr__(self, "_yield_callback", yield_callback)
  
imports: import threading
  from contextlib import contextmanager
  from typing import Any, Callable, Dict, Iterator, List, Optional, Set
  from streamlit.proto.WidgetStates_pb2 import WidgetState
  from streamlit.proto.WidgetStates_pb2 import WidgetStates
  from streamlit.runtime.state.common import RegisterWidgetResult, T, WidgetMetadata
  from streamlit.runtime.state.query_params import QueryParams
  from streamlit.runtime.state.session_state import SessionState
label_desc: Use image node_id 1 to create a new SafeSessionState object  with example: obj = SafeSessionState(state, yield_callback)