Merge ~cjwatson/launchpad:py3-traceback-reference-cycles into launchpad:master
- Git
- lp:~cjwatson/launchpad
- py3-traceback-reference-cycles
- Merge into master
Proposed by
Colin Watson
Status: | Merged |
---|---|
Approved by: | Colin Watson |
Approved revision: | 695d975ad2d8d9e66f3340a0b6e3f3784437ae13 |
Merge reported by: | Otto Co-Pilot |
Merged at revision: | not available |
Proposed branch: | ~cjwatson/launchpad:py3-traceback-reference-cycles |
Merge into: | launchpad:master |
Diff against target: |
443 lines (+157/-93) 12 files modified
lib/lp/app/widgets/date.py (+6/-2) lib/lp/bugs/mail/handler.py (+6/-1) lib/lp/bugs/tests/test_bzremotecomponentfinder.py (+5/-1) lib/lp/code/mail/codehandler.py (+17/-13) lib/lp/code/model/branchhosting.py (+7/-3) lib/lp/code/model/githosting.py (+7/-3) lib/lp/code/xmlrpc/git.py (+79/-51) lib/lp/oci/model/ociregistryclient.py (+16/-12) lib/lp/services/gpg/handler.py (+2/-4) lib/lp/services/looptuner.py (+5/-1) lib/lp/services/timeout.py (+5/-1) lib/lp/services/webapp/adapter.py (+2/-1) |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Ioana Lasc (community) | Approve | ||
Review via email:
|
Commit message
Avoid various traceback reference cycles
Description of the change
On Python 3, exceptions have their associated traceback as a `__traceback__` attribute, which means that it's possible to end up with reference cycles by storing exception objects in variables local to frames that are part of their traceback. Delete those local variables before returning to avoid various cases of this.
To post a comment you must log in.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | diff --git a/lib/lp/app/widgets/date.py b/lib/lp/app/widgets/date.py | |||
2 | index dd8ef78..85d0756 100644 | |||
3 | --- a/lib/lp/app/widgets/date.py | |||
4 | +++ b/lib/lp/app/widgets/date.py | |||
5 | @@ -348,8 +348,12 @@ class DateTimeWidget(TextWidget): | |||
6 | 348 | failure = e | 348 | failure = e |
7 | 349 | else: | 349 | else: |
8 | 350 | return | 350 | return |
11 | 351 | if failure: | 351 | try: |
12 | 352 | raise ConversionError('Invalid date value', failure) | 352 | if failure: |
13 | 353 | raise ConversionError('Invalid date value', failure) | ||
14 | 354 | finally: | ||
15 | 355 | # Avoid traceback reference cycles. | ||
16 | 356 | del failure | ||
17 | 353 | 357 | ||
18 | 354 | def _toFieldValue(self, input): | 358 | def _toFieldValue(self, input): |
19 | 355 | """Return parsed input (datetime) as a date.""" | 359 | """Return parsed input (datetime) as a date.""" |
20 | diff --git a/lib/lp/bugs/mail/handler.py b/lib/lp/bugs/mail/handler.py | |||
21 | index b64b815..3a151e2 100644 | |||
22 | --- a/lib/lp/bugs/mail/handler.py | |||
23 | +++ b/lib/lp/bugs/mail/handler.py | |||
24 | @@ -257,6 +257,8 @@ class MaloneHandler: | |||
25 | 257 | def process(self, signed_msg, to_addr, filealias=None, log=None): | 257 | def process(self, signed_msg, to_addr, filealias=None, log=None): |
26 | 258 | """See IMailHandler.""" | 258 | """See IMailHandler.""" |
27 | 259 | 259 | ||
28 | 260 | processing_errors = [] | ||
29 | 261 | |||
30 | 260 | try: | 262 | try: |
31 | 261 | (final_result, add_comment_to_bug, | 263 | (final_result, add_comment_to_bug, |
32 | 262 | commands, ) = self.extractAndAuthenticateCommands( | 264 | commands, ) = self.extractAndAuthenticateCommands( |
33 | @@ -269,7 +271,6 @@ class MaloneHandler: | |||
34 | 269 | bugtask = None | 271 | bugtask = None |
35 | 270 | bugtask_event = None | 272 | bugtask_event = None |
36 | 271 | 273 | ||
37 | 272 | processing_errors = [] | ||
38 | 273 | while len(commands) > 0: | 274 | while len(commands) > 0: |
39 | 274 | command = commands.pop(0) | 275 | command = commands.pop(0) |
40 | 275 | try: | 276 | try: |
41 | @@ -332,6 +333,10 @@ class MaloneHandler: | |||
42 | 332 | 'Submit Request Failure', | 333 | 'Submit Request Failure', |
43 | 333 | error.message, signed_msg, error.failing_command) | 334 | error.message, signed_msg, error.failing_command) |
44 | 334 | 335 | ||
45 | 336 | finally: | ||
46 | 337 | # Avoid traceback reference cycles. | ||
47 | 338 | del processing_errors | ||
48 | 339 | |||
49 | 335 | return True | 340 | return True |
50 | 336 | 341 | ||
51 | 337 | def sendHelpEmail(self, to_address): | 342 | def sendHelpEmail(self, to_address): |
52 | diff --git a/lib/lp/bugs/tests/test_bzremotecomponentfinder.py b/lib/lp/bugs/tests/test_bzremotecomponentfinder.py | |||
53 | index 13faf66..767d84b 100644 | |||
54 | --- a/lib/lp/bugs/tests/test_bzremotecomponentfinder.py | |||
55 | +++ b/lib/lp/bugs/tests/test_bzremotecomponentfinder.py | |||
56 | @@ -104,7 +104,11 @@ class TestBugzillaRemoteComponentFinder(TestCaseWithFactory): | |||
57 | 104 | finder.getRemoteProductsAndComponents() | 104 | finder.getRemoteProductsAndComponents() |
58 | 105 | except Exception as e: | 105 | except Exception as e: |
59 | 106 | asserted = e | 106 | asserted = e |
61 | 107 | self.assertIs(None, asserted) | 107 | try: |
62 | 108 | self.assertIs(None, asserted) | ||
63 | 109 | finally: | ||
64 | 110 | # Avoid traceback reference cycles. | ||
65 | 111 | del asserted | ||
66 | 108 | 112 | ||
67 | 109 | @responses.activate | 113 | @responses.activate |
68 | 110 | def test_store(self): | 114 | def test_store(self): |
69 | diff --git a/lib/lp/code/mail/codehandler.py b/lib/lp/code/mail/codehandler.py | |||
70 | index 508fb46..fb44573 100644 | |||
71 | --- a/lib/lp/code/mail/codehandler.py | |||
72 | +++ b/lib/lp/code/mail/codehandler.py | |||
73 | @@ -262,19 +262,23 @@ class CodeHandler: | |||
74 | 262 | def processCommands(self, context, commands): | 262 | def processCommands(self, context, commands): |
75 | 263 | """Process the various merge proposal commands against the context.""" | 263 | """Process the various merge proposal commands against the context.""" |
76 | 264 | processing_errors = [] | 264 | processing_errors = [] |
90 | 265 | with BranchMergeProposalNoPreviewDiffDelta.monitor( | 265 | try: |
91 | 266 | context.merge_proposal): | 266 | with BranchMergeProposalNoPreviewDiffDelta.monitor( |
92 | 267 | for command in commands: | 267 | context.merge_proposal): |
93 | 268 | try: | 268 | for command in commands: |
94 | 269 | command.execute(context) | 269 | try: |
95 | 270 | except EmailProcessingError as error: | 270 | command.execute(context) |
96 | 271 | processing_errors.append((error, command)) | 271 | except EmailProcessingError as error: |
97 | 272 | 272 | processing_errors.append((error, command)) | |
98 | 273 | if len(processing_errors) > 0: | 273 | |
99 | 274 | errors, commands = zip(*processing_errors) | 274 | if len(processing_errors) > 0: |
100 | 275 | raise IncomingEmailError( | 275 | errors, commands = zip(*processing_errors) |
101 | 276 | '\n'.join(str(error) for error in errors), | 276 | raise IncomingEmailError( |
102 | 277 | list(commands)) | 277 | '\n'.join(str(error) for error in errors), |
103 | 278 | list(commands)) | ||
104 | 279 | finally: | ||
105 | 280 | # Avoid traceback reference cycles. | ||
106 | 281 | del processing_errors | ||
107 | 278 | 282 | ||
108 | 279 | return len(commands) | 283 | return len(commands) |
109 | 280 | 284 | ||
110 | diff --git a/lib/lp/code/model/branchhosting.py b/lib/lp/code/model/branchhosting.py | |||
111 | index a245307..57e373c 100644 | |||
112 | --- a/lib/lp/code/model/branchhosting.py | |||
113 | +++ b/lib/lp/code/model/branchhosting.py | |||
114 | @@ -74,9 +74,13 @@ class BranchHostingClient: | |||
115 | 74 | raise | 74 | raise |
116 | 75 | except Exception: | 75 | except Exception: |
117 | 76 | _, val, tb = sys.exc_info() | 76 | _, val, tb = sys.exc_info() |
121 | 77 | reraise( | 77 | try: |
122 | 78 | RequestExceptionWrapper, RequestExceptionWrapper(*val.args), | 78 | reraise( |
123 | 79 | tb) | 79 | RequestExceptionWrapper, |
124 | 80 | RequestExceptionWrapper(*val.args), tb) | ||
125 | 81 | finally: | ||
126 | 82 | # Avoid traceback reference cycles. | ||
127 | 83 | del val, tb | ||
128 | 80 | finally: | 84 | finally: |
129 | 81 | action.finish() | 85 | action.finish() |
130 | 82 | if as_json: | 86 | if as_json: |
131 | diff --git a/lib/lp/code/model/githosting.py b/lib/lp/code/model/githosting.py | |||
132 | index 4f07f44..787e63e 100644 | |||
133 | --- a/lib/lp/code/model/githosting.py | |||
134 | +++ b/lib/lp/code/model/githosting.py | |||
135 | @@ -89,9 +89,13 @@ class GitHostingClient: | |||
136 | 89 | raise | 89 | raise |
137 | 90 | except Exception: | 90 | except Exception: |
138 | 91 | _, val, tb = sys.exc_info() | 91 | _, val, tb = sys.exc_info() |
142 | 92 | reraise( | 92 | try: |
143 | 93 | RequestExceptionWrapper, RequestExceptionWrapper(*val.args), | 93 | reraise( |
144 | 94 | tb) | 94 | RequestExceptionWrapper, |
145 | 95 | RequestExceptionWrapper(*val.args), tb) | ||
146 | 96 | finally: | ||
147 | 97 | # Avoid traceback reference cycles. | ||
148 | 98 | del val, tb | ||
149 | 95 | finally: | 99 | finally: |
150 | 96 | action.finish() | 100 | action.finish() |
151 | 97 | if response.content: | 101 | if response.content: |
152 | diff --git a/lib/lp/code/xmlrpc/git.py b/lib/lp/code/xmlrpc/git.py | |||
153 | index 21e728d..6e181c3 100644 | |||
154 | --- a/lib/lp/code/xmlrpc/git.py | |||
155 | +++ b/lib/lp/code/xmlrpc/git.py | |||
156 | @@ -454,14 +454,18 @@ class GitAPI(LaunchpadXMLRPCView): | |||
157 | 454 | result = run_with_login( | 454 | result = run_with_login( |
158 | 455 | requester_id, self._translatePath, | 455 | requester_id, self._translatePath, |
159 | 456 | six.ensure_text(path).strip("/"), permission, auth_params) | 456 | six.ensure_text(path).strip("/"), permission, auth_params) |
168 | 457 | if isinstance(result, xmlrpc_client.Fault): | 457 | try: |
169 | 458 | logger.error("translatePath failed: %r", result) | 458 | if isinstance(result, xmlrpc_client.Fault): |
170 | 459 | else: | 459 | logger.error("translatePath failed: %r", result) |
171 | 460 | # The results of path translation are not sensitive for logging | 460 | else: |
172 | 461 | # purposes (they may refer to private artifacts, but contain no | 461 | # The results of path translation are not sensitive for |
173 | 462 | # credentials). | 462 | # logging purposes (they may refer to private artifacts, but |
174 | 463 | logger.info("translatePath succeeded: %s", result) | 463 | # contain no credentials). |
175 | 464 | return result | 464 | logger.info("translatePath succeeded: %s", result) |
176 | 465 | return result | ||
177 | 466 | finally: | ||
178 | 467 | # Avoid traceback reference cycles. | ||
179 | 468 | del result | ||
180 | 465 | 469 | ||
181 | 466 | @return_fault | 470 | @return_fault |
182 | 467 | def _notify(self, requester, translated_path, statistics, auth_params): | 471 | def _notify(self, requester, translated_path, statistics, auth_params): |
183 | @@ -498,11 +502,15 @@ class GitAPI(LaunchpadXMLRPCView): | |||
184 | 498 | result = run_with_login( | 502 | result = run_with_login( |
185 | 499 | requester_id, self._notify, | 503 | requester_id, self._notify, |
186 | 500 | translated_path, statistics, auth_params) | 504 | translated_path, statistics, auth_params) |
192 | 501 | if isinstance(result, xmlrpc_client.Fault): | 505 | try: |
193 | 502 | logger.error("notify failed: %r", result) | 506 | if isinstance(result, xmlrpc_client.Fault): |
194 | 503 | else: | 507 | logger.error("notify failed: %r", result) |
195 | 504 | logger.info("notify succeeded: %s" % result) | 508 | else: |
196 | 505 | return result | 509 | logger.info("notify succeeded: %s" % result) |
197 | 510 | return result | ||
198 | 511 | finally: | ||
199 | 512 | # Avoid traceback reference cycles. | ||
200 | 513 | del result | ||
201 | 506 | 514 | ||
202 | 507 | @return_fault | 515 | @return_fault |
203 | 508 | def _getMergeProposalURL(self, requester, translated_path, branch, | 516 | def _getMergeProposalURL(self, requester, translated_path, branch, |
204 | @@ -536,14 +544,18 @@ class GitAPI(LaunchpadXMLRPCView): | |||
205 | 536 | result = run_with_login( | 544 | result = run_with_login( |
206 | 537 | requester_id, self._getMergeProposalURL, | 545 | requester_id, self._getMergeProposalURL, |
207 | 538 | translated_path, branch, auth_params) | 546 | translated_path, branch, auth_params) |
216 | 539 | if isinstance(result, xmlrpc_client.Fault): | 547 | try: |
217 | 540 | logger.error("getMergeProposalURL failed: %r", result) | 548 | if isinstance(result, xmlrpc_client.Fault): |
218 | 541 | else: | 549 | logger.error("getMergeProposalURL failed: %r", result) |
219 | 542 | # The result of getMergeProposalURL is not sensitive for logging | 550 | else: |
220 | 543 | # purposes (it may refer to private artifacts, but contains no | 551 | # The result of getMergeProposalURL is not sensitive for |
221 | 544 | # credentials, only the merge proposal URL). | 552 | # logging purposes (it may refer to private artifacts, but |
222 | 545 | logger.info("getMergeProposalURL succeeded: %s" % result) | 553 | # contains no credentials, only the merge proposal URL). |
223 | 546 | return result | 554 | logger.info("getMergeProposalURL succeeded: %s" % result) |
224 | 555 | return result | ||
225 | 556 | finally: | ||
226 | 557 | # Avoid traceback reference cycles. | ||
227 | 558 | del result | ||
228 | 547 | 559 | ||
229 | 548 | @return_fault | 560 | @return_fault |
230 | 549 | def _authenticateWithPassword(self, username, password): | 561 | def _authenticateWithPassword(self, username, password): |
231 | @@ -571,15 +583,19 @@ class GitAPI(LaunchpadXMLRPCView): | |||
232 | 571 | logger.info( | 583 | logger.info( |
233 | 572 | "Request received: authenticateWithPassword('%s')", username) | 584 | "Request received: authenticateWithPassword('%s')", username) |
234 | 573 | result = self._authenticateWithPassword(username, password) | 585 | result = self._authenticateWithPassword(username, password) |
244 | 574 | if isinstance(result, xmlrpc_client.Fault): | 586 | try: |
245 | 575 | logger.error("authenticateWithPassword failed: %r", result) | 587 | if isinstance(result, xmlrpc_client.Fault): |
246 | 576 | else: | 588 | logger.error("authenticateWithPassword failed: %r", result) |
247 | 577 | # The results of authentication may be sensitive, but we can at | 589 | else: |
248 | 578 | # least log the authenticated user. | 590 | # The results of authentication may be sensitive, but we can |
249 | 579 | logger.info( | 591 | # at least log the authenticated user. |
250 | 580 | "authenticateWithPassword succeeded: %s", | 592 | logger.info( |
251 | 581 | result.get("uid", result.get("user"))) | 593 | "authenticateWithPassword succeeded: %s", |
252 | 582 | return result | 594 | result.get("uid", result.get("user"))) |
253 | 595 | return result | ||
254 | 596 | finally: | ||
255 | 597 | # Avoid traceback reference cycles. | ||
256 | 598 | del result | ||
257 | 583 | 599 | ||
258 | 584 | def _renderPermissions(self, set_of_permissions): | 600 | def _renderPermissions(self, set_of_permissions): |
259 | 585 | """Render a set of permission strings for XML-RPC output.""" | 601 | """Render a set of permission strings for XML-RPC output.""" |
260 | @@ -647,17 +663,21 @@ class GitAPI(LaunchpadXMLRPCView): | |||
261 | 647 | result = run_with_login( | 663 | result = run_with_login( |
262 | 648 | requester_id, self._checkRefPermissions, | 664 | requester_id, self._checkRefPermissions, |
263 | 649 | translated_path, ref_paths, auth_params) | 665 | translated_path, ref_paths, auth_params) |
275 | 650 | if isinstance(result, xmlrpc_client.Fault): | 666 | try: |
276 | 651 | logger.error("checkRefPermissions failed: %r", result) | 667 | if isinstance(result, xmlrpc_client.Fault): |
277 | 652 | else: | 668 | logger.error("checkRefPermissions failed: %r", result) |
278 | 653 | # The results of ref permission checks are not sensitive for | 669 | else: |
279 | 654 | # logging purposes (they may refer to private artifacts, but | 670 | # The results of ref permission checks are not sensitive for |
280 | 655 | # contain no credentials). | 671 | # logging purposes (they may refer to private artifacts, but |
281 | 656 | logger.info( | 672 | # contain no credentials). |
282 | 657 | "checkRefPermissions succeeded: %s", | 673 | logger.info( |
283 | 658 | [(ref_path.data, permissions) | 674 | "checkRefPermissions succeeded: %s", |
284 | 659 | for ref_path, permissions in result]) | 675 | [(ref_path.data, permissions) |
285 | 660 | return result | 676 | for ref_path, permissions in result]) |
286 | 677 | return result | ||
287 | 678 | finally: | ||
288 | 679 | # Avoid traceback reference cycles. | ||
289 | 680 | del result | ||
290 | 661 | 681 | ||
291 | 662 | def _validateRequesterCanManageRepoCreation( | 682 | def _validateRequesterCanManageRepoCreation( |
292 | 663 | self, requester, repository, auth_params): | 683 | self, requester, repository, auth_params): |
293 | @@ -713,11 +733,15 @@ class GitAPI(LaunchpadXMLRPCView): | |||
294 | 713 | translated_path, auth_params) | 733 | translated_path, auth_params) |
295 | 714 | except Exception as e: | 734 | except Exception as e: |
296 | 715 | result = e | 735 | result = e |
302 | 716 | if isinstance(result, xmlrpc_client.Fault): | 736 | try: |
303 | 717 | logger.error("confirmRepoCreation failed: %r", result) | 737 | if isinstance(result, xmlrpc_client.Fault): |
304 | 718 | else: | 738 | logger.error("confirmRepoCreation failed: %r", result) |
305 | 719 | logger.info("confirmRepoCreation succeeded: %s" % result) | 739 | else: |
306 | 720 | return result | 740 | logger.info("confirmRepoCreation succeeded: %s" % result) |
307 | 741 | return result | ||
308 | 742 | finally: | ||
309 | 743 | # Avoid traceback reference cycles. | ||
310 | 744 | del result | ||
311 | 721 | 745 | ||
312 | 722 | def _abortRepoCreation(self, requester, translated_path, auth_params): | 746 | def _abortRepoCreation(self, requester, translated_path, auth_params): |
313 | 723 | naked_repo = removeSecurityProxy( | 747 | naked_repo = removeSecurityProxy( |
314 | @@ -740,8 +764,12 @@ class GitAPI(LaunchpadXMLRPCView): | |||
315 | 740 | translated_path, auth_params) | 764 | translated_path, auth_params) |
316 | 741 | except Exception as e: | 765 | except Exception as e: |
317 | 742 | result = e | 766 | result = e |
323 | 743 | if isinstance(result, xmlrpc_client.Fault): | 767 | try: |
324 | 744 | logger.error("abortRepoCreation failed: %r", result) | 768 | if isinstance(result, xmlrpc_client.Fault): |
325 | 745 | else: | 769 | logger.error("abortRepoCreation failed: %r", result) |
326 | 746 | logger.info("abortRepoCreation succeeded: %s" % result) | 770 | else: |
327 | 747 | return result | 771 | logger.info("abortRepoCreation succeeded: %s" % result) |
328 | 772 | return result | ||
329 | 773 | finally: | ||
330 | 774 | # Avoid traceback reference cycles. | ||
331 | 775 | del result | ||
332 | diff --git a/lib/lp/oci/model/ociregistryclient.py b/lib/lp/oci/model/ociregistryclient.py | |||
333 | index 51b00af..f3e623b 100644 | |||
334 | --- a/lib/lp/oci/model/ociregistryclient.py | |||
335 | +++ b/lib/lp/oci/model/ociregistryclient.py | |||
336 | @@ -387,18 +387,22 @@ class OCIRegistryClient: | |||
337 | 387 | preloaded_data = cls._preloadFiles(build, manifest, digests) | 387 | preloaded_data = cls._preloadFiles(build, manifest, digests) |
338 | 388 | 388 | ||
339 | 389 | exceptions = [] | 389 | exceptions = [] |
352 | 390 | for push_rule in build.recipe.push_rules: | 390 | try: |
353 | 391 | for tag in cls._calculateTags(build.recipe): | 391 | for push_rule in build.recipe.push_rules: |
354 | 392 | try: | 392 | for tag in cls._calculateTags(build.recipe): |
355 | 393 | cls._upload_to_push_rule( | 393 | try: |
356 | 394 | push_rule, build, manifest, digests, preloaded_data, | 394 | cls._upload_to_push_rule( |
357 | 395 | tag) | 395 | push_rule, build, manifest, digests, |
358 | 396 | except Exception as e: | 396 | preloaded_data, tag) |
359 | 397 | exceptions.append(e) | 397 | except Exception as e: |
360 | 398 | if len(exceptions) == 1: | 398 | exceptions.append(e) |
361 | 399 | raise exceptions[0] | 399 | if len(exceptions) == 1: |
362 | 400 | elif len(exceptions) > 1: | 400 | raise exceptions[0] |
363 | 401 | raise MultipleOCIRegistryError(exceptions) | 401 | elif len(exceptions) > 1: |
364 | 402 | raise MultipleOCIRegistryError(exceptions) | ||
365 | 403 | finally: | ||
366 | 404 | # Avoid traceback reference cycles. | ||
367 | 405 | del exceptions | ||
368 | 402 | 406 | ||
369 | 403 | @classmethod | 407 | @classmethod |
370 | 404 | def makeMultiArchManifest(cls, http_client, push_rule, build_request, | 408 | def makeMultiArchManifest(cls, http_client, push_rule, build_request, |
371 | diff --git a/lib/lp/services/gpg/handler.py b/lib/lp/services/gpg/handler.py | |||
372 | index 643246b..86770c9 100644 | |||
373 | --- a/lib/lp/services/gpg/handler.py | |||
374 | +++ b/lib/lp/services/gpg/handler.py | |||
375 | @@ -140,18 +140,16 @@ class GPGHandler: | |||
376 | 140 | 140 | ||
377 | 141 | def getVerifiedSignatureResilient(self, content, signature=None): | 141 | def getVerifiedSignatureResilient(self, content, signature=None): |
378 | 142 | """See IGPGHandler.""" | 142 | """See IGPGHandler.""" |
380 | 143 | errors = [] | 143 | stored_errors = [] |
381 | 144 | 144 | ||
382 | 145 | for i in range(3): | 145 | for i in range(3): |
383 | 146 | try: | 146 | try: |
384 | 147 | signature = self.getVerifiedSignature(content, signature) | 147 | signature = self.getVerifiedSignature(content, signature) |
385 | 148 | except GPGKeyNotFoundError as info: | 148 | except GPGKeyNotFoundError as info: |
387 | 149 | errors.append(info) | 149 | stored_errors.append(str(info)) |
388 | 150 | else: | 150 | else: |
389 | 151 | return signature | 151 | return signature |
390 | 152 | 152 | ||
391 | 153 | stored_errors = [str(err) for err in errors] | ||
392 | 154 | |||
393 | 155 | raise GPGVerificationError( | 153 | raise GPGVerificationError( |
394 | 156 | "Verification failed 3 times: %s " % stored_errors) | 154 | "Verification failed 3 times: %s " % stored_errors) |
395 | 157 | 155 | ||
396 | diff --git a/lib/lp/services/looptuner.py b/lib/lp/services/looptuner.py | |||
397 | index 6072bf6..32e95ec 100644 | |||
398 | --- a/lib/lp/services/looptuner.py | |||
399 | +++ b/lib/lp/services/looptuner.py | |||
400 | @@ -216,7 +216,11 @@ class LoopTuner: | |||
401 | 216 | # failure, so log it. | 216 | # failure, so log it. |
402 | 217 | self.log.exception("Unhandled exception in cleanUp") | 217 | self.log.exception("Unhandled exception in cleanUp") |
403 | 218 | # Reraise the original exception. | 218 | # Reraise the original exception. |
405 | 219 | reraise(exc_info[0], exc_info[1], tb=exc_info[2]) | 219 | try: |
406 | 220 | reraise(exc_info[0], exc_info[1], tb=exc_info[2]) | ||
407 | 221 | finally: | ||
408 | 222 | # Avoid traceback reference cycles. | ||
409 | 223 | del exc_info | ||
410 | 220 | else: | 224 | else: |
411 | 221 | cleanup() | 225 | cleanup() |
412 | 222 | 226 | ||
413 | diff --git a/lib/lp/services/timeout.py b/lib/lp/services/timeout.py | |||
414 | index 6ba700c..b8b3a7d 100644 | |||
415 | --- a/lib/lp/services/timeout.py | |||
416 | +++ b/lib/lp/services/timeout.py | |||
417 | @@ -239,7 +239,11 @@ class with_timeout: | |||
418 | 239 | exc_info = t.exc_info | 239 | exc_info = t.exc_info |
419 | 240 | # Remove the cyclic reference for faster GC. | 240 | # Remove the cyclic reference for faster GC. |
420 | 241 | del t.exc_info | 241 | del t.exc_info |
422 | 242 | reraise(exc_info[0], exc_info[1], tb=exc_info[2]) | 242 | try: |
423 | 243 | reraise(exc_info[0], exc_info[1], tb=exc_info[2]) | ||
424 | 244 | finally: | ||
425 | 245 | # Avoid traceback reference cycles. | ||
426 | 246 | del exc_info | ||
427 | 243 | return t.result | 247 | return t.result |
428 | 244 | 248 | ||
429 | 245 | return call_with_timeout | 249 | return call_with_timeout |
430 | diff --git a/lib/lp/services/webapp/adapter.py b/lib/lp/services/webapp/adapter.py | |||
431 | index 37c819d..637ad17 100644 | |||
432 | --- a/lib/lp/services/webapp/adapter.py | |||
433 | +++ b/lib/lp/services/webapp/adapter.py | |||
434 | @@ -642,7 +642,8 @@ class LaunchpadTimeoutTracer(PostgresTimeoutTracer): | |||
435 | 642 | try: | 642 | try: |
436 | 643 | reraise(info[0], info[1], tb=info[2]) | 643 | reraise(info[0], info[1], tb=info[2]) |
437 | 644 | finally: | 644 | finally: |
439 | 645 | info = None | 645 | # Avoid traceback reference cycles. |
440 | 646 | del info | ||
441 | 646 | 647 | ||
442 | 647 | def connection_raw_execute_error(self, connection, raw_cursor, | 648 | def connection_raw_execute_error(self, connection, raw_cursor, |
443 | 648 | statement, params, error): | 649 | statement, params, error): |
looks good