| 
						
						
							
								
							
						
						
					 | 
					@ -101,6 +101,7 @@ class Repo: | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					            c_issues_name_fmt = "issues_page={p}{q}.json", | 
					 | 
					 | 
					            c_issues_name_fmt = "issues_page={p}{q}.json", | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					            c_issue_name_fmt = "issues_{issue_no}.json", | 
					 | 
					 | 
					            c_issue_name_fmt = "issues_{issue_no}.json", | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					            default_query = {'state':'open'}, | 
					 | 
					 | 
					            default_query = {'state':'open'}, | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					            hide_events = ['renamed', 'assigned'], | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        ): | 
					 | 
					 | 
					        ): | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        ''' | 
					 | 
					 | 
					        ''' | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        Keyword arguments: | 
					 | 
					 | 
					        Keyword arguments: | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					@ -123,6 +124,8 @@ class Repo: | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        default_query -- This dictionary must contain all URL query | 
					 | 
					 | 
					        default_query -- This dictionary must contain all URL query | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					                         parameters that the API assumes and that don't | 
					 | 
					 | 
					                         parameters that the API assumes and that don't | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					                         need to be provided in the URL. | 
					 | 
					 | 
					                         need to be provided in the URL. | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					        hide_events -- Do not show these event types in an issue's | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					                       timeline. | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        ''' | 
					 | 
					 | 
					        ''' | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        self.page = None | 
					 | 
					 | 
					        self.page = None | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        self.remote_user = remote_user | 
					 | 
					 | 
					        self.remote_user = remote_user | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					@ -147,7 +150,7 @@ class Repo: | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        self.label_ids = []  # all label ids in the repo | 
					 | 
					 | 
					        self.label_ids = []  # all label ids in the repo | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        self.labels = []  # all labels in the repo | 
					 | 
					 | 
					        self.labels = []  # all labels in the repo | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        self.default_query = default_query | 
					 | 
					 | 
					        self.default_query = default_query | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					
 | 
					 | 
					 | 
					        self.hide_events = hide_events | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					        self.issues = None | 
					 | 
					 | 
					        self.issues = None | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    def get_issues(self, query=None, issue_no=None): | 
					 | 
					 | 
					    def get_issues(self, query=None, issue_no=None): | 
				
			
			
		
	
	
		
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
					@ -313,7 +316,8 @@ class Repo: | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					                "\\t", | 
					 | 
					 | 
					                "\\t", | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					                "\t" | 
					 | 
					 | 
					                "\t" | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					            ) | 
					 | 
					 | 
					            ) | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					        left_w = 10 | 
					 | 
					 | 
					        left_w = 11 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					        # ^ left_w must be >=11 or "updated_at:" will push the next col. | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        spacer = " " | 
					 | 
					 | 
					        spacer = " " | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        line_fmt = "{: <" + str(left_w) + "}" + spacer + "{}" | 
					 | 
					 | 
					        line_fmt = "{: <" + str(left_w) + "}" + spacer + "{}" | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        print(line_fmt.format("html_url:",  issue["html_url"])) | 
					 | 
					 | 
					        print(line_fmt.format("html_url:",  issue["html_url"])) | 
				
			
			
		
	
	
		
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
					@ -344,28 +348,95 @@ class Repo: | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					            print('"""') | 
					 | 
					 | 
					            print('"""') | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        else: | 
					 | 
					 | 
					        else: | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					            print("(no description)") | 
					 | 
					 | 
					            print("(no description)") | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					        if issue_data["comments"] > 0: | 
					 | 
					 | 
					
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					        comments = issue_data.get("comments") | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					        if comments is None: | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					            comments = 0 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					        if comments > 0: | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					            print("") | 
					 | 
					 | 
					            print("") | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					            print("") | 
					 | 
					 | 
					            print("") | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					            print("({}) comment(s):".format(issue_data["comments"])) | 
					 | 
					 | 
					            print("({}) comment(s):".format(comments)) | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					        left_margin = "    " | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					        c_prop_fmt = (left_margin + "{: <" + str(left_w) + "}" | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					                      + spacer + "{}") | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					        # ^ Ensure that the second column is justified | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					        #   (in a Terminal using a monospaced font). | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					        # NOTE: Timeline is nicer than events because it has both | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					        #       comments and events. | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					        ''' | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					        this_evts_json_url = issue_data.get('events_url') | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					        if this_evts_json_url is not None: | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					            evts_res = request.urlopen(this_evts_json_url) | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					            evts_data_s = decode_safe(evts_res.read()) | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					            evts_data = json.loads(evts_data_s) | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					        ''' | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					        this_tmln_json_url = issue_data.get('timeline_url') | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					        data = [] | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					        if this_tmln_json_url is not None: | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					            tmln_res = request.urlopen(this_tmln_json_url) | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					            tmln_data_s = decode_safe(tmln_res.read()) | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					            tmln_data = json.loads(tmln_data_s) | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					            data = tmln_data | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					        elif comments > 0: | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					            this_cmts_json_url = issue_data["comments_url"] | 
					 | 
					 | 
					            this_cmts_json_url = issue_data["comments_url"] | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					            response = request.urlopen(this_cmts_json_url) | 
					 | 
					 | 
					            response = request.urlopen(this_cmts_json_url) | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					            cmts_data_s = decode_safe(response.read()) | 
					 | 
					 | 
					            cmts_data_s = decode_safe(response.read()) | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					            cmts_data = json.loads(cmts_data_s) | 
					 | 
					 | 
					            cmts_data = json.loads(cmts_data_s) | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					            left_margin = "    " | 
					 | 
					 | 
					            data = cmts_data | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					            c_prop_fmt = (left_margin + "{: <" + str(left_w) + "}" | 
					 | 
					 | 
					
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					                          + spacer + "{}") | 
					 | 
					 | 
					        for evt in data: | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					            for cmt in cmts_data: | 
					 | 
					 | 
					            user = evt.get('user') | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					            login = None | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					            if user is not None: | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					                print("") | 
					 | 
					 | 
					                print("") | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					                print("") | 
					 | 
					 | 
					                print("") | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					                print(c_prop_fmt.format("from:", cmt["user"]["login"])) | 
					 | 
					 | 
					                login = user.get('login') | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					            if login is not None: | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					                print(c_prop_fmt.format("from:", login)) | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					            updated_at = evt.get("updated_at") | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					            if updated_at is not None: | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					                print(c_prop_fmt.format("updated_at:", | 
					 | 
					 | 
					                print(c_prop_fmt.format("updated_at:", | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					                                        cmt["updated_at"])) | 
					 | 
					 | 
					                                        updated_at)) | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					            body = evt.get("body") | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					            if body is not None: | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					                print("") | 
					 | 
					 | 
					                print("") | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					                print(left_margin + '"""') | 
					 | 
					 | 
					                print(left_margin + '"""') | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					                print(left_margin + cmt["body"]) | 
					 | 
					 | 
					                print(left_margin + body) | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					                print(left_margin + '"""') | 
					 | 
					 | 
					                print(left_margin + '"""') | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					                print("") | 
					 | 
					 | 
					                print("") | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					            rename = evt.get('rename') | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					            event = evt.get('event') | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					            ignore_events = ['commented', 'labeled'] | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					            if self.hide_events: | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					                ignore_events.extend(self.hide_events) | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					            if event is not None: | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					                actor = evt.get('actor') | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					                if actor is not None: | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					                    login = actor.get('login') | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					                created_at = evt.get('created_at') | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					                if event == "cross-referenced": | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					                    source = evt.get('source') | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					                    source_type = source.get('type') | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					                    source_issue = source.get('issue') | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					                    if source_issue is not None: | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					                        source_number = source_issue.get('number') | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					                    print(left_margin | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					                          +"cross-reference: {} referenced this issue" | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					                          " in {} {}." | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					                          "".format(login, source_type, source_number)) | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					                # elif (event == "closed") or (event == "reopened"): | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					                elif event not in ignore_events: | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					                    print(left_margin+"{} {} by {}" | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					                          "".format(event.upper(), created_at, login)) | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					            if (rename is not None) and ('renamed' not in ignore_events): | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					                # already said "RENAMED" above (evt.get('event')) | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					                # print(left_margin+"renamed issue") | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					                print(left_margin+"  from:{}".format(rename.get('from'))) | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					                print(left_margin+"  to:{}".format(rename.get('to'))) | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        closed_by = issue_data.get('closed_by') | 
					 | 
					 | 
					        closed_by = issue_data.get('closed_by') | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					@ -373,9 +444,9 @@ class Repo: | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        if (closed_by is not None) or (closed_at is not None): | 
					 | 
					 | 
					        if (closed_by is not None) or (closed_at is not None): | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					            # INFO: closed_by may be present even if reopened | 
					 | 
					 | 
					            # INFO: closed_by may be present even if reopened | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					            # (determine this by getting 'state'). | 
					 | 
					 | 
					            # (determine this by getting 'state'). | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					            # - [ ] The same could be accomplished more clearly by | 
					 | 
					 | 
					            # The "REOPENED" and "CLOSED" events also appear in the | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					            #   checking for "event" on 'events_url') | 
					 | 
					 | 
					            # timeline (see this_tmln_json_url). | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					            #   instead (that would replace the use of 'comments_url'. | 
					 | 
					 | 
					            print() | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					            state = issue_data.get('state') | 
					 | 
					 | 
					            state = issue_data.get('state') | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					            closet_at_str = "" | 
					 | 
					 | 
					            closet_at_str = "" | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					            if closed_at is not None: | 
					 | 
					 | 
					            if closed_at is not None: | 
				
			
			
		
	
	
		
		
			
				
					| 
						
							
								
							
						
						
						
					 | 
					
  |