class SessionData:
    """
    Contains parameters related to running a script, and also houses
    the ForwardMsgQueue that is used to deliver messages to a connected browser.
    """

    script_path: str
    script_folder: str
    name: str
    command_line: str
    script_run_id: str
    _browser_queue: ForwardMsgQueue

    def __init__(self, script_path: str, command_line: str):
        """Constructor.

        Parameters
        ----------
        script_path : str
            Path of the Python file from which this app is generated.

        command_line : string
            Command line as input by the user

        """
        basename = os.path.basename(script_path)

        self.script_path = os.path.abspath(script_path)
        self.script_folder = os.path.dirname(self.script_path)
        self.name = str(os.path.splitext(basename)[0])

        # The browser queue contains messages that haven't yet been
        # delivered to the browser. Periodically, the server flushes
        # this queue and delivers its contents to the browser.
        self._browser_queue = ForwardMsgQueue()

        self.script_run_id = generate_new_id()

        self.command_line = command_line

    def enqueue(self, msg):
        self._browser_queue.enqueue(msg)

    def clear(self):
        self._browser_queue.clear()

    def flush_browser_queue(self):
        """Clears our browser queue and returns the messages it contained.

        The Server calls this periodically to deliver new messages
        to the browser associated with this session.

        Returns
        -------
        list[ForwardMsg]
            The messages that were removed from the queue and should
            be delivered to the browser.

        """
        return self._browser_queue.flush()
Esempio n. 2
0
class DeltaGeneratorTestCase(unittest.TestCase):
    def setUp(self, override_root=True):
        self.forward_msg_queue = ForwardMsgQueue()
        self.override_root = override_root
        self.orig_report_ctx = None
        self.new_script_run_ctx = ScriptRunContext(
            session_id="test session id",
            enqueue=self.forward_msg_queue.enqueue,
            query_string="",
            session_state=SessionState(),
            uploaded_file_mgr=UploadedFileManager(),
        )

        if self.override_root:
            self.orig_report_ctx = get_script_run_ctx()
            add_script_run_ctx(threading.current_thread(),
                               self.new_script_run_ctx)

        self.app_session = FakeAppSession()

    def tearDown(self):
        self.clear_queue()
        if self.override_root:
            add_script_run_ctx(threading.current_thread(),
                               self.orig_report_ctx)

    def get_message_from_queue(self, index=-1) -> ForwardMsg:
        """Get a ForwardMsg proto from the queue, by index."""
        return self.forward_msg_queue._queue[index]

    def get_delta_from_queue(self, index=-1) -> Delta:
        """Get a Delta proto from the queue, by index."""
        deltas = self.get_all_deltas_from_queue()
        return deltas[index]

    def get_all_deltas_from_queue(self) -> List[Delta]:
        """Return all the delta messages in our ForwardMsgQueue"""
        return [
            msg.delta for msg in self.forward_msg_queue._queue
            if msg.HasField("delta")
        ]

    def clear_queue(self) -> None:
        self.forward_msg_queue.clear()
Esempio n. 3
0
class TestScriptRunner(ScriptRunner):
    """Subclasses ScriptRunner to provide some testing features."""
    def __init__(self, script_name):
        """Initializes the ScriptRunner for the given script_name"""
        # DeltaGenerator deltas will be enqueued into self.forward_msg_queue.
        self.forward_msg_queue = ForwardMsgQueue()

        self.script_request_queue = ScriptRequestQueue()
        main_script_path = os.path.join(os.path.dirname(__file__), "test_data",
                                        script_name)

        super(TestScriptRunner, self).__init__(
            session_id="test session id",
            session_data=SessionData(main_script_path, "test command line"),
            enqueue_forward_msg=self.forward_msg_queue.enqueue,
            client_state=ClientState(),
            session_state=SessionState(),
            request_queue=self.script_request_queue,
            uploaded_file_mgr=UploadedFileManager(),
        )

        # Accumulates uncaught exceptions thrown by our run thread.
        self.script_thread_exceptions = []

        # Accumulates all ScriptRunnerEvents emitted by us.
        self.events: List[ScriptRunnerEvent] = []
        self.event_data: List[Any] = []

        def record_event(sender: Optional[ScriptRunner],
                         event: ScriptRunnerEvent, **kwargs):
            # Assert that we're not getting unexpected `sender` params
            # from ScriptRunner.on_event
            assert (sender is None
                    or sender == self), "Unexpected ScriptRunnerEvent sender!"
            self.events.append(event)
            self.event_data.append(kwargs)

        self.on_event.connect(record_event, weak=False)

    def enqueue_rerun(self, argv=None, widget_states=None, query_string=""):
        self.script_request_queue.enqueue(
            ScriptRequest.RERUN,
            RerunData(widget_states=widget_states, query_string=query_string),
        )

    def enqueue_stop(self):
        self.script_request_queue.enqueue(ScriptRequest.STOP)

    def enqueue_shutdown(self):
        self.script_request_queue.enqueue(ScriptRequest.SHUTDOWN)

    def _run_script_thread(self):
        try:
            super()._run_script_thread()
        except BaseException as e:
            self.script_thread_exceptions.append(e)

    def _run_script(self, rerun_data):
        self.forward_msg_queue.clear()
        super()._run_script(rerun_data)

    def join(self):
        """Joins the run thread, if it was started"""
        if self._script_thread is not None:
            self._script_thread.join()

    def clear_deltas(self):
        """Clear all delta messages from our ForwardMsgQueue"""
        self.forward_msg_queue.clear()

    def deltas(self) -> List[Delta]:
        """Return the delta messages in our ForwardMsgQueue"""
        return [
            msg.delta for msg in self.forward_msg_queue._queue
            if msg.HasField("delta")
        ]

    def elements(self) -> List[Element]:
        """Return the delta.new_element messages in our ForwardMsgQueue."""
        return [delta.new_element for delta in self.deltas()]

    def text_deltas(self) -> List[str]:
        """Return the string contents of text deltas in our ForwardMsgQueue"""
        return [
            element.text.body for element in self.elements()
            if element.WhichOneof("type") == "text"
        ]

    def get_widget_id(self, widget_type, label):
        """Returns the id of the widget with the specified type and label"""
        for delta in self.deltas():
            new_element = getattr(delta, "new_element", None)
            widget = getattr(new_element, widget_type, None)
            widget_label = getattr(widget, "label", None)
            if widget_label == label:
                return widget.id
        return None