Index: test/test_templating.py =================================================================== --- test/test_templating.py (revision 81591) +++ test/test_templating.py (working copy) @@ -147,9 +147,23 @@ p = StringHTMLProperty(self.client, 'test', '1', None, 'test', '') def t(s): return p.hyper_re.sub(p._hyper_repl, s) ae = self.assertEquals - ae(t('http://roundup.net/'), 'http://roundup.net/') - ae(t('<HTTP://roundup.net/>'), '<HTTP://roundup.net/>') - ae(t('<www.roundup.net>'), '<www.roundup.net>') + ae(t('http://roundup.net/'), + 'http://roundup.net/') + ae(t('<HTTP://roundup.net/>'), + '<HTTP://roundup.net/>') + ae(t('<www.roundup.net>'), + '<www.roundup.net>') + ae(t('(www.roundup.net)'), + '(www.roundup.net)') + ae(t('foo http://msdn.microsoft.com/en-us/library/ms741540(VS.85).aspx bar'), + 'foo ' + 'http://msdn.microsoft.com/en-us/library/ms741540(VS.85).aspx bar') + ae(t('(e.g. http://en.wikipedia.org/wiki/Python_(programming_language))'), + '(e.g. ' + 'http://en.wikipedia.org/wiki/Python_(programming_language))') + ae(t('(e.g. http://en.wikipedia.org/wiki/Python_(programming_language)).'), + '(e.g. ' + 'http://en.wikipedia.org/wiki/Python_(programming_language)).') ''' class HTMLPermissions: Index: roundup/cgi/templating.py =================================================================== --- roundup/cgi/templating.py (revision 81591) +++ roundup/cgi/templating.py (working copy) @@ -1343,16 +1343,21 @@ u = s = match.group('url') if not self.protocol_re.search(s): u = 'http://' + s - # catch an escaped ">" at the end of the URL if s.endswith('>'): + # catch an escaped ">" at the end of the URL u = s = s[:-4] e = '>' + elif s.count('(') != s.count(')'): + # don't include extraneous ')' in the link + pos = s.rfind(')') + e = s[pos:] + u = s = s[:pos] else: e = '' - return '%s%s'%(u, s, e) + return '%s%s' % (u, s, e) elif match.group('email'): s = match.group('email') - return '%s'%(s, s) + return '%s' % (s, s) elif len(match.group('id')) < 10: return self._hyper_repl_item(match, '%(item)s')