def make_requirement(sr: Sequence[SubmissionRequirements], descriptors: Sequence[InputDescriptors]) -> Requirement: if not sr: sr = [] if not descriptors: descriptors = [] if len(sr) == 0: requirement = Requirement( count=len(descriptors), input_descriptors=descriptors, ) return requirement requirement = Requirement( count=len(sr), nested_req=[], ) for tmp_sub_req in sr: try: requirement.nested_req.append( to_requirement(tmp_sub_req, descriptors)) except Exception as err: print( f"Error creating requirement inside to_requirement function, {err}" ) return requirement
def export_rss(self, req, requirement): db = self.env.get_db_cnx() model = Requirement(self) changes = [] change_summary = {} description = wiki_to_html(requirement['description'], self.env, req, db) req.hdf['requirement.description.formatted'] = unicode(description) for change in model.grouped_changelog_entries(requirement, db): changes.append(change) # compute a change summary change_summary = {} # wikify comment if 'comment' in change: comment = change['comment'] change['comment'] = unicode(wiki_to_html( comment, self.env, req, db, absurls=True)) change_summary['added'] = ['comment'] for field, values in change['fields'].iteritems(): if field == 'description': change_summary.setdefault('changed', []).append(field) else: chg = 'changed' if not values['old']: chg = 'set' elif not values['new']: chg = 'deleted' change_summary.setdefault(chg, []).append(field) change['title'] = '; '.join(['%s %s' % (', '.join(v), k) for k, v \ in change_summary.iteritems()]) req.hdf['requirement.changes'] = changes return (req.hdf.render('requirement_rss.cs'), 'application/rss+xml')
def test_job_transmission(self): self.awake_single() # campaignをセット campaign = Campaign(author="cxxx0", requirement=Requirement(values=["zero", "random"], trigger={"timer": 1}), trigger={"timer": 5}, place="All", purpose="test_purpose", destination="mongodb://localhost:27017/") clients["cxxx0"].post('/commander/campaigns', data=json.dumps(campaign.to_dict()), content_type='application/json') time.sleep(1.5) # heartbeatを待つ; 0.7 + 0.4 + alpha # missionを確認 mission = Mission(author="lxxx0", requirement=Requirement(values=["zero", "random"], trigger={"timer": 1}), trigger={"timer": 5}, place="All", purpose=campaign.get_id()) self.assertIn(mission, self.models["lxxx0"].missions.values()) # orderを確認 order = Order(author="sxxx0", values=["zero", "random"], trigger={"timer": 1}, purpose=mission.get_id()) self.assertIn(order, self.models["sxxx0"].orders.values())
def process_request(self, req): req.perm.assert_permission('REQUIREMENT_VIEW') if req.perm.has_permission('REQUIREMENT_CREATE'): req.hdf['report.add_requirement_href'] = req.href.newrequirement() req.hdf['report.edit_fphyp_href'] = req.href('editdict', 'fp') db = self.env.get_db_cnx() report = req.args.get('report', '') # only for use in reports showing (nearly) all requirements if (report == '1' or report == '2' or report == '3'): # flag the report to use the validation button req.hdf['report.is_all_reqs_report'] = 1 myreq = Requirement(self.env) req.hdf['report.currently_validated'] = \ myreq.get_current_reqs_validated() validation_time = myreq.get_most_recent_validation() if validation_time is not None: req.hdf['report.latest_validation'] = \ format_datetime(validation_time) else: req.hdf['report.latest_validation'] = '(None)' # get the value from the validation button if it exists: if req.method == 'POST': validate = req.args.get('ValidateSubmit', '') if validate == 'Validate': # set this flag... # ... and validate the current set of requirements: if myreq.validate_requirements(): req.hdf['report.validate'] = 2 req.hdf['report.latest_validation'] = format_datetime() else: req.hdf['report.validate'] = 1 if report is not '': add_link(req, 'up', req.href('requirements', 'report')) resp = self._render_view(req, db, report) if not resp: return None template, content_type = resp if content_type: return resp add_stylesheet(req, 'hw/css/req_report.css') return 'req_report.cs', None
def to_requirement(sr: SubmissionRequirements, descriptors: Sequence[InputDescriptors]) -> Requirement: input_descriptors = [] nested = [] total_count = 0 if sr._from: if sr._from != "": for tmp_descriptor in descriptors: if contains(tmp_descriptor.groups, sr._from): input_descriptors.append(tmp_descriptor) total_count = len(input_descriptors) if total_count == 0: raise Exception(f"No descriptors for from: {sr._from}") else: for tmp_sub_req in sr.from_nested: try: # recursion logic tmp_req = to_requirement(tmp_sub_req, descriptors) nested.append(tmp_req) except Exception as err: print( f"Error creating requirement from nested submission_requirements, {err}" ) total_count = len(nested) count = sr.count if sr.rule == "all": count = total_count requirement = Requirement(count=count, maximum=sr.maximum, minimum=sr.minimum, input_descriptors=input_descriptors, nested_req=nested) return requirement
def test_get_campaigns_single(self): # add a campaigns campaign = Campaign(author='cxxx0', destination='mongoserv', place='S101', purpose='A great app', requirement=Requirement(values=["zero", "random"], trigger={"timer": 10}), trigger={"timer": 30}) self.app.post('/commander/campaigns', data=json.dumps(campaign.to_dict()), content_type='application/json') # get subordinates response = self.app.get('/commander/campaigns') self.assertEqual(response.status_code, 200) actual = json.loads(response.data.decode("utf-8")) # assert expected = { "_status": { 'success': True, 'msg': "status is ok" }, 'campaigns': [campaign.to_dict()] } self.assertEqual(actual, expected)
def test_add_campaign(self): # 各種パラメータの詳細が決まっていないため、暫定値を採用。 # 最終的には、API自体に無効な入力パラメータをハネる機能を搭載したうえで # TODO: 無効値を確認する用のテストを作成すべき campaign = Campaign(author='cxxx0', destination='mongoserv', place='S101', purpose='A great app', requirement=Requirement(values=["zero", "random"], trigger={"timer": 10}), trigger={"timer": 30}) response = self.app.post('/commander/campaigns', data=json.dumps(campaign.to_dict()), content_type='application/json') self.assertEqual(response.status_code, 200) actual = json.loads(response.data.decode("utf-8")) expected = { "_status": { 'success': True, 'msg': "status is ok" }, "accepted": campaign.to_dict() } self.assertEqual(actual, expected)
def create_requirement(type): """Create and return requirement""" requirement = Requirement(type=type) db.session.add(requirement) db.session.commit() return requirement
def test_get_missions_multi(self): # add some missions mission_base = Mission(author='lxxx0', place='on desk', purpose='A great app', requirement=Requirement( values=["zero", "random"], trigger={"timer": 10}), trigger={"timer": 30}) mission_list = [] for purpose in ['on chair', 'front of door', 'on desk', 'living room']: m = copy.deepcopy(mission_base) m.purpose = purpose mission_list.append(m) for m in mission_list: self.leader_obj.accept_mission(m) # get missions response = self.app.get('/leader/missions') self.assertEqual(response.status_code, 200) actual = loads(response.data.decode("utf-8")) actual_list = actual['missions'] # assert status expected_status = {'success': True, 'msg': "status is ok"} self.assertEqual(actual['_status'], expected_status) # assert items expected_list = [c.to_dict() for c in mission_list] self.assertEqual(len(actual_list), len(expected_list)) for exp in expected_list: if exp not in actual_list: self.fail('{0} is not found.'.format(exp)) pass
def _do_modify(self, req, db): self._do_arg_checks(req) component = req.args.get('component') fp = Fp(self.env, name=req.args.get('fp')) object = Object(self.env, name=req.args.get('object')) requirement = Requirement(self.env, component, fp['id'], object['id'], db) status = requirement['status'] requirement.populate(req.args) requirement['fp'] = fp['id'] requirement['object'] = object['id'] requirement['status'] = status now = int(time.time()) cnum = req.args.get('cnum') replyto = req.args.get('replyto') internal_cnum = cnum if cnum and replyto: internal_cnum = '%s.%s' % (replyto, cnum) if (status != 'disabled' and req.args.get('status') != 'on') \ or \ (status == 'disabled' and req.args.get('status') == 'on'): req.perm.assert_permission('REQUIREMENT_DISENABLE') if req.args.get('status') == 'on': requirement['status'] = 'enabled' else: requirement['status'] = 'disabled' if requirement.save_changes(get_reporter_id(req, 'author'), req.args.get('comment'), when=now, db=db, cnum=internal_cnum): db.commit() # Notify try: rn = RequirementNotifyEmail(self.env) rn.notify(requirement, newrequirement=False) except Exception, e: self.log.exception("Failure sending notification on creation " "of requirement <%s %s>: %s" % (fp['name'], object['name'], e))
def _do_create(self, req, db=None): if not req.args.get('component'): raise TracError('Requirements must contain a component.') if not req.args.get('fp'): raise TracError('Requirements must contain a functional primitive.') if not req.args.get('object'): raise TracError('Requirements must contain an object.') requirement = Requirement(self.env, db=db) requirement.populate(req.args) try: # if a known hyponym was used, get corresponding fp. temp_hyp = Hyponym(self.env, name=req.args.get('fp'), db=db) temp_fp = Fp(self.env, id=temp_hyp['fp'], db=db) except TracError: try: #or, if a known fp was used, get instance of Fp temp_fp = Fp(self.env, name=req.args.get('fp'), db=db) except TracError: #run check funtion for enabled adding fp #if unknown fp used, insert it into the database if(Fp(self.env).check_on_fly_fp() == "enabled"): temp_fp = Fp(self.env, db=db) temp_fp['name'] = req.args.get('fp') temp_fp.insert(db=db) else: raise TracError("On the fly creation of Fps disabled") requirement.values['fp'] = temp_fp['id'] try: temp_object = Object(self.env, name=req.args.get('object'), db=db) except TracError: #run check for function enabling obj if(Object(self.env).check_on_fly_obj() == "enabled"): temp_object = Object(self.env, db=db) temp_object['name'] = req.args.get('object') temp_object.insert(db=db) else: raise TracError("On the fly creation of objects disabled") requirement.values['object'] = temp_object['id'] requirement.values['creator'] = get_reporter_id(req, 'creator') requirement.insert(db=db) # Notify try: rn = RequirementNotifyEmail(self.env) rn.notify(requirement, newrequirement=True) except Exception, e: self.log.exception("Failure sending notification on creation of " "requirement <%s %s>: %s" % (temp_fp['name'], temp_object['name'], e))
def process_request(self, req): template = 'dashboard.cs' add_stylesheet(req, 'hw/css/dashboard.css') reports = [('Requirements by Component', 'report/1'), ('Requirements with Associated Tickets', 'report/5'), ('Most/least Changed Requirements','view/3' ), ('Requirements by Milestone', 'report/7'), ('Disabled Requirements by Component', 'report/8')] req.hdf['report_href'] = req.href('requirements', 'report') req.hdf['rlist'] = reports req.hdf['requirement_href'] = req.href.requirements() #Valdation Dashboard Module Data tmpreq = Requirement(self.env) val_time = tmpreq.get_most_recent_validation() if val_time != None: req.hdf['recent_val_date'] = format_datetime(val_time) else: req.hdf['recent_val_date'] = 1 req.hdf['current_val'] = tmpreq.get_current_reqs_validated() req.hdf['show_val_report'] = tmpreq.get_changed_reqs_since_validation() req.hdf['req_ood_href'] = req.href('requirements', 'report', '11') req.hdf['req_changed_href'] = req.href.requirements('report', '12') #dashboard header links req.hdf['editdict.href_fp'] = req.href('editdict', 'fp') req.hdf['requirement.add_requirement_href'] = req.href.newrequirement() req.hdf['trac.href.editdict'] = req.href('editdict', 'fp') #dashboard graph links req.hdf['graph_path'] = req.href.requirements() + '/graph' add_link(req, 'top', req.href('requirements', 'report')) return (template, None)
def process_request(self, req): req.perm.assert_permission('REQUIREMENT_CREATE') template = 'newrequirement.cs'; # No need to preview a tiny form like this if req.method == 'POST' and not req.args.has_key('preview'): self._do_create(req) requirement = Requirement(self.env) req.hdf['components'] = requirement.get_components() req.hdf['trac.href.newrequirement'] = req.href.newrequirement() req.hdf['trac.href.auto_complete'] = req.href.newrequirement('ajax') req.hdf['title'] = 'New Requirement' # Provide FORM_TOKEN for Ajax POST request req.hdf['form_token'] = req.form_token add_stylesheet(req, 'hw/css/requirement.css') add_script(req, 'hw/javascript/prototype.js') add_script(req, 'hw/javascript/scriptaculous.js') return (template, None)
def test_get_campaigns_multi(self): # add some campaigns campaign_base = Campaign(author='cxxx0', destination='mongoserv', place='S101', purpose='A great app', requirement=Requirement( values=["zero", "random"], trigger={"timer": 10}), trigger={"timer": 30}) campaign_list = [] for place in ['S101', 'S102', 'S103', 'S104']: c = copy.deepcopy(campaign_base) c.place = place campaign_list.append(c) for c in campaign_list: self.app.post('/commander/campaigns', data=json.dumps(c.to_dict()), content_type='application/json') # get campaigns response = self.app.get('/commander/campaigns') self.assertEqual(response.status_code, 200) actual = json.loads(response.data.decode("utf-8")) actual_list = actual['campaigns'] # assert status expected_status = {'success': True, 'msg': "status is ok"} self.assertEqual(actual['_status'], expected_status) # assert items expected_list = [c.to_dict() for c in campaign_list] self.assertEqual(len(actual_list), len(expected_list)) for exp in expected_list: if exp not in actual_list: self.fail('{0} is not found.'.format(exp)) pass
def test_get_missions_single(self): # add a mission mission = Mission(author='lxxx0', place='on desk', purpose='A great app', requirement=Requirement(values=["zero", "random"], trigger={"timer": 10}), trigger={"timer": 30}) self.leader_obj.accept_mission(mission) # get subordinates response = self.app.get('/leader/missions') self.assertEqual(response.status_code, 200) actual = loads(response.data.decode("utf-8")) # assert expected = { "_status": { 'success': True, 'msg': "status is ok" }, 'missions': [mission.to_dict()] } self.assertEqual(actual, expected)
def process_request(self, req): # initialize cache component self.cache = DataCache(self.env) # Grab arguments if re.match(r'/requirements/graph/\w+/?$',req.path_info) is not None: m = re.match(r'/requirements/graph/(\w+)/?$', req.path_info) (graph,) = m.groups() cacheddata = self.cache.get_data(None, None, None, graph) if cacheddata: data = pickle.loads(cacheddata) else: # Determine which image generator to call canvas = None # Initialize requirement (to grab metric data) self.requirement = Requirement(self.env) # Dashboard Graphs if graph[0:12] == 'dash_overall': canvas = self.dash_overall() elif graph[0:19] == 'component_req_count': canvas = self.component_req_count() elif graph[0:8] == 'dash_pie': canvas = self.dash_pie() # Other Graphs elif graph[0:7] == 'entropy': canvas = self.entropy_graph() # Extract the image into a string data = self._image_data(canvas) self.cache.set_data(None, None, None, graph, pickle.dumps(data)) else: m = re.match(r'/requirement/graph/(\w+)-(\w+)-(\w+)/(\w+)/?$', req.path_info) (component, fp, object, graph) = m.groups() cacheddata = self.cache.get_data(component, fp, object, graph) if cacheddata: data = pickle.loads(cacheddata) else: # Initialize requirement (to grab metric data) self.requirement = Requirement(self.env, component, Fp(self.env, name=fp)['id'], Object(self.env, name=object)['id']) # Determine which image generator to call # *** Requirement specific graphs *** canvas = None if graph[0:3] == 'mls': (mls, width) = graph.split('_') data = self.most_least_cited( int( width ) ) else: if graph == 'test': canvas = self.test() elif graph[0:17] == 'changes_over_time': ( garbage, garbage, garbage, secs_in_unit ) = graph.split('_') canvas = self.changes_over_time(int(secs_in_unit)) elif graph[0:17] == 'tickets_over_time': canvas = self.tickets_over_time() # Extract the image into a string data = self._image_data(canvas) self.cache.set_data(component, fp, object, graph, pickle.dumps(data)) # Send reponse headers & the image string req.send_header('content-type', 'image/png') req.end_headers() req.write(data) # Return nothing, as we have done all the work return None
def test_missoin_do(self): def post_report(url, data=None, json=None, etag=None, **kwargs): res = requests.Response() res.status_code = 200 res_dict = { "_status": { "msg": "ok", "success": True }, "accepted": json } res._content = dumps(res_dict).encode() return res, None self.leader_obj.superior_ep = "test://cxxx0/commander/" soldier = SoldierInfo(id="sxxx0", name="sol-test", place="left", weapons=[], orders=[]) self.leader_obj.accept_subordinate(soldier) mission = Mission(author="sxxx0", requirement=Requirement(values=["zero", "random"], trigger={"timer": 0.4}), trigger={"timer": 0.7}, place="All", purpose="some purpose hash") work_1 = Work(time=datetime.utcnow().isoformat(), purpose=mission.get_id(), values=[0, 0.584249]) work_2 = Work(time=datetime.utcnow().isoformat(), purpose=mission.get_id(), values=[0, 0.238491]) work_3 = Work( time=datetime.utcnow().isoformat(), purpose="0" + mission.get_id()[:-1], # 上2つとずらす values=[0, 0.045066]) self.leader_obj.accept_work("sxxx0", work_1) self.leader_obj.accept_work("sxxx0", work_2) self.leader_obj.accept_work("sxxx0", work_3) with patch("utils.rest.post", side_effect=post_report) as m: self.leader_obj.accept_mission(mission) time.sleep(1) self.assertEqual(m.call_count, 1) self.assertEqual( m.call_args[0][0], "test://cxxx0/commander/subordinates/lxxx0/report") # reportのチェック actual = m.call_args[1]["json"] self.assertEqual(set(actual.keys()), {"time", "place", "purpose", "values"}) self.assertEqual(actual["purpose"], "some purpose hash") self.assertEqual(len(actual["values"]), 2) # report.valuesのチェック work_in_1 = work_1.to_dict() del work_in_1["purpose"] work_in_1["place"] = "left" work_in_2 = work_2.to_dict() del work_in_2["purpose"] work_in_2["place"] = "left" self.assertIn(work_in_1, actual["values"]) self.assertIn(work_in_2, actual["values"]) self.leader_obj.superior_ep = "" # shutdownでDELETEを送信するのを阻止
class RequirementGraphComponent(Component): implements(IRequestHandler) # Don't let trac.web.main.process_request use a template on us use_template = False # Reserve room for a Requirement instance requirement = None # IRequestHandler methods def match_request(self, req): """ Match /requirement/graph/component-fp-object/graph_name """ if re.match(r'/requirement/graph/\w+-\w+-\w+/\w+/?$', req.path_info) is not None: return True elif re.match(r'/requirements/graph/\w+/?$', req.path_info) is not None: return True else: return False def process_request(self, req): # initialize cache component self.cache = DataCache(self.env) # Grab arguments if re.match(r'/requirements/graph/\w+/?$',req.path_info) is not None: m = re.match(r'/requirements/graph/(\w+)/?$', req.path_info) (graph,) = m.groups() cacheddata = self.cache.get_data(None, None, None, graph) if cacheddata: data = pickle.loads(cacheddata) else: # Determine which image generator to call canvas = None # Initialize requirement (to grab metric data) self.requirement = Requirement(self.env) # Dashboard Graphs if graph[0:12] == 'dash_overall': canvas = self.dash_overall() elif graph[0:19] == 'component_req_count': canvas = self.component_req_count() elif graph[0:8] == 'dash_pie': canvas = self.dash_pie() # Other Graphs elif graph[0:7] == 'entropy': canvas = self.entropy_graph() # Extract the image into a string data = self._image_data(canvas) self.cache.set_data(None, None, None, graph, pickle.dumps(data)) else: m = re.match(r'/requirement/graph/(\w+)-(\w+)-(\w+)/(\w+)/?$', req.path_info) (component, fp, object, graph) = m.groups() cacheddata = self.cache.get_data(component, fp, object, graph) if cacheddata: data = pickle.loads(cacheddata) else: # Initialize requirement (to grab metric data) self.requirement = Requirement(self.env, component, Fp(self.env, name=fp)['id'], Object(self.env, name=object)['id']) # Determine which image generator to call # *** Requirement specific graphs *** canvas = None if graph[0:3] == 'mls': (mls, width) = graph.split('_') data = self.most_least_cited( int( width ) ) else: if graph == 'test': canvas = self.test() elif graph[0:17] == 'changes_over_time': ( garbage, garbage, garbage, secs_in_unit ) = graph.split('_') canvas = self.changes_over_time(int(secs_in_unit)) elif graph[0:17] == 'tickets_over_time': canvas = self.tickets_over_time() # Extract the image into a string data = self._image_data(canvas) self.cache.set_data(component, fp, object, graph, pickle.dumps(data)) # Send reponse headers & the image string req.send_header('content-type', 'image/png') req.end_headers() req.write(data) # Return nothing, as we have done all the work return None def test(self): # Grab a blank, 100x100 image and the color palette fig = self._new_image((2,2)) canvas = FigureCanvasAgg(fig) plot = fig.add_subplot(111) # Return our image return canvas def entropy_graph(self): """Creates a graph of entropy over time for requirements This returns an image with each requirement's entropy over time shown over the course of the project. If a project is old, or there are a lot of requirements, this can be a time consuming process. """ # Image generation prelude. fig = self._new_image((4,4)) canvas = FigureCanvasAgg(fig) ax = fig.add_axes([0.1, 0.2, 0.85, 0.75]) # Set up our time range from oldest time to now/newest. metric = RequirementMetric(Requirement(self.env)) start_time = metric.model.get_timestamp_first_entity() end_time = metric.model.get_timestamp_latest_req_reqchange_milestone() current_time = int(time.time()) if current_time > end_time: end_time = current_time #create the list of timestamps and make labels. times = [] timestamp = end_time # We'll use two week increments for now to reduce # delay while loading. seconds_in_unit = (60 * 60 * 24 * 7 * 2) while timestamp > start_time: times.append(timestamp) timestamp -= seconds_in_unit times.reverse() labels = [time.strftime("%b %d '%y",time.gmtime(timestamp)) \ for timestamp in times] # Create the coordinates lists for graphing coords = {} i = 0 for timestamp in times: i = i + 1 if timestamp > current_time: break; entropy_data = metric.entropy(timestamp) if entropy_data: _,_,_, req_entropies, _, _ = entropy_data for key in req_entropies.keys(): if not coords.has_key(key): coords[key] = [(i, req_entropies[key])] else: coords[key].append((i, req_entropies[key])) biggest = [] # Now we can actually graph them all for req in coords.keys(): x = [x[0] for x in coords[req]] y = [y[1] for y in coords[req]] biggest.append(max(y)) ax.plot(x,y,'k-') # Add the milestone markers. milestones = Requirement(self.env).get_milestones() x = [] for (_, due) in milestones: if due == 0: continue x.append( float(due - times[0]) / float( seconds_in_unit)) height = int(float(max(biggest)) + 1.5) ax.vlines(x, 0, height,colors='r') # Label and shape the graph ax.set_xticks(range(0, len(times), 1)) ax.set_xticklabels(labels) ax.set_xlim(0, len(times)) setp(ax.get_xticklabels(),'rotation', 80, fontsize=6) ax.set_xlabel('Time in two-week increments', fontsize=6) ax.set_yticks(arange(0,height, 1)) ax.set_ylim(0, height) setp(ax.get_yticklabels(), fontsize=6) ax.set_ylabel("Entropy", fontsize=6) return canvas def tickets_over_time(self): fig = self._new_image((3,3)) canvas = FigureCanvasAgg(fig) when = now = int(time.time()) month=['Jan','Feb','Mar','Apr','May','Jun', 'Jul','Aug','Sep','Oct','Nov','Dec'] numMonth=datetime.date.today().month dates={} #rotates months to puts the current month #as the last month in the array # FIXME: there has to be a simpler/clearer/faster # way to do this. (modulus and offsets?) for j in range(0,12): dates[j+1]=month[j] current=dates[numMonth] while(month[11]!=current): tempMonth=month[0] for i in range(0,11): month[i]=month[i+1] month[11]=tempMonth valEnh=[0,0,0,0,0,0,0,0,0,0,0,0] valDef=[0,0,0,0,0,0,0,0,0,0,0,0] valTas=[0,0,0,0,0,0,0,0,0,0,0,0] for i in range(11, -1, -1): metrics = self.requirement.get_tickets_over_time_metrics(when) for metric in metrics: type, count = metric if type == 'task': valTas[i] = count elif type == 'defect': valDef[i] = count elif type == 'enhancement': valEnh[i] = count when = when - (3600 * 24 * 30) maxVal = max([max(valEnh), max(valDef), max(valTas)]) #the maximum value if maxVal == 0: # If there are no tickets ever associated, return blank # image instead of empty graph. return canvas # If we have usable data (tickets reference this requirement) # then we will graph them by month. ax=fig.add_subplot(111) num = 12 #the total number of values ind = arange(num) # the x locations for the groups if maxVal > 20: # sets how often the y-axis increments inc = maxVal / 10 else: inc=1 width=.2 # sets the width of the bars maxY = maxVal + 5 p1 = ax.bar(ind,valEnh, width=width, align='center',color='b') p2 = ax.bar(ind+width,valTas, width=width, align='center',color='g') p3 = ax.bar(ind+2*width,valDef, width=width, align='center',color='r') ax.set_xticks(ind+((3/2)*width)) ax.set_xticklabels(month) ax.set_xlim(-width,len(ind)) setp(ax.get_xticklabels(),'rotation', 45, fontsize=8) ax.set_yticks(arange(0,maxY,(inc))) ax.set_ylim(0,maxY) # Return return canvas def component_req_count(self): """Show graph of how many requirements each component has. This returns a canvas drawn with matplotlib's backend graphics tools for display on the requirements dashboard. This graph list all components so they can be compared by their number of associated (active) requirements. This is one way of describing a components relative 'size' and 'importance' in relation to the other components. """ cr_list = Requirement(self.env).get_component_req_count() count = len(cr_list) #heres a trick to cycle colors. Can add more base colors later. base_colors = ['b', 'g', 'r', 'c', 'm'] colors = [base_colors[x % 5] for x in range(count)] fig = self._new_image((5,4)) canvas = FigureCanvasAgg(fig) ax = fig.add_axes([0.08, 0.35, 0.9, 0.6]) #extract the labels and values from cr_list labels = [x[0] for x in cr_list] y = [y[1] for y in cr_list] #establish height of y axis if max(y) == 0: height = 5 elif max(y) % 5 == 0: height = max(y) else: height = max(y) + 5 - (max(y) % 5) #relative width of each bar width = 1 #scale vertically if height >= 20: inc = height/10 else: inc = 1 #position labels appropriately for horizontal scaling if count > 20: label_offset = 0 if count > 30: rotation = 80 else: label_offset = .5*width rotation = 60 #set the horizontal points x = arange(0,count * width, width) #draw the graph p1 = ax.bar(x, y, width=width, color=colors) #set the x axis labels ax.set_xticks(x + label_offset) ax.set_xticklabels(labels) ax.set_xlim(0,count) setp(ax.get_xticklabels(), 'rotation',rotation,fontsize=6) #set the y axis labels ax.set_yticks(arange(0,height + 1, (inc))) ax.set_ylim(0,height) #we're done! return canvas def changes_over_time(self, seconds_in_unit=60): fig = self._new_image((3,3)) canvas = FigureCanvasAgg(fig) (time_created, times_changed) = self.requirement.get_changes_metrics() ax = fig.add_subplot(111) # Obtain the timestamp of the first entity every created and treat # that as the projects start time since there is no available project # start time. proj_start_time = self.requirement.get_timestamp_first_entity() # Obtain the largest timestamp of either a milestone, requirement, # or a requirement change. most_recent_time = self.requirement.get_timestamp_latest_req_reqchange_milestone() # Obtain the current time. current_time = int(time.time()) if (current_time > most_recent_time): most_recent_time = current_time # Obtain all the milestones and their associated due dates in # seconds since epoch. milestones = self.requirement.get_milestones() tot_horiz_units = int((most_recent_time - proj_start_time) / seconds_in_unit) # Initialize base variables height=10 startY=0 startX=time_created # Obtain the amount of time between each change made to the # requirement, and place them in an array valid_change_offsets = [] prev_time = time_created for cur_time in times_changed: if (cur_time != prev_time): cur_horiz_unit_offset = int(((cur_time - prev_time) / seconds_in_unit)) valid_change_offsets.append(cur_horiz_unit_offset) prev_time = cur_time # Append the amount of time between the last change and # the current time to the array cur_horiz_unit_offset = int(((current_time - prev_time) / seconds_in_unit)) valid_change_offsets.append(cur_horiz_unit_offset) # Set the point where the requirement will begin graphing cur_x_pos = int((time_created - proj_start_time) / seconds_in_unit) height=1 startX=0 startY=0 tot_horiz_units = ((most_recent_time - proj_start_time) / seconds_in_unit) #setup a blank template for y-axis increments graphSegments=[] for unit in range(0,tot_horiz_units): graphSegments.append(0) # Graph the requirement for cur_x_offset in valid_change_offsets: ax.broken_barh([ (cur_x_pos, cur_x_offset)] , (startY, height), facecolors='blue') cur_x_pos += cur_x_offset startY += height # Graph the milestones for (garbage, milestone_due) in milestones: if milestone_due == 0: continue milestone_x_pos = int((milestone_due - proj_start_time) / seconds_in_unit) ax.axvline(milestone_x_pos, color='r') last_date=milestone_due if last_date == 0: last_date = current_time # Set the limits and ticks of the graph x_tick_lines=[] for i in range(0, (tot_horiz_units + 1)): x_tick_lines.append(i) ax.set_xticks(x_tick_lines) ax.set(xticklabels=[]) ax.set_yticks(arange(0,(startY+height),height)) # Return our image return canvas def most_least_cited( self, width ): """This is the only function using gd, so we handle it more directly for now. """ image = gd.image((10*width, 10)) image.filledRectangle((0,0),(10*width-1, 10), image.colorAllocate((255,0,0))) buffer = cStringIO.StringIO() image.writePng(buffer) data = buffer.getvalue() buffer.close() return data def dash_overall(self, seconds_in_unit=604800): fig = self._new_image((5,5)) canvas = FigureCanvasAgg(fig) ax = fig.add_subplot(111) # Obtain the timestamp of the first entity every created and treat # that as the projects start time since there is no available project # start time. proj_start_time = self.requirement.get_timestamp_first_entity() start_time = proj_start_time # Obtain the largest timestamp of either a milestone, requirement, # or a requirement change. most_recent_time = self.requirement.get_timestamp_latest_req_reqchange_milestone() # Obtain the current time. current_time = int(time.time()) if (current_time > most_recent_time): most_recent_time = current_time #This is the bargraph portion #Initialize variables width = 1 val = [] xTime = current_time endTime = proj_start_time #current_time - (31536000) #Get data while(xTime >= endTime): val.append(self.requirement.get_num_changes(endTime,endTime+seconds_in_unit)) endTime+=seconds_in_unit ind = arange(len(val)) # the x locations for the groups #Create bargraph graphBar = ax.bar(ind,val,width=width, color='y') #This is the line graph portion # this shows the number of active requirements #Initialize Variables #Get data #get the total number of requirements # at each given time checktime=proj_start_time yValues=[] while checktime <= current_time+seconds_in_unit: yValues.append(self.requirement.get_num_req(checktime)) checktime+=seconds_in_unit xValues=[] for _ in range(0,len(yValues)): xValues.append(_) #Create Line graph lineGraph=ax.plot(xValues,yValues) #create the list of timestamps and make labels. times = [] timestamp = current_time # We'll use two week increments for now to reduce # delay while loading. while timestamp > start_time: times.append(timestamp) timestamp -= seconds_in_unit times.reverse() labels = [time.strftime("%b %d '%y",time.gmtime(timestamp)) \ for timestamp in times] maxY=max(max(val),max(yValues)) if maxY < 20: maxY+=5 else: maxY=int(maxY*1.5) #This is the triangles portion # this is the validation points #Initialize Variables #Get data valTimes=[] valTimes=self.requirement.get_val_times() valHeight=[] temp=[] if len(valTimes) is not 0: for elem in valTimes: valHeight.append(maxY*0.9) temp.append(int((elem - proj_start_time) / seconds_in_unit)) valTimes=temp #Create triangles graph #use a scatterplot maybe and make each point for the graph be a triangle validationGraph=ax.scatter(valTimes,valHeight,color='g', marker='^', linewidth=5) #This is the milestones portion #Initialize Variables #Get data # Obtain all the milestones and their associated due dates in # seconds since epoch. milestones = self.requirement.get_milestones() tot_horiz_units = ((most_recent_time - proj_start_time) / seconds_in_unit) #Create line for milestones graph for (garbage, milestone_due) in milestones: if milestone_due == 0: continue milestone_x_pos = int((milestone_due - proj_start_time) / seconds_in_unit) #axvline(x=milestone_x_pos, xymin=0,ymax=100, color='r') milestoneBar = ax.bar(milestone_x_pos+0.5,maxY,width=(0), color='r', edgecolor='r') ax.set_xticklabels(labels) ax.set_xlim(0, len(times)) setp(ax.get_xticklabels(),'rotation', 80, fontsize=6) #format the graph #ax.set_xlim(proj_start_time,most_recent_time) ax.set_ylim(0,maxY) #return the graph return canvas def dash_pie(self): fig = self._new_image((4,4)) canvas = FigureCanvasAgg(fig) ax = fig.add_axes([0.1, 0.1, 0.8, 0.8]) fracs = [] vals = Requirement(self.env).get_type_req_tickets() total = 0 for val in vals: total += val labels = [] if total == 0: labels = ['None'] fracs = [1] else: if vals[0] != 0: labels.append('Open') fracs.append(float(vals[0]) / float(total)) if vals[1] != 0: labels.append('Closed') fracs.append(float(vals[1]) / float(total)) if vals[2] != 0: labels.append('None') fracs.append(float(vals[2]) / float(total)) labels = tuple(labels) ax.pie(fracs, labels=labels, autopct='%1.1f%%') return canvas def _new_image(self, (width,height)): # Return the blank figure return Figure(figsize=(width,height))
def process_request(self, req): template = 'requirement.cs'; db = self.env.get_db_cnx() if req.method == 'POST' and 'creator' in req.args and \ not req.perm.has_permission('REQUIREMENT_MODIFY'): del req.args['creator'] if req.method == 'POST': self._do_modify(req, db) else: (component, fp, object) = self._get_requirement_parts(req) fp = Fp(self.env, name=fp) object = Object(self.env, name=object) requirement = Requirement(self.env, component, fp['id'], object['id'], db) req.hdf['components'] = requirement.get_components() req.hdf['requirement'] = requirement.values req.hdf['fp'] = fp['name'] req.hdf['object'] = object['name'] req.hdf['requirement.created'] = format_datetime(requirement.time_created) req.hdf['requirement.created_delta'] = pretty_timedelta(requirement.time_created) if requirement.time_changed != requirement.time_created: req.hdf['requirement'] = { 'lastmod': format_datetime(requirement.time_changed), 'lastmod_delta': pretty_timedelta(requirement.time_changed) } for field in RequirementSystem(self.env).get_requirement_fields(): if field['type'] in ('radio', 'select'): value = requirement.values.get(field['name']) options = field['options'] if value and not value in options: options.append(value) field['options'] = options name = field['name'] del field['name'] if name in ('component', 'fp', 'object', 'status', 'creator', 'description'): field['skip'] = True req.hdf['requirement.fields.' + name] = field req.hdf['requirement.description.formatted'] = wiki_to_html( requirement['description'], self.env, req, db) replyto = req.args.get('replyto') req.hdf['requirement'] = { 'href': req.href.requirement('%s-%s-%s' % (requirement.component, fp['name'], object['name'])), 'replyto': replyto } def quote_original(author, original, link): if not 'comment' in req.args: # i.e. the comment was not yet edited req.hdf['requirement.comment'] = '\n'.join( ['Replying to [%s %s]:' % (link, author)] + ['> %s' % line for line in original.splitlines()] + ['']) if replyto == 'description': quote_original(requirement['creator'], requirement['description'], 'requirement:%s-%s-%s' % (requirement.component, fp['name'], object['name'])) replies = {} changes = [] cnum = 0 description_lastmod = description_author = None for change in self.grouped_changelog_entries(requirement, db): changes.append(change) # wikify comment comment = '' if 'comment' in change: comment = change['comment'] change['comment'] = wiki_to_html(comment, self.env, req, db) cnum = change['cnum'] # keep track of replies threading if 'replyto' in change: replies.setdefault(change['replyto'], []).append(cnum) # eventually cite the replied to comment if replyto == str(cnum): quote_original(change['author'], comment, 'reqcomment:%s' % replyto) if 'description' in change['fields']: change['fields']['description'] = '' description_lastmod = change['date'] description_author = change['author'] req.hdf['requirement'] = { 'changes': changes, 'replies': replies, 'cnum': cnum + 1 } if description_lastmod: req.hdf['requirement.description'] = {'lastmod': description_lastmod, 'author': description_author} req.hdf['title'] = 'Requirements' req.hdf['graph_path'] = req.href.requirement() + '/graph/' actions = RequirementSystem(self.env).get_available_actions(requirement, req.perm) for action in actions: req.hdf['requirement.actions.' + action] = '1' add_stylesheet(req, 'common/css/code.css') add_stylesheet(req, 'hw/css/requirement.css') return (template, None)