async def main(): logger.configure() win = MainWindow() async with qtrio.enter_emissions_channel(signals=[win.closed]) as emissions: win.show() await emissions.channel.receive()
async def main(window=None): """Show the example window and iterate over the relevant signal emissions to respond to user interactions with the GUI. """ if window is None: # pragma: no cover window = Window.build() signals = [ window.decrement.clicked, window.increment.clicked, window.widget.closed, ] async with qtrio.enter_emissions_channel(signals=signals) as emissions: window.show() async for emission in emissions.channel: if emission.is_from(window.decrement.clicked): window.decrement_count() elif emission.is_from(window.increment.clicked): window.increment_count() elif emission.is_from(window.widget.closed): break else: # pragma: no cover raise qtrio.QTrioException(f"Unexpected emission: {emission}")
async def serve( self, *, task_status: trio_typing.TaskStatus[None] = trio.TASK_STATUS_IGNORED, ) -> None: signals = [ self.decrement.clicked, self.increment.clicked, self.widget.closed, ] async with qtrio.enter_emissions_channel(signals=signals) as emissions: await self.show() task_status.started() self.serving_event.set() async for emission in emissions.channel: if emission.is_from(self.decrement.clicked): self.decrement_count() elif emission.is_from(self.increment.clicked): self.increment_count() elif emission.is_from(self.widget.closed): break else: # pragma: no cover raise qtrio.QTrioException( f"Unexpected emission: {emission}")
async def wait_send_task(self): async with qtrio.enter_emissions_channel(signals=[ self.closed, self.w_edit_button.clicked, self.w_info_button.clicked ]) as emissions: async for emission in emissions.channel: if emission.is_from(self.closed) : break elif emission.is_from(self.w_edit_button.clicked): await self.on_send_to_lean() elif emission.is_from(self.w_info_button.clicked): await self.on_lean_info() self.log.info("Exit")
async def main(button: typing.Optional[QtWidgets.QPushButton] = None): if button is None: # pragma: no cover button = QtWidgets.QPushButton() button.setText("Exit") async with qtrio.enter_emissions_channel(signals=[button.clicked]) as emissions: button.show() await emissions.channel.receive()
async def main(): """ This is the main loop. It opens a trio.nursery, instantiate a Container for signals and slots, and call the Container.choose_exercise method. Then it listens to signals emitted when windows are closed, and decides to quit when all windows are closed. Quitting implies stopping the lean server that may be running and closing the trio's nursery. """ async with trio.open_nursery() as nursery: await site_installation_check(nursery) # Create container container = Container(nursery) # Choose first exercise exercise = exercise_from_argv() if not exercise: container.choose_exercise() else: container.start_exercise(exercise) # Main loop that just listen to closing windows signals, # and quit if there is no more open windows. signals = [ container.close_chooser_window, container.close_exercise_window ] try: async with qtrio.enter_emissions_channel(signals=signals) as \ emissions: async for emission in emissions.channel: log.debug("Signal received") if emission.is_from(container.close_chooser_window): # Remember that there is no more chooser window: container.chooser_window = None log.debug("No more chooser window") elif emission.is_from(container.close_exercise_window): # Remember that there is no more exercise window: container.exercise_window = None log.debug("No more exercise window") # Quit if no more open window: if not (container.chooser_window or container.exercise_window): log.debug("Closing d∃∀duction") break # log.debug("Out of async for loop") # log.debug("Out of async with") finally: # Finally closing d∃∀duction if container.servint: await container.servint.file_invalidated.wait() container.servint.stop() # Good job, buddy log.info("Lean server stopped!") if container.nursery: container.nursery.cancel_scope.cancel()
async def test_main( qtbot: pytestqt.qtbot.QtBot, optional_hold_event: typing.Optional[trio.Event], ) -> None: message = "test world" async with trio.open_nursery() as nursery: start = functools.partial( qtrio.examples.buildingrespect.start_widget, message=message, hold_event=optional_hold_event, ) widget: qtrio.examples.buildingrespect.Widget = await nursery.start( start) qtbot.addWidget(widget.widget) async with qtrio.enter_emissions_channel(signals=[widget.text_changed ], ) as emissions: if optional_hold_event is not None: optional_hold_event.set() await trio.testing.wait_all_tasks_blocked(cushion=0.01) # lazily click the button and collect results in the memory channel rather # than starting concurrent tasks. # close the send channel so the receive channel knows when it is done async with emissions.send_channel: for _ in message: widget.button.click() # give Qt etc a chance to handle the clicks before closing the channel await trio.testing.wait_all_tasks_blocked(cushion=0.01) results: typing.List[typing.Tuple[object]] = [ emission.args async for emission in emissions.channel ] widget.button.click() assert results == [ ("t", ), ("te", ), ("tes", ), ("test", ), ("test ", ), ("test w", ), ("test wo", ), ("test wor", ), ("test worl", ), ("test world", ), ]
async def main(): async with trio.open_nursery() as nursery: logger.configure() srv = SimpleServerInterface(nursery) win = MainWindow(nursery, srv) async with qtrio.enter_emissions_channel(signals=[win.closed]) as emissions: await srv.start() win.show() await emissions.channel.receive() srv.stop()
async def server_task(self): await self.server.start() await self.server.exercise_set(self.exercise) async with qtrio.enter_emissions_channel( signals=[self.closed, self.send.clicked, self.undo.clicked ]) as emissions: async for emission in emissions.channel: if emission.is_from(self.closed): break elif emission.is_from(self.send.clicked): await self.go_send() elif emission.is_from(self.undo.clicked): await self.go_undo() self.server.stop()
async def site_installation_check(nursery): missing_packages = inst.check() if missing_packages: want_install_dialog = WantInstallMissingDependencies( map(lambda x: x[0], missing_packages)) want_install_dialog.exec_() if want_install_dialog.yes: inst_stg = Install_Dependencies_Stage(nursery, missing_packages) async with qtrio.enter_emissions_channel(signals=[inst_stg.start_deaduction]) as \ emissions: inst_stg.start() async for emission in emissions.channel: if emission.is_from(inst_stg.start_deaduction): break inst_stg.stop()
async def test_enter_emissions_channel_closes_both_channels(): """Exiting enter_emissions_channel() closes send and receive channels on exit.""" class MyQObject(QtCore.QObject): signal = QtCore.Signal(int) instance = MyQObject() max_buffer_size = 10 async with qtrio.enter_emissions_channel( signals=[instance.signal], max_buffer_size=max_buffer_size, ) as emissions: pass with pytest.raises(trio.ClosedResourceError): emissions.channel.receive_nowait() with pytest.raises(trio.ClosedResourceError): emissions.send_channel.send_nowait(None)
async def serve( self, *, task_status: trio_typing.TaskStatus[None] = trio.TASK_STATUS_IGNORED, ) -> None: async with qtrio.enter_emissions_channel( signals=[self.button.clicked]) as emissions: i = 1 await self.show() task_status.started() async for _ in emissions.channel: # pragma: no branch self.set_text(self.message[:i]) i += 1 if i > len(self.message): break # wait for another click to finish await emissions.channel.receive()
async def main(): async with trio.open_nursery() as nursery: logger.configure() course = Course.from_file( Path("../../tests/lean_files/short_course/exercises.lean")) for counter, statement in enumerate(course.statements): print(f"Statement n°{counter:2d}: " f"(exercise: {isinstance(statement, Exercise)}) " f"{statement.lean_name}" f" ({statement.pretty_name})") statement_id = int(input("Exercice n° ? ")) exercise = course.statements[statement_id] win = ExerciseWindow(nursery, exercise) async with qtrio.enter_emissions_channel( signals=[win.closed]) as emissions: win.show() await emissions.channel.receive()
async def test_main(qtbot: pytestqt.qtbot.QtBot, optional_hold_event: typing.Optional[trio.Event]) -> None: message = "test world" async with trio.open_nursery() as nursery: start = functools.partial( qtrio.examples.crossingpaths.start_widget, message=message, change_delay=0.01, close_delay=0.01, hold_event=optional_hold_event, ) widget: qtrio.examples.crossingpaths.Widget = await nursery.start(start ) qtbot.addWidget(widget) async with qtrio.enter_emissions_channel(signals=[widget.text_changed ], ) as emissions: if optional_hold_event is not None: optional_hold_event.set() async with emissions.send_channel: await widget.done_event.wait() results = [emission.args async for emission in emissions.channel] assert results == [ ("t", ), ("te", ), ("tes", ), ("test", ), ("test ", ), ("test w", ), ("test wo", ), ("test wor", ), ("test worl", ), ("test world", ), ]
async def test_file_open_set_path(tmp_path: pathlib.Path) -> None: file_path = tmp_path.joinpath("some_file") file_path.touch() dialog = qtrio.dialogs.create_file_open_dialog() trio_file_path = trio.Path(file_path) async def user(): await emissions.channel.receive() await dialog.set_path(path=trio_file_path) assert dialog.accept_button is not None dialog.accept_button.click() async with qtrio.enter_emissions_channel( signals=[dialog.shown]) as emissions: async with trio.open_nursery() as nursery: nursery.start_soon(user) selected_path = await dialog.wait() assert selected_path == trio_file_path
async def auto_test(container: Container): """ Test the Exercise's instance container.exercise by listening to deaduction signals and simulating user pressing buttons according to the instructions found in exercise.auto_test. The function assumes that the ExerciseMainWindow has been launched. Note that just one exercise is tested, this function is not in charge of processing to the next exercise to be tested. """ # Auto-steps loop exercise = container.exercise log.info(f"Testing exercise {exercise.pretty_name}") auto_steps = exercise.refined_auto_steps log.debug('auto_steps:') total_string = 'AutoTest\n' for step in auto_steps: total_string += ' ' + step.raw_string + ',\n' log.debug(total_string) emw = container.exercise_window signals = [emw.proof_step_updated, emw.ui_updated] test_success = True steps_counter = 0 async with qtrio.enter_emissions_channel(signals=signals) as \ emissions: reports = [f'Exercise {exercise.pretty_name}'] container.report.append(reports) async for emission in emissions.channel: # Check result # if emission.is_from(emw.proof_step_updated) and steps_counter: step = auto_steps[steps_counter - 1] report, step_success = emw.displayed_proof_step.compare(step) test_success = test_success and step_success if not report: report = f'Success with {step.raw_string}' else: report = f'{step.raw_string}' + report report = f"Step {steps_counter}: " + report if not emw.displayed_proof_step.success_msg \ and emw.displayed_proof_step.button \ and not emw.displayed_proof_step.button.is_cqfd() \ and not emw.displayed_proof_step.is_error(): report += "(no success msg)" reports.append(report) # Apply next step # elif emission.is_from(emw.ui_updated): log.debug("ui_updated received") step = auto_steps[steps_counter] steps_counter += 1 log.debug(f"auto_step found: {step}") if not step: log.debug("Found 'None' step, giving up") emw.close() break auto_selection, success = find_selection(step, emw) if not success: # Quit this exercise container.exercise_window.close() selection_names = [ item.display_name for item in auto_selection ] log.debug(f"Selection: {selection_names}") auto_user_input = [ int(item) if item.isdecimal() else item for item in step.user_input ] if step.button: # Auto step is a button step if step.button.endswith('undo'): await emw.process_async_signal(emw.servint.history_undo ) elif step.button.endswith('redo'): await emw.process_async_signal(emw.servint.history_redo ) elif step.button.endswith('rewind'): await emw.process_async_signal( emw.servint.history_rewind) else: # e.g. Nouvel_Objet -> Nouvel Objet step.button = step.button.replace('_', ' ') action_btn = emw.ecw.action_button(step.button) log.debug(f"Button: {action_btn}") await emw.process_async_signal( partial(emw.__server_call_action, action_btn, auto_selection, auto_user_input)) elif step.statement: # Auto step is a statement step statement_widget = emw.ecw.statements_tree.from_name( step.statement) log.debug(f"Statement: {statement_widget}") await emw.process_async_signal( partial(emw.__server_call_statement, statement_widget, auto_selection)) else: log.warning("Auto-step loop: empty step") if steps_counter == len(auto_steps): break log.debug(f"Auto_test successfull: {test_success}") reports.insert(0, test_success)
async def main(): """ Select exercises to be tested, launch ExerciseMainWindow and Lean server, and then call auto_test successively on each exercise. The exercise in initialized by the Container.test_exercise method. The loop first collect a collection of exercises from arguments. Arguments may include 1) a directory, 2) a file path to a course, maybe with with the name of some exercise, 3) or a file path to an individual exercise in a pkl file. - In the first case, it will collect all exercises with autotest data in all courses in the directory, as well ass all individual pkl test_exercises. - In the second case it will collect the individual exercise if specified, or all the exercises from this one, or all exercises in the specified course if no exercise is specified. - In the last case it will collect the specified exercise. """ # ─────────────── Choose exercises ─────────────── # exercises = None dir_, course, exercise, all_from_this_one = coex_from_argv() # dir: Path # course : Course # exercise: Exercise # all_from_this_one: bool if dir_: exercises = get_exercises_from_dir(dir_) elif course: exercises = get_exercises_from_course(course, exercise, all_from_this_one) elif exercise: exercises = [exercise] if not exercises: quit() else: log.debug(f"Found {len(exercises)} with AutoTest metadata") # ─────────────── Testing exercises ─────────────── # async with trio.open_nursery() as nursery: # Create container and enter test mode container = Container(nursery) container.exercises = exercises # Main loop: quit if window is closed by user or if there is no more # exercise. signals = [container.test_complete, container.close_exercise_window] try: async with qtrio.enter_emissions_channel(signals=signals) as \ emissions: log.info("Entering main test loop") # Test first exercise container.exercise = container.exercises[0] container.exercises = container.exercises[1:] await container.test_exercise() container.nursery.start_soon(auto_test, container) async for emission in emissions.channel: if emission.is_from(container.test_complete) \ and container.exercises: # Test next exercise log.debug("Test complete -> next exercise") log.debug(f"{len(container.exercises)} exercises " f"remaining to test") # Close window container.exercise_window.window_closed.disconnect() container.exercise_window.close() if container.exercises: # Test next exercise container.exercise = container.exercises[0] container.exercises = container.exercises[1:] await container.test_exercise() container.nursery.start_soon(auto_test, container) else: log.debug("No more exercises to test!") break elif emission.is_from(container.close_exercise_window): log.info("Exercise window closed") break finally: print("================================================") global_success = False not in [ exo_report[0] for exo_report in container.report ] print(f"Global success : {global_success}") for exo_report in container.report: success = "success" if exo_report[0] else "FAILURE" if len(exo_report) > 1: print(exo_report[1] + ": " + success) for step_report in exo_report[2:]: print(step_report) # Finally closing d∃∀duction if container.servint: await container.servint.file_invalidated.wait() container.servint.stop() # Good job, buddy log.info("Lean server stopped!") if container.nursery: container.nursery.cancel_scope.cancel()
async def server_task(self): """ This method handles sending user data and actions to the server interface (self.servint). It listens to signals and calls specific methods for those signals accordingly. Async / await processes are used in accordance to what is done in the server interface. This method is called in self.__init__. The user actions are stored in self.proof_step. """ self.freeze() await self.servint.exercise_set(self.exercise) self.freeze(False) async with qtrio.enter_emissions_channel(signals=[ self.lean_editor.editor_send_lean, self.toolbar.redo_action. triggered, self.toolbar.undo_action.triggered, self.toolbar.rewind.triggered, self.__action_triggered, self.__statement_triggered, self.__apply_math_object_triggered ]) as emissions: async for emission in emissions.channel: self.statusBar.erase() if emission.is_from(self.lean_editor.editor_send_lean): await self.process_async_signal( self.__server_send_editor_lean) elif emission.is_from(self.toolbar.redo_action.triggered)\ and not self.lean_file.history_at_end: # No need to call self.update_goal, this emits the # signal proof_state_change of which # self.update_goal is a slot. # The UI simulate the redone step if possible. self.proof_step.button = 'history_redo' proof_step = self.lean_file.next_proof_step if proof_step: await self.simulate(proof_step) await self.process_async_signal(self.servint.history_redo) elif emission.is_from(self.toolbar.undo_action.triggered): self.proof_step.button = 'history_undo' await self.process_async_signal(self.servint.history_undo) elif emission.is_from(self.toolbar.rewind.triggered): self.proof_step.button = 'history_rewind' await self.process_async_signal(self.servint.history_rewind ) elif emission.is_from(self.window_closed): break elif emission.is_from(self.__action_triggered): # emission.args[0] is the ActionButton triggered by user button = emission.args[0] self.proof_step.button = button if button == self.ecw.action_apply_button \ and self.double_clicked_item: # Make sure item is marked and added to selection item = self.double_clicked_item if item in self.current_selection: self.current_selection.remove(item) self.current_selection.append(item) # Item is last self.double_clicked_item = None await self.process_async_signal( partial(self.__server_call_action, emission.args[0])) elif emission.is_from(self.__statement_triggered): # emission.args[0] is the StatementTreeWidgetItem # triggered by user if hasattr(emission.args[0], 'statement'): self.proof_step.statement_item = emission.args[0] await self.process_async_signal( partial(self.__server_call_statement, emission.args[0])) elif emission.is_from(self.__apply_math_object_triggered): self.double_clicked_item = emission.args[0] # Emulate click on 'apply' button: self.ecw.action_apply_button.animateClick(msec=500)