Skip to content

Commit

Permalink
fix Python-2.3-compatibility problems
Browse files Browse the repository at this point in the history
  • Loading branch information
electrofelix authored and Dustin J. Mitchell committed Jan 17, 2010
1 parent 5d42eda commit c35617c
Show file tree
Hide file tree
Showing 4 changed files with 147 additions and 7 deletions.
8 changes: 4 additions & 4 deletions buildbot/status/web/console.py
Expand Up @@ -200,7 +200,7 @@ def getAllChanges(self, source, status, debugInfo):

# the new changes are not sorted, and can contain duplicates.
# Sort the list.
allChanges.sort(key=self.comparator.getSortingKey())
allChanges.sort(lambda a, b: cmp(getattr(a, self.comparator.getSortingKey()), getattr(b, self.comparator.getSortingKey())))

# Remove the dups
prevChange = None
Expand Down Expand Up @@ -356,7 +356,7 @@ def getChangeForBuild(self, build, revision):

# No matching change, return the last change in build.
changes = list(build.getChanges())
changes.sort(key=self.comparator.getSortingKey())
changes.sort(lambda a, b: cmp(getattr(a, self.comparator.getSortingKey()), getattr(b, self.comparator.getSortingKey())))
return changes[-1]

def getAllBuildsForRevision(self, status, request, lastRevision, numBuilds,
Expand Down Expand Up @@ -827,7 +827,7 @@ def isValidRevision(self, revision):
return True # No general way of determining

def getSortingKey(self):
return operator.attrgetter('when')
return "when"

class IntegerRevisionComparator(RevisionComparator):
def isRevisionEarlier(self, first, second):
Expand All @@ -841,5 +841,5 @@ def isValidRevision(self, revision):
return False

def getSortingKey(self):
return operator.attrgetter('revision')
return "revision"

6 changes: 5 additions & 1 deletion buildbot/status/web/console_html.py
@@ -1,4 +1,8 @@
from string import Template
try:
from string import Template
except ImportError:
from buildbot.stringTemplate import Template


top_header = Template('''
<div align="center">
Expand Down
129 changes: 129 additions & 0 deletions buildbot/stringTemplate.py
@@ -0,0 +1,129 @@
"""A copy of the string Template class from python 2.4, included
for compatibility with python 2.3.
"""

import re as _re

class _multimap:
"""Helper class for combining multiple mappings.
Used by .{safe_,}substitute() to combine the mapping and keyword
arguments.
"""
def __init__(self, primary, secondary):
self._primary = primary
self._secondary = secondary

def __getitem__(self, key):
try:
return self._primary[key]
except KeyError:
return self._secondary[key]


class _TemplateMetaclass(type):
pattern = r"""
%(delim)s(?:
(?P<escaped>%(delim)s) | # Escape sequence of two delimiters
(?P<named>%(id)s) | # delimiter and a Python identifier
{(?P<braced>%(id)s)} | # delimiter and a braced identifier
(?P<invalid>) # Other ill-formed delimiter exprs
)
"""

def __init__(cls, name, bases, dct):
super(_TemplateMetaclass, cls).__init__(name, bases, dct)
if 'pattern' in dct:
pattern = cls.pattern
else:
pattern = _TemplateMetaclass.pattern % {
'delim' : _re.escape(cls.delimiter),
'id' : cls.idpattern,
}
cls.pattern = _re.compile(pattern, _re.IGNORECASE | _re.VERBOSE)


class Template:
"""A string class for supporting $-substitutions."""
__metaclass__ = _TemplateMetaclass

delimiter = '$'
idpattern = r'[_a-z][_a-z0-9]*'

def __init__(self, template):
self.template = template

# Search for $$, $identifier, ${identifier}, and any bare $'s

def _invalid(self, mo):
i = mo.start('invalid')
lines = self.template[:i].splitlines(True)
if not lines:
colno = 1
lineno = 1
else:
colno = i - len(''.join(lines[:-1]))
lineno = len(lines)
raise ValueError('Invalid placeholder in string: line %d, col %d' %
(lineno, colno))

def substitute(self, *args, **kws):
if len(args) > 1:
raise TypeError('Too many positional arguments')
if not args:
mapping = kws
elif kws:
mapping = _multimap(kws, args[0])
else:
mapping = args[0]
# Helper function for .sub()
def convert(mo):
# Check the most common path first.
named = mo.group('named') or mo.group('braced')
if named is not None:
val = mapping[named]
# We use this idiom instead of str() because the latter will
# fail if val is a Unicode containing non-ASCII characters.
return '%s' % val
if mo.group('escaped') is not None:
return self.delimiter
if mo.group('invalid') is not None:
self._invalid(mo)
raise ValueError('Unrecognized named group in pattern',
self.pattern)
return self.pattern.sub(convert, self.template)

def safe_substitute(self, *args, **kws):
if len(args) > 1:
raise TypeError('Too many positional arguments')
if not args:
mapping = kws
elif kws:
mapping = _multimap(kws, args[0])
else:
mapping = args[0]
# Helper function for .sub()
def convert(mo):
named = mo.group('named')
if named is not None:
try:
# We use this idiom instead of str() because the latter
# will fail if val is a Unicode containing non-ASCII
return '%s' % mapping[named]
except KeyError:
return self.delimiter + named
braced = mo.group('braced')
if braced is not None:
try:
return '%s' % mapping[braced]
except KeyError:
return self.delimiter + '{' + braced + '}'
if mo.group('escaped') is not None:
return self.delimiter
if mo.group('invalid') is not None:
return self.delimiter
raise ValueError('Unrecognized named group in pattern',
self.pattern)
return self.pattern.sub(convert, self.template)


11 changes: 9 additions & 2 deletions buildbot/test/test_console.py
Expand Up @@ -7,6 +7,13 @@
from buildbot.test.runutils import RunMixin
from buildbot.changes import changes

try:
reversed
except NameError:
def reversed(data):
for index in xrange(len(data)-1,-1,-1):
yield data[index]

# Configuration to be used by the getBuildDetailsTest
run_config = """
from buildbot.process import factory
Expand Down Expand Up @@ -76,7 +83,7 @@ def testReturnedKeySortsRevisionsCorrectly(self):
my_changes[i].when = my_changes[i-1].when + 1

reversed_changes = list(reversed(my_changes))
reversed_changes.sort(key=self.comparator.getSortingKey())
reversed_changes.sort(lambda a,b: cmp(getattr(a, self.comparator.getSortingKey()), getattr(b, self.comparator.getSortingKey())))
self.assertEqual(my_changes, reversed_changes)

class IntegerRevisionComparatorTest(unittest.TestCase):
Expand Down Expand Up @@ -105,7 +112,7 @@ def testReturnedKeySortsRevisionsCorrectly(self):
my_changes = [_createDummyChange(str(i)) for i in range(1, 6)]

reversed_changes = list(reversed(my_changes))
reversed_changes.sort(key=self.comparator.getSortingKey())
reversed_changes.sort(lambda a,b: cmp(getattr(a, self.comparator.getSortingKey()), getattr(b, self.comparator.getSortingKey())))
self.assertEqual(my_changes, reversed_changes)

# Helper class to mock a request. We define only what we really need.
Expand Down

0 comments on commit c35617c

Please sign in to comment.