Florian Weimer
2010-May-07 21:08 UTC
[Secure-testing-commits] r14630 - in lib/python: . sectracker
Author: fw Date: 2010-05-07 21:08:39 +0000 (Fri, 07 May 2010) New Revision: 14630 Added: lib/python/sectracker/regexpcase.py Removed: lib/python/regexpcase.py Modified: lib/python/parsers.py Log: sectracker.regexpcase: renamed from regexpcase Modified: lib/python/parsers.py ==================================================================--- lib/python/parsers.py 2010-05-07 21:05:30 UTC (rev 14629) +++ lib/python/parsers.py 2010-05-07 21:08:39 UTC (rev 14630) @@ -19,7 +19,7 @@ import re import debian_support -import regexpcase +import sectracker.regexpcase as _regexpcase import xcollections import xpickle @@ -81,14 +81,14 @@ def _annotationdispatcher(): # Parser for inner annotations, like (bug #1345; low) urgencies=set("unimportant low medium high".split()) - @regexpcase.rule(''(bug filed|%s)'' % ''|''.join(urgencies)) + @_regexpcase.rule(''(bug filed|%s)'' % ''|''.join(urgencies)) def innerflag(groups, diag, flags, bugs): f = groups[0] if f in flags: diag.error("duplicate flag: " + repr(f)) else: flags.add(f) - @regexpcase.rule(r''bug #(\d+)'') + @_regexpcase.rule(r''bug #(\d+)'') def innerbug(groups, diag, flags, bugs): no = int(groups[0]) if no in bugs: @@ -97,8 +97,8 @@ bugs.add(no) def innerdefault(text, diag, flags, bugs): diag.error("invalid inner annotation: " + repr(text)) - innerdispatch = regexpcase.RegexpCase((innerflag, innerbug), - default=innerdefault) + innerdispatch = _regexpcase.RegexpCase((innerflag, innerbug), + default=innerdefault) def parseinner(diag, inner): if not inner: @@ -126,8 +126,8 @@ # Parsers for indented annotations (NOT-FOR-US:, " - foo <unfixed>" etc.) - @regexpcase.rule(r''(?:\[([a-z]+)\]\s)?-\s([A-Za-z0-9:.+-]+)\s*'' - + r''(?:\s([A-Za-z0-9:.+~-]+)\s*)?(?:\s\((.*)\))?'') + @_regexpcase.rule(r''(?:\[([a-z]+)\]\s)?-\s([A-Za-z0-9:.+-]+)\s*'' + + r''(?:\s([A-Za-z0-9:.+~-]+)\s*)?(?:\s\((.*)\))?'') def package_version(groups, diag, anns): release, package, version, inner = groups inner = parseinner(diag, inner) @@ -141,8 +141,8 @@ pseudo_freetext = "no-dsa not-affected end-of-life".split() pseudo_struct = set("unfixed removed itp undetermined".split()) - @regexpcase.rule(r''(?:\[([a-z]+)\]\s)?-\s([A-Za-z0-9:.+-]+)'' - + r''\s+<([a-z-]+)>\s*(?:\s\((.*)\))?'') + @_regexpcase.rule(r''(?:\[([a-z]+)\]\s)?-\s([A-Za-z0-9:.+-]+)'' + + r''\s+<([a-z-]+)>\s*(?:\s\((.*)\))?'') def package_pseudo(groups, diag, anns): release, package, version, inner = groups if version in pseudo_freetext: @@ -159,7 +159,7 @@ else: diag.error("invalid pseudo-version: " + repr(version)) - @regexpcase.rule(r''\{(.*)\}'') + @_regexpcase.rule(r''\{(.*)\}'') def xref(groups, diag, anns): x = _sortedtuple(groups[0].strip().split()) if x: @@ -167,7 +167,7 @@ else: diag.error("empty cross-reference") - return regexpcase.RegexpCase( + return _regexpcase.RegexpCase( ((r''(RESERVED|REJECTED)'', lambda groups, diag, anns: anns.append(FlagAnnotation(diag.line(), groups[0]))), Deleted: lib/python/regexpcase.py ==================================================================--- lib/python/regexpcase.py 2010-05-07 21:05:30 UTC (rev 14629) +++ lib/python/regexpcase.py 2010-05-07 21:08:39 UTC (rev 14630) @@ -1,127 +0,0 @@ -# regexpcase.py -- Python module for regexp-based dispatching -# Copyright (C) 2009, 2010 Florian Weimer <fw at deneb.enyo.de> -# -# 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 - -import re - -class RegexpCase(object): - def __init__(self, rules, prefix=None, suffix=None, default=None): - offset = 0 - probes = [] - maycall = default is None or callable(default) - - # We use a single regular expression and use special probe - # captures to figure out which one has actually matched. - # Hopefully, the regular expression engine will make this run - # fast. - for (regexp, action) in rules: - compiled = re.compile(regexp) - probes.append((offset, offset + 1, offset + compiled.groups + 1, - action)) - offset += compiled.groups + 1 - if action is not None: - maycall = maycall and callable(action) - self.probes = tuple(probes) - self.maycall = maycall - - if not self.probes: - raise ValueError("empty rule list") - if prefix is None: - prefix = "^(?:(" - else: - if re.compile(prefix).groups > 0: - raise ValueError("prefix must not contain captures") - prefix = "^(?:" + prefix + ")(?:(" - - if suffix is None: - suffix = "))$" - else: - if re.compile(suffix).groups > 0: - raise ValueError("suffix must not contain captures") - suffix = "))(?:" + suffix + ")$" - - self.regexp = re.compile( - prefix + '')|(''.join(regexp for (regexp, action) in rules) - + suffix) - - self.default = default - - def match(self, key): - match = self.regexp.match(key) - if match is None: - return (None, self.default) - groups = match.groups() - for (probe, i, j, action) in self.probes: - if groups[probe] is not None: - return (groups[i:j], action) - raise AssertionError("pattern and offset list incongruent") - - def __getitem__(self, key): - return self.match(key)[1] - - def __call__(self, key, *args): - if not self.maycall: - raise TypeError, "not all actions are callable" - (groups, action) = self.match(key) - if action is None: - return None - if groups is None: - groups = key - return action(groups, *args) - -def rule(regexp): - """Add a regular expression to the function, for the rule list""" - return lambda f: (regexp, f) - -if __name__ == "__main__": - import unittest - - class TestRegexpCase(unittest.TestCase): - def testempty(self): - self.assertRaises(ValueError, RegexpCase, ()) - self.assertRaises(ValueError, RegexpCase, (), prefix="foo") - self.assertRaises(ValueError, RegexpCase, (), suffix="foo") - self.assertRaises(ValueError, RegexpCase, (), default="foo") - self.assertRaises(ValueError, RegexpCase, (("two", 2)), - prefix="(f)oo") - self.assertRaises(ValueError, RegexpCase, (("two", 2)), - suffix="(f)oo") - - def teststrings(self): - rc = RegexpCase((("two", 2), - ("three", 3), - ("five", 5))) - self.assertEqual(2, rc["two"]) - self.assertEqual(3, rc["three"]) - self.assertEqual(5, rc["five"]) - self.assertEqual(None, rc["seven"]) - self.assertEquals((None, None), rc.match("seven")) - self.assertRaises(TypeError, rc.__call__, ()) - - def testcallstrings(self): - rc = RegexpCase((("(two)", lambda groups, x: (groups, x)), - ("three", lambda groups, x: (groups, x)), - ("f(i)v(e)", lambda groups, x : (groups, x)))) - self.assertEqual((("two",), -2), rc("two", -2)) - self.assertEqual(((), -3), rc("three", -3)) - self.assertEqual((tuple("ie"), -5), rc("five", -5)) - self.assertEqual(None, rc("seven", -1)) - def testcallstringsdefault(self): - rc = RegexpCase([("f(i)v(e)", lambda groups, x : (groups, x))], - default=lambda key, x: (key, x)) - self.assertEqual(("seven", -1), rc("seven", -1)) - - unittest.main() Copied: lib/python/sectracker/regexpcase.py (from rev 14622, lib/python/regexpcase.py) ==================================================================--- lib/python/sectracker/regexpcase.py (rev 0) +++ lib/python/sectracker/regexpcase.py 2010-05-07 21:08:39 UTC (rev 14630) @@ -0,0 +1,127 @@ +# sectracker.regexpcase -- Python module for regexp-based dispatching +# Copyright (C) 2009, 2010 Florian Weimer <fw at deneb.enyo.de> +# +# 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 + +import re + +class RegexpCase(object): + def __init__(self, rules, prefix=None, suffix=None, default=None): + offset = 0 + probes = [] + maycall = default is None or callable(default) + + # We use a single regular expression and use special probe + # captures to figure out which one has actually matched. + # Hopefully, the regular expression engine will make this run + # fast. + for (regexp, action) in rules: + compiled = re.compile(regexp) + probes.append((offset, offset + 1, offset + compiled.groups + 1, + action)) + offset += compiled.groups + 1 + if action is not None: + maycall = maycall and callable(action) + self.probes = tuple(probes) + self.maycall = maycall + + if not self.probes: + raise ValueError("empty rule list") + if prefix is None: + prefix = "^(?:(" + else: + if re.compile(prefix).groups > 0: + raise ValueError("prefix must not contain captures") + prefix = "^(?:" + prefix + ")(?:(" + + if suffix is None: + suffix = "))$" + else: + if re.compile(suffix).groups > 0: + raise ValueError("suffix must not contain captures") + suffix = "))(?:" + suffix + ")$" + + self.regexp = re.compile( + prefix + '')|(''.join(regexp for (regexp, action) in rules) + + suffix) + + self.default = default + + def match(self, key): + match = self.regexp.match(key) + if match is None: + return (None, self.default) + groups = match.groups() + for (probe, i, j, action) in self.probes: + if groups[probe] is not None: + return (groups[i:j], action) + raise AssertionError("pattern and offset list incongruent") + + def __getitem__(self, key): + return self.match(key)[1] + + def __call__(self, key, *args): + if not self.maycall: + raise TypeError, "not all actions are callable" + (groups, action) = self.match(key) + if action is None: + return None + if groups is None: + groups = key + return action(groups, *args) + +def rule(regexp): + """Add a regular expression to the function, for the rule list""" + return lambda f: (regexp, f) + +if __name__ == "__main__": + import unittest + + class TestRegexpCase(unittest.TestCase): + def testempty(self): + self.assertRaises(ValueError, RegexpCase, ()) + self.assertRaises(ValueError, RegexpCase, (), prefix="foo") + self.assertRaises(ValueError, RegexpCase, (), suffix="foo") + self.assertRaises(ValueError, RegexpCase, (), default="foo") + self.assertRaises(ValueError, RegexpCase, (("two", 2)), + prefix="(f)oo") + self.assertRaises(ValueError, RegexpCase, (("two", 2)), + suffix="(f)oo") + + def teststrings(self): + rc = RegexpCase((("two", 2), + ("three", 3), + ("five", 5))) + self.assertEqual(2, rc["two"]) + self.assertEqual(3, rc["three"]) + self.assertEqual(5, rc["five"]) + self.assertEqual(None, rc["seven"]) + self.assertEquals((None, None), rc.match("seven")) + self.assertRaises(TypeError, rc.__call__, ()) + + def testcallstrings(self): + rc = RegexpCase((("(two)", lambda groups, x: (groups, x)), + ("three", lambda groups, x: (groups, x)), + ("f(i)v(e)", lambda groups, x : (groups, x)))) + self.assertEqual((("two",), -2), rc("two", -2)) + self.assertEqual(((), -3), rc("three", -3)) + self.assertEqual((tuple("ie"), -5), rc("five", -5)) + self.assertEqual(None, rc("seven", -1)) + def testcallstringsdefault(self): + rc = RegexpCase([("f(i)v(e)", lambda groups, x : (groups, x))], + default=lambda key, x: (key, x)) + self.assertEqual(("seven", -1), rc("seven", -1)) + + unittest.main()