Merge lp:~jamesodhunt/python-apt/test-for-size_to_str into lp:~mvo/python-apt/debian-sid-mirrored

Proposed by James Hunt
Status: Needs review
Proposed branch: lp:~jamesodhunt/python-apt/test-for-size_to_str
Merge into: lp:~mvo/python-apt/debian-sid-mirrored
Diff against target: 218 lines (+155/-15)
4 files modified
debian/changelog (+12/-0)
python/cache.cc (+1/-1)
python/progress.cc (+31/-14)
tests/test_apt_pkg.py (+111/-0)
To merge this branch: bzr merge lp:~jamesodhunt/python-apt/test-for-size_to_str
Reviewer Review Type Date Requested Status
Michael Vogt Needs Information
Review via email: mp+127435@code.launchpad.net

Description of the change

  * python/progress.cc:
    - setattr(): Check return from Py_BuildValue().
    - PyFetchProgress:Pulse(): Check return from setattr().
  * tests/test_apt_pkg.py: New test, currently only for
    size_to_str() method.

To post a comment you must log in.
Revision history for this message
Michael Vogt (mvo) wrote :

Hi, thanks for your branch. Its great to see test improvements/code fixes!

I have some questions:
- setattr() is used a bunch of times with no checking of the return value - should it be checked there as well?
- under what circumstances can setattr() fail, i.e. is this branch a result of a specific bug?

Its great that the test is added, it seems to be unreleated to the changes for PyFetchProgress::Pulse() and its also currently working even without the pulse changes. Is it addressing a specific bug? Or just there to have better test coverage (which is welcome of course :)

As for the test itself, a bit of nitpicking:
- the name "data" in test_apt_pkg.py could probably be something more meaningful for the time when more tests get added.
- I would slightly prefer to have a SizeToStrTestCase() and multiple methods like test_raises_for_string(), test_from_data(), test_raises_on_none()

Sorry for the relatively long review, I went through the code-review school of launchpad recently ;) Happy to talk to you about any of the points I mentioned or help with resolving them.

Thanks,
 Michael

review: Needs Information
Revision history for this message
Michael Vogt (mvo) wrote :

One more thing, returning "false" from PyFetchProgress::Pulse() will result in the fetching getting cancelled (see the comment some lines down in ::Pulse). I'm not sure this is desired behavior, but then I don't know yet when setattr() may fail so maybe it is :)

Revision history for this message
Barry Warsaw (barry) wrote :

A few additional comments. To fix bug 1030278 (sorry about crossing signals on that one!) I added a test specifically for that bug, which of course fails without the patch. I think I called it test_lp1030278.py modeled after another LP bug test.

I would suggest moving that into test_apt_pkg.py. Maybe you can combine that with grabbing my patch for the bug (only applied to the ubuntu package) and combining it with this merge proposal?

Revision history for this message
Barry Warsaw (barry) wrote :

Note that if you wanted to be strict about it (generally not a bad idea when dealing with the Python C API), setattr() in progress.cc should really be checking the return value of Py_BuildValue() too; if that returns NULL, then setattr() should return 0 before calling PyObject_SetAttrString().

As for checking the return value of setattr(), that's probably a good idea to do. The alternative is to be optimistic, don't check the return values, and then do a blanket check of PyErr_Occurred() to see if any of them failed. In some sense, it's not as safe, but practically speaking it's probably good enough, especially since if any of them fail, you're probably in trouble. It's probably not a good idea to just let exceptions pass unchecked - that was one of the fundamental problems with LP: #1030278.

Revision history for this message
Michael Vogt (mvo) wrote :

On Tue, Oct 02, 2012 at 02:20:24PM -0000, Barry Warsaw wrote:
> A few additional comments. To fix bug 1030278 (sorry about crossing signals on that one!) I added a test specifically for that bug, which of course fails without the patch. I think I called it test_lp1030278.py modeled after another LP bug test.
>
> I would suggest moving that into test_apt_pkg.py. Maybe you can combine that with grabbing my patch for the bug (only applied to the ubuntu package) and combining it with this merge proposal?

Thanks for this suggestion, I had a similar thought :)

I merge them into the debian-sid branch now and put them there as
"test_size_to_str.py" for now.

Thanks!
 Michael

Unmerged revisions

620. By James Hunt

tests/test_apt_pkg.py: New test, currently only for
size_to_str() method.

619. By James Hunt

* python/progress.cc:
  - setattr(): Check return from Py_BuildValue().
  - PyFetchProgress:Pulse(): Check return from setattr().

618. By James Hunt

python/cache.cc: PkgCacheGetIsMultiArch(): Return calculated
value rather than a random one.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'debian/changelog'
2--- debian/changelog 2012-06-22 08:37:31 +0000
3+++ debian/changelog 2012-10-02 08:29:26 +0000
4@@ -1,3 +1,15 @@
5+python-apt (0.8.5ubuntu3) UNRELEASED; urgency=low
6+
7+ * python/cache.cc: PkgCacheGetIsMultiArch(): Return calculated
8+ value rather than a random one.
9+ * python/progress.cc:
10+ - setattr(): Check return from Py_BuildValue().
11+ - PyFetchProgress:Pulse(): Check return from setattr().
12+ * tests/test_apt_pkg.py: New test, currently only for
13+ size_to_str() method.
14+
15+ -- James Hunt <james.hunt@ubuntu.com> Tue, 02 Oct 2012 09:25:45 +0100
16+
17 python-apt (0.8.5) unstable; urgency=low
18
19 [ Michael Vogt ]
20
21=== modified file 'python/cache.cc'
22--- python/cache.cc 2012-04-17 19:17:10 +0000
23+++ python/cache.cc 2012-10-02 08:29:26 +0000
24@@ -286,7 +286,7 @@
25
26 static PyObject *PkgCacheGetIsMultiArch(PyObject *Self, void*) {
27 pkgCache *Cache = GetCpp<pkgCache *>(Self);
28- PyBool_FromLong(Cache->MultiArchCache());
29+ return PyBool_FromLong(Cache->MultiArchCache());
30 }
31
32 static PyGetSetDef PkgCacheGetSet[] = {
33
34=== modified file 'python/progress.cc'
35--- python/progress.cc 2011-11-10 16:20:58 +0000
36+++ python/progress.cc 2012-10-02 08:29:26 +0000
37@@ -28,6 +28,8 @@
38 if (!object)
39 return false;
40 PyObject *value = Py_BuildValue(fmt, arg);
41+ if (! value)
42+ return false;
43
44 int result = PyObject_SetAttrString(object, attr, value);
45 Py_DECREF(value);
46@@ -280,14 +282,22 @@
47 return false;
48 }
49
50- setattr(callbackInst, "last_bytes", "N", MkPyNumber(LastBytes));
51- setattr(callbackInst, "current_cps", "N", MkPyNumber(CurrentCPS));
52- setattr(callbackInst, "current_bytes", "N", MkPyNumber(CurrentBytes));
53- setattr(callbackInst, "total_bytes", "N", MkPyNumber(TotalBytes));
54- setattr(callbackInst, "fetched_bytes", "N", MkPyNumber(FetchedBytes));
55- setattr(callbackInst, "elapsed_time", "N", MkPyNumber(ElapsedTime));
56- setattr(callbackInst, "current_items", "N", MkPyNumber(CurrentItems));
57- setattr(callbackInst, "total_items", "N", MkPyNumber(TotalItems));
58+ if (! setattr(callbackInst, "last_bytes", "N", MkPyNumber(LastBytes)))
59+ return false;
60+ if (! setattr(callbackInst, "current_cps", "N", MkPyNumber(CurrentCPS)))
61+ return false;
62+ if (! setattr(callbackInst, "current_bytes", "N", MkPyNumber(CurrentBytes)))
63+ return false;
64+ if (! setattr(callbackInst, "total_bytes", "N", MkPyNumber(TotalBytes)))
65+ return false;
66+ if (! setattr(callbackInst, "fetched_bytes", "N", MkPyNumber(FetchedBytes)))
67+ return false;
68+ if (! setattr(callbackInst, "elapsed_time", "N", MkPyNumber(ElapsedTime)))
69+ return false;
70+ if (! setattr(callbackInst, "current_items", "N", MkPyNumber(CurrentItems)))
71+ return false;
72+ if (! setattr(callbackInst, "total_items", "N", MkPyNumber(TotalItems)))
73+ return false;
74
75 // New style
76 if (!PyObject_HasAttrString(callbackInst, "updateStatus")) {
77@@ -313,12 +323,19 @@
78 return true;
79 }
80 #ifdef COMPAT_0_7
81- setattr(callbackInst, "currentCPS", "N", MkPyNumber(CurrentCPS));
82- setattr(callbackInst, "currentBytes", "N", MkPyNumber(CurrentBytes));
83- setattr(callbackInst, "totalBytes", "N", MkPyNumber(TotalBytes));
84- setattr(callbackInst, "fetchedBytes", "N", MkPyNumber(FetchedBytes));
85- setattr(callbackInst, "currentItems", "N", MkPyNumber(CurrentItems));
86- setattr(callbackInst, "totalItems", "N", MkPyNumber(TotalItems));
87+ if (! setattr(callbackInst, "currentCPS", "N", MkPyNumber(CurrentCPS)))
88+ return false;
89+ if (! setattr(callbackInst, "currentBytes", "N", MkPyNumber(CurrentBytes)))
90+ return false;
91+ if (! setattr(callbackInst, "totalBytes", "N", MkPyNumber(TotalBytes)))
92+ return false;
93+ if (! setattr(callbackInst, "fetchedBytes", "N", MkPyNumber(FetchedBytes)))
94+ return false;
95+ if (! setattr(callbackInst, "currentItems", "N", MkPyNumber(CurrentItems)))
96+ return false;
97+ if (! setattr(callbackInst, "totalItems", "N", MkPyNumber(TotalItems)))
98+ return false;
99+
100 // Go through the list of items and add active items to the
101 // activeItems vector.
102 map<pkgAcquire::Worker *, pkgAcquire::ItemDesc *> activeItemMap;
103
104=== added file 'tests/test_apt_pkg.py'
105--- tests/test_apt_pkg.py 1970-01-01 00:00:00 +0000
106+++ tests/test_apt_pkg.py 2012-10-02 08:29:26 +0000
107@@ -0,0 +1,111 @@
108+#!/usr/bin/env python
109+
110+import sys
111+import unittest
112+
113+import apt_pkg
114+
115+data = {
116+ # XXX: note the trailing spaces for some of these entries!
117+ 10 ** 1 : "10 ",
118+ 10 ** 2 : "100 ",
119+ 10 ** 3 : "1000 ",
120+ 10 ** 4 : "10.0 k",
121+ 10 ** 5 : "100 k",
122+ 10 ** 6 : "1000 k",
123+ 10 ** 7 : "10.0 M",
124+ 10 ** 8 : "100 M",
125+ 10 ** 9 : "1000 M",
126+ 10 ** 10 : "10.0 G",
127+ 10 ** 11 : "100 G",
128+ 10 ** 12 : "1000 G",
129+ 10 ** 13 : "10.0 T",
130+ 10 ** 14 : "100 T",
131+ 10 ** 15 : "1000 T",
132+ 10 ** 16 : "10.0 P",
133+ 10 ** 17 : "100 P",
134+ 10 ** 18 : "1000 P",
135+ 10 ** 19 : "10.0 E",
136+ 10 ** 20 : "100 E",
137+ 10 ** 21 : "1000 E",
138+ 10 ** 22 : "10.0 Z",
139+ 10 ** 23 : "100.0 Z",
140+ 10 ** 24 : "1000 Z",
141+ 10 ** 25 : "10.0 Y",
142+ 10 ** 26 : "100 Y",
143+ 10 ** 27 : "1000 Y",
144+
145+ # That's our limit :)
146+ 10 ** 28 : "10000 Y",
147+
148+ 0 : "0 ",
149+ 1 : "1 ",
150+ 1024 : "1024 ",
151+ 10240 : "10.2 k",
152+ 102400 : "102 k",
153+ 1024000 : "1024 k",
154+ 10240000 : "10.2 M",
155+ 102400000 : "102 M",
156+ 2147483647 : "2147 M",
157+ 2147483648 : "2147 M",
158+ 1024000000 : "1024 M",
159+ 10240000000 : "10.2 G",
160+
161+ 9 : "9 ",
162+ 99 : "99 ",
163+ 999 : "999 ",
164+ 9999 : "9999 ",
165+ 99999 : "100.0 k",
166+ 999999 : "1000 k",
167+ 9999999 : "10000 k",
168+ 99999999 : "100.0 M",
169+ 999999999 : "1000 M",
170+ 9999999999 : "10000 M",
171+ 99999999999 : "100.0 G",
172+ 999999999999 : "1000 G",
173+ 9999999999999 : "10000 G",
174+ 99999999999999 : "100.0 T",
175+ 999999999999999 : "1000 T",
176+ 9999999999999999 : "10.0 P",
177+ 99999999999999999 : "100 P",
178+ 999999999999999999 : "1000 P",
179+ 9999999999999999999 : "10.0 E",
180+ 99999999999999999999 : "100 E",
181+ 999999999999999999999 : "1000 E",
182+ 9999999999999999999999 : "10.0 Z",
183+ 999999999999999999999999 : "1000 Z",
184+}
185+
186+class TestAptPkg(unittest.TestCase):
187+ """Test apt_pkg."""
188+
189+ def setUp(self):
190+ pass
191+
192+ def test_size_to_str(self):
193+ try:
194+ for k, v in data.items():
195+ size = apt_pkg.size_to_str(k)
196+ msg = "size_to_str(%s) returned '%s', expected '%s'" % (k, size, v)
197+ self.assertEqual(size, v, msg)
198+ except:
199+ self.fail(sys.exc_info())
200+
201+ with self.assertRaises(TypeError):
202+ apt_pkg.size_to_str("hello")
203+
204+ with self.assertRaises(TypeError):
205+ apt_pkg.size_to_str(None)
206+
207+ with self.assertRaises(TypeError):
208+ apt_pkg.size_to_str({})
209+
210+ with self.assertRaises(TypeError):
211+ apt_pkg.size_to_str([])
212+
213+ with self.assertRaises(TypeError):
214+ apt_pkg.size_to_str(())
215+
216+
217+if __name__ == "__main__":
218+ unittest.main()

Subscribers

People subscribed via source and target branches

to all changes: