Ticket #1389: 1389-include-original-msg.darcs.patch

File 1389-include-original-msg.darcs.patch, 16.6 KB (added by davidsarah, at 2011-04-10T15:52:40Z)

packaging: show also the message of the original ImportError?. Ensure that an empty traceback is tolerated. Updates and makes minor cleanups to test. refs #1389

Line 
14 patches for repository davidsarah@dev.allmydata.org:/home/darcs/tahoe/trunk:
2
3Sat Apr  9 01:44:33 BST 2011  david-sarah@jacaranda.org
4  * allmydata/__init__.py: preserve the message of ImportErrors in the package versions string. fixes #1389
5
6Sun Apr 10 13:01:30 BST 2011  zooko@zooko.com
7  * tests: add test for including ImportError message in the summary of dependencies
8  refs. #1389
9
10Sun Apr 10 15:59:55 BST 2011  zooko@zooko.com
11  * packaging: show the file, line number, function, and line of code that raised ImportError
12  ref #1389
13
14Sun Apr 10 16:49:55 BST 2011  david-sarah@jacaranda.org
15  * packaging: show also the message of the original ImportError. Ensure that an empty traceback is tolerated. Updates and makes minor cleanups to test. refs #1389
16
17New patches:
18
19[allmydata/__init__.py: preserve the message of ImportErrors in the package versions string. fixes #1389
20david-sarah@jacaranda.org**20110409004433
21 Ignore-this: caff24ad49573d66bc61d0a397b51afe
22] {
23hunk ./src/allmydata/__init__.py 189
24             try:
25                 __import__(modulename)
26                 module = sys.modules[modulename]
27-            except ImportError:
28-                packages.append( (pkgname, (None, None, modulename)) )
29+            except ImportError, e:
30+                packages.append( (pkgname, (None, None, "%s because of: %s" % (modulename, str(e)))) )
31             else:
32                 if 'sqlite' in pkgname:
33                     packages.append( (pkgname, (get_version(module, 'version'), package_dir(module.__file__),
34hunk ./src/allmydata/__init__.py 221
35         return
36     (actual, location, comment) = vers_and_locs[name]
37     if actual is None:
38-        # comment is the module name
39-        raise ImportError("could not import %r for requirement %r" % (comment, req))
40+        # comment is the module name and message of the original ImportError
41+        raise ImportError("for requirement %r, could not import %s" % (req, comment))
42     if actual == 'unknown':
43         return
44     actualver = normalized_version(actual, what="actual version %r of %s from %r" % (actual, name, location))
45}
46[tests: add test for including ImportError message in the summary of dependencies
47zooko@zooko.com**20110410120130
48 Ignore-this: 581b37aaba6ee00fea8d0beea45d556c
49 refs. #1389
50] {
51addfile ./src/allmydata/test/test_package_initialization.py
52hunk ./src/allmydata/test/test_package_initialization.py 1
53+
54+from twisted.trial import unittest
55+
56+import allmydata
57+
58+import sys
59+
60+class T(unittest.TestCase):
61+    def test_report_import_error(self):
62+        try:
63+            real_import_func = __builtins__['__import__']
64+
65+            def raiseIE(name, *args):
66+                if name == "foolscap":
67+                    raise ImportError("wheeeyo foolscap cant be imported")
68+                else:
69+                    return real_import_func(name, *args)
70+
71+            __builtins__['__import__'] = raiseIE
72+            vers_and_locs =  allmydata.get_package_versions_and_locations()
73+            for (pkgname, stuff) in vers_and_locs:
74+                if pkgname == 'foolscap':
75+                    self.failUnless('wheeeyo' in stuff[2], stuff)
76+        finally:
77+            __builtins__['__import__'] = real_import_func
78}
79[packaging: show the file, line number, function, and line of code that raised ImportError
80zooko@zooko.com**20110410145955
81 Ignore-this: 82e0c1261a5b03c136241660a52b9a0b
82 ref #1389
83] {
84hunk ./src/allmydata/__init__.py 35
85 # http://allmydata.org/trac/tahoe/wiki/Versioning
86 __full_version__ = __appname__ + '/' + str(__version__)
87 
88-import os, platform, re, subprocess, sys
89+import os, platform, re, subprocess, sys, traceback
90 _distributor_id_cmdline_re = re.compile("(?:Distributor ID:)\s*(.*)", re.I)
91 _release_cmdline_re = re.compile("(?:Release:)\s*(.*)", re.I)
92 
93hunk ./src/allmydata/__init__.py 140
94     try:
95         return verlib.NormalizedVersion(verlib.suggest_normalized_version(verstr))
96     except (StandardError, verlib.IrrationalVersionError):
97-        cls, value, traceback = sys.exc_info()
98+        cls, value, trace = sys.exc_info()
99         raise PackagingError, ("could not parse %s due to %s: %s"
100hunk ./src/allmydata/__init__.py 142
101-                               % (what or repr(verstr), cls.__name__, value)), traceback
102+                               % (what or repr(verstr), cls.__name__, value)), trace
103 
104 
105 def get_package_versions_and_locations():
106hunk ./src/allmydata/__init__.py 189
107             try:
108                 __import__(modulename)
109                 module = sys.modules[modulename]
110-            except ImportError, e:
111-                packages.append( (pkgname, (None, None, "%s because of: %s" % (modulename, str(e)))) )
112+            except ImportError:
113+                etype, emsg, etrace = sys.exc_info()
114+                tracestr = traceback.extract_tb(etrace)[-1]
115+                packages.append( (pkgname, (None, None, tracestr)) )
116             else:
117                 if 'sqlite' in pkgname:
118                     packages.append( (pkgname, (get_version(module, 'version'), package_dir(module.__file__),
119hunk ./src/allmydata/__init__.py 224
120     (actual, location, comment) = vers_and_locs[name]
121     if actual is None:
122         # comment is the module name and message of the original ImportError
123-        raise ImportError("for requirement %r, could not import %s" % (req, comment))
124+        raise ImportError("for requirement %r: %s" % (req, comment))
125     if actual == 'unknown':
126         return
127     actualver = normalized_version(actual, what="actual version %r of %s from %r" % (actual, name, location))
128hunk ./src/allmydata/test/test_package_initialization.py 6
129 
130 import allmydata
131 
132-import sys
133+import mock
134+
135+real_import_func = __builtins__['__import__']
136 
137 class T(unittest.TestCase):
138hunk ./src/allmydata/test/test_package_initialization.py 11
139-    def test_report_import_error(self):
140-        try:
141-            real_import_func = __builtins__['__import__']
142+    @mock.patch('__builtin__.__import__')
143+    def test_report_import_error(self, mockimport):
144+        def raiseIE_from_this_particular_func(name, *args):
145+            if name == "foolscap":
146+                raise ImportError("wheeeyo foolscap cant be imported")
147+            else:
148+                return real_import_func(name, *args)
149 
150hunk ./src/allmydata/test/test_package_initialization.py 19
151-            def raiseIE(name, *args):
152-                if name == "foolscap":
153-                    raise ImportError("wheeeyo foolscap cant be imported")
154-                else:
155-                    return real_import_func(name, *args)
156+        mockimport.side_effect = raiseIE_from_this_particular_func
157 
158hunk ./src/allmydata/test/test_package_initialization.py 21
159-            __builtins__['__import__'] = raiseIE
160-            vers_and_locs =  allmydata.get_package_versions_and_locations()
161-            for (pkgname, stuff) in vers_and_locs:
162-                if pkgname == 'foolscap':
163-                    self.failUnless('wheeeyo' in stuff[2], stuff)
164-        finally:
165-            __builtins__['__import__'] = real_import_func
166+        vers_and_locs =  allmydata.get_package_versions_and_locations()
167+        for (pkgname, stuff) in vers_and_locs:
168+            if pkgname == 'foolscap':
169+                self.failUnless('wheeeyo' in str(stuff[2]), stuff)
170+                self.failUnless('raiseIE_from_this_particular_func' in stuff[2], stuff)
171}
172[packaging: show also the message of the original ImportError. Ensure that an empty traceback is tolerated. Updates and makes minor cleanups to test. refs #1389
173david-sarah@jacaranda.org**20110410154955
174 Ignore-this: e9a70998d64af82a598f45d526ae2aa6
175] {
176hunk ./src/allmydata/__init__.py 191
177                 module = sys.modules[modulename]
178             except ImportError:
179                 etype, emsg, etrace = sys.exc_info()
180-                tracestr = traceback.extract_tb(etrace)[-1]
181-                packages.append( (pkgname, (None, None, tracestr)) )
182+                trace_info = (emsg, ([None] + traceback.extract_tb(etrace))[-1])
183+                packages.append( (pkgname, (None, None, trace_info)) )
184             else:
185                 if 'sqlite' in pkgname:
186                     packages.append( (pkgname, (get_version(module, 'version'), package_dir(module.__file__),
187hunk ./src/allmydata/__init__.py 223
188         return
189     (actual, location, comment) = vers_and_locs[name]
190     if actual is None:
191-        # comment is the module name and message of the original ImportError
192+        # comment is (message, (filename, line number, function name, text)) for the original ImportError
193         raise ImportError("for requirement %r: %s" % (req, comment))
194     if actual == 'unknown':
195         return
196hunk ./src/allmydata/test/test_package_initialization.py 5
197 from twisted.trial import unittest
198 
199 import allmydata
200-
201 import mock
202 
203hunk ./src/allmydata/test/test_package_initialization.py 7
204-real_import_func = __builtins__['__import__']
205+real_import_func = __import__
206 
207 class T(unittest.TestCase):
208     @mock.patch('__builtin__.__import__')
209hunk ./src/allmydata/test/test_package_initialization.py 14
210     def test_report_import_error(self, mockimport):
211         def raiseIE_from_this_particular_func(name, *args):
212             if name == "foolscap":
213-                raise ImportError("wheeeyo foolscap cant be imported")
214+                marker = "wheeeyo"
215+                raise ImportError(marker + " foolscap cant be imported")
216             else:
217                 return real_import_func(name, *args)
218 
219hunk ./src/allmydata/test/test_package_initialization.py 25
220         for (pkgname, stuff) in vers_and_locs:
221             if pkgname == 'foolscap':
222                 self.failUnless('wheeeyo' in str(stuff[2]), stuff)
223-                self.failUnless('raiseIE_from_this_particular_func' in stuff[2], stuff)
224+                self.failUnless('raiseIE_from_this_particular_func' in str(stuff[2]), stuff)
225}
226
227Context:
228
229[remove unused variable detected by pyflakes
230zooko@zooko.com**20110407172231
231 Ignore-this: 7344652d5e0720af822070d91f03daf9
232]
233[allmydata/__init__.py: Nicer reporting of unparseable version numbers in dependencies. fixes #1388
234david-sarah@jacaranda.org**20110401202750
235 Ignore-this: 9c6bd599259d2405e1caadbb3e0d8c7f
236]
237[update FTP-and-SFTP.rst: the necessary patch is included in Twisted-10.1
238Brian Warner <warner@lothar.com>**20110325232511
239 Ignore-this: d5307faa6900f143193bfbe14e0f01a
240]
241[control.py: remove all uses of s.get_serverid()
242warner@lothar.com**20110227011203
243 Ignore-this: f80a787953bd7fa3d40e828bde00e855
244]
245[web: remove some uses of s.get_serverid(), not all
246warner@lothar.com**20110227011159
247 Ignore-this: a9347d9cf6436537a47edc6efde9f8be
248]
249[immutable/downloader/fetcher.py: remove all get_serverid() calls
250warner@lothar.com**20110227011156
251 Ignore-this: fb5ef018ade1749348b546ec24f7f09a
252]
253[immutable/downloader/fetcher.py: fix diversity bug in server-response handling
254warner@lothar.com**20110227011153
255 Ignore-this: bcd62232c9159371ae8a16ff63d22c1b
256 
257 When blocks terminate (either COMPLETE or CORRUPT/DEAD/BADSEGNUM), the
258 _shares_from_server dict was being popped incorrectly (using shnum as the
259 index instead of serverid). I'm still thinking through the consequences of
260 this bug. It was probably benign and really hard to detect. I think it would
261 cause us to incorrectly believe that we're pulling too many shares from a
262 server, and thus prefer a different server rather than asking for a second
263 share from the first server. The diversity code is intended to spread out the
264 number of shares simultaneously being requested from each server, but with
265 this bug, it might be spreading out the total number of shares requested at
266 all, not just simultaneously. (note that SegmentFetcher is scoped to a single
267 segment, so the effect doesn't last very long).
268]
269[immutable/downloader/share.py: reduce get_serverid(), one left, update ext deps
270warner@lothar.com**20110227011150
271 Ignore-this: d8d56dd8e7b280792b40105e13664554
272 
273 test_download.py: create+check MyShare instances better, make sure they share
274 Server objects, now that finder.py cares
275]
276[immutable/downloader/finder.py: reduce use of get_serverid(), one left
277warner@lothar.com**20110227011146
278 Ignore-this: 5785be173b491ae8a78faf5142892020
279]
280[immutable/offloaded.py: reduce use of get_serverid() a bit more
281warner@lothar.com**20110227011142
282 Ignore-this: b48acc1b2ae1b311da7f3ba4ffba38f
283]
284[immutable/upload.py: reduce use of get_serverid()
285warner@lothar.com**20110227011138
286 Ignore-this: ffdd7ff32bca890782119a6e9f1495f6
287]
288[immutable/checker.py: remove some uses of s.get_serverid(), not all
289warner@lothar.com**20110227011134
290 Ignore-this: e480a37efa9e94e8016d826c492f626e
291]
292[add remaining get_* methods to storage_client.Server, NoNetworkServer, and
293warner@lothar.com**20110227011132
294 Ignore-this: 6078279ddf42b179996a4b53bee8c421
295 MockIServer stubs
296]
297[upload.py: rearrange _make_trackers a bit, no behavior changes
298warner@lothar.com**20110227011128
299 Ignore-this: 296d4819e2af452b107177aef6ebb40f
300]
301[happinessutil.py: finally rename merge_peers to merge_servers
302warner@lothar.com**20110227011124
303 Ignore-this: c8cd381fea1dd888899cb71e4f86de6e
304]
305[test_upload.py: factor out FakeServerTracker
306warner@lothar.com**20110227011120
307 Ignore-this: 6c182cba90e908221099472cc159325b
308]
309[test_upload.py: server-vs-tracker cleanup
310warner@lothar.com**20110227011115
311 Ignore-this: 2915133be1a3ba456e8603885437e03
312]
313[happinessutil.py: server-vs-tracker cleanup
314warner@lothar.com**20110227011111
315 Ignore-this: b856c84033562d7d718cae7cb01085a9
316]
317[upload.py: more tracker-vs-server cleanup
318warner@lothar.com**20110227011107
319 Ignore-this: bb75ed2afef55e47c085b35def2de315
320]
321[upload.py: fix var names to avoid confusion between 'trackers' and 'servers'
322warner@lothar.com**20110227011103
323 Ignore-this: 5d5e3415b7d2732d92f42413c25d205d
324]
325[refactor: s/peer/server/ in immutable/upload, happinessutil.py, test_upload
326warner@lothar.com**20110227011100
327 Ignore-this: 7ea858755cbe5896ac212a925840fe68
328 
329 No behavioral changes, just updating variable/method names and log messages.
330 The effects outside these three files should be minimal: some exception
331 messages changed (to say "server" instead of "peer"), and some internal class
332 names were changed. A few things still use "peer" to minimize external
333 changes, like UploadResults.timings["peer_selection"] and
334 happinessutil.merge_peers, which can be changed later.
335]
336[storage_client.py: clean up test_add_server/test_add_descriptor, remove .test_servers
337warner@lothar.com**20110227011056
338 Ignore-this: efad933e78179d3d5fdcd6d1ef2b19cc
339]
340[test_client.py, upload.py:: remove KiB/MiB/etc constants, and other dead code
341warner@lothar.com**20110227011051
342 Ignore-this: dc83c5794c2afc4f81e592f689c0dc2d
343]
344[test: increase timeout on a network test because Francois's ARM machine hit that timeout
345zooko@zooko.com**20110317165909
346 Ignore-this: 380c345cdcbd196268ca5b65664ac85b
347 I'm skeptical that the test was proceeding correctly but ran out of time. It seems more likely that it had gotten hung. But if we raise the timeout to an even more extravagant number then we can be even more certain that the test was never going to finish.
348]
349[docs/configuration.rst: add a "Frontend Configuration" section
350Brian Warner <warner@lothar.com>**20110222014323
351 Ignore-this: 657018aa501fe4f0efef9851628444ca
352 
353 this points to docs/frontends/*.rst, which were previously underlinked
354]
355[web/filenode.py: avoid calling req.finish() on closed HTTP connections. Closes #1366
356"Brian Warner <warner@lothar.com>"**20110221061544
357 Ignore-this: 799d4de19933f2309b3c0c19a63bb888
358]
359[Add unit tests for cross_check_pkg_resources_versus_import, and a regression test for ref #1355. This requires a little refactoring to make it testable.
360david-sarah@jacaranda.org**20110221015817
361 Ignore-this: 51d181698f8c20d3aca58b057e9c475a
362]
363[allmydata/__init__.py: .name was used in place of the correct .__name__ when printing an exception. Also, robustify string formatting by using %r instead of %s in some places. fixes #1355.
364david-sarah@jacaranda.org**20110221020125
365 Ignore-this: b0744ed58f161bf188e037bad077fc48
366]
367[Refactor StorageFarmBroker handling of servers
368Brian Warner <warner@lothar.com>**20110221015804
369 Ignore-this: 842144ed92f5717699b8f580eab32a51
370 
371 Pass around IServer instance instead of (peerid, rref) tuple. Replace
372 "descriptor" with "server". Other replacements:
373 
374  get_all_servers -> get_connected_servers/get_known_servers
375  get_servers_for_index -> get_servers_for_psi (now returns IServers)
376 
377 This change still needs to be pushed further down: lots of code is now
378 getting the IServer and then distributing (peerid, rref) internally.
379 Instead, it ought to distribute the IServer internally and delay
380 extracting a serverid or rref until the last moment.
381 
382 no_network.py was updated to retain parallelism.
383]
384[TAG allmydata-tahoe-1.8.2
385warner@lothar.com**20110131020101]
386Patch bundle hash:
387958c2019b3d2fd1fb45268c1a937eab496c6abe5