launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #06262
[Merge] lp:~wgrant/launchpad/remove-heat-ratio-flag into lp:launchpad
William Grant has proposed merging lp:~wgrant/launchpad/remove-heat-ratio-flag into lp:launchpad.
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
Related bugs:
Bug #915267 in Launchpad itself: "bug heat flames are expensive to calculate"
https://bugs.launchpad.net/launchpad/+bug/915267
For more details, see:
https://code.launchpad.net/~wgrant/launchpad/remove-heat-ratio-flag/+merge/91777
This branch drops the heat display feature flag, and the old disabled ratio display code. This is the next phase of the campaign against max_bug_heat.
I also fixed the other visible users of max_bug_heat, DistroSeries.getPrioritized*. They now use bug_count * 10, which seems to work reasonably well.
--
https://code.launchpad.net/~wgrant/launchpad/remove-heat-ratio-flag/+merge/91777
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~wgrant/launchpad/remove-heat-ratio-flag into lp:launchpad.
=== modified file 'lib/lp/bugs/browser/bugtask.py'
--- lib/lp/bugs/browser/bugtask.py 2012-01-25 05:34:12 +0000
+++ lib/lp/bugs/browser/bugtask.py 2012-02-07 08:14:20 +0000
@@ -14,7 +14,6 @@
'bugtarget_renderer',
'BugTargetTraversalMixin',
'BugTargetView',
- 'bugtask_heat_html',
'BugTaskBreadcrumb',
'BugTaskContextMenu',
'BugTaskCreateQuestionView',
@@ -32,7 +31,6 @@
'BugTaskTableRowView',
'BugTaskTextView',
'BugTaskView',
- 'calculate_heat_display',
'get_buglisting_search_filter_url',
'get_comments_for_bugtask',
'get_sortorder_from_request',
@@ -1089,16 +1087,9 @@
@property
def bug_heat_html(self):
"""HTML representation of the bug heat."""
- if getFeatureFlag('bugs.heat_ratio_display.disabled'):
- return (
- '<span><a href="/+help-bugs/bug-heat.html" target="help" '
- 'class="sprite flame">%d</a></span>' % self.context.bug.heat)
- else:
- if IDistributionSourcePackage.providedBy(self.context.target):
- return bugtask_heat_html(
- self.context, target=self.context.distribution)
- else:
- return bugtask_heat_html(self.context)
+ return (
+ '<span><a href="/+help-bugs/bug-heat.html" target="help" '
+ 'class="sprite flame">%d</a></span>' % self.context.bug.heat)
@property
def privacy_notice_classes(self):
@@ -1108,40 +1099,6 @@
return ''
-def calculate_heat_display(heat, max_bug_heat):
- """Calculate the number of heat 'flames' to display."""
- heat = float(heat)
- max_bug_heat = float(max_bug_heat)
- if max_bug_heat == 0:
- return 0
- if heat / max_bug_heat < 0.33333:
- return 0
- if heat / max_bug_heat < 0.66666 or max_bug_heat < 2:
- return int(floor((heat / max_bug_heat) * 4))
- else:
- heat_index = int(floor((log(heat) / log(max_bug_heat)) * 4))
- # ensure that we never return a value > 4, even if
- # max_bug_heat is outdated.
- return min(heat_index, 4)
-
-
-def bugtask_heat_html(bugtask, target=None):
- """Render the HTML representing bug heat for a given bugask."""
- if target is None:
- target = bugtask.target
- max_bug_heat = target.max_bug_heat
- if max_bug_heat is None:
- max_bug_heat = 5000
- heat_ratio = calculate_heat_display(bugtask.bug.heat, max_bug_heat)
- html = (
- '<span><a href="/+help-bugs/bug-heat.html" target="help" '
- 'class="icon"><img src="/@@/bug-heat-%(ratio)i.png" '
- 'alt="%(ratio)i out of 4 heat flames" title="Heat: %(heat)i" /></a>'
- '</span>'
- % {'ratio': heat_ratio, 'heat': bugtask.bug.heat})
- return html
-
-
class BugTaskBatchedCommentsAndActivityView(BugTaskView):
"""A view for displaying batches of bug comments and activity."""
@@ -2224,20 +2181,12 @@
@property
def bug_heat_html(self):
"""Returns the bug heat flames HTML."""
- if getFeatureFlag('bugs.heat_ratio_display.disabled'):
- if getFeatureFlag('bugs.dynamic_bug_listings.enabled'):
- return (
- '<span class="sprite flame">%d</span>'
- % self.bugtask.bug.heat)
- else:
- return str(self.bugtask.bug.heat)
+ if getFeatureFlag('bugs.dynamic_bug_listings.enabled'):
+ return (
+ '<span class="sprite flame">%d</span>'
+ % self.bugtask.bug.heat)
else:
- return bugtask_heat_html(self.bugtask, target=self.target_context)
-
- @property
- def center_bug_heat(self):
- """Returns whether the bug_heat_html should be centered."""
- return not getFeatureFlag('bugs.heat_ratio_display.disabled')
+ return str(self.bugtask.bug.heat)
@property
def model(self):
=== removed file 'lib/lp/bugs/browser/tests/bug-heat-view.txt'
--- lib/lp/bugs/browser/tests/bug-heat-view.txt 2011-12-24 15:18:32 +0000
+++ lib/lp/bugs/browser/tests/bug-heat-view.txt 1970-01-01 00:00:00 +0000
@@ -1,119 +0,0 @@
-= Bug heat view =
-
-Bug heat is represented as four flame icons. The quantity of flames that are
-coloured is dependent on the value of the heat field. The function
-bugtask_heat_html is used to render the flames.
-
- >>> MAX_HEAT = 5000.0
- >>> from lp.testing import login, logout
- >>> from zope.security.proxy import removeSecurityProxy
- >>> from BeautifulSoup import BeautifulSoup
- >>> from lp.bugs.browser.bugtask import bugtask_heat_html
- >>> def print_flames(bugtask, target=None):
- ... html = bugtask_heat_html(bugtask, target=target)
- ... soup = BeautifulSoup(html)
- ... for img in soup.span.a.contents:
- ... print img['src']
- ... print img['alt']
- ... print img['title']
- >>> login('foo.bar@xxxxxxxxxxxxx')
- >>> bug = factory.makeBug()
-
-The maximum heat is defined as a constant in browser/bug.py. A bug with
-a heat of half the maximum will result in a display of two coloured flames
-and two black-and-white flames.
-
- >>> removeSecurityProxy(bug.default_bugtask.target).max_bug_heat = MAX_HEAT
- >>> removeSecurityProxy(bug).heat = MAX_HEAT / 2
- >>> print_flames(bug.default_bugtask)
- /@@/bug-heat-2.png
- 2 out of 4 heat flames
- Heat: 2500
-
-A bug with a maximum heat will display all four flames coloured.
-
- >>> removeSecurityProxy(bug).heat = MAX_HEAT
- >>> print_flames(bug.default_bugtask)
- /@@/bug-heat-4.png
- 4 out of 4 heat flames
- Heat: 5000
-
-A heat of less than a quarter of the maximum will display no coloured flames.
-
- >>> removeSecurityProxy(bug).heat = 0.1 * MAX_HEAT
- >>> print_flames(bug.default_bugtask)
- /@@/bug-heat-0.png
- 0 out of 4 heat flames
- Heat: 500
-
-
-== Specifying the target ==
-
-Some bugs can be viewed in a context different from their task's target. For
-example, bugs with tasks on packages can be viewed in the context of the entire
-distribution. In such cases, we want to explicitly specify the target, rather
-than use the bugtask's. We can do that by passing the target as a keyword
-parameter.
-
- >>> bug = factory.makeBug()
- >>> distro = factory.makeDistribution()
- >>> dsp = factory.makeDistributionSourcePackage(distribution=distro)
- >>> dsp_task = bug.addTask(bug.owner, dsp)
- >>> removeSecurityProxy(distro).max_bug_heat = MAX_HEAT
- >>> removeSecurityProxy(dsp).max_bug_heat = MAX_HEAT / 2
- >>> removeSecurityProxy(bug).heat = MAX_HEAT / 4
- >>> print_flames(dsp_task)
- /@@/bug-heat-2.png
- 2 out of 4 heat flames
- Heat: 1250
- >>> print_flames(dsp_task, target=distro)
- /@@/bug-heat-0.png
- 0 out of 4 heat flames
- Heat: 1250
-
- >>> logout()
-
-
-== Scaling Bug Heat ==
-
-To ensure a reasonable proportion of cold and hot bugs, the number used to
-calculate the number of flames to display is not a straight-forward ratio.
-Instead, we transform it by forcing low heat bugs to produce no flames and
-scaling the hottest bugs logarithmically.
-
- >>> from lp.bugs.browser.bugtask import calculate_heat_display
- >>> from math import floor
-
-Heat values less than a third of the maximum heat don't produce any flames.
-
- >>> print int(floor((300.0 / 1000.0) * 4))
- 1
- >>> print calculate_heat_display(300.0, 1000.0)
- 0
-
-Heat values higher than a third of the max but lower than two thirds are treated
-as a straightforward ratio.
-
- >>> print int(floor((500.0 / 1000.0) * 4))
- 2
- >>> print calculate_heat_display(500.0, 1000.0)
- 2
-
-Heat values higher than two thirds of the maximum heat are scaled upwards.
-
- >>> print int(floor((700.0 / 1000.0) * 4))
- 2
- >>> print calculate_heat_display(800.0, 1000.0)
- 3
-
-A max heat value of 1 works too, because we don't divide by
-log(max_heat) in this case.
-
- >>> print calculate_heat_display(1, 1)
- 4
-
-Even if the max heat value is smaller than the heat value itself,
-calculate_heat_display() does not return a value greater than 4.
-
- >>> print calculate_heat_display(2000, 1000)
- 4
=== modified file 'lib/lp/bugs/browser/tests/test_bugtask.py'
--- lib/lp/bugs/browser/tests/test_bugtask.py 2012-01-25 05:34:12 +0000
+++ lib/lp/bugs/browser/tests/test_bugtask.py 2012-02-07 08:14:20 +0000
@@ -1909,11 +1909,11 @@
self.useContext(person_logged_in(owner))
with dynamic_listings():
view = self.makeView(item.bugtask)
- cache = IJSONRequestCache(view.request)
- items = cache.objects['mustache_model']['items']
- self.assertEqual(1, len(items))
- combined = dict(item.model)
- combined.update(view.search().field_visibility)
+ cache = IJSONRequestCache(view.request)
+ items = cache.objects['mustache_model']['items']
+ self.assertEqual(1, len(items))
+ combined = dict(item.model)
+ combined.update(view.search().field_visibility)
self.assertEqual(combined, items[0])
def test_no_next_prev_for_single_batch(self):
@@ -2407,15 +2407,3 @@
2001, 1, 1, tzinfo=UTC)
self.assertEqual(
'on 2001-01-01', item.model['last_updated'])
-
- def test_model_numeric_heat(self):
- """bug_heat_html contains just the number if the flag is enabled."""
- with FeatureFixture({'bugs.heat_ratio_display.disabled': 'true'}):
- with dynamic_listings():
- owner, item = make_bug_task_listing_item(self.factory)
- self.assertNotIn('/@@/bug-heat', item.bug_heat_html)
- self.assertIn('sprite flame', item.bug_heat_html)
- with person_logged_in(owner):
- model = item.model
- self.assertEqual(
- item.bug_heat_html, model['bug_heat_html'])
=== modified file 'lib/lp/bugs/help/bug-heat.html'
--- lib/lp/bugs/help/bug-heat.html 2010-07-14 10:51:14 +0000
+++ lib/lp/bugs/help/bug-heat.html 2012-02-07 08:14:20 +0000
@@ -13,40 +13,13 @@
<p>
Launchpad helps you to appraise a bug by giving you a calculated measure
- — called bug heat — of its likely significance.
- </p>
-
- <p>
- You can see bug heat in bug listings, and also on individual bug pages,
- as four flames: the more flames that are lit, the higher the bug's
- <em>heat</em>.
- </p>
-
- <p>
- Launchpad works out how many flames to light by calculating a bug heat
- score and then seeing how that compares with the bug heat of other bugs
- for that project. If you want to see the bug heat score itself, hover
- your mouse over the flames icon.
- </p>
-
- <p>
- To calculate the bug heat score, Launchpad looks at the bug's:
- </p>
-
- <ul>
- <li>privacy status</li>
- <li>security status</li>
- <li>number of subscribers</li>
- <li>number of duplicates</li>
- <li>number of people who've selected the "this bug affects me" option
- <li>length of time since the last action.</li>
- </ul>
-
- <h2>How Launchpad calculates bug heat — the detailed version</h2>
-
- <p>
- Here's exactly how Launchpad calculates the bug heat score. First
- Launchpad gives the bug a base score:
+ — called bug heat — of its likely significance. You can see
+ bug heat in bug listings, and also on individual bug pages, as a
+ number next to a flame icon.
+ </p>
+
+ <p>
+ Here's how Launchpad calculates the bug heat score:
</p>
<table width="100%">
@@ -104,88 +77,5 @@
</td>
</tr>
</table>
-
- <p>
- Next, it adjusts the score depending on how active the bug is:
- </p>
-
- <table width="100%">
- <tr>
- <th>
- <strong>Nature of recent activity</strong>
- </th>
- <th>
- <strong>Calculation</strong>
- </th>
- </tr>
-
- <tr>
- <td>
- Bug has been active* within the past 24 hours
- </td>
- <td>
- Add 25% of the project's <em>hottest</em> bug's score divided by the
- number of days since the first activity on the bug in question
- </td>
- </tr>
- <tr>
- <td>
- Bug has <strong>not</strong> been active* in within the past 24
- hours
- </td>
- <td>
- Subtract 1% of the bug heat score for every day of inactivity
- </td>
- </tr>
- </table>
-
- <p>
- <small><em>* Activity is either a comment posted or some other update to
- the bug report.</em></small>
- </p>
-
- <p>
- Some bug statuses will also affect the overall score:
- </p>
-
- <table width="100%">
- <tr>
- <th>
- <strong>Status</strong>
- </th>
- <th>
- <strong>Affect on bug heat score</strong>
- </th>
- </tr>
- <tr>
- <td>
- Fix Released
- </td>
- <td rowspan="4">
- Reduces the total bug heat score to zero
- </td>
- <tr>
- <td>
- Invalid
- </td>
- </tr>
- <tr>
- <td>
- Won't Fix
- </td>
- </tr>
- <tr>
- <td>
- Expired
- </td>
- </tr>
- </table>
-
- <p>To view the code that calculates bug heat, look for
- calculate_bug_heat in the file
- <a target="_blank"
- href="http://bazaar.launchpad.net/~launchpad-pqm/launchpad/db-devel/annotate/head:/database/schema/trusted.sql">trusted.sql</a>
- </p>
-
</body>
</html>
=== modified file 'lib/lp/bugs/stories/bugs/xx-bug-heat-on-bug-page.txt'
--- lib/lp/bugs/stories/bugs/xx-bug-heat-on-bug-page.txt 2012-01-13 08:22:04 +0000
+++ lib/lp/bugs/stories/bugs/xx-bug-heat-on-bug-page.txt 2012-02-07 08:14:20 +0000
@@ -1,47 +1,8 @@
= Bug heat on bug page =
-By default the bug heat appears on the bug index page as four flames.
+Bug heat appears on the bug index page:
- >>> def print_heat():
- ... content = find_main_content(anon_browser.contents)
- ... print content.find('a', href='/+help-bugs/bug-heat.html')
>>> anon_browser.open('http://bugs.launchpad.dev/firefox/+bug/1')
- >>> print_heat()
- <a href="/+help-bugs/bug-heat.html" target="help" class="icon"><img src="/@@/bug-heat-0.png" alt="0 out of 4 heat flames" title="Heat: 0" /></a>
-
-But the bugs.heat_ratio_display.disabled feature flag displays it as a number
-instead.
-
- >>> from lp.services.features.testing import FeatureFixture
- >>> with FeatureFixture({'bugs.heat_ratio_display.disabled': 'true'}):
- ... anon_browser.open('http://bugs.launchpad.dev/firefox/+bug/1')
- >>> print_heat()
+ >>> content = find_main_content(anon_browser.contents)
+ >>> print content.find('a', href='/+help-bugs/bug-heat.html')
<a href="/+help-bugs/bug-heat.html" target="help" class="sprite flame">0</a>
-
-
-Packages use their distribution as context when generating flame icons
-for a bug page, since a package of low heat value could be displayed
-with four flames if there are few reported bugs against the package.
-
- >>> from lp.testing import login, logout
- >>> from lp.services.webapp import canonical_url
- >>> from lp.bugs.interfaces.bug import CreateBugParams
- >>> login('foo.bar@xxxxxxxxxxxxx')
- >>> max_heat = 5000.0
- >>> distro = factory.makeDistribution()
- >>> dsp = factory.makeDistributionSourcePackage(distribution=distro)
- >>> person = factory.makePerson()
- >>> bug_params = CreateBugParams(
- ... owner=person,
- ... title="A new bug",
- ... comment="This is a new bug")
- >>> dsp_bug = dsp.createBug(bug_params)
- >>> dsp_bug.setHeat(max_heat/4)
- >>> dsp.setMaxBugHeat(max_heat/4)
- >>> distro.setMaxBugHeat(max_heat)
- >>> logout()
-
- >>> anon_browser.open(canonical_url(dsp_bug))
- >>> print find_main_content(
- ... anon_browser.contents).find('img', src='/@@/bug-heat-0.png')
- <img src="/@@/bug-heat-0.png" alt="0 out of 4 heat flames" title="Heat: 1250" />
=== modified file 'lib/lp/bugs/templates/bugs-listing-table-without-navlinks.pt'
--- lib/lp/bugs/templates/bugs-listing-table-without-navlinks.pt 2012-01-13 08:09:30 +0000
+++ lib/lp/bugs/templates/bugs-listing-table-without-navlinks.pt 2012-02-07 08:14:20 +0000
@@ -70,9 +70,7 @@
tal:condition="context/show_column/date_last_updated|nothing">
2007-11-25</td>
<td tal:condition="context/show_column/heat|nothing"
- tal:content="structure bugtask/bug_heat_html"
- tal:attributes="style python: 'text-align: center' if
- bugtask.center_bug_heat else ''">
+ tal:content="structure bugtask/bug_heat_html">
HEAT</td>
</tr>
</tbody>
=== modified file 'lib/lp/registry/model/distroseries.py'
--- lib/lp/registry/model/distroseries.py 2012-01-18 05:22:41 +0000
+++ lib/lp/registry/model/distroseries.py 2012-02-07 08:14:20 +0000
@@ -483,13 +483,13 @@
def getPrioritizedUnlinkedSourcePackages(self):
"""See `IDistroSeries`.
- The prioritization is a heuristic rule using bug heat,
+ The prioritization is a heuristic rule using bug count,
translatable messages, and the source package release's component.
"""
find_spec = (
SourcePackageName,
SQL("""
- coalesce(total_bug_heat, 0) + coalesce(po_messages, 0) +
+ coalesce(bug_count * 10, 0) + coalesce(po_messages, 0) +
CASE WHEN component = 1 THEN 1000 ELSE 0 END AS score"""),
SQL("coalesce(bug_count, 0) AS bug_count"),
SQL("coalesce(total_messages, 0) AS total_messages"))
@@ -502,7 +502,6 @@
spr.sourcepackagename,
spr.component,
bug_count,
- total_bug_heat,
SUM(POTemplate.messagecount) * %(po_message_weight)s AS po_messages,
SUM(POTemplate.messagecount) AS total_messages
FROM
@@ -532,7 +531,7 @@
Packaging.sourcepackagename = spr.sourcepackagename
AND Packaging.distroseries = spph.distroseries)
GROUP BY
- spr.sourcepackagename, spr.component, bug_count, total_bug_heat
+ spr.sourcepackagename, spr.component, bug_count
) AS spn_info""" % sqlvalues(
po_message_weight=self._current_sourcepackage_po_weight,
distroseries=self,
@@ -571,7 +570,7 @@
Packaging.*,
spr.component AS spr_component,
SourcePackageName.name AS spn_name,
- total_bug_heat,
+ bug_count,
po_messages
FROM %(joins)s
WHERE %(conditions)s
@@ -585,7 +584,7 @@
return IStore(self).using(origin).find(Packaging).order_by('''
(CASE WHEN spr_component = 1 THEN 1000 ELSE 0 END
+ CASE WHEN Product.bugtracker IS NULL
- THEN coalesce(total_bug_heat, 10) ELSE 0 END
+ THEN coalesce(bug_count * 10, 10) ELSE 0 END
+ CASE WHEN ProductSeries.translations_autoimport_mode = 1
THEN coalesce(po_messages, 10) ELSE 0 END
+ CASE WHEN ProductSeries.branch IS NULL THEN 500 ELSE 0 END
=== modified file 'lib/lp/registry/tests/test_distroseries.py'
--- lib/lp/registry/tests/test_distroseries.py 2012-01-01 02:58:52 +0000
+++ lib/lp/registry/tests/test_distroseries.py 2012-02-07 08:14:20 +0000
@@ -321,22 +321,21 @@
self.universe_component = component_set['universe']
self.makeSeriesPackage('normal')
self.makeSeriesPackage('translatable', messages=800)
- hot_package = self.makeSeriesPackage('hot', heat=500)
+ hot_package = self.makeSeriesPackage('hot', bugs=50)
# Create a second SPPH for 'hot', to verify that duplicates are
# eliminated in the queries.
self.factory.makeSourcePackagePublishingHistory(
sourcepackagename=hot_package.sourcepackagename,
distroseries=self.series,
component=self.universe_component, section_name='web')
- self.makeSeriesPackage('hot-translatable', heat=250, messages=1000)
+ self.makeSeriesPackage('hot-translatable', bugs=25, messages=1000)
self.makeSeriesPackage('main', is_main=True)
self.makeSeriesPackage('linked')
self.linkPackage('linked')
transaction.commit()
login(ANONYMOUS)
- def makeSeriesPackage(self, name,
- is_main=False, heat=None, messages=None,
+ def makeSeriesPackage(self, name, is_main=False, bugs=None, messages=None,
is_translations=False):
# Make a published source package.
if is_main:
@@ -353,10 +352,10 @@
component=component, section_name=section)
source_package = self.factory.makeSourcePackage(
sourcepackagename=sourcepackagename, distroseries=self.series)
- if heat is not None:
- bugtask = self.factory.makeBugTask(
- target=source_package, owner=self.user)
- bugtask.bug.setHeat(heat)
+ if bugs is not None:
+ dsp = removeSecurityProxy(
+ source_package.distribution_sourcepackage)
+ dsp.bug_count = bugs
if messages is not None:
template = self.factory.makePOTemplate(
distroseries=self.series, sourcepackagename=sourcepackagename,