Bug#489722: python-debian: names should conform with PEP 8
Ben Finney
ben+debian at benfinney.id.au
Mon Jul 7 11:49:48 UTC 2008
Package: python-debian
Version: 0.1.10
Severity: minor
Tags: patch
The Python community largely expects code to conform to PEP 8
<URL:http://www.python.org/dev/peps/pep-0008>, which helps ensure that
code and interfaces are standardised to some extent.
One of the provisions of PEP 8 is that function, method, and instance
names should be named with all lowercase, with underscores between
words where helpful.
The code base in 'python-debian' is only following this standard in
some places, making it more cumbersome to read than necessary, and
making the API confusingly inconsistent.
The attached file is a Bazaar patch bundle against the current state
of the official VCS location,
<URL:http://bzr.debian.org/pkg-python-debian/trunk/>. It renames all
mixedCase names to be lower_case in conformance with PEP 8. Where
those names are part of the API, a function with the existing name is
provided that raises a DeprecationWarning and calls the real function.
--
\ “As far as the laws of mathematics refer to reality, they are |
`\ not certain, and as far as they are certain, they do not refer |
_o__) to reality.” —Albert Einstein, 1983 |
Ben Finney <ben at benfinney.id.au>
-------------- next part --------------
# Bazaar merge directive format 2 (Bazaar 0.90)
# revision_id: ben+debian at benfinney.id.au-20080707113428-\
# o35qhbkzdoyc8ut3
# target_branch: sftp://bzr.debian.org/bzr/pkg-python-debian/trunk/
# testament_sha1: f5a9b13116ef0e61bd0b120e41a07de4241dc99f
# timestamp: 2008-07-07 21:36:22 +1000
# base_revision_id: jw+debian at jameswestby.net-20080612111747-\
# 101ly7y9h95xce4o
#
# Begin patch
=== modified file 'debian_bundle/arfile.py'
--- debian_bundle/arfile.py 2007-07-18 14:50:22 +0000
+++ debian_bundle/arfile.py 2008-07-07 07:27:01 +0000
@@ -44,10 +44,10 @@
self.__fileobj = fileobj
if mode == "r":
- self.__indexArchive()
+ self.__index_archive()
pass # TODO write support
- def __indexArchive(self):
+ def __index_archive(self):
if self.__fname:
fp = open(self.__fname, "rb")
elif self.__fileobj:
=== modified file 'debian_bundle/deb822.py'
--- debian_bundle/deb822.py 2008-05-01 05:52:14 +0000
+++ debian_bundle/deb822.py 2008-07-07 11:34:28 +0000
@@ -21,6 +21,7 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+from deprecation import function_deprecated_by
try:
import apt_pkg
@@ -272,22 +273,26 @@
###
- def isSingleLine(self, s):
+ def is_single_line(self, s):
if s.count("\n"):
return False
else:
return True
- def isMultiLine(self, s):
- return not self.isSingleLine(s)
-
- def _mergeFields(self, s1, s2):
+ isSingleLine = function_deprecated_by(is_single_line)
+
+ def is_multi_line(self, s):
+ return not self.is_single_line(s)
+
+ isMultiLine = function_deprecated_by(is_multi_line)
+
+ def _merge_fields(self, s1, s2):
if not s2:
return s1
if not s1:
return s2
- if self.isSingleLine(s1) and self.isSingleLine(s2):
+ if self.is_single_line(s1) and self.is_single_line(s2):
## some fields are delimited by a single space, others
## a comma followed by a space. this heuristic assumes
## that there are multiple items in one of the string fields
@@ -309,7 +314,7 @@
prev = item
return merged
- if self.isMultiLine(s1) and self.isMultiLine(s2):
+ if self.is_multi_line(s1) and self.is_multi_line(s2):
for item in s2.splitlines(True):
if item not in s1.splitlines(True):
s1 = s1 + "\n" + item
@@ -317,7 +322,9 @@
raise ValueError
- def mergeFields(self, key, d1, d2 = None):
+ _mergeFields = function_deprecated_by(_merge_fields)
+
+ def merge_fields(self, key, d1, d2=None):
## this method can work in two ways - abstract that away
if d2 == None:
x1 = self
@@ -347,7 +354,8 @@
return None
return merged
- ###
+
+ mergeFields = function_deprecated_by(merge_fields)
def gpg_stripped_paragraph(sequence):
lines = []
@@ -409,7 +417,7 @@
except KeyError:
continue
- if self.isMultiLine(contents):
+ if self.is_multi_line(contents):
self[field] = []
updater_method = self[field].append
else:
=== modified file 'debian_bundle/debian_support.py'
--- debian_bundle/debian_support.py 2007-12-27 17:25:09 +0000
+++ debian_bundle/debian_support.py 2008-07-07 11:34:28 +0000
@@ -22,6 +22,7 @@
import sha
import types
+from deprecation import function_deprecated_by
import apt_pkg
apt_pkg.init()
@@ -50,11 +51,13 @@
self.lineno,
`self.msg`)
- def printOut(self, file):
+ def print_out(self, file):
"""Writes a machine-parsable error message to file."""
file.write("%s:%d: %s\n" % (self.filename, self.lineno, self.msg))
file.flush()
+ printOut = function_deprecated_by(print_out)
+
class Version:
"""Version class which uses the original APT comparison algorithm."""
@@ -89,17 +92,17 @@
re_field = re.compile(r'^([A-Za-z][A-Za-z0-9-]+):(?:\s*(.*?))?\s*$')
re_continuation = re.compile(r'^\s+(?:\.|(\S.*?)\s*)$')
- def __init__(self, name, fileObj=None):
+ def __init__(self, name, file_obj=None):
"""Creates a new package file object.
name - the name of the file the data comes from
- fileObj - an alternate data source; the default is to open the
+ file_obj - an alternate data source; the default is to open the
file with the indicated name.
"""
- if fileObj is None:
- fileObj = file(name)
+ if file_obj is None:
+ file_obj = file(name)
self.name = name
- self.file = fileObj
+ self.file = file_obj
self.lineno = 0
def __iter__(self):
@@ -109,7 +112,7 @@
while line:
if line == '\n':
if len(pkg) == 0:
- self.raiseSyntaxError('expected package record')
+ self.raise_syntax_error('expected package record')
yield pkg
pkg = []
line = self.file.readline()
@@ -118,7 +121,7 @@
match = self.re_field.match(line)
if not match:
- self.raiseSyntaxError("expected package field")
+ self.raise_syntax_error("expected package field")
(name, contents) = match.groups()
contents = contents or ''
@@ -137,11 +140,13 @@
if pkg:
yield pkg
- def raiseSyntaxError(self, msg, lineno=None):
+ def raise_syntax_error(self, msg, lineno=None):
if lineno is None:
lineno = self.lineno
raise ParseError(self.name, lineno, msg)
+ raiseSyntaxError = function_deprecated_by(raise_syntax_error)
+
class PseudoEnum:
"""A base class for types which resemble enumeration types."""
def __init__(self, name, order):
@@ -158,27 +163,36 @@
class Release(PseudoEnum): pass
-def listReleases():
+def list_releases():
releases = {}
rels = ("potato", "woody", "sarge", "etch", "lenny", "sid")
for r in range(len(rels)):
releases[rels[r]] = Release(rels[r], r)
Release.releases = releases
return releases
-def internRelease(name, releases=listReleases()):
+
+listReleases = function_deprecated_by(list_releases)
+
+def intern_release(name, releases=list_releases()):
if releases.has_key(name):
return releases[name]
else:
return None
+
+internRelease = function_deprecated_by(intern_release)
+
del listReleases
+del list_releases
-def readLinesSHA1(lines):
+def read_lines_sha1(lines):
m = sha.new()
for l in lines:
m.update(l)
return m.hexdigest()
-def patchesFromEdScript(source,
+readLinesSHA1 = function_deprecated_by(read_lines_sha1)
+
+def patches_from_ed_script(source,
re_cmd=re.compile(r'^(\d+)(?:,(\d+))?([acd])$')):
"""Converts source to a stream of patches.
@@ -229,12 +243,16 @@
lines.append(l)
yield (first, last, lines)
-def patchLines(lines, patches):
+patchesFromEdScript = function_deprecated_by(patches_from_ed_script)
+
+def patch_lines(lines, patches):
"""Applies patches to lines. Updates lines in place."""
for (first, last, args) in patches:
lines[first:last] = args
-def replaceFile(lines, local):
+patchLines = function_deprecated_by(patch_lines)
+
+def replace_file(lines, local):
import os.path
@@ -250,7 +268,9 @@
if os.path.exists(local_new):
os.unlink(local_new)
-def downloadGunzipLines(remote):
+replaceFile = function_deprecated_by(replace_file)
+
+def download_gunzip_lines(remote):
"""Downloads a file from a remote location and gunzips it.
Returns the lines in the file."""
@@ -272,19 +292,23 @@
finally:
os.unlink(fname)
return lines
-
-def downloadFile(remote, local):
+
+downloadGunzipLines = function_deprecated_by(download_gunzip_lines)
+
+def download_file(remote, local):
"""Copies a gzipped remote file to the local system.
remote - URL, without the .gz suffix
local - name of the local file
"""
- lines = downloadGunzipLines(remote + '.gz')
- replaceFile(lines, local)
+ lines = download_gunzip_lines(remote + '.gz')
+ replace_file(lines, local)
return lines
-def updateFile(remote, local, verbose=None):
+downloadFile = function_deprecated_by(download_file)
+
+def update_file(remote, local, verbose=None):
"""Updates the local file by downloading a remote patch.
Returns a list of lines in the local file.
@@ -294,12 +318,12 @@
local_file = file(local)
except IOError:
if verbose:
- print "updateFile: no local copy, downloading full file"
- return downloadFile(remote, local)
+ print "update_file: no local copy, downloading full file"
+ return download_file(remote, local)
lines = local_file.readlines()
local_file.close()
- local_hash = readLinesSHA1(lines)
+ local_hash = read_lines_sha1(lines)
patches_to_apply = []
patch_hashes = {}
@@ -315,12 +339,12 @@
# FIXME: urllib does not raise a proper exception, so we parse
# the error message.
if verbose:
- print "updateFile: could not interpret patch index file"
- return downloadFile(remote, local)
+ print "update_file: could not interpret patch index file"
+ return download_file(remote, local)
except IOError:
if verbose:
- print "updateFile: could not download patch index file"
- return downloadFile(remote, local)
+ print "update_file: could not download patch index file"
+ return download_file(remote, local)
for fields in index_fields:
for (field, value) in fields:
@@ -328,7 +352,7 @@
(remote_hash, remote_size) = re_whitespace.split(value)
if local_hash == remote_hash:
if verbose:
- print "updateFile: local file is up-to-date"
+ print "update_file: local file is up-to-date"
return lines
continue
@@ -356,30 +380,32 @@
continue
if verbose:
- print "updateFile: field %s ignored" % `field`
+ print "update_file: field %s ignored" % `field`
if not patches_to_apply:
if verbose:
- print "updateFile: could not find historic entry", local_hash
- return downloadFile(remote, local)
+ print "update_file: could not find historic entry", local_hash
+ return download_file(remote, local)
for patch_name in patches_to_apply:
- print "updateFile: downloading patch " + `patch_name`
- patch_contents = downloadGunzipLines(remote + '.diff/' + patch_name
+ print "update_file: downloading patch " + `patch_name`
+ patch_contents = download_gunzip_lines(remote + '.diff/' + patch_name
+ '.gz')
- if readLinesSHA1(patch_contents ) <> patch_hashes[patch_name]:
+ if read_lines_sha1(patch_contents ) <> patch_hashes[patch_name]:
raise ValueError, "patch %s was garbled" % `patch_name`
- patchLines(lines, patchesFromEdScript(patch_contents))
+ patch_lines(lines, patches_from_ed_script(patch_contents))
- new_hash = readLinesSHA1(lines)
+ new_hash = read_lines_sha1(lines)
if new_hash <> remote_hash:
raise ValueError, ("patch failed, got %s instead of %s"
% (new_hash, remote_hash))
- replaceFile(lines, local)
+ replace_file(lines, local)
return lines
-def mergeAsSets(*args):
+updateFile = function_deprecated_by(update_file)
+
+def merge_as_sets(*args):
"""Create an order set (represented as a list) of the objects in
the sequences passed as arguments."""
s = {}
@@ -390,6 +416,8 @@
l.sort()
return l
+mergeAsSets = function_deprecated_by(merge_as_sets)
+
def test():
# Version
assert Version('0') < Version('a')
@@ -411,7 +439,7 @@
assert Version('1.5~rc1') > Version('1.5~dev0')
# Release
- assert internRelease('sarge') < internRelease('etch')
+ assert intern_release('sarge') < intern_release('etch')
# PackageFile
# for p in PackageFile('../../data/packages/sarge/Sources'):
@@ -420,8 +448,8 @@
# assert p[0][0] == 'Package'
# Helper routines
- assert readLinesSHA1([]) == 'da39a3ee5e6b4b0d3255bfef95601890afd80709'
- assert readLinesSHA1(['1\n', '23\n']) \
+ assert read_lines_sha1([]) == 'da39a3ee5e6b4b0d3255bfef95601890afd80709'
+ assert read_lines_sha1(['1\n', '23\n']) \
== '14293c9bd646a15dc656eaf8fba95124020dfada'
file_a = map(lambda x: "%d\n" % x, range(1, 18))
@@ -431,11 +459,11 @@
patch = ['15a\n', 'A\n', 'B\n', 'C\n', '.\n', '13c\n', '<13>\n', '.\n',
'9,10d\n', '6d\n', '2,3c\n', '<2>\n', '<3>\n', '.\n', '0a\n',
'0\n', '.\n']
- patchLines(file_a, patchesFromEdScript(patch))
+ patch_lines(file_a, patches_from_ed_script(patch))
assert ''.join(file_b) == ''.join(file_a)
- assert len(mergeAsSets([])) == 0
- assert ''.join(mergeAsSets("abc", "cb")) == "abc"
+ assert len(merge_as_sets([])) == 0
+ assert ''.join(merge_as_sets("abc", "cb")) == "abc"
if __name__ == "__main__":
test()
=== modified file 'debian_bundle/debtags.py'
--- debian_bundle/debtags.py 2007-07-15 14:47:13 +0000
+++ debian_bundle/debtags.py 2008-07-07 11:34:28 +0000
@@ -17,7 +17,9 @@
import math, re, cPickle
-def parseTags(input):
+from deprecation import function_deprecated_by
+
+def parse_tags(input):
lre = re.compile(r"^(.+?)(?::?\s*|:\s+(.+?)\s*)$")
for line in input:
# Is there a way to remove the last character of a line that does not
@@ -30,19 +32,23 @@
tags = set()
yield pkgs, tags
-def readTagDatabase(input):
+parseTags = function_deprecated_by(parse_tags)
+
+def read_tag_database(input):
"Read the tag database, returning a pkg->tags dictionary"
db = {}
- for pkgs, tags in parseTags(input):
+ for pkgs, tags in parse_tags(input):
# Create the tag set using the native set
for p in pkgs:
db[p] = tags.copy()
return db;
-def readTagDatabaseReversed(input):
+readTagDatabase = function_deprecated_by(read_tag_database)
+
+def read_tag_database_reversed(input):
"Read the tag database, returning a tag->pkgs dictionary"
db = {}
- for pkgs, tags in parseTags(input):
+ for pkgs, tags in parse_tags(input):
# Create the tag set using the native set
for tag in tags:
if db.has_key(tag):
@@ -51,16 +57,18 @@
db[tag] = pkgs.copy()
return db;
-def readTagDatabaseBothWays(input, tagFilter = None):
+readTagDatabaseReversed = function_deprecated_by(read_tag_database_reversed)
+
+def read_tag_database_both_ways(input, tag_filter = None):
"Read the tag database, returning a pkg->tags and a tag->pkgs dictionary"
db = {}
dbr = {}
- for pkgs, tags in parseTags(input):
+ for pkgs, tags in parse_tags(input):
# Create the tag set using the native set
- if tagFilter == None:
+ if tag_filter == None:
tags = set(tags)
else:
- tags = set(filter(tagFilter, tags))
+ tags = set(filter(tag_filter, tags))
for pkg in pkgs:
db[pkg] = tags.copy()
for tag in tags:
@@ -70,6 +78,7 @@
dbr[tag] = pkgs.copy()
return db, dbr;
+readTagDatabaseBothWays = function_deprecated_by(read_tag_database_both_ways)
def reverse(db):
"Reverse a tag database, from package -> tags to tag->packages"
@@ -90,24 +99,24 @@
print "%s:" % (pkg), ", ".join(tags)
-def relevanceIndexFunction(full, sub):
- #return (float(sub.card(tag)) / float(sub.tagCount())) / \
- # (float(full.card(tag)) / float(full.tagCount()))
- #return sub.card(tag) * full.card(tag) / sub.tagCount()
+def relevance_index_function(full, sub):
+ #return (float(sub.card(tag)) / float(sub.tag_count())) / \
+ # (float(full.card(tag)) / float(full.tag_count()))
+ #return sub.card(tag) * full.card(tag) / sub.tag_count()
# New cardinality divided by the old cardinality
#return float(sub.card(tag)) / float(full.card(tag))
## Same as before, but weighted by the relevance the tag had in the
## full collection, to downplay the importance of rare tags
- #return float(sub.card(tag) * full.card(tag)) / float(full.card(tag) * full.tagCount())
+ #return float(sub.card(tag) * full.card(tag)) / float(full.card(tag) * full.tag_count())
# Simplified version:
- #return float(sub.card(tag)) / float(full.tagCount())
+ #return float(sub.card(tag)) / float(full.tag_count())
# Weighted by the square root of the relevance, to downplay the very
# common tags a bit
- #return lambda tag: float(sub.card(tag)) / float(full.card(tag)) * math.sqrt(full.card(tag) / float(full.tagCount()))
- #return lambda tag: float(sub.card(tag)) / float(full.card(tag)) * math.sqrt(full.card(tag) / float(full.packageCount()))
+ #return lambda tag: float(sub.card(tag)) / float(full.card(tag)) * math.sqrt(full.card(tag) / float(full.tag_count()))
+ #return lambda tag: float(sub.card(tag)) / float(full.card(tag)) * math.sqrt(full.card(tag) / float(full.package_count()))
# One useless factor removed, and simplified further, thanks to Benjamin Mesing
return lambda tag: float(sub.card(tag)**2) / float(full.card(tag))
@@ -120,8 +129,9 @@
# Same but it tries to downplay the 'how many are out' value in the
# case of popular tags, to mitigate the 'there will always be popular
# tags left out' cases. Does not seem to be much of an improvement.
- #return lambda tag: sub.card(tag) - float(full.card(tag) - sub.card(tag))/(math.sin(float(full.card(tag))*3.1415/full.packageCount())/4 + 0.75)
+ #return lambda tag: sub.card(tag) - float(full.card(tag) - sub.card(tag))/(math.sin(float(full.card(tag))*3.1415/full.package_count())/4 + 0.75)
+relevanceIndexFunction = function_deprecated_by(relevance_index_function)
class DB:
"""
@@ -132,7 +142,7 @@
self.db = {}
self.rdb = {}
- def read(self, input, tagFilter = None):
+ def read(self, input, tag_filter=None):
"""
Read the database from a file.
@@ -140,7 +150,7 @@
# Read the system Debtags database
db.read(open("/var/lib/debtags/package-tags", "r"))
"""
- self.db, self.rdb = readTagDatabaseBothWays(input, tagFilter)
+ self.db, self.rdb = read_tag_database_both_ways(input, tag_filter)
def qwrite(self, file):
"Quickly write the data to a pickled file"
@@ -163,8 +173,10 @@
def dump(self):
output(self.db)
- def dumpReverse(self):
+ def dump_reverse(self):
output(self.rdb)
+
+ dumpReverse = function_deprecated_by(dump_reverse)
def reverse(self):
"Return the reverse collection, sharing tagsets with this one"
@@ -173,18 +185,20 @@
res.rdb = self.db
return res
- def facetCollection(self):
+ def facet_collection(self):
"""
Return a copy of this collection, but replaces the tag names
with only their facets.
"""
fcoll = DB()
tofacet = re.compile(r"^([^:]+).+")
- for pkg, tags in self.iterPackagesTags():
+ for pkg, tags in self.iter_packagesTags():
ftags = set([tofacet.sub(r"\1", t) for t in tags])
fcoll.insert(pkg, ftags)
return fcoll
+ facetCollection = function_deprecated_by(facet_collection)
+
def copy(self):
"""
Return a copy of this collection, with the tagsets copied as
@@ -195,7 +209,7 @@
res.rdb = self.rdb.copy()
return res
- def reverseCopy(self):
+ def reverse_copy(self):
"""
Return the reverse collection, with a copy of the tagsets of
this one.
@@ -205,33 +219,39 @@
res.rdb = self.db.copy()
return res
- def choosePackages(self, packageIter):
+ reverseCopy = function_deprecated_by(reverse_copy)
+
+ def choose_packages(self, package_iter):
"""
- Return a collection with only the packages in packageIter,
+ Return a collection with only the packages in package_iter,
sharing tagsets with this one
"""
res = DB()
db = {}
- for pkg in packageIter:
+ for pkg in package_iter:
if self.db.has_key(pkg): db[pkg] = self.db[pkg]
res.db = db
res.rdb = reverse(db)
return res
- def choosePackagesCopy(self, packageIter):
+ choosePackages = function_deprecated_by(choose_packages)
+
+ def choose_packages_copy(self, package_iter):
"""
- Return a collection with only the packages in packageIter,
+ Return a collection with only the packages in package_iter,
with a copy of the tagsets of this one
"""
res = DB()
db = {}
- for pkg in packageIter:
+ for pkg in package_iter:
db[pkg] = self.db[pkg]
res.db = db
res.rdb = reverse(db)
return res
- def filterPackages(self, packageFilter):
+ choosePackagesCopy = function_deprecated_by(choose_packages_copy)
+
+ def filter_packages(self, package_filter):
"""
Return a collection with only those packages that match a
filter, sharing tagsets with this one. The filter will match
@@ -239,13 +259,15 @@
"""
res = DB()
db = {}
- for pkg in filter(packageFilter, self.db.iterkeys()):
+ for pkg in filter(package_filter, self.db.iterkeys()):
db[pkg] = self.db[pkg]
res.db = db
res.rdb = reverse(db)
return res
- def filterPackagesCopy(self, filter):
+ filterPackages = function_deprecated_by(filter_packages)
+
+ def filter_packages_copy(self, filter):
"""
Return a collection with only those packages that match a
filter, with a copy of the tagsets of this one. The filter
@@ -259,7 +281,9 @@
res.rdb = reverse(db)
return res
- def filterPackagesTags(self, packageTagFilter):
+ filterPackagesCopy = function_deprecated_by(filter_packages_copy)
+
+ def filter_packages_tags(self, package_tag_filter):
"""
Return a collection with only those packages that match a
filter, sharing tagsets with this one. The filter will match
@@ -267,13 +291,15 @@
"""
res = DB()
db = {}
- for pkg, tags in filter(packageTagFilter, self.db.iteritems()):
+ for pkg, tags in filter(package_tag_filter, self.db.iteritems()):
db[pkg] = self.db[pkg]
res.db = db
res.rdb = reverse(db)
return res
- def filterPackagesTagsCopy(self, packageTagFilter):
+ filterPackagesTags = function_deprecated_by(filter_packages_tags)
+
+ def filter_packages_tags_copy(self, package_tag_filter):
"""
Return a collection with only those packages that match a
filter, with a copy of the tagsets of this one. The filter
@@ -281,13 +307,15 @@
"""
res = DB()
db = {}
- for pkg, tags in filter(packageTagFilter, self.db.iteritems()):
+ for pkg, tags in filter(package_tag_filter, self.db.iteritems()):
db[pkg] = self.db[pkg].copy()
res.db = db
res.rdb = reverse(db)
return res
- def filterTags(self, tagFilter):
+ filterPackagesTagsCopy = function_deprecated_by(filter_packages_tags_copy)
+
+ def filter_tags(self, tag_filter):
"""
Return a collection with only those tags that match a
filter, sharing package sets with this one. The filter will match
@@ -295,13 +323,15 @@
"""
res = DB()
rdb = {}
- for tag in filter(tagFilter, self.rdb.iterkeys()):
+ for tag in filter(tag_filter, self.rdb.iterkeys()):
rdb[tag] = self.rdb[tag]
res.rdb = rdb
res.db = reverse(rdb)
return res
- def filterTagsCopy(self, tagFilter):
+ filterTags = function_deprecated_by(filter_tags)
+
+ def filter_tags_copy(self, tag_filter):
"""
Return a collection with only those tags that match a
filter, with a copy of the package sets of this one. The
@@ -309,48 +339,62 @@
"""
res = DB()
rdb = {}
- for tag in filter(tagFilter, self.rdb.iterkeys()):
+ for tag in filter(tag_filter, self.rdb.iterkeys()):
rdb[tag] = self.rdb[tag].copy()
res.rdb = rdb
res.db = reverse(rdb)
return res
- def hasPackage(self, pkg):
+ filterTagsCopy = function_deprecated_by(filter_tags_copy)
+
+ def has_package(self, pkg):
"""Check if the collection contains the given package"""
return self.db.has_key(pkg)
- def hasTag(self, tag):
+ hasPackage = function_deprecated_by(has_package)
+
+ def has_tag(self, tag):
"""Check if the collection contains packages tagged with tag"""
return self.rdb.has_key(tag)
- def tagsOfPackage(self, pkg):
+ hasTag = function_deprecated_by(has_tag)
+
+ def tags_of_package(self, pkg):
"""Return the tag set of a package"""
return self.db.has_key(pkg) and self.db[pkg] or set()
- def packagesOfTag(self, tag):
+ tagsOfPackage = function_deprecated_by(tags_of_package)
+
+ def packages_of_tag(self, tag):
"""Return the package set of a tag"""
return self.rdb.has_key(tag) and self.rdb[tag] or set()
- def tagsOfPackages(self, pkgs):
+ packagesOfTag = function_deprecated_by(packages_of_tag)
+
+ def tags_of_packages(self, pkgs):
"""Return the set of tags that have all the packages in pkgs"""
res = None
for p in pkgs:
if res == None:
- res = set(self.tagsOfPackage(p))
+ res = set(self.tags_of_package(p))
else:
- res &= self.tagsOfPackage(p)
+ res &= self.tags_of_package(p)
return res
- def packagesOfTags(self, tags):
+ tagsOfPackages = function_deprecated_by(tags_of_packages)
+
+ def packages_of_tags(self, tags):
"""Return the set of packages that have all the tags in tags"""
res = None
for t in tags:
if res == None:
- res = set(self.packagesOfTag(t))
+ res = set(self.packages_of_tag(t))
else:
- res &= self.packagesOfTag(t)
+ res &= self.packages_of_tag(t)
return res
+ packagesOfTags = function_deprecated_by(packages_of_tags)
+
def card(self, tag):
"""
Return the cardinality of a tag
@@ -367,34 +411,46 @@
tag.
"""
n = self.card(tag)
- tot = self.packageCount()
+ tot = self.package_count()
return min(n, tot - n)
- def iterPackages(self):
+ def iter_packages(self):
"""Iterate over the packages"""
return self.db.iterkeys()
- def iterTags(self):
+ iterPackages = function_deprecated_by(iter_packages)
+
+ def iter_tags(self):
"""Iterate over the tags"""
return self.rdb.iterkeys()
- def iterPackagesTags(self):
+ iterTags = function_deprecated_by(iter_tags)
+
+ def iter_packages_tags(self):
"""Iterate over 2-tuples of (pkg, tags)"""
return self.db.iteritems()
- def iterTagsPackages(self):
+ iterPackagesTags = function_deprecated_by(iter_packages_tags)
+
+ def iter_tags_packages(self):
"""Iterate over 2-tuples of (tag, pkgs)"""
return self.rdb.iteritems()
- def packageCount(self):
+ iterTagsPackages = function_deprecated_by(iter_tags_packages)
+
+ def package_count(self):
"""Return the number of packages"""
return len(self.db)
- def tagCount(self):
+ packageCount = function_deprecated_by(package_count)
+
+ def tag_count(self):
"""Return the number of tags"""
return len(self.rdb)
- def idealTagset(self, tags):
+ tagCount = function_deprecated_by(tag_count)
+
+ def ideal_tagset(self, tags):
"""
Return an ideal selection of the top tags in a list of tags.
@@ -416,7 +472,7 @@
tagset = set()
min_score = 3
for i in range(len(tags)):
- pkgs = self.packagesOfTags(tags[:i+1])
+ pkgs = self.packages_of_tags(tags[:i+1])
card = len(pkgs)
if card == 0: break;
score = score_fun(card)
@@ -430,6 +486,8 @@
else:
return tagset
+ idealTagset = function_deprecated_by(ideal_tagset)
+
def correlations(self):
"""
Generate the list of correlation as a tuple (hastag, hasalsotag, score).
@@ -437,11 +495,11 @@
Every touple will indicate that the tag 'hastag' tends to also
have 'hasalsotag' with a score of 'score'.
"""
- for pivot in self.iterTags():
- with_ = self.filterPackagesTags(lambda pt: pivot in pt[1])
- without = self.filterPackagesTags(lambda pt: pivot not in pt[1])
- for tag in with_.iterTags():
+ for pivot in self.iter_tags():
+ with_ = self.filter_packages_tags(lambda pt: pivot in pt[1])
+ without = self.filter_packages_tags(lambda pt: pivot not in pt[1])
+ for tag in with_.iter_tags():
if tag == pivot: continue
- has = float(with_.card(tag)) / float(with_.packageCount())
- hasnt = float(without.card(tag)) / float(without.packageCount())
+ has = float(with_.card(tag)) / float(with_.package_count())
+ hasnt = float(without.card(tag)) / float(without.package_count())
yield pivot, tag, has - hasnt
=== added file 'debian_bundle/deprecation.py'
--- debian_bundle/deprecation.py 1970-01-01 00:00:00 +0000
+++ debian_bundle/deprecation.py 2008-07-07 10:36:50 +0000
@@ -0,0 +1,38 @@
+# -*- coding: utf-8 -*- vim: fileencoding=utf-8 :
+#
+# debian_bundle/deprecation.py
+# Utility module to deprecate features
+#
+# Copyright © Ben Finney <ben+debian at benfinney.id.au>
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation, either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+""" Utility module to deprecate features """
+
+import warnings
+
+def function_deprecated_by(func):
+ """ Return a function that warns it is deprecated by another function.
+
+ Returns a new function that warns it is deprecated by function
+ ``func``, then acts as a pass-through wrapper for ``func``.
+
+ """
+ func_name = func.__name__
+ warn_msg = "Use %(func_name)s instead" % vars()
+ def deprecated_func(*args, **kwargs):
+ warnings.warn(warn_msg, DeprecationWarning, stacklevel=2)
+ return func(*args, **kwargs)
+ return deprecated_func
=== modified file 'debian_bundle/doc-debtags'
--- debian_bundle/doc-debtags 2006-10-30 10:20:18 +0000
+++ debian_bundle/doc-debtags 2008-07-07 11:34:28 +0000
@@ -60,10 +60,10 @@
in a package-centered or in a tag-centered way:
"""
-document(debtags.DB.iterPackages)
-document(debtags.DB.iterPackagesTags)
-document(debtags.DB.iterTags)
-document(debtags.DB.iterTagsPackages)
+document(debtags.DB.iter_packages)
+document(debtags.DB.iter_packages_tags)
+document(debtags.DB.iter_tags)
+document(debtags.DB.iter_tags_packages)
print """Sample usage
@@ -76,9 +76,9 @@
db = debtags.DB()
db.read(open("/var/lib/debtags/package-tags", "r"))
- print db.packageCount(), "packages in the database"
+ print db.package_count(), "packages in the database"
print "Image editors:"
- for pkg in db.packagesOfTags(set(("use::editing", "works-with::image:raster"))):
+ for pkg in db.packages_of_tags(set(("use::editing", "works-with::image:raster"))):
print " *", pkg
This example computes the set of tags that belong to all the packages in a
@@ -88,11 +88,11 @@
db = debtags.DB()
db.read(open("/var/lib/debtags/package-tags", "r"))
- tags = db.tagsOfPackages(("gimp", "krita"))
+ tags = db.tags_of_packages(("gimp", "krita"))
print "Common tags:"
for tag in tags:
print " *", tag
print "Packages similar to gimp and krita:"
- for pkg in db.packagesOfTags(tags):
+ for pkg in db.packages_of_tags(tags):
print " *", pkg
"""
=== modified file 'examples/debfile/dpkg-info'
--- examples/debfile/dpkg-info 2007-08-17 17:42:24 +0000
+++ examples/debfile/dpkg-info 2008-07-07 11:34:28 +0000
@@ -46,9 +46,9 @@
for n, v in deb.debcontrol().iteritems(): # print DEBIAN/control fields
if n.lower() == 'description': # increase indentation of long dsc
lines = v.split('\n')
- shortDsc = lines[0]
- longDsc = string.join(map(lambda l: ' ' + l, lines[1:]), '\n')
- print ' %s: %s\n%s' % (n, shortDsc, longDsc)
+ short_dsc = lines[0]
+ long_dsc = string.join(map(lambda l: ' ' + l, lines[1:]), '\n')
+ print ' %s: %s\n%s' % (n, short_dsc, long_dsc)
else:
print ' %s: %s' % (n, v)
=== modified file 'examples/debtags/pkgwalk'
--- examples/debtags/pkgwalk 2007-01-30 21:03:05 +0000
+++ examples/debtags/pkgwalk 2008-07-07 11:34:28 +0000
@@ -42,10 +42,10 @@
# Read full database
db = debtags.DB()
- tagFilter = re.compile(r"^special::.+$|^.+::TODO$")
- db.read(open(options.tagdb, "r"), lambda x: not tagFilter.match(x))
+ tag_filter = re.compile(r"^special::.+$|^.+::TODO$")
+ db.read(open(options.tagdb, "r"), lambda x: not tag_filter.match(x))
- aptCache = apt.Cache()
+ apt_cache = apt.Cache()
# Maximum number of previous packages to remember
maxlen = 5
@@ -64,7 +64,7 @@
# For every tag, find the number of packages in trail that have the tag
tagscores = {}
for pkg in trail:
- for tag in db.tagsOfPackage(pkg):
+ for tag in db.tags_of_package(pkg):
if tag in tagscores:
tagscores[tag] += pkgweight[pkg]
else:
@@ -81,14 +81,14 @@
# Get the list of packages whose tagsets intersect the trail tagset
nextpkgs = set()
- for pkg, tags in db.iterPackagesTags():
+ for pkg, tags in db.iter_packages_tags():
if trailtags & tags:
nextpkgs.add(pkg)
# Score every package by the sum of the weight of its tags
def pkgscore(pkg):
score = 0.0
- for tag in db.tagsOfPackage(pkg):
+ for tag in db.tags_of_package(pkg):
if tag in tagscores:
score += tagscores[tag]
return score
@@ -97,8 +97,8 @@
#display = sorted(nextpkgs - set(trail), key=pkgscore, reverse=True)[:20]
display = sorted(nextpkgs, key=pkgscore, reverse=True)[:20]
for num, pkg in enumerate(display):
- aptpkg = aptCache[pkg]
- desc = aptpkg.rawDescription.split("\n")[0]
+ aptpkg = apt_cache[pkg]
+ desc = aptpkg.raw_description.split("\n")[0]
print "%2d) %s - %s" % (num + 1, pkg, desc)
# Ask the user to choose a new package
=== modified file 'examples/debtags/reverse'
--- examples/debtags/reverse 2006-11-20 21:14:17 +0000
+++ examples/debtags/reverse 2008-07-07 11:34:28 +0000
@@ -25,10 +25,10 @@
if len(sys.argv) > 1:
input = open(sys.argv[1],"r")
-#db = readTagDatabase(input)
+#db = read_tag_database(input)
#db = reverse(db)
-db = debtags.readTagDatabaseReversed(input)
-#dummy, db = debtags.readTagDatabaseBothWays(input)
+db = debtags.read_tag_database_reversed(input)
+#dummy, db = debtags.read_tag_database_both_ways(input)
for pkg, tags in db.items():
# Using % here seems awkward to me, but if I use calls to
=== modified file 'examples/debtags/smartsearch'
--- examples/debtags/smartsearch 2006-11-20 21:14:17 +0000
+++ examples/debtags/smartsearch 2008-07-07 11:34:28 +0000
@@ -26,23 +26,23 @@
class SmartSearcher:
def __init__(self, fullcoll, query):
- self.aptCache = apt.Cache()
+ self.apt_cache = apt.Cache()
self.wanted = set()
self.unwanted = set()
self.ignored = set()
self.interesting = []
- self.tagsInMenu = []
+ self.tags_in_menu = []
self.fullcoll = fullcoll
self.subcoll = fullcoll
# Initialise the search
- self.computeInteresting(query)
+ self.compute_interesting(query)
- def computeInteresting(self, query):
+ def compute_interesting(self, query):
input = subprocess.Popen("apt-cache search " + query, shell=True, stdout = subprocess.PIPE, close_fds = True)
# Read the package list and create the subcollection
@@ -52,15 +52,15 @@
#print pkg
pkgs.append(pkg)
- subcoll = self.fullcoll.choosePackages(pkgs)
+ subcoll = self.fullcoll.choose_packages(pkgs)
- relIndex = debtags.relevanceIndexFunction(self.fullcoll, subcoll)
+ rel_index = debtags.relevance_index_function(self.fullcoll, subcoll)
# Get all the tags sorted by increasing relevance
- self.interesting = sorted(self.subcoll.iterTags(), lambda b, a: cmp(relIndex(a), relIndex(b)))
+ self.interesting = sorted(self.subcoll.iter_tags(), lambda b, a: cmp(rel_index(a), rel_index(b)))
- def tagMatch(self, pkg):
- tags = self.fullcoll.tagsOfPackage(pkg)
+ def tag_match(self, pkg):
+ tags = self.fullcoll.tags_of_package(pkg)
if len(self.wanted) > 0 and not self.wanted.issubset(tags):
return False
if len(self.unwanted) > 0 and len(tags.intersection(self.unwanted)) > 0:
@@ -69,48 +69,48 @@
def refilter(self):
# Regenerate subcoll
- self.subcoll = self.fullcoll.filterPackages(self.tagMatch)
+ self.subcoll = self.fullcoll.filter_packages(self.tag_match)
- def showSet(self, tags, type):
+ def show_set(self, tags, type):
for tag in tags:
- self.tagsInMenu.append(tag)
- print "%d) %s (%s)" % (len(self.tagsInMenu), tag, type)
+ self.tags_in_menu.append(tag)
+ print "%d) %s (%s)" % (len(self.tags_in_menu), tag, type)
- def showChoiceSequence(self, seq, max = 7):
+ def show_choice_sequence(self, seq, max = 7):
for tag in seq:
if tag in self.wanted or tag in self.unwanted or tag in self.ignored:
continue
- self.tagsInMenu.append(tag)
+ self.tags_in_menu.append(tag)
print "%d) %s (%d/%d)" % \
- (len(self.tagsInMenu), tag, self.subcoll.card(tag), self.subcoll.packageCount())
+ (len(self.tags_in_menu), tag, self.subcoll.card(tag), self.subcoll.package_count())
max = max - 1
if max == 0: break
- def showTags(self):
- self.tagsInMenu = []
- self.showSet(self.wanted, "wanted")
- self.showSet(self.unwanted, "unwanted")
- self.showSet(self.ignored, "ignored")
+ def show_tags(self):
+ self.tags_in_menu = []
+ self.show_set(self.wanted, "wanted")
+ self.show_set(self.unwanted, "unwanted")
+ self.show_set(self.ignored, "ignored")
print
- self.showChoiceSequence(self.interesting)
+ self.show_choice_sequence(self.interesting)
print
# Compute the most interesting tags by discriminance
- discr = sorted(self.subcoll.iterTags(), \
+ discr = sorted(self.subcoll.iter_tags(), \
lambda a, b: cmp(self.subcoll.discriminance(a), self.subcoll.discriminance(b)))
- self.showChoiceSequence(discr)
+ self.show_choice_sequence(discr)
- def outputPackages(self):
- for pkg in self.subcoll.iterPackages():
- aptpkg = self.aptCache[pkg]
- desc = aptpkg.rawDescription.split("\n")[0]
+ def output_packages(self):
+ for pkg in self.subcoll.iter_packages():
+ aptpkg = self.apt_cache[pkg]
+ desc = aptpkg.raw_description.split("\n")[0]
print pkg, "-", desc
def interact(self):
done = False
while not done:
print "Tag selection:"
- self.showTags()
- print self.subcoll.packageCount(), " packages selected so far."
+ self.show_tags()
+ print self.subcoll.package_count(), " packages selected so far."
changed = False
@@ -137,7 +137,7 @@
if len(ans) == 0:
print "The 'k' command needs a keyword to use for finding new interesting tags."
else:
- self.computeInteresting(ans)
+ self.compute_interesting(ans)
ans = ''
else:
# Split the answer by spaces
@@ -148,10 +148,10 @@
except ValueError:
print cmd, "should have a number after +, - or ="
continue
- if idx > len(self.tagsInMenu):
+ if idx > len(self.tags_in_menu):
print "Tag", idx, "was not on the menu."
else:
- tag = self.tagsInMenu[idx - 1]
+ tag = self.tags_in_menu[idx - 1]
# cout << "Understood " << ans << " as " << ans[0] << tag.fullname() << endl;
if cmd[0] == '+':
@@ -168,9 +168,9 @@
self.ignored.add(tag)
changed = True
elif cmd == "V" or cmd == "v":
- self.outputPackages()
+ self.output_packages()
elif cmd == "D" or cmd == "d":
- self.outputPackages()
+ self.output_packages()
done = True;
elif cmd == "Q" or cmd == "q":
done = True;
@@ -189,8 +189,8 @@
fullcoll = debtags.DB()
# Read full database
-tagFilter = re.compile(r"^special::.+$|^.+::TODO$")
-fullcoll.read(open(sys.argv[1], "r"), lambda x: not tagFilter.match(x))
+tag_filter = re.compile(r"^special::.+$|^.+::TODO$")
+fullcoll.read(open(sys.argv[1], "r"), lambda x: not tag_filter.match(x))
searcher = SmartSearcher(fullcoll, " ".join(sys.argv[2:]))
searcher.interact()
=== modified file 'examples/debtags/tagminer'
--- examples/debtags/tagminer 2007-01-30 21:03:05 +0000
+++ examples/debtags/tagminer 2008-07-07 11:34:28 +0000
@@ -121,8 +121,8 @@
# Read full database
fullcoll = debtags.DB()
- tagFilter = re.compile(r"^special::.+$|^.+::TODO$")
- fullcoll.read(open(options.tagdb, "r"), lambda x: not tagFilter.match(x))
+ tag_filter = re.compile(r"^special::.+$|^.+::TODO$")
+ fullcoll.read(open(options.tagdb, "r"), lambda x: not tag_filter.match(x))
type = mimetype(args[0])
#print >>sys.stderr, "Mime type:", type
@@ -136,23 +136,23 @@
print >>sys.stderr, "Unhandled mime type:", type
else:
if options.action != None:
- aptCache = apt.Cache()
+ apt_cache = apt.Cache()
query = found.copy()
query.add("role::program")
query.add("use::"+options.action)
print "Debtags query:", " && ".join(query)
- subcoll = fullcoll.filterPackagesTags(lambda pt: query.issubset(pt[1]))
- for i in subcoll.iterPackages():
- aptpkg = aptCache[i]
- desc = aptpkg.rawDescription.split("\n")[0]
+ subcoll = fullcoll.filter_packages_tags(lambda pt: query.issubset(pt[1]))
+ for i in subcoll.iter_packages():
+ aptpkg = apt_cache[i]
+ desc = aptpkg.raw_description.split("\n")[0]
print i, "-", desc
else:
print "Debtags query:", " && ".join(found)
query = found.copy()
query.add("role::program")
- subcoll = fullcoll.filterPackagesTags(lambda pt: query.issubset(pt[1]))
- uses = map(lambda x:x[5:], filter(lambda x:x.startswith("use::"), subcoll.iterTags()))
+ subcoll = fullcoll.filter_packages_tags(lambda pt: query.issubset(pt[1]))
+ uses = map(lambda x:x[5:], filter(lambda x:x.startswith("use::"), subcoll.iter_tags()))
print "Available actions:", ", ".join(uses)
# vim:set ts=4 sw=4:
=== renamed file 'examples/debtags/tagsByRelevance' => 'examples/debtags/tagsbyrelevance'
--- examples/debtags/tagsByRelevance 2006-11-20 21:14:17 +0000
+++ examples/debtags/tagsbyrelevance 2008-07-07 11:34:28 +0000
@@ -28,8 +28,8 @@
full = debtags.DB()
# Read full database
-tagFilter = re.compile(r"^special::.+$|^.+::TODO$")
-full.read(open(sys.argv[1], "r"), lambda x: not tagFilter.match(x))
+tag_filter = re.compile(r"^special::.+$|^.+::TODO$")
+full.read(open(sys.argv[1], "r"), lambda x: not tag_filter.match(x))
# Read the package list and create the subcollection
input = len(sys.argv) > 2 and open(sys.argv[2],"r") or sys.stdin
@@ -39,12 +39,12 @@
pkg, none = pkg.rstrip("\n").split(' - ', 1)
pkgs.add(pkg)
-sub = full.choosePackages(pkgs)
+sub = full.choose_packages(pkgs)
-relIndex = debtags.relevanceIndexFunction(full, sub)
+rel_index = debtags.relevance_index_function(full, sub)
# Get all the tags sorted by increasing relevance
-tags = sorted(sub.iterTags(), lambda a, b: cmp(relIndex(a), relIndex(b)))
+tags = sorted(sub.iter_tags(), lambda a, b: cmp(rel_index(a), rel_index(b)))
## And finally print them
for tag in tags:
=== modified file 'examples/debtags/wxssearch'
--- examples/debtags/wxssearch 2006-11-20 21:14:17 +0000
+++ examples/debtags/wxssearch 2008-07-07 11:34:28 +0000
@@ -32,8 +32,8 @@
class Model(wx.EvtHandler):
class ModelEvent(wx.PyCommandEvent):
- def __init__(self, eventType):
- wx.PyCommandEvent.__init__(self, eventType)
+ def __init__(self, event_type):
+ wx.PyCommandEvent.__init__(self, event_type)
# Create custom events
wxEVT_CHANGED = wx.NewEventType()
@@ -41,7 +41,7 @@
def __init__(self, fullcoll):
wx.EvtHandler.__init__(self)
- self.aptCache = apt.Cache()
+ self.apt_cache = apt.Cache()
self.wanted = set()
self.unwanted = set()
@@ -55,8 +55,8 @@
self.refilter()
- def tagMatch(self, pkg):
- tags = self.fullcoll.tagsOfPackage(pkg)
+ def tag_match(self, pkg):
+ tags = self.fullcoll.tags_of_package(pkg)
if len(self.wanted) > 0 and not self.wanted.issubset(tags):
return False
if len(self.unwanted) > 0 and len(tags.intersection(self.unwanted)) > 0:
@@ -68,10 +68,10 @@
if len(self.wanted) == 0 and len(self.unwanted) == 0:
self.subcoll = self.fullcoll
else:
- self.subcoll = self.fullcoll.filterPackages(self.tagMatch)
+ self.subcoll = self.fullcoll.filter_packages(self.tag_match)
# Compute the most interesting tags by discriminance
- self.discriminant = sorted(self.subcoll.iterTags(), \
+ self.discriminant = sorted(self.subcoll.iter_tags(), \
lambda b, a: cmp(self.subcoll.discriminance(a), self.subcoll.discriminance(b)))
#print "-----------------------------"
#for d in self.discriminant:
@@ -81,61 +81,61 @@
e = Model.ModelEvent(Model.wxEVT_CHANGED)
self.ProcessEvent(e)
- def addWanted(self, tag):
+ def add_wanted(self, tag):
self.wanted.add(tag)
if tag in self.unwanted: self.unwanted.remove(tag)
if tag in self.ignored: self.ignored.remove(tag)
self.refilter()
- def addUnwanted(self, tag):
+ def add_unwanted(self, tag):
self.unwanted.add(tag)
if tag in self.wanted: self.wanted.remove(tag)
if tag in self.ignored: self.ignored.remove(tag)
self.refilter()
- def addIgnored(self, tag):
+ def add_ignored(self, tag):
self.ignored.add(tag)
if tag in self.wanted: self.wanted.remove(tag)
if tag in self.unwanted: self.unwanted.remove(tag)
self.refilter()
- def removeTagFromFilter(self, tag):
+ def remove_tag_from_filter(self, tag):
if tag in self.wanted: self.wanted.remove(tag)
if tag in self.unwanted: self.unwanted.remove(tag)
if tag in self.ignored: self.ignored.remove(tag)
self.refilter()
- def setQuery(self, query):
+ def set_query(self, query):
query = query.split()
def match(pkg):
for q in query:
try:
if pkg.name.find(q) == -1 and \
- pkg.rawDescription.find(q) == -1:
+ pkg.raw_description.find(q) == -1:
return False
except UnicodeDecodeError:
- desc = pkg.rawDescription.decode("ascii", "replace")
+ desc = pkg.raw_description.decode("ascii", "replace")
if pkg.name.find(q) == -1 and \
desc.find(q) == -1:
return False
return True
- subcoll = self.fullcoll.choosePackages(map(lambda x: x.name, filter(match, self.aptCache)))
+ subcoll = self.fullcoll.choose_packages(map(lambda x: x.name, filter(match, self.apt_cache)))
- relIndex = debtags.relevanceIndexFunction(self.fullcoll, subcoll)
+ rel_index = debtags.relevance_index_function(self.fullcoll, subcoll)
# Get all the tags sorted by increasing relevance
- self.interesting = sorted(subcoll.iterTags(), lambda b, a: cmp(relIndex(a), relIndex(b)))
+ self.interesting = sorted(subcoll.iter_tags(), lambda b, a: cmp(rel_index(a), rel_index(b)))
# Get the list of the uninteresting tags, sorted by cardinality (the
# ones that you are less likely to want, and first the ones that will
# weed out most results)
- self.uninteresting = set(self.fullcoll.iterTags())
- self.uninteresting -= set(subcoll.iterTags())
+ self.uninteresting = set(self.fullcoll.iter_tags())
+ self.uninteresting -= set(subcoll.iter_tags())
if len(self.wanted) == 0:
- self.wanted = set(fullcoll.idealTagset(self.interesting))
+ self.wanted = set(fullcoll.ideal_tagset(self.interesting))
self.refilter()
# Notify the change
@@ -144,8 +144,8 @@
class TagList(wx.html.HtmlWindow):
class TagListEvent(wx.PyCommandEvent):
- def __init__(self, eventType):
- wx.PyCommandEvent.__init__(self, eventType)
+ def __init__(self, event_type):
+ wx.PyCommandEvent.__init__(self, event_type)
self.action = None
self.tag = None
@@ -156,18 +156,18 @@
def __init__(self, parent, model):
wx.html.HtmlWindow.__init__(self, parent)
self.model = model
- self.model.Bind(Model.EVT_CHANGED, self.modelChanged)
+ self.model.Bind(Model.EVT_CHANGED, self.model_changed)
self.SetBorders(0)
self.SetFonts("", "", [4, 6, 8, 10, 11, 12, 13])
- def OnLinkClicked(self, linkInfo):
+ def OnLinkClicked(self, link_info):
# Notify the change
- action, tag = linkInfo.GetHref().split(':',1)
+ action, tag = link_info.GetHref().split(':',1)
e = TagList.TagListEvent(TagList.wxEVT_ACTION)
e.action, e.tag = action, tag
self.ProcessEvent(e)
- def modelChanged(self, event):
+ def model_changed(self, event):
#print "TLMC"
self.SetPage("<html><body>")
first = True
@@ -186,14 +186,14 @@
for tag in self.model.unwanted:
self.AppendToPage(" <a href='del:%s'>%s</a><br>" % (tag, tag))
- def filterCandidate(tag):
+ def filter_candidate(tag):
if self.model.subcoll.card(tag) == 0: return False
if tag in self.model.wanted: return False
if tag in self.model.unwanted: return False
if tag in self.model.ignored: return False
return True
- interesting = filter(filterCandidate, self.model.interesting)[:7]
+ interesting = filter(filter_candidate, self.model.interesting)[:7]
if len(interesting):
if first: first = False;
else: self.AppendToPage("<br>")
@@ -201,14 +201,14 @@
for tag in interesting:
self.AppendToPage(" <a href='add:%s'>%s</a> <a href='addnot:%s'>[no]</a> (%d pkgs)<br>" % (tag, tag, tag, self.model.subcoll.card(tag)))
- discr = filter(filterCandidate, self.model.discriminant)[:7]
+ discr = filter(filter_candidate, self.model.discriminant)[:7]
if len(discr):
if first: first = False;
else: self.AppendToPage("<br>")
for tag in discr:
self.AppendToPage(" <a href='add:%s'>%s</a> <a href='addnot:%s'>[no]</a> (%d pkgs)<br>" % (tag, tag, tag, self.model.subcoll.card(tag)))
- unint = filter(filterCandidate,
+ unint = filter(filter_candidate,
sorted(self.model.uninteresting, lambda a,b: cmp(self.model.subcoll.card(b), self.model.subcoll.card(a))))[:7]
if len(unint):
if first: first = False;
@@ -224,7 +224,7 @@
def __init__(self, parent, model):
wx.ListCtrl.__init__(self, parent, style=wx.LC_REPORT|wx.LC_VIRTUAL)
self.model = model
- self.model.Bind(Model.EVT_CHANGED, self.modelChanged)
+ self.model.Bind(Model.EVT_CHANGED, self.model_changed)
self.packages = []
@@ -236,7 +236,7 @@
self.Bind(wx.EVT_SIZE, self.OnResize)
- def resizeColumns(self):
+ def resize_columns(self):
"""
Ugly hack to have some decent size for the columns, since the ListCtrl
appearently won't autosize itself.
@@ -246,23 +246,23 @@
# -20 to hope to account for the vertical scrollbar, when it's present
self.SetColumnWidth(1, w * 0.7 - 20)
- def modelChanged(self, event):
- self.packages = sorted(self.model.subcoll.iterPackages())
+ def model_changed(self, event):
+ self.packages = sorted(self.model.subcoll.iter_packages())
self.packages.sort()
self.SetItemCount(len(self.packages))
- self.resizeColumns()
+ self.resize_columns()
event.Skip()
def OnResize(self, event):
- self.resizeColumns()
+ self.resize_columns()
event.Skip()
def OnGetItemText(self, row, col):
if col == 0:
return self.packages[row]
else:
- aptpkg = self.model.aptCache[self.packages[row]]
- return aptpkg.rawDescription.split("\n")[0]
+ aptpkg = self.model.apt_cache[self.packages[row]]
+ return aptpkg.raw_description.split("\n")[0]
class SearchWindow(wx.Frame):
@@ -274,65 +274,65 @@
wx.Frame.__init__(self, parent, -1, title,
style=wx.DEFAULT_FRAME_STYLE | wx.NO_FULL_REPAINT_ON_RESIZE)
- self.statusBar = self.CreateStatusBar()
+ self.status_bar = self.CreateStatusBar()
# Create menu bar
- self.menuBar = wx.MenuBar()
- mFile = wx.Menu()
- mFile.Append(SearchWindow.ACTION_QUIT, "&Quit", "Quit wxdballe")
- self.menuBar.Append(mFile, "&File")
- mFile = wx.Menu()
- mFile.Append(SearchWindow.ACTION_CONTEXT_HELP, "&What is...", "Show context information about interface elements")
- mFile.Append(SearchWindow.ACTION_ABOUT, "&About...", "Show information about this application")
- self.menuBar.Append(mFile, "&Help")
- self.SetMenuBar(self.menuBar)
- self.Bind(wx.EVT_MENU, self.onAction)
+ self.menu_bar = wx.MenuBar()
+ m_file = wx.Menu()
+ m_file.Append(SearchWindow.ACTION_QUIT, "&Quit", "Quit wxdballe")
+ self.menu_bar.Append(m_file, "&File")
+ m_file = wx.Menu()
+ m_file.Append(SearchWindow.ACTION_CONTEXT_HELP, "&What is...", "Show context information about interface elements")
+ m_file.Append(SearchWindow.ACTION_ABOUT, "&About...", "Show information about this application")
+ self.menu_bar.Append(m_file, "&Help")
+ self.SetMenuBar(self.menu_bar)
+ self.Bind(wx.EVT_MENU, self.on_action)
self.model = model
- self.model.Bind(Model.EVT_CHANGED, self.modelChanged)
+ self.model.Bind(Model.EVT_CHANGED, self.model_changed)
self.SetSizeHints(500, 500)
- queryPanel = wx.Panel(self, style=wx.SUNKEN_BORDER)
+ query_panel = wx.Panel(self, style=wx.SUNKEN_BORDER)
- queryField = wx.Panel(queryPanel)
- self.query = wx.TextCtrl(queryField)
+ query_field = wx.Panel(query_panel)
+ self.query = wx.TextCtrl(query_field)
self.query.SetHelpText("Enter here some keyword about what you are looking for. They will lead you to a selection of categories that you can use to browse the packages")
- self.query.Bind(wx.EVT_CHAR, self.queryChanged)
- # self.query.Bind(wx.EVT_TEXT, self.queryChanged)
- self.queryButton = wx.Button(queryField, -1, "Go", style=wx.BU_EXACTFIT)
- self.queryButton.Bind(wx.EVT_BUTTON, self.goButtonPressed)
- self.queryButton.SetHelpText("Look for keyword corresponding to the text entered in the Search field.")
+ self.query.Bind(wx.EVT_CHAR, self.query_changed)
+ # self.query.Bind(wx.EVT_TEXT, self.query_changed)
+ self.query_button = wx.Button(query_field, -1, "Go", style=wx.BU_EXACTFIT)
+ self.query_button.Bind(wx.EVT_BUTTON, self.go_button_pressed)
+ self.query_button.SetHelpText("Look for keyword corresponding to the text entered in the Search field.")
box = wx.BoxSizer(wx.HORIZONTAL)
- box.Add(wx.StaticText(queryField, -1, "Search: "), 0, wx.ALIGN_CENTER_VERTICAL)
+ box.Add(wx.StaticText(query_field, -1, "Search: "), 0, wx.ALIGN_CENTER_VERTICAL)
box.Add(self.query, 1, wx.EXPAND)
- box.Add(self.queryButton, 0, wx.ALIGN_CENTER_VERTICAL)
- queryField.SetSizerAndFit(box)
+ box.Add(self.query_button, 0, wx.ALIGN_CENTER_VERTICAL)
+ query_field.SetSizerAndFit(box)
- self.tagList = TagList(queryPanel, model)
- self.tagList.Bind(TagList.EVT_ACTION, self.wantedEvent)
- self.tagList.SetHelpText("Tags used for searching. Candidate tags are up for selection: click on a tag to say that you want it, and click on 'no' next to it to say that you do not want it. To remove a tag from the 'wanted' or 'unwanted' list, just click on it")
+ self.tag_list = TagList(query_panel, model)
+ self.tag_list.Bind(TagList.EVT_ACTION, self.wanted_event)
+ self.tag_list.SetHelpText("Tags used for searching. Candidate tags are up for selection: click on a tag to say that you want it, and click on 'no' next to it to say that you do not want it. To remove a tag from the 'wanted' or 'unwanted' list, just click on it")
box = wx.BoxSizer(wx.VERTICAL)
- box.Add(queryField, 0, wx.EXPAND)
- box.Add(self.tagList, 3, wx.EXPAND)
- queryPanel.SetSizerAndFit(box)
+ box.Add(query_field, 0, wx.EXPAND)
+ box.Add(self.tag_list, 3, wx.EXPAND)
+ query_panel.SetSizerAndFit(box)
self.results = Results(self, model)
self.results.SetHelpText("List of packages matching the current selecion of tags")
box = wx.BoxSizer(wx.HORIZONTAL)
- box.Add(queryPanel, 2, wx.EXPAND)
+ box.Add(query_panel, 2, wx.EXPAND)
box.Add(self.results, 3, wx.EXPAND)
self.SetSizerAndFit(box)
- self.timedUpdater = None
+ self.timed_updater = None
- self.Bind(wx.EVT_CHAR, self.onChar)
+ self.Bind(wx.EVT_CHAR, self.on_char)
self.query.SetFocus()
- def onAction(self, event):
+ def on_action(self, event):
id = event.GetId()
if id == SearchWindow.ACTION_QUIT:
self.Destroy()
@@ -367,40 +367,40 @@
dia = wx.lib.dialogs.ScrolledMessageDialog(self, msg, "About Debtags Smart Search")
dia.ShowModal()
elif id == SearchWindow.ACTION_CONTEXT_HELP:
- contextHelp = wx.ContextHelp()
- contextHelp.BeginContextHelp()
+ context_help = wx.ContextHelp()
+ context_help.BeginContextHelp()
- def onChar(self, event):
+ def on_char(self, event):
c = event.GetKeyCode()
# Quit on ^Q
if c == 17:
self.Destroy()
- def wantedEvent(self, event):
+ def wanted_event(self, event):
action, tag = event.action, event.tag
if action == 'add':
- self.model.addWanted(tag)
+ self.model.add_wanted(tag)
elif action == 'addnot':
- print "wantedEvent -> addnot"
- self.model.addUnwanted(tag)
+ print "wanted_event -> addnot"
+ self.model.add_unwanted(tag)
elif action == 'del':
- self.model.removeTagFromFilter(tag)
+ self.model.remove_tag_from_filter(tag)
else:
print "Unknown action", action
- def goButtonPressed(self, event):
- self.model.setQuery(self.query.GetValue())
+ def go_button_pressed(self, event):
+ self.model.set_query(self.query.GetValue())
- def queryChanged(self, event):
+ def query_changed(self, event):
"Delayed update of the filter from the value of the input fields"
c = event.GetKeyCode()
if c == 13:
- self.model.setQuery(self.query.GetValue())
+ self.model.set_query(self.query.GetValue())
event.Skip()
- def modelChanged(self, event):
- self.statusBar.SetStatusText("%d packages" % (self.model.subcoll.packageCount()))
+ def model_changed(self, event):
+ self.status_bar.SetStatusText("%d packages" % (self.model.subcoll.package_count()))
event.Skip()
@@ -432,8 +432,8 @@
# Read full database
fullcoll = debtags.DB()
- tagFilter = re.compile(r"^special::.+$|^.+::TODO$")
- fullcoll.read(open(options.tagdb, "r"), lambda x: not tagFilter.match(x))
+ tag_filter = re.compile(r"^special::.+$|^.+::TODO$")
+ fullcoll.read(open(options.tagdb, "r"), lambda x: not tag_filter.match(x))
model = Model(fullcoll)
sw = SearchWindow(None, model, "Debtags Smart Search")
=== modified file 'tests/test_debtags.py'
--- tests/test_debtags.py 2008-02-20 15:44:10 +0000
+++ tests/test_debtags.py 2008-07-07 11:34:28 +0000
@@ -32,40 +32,40 @@
def test_insert(self):
db = debtags.DB()
db.insert("test", set(("a", "b")));
- assert db.hasPackage("test")
- assert not db.hasPackage("a")
- assert not db.hasPackage("b")
- assert db.hasTag("a")
- assert db.hasTag("b")
- assert not db.hasTag("test")
- self.assertEqual(db.tagsOfPackage("test"), set(("a", "b")))
- self.assertEqual(db.packagesOfTag("a"), set(("test")))
- self.assertEqual(db.packagesOfTag("b"), set(("test")))
- self.assertEqual(db.packageCount(), 1)
- self.assertEqual(db.tagCount(), 2)
+ assert db.has_package("test")
+ assert not db.has_package("a")
+ assert not db.has_package("b")
+ assert db.has_tag("a")
+ assert db.has_tag("b")
+ assert not db.has_tag("test")
+ self.assertEqual(db.tags_of_package("test"), set(("a", "b")))
+ self.assertEqual(db.packages_of_tag("a"), set(("test")))
+ self.assertEqual(db.packages_of_tag("b"), set(("test")))
+ self.assertEqual(db.package_count(), 1)
+ self.assertEqual(db.tag_count(), 2)
def test_reverse(self):
db = debtags.DB()
db.insert("test", set(("a", "b")));
db = db.reverse()
- assert db.hasPackage("a")
- assert db.hasPackage("b")
- assert not db.hasPackage("test")
- assert db.hasTag("test")
- assert not db.hasTag("a")
- assert not db.hasTag("b")
- self.assertEqual(db.packagesOfTag("test"), set(("a", "b")))
- self.assertEqual(db.tagsOfPackage("a"), set(("test")))
- self.assertEqual(db.tagsOfPackage("b"), set(("test")))
- self.assertEqual(db.packageCount(), 2)
- self.assertEqual(db.tagCount(), 1)
+ assert db.has_package("a")
+ assert db.has_package("b")
+ assert not db.has_package("test")
+ assert db.has_tag("test")
+ assert not db.has_tag("a")
+ assert not db.has_tag("b")
+ self.assertEqual(db.packages_of_tag("test"), set(("a", "b")))
+ self.assertEqual(db.tags_of_package("a"), set(("test")))
+ self.assertEqual(db.tags_of_package("b"), set(("test")))
+ self.assertEqual(db.package_count(), 2)
+ self.assertEqual(db.tag_count(), 1)
def test_read(self):
db = self.mkdb()
- self.assertEqual(db.tagsOfPackage("polygen"), set(("devel::interpreter", "game::toys", "interface::commandline", "works-with::text")))
- assert "polygen" in db.packagesOfTag("interface::commandline")
- self.assertEqual(db.packageCount(), 144)
- self.assertEqual(db.tagCount(), 94)
+ self.assertEqual(db.tags_of_package("polygen"), set(("devel::interpreter", "game::toys", "interface::commandline", "works-with::text")))
+ assert "polygen" in db.packages_of_tag("interface::commandline")
+ self.assertEqual(db.package_count(), 144)
+ self.assertEqual(db.tag_count(), 94)
if __name__ == '__main__':
unittest.main()
# Begin bundle
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
QA==
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 197 bytes
Desc: Digital signature
Url : http://lists.alioth.debian.org/pipermail/pkg-python-debian-maint/attachments/20080707/ea0d9cd5/attachment-0001.pgp
More information about the pkg-python-debian-maint
mailing list