def context(): """A context instance.""" return Context( artists=[ Artist("artist1"), Artist("artist2"), ], tasks=[ Task("0010", 1), Task("0020", 2), Task("0030", 3), ], )
def test_import_assignments_to_csv(tmpdir): """Ensure we can import a list of assignments to a .csv file.""" path = os.path.join(tmpdir, "artists.csv") with open(path, "w") as stream: stream.write("0010,Artist1\n0020,Artist2\n") artist1 = Artist("Artist1") artist2 = Artist("Artist2") task1 = Task("0010", 1) task2 = Task("0020", 2) context = Context( artists=[artist1, artist2], tasks=[task1, task2], ) actual = _io.import_assignments_from_csv(context, path) assert actual == [Assignment(artist1, task1), Assignment(artist2, task2)]
def __init__(self, context: Context, auto_solve=False): super().__init__() self.context = context # type: Context self.assignments = () # type: Tuple[Assignment, ...] self.statistics = () # type: Tuple[Score, ...] self.solution_count = 0 self.current_score = 0 self.auto_solve = auto_solve self.dirty = False self.path = "" self._path_autosave = os.path.join(tempfile.gettempdir(), "tmp.yml") self._thread = WorkerThread() self._thread.started.connect(self.onSolvingStarted.emit, Qt.DirectConnection) # type: ignore self._thread.finished.connect(self.onSolvingEnded.emit, Qt.DirectConnection) # type: ignore self._thread.foundSolution.connect(self._on_solution_found, Qt.DirectConnection) # type: ignore self.set_context(context or Context()) if self.auto_solve and self.can_play(): self.play()
def test_export_assignments_to_csv(tmpdir): """Ensure we can export a list of assignments to a .csv file.""" path = os.path.join(tmpdir, "artists.csv") artist1 = Artist("Artist1") artist2 = Artist("Artist2") task1 = Task("0010", 1) task2 = Task("0020", 2) context = Context( artists=[artist1, artist2], tasks=[task1, task2], assignments=[Assignment(artist1, task1), Assignment(artist2, task2)], ) _io.export_assignments_to_csv(context.assignments, path) with open(path) as stream: actual = stream.read() assert actual == "0010,Artist1\n0020,Artist2\n"
def __init__(self, context=None, parent=None): super().__init__(parent) context = context or Context() self._manager = Manager(context) # Build top menu self.action_new = QAction("New", self) self.action_save = QAction("Save", self) self.action_open = QAction("Open", self) self.action_save_as = QAction("Save As", self) self.action_quit = QAction("Quit", self) self.action_show_artists = QAction("Artists", self) self.action_show_artists.setCheckable(True) self.action_show_artists.setChecked(True) self.action_show_tasks = QAction("Tasks", self) self.action_show_tasks.setCheckable(True) self.action_show_tasks.setChecked(True) self.action_show_taskgroups = QAction("Task Groups", self) self.action_show_taskgroups.setCheckable(True) self.action_show_settings = QAction("Settings", self) self.action_show_settings.setCheckable(True) self.action_show_scores = QAction("Score", self) self.action_show_scores.setCheckable(True) self.menubar = QMenuBar(self) self.menu_file = QMenu("File", self.menubar) self.menu_view = QMenu("View", self.menubar) self.menubar.addAction(self.menu_file.menuAction()) self.menubar.addAction(self.menu_view.menuAction()) self.menu_file.addAction(self.action_new) self.menu_file.addAction(self.action_open) self.menu_file.addAction(self.action_save) self.menu_file.addAction(self.action_save_as) self.menu_file.addSeparator() self.menu_view.addAction(self.action_show_artists) self.menu_view.addAction(self.action_show_tasks) self.menu_view.addAction(self.action_show_taskgroups) self.menu_view.addAction(self.action_show_settings) self.menu_view.addAction(self.action_show_scores) self.setMenuBar(self.menubar) # Build dock widgets self.widget_artists = ArtistsWidget(self, self._manager) self.widget_tasks = TasksWidget(self, self._manager) self.widget_settings = SettingsWidget(self, self._manager) self.widget_scores = ScoresWidget(self) self.widget_tasksgroups = TasksGroupsWidget(self, self._manager, self.widget_tasks) self.widget_gantt = GanttWidget( self, self._manager, self.widget_artists.model, self.widget_tasks.model, self.widget_artists.table.selectionModel(), self.widget_tasks.table.selectionModel(), ) self.widget_footer = FooterBarWidget(self, self._manager) self.addDockWidget(Qt.RightDockWidgetArea, self.widget_artists) self.addDockWidget(Qt.RightDockWidgetArea, self.widget_tasks) self.addDockWidget(Qt.RightDockWidgetArea, self.widget_tasksgroups) self.addDockWidget(Qt.LeftDockWidgetArea, self.widget_gantt) self.addDockWidget(Qt.LeftDockWidgetArea, self.widget_scores) self.addDockWidget(Qt.LeftDockWidgetArea, self.widget_settings) self.addToolBar(Qt.BottomToolBarArea, self.widget_footer) # Connect events self.widget_footer.actionPlay.connect(self._manager.play) self.widget_footer.actionStop.connect(self._manager.stop) self.widget_footer.actionLiveModeToggle.connect( self.on_autosolve_changed) self._manager.onSolutionFound.connect(self.on_solution_found) self._manager.onContextChanged.connect(self.on_context_changed) self._manager.onDirty.connect(self.on_dirty) self.action_new.triggered.connect(self.file_new) self.action_open.triggered.connect(self.file_open) self.action_save.triggered.connect(self.file_save) self.action_save_as.triggered.connect(self.file_save_as) self.widget_artists.artistDeleted.connect(self._on_artist_deleted) self.widget_tasks.taskDeleted.connect(self._on_task_deleted) for action, widget in ( (self.action_show_artists, self.widget_artists), (self.action_show_tasks, self.widget_tasks), (self.action_show_taskgroups, self.widget_tasksgroups), (self.action_show_settings, self.widget_settings), (self.action_show_scores, self.widget_scores), ): widget.setVisible(action.isChecked()) action.toggled.connect(widget.setVisible) self.shortcut = QShortcut(QKeySequence("Space"), self) self.shortcut.activated.connect(self._manager.toogle) self._manager.restore_autosave() self._update_window_title()
def file_new(self): """Clear the current session.""" self._manager.set_context(Context()) self._update_window_title()
def manager(): return Manager(Context())
def test_serialization(tmp_path): """Validate we can serialize/deserialize a context. """ path = tmp_path / "context.yml" artist1 = Artist("Artist1", tags={"0010": 1}) artist2 = Artist("Artist1", tags={"0010": 1}) task1 = Task("0010", 1, tags=["acting"]) task2 = Task("0020", 1) context = Context( artists=[artist1], tasks=[task1, task2], assignments=[Assignment(artist1, task1), Assignment(artist2, task2)], combinations=[TaskGroup([task1], 1)], ) # Test serialization _io.export_context_to_yml(context, path) actual = yaml.load(path.read_text()) expected = { "artists": [{ "name": "Artist1", "availability": 100, "tags": [{ "name": "0010", "weight": 1 }], }], "tasks": [ { "name": "0010", "duration": 1.0, "tags": ["acting"] }, { "name": "0020", "duration": 1.0 }, ], "settings": { "TAGS": 100, "EQUAL_TASKS_BY_USER": 10, "EQUAL_TASKS_COUNT_BY_USER": 10, }, "assignments": [ { "artist": "Artist1", "task": "0010" }, { "artist": "Artist1", "task": "0020" }, ], "combinations": [{ "tasks": ["0010"], "weight": 1 }], } assert actual == expected # Test deserialization round-trip deserialized = _io.import_context_from_yml(path) assert context == deserialized