def _compose_category_description(category): descr_pairs = _methods_of(category) description = "" doc = category.__doc__ if doc: description = doc.strip() if descr_pairs: description += "\n\nCommands:\n" sublen = lambda item: len(item[0]) if item[0] else 0 first_column_len = max(map(sublen, descr_pairs)) + MARGIN for item in descr_pairs: if item[0] is None: description += "\n" continue name = getattr(item[1], "alias", item[0].replace("_", "-")) if item[1].__doc__: doc = info.parse_docstring( item[1].__doc__)["short_description"] else: doc = "" name += " " * (first_column_len - len(name)) description += " %s%s\n" % (name, doc) return description
def test_all_scenarios_have_docstrings(self): ignored_params = ["self", "scenario_obj"] for scenario_inst in scenario.Scenario.get_all(): self.assertIsNotNone( scenario_inst.__doc__, "%s doensn't have a docstring." % scenario_inst.get_name()) doc = info.parse_docstring(scenario_inst.__doc__) short_description = doc["short_description"] self.assertIsNotNone( short_description, "Docstring for %s should have " "at least a one-line description." % scenario_inst.get_name()) self.assertFalse( short_description.startswith("Test"), "One-line description for %s " "should be declarative and not start " "with 'Test(s) ...'" % scenario_inst.get_name()) params_count = scenario_inst.__code__.co_argcount params = scenario_inst.__code__.co_varnames[:params_count] documented_params = [p["name"] for p in doc["params"]] for param in params: if param not in ignored_params: self.assertIn( param, documented_params, "Docstring for %(scenario)s should " "describe the '%(param)s' parameter " "in the :param <name>: clause." % { "scenario": scenario_inst.get_name(), "param": param })
def test_parse_incomplete_docstring(self): docstring = """One-line description. :param p1: Param 1 description. :param p2: Param 2 description. """ expected = { "short_description": "One-line description.", "long_description": "", "params": [{ "name": "p1", "doc": "Param 1 description.\n" }, { "name": "p2", "doc": "Param 2\n" "description.\n" }], "returns": "" } self.assertEqual(expected, info.parse_docstring(docstring))
def test_all_scenarios_have_docstrings(self): ignored_params = ["self", "scenario_obj"] for scenario_inst in scenario.Scenario.get_all(): self.assertIsNotNone(scenario_inst.__doc__, "%s doensn't have a docstring." % scenario_inst.get_name()) doc = info.parse_docstring(scenario_inst.__doc__) short_description = doc["short_description"] self.assertIsNotNone(short_description, "Docstring for %s should have " "at least a one-line description." % scenario_inst.get_name()) self.assertFalse(short_description.startswith("Test"), "One-line description for %s " "should be declarative and not start " "with 'Test(s) ...'" % scenario_inst.get_name()) params_count = scenario_inst.__code__.co_argcount params = scenario_inst.__code__.co_varnames[:params_count] documented_params = [p["name"] for p in doc["params"]] for param in params: if param not in ignored_params: self.assertIn(param, documented_params, "Docstring for %(scenario)s should " "describe the '%(param)s' parameter " "in the :param <name>: clause." % {"scenario": scenario_inst.get_name(), "param": param})
def _compose_action_description(action_fn): description = "" if action_fn.__doc__: parsed_doc = info.parse_docstring(action_fn.__doc__) short = parsed_doc.get("short_description") long = parsed_doc.get("long_description") description = "%s\n\n%s" % (short, long) if long else short return description
def test_parse_docstring_short_only(self): docstring = """One-line description.""" expected = { "short_description": "One-line description.", "long_description": "", "params": [], "returns": "" } self.assertEqual(expected, info.parse_docstring(docstring))
def _check_docstrings(self, plg_cls, msg_buffer): doc = info.parse_docstring(plg_cls.__doc__) short_description = doc["short_description"] if short_description.startswith("Test"): msg_buffer.append("One-line description for %s" " should be declarative and not" " start with 'Test(s) ...'" % plg_cls.__name__) if not plg_cls.get_info()["title"]: msg = "Class '{}.{}' should have a docstring." msg_buffer.append(msg.format(plg_cls.__module__, plg_cls.__name__))
def test_params(self): for category in main.categories.values(): all_methods = self._get_all_category_methods(category) for name, method in all_methods: m_info = info.parse_docstring(method.__doc__) if m_info["params"]: print(m_info) self.fail("The description of parameters for CLI methods " "should be transmitted as a 'help' argument of " "`rally.cli.cliutils.arg` decorator. You should " "remove descriptions from docstring of " "`%s.%s.%s`" % (category.__module__, category.__class__, name))
def _check_docstrings(self, msg_buffer): for plg_cls in plugin.Plugin.get_all(): if plg_cls.__module__.startswith("rally."): doc = info.parse_docstring(plg_cls.__doc__) short_description = doc["short_description"] if short_description.startswith("Test"): msg_buffer.append("One-line description for %s" " should be declarative and not" " start with 'Test(s) ...'" % plg_cls.__name__) if not plg_cls.get_info()["title"]: msg = "Class '{}.{}' should have a docstring." msg_buffer.append(msg.format(plg_cls.__module__, plg_cls.__name__))
def _assert_class_has_docstrings(self, obj, long_description=True): if not obj.__module__.startswith("rally."): return self.assertIsNotNone(obj.__doc__, "%s doesn't have a class-level docstring." % obj) doc = info.parse_docstring(obj.__doc__) self.assertIsNotNone( doc["short_description"], "Docstring for %s should have a one-line description." % obj) if long_description: self.assertIsNotNone( doc["long_description"], "Docstring for %s should have a multi-line description." % obj)
def _check_docstrings(self, msg_buffer): for plg_cls in plugin.Plugin.get_all(): if plg_cls.__module__.startswith("rally."): if plg_cls.get_name().lower() not in self.exceptions: doc = info.parse_docstring(plg_cls.__doc__) short_description = doc["short_description"] if short_description.startswith("Test"): msg_buffer.append("One-line description for %s" " should be declarative and not" " start with 'Test(s) ...'" % plg_cls.__name__) if not plg_cls.get_info()["title"]: msg = ("Class '{}' should have a docstring.") inst_name = plg_cls.__name__ msg_buffer.append(msg.format(inst_name))
def test_parse_incomplete_docstring(self): docstring = """One-line description. :param p1: Param 1 description. :param p2: Param 2 description. """ expected = { "short_description": "One-line description.", "long_description": "", "params": [{"name": "p1", "doc": "Param 1 description."}, {"name": "p2", "doc": "Param 2\ndescription."}], "returns": "" } self.assertEqual(expected, info.parse_docstring(docstring))
def test_parse_docstring_with_no_params(self): docstring = """One-line description. Multi- line- description. :returns: Return value description. """ expected = { "short_description": "One-line description.", "long_description": "Multi-\nline-\ndescription.", "params": [], "returns": "Return value\ndescription." } self.assertEqual(expected, info.parse_docstring(docstring))
def test_all_scenarios_have_docstrings(self): ignored_params = ["self", "scenario_obj"] for scenario_inst in scenario.Scenario.get_all(): try: self.assertIsNotNone( scenario_inst.__doc__, "%s doensn't have a docstring." % scenario_inst.get_name()) except Exception: msg = ("'{}.run' doesn't have a docstring. " "At least class '{}' or method '{}.run' " "should contain a docstring") inst_name = scenario_inst.__name__ if scenario_inst.is_classbased: self.assertIsNotNone( scenario_inst.run.__doc__, msg.format(inst_name, inst_name, inst_name)) doc = info.parse_docstring(scenario_inst.__doc__) short_description = doc["short_description"] self.assertIsNotNone( short_description, "Docstring for %s should have " "at least a one-line description." % scenario_inst.get_name()) self.assertFalse( short_description.startswith("Test"), "One-line description for %s " "should be declarative and not start " "with 'Test(s) ...'" % scenario_inst.get_name()) if not scenario_inst.is_classbased: params_count = scenario_inst.__code__.co_argcount params = scenario_inst.__code__.co_varnames[:params_count] documented_params = [p["name"] for p in doc["params"]] for param in params: if param not in ignored_params: self.assertIn( param, documented_params, "Docstring for %(scenario)s should " "describe the '%(param)s' parameter " "in the :param <name>: clause." % { "scenario": scenario_inst.get_name(), "param": param })
def test_all_scenarios_have_docstrings(self): ignored_params = ["self", "scenario_obj"] for scenario_inst in scenario.Scenario.get_all(): try: self.assertIsNotNone(scenario_inst.__doc__, "%s doensn't have a docstring." % scenario_inst.get_name()) except Exception: msg = ("'{}.run' doesn't have a docstring. " "At least class '{}' or method '{}.run' " "should contain a docstring") inst_name = scenario_inst.__name__ if scenario_inst.is_classbased: self.assertIsNotNone(scenario_inst.run.__doc__, msg.format(inst_name, inst_name, inst_name)) doc = info.parse_docstring(scenario_inst.__doc__) short_description = doc["short_description"] self.assertIsNotNone(short_description, "Docstring for %s should have " "at least a one-line description." % scenario_inst.get_name()) self.assertFalse(short_description.startswith("Test"), "One-line description for %s " "should be declarative and not start " "with 'Test(s) ...'" % scenario_inst.get_name()) if not scenario_inst.is_classbased: params_count = scenario_inst.__code__.co_argcount params = scenario_inst.__code__.co_varnames[:params_count] documented_params = [p["name"] for p in doc["params"]] for param in params: if param not in ignored_params: self.assertIn(param, documented_params, "Docstring for %(scenario)s should " "describe the '%(param)s' parameter " "in the :param <name>: clause." % {"scenario": scenario_inst.get_name(), "param": param})
def test_parse_complete_docstring(self): docstring = """One-line description. Multi- line- description. :param p1: Param 1 description. :param p2: Param 2 description. :returns: Return value description. """ expected = { "short_description": "One-line description.", "long_description": "Multi-\nline-\ndescription.", "params": [{"name": "p1", "doc": "Param 1 description."}, {"name": "p2", "doc": "Param 2\ndescription."}], "returns": "Return value\ndescription." } self.assertEqual(expected, info.parse_docstring(docstring))
def test_parse_complete_docstring(self): docstring = """One-line description. Multi- line- description. :param p1: Param 1 description. :param p2: Param 2 description. :returns: Return value description. """ expected = { "short_description": "One-line description.", "long_description": "Multi-\nline-\ndescription.", "params": [{"name": "p1", "doc": "Param 1 description.\n"}, {"name": "p2", "doc": "Param 2\n" "description.\n"}], "returns": "Return value\ndescription." } self.assertEqual(expected, info.parse_docstring(docstring))