Merge lp:~jelmer/qbrz/context-managers into lp:qbrz
- context-managers
- Merge into trunk
Proposed by
Jelmer Vernooij
Status: | Merged |
---|---|
Approved by: | Jelmer Vernooij |
Approved revision: | 1653 |
Merged at revision: | 1650 |
Proposed branch: | lp:~jelmer/qbrz/context-managers |
Merge into: | lp:qbrz |
Diff against target: |
1586 lines (+198/-535) 25 files modified
extras/build_pot.py (+2/-8) extras/import_po.py (+1/-4) lib/annotate.py (+3/-12) lib/browse.py (+29/-33) lib/cat.py (+3/-14) lib/cleanup.py (+0/-184) lib/commands.py (+4/-14) lib/commit.py (+2/-5) lib/commit_data.py (+2/-8) lib/diff.py (+20/-39) lib/diff_arg.py (+8/-11) lib/diffview.py (+1/-1) lib/diffwindow.py (+7/-11) lib/extra/isignored.py (+1/-1) lib/extra/isversioned.py (+1/-1) lib/lazycachedrevloader.py (+14/-17) lib/log.py (+4/-13) lib/loggraphviz.py (+4/-17) lib/spellcheck_enchant.py (+2/-2) lib/subprocess.py (+2/-8) lib/tests/test_extdiff.py (+4/-4) lib/tests/test_guidebar.py (+1/-1) lib/treewidget.py (+7/-32) lib/widgets/shelve.py (+69/-81) lib/widgets/shelvelist.py (+7/-14) |
To merge this branch: | bzr merge lp:~jelmer/qbrz/context-managers |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Jelmer Vernooij | Approve | ||
Review via email: mp+426396@code.launchpad.net |
Commit message
Use more context managers.
Description of the change
Use more context managers.
To post a comment you must log in.
Revision history for this message
Jelmer Vernooij (jelmer) : | # |
review:
Approve
Revision history for this message
Aleksandr Smyshliaev (a1s) : | # |
Revision history for this message
Aleksandr Smyshliaev (a1s) : | # |
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'extras/build_pot.py' |
2 | --- extras/build_pot.py 2020-07-15 09:34:25 +0000 |
3 | +++ extras/build_pot.py 2022-07-06 15:37:54 +0000 |
4 | @@ -63,18 +63,12 @@ |
5 | raise DistutilsOptionError("You can't use options --lang=XXX and --no-lang in the same time.") |
6 | |
7 | def _force_LF(self, src, dst=None): |
8 | - f = open(src, 'rU') |
9 | - try: |
10 | + with open(src, 'rU') as f: |
11 | content = f.read() |
12 | - finally: |
13 | - f.close() |
14 | if dst is None: |
15 | dst = src |
16 | - f = open(dst, 'wb') |
17 | - try: |
18 | + with open(dst, 'wb') as f: |
19 | f.write(content) |
20 | - finally: |
21 | - f.close() |
22 | |
23 | def run(self): |
24 | """Run xgettext for project sources""" |
25 | |
26 | === modified file 'extras/import_po.py' |
27 | --- extras/import_po.py 2019-10-27 14:48:19 +0000 |
28 | +++ extras/import_po.py 2022-07-06 15:37:54 +0000 |
29 | @@ -80,11 +80,8 @@ |
30 | for n, fn in entries: |
31 | log.info(' %s -> %s' % (n, fn)) |
32 | ft = t.extractfile(n) |
33 | - fd = open(fn, 'wb') |
34 | - try: |
35 | + with open(fn, 'wb') as fd: |
36 | fd.write(ft.read()) |
37 | - finally: |
38 | - fd.close() |
39 | if pot_file: |
40 | if find_executable('msginit') is None: |
41 | log.warn("GNU gettext msginit utility not found!") |
42 | |
43 | === modified file 'lib/annotate.py' |
44 | --- lib/annotate.py 2022-01-07 14:04:10 +0000 |
45 | +++ lib/annotate.py 2022-07-06 15:37:54 +0000 |
46 | @@ -410,12 +410,9 @@ |
47 | QtCore.QCoreApplication.processEvents() |
48 | self.encoding = get_set_encoding(self.encoding, self.branch) |
49 | self.encoding_selector.encoding = self.encoding |
50 | - self.branch.lock_read() |
51 | - try: |
52 | + with self.branch.lock_read(): |
53 | self.set_annotate_title() |
54 | self.annotate(self.annotate_tree, self.fileId, self.path) |
55 | - finally: |
56 | - self.branch.unlock() |
57 | finally: |
58 | self.throbber.hide() |
59 | QtCore.QTimer.singleShot(1, self._activate_line) |
60 | @@ -634,8 +631,7 @@ |
61 | def set_annotate_revision(self): |
62 | self.throbber.show() |
63 | try: |
64 | - self.branch.lock_read() |
65 | - try: |
66 | + with self.branch.lock_read(): |
67 | revid = self.log_list.currentIndex().data(logmodel.RevIdRole) |
68 | if revid.startswith(CURRENT_REVISION): |
69 | rev = cached_revisions[revid] |
70 | @@ -646,8 +642,6 @@ |
71 | self.set_annotate_title() |
72 | self.processEvents() |
73 | self.annotate(self.annotate_tree, self.fileId, self.path) |
74 | - finally: |
75 | - self.branch.unlock() |
76 | finally: |
77 | self.throbber.hide() |
78 | |
79 | @@ -657,11 +651,8 @@ |
80 | get_set_encoding(encoding, self.branch) |
81 | self.throbber.show() |
82 | try: |
83 | - self.branch.lock_read() |
84 | - try: |
85 | + with self.branch.lock_read(): |
86 | self.annotate(self.annotate_tree, self.fileId, self.path) |
87 | - finally: |
88 | - self.branch.unlock() |
89 | finally: |
90 | self.throbber.hide() |
91 | |
92 | |
93 | === modified file 'lib/browse.py' |
94 | --- lib/browse.py 2021-01-08 13:56:34 +0000 |
95 | +++ lib/browse.py 2022-07-06 15:37:54 +0000 |
96 | @@ -158,49 +158,45 @@ |
97 | self.diffbuttons, |
98 | self.refresh_button) |
99 | state = self.file_tree.get_state() |
100 | - if text=="wt:": |
101 | + if text == "wt:": |
102 | self.tree = self.workingtree |
103 | - self.tree.lock_read() |
104 | + with self.tree.lock_read(): |
105 | try: |
106 | self.file_tree.set_tree(self.workingtree, self.branch) |
107 | self.file_tree.restore_state(state) |
108 | - finally: |
109 | - self.tree.unlock() |
110 | for button in buttons: |
111 | button.setEnabled(True) |
112 | else: |
113 | branch = self.branch |
114 | - branch.lock_read() |
115 | - self.processEvents() |
116 | - |
117 | - for button in buttons: |
118 | - button.setEnabled(False) |
119 | - fmodel = self.file_tree.tree_filter_model |
120 | - fmodel.setFilter(fmodel.UNCHANGED, True) |
121 | - self.filter_menu.set_filters(fmodel.filters) |
122 | - |
123 | - try: |
124 | - if revision_id is None: |
125 | - text = revspec.spec or '' |
126 | - if revspec.in_branch == revspec.in_history: |
127 | - args = [branch] |
128 | - else: |
129 | - args = [branch, False] |
130 | - |
131 | - revision_id = revspec.in_branch(*args).rev_id |
132 | - |
133 | - self.revision_id = revision_id |
134 | - self.tree = branch.repository.revision_tree(revision_id) |
135 | + with branch.lock_read(): |
136 | self.processEvents() |
137 | - self.file_tree.set_tree(self.tree, self.branch) |
138 | - self.file_tree.restore_state(state) |
139 | - if self.revno_map is None: |
140 | + |
141 | + for button in buttons: |
142 | + button.setEnabled(False) |
143 | + fmodel = self.file_tree.tree_filter_model |
144 | + fmodel.setFilter(fmodel.UNCHANGED, True) |
145 | + self.filter_menu.set_filters(fmodel.filters) |
146 | + |
147 | + try: |
148 | + if revision_id is None: |
149 | + text = revspec.spec or '' |
150 | + if revspec.in_branch == revspec.in_history: |
151 | + args = [branch] |
152 | + else: |
153 | + args = [branch, False] |
154 | + |
155 | + revision_id = revspec.in_branch(*args).rev_id |
156 | + |
157 | + self.revision_id = revision_id |
158 | + self.tree = branch.repository.revision_tree(revision_id) |
159 | self.processEvents() |
160 | - # XXX make this operation lazy? how? |
161 | - self.revno_map = self.branch.get_revision_id_to_revno_map() |
162 | - self.file_tree.tree_model.set_revno_map(self.revno_map) |
163 | - finally: |
164 | - branch.unlock() |
165 | + self.file_tree.set_tree(self.tree, self.branch) |
166 | + self.file_tree.restore_state(state) |
167 | + if self.revno_map is None: |
168 | + self.processEvents() |
169 | + # XXX make this operation lazy? how? |
170 | + self.revno_map = self.branch.get_revision_id_to_revno_map() |
171 | + self.file_tree.tree_model.set_revno_map(self.revno_map) |
172 | self.revision_edit.setText(text) |
173 | finally: |
174 | self.throbber.hide() |
175 | |
176 | === modified file 'lib/cat.py' |
177 | --- lib/cat.py 2021-01-08 08:16:13 +0000 |
178 | +++ lib/cat.py 2022-07-06 15:37:54 +0000 |
179 | @@ -142,8 +142,7 @@ |
180 | "%r is not present in revision %s" % ( |
181 | self.filename, self.tree.get_revision_id())) |
182 | |
183 | - self.tree.lock_read() |
184 | - try: |
185 | + with self.tree.lock_read(): |
186 | kind = self.tree.kind(self.filename) |
187 | if kind == 'file': |
188 | text = self.tree.get_file_text(self.filename) |
189 | @@ -151,8 +150,6 @@ |
190 | text = self.tree.get_symlink_target(self.filename) |
191 | else: |
192 | text = '' |
193 | - finally: |
194 | - self.tree.unlock() |
195 | self.processEvents() |
196 | |
197 | self.text = text |
198 | @@ -304,11 +301,8 @@ |
199 | kind = osutils.file_kind(self.filename) |
200 | text = '' |
201 | if kind == 'file': |
202 | - f = open(self.filename, 'rb') |
203 | - try: |
204 | + with open(self.filename, 'rb') as f: |
205 | text = f.read() |
206 | - finally: |
207 | - f.close() |
208 | elif kind == 'symlink': |
209 | text = os.readlink(self.filename) |
210 | self.text = text |
211 | @@ -337,13 +331,8 @@ |
212 | os.makedirs(qdir) |
213 | basename = os.path.basename(relpath) |
214 | fname = os.path.join(qdir, basename) |
215 | - f = open(fname, 'wb') |
216 | - tree.lock_read() |
217 | - try: |
218 | + with open(fname, 'wb') as f, tree.lock_read(): |
219 | f.write(tree.get_file_text(relpath)) |
220 | - finally: |
221 | - tree.unlock() |
222 | - f.close() |
223 | # open it |
224 | url = QtCore.QUrl.fromLocalFile(fname) |
225 | result = QtGui.QDesktopServices.openUrl(url) |
226 | |
227 | === removed file 'lib/cleanup.py' |
228 | --- lib/cleanup.py 2020-07-14 15:58:13 +0000 |
229 | +++ lib/cleanup.py 1970-01-01 00:00:00 +0000 |
230 | @@ -1,184 +0,0 @@ |
231 | -# Copyright (C) 2009, 2010 Canonical Ltd |
232 | -# |
233 | -# This program is free software; you can redistribute it and/or modify |
234 | -# it under the terms of the GNU General Public License as published by |
235 | -# the Free Software Foundation; either version 2 of the License, or |
236 | -# (at your option) any later version. |
237 | -# |
238 | -# This program is distributed in the hope that it will be useful, |
239 | -# but WITHOUT ANY WARRANTY; without even the implied warranty of |
240 | -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
241 | -# GNU General Public License for more details. |
242 | -# |
243 | -# You should have received a copy of the GNU General Public License |
244 | -# along with this program; if not, write to the Free Software |
245 | -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
246 | - |
247 | -"""Helpers for managing cleanup functions and the errors they might raise. |
248 | - |
249 | -The usual way to run cleanup code in Python is:: |
250 | - |
251 | - try: |
252 | - do_something() |
253 | - finally: |
254 | - cleanup_something() |
255 | - |
256 | -However if both `do_something` and `cleanup_something` raise an exception |
257 | -Python will forget the original exception and propagate the one from |
258 | -cleanup_something. Unfortunately, this is almost always much less useful than |
259 | -the original exception. |
260 | - |
261 | -If you want to be certain that the first, and only the first, error is raised, |
262 | -then use:: |
263 | - |
264 | - operation = OperationWithCleanups(do_something) |
265 | - operation.add_cleanup(cleanup_something) |
266 | - operation.run_simple() |
267 | - |
268 | -This is more inconvenient (because you need to make every try block a |
269 | -function), but will ensure that the first error encountered is the one raised, |
270 | -while also ensuring all cleanups are run. See OperationWithCleanups for more |
271 | -details. |
272 | -""" |
273 | - |
274 | -from __future__ import absolute_import |
275 | - |
276 | -from collections import deque |
277 | -# import sys |
278 | -# from . import ( |
279 | -# debug, |
280 | -# trace, |
281 | -# ) |
282 | - |
283 | -from breezy import ( |
284 | - debug, |
285 | - trace, |
286 | - ) |
287 | - |
288 | - |
289 | -def _log_cleanup_error(exc): |
290 | - trace.mutter('Cleanup failed:') |
291 | - trace.log_exception_quietly() |
292 | - if 'cleanup' in debug.debug_flags: |
293 | - trace.warning('brz: warning: Cleanup failed: %s', exc) |
294 | - |
295 | - |
296 | -def _run_cleanup(func, *args, **kwargs): |
297 | - """Run func(*args, **kwargs), logging but not propagating any error it |
298 | - raises. |
299 | - |
300 | - :returns: True if func raised no errors, else False. |
301 | - """ |
302 | - try: |
303 | - func(*args, **kwargs) |
304 | - except KeyboardInterrupt: |
305 | - raise |
306 | - except Exception as exc: |
307 | - _log_cleanup_error(exc) |
308 | - return False |
309 | - return True |
310 | - |
311 | - |
312 | -def _run_cleanups(funcs): |
313 | - """Run a series of cleanup functions.""" |
314 | - for func, args, kwargs in funcs: |
315 | - _run_cleanup(func, *args, **kwargs) |
316 | - |
317 | - |
318 | -class ObjectWithCleanups(object): |
319 | - """A mixin for objects that hold a cleanup list. |
320 | - |
321 | - Subclass or client code can call add_cleanup and then later `cleanup_now`. |
322 | - """ |
323 | - def __init__(self): |
324 | - self.cleanups = deque() |
325 | - |
326 | - def add_cleanup(self, cleanup_func, *args, **kwargs): |
327 | - """Add a cleanup to run. |
328 | - |
329 | - Cleanups may be added at any time. |
330 | - Cleanups will be executed in LIFO order. |
331 | - """ |
332 | - self.cleanups.appendleft((cleanup_func, args, kwargs)) |
333 | - |
334 | - def cleanup_now(self): |
335 | - _run_cleanups(self.cleanups) |
336 | - self.cleanups.clear() |
337 | - |
338 | - |
339 | -class OperationWithCleanups(ObjectWithCleanups): |
340 | - """A way to run some code with a dynamic cleanup list. |
341 | - |
342 | - This provides a way to add cleanups while the function-with-cleanups is |
343 | - running. |
344 | - |
345 | - Typical use:: |
346 | - |
347 | - operation = OperationWithCleanups(some_func) |
348 | - operation.run(args...) |
349 | - |
350 | - where `some_func` is:: |
351 | - |
352 | - def some_func(operation, args, ...): |
353 | - do_something() |
354 | - operation.add_cleanup(something) |
355 | - # etc |
356 | - |
357 | - Note that the first argument passed to `some_func` will be the |
358 | - OperationWithCleanups object. To invoke `some_func` without that, use |
359 | - `run_simple` instead of `run`. |
360 | - """ |
361 | - |
362 | - def __init__(self, func): |
363 | - super(OperationWithCleanups, self).__init__() |
364 | - self.func = func |
365 | - |
366 | - def run(self, *args, **kwargs): |
367 | - return _do_with_cleanups(self.cleanups, self.func, self, *args, **kwargs) |
368 | - |
369 | - def run_simple(self, *args, **kwargs): |
370 | - return _do_with_cleanups(self.cleanups, self.func, *args, **kwargs) |
371 | - |
372 | - |
373 | -def _do_with_cleanups(cleanup_funcs, func, *args, **kwargs): |
374 | - """Run `func`, then call all the cleanup_funcs. |
375 | - |
376 | - All the cleanup_funcs are guaranteed to be run. The first exception raised |
377 | - by func or any of the cleanup_funcs is the one that will be propagted by |
378 | - this function (subsequent errors are caught and logged). |
379 | - |
380 | - Conceptually similar to:: |
381 | - |
382 | - try: |
383 | - return func(*args, **kwargs) |
384 | - finally: |
385 | - for cleanup, cargs, ckwargs in cleanup_funcs: |
386 | - cleanup(*cargs, **ckwargs) |
387 | - |
388 | - It avoids several problems with using try/finally directly: |
389 | - * an exception from func will not be obscured by a subsequent exception |
390 | - from a cleanup. |
391 | - * an exception from a cleanup will not prevent other cleanups from |
392 | - running (but the first exception encountered is still the one |
393 | - propagated). |
394 | - |
395 | - Unike `_run_cleanup`, `_do_with_cleanups` can propagate an exception from a |
396 | - cleanup, but only if there is no exception from func. |
397 | - """ |
398 | - try: |
399 | - result = func(*args, **kwargs) |
400 | - except: |
401 | - # We have an exception from func already, so suppress cleanup errors. |
402 | - _run_cleanups(cleanup_funcs) |
403 | - raise |
404 | - # No exception from func, so allow first cleanup error to propgate. |
405 | - pending_cleanups = iter(cleanup_funcs) |
406 | - try: |
407 | - for cleanup, c_args, c_kwargs in pending_cleanups: |
408 | - cleanup(*c_args, **c_kwargs) |
409 | - except: |
410 | - # Still run the remaining cleanups but suppress any further errors. |
411 | - _run_cleanups(pending_cleanups) |
412 | - raise |
413 | - # No error, so we can return the result |
414 | - return result |
415 | |
416 | === modified file 'lib/commands.py' |
417 | --- lib/commands.py 2021-08-05 11:12:43 +0000 |
418 | +++ lib/commands.py 2022-07-06 15:37:54 +0000 |
419 | @@ -367,11 +367,8 @@ |
420 | if message is not None and file: |
421 | raise errors.BzrCommandError("please specify either --message or --file") |
422 | if file: |
423 | - f = open(file) |
424 | - try: |
425 | + with open(file) as f: |
426 | message = f.read().decode(file_encoding or osutils.get_user_encoding()) |
427 | - finally: |
428 | - f.close() |
429 | tree, selected_list = WorkingTree.open_containing_paths(selected_list) |
430 | if selected_list == ['']: |
431 | selected_list = None |
432 | @@ -403,18 +400,11 @@ |
433 | takes_options.append('change') |
434 | aliases = ['qdi'] |
435 | |
436 | - def get_diff_window_args(self, processEvents, add_cleanup): |
437 | - # RJL if you get a ``AttributeError: 'function' object has no attribute 'enter_context'`` |
438 | - # error, or something similar, use something like: |
439 | - # |
440 | - # exit_stack = contextlib.ExitStack() |
441 | - # |
442 | - # and pass that as add_cleanup |
443 | - # |
444 | + def get_diff_window_args(self, processEvents, es): |
445 | args = {} |
446 | (args["old_tree"], args["new_tree"], |
447 | args["old_branch"], args["new_branch"], |
448 | - args["specific_files"], _) = get_trees_and_branches_to_diff_locked(self.file_list, self.revision, self.old, self.new, add_cleanup) |
449 | + args["specific_files"], _) = get_trees_and_branches_to_diff_locked(self.file_list, self.revision, self.old, self.new, es) |
450 | args["ignore_whitespace"] = self.ignore_whitespace |
451 | return args |
452 | |
453 | @@ -716,7 +706,7 @@ |
454 | del kw['encoding'] |
455 | return breezy.builtins.cmd_merge.run(self, *args, **kw) |
456 | |
457 | - def get_diff_window_args(self, processEvents, add_cleanup): |
458 | + def get_diff_window_args(self, processEvents, es): |
459 | tree_merger = self.merger.make_merger() |
460 | self.tt = tree_merger.make_preview_transform() |
461 | result_tree = self.tt.get_preview_tree() |
462 | |
463 | === modified file 'lib/commit.py' |
464 | --- lib/commit.py 2022-01-07 15:10:55 +0000 |
465 | +++ lib/commit.py 2022-07-06 15:37:54 +0000 |
466 | @@ -465,8 +465,7 @@ |
467 | self.throbber.show() |
468 | self.refresh_button.setDisabled(True) |
469 | try: |
470 | - self.tree.lock_read() |
471 | - try: |
472 | + with self.tree.lock_read(): |
473 | if self.pending_merges_list: |
474 | self.pending_merges_list.load_tree(self.tree) |
475 | # Force the loading of the revisions, before we start |
476 | @@ -488,7 +487,7 @@ |
477 | # if there are any paths from the command line that |
478 | # are not versioned, we want_unversioned. |
479 | for path in self.initial_selected_list: |
480 | - if not self.tree.path2id(path): |
481 | + if not self.tree.is_versioned(path): |
482 | want_unversioned = True |
483 | break |
484 | |
485 | @@ -504,8 +503,6 @@ |
486 | self.is_loading = False |
487 | self.processEvents() |
488 | self.update_compleater_words() |
489 | - finally: |
490 | - self.tree.unlock() |
491 | finally: |
492 | self.throbber.hide() |
493 | self.refresh_button.setDisabled(False) |
494 | |
495 | === modified file 'lib/commit_data.py' |
496 | --- lib/commit_data.py 2019-10-27 14:48:19 +0000 |
497 | +++ lib/commit_data.py 2022-07-06 15:37:54 +0000 |
498 | @@ -164,14 +164,11 @@ |
499 | def save(self): |
500 | """Save data to the branch/tree.""" |
501 | br = self._get_branch() |
502 | - br.lock_write() |
503 | - try: |
504 | + with br.lock_write(): |
505 | # XXX save should wipe if self._data is empty |
506 | self._set_new_commit_data(self._filtered_data()) |
507 | # clear old data |
508 | self._wipe_old_data() |
509 | - finally: |
510 | - br.unlock() |
511 | |
512 | def _wipe_old_data(self): |
513 | """Wipe saved data in old format.""" |
514 | @@ -180,13 +177,10 @@ |
515 | def wipe(self): |
516 | """Delete saved data from branch/tree config.""" |
517 | br = self._get_branch() |
518 | - br.lock_write() |
519 | - try: |
520 | + with br.lock_write(): |
521 | self._set_new_commit_data({}) |
522 | # clear old data |
523 | self._wipe_old_data() |
524 | - finally: |
525 | - br.unlock() |
526 | |
527 | def _get_branch(self): |
528 | """Return branch object if either branch or tree was specified on init. |
529 | |
530 | === modified file 'lib/diff.py' |
531 | --- lib/diff.py 2022-01-08 11:48:59 +0000 |
532 | +++ lib/diff.py 2022-07-06 15:37:54 +0000 |
533 | @@ -17,8 +17,18 @@ |
534 | # along with this program; if not, write to the Free Software |
535 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
536 | |
537 | +from contextlib import ExitStack |
538 | +import errno |
539 | +import re |
540 | +import time |
541 | +import sys |
542 | +import os |
543 | +import glob |
544 | + |
545 | from PyQt5 import QtCore, QtGui, QtWidgets |
546 | |
547 | +from breezy import trace, osutils, cmdline |
548 | + |
549 | from breezy.errors import NoSuchId, ExecutableMissing |
550 | from breezy.tree import FileTimestampUnavailable |
551 | from breezy.plugins.qbrz.lib.diff_arg import * # import DiffArgProvider classes |
552 | @@ -30,22 +40,9 @@ |
553 | ) |
554 | |
555 | from breezy.lazy_import import lazy_import |
556 | -try: |
557 | - QString = unicode |
558 | -except NameError: |
559 | - # Python 3 |
560 | - QString = str |
561 | - |
562 | lazy_import(globals(), ''' |
563 | -import errno |
564 | -import re |
565 | -import time |
566 | -import sys |
567 | -import os |
568 | -import glob |
569 | from patiencediff import PatienceSequenceMatcher as SequenceMatcher |
570 | from breezy.plugins.qbrz.lib.i18n import gettext, ngettext, N_ |
571 | -from breezy import trace, osutils, cmdline |
572 | from breezy.workingtree import WorkingTree |
573 | from breezy.trace import mutter |
574 | ''') |
575 | @@ -78,10 +75,9 @@ |
576 | parent_window.windows.append(window) |
577 | elif context: |
578 | ext_diff = str(ext_diff) # convert QString to str |
579 | - cleanup = [] |
580 | - try: |
581 | + with ExitStack() as es: |
582 | args = arg_provider.get_diff_window_args( |
583 | - QtWidgets.QApplication.processEvents, cleanup.append |
584 | + QtWidgets.QApplication.processEvents, es |
585 | ) |
586 | old_tree = args["old_tree"] |
587 | new_tree = args["new_tree"] |
588 | @@ -91,9 +87,6 @@ |
589 | context.diff_paths(specific_files) |
590 | else: |
591 | context.diff_tree() |
592 | - finally: |
593 | - while cleanup: |
594 | - cleanup.pop()() |
595 | |
596 | else: |
597 | args=["diff", "--using", ext_diff] # NEVER USE --using=xxx, ALWAYS --using xxx |
598 | @@ -188,11 +181,10 @@ |
599 | """ |
600 | RJLRJL: updated to call .iter_changes directly |
601 | """ |
602 | - try: |
603 | - cleanup = [] |
604 | + with ExitStack() as es: |
605 | if lock_trees: |
606 | for t in trees: |
607 | - cleanup.append(t.lock_read().unlock) |
608 | + es.enter_context(t.lock_read()) |
609 | |
610 | # changes = trees[1].iter_changes(trees[0], specific_files=specific_files, require_versioned=True) |
611 | |
612 | @@ -215,9 +207,6 @@ |
613 | if not di: |
614 | continue |
615 | yield di |
616 | - finally: |
617 | - while cleanup: |
618 | - cleanup.pop()() |
619 | |
620 | @classmethod |
621 | def create(cls, trees, file_id, paths, changed_content, versioned, |
622 | @@ -588,17 +577,13 @@ |
623 | NOTE: Directories cannot be specified. |
624 | Use diff_tree or diff_paths instead when specifing directory. |
625 | """ |
626 | - cleanup = [] |
627 | - try: |
628 | + with ExitStack() as es: |
629 | if lock_trees: |
630 | - cleanup.append(self._differ.new_tree.lock_read().unlock) |
631 | - cleanup.append(self._differ.old_tree.lock_read().unlock) |
632 | + es.enter_context(self._differ.new_tree.lock_read()) |
633 | + es.enter_context(self._differ.old_tree.lock_read()) |
634 | for file_id in file_ids: |
635 | self._differ.diff(file_id) |
636 | time.sleep(interval * 0.001) |
637 | - finally: |
638 | - while cleanup: |
639 | - cleanup.pop()() |
640 | |
641 | def diff_paths(self, paths, interval=50, lock_trees=True): |
642 | """ |
643 | @@ -610,12 +595,11 @@ |
644 | valid_paths = [] |
645 | ids = [] |
646 | dir_included = False |
647 | - cleanup = [] |
648 | - try: |
649 | + with ExitStack() as es: |
650 | # Sometimes, we must lock tree before calling tree.kind() |
651 | if lock_trees: |
652 | - cleanup.append(new_tree.lock_read().unlock) |
653 | - cleanup.append(old_tree.lock_read().unlock) |
654 | + es.enter_context(new_tree.lock_read()) |
655 | + es.enter_context(old_tree.lock_read()) |
656 | for p in paths: |
657 | id = new_tree.path2id(p) |
658 | if id: |
659 | @@ -630,9 +614,6 @@ |
660 | self.diff_tree(valid_paths, interval, False) |
661 | else: |
662 | self.diff_ids(ids, interval, False) |
663 | - finally: |
664 | - while cleanup: |
665 | - cleanup.pop()() |
666 | |
667 | def diff_tree(self, specific_files=None, interval=50, lock_trees=True): |
668 | """ |
669 | |
670 | === modified file 'lib/diff_arg.py' |
671 | --- lib/diff_arg.py 2017-09-11 06:53:22 +0000 |
672 | +++ lib/diff_arg.py 2022-07-06 15:37:54 +0000 |
673 | @@ -30,7 +30,7 @@ |
674 | """Contract class to pass arguments to either builtin diff window, or |
675 | external diffs""" |
676 | |
677 | - def get_diff_window_args(self, processEvents, add_cleanup): |
678 | + def get_diff_window_args(self, processEvents, es): |
679 | """Returns the arguments for the builtin diff window. |
680 | |
681 | :return: {"old_tree": old_tree, |
682 | @@ -52,7 +52,7 @@ |
683 | |
684 | class InternalDiffArgProvider(DiffArgProvider): |
685 | """Use for passing arguments from internal source.""" |
686 | - |
687 | + |
688 | def __init__(self, |
689 | old_revid, new_revid, |
690 | old_branch, new_branch, |
691 | @@ -67,7 +67,7 @@ |
692 | |
693 | self.old_tree = old_tree |
694 | self.new_tree = new_tree |
695 | - |
696 | + |
697 | def need_to_load_paths(self): |
698 | return self.specific_file_ids is not None \ |
699 | and self.specific_files is None |
700 | @@ -83,14 +83,11 @@ |
701 | self.new_branch.repository.revision_tree(self.new_revid) |
702 | |
703 | if self.need_to_load_paths(): |
704 | - self.new_tree.lock_read() |
705 | - try: |
706 | + with self.new_tree.lock_read(): |
707 | self.specific_files = [self.new_tree.id2path(id) \ |
708 | for id in self.specific_file_ids] |
709 | - finally: |
710 | - self.new_tree.unlock() |
711 | |
712 | - def get_diff_window_args(self, processEvents, add_cleanup): |
713 | + def get_diff_window_args(self, processEvents, es): |
714 | self.load_old_tree() |
715 | processEvents() |
716 | self.load_new_tree_and_paths() |
717 | @@ -107,11 +104,11 @@ |
718 | if revid.startswith(CURRENT_REVISION): |
719 | return '' |
720 | return 'revid:%s' % revid |
721 | - |
722 | + |
723 | return "-r%s..%s" % ( |
724 | get_revspec_part(self.old_revid), |
725 | get_revspec_part(self.new_revid)) |
726 | - |
727 | + |
728 | def get_ext_diff_args(self, processEvents): |
729 | from breezy import urlutils |
730 | from breezy import errors |
731 | @@ -177,7 +174,7 @@ |
732 | else: |
733 | InternalDiffArgProvider.load_old_tree(self) |
734 | |
735 | - def get_diff_window_args(self, processEvents, add_cleanup): |
736 | + def get_diff_window_args(self, processEvents, es): |
737 | self.load_old_tree() |
738 | processEvents() |
739 | |
740 | |
741 | === modified file 'lib/diffview.py' |
742 | --- lib/diffview.py 2022-01-08 10:52:49 +0000 |
743 | +++ lib/diffview.py 2022-07-06 15:37:54 +0000 |
744 | @@ -295,7 +295,7 @@ |
745 | def adjust_range(self): |
746 | page_step = self.browsers[0].verticalScrollBar().pageStep() |
747 | self.setPageStep(page_step) |
748 | - self.setRange(0, self.total_length - page_step + 4) |
749 | + self.setRange(0, int(self.total_length - page_step + 4)) |
750 | self.setVisible(self.total_length > page_step) |
751 | |
752 | def get_position_info(self, target): |
753 | |
754 | === modified file 'lib/diffwindow.py' |
755 | --- lib/diffwindow.py 2022-01-08 11:48:59 +0000 |
756 | +++ lib/diffwindow.py 2022-07-06 15:37:54 +0000 |
757 | @@ -20,6 +20,7 @@ |
758 | # along with this program; if not, write to the Free Software |
759 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
760 | |
761 | +from contextlib import ExitStack |
762 | import errno |
763 | import re |
764 | import time |
765 | @@ -35,8 +36,6 @@ |
766 | from breezy.workingtree import WorkingTree |
767 | from breezy.bzr.workingtree_4 import DirStateRevisionTree |
768 | from breezy import trace |
769 | -# from breezy import cleanup |
770 | -from breezy.plugins.qbrz.lib import cleanup |
771 | |
772 | from breezy.plugins.qbrz.lib.diffview import ( |
773 | SidebySideDiffView, |
774 | @@ -345,16 +344,13 @@ |
775 | throbber window, then loads the branches etc if they weren't specified |
776 | in our constructor. |
777 | """ |
778 | - op = cleanup.OperationWithCleanups(self._initial_load) |
779 | - self.throbber.show() |
780 | - op.add_cleanup(self.throbber.hide) |
781 | - op.run() |
782 | + with ExitStack() as es: |
783 | + es.callback(self.throbber.hide) |
784 | + self.throbber.show() |
785 | + self._initial_load(es) |
786 | |
787 | - def _initial_load(self, op): |
788 | - # RJL Breezy expects a context handler of some type |
789 | - exit_stack = contextlib.ExitStack() |
790 | - args = self.arg_provider.get_diff_window_args(self.processEvents, exit_stack) |
791 | - # args = self.arg_provider.get_diff_window_args(self.processEvents, op.add_cleanup) |
792 | + def _initial_load(self, es): |
793 | + args = self.arg_provider.get_diff_window_args(self.processEvents, es) |
794 | |
795 | self.trees = (args["old_tree"], args["new_tree"]) |
796 | self.branches = (args.get("old_branch", None), args.get("new_branch",None)) |
797 | |
798 | === modified file 'lib/extra/isignored.py' |
799 | --- lib/extra/isignored.py 2019-10-27 14:48:19 +0000 |
800 | +++ lib/extra/isignored.py 2022-07-06 15:37:54 +0000 |
801 | @@ -33,7 +33,7 @@ |
802 | |
803 | def run(self, filename): |
804 | tree, relpath = workingtree.WorkingTree.open_containing(filename) |
805 | - if tree.is_ignored(relpath) and not tree.path2id(relpath): |
806 | + if tree.is_ignored(relpath) and not tree.is_versioned(relpath): |
807 | if not trace.is_quiet(): |
808 | print('ignored', file=self.outf) |
809 | return 1 |
810 | |
811 | === modified file 'lib/extra/isversioned.py' |
812 | --- lib/extra/isversioned.py 2019-10-27 14:48:19 +0000 |
813 | +++ lib/extra/isversioned.py 2022-07-06 15:37:54 +0000 |
814 | @@ -33,7 +33,7 @@ |
815 | |
816 | def run(self, filename): |
817 | tree, relpath = workingtree.WorkingTree.open_containing(filename) |
818 | - if tree.path2id(relpath): |
819 | + if tree.is_versioned(relpath): |
820 | if not trace.is_quiet(): |
821 | print('versioned', file=self.outf) |
822 | return 1 |
823 | |
824 | === modified file 'lib/lazycachedrevloader.py' |
825 | --- lib/lazycachedrevloader.py 2021-01-05 13:03:34 +0000 |
826 | +++ lib/lazycachedrevloader.py 2022-07-06 15:37:54 +0000 |
827 | @@ -37,13 +37,13 @@ |
828 | before_batch_load = None, |
829 | revisions_loaded = None, |
830 | pass_prev_loaded_rev = False): |
831 | - |
832 | + |
833 | start_time = time.process_time() |
834 | showed_throbber = False |
835 | revids = [revid for revid in revids if not revid == "root:"] |
836 | return_revisions = {} |
837 | throbber = current_throbber() |
838 | - |
839 | + |
840 | try: |
841 | for revid in [revid for revid in revids |
842 | if revid in cached_revisions]: |
843 | @@ -51,7 +51,7 @@ |
844 | if pass_prev_loaded_rev: |
845 | if revisions_loaded is not None: |
846 | revisions_loaded(return_revisions, False) |
847 | - |
848 | + |
849 | revs_loaded = {} |
850 | revids = [revid for revid in revids if revid not in cached_revisions] |
851 | if revids: |
852 | @@ -59,24 +59,23 @@ |
853 | repo_revids=((repo, revids),) |
854 | else: |
855 | repo_revids = repo(revids) |
856 | - |
857 | + |
858 | for repo, revids in repo_revids: |
859 | repo_is_local = isinstance(repo.controldir.transport, LocalTransport) |
860 | if repo_is_local: |
861 | batch_size = local_batch_size |
862 | else: |
863 | batch_size = remote_batch_size |
864 | - |
865 | + |
866 | if revids: |
867 | - repo.lock_read() |
868 | - try: |
869 | + with repo.lock_read(): |
870 | if not repo_is_local: |
871 | update_ui() |
872 | - |
873 | + |
874 | for offset in range(0, len(revids), batch_size): |
875 | - |
876 | + |
877 | running_time = time.process_time() - start_time |
878 | - |
879 | + |
880 | if time_before_first_ui_update < running_time: |
881 | if revisions_loaded is not None: |
882 | revisions_loaded(revs_loaded, False) |
883 | @@ -86,28 +85,26 @@ |
884 | throbber.show() |
885 | showed_throbber = True |
886 | update_ui() |
887 | - |
888 | + |
889 | batch_revids = revids[offset:offset+batch_size] |
890 | - |
891 | + |
892 | if before_batch_load is not None: |
893 | stop = before_batch_load(repo, batch_revids) |
894 | if stop: |
895 | break |
896 | - |
897 | + |
898 | for rev in repo.get_revisions(batch_revids): |
899 | cached_revisions[rev.revision_id] = rev |
900 | return_revisions[rev.revision_id] = rev |
901 | revs_loaded[rev.revision_id] = rev |
902 | rev.repository = repo |
903 | - finally: |
904 | - repo.unlock() |
905 | - |
906 | + |
907 | if revisions_loaded is not None: |
908 | revisions_loaded(revs_loaded, True) |
909 | finally: |
910 | if showed_throbber: |
911 | throbber.hide() |
912 | - |
913 | + |
914 | return return_revisions |
915 | |
916 | def update_ui(): |
917 | |
918 | === modified file 'lib/log.py' |
919 | --- lib/log.py 2022-01-08 11:48:59 +0000 |
920 | +++ lib/log.py 2022-07-06 15:37:54 +0000 |
921 | @@ -612,9 +612,8 @@ |
922 | for repo, repo_revids in repos_revids: |
923 | repo_revids = [revid for revid in repo_revids if revid not in self.tree_cache] |
924 | if repo_revids: |
925 | - repo.lock_read() |
926 | - self.processEvents() |
927 | - try: |
928 | + with repo.lock_read(): |
929 | + self.processEvents() |
930 | for revid in repo_revids: |
931 | if (revid.startswith(CURRENT_REVISION) and gv_is_wtgv): |
932 | tree = gv.working_trees[revid] |
933 | @@ -622,8 +621,6 @@ |
934 | tree = repo.revision_tree(revid) |
935 | self.tree_cache[revid] = tree |
936 | self.processEvents() |
937 | - finally: |
938 | - repo.unlock() |
939 | self.processEvents() |
940 | |
941 | delta = self.tree_cache[revids[0]].changes_from(self.tree_cache[revids[1]]) |
942 | @@ -830,13 +827,10 @@ |
943 | tree = branch.repository.revision_tree(top_revid) |
944 | file_id = file_ids[0] |
945 | path = paths[0] |
946 | - tree.lock_read() |
947 | - try: |
948 | + with tree.lock_read(): |
949 | kind = tree.kind(path) |
950 | if kind == 'file': |
951 | file_content_bytes = tree.get_file_text(path) |
952 | - finally: |
953 | - tree.unlock() |
954 | if kind != 'file': |
955 | QtWidgets.QMessageBox.information(self, gettext("Not a file"), |
956 | gettext("Operation is supported for a single file only,\n" |
957 | @@ -844,11 +838,8 @@ |
958 | return |
959 | filename = QtWidgets.QFileDialog.getSaveFileName(self, gettext("Save file in this revision as..."))[0] |
960 | if filename: |
961 | - f = open(str(filename), 'wb') |
962 | - try: |
963 | + with open(str(filename), 'wb') as f: |
964 | f.write(file_content_bytes) |
965 | - finally: |
966 | - f.close() |
967 | |
968 | @ui_current_widget |
969 | def revert_file(self): |
970 | |
971 | === modified file 'lib/loggraphviz.py' |
972 | --- lib/loggraphviz.py 2021-08-05 11:27:16 +0000 |
973 | +++ lib/loggraphviz.py 2022-07-06 15:37:54 +0000 |
974 | @@ -219,7 +219,6 @@ |
975 | finally: |
976 | self.unlock_branches() |
977 | |
978 | - |
979 | def load_current_dir_repo(self): |
980 | # There are no local repositories. Try open the repository |
981 | # of the current directory, and try load revisions data from |
982 | @@ -1050,13 +1049,10 @@ |
983 | return_revisions = {} |
984 | for repo, revids in self.get_repo_revids(revids): |
985 | if revids: |
986 | - repo.lock_read() |
987 | - try: |
988 | + with repo.lock_read(): |
989 | self.update_ui() |
990 | for rev in repo.get_revisions(revids): |
991 | return_revisions[rev.revision_id] = rev |
992 | - finally: |
993 | - repo.unlock() |
994 | return return_revisions |
995 | |
996 | |
997 | @@ -1443,8 +1439,7 @@ |
998 | if tree is None: |
999 | tree = bi.branch.basis_tree() |
1000 | |
1001 | - tree.lock_read() |
1002 | - try: |
1003 | + with tree.lock_read(): |
1004 | for file_id in self.file_ids: |
1005 | if tree.kind(tree.id2path(file_id)) in ('directory', |
1006 | 'tree-reference'): |
1007 | @@ -1452,8 +1447,6 @@ |
1008 | break |
1009 | if self.has_dir: |
1010 | break |
1011 | - finally: |
1012 | - tree.unlock() |
1013 | |
1014 | if revids is None: |
1015 | revids = [rev.revid for rev in self.graph_viz.revisions] |
1016 | @@ -1485,8 +1478,7 @@ |
1017 | self.filter_changed_callback(changed_revs, False) |
1018 | self.graph_viz.update_ui() |
1019 | |
1020 | - repo.lock_read() |
1021 | - try: |
1022 | + with repo.lock_read(): |
1023 | if not self.uses_inventory(): |
1024 | text_keys = [(file_id, revid) |
1025 | for revid in revids |
1026 | @@ -1508,8 +1500,6 @@ |
1027 | self.graph_viz.update_ui() |
1028 | |
1029 | check_text_keys(text_keys) |
1030 | - finally: |
1031 | - repo.unlock() |
1032 | |
1033 | def load_filter_file_id_chunk_finished(self): |
1034 | self.filter_changed_callback([], True) |
1035 | @@ -1555,8 +1545,7 @@ |
1036 | |
1037 | :return: True if a change is found. False otherwise |
1038 | """ |
1039 | - tree.lock_read() |
1040 | - try: |
1041 | + with tree.lock_read(): |
1042 | # Copied from mutabletree, cause we need file_ids too. |
1043 | # Check pending merges |
1044 | if len(tree.get_parent_ids()) > 1: |
1045 | @@ -1579,8 +1568,6 @@ |
1046 | except StopIteration: |
1047 | # No changes |
1048 | return False |
1049 | - finally: |
1050 | - tree.unlock() |
1051 | |
1052 | def get_revision_visible(self, rev): |
1053 | if rev.revid.startswith(CURRENT_REVISION): |
1054 | |
1055 | === modified file 'lib/spellcheck_enchant.py' |
1056 | --- lib/spellcheck_enchant.py 2019-10-27 14:48:19 +0000 |
1057 | +++ lib/spellcheck_enchant.py 2022-07-06 15:37:54 +0000 |
1058 | @@ -30,7 +30,7 @@ |
1059 | text = self._text[offset:] |
1060 | if not text: |
1061 | raise StopIteration() |
1062 | - match = re.match('(\w+?)[A-Z]', text) |
1063 | + match = re.match(br'(\w+?)[A-Z]', text) |
1064 | if match is None: |
1065 | word = text |
1066 | else: |
1067 | @@ -60,7 +60,7 @@ |
1068 | self.checker.set_text(text) |
1069 | for err in self.checker: |
1070 | yield err.wordpos, len(err.word) |
1071 | - |
1072 | + |
1073 | def suggest(self, text): |
1074 | return self.dict.suggest(text) |
1075 | |
1076 | |
1077 | === modified file 'lib/subprocess.py' |
1078 | --- lib/subprocess.py 2022-04-14 11:45:16 +0000 |
1079 | +++ lib/subprocess.py 2022-07-06 15:37:54 +0000 |
1080 | @@ -847,12 +847,9 @@ |
1081 | if not os.path.isdir(qdir): |
1082 | os.makedirs(qdir) |
1083 | fd, fname = tempfile.mkstemp(dir=qdir) |
1084 | - f = os.fdopen(fd, "wb") |
1085 | - try: |
1086 | + with os.fdopen(fd, "wb") as f: |
1087 | # f.write(text.decode('utf8')) |
1088 | f.write(text) |
1089 | - finally: |
1090 | - f.close() # it closes fd as well |
1091 | self._args_file = fname |
1092 | return fname |
1093 | |
1094 | @@ -1074,11 +1071,8 @@ |
1095 | if s_cmd[0][0] == '@': |
1096 | fname = s_cmd[1:] |
1097 | # Changed this: it's written in 'b' so must be read that way too |
1098 | - f = open(fname, 'rb') |
1099 | - try: |
1100 | + with open(fname, 'rb') as f: |
1101 | s_cmd = f.read() |
1102 | - finally: |
1103 | - f.close() |
1104 | # We stored a bencoded string like b'l6:ignore18:qbrz-setup-iss.loge', so...: |
1105 | s_cmd = bencode.bdecode(s_cmd) |
1106 | # ...and again, sometimes we get a list like [b'ignore', b'qbrz-setup-iss.log'], so... |
1107 | |
1108 | === modified file 'lib/tests/test_extdiff.py' |
1109 | --- lib/tests/test_extdiff.py 2020-07-05 15:21:39 +0000 |
1110 | +++ lib/tests/test_extdiff.py 2022-07-06 15:37:54 +0000 |
1111 | @@ -25,11 +25,11 @@ |
1112 | |
1113 | def test_no_arguments(self): |
1114 | self.differ.set_command_string("test") |
1115 | - self.assertEqual(self.differ.command_template, ["test", "@old_path", "@new_path"]) |
1116 | + self.assertEqual(self.differ.command_template, ["test", "{old_path}", "{new_path}"]) |
1117 | |
1118 | def test_has_arguments(self): |
1119 | - self.differ.set_command_string("test --old @old_path --new @new_path") |
1120 | - self.assertEqual(self.differ.command_template, ["test", "--old", "@old_path", "--new", "@new_path"]) |
1121 | + self.differ.set_command_string("test --old {old_path} --new {new_path}") |
1122 | + self.assertEqual(self.differ.command_template, ["test", "--old", "{old_path}", "--new", "{new_path}"]) |
1123 | |
1124 | class TestPrefix(QTestCase): |
1125 | def setUp(self): |
1126 | @@ -221,7 +221,7 @@ |
1127 | def assertPopen(self, paths, old_contents): |
1128 | for args, path, old_content in zip(self.popen_mock.args, paths, old_contents): |
1129 | # tool, old_path, new_path = args[0][0] |
1130 | - tool, _, _, old_path, new_path = args[0][0] |
1131 | + tool, old_path, new_path = args[0][0] |
1132 | self.assertEqual(tool, "diff.exe") |
1133 | self.assertFileContent(old_path, old_content) |
1134 | self.assertEqual(new_path, self.tree.abspath(path)) |
1135 | |
1136 | === modified file 'lib/tests/test_guidebar.py' |
1137 | --- lib/tests/test_guidebar.py 2021-01-05 16:26:04 +0000 |
1138 | +++ lib/tests/test_guidebar.py 2022-07-06 15:37:54 +0000 |
1139 | @@ -24,7 +24,7 @@ |
1140 | def __init__(self, tree): |
1141 | self.tree = tree |
1142 | |
1143 | - def get_diff_window_args(self, processEvents, add_cleanup): |
1144 | + def get_diff_window_args(self, processEvents, es): |
1145 | # This will be used by DiffWindow::_initial_load |
1146 | return dict( |
1147 | old_tree=self.tree.basis_tree(), |
1148 | |
1149 | === modified file 'lib/treewidget.py' |
1150 | --- lib/treewidget.py 2022-01-08 11:48:59 +0000 |
1151 | +++ lib/treewidget.py 2022-07-06 15:37:54 +0000 |
1152 | @@ -485,16 +485,10 @@ |
1153 | |
1154 | if isinstance(self.tree, WorkingTree): |
1155 | # print(':::-> tree.lock_read (try) about to execute') |
1156 | - tree.lock_read() |
1157 | - try: |
1158 | - # RJL Breezy release notes state that: |
1159 | - # |
1160 | - # The ``Tree.get_root_id`` method has been removed. Use``Tree.path2id('')`` instead. (Jelmer Vernooij) |
1161 | - # |
1162 | + with tree.lock_read(): |
1163 | root_id = self.tree.path2id('') |
1164 | basis_tree = self.tree.basis_tree() |
1165 | - basis_tree.lock_read() |
1166 | - try: |
1167 | + with basis_tree.lock_read(): |
1168 | # print(':::->>second try block') |
1169 | for the_change in self.tree.iter_changes(basis_tree, want_unversioned=want_unversioned): |
1170 | # iter_changes now seems to appear to return a TreeChange type See Jelmer's 7390. |
1171 | @@ -641,12 +635,8 @@ |
1172 | dir_fileid = self.tree.path2id(dir_path) |
1173 | # print('\tname setting gave ', item_data, item_data.path, dir_path, name, dir_fileid) |
1174 | item_data.item.name = get_name(dir_fileid, dir_path, item_data.path, item_data.change) |
1175 | - finally: |
1176 | - basis_tree.unlock() |
1177 | # print('\n\t\t FIRST process_tree...', initial_checked_paths, load_dirs) |
1178 | self.process_tree(self.working_tree_get_children, initial_checked_paths, load_dirs) |
1179 | - finally: |
1180 | - tree.unlock() |
1181 | else: |
1182 | # print('\n\t\t SECOND process_tree...', initial_checked_paths, load_dirs) |
1183 | self.process_tree(self.revision_tree_get_children, initial_checked_paths, load_dirs) |
1184 | @@ -1579,11 +1569,8 @@ |
1185 | self.change_load_filter = change_load_filter |
1186 | |
1187 | if branch: |
1188 | - branch.lock_read() |
1189 | - try: |
1190 | + with branch.lock_read(): |
1191 | last_revno = branch.last_revision_info()[0] |
1192 | - finally: |
1193 | - branch.unlock() |
1194 | self.revno_item_delegate.set_max_revno(last_revno) |
1195 | # update width uncoditionally because we may change the revno column |
1196 | self.set_header_width_settings() |
1197 | @@ -1656,8 +1643,7 @@ |
1198 | |
1199 | def restore_state(self, state): |
1200 | (checked, expanded, selected, v_scroll) = state |
1201 | - self.tree.lock_read() |
1202 | - try: |
1203 | + with self.tree.lock_read(): |
1204 | if self.tree_model.checkable and checked is not None: |
1205 | for (ref, state) in checked: |
1206 | if not state == QtCore.Qt.PartiallyChecked: |
1207 | @@ -1679,12 +1665,9 @@ |
1208 | QtCore.QItemSelectionModel.SelectCurrent | |
1209 | QtCore.QItemSelectionModel.Rows) |
1210 | self.verticalScrollBar().setValue(v_scroll) |
1211 | - finally: |
1212 | - self.tree.unlock() |
1213 | |
1214 | def refresh(self): |
1215 | - self.tree.lock_read() |
1216 | - try: |
1217 | + with self.tree.lock_read(): |
1218 | state = self.get_state() |
1219 | self.tree_model.set_tree(self.tree, self.branch, |
1220 | self.changes_mode, self.want_unversioned, |
1221 | @@ -1699,8 +1682,6 @@ |
1222 | # after every time we do a layout changed. The issue is similar to |
1223 | # http://www.qtsoftware.com/developer/task-tracker/index_html?method=entry&id=236755 |
1224 | self.set_header_width_settings() |
1225 | - finally: |
1226 | - self.tree.unlock() |
1227 | |
1228 | def mousePressEvent(self, event): |
1229 | index = self.indexAt(event.pos()) |
1230 | @@ -1917,11 +1898,8 @@ |
1231 | item = items[0] |
1232 | |
1233 | if isinstance(self.tree, WorkingTree): |
1234 | - self.tree.lock_read() |
1235 | - try: |
1236 | + with self.tree.lock_read(): |
1237 | abspath = self.tree.abspath(item.path) |
1238 | - finally: |
1239 | - self.tree.unlock() |
1240 | url = QtCore.QUrl.fromLocalFile(abspath) |
1241 | QtGui.QDesktopServices.openUrl(url) |
1242 | else: |
1243 | @@ -2020,11 +1998,8 @@ |
1244 | QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No) |
1245 | if res == QtWidgets.QMessageBox.Yes: |
1246 | try: |
1247 | - self.tree.lock_write() |
1248 | - try: |
1249 | + with self.tree.lock_write(): |
1250 | self.tree.revert(paths, self.tree.basis_tree()) |
1251 | - finally: |
1252 | - self.tree.unlock() |
1253 | except Exception: |
1254 | report_exception(type=SUB_LOAD_METHOD, window=self.window()) |
1255 | # XXX - it would be good it we could just refresh the selected items |
1256 | |
1257 | === modified file 'lib/widgets/shelve.py' |
1258 | --- lib/widgets/shelve.py 2021-01-06 09:29:35 +0000 |
1259 | +++ lib/widgets/shelve.py 2022-07-06 15:37:54 +0000 |
1260 | @@ -17,6 +17,8 @@ |
1261 | # along with this program; if not, write to the Free Software |
1262 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
1263 | |
1264 | +from contextlib import ExitStack |
1265 | +import os |
1266 | import sys, time |
1267 | from PyQt5 import QtCore, QtGui, QtWidgets |
1268 | |
1269 | @@ -56,8 +58,6 @@ |
1270 | from breezy.shelf import ShelfCreator |
1271 | from breezy.shelf_ui import Shelver |
1272 | from breezy.osutils import split_lines |
1273 | -from cStringIO import StringIO |
1274 | -import os |
1275 | ''') |
1276 | |
1277 | |
1278 | @@ -453,15 +453,14 @@ |
1279 | self.hunk_view.set_tab_width(pixels) |
1280 | |
1281 | def refresh(self): |
1282 | - cleanup = [] |
1283 | - try: |
1284 | + with ExitStack() as es: |
1285 | old_rev = self.revision |
1286 | old_changes = self._get_change_dictionary() |
1287 | self.clear(clear_message = False) |
1288 | |
1289 | shelver, creator = self._create_shelver_and_creator() |
1290 | - cleanup.append(shelver.finalize) |
1291 | - cleanup.append(creator.finalize) |
1292 | + es.callback(shelver.finalize) |
1293 | + es.callback(creator.finalize) |
1294 | |
1295 | file_list = shelver.file_list |
1296 | if file_list: |
1297 | @@ -489,10 +488,6 @@ |
1298 | item = self._create_item(change, shelver, self.trees, old_changes) |
1299 | self.file_view.addTopLevelItem(item) |
1300 | |
1301 | - finally: |
1302 | - for func in cleanup: |
1303 | - func() |
1304 | - |
1305 | if self.select_all: |
1306 | self.check_all(True) |
1307 | self.select_all = False |
1308 | @@ -625,16 +620,15 @@ |
1309 | self.loaded = False |
1310 | |
1311 | def use_editor(self): |
1312 | - cleanup = [] |
1313 | items = self.file_view.selectedItems() |
1314 | if len(items) != 1 or items[0].change.status != 'modify text': |
1315 | return |
1316 | else: |
1317 | change = items[0].change |
1318 | - try: |
1319 | + with ExitStack() as es: |
1320 | target_tree, work_tree = self.trees |
1321 | - cleanup.append(work_tree.lock_read().unlock) |
1322 | - cleanup.append(target_tree.lock_read().unlock) |
1323 | + es.enter_context(work_tree.lock_read()) |
1324 | + es.enter_context(target_tree.lock_read()) |
1325 | config = work_tree.branch.get_config() |
1326 | change_editor = config.get_change_editor(target_tree, work_tree) |
1327 | if change_editor is None: |
1328 | @@ -643,16 +637,13 @@ |
1329 | self.editor_button.setEnabled(False) |
1330 | return |
1331 | |
1332 | - cleanup.append(change_editor.finish) |
1333 | + es.callback(change_editor.finish) |
1334 | lines = split_lines(change_editor.edit_file(change.file_id)) |
1335 | change_count = Shelver._count_changed_regions(change.work_lines, lines) |
1336 | if change_count > 0: |
1337 | change.edited_lines = lines |
1338 | self.update_item(items[0]) |
1339 | self.selected_file_changed() |
1340 | - finally: |
1341 | - while cleanup: |
1342 | - cleanup.pop()() |
1343 | |
1344 | def _get_change_dictionary(self): |
1345 | change_dict = {} |
1346 | @@ -683,59 +674,56 @@ |
1347 | QtWidgets.QMessageBox.information(self, gettext('Shelve'), gettext('No changes selected.'), gettext('&OK')) |
1348 | return |
1349 | |
1350 | - cleanup = [] |
1351 | - try: |
1352 | - shelver, creator = self._create_shelver_and_creator(destroy=destroy) |
1353 | - cleanup.append(shelver.finalize) |
1354 | - cleanup.append(creator.finalize) |
1355 | - trees = (shelver.target_tree, shelver.work_tree) |
1356 | - if len(trees[1].get_parent_ids()) > 1: |
1357 | - raise WorkingTreeHasPendingMarge |
1358 | - if self.revision != trees[0].get_revision_id(): |
1359 | - raise WorkingTreeHasChanged |
1360 | - |
1361 | - changes = [] |
1362 | - for ch in creator.iter_shelvable(): |
1363 | - change = Change(ch, shelver, trees) |
1364 | - key = (change.file_id, change.status) |
1365 | - org_change = change_dict.get(key) |
1366 | - if org_change is None: |
1367 | - continue |
1368 | - if not change.is_same_change(org_change): |
1369 | - raise WorkingTreeHasChanged |
1370 | - del(change_dict[key]) |
1371 | - changes.append(org_change) |
1372 | - |
1373 | - if change_dict: |
1374 | - raise WorkingTreeHasChanged |
1375 | - |
1376 | - for change in changes: |
1377 | - if change.status == 'modify text': |
1378 | - self.handle_modify_text(creator, change) |
1379 | - elif change.status == 'modify binary': |
1380 | - creator.shelve_content_change(change.data[1]) |
1381 | + with ExitStack() as es: |
1382 | + try: |
1383 | + shelver, creator = self._create_shelver_and_creator(destroy=destroy) |
1384 | + es.callback(shelver.finalize) |
1385 | + es.callback(creator.finalize) |
1386 | + trees = (shelver.target_tree, shelver.work_tree) |
1387 | + if len(trees[1].get_parent_ids()) > 1: |
1388 | + raise WorkingTreeHasPendingMarge |
1389 | + if self.revision != trees[0].get_revision_id(): |
1390 | + raise WorkingTreeHasChanged |
1391 | + |
1392 | + changes = [] |
1393 | + for ch in creator.iter_shelvable(): |
1394 | + change = Change(ch, shelver, trees) |
1395 | + key = (change.file_id, change.status) |
1396 | + org_change = change_dict.get(key) |
1397 | + if org_change is None: |
1398 | + continue |
1399 | + if not change.is_same_change(org_change): |
1400 | + raise WorkingTreeHasChanged |
1401 | + del(change_dict[key]) |
1402 | + changes.append(org_change) |
1403 | + |
1404 | + if change_dict: |
1405 | + raise WorkingTreeHasChanged |
1406 | + |
1407 | + for change in changes: |
1408 | + if change.status == 'modify text': |
1409 | + self.handle_modify_text(creator, change) |
1410 | + elif change.status == 'modify binary': |
1411 | + creator.shelve_content_change(change.data[1]) |
1412 | + else: |
1413 | + creator.shelve_change(change.data) |
1414 | + manager = shelver.work_tree.get_shelf_manager() |
1415 | + message = str(self.message.toPlainText()).strip() or gettext('<no message>') |
1416 | + if destroy: |
1417 | + creator.transform() |
1418 | + shelf_id = -1 |
1419 | else: |
1420 | - creator.shelve_change(change.data) |
1421 | - manager = shelver.work_tree.get_shelf_manager() |
1422 | - message = str(self.message.toPlainText()).strip() or gettext('<no message>') |
1423 | - if destroy: |
1424 | - creator.transform() |
1425 | - shelf_id = -1 |
1426 | - else: |
1427 | - shelf_id = manager.shelve_changes(creator, message) |
1428 | - |
1429 | - except WorkingTreeHasPendingMarge: |
1430 | - QtWidgets.QMessageBox.warning(self, gettext('Shelve'), |
1431 | - gettext('Operation aborted because working tree has pending merges.'), gettext('&OK')) |
1432 | - return |
1433 | - except WorkingTreeHasChanged: |
1434 | - QtWidgets.QMessageBox.warning(self, gettext('Shelve'), |
1435 | - gettext('Operation aborted because target files has been changed.'), gettext('&OK')) |
1436 | - return |
1437 | - |
1438 | - finally: |
1439 | - while cleanup: |
1440 | - cleanup.pop()() |
1441 | + shelf_id = manager.shelve_changes(creator, message) |
1442 | + |
1443 | + except WorkingTreeHasPendingMarge: |
1444 | + QtWidgets.QMessageBox.warning(self, gettext('Shelve'), |
1445 | + gettext('Operation aborted because working tree has pending merges.'), gettext('&OK')) |
1446 | + return |
1447 | + except WorkingTreeHasChanged: |
1448 | + QtWidgets.QMessageBox.warning(self, gettext('Shelve'), |
1449 | + gettext('Operation aborted because target files has been changed.'), gettext('&OK')) |
1450 | + return |
1451 | + |
1452 | self.shelfCreated.emit(shelf_id) |
1453 | self.clear() |
1454 | |
1455 | @@ -888,12 +876,12 @@ |
1456 | continue |
1457 | if bottom < y1: |
1458 | break |
1459 | - painter.fillRect(6, y1, 13, 13, QtCore.Qt.white) |
1460 | + painter.fillRect(6, int(y1), 13, 13, QtCore.Qt.white) |
1461 | |
1462 | - painter.drawRect(6, y1, 13, 13) |
1463 | + painter.drawRect(6, int(y1), 13, 13) |
1464 | if hunk.selected: |
1465 | - painter.drawLine(9, y1 + 7, 12, y1 + 10) |
1466 | - painter.drawLine(16, y1 + 3, 12, y1 + 10) |
1467 | + painter.drawLine(9, int(y1) + 7, 12, int(y1) + 10) |
1468 | + painter.drawLine(16, int(y1) + 3, 12, int(y1) + 10) |
1469 | |
1470 | del painter |
1471 | |
1472 | @@ -942,7 +930,7 @@ |
1473 | self.monospacedInactiveFormat.setForeground(QtGui.QColor(128, 128, 128)) |
1474 | |
1475 | titleFont = QtGui.QFont(monospacedFont) |
1476 | - titleFont.setPointSize(titleFont.pointSize() * 140 / 100) |
1477 | + titleFont.setPointSize(titleFont.pointSize() * 140 // 100) |
1478 | titleFont.setBold(True) |
1479 | titleFont.setItalic(True) |
1480 | |
1481 | @@ -1062,17 +1050,17 @@ |
1482 | continue |
1483 | if not self.complete: |
1484 | # Fill header rect. |
1485 | - painter.fillRect(left, y1, width, 20, self.header_color) |
1486 | + painter.fillRect(left, int(y1), width, 20, self.header_color) |
1487 | # Overlay focus rect. |
1488 | if i == self._focused_index: |
1489 | if self.hasFocus(): |
1490 | color = self.focus_color |
1491 | else: |
1492 | color = self.focus_color_inactive |
1493 | - painter.fillRect(left, y1, width, y2 - y1, color) |
1494 | + painter.fillRect(left, int(y1), width, int(y2 - y1), color) |
1495 | # Draw border. |
1496 | - painter.drawLine(left, y1, right, y1) |
1497 | - painter.drawLine(left, y2, right, y2) |
1498 | + painter.drawLine(left, int(y1), right, int(y1)) |
1499 | + painter.drawLine(left, int(y2), right, int(y2)) |
1500 | |
1501 | def move_next(self): |
1502 | index = int(self._focused_index + 1) |
1503 | @@ -1127,8 +1115,8 @@ |
1504 | MARGIN = 24 |
1505 | height = self.viewport().height() |
1506 | cur_pos = sbar.value() |
1507 | - max_pos = self.hunk_list[index][1] - MARGIN |
1508 | - min_pos = self.hunk_list[index][2] - height + MARGIN |
1509 | + max_pos = int(self.hunk_list[index][1] - MARGIN) |
1510 | + min_pos = int(self.hunk_list[index][2] - height + MARGIN) |
1511 | if max_pos <= min_pos or max_pos < cur_pos: |
1512 | sbar.setValue(max_pos) |
1513 | elif cur_pos < min_pos: |
1514 | |
1515 | === modified file 'lib/widgets/shelvelist.py' |
1516 | --- lib/widgets/shelvelist.py 2021-01-06 09:29:35 +0000 |
1517 | +++ lib/widgets/shelvelist.py 2022-07-06 15:37:54 +0000 |
1518 | @@ -17,6 +17,8 @@ |
1519 | # along with this program; if not, write to the Free Software |
1520 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
1521 | |
1522 | +from contextlib import ExitStack |
1523 | + |
1524 | import sys, time |
1525 | from PyQt5 import QtCore, QtGui, QtWidgets |
1526 | from PyQt5.QtGui import QKeySequence |
1527 | @@ -55,7 +57,6 @@ |
1528 | from breezy.plugins.qbrz.lib.widgets.texteditaccessory import setup_guidebar_for_find |
1529 | from breezy.lazy_import import lazy_import |
1530 | lazy_import(globals(), ''' |
1531 | -from breezy import transform |
1532 | from breezy.workingtree import WorkingTree |
1533 | from breezy.plugins.qbrz.lib.encoding_selector import EncodingMenuSelector |
1534 | from breezy.plugins.qbrz.lib.diff import DiffItem |
1535 | @@ -274,8 +275,7 @@ |
1536 | self.loaded = False |
1537 | self.clear() |
1538 | tree = WorkingTree.open_containing(self.directory)[0] |
1539 | - tree.lock_read() |
1540 | - try: |
1541 | + with tree.lock_read(): |
1542 | manager = tree.get_shelf_manager() |
1543 | shelves = manager.active_shelves() |
1544 | for shelf_id in reversed(shelves): |
1545 | @@ -298,8 +298,6 @@ |
1546 | self.tabwidth_selector.setTabWidth(tabwidth) |
1547 | self._on_tabwidth_changed(tabwidth) |
1548 | |
1549 | - finally: |
1550 | - tree.unlock() |
1551 | self.update() |
1552 | self.loaded = True |
1553 | |
1554 | @@ -312,18 +310,17 @@ |
1555 | self.manager = None |
1556 | |
1557 | def show_changes(self, shelf_id): |
1558 | - cleanup = [] |
1559 | shelf_file = self.manager.read_shelf(shelf_id) |
1560 | - cleanup.append(shelf_file.close) |
1561 | - try: |
1562 | + with ExitStack() as es: |
1563 | + es.callback(shelf_file.close) |
1564 | records = Unshelver.iter_records(shelf_file) |
1565 | revid = Unshelver.parse_metadata(records)[b'revision_id'] |
1566 | try: |
1567 | base_tree = self.tree.revision_tree(revid) |
1568 | except NoSuchRevisionInTree: |
1569 | base_tree = self.tree.branch.repository.revision_tree(revid) |
1570 | - preview = transform.TransformPreview(base_tree) |
1571 | - cleanup.append(preview.finalize) |
1572 | + preview = base_tree.preview_transform() |
1573 | + es.callback(preview.finalize) |
1574 | preview.deserialize(records) |
1575 | |
1576 | tabwidth = get_tab_width_pixels(self.tree.branch) |
1577 | @@ -332,10 +329,6 @@ |
1578 | |
1579 | self.load_diff(preview.get_preview_tree(), base_tree) |
1580 | |
1581 | - finally: |
1582 | - for func in cleanup: |
1583 | - func() |
1584 | - |
1585 | def load_diff(self, tree, base_tree): |
1586 | self.file_view.clear() |
1587 |