Ejemplo n.º 1
0
    def test_coalesce_widget_states(self):
        old_states = WidgetStates()

        _create_widget("old_set_trigger", old_states).trigger_value = True
        _create_widget("old_unset_trigger", old_states).trigger_value = False
        _create_widget("missing_in_new", old_states).int_value = 123
        _create_widget("shape_changing_trigger", old_states).trigger_value = True

        new_states = WidgetStates()

        _create_widget("old_set_trigger", new_states).trigger_value = False
        _create_widget("new_set_trigger", new_states).trigger_value = True
        _create_widget("added_in_new", new_states).int_value = 456
        _create_widget("shape_changing_trigger", new_states).int_value = 3

        widgets = Widgets()
        widgets.set_state(coalesce_widget_states(old_states, new_states))

        self.assertIsNone(widgets.get_widget_value("old_unset_trigger"))
        self.assertIsNone(widgets.get_widget_value("missing_in_new"))

        self.assertEqual(True, widgets.get_widget_value("old_set_trigger"))
        self.assertEqual(True, widgets.get_widget_value("new_set_trigger"))
        self.assertEqual(456, widgets.get_widget_value("added_in_new"))

        # Widgets that were triggers before, but no longer are, will *not*
        # be coalesced
        self.assertEqual(3, widgets.get_widget_value("shape_changing_trigger"))
Ejemplo n.º 2
0
    def setUp(self, override_root=True):
        self.report_queue = ReportQueue()

        if override_root:
            main_dg = self.new_delta_generator()
            sidebar_dg = self.new_delta_generator()
            setattr(threading.current_thread(),
                    REPORT_CONTEXT_ATTR_NAME,
                    ReportContext(main_dg=main_dg, sidebar_dg=sidebar_dg,
                                  widgets=Widgets()))
Ejemplo n.º 3
0
    def test_set_page_config_immutable(self):
        """st.set_page_config must be called at most once"""

        fake_enqueue = lambda msg: None
        ctx = ReportContext("TestSessionID", fake_enqueue, "", Widgets(),
                            UploadedFileManager())

        msg = ForwardMsg()
        msg.page_config_changed.title = "foo"

        ctx.enqueue(msg)
        with self.assertRaises(StreamlitAPIException):
            ctx.enqueue(msg)
Ejemplo n.º 4
0
    def __init__(self, report):
        """Initialize.

        Parameters
        ----------
        report : Report
            The report with the script to run.

        """
        self._report = report
        self._event_queue = ScriptEventQueue()
        self._state = ScriptState.STOPPED
        self._last_run_data = RerunData(argv=report.argv,
                                        widget_state=WidgetStates())
        self._widgets = Widgets()

        self.run_on_save = config.get_option('server.runOnSave')

        self.on_state_changed = Signal(
            doc="""Emitted when the script's execution state state changes.

            Parameters
            ----------
            state : ScriptState
            """)

        self.on_file_change_not_handled = Signal(
            doc="Emitted when the file is modified and we haven't handled it.")

        self.on_script_compile_error = Signal(
            doc="""Emitted if our script fails to compile.  (*Not* emitted
            for normal exceptions thrown while a script is running.)

            Parameters
            ----------
            exception : Exception
                The exception that was thrown
            """)

        self._local_sources_watcher = LocalSourcesWatcher(
            self._report, self._on_source_file_changed)

        # Will be set to true when we process a SHUTDOWN event
        self._shutdown_requested = False

        self._script_thread = None
        self._ctx = None

        # Set to true while we're executing. Used by
        # maybe_handle_execution_control_request.
        self._execing = False
Ejemplo n.º 5
0
    def test_reset_triggers(self):
        states = WidgetStates()
        widgets = Widgets()

        _create_widget("trigger", states).trigger_value = True
        _create_widget("int", states).int_value = 123
        widgets.set_state(states)

        self.assertEqual(True, widgets.get_widget_value("trigger"))
        self.assertEqual(123, widgets.get_widget_value("int"))

        widgets.reset_triggers()

        self.assertEqual(None, widgets.get_widget_value("trigger"))
        self.assertEqual(123, widgets.get_widget_value("int"))
