def _get_scenario_info(self, query): try: scenario_inst = scenario.Scenario.get(query) header = "%s (task scenario)" % scenario_inst.get_name() info = self._make_header(header) info += "\n\n" doc = utils.parse_docstring(scenario_inst.__doc__) if not doc["short_description"]: return None info += doc["short_description"] + "\n\n" if doc["long_description"]: info += doc["long_description"] + "\n\n" if doc["params"]: args = inspect.getargspec(scenario_inst) if args.defaults: default_values = dict(zip(args.args[-len(args.defaults):], args.defaults)) else: default_values = {} info += "Parameters:\n" for param in doc["params"]: info += " - %(name)s: %(doc)s" % param name = param["name"] if name in default_values: if default_values[name] is not None: info += " [Default: %s]" % default_values[name] else: info += " [optional]" info += "\n" if doc["returns"]: info += "Returns: %s" % doc["returns"] return info except exceptions.PluginNotFound: return None
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. """ dct = utils.parse_docstring(docstring) expected = { "short_description": "One-line description.", "long_description": "Multi-\nline-\ndescription.", "params": [{ "name": "p1", "doc": "Param 1 description." }, { "name": "p2", "doc": "Param 2\n\tdescription." }], "returns": "Return value\n\tdescription." } self.assertEqual(expected, dct)
def test_all_scenarios_have_docstrings(self): ignored_params = ["self", "scenario_obj"] for scenario_group in utils.itersubclasses(base.Scenario): if scenario_group.__module__.startswith("tests."): continue for method in dir(scenario_group): if base.Scenario.is_scenario(scenario_group, method): scenario = getattr(scenario_group, method) scenario_name = scenario_group.__name__ + "." + method self.assertIsNotNone(scenario.__doc__, "%s doensn't have a docstring." % scenario_name) doc = utils.parse_docstring(scenario.__doc__) short_description = doc["short_description"] self.assertIsNotNone(short_description, "Docstring for %s should have " "at least a one-line description." % scenario_name) self.assertFalse(short_description.startswith("Test"), "One-line description for %s " "should be declarative and not start " "with 'Test(s) ...'" % scenario_name) params_count = scenario.__code__.co_argcount params = scenario.__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_name, "param": param})
def _get_scenario_info(self, query): try: scenario = scenario_base.Scenario.get_scenario_by_name(query) scenario_group_name = utils.get_method_class(scenario).get_name() header = ("%(scenario_group)s.%(scenario_name)s " "(benchmark scenario)" % {"scenario_group": scenario_group_name, "scenario_name": scenario.__name__}) info = self._make_header(header) info += "\n\n" doc = utils.parse_docstring(scenario.__doc__) if not doc["short_description"]: return None info += doc["short_description"] + "\n\n" if doc["long_description"]: info += doc["long_description"] + "\n\n" if doc["params"]: info += "Parameters:\n" for param in doc["params"]: info += " - %(name)s: %(doc)s" % param + "\n" if doc["returns"]: info += "Returns: %s" % doc["returns"] return info except exceptions.NoSuchScenario: return None
def test_parse_incomplete_docstring(self): docstring = """One-line description. :param p1: Param 1 description. :param p2: Param 2 description. """ dct = utils.parse_docstring(docstring) expected = { "short_description": "One-line description.", "long_description": None, "params": [{ "name": "p1", "doc": "Param 1 description." }, { "name": "p2", "doc": "Param 2 description." }], "returns": None } self.assertEqual(dct, expected)
def _get_scenario_info(self, query): try: scenario = scenario_base.Scenario.get_scenario_by_name(query) scenario_group_name = utils.get_method_class(scenario).__name__ header = ("%(scenario_group)s.%(scenario_name)s " "(benchmark scenario)" % { "scenario_group": scenario_group_name, "scenario_name": scenario.__name__ }) info = self._make_header(header) info += "\n\n" doc = utils.parse_docstring(scenario.__doc__) if not doc["short_description"]: return None info += doc["short_description"] + "\n\n" if doc["long_description"]: info += doc["long_description"] + "\n\n" if doc["params"]: info += "Parameters:\n" for param in doc["params"]: info += " - %(name)s: %(doc)s" % param + "\n" if doc["returns"]: info += "Returns: %s" % doc["returns"] return info except exceptions.NoSuchScenario: return None
def _get_descriptions(self, base_cls): descriptions = [] for entity in base_cls.get_all(): name = entity.get_name() doc = utils.parse_docstring(entity.__doc__) description = doc["short_description"] or "" descriptions.append((name, description)) descriptions.sort(key=lambda d: d[0]) return descriptions
def _compose_action_description(action_fn): description = "" if action_fn.__doc__: parsed_doc = utils.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.""" dct = utils.parse_docstring(docstring) expected = { "short_description": "One-line description.", "long_description": None, "params": [], "returns": None } self.assertEqual(expected, dct)
def _get_descriptions(self, base_cls, subclass_filter=None): descriptions = [] subclasses = discover.itersubclasses(base_cls) if subclass_filter: subclasses = filter(subclass_filter, subclasses) for entity in subclasses: name = entity.get_name() doc = utils.parse_docstring(entity.__doc__) description = doc["short_description"] or "" descriptions.append((name, description)) descriptions.sort(key=lambda d: d[0]) return descriptions
def _get_descriptions(self, base_cls, subclass_filter=None): descriptions = [] subclasses = utils.itersubclasses(base_cls) if subclass_filter: subclasses = filter(subclass_filter, subclasses) for entity in subclasses: name = entity.__name__ doc = utils.parse_docstring(entity.__doc__) description = doc["short_description"] or "" descriptions.append((name, description)) descriptions.sort(key=lambda d: d[0]) return descriptions
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 = utils.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 test_parse_incomplete_docstring(self): docstring = """One-line description. :param p1: Param 1 description. :param p2: Param 2 description. """ dct = utils.parse_docstring(docstring) expected = { "short_description": "One-line description.", "long_description": None, "params": [{"name": "p1", "doc": "Param 1 description."}, {"name": "p2", "doc": "Param 2 description."}], "returns": None } self.assertEqual(dct, expected)
def test_parse_docstring_with_no_params(self): docstring = """One-line description. Multi- line- description. :returns: Return value description. """ dct = utils.parse_docstring(docstring) expected = { "short_description": "One-line description.", "long_description": "Multi-\nline-\ndescription.", "params": [], "returns": "Return value description." } self.assertEqual(dct, expected)
def _get_scenario_group_info(self, query): try: scenario_group = scenario.Scenario.get_by_name(query) if not any(scenario.Scenario.is_scenario(scenario_group, m) for m in dir(scenario_group)): return None info = self._make_header("%s (benchmark scenario group)" % scenario_group.get_name()) info += "\n\n" info += utils.format_docstring(scenario_group.__doc__) scenarios = scenario_group.list_benchmark_scenarios() descriptions = [] for scenario_name in scenarios: cls, method_name = scenario_name.split(".") if hasattr(scenario_group, method_name): scenario_inst = getattr(scenario_group, method_name) doc = utils.parse_docstring(scenario_inst.__doc__) descr = doc["short_description"] or "" descriptions.append((scenario_name, descr)) info += self._compose_table("Benchmark scenarios", descriptions) return info except exceptions.NoSuchScenario: return None
def _get_scenario_info(self, query): try: scenario_inst = scenario.Scenario.get_scenario_by_name(query) scenario_gr_name = utils.get_method_class(scenario_inst).get_name() header = ("%(scenario_group)s.%(scenario_name)s " "(benchmark scenario)" % { "scenario_group": scenario_gr_name, "scenario_name": scenario_inst.__name__ }) info = self._make_header(header) info += "\n\n" doc = utils.parse_docstring(scenario_inst.__doc__) if not doc["short_description"]: return None info += doc["short_description"] + "\n\n" if doc["long_description"]: info += doc["long_description"] + "\n\n" if doc["params"]: args = inspect.getargspec(scenario_inst) if args.defaults: default_values = dict( zip(args.args[-len(args.defaults):], args.defaults)) else: default_values = {} info += "Parameters:\n" for param in doc["params"]: info += " - %(name)s: %(doc)s" % param name = param["name"] if name in default_values: if default_values[name] is not None: info += " [Default: %s]" % default_values[name] else: info += " [optional]" info += "\n" if doc["returns"]: info += "Returns: %s" % doc["returns"] return info except exceptions.NoSuchScenario: return None
def _get_scenario_info(self, query): try: scenario_inst = scenario.Scenario.get_scenario_by_name(query) scenario_gr_name = utils.get_method_class(scenario_inst).get_name() header = ("%(scenario_group)s.%(scenario_name)s " "(benchmark scenario)" % {"scenario_group": scenario_gr_name, "scenario_name": scenario_inst.__name__}) info = self._make_header(header) info += "\n\n" doc = utils.parse_docstring(scenario_inst.__doc__) if not doc["short_description"]: return None info += doc["short_description"] + "\n\n" if doc["long_description"]: info += doc["long_description"] + "\n\n" if doc["params"]: args = inspect.getargspec(scenario_inst) if args.defaults: default_values = dict(zip(args.args[-len(args.defaults):], args.defaults)) else: default_values = {} info += "Parameters:\n" for param in doc["params"]: info += " - %(name)s: %(doc)s" % param name = param["name"] if name in default_values: if default_values[name] is not None: info += " [Default: %s]" % default_values[name] else: info += " [optional]" info += "\n" if doc["returns"]: info += "Returns: %s" % doc["returns"] return info except exceptions.NoSuchScenario: return None
def _get_scenario_group_info(self, query): try: scenario_group = scenario_base.Scenario.get_by_name(query) if not any(scenario_base.Scenario.is_scenario(scenario_group, m) for m in dir(scenario_group)): return None info = self._make_header("%s (benchmark scenario group)" % scenario_group.__name__) info += "\n\n" info += utils.format_docstring(scenario_group.__doc__) scenarios = scenario_group.list_benchmark_scenarios() descriptions = [] for scenario_name in scenarios: cls, method_name = scenario_name.split(".") if hasattr(scenario_group, method_name): scenario = getattr(scenario_group, method_name) doc = utils.parse_docstring(scenario.__doc__) descr = doc["short_description"] or "" descriptions.append((scenario_name, descr)) info += self._compose_table("Benchmark scenarios", descriptions) return info except exceptions.NoSuchScenario: return None
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]) first_column_len = max(map(sublen, descr_pairs)) + MARGIN for item in descr_pairs: name = getattr(item[1], "alias", item[0]) if item[1].__doc__: doc = utils.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_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. """ dct = utils.parse_docstring(docstring) expected = { "short_description": "One-line description.", "long_description": "Multi-\nline-\ndescription.", "params": [{"name": "p1", "doc": "Param 1 description."}, {"name": "p2", "doc": "Param 2\n\tdescription."}], "returns": "Return value\n\tdescription." } self.assertEqual(expected, dct)
def test_all_scenarios_have_docstrings(self): ignored_params = ["self", "scenario_obj"] for scenario_group in discover.itersubclasses(base.Scenario): if scenario_group.__module__.startswith("tests."): continue for method in dir(scenario_group): if base.Scenario.is_scenario(scenario_group, method): scenario = getattr(scenario_group, method) scenario_name = scenario_group.__name__ + "." + method self.assertIsNotNone( scenario.__doc__, "%s doensn't have a docstring." % scenario_name) doc = utils.parse_docstring(scenario.__doc__) short_description = doc["short_description"] self.assertIsNotNone( short_description, "Docstring for %s should have " "at least a one-line description." % scenario_name) self.assertFalse( short_description.startswith("Test"), "One-line description for %s " "should be declarative and not start " "with 'Test(s) ...'" % scenario_name) params_count = scenario.__code__.co_argcount params = scenario.__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_name, "param": param })