grim/pyparser

A bunch of unit tests and other tweaks

2013-04-19, Gary Kramlich
6f2bab600b84
Parents 7b44def95dff
Children bd427975d72e
A bunch of unit tests and other tweaks
--- a/src/pyparser/__init__.py Fri Apr 19 02:08:37 2013 -0500
+++ b/src/pyparser/__init__.py Fri Apr 19 02:25:41 2013 -0500
@@ -29,16 +29,12 @@
started.
"""
- pass
-
def finish(self):
"""
Override this method to have your parser know when processing has
finished.
"""
-
- pass
@abc.abstractmethod
@@ -49,8 +45,6 @@
parsing.
"""
- pass
-
def parse(self, iterable):
"""
--- a/src/pyparser/regex.py Fri Apr 19 02:08:37 2013 -0500
+++ b/src/pyparser/regex.py Fri Apr 19 02:25:41 2013 -0500
@@ -2,15 +2,22 @@
This module contains the RegexParser and Pattern decorator
"""
+import logging
import re
from pyparser import Parser
-_ATTRIBUTE_NAME = '_re_pattern'
+_ATTRIBUTE_NAME = '_pyparser_re_pattern'
-class Pattern(object):
+class Pattern(object): # pylint:disable-msg=R0903
+ """
+ This class is a decorator that'll attach a regular expression attribute
+ to a function that the RegexParser class will use to call that function if
+ the regular expression matches.
+ """
+
def __init__(self, pattern):
self.pattern = pattern
@@ -35,6 +42,9 @@
The kwargs argument will have the parser call your methods with the match
object's groupdict as keyword args.
+ The handle_errors argument if True, will catch and log any exceptions
+ caused by the Pattern decorator instead of passing on the exception.
+
Here is an example subclass without using keywords that will count how many
lines contain the string 'foo'.
@@ -72,7 +82,7 @@
self.processor[attribute] = value
"""
- def __init__(self, strip=False, kwargs=False):
+ def __init__(self, strip=False, kwargs=False, handle_errors=True):
Parser.__init__(self, strip)
self.kwargs = kwargs
@@ -85,8 +95,15 @@
if pattern is None:
continue
- self.regexes[re.compile(pattern)] = symbol
-
+
+ try:
+ self.regexes[re.compile(pattern)] = symbol
+ except Exception, exp: # pylint:disable-msg=W0703
+ if handle_errors:
+ logging.exception(exp.message)
+ else:
+ raise exp
+
def default(self, line):
"""
--- a/tests/parser.py Fri Apr 19 02:08:37 2013 -0500
+++ b/tests/parser.py Fri Apr 19 02:25:41 2013 -0500
@@ -2,14 +2,11 @@
Unittests for the main pyparser.Parser class
"""
-import os
import unittest
from pyparser import Parser
-
-def _get_filename(filename):
- return os.path.join(os.path.dirname(__file__), 'data', filename)
+from utils import get_filename, parse_file
class CountingParser(Parser):
@@ -48,10 +45,6 @@
self.parser = CountingParser()
- def tearDown(self): # pylint:disable-msg=C0103
- self.parser = None
-
-
def _parse_file(self, filename, lines):
"""
The main method that does all of the testing
@@ -59,8 +52,8 @@
self.assertFalse(self.parser.started)
self.assertFalse(self.parser.finished)
-
- ifp = open(_get_filename(filename))
+
+ ifp = open(get_filename(filename))
parsed = self.parser.parse(ifp)
ifp.close()
@@ -119,9 +112,7 @@
the correct number of lines with leading and trailing whitespace.
"""
- ifp = open(_get_filename(filename))
- data = WhiteSpaceParser(strip).parse(ifp)
- ifp.close()
+ data = parse_file(WhiteSpaceParser, filename, strip=strip)
self.assertEqual(data['leading'], leading)
self.assertEqual(data['trailing'], trailing)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/regex.py Fri Apr 19 02:25:41 2013 -0500
@@ -0,0 +1,41 @@
+import unittest
+
+from pyparser.regex import RegexParser, Pattern
+
+
+
+
+class InvalidRegexPatternTest(unittest.TestCase): # pylint:disable-msg=R0904
+ """
+ Tests that we don't raise an exception on a bad regex but instead output
+ to the log.
+ """
+
+ class InvalidRegexParser(RegexParser):
+ """ A parser that has an invalid regular expression decorator """
+ def __init__(self, handle_errors):
+ RegexParser.__init__(self, handle_errors=handle_errors)
+
+
+ @Pattern('(')
+ def _broken(self):
+ """ An invalid regex pattern function """
+ pass
+
+
+ def test_no_error_handling(self):
+ """
+ Tests that an exception is raised with a bad regex and no error handling
+ """
+
+ with self.assertRaises(Exception):
+ InvalidRegexPatternTest.InvalidRegexParser(False)
+
+
+ def test_error_handling(self): # pylint:disable-msg=R0201
+ """
+ Tests that an exception is not raised with a bad regex and error handling
+ """
+
+ InvalidRegexPatternTest.InvalidRegexParser(True)
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/utils.py Fri Apr 19 02:25:41 2013 -0500
@@ -0,0 +1,26 @@
+"""
+Some helper methods for unittesting
+"""
+
+import os
+
+def get_filename(filename):
+ """
+ Gets the full filename for a data reference file
+ """
+
+ return os.path.join(os.path.dirname(__file__), 'data', filename)
+
+
+def parse_file(parser, filename, *args, **kwargs):
+ """
+ Given a parser and a filename, will open the file, create an instance of
+ parser, and parse the file with the parser and return the data.
+ """
+
+ ifp = open(get_filename(filename))
+ data = parser(*args, **kwargs).parse(ifp)
+ ifp.close()
+
+ return data
+