---
ConfigFile.py | 4 +-
csvdump.py | 4 +-
database.py | 22 +++++------
gitdm | 27 ++++++-------
gitlog.py | 8 ++--
logparser.py | 6 +--
reports.py | 106 +++++++++++++++-----------------------------------
utils.py | 4 +-
8 files changed, 70 insertions(+), 111 deletions(-)
diff --git a/ConfigFile.py b/ConfigFile.py
index 3a1e208..e58c601 100644
--- a/ConfigFile.py
+++ b/ConfigFile.py
@@ -147,10 +147,10 @@ def ReadFileType (filename):
m = regex_file_type.match (line)
if not m or len (m.groups ()) != 2:
ConfigFile.croak ('Funky file type line "%s"' % (line))
- if not patterns.has_key (m.group (1)):
+ if m.group (1) not in patterns:
patterns[m.group (1)] = []
if m.group (1) not in order:
- print '%s not found, appended to the last order' % m.group (1)
+ print('%s not found, appended to the last order' % m.group (1))
order.append (m.group (1))
patterns[m.group (1)].append (re.compile (m.group (2), re.IGNORECASE))
diff --git a/csvdump.py b/csvdump.py
index 9d1a65e..55e38a0 100644
--- a/csvdump.py
+++ b/csvdump.py
@@ -50,7 +50,7 @@ def store_patch(patch):
ChangeSets.append([patch.commit, str(patch.date),
patch.email, domain, author, employer,
patch.added, patch.removed])
- for (filetype, (added, removed)) in patch.filetypes.iteritems():
+ for (filetype, (added, removed)) in patch.filetypes.items():
FileTypes.append([patch.commit, filetype, added, removed])
@@ -82,7 +82,7 @@ def OutputCSV (file):
writer = csv.writer (file, quoting=csv.QUOTE_NONNUMERIC)
writer.writerow (['Name', 'Email', 'Affliation', 'Date',
'Added', 'Removed', 'Changesets'])
- for date, stat in PeriodCommitHash.items():
+ for date, stat in list(PeriodCommitHash.items()):
# sanitise names " is common and \" sometimes too
empl_name = stat.employer.name.replace ('"', '.').replace ('\\', '.')
author_name = stat.name.replace ('"', '.').replace ('\\', '.')
diff --git a/database.py b/database.py
index bf13227..b267ed5 100644
--- a/database.py
+++ b/database.py
@@ -40,7 +40,7 @@ class Hacker:
for edate, empl in self.employer[i]:
if edate > date:
return empl
- print 'OOPS. ', self.name, self.employer, self.email, email, date
+ print('OOPS. ', self.name, self.employer, self.email, email, date)
return None # Should not happen
def addpatch (self, patch):
@@ -124,11 +124,11 @@ def LookupStoreHacker(name, email, mapunknown = True):
def AllHackers ():
- return HackersByID.values ()
+ return list(HackersByID.values ())
def DumpDB ():
out = open ('database.dump', 'w')
- names = HackersByName.keys ()
+ names = list(HackersByName.keys ())
names.sort ()
for name in names:
h = HackersByName[name]
@@ -149,7 +149,7 @@ def DumpDB ():
# push it backward through the changes we've already seen.
#
def ApplyFirstTag (tag):
- for n in HackersByName.keys ():
+ for n in list(HackersByName.keys ()):
if HackersByName[n].versions:
HackersByName[n].versions = [tag]
@@ -185,7 +185,7 @@ def GetEmployer (name):
return e
def AllEmployers ():
- return Employers.values ()
+ return list(Employers.values ())
#
# Certain obnoxious developers, who will remain nameless (because we
@@ -215,8 +215,8 @@ class VirtualEmployer (Employer):
self.__init__ (name) # Reset counts just in case
def store (self):
- if Employers.has_key (self.name):
- print Employers[self.name]
+ if self.name in Employers:
+ print(Employers[self.name])
sys.stderr.write ('WARNING: Virtual empl %s overwrites another\n'
% (self.name))
if len (self.splits) == 0:
@@ -235,7 +235,7 @@ class FileType:
order = order or self.order
for file_type in order:
- if patterns.has_key (file_type):
+ if file_type in patterns:
for patt in patterns[file_type]:
if patt.search (filename):
return file_type
@@ -261,7 +261,7 @@ def MixVirtuals ():
EmailAliases = { }
def AddEmailAlias (variant, canonical):
- if EmailAliases.has_key (variant):
+ if variant in EmailAliases:
sys.stderr.write ('Duplicate email alias for %s\n' % (variant))
EmailAliases[variant] = canonical
@@ -288,7 +288,7 @@ def AddEmailEmployerMapping (email, employer, end = nextyear):
for i in range (0, len(l)):
date, xempl = l[i]
if date == end: # probably both nextyear
- print 'WARNING: duplicate email/empl for %s' % (email)
+ print('WARNING: duplicate email/empl for %s' % (email))
if date > end:
l.insert (i, (end, empl))
return
@@ -305,7 +305,7 @@ def MapToEmployer (email, unknown = 0):
pass
namedom = email.split ('@')
if len (namedom) < 2:
- print 'Oops...funky email %s' % email
+ print('Oops...funky email %s' % email)
return [(nextyear, GetEmployer ('Funky'))]
s = namedom[1].split ('.')
for dots in range (len (s) - 2, -1, -1):
diff --git a/gitdm b/gitdm
index 61318ad..f426cc7 100755
--- a/gitdm
+++ b/gitdm
@@ -1,4 +1,4 @@
-#!/usr/bin/pypy
+#!/usr/bin/python3
#-*- coding:utf-8 -*-
#
@@ -15,7 +15,8 @@
import database, csvdump, ConfigFile, reports
import getopt, datetime
-import os, re, sys, rfc822, string, os.path
+from email.utils import parsedate_tz
+import os, re, sys, string, os.path
import logparser
from patterns import patterns
@@ -108,7 +109,7 @@ def ParseOpts():
elif opt[0] == '-p':
CSVPrefix = opt[1]
elif opt[0] == '-r':
- print 'Filter on "%s"' % (opt[1])
+ print('Filter on "%s"' % (opt[1]))
FileFilter = re.compile(opt[1])
elif opt[0] == '-s':
AuthorSOBs = 0
@@ -120,7 +121,7 @@ def ParseOpts():
ReportUnknowns = True
elif opt[0] == '-x':
CSVFile = open(opt[1], 'w')
- print "open output file " + opt[1] + "\n"
+ print("open output file " + opt[1] + "\n")
elif opt [0] == '-w':
Aggregate = 'week'
elif opt [0] == '-y':
@@ -172,7 +173,7 @@ DateMap = { }
def AddDateLines(date, lines):
if lines > 1000000:
- print 'Skip big patch (%d)' % lines
+ print('Skip big patch (%d)' % lines)
return
try:
DateMap[date] += lines
@@ -180,7 +181,7 @@ def AddDateLines(date, lines):
DateMap[date] = lines
def PrintDateStats():
- dates = DateMap.keys()
+ dates = list(DateMap.keys())
dates.sort()
total = 0
datef = open('datelc.csv', 'w')
@@ -195,7 +196,7 @@ def PrintDateStats():
# Let's slowly try to move some smarts into this class.
#
class patch:
- (ADDED, REMOVED) = range(2)
+ (ADDED, REMOVED) = list(range(2))
def __init__(self, commit):
self.commit = commit
@@ -219,7 +220,7 @@ class patch:
self.reports.append(reporter)
def addfiletype(self, filetype, added, removed):
- if self.filetypes.has_key(filetype):
+ if filetype in self.filetypes:
self.filetypes[filetype][self.ADDED] += added
self.filetypes[filetype][self.REMOVED] += removed
else:
@@ -330,7 +331,7 @@ def grabpatch(logpatch):
#
m = patterns['date'].match(Line)
if m:
- dt = rfc822.parsedate(m.group(2))
+ dt = parsedate_tz(m.group(2))
p.date = datetime.date(dt[0], dt[1], dt[2])
if p.date > Today:
sys.stderr.write('Funky date: %s\n' % p.date)
@@ -389,7 +390,7 @@ def GripeAboutAuthorName(name):
if name in GripedAuthorNames:
return
GripedAuthorNames.append(name)
- print '%s is an author name, probably not what you want' % (name)
+ print('%s is an author name, probably not what you want' % (name))
def ApplyFileFilter(line, ignore):
#
@@ -462,14 +463,14 @@ TotalChanged = TotalAdded = TotalRemoved = 0
#
# Snarf changesets.
#
-print >> sys.stderr, 'Grabbing changesets...\r',
+print('Grabbing changesets...\r', end=' ', file=sys.stderr)
patches = logparser.LogPatchSplitter(sys.stdin)
printcount = CSCount = 0
for logpatch in patches:
if (printcount % 50) == 0:
- print >> sys.stderr, 'Grabbing changesets...%d\r' % printcount,
+ print('Grabbing changesets...%d\r' % printcount, end=' ',
file=sys.stderr)
printcount += 1
# We want to ignore commits on svn tags since in Subversion
@@ -528,7 +529,7 @@ for logpatch in patches:
CSCount += 1
csvdump.AccumulatePatch(p, Aggregate)
csvdump.store_patch(p)
-print >> sys.stderr, 'Grabbing changesets...done '
+print('Grabbing changesets...done ', file=sys.stderr)
if DumpDB:
database.DumpDB()
diff --git a/gitlog.py b/gitlog.py
index 71efee1..4b1c5d6 100644
--- a/gitlog.py
+++ b/gitlog.py
@@ -61,7 +61,7 @@ S_DONE = 5
def get_header(patch, line, input):
if line == '':
if patch.author == '':
- print 'Funky auth line in', patch.commit
+ print('Funky auth line in', patch.commit)
patch.author = database.LookupStoreHacker('Unknown',
'unkn...@hacker.net')
return S_DESC
@@ -78,7 +78,7 @@ def get_header(patch, line, input):
def get_desc(patch, line, input):
if not line:
- print 'Missing desc in', patch.commit
+ print('Missing desc in', patch.commit)
return S_CHANGELOG
patch.desc = line
line = getline(input)
@@ -188,7 +188,7 @@ def grabpatch(input):
return None
m = patterns['commit'].match(line)
if not m:
- print 'noncommit', line
+ print('noncommit', line)
return None
p = patch(m.group(1))
state = S_HEADER
@@ -199,7 +199,7 @@ def grabpatch(input):
line = getline(input)
if line is None:
if state != S_NUMSTAT:
- print 'Ran out of patch', state
+ print('Ran out of patch', state)
return None
return p
state = grabbers[state](p, line, input)
diff --git a/logparser.py b/logparser.py
index b375034..88293c5 100644
--- a/logparser.py
+++ b/logparser.py
@@ -41,7 +41,7 @@ class LogPatchSplitter:
def __iter__(self):
return self
- def next(self):
+ def __next__(self):
patch = self.__grab_patch__()
if not patch:
raise StopIteration
@@ -85,6 +85,6 @@ if __name__ == '__main__':
patches = LogPatchSplitter(sys.stdin)
for patch in patches:
- print '---------- NEW PATCH ----------'
+ print('---------- NEW PATCH ----------')
for line in patch:
- print line,
+ print(line, end=' ')
diff --git a/reports.py b/reports.py
index d7a96bc..3e03e69 100644
--- a/reports.py
+++ b/reports.py
@@ -69,11 +69,8 @@ def EndReport():
#
# Comparison and report generation functions.
#
-def ComparePCount(h1, h2):
- return len(h2.patches) - len(h1.patches)
-
def ReportByPCount(hlist, cscount):
- hlist.sort(ComparePCount)
+ hlist.sort(key=lambda h: -len(h.patches))
count = 0
BeginReport('Developers with the most changesets')
for h in hlist:
@@ -87,11 +84,8 @@ def ReportByPCount(hlist, cscount):
break
EndReport()
-def CompareLChanged(h1, h2):
- return h2.changed - h1.changed
-
def ReportByLChanged(hlist, totalchanged):
- hlist.sort(CompareLChanged)
+ hlist.sort(key=lambda h: -h.changed)
count = 0
BeginReport('Developers with the most changed lines')
for h in hlist:
@@ -103,11 +97,8 @@ def ReportByLChanged(hlist, totalchanged):
break
EndReport()
-def CompareLRemoved(h1, h2):
- return (h2.removed - h2.added) - (h1.removed - h1.added)
-
def ReportByLRemoved(hlist, totalremoved):
- hlist.sort(CompareLRemoved)
+ hlist.sort(key=lambda h: h.added - h.removed)
count = 0
BeginReport('Developers with the most lines removed')
for h in hlist:
@@ -121,11 +112,8 @@ def ReportByLRemoved(hlist, totalremoved):
break
EndReport()
-def CompareEPCount(e1, e2):
- return e2.count - e1.count
-
def ReportByPCEmpl(elist, cscount):
- elist.sort(CompareEPCount)
+ elist.sort(key=lambda e: -e.count)
count = 0
BeginReport('Top changeset contributors by employer')
for e in elist:
@@ -137,11 +125,8 @@ def ReportByPCEmpl(elist, cscount):
EndReport()
-def CompareELChanged(e1, e2):
- return e2.changed - e1.changed
-
def ReportByELChanged(elist, totalchanged):
- elist.sort(CompareELChanged)
+ elist.sort(key=lambda e: -e.changed)
count = 0
BeginReport('Top lines changed by employer')
for e in elist:
@@ -154,11 +139,8 @@ def ReportByELChanged(elist, totalchanged):
-def CompareSOBs(h1, h2):
- return len(h2.signoffs) - len(h1.signoffs)
-
def ReportBySOBs(hlist):
- hlist.sort(CompareSOBs)
+ hlist.sort(key = lambda h: -len(h.signoffs))
totalsobs = 0
for h in hlist:
totalsobs += len(h.signoffs)
@@ -176,11 +158,8 @@ def ReportBySOBs(hlist):
#
# Reviewer reporting.
#
-def CompareRevs(h1, h2):
- return len(h2.reviews) - len(h1.reviews)
-
def ReportByRevs(hlist):
- hlist.sort(CompareRevs)
+ hlist.sort(key=lambda h: -len(h.reviews))
totalrevs = 0
for h in hlist:
totalrevs += len(h.reviews)
@@ -198,11 +177,8 @@ def ReportByRevs(hlist):
#
# tester reporting.
#
-def CompareTests(h1, h2):
- return len(h2.tested) - len(h1.tested)
-
def ReportByTests(hlist):
- hlist.sort(CompareTests)
+ hlist.sort(key=lambda h: -len(h.tested))
totaltests = 0
for h in hlist:
totaltests += len(h.tested)
@@ -217,11 +193,8 @@ def ReportByTests(hlist):
break
EndReport()
-def CompareTestCred(h1, h2):
- return h2.testcred - h1.testcred
-
def ReportByTestCreds(hlist):
- hlist.sort(CompareTestCred)
+ hlist.sort(key=lambda h: -h.testcred)
totaltests = 0
for h in hlist:
totaltests += h.testcred
@@ -240,11 +213,8 @@ def ReportByTestCreds(hlist):
#
# Reporter reporting.
#
-def CompareReports(h1, h2):
- return len(h2.reports) - len(h1.reports)
-
def ReportByReports(hlist):
- hlist.sort(CompareReports)
+ hlist.sort(key=lambda h: -len(h.reports))
totalreps = 0
for h in hlist:
totalreps += len(h.reports)
@@ -259,11 +229,8 @@ def ReportByReports(hlist):
break
EndReport()
-def CompareRepCred(h1, h2):
- return h2.repcred - h1.repcred
-
def ReportByRepCreds(hlist):
- hlist.sort(CompareRepCred)
+ hlist.sort(key=lambda h: -h.repcred)
totalreps = 0
for h in hlist:
totalreps += h.repcred
@@ -280,14 +247,11 @@ def ReportByRepCreds(hlist):
#
# Versions.
#
-def CompareVersionCounts(h1, h2):
- if h1.versions and h2.versions:
- return len(h2.versions) - len(h1.versions)
- if h2.versions:
- return 1
- if h1.versions:
- return -1
- return 0
+def VersionCount(h):
+ if h.versions:
+ return len(h.versions)
+ else:
+ return 0
def MissedVersions(hv, allv):
missed = [v for v in allv if v not in hv]
@@ -295,7 +259,7 @@ def MissedVersions(hv, allv):
return ' '.join(missed)
def ReportVersions(hlist):
- hlist.sort(CompareVersionCounts)
+ hlist.sort(key=lambda h: -VersionCount(h))
BeginReport('Developers represented in the most kernel versions')
count = 0
allversions = hlist[0].versions
@@ -307,11 +271,8 @@ def ReportVersions(hlist):
EndReport()
-def CompareESOBs(e1, e2):
- return e2.sobs - e1.sobs
-
def ReportByESOBs(elist):
- elist.sort(CompareESOBs)
+ elist.sort(key=lambda e: -e.sobs)
totalsobs = 0
for e in elist:
totalsobs += e.sobs
@@ -325,11 +286,8 @@ def ReportByESOBs(elist):
break
EndReport()
-def CompareHackers(e1, e2):
- return len(e2.hackers) - len(e1.hackers)
-
def ReportByEHackers(elist):
- elist.sort(CompareHackers)
+ elist.sort(key=lambda e: -len(e.hackers))
totalhackers = 0
for e in elist:
totalhackers += len(e.hackers)
@@ -375,7 +333,7 @@ def ReportUnknowns(hlist, cscount):
# mapping to (Unknown) is happening or not.
#
ulist = [ h for h in hlist if IsUnknown(h) ]
- ulist.sort(ComparePCount)
+ ulist.sort(lambda h: len(h.patches))
count = 0
BeginReport('Developers with unknown affiliation')
for h in ulist:
@@ -398,46 +356,46 @@ def ReportByFileType(hacker_list):
by_hacker = {}
for patch in h.patches:
# Get a summary by hacker
- for (filetype, (added, removed)) in patch.filetypes.iteritems():
- if by_hacker.has_key(filetype):
+ for (filetype, (added, removed)) in patch.filetypes.items():
+ if filetype in by_hacker:
by_hacker[filetype][patch.ADDED] += added
by_hacker[filetype][patch.REMOVED] += removed
else:
by_hacker[filetype] = [added, removed]
# Update the totals
- if total.has_key(filetype):
+ if filetype in total:
total[filetype][patch.ADDED] += added
total[filetype][patch.REMOVED] += removed
else:
total[filetype] = [added, removed, []]
# Print a summary by hacker
- print h.name
- for filetype, counters in by_hacker.iteritems():
- print '\t', filetype, counters
+ print(h.name)
+ for filetype, counters in by_hacker.items():
+ print('\t', filetype, counters)
h_added = by_hacker[filetype][patch.ADDED]
h_removed = by_hacker[filetype][patch.REMOVED]
total[filetype][2].append([h.name, h_added, h_removed])
# Print the global summary
BeginReport('Contributions by type and developers')
- for filetype, (added, removed, hackers) in total.iteritems():
- print filetype, added, removed
+ for filetype, (added, removed, hackers) in total.items():
+ print(filetype, added, removed)
for h, h_added, h_removed in hackers:
- print '\t%s: [%d, %d]' % (h, h_added, h_removed)
+ print('\t%s: [%d, %d]' % (h, h_added, h_removed))
# Print the very global summary
BeginReport('General contributions by type')
- for filetype, (added, removed, hackers) in total.iteritems():
- print filetype, added, removed
+ for filetype, (added, removed, hackers) in total.items():
+ print(filetype, added, removed)
#
# The file access report is a special beast.
#
def FileAccessReport(name, accesses, total):
outf = open(name, 'w')
- files = accesses.keys()
+ files = list(accesses.keys())
files.sort()
for file in files:
a = accesses[file]
diff --git a/utils.py b/utils.py
index 2b3be5d..9f17911 100644
--- a/utils.py
+++ b/utils.py
@@ -21,7 +21,7 @@ class accumulator:
return default
def append(self, key, item, unique = False):
- if unique and self._data.has_key(key) and \
+ if unique and key in self._data and \
item in self._data[key]:
return
try:
@@ -30,7 +30,7 @@ class accumulator:
self._data[key] = [item]
def keys(self):
- return self._data.keys()
+ return list(self._data.keys())
def __getitem__(self, key):
return self._data[key]