diff --git a/grade/decorators.py b/grade/decorators.py index c7533a2..30bcd43 100644 --- a/grade/decorators.py +++ b/grade/decorators.py @@ -37,6 +37,12 @@ def decorate(func): - `visible` (default): test case will always be shown """ +name = partial(static, "__name__") +name.__doc__ = """ Simple decorator to add a __name__ property to a function + + Usage: @name("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..f258e3a 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 name(self) -> str: + """ Returns the name of the test. + + This controls which name the students will see for a test. + """ + return getattr(self.getTest(), "__name__", None) + + @name.setter + def name(self, name: str): + """ Sets the name of the test. """ + self.setattr("__name__", 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..987595a 100644 --- a/grade/result.py +++ b/grade/result.py @@ -61,11 +61,15 @@ def getExceptions(self, test) -> List[Tuple]: return [m for f, m in [*self.failures, *self.errors] if f == test] def getName(self, test): - name = self.getattr(test, "__qualname__") - # TODO: Walrus once python 3.8 is supported. - description = test.shortDescription() - if description: - name = f"{name}: {description}" + # If a user-defined name exists, use it. + 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 c6eeafd..87b08a3 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_name(self): + @name("Test Name") + def test_name_exists(): + return + + self.assertEqual(test_name_exists.__name__, "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..c939a76 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_name(self): + + class Test(ScoringMixin): + def test_name_exists(self): + self.name = "Name Test" + assert self.name == "Name Test" + + x = Test() + x.test_name_exists() + self.assertEqual(x.test_name_exists.__name__, "Name Test") + return + def test_leaderboard(self): """ Can we modify and recall a tests leaderboard standing? """