Ejemplo n.º 6
0
    def test_reset_triggers(self):
        states = WidgetStates()
        widgets = Widgets()

        _create_widget('trigger', states).trigger_value = True
        _create_widget('int', states).int_value = 123
        widgets.set_state(states)

        self.assertEqual(True, widgets.get_widget_value('trigger'))
        self.assertEqual(123, widgets.get_widget_value('int'))

        widgets.set_state(reset_widget_triggers(states))

        self.assertEqual(False, widgets.get_widget_value('trigger'))
        self.assertEqual(123, widgets.get_widget_value('int'))
Ejemplo n.º 7
0
    def test_set_page_config_reset(self):
        """st.set_page_config should be allowed after a rerun"""

        fake_enqueue = lambda msg: None
        ctx = ReportContext("TestSessionID", fake_enqueue, "", Widgets(),
                            UploadedFileManager())

        msg = ForwardMsg()
        msg.page_config_changed.title = "foo"

        ctx.enqueue(msg)
        ctx.reset()
        try:
            ctx.enqueue(msg)
        except StreamlitAPIException:
            self.fail("set_page_config should have succeeded after reset!")
Ejemplo n.º 8
0
    def test_set_page_config_first(self):
        """st.set_page_config must be called before other st commands"""

        fake_enqueue = lambda msg: None
        ctx = ReportContext("TestSessionID", fake_enqueue, "", Widgets(),
                            UploadedFileManager())

        markdown_msg = ForwardMsg()
        markdown_msg.delta.new_element.markdown.body = "foo"

        msg = ForwardMsg()
        msg.page_config_changed.title = "foo"

        ctx.enqueue(markdown_msg)
        with self.assertRaises(StreamlitAPIException):
            ctx.enqueue(msg)
Ejemplo n.º 9
0
    def setUp(self, override_root=True):
        self.report_queue = ReportQueue()
        self.override_root = override_root
        self.orig_report_ctx = None

        if self.override_root:
            self.orig_report_ctx = get_report_ctx()
            add_report_ctx(
                threading.current_thread(),
                ReportContext(
                    enqueue=self.report_queue.enqueue,
                    widgets=Widgets(),
                    widget_ids_this_run=_WidgetIDSet(),
                    uploaded_file_mgr=UploadedFileManager(),
                ),
            )
Ejemplo n.º 10
0
    def setUp(self, override_root=True):
        self.report_queue = ReportQueue()

        if override_root:
            main_dg = self.new_delta_generator()
            sidebar_dg = self.new_delta_generator(container=BlockPath.SIDEBAR)
            setattr(
                threading.current_thread(),
                REPORT_CONTEXT_ATTR_NAME,
                ReportContext(
                    main_dg=main_dg,
                    sidebar_dg=sidebar_dg,
                    widgets=Widgets(),
                    widget_ids_this_run=_WidgetIDSet(),
                ),
            )
Ejemplo n.º 11
0
    def test_values(self):
        states = WidgetStates()

        _create_widget('trigger', states).trigger_value = True
        _create_widget('bool', states).bool_value = True
        _create_widget('float', states).float_value = 0.5
        _create_widget('int', states).int_value = 123
        _create_widget('string', states).string_value = 'howdy!'

        widgets = Widgets()
        widgets.set_state(states)

        self.assertEqual(True, widgets.get_widget_value('trigger'))
        self.assertEqual(True, widgets.get_widget_value('bool'))
        self.assertAlmostEqual(0.5, widgets.get_widget_value('float'))
        self.assertEqual(123, widgets.get_widget_value('int'))
        self.assertEqual('howdy!', widgets.get_widget_value('string'))
Ejemplo n.º 12
0
    def setUp(self, override_root=True):
        self.report_queue = ReportQueue()
        self.override_root = override_root
        self.orig_report_ctx = None

        if self.override_root:
            self.orig_report_ctx = get_report_ctx()
            add_report_ctx(
                threading.current_thread(),
                ReportContext(
                    session_id="test session id",
                    enqueue=self.report_queue.enqueue,
                    query_string="",
                    widgets=Widgets(),
                    uploaded_file_mgr=UploadedFileManager(),
                ),
            )
Ejemplo n.º 13
0
    def test_values(self):
        states = WidgetStates()

        _create_widget("trigger", states).trigger_value = True
        _create_widget("bool", states).bool_value = True
        _create_widget("float", states).double_value = 0.5
        _create_widget("int", states).int_value = 123
        _create_widget("string", states).string_value = "howdy!"

        widgets = Widgets()
        widgets.set_state(states)

        self.assertEqual(True, widgets.get_widget_value("trigger"))
        self.assertEqual(True, widgets.get_widget_value("bool"))
        self.assertAlmostEqual(0.5, widgets.get_widget_value("float"))
        self.assertEqual(123, widgets.get_widget_value("int"))
        self.assertEqual("howdy!", widgets.get_widget_value("string"))
