def run(self): ############################################################################################# # Get environment ############################################################################################# env = self.env # ToDo: Keep this in directive!!! collapse = self.options.get("collapse", None) if isinstance(collapse, str) and len(collapse) > 0: if collapse.upper() in ["TRUE", 1, "YES"]: collapse = True elif collapse.upper() in ["FALSE", 0, "NO"]: collapse = False else: raise Exception("collapse attribute must be true or false") else: collapse = getattr(env.app.config, "needs_collapse_details", None) hide = True if "hide" in self.options.keys() else False id = self.options.get("id", None) content = "\n".join(self.content) status = self.options.get("status", None) tags = self.options.get("tags", '') style = self.options.get("style", None) layout = self.options.get("layout", '') template = self.options.get("template", None) pre_template = self.options.get("pre_template", None) post_template = self.options.get("post_template", None) duration = self.options.get("duration", None) completion = self.options.get("completion", None) need_extra_options = {'duration': duration, 'completion': completion} for extra_link in env.config.needs_extra_links: need_extra_options[extra_link['option']] = self.options.get( extra_link['option'], '') for extra_option in env.config.needs_extra_options.keys(): need_extra_options[extra_option] = self.options.get( extra_option, '') return add_need(env.app, self.state, self.docname, self.lineno, need_type=self.name, title=self.trimmed_title, id=id, content=content, status=status, tags=tags, hide=hide, template=template, pre_template=pre_template, post_template=post_template, collapse=collapse, style=style, layout=layout, **need_extra_options)
def run(self): self.prepare_basic_options() self.load_test_file() suite_name = self.options.get('suite', None) if suite_name is None: raise TestReportInvalidOption('Suite not given!') suite = None for suite_obj in self.results: if suite_obj['name'] == suite_name: suite = suite_obj break if suite is None: raise TestReportInvalidOption( 'Suite {} not found in test file {}'.format( suite_name, self.test_file)) cases = suite['tests'] passed = suite['passed'] skipped = suite['skips'] errors = suite['errors'] failed = suite['failures'] main_section = [] docname = self.state.document.settings.env.docname main_section += add_need(self.app, self.state, docname, self.lineno, need_type=self.need_type, title=self.test_name, id=self.test_id, content=self.test_content, links=self.test_links, tags=self.test_tags, status=self.test_status, collapse=self.collapse, file=self.test_file_given, suite=suite['name'], cases=cases, passed=passed, skipped=skipped, failed=failed, errors=errors) if 'auto_cases' in self.options.keys(): for case in suite['testcases']: case_id = self.test_id case_id += '_' + hashlib.sha1( case['classname'].encode("UTF-8") + case['name'].encode("UTF-8")).hexdigest().upper()[:5] options = self.options options['case'] = case['name'] options['classname'] = case['classname'] options['id'] = case_id if 'links' not in self.options: options['links'] = self.test_id elif self.test_id not in options['links']: options['links'] = options['links'] + ';' + self.test_id arguments = [case['name']] case_directive = sphinxcontrib.test_reports.directives.test_case.TestCaseDirective( self.app.config.tr_case[0], arguments, options, '', self.lineno, # no content self.content_offset, self.block_text, self.state, self.state_machine) main_section += case_directive.run() return main_section
def run(self): docname = self.state.document.settings.env.docname app = self.env.app needs_services = self.env.app.needs_services service_name = self.arguments[0] service = needs_services.get(service_name) section = [] if "debug" not in self.options: service_data = service.request(self.options) for datum in service_data: options = {} try: content = datum["content"].split("\n") except KeyError: content = [] content.extend(self.content) if "type" not in datum.keys(): # Use the first defined type, if nothing got defined by service (should not be the case) need_type = self.env.app.config.needs_types[0]["directive"] else: need_type = datum["type"] del datum["type"] if "title" not in datum.keys(): need_title = "" else: need_title = datum["title"] del datum["title"] # We need to check if all given options from services are really available as configured # extra_option or extra_link missing_options = {} for element in datum.keys(): defined_options = list(self.__class__.option_spec.keys()) defined_options.append( "content" ) # Add content, so that it gets not detected as missing if element not in defined_options and element not in getattr( app.config, "needs_extra_links", []): missing_options[element] = datum[element] # Finally delete not found options for missing_option in missing_options: del datum[missing_option] if app.config.needs_service_all_data: for name, value in missing_options.items(): content.append(f"\n:{name}: {value}") # content.insert(0, '.. code-block:: text\n') options["content"] = "\n".join(content) # Replace values in datum with calculated/checked ones. datum.update(options) # ToDo: Tags and Status are not set (but exist in data) section += add_need(self.env.app, self.state, docname, self.lineno, need_type, need_title, **datum) else: try: service_debug_data = service.debug(self.options) except NotImplementedError: service_debug_data = { "error": f'Service {service_name} does not support "debug" output.' } viewer_node = get_data_viewer_node(title="Debug data", data=service_debug_data) section.append(viewer_node) return section
def run(self): docname = self.state.document.settings.env.docname app = self.env.app needs_services = self.env.app.needs_services service_name = self.arguments[0] service = needs_services.get(service_name) service_data = service.request(self.options) section = [] for datum in service_data: options = {} try: content = datum['content'].split('\n') except KeyError: content = [] content.extend(self.content) if 'type' not in datum.keys(): # Use the first defined type, if nothing got defined by service (should not be the case) need_type = self.env.app.config.needs_types[0]['directive'] else: need_type = datum['type'] del datum['type'] if 'title' not in datum.keys(): need_title = "" else: need_title = datum['title'] del datum['title'] # We need to check if all given options from services are really available as configured # extra_option or extra_link missing_options = {} for element in datum.keys(): defined_options = list(self.__class__.option_spec.keys()) defined_options.append( 'content' ) # Add content, so that it gets not detected as missing if element not in defined_options and element not in getattr( app.config, "needs_extra_links", []): missing_options[element] = datum[element] # Finally delete not found options for missing_option in missing_options: del datum[missing_option] if app.config.needs_service_all_data: for name, value in missing_options.items(): content.append('\n:{}: {}'.format(name, value)) # content.insert(0, '.. code-block:: text\n') options['content'] = '\n'.join(content) # Replace values in datum with calculated/checked ones. datum.update(options) # ToDo: Tags and Status are not set (but exist in data) section += add_need(self.env.app, self.state, docname, self.lineno, need_type, need_title, **datum) return section
case_name = case_full_name case_parameter = '' if case_parameter is None: case_parameter = '' main_section = [] docname = self.state.document.settings.env.docname main_section += add_need(self.app, self.state, docname, self.lineno, need_type=self.need_type, title=self.test_name, id=self.test_id, content=content, links=self.test_links, tags=self.test_tags, status=self.test_status, collapse=self.collapse, file=self.test_file_given, suite=suite['name'], case=case_full_name, case_name=case_name, case_parameter=case_parameter, classname=class_name, result=result, time=time, style=style) return main_section
def run(self): ############################################################################################# # Get environment ############################################################################################# env = self.env # ToDo: Keep this in directive!!! collapse = self.options.get("collapse", None) if isinstance(collapse, str): if collapse.upper() in ["TRUE", 1, "YES"]: collapse = True elif collapse.upper() in ["FALSE", 0, "NO"]: collapse = False else: raise Exception("collapse attribute must be true or false") hide = "hide" in self.options id = self.options.get("id", None) content = "\n".join(self.content) status = self.options.get("status", None) if status: status = status.replace( "__", "" ) # Support for multiline options, which must use __ for empty lines tags = self.options.get("tags", "") style = self.options.get("style", None) layout = self.options.get("layout", "") template = self.options.get("template", None) pre_template = self.options.get("pre_template", None) post_template = self.options.get("post_template", None) duration = self.options.get("duration", None) completion = self.options.get("completion", None) need_extra_options = {"duration": duration, "completion": completion} for extra_link in env.config.needs_extra_links: need_extra_options[extra_link["option"]] = self.options.get( extra_link["option"], "") NEEDS_CONFIG.get("extra_options") for extra_option in NEEDS_CONFIG.get("extra_options").keys(): need_extra_options[extra_option] = self.options.get( extra_option, "") need_nodes = add_need( env.app, self.state, self.docname, self.lineno, need_type=self.name, title=self.trimmed_title, id=id, content=content, status=status, tags=tags, hide=hide, template=template, pre_template=pre_template, post_template=post_template, collapse=collapse, style=style, layout=layout, **need_extra_options, ) return need_nodes
def run(self): needs_list = {} version = self.options.get("version", None) filter_string = self.options.get("filter", None) id_prefix = self.options.get("id_prefix", "") tags = self.options.get("tags", []) if len(tags) > 0: tags = [tag.strip() for tag in re.split(";|,", tags)] env = self.state.document.settings.env need_import_path = self.arguments[0] if not os.path.isabs(need_import_path): # Relative path should starts from current rst file directory curr_dir = os.path.dirname(self.docname) new_need_import_path = os.path.join(env.app.confdir, curr_dir, need_import_path) correct_need_import_path = new_need_import_path if not os.path.exists(new_need_import_path): # Check the old way that calculates relative path starting from conf.py directory old_need_import_path = os.path.join(env.app.confdir, need_import_path) if os.path.exists(old_need_import_path): correct_need_import_path = old_need_import_path logger.warning( "Deprecation warning: Relative path must be relative to the current document in future, " "not to the conf.py location. Use a starting '/', like '/needs.json', to make the path " "relative to conf.py.") else: # Absolute path starts with /, based on the conf.py directory. The / need to be striped correct_need_import_path = os.path.join(env.app.confdir, need_import_path[1:]) if not os.path.exists(correct_need_import_path): raise ReferenceError( f"Could not load needs import file {correct_need_import_path}") with open(correct_need_import_path) as needs_file: needs_file_content = needs_file.read() try: needs_import_list = json.loads(needs_file_content) except json.JSONDecodeError as e: # ToDo: Add exception handling raise e if version is None: try: version = needs_import_list["current_version"] if not isinstance(version, str): raise KeyError except KeyError: raise CorruptedNeedsFile( f"Key 'current_version' missing or corrupted in {correct_need_import_path}" ) if version not in needs_import_list["versions"].keys(): raise VersionNotFound( f"Version {version} not found in needs import file {correct_need_import_path}" ) needs_list = needs_import_list["versions"][version]["needs"] # Filter imported needs needs_list_filtered = {} for key, need in needs_list.items(): if filter_string is None: needs_list_filtered[key] = need else: filter_context = {key: value for key, value in need.items()} # Support both ways of addressing the description, as "description" is used in json file, but # "content" is the sphinx internal name for this kind of information filter_context["content"] = need["description"] try: if filter_single_need(env.app, filter_context, filter_string): needs_list_filtered[key] = need except Exception as e: logger.warning( "needimport: Filter {} not valid. Error: {}. {}{}". format(filter_string, e, self.docname, self.lineno)) needs_list = needs_list_filtered # If we need to set an id prefix, we also need to manipulate all used ids in the imported data. if id_prefix: needs_ids = needs_list.keys() for need in needs_list.values(): for id in needs_ids: # Manipulate links in all link types for extra_link in env.config.needs_extra_links: if extra_link["option"] in need and id in need[ extra_link["option"]]: for n, link in enumerate( need[extra_link["option"]]): if id == link: need[extra_link["option"]][n] = "".join( [id_prefix, id]) # Manipulate descriptions # ToDo: Use regex for better matches. need["description"] = need["description"].replace( id, "".join([id_prefix, id])) # tags update for need in needs_list.values(): need["tags"] = need["tags"] + tags need_nodes = [] for need in needs_list.values(): # Set some values based on given option or value from imported need. need["template"] = self.options.get( "template", getattr(need, "template", None)) need["pre_template"] = self.options.get( "pre_template", getattr(need, "pre_template", None)) need["post_template"] = self.options.get( "post_template", getattr(need, "post_template", None)) need["layout"] = self.options.get("layout", getattr(need, "layout", None)) need["style"] = self.options.get("style", getattr(need, "style", None)) need["style"] = self.options.get("style", getattr(need, "style", None)) if "hide" in self.options: need["hide"] = True else: need["hide"] = getattr(need, "hide", None) need["collapse"] = self.options.get( "collapse", getattr(need, "collapse", None)) # The key needs to be different for add_need() api call. need["need_type"] = need["type"] # Replace id, to get unique ids need["id"] = id_prefix + need["id"] need["content"] = need["description"] # Remove unknown options, as they may be defined in source system, but not in this sphinx project extra_link_keys = [ x["option"] for x in env.config.needs_extra_links ] extra_option_keys = list(NEEDS_CONFIG.get("extra_options").keys()) default_options = [ "title", "status", "content", "id", "tags", "hide", "template", "pre_template", "post_template", "collapse", "style", "layout", "need_type", ] delete_options = [] for option in need.keys(): if option not in default_options + extra_link_keys + extra_option_keys: delete_options.append(option) for option in delete_options: del need[option] need["docname"] = self.docname need["lineno"] = self.lineno nodes = add_need(env.app, self.state, **need) need_nodes.extend(nodes) return need_nodes
def run(self): self.prepare_basic_options() results = self.load_test_file() # Error handling, if file not found if results is None: main_section = [] content = nodes.error() para = nodes.paragraph() text_string = "Test file not found: {}".format(self.test_file) text = nodes.Text(text_string, text_string) para += text content.append(para) main_section.append(content) return main_section suites = len(self.results) cases = sum([int(x['tests']) for x in self.results]) passed = sum([x['passed'] for x in self.results]) skipped = sum([x['skips'] for x in self.results]) errors = sum([x['errors'] for x in self.results]) failed = sum([x['failures'] for x in self.results]) main_section = [] docname = self.state.document.settings.env.docname main_section += add_need(self.app, self.state, docname, self.lineno, need_type=self.need_type, title=self.test_name, id=self.test_id, content=self.test_content, links=self.test_links, tags=self.test_tags, status=self.test_status, collapse=self.collapse, file=self.test_file_given, suites=suites, cases=cases, passed=passed, skipped=skipped, failed=failed, errors=errors) if 'auto_cases' in self.options.keys( ) and 'auto_suites' not in self.options.keys(): raise TestReportIncompleteConfiguration( 'option auto_cases must be used together with ' 'auto_suites for test-file directives.') if 'auto_suites' in self.options.keys(): for suite in self.results: suite_id = self.test_id suite_id += '_' + hashlib.sha1( suite['name'].encode("UTF-8")).hexdigest().upper()[:3] options = self.options options['suite'] = suite['name'] options['id'] = suite_id if 'links' not in self.options: options['links'] = self.test_id elif self.test_id not in options['links']: options['links'] = options['links'] + ';' + self.test_id arguments = [suite['name']] suite_directive = sphinxcontrib.test_reports.directives.test_suite.TestSuiteDirective( self.app.config.tr_suite[0], arguments, options, '', self.lineno, # no content self.content_offset, self.block_text, self.state, self.state_machine) main_section += suite_directive.run() return main_section