You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@allura.apache.org by jo...@apache.org on 2013/05/06 23:45:04 UTC

[1/4] git commit: [#6133] remove histogram, and matplotlib & numpy dependences

Updated Branches:
  refs/heads/master fae747927 -> 3e12f6d57


[#6133] remove histogram, and matplotlib & numpy dependences

Only remaining use of matplotlib was a histogram (bar chart)
of a user's projects per trove category.  This is a simple chart
and the data is available in a table, so not worth the very big
and complex dependencies of matplotlib and numpy and associated
workarounds due to them.  So removing the histogram, dependencies,
and workarounds.


Project: http://git-wip-us.apache.org/repos/asf/incubator-allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-allura/commit/3e12f6d5
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/3e12f6d5
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/3e12f6d5

Branch: refs/heads/master
Commit: 3e12f6d574d4685c0bed84e3ae95772b24cd6425
Parents: b21778f
Author: Dave Brondsema <db...@slashdotmedia.com>
Authored: Sat May 4 23:03:06 2013 -0400
Committer: Cory Johns <cj...@slashdotmedia.com>
Committed: Mon May 6 21:34:31 2013 +0000

----------------------------------------------------------------------
 Allura/allura/lib/graphics/__init__.py             |   16 ---
 Allura/allura/lib/graphics/graphic_methods.py      |   86 ---------------
 Allura/docs/conf.py                                |   25 ----
 .../forgeuserstats/controllers/userstats.py        |   30 -----
 ForgeUserStats/forgeuserstats/templates/index.html |    9 --
 requirements-common.txt                            |    2 -
 vagrant/manifests/ubuntu-1204-server-amd64.pp      |   14 ---
 7 files changed, 0 insertions(+), 182 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/3e12f6d5/Allura/allura/lib/graphics/__init__.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/graphics/__init__.py b/Allura/allura/lib/graphics/__init__.py
deleted file mode 100644
index 144e298..0000000
--- a/Allura/allura/lib/graphics/__init__.py
+++ /dev/null
@@ -1,16 +0,0 @@
-#       Licensed to the Apache Software Foundation (ASF) under one
-#       or more contributor license agreements.  See the NOTICE file
-#       distributed with this work for additional information
-#       regarding copyright ownership.  The ASF licenses this file
-#       to you under the Apache License, Version 2.0 (the
-#       "License"); you may not use this file except in compliance
-#       with the License.  You may obtain a copy of the License at
-#
-#         http://www.apache.org/licenses/LICENSE-2.0
-#
-#       Unless required by applicable law or agreed to in writing,
-#       software distributed under the License is distributed on an
-#       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-#       KIND, either express or implied.  See the License for the
-#       specific language governing permissions and limitations
-#       under the License.

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/3e12f6d5/Allura/allura/lib/graphics/graphic_methods.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/graphics/graphic_methods.py b/Allura/allura/lib/graphics/graphic_methods.py
deleted file mode 100644
index 777cfc0..0000000
--- a/Allura/allura/lib/graphics/graphic_methods.py
+++ /dev/null
@@ -1,86 +0,0 @@
-#       Licensed to the Apache Software Foundation (ASF) under one
-#       or more contributor license agreements.  See the NOTICE file
-#       distributed with this work for additional information
-#       regarding copyright ownership.  The ASF licenses this file
-#       to you under the Apache License, Version 2.0 (the
-#       "License"); you may not use this file except in compliance
-#       with the License.  You may obtain a copy of the License at
-#
-#         http://www.apache.org/licenses/LICENSE-2.0
-#
-#       Unless required by applicable law or agreed to in writing,
-#       software distributed under the License is distributed on an
-#       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-#       KIND, either express or implied.  See the License for the
-#       specific language governing permissions and limitations
-#       under the License.
-
-import StringIO
-
-from matplotlib.backends.backend_agg import FigureCanvasAgg
-from matplotlib.figure import Figure
-import Image
-
-
-def create_histogram(data, tick_labels, y_label, title):
-    fig = Figure(figsize=(10,5), dpi=80, facecolor='white')
-    ax = fig.add_subplot(111, axisbg='#EEEEFF')
-
-    canvas = FigureCanvasAgg(fig)
-    n, bins, patches = ax.hist(data, facecolor='#330099', edgecolor='white')
-    ax.set_ylabel(y_label)
-    ax.set_title(title)
-
-    ax.set_xticks(range(len(tick_labels)+1))
-    ax.get_xaxis().set_ticklabels(tick_labels, rotation=45, va='top', ha='right')
-    ax.get_xaxis().set_ticks_position('none')
-    ax.set_autoscalex_on(False)
-
-    ax.set_xlim((-1, len(tick_labels)))
-    ax.set_ylim((0, 1+max([data.count(el) for el in data])))
-    fig.subplots_adjust(bottom=0.3)
-
-    canvas.draw()
-
-    s = canvas.tostring_rgb()
-    l,b,w,h = fig.bbox.bounds
-    w, h = int(w), int(h)
-
-    output = StringIO.StringIO()
-    im = Image.fromstring( "RGB", (w,h), s)
-    im.save(output, 'PNG')
-
-    return output.getvalue()
-
-def create_progress_bar(value):
-    value = value / 100.0
-    if value < 1 / 5.0:
-        color = 'red'
-    elif value < 2 / 5.0:
-        color = 'orange'
-    elif value < 3 / 5.0:
-        color = 'yellow'
-    elif value < 4 / 5.0:
-        color = 'lightgreen'
-    else:
-        color = 'green'
-
-    fig = Figure(figsize=(3,0.5), dpi=40, facecolor='gray')
-    canvas = FigureCanvasAgg(fig)
-    canvas.draw()
-
-    from matplotlib.patches import Rectangle
-    from matplotlib.axes import Axes
-
-    fig.draw_artist(Rectangle((0,0), int(value * 120), 20, color=color))
-    fig.draw_artist(Rectangle((1,0), 119, 19, fill=False, ec='black'))
-
-    l,b,w,h = fig.bbox.bounds
-    s = canvas.tostring_rgb()
-    w, h = int(w), int(h)
-
-    output = StringIO.StringIO()
-    im = Image.fromstring( "RGB", (w,h), s)
-    im.save(output, 'PNG')
-
-    return output.getvalue()

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/3e12f6d5/Allura/docs/conf.py
----------------------------------------------------------------------
diff --git a/Allura/docs/conf.py b/Allura/docs/conf.py
index 81c0e1f..f7d8757 100644
--- a/Allura/docs/conf.py
+++ b/Allura/docs/conf.py
@@ -30,31 +30,6 @@
 
 import sys, os
 
-class Mock(object):
-    def __init__(self, *args, **kwargs):
-        pass
-
-    def __call__(self, *args, **kwargs):
-        return Mock()
-
-    @classmethod
-    def __getattr__(cls, name):
-        if name in ('__file__', '__path__'):
-            return '/dev/null'
-        elif name[0] == name[0].upper():
-            mockType = type(name, (), {})
-            mockType.__module__ = __name__
-            return mockType
-        else:
-            return Mock()
-
-MOCK_MODULES = ['matplotlib', 'matplotlib.axes',
-        'matplotlib.backends', 'matplotlib.backends.backend_agg',
-        'matplotlib.figure', 'matplotlib.patches']
-
-for mod_name in MOCK_MODULES:
-    sys.modules[mod_name] = Mock()
-
 # If extensions (or modules to document with autodoc) are in another directory,
 # add these directories to sys.path here. If the directory is relative to the
 # documentation root, use os.path.abspath to make it absolute, like shown here.

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/3e12f6d5/ForgeUserStats/forgeuserstats/controllers/userstats.py
----------------------------------------------------------------------
diff --git a/ForgeUserStats/forgeuserstats/controllers/userstats.py b/ForgeUserStats/forgeuserstats/controllers/userstats.py
index 1cb5505..85b26df 100644
--- a/ForgeUserStats/forgeuserstats/controllers/userstats.py
+++ b/ForgeUserStats/forgeuserstats/controllers/userstats.py
@@ -20,7 +20,6 @@ from tg.decorators import with_trailing_slash
 from datetime import datetime
 from allura.controllers import BaseController
 import allura.model as M
-from allura.lib.graphics.graphic_methods import create_histogram, create_progress_bar
 from forgeuserstats.model.stats import UserStats
 from pylons import tmpl_context as c
 from allura.lib.security import require_access
@@ -195,35 +194,6 @@ class ForgeUserStatsController(BaseController):
             user=self.user,
             data=artifacts)
 
-    @expose()
-    def categories_graph(self):
-        self.user = c.project.user_project_of
-        if not self.user:
-            return None
-
-        categories = {}
-        for p in self.user.my_projects():
-            for cat in p.trove_topic:
-                cat = M.TroveCategory.query.get(_id = cat)
-                if categories.get(cat):
-                    categories[cat] += 1
-                else:
-                    categories[cat] = 1
-        data = []
-        labels = []
-        i = 0
-        for cat in sorted(categories.keys(), key=lambda x:x.fullname):
-            n = categories[cat]
-            data = data + [i] * n
-            label = cat.fullname
-            if len(label) > 15:
-                label = label[:15] + "..."
-            labels.append(label)
-            i += 1
-
-        return create_histogram(data, labels,
-            'Number of projects', 'Projects by category')
-
 
 def _getDataForCategory(category, stats):
     totcommits = stats.getCommits(category)

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/3e12f6d5/ForgeUserStats/forgeuserstats/templates/index.html
----------------------------------------------------------------------
diff --git a/ForgeUserStats/forgeuserstats/templates/index.html b/ForgeUserStats/forgeuserstats/templates/index.html
index 2bb6314..406fb20 100644
--- a/ForgeUserStats/forgeuserstats/templates/index.html
+++ b/ForgeUserStats/forgeuserstats/templates/index.html
@@ -381,15 +381,6 @@
             {% endfor %}
           </tbody>
         </table>
-
-        {% if categories|length > 1 %}
-          <p>
-            The same data listed in the previous table is graphically presented by the following histogram.
-          </p>
-          <p>
-            <img src="{{c.project.url()}}userstats/categories_graph"/>
-          </p>
-        {% endif %}
     {% endif %}
   {% else %}
     {% if user %}

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/3e12f6d5/requirements-common.txt
----------------------------------------------------------------------
diff --git a/requirements-common.txt b/requirements-common.txt
index 75f4541..21ea929 100644
--- a/requirements-common.txt
+++ b/requirements-common.txt
@@ -47,8 +47,6 @@ TurboGears2==2.1.5
 WebOb==1.0.8
 # part of the stdlib, but with a version number.  see http://guide.python-distribute.org/pip.html#listing-installed-packages
 wsgiref==0.1.2
-numpy==1.6.1
-matplotlib==1.1.1
 
 # tg2 deps (not used directly)
 Babel==0.9.6

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/3e12f6d5/vagrant/manifests/ubuntu-1204-server-amd64.pp
----------------------------------------------------------------------
diff --git a/vagrant/manifests/ubuntu-1204-server-amd64.pp b/vagrant/manifests/ubuntu-1204-server-amd64.pp
index 1feb18e..4031084 100644
--- a/vagrant/manifests/ubuntu-1204-server-amd64.pp
+++ b/vagrant/manifests/ubuntu-1204-server-amd64.pp
@@ -107,19 +107,6 @@ file { '/home/vagrant/src/allura':
   require => [ File['/home/vagrant/src'], Exec['clone repo'] ],
 }
 
-# HACK to get numpy installed in the venv before installing
-# remaining dependencies via requirements file
-exec { "pip install numpy":
-  command => "/home/vagrant/env-allura/bin/pip install numpy==1.6.1",
-  cwd     => "/vagrant/allura",
-  timeout => 0,
-  logoutput => true,
-  returns => 0,
-  tries => 3,
-  require => [ Exec[ "clone repo"], Exec[ "create allura venv" ],
-               ],
-}
-
 # install Allura dependencies
 exec { "pip install":
   command => "/home/vagrant/env-allura/bin/pip install -r requirements.txt",
@@ -132,7 +119,6 @@ exec { "pip install":
   tries => 3,
   require => [ Exec[ "clone repo"], Exec[ "create allura venv" ],
                File["/usr/lib/libjpeg.so"], File["/usr/lib/libz.so"],
-               Exec["pip install numpy"],
                ],
 }
 


[2/4] git commit: [#6133] ticket solved values are percentages, so *100

Posted by jo...@apache.org.
[#6133] ticket solved values are percentages, so *100


Project: http://git-wip-us.apache.org/repos/asf/incubator-allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-allura/commit/47e7e084
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/47e7e084
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/47e7e084

Branch: refs/heads/master
Commit: 47e7e084e97edadfea372dffb27d07f936140dd2
Parents: 59ea05c
Author: Dave Brondsema <db...@slashdotmedia.com>
Authored: Sat May 4 22:46:19 2013 -0400
Committer: Cory Johns <cj...@slashdotmedia.com>
Committed: Mon May 6 21:34:31 2013 +0000

----------------------------------------------------------------------
 ForgeUserStats/forgeuserstats/templates/index.html |   22 +++++++-------
 1 files changed, 11 insertions(+), 11 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/47e7e084/ForgeUserStats/forgeuserstats/templates/index.html
----------------------------------------------------------------------
diff --git a/ForgeUserStats/forgeuserstats/templates/index.html b/ForgeUserStats/forgeuserstats/templates/index.html
index ceb3f81..bc23ec0 100644
--- a/ForgeUserStats/forgeuserstats/templates/index.html
+++ b/ForgeUserStats/forgeuserstats/templates/index.html
@@ -45,10 +45,10 @@
           <th>Time interval</th>
         </tr>
       </thead>
-      <tbody> 
+      <tbody>
         <tr>
           <td>Registration date</td>
-          <td>{{registration_date.strftime("%d %b %Y, %H:%M:%S (UTC)")}}</td> 
+          <td>{{registration_date.strftime("%d %b %Y, %H:%M:%S (UTC)")}}</td>
            <td>{{days}} day{% if days != 1 %}s{% endif %} ago</td>
         </tr>
         {% if last_login %}
@@ -187,7 +187,7 @@
             </td>
           {% endif %}
         </tr>
-        
+
         {% for key, value in artifacts_by_type.items() %}
           <tr>
             <td>
@@ -332,7 +332,7 @@
           </td>
           <td>
             {% if tottickets.averagesolvingtime %}
-              {{tottickets.averagesolvingtime.days}} days, 
+              {{tottickets.averagesolvingtime.days}} days,
               {{tottickets.averagesolvingtime.hours}} hours,
               {{tottickets.averagesolvingtime.minutes}} min
             {% else %}n/a{% endif %}
@@ -340,7 +340,7 @@
           <td>n/a</td>
           <td>
             {% if lastmonthtickets.averagesolvingtime %}
-              {{lastmonthtickets.averagesolvingtime.days}} days, 
+              {{lastmonthtickets.averagesolvingtime.days}} days,
               {{lastmonthtickets.averagesolvingtime.hours}} hours,
               {{lastmonthtickets.averagesolvingtime.minutes}} min
             {% else %}n/a{% endif %}
@@ -381,7 +381,7 @@
             {% endfor %}
           </tbody>
         </table>
-         
+
         {% if categories|length > 1 %}
           <p>
             The same data listed in the previous table is graphically presented by the following histogram.
@@ -420,9 +420,9 @@
           </tr>
           <tr>
             <td>Solved issues</td>
-            <td>{{ticketcontribution}} %</td>
-            <td>{{averageticketcontrib}} %</td>
-            <td>{{maxticketcontrib}} %</td>
+            <td>{{ticketcontribution*100}} %</td>
+            <td>{{averageticketcontrib*100}} %</td>
+            <td>{{maxticketcontrib*100}} %</td>
             <td><img src="{{c.project.url()}}userstats/tickets_ranking_bar"/> {{ticketspercentage}} %</td>
           </tr>
         </tbody>
@@ -438,13 +438,13 @@
   {% else %}
     {% if user %}
       <h2>Statistics not available</h2>
-      <div class="grid-20"> 
+      <div class="grid-20">
         This user has set his or her preferences so that personal statistics are not visible
         to other users of the forge.
       </div>
     {% else %}
       <h2>Invalid user</h2>
-      <div class="grid-20"> 
+      <div class="grid-20">
         You are looking for personal statistics of a user which doesn't exist on this forge. Check your url.
       </div>
     {% endif %}


[3/4] git commit: [#6133] remove extremely slow methods using `self.query.find()`

Posted by jo...@apache.org.
[#6133] remove extremely slow methods using `self.query.find()`

And remove table displaying these values.  A few other values of this
table (the 'Value' column) could still be displayed, but showing just
one column in a table would look bad, and these values are basically
available from the main table on the stats page anyway.  The methods
for computing those values were left, just unused now.


Project: http://git-wip-us.apache.org/repos/asf/incubator-allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-allura/commit/b21778f7
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/b21778f7
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/b21778f7

Branch: refs/heads/master
Commit: b21778f718934462187b1fdc1d76107c37450176
Parents: 47e7e08
Author: Dave Brondsema <db...@slashdotmedia.com>
Authored: Sat May 4 22:47:52 2013 -0400
Committer: Cory Johns <cj...@slashdotmedia.com>
Committed: Mon May 6 21:34:31 2013 +0000

----------------------------------------------------------------------
 Allura/allura/model/stats.py                       |   60 -----------
 .../forgeuserstats/controllers/userstats.py        |   81 ++++-----------
 ForgeUserStats/forgeuserstats/templates/index.html |   44 --------
 3 files changed, 22 insertions(+), 163 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/b21778f7/Allura/allura/model/stats.py
----------------------------------------------------------------------
diff --git a/Allura/allura/model/stats.py b/Allura/allura/model/stats.py
index 06ed07d..cff1abc 100644
--- a/Allura/allura/model/stats.py
+++ b/Allura/allura/model/stats.py
@@ -117,66 +117,6 @@ class Stats(MappedClass):
                 return round(float(tickets.solved) / tickets.assigned, 2)
         return 0
 
-    @classmethod
-    def getMaxAndAverageCodeContribution(self):
-        res = self.query.find()
-        n = res.count()
-        if n == 0:
-            return 0, 0
-        values = [x.getCodeContribution() for x in res]
-        maxcontribution=max(values)
-        averagecontribution=sum(values) / n
-        return maxcontribution, round(averagecontribution, 2)
-
-    @classmethod
-    def getMaxAndAverageDiscussionContribution(self):
-        res = self.query.find()
-        n = res.count()
-        if n == 0:
-            return 0, 0
-        values = [x.getDiscussionContribution() for x in res]
-        maxcontribution=max(values)
-        averagecontribution=sum(values)/n
-        return maxcontribution, round(averagecontribution, 2)
-
-    @classmethod
-    def getMaxAndAverageTicketsSolvingPercentage(self):
-        res = self.query.find()
-        n = res.count()
-        if n == 0:
-            return 0, 0
-        values = [x.getTicketsContribution() for x in res]
-        maxcontribution=max(values)
-        averagecontribution=sum(values)/n
-        return maxcontribution, round(averagecontribution, 2)
-
-    def codeRanking(self):
-        res = self.query.find()
-        totn = res.count()
-        if totn == 0:
-            return 0
-        codcontr = self.getCodeContribution()
-        upper = len([x for x in res if x.getCodeContribution() > codcontr])
-        return round((totn - upper) * 100.0 / totn, 2)
-
-    def discussionRanking(self):
-        res = self.query.find()
-        totn = res.count()
-        if totn == 0:
-            return 0
-        disccontr = self.getDiscussionContribution()
-        upper=len([x for x in res if x.getDiscussionContribution()>disccontr])
-        return round((totn - upper) * 100.0 / totn, 2)
-
-    def ticketsRanking(self):
-        res = self.query.find()
-        totn = res.count()
-        if totn == 0:
-            return 0
-        ticketscontr = self.getTicketsContribution()
-        upper=len([x for x in res if x.getTicketsContribution()>ticketscontr])
-        return round((totn - upper) * 100.0 / totn, 2)
-
     def getCommits(self, category = None):
         i = getElementIndex(self.general, category = category)
         if i is None:

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/b21778f7/ForgeUserStats/forgeuserstats/controllers/userstats.py
----------------------------------------------------------------------
diff --git a/ForgeUserStats/forgeuserstats/controllers/userstats.py b/ForgeUserStats/forgeuserstats/controllers/userstats.py
index 5b95954..1cb5505 100644
--- a/ForgeUserStats/forgeuserstats/controllers/userstats.py
+++ b/ForgeUserStats/forgeuserstats/controllers/userstats.py
@@ -45,14 +45,14 @@ class ForgeUserStatsCatController(BaseController):
     @with_trailing_slash
     def index(self, **kw):
         self.user = c.project.user_project_of
-        if not self.user: 
+        if not self.user:
             return None
         stats = self.user.stats
         if (not stats.visible) and (c.user != self.user):
             return dict(user=self.user)
-        
+
         cat_id = None
-        if self.category: 
+        if self.category:
             cat_id = self.category._id
         ret_dict = _getDataForCategory(cat_id, stats)
         ret_dict['user'] = self.user
@@ -62,23 +62,23 @@ class ForgeUserStatsCatController(BaseController):
 
 class ForgeUserStatsController(BaseController):
 
-    category = ForgeUserStatsCatController()            
-    
+    category = ForgeUserStatsCatController()
+
     @expose('jinja:forgeuserstats:templates/settings.html')
     @with_trailing_slash
     def settings(self, **kw):
         require_access(c.project, 'admin')
 
         self.user = c.project.user_project_of
-        if not self.user: 
+        if not self.user:
             return dict(user=None)
         if not self.user.stats:
             UserStats.create(self.user)
         return dict(
-            user = self.user, 
+            user = self.user,
             form = StatsPreferencesForm(
                 action = c.project.url() + 'userstats/change_settings'))
-      
+
     @expose()
     @require_post()
     @validate(stats_preferences_form, error_handler=settings)
@@ -86,7 +86,7 @@ class ForgeUserStatsController(BaseController):
         require_access(c.project, 'admin')
 
         self.user = c.project.user_project_of
-        if not self.user: 
+        if not self.user:
             return dict(user=None)
         if not self.user.stats:
             UserStats.create(self.user)
@@ -98,7 +98,7 @@ class ForgeUserStatsController(BaseController):
     @with_trailing_slash
     def index(self, **kw):
         self.user = c.project.user_project_of
-        if not self.user: 
+        if not self.user:
             return dict(user=None)
         if not self.user.stats:
             UserStats.create(self.user)
@@ -131,25 +131,12 @@ class ForgeUserStatsController(BaseController):
         ret_dict['lastmonth_logins'] = stats.getLastMonthLogins()
         ret_dict['categories'] = categories
         days = ret_dict['days']
-        if days >= 30: 
+        if days >= 30:
             ret_dict['permonthlogins'] = \
                 round(stats.tot_logins_count*30.0/days,2)
         else:
             ret_dict['permonthlogins'] = 'n/a'
 
-        ret_dict['codepercentage'] = stats.codeRanking()
-        ret_dict['discussionpercentage'] = stats.discussionRanking()
-        ret_dict['ticketspercentage'] = stats.ticketsRanking()
-        ret_dict['codecontribution'] = stats.getCodeContribution()
-        ret_dict['discussioncontribution'] = stats.getDiscussionContribution()
-        ret_dict['ticketcontribution'] = stats.getTicketsContribution()
-        ret_dict['maxcodecontrib'], ret_dict['averagecodecontrib'] =\
-            stats.getMaxAndAverageCodeContribution()
-        ret_dict['maxdisccontrib'], ret_dict['averagedisccontrib'] =\
-            stats.getMaxAndAverageDiscussionContribution()
-        ret_dict['maxticketcontrib'], ret_dict['averageticketcontrib'] =\
-            stats.getMaxAndAverageTicketsSolvingPercentage()
-        
         return ret_dict
 
 
@@ -157,7 +144,7 @@ class ForgeUserStatsController(BaseController):
     @with_trailing_slash
     def commits(self, **kw):
         self.user = c.project.user_project_of
-        if not self.user: 
+        if not self.user:
             return dict(user=None)
         if not self.user.stats:
             UserStats.create(self.user)
@@ -165,17 +152,17 @@ class ForgeUserStatsController(BaseController):
 
         if (not stats.visible) and (c.user != self.user):
             return dict(user=self.user)
-        
+
         commits = stats.getCommitsByCategory()
         return dict(
             user = self.user,
-            data = commits) 
+            data = commits)
 
     @expose('jinja:forgeuserstats:templates/artifacts.html')
     @with_trailing_slash
     def artifacts(self, **kw):
         self.user = c.project.user_project_of
-        if not self.user: 
+        if not self.user:
             return dict(user=None)
         if not self.user.stats:
             UserStats.create(self.user)
@@ -184,7 +171,7 @@ class ForgeUserStatsController(BaseController):
         if (not stats.visible) and (c.user != self.user):
             return dict(user=self.user)
 
-        stats = self.user.stats       
+        stats = self.user.stats
         artifacts = stats.getArtifactsByCategory(detailed=True)
         return dict(
             user = self.user,
@@ -194,7 +181,7 @@ class ForgeUserStatsController(BaseController):
     @with_trailing_slash
     def tickets(self, **kw):
         self.user = c.project.user_project_of
-        if not self.user: 
+        if not self.user:
             return dict(user=None)
         if not self.user.stats:
             UserStats.create(self.user)
@@ -211,7 +198,7 @@ class ForgeUserStatsController(BaseController):
     @expose()
     def categories_graph(self):
         self.user = c.project.user_project_of
-        if not self.user: 
+        if not self.user:
             return None
 
         categories = {}
@@ -234,39 +221,16 @@ class ForgeUserStatsController(BaseController):
             labels.append(label)
             i += 1
 
-        return create_histogram(data, labels, 
+        return create_histogram(data, labels,
             'Number of projects', 'Projects by category')
 
-    @expose()
-    def code_ranking_bar(self):
-        self.user = c.project.user_project_of
-        if not self.user: 
-            return None
-        stats = self.user.stats
-        return create_progress_bar(stats.codeRanking())
-
-    @expose()
-    def discussion_ranking_bar(self):
-        self.user = c.project.user_project_of
-        if not self.user: 
-            return None
-        stats = self.user.stats
-        return create_progress_bar(stats.discussionRanking())
-
-    @expose()
-    def tickets_ranking_bar(self):
-        self.user = c.project.user_project_of
-        if not self.user: 
-            return None
-        stats = self.user.stats
-        return create_progress_bar(stats.ticketsRanking())
 
 def _getDataForCategory(category, stats):
     totcommits = stats.getCommits(category)
     tottickets = stats.getTickets(category)
     averagetime = tottickets.get('averagesolvingtime')
     artifacts_by_type = stats.getArtifactsByType(category)
-    totartifacts = artifacts_by_type.get(None) 
+    totartifacts = artifacts_by_type.get(None)
     if totartifacts:
         del artifacts_by_type[None]
     else:
@@ -279,7 +243,7 @@ def _getDataForCategory(category, stats):
     averagetime = lm_tickets.get('averagesolvingtime')
 
     days = (datetime.utcnow() - stats.registration_date).days
-    if days >= 30: 
+    if days >= 30:
         pmartifacts = dict(
             created = round(totartifacts['created']*30.0/days,2),
             modified=round(totartifacts['modified']*30.0/days,2))
@@ -297,7 +261,7 @@ def _getDataForCategory(category, stats):
                 round(value['created']*30.0/days,2)
             artifacts_by_type[key]['pmmodified']= \
                 round(value['modified']*30.0/days,2)
-    else: 
+    else:
         pmartifacts = dict(created='n/a', modified='n/a')
         pmcommits = dict(number='n/a', lines='n/a')
         pmtickets = dict(
@@ -322,4 +286,3 @@ def _getDataForCategory(category, stats):
         artifacts_by_type = artifacts_by_type,
         lastmonth_artifacts_by_type = lm_artifacts_by_type,
         permonthtickets = pmtickets)
-

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/b21778f7/ForgeUserStats/forgeuserstats/templates/index.html
----------------------------------------------------------------------
diff --git a/ForgeUserStats/forgeuserstats/templates/index.html b/ForgeUserStats/forgeuserstats/templates/index.html
index bc23ec0..2bb6314 100644
--- a/ForgeUserStats/forgeuserstats/templates/index.html
+++ b/ForgeUserStats/forgeuserstats/templates/index.html
@@ -391,50 +391,6 @@
           </p>
         {% endif %}
     {% endif %}
-    {% if not category %}
-      <h2>Overview</h2>
-      <table>
-        <thead>
-          <tr>
-            <th>Field</th>
-            <th>Value</th>
-            <th>Average per-user value</th>
-            <th>Maximum per-user value</th>
-            <th>Rank bar</th>
-          </tr>
-        </thead>
-        <tbody>
-          <tr>
-            <td>Code</td>
-            <td>{{codecontribution}} LOC{% if codecontribution != 1 %}s{% endif %}/month</td>
-            <td>{{averagecodecontrib}} LOC{% if averagecodecontrib != 1 %}s{% endif %}/month</td>
-            <td>{{maxcodecontrib}} LOC{% if maxcodecontrib != 1 %}s{% endif %}/month</td>
-            <td><img src="{{c.project.url()}}userstats/code_ranking_bar"/> {{codepercentage}} %</td>
-          </tr>
-          <tr>
-            <td>Discussion</td>
-            <td>{{discussioncontribution}} contr./month</td>
-            <td>{{averagedisccontrib}} contr./month</td>
-            <td>{{maxdisccontrib}} contr./month</td>
-            <td><img src="{{c.project.url()}}userstats/discussion_ranking_bar"/> {{discussionpercentage}} %</td>
-          </tr>
-          <tr>
-            <td>Solved issues</td>
-            <td>{{ticketcontribution*100}} %</td>
-            <td>{{averageticketcontrib*100}} %</td>
-            <td>{{maxticketcontrib*100}} %</td>
-            <td><img src="{{c.project.url()}}userstats/tickets_ranking_bar"/> {{ticketspercentage}} %</td>
-          </tr>
-        </tbody>
-      </table>
-      <h3>Note</h3>
-      <p>
-         The above table compares the average monthly contribution of this user with the average monthly contributions of the
-         other users of the forge. The progressbar and the percentage refer to the user's position in an overall ranking of the
-         users of this forge. For example, a value of 100% in the field "Code" is associated to the user who has the highest
-         average number of committed LOCs per month. Of course, this doesn't consider the quality of the contributions.
-      </p>
-    {% endif %}
   {% else %}
     {% if user %}
       <h2>Statistics not available</h2>


[4/4] git commit: [#6133] avoid div by 0 errors when no data

Posted by jo...@apache.org.
[#6133] avoid div by 0 errors when no data


Project: http://git-wip-us.apache.org/repos/asf/incubator-allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-allura/commit/59ea05c1
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/59ea05c1
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/59ea05c1

Branch: refs/heads/master
Commit: 59ea05c12a813fdddb047953c7c5ed93b37a991d
Parents: fae7479
Author: Dave Brondsema <db...@slashdotmedia.com>
Authored: Sat May 4 21:41:45 2013 -0400
Committer: Cory Johns <cj...@slashdotmedia.com>
Committed: Mon May 6 21:34:31 2013 +0000

----------------------------------------------------------------------
 Allura/allura/model/stats.py |   88 ++++++++++++++++++++-----------------
 1 files changed, 47 insertions(+), 41 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/59ea05c1/Allura/allura/model/stats.py
----------------------------------------------------------------------
diff --git a/Allura/allura/model/stats.py b/Allura/allura/model/stats.py
index 5365503..06ed07d 100644
--- a/Allura/allura/model/stats.py
+++ b/Allura/allura/model/stats.py
@@ -86,7 +86,7 @@ class Stats(MappedClass):
         for val in self['general']:
             if val['category'] is None:
                 for commits in val['commits']:
-                    if commits['language'] is None: 
+                    if commits['language'] is None:
                         if days > 30:
                             return round(float(commits.lines)/days*30, 2)
                         else:
@@ -100,7 +100,7 @@ class Stats(MappedClass):
         for val in self['general']:
             if val['category'] is None:
                 for artifact in val['messages']:
-                    if artifact['messagetype'] is None: 
+                    if artifact['messagetype'] is None:
                         tot = artifact.created+artifact.modified
                         if days > 30:
                             return round(float(tot)/days*30,2)
@@ -153,6 +153,8 @@ class Stats(MappedClass):
     def codeRanking(self):
         res = self.query.find()
         totn = res.count()
+        if totn == 0:
+            return 0
         codcontr = self.getCodeContribution()
         upper = len([x for x in res if x.getCodeContribution() > codcontr])
         return round((totn - upper) * 100.0 / totn, 2)
@@ -160,6 +162,8 @@ class Stats(MappedClass):
     def discussionRanking(self):
         res = self.query.find()
         totn = res.count()
+        if totn == 0:
+            return 0
         disccontr = self.getDiscussionContribution()
         upper=len([x for x in res if x.getDiscussionContribution()>disccontr])
         return round((totn - upper) * 100.0 / totn, 2)
@@ -167,20 +171,22 @@ class Stats(MappedClass):
     def ticketsRanking(self):
         res = self.query.find()
         totn = res.count()
+        if totn == 0:
+            return 0
         ticketscontr = self.getTicketsContribution()
         upper=len([x for x in res if x.getTicketsContribution()>ticketscontr])
         return round((totn - upper) * 100.0 / totn, 2)
 
     def getCommits(self, category = None):
         i = getElementIndex(self.general, category = category)
-        if i is None: 
+        if i is None:
             return dict(number=0, lines=0)
         cat = self.general[i]
         j = getElementIndex(cat.commits, language = None)
         if j is None:
             return dict(number=0, lines=0)
         return dict(
-            number=cat.commits[j]['number'], 
+            number=cat.commits[j]['number'],
             lines=cat.commits[j]['lines'])
 
     def getArtifacts(self, category = None, art_type = None):
@@ -202,10 +208,10 @@ class Stats(MappedClass):
                 revoked=0,
                 averagesolvingtime=None)
         if self.general[i].tickets.solved > 0:
-            tot = self.general[i].tickets.totsolvingtime 
+            tot = self.general[i].tickets.totsolvingtime
             number = self.general[i].tickets.solved
             average = tot / number
-        else: 
+        else:
             average = None
         return dict(
             assigned=self.general[i].tickets.assigned,
@@ -220,9 +226,9 @@ class Stats(MappedClass):
         for entry in self.general:
             cat = entry.category
             i = getElementIndex(entry.commits, language = None)
-            if i is None: 
+            if i is None:
                 n, lines = 0, 0
-            else: 
+            else:
                 n, lines = entry.commits[i].number, entry.commits[i].lines
             if cat != None:
                 cat = TroveCategory.query.get(_id = cat)
@@ -237,7 +243,7 @@ class Stats(MappedClass):
         langlist = []
         by_lang = {}
         i = getElementIndex(self.general, category=None)
-        if i is None: 
+        if i is None:
             return dict(number=0, lines=0)
         return dict([(el.language, dict(lines=el.lines, number=el.number))
                      for el in self.general[i].commits])
@@ -248,21 +254,21 @@ class Stats(MappedClass):
         by_cat = {}
         for entry in self.general:
             cat = entry.category
-            if cat != None: 
+            if cat != None:
                 cat = TroveCategory.query.get(_id = cat)
-            if detailed: 
+            if detailed:
                 by_cat[cat] = entry.messages
             else:
                 i = getElementIndex(entry.messages, messagetype=None)
                 if i is not None:
                     by_cat[cat] = entry.messages[i]
-                else: 
+                else:
                     by_cat[cat] = dict(created=0, modified=0)
         return by_cat
 
     def getArtifactsByType(self, category=None):
         i = getElementIndex(self.general, category = category)
-        if i is None: 
+        if i is None:
             return {}
         entry = self.general[i].messages
         by_type = dict([(el.messagetype, dict(created=el.created,
@@ -287,12 +293,12 @@ class Stats(MappedClass):
             by_cat[cat] = dict(
                 assigned=a,
                 solved=s,
-                revoked=r, 
+                revoked=r,
                 averagesolvingtime=_convertTimeDiff(average))
         return by_cat
 
     def getLastMonthCommits(self, category = None):
-        self.checkOldArtifacts() 
+        self.checkOldArtifacts()
         lineslist = [el.lines for el in self.lastmonth.commits
                      if category in el.categories + [None]]
         return dict(number=len(lineslist), lines=sum(lineslist))
@@ -300,7 +306,7 @@ class Stats(MappedClass):
     def getLastMonthCommitsByCategory(self):
         from allura.model.project import TroveCategory
 
-        self.checkOldArtifacts() 
+        self.checkOldArtifacts()
         seen = set()
         catlist=[el.category for el in self.general
                  if el.category not in seen and not seen.add(el.category)]
@@ -319,7 +325,7 @@ class Stats(MappedClass):
     def getLastMonthCommitsByLanguage(self):
         from allura.model.project import TroveCategory
 
-        self.checkOldArtifacts() 
+        self.checkOldArtifacts()
         seen = set()
         langlist=[el.language for el in self.general
                   if el.language not in seen and not seen.add(el.language)]
@@ -336,13 +342,13 @@ class Stats(MappedClass):
         return by_lang
 
     def getLastMonthArtifacts(self, category = None, art_type = None):
-        self.checkOldArtifacts() 
+        self.checkOldArtifacts()
         cre, mod = reduce(
-            addtuple, 
+            addtuple,
             [(int(el.created),1-int(el.created))
                 for el in self.lastmonth.messages
-                if (category is None or category in el.categories) and 
-                (el.messagetype == art_type or art_type is None)], 
+                if (category is None or category in el.categories) and
+                (el.messagetype == art_type or art_type is None)],
             (0,0))
         return dict(created=cre, modified=mod)
 
@@ -355,7 +361,7 @@ class Stats(MappedClass):
         by_type = {}
         for t in types:
             cre, mod = reduce(
-                addtuple, 
+                addtuple,
                 [(int(el.created),1-int(el.created))
                  for el in self.lastmonth.messages
                  if el.messagetype == t and
@@ -367,7 +373,7 @@ class Stats(MappedClass):
     def getLastMonthArtifactsByCategory(self):
         from allura.model.project import TroveCategory
 
-        self.checkOldArtifacts() 
+        self.checkOldArtifacts()
         seen = set()
         catlist=[el.category for el in self.general
                  if el.category not in seen and not seen.add(el.category)]
@@ -375,9 +381,9 @@ class Stats(MappedClass):
         by_cat = {}
         for cat in catlist:
             cre, mod = reduce(
-                addtuple, 
+                addtuple,
                 [(int(el.created),1-int(el.created))
-                 for el in self.lastmonth.messages 
+                 for el in self.lastmonth.messages
                  if cat in el.categories + [None]], (0,0))
             if cat != None:
                 cat = TroveCategory.query.get(_id = cat)
@@ -393,7 +399,7 @@ class Stats(MappedClass):
         r = len([el for el in self.lastmonth.revokedtickets
                  if category in el.categories + [None]])
         s, time = reduce(
-            addtuple, 
+            addtuple,
             [(1, el.solvingtime)
              for el in self.lastmonth.solvedtickets
              if category in el.categories + [None]],
@@ -407,9 +413,9 @@ class Stats(MappedClass):
         return dict(
             assigned=a,
             revoked=r,
-            solved=s, 
+            solved=s,
             averagesolvingtime=_convertTimeDiff(time))
-        
+
     def getLastMonthTicketsByCategory(self):
         from allura.model.project import TroveCategory
 
@@ -428,17 +434,17 @@ class Stats(MappedClass):
                                         if cat in el.categories+[None]],(0,0))
             if cat != None:
                 cat = TroveCategory.query.get(_id = cat)
-            if s > 0: 
+            if s > 0:
                 time = time / s
             else:
                 time = None
             by_cat[cat] = dict(
                 assigned=a,
                 revoked=r,
-                solved=s, 
+                solved=s,
                 averagesolvingtime=_convertTimeDiff(time))
         return by_cat
-        
+
     def checkOldArtifacts(self):
         now = datetime.utcnow()
         for m in self.lastmonth.messages:
@@ -509,11 +515,11 @@ class Stats(MappedClass):
                 lines = 0
             return lines
 
-        def _addCommitData(stats, topics, languages, lines):          
+        def _addCommitData(stats, topics, languages, lines):
             lt = topics + [None]
             ll = languages + [None]
             for t in lt:
-                i = getElementIndex(stats.general, category=t) 
+                i = getElementIndex(stats.general, category=t)
                 if i is None:
                     newstats = dict(
                         category=t,
@@ -561,14 +567,14 @@ class Stats(MappedClass):
         _addCommitData(self, topics, languages, totlines)
 
         self.lastmonth.commits.append(dict(
-            datetime=commit_datetime, 
-            categories=topics, 
+            datetime=commit_datetime,
+            categories=topics,
             programming_languages=languages,
             lines=totlines))
         self.checkOldArtifacts()
 
     def _updateArtifactsStats(self, art_type, art_datetime, project, action):
-        if action not in ['created', 'modified']: 
+        if action not in ['created', 'modified']:
             return
         topics = [t for t in project.trove_topic if t]
         lt = [None] + topics
@@ -601,7 +607,7 @@ class Stats(MappedClass):
             created=(action == 'created'),
             categories=topics,
             messagetype=art_type))
-        self.checkOldArtifacts() 
+        self.checkOldArtifacts()
 
     def _updateTicketsStats(self, topics, action, s_time = None):
         if action not in ['solved', 'assigned', 'revoked']:
@@ -621,8 +627,8 @@ class Stats(MappedClass):
                     messages=[])
                 self.general.append(stats)
                 i = getElementIndex(self.general, category = t)
-            self.general[i]['tickets'][action] += 1 
-            if action == 'solved': 
+            self.general[i]['tickets'][action] += 1
+            if action == 'solved':
                 self.general[i]['tickets']['totsolvingtime']+=s_time
 
 def getElementIndex(el_list, **kw):
@@ -649,8 +655,8 @@ def _convertTimeDiff(int_seconds):
     minutes = seconds / 60
     seconds = seconds % 60
     return dict(
-        days=days, 
-        hours=hours, 
+        days=days,
+        hours=hours,
         minutes=minutes,
         seconds=seconds)