Ejemplo n.º 14
0
    def test_handle_save_request(self, _1):
        """Test that handle_save_request serializes files correctly."""
        # Create a ReportSession with some mocked bits
        rs = ReportSession(self.io_loop, "mock_report.py", "",
                           UploadedFileManager())
        rs._report.report_id = "TestReportID"

        orig_ctx = get_report_ctx()
        ctx = ReportContext("TestSessionID", rs._report.enqueue, "", Widgets(),
                            UploadedFileManager())
        add_report_ctx(ctx=ctx)

        rs._scriptrunner = MagicMock()

        storage = MockStorage()
        rs._storage = storage

        # Send two deltas: empty and markdown
        st.empty()
        st.markdown("Text!")

        yield rs.handle_save_request(_create_mock_websocket())

        # Check the order of the received files. Manifest should be last.
        self.assertEqual(3, len(storage.files))
        self.assertEqual("reports/TestReportID/0.pb", storage.get_filename(0))
        self.assertEqual("reports/TestReportID/1.pb", storage.get_filename(1))
        self.assertEqual("reports/TestReportID/manifest.pb",
                         storage.get_filename(2))

        # Check the manifest
        manifest = storage.get_message(2, StaticManifest)
        self.assertEqual("mock_report", manifest.name)
        self.assertEqual(2, manifest.num_messages)
        self.assertEqual(StaticManifest.DONE, manifest.server_status)

        # Check that the deltas we sent match messages in storage
        sent_messages = rs._report._master_queue._queue
        received_messages = [
            storage.get_message(0, ForwardMsg),
            storage.get_message(1, ForwardMsg),
        ]

        self.assertEqual(sent_messages, received_messages)

        add_report_ctx(ctx=orig_ctx)
Ejemplo n.º 15
0
    def test_rerun_data_coalescing(self):
        """Test that multiple RERUN requests get coalesced with
        expected values.

        (This is similar to widgets_test.test_coalesce_widget_states -
        it's testing the same thing, but through the ScriptEventQueue
        interface.)
        """
        queue = ScriptRequestQueue()

        states = WidgetStates()
        _create_widget('trigger', states).trigger_value = True
        _create_widget('int', states).int_value = 123

        queue.enqueue(ScriptRequest.RERUN,
                      RerunData(argv=None, widget_state=states))

        states = WidgetStates()
        _create_widget('trigger', states).trigger_value = False
        _create_widget('int', states).int_value = 456

        queue.enqueue(ScriptRequest.RERUN,
                      RerunData(argv=None, widget_state=states))

        event, data = queue.dequeue()
        self.assertEqual(event, ScriptRequest.RERUN)

        widgets = Widgets()
        widgets.set_state(data.widget_state)

        # Coalesced triggers should be True if either the old or
        # new value was True
        self.assertEqual(True, widgets.get_widget_value('trigger'))

        # Other widgets should have their newest value
        self.assertEqual(456, widgets.get_widget_value('int'))

        # We should have no more events
        self.assertEqual((None, None), queue.dequeue(),
                         'Expected empty event queue')

        # Test that we can coalesce if previous widget state is None
        queue.enqueue(ScriptRequest.RERUN,
                      RerunData(argv=None, widget_state=None))
        queue.enqueue(ScriptRequest.RERUN,
                      RerunData(argv=None, widget_state=None))

        states = WidgetStates()
        _create_widget('int', states).int_value = 789

        queue.enqueue(ScriptRequest.RERUN,
                      RerunData(argv=None, widget_state=states))

        event, data = queue.dequeue()
        widgets = Widgets()
        widgets.set_state(data.widget_state)

        self.assertEqual(event, ScriptRequest.RERUN)
        self.assertEqual(789, widgets.get_widget_value('int'))

        # We should have no more events
        self.assertEqual((None, None), queue.dequeue(),
                         'Expected empty event queue')

        # Test that we can coalesce if our *new* widget state is None
        states = WidgetStates()
        _create_widget('int', states).int_value = 101112

        queue.enqueue(ScriptRequest.RERUN,
                      RerunData(argv=None, widget_state=states))

        queue.enqueue(ScriptRequest.RERUN,
                      RerunData(argv=None, widget_state=None))

        event, data = queue.dequeue()
        widgets = Widgets()
        widgets.set_state(data.widget_state)

        self.assertEqual(event, ScriptRequest.RERUN)
        self.assertEqual(101112, widgets.get_widget_value('int'))

        # We should have no more events
        self.assertEqual((None, None), queue.dequeue(),
                         'Expected empty event queue')
