def __read(self, tname, input_handler, commit, file_info, req_set): '''Read in the topic and create all the tags.''' self.__tags = TxtRecord.from_string(file_info.get_content(), tname, input_handler.get_txt_io_config()) for tag in self.__tags: # If the topic has subtopics, read them also in. if tag.get_tag() == "SubTopic": lfile_info = input_handler.get_file_info_with_type( commit, "topics", tag.get_content() + ".tic") ntopic = Topic(self.__topicset, self._config, input_handler, commit, lfile_info, req_set) # The topic itself is already added in the constrcutor of Topic. # Therefore there is no need to add it here (again). # self.__topicset.add_node(ntopic) self.__topicset.create_edge(self, ntopic) elif tag.get_tag() == "Name": if self.__topic_name != None: # TODO: Multiple Names assert (False) self.__topic_name = tag.get_content() elif tag.get_tag() == "IncludeRequirements": if tag.get_content() != "full": raise RMTException( 113, "IncludeRequirements value not " "supported [%s]" % tag.get_content(), self.get_name()) self.__requirements = req_set.restrict_to_topics(tname) tracer.debug( "Found [%d] requirements for topic [%s]." % (self.__requirements.get_requirements_cnt(), tname)) # Check for the existence of the name if self.__topic_name == None: raise RMTException(62, "Mandatory tag 'Name' not given in topic", self.get_name())
def __read(self, tname, input_handler, commit, file_info, req_set): '''Read in the topic and create all the tags.''' Encoding.check_unicode(tname) self.__tags = TxtRecord.from_string(file_info.get_content(), tname, input_handler.get_txt_io_config()) for tag in self.__tags: # If the topic has subtopics, read them also in. if tag.get_tag() == "SubTopic": lfile_info = input_handler.get_file_info_with_type( commit, "topics", tag.get_content() + ".tic") ntopic = Topic(self.__digraph, self._config, input_handler, commit, lfile_info, req_set) self.__digraph.add_node(ntopic) Digraph.create_edge(self, ntopic) elif tag.get_tag() == "Name": if self.__topic_name is not None: # There can (currently) be only one name assert False self.__topic_name = tag.get_content() elif tag.get_tag() == "IncludeRequirements": if tag.get_content() != "full": raise RMTException( 113, "IncludeRequirements value not " "supported [%s]" % tag.get_content(), self.name) self.__requirements = req_set.restrict_to_topics(tname) tracer.debug("Found [%d] requirements for topic [%s]", self.__requirements.get_requirements_cnt(), tname) # Check for the existence of the name if self.__topic_name is None: raise RMTException(62, "Mandatory tag 'Name' not given in topic", self.name)
def generate(self, config, rid, txt): """Generate a RequirementsStatus object based on the parameters""" txt_split = txt.split(':') try: return self.__plugin_manager[txt_split[0]].plugin(config, rid, txt) except KeyError: raise RMTException(91, "%s: Status tag invalid '%s'" % (rid, txt))
def get_named_node(self, name): """Mostly the same as before, but throws if the node can not be found.""" res = self.get_named_node_no_throw(name) if res is None: raise RMTException(23, "node with name '%s' not available" % name) return res
def convert_to_dict(self): self.ldict = {} for i in self: tag = i.get_tag() if tag in self.ldict: raise RMTException(81, "Tag '%s' multiple defined" % tag) self.ldict[i.get_tag()] = i
def find_wt(self, name): '''Get the node with the given name. Throw if not available.''' res = self.find(name) if res == None: raise RMTException(23, "node with name '%s' not available" % name) return res
def parse_date(rid, ds): try: return datetime.datetime.strptime(ds, "%Y-%m-%d").date() except ValueError: raise RMTException( 8, "%s: invalid date specified (must be " "YYYY-MM-DD) was '%s'" % (rid, ds))
def __create_local_ce3s(self): '''Create the local Constraint Execution Environments and evaluate the given statements. This method does two things: - evaluating the constraints in the CE3 - Resetting the 'Constraints' entry in the requirement (instead of the TextRecord a map of name to constraint object is stored).''' tracer.debug("Called.") for req_name, req in self.__requirements.items(): # In each case store a (maybe empty) CE3 in the set. ce3 = CE3() cstrnts = req.get_value("Constraints") if cstrnts is not None: sval = json.loads(cstrnts.get_content()) ctr_dict = {} for ctr in sval: ctr_name = self.get_ctr_name(ctr) if ctr_name not in self.__constraints: raise RMTException(88, "Constraint [%s] does not " "exists" % ctr_name) rcs = self.__constraints.get(ctr_name) ce3.eval(rcs, ctr_name, ctr) ctr_dict[ctr_name] = rcs req.set_value("Constraints", ctr_dict) # Store the fresh create CE3 into the ce3set self.__ce3set.insert(req_name, ce3) tracer.debug("Finished. Number of constraints [%d]", self.__ce3set.length())
def execute(self, executor, func_prefix): '''Execute the parts which are needed for TopicsContinuum.''' tracer.debug("Calling pre [%s]", self.name) FuncCall.pcall(executor, func_prefix + "topic_pre", self) tracer.debug("Calling sub [%s]", self.name) for tag in self.__tags: rtag = tag.get_tag() if rtag == "Name": FuncCall.pcall(executor, func_prefix + "topic_name", tag.get_content()) continue if rtag == "SubTopic": subtopic = self.__digraph.find(tag.get_content()) assert subtopic is not None FuncCall.pcall(executor, func_prefix + "topic_sub_pre", subtopic) subtopic.execute(executor, func_prefix) FuncCall.pcall(executor, func_prefix + "topic_sub_post", subtopic) continue if rtag == "IncludeRequirements": self.__requirements.execute(executor, func_prefix) continue if rtag == "Text": FuncCall.pcall(executor, func_prefix + "topic_text", tag.get_content()) continue raise RMTException(114, "Unknown tag in topic [%s]" % rtag, self.name) tracer.debug("Calling post [%s]", self.name) FuncCall.pcall(executor, func_prefix + "topic_post", self) tracer.debug("Finished [%s]", self.name)
def create_requirement_status(config, rid, l): for rs in [RequirementStatusNotDone, RequirementStatusAssigned, RequirementStatusFinished]: if l.startswith(rs.tval): return rs(config, rid, l) raise RMTException(91, "%s: Status tag invalid '%s'" % (rid, l))
def __get_reqs_impl_detail(self, topic_set): '''Return the implementation details of the requirements.''' prios_impl = [] prios_detail = [] prios_selected = [] prios_assigned = [] prios_finished = [] req_set = topic_set.get_requirement_set() for reqid in req_set.get_all_requirement_ids(): tr = req_set.get_requirement(reqid) try: status = tr.get_status() if isinstance(status, RequirementStatusNotDone): rclass = tr.values["Class"] if isinstance(rclass, ClassTypeImplementable): prios_impl.append([tr.get_prio(), tr.get_id()]) elif isinstance(rclass, ClassTypeSelected): prios_selected.append([tr.get_prio(), tr.get_id()]) else: prios_detail.append([tr.get_prio(), tr.get_id()]) elif isinstance(status, RequirementStatusAssigned): prios_assigned.append(tr) elif isinstance(status, RequirementStatusFinished): prios_finished.append(tr) except KeyError as ke: raise RMTException(35, "%s: KeyError: %s" % (tr.get_id(), ke)) return prios_impl, prios_detail, prios_selected, \ prios_assigned, prios_finished
def __check_for_circles(self): '''This does check if there is a directed circle (e.g. an strongly connected component) in the modules graph.''' scc = strongly_connected_components(self) if check_for_strongly_connected_components(scc): raise RMTException( 26, "There is a strongly connected " "component in the modules graph '%s'" % scc)
def find(self, n): c = 0 for i in self.cs: if n in i: return c, i c += 1 # Node not found raise RMTException(68, "Node [%s] not found" % n)
def add_node(self, node_a): """Adds a new node to the graph""" # Check if the node with the same name already exists. for node_idx in self.nodes: if node_idx.name == node_a.name: raise RMTException( 39, "Node with name '%s' already exists" % node_a.name) self.nodes.append(node_a)
def parse_date(rid, date_str): """Parse the given date as YYYY-MM-DD""" try: return datetime.datetime.strptime(date_str, "%Y-%m-%d").date() except ValueError: raise RMTException( 8, "%s: invalid date specified (must be " "YYYY-MM-DD) was '%s'" % (rid, date_str))
def convert_to_dict(self): """Convert the (internal) list of entries into a dict""" self.ldict = {} for i in self: tag = i.get_tag() if tag in self.ldict: raise RMTException(81, "Tag '%s' multiple defined" % tag) self.ldict[i.get_tag()] = i
def rewrite(self, rid, req): """This tag is mandatory - but might be empty""" if self.get_tag() not in req: return "Factor", 0.0 # Compute the priority. This is done by adding the simple # priorities and afterwars build the average from this. tag = req[self.get_tag()] lop = tag.get_content().split() # The (computed) priority priority_sum = 0.0 num_stakeholders = 0 # A list to check if each stakeholder votes maximal one time. priority_done = [] for line in lop: split_line = line.split(":", 1) if len(split_line) != 2 or not split_line[1]: raise RMTException( 12, "%s: faulty priority declaration '%s'" % (rid, line)) # p[0] is the stakeholder # p[1] is the given priority if split_line[0] not in self.get_config().get_value( 'requirements.stakeholders'): raise RMTException( 13, "%s: stakeholder '%s' not known" % (rid, split_line[0])) if split_line[0] in priority_done: raise RMTException( 14, "%s: stakeholder '%s' voted more " "than once" % (rid, split_line[0])) # Convert it to a float - so it's easier to compare. prio_f = float(split_line[1]) # Check if in valid range [0..10] if prio_f < 0 or prio_f > 10: raise RMTException( 15, "%s: invalid priority '%f' - must " "be between 0 and 10" % (rid, prio_f)) # Compute new sum... priority_sum += prio_f / 10 # ... and increase the stakeholders count. num_stakeholders += 1 # Flag stakeholder that he voted already priority_done.append(split_line[0]) del req[self.get_tag()] return "Factor", priority_sum / float(num_stakeholders)
def __init__(self, _config, rid, t): ts = t.split(":") if len(ts)!=3: raise RMTException(93, "%s: Assigned values invalid '%s'" % (rid, t)) assert(ts[0]==self.tval) self.person = ts[1] self.date = parse_date(rid, ts[2])
def __get_tree_direct(self, base_tree, directory): '''Return the tree of the given directory. This does not walk down the directory structure. It just checks the current hierarchy.''' for tree in base_tree.trees: if tree.name == directory: return tree raise RMTException(108, "directory entry [%s] not found in tree " "[%s]." % (directory, base_tree.name))
def get_value(self, key): '''Returns the value of the given key. If key is not found a RMTException is thrown.''' try: return self.get_raw(key) except CfgEx, cex: raise RMTException(96, "Mandatory configuration parameter " "[%s] not found. (Root cause: [%s])" % (key, cex))
def __init__(self, _config, rid, txt): txt_split = txt.split(":") if len(txt_split) != 3: raise RMTException(93, "%s: Assigned values invalid '%s'" % (rid, txt)) assert txt_split[0] == self.tval RequirementStatusBaseExt.__init__(self, txt_split[1], parse_date(rid, txt_split[2]))
def create_class_type(rid, l): if l == "implementable": return ClassTypeImplementable() if l == "detailable": return ClassTypeDetailable() if l == "selected": return ClassTypeSelected() raise RMTException(95, "%s:class type invalid '%s'" % (rid, l))
def __init_overwrite(self, config, type_str): '''Overwrite the existing default parameters with parameters from the configuration.''' self.__max_line_length = config.get_integer('max_input_line_length', 80) if self.__max_line_length < 0: raise RMTException( 72, "max_input_line_length for type [%s] is " "negative [%s]" % (type_str, self.__max_line_length))
def __check_if_dir_is_in_repo(self, directory): '''Checks if all the directories are the in repository. The absolute path is computed if the path is relative and then compared to the repository base directory.''' tracer.debug("called: directory [%s]" % directory) if self.__repo_base_dir == None: self.__setup_repo(directory) if not directory.startswith(self.__repo_base_dir): raise RMTException(28, "directory [%s] not in repository" % directory)
def create_class_type(rid, type_desc): """Creates the class typed based on the type description""" if type_desc == "implementable": return ClassTypeImplementable() if type_desc == "detailable": return ClassTypeDetailable() if type_desc == "selected": return ClassTypeSelected() raise RMTException(95, "%s:class type invalid '%s'" % (rid, type_desc))
def check_mandatory_tag(self, rid, req, eid): '''Call this from the 'rewrite()' method, if the tag is mandatory. Note: this function only checks the availability of the tag but does not perform any other check. Returns 'True' if the tag is available and 'False' if the tag is not available.''' # The given tag is mandatory if self.__tag not in req: raise RMTException(eid, "Does not contain the " "tag '%s'" % self.__tag, rid)
def rewrite(self, rid, req): '''This attrbute is optional.''' tag, value = self.handle_optional_tag(req) if value is None: return tag, value ival = int(value.get_content()) if ival not in self.valid_values: raise RMTException(4, "%s: effort estimation must be one of %s" % (rid, self.valid_values)) return tag, ival
def get_file_info_with_type(self, commit, file_type, filename): '''Returns the FileInfo object for the given filename.''' assert commit == None tracer.debug("called: file type [%s] filename [%s]" % (file_type, filename)) for directory in self.__dirs[file_type]: tracer.debug("searching in directory [%s]" % directory) full_path = os.path.join(directory, filename) if os.path.exists(full_path): return FileSystem.FileInfo(directory, filename) raise RMTException(112, "file [%s] in [%s] base file not found" % (filename, file_type))
def __connect_nodes(self): '''Precondition: the depends_on must be set. The method connect all the nodes based on this value.''' for mod_name, mod in self.__tagtypes[InputModuleTypes.reqdeps].items(): for node in mod.depends_on: # Connect in both directions if node not in self.__tagtypes[InputModuleTypes.reqdeps]: raise RMTException( 27, "Module '%s' depends on " "'%s' - which does not exists" % (mod_name, node)) self.create_edge( mod, self.__tagtypes[InputModuleTypes.reqdeps][node])
def add_node(self, anode): '''Adds a new node to the graph. Check if the node with the same name already exists.''' assert issubclass(anode.__class__, Digraph.Node) for node in self._named_nodes.values(): if node.get_name() == anode.get_name(): # assert False raise RMTException( 39, "Node with name '%s' already exists" % anode.get_name()) self._named_nodes[anode.get_name()] = anode
def rmttest_positive_02(self): "Checks the __str__ method: with file, no line" rmte = RMTException(77, "ExceptMsg", "MyFile") assert 77 == rmte.get_id() assert "ExceptMsg" == rmte.get_msg() assert "MyFile" == rmte.get_efile() assert rmte.get_eline() is None assert '[ 77]:MyFile: ExceptMsg' == rmte.__str__()
def test_positive_02(self): "Checks the __str__ method: with file, no line" rmte = RMTException(77, "ExceptMsg", "MyFile") assert rmte.get_id() == 77 assert rmte.get_msg() == "ExceptMsg" assert rmte.get_efile() == "MyFile" assert rmte.get_eline() == None assert rmte.__str__() == "[ 77]:MyFile: ExceptMsg"
def test_positive_03(self): "Checks the __str__ method: with file, with line" rmte = RMTException(77, "ExceptMsg", "MyFile", 678) assert rmte.get_id() == 77 assert rmte.get_msg() == "ExceptMsg" assert rmte.get_efile() == "MyFile" assert rmte.get_eline() == 678 assert rmte.__str__() == "[ 77]:MyFile:678: ExceptMsg"
def rmttest_positive_03(self): "Checks the __str__ method: with file, with line" rmte = RMTException(77, "ExceptMsg", "MyFile", 678) assert 77 == rmte.get_id() assert "ExceptMsg" == rmte.get_msg() assert "MyFile" == rmte.get_efile() assert 678 == rmte.get_eline() assert '[ 77]:MyFile:678: ExceptMsg' == rmte.__str__()