Repository: hugovk/pypistats

Issue:
Add percent column to tables
Put it before the downloads column.

Discussion:

Patch:
diff --git a/pypistats/__init__.py b/pypistats/__init__.py
index 9ebc7e6..79cbc13 100644
--- a/pypistats/__init__.py
+++ b/pypistats/__init__.py
@@ -4,8 +4,8 @@
 Python interface to PyPI Stats API
 https://pypistats.org/api
 """
-import pytablewriter
 import requests
+from pytablewriter import Align, MarkdownTableWriter
 
 from . import version
 
@@ -47,12 +47,13 @@ def pypi_stats_api(
         return res
 
     # These only for table
+    data = res["data"]
     if sort:
-        res["data"] = _sort(res["data"])
+        data = _sort(data)
 
-    res["data"] = _grand_total(res["data"])
+    data = _percent(data)
+    data = _grand_total(data)
 
-    data = res["data"]
     return _tabulate(data)
 
 
@@ -121,10 +122,25 @@ def _grand_total(data):
     return data
 
 
+def _percent(data):
+    """Add a percent column"""
+
+    # Only for lists of dicts, not a single dict
+    if isinstance(data, dict):
+        return data
+
+    grand_total = sum(row["downloads"] for row in data)
+
+    for row in data:
+        row["percent"] = "{:.2%}".format(row["downloads"] / grand_total)
+
+    return data
+
+
 def _tabulate(data):
     """Return data in table"""
 
-    writer = pytablewriter.MarkdownTableWriter()
+    writer = MarkdownTableWriter()
     writer.margin = 1
 
     if isinstance(data, dict):
@@ -139,6 +155,13 @@ def _tabulate(data):
     header_list.remove("downloads")
     writer.header_list = header_list
 
+    # Custom alignment
+    writer.align_list = [Align.AUTO] * len(header_list)
+    try:
+        writer.align_list[header_list.index("percent")] = Align.RIGHT
+    except ValueError:
+        pass
+
     return writer.dumps()
 
 


Test patch:
diff --git a/tests/test_pypistats.py b/tests/test_pypistats.py
index 1e3f8fe..feae931 100644
--- a/tests/test_pypistats.py
+++ b/tests/test_pypistats.py
@@ -127,7 +127,7 @@ class TestPypiStats(unittest.TestCase):
 
     def test__tabulate(self):
         # Arrange
-        data = SAMPLE_DATA
+        data = copy.deepcopy(SAMPLE_DATA)
         expected_output = """
 | category |    date    | downloads |
 |----------|------------|----------:|
@@ -151,7 +151,7 @@ class TestPypiStats(unittest.TestCase):
 
     def test__sort(self):
         # Arrange
-        data = SAMPLE_DATA
+        data = copy.deepcopy(SAMPLE_DATA)
         expected_output = [
             {"category": "2.7", "date": "2018-08-15", "downloads": 63749},
             {"category": "3.6", "date": "2018-08-15", "downloads": 35274},
@@ -225,3 +225,34 @@ class TestPypiStats(unittest.TestCase):
 
         # Assert
         self.assertEqual(output, data)
+
+    def test__percent(self):
+        # Arrange
+        data = [
+            {"category": "2.7", "downloads": 63749},
+            {"category": "3.6", "downloads": 35274},
+            {"category": "2.6", "downloads": 51},
+            {"category": "3.2", "downloads": 2},
+        ]
+        expected_output = [
+            {"category": "2.7", "percent": "64.34%", "downloads": 63749},
+            {"category": "3.6", "percent": "35.60%", "downloads": 35274},
+            {"category": "2.6", "percent": "0.05%", "downloads": 51},
+            {"category": "3.2", "percent": "0.00%", "downloads": 2},
+        ]
+
+        # Act
+        output = pypistats._percent(data)
+
+        # Assert
+        self.assertEqual(output, expected_output)
+
+    def test__percent_recent(self):
+        # Arrange
+        data = {"last_day": 123002, "last_month": 3254221, "last_week": 761649}
+
+        # Act
+        output = pypistats._percent(data)
+
+        # Assert
+        self.assertEqual(output, data)