Ejemplo n.º 16
0
    def __init__(
        self,
        session_id,
        report,
        enqueue_forward_msg,
        client_state,
        request_queue,
        uploaded_file_mgr=None,
    ):
        """Initialize the ScriptRunner.

        (The ScriptRunner won't start executing until start() is called.)

        Parameters
        ----------
        session_id : str
            The ReportSession's id.

        report : Report
            The ReportSession's report.

        client_state : streamlit.proto.ClientState_pb2.ClientState
            The current state from the client (widgets and query params).

        request_queue : ScriptRequestQueue
            The queue that the ReportSession is publishing ScriptRequests to.
            ScriptRunner will continue running until the queue is empty,
            and then shut down.

        uploaded_file_mgr : UploadedFileManager
            The File manager to store the data uploaded by the file_uploader widget.

        """
        self._session_id = session_id
        self._report = report
        self._enqueue_forward_msg = enqueue_forward_msg
        self._request_queue = request_queue
        self._uploaded_file_mgr = uploaded_file_mgr

        self._client_state = client_state
        self._widgets = Widgets()
        self._widgets.set_state(client_state.widget_states)

        self.on_event = Signal(doc="""Emitted when a ScriptRunnerEvent occurs.

            This signal is *not* emitted on the same thread that the
            ScriptRunner was created on.

            Parameters
            ----------
            event : ScriptRunnerEvent

            exception : BaseException | None
                Our compile error. Set only for the
                SCRIPT_STOPPED_WITH_COMPILE_ERROR event.

            widget_states : streamlit.proto.WidgetStates_pb2.WidgetStates | None
                The ScriptRunner's final WidgetStates. Set only for the
                SHUTDOWN event.
            """)

        # Set to true when we process a SHUTDOWN request
        self._shutdown_requested = False

        # Set to true while we're executing. Used by
        # maybe_handle_execution_control_request.
        self._execing = False

        # This is initialized in start()
        self._script_thread = None
Ejemplo n.º 17
0
    def __init__(self, report, main_dg, sidebar_dg, widget_states,
                 request_queue):
        """Initialize the ScriptRunner.

        (The ScriptRunner won't start executing until start() is called.)

        Parameters
        ----------
        report : Report
            The ReportSession's report.

        main_dg : DeltaGenerator
            The ReportSession's main DeltaGenerator.

        sidebar_dg : DeltaGenerator
            The ReportSession's sidebar DeltaGenerator.

        widget_states : streamlit.proto.Widget_pb2.WidgetStates
            The ReportSession's current widget states

        request_queue : ScriptRequestQueue
            The queue that the ReportSession is publishing ScriptRequests to.
            ScriptRunner will continue running until the queue is empty,
            and then shut down.

        """
        self._report = report
        self._main_dg = main_dg
        self._sidebar_dg = sidebar_dg
        self._request_queue = request_queue

        self._widgets = Widgets()
        self._widgets.set_state(widget_states)

        self.on_event = Signal(doc="""Emitted when a ScriptRunnerEvent occurs.

            This signal is *not* emitted on the same thread that the
            ScriptRunner was created on.

            Parameters
            ----------
            event : ScriptRunnerEvent

            exception : BaseException | None
                Our compile error. Set only for the
                SCRIPT_STOPPED_WITH_COMPILE_ERROR event.

            widget_states : streamlit.proto.Widget_pb2.WidgetStates | None
                The ScriptRunner's final WidgetStates. Set only for the
                SHUTDOWN event.
            """)

        # Set to true when we process a SHUTDOWN request
        self._shutdown_requested = False

        # Set to true while we're executing. Used by
        # maybe_handle_execution_control_request.
        self._execing = False

        # This is initialized in start()
        self._script_thread = None
Ejemplo n.º 18
0
 def __init__(self, delta_generator):
     self.root_dg = delta_generator
     self.widgets = Widgets()