From 696aed8a590fa9c67a6b9c723e2134b2663bd769 Mon Sep 17 00:00:00 2001 From: Christian Heller Date: Mon, 22 Apr 2024 07:12:11 +0200 Subject: [PATCH] On posting new Todo to Day, make missing Todo children not found through adoption. --- plomtask/http.py | 1 + plomtask/todos.py | 23 ++++++++++++++++------- tests/todos.py | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 63 insertions(+), 7 deletions(-) diff --git a/plomtask/http.py b/plomtask/http.py index deadb21..8f247cd 100644 --- a/plomtask/http.py +++ b/plomtask/http.py @@ -201,6 +201,7 @@ class TaskHandler(BaseHTTPRequestHandler): todo = Todo(None, process, False, day.date) todo.save(self.conn) todo.adopt_from(existing_todos) + todo.make_missing_children(self.conn) todo.save(self.conn) def do_POST_todo(self) -> None: diff --git a/plomtask/todos.py b/plomtask/todos.py index ed78ca9..80dc97c 100644 --- a/plomtask/todos.py +++ b/plomtask/todos.py @@ -130,12 +130,12 @@ class Todo(BaseModel, ConditionsRelations): @property def unsatisfied_dependencies(self) -> list[int]: """Return Process IDs of .process.explicit_steps not in .children.""" - child_process_ids = {c.process.id_ for c in self.children} - unsatisfied: list[int] = [] - for process_id in [s.step_process_id - for s in self.process.explicit_steps]: - if process_id not in child_process_ids: - unsatisfied += [process_id] + unsatisfied = [s.step_process_id for s in self.process.explicit_steps + if s.parent_step_id is None] + for child_process_id in [c.process.id_ for c in self.children]: + if child_process_id in unsatisfied: + assert isinstance(child_process_id, int) + unsatisfied.remove(child_process_id) return unsatisfied @property @@ -158,10 +158,19 @@ class Todo(BaseModel, ConditionsRelations): def adopt_from(self, todos: list[Todo]) -> None: """As far as possible, fill unsatisfied dependencies from todos.""" for process_id in self.unsatisfied_dependencies: - for todo in [t for t in todos if t.process.id_ == process_id]: + for todo in [t for t in todos if t.process.id_ == process_id + and t not in self.children]: self.add_child(todo) break + def make_missing_children(self, db_conn: DatabaseConnection) -> None: + """Fill unsatisfied dependencies with new Todos.""" + for process_id in self.unsatisfied_dependencies: + process = Process.by_id(db_conn, process_id) + todo = self.__class__(None, process, False, self.date) + todo.save(db_conn) + self.add_child(todo) + def get_step_tree(self, seen_todos: set[int], seen_conditions: set[int]) -> TodoStepsNode: """Return tree of depended-on Todos and Conditions.""" diff --git a/tests/todos.py b/tests/todos.py index b5953dc..7aed5f8 100644 --- a/tests/todos.py +++ b/tests/todos.py @@ -209,6 +209,52 @@ class TestsWithDB(TestCaseWithDB): node_2.children.remove(node_6) self.assertEqual(todo_1.get_step_tree(set(), set()), node_0) + def test_Todo_unsatisfied_steps(self) -> None: + """Test options of satisfying unfulfilled Process.explicit_steps.""" + assert isinstance(self.proc.id_, int) + todo_1 = Todo(None, self.proc, False, self.date1) + todo_1.save(self.db_conn) + proc2 = Process(None) + proc2.save(self.db_conn) + assert isinstance(proc2.id_, int) + proc3 = Process(None) + proc3.save(self.db_conn) + assert isinstance(proc3.id_, int) + proc4 = Process(None) + proc4.save(self.db_conn) + assert isinstance(proc4.id_, int) + proc3.set_steps(self.db_conn, [(None, proc4.id_, None)]) + proc2.set_steps(self.db_conn, [(None, self.proc.id_, None), + (None, self.proc.id_, None), + (None, proc3.id_, None)]) + todo_2 = Todo(None, proc2, False, self.date1) + todo_2.save(self.db_conn) + # test empty adoption does nothing + todo_2.adopt_from([]) + self.assertEqual(todo_2.children, []) + # test basic adoption + todo_2.adopt_from([todo_1]) + self.assertEqual(todo_2.children, [todo_1]) + self.assertEqual(todo_1.parents, [todo_2]) + # test making missing children + todo_2.make_missing_children(self.db_conn) + todo_3 = Todo.by_id(self.db_conn, 3) + todo_4 = Todo.by_id(self.db_conn, 4) + self.assertEqual(todo_2.children, [todo_1, todo_3, todo_4]) + self.assertEqual(todo_3.process, self.proc) + self.assertEqual(todo_3.parents, [todo_2]) + self.assertEqual(todo_3.children, []) + self.assertEqual(todo_4.process, proc3) + self.assertEqual(todo_4.parents, [todo_2]) + # test .make_missing_children doesn't further than top-level + self.assertEqual(todo_4.children, []) + # test .make_missing_children lower down the tree + todo_4.make_missing_children(self.db_conn) + todo_5 = Todo.by_id(self.db_conn, 5) + self.assertEqual(todo_5.process, proc4) + self.assertEqual(todo_4.children, [todo_5]) + self.assertEqual(todo_5.parents, [todo_4]) + def test_Todo_singularity(self) -> None: """Test pointers made for single object keep pointing to it.""" todo = Todo(None, self.proc, False, self.date1) -- 2.30.2