Merge ~isidroas/ubuntu/+source/command-not-found:black_formatter into ubuntu/+source/command-not-found:ubuntu/devel
- Git
- lp:~isidroas/ubuntu/+source/command-not-found
- black_formatter
- Merge into ubuntu/devel
Proposed by
isidro
Status: | Needs review |
---|---|
Proposed branch: | ~isidroas/ubuntu/+source/command-not-found:black_formatter |
Merge into: | ubuntu/+source/command-not-found:ubuntu/devel |
Diff against target: |
1407 lines (+418/-224) 9 files modified
CommandNotFound/CommandNotFound.py (+173/-68) CommandNotFound/__init__.py (+0/-1) CommandNotFound/db/creator.py (+114/-63) CommandNotFound/db/db.py (+6/-5) CommandNotFound/db/tests/test_db.py (+61/-41) CommandNotFound/tests/test_command_not_found.py (+29/-26) CommandNotFound/tests/test_pyflakes.py (+4/-3) CommandNotFound/util.py (+17/-5) setup.py (+14/-12) |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Julian Andres Klode | Pending | ||
git-ubuntu import | Pending | ||
Review via email: mp+461374@code.launchpad.net |
Commit message
Description of the change
The black formatter (https:/
To post a comment you must log in.
Unmerged commits
- 50b23e1... by isidro
-
black formatter
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | diff --git a/CommandNotFound/CommandNotFound.py b/CommandNotFound/CommandNotFound.py |
2 | index 74f1b89..8df73e6 100644 |
3 | --- a/CommandNotFound/CommandNotFound.py |
4 | +++ b/CommandNotFound/CommandNotFound.py |
5 | @@ -24,32 +24,31 @@ else: |
6 | _gettext_method = "ugettext" |
7 | _ = getattr(gettext.translation("command-not-found", fallback=True), _gettext_method) |
8 | |
9 | - |
10 | + |
11 | def similar_words(word): |
12 | """ |
13 | return a set with spelling1 distance alternative spellings |
14 | |
15 | based on http://norvig.com/spell-correct.html |
16 | """ |
17 | - alphabet = 'abcdefghijklmnopqrstuvwxyz-_0123456789' |
18 | + alphabet = "abcdefghijklmnopqrstuvwxyz-_0123456789" |
19 | s = [(word[:i], word[i:]) for i in range(len(word) + 1)] |
20 | deletes = [a + b[1:] for a, b in s if b] |
21 | transposes = [a + b[1] + b[0] + b[2:] for a, b in s if len(b) > 1] |
22 | replaces = [a + c + b[1:] for a, b in s for c in alphabet if b] |
23 | - inserts = [a + c + b for a, b in s for c in alphabet] |
24 | + inserts = [a + c + b for a, b in s for c in alphabet] |
25 | return set(deletes + transposes + replaces + inserts) |
26 | |
27 | |
28 | def user_can_sudo(): |
29 | try: |
30 | groups = posix.getgroups() |
31 | - return (grp.getgrnam("sudo")[2] in groups or |
32 | - grp.getgrnam("admin")[2] in groups) |
33 | + return grp.getgrnam("sudo")[2] in groups or grp.getgrnam("admin")[2] in groups |
34 | except KeyError: |
35 | return False |
36 | |
37 | |
38 | -# the new style DB - if that exists we skip the legacy DB |
39 | +# the new style DB - if that exists we skip the legacy DB |
40 | dbpath = "/var/lib/command-not-found/commands.db" |
41 | |
42 | |
43 | @@ -57,7 +56,7 @@ class CommandNotFound(object): |
44 | |
45 | programs_dir = "programs.d" |
46 | max_len = 256 |
47 | - |
48 | + |
49 | prefixes = ( |
50 | "/snap/bin", |
51 | "/bin", |
52 | @@ -66,7 +65,8 @@ class CommandNotFound(object): |
53 | "/sbin", |
54 | "/usr/sbin", |
55 | "/usr/local/sbin", |
56 | - "/usr/games") |
57 | + "/usr/games", |
58 | + ) |
59 | |
60 | snap_cmd = "/usr/bin/snap" |
61 | |
62 | @@ -83,13 +83,13 @@ class CommandNotFound(object): |
63 | self.euid = posix.geteuid() |
64 | |
65 | def spelling_suggestions(self, word, min_len=3): |
66 | - """ try to correct the spelling """ |
67 | + """try to correct the spelling""" |
68 | possible_alternatives = [] |
69 | if not (min_len <= len(word) <= self.max_len): |
70 | return possible_alternatives |
71 | for w in similar_words(word): |
72 | packages = self.get_packages(w) |
73 | - for (package, ver, comp) in packages: |
74 | + for package, ver, comp in packages: |
75 | possible_alternatives.append((w, package, comp, ver)) |
76 | return possible_alternatives |
77 | |
78 | @@ -105,10 +105,16 @@ class CommandNotFound(object): |
79 | try: |
80 | with open(os.devnull) as devnull: |
81 | output = subprocess.check_output( |
82 | - [self.snap_cmd, "advise-snap", "--format=json", |
83 | - "--command", command], |
84 | + [ |
85 | + self.snap_cmd, |
86 | + "advise-snap", |
87 | + "--format=json", |
88 | + "--command", |
89 | + command, |
90 | + ], |
91 | stderr=devnull, |
92 | - universal_newlines=True) |
93 | + universal_newlines=True, |
94 | + ) |
95 | except subprocess.CalledProcessError as e: |
96 | logging.debug("calling snap advice-snap returned an error: %s" % e) |
97 | return [], [] |
98 | @@ -120,14 +126,22 @@ class CommandNotFound(object): |
99 | return [], [] |
100 | for snap in snaps: |
101 | if snap["Command"] == command: |
102 | - exact_result.append((snap["Snap"], snap["Command"], snap.get("Version"))) |
103 | + exact_result.append( |
104 | + (snap["Snap"], snap["Command"], snap.get("Version")) |
105 | + ) |
106 | else: |
107 | - mispell_result.append((snap["Command"], snap["Snap"], snap.get("Version"))) |
108 | + mispell_result.append( |
109 | + (snap["Command"], snap["Snap"], snap.get("Version")) |
110 | + ) |
111 | return exact_result, mispell_result |
112 | - |
113 | + |
114 | def getBlacklist(self): |
115 | try: |
116 | - with open(os.sep.join((os.getenv("HOME", "/root"), ".command-not-found.blacklist"))) as blacklist: |
117 | + with open( |
118 | + os.sep.join( |
119 | + (os.getenv("HOME", "/root"), ".command-not-found.blacklist") |
120 | + ) |
121 | + ) as blacklist: |
122 | return [line.strip() for line in blacklist if line.strip() != ""] |
123 | except IOError: |
124 | return [] |
125 | @@ -136,6 +150,7 @@ class CommandNotFound(object): |
126 | try: |
127 | import apt_pkg |
128 | from aptsources.sourceslist import SourcesList |
129 | + |
130 | apt_pkg.init() |
131 | except (SystemError, ImportError): |
132 | return [] |
133 | @@ -158,7 +173,7 @@ class CommandNotFound(object): |
134 | return |
135 | if package_name: |
136 | prompt = _("Do you want to install it? (N/y)") |
137 | - if sys.version >= '3': |
138 | + if sys.version >= "3": |
139 | answer = input(prompt) |
140 | raw_input = lambda x: x # pyflakes |
141 | else: |
142 | @@ -175,28 +190,45 @@ class CommandNotFound(object): |
143 | print("%s" % install_command, file=sys.stdout) |
144 | subprocess.call(install_command.split(), shell=False) |
145 | |
146 | - def print_spelling_suggestions(self, word, mispell_packages, mispell_snaps, max_alt=15): |
147 | - """ print spelling suggestions for packages and snaps """ |
148 | - if len(mispell_packages)+len(mispell_snaps) > max_alt: |
149 | - print(_("Command '%s' not found, but there are %s similar ones.") % (word, len(mispell_packages)), file=self.output_fd) |
150 | + def print_spelling_suggestions( |
151 | + self, word, mispell_packages, mispell_snaps, max_alt=15 |
152 | + ): |
153 | + """print spelling suggestions for packages and snaps""" |
154 | + if len(mispell_packages) + len(mispell_snaps) > max_alt: |
155 | + print( |
156 | + _("Command '%s' not found, but there are %s similar ones.") |
157 | + % (word, len(mispell_packages)), |
158 | + file=self.output_fd, |
159 | + ) |
160 | self.output_fd.flush() |
161 | return |
162 | - elif len(mispell_packages)+len(mispell_snaps) > 0: |
163 | - print(_("Command '%s' not found, did you mean:") % word, file=self.output_fd) |
164 | - for (command, snap, ver) in mispell_snaps: |
165 | + elif len(mispell_packages) + len(mispell_snaps) > 0: |
166 | + print( |
167 | + _("Command '%s' not found, did you mean:") % word, file=self.output_fd |
168 | + ) |
169 | + for command, snap, ver in mispell_snaps: |
170 | if ver: |
171 | ver = " (%s)" % ver |
172 | else: |
173 | ver = "" |
174 | - print(_(" command '%s' from snap %s%s") % (command, snap, ver), file=self.output_fd) |
175 | - for (command, package, comp, ver) in mispell_packages: |
176 | + print( |
177 | + _(" command '%s' from snap %s%s") % (command, snap, ver), |
178 | + file=self.output_fd, |
179 | + ) |
180 | + for command, package, comp, ver in mispell_packages: |
181 | if ver: |
182 | ver = " (%s)" % ver |
183 | else: |
184 | ver = "" |
185 | - print(_(" command '%s' from deb %s%s") % (command, package, ver), file=self.output_fd) |
186 | + print( |
187 | + _(" command '%s' from deb %s%s") % (command, package, ver), |
188 | + file=self.output_fd, |
189 | + ) |
190 | if len(mispell_snaps) > 0: |
191 | - print(_("See 'snap info <snapname>' for additional versions."), file=self.output_fd) |
192 | + print( |
193 | + _("See 'snap info <snapname>' for additional versions."), |
194 | + file=self.output_fd, |
195 | + ) |
196 | elif len(mispell_packages) > 0: |
197 | if self.user_can_sudo: |
198 | print(_("Try: %s <deb name>") % "sudo apt install", file=self.output_fd) |
199 | @@ -205,8 +237,11 @@ class CommandNotFound(object): |
200 | self.output_fd.flush() |
201 | |
202 | def _print_exact_header(self, command): |
203 | - print(_("Command '%(command)s' not found, but can be installed with:") % { |
204 | - 'command': command}, file=self.output_fd) |
205 | + print( |
206 | + _("Command '%(command)s' not found, but can be installed with:") |
207 | + % {"command": command}, |
208 | + file=self.output_fd, |
209 | + ) |
210 | |
211 | def advice_single_snap_package(self, command, packages, snaps): |
212 | self._print_exact_header(command) |
213 | @@ -219,7 +254,7 @@ class CommandNotFound(object): |
214 | print("snap install %s" % snap[0], file=self.output_fd) |
215 | print(_("Please ask your administrator.")) |
216 | self.output_fd.flush() |
217 | - |
218 | + |
219 | def advice_single_deb_package(self, command, packages, snaps): |
220 | self._print_exact_header(command) |
221 | if self.euid == 0: |
222 | @@ -232,17 +267,21 @@ class CommandNotFound(object): |
223 | print("apt install %s" % packages[0][0], file=self.output_fd) |
224 | print(_("Please ask your administrator.")) |
225 | if not packages[0][2] in self.sources_list: |
226 | - print(_("You will have to enable the component called '%s'") % packages[0][2], file=self.output_fd) |
227 | + print( |
228 | + _("You will have to enable the component called '%s'") |
229 | + % packages[0][2], |
230 | + file=self.output_fd, |
231 | + ) |
232 | self.output_fd.flush() |
233 | |
234 | def sudo(self): |
235 | if self.euid != 0 and self.user_can_sudo: |
236 | return "sudo " |
237 | - return "" |
238 | + return "" |
239 | |
240 | def advice_multi_deb_package(self, command, packages, snaps): |
241 | self._print_exact_header(command) |
242 | - pad = max([len(s[0]) for s in snaps+packages]) |
243 | + pad = max([len(s[0]) for s in snaps + packages]) |
244 | for i, package in enumerate(packages): |
245 | ver = "" |
246 | if package[1]: |
247 | @@ -251,16 +290,27 @@ class CommandNotFound(object): |
248 | else: |
249 | ver = " # version %s" % (package[1]) |
250 | if package[2] in self.sources_list: |
251 | - print("%sapt install %-*s%s" % (self.sudo(), pad, package[0], ver), file=self.output_fd) |
252 | + print( |
253 | + "%sapt install %-*s%s" % (self.sudo(), pad, package[0], ver), |
254 | + file=self.output_fd, |
255 | + ) |
256 | else: |
257 | - print("%sapt install %-*s%s" % (self.sudo(), pad, package[0], ver) + " (" + _("You will have to enable component called '%s'") % package[2] + ")", file=self.output_fd) |
258 | + print( |
259 | + "%sapt install %-*s%s" % (self.sudo(), pad, package[0], ver) |
260 | + + " (" |
261 | + + _("You will have to enable component called '%s'") % package[2] |
262 | + + ")", |
263 | + file=self.output_fd, |
264 | + ) |
265 | if self.euid != 0 and not self.user_can_sudo: |
266 | - print(_("Ask your administrator to install one of them."), file=self.output_fd) |
267 | + print( |
268 | + _("Ask your administrator to install one of them."), file=self.output_fd |
269 | + ) |
270 | self.output_fd.flush() |
271 | |
272 | def advice_multi_snap_packages(self, command, packages, snaps): |
273 | self._print_exact_header(command) |
274 | - pad = max([len(s[0]) for s in snaps+packages]) |
275 | + pad = max([len(s[0]) for s in snaps + packages]) |
276 | for i, snap in enumerate(snaps): |
277 | ver = "" |
278 | if snap[2]: |
279 | @@ -268,69 +318,109 @@ class CommandNotFound(object): |
280 | ver = " # version %s, or" % snap[2] |
281 | else: |
282 | ver = " # version %s" % snap[2] |
283 | - print("%ssnap install %-*s%s" % (self.sudo(), pad, snap[0], ver), file=self.output_fd) |
284 | - print(_("See 'snap info <snapname>' for additional versions."), file=self.output_fd) |
285 | + print( |
286 | + "%ssnap install %-*s%s" % (self.sudo(), pad, snap[0], ver), |
287 | + file=self.output_fd, |
288 | + ) |
289 | + print( |
290 | + _("See 'snap info <snapname>' for additional versions."), |
291 | + file=self.output_fd, |
292 | + ) |
293 | self.output_fd.flush() |
294 | |
295 | def advice_multi_mixed_packages(self, command, packages, snaps): |
296 | self._print_exact_header(command) |
297 | - pad = max([len(s[0]) for s in snaps+packages]) |
298 | + pad = max([len(s[0]) for s in snaps + packages]) |
299 | for i, snap in enumerate(snaps): |
300 | - ver="" |
301 | + ver = "" |
302 | if snap[2]: |
303 | if i == 0: |
304 | ver = " # version %s, or" % snap[2] |
305 | else: |
306 | ver = " # version %s" % snap[2] |
307 | - print("%ssnap install %-*s%s" % (self.sudo(), pad, snap[0], ver), file=self.output_fd) |
308 | + print( |
309 | + "%ssnap install %-*s%s" % (self.sudo(), pad, snap[0], ver), |
310 | + file=self.output_fd, |
311 | + ) |
312 | for package in packages: |
313 | - ver="" |
314 | + ver = "" |
315 | if package[1]: |
316 | ver = " # version %s" % package[1] |
317 | - print("%sapt install %-*s%s" % (self.sudo(), pad, package[0], ver), file=self.output_fd) |
318 | + print( |
319 | + "%sapt install %-*s%s" % (self.sudo(), pad, package[0], ver), |
320 | + file=self.output_fd, |
321 | + ) |
322 | if len(snaps) == 1: |
323 | - print(_("See 'snap info %s' for additional versions.") % snaps[0][0], file=self.output_fd) |
324 | + print( |
325 | + _("See 'snap info %s' for additional versions.") % snaps[0][0], |
326 | + file=self.output_fd, |
327 | + ) |
328 | else: |
329 | - print(_("See 'snap info <snapname>' for additional versions."), file=self.output_fd) |
330 | + print( |
331 | + _("See 'snap info <snapname>' for additional versions."), |
332 | + file=self.output_fd, |
333 | + ) |
334 | self.output_fd.flush() |
335 | - |
336 | + |
337 | def advise(self, command, ignore_installed=False): |
338 | - " give advice where to find the given command to stderr " |
339 | + "give advice where to find the given command to stderr" |
340 | + |
341 | def _in_prefix(prefix, command): |
342 | - " helper that returns if a command is found in the given prefix " |
343 | - return (os.path.exists(os.path.join(prefix, command)) |
344 | - and not os.path.isdir(os.path.join(prefix, command))) |
345 | + "helper that returns if a command is found in the given prefix" |
346 | + return os.path.exists(os.path.join(prefix, command)) and not os.path.isdir( |
347 | + os.path.join(prefix, command) |
348 | + ) |
349 | |
350 | if len(command) > self.max_len: |
351 | return False |
352 | - |
353 | + |
354 | if command.startswith("/"): |
355 | if os.path.exists(command): |
356 | prefixes = [os.path.dirname(command)] |
357 | else: |
358 | prefixes = [] |
359 | else: |
360 | - prefixes = [prefix for prefix in self.prefixes if _in_prefix(prefix, command)] |
361 | + prefixes = [ |
362 | + prefix for prefix in self.prefixes if _in_prefix(prefix, command) |
363 | + ] |
364 | |
365 | # check if we have it in a common prefix that may not be in the PATH |
366 | if prefixes and not ignore_installed: |
367 | if len(prefixes) == 1: |
368 | - print(_("Command '%(command)s' is available in '%(place)s'") % {"command": command, "place": os.path.join(prefixes[0], command)}, file=self.output_fd) |
369 | + print( |
370 | + _("Command '%(command)s' is available in '%(place)s'") |
371 | + % {"command": command, "place": os.path.join(prefixes[0], command)}, |
372 | + file=self.output_fd, |
373 | + ) |
374 | else: |
375 | - print(_("Command '%(command)s' is available in the following places") % {"command": command}, file=self.output_fd) |
376 | + print( |
377 | + _("Command '%(command)s' is available in the following places") |
378 | + % {"command": command}, |
379 | + file=self.output_fd, |
380 | + ) |
381 | for prefix in prefixes: |
382 | print(" * %s" % os.path.join(prefix, command), file=self.output_fd) |
383 | missing = list(set(prefixes) - set(os.getenv("PATH", "").split(":"))) |
384 | if len(missing) > 0: |
385 | - print(_("The command could not be located because '%s' is not included in the PATH environment variable.") % ":".join(missing), file=self.output_fd) |
386 | + print( |
387 | + _( |
388 | + "The command could not be located because '%s' is not included in the PATH environment variable." |
389 | + ) |
390 | + % ":".join(missing), |
391 | + file=self.output_fd, |
392 | + ) |
393 | if "sbin" in ":".join(missing): |
394 | - print(_("This is most likely caused by the lack of administrative privileges associated with your user account."), file=self.output_fd) |
395 | + print( |
396 | + _( |
397 | + "This is most likely caused by the lack of administrative privileges associated with your user account." |
398 | + ), |
399 | + file=self.output_fd, |
400 | + ) |
401 | return False |
402 | |
403 | # do not give advice if we are in a situation where apt |
404 | # or aptitude are not available (LP: #394843) |
405 | - if not (os.path.exists("/usr/bin/apt") or |
406 | - os.path.exists("/usr/bin/aptitude")): |
407 | + if not (os.path.exists("/usr/bin/apt") or os.path.exists("/usr/bin/aptitude")): |
408 | return False |
409 | |
410 | if command in self.getBlacklist(): |
411 | @@ -340,18 +430,29 @@ class CommandNotFound(object): |
412 | # people to use python3 only, and command-not-found depends on |
413 | # python3, so must be available |
414 | if command == "python": |
415 | - print(_("Command '%s' not found, did you mean:") % command, file=self.output_fd) |
416 | - print(_(" command '%s' from deb %s%s") % ("python3", "python3", ""), file=self.output_fd) |
417 | - print(_(" command '%s' from deb %s%s") % ("python", "python-is-python3", ""), file=self.output_fd) |
418 | + print( |
419 | + _("Command '%s' not found, did you mean:") % command, |
420 | + file=self.output_fd, |
421 | + ) |
422 | + print( |
423 | + _(" command '%s' from deb %s%s") % ("python3", "python3", ""), |
424 | + file=self.output_fd, |
425 | + ) |
426 | + print( |
427 | + _(" command '%s' from deb %s%s") % ("python", "python-is-python3", ""), |
428 | + file=self.output_fd, |
429 | + ) |
430 | return True |
431 | - |
432 | + |
433 | packages = self.get_packages(command) |
434 | snaps, mispell_snaps = self.get_snaps(command) |
435 | logging.debug("got debs: %s snaps: %s" % (packages, snaps)) |
436 | if len(packages) == 0 and len(snaps) == 0: |
437 | mispell_packages = self.spelling_suggestions(command) |
438 | if len(mispell_packages) > 0 or len(mispell_snaps) > 0: |
439 | - self.print_spelling_suggestions(command, mispell_packages, mispell_snaps) |
440 | + self.print_spelling_suggestions( |
441 | + command, mispell_packages, mispell_snaps |
442 | + ) |
443 | elif len(packages) == 0 and len(snaps) == 1: |
444 | self.advice_single_snap_package(command, packages, snaps) |
445 | elif len(snaps) > 0 and len(packages) == 0: |
446 | @@ -363,5 +464,9 @@ class CommandNotFound(object): |
447 | elif len(packages) > 0 and len(snaps) > 0: |
448 | self.advice_multi_mixed_packages(command, packages, snaps) |
449 | |
450 | - return (len(packages) > 0 or len(snaps) > 0 or |
451 | - len(mispell_snaps) > 0 or len(mispell_packages) > 0) |
452 | + return ( |
453 | + len(packages) > 0 |
454 | + or len(snaps) > 0 |
455 | + or len(mispell_snaps) > 0 |
456 | + or len(mispell_packages) > 0 |
457 | + ) |
458 | diff --git a/CommandNotFound/__init__.py b/CommandNotFound/__init__.py |
459 | index 66b6508..c396168 100644 |
460 | --- a/CommandNotFound/__init__.py |
461 | +++ b/CommandNotFound/__init__.py |
462 | @@ -1,2 +1 @@ |
463 | from __future__ import absolute_import |
464 | - |
465 | diff --git a/CommandNotFound/db/creator.py b/CommandNotFound/db/creator.py |
466 | index 8b86375..de82b0b 100755 |
467 | --- a/CommandNotFound/db/creator.py |
468 | +++ b/CommandNotFound/db/creator.py |
469 | @@ -10,6 +10,7 @@ import sys |
470 | import time |
471 | |
472 | import apt_pkg |
473 | + |
474 | apt_pkg.init() |
475 | |
476 | # TODO: |
477 | @@ -17,19 +18,19 @@ apt_pkg.init() |
478 | # - add apt::update::post-invoke-success handler |
479 | |
480 | component_priorities = { |
481 | - 'main': 120, |
482 | - 'universe': 100, |
483 | - 'contrib': 80, |
484 | - 'non-free-firmware': 60, |
485 | - 'restricted': 60, |
486 | - 'non-free': 40, |
487 | - 'multiverse': 20, |
488 | + "main": 120, |
489 | + "universe": 100, |
490 | + "contrib": 80, |
491 | + "non-free-firmware": 60, |
492 | + "restricted": 60, |
493 | + "non-free": 40, |
494 | + "multiverse": 20, |
495 | } |
496 | |
497 | # pkgnames in here are blacklisted |
498 | |
499 | |
500 | -create_db_sql=""" |
501 | +create_db_sql = """ |
502 | CREATE TABLE IF NOT EXISTS "commands" |
503 | ( |
504 | [cmdID] INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, |
505 | @@ -58,12 +59,15 @@ create_db_sql=""" |
506 | # - add "last-mtime" into the DB, then we can skip all packages files |
507 | # where the mtime is older and we only need to update the DB |
508 | |
509 | + |
510 | class measure: |
511 | def __init__(self, what, stats): |
512 | self.what = what |
513 | self.stats = stats |
514 | + |
515 | def __enter__(self): |
516 | self.now = time.time() |
517 | + |
518 | def __exit__(self, *args): |
519 | if not self.what in self.stats: |
520 | self.stats[self.what] = 0 |
521 | @@ -82,14 +86,14 @@ class DbCreator: |
522 | def __init__(self, files): |
523 | self.files = files |
524 | self.primary_arch = apt_pkg.get_architectures()[0] |
525 | - self.stats = {"total": 0,"total_time": time.time()} |
526 | + self.stats = {"total": 0, "total_time": time.time()} |
527 | + |
528 | def create(self, dbname): |
529 | - metadata_file = dbname+".metadata" |
530 | + metadata_file = dbname + ".metadata" |
531 | if not self._db_update_needed(metadata_file): |
532 | - logging.info( |
533 | - "%s does not require an update (inputs unchanged)", dbname) |
534 | + logging.info("%s does not require an update (inputs unchanged)", dbname) |
535 | return |
536 | - tmpdb = dbname+".tmp" |
537 | + tmpdb = dbname + ".tmp" |
538 | with sqlite3.connect(tmpdb) as con: |
539 | try: |
540 | con.executescript(create_db_sql) |
541 | @@ -99,8 +103,7 @@ class DbCreator: |
542 | # tmpdb. Just stop execution in this case, as the other process |
543 | # should produce the correct result. |
544 | if str(e) == "database is locked": |
545 | - logging.warning( |
546 | - "%s is locked by another process. Ignoring.", tmpdb) |
547 | + logging.warning("%s is locked by another process. Ignoring.", tmpdb) |
548 | sys.exit(0) |
549 | else: |
550 | raise e |
551 | @@ -111,6 +114,7 @@ class DbCreator: |
552 | # add new metadata |
553 | with open(metadata_file, "w") as fp: |
554 | json.dump(self._calc_input_metadata(), fp) |
555 | + |
556 | def _db_update_needed(self, metadata_file): |
557 | if not os.path.exists(metadata_file): |
558 | return True |
559 | @@ -121,33 +125,42 @@ class DbCreator: |
560 | except Exception as e: |
561 | logging.warning("cannot read %s: %s", metadata_file, e) |
562 | return True |
563 | + |
564 | def _calc_input_metadata(self): |
565 | meta = {} |
566 | for p in self.files: |
567 | st = os.stat(p) |
568 | meta[p] = { |
569 | - 'st_ino': st.st_ino, |
570 | - 'st_dev': st.st_dev, |
571 | - 'st_uid': st.st_uid, |
572 | - 'st_gid': st.st_gid, |
573 | - 'st_size': st.st_size, |
574 | - 'st_mtime': st.st_mtime, |
575 | + "st_ino": st.st_ino, |
576 | + "st_dev": st.st_dev, |
577 | + "st_uid": st.st_uid, |
578 | + "st_gid": st.st_gid, |
579 | + "st_size": st.st_size, |
580 | + "st_mtime": st.st_mtime, |
581 | } |
582 | return meta |
583 | + |
584 | def _fill_commands(self, con): |
585 | for f in self.files: |
586 | - with subprocess.Popen(["/usr/lib/apt/apt-helper", "cat-file", f], stdout=subprocess.PIPE) as sub: |
587 | + with subprocess.Popen( |
588 | + ["/usr/lib/apt/apt-helper", "cat-file", f], stdout=subprocess.PIPE |
589 | + ) as sub: |
590 | if "Contents" in f: |
591 | self._parse_single_contents_file(con, f, sub.stdout) |
592 | else: |
593 | self._parse_single_commands_file(con, sub.stdout) |
594 | if sub.wait() != 0: |
595 | - raise subprocess.CalledProcessError(returncode=sub.returncode, |
596 | - cmd="/usr/lib/apt/apt-helper cat-file {}".format(f)) |
597 | + raise subprocess.CalledProcessError( |
598 | + returncode=sub.returncode, |
599 | + cmd="/usr/lib/apt/apt-helper cat-file {}".format(f), |
600 | + ) |
601 | |
602 | self.stats["total_time"] = time.time() - self.stats["total_time"] |
603 | - logging.info("processed %i packages in %.2fs" % ( |
604 | - self.stats["total"], self.stats["total_time"])) |
605 | + logging.info( |
606 | + "processed %i packages in %.2fs" |
607 | + % (self.stats["total"], self.stats["total_time"]) |
608 | + ) |
609 | + |
610 | def _in_db(self, con, command, pkgname): |
611 | already_in_db = con.execute( |
612 | """ |
613 | @@ -155,73 +168,95 @@ class DbCreator: |
614 | FROM commands |
615 | INNER JOIN packages on packages.pkgID = commands.pkgID |
616 | WHERE commands.command=? AND packages.name=?; |
617 | - """, (command, pkgname)).fetchone() |
618 | + """, |
619 | + (command, pkgname), |
620 | + ).fetchone() |
621 | return already_in_db |
622 | + |
623 | def _delete_pkgid(self, con, pkgid): |
624 | - con.execute("DELETE FROM packages WHERE pkgID=?", (pkgid,) ) |
625 | - con.execute("DELETE FROM commands WHERE pkgID=?", (pkgid,) ) |
626 | + con.execute("DELETE FROM packages WHERE pkgID=?", (pkgid,)) |
627 | + con.execute("DELETE FROM commands WHERE pkgID=?", (pkgid,)) |
628 | + |
629 | def _get_pkgid(self, con, pkgname): |
630 | have_pkg = con.execute( |
631 | - "SELECT pkgID from packages WHERE name=?", (pkgname,)).fetchone() |
632 | + "SELECT pkgID from packages WHERE name=?", (pkgname,) |
633 | + ).fetchone() |
634 | if have_pkg: |
635 | return have_pkg[0] |
636 | return None |
637 | + |
638 | def _insert_package(self, con, pkgname, version, component, priority): |
639 | - cur=con.execute(""" |
640 | + cur = con.execute( |
641 | + """ |
642 | INSERT INTO packages (name, version, component, priority) |
643 | VALUES (?, ?, ?, ?); |
644 | - """, (pkgname, version, component, priority)) |
645 | + """, |
646 | + (pkgname, version, component, priority), |
647 | + ) |
648 | return cur.lastrowid |
649 | + |
650 | def _insert_command(self, con, command, pkg_id): |
651 | - con.execute(""" |
652 | + con.execute( |
653 | + """ |
654 | INSERT INTO commands (command, pkgID) VALUES (?, ?); |
655 | - """, (command, pkg_id)) |
656 | + """, |
657 | + (command, pkg_id), |
658 | + ) |
659 | + |
660 | def _parse_single_commands_file(self, con, fp): |
661 | tagf = apt_pkg.TagFile(fp) |
662 | # file empty |
663 | if not tagf.step(): |
664 | return |
665 | # read header |
666 | - suite=tagf.section["suite"] |
667 | + suite = tagf.section["suite"] |
668 | # FIXME: support backports |
669 | if suite.endswith("-backports"): |
670 | return |
671 | - component=tagf.section["component"] |
672 | - arch=tagf.section["arch"] |
673 | + component = tagf.section["component"] |
674 | + arch = tagf.section["arch"] |
675 | # FIXME: add code for secondary arch handling! |
676 | if arch != "all" and arch != self.primary_arch: |
677 | return |
678 | # step over the pkgs |
679 | while tagf.step(): |
680 | self.stats["total"] += 1 |
681 | - pkgname=tagf.section["name"] |
682 | + pkgname = tagf.section["name"] |
683 | # allow to override the viisble pkgname to accomodate for |
684 | # cases like "python2.7" which is part of python2.7-minimal |
685 | # but users should just install python2.7 |
686 | if tagf.section.get("visible-pkgname"): |
687 | pkgname = tagf.section["visible-pkgname"] |
688 | - version=tagf.section.get("version", "") |
689 | - ignore_commands=set() |
690 | + version = tagf.section.get("version", "") |
691 | + ignore_commands = set() |
692 | if tagf.section.get("ignore-commands", ""): |
693 | - ignore_commands=set(tagf.section.get("ignore-commands", "").split(",")) |
694 | + ignore_commands = set( |
695 | + tagf.section.get("ignore-commands", "").split(",") |
696 | + ) |
697 | for command in tagf.section["commands"].split(","): |
698 | if command in ignore_commands: |
699 | continue |
700 | # see if we have the command already |
701 | with measure("sql_already_db", self.stats): |
702 | - already_in_db=self._in_db(con, command, pkgname) |
703 | + already_in_db = self._in_db(con, command, pkgname) |
704 | if already_in_db: |
705 | # we found a version that is higher what we have |
706 | # in the DB -> remove current, insert higher |
707 | if apt_pkg.version_compare(version, already_in_db[2]) > 0: |
708 | - logging.debug("replacing exiting %s in DB (higher version)" % command) |
709 | + logging.debug( |
710 | + "replacing exiting %s in DB (higher version)" % command |
711 | + ) |
712 | with measure("sql_delete_already_in_db", self.stats): |
713 | self._delete_pkgid(con, already_in_db[0]) |
714 | else: |
715 | - logging.debug("skipping %s from %s (lower/same version)" % (command, suite)) |
716 | + logging.debug( |
717 | + "skipping %s from %s (lower/same version)" |
718 | + % (command, suite) |
719 | + ) |
720 | continue |
721 | - logging.debug("adding %s from %s/%s (%s)" % ( |
722 | - command, pkgname, version, suite)) |
723 | + logging.debug( |
724 | + "adding %s from %s/%s (%s)" % (command, pkgname, version, suite) |
725 | + ) |
726 | # insert new data |
727 | with measure("sql_have_pkg", self.stats): |
728 | pkg_id = self._get_pkgid(con, pkgname) |
729 | @@ -229,18 +264,24 @@ class DbCreator: |
730 | priority = component_priorities.get(component, 0) |
731 | priority += int(tagf.section.get("priority-bonus", "0")) |
732 | with measure("sql_insert_pkg", self.stats): |
733 | - pkg_id = self._insert_package(con, pkgname, version, component, priority) |
734 | + pkg_id = self._insert_package( |
735 | + con, pkgname, version, component, priority |
736 | + ) |
737 | with measure("sql_insert_cmd", self.stats): |
738 | self._insert_command(con, command, pkg_id) |
739 | |
740 | def _parse_single_contents_file(self, con, f, fp): |
741 | # read header |
742 | - suite=None # FIXME |
743 | + suite = None # FIXME |
744 | |
745 | for l in fp: |
746 | l = l.decode("utf-8") |
747 | - if not (l.startswith('usr/sbin') or l.startswith('usr/bin') or |
748 | - l.startswith('bin') or l.startswith('sbin')): |
749 | + if not ( |
750 | + l.startswith("usr/sbin") |
751 | + or l.startswith("usr/bin") |
752 | + or l.startswith("bin") |
753 | + or l.startswith("sbin") |
754 | + ): |
755 | continue |
756 | try: |
757 | command, pkgnames = l.split(None, 1) |
758 | @@ -249,41 +290,49 @@ class DbCreator: |
759 | |
760 | command = os.path.basename(command) |
761 | |
762 | - for pkgname in pkgnames.split(','): |
763 | + for pkgname in pkgnames.split(","): |
764 | try: |
765 | - section, pkgname = pkgname.strip().rsplit('/', 1) |
766 | + section, pkgname = pkgname.strip().rsplit("/", 1) |
767 | except ValueError: |
768 | pkgname = pkgname.strip() |
769 | section = "unknown" |
770 | - if len(section.split('/')) == 2: |
771 | - component, section = section.split('/') |
772 | + if len(section.split("/")) == 2: |
773 | + component, section = section.split("/") |
774 | else: |
775 | - component = 'main' |
776 | + component = "main" |
777 | |
778 | # FIXME - Don't really know how. |
779 | version = None |
780 | # see if we have the command already |
781 | with measure("sql_already_db", self.stats): |
782 | - already_in_db=self._in_db(con, command, pkgname) |
783 | + already_in_db = self._in_db(con, command, pkgname) |
784 | if already_in_db: |
785 | # we found a version that is higher what we have |
786 | # in the DB -> remove current, insert higher |
787 | if False and apt_pkg.version_compare(version, already_in_db[2]) > 0: |
788 | - logging.debug("replacing exiting %s in DB (higher version)" % command) |
789 | + logging.debug( |
790 | + "replacing exiting %s in DB (higher version)" % command |
791 | + ) |
792 | with measure("sql_delete_already_in_db", self.stats): |
793 | self._delete_pkgid(con, already_in_db[0]) |
794 | else: |
795 | - logging.debug("skipping %s from %s (lower/same version)" % (command, suite)) |
796 | + logging.debug( |
797 | + "skipping %s from %s (lower/same version)" |
798 | + % (command, suite) |
799 | + ) |
800 | continue |
801 | - logging.debug("adding %s from %s/%s (%s)" % ( |
802 | - command, pkgname, version, suite)) |
803 | + logging.debug( |
804 | + "adding %s from %s/%s (%s)" % (command, pkgname, version, suite) |
805 | + ) |
806 | # insert new data |
807 | with measure("sql_have_pkg", self.stats): |
808 | pkg_id = self._get_pkgid(con, pkgname) |
809 | if not pkg_id: |
810 | priority = component_priorities.get(component, 0) |
811 | with measure("sql_insert_pkg", self.stats): |
812 | - pkg_id = self._insert_package(con, pkgname, version, component, priority) |
813 | + pkg_id = self._insert_package( |
814 | + con, pkgname, version, component, priority |
815 | + ) |
816 | with measure("sql_insert_cmd", self.stats): |
817 | self._insert_command(con, command, pkg_id) |
818 | |
819 | @@ -293,10 +342,12 @@ if __name__ == "__main__": |
820 | if len(sys.argv) < 3: |
821 | print("usage: %s <output-db-path> <files...>" % sys.argv[0]) |
822 | print(" e.g.: %s commands.db ./dists/*/*/*/Commands-*" % sys.argv[0]) |
823 | - print(" e.g.: %s /var/lib/command-not-found/commands.db /var/lib/apt/lists/*Commands-*", sys.argv[0]) |
824 | + print( |
825 | + " e.g.: %s /var/lib/command-not-found/commands.db /var/lib/apt/lists/*Commands-*", |
826 | + sys.argv[0], |
827 | + ) |
828 | sys.exit(1) |
829 | col = DbCreator(sys.argv[2:]) |
830 | col.create(sys.argv[1]) |
831 | for stat, amount in col.stats.items(): |
832 | logging.debug("%s: %s" % (stat, amount)) |
833 | - |
834 | diff --git a/CommandNotFound/db/db.py b/CommandNotFound/db/db.py |
835 | index c776893..0b108b3 100644 |
836 | --- a/CommandNotFound/db/db.py |
837 | +++ b/CommandNotFound/db/db.py |
838 | @@ -3,11 +3,11 @@ |
839 | import sqlite3 |
840 | |
841 | import apt_pkg |
842 | + |
843 | apt_pkg.init() |
844 | |
845 | |
846 | class SqliteDatabase(object): |
847 | - |
848 | def __init__(self, filename): |
849 | self.con = sqlite3.connect(filename) |
850 | self.component = "" |
851 | @@ -17,13 +17,14 @@ class SqliteDatabase(object): |
852 | command = command.encode("utf-8", "surrogateescape").decode("utf-8", "replace") |
853 | results = [] |
854 | for row in self.con.execute( |
855 | - """ |
856 | + """ |
857 | SELECT packages.name, packages.version, packages.component |
858 | FROM commands |
859 | INNER JOIN packages on packages.pkgID = commands.pkgID |
860 | WHERE commands.command=? |
861 | ORDER BY packages.priority DESC |
862 | - """, (command,)).fetchall(): |
863 | - results.append( (row[0], row[1], row[2]) ) |
864 | + """, |
865 | + (command,), |
866 | + ).fetchall(): |
867 | + results.append((row[0], row[1], row[2])) |
868 | return results |
869 | - |
870 | diff --git a/CommandNotFound/db/tests/test_db.py b/CommandNotFound/db/tests/test_db.py |
871 | index d743a6f..6cbb92c 100644 |
872 | --- a/CommandNotFound/db/tests/test_db.py |
873 | +++ b/CommandNotFound/db/tests/test_db.py |
874 | @@ -6,6 +6,7 @@ import tempfile |
875 | import unittest |
876 | |
877 | import logging |
878 | + |
879 | logging.basicConfig(level=logging.DEBUG) |
880 | |
881 | from CommandNotFound.db.creator import DbCreator |
882 | @@ -75,8 +76,8 @@ version: 3.0 |
883 | commands: bzr |
884 | """ |
885 | |
886 | -class DbTestCase(unittest.TestCase): |
887 | |
888 | +class DbTestCase(unittest.TestCase): |
889 | def setUp(self): |
890 | self.tmpdir = tempfile.mkdtemp() |
891 | |
892 | @@ -84,7 +85,14 @@ class DbTestCase(unittest.TestCase): |
893 | shutil.rmtree(self.tmpdir) |
894 | |
895 | def make_mock_commands_file(self, suite, content): |
896 | - path = os.path.join(self.tmpdir, "var", "lib", "apt", "lists", "archive.ubuntu.com_ubuntu_dists_%s_Commands-all" % suite) |
897 | + path = os.path.join( |
898 | + self.tmpdir, |
899 | + "var", |
900 | + "lib", |
901 | + "apt", |
902 | + "lists", |
903 | + "archive.ubuntu.com_ubuntu_dists_%s_Commands-all" % suite, |
904 | + ) |
905 | try: |
906 | os.makedirs(os.path.dirname(path)) |
907 | except OSError: |
908 | @@ -92,74 +100,79 @@ class DbTestCase(unittest.TestCase): |
909 | with open(path, "w") as fp: |
910 | fp.write(content) |
911 | return path |
912 | - |
913 | + |
914 | def test_create_trivial_db(self): |
915 | mock_commands_file = self.make_mock_commands_file( |
916 | - "bionic_main", mock_commands_bionic) |
917 | + "bionic_main", mock_commands_bionic |
918 | + ) |
919 | cre = DbCreator([mock_commands_file]) |
920 | dbpath = os.path.join(self.tmpdir, "test.db") |
921 | cre.create(dbpath) |
922 | # validate content |
923 | db = SqliteDatabase(dbpath) |
924 | + self.assertEqual(db.lookup("wall"), [("bsdutils", "1.0", "main")]) |
925 | self.assertEqual( |
926 | - db.lookup("wall"), [("bsdutils", "1.0", "main")]) |
927 | - self.assertEqual( |
928 | - db.lookup("removed-in-version-2.0"), [("bsdutils", "1.0", "main")]) |
929 | + db.lookup("removed-in-version-2.0"), [("bsdutils", "1.0", "main")] |
930 | + ) |
931 | |
932 | def test_create_multiple_dbs(self): |
933 | mock_commands_1 = self.make_mock_commands_file( |
934 | - "bionic_main", mock_commands_bionic) |
935 | + "bionic_main", mock_commands_bionic |
936 | + ) |
937 | mock_commands_2 = self.make_mock_commands_file( |
938 | - "bionic-proposed_main", mock_commands_bionic_proposed) |
939 | + "bionic-proposed_main", mock_commands_bionic_proposed |
940 | + ) |
941 | cre = DbCreator([mock_commands_1, mock_commands_2]) |
942 | dbpath = os.path.join(self.tmpdir, "test.db") |
943 | cre.create(dbpath) |
944 | # validate content |
945 | db = SqliteDatabase(dbpath) |
946 | # newer version 2.0 ovrride older version 1.0 |
947 | - self.assertEqual( |
948 | - db.lookup("wall"), [("bsdutils", "2.0", "main")]) |
949 | + self.assertEqual(db.lookup("wall"), [("bsdutils", "2.0", "main")]) |
950 | # binaries from older versions do not linger around |
951 | - self.assertEqual( |
952 | - db.lookup("removed-in-version-2.0"), []) |
953 | + self.assertEqual(db.lookup("removed-in-version-2.0"), []) |
954 | # versions only from a single file are available |
955 | self.assertEqual( |
956 | - db.lookup("bzr"), [ |
957 | + db.lookup("bzr"), |
958 | + [ |
959 | ("bzr1", "1.0", "main"), |
960 | ("bzr2", "2.7", "main"), |
961 | - ]) |
962 | + ], |
963 | + ) |
964 | |
965 | def test_create_backports_excluded_dbs(self): |
966 | mock_commands_1 = self.make_mock_commands_file( |
967 | - "bionic_main", mock_commands_bionic) |
968 | + "bionic_main", mock_commands_bionic |
969 | + ) |
970 | mock_commands_2 = self.make_mock_commands_file( |
971 | - "bionic-backports_main", mock_commands_bionic_backports) |
972 | + "bionic-backports_main", mock_commands_bionic_backports |
973 | + ) |
974 | cre = DbCreator([mock_commands_1, mock_commands_2]) |
975 | dbpath = os.path.join(self.tmpdir, "test.db") |
976 | cre.create(dbpath) |
977 | # validate content |
978 | db = SqliteDatabase(dbpath) |
979 | - self.assertEqual( |
980 | - db.lookup("wall"), [("bsdutils", "1.0", "main")]) |
981 | - self.assertEqual( |
982 | - db.lookup("new-stuff-only-in-backports"), []) |
983 | + self.assertEqual(db.lookup("wall"), [("bsdutils", "1.0", "main")]) |
984 | + self.assertEqual(db.lookup("new-stuff-only-in-backports"), []) |
985 | |
986 | def test_create_no_versions_does_not_crash(self): |
987 | mock_commands = self.make_mock_commands_file( |
988 | - "bionic_main", mock_commands_bionic.replace("version: 1.0\n", "")) |
989 | + "bionic_main", mock_commands_bionic.replace("version: 1.0\n", "") |
990 | + ) |
991 | cre = DbCreator([mock_commands]) |
992 | dbpath = os.path.join(self.tmpdir, "test.db") |
993 | cre.create(dbpath) |
994 | # validate content |
995 | db = SqliteDatabase(dbpath) |
996 | - self.assertEqual( |
997 | - db.lookup("wall"), [("bsdutils", "", "main")]) |
998 | - |
999 | + self.assertEqual(db.lookup("wall"), [("bsdutils", "", "main")]) |
1000 | + |
1001 | def test_create_priorities_work(self): |
1002 | mock_commands_1 = self.make_mock_commands_file( |
1003 | - "bionic_main", mock_commands_bionic) |
1004 | + "bionic_main", mock_commands_bionic |
1005 | + ) |
1006 | mock_commands_2 = self.make_mock_commands_file( |
1007 | - "bionic_universe", mock_commands_bionic_universe) |
1008 | + "bionic_universe", mock_commands_bionic_universe |
1009 | + ) |
1010 | self.assertNotEqual(mock_commands_1, mock_commands_2) |
1011 | cre = DbCreator([mock_commands_1, mock_commands_2]) |
1012 | dbpath = os.path.join(self.tmpdir, "test.db") |
1013 | @@ -170,15 +183,18 @@ class DbTestCase(unittest.TestCase): |
1014 | # ensure that we always sort "main" before universe" |
1015 | # and that the same component is sorted alphabetically |
1016 | self.assertEqual( |
1017 | - db.lookup("bzr"), [ |
1018 | + db.lookup("bzr"), |
1019 | + [ |
1020 | ("bzr1", "1.0", "main"), |
1021 | ("bzr2", "2.7", "main"), |
1022 | ("bzr-tng", "3.0", "universe"), |
1023 | - ]) |
1024 | + ], |
1025 | + ) |
1026 | |
1027 | def test_priorities_bonus_works(self): |
1028 | mock_commands_1 = self.make_mock_commands_file( |
1029 | - "bionic_main", mock_commands_bionic) |
1030 | + "bionic_main", mock_commands_bionic |
1031 | + ) |
1032 | cre = DbCreator([mock_commands_1]) |
1033 | dbpath = os.path.join(self.tmpdir, "test.db") |
1034 | cre.create(dbpath) |
1035 | @@ -186,33 +202,37 @@ class DbTestCase(unittest.TestCase): |
1036 | db = SqliteDatabase(dbpath) |
1037 | for i in range(100): |
1038 | self.assertEqual( |
1039 | - db.lookup("java"), [ |
1040 | + db.lookup("java"), |
1041 | + [ |
1042 | ("default-jre", "8", "main"), |
1043 | ("aaa-openjre-7", "7", "main"), |
1044 | - ]) |
1045 | + ], |
1046 | + ) |
1047 | |
1048 | def test_visible_pkgname_works(self): |
1049 | mock_commands_1 = self.make_mock_commands_file( |
1050 | - "bionic_main", mock_commands_bionic) |
1051 | + "bionic_main", mock_commands_bionic |
1052 | + ) |
1053 | cre = DbCreator([mock_commands_1]) |
1054 | dbpath = os.path.join(self.tmpdir, "test.db") |
1055 | cre.create(dbpath) |
1056 | # validate content |
1057 | db = SqliteDatabase(dbpath) |
1058 | for i in range(100): |
1059 | - self.assertEqual( |
1060 | - db.lookup("python2.7"), [("python2.7", "2.7", "main")]) |
1061 | + self.assertEqual(db.lookup("python2.7"), [("python2.7", "2.7", "main")]) |
1062 | |
1063 | def test_create_multiple_no_unneeded_creates(self): |
1064 | mock_commands_1 = self.make_mock_commands_file( |
1065 | - "bionic_main", mock_commands_bionic) |
1066 | + "bionic_main", mock_commands_bionic |
1067 | + ) |
1068 | mock_commands_2 = self.make_mock_commands_file( |
1069 | - "bionic-proposed_main", mock_commands_bionic_proposed) |
1070 | + "bionic-proposed_main", mock_commands_bionic_proposed |
1071 | + ) |
1072 | cre = DbCreator([mock_commands_1, mock_commands_2]) |
1073 | dbpath = os.path.join(self.tmpdir, "test.db") |
1074 | cre.create(dbpath) |
1075 | # ensure the metadata file was created |
1076 | - self.assertTrue(os.path.exists(dbpath+".metadata")) |
1077 | + self.assertTrue(os.path.exists(dbpath + ".metadata")) |
1078 | # ensure the caching works and the db is not created twice |
1079 | st = os.stat(dbpath) |
1080 | cre.create(dbpath) |
1081 | @@ -220,13 +240,13 @@ class DbTestCase(unittest.TestCase): |
1082 | |
1083 | def test_create_honors_ignore_comamnds(self): |
1084 | mock_commands_file = self.make_mock_commands_file( |
1085 | - "bionic_main", mock_commands_bionic) |
1086 | + "bionic_main", mock_commands_bionic |
1087 | + ) |
1088 | cre = DbCreator([mock_commands_file]) |
1089 | dbpath = os.path.join(self.tmpdir, "test.db") |
1090 | cre.create(dbpath) |
1091 | # validate content |
1092 | db = SqliteDatabase(dbpath) |
1093 | # ignore-commands is correctly handled |
1094 | - self.assertEqual( |
1095 | - db.lookup("foo-cmd"), [("foo", "3.0", "main")]) |
1096 | + self.assertEqual(db.lookup("foo-cmd"), [("foo", "3.0", "main")]) |
1097 | self.assertEqual(db.lookup("igore-me"), []) |
1098 | diff --git a/CommandNotFound/tests/test_command_not_found.py b/CommandNotFound/tests/test_command_not_found.py |
1099 | index 809809f..c4bde59 100644 |
1100 | --- a/CommandNotFound/tests/test_command_not_found.py |
1101 | +++ b/CommandNotFound/tests/test_command_not_found.py |
1102 | @@ -1,8 +1,9 @@ |
1103 | #!/usr/bin/python |
1104 | |
1105 | import json |
1106 | -#import logging |
1107 | -#logging.basicConfig(level=logging.DEBUG) |
1108 | + |
1109 | +# import logging |
1110 | +# logging.basicConfig(level=logging.DEBUG) |
1111 | import os |
1112 | import shutil |
1113 | import tempfile |
1114 | @@ -16,14 +17,14 @@ from CommandNotFound.CommandNotFound import ( |
1115 | from CommandNotFound.db.creator import DbCreator |
1116 | |
1117 | test_specs = [ |
1118 | -""" |
1119 | + """ |
1120 | test: single snap advise |
1121 | snaps: spotify/1.0:x-spotify |
1122 | with: x-spotify |
1123 | Command 'x-spotify' not found, but can be installed with: |
1124 | sudo snap install spotify |
1125 | """, |
1126 | -""" |
1127 | + """ |
1128 | test: mixed advise, single snap |
1129 | debs: aws/1.0:x-aws,other-cmd |
1130 | snaps: aws-cli/2.0:x-aws |
1131 | @@ -33,7 +34,7 @@ sudo snap install aws-cli # version 2.0, or |
1132 | sudo apt install aws # version 1.0 |
1133 | See 'snap info aws-cli' for additional versions. |
1134 | """, |
1135 | -""" |
1136 | + """ |
1137 | test: mixed advise, multi-snap |
1138 | debs: aws/1.0:x-aws,other-cmd |
1139 | snaps: aws-cli/2.0:x-aws;aws-cli-compat/0.1:x-aws |
1140 | @@ -44,14 +45,14 @@ sudo snap install aws-cli-compat # version 0.1 |
1141 | sudo apt install aws # version 1.0 |
1142 | See 'snap info <snapname>' for additional versions. |
1143 | """, |
1144 | -""" |
1145 | + """ |
1146 | test: single advise deb |
1147 | debs: pylint/1.0:x-pylint |
1148 | with: x-pylint |
1149 | Command 'x-pylint' not found, but can be installed with: |
1150 | sudo apt install pylint |
1151 | """, |
1152 | -""" |
1153 | + """ |
1154 | test: multi advise debs |
1155 | debs: vim/1.0:x-vi;neovim/2.0:x-vi |
1156 | with: x-vi |
1157 | @@ -59,7 +60,7 @@ Command 'x-vi' not found, but can be installed with: |
1158 | sudo apt install vim # version 1.0, or |
1159 | sudo apt install neovim # version 2.0 |
1160 | """, |
1161 | -""" |
1162 | + """ |
1163 | test: fuzzy advise debs only |
1164 | debs: vim/1.0:x-vi;neovim/2.0:x-vi |
1165 | with: x-via |
1166 | @@ -68,14 +69,14 @@ Command 'x-via' not found, did you mean: |
1167 | command 'x-vi' from deb neovim (2.0) |
1168 | Try: sudo apt install <deb name> |
1169 | """, |
1170 | -""" |
1171 | + """ |
1172 | test: single advise snaps |
1173 | snaps: spotify/1.0:x-spotify |
1174 | with: x-spotify |
1175 | Command 'x-spotify' not found, but can be installed with: |
1176 | sudo snap install spotify |
1177 | """, |
1178 | -""" |
1179 | + """ |
1180 | test: multi advise snaps |
1181 | snaps: foo1/1.0:x-foo;foo2/2.0:x-foo |
1182 | with: x-foo |
1183 | @@ -84,7 +85,7 @@ sudo snap install foo1 # version 1.0, or |
1184 | sudo snap install foo2 # version 2.0 |
1185 | See 'snap info <snapname>' for additional versions. |
1186 | """, |
1187 | -""" |
1188 | + """ |
1189 | test: mixed fuzzy advise |
1190 | debs: aws/1.0:x-aws,other-cmd |
1191 | snaps: aws-cli/2.0:x-aws |
1192 | @@ -94,24 +95,24 @@ Command 'x-awsX' not found, did you mean: |
1193 | command 'x-aws' from deb aws (1.0) |
1194 | See 'snap info <snapname>' for additional versions. |
1195 | """, |
1196 | -""" |
1197 | + """ |
1198 | test: many mispellings just prints a summary |
1199 | debs: lsa/1.0:lsa;lsb/1.0:lsb;lsc/1.0:lsc;lsd/1.0:lsd;lsd/1.0:lsd;lse/1.0:lse;lsf/1.0:lsf;lsg/1.0:lsg;lse/1.0:lsh;lse/1.0:lsh;lsi/1.0:lsi;lsj/1.0:lsj;lsk/1.0:lsk;lsl/1.0:lsl;lsm/1.0:lsm;lsn/1.0:lsn;lso/1.0:lso |
1200 | with: lsx |
1201 | Command 'lsx' not found, but there are 17 similar ones. |
1202 | """, |
1203 | ] |
1204 | - |
1205 | + |
1206 | |
1207 | class MockAptDB: |
1208 | def __init__(self): |
1209 | self._db = {} |
1210 | + |
1211 | def lookup(self, command): |
1212 | return self._db.get(command, []) |
1213 | |
1214 | - |
1215 | -class CommandNotFoundOutputTest(unittest.TestCase): |
1216 | |
1217 | +class CommandNotFoundOutputTest(unittest.TestCase): |
1218 | def setUp(self): |
1219 | self.tmpdir = tempfile.mkdtemp() |
1220 | self.mock_db() |
1221 | @@ -137,17 +138,20 @@ class CommandNotFoundOutputTest(unittest.TestCase): |
1222 | |
1223 | def set_mock_snap_cmd_json(self, json): |
1224 | with open(self.cnf.snap_cmd, "w") as fp: |
1225 | - fp.write("""#!/bin/sh |
1226 | + fp.write( |
1227 | + """#!/bin/sh |
1228 | set -e |
1229 | |
1230 | echo '%s' |
1231 | -""" % json) |
1232 | +""" |
1233 | + % json |
1234 | + ) |
1235 | os.chmod(self.cnf.snap_cmd, 0o755) |
1236 | |
1237 | def test_from_table(self): |
1238 | for i, spec in enumerate(test_specs): |
1239 | self._test_spec(spec) |
1240 | - |
1241 | + |
1242 | def _test_spec(self, spec): |
1243 | # setup |
1244 | self.cnf.db = MockAptDB() |
1245 | @@ -158,7 +162,7 @@ echo '%s' |
1246 | test = "unkown test" |
1247 | for i, line in enumerate(lines): |
1248 | if line.startswith("debs: "): |
1249 | - debs = line[len("debs: "):].split(";") |
1250 | + debs = line[len("debs: ") :].split(";") |
1251 | for deb in debs: |
1252 | l = deb.split(":") |
1253 | name, ver = l[0].split("/") |
1254 | @@ -166,9 +170,9 @@ echo '%s' |
1255 | for cmd in cmds: |
1256 | if not cmd in self.cnf.db._db: |
1257 | self.cnf.db._db[cmd] = [] |
1258 | - self.cnf.db._db[cmd].append( (name, ver, "main") ) |
1259 | + self.cnf.db._db[cmd].append((name, ver, "main")) |
1260 | if line.startswith("snaps: "): |
1261 | - snaps = line[len("snaps: "):].split(";") |
1262 | + snaps = line[len("snaps: ") :].split(";") |
1263 | mock_json = [] |
1264 | for snap in snaps: |
1265 | l = snap.split(":") |
1266 | @@ -178,11 +182,11 @@ echo '%s' |
1267 | mock_json.append({"Snap": name, "Command": cmd, "Version": ver}) |
1268 | self.set_mock_snap_cmd_json(json.dumps(mock_json)) |
1269 | if line.startswith("test: "): |
1270 | - test = line[len("test: "):] |
1271 | + test = line[len("test: ") :] |
1272 | if line.startswith("with: "): |
1273 | - cmd = line[len("with: "):] |
1274 | + cmd = line[len("with: ") :] |
1275 | break |
1276 | - expected_output = "\n".join(lines[i+1:]) |
1277 | + expected_output = "\n".join(lines[i + 1 :]) |
1278 | # run test |
1279 | self.cnf.advise(cmd) |
1280 | # validate |
1281 | @@ -191,10 +195,9 @@ echo '%s' |
1282 | self.assertEqual(output, expected_output, "test '%s' broken" % test) |
1283 | # cleanup |
1284 | self.cnf.output_fd.close() |
1285 | - |
1286 | |
1287 | -class RegressionTestCase(unittest.TestCase): |
1288 | |
1289 | +class RegressionTestCase(unittest.TestCase): |
1290 | def test_lp1130444(self): |
1291 | tmpdir = tempfile.mkdtemp() |
1292 | self.addCleanup(shutil.rmtree, tmpdir) |
1293 | diff --git a/CommandNotFound/tests/test_pyflakes.py b/CommandNotFound/tests/test_pyflakes.py |
1294 | index 5f97d13..a4a4a14 100755 |
1295 | --- a/CommandNotFound/tests/test_pyflakes.py |
1296 | +++ b/CommandNotFound/tests/test_pyflakes.py |
1297 | @@ -3,17 +3,18 @@ import os |
1298 | import subprocess |
1299 | import unittest |
1300 | |
1301 | + |
1302 | class TestPyflakesClean(unittest.TestCase): |
1303 | - """ ensure that the tree is pyflakes clean """ |
1304 | + """ensure that the tree is pyflakes clean""" |
1305 | |
1306 | def setUp(self): |
1307 | self.paths = [] |
1308 | basedir = os.path.abspath(os.path.join(os.path.dirname(__file__), "..")) |
1309 | for dirpath, dirs, files in os.walk(basedir): |
1310 | - self.paths.extend(glob.glob(dirpath+"/*.py")) |
1311 | + self.paths.extend(glob.glob(dirpath + "/*.py")) |
1312 | |
1313 | def test_pyflakes3_clean(self): |
1314 | - self.assertEqual(subprocess.check_call(['pyflakes3'] + self.paths), 0) |
1315 | + self.assertEqual(subprocess.check_call(["pyflakes3"] + self.paths), 0) |
1316 | |
1317 | |
1318 | if __name__ == "__main__": |
1319 | diff --git a/CommandNotFound/util.py b/CommandNotFound/util.py |
1320 | index c371423..2407f73 100644 |
1321 | --- a/CommandNotFound/util.py |
1322 | +++ b/CommandNotFound/util.py |
1323 | @@ -15,22 +15,33 @@ _ = getattr(gettext.translation("command-not-found", fallback=True), _gettext_me |
1324 | |
1325 | |
1326 | def crash_guard(callback, bug_report_url, version): |
1327 | - """ Calls callback and catches all exceptions. |
1328 | + """Calls callback and catches all exceptions. |
1329 | When something bad happens prints a long error message |
1330 | with bug report information and exits the program""" |
1331 | try: |
1332 | try: |
1333 | callback() |
1334 | except Exception as ex: |
1335 | - print(_("Sorry, command-not-found has crashed! Please file a bug report at:"), file=sys.stderr) |
1336 | + print( |
1337 | + _("Sorry, command-not-found has crashed! Please file a bug report at:"), |
1338 | + file=sys.stderr, |
1339 | + ) |
1340 | print(bug_report_url, file=sys.stderr) |
1341 | - print(_("Please include the following information with the report:"), file=sys.stderr) |
1342 | + print( |
1343 | + _("Please include the following information with the report:"), |
1344 | + file=sys.stderr, |
1345 | + ) |
1346 | print(file=sys.stderr) |
1347 | print(_("command-not-found version: %s") % version, file=sys.stderr) |
1348 | - print(_("Python version: %d.%d.%d %s %d") % sys.version_info, file=sys.stderr) |
1349 | + print( |
1350 | + _("Python version: %d.%d.%d %s %d") % sys.version_info, file=sys.stderr |
1351 | + ) |
1352 | try: |
1353 | import subprocess |
1354 | - subprocess.call(["lsb_release", "-i", "-d", "-r", "-c"], stdout=sys.stderr) |
1355 | + |
1356 | + subprocess.call( |
1357 | + ["lsb_release", "-i", "-d", "-r", "-c"], stdout=sys.stderr |
1358 | + ) |
1359 | except (ImportError, OSError): |
1360 | pass |
1361 | print(_("Exception information:"), file=sys.stderr) |
1362 | @@ -38,6 +49,7 @@ def crash_guard(callback, bug_report_url, version): |
1363 | print(ex, file=sys.stderr) |
1364 | try: |
1365 | import traceback |
1366 | + |
1367 | traceback.print_exc() |
1368 | except ImportError: |
1369 | pass |
1370 | diff --git a/setup.py b/setup.py |
1371 | index 3ced20e..42df58d 100755 |
1372 | --- a/setup.py |
1373 | +++ b/setup.py |
1374 | @@ -1,19 +1,21 @@ |
1375 | #!/usr/bin/python3 |
1376 | |
1377 | from distutils.core import setup |
1378 | -from DistUtilsExtra.command import (build_extra, build_i18n) |
1379 | +from DistUtilsExtra.command import build_extra, build_i18n |
1380 | import glob |
1381 | |
1382 | setup( |
1383 | - name='command-not-found', |
1384 | - version='0.3', |
1385 | - packages=['CommandNotFound', 'CommandNotFound.db'], |
1386 | - scripts=['command-not-found', 'cnf-update-db'], |
1387 | - cmdclass={"build": build_extra.build_extra, |
1388 | - "build_i18n": build_i18n.build_i18n, |
1389 | - }, |
1390 | + name="command-not-found", |
1391 | + version="0.3", |
1392 | + packages=["CommandNotFound", "CommandNotFound.db"], |
1393 | + scripts=["command-not-found", "cnf-update-db"], |
1394 | + cmdclass={ |
1395 | + "build": build_extra.build_extra, |
1396 | + "build_i18n": build_i18n.build_i18n, |
1397 | + }, |
1398 | data_files=[ |
1399 | - ('share/command-not-found/', glob.glob("data/*.db")), |
1400 | - ('../etc', ['bash_command_not_found', 'zsh_command_not_found']), |
1401 | - ('../etc/apt/apt.conf.d', ['data/50command-not-found']), |
1402 | - ]) |
1403 | + ("share/command-not-found/", glob.glob("data/*.db")), |
1404 | + ("../etc", ["bash_command_not_found", "zsh_command_not_found"]), |
1405 | + ("../etc/apt/apt.conf.d", ["data/50command-not-found"]), |
1406 | + ], |
1407 | +) |
While I appreciate format cleanups I'm not sure this is the best venue for this type of change, because I'd have to run black locally myself, and then compare the outcomes anyway, and there's no work to make sure future uploads are correctly formatted.
Ultimately it would be nice to setup the launchpad CI thingy and https:/ /pre-commit. com/ that runs ruff to format the code and do linting of it (or alternatively the individual tools, but it seems the community is gravitating towards ruff these days) and fail if linting fails or ruff fails.
Not sure if now is the right time for this, I believe that ultimately this would improve quality for 24.04, and it's not a feature, so it should not be affected by feature freeze.
What do you think?