From: Jacob Lifshay Date: Fri, 18 Sep 2020 02:18:17 +0000 (-0700) Subject: add status field to budget_graph.Node X-Git-Url: https://git.libre-soc.org/?p=utils.git;a=commitdiff_plain;h=0285c62dce3e85b5df44f304e51bde1858318022 add status field to budget_graph.Node --- diff --git a/src/budget_sync/budget_graph.py b/src/budget_sync/budget_graph.py index 463c3e1..322b240 100644 --- a/src/budget_sync/budget_graph.py +++ b/src/budget_sync/budget_graph.py @@ -1,7 +1,6 @@ from bugzilla.bug import Bug -from bugzilla import Bugzilla from typing import Set, Dict, Iterable, Optional, List, Union, Any -from budget_sync.util import all_bugs +from budget_sync.util import BugStatus from budget_sync.money import Money from budget_sync.config import Config, Person, Milestone from functools import cached_property @@ -212,6 +211,16 @@ class BudgetGraphUnknownMilestone(BudgetGraphParseError): f"#{self.bug_id}: unknown milestone: {self.milestone_str!r}" +class BudgetGraphUnknownStatus(BudgetGraphParseError): + def __init__(self, bug_id: int, status_str: str): + super().__init__(bug_id) + self.status_str = status_str + + def __str__(self): + return f"failed to parse status field of bug " \ + f"#{self.bug_id}: unknown status: {self.status_str!r}" + + class Node: graph: "BudgetGraph" bug: Bug @@ -236,6 +245,14 @@ class Node: if self.milestone_str == "---": self.milestone_str = None + @property + def status(self) -> BugStatus: + try: + return BugStatus.cast(self.bug.status) + except ValueError: + new_err = BudgetGraphUnknownStatus(self.bug.id, self.bug.status) + raise new_err.with_traceback(sys.exc_info()[2]) + @cached_property def bug_url(self) -> str: return f"{self.graph.config.bugzilla_url_stripped}/show_bug.cgi?" \ @@ -330,6 +347,10 @@ class Node: milestone = repr(self.milestone) except BudgetGraphBaseError: milestone = "" + try: + status = repr(self.status) + except BudgetGraphBaseError: + status = f"" immediate_children = [] for i in self.immediate_children: immediate_children.append(_NodeSimpleReprWrapper(i)) @@ -347,7 +368,8 @@ class Node: f"milestone_str={self.milestone_str!r}, " f"milestone={milestone}, " f"immediate_children={immediate_children!r}, " - f"payments={payments!r}") + f"payments={payments!r}, " + f"status={status})") class BudgetGraphError(BudgetGraphBaseError): @@ -497,6 +519,12 @@ class BudgetGraph: except BudgetGraphBaseError as e: errors.append(e) + try: + # check for status errors + node.status + except BudgetGraphBaseError as e: + errors.append(e) + if node.milestone_str != root.milestone_str: errors.append(BudgetGraphMilestoneMismatch( node.bug.id, root.bug.id)) @@ -672,3 +700,13 @@ class BudgetGraph: for payment in node.payments.values(): retval[payment.payee][node.milestone].append(payment) return retval + + def __repr__(self): + nodes = [*self.nodes.values()] + try: + roots = [_NodeSimpleReprWrapper(i) for i in self.roots] + roots.sort() + roots_str = repr(roots) + except BudgetGraphBaseError: + roots_str = "" + return f"BudgetGraph{{nodes={nodes!r}, roots={roots}}}" diff --git a/src/budget_sync/test/test_budget_graph.py b/src/budget_sync/test/test_budget_graph.py index 9fe072a..60ce3d0 100644 --- a/src/budget_sync/test/test_budget_graph.py +++ b/src/budget_sync/test/test_budget_graph.py @@ -7,8 +7,10 @@ from budget_sync.budget_graph import ( BudgetGraphNegativeMoney, BudgetGraphMilestoneMismatch, BudgetGraphNegativePayeeMoney, BudgetGraphPayeesParseError, BudgetGraphPayeesMoneyMismatch, BudgetGraphUnknownMilestone, - BudgetGraphDuplicatePayeesForTask, BudgetGraphIncorrectRootForMilestone) + BudgetGraphDuplicatePayeesForTask, BudgetGraphIncorrectRootForMilestone, + BudgetGraphUnknownStatus) from budget_sync.money import Money +from budget_sync.util import BugStatus from typing import List, Type import unittest @@ -52,6 +54,12 @@ class TestErrorFormatting(unittest.TestCase): "failed to parse cf_nlnet_milestone field of bug " "#123: unknown milestone: 'fake milestone'") + def test_budget_graph_unknown_status(self): + self.assertEqual(str(BudgetGraphUnknownStatus( + 123, "fake status")), + "failed to parse status field of bug " + "#123: unknown status: 'fake status'") + def test_budget_graph_money_mismatch(self): self.assertEqual(str( BudgetGraphMoneyMismatchForBudgetExcludingSubtasks( @@ -168,6 +176,38 @@ class TestBudgetGraph(unittest.TestCase): error_types.append(type(error)) self.assertEqual(wrap_type_list(error_types), wrap_type_list(template)) + def test_repr(self): + bg = BudgetGraph([EXAMPLE_PARENT_BUG1, EXAMPLE_CHILD_BUG2], + EXAMPLE_CONFIG) + self.assertEqual( + repr(bg), + "BudgetGraph{nodes=[Node(graph=..., id=#1, root=#1, parent=None, " + "budget_excluding_subtasks=10, budget_including_subtasks=20, " + "fixed_budget_excluding_subtasks=10, " + "fixed_budget_including_subtasks=20, " + "milestone_str='milestone 1', milestone=Milestone(config=..., " + "identifier='milestone 1', canonical_bug_id=1), " + "immediate_children=[#2], payments=[], " + "status=BugStatus.CONFIRMED), Node(graph=..., id=#2, root=#1, " + "parent=#1, budget_excluding_subtasks=10, " + "budget_including_subtasks=10, " + "fixed_budget_excluding_subtasks=10, " + "fixed_budget_including_subtasks=10, " + "milestone_str='milestone 1', milestone=Milestone(config=..., " + "identifier='milestone 1', canonical_bug_id=1), " + "immediate_children=[], payments=[], " + "status=BugStatus.CONFIRMED)], roots=[#1]}") + bg = BudgetGraph([MockBug(bug_id=1, status="blah")], + EXAMPLE_CONFIG) + self.assertEqual( + repr(bg), + "BudgetGraph{nodes=[Node(graph=..., id=#1, root=#1, parent=None, " + "budget_excluding_subtasks=0, budget_including_subtasks=0, " + "fixed_budget_excluding_subtasks=0, " + "fixed_budget_including_subtasks=0, milestone_str=None, " + "milestone=None, immediate_children=[], payments=[], " + "status=)], roots=[#1]}") + def test_empty(self): bg = BudgetGraph([], EXAMPLE_CONFIG) self.assertEqual(len(bg.nodes), 0) @@ -1189,6 +1229,20 @@ class TestBudgetGraph(unittest.TestCase): }, }) + def test_status(self): + bg = BudgetGraph([MockBug(bug_id=1, status="blah")], + EXAMPLE_CONFIG) + errors = bg.get_errors() + self.assertErrorTypesMatches(errors, + [BudgetGraphUnknownStatus]) + self.assertEqual(errors[0].bug_id, 1) + self.assertEqual(errors[0].status_str, "blah") + for status in BugStatus: + bg = BudgetGraph([MockBug(bug_id=1, status=status)], + EXAMPLE_CONFIG) + self.assertErrorTypesMatches(bg.get_errors(), []) + self.assertEqual(bg.nodes[1].status, status) + if __name__ == "__main__": unittest.main()