From 9eb3a5d86aac1d2f82a1d1329e295b2eb2b33b3f Mon Sep 17 00:00:00 2001 From: Justin Date: Thu, 5 Mar 2020 13:32:38 -0500 Subject: [PATCH 1/2] feature: testname decorator A potentially working name decorator, called test_name to not mess with the built-in __name__ attribute. --- grade/decorators.py | 6 ++++++ grade/mixins.py | 13 +++++++++++++ grade/result.py | 5 +++++ test/test_decorators.py | 8 ++++++++ test/test_mixins.py | 12 ++++++++++++ 5 files changed, 44 insertions(+) diff --git a/grade/decorators.py b/grade/decorators.py index c7533a2..76249e6 100644 --- a/grade/decorators.py +++ b/grade/decorators.py @@ -37,6 +37,12 @@ def decorate(func): - `visible` (default): test case will always be shown """ +testname = partial(static, "__testname__") +testname.__doc__ = """ Simple decorator to add a __testname__ property to a function + + Usage: @testname("Functionality Test") + """ + def leaderboard(name=None, order="desc"): """ Decorator that indicates that a test corresponds to a leaderboard column diff --git a/grade/mixins.py b/grade/mixins.py index 354856f..b8f8547 100644 --- a/grade/mixins.py +++ b/grade/mixins.py @@ -81,6 +81,19 @@ def visibility(self, visibility: str) -> None: """ Sets the visibility of the test. """ self.setattr("__visibility__", visibility) + @property + def testname(self) -> str: + """ Returns the name of the test. + + This controls which name the students will see for a test. + """ + return getattr(self.getTest(), "__testname__", None) + + @testname.setter + def testname(self, name: str): + """ Sets the name of the test. """ + self.setattr("__testname__", name) + @property def leaderboard(self) -> dict: """ Returns a dictionary with all leaderboard attributes. """ diff --git a/grade/result.py b/grade/result.py index 6c793aa..538fb33 100644 --- a/grade/result.py +++ b/grade/result.py @@ -61,6 +61,11 @@ def getExceptions(self, test) -> List[Tuple]: return [m for f, m in [*self.failures, *self.errors] if f == test] def getName(self, test): + # If a user-defined name exists, use it. + name = self.getattr(test, "__testname__", None) + if name: + return name + name = self.getattr(test, "__qualname__") # TODO: Walrus once python 3.8 is supported. description = test.shortDescription() diff --git a/test/test_decorators.py b/test/test_decorators.py index c6eeafd..269cd5b 100644 --- a/test/test_decorators.py +++ b/test/test_decorators.py @@ -46,6 +46,14 @@ def test_visible(): self.assertEqual(test_visible.__visibility__, "visible") return + def test_testname(self): + @name("Test Name") + def test_name_exists(): + return + + self.assertEqual(test_name_exists.__testname__, "Test Name") + return + def test_leaderboard(self): @leaderboard() def test_defaults(): diff --git a/test/test_mixins.py b/test/test_mixins.py index 8b46a4f..6a25b2e 100644 --- a/test/test_mixins.py +++ b/test/test_mixins.py @@ -62,6 +62,18 @@ def test_something(self): self.assertEqual(x.test_something.__visibility__, "invisible") return + def test_testname(self): + + class Test(ScoringMixin): + def test_name(self): + self.testname = "Name Test" + assert self.testname == "Name Test" + + x = Test() + x.test_name() + self.assertEqual(x.test_name.__testname__, "Name Test") + return + def test_leaderboard(self): """ Can we modify and recall a tests leaderboard standing? """ From 89926ab7b7a643f37f334cb3481e33694a463d39 Mon Sep 17 00:00:00 2001 From: Justin Date: Fri, 6 Mar 2020 10:23:05 -0500 Subject: [PATCH 2/2] testname changed to name --- grade/decorators.py | 6 +++--- grade/mixins.py | 10 +++++----- grade/result.py | 17 ++++++++--------- test/test_decorators.py | 4 ++-- test/test_mixins.py | 12 ++++++------ 5 files changed, 24 insertions(+), 25 deletions(-) diff --git a/grade/decorators.py b/grade/decorators.py index 76249e6..30bcd43 100644 --- a/grade/decorators.py +++ b/grade/decorators.py @@ -37,10 +37,10 @@ def decorate(func): - `visible` (default): test case will always be shown """ -testname = partial(static, "__testname__") -testname.__doc__ = """ Simple decorator to add a __testname__ property to a function +name = partial(static, "__name__") +name.__doc__ = """ Simple decorator to add a __name__ property to a function - Usage: @testname("Functionality Test") + Usage: @name("Functionality Test") """ diff --git a/grade/mixins.py b/grade/mixins.py index b8f8547..f258e3a 100644 --- a/grade/mixins.py +++ b/grade/mixins.py @@ -82,17 +82,17 @@ def visibility(self, visibility: str) -> None: self.setattr("__visibility__", visibility) @property - def testname(self) -> str: + def name(self) -> str: """ Returns the name of the test. This controls which name the students will see for a test. """ - return getattr(self.getTest(), "__testname__", None) + return getattr(self.getTest(), "__name__", None) - @testname.setter - def testname(self, name: str): + @name.setter + def name(self, name: str): """ Sets the name of the test. """ - self.setattr("__testname__", name) + self.setattr("__name__", name) @property def leaderboard(self) -> dict: diff --git a/grade/result.py b/grade/result.py index 538fb33..987595a 100644 --- a/grade/result.py +++ b/grade/result.py @@ -62,15 +62,14 @@ def getExceptions(self, test) -> List[Tuple]: def getName(self, test): # If a user-defined name exists, use it. - name = self.getattr(test, "__testname__", None) - if name: - return name - - name = self.getattr(test, "__qualname__") - # TODO: Walrus once python 3.8 is supported. - description = test.shortDescription() - if description: - name = f"{name}: {description}" + name = self.getattr(test, "__name__", None) + if not name: + name = self.getattr(test, "__qualname__") + # TODO: Walrus once python 3.8 is supported. + description = test.shortDescription() + if description: + name = f"{name}: {description}" + return name def getScore(self, test): diff --git a/test/test_decorators.py b/test/test_decorators.py index 269cd5b..87b08a3 100644 --- a/test/test_decorators.py +++ b/test/test_decorators.py @@ -46,12 +46,12 @@ def test_visible(): self.assertEqual(test_visible.__visibility__, "visible") return - def test_testname(self): + def test_name(self): @name("Test Name") def test_name_exists(): return - self.assertEqual(test_name_exists.__testname__, "Test Name") + self.assertEqual(test_name_exists.__name__, "Test Name") return def test_leaderboard(self): diff --git a/test/test_mixins.py b/test/test_mixins.py index 6a25b2e..c939a76 100644 --- a/test/test_mixins.py +++ b/test/test_mixins.py @@ -62,16 +62,16 @@ def test_something(self): self.assertEqual(x.test_something.__visibility__, "invisible") return - def test_testname(self): + def test_name(self): class Test(ScoringMixin): - def test_name(self): - self.testname = "Name Test" - assert self.testname == "Name Test" + def test_name_exists(self): + self.name = "Name Test" + assert self.name == "Name Test" x = Test() - x.test_name() - self.assertEqual(x.test_name.__testname__, "Name Test") + x.test_name_exists() + self.assertEqual(x.test_name_exists.__name__, "Name Test") return def test_leaderboard(self):