Reviewers: mp+195991_code.launchpad.net,
Message: Please take a look.
Description: Add download stats to bundle API call.
https://code.launchpad.net/~bac/charmworld/add-stats-to-api/+merge/195991
(do not edit description out of merge proposal)
Please review this at https://codereview.appspot.com/29850043/
Affected files (+58, -31 lines): A [revision details] M charmworld/views/api/__init__.py M charmworld/views/bundles.py M charmworld/views/tests/test_api.py M charmworld/views/tests/test_bundles.py M charmworld/views/utils.py
Index: [revision details] === added file '[revision details]' --- [revision details] 2012-01-01 00:00:00 +0000 +++ [revision details] 2012-01-01 00:00:00 +0000 @@ -0,0 +1,2 @@ +Old revision: tarmac-20131119203355-yu8j8hqzmyv8f9d1 +New revision: <email address hidden>
Index: charmworld/views/bundles.py === modified file 'charmworld/views/bundles.py' --- charmworld/views/bundles.py 2013-11-13 17:40:11 +0000 +++ charmworld/views/bundles.py 2013-11-20 18:08:03 +0000 @@ -8,12 +8,8 @@ from charmworld import cached_view_config from charmworld.models import ( Bundle, - DatedMetricSource, -) -from charmworld.utils import ( - build_metric_key, - utc_today, -) +) +from charmworld.views.utils import get_bundle_downloads from charmworld.views.api import json_response from charmworld.views.helpers import ( find_bundle, @@ -29,17 +25,6 @@ SUPPORTED_README_EXTS = ('', '.txt', '.md', '.markdown', '.mkd', '.rst')
-class Statistics: - """A template helper that wraps a DatedMetric instance.""" - - def __init__(self, metric, day=None): - day = day or utc_today() - self.past_7_days = metric.get_range_total(7, day) - self.past_30_days = metric.get_range_total(30, day) - self.past_half_year = metric.get_range_total(365 / 2, day) - self.total = metric.get_total() - - class BundleDetail(Bundle):
service_keys = ( @@ -113,11 +98,8 @@
def _bundle_view(request, bundle): - source = DatedMetricSource.from_db(request.db) - metric_key = build_metric_key('deployments', bundle.id) - metric = source.retrieve(metric_key, create=True) + downloads = get_bundle_downloads(request.db, bundle.id) bundle = BundleDetail(dict(bundle)) - downloads = Statistics(metric) try: is_owner = bool((request.user is not None) and (request.user.nickname == bundle.owner))
Index: charmworld/views/utils.py === modified file 'charmworld/views/utils.py' --- charmworld/views/utils.py 2013-10-20 19:09:02 +0000 +++ charmworld/views/utils.py 2013-11-20 17:16:29 +0000 @@ -1,5 +1,10 @@ import json from webob import Response +from charmworld.models import DatedMetricSource +from charmworld.utils import ( + build_metric_key, + utc_today, +)
def json_response(status, value, headers=[]): @@ -31,3 +36,22 @@
('Access-Control-Allow-Headers', 'X-Requested-With'), ] + headers, status_code=status) + + +class Statistics: + """A template helper that wraps a DatedMetric instance.""" + + def __init__(self, metric, day=None): + day = day or utc_today() + self.past_7_days = metric.get_range_total(7, day) + self.past_30_days = metric.get_range_total(30, day) + self.past_half_year = metric.get_range_total(365 / 2, day) + self.total = metric.get_total() + + +def get_bundle_downloads(db, bundle_id): + """Return a Statistics object for the bundle's downloads.""" + source = DatedMetricSource.from_db(db) + metric_key = build_metric_key('deployments', bundle_id) + metric = source.retrieve(metric_key, create=True) + return Statistics(metric)
Index: charmworld/views/api/__init__.py === modified file 'charmworld/views/api/__init__.py' --- charmworld/views/api/__init__.py 2013-11-13 17:40:11 +0000 +++ charmworld/views/api/__init__.py 2013-11-20 18:08:03 +0000 @@ -45,7 +45,10 @@ timestamp, ) from charmworld.views.api.proof import proof_deployer -from charmworld.views.utils import json_response +from charmworld.views.utils import ( + get_bundle_downloads, + json_response, +)
@view_config(route_name="search-json-obsolete") @@ -428,6 +431,12 @@ owner=bundle_dict['owner'], rev=bundle_dict['basket_revision'], ) + + # Add in download data. + downloads = get_bundle_downloads(db, bundle.id) + bundle_dict['downloads'] = downloads.total + bundle_dict['downloads_in_past_30_days'] = downloads.past_30_days + service_data = bundle_dict.get('data') # Now load the charm information we require for the services in the # bundle.
Index: charmworld/views/tests/test_api.py === modified file 'charmworld/views/tests/test_api.py' --- charmworld/views/tests/test_api.py 2013-11-08 19:14:29 +0000 +++ charmworld/views/tests/test_api.py 2013-11-20 18:08:03 +0000 @@ -786,23 +786,29 @@ response = self.get_response('bundle', 'byobu/bat') self.assertEqual(200, response.status_code)
- def test_results_match(self): + def test_results_are_correct(self): self.enable_routes() # Make the charm that we'll use as a service. - _id, charm = factory.makeCharm( - self.db, - description='' - ) + _id, charm = factory.makeCharm(self.db, description='') services = { u'charm': { u'branch': charm['branch_spec'], - u'charm': charm['name'] + u'charm': charm['name'], } } self.makeBundle( name='bat', owner='bac', basket_with_rev='byobu/4', services=services) - response = self.get_response('bundle', '~bac/byobu/4/bat') + + class FakeObject(object): + pass + + fake_stat = FakeObject + fake_stat.total = 10 + fake_stat.past_30_days = 5 + mock_path = 'charmworld.views.api.get_bundle_downloads' + with patch(mock_path, return_value=fake_stat): + response = self.get_response('bundle', '~bac/byobu/4/bat') self.assertEqual(200, response.status_code) deployer_url = u'http://example.com/bundle/%7Ebac/byobu/4/bat/json' self.assertEqual( @@ -812,7 +818,7 @@ u'basket_revision': 4, u'branch_deleted': False, u'charm_metadata': { - u'charm': self.api_class._format_charm(Charm(charm)) + u'charm': self.api_class._format_charm(Charm(charm)), }, u'data': { u'series': u'precise', @@ -837,6 +843,8 @@ u'promulgated': False, u'title': u'', u'deployer_file_url': deployer_url, + u'downloads': 10, + u'downloads_in_past_30_days': 5, })
def test_extracting_bundle_id_with_trailing_full_id(self):
Index: charmworld/views/tests/test_bundles.py === modified file 'charmworld/views/tests/test_bundles.py' --- charmworld/views/tests/test_bundles.py 2013-11-13 17:40:11 +0000 +++ charmworld/views/tests/test_bundles.py 2013-11-20 18:08:03 +0000 @@ -17,12 +17,14 @@ ) from charmworld.views.bundles import ( BundleDetail, - Statistics, find_bundle, official_bundle_json, personal_bundle, personal_bundle_json, ) +from charmworld.views.utils import ( + Statistics, +)
class TestBundleDetail(ViewTestBase):
« Back to merge proposal
Reviewers: mp+195991_ code.launchpad. net,
Message:
Please take a look.
Description:
Add download stats to bundle API call.
https:/ /code.launchpad .net/~bac/ charmworld/ add-stats- to-api/ +merge/ 195991
(do not edit description out of merge proposal)
Please review this at https:/ /codereview. appspot. com/29850043/
Affected files (+58, -31 lines): views/api/ __init_ _.py views/bundles. py views/tests/ test_api. py views/tests/ test_bundles. py views/utils. py
A [revision details]
M charmworld/
M charmworld/
M charmworld/
M charmworld/
M charmworld/
Index: [revision details] 20131119203355- yu8j8hqzmyv8f9d 1
=== added file '[revision details]'
--- [revision details] 2012-01-01 00:00:00 +0000
+++ [revision details] 2012-01-01 00:00:00 +0000
@@ -0,0 +1,2 @@
+Old revision: tarmac-
+New revision: <email address hidden>
Index: charmworld/ views/bundles. py views/bundles. py' views/bundles. py 2013-11-13 17:40:11 +0000 views/bundles. py 2013-11-20 18:08:03 +0000 views.utils import get_bundle_ downloads views.api import json_response views.helpers import ( README_ EXTS = ('', '.txt', '.md', '.markdown', '.mkd', '.rst')
=== modified file 'charmworld/
--- charmworld/
+++ charmworld/
@@ -8,12 +8,8 @@
from charmworld import cached_view_config
from charmworld.models import (
Bundle,
- DatedMetricSource,
-)
-from charmworld.utils import (
- build_metric_key,
- utc_today,
-)
+)
+from charmworld.
from charmworld.
from charmworld.
find_bundle,
@@ -29,17 +25,6 @@
SUPPORTED_
-class Statistics: get_range_ total(7, day) get_range_ total(30, day) get_range_ total(365 / 2, day) Bundle) :
- """A template helper that wraps a DatedMetric instance."""
-
- def __init__(self, metric, day=None):
- day = day or utc_today()
- self.past_7_days = metric.
- self.past_30_days = metric.
- self.past_half_year = metric.
- self.total = metric.get_total()
-
-
class BundleDetail(
service_keys = (
@@ -113,11 +98,8 @@
def _bundle_ view(request, bundle): ce.from_ db(request. db) key('deployment s', bundle.id) retrieve( metric_ key, create=True) downloads( request. db, bundle.id) dict(bundle) )
(request. user.nickname == bundle.owner))
- source = DatedMetricSour
- metric_key = build_metric_
- metric = source.
+ downloads = get_bundle_
bundle = BundleDetail(
- downloads = Statistics(metric)
try:
is_owner = bool((request.user is not None) and
Index: charmworld/ views/utils. py views/utils. py' views/utils. py 2013-10-20 19:09:02 +0000 views/utils. py 2013-11-20 17:16:29 +0000
=== modified file 'charmworld/
--- charmworld/
+++ charmworld/
@@ -1,5 +1,10 @@
import json
from webob import Response
+from charmworld.models import DatedMetricSource
+from charmworld.utils import (
+ build_metric_key,
+ utc_today,
+)
def json_response( status, value, headers=[]):
@@ -31,3 +36,22 @@
('Access- Control- Allow-Headers' , 'X-Requested- With'),
] + headers,
status_ code=status) get_range_ total(7, day) get_range_ total(30, day) get_range_ total(365 / 2, day) downloads( db, bundle_id): ce.from_ db(db) key('deployment s', bundle_id) retrieve( metric_ key, create=True)
+
+
+class Statistics:
+ """A template helper that wraps a DatedMetric instance."""
+
+ def __init__(self, metric, day=None):
+ day = day or utc_today()
+ self.past_7_days = metric.
+ self.past_30_days = metric.
+ self.past_half_year = metric.
+ self.total = metric.get_total()
+
+
+def get_bundle_
+ """Return a Statistics object for the bundle's downloads."""
+ source = DatedMetricSour
+ metric_key = build_metric_
+ metric = source.
+ return Statistics(metric)
Index: charmworld/ views/api/ __init_ _.py views/api/ __init_ _.py' views/api/ __init_ _.py 2013-11-13 17:40:11 +0000 views/api/ __init_ _.py 2013-11-20 18:08:03 +0000 views.api. proof import proof_deployer views.utils import json_response views.utils import ( downloads,
=== modified file 'charmworld/
--- charmworld/
+++ charmworld/
@@ -45,7 +45,10 @@
timestamp,
)
from charmworld.
-from charmworld.
+from charmworld.
+ get_bundle_
+ json_response,
+)
@view_ config( route_name= "search- json-obsolete" )
owner=bundle_ dict['owner' ],
rev=bundle_ dict['basket_ revision' ], downloads( db, bundle.id) dict['downloads '] = downloads.total dict['downloads _in_past_ 30_days' ] = downloads. past_30_ days
service_ data = bundle_ dict.get( 'data')
@@ -428,6 +431,12 @@
)
+
+ # Add in download data.
+ downloads = get_bundle_
+ bundle_
+ bundle_
+
# Now load the charm information we require for the services in the
# bundle.
Index: charmworld/ views/tests/ test_api. py views/tests/ test_api. py' views/tests/ test_api. py 2013-11-08 19:14:29 +0000 views/tests/ test_api. py 2013-11-20 18:08:03 +0000 response( 'bundle' , 'byobu/bat')
self. assertEqual( 200, response. status_ code)
=== modified file 'charmworld/
--- charmworld/
+++ charmworld/
@@ -786,23 +786,29 @@
response = self.get_
- def test_results_ match(self) : are_correct( self):
self. enable_ routes( ) makeCharm( self.db, description='')
u'charm' : {
u'branch' : charm[' branch_ spec'],
self. makeBundle(
name='bat' , owner='bac',
basket_ with_rev= 'byobu/ 4', services=services) response( 'bundle' , '~bac/byobu/4/bat') past_30_ days = 5 views.api. get_bundle_ downloads' value=fake_ stat): response( 'bundle' , '~bac/byobu/4/bat')
self. assertEqual( 200, response. status_ code)
deployer_ url = u'http:// example. com/bundle/ %7Ebac/ byobu/4/ bat/json'
self. assertEqual(
u'basket_ revision' : 4,
u'branch_ deleted' : False,
u'charm_ metadata' : { class._ format_ charm(Charm( charm)) class._ format_ charm(Charm( charm)) ,
},
u'data' : {
u'series' : u'precise',
u'promulgat ed': False,
u'title' : u'',
u'deployer_ file_url' : deployer_url, in_past_ 30_days' : 5,
+ def test_results_
# Make the charm that we'll use as a service.
- _id, charm = factory.makeCharm(
- self.db,
- description=''
- )
+ _id, charm = factory.
services = {
- u'charm': charm['name']
+ u'charm': charm['name'],
}
}
- response = self.get_
+
+ class FakeObject(object):
+ pass
+
+ fake_stat = FakeObject
+ fake_stat.total = 10
+ fake_stat.
+ mock_path = 'charmworld.
+ with patch(mock_path, return_
+ response = self.get_
@@ -812,7 +818,7 @@
- u'charm': self.api_
+ u'charm': self.api_
@@ -837,6 +843,8 @@
+ u'downloads': 10,
+ u'downloads_
})
def test_extracting _bundle_ id_with_ trailing_ full_id( self):
Index: charmworld/ views/tests/ test_bundles. py views/tests/ test_bundles. py' views/tests/ test_bundles. py 2013-11-13 17:40:11 +0000 views/tests/ test_bundles. py 2013-11-20 18:08:03 +0000 views.bundles import ( bundle_ json, bundle, bundle_ json, views.utils import (
=== modified file 'charmworld/
--- charmworld/
+++ charmworld/
@@ -17,12 +17,14 @@
)
from charmworld.
BundleDetail,
- Statistics,
find_bundle,
official_
personal_
personal_
)
+from charmworld.
+ Statistics,
+)
class TestBundleDetai l(ViewTestBase) :