mirror of
https://github.com/jlu5/SupyPlugins.git
synced 2025-04-27 05:21:10 -05:00
PkgInfo: Code cleanup & PEP8 compliancy
- Use supybot.utils.str.format() for correct pluralization of 'results' - Better code readability
This commit is contained in:
parent
f1f8c6176e
commit
82b353a075
@ -45,8 +45,8 @@ try:
|
|||||||
from bs4 import BeautifulSoup
|
from bs4 import BeautifulSoup
|
||||||
except ImportError:
|
except ImportError:
|
||||||
raise ImportError("Beautiful Soup 4 is required for this plugin: get it"
|
raise ImportError("Beautiful Soup 4 is required for this plugin: get it"
|
||||||
" at http://www.crummy.com/software/BeautifulSoup/bs4/doc/"
|
" at http://www.crummy.com/software/BeautifulSoup/bs4/"
|
||||||
"#installing-beautiful-soup")
|
"doc/#installing-beautiful-soup")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from supybot.i18n import PluginInternationalization
|
from supybot.i18n import PluginInternationalization
|
||||||
@ -56,6 +56,7 @@ except ImportError:
|
|||||||
# without the i18n module
|
# without the i18n module
|
||||||
_ = lambda x: x
|
_ = lambda x: x
|
||||||
|
|
||||||
|
|
||||||
class PkgInfo(callbacks.Plugin):
|
class PkgInfo(callbacks.Plugin):
|
||||||
"""Fetches package information from the repositories of
|
"""Fetches package information from the repositories of
|
||||||
Debian, Arch Linux, Linux Mint, and Ubuntu."""
|
Debian, Arch Linux, Linux Mint, and Ubuntu."""
|
||||||
@ -75,20 +76,24 @@ class PkgInfo(callbacks.Plugin):
|
|||||||
if release.startswith(("oldstable", "squeeze", "wheezy", "stable",
|
if release.startswith(("oldstable", "squeeze", "wheezy", "stable",
|
||||||
"jessie", "testing", "sid", "unstable")):
|
"jessie", "testing", "sid", "unstable")):
|
||||||
distro = "debian"
|
distro = "debian"
|
||||||
elif release.startswith(("hardy","lucid","maverick","natty","oneiric",
|
elif release.startswith(("hardy", "lucid", "maverick", "natty",
|
||||||
"precise","quantal","raring","saucy","trusty","utopic","vivid")):
|
"oneiric", "precise", "quantal", "raring",
|
||||||
|
"saucy", "trusty", "utopic", "vivid")):
|
||||||
distro = "ubuntu"
|
distro = "ubuntu"
|
||||||
else:
|
else:
|
||||||
distro = None
|
distro = None
|
||||||
return distro
|
return distro
|
||||||
|
|
||||||
def MadisonParse(self, pkg, dist, codenames='', suite='', useSource=False, reverse=False):
|
def MadisonParse(self, pkg, dist, codenames='', suite='', useSource=False,
|
||||||
# The arch value implies 'all' (architecture-independent packages) and 'source'
|
reverse=False):
|
||||||
# (source packages), in order to prevent misleading "Not found" errors.
|
"""Parser for the madison API at https://qa.debian.org/madison.php."""
|
||||||
|
# This arch value implies 'all' (architecture-independent packages)
|
||||||
|
# and 'source' (source packages), in order to prevent misleading
|
||||||
|
# "Not found" errors.
|
||||||
arch = self.registryValue("archs") + ['all', 'source']
|
arch = self.registryValue("archs") + ['all', 'source']
|
||||||
arch = ','.join(set(arch))
|
arch = ','.join(set(arch))
|
||||||
self.arg = {'package':pkg,'table':dist,'a':arch,'c':codenames,'s':suite,
|
self.arg = {'package': pkg, 'table': dist, 'a': arch, 'c': codenames,
|
||||||
}
|
's': suite}
|
||||||
if useSource:
|
if useSource:
|
||||||
self.arg['S'] = 'on'
|
self.arg['S'] = 'on'
|
||||||
self.arg = urlencode(self.arg)
|
self.arg = urlencode(self.arg)
|
||||||
@ -98,21 +103,24 @@ class PkgInfo(callbacks.Plugin):
|
|||||||
fd = utils.web.getUrlFd(url)
|
fd = utils.web.getUrlFd(url)
|
||||||
for line in fd.readlines():
|
for line in fd.readlines():
|
||||||
L = line.decode("utf-8").split("|")
|
L = line.decode("utf-8").split("|")
|
||||||
L = list(map(str.strip, list(map(str, L))))
|
L = map(str.strip, L)
|
||||||
|
name, version, release, archs = L
|
||||||
if useSource:
|
if useSource:
|
||||||
d['%s: %s' % (L[2], L[0])] = (L[1], L[3])
|
d['%s: %s' % (release, name)] = (version, archs)
|
||||||
else:
|
else:
|
||||||
d[L[2]] = (L[1],L[3])
|
d[release] = (version, archs)
|
||||||
if d:
|
if d:
|
||||||
if reverse:
|
if reverse:
|
||||||
# *sigh*... I wish there was a better way to do this
|
# *sigh*... I wish there was a better way to do this
|
||||||
d = OrderedDict(reversed(tuple(d.items())))
|
d = OrderedDict(reversed(tuple(d.items())))
|
||||||
if self.registryValue("verbose"):
|
if self.registryValue("verbose"):
|
||||||
return 'Found %s results: ' % len(d) + ', '.join("{!s} " \
|
items = ["{name} \x02({version} [{archs}])\x02".format(name=k,
|
||||||
"\x02({!s} [{!s}])\x02".format(k,v[0],v[1]) for (k,v) in \
|
version=v[0], archs=v[1]) for (k, v) in d.items()]
|
||||||
d.items())
|
else:
|
||||||
return 'Found %s results: ' % len(d) + ', '.join("{!s} " \
|
items = ["{name} \x02({version})\x02".format(name=k,
|
||||||
"\x02({!s})\x02".format(k,v[0]) for (k,v) in d.items())
|
version=v[0]) for (k, v) in d.items()]
|
||||||
|
s = format('Found %n: %L', (len(d), 'result'), items)
|
||||||
|
return s
|
||||||
else:
|
else:
|
||||||
self.log.debug("PkgInfo: No results found for URL %s", url)
|
self.log.debug("PkgInfo: No results found for URL %s", url)
|
||||||
|
|
||||||
@ -121,8 +129,8 @@ class PkgInfo(callbacks.Plugin):
|
|||||||
|
|
||||||
Fetches information for <package> from Debian or Ubuntu's repositories.
|
Fetches information for <package> from Debian or Ubuntu's repositories.
|
||||||
<release> is the codename/release name (e.g. 'trusty', 'squeeze'). If
|
<release> is the codename/release name (e.g. 'trusty', 'squeeze'). If
|
||||||
--depends, --recommends, or --suggests is given, fetches dependency info
|
--depends, --recommends, or --suggests is given, fetches dependency
|
||||||
for <package>.
|
info for <package>.
|
||||||
For Arch Linux packages, please use 'archpkg' and 'archaur' instead."""
|
For Arch Linux packages, please use 'archpkg' and 'archaur' instead."""
|
||||||
pkg = pkg.lower()
|
pkg = pkg.lower()
|
||||||
distro = self._getDistro(release)
|
distro = self._getDistro(release)
|
||||||
@ -144,7 +152,8 @@ class PkgInfo(callbacks.Plugin):
|
|||||||
opts = dict(opts)
|
opts = dict(opts)
|
||||||
if opts:
|
if opts:
|
||||||
items = soup.find_all('dt')
|
items = soup.find_all('dt')
|
||||||
keyws = {'depends': 'dep:', 'recommends': 'rec:', 'suggests': 'sug:'}
|
keyws = {'depends': 'dep:', 'recommends': 'rec:',
|
||||||
|
'suggests': 'sug:'}
|
||||||
if 'depends' in opts:
|
if 'depends' in opts:
|
||||||
lookup = 'depends'
|
lookup = 'depends'
|
||||||
elif 'recommends' in opts:
|
elif 'recommends' in opts:
|
||||||
@ -164,8 +173,8 @@ class PkgInfo(callbacks.Plugin):
|
|||||||
except AttributeError as e:
|
except AttributeError as e:
|
||||||
continue
|
continue
|
||||||
if res:
|
if res:
|
||||||
s = format("Package \x02%s\x02 %s: %L, View more at %u", pkg, lookup,
|
s = format("Package \x02%s\x02 %s: %L, View more at %u", pkg,
|
||||||
res, url)
|
lookup, res, url)
|
||||||
irc.reply(s)
|
irc.reply(s)
|
||||||
else:
|
else:
|
||||||
irc.error("%s doesn't seem to have any %s." % (pkg, lookup))
|
irc.error("%s doesn't seem to have any %s." % (pkg, lookup))
|
||||||
@ -177,11 +186,12 @@ class PkgInfo(callbacks.Plugin):
|
|||||||
version = keywords[-1]
|
version = keywords[-1]
|
||||||
if version == "virtual":
|
if version == "virtual":
|
||||||
providing = [obj.a.text for obj in soup.find_all('dt')]
|
providing = [obj.a.text for obj in soup.find_all('dt')]
|
||||||
desc = "Virtual package provided by: \x02%s\x02" % ', '.join(providing[:10])
|
desc = ("Virtual package provided by: \x02%s\x02" %
|
||||||
|
', '.join(providing[:10]))
|
||||||
if len(providing) > 10:
|
if len(providing) > 10:
|
||||||
desc += " and \x02%s\x02 others" % (len(providing) - 10)
|
desc += " and \x02%s\x02 others" % (len(providing) - 10)
|
||||||
s = format("Package: \x02%s (%s)\x02 in %s - %s, View more at: %u", pkg,
|
s = format("Package: \x02%s (%s)\x02 in %s - %s, View more at: %u",
|
||||||
version, keywords[1], desc, url)
|
pkg, version, keywords[1], desc, url)
|
||||||
irc.reply(s)
|
irc.reply(s)
|
||||||
pkg = wrap(package, ['somethingWithoutSpaces', 'somethingWithoutSpaces',
|
pkg = wrap(package, ['somethingWithoutSpaces', 'somethingWithoutSpaces',
|
||||||
getopts({'depends': '', 'recommends': '', 'suggests': ''})])
|
getopts({'depends': '', 'recommends': '', 'suggests': ''})])
|
||||||
@ -203,16 +213,18 @@ class PkgInfo(callbacks.Plugin):
|
|||||||
irc.error("Unknown distribution.", Raise=True)
|
irc.error("Unknown distribution.", Raise=True)
|
||||||
opts = dict(opts)
|
opts = dict(opts)
|
||||||
reverse = 'reverse' in opts
|
reverse = 'reverse' in opts
|
||||||
d = self.MadisonParse(pkg, distro, useSource='source' in opts, reverse=reverse)
|
d = self.MadisonParse(pkg, distro, useSource='source' in opts,
|
||||||
if not d: irc.error("No results found.",Raise=True)
|
reverse=reverse)
|
||||||
|
if not d:
|
||||||
|
irc.error("No results found.", Raise=True)
|
||||||
try:
|
try:
|
||||||
url = "{}search?keywords={}".format(self.addrs[distro], pkg)
|
url = "{}search?keywords={}".format(self.addrs[distro], pkg)
|
||||||
d += format(" View more at: %u", url)
|
d += format(" View more at: %u", url)
|
||||||
except KeyError:
|
except KeyError:
|
||||||
pass
|
pass
|
||||||
irc.reply(d)
|
irc.reply(d)
|
||||||
vlist = wrap(vlist, ['somethingWithoutSpaces', 'somethingWithoutSpaces', getopts({'source':'',
|
vlist = wrap(vlist, ['somethingWithoutSpaces', 'somethingWithoutSpaces',
|
||||||
'reverse':''})])
|
getopts({'source': '', 'reverse': ''})])
|
||||||
|
|
||||||
def archpkg(self, irc, msg, args, pkg, opts):
|
def archpkg(self, irc, msg, args, pkg, opts):
|
||||||
"""<package> [--exact]
|
"""<package> [--exact]
|
||||||
@ -230,19 +242,22 @@ class PkgInfo(callbacks.Plugin):
|
|||||||
fd = utils.web.getUrl(url)
|
fd = utils.web.getUrl(url)
|
||||||
data = json.loads(fd.decode("utf-8"))
|
data = json.loads(fd.decode("utf-8"))
|
||||||
if data['valid'] and data['results']:
|
if data['valid'] and data['results']:
|
||||||
f = set()
|
# We want one entry per package, but the API gives one
|
||||||
|
# entry per architecture! Remove duplicates with a set:
|
||||||
|
results = set()
|
||||||
archs = defaultdict(list)
|
archs = defaultdict(list)
|
||||||
for x in data['results']:
|
for x in data['results']:
|
||||||
s = "{} - {} \x02({})\x02".format(x['pkgname'],x['pkgdesc'],x['pkgver'])
|
s = "\x02{name}\x02 - {desc} \x02({version})\x02".format(
|
||||||
f.add(s)
|
name=x['pkgname'], desc=x['pkgdesc'], version=x['pkgver'])
|
||||||
|
results.add(s)
|
||||||
archs[s].append(x['arch'])
|
archs[s].append(x['arch'])
|
||||||
count = len(f)
|
count = len(results)
|
||||||
if self.registryValue("verbose"):
|
items = [format("%s \x02[%s]\x02", s, ', '.join(archs[s])) for s
|
||||||
irc.reply('Found %s results: ' % count + ', ' \
|
in results]
|
||||||
.join("{} \x02[{!s}]\x02".format(s, ', '.join(archs[s])) for s in f))
|
irc.reply(format('Found %n: %L', (len(results), 'result'),
|
||||||
|
list(results)))
|
||||||
else:
|
else:
|
||||||
irc.reply('Found {} results: {}'.format(count,', '.join(f)))
|
irc.error("No results found.", Raise=True)
|
||||||
else: irc.error("No results found.",Raise=True)
|
|
||||||
archpkg = wrap(archpkg, ['somethingWithoutSpaces', getopts({'exact': ''})])
|
archpkg = wrap(archpkg, ['somethingWithoutSpaces', getopts({'exact': ''})])
|
||||||
|
|
||||||
def archaur(self, irc, msg, args, pkg):
|
def archaur(self, irc, msg, args, pkg):
|
||||||
@ -263,13 +278,15 @@ class PkgInfo(callbacks.Plugin):
|
|||||||
# in the bot.
|
# in the bot.
|
||||||
if count > 150:
|
if count > 150:
|
||||||
count = '150+'
|
count = '150+'
|
||||||
s = "Found {} result{}: ".format(count,
|
s = format("Found %n: ", (data["resultcount"], 'result'))
|
||||||
's' if data["resultcount"] != 1 else '')
|
|
||||||
for x in data['results'][:150]:
|
for x in data['results'][:150]:
|
||||||
verboseInfo = ''
|
verboseInfo = ''
|
||||||
if self.registryValue("verbose"):
|
if self.registryValue("verbose"):
|
||||||
verboseInfo = " [ID:{} Votes:{}]".format(x['ID'], x['NumVotes'])
|
verboseInfo = format("[ID: %s Votes: %s]", x['ID'],
|
||||||
s += "{} - {} \x02({}{})\x02, ".format(x['Name'],x['Description'],x['Version'], verboseInfo)
|
x['NumVotes'])
|
||||||
|
s += "{name} - {desc} \x02({version} {verbose})\x02, " \
|
||||||
|
.format(name=x['Name'], desc=x['Description'],
|
||||||
|
version=x['Version'], verbose=verboseInfo)
|
||||||
irc.reply(s[:-2]) # cut off the ", " at the end
|
irc.reply(s[:-2]) # cut off the ", " at the end
|
||||||
else:
|
else:
|
||||||
irc.error("No results found.", Raise=True)
|
irc.error("No results found.", Raise=True)
|
||||||
@ -294,30 +311,36 @@ class PkgInfo(callbacks.Plugin):
|
|||||||
# Debian/Ubuntu use h3 for result names in the format 'Package abcd'
|
# Debian/Ubuntu use h3 for result names in the format 'Package abcd'
|
||||||
results = [pkg.string.split()[1] for pkg in soup.find_all('h3')]
|
results = [pkg.string.split()[1] for pkg in soup.find_all('h3')]
|
||||||
if results:
|
if results:
|
||||||
s = format("Found %s results: \x02%L\x02, View more at: %u", len(results),
|
s = format("Found %n: \x02%L\x02, View more at: %u",
|
||||||
results, url)
|
(len(results), 'result'), results, url)
|
||||||
irc.reply(s)
|
irc.reply(s)
|
||||||
else:
|
else:
|
||||||
e = "No results found."
|
|
||||||
try:
|
try:
|
||||||
|
# Look for "too many results" errors and others reported by the
|
||||||
|
# web interface.
|
||||||
if distro == "debian":
|
if distro == "debian":
|
||||||
errorParse = soup.find("div", class_="note").p
|
errorParse = soup.find("div", class_="note").p
|
||||||
else:
|
else:
|
||||||
errorParse = soup.find("p", attrs={"id": "psearchtoomanyhits"})
|
errorParse = soup.find("p", attrs={"id":
|
||||||
|
"psearchtoomanyhits"})
|
||||||
if errorParse:
|
if errorParse:
|
||||||
for br in errorParse.findAll('br'):
|
for br in errorParse.findAll('br'):
|
||||||
br.replace_with(" ")
|
br.replace_with(" ")
|
||||||
e = errorParse.text.strip()
|
e = errorParse.text.strip()
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
pass
|
e = "No results found."
|
||||||
irc.error(e)
|
irc.error(e)
|
||||||
pkgsearch = wrap(pkgsearch, ['somethingWithoutSpaces', 'somethingWithoutSpaces'])
|
pkgsearch = wrap(pkgsearch, ['somethingWithoutSpaces',
|
||||||
|
'somethingWithoutSpaces'])
|
||||||
|
|
||||||
def mintpkg(self, irc, msg, args, release, query, opts):
|
def mintpkg(self, irc, msg, args, release, query, opts):
|
||||||
"""<release> <package> [--exact]
|
"""<release> <package> [--exact]
|
||||||
|
|
||||||
Looks up <package> in Linux Mint's repositories."""
|
Looks up <package> in Linux Mint's repositories. If --exact is given,
|
||||||
addr = 'http://packages.linuxmint.com/list.php?release=' + quote(release)
|
look up packages by the exact package name. Otherwise, look it up
|
||||||
|
as a simple glob pattern."""
|
||||||
|
addr = 'http://packages.linuxmint.com/list.php?release=' + \
|
||||||
|
quote(release)
|
||||||
try:
|
try:
|
||||||
fd = utils.web.getUrl(addr).decode("utf-8")
|
fd = utils.web.getUrl(addr).decode("utf-8")
|
||||||
except utils.web.Error as e:
|
except utils.web.Error as e:
|
||||||
@ -336,20 +359,25 @@ class PkgInfo(callbacks.Plugin):
|
|||||||
# Ascend to find the section name (in <h2>):
|
# Ascend to find the section name (in <h2>):
|
||||||
section = result.parent.parent.parent.previous_sibling.\
|
section = result.parent.parent.parent.previous_sibling.\
|
||||||
previous_sibling.string
|
previous_sibling.string
|
||||||
# Find the package version in the next <td>; for some reason we have
|
# Find the package version in the next <td>; for some reason we
|
||||||
# to go two siblings further, as the first .next_sibling returns '\n'.
|
# have to go two siblings further, as the first .next_sibling
|
||||||
# This is mentioned briefly in Beautiful Soup 4's documentation...
|
# returns '\n'. This is mentioned briefly in Beautiful Soup 4's
|
||||||
|
# documentation...
|
||||||
version = result.next_sibling.next_sibling.string
|
version = result.next_sibling.next_sibling.string
|
||||||
|
# We format our found dictionary this way because the same
|
||||||
|
# package can exist multiple times in different sections of
|
||||||
|
# the repository (e.g. one in Main, one in Backports, etc.)
|
||||||
found['%s [\x02%s\x02]' % (name, section)] = version
|
found['%s [\x02%s\x02]' % (name, section)] = version
|
||||||
if found:
|
if found:
|
||||||
s = 'Found %s results: ' % len(found)
|
items = [format('%s \x02(%s)\x02', pkg, found[pkg]) for pkg in
|
||||||
for x in found:
|
found]
|
||||||
s += '%s \x02(%s)\x02, ' % (x, found[x])
|
s = format('Found %n: %L, %s %u', (len(found), 'result'), items,
|
||||||
s += format('View more at: %u', addr)
|
_('View more at: '), addr)
|
||||||
irc.reply(s)
|
irc.reply(s)
|
||||||
else:
|
else:
|
||||||
irc.error('No results found.')
|
irc.error('No results found.')
|
||||||
mintpkg = wrap(mintpkg, ['somethingWithoutSpaces', 'somethingWithoutSpaces',
|
mintpkg = wrap(mintpkg, ['somethingWithoutSpaces',
|
||||||
|
'somethingWithoutSpaces',
|
||||||
getopts({'exact': ''})])
|
getopts({'exact': ''})])
|
||||||
|
|
||||||
Class = PkgInfo
|
Class = PkgInfo
|
||||||
|
Loading…
x
Reference in New Issue
Block a user