Merge lp:~mvo/software-center/dataprovider-desktop-dependency-property into lp:software-center

Proposed by Michael Vogt on 2012-09-14
Status: Merged
Merged at revision: 3185
Proposed branch: lp:~mvo/software-center/dataprovider-desktop-dependency-property
Merge into: lp:software-center
Diff against target: 246 lines (+119/-19)
3 files modified
softwarecenter/db/application.py (+19/-3)
softwarecenter/db/dataprovider.py (+18/-14)
tests/test_dataprovider.py (+82/-2)
To merge this branch: bzr merge lp:~mvo/software-center/dataprovider-desktop-dependency-property
Reviewer Review Type Date Requested Status
Michael Nelson 2012-09-14 Approve on 2012-09-18
Review via email: mp+124462@code.launchpad.net

Description of the change

Small branch for the unity guys

To post a comment you must log in.
Michael Vogt (mvo) wrote :

Setting back to WIP until I get a +1 from the unity people

Michael Vogt (mvo) wrote :

According to pstolowski it crashes with:

(process:24210): unity-applications-daemon-WARNING **: daemon.vala:1263: Failed to get package details for 'application://keepassx.desktop': GDBus.Error:org.freedesktop.DBus.Python.TypeError: Traceback (most recent call last):
  File "/usr/lib/python2.7/dist-packages/dbus/service.py", line 751, in _message_cb
    _method_reply_return(connection, message, method_name, signature, *retval)
  File "/usr/lib/python2.7/dist-packages/dbus/service.py", line 254, in _method_reply_return
    reply.append(signature=signature, *retval)
TypeError: Don't know which D-Bus type to use to encode type "set"

so definitely a issue with the test not catching this.

Michael Vogt (mvo) wrote :

Setting to needs-review based on:
"""
From: Pawel Stolowski
Hi Michael,

Your branch now works fine, thanks a lot for your work!
"""

Michael Nelson (michael.nelson) wrote :

06:47 < mvo> I wonder if I could get a quick review for https://code.launchpad.net/~mvo/software-center/dataprovider-desktop-dependency-property/+merge/124462 to merge/upload it in before the b2 freeze (which will probably start around noon today)
06:47 * noodles looks
06:49 < noodles> mvo: why do you need lines 17-19 when you've got lines 23?
06:49 < noodles> mvo: ah, nm.
06:49 < noodles> I see (I'd reversed the removed/added)
06:52 < noodles> mvo: looks great. I'm assuming you didn't mean to leave 183-184 in the diff? But whatever - see what you think.
06:52 * noodles adds +1.
06:53 < noodles> mvo: also, it'd be pretty easy to update the two tests that you've already touched there to actually test values when there's a set, or empty list or empty dict? Just a thought.

review: Approve
3179. By Michael Vogt on 2012-09-18

improve tests to actually cover AppDetails.as_dbus_property_dict() explicitely

3180. By Michael Vogt on 2012-09-18

trivial docstring updates

3181. By Michael Vogt on 2012-09-18

add real dbus bus test

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'softwarecenter/db/application.py'
2--- softwarecenter/db/application.py 2012-09-14 09:19:09 +0000
3+++ softwarecenter/db/application.py 2012-09-18 08:18:20 +0000
4@@ -261,7 +261,7 @@
5 raise ValueError("pkg '%s' has not archive_suite '%s'" % (
6 pkg, archive_suite))
7
8- def as_property_dict(self):
9+ def as_dbus_property_dict(self):
10 """ return all properties as a dict with name/value """
11 import inspect
12 properties = {}
13@@ -270,12 +270,19 @@
14 for name, value in inspect.getmembers(self):
15 if name.startswith("_") or callable(value) or name in NOT_EXPOSE:
16 continue
17+ # dbus does not like sets
18+ if isinstance(value, set):
19+ value = list(value)
20 # make sure that the type can be encoded
21 if not type(value) in [
22- list, dict, tuple, set, basestring, int, float, bool, None]:
23+ list, dict, tuple, basestring, int, float, bool, None]:
24 value = "%s" % value
25+ # dbus does not like empty dicts/lists
26+ if isinstance(value, dict) or isinstance(value, list):
27+ if len(value) == 0:
28+ value = ""
29 # and set it
30- properties[name] = value or ""
31+ properties[name] = value
32 return properties
33
34 @property
35@@ -408,6 +415,15 @@
36 return self._history.get_installed_date(self.pkgname)
37
38 @property
39+ def is_desktop_dependency(self):
40+ if self._pkg:
41+ depends = self._cache.get_packages_removed_on_remove(
42+ self._pkg)
43+ if "ubuntu-desktop" in depends:
44+ return True
45+ return False
46+
47+ @property
48 def purchase_date(self):
49 if self._doc:
50 return self._doc.get_value(XapianValues.PURCHASED_DATE)
51
52=== modified file 'softwarecenter/db/dataprovider.py'
53--- softwarecenter/db/dataprovider.py 2012-09-14 07:12:33 +0000
54+++ softwarecenter/db/dataprovider.py 2012-09-18 08:18:20 +0000
55@@ -35,20 +35,24 @@
56 from softwarecenter.db.utils import run_software_center_agent
57
58 # To test, run with e.g.
59-# dbus-send --session --type=method_call \
60-# --dest=com.ubuntu.SoftwareCenterDataProvider --print-reply \
61-# /com/ubuntu/SoftwareCenterDataProvider
62-# com.ubuntu.SoftwareCenterDataProvider.GetAppDetails string:"" string:"apt"
63-#
64+"""
65+dbus-send --session --type=method_call \
66+ --dest=com.ubuntu.SoftwareCenterDataProvider --print-reply \
67+ /com/ubuntu/SoftwareCenterDataProvider \
68+ com.ubuntu.SoftwareCenterDataProvider.GetAppDetails string:"" string:"apt"
69+"""
70
71
72 LOG = logging.getLogger(__file__)
73
74+DBUS_BUS_NAME = 'com.ubuntu.SoftwareCenterDataProvider'
75+DBUS_DATA_PROVIDER_IFACE = 'com.ubuntu.SoftwareCenterDataProvider'
76+DBUS_DATA_PROVIDER_PATH = '/com/ubuntu/SoftwareCenterDataProvider'
77+
78
79 class SoftwareCenterDataProvider(dbus.service.Object):
80
81- def __init__(self, bus_name,
82- object_path='/com/ubuntu/SoftwareCenterDataProvider'):
83+ def __init__(self, bus_name, object_path=DBUS_DATA_PROVIDER_PATH):
84 dbus.service.Object.__init__(self, bus_name, object_path)
85 self.bus_name = bus_name
86 # the database
87@@ -67,14 +71,14 @@
88 """ stop the dbus controller and remove from the bus """
89 self.remove_from_connection()
90
91- @dbus.service.method('com.ubuntu.SoftwareCenterDataProvider',
92+ @dbus.service.method(DBUS_DATA_PROVIDER_IFACE,
93 in_signature='ss', out_signature='a{sv}')
94 def GetAppDetails(self, appname, pkgname):
95 LOG.debug("GetAppDetails() called with ('%s', '%s')" % (
96 appname, pkgname))
97 app = Application(appname, pkgname)
98 appdetails = app.get_details(self.db)
99- return appdetails.as_property_dict()
100+ return appdetails.as_dbus_property_dict()
101
102 @dbus.service.method('com.ubuntu.SoftwareCenterDataProvider',
103 in_signature='', out_signature='as')
104@@ -82,7 +86,7 @@
105 LOG.debug("GetAvailableCategories() called")
106 return [cat.name for cat in self.categories]
107
108- @dbus.service.method('com.ubuntu.SoftwareCenterDataProvider',
109+ @dbus.service.method(DBUS_DATA_PROVIDER_IFACE,
110 in_signature='s', out_signature='as')
111 def GetAvailableSubcategories(self, category_name):
112 LOG.debug("GetAvailableSubcategories() called")
113@@ -105,10 +109,10 @@
114 return result
115
116
117-def dbus_main():
118- bus = dbus.SessionBus()
119- bus_name = dbus.service.BusName(
120- 'com.ubuntu.SoftwareCenterDataProvider', bus)
121+def dbus_main(bus=None):
122+ if bus is None:
123+ bus = dbus.SessionBus()
124+ bus_name = dbus.service.BusName(DBUS_BUS_NAME, bus)
125 data_provider = SoftwareCenterDataProvider(bus_name)
126 data_provider # pyflakes
127
128
129=== modified file 'tests/test_dataprovider.py'
130--- tests/test_dataprovider.py 2012-09-12 12:41:05 +0000
131+++ tests/test_dataprovider.py 2012-09-18 08:18:20 +0000
132@@ -1,7 +1,14 @@
133
134 import dbus
135+import time
136 import unittest
137
138+from dbus.mainloop.glib import DBusGMainLoop
139+DBusGMainLoop(set_as_default=True)
140+
141+from multiprocessing import Process
142+from mock import Mock
143+
144 from tests.utils import (
145 kill_process,
146 setup_test_env,
147@@ -9,11 +16,76 @@
148 )
149 setup_test_env()
150
151-from softwarecenter.db.dataprovider import SoftwareCenterDataProvider
152-
153+from softwarecenter.db.application import AppDetails
154+from softwarecenter.db.dataprovider import (
155+ SoftwareCenterDataProvider,
156+ dbus_main,
157+ DBUS_BUS_NAME,
158+ DBUS_DATA_PROVIDER_IFACE,
159+ DBUS_DATA_PROVIDER_PATH,
160+ )
161+
162+
163+class DbusForRealTestCase(unittest.TestCase):
164+ """Test the dataprovider over a real dbus bus"""
165+
166+ @classmethod
167+ def setUpClass(cls):
168+ cls.p = Process(target=dbus_main)
169+ cls.p.start()
170+ time.sleep(1)
171+
172+ @classmethod
173+ def tearDown(cls):
174+ cls.p.terminate()
175+
176+ def setUp(self):
177+ bus = dbus.SessionBus()
178+ obj = bus.get_object(bus_name=DBUS_BUS_NAME,
179+ object_path=DBUS_DATA_PROVIDER_PATH,
180+ follow_name_owner_changes=True)
181+ self.proxy = dbus.Interface(object=obj,
182+ dbus_interface=DBUS_DATA_PROVIDER_IFACE)
183+
184+ def test_dbus_for_real(self):
185+ result = self.proxy.GetAppDetails("", "gedit")
186+ self.assertEqual(result["pkgname"], "gedit")
187+
188+
189+class PropertyDictExceptionsTestCase(unittest.TestCase):
190+ """Test that the exceptions in the AppDetails for the dbus properties
191+ are handled correctly
192+ """
193+
194+ def setUp(self):
195+ self.mock_app_details = Mock(AppDetails)
196+
197+ def test_simple(self):
198+ self.mock_app_details.name = "fake-app"
199+ properties = AppDetails.as_dbus_property_dict(self.mock_app_details)
200+ self.assertEqual(properties["name"], "fake-app")
201+
202+ def test_empty_dict_set(self):
203+ self.mock_app_details.empty_set = set()
204+ self.mock_app_details.empty_dict = {}
205+ properties = AppDetails.as_dbus_property_dict(self.mock_app_details)
206+ self.assertEqual(properties["empty_set"], "")
207+ self.assertEqual(properties["empty_dict"], "")
208+
209+ def test_normal_dict(self):
210+ self.mock_app_details.non_empty_dict = { "moo" : "bar" }
211+ properties = AppDetails.as_dbus_property_dict(self.mock_app_details)
212+ self.assertEqual(properties["non_empty_dict"], { "moo" : "bar" })
213+
214+ def test_normal_set(self):
215+ self.mock_app_details.non_empty_set = set(["foo", "bar", "baz"])
216+ properties = AppDetails.as_dbus_property_dict(self.mock_app_details)
217+ self.assertEqual(
218+ sorted(properties["non_empty_set"]), ["bar", "baz", "foo"])
219
220
221 class DataProviderTestCase(unittest.TestCase):
222+ """ Test the methods of the dataprovider """
223
224 @classmethod
225 def setUpClass(cls):
226@@ -41,6 +113,11 @@
227 self.assertEqual(result["pkgname"], "gedit")
228 self.assertEqual(result["price"], "Free")
229 self.assertEqual(result["raw_price"], "")
230+ self.assertEqual(result["is_desktop_dependency"], True)
231+
232+ def test_get_details_non_desktop(self):
233+ result = self.provider.GetAppDetails("", "apache2")
234+ self.assertEqual(result["is_desktop_dependency"], False)
235
236 # get available categories/subcategories
237 def test_get_categories(self):
238@@ -69,5 +146,8 @@
239 result = self.provider.GetItemsForCategory(u"What\u2019s New")
240 self.assertEqual(len(result), 20)
241
242+
243 if __name__ == "__main__":
244+ #import logging
245+ #logging.basicConfig(level=logging.DEBUG)
246 unittest.main()

Subscribers

People subscribed via source and target branches