From 91aef251bf2883088c38970961778fac0e71af0e Mon Sep 17 00:00:00 2001 From: Sachin Kamath Date: Jun 05 2016 15:56:13 +0000 Subject: [PATCH 1/2] Updated Documentation --- diff --git a/README.md b/README.md index 8754b61..20ecd8a 100644 --- a/README.md +++ b/README.md @@ -8,32 +8,42 @@ This tool will help anyone to pull statistics of any registered Fedora user wit ### Usage -This tool uses`argparse` to parse arguments. The only mandatory argument is `-u / --user` which will take any FAS account name as argument. +This tool uses`argparse` to parse arguments. This can be used in two ways, one-liner / interactive method. +The interactive mode can be enabled by using the `--interactive` or `-i` flag. This mode of usage does not require any additional argument. Please not that the arguments passed (if any) will be invalid. -`python stats.py --user=nobody` or `python stats.py -u nobody` will generate text based statistics of user `nobody` ftom datagrepper. +One-liner uses the classic argument parsing method to generate output. This is useful for automating the report generation process. The only mandatory argument is `--user / -u` which takes the FAS username as input. + +`python stats.py --user=nobody` or `python stats.py -u nobody` will generate text based statistics of user `nobody` from datagrepper. ####Arguments : `--user / -u` + * Takes any FAS Username as argument. There is no default value and the tool will throw an error if this argument is left blank/not used. `--weeks / -w` + * Takes an integer value to represent number of weeks. Converts it into timedelta. (1week = 604,800 seconds). Default value is 1. `--mode / -m` * Takes a single word string input. Supported input modes are : json, text, svg and png. The default value is `text`. *(More features will be added soon)* +`--category / -c` + +* Take a single word string input. This will define the category for which deeper analytics are required. Some example categories : pagure, irc, mailman, etc. + `--output / -o` -* Takes a single word string input. This will define the output file name. This option is to be combined with the `--mode/-m` argument. Please note that this option **DOES NOT** require an extension type. For instance, if you need an SVG output with the name `nobody.svg`, the --output flag should be set as `nobody` and not `nobody.svg`. the dedault value is `stats` -####Examples : +* Takes a single word string input. This will define the output file name. This option is to be combined with the `--mode/-m` argument. Please note that this option **DOES NOT** require an extension type. For instance, if you need an SVG output with the name `nobody.svg`, the --output flag should be set as `nobody` and not `nobody.svg`. the default value is `stats` + +####Examples : -* Generate statistics of user nobody for a week and view the text logs : +* Generate statistics of user nobody for a week and view the text logs : `python main.py --user=nobody` -* Generate statistics of user foo in `.svg` format : +* Generate statistics of user foo in `.svg` format : `python main.py --user=foo --mode=svg` @@ -43,6 +53,6 @@ This will create `stats.svg` in your `$pwd`. `python main.py --user=foo --mode=png --output=foo_stats` -#### Basic Troubleshooting : +#### Basic Troubleshooting : -Please take a look at this [blogpost](https://sachinwrites.xyz/2016/05/28/getting-fedstats-gsoc-production-ready/). +Please take a look at this [blog-post](https://sachinwrites.xyz/2016/05/28/getting-fedstats-gsoc-production-ready/). From 065d998c6c1d50a056093ef7e2327c5789361f78 Mon Sep 17 00:00:00 2001 From: Sachin Kamath Date: Jun 05 2016 22:13:24 +0000 Subject: [PATCH 2/2] Added category wise text report and modified requirements --- diff --git a/main.py b/main.py index e3ab3e7..754e4fb 100644 --- a/main.py +++ b/main.py @@ -8,6 +8,7 @@ import fedmsg.meta import stats import output from termcolor import colored +from six.moves import input def main(): @@ -17,22 +18,23 @@ def main(): # Argument Parser initialization parser = argparse.ArgumentParser(description='Fedora GSoC stats gatherer') - parser.add_argument('--user', help='FAS username') - parser.add_argument('--weeks', help='Time in weeks', default=1) - parser.add_argument('--mode', help="Type of Output", default='text') - parser.add_argument('--output', help="Output name", default='stats') - parser.add_argument('--category', help="Category for graphs", default=None) + parser.add_argument('--user', '-u', help='FAS username') + parser.add_argument('--weeks','-w', help='Time in weeks', default=1) + parser.add_argument('--mode', '-m', help="Type of Output", default='text') + parser.add_argument('--output', '-o', help="Output name", default='stats') + parser.add_argument('--category', '-c', help="Category for graphs", default=None) parser.add_argument('--interactive', '-i', help="Enable interactive mode", action='store_true') args = parser.parse_args() # Object inits and argument processing if args.interactive: - stats.values['user'] = str(raw_input("Enter FAS Username : ")) - stats.values['delta'] = 604800 * int(raw_input("Number of weeks stats required for : ")) - stats.category = str(raw_input("Enter category : ")) - output.mode = str(raw_input("Type of output : ")) - output.filename = str(raw_input("Output file : ")) + stats.values['user'] = str(input("Enter FAS Username : ")) + stats.values['delta'] = 604800 * int(input("Number of weeks stats required for : ")) + stats.category = str(input("Enter category : ")) + output.mode = str(input("Type of output : ")) + output.filename = str(input("Output file : ")) + # Check if the user argument exists elif args.user is None: print(colored("[!] ", 'red') + "Username is required. Use -h for help") return 1 @@ -47,28 +49,36 @@ def main(): # For json and text output, we need the JSON rather than the categories if output.mode == 'svg' or output.mode == 'png': draw_obj = stats.return_categories() - draw_obj2 = stats.return_subcategories(stats.category) - interactions = stats.return_interactions(draw_obj2) + # To handle user with no activity if len(draw_obj) == 0: print ('[!] No activity found for user ' + str(args.user)) return 1 + # Generate the output graphs + output.generate_graph(draw_obj, "Topic distribution of " + str(stats.values['user']), 'pie') + draw_obj2 = stats.return_subcategories(stats.category) + interactions = stats.return_interactions(draw_obj2) + # Check if a category input was given + if not stats.category is None : + output.generate_graph(draw_obj2, "Category: " + str(stats.category).capitalize()\ + + "\nUser: " + str(stats.values['user']), 'bar') + + # Check if the sub-sub-category exists + if not None in list(interactions.keys()): + for keys in interactions: + output.generate_graph(interactions[keys], "Interaction with "+str(keys)+"\nCategory: "\ + + str(stats.category).capitalize(), 'pie') - elif args.mode.lower() == 'json' or args.mode.lower() == 'text': + + elif output.mode.lower() == 'json' or output.mode.lower() == 'text': draw_obj = stats.return_json() # To handle user with no activity if draw_obj['total'] == 0: print ('[!] No activity found for user ' + str(args.user)) return 1 + output.generate_graph(draw_obj, str(stats.values['user'])) + - output.generate_graph(draw_obj, "Topic distribution of " + str(stats.values['user']), 'pie') - output.generate_graph(draw_obj2, "Category: " + str(stats.category).capitalize()\ - + "\nUser: " + str(stats.values['user']), 'bar') - - if interactions != 1: - for keys in interactions: - output.generate_graph(interactions[keys], "Interaction with "+str(keys)+"\nCategory: "\ - + str(stats.category).capitalize(), 'pie') if __name__ == '__main__': main() diff --git a/output.py b/output.py index f47e037..f3af9b4 100644 --- a/output.py +++ b/output.py @@ -17,7 +17,7 @@ def draw_svg(graph_obj): global count fname = filename + str(count) + '.svg' graph_obj.render_to_file(fname) - os.system('firefox ' + fname) + os.system("firefox " + fname) def draw_category_png(graph_obj): fname = filename + str(count) + '.png' @@ -39,22 +39,29 @@ def draw_bar(output_json, title): return bar_chart def save_text(unicode_json, username): + global count fname = filename + str(count) + '.txt' fout = open(fname, 'w') - # Entire Log Write - fout.write("*****Full log for user " + username + "*****\n\n\n") - for activity in unicode_json['raw_messages']: - fout.write(fedmsg.meta.msg2subtitle(activity)+"\n") -''' - # Category-wise Log - fout.write("\n\n*****Category-wise activities*****\n\n") + # Category-wise Log, markdown ready + fout.write("\n\n### Category-wise activities\n\n") for category in stats.return_categories(): + flag = True + count = 0 for activity in unicode_json['raw_messages']: if category == activity['topic'].split('.')[3]: - fout.write() + count += 1 + # Print the category once + if flag is True: + fout.write("\n\n#### Category : "+category.capitalize()+"\n") + flag = False + fout.write("* "+fedmsg.meta.msg2subtitle(activity)+"\n") + fout.write("\n Total Entries in category : " + str(count) + "") + fout.write("\n Percentage participation in category : " + \ + str(round(100*count/float(unicode_json['total']),2))) + + -''' def save_json(unicode_json): filename = filename + str(count) + '.json' try: @@ -63,7 +70,7 @@ def save_json(unicode_json): except IOError: print("[!] Could not write into directory. Check Permissions") -def generate_graph(output_json, username, gtype): +def generate_graph(output_json, username, gtype=None): global count print('[*] Readying Output..') count += 1 diff --git a/requirements.pip b/requirements.pip index de29f88..3299c8b 100644 --- a/requirements.pip +++ b/requirements.pip @@ -8,3 +8,4 @@ fedmsg>=0.17.2 fedmsg-meta-fedora-infrastructure>=0.17.4 pygal>=2.2.2 tinycss>=0.3 +termcolor==1.1.0 diff --git a/stats.py b/stats.py index 265bbc5..094b6fc 100644 --- a/stats.py +++ b/stats.py @@ -6,7 +6,7 @@ import json import requests from collections import Counter - +# This dictionary will be passed as param to requests later values = dict() values['user'] = None values['delta'] = 604800 @@ -22,8 +22,9 @@ def return_user(): def return_json(): global unicode_json print('[*] Grabbing datagrepper values..') - response = requests.get(baseurl, params=values) - unicode_json = json.loads(response.text) + if len(unicode_json) == 0: + response = requests.get(baseurl, params=values) + unicode_json = json.loads(response.text) return unicode_json def return_categories(): @@ -67,7 +68,7 @@ def return_interactions(subcategories): interaction_dict[object].append(activity['topic'].split('.')[5]) except IndexError: print("[!] That category doesn't have any more interactions!") - return 1 + return {None:None} # Changing list to a counter for key in interaction_dict: