Mercurial > p > roundup > code
comparison scripts/stats.xmlrpc.py @ 6553:75da037d1c54
Add another xmlrpc example script and update readme.
Also added basic description of Docker files in Docker subdirectory
(to be added).
| author | John Rouillard <rouilj@ieee.org> |
|---|---|
| date | Sat, 11 Dec 2021 21:26:46 -0500 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 6552:e1146767b42e | 6553:75da037d1c54 |
|---|---|
| 1 """Count how many issues use each bpo field and print a report.""" | |
| 2 """ sample output: https://github.com/psf/gh-migration/issues/5#issuecomment-935697646""" | |
| 3 | |
| 4 import xmlrpc.client | |
| 5 | |
| 6 from collections import defaultdict | |
| 7 | |
| 8 class SpecialTransport(xmlrpc.client.SafeTransport): | |
| 9 def send_content(self, connection, request_body): | |
| 10 connection.putheader("Referer", "https://bugs.python.org/") | |
| 11 connection.putheader("Origin", "https://bugs.python.org") | |
| 12 connection.putheader("X-Requested-With", "XMLHttpRequest") | |
| 13 xmlrpc.client.SafeTransport.send_content(self, connection, request_body) | |
| 14 | |
| 15 # connect to bpo | |
| 16 roundup = xmlrpc.client.ServerProxy('https://bugs.python.org/xmlrpc', | |
| 17 transport=SpecialTransport(), | |
| 18 allow_none=True) | |
| 19 | |
| 20 # map bpo classes -> propname | |
| 21 # the class is the name of the class (e.g. issue_type, keyword -- | |
| 22 # also used in e.g. in https://bugs.python.org/keyword) | |
| 23 # the propname is the name used as attribute on the issue class | |
| 24 # (e.g. issue.type, issue.keywords) | |
| 25 classes = { | |
| 26 # 'status': 'status', # skip this | |
| 27 'issue_type': 'type', | |
| 28 'stage': 'stage', | |
| 29 'component': 'components', | |
| 30 'version': 'versions', | |
| 31 'resolution': 'resolution', | |
| 32 'priority': 'priority', | |
| 33 'keyword': 'keywords', | |
| 34 } | |
| 35 | |
| 36 # find the id for the 'open' status | |
| 37 open_id = roundup.lookup('status', 'open') | |
| 38 | |
| 39 print(f'* Counting total issues...') | |
| 40 total_issues_num = len(roundup.filter('issue', None, {})) | |
| 41 | |
| 42 print(f'* Counting open issues...') | |
| 43 # use this list to filter only the open issues | |
| 44 open_issues = roundup.filter('issue', None, {'status': open_id}) | |
| 45 open_issues_num = len(open_issues) | |
| 46 | |
| 47 # save the totals in a dict with this structure: | |
| 48 # totals[propname][open/all][num/perc][name] | |
| 49 # where propname is e.g. 'keyword' and name is e.g. 'easy' | |
| 50 totals = defaultdict(lambda: {'all': {'perc': {}, 'num': {}}, | |
| 51 'open': {'perc': {}, 'num': {}}}) | |
| 52 for cls, propname in classes.items(): | |
| 53 print(f'* Counting <{cls}>...') | |
| 54 # get the list of ids/names for the given class (e.g. 'easy' is 6) | |
| 55 ids = roundup.list(cls, 'id') | |
| 56 names = roundup.list(cls, 'name') | |
| 57 for id, name in zip(ids, names): | |
| 58 # filter and count on *all* issues with the given propname | |
| 59 tot_all = len(roundup.filter('issue', None, {propname: id})) | |
| 60 totals[propname]['all']['num'][name] = tot_all | |
| 61 totals[propname]['all']['perc'][name] = tot_all / total_issues_num | |
| 62 # filter and count on *open* issues with the given propname | |
| 63 tot_open = len(roundup.filter('issue', open_issues, {propname: id})) | |
| 64 totals[propname]['open']['num'][name] = tot_open | |
| 65 totals[propname]['open']['perc'][name] = tot_open / open_issues_num | |
| 66 | |
| 67 | |
| 68 print(f'Issues (open/all): {open_issues_num}/{total_issues_num}') | |
| 69 | |
| 70 # print a list of markdown tables for each bpo class name | |
| 71 for propname in classes.values(): | |
| 72 print(f'### {propname}') | |
| 73 print('| bpo field | open | all |') | |
| 74 print('| :--- | ---: | ---: |') | |
| 75 # pick the dict for the given propname (e.g. keywords) | |
| 76 proptots = totals[propname] | |
| 77 names = proptots['open']['num'] | |
| 78 # sort the names (e.g. 'easy') in reverse order | |
| 79 # based on the number of open issues | |
| 80 for name in sorted(names, key=names.get, reverse=True): | |
| 81 # get and print num/perc for all/open issues | |
| 82 issues_all = proptots['all']['num'][name] | |
| 83 issues_open = proptots['open']['num'][name] | |
| 84 perc_all = proptots['all']['perc'][name] | |
| 85 perc_open = proptots['open']['perc'][name] | |
| 86 print(f'| {name:20} | {issues_open:>5} ({perc_open:5.1%}) |' | |
| 87 f' {issues_all:>5} ({perc_all:5.1%}) |') | |
| 88 # calc and print num/perc for all/open issues | |
| 89 tot_issues_all = sum(proptots['all']['num'].values()) | |
| 90 tot_issues_open = sum(proptots['open']['num'].values()) | |
| 91 tot_perc_all = sum(proptots['all']['perc'].values()) | |
| 92 tot_perc_open = sum(proptots['open']['perc'].values()) | |
| 93 print(f'| **Total** | {tot_issues_open:>5} ({tot_perc_open:5.1%}) |' | |
| 94 f' {tot_issues_all:>5} ({tot_perc_all:5.1%}) |') | |
| 95 |
