Merge ~isidroas/ubuntu/+source/command-not-found:black_formatter into ubuntu/+source/command-not-found: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)
Reviewer Review Type Date Requested Status
Julian Andres Klode Pending
git-ubuntu import Pending
Review via email: mp+461374@code.launchpad.net

Description of the change

The black formatter (https://github.com/psf/black) makes your code follow the [official style recomendation](https://peps.python.org/pep-0008/). I could list some important projects that use it.

To post a comment you must log in.
Revision history for this message
Julian Andres Klode (juliank) wrote :

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?

Unmerged commits

50b23e1... by isidro

black formatter

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/CommandNotFound/CommandNotFound.py b/CommandNotFound/CommandNotFound.py
2index 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+ )
458diff --git a/CommandNotFound/__init__.py b/CommandNotFound/__init__.py
459index 66b6508..c396168 100644
460--- a/CommandNotFound/__init__.py
461+++ b/CommandNotFound/__init__.py
462@@ -1,2 +1 @@
463 from __future__ import absolute_import
464-
465diff --git a/CommandNotFound/db/creator.py b/CommandNotFound/db/creator.py
466index 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-
834diff --git a/CommandNotFound/db/db.py b/CommandNotFound/db/db.py
835index 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-
870diff --git a/CommandNotFound/db/tests/test_db.py b/CommandNotFound/db/tests/test_db.py
871index 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"), [])
1098diff --git a/CommandNotFound/tests/test_command_not_found.py b/CommandNotFound/tests/test_command_not_found.py
1099index 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)
1293diff --git a/CommandNotFound/tests/test_pyflakes.py b/CommandNotFound/tests/test_pyflakes.py
1294index 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__":
1319diff --git a/CommandNotFound/util.py b/CommandNotFound/util.py
1320index 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
1370diff --git a/setup.py b/setup.py
1371index 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+)

Subscribers

People subscribed via source and target branches

to all changes: