aboutsummaryrefslogtreecommitdiffstats
path: root/tests/test_builder.py
diff options
context:
space:
mode:
Diffstat (limited to 'tests/test_builder.py')
-rwxr-xr-xtests/test_builder.py551
1 files changed, 551 insertions, 0 deletions
diff --git a/tests/test_builder.py b/tests/test_builder.py
new file mode 100755
index 0000000..bf6582a
--- /dev/null
+++ b/tests/test_builder.py
@@ -0,0 +1,551 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+"""
+Test suite for parse_type.py
+
+REQUIRES: parse >= 1.8.4 ('pattern' attribute support)
+"""
+
+from __future__ import absolute_import
+import re
+import unittest
+import parse
+from .parse_type_test import ParseTypeTestCase
+from .parse_type_test \
+ import parse_number, parse_yesno, parse_person_choice, parse_color, Color
+from parse_type import TypeBuilder, build_type_dict
+from enum import Enum
+
+
+# -----------------------------------------------------------------------------
+# TEST CASE: TestTypeBuilder4Enum
+# -----------------------------------------------------------------------------
+class TestTypeBuilder4Enum(ParseTypeTestCase):
+
+ TYPE_CONVERTERS = [ parse_yesno ]
+
+ def test_parse_enum_yesno(self):
+ extra_types = build_type_dict([ parse_yesno ])
+ schema = "Answer: {answer:YesNo}"
+ parser = parse.Parser(schema, extra_types)
+
+ # -- PERFORM TESTS:
+ self.ensure_can_parse_all_enum_values(parser,
+ parse_yesno, "Answer: %s", "answer")
+
+ # -- VALID:
+ self.assert_match(parser, "Answer: yes", "answer", True)
+ self.assert_match(parser, "Answer: no", "answer", False)
+
+ # -- IGNORE-CASE: In parsing, calls type converter function !!!
+ self.assert_match(parser, "Answer: YES", "answer", True)
+
+ # -- PARSE MISMATCH:
+ self.assert_mismatch(parser, "Answer: __YES__", "answer")
+ self.assert_mismatch(parser, "Answer: yes ", "answer")
+ self.assert_mismatch(parser, "Answer: yes ZZZ", "answer")
+
+ def test_make_enum_with_dict(self):
+ parse_nword = TypeBuilder.make_enum({"one": 1, "two": 2, "three": 3})
+ parse_nword.name = "NumberAsWord"
+
+ extra_types = build_type_dict([ parse_nword ])
+ schema = "Answer: {number:NumberAsWord}"
+ parser = parse.Parser(schema, extra_types)
+
+ # -- PERFORM TESTS:
+ self.ensure_can_parse_all_enum_values(parser,
+ parse_nword, "Answer: %s", "number")
+
+ # -- VALID:
+ self.assert_match(parser, "Answer: one", "number", 1)
+ self.assert_match(parser, "Answer: two", "number", 2)
+
+ # -- IGNORE-CASE: In parsing, calls type converter function !!!
+ self.assert_match(parser, "Answer: THREE", "number", 3)
+
+ # -- PARSE MISMATCH:
+ self.assert_mismatch(parser, "Answer: __one__", "number")
+ self.assert_mismatch(parser, "Answer: one ", "number")
+ self.assert_mismatch(parser, "Answer: one_", "number")
+ self.assert_mismatch(parser, "Answer: one ZZZ", "number")
+
+ def test_make_enum_with_enum_class(self):
+ """
+ Use :meth:`parse_type.TypeBuilder.make_enum()` with enum34 classes.
+ """
+ class Color(Enum):
+ red = 1
+ green = 2
+ blue = 3
+
+ parse_color = TypeBuilder.make_enum(Color)
+ parse_color.name = "Color"
+ schema = "Answer: {color:Color}"
+ parser = parse.Parser(schema, dict(Color=parse_color))
+
+ # -- PERFORM TESTS:
+ self.ensure_can_parse_all_enum_values(parser,
+ parse_color, "Answer: %s", "color")
+
+ # -- VALID:
+ self.assert_match(parser, "Answer: red", "color", Color.red)
+ self.assert_match(parser, "Answer: green", "color", Color.green)
+ self.assert_match(parser, "Answer: blue", "color", Color.blue)
+
+ # -- IGNORE-CASE: In parsing, calls type converter function !!!
+ self.assert_match(parser, "Answer: RED", "color", Color.red)
+
+ # -- PARSE MISMATCH:
+ self.assert_mismatch(parser, "Answer: __RED__", "color")
+ self.assert_mismatch(parser, "Answer: red ", "color")
+ self.assert_mismatch(parser, "Answer: redx", "color")
+ self.assert_mismatch(parser, "Answer: redx ZZZ", "color")
+
+
+# -----------------------------------------------------------------------------
+# TEST CASE: TestTypeBuilder4Choice
+# -----------------------------------------------------------------------------
+class TestTypeBuilder4Choice(ParseTypeTestCase):
+
+ def test_parse_choice_persons(self):
+ extra_types = build_type_dict([ parse_person_choice ])
+ schema = "Answer: {answer:PersonChoice}"
+ parser = parse.Parser(schema, extra_types)
+
+ # -- PERFORM TESTS:
+ self.assert_match(parser, "Answer: Alice", "answer", "Alice")
+ self.assert_match(parser, "Answer: Bob", "answer", "Bob")
+ self.ensure_can_parse_all_choices(parser,
+ parse_person_choice, "Answer: %s", "answer")
+
+ # -- IGNORE-CASE: In parsing, calls type converter function !!!
+ # SKIP-WART: self.assert_match(parser, "Answer: BOB", "answer", "BOB")
+
+ # -- PARSE MISMATCH:
+ self.assert_mismatch(parser, "Answer: __Alice__", "answer")
+ self.assert_mismatch(parser, "Answer: Alice ", "answer")
+ self.assert_mismatch(parser, "Answer: Alice ZZZ", "answer")
+
+ def test_make_choice(self):
+ parse_choice = TypeBuilder.make_choice(["one", "two", "three"])
+ parse_choice.name = "NumberWordChoice"
+ extra_types = build_type_dict([ parse_choice ])
+ schema = "Answer: {answer:NumberWordChoice}"
+ parser = parse.Parser(schema, extra_types)
+
+ # -- PERFORM TESTS:
+ self.assert_match(parser, "Answer: one", "answer", "one")
+ self.assert_match(parser, "Answer: two", "answer", "two")
+ self.ensure_can_parse_all_choices(parser,
+ parse_choice, "Answer: %s", "answer")
+
+ # -- PARSE MISMATCH:
+ self.assert_mismatch(parser, "Answer: __one__", "answer")
+ self.assert_mismatch(parser, "Answer: one ", "answer")
+ self.assert_mismatch(parser, "Answer: one ZZZ", "answer")
+
+ def test_make_choice__anycase_accepted_case_sensitity(self):
+ # -- NOTE: strict=False => Disable errors due to case-mismatch.
+ parse_choice = TypeBuilder.make_choice(["one", "two", "three"],
+ strict=False)
+ schema = "Answer: {answer:NumberWordChoice}"
+ parser = parse.Parser(schema, dict(NumberWordChoice=parse_choice))
+
+ # -- PERFORM TESTS:
+ # NOTE: Parser uses re.IGNORECASE flag => Any case accepted.
+ self.assert_match(parser, "Answer: one", "answer", "one")
+ self.assert_match(parser, "Answer: TWO", "answer", "TWO")
+ self.assert_match(parser, "Answer: Three", "answer", "Three")
+
+ def test_make_choice__samecase_match_or_error(self):
+ # -- NOTE: strict=True => Enable errors due to case-mismatch.
+ parse_choice = TypeBuilder.make_choice(["One", "TWO", "three"],
+ strict=True)
+ schema = "Answer: {answer:NumberWordChoice}"
+ parser = parse.Parser(schema, dict(NumberWordChoice=parse_choice))
+
+ # -- PERFORM TESTS: Case matches.
+ # NOTE: Parser uses re.IGNORECASE flag => Any case accepted.
+ self.assert_match(parser, "Answer: One", "answer", "One")
+ self.assert_match(parser, "Answer: TWO", "answer", "TWO")
+ self.assert_match(parser, "Answer: three", "answer", "three")
+
+ # -- PERFORM TESTS: EXACT-CASE MISMATCH
+ case_mismatch_input_data = ["one", "ONE", "Two", "two", "Three" ]
+ for input_value in case_mismatch_input_data:
+ input_text = "Answer: %s" % input_value
+ with self.assertRaises(ValueError):
+ parser.parse(input_text)
+
+ def test_make_choice__anycase_accepted_lowercase_enforced(self):
+ # -- NOTE: strict=True => Enable errors due to case-mismatch.
+ parse_choice = TypeBuilder.make_choice(["one", "two", "three"],
+ transform=lambda x: x.lower(), strict=True)
+ schema = "Answer: {answer:NumberWordChoice}"
+ parser = parse.Parser(schema, dict(NumberWordChoice=parse_choice))
+
+ # -- PERFORM TESTS:
+ # NOTE: Parser uses re.IGNORECASE flag
+ # => Any case accepted, but result is in lower case.
+ self.assert_match(parser, "Answer: one", "answer", "one")
+ self.assert_match(parser, "Answer: TWO", "answer", "two")
+ self.assert_match(parser, "Answer: Three", "answer", "three")
+
+ def test_make_choice__with_transform(self):
+ transform = lambda x: x.upper()
+ parse_choice = TypeBuilder.make_choice(["ONE", "two", "Three"],
+ transform)
+ self.assertSequenceEqual(parse_choice.choices, ["ONE", "TWO", "THREE"])
+ schema = "Answer: {answer:NumberWordChoice}"
+ parser = parse.Parser(schema, dict(NumberWordChoice=parse_choice))
+
+ # -- PERFORM TESTS:
+ self.assert_match(parser, "Answer: one", "answer", "ONE")
+ self.assert_match(parser, "Answer: two", "answer", "TWO")
+ self.ensure_can_parse_all_choices(parser,
+ parse_choice, "Answer: %s", "answer")
+
+ # -- PARSE MISMATCH:
+ self.assert_mismatch(parser, "Answer: __one__", "answer")
+ self.assert_mismatch(parser, "Answer: one ", "answer")
+ self.assert_mismatch(parser, "Answer: one ZZZ", "answer")
+
+ def test_make_choice2(self):
+ # -- strict=False: Disable errors due to case mismatch.
+ parse_choice2 = TypeBuilder.make_choice2(["zero", "one", "two"],
+ strict=False)
+ parse_choice2.name = "NumberWordChoice2"
+ extra_types = build_type_dict([ parse_choice2 ])
+ schema = "Answer: {answer:NumberWordChoice2}"
+ parser = parse.Parser(schema, extra_types)
+
+ # -- PERFORM TESTS:
+ self.assert_match(parser, "Answer: zero", "answer", (0, "zero"))
+ self.assert_match(parser, "Answer: one", "answer", (1, "one"))
+ self.assert_match(parser, "Answer: two", "answer", (2, "two"))
+ self.ensure_can_parse_all_choices2(parser,
+ parse_choice2, "Answer: %s", "answer")
+
+ # -- PARSE MISMATCH:
+ self.assert_mismatch(parser, "Answer: __one__", "answer")
+ self.assert_mismatch(parser, "Answer: one ", "answer")
+ self.assert_mismatch(parser, "Answer: one ZZZ", "answer")
+
+ def test_make_choice2__with_transform(self):
+ transform = lambda x: x.lower()
+ parse_choice2 = TypeBuilder.make_choice2(["ZERO", "one", "Two"],
+ transform=transform)
+ self.assertSequenceEqual(parse_choice2.choices, ["zero", "one", "two"])
+ schema = "Answer: {answer:NumberWordChoice}"
+ parser = parse.Parser(schema, dict(NumberWordChoice=parse_choice2))
+
+ # -- PERFORM TESTS:
+ # NOTE: Parser uses re.IGNORECASE => Any case is accepted.
+ self.assert_match(parser, "Answer: zERO", "answer", (0, "zero"))
+ self.assert_match(parser, "Answer: ONE", "answer", (1, "one"))
+ self.assert_match(parser, "Answer: Two", "answer", (2, "two"))
+
+ def test_make_choice2__samecase_match_or_error(self):
+ # -- NOTE: strict=True => Enable errors due to case-mismatch.
+ parse_choice2 = TypeBuilder.make_choice2(["Zero", "one", "TWO"],
+ strict=True)
+ schema = "Answer: {answer:NumberWordChoice}"
+ parser = parse.Parser(schema, dict(NumberWordChoice=parse_choice2))
+
+ # -- PERFORM TESTS: Case matches.
+ # NOTE: Parser uses re.IGNORECASE flag => Any case accepted.
+ self.assert_match(parser, "Answer: Zero", "answer", (0, "Zero"))
+ self.assert_match(parser, "Answer: one", "answer", (1, "one"))
+ self.assert_match(parser, "Answer: TWO", "answer", (2, "TWO"))
+
+ # -- PERFORM TESTS: EXACT-CASE MISMATCH
+ case_mismatch_input_data = ["zero", "ZERO", "One", "ONE", "two" ]
+ for input_value in case_mismatch_input_data:
+ input_text = "Answer: %s" % input_value
+ with self.assertRaises(ValueError):
+ parser.parse(input_text)
+
+# -----------------------------------------------------------------------------
+# TEST CASE: TestTypeBuilder4Variant
+# -----------------------------------------------------------------------------
+class TestTypeBuilder4Variant(ParseTypeTestCase):
+
+ TYPE_CONVERTERS = [ parse_number, parse_yesno ]
+
+ def check_parse_variant_number_or_yesno(self, parse_variant,
+ with_ignorecase=True):
+ schema = "Variant: {variant:YesNo_or_Number}"
+ parser = parse.Parser(schema, dict(YesNo_or_Number=parse_variant))
+
+ # -- TYPE 1: YesNo
+ self.assert_match(parser, "Variant: yes", "variant", True)
+ self.assert_match(parser, "Variant: no", "variant", False)
+ # -- IGNORECASE problem => re_opts
+ if with_ignorecase:
+ self.assert_match(parser, "Variant: YES", "variant", True)
+
+ # -- TYPE 2: Number
+ self.assert_match(parser, "Variant: 0", "variant", 0)
+ self.assert_match(parser, "Variant: 1", "variant", 1)
+ self.assert_match(parser, "Variant: 12", "variant", 12)
+ self.assert_match(parser, "Variant: 42", "variant", 42)
+
+ # -- PARSE MISMATCH:
+ self.assert_mismatch(parser, "Variant: __YES__")
+ self.assert_mismatch(parser, "Variant: yes ")
+ self.assert_mismatch(parser, "Variant: yes ZZZ")
+ self.assert_mismatch(parser, "Variant: -1")
+
+ # -- PERFORM TESTS:
+ self.ensure_can_parse_all_enum_values(parser,
+ parse_yesno, "Variant: %s", "variant")
+
+ def test_make_variant__uncompiled(self):
+ type_converters = [parse_yesno, parse_number]
+ parse_variant1 = TypeBuilder.make_variant(type_converters)
+ self.check_parse_variant_number_or_yesno(parse_variant1)
+
+ def test_make_variant__compiled(self):
+ # -- REVERSED ORDER VARIANT:
+ type_converters = [parse_number, parse_yesno]
+ parse_variant2 = TypeBuilder.make_variant(type_converters,
+ compiled=True)
+ self.check_parse_variant_number_or_yesno(parse_variant2)
+
+
+ def test_make_variant__with_re_opts_0(self):
+ # -- SKIP: IGNORECASE checks which would raise an error in strict mode.
+ type_converters = [parse_number, parse_yesno]
+ parse_variant3 = TypeBuilder.make_variant(type_converters, re_opts=0)
+ self.check_parse_variant_number_or_yesno(parse_variant3,
+ with_ignorecase=False)
+
+ def test_make_variant__with_re_opts_IGNORECASE(self):
+ type_converters = [parse_number, parse_yesno]
+ parse_variant3 = TypeBuilder.make_variant(type_converters,
+ re_opts=re.IGNORECASE)
+ self.check_parse_variant_number_or_yesno(parse_variant3)
+
+ def test_make_variant__with_strict(self):
+ # -- SKIP: IGNORECASE checks which would raise an error in strict mode.
+ type_converters = [parse_number, parse_yesno]
+ parse_variant = TypeBuilder.make_variant(type_converters, strict=True)
+ self.check_parse_variant_number_or_yesno(parse_variant,
+ with_ignorecase=False)
+
+ def test_make_variant__with_strict_raises_error_on_case_mismatch(self):
+ # -- NEEDS:
+ # * re_opts=0 (IGNORECASE disabled)
+ # * strict=True, allow that an error is raised
+ type_converters = [parse_number, parse_yesno]
+ parse_variant = TypeBuilder.make_variant(type_converters,
+ strict=True, re_opts=0)
+ schema = "Variant: {variant:YesNo_or_Number}"
+ parser = parse.Parser(schema, dict(YesNo_or_Number=parse_variant))
+ self.assertRaises(AssertionError, parser.parse, "Variant: YES")
+
+ def test_make_variant__without_strict_may_return_none_on_case_mismatch(self):
+ # -- NEEDS:
+ # * re_opts=0 (IGNORECASE disabled)
+ # * strict=False, otherwise an error is raised
+ type_converters = [parse_number, parse_yesno]
+ parse_variant = TypeBuilder.make_variant(type_converters, re_opts=0,
+ strict=False)
+ schema = "Variant: {variant:YesNo_or_Number}"
+ parser = parse.Parser(schema, dict(YesNo_or_Number=parse_variant))
+ result = parser.parse("Variant: No")
+ self.assertNotEqual(result, None)
+ self.assertEqual(result["variant"], None)
+
+ def test_make_variant__with_strict_and_compiled_raises_error_on_case_mismatch(self):
+ # XXX re_opts=0 seems to work differently.
+ # -- NEEDS:
+ # * re_opts=0 (IGNORECASE disabled)
+ # * strict=True, allow that an error is raised
+ type_converters = [parse_number, parse_yesno]
+ # -- ENSURE: coverage for cornercase.
+ parse_number.matcher = re.compile(parse_number.pattern)
+
+ parse_variant = TypeBuilder.make_variant(type_converters,
+ compiled=True, re_opts=0, strict=True)
+ schema = "Variant: {variant:YesNo_or_Number}"
+ parser = parse.Parser(schema, dict(YesNo_or_Number=parse_variant))
+ # XXX self.assertRaises(AssertionError, parser.parse, "Variant: YES")
+ result = parser.parse("Variant: Yes")
+ self.assertNotEqual(result, None)
+ self.assertEqual(result["variant"], True)
+
+ def test_make_variant__without_strict_and_compiled_may_return_none_on_case_mismatch(self):
+ # XXX re_opts=0 seems to work differently.
+ # -- NEEDS:
+ # * re_opts=0 (IGNORECASE disabled)
+ # * strict=False, otherwise an error is raised
+ type_converters = [parse_number, parse_yesno]
+ parse_variant = TypeBuilder.make_variant(type_converters,
+ compiled=True, re_opts=0, strict=True)
+ schema = "Variant: {variant:YesNo_or_Number}"
+ parser = parse.Parser(schema, dict(YesNo_or_Number=parse_variant))
+ result = parser.parse("Variant: NO")
+ self.assertNotEqual(result, None)
+ self.assertEqual(result["variant"], False)
+
+
+ def test_make_variant__with_color_or_person(self):
+ type_converters = [parse_color, parse_person_choice]
+ parse_variant2 = TypeBuilder.make_variant(type_converters)
+ schema = "Variant2: {variant:Color_or_Person}"
+ parser = parse.Parser(schema, dict(Color_or_Person=parse_variant2))
+
+ # -- TYPE 1: Color
+ self.assert_match(parser, "Variant2: red", "variant", Color.red)
+ self.assert_match(parser, "Variant2: blue", "variant", Color.blue)
+
+ # -- TYPE 2: Person
+ self.assert_match(parser, "Variant2: Alice", "variant", "Alice")
+ self.assert_match(parser, "Variant2: Bob", "variant", "Bob")
+ self.assert_match(parser, "Variant2: Charly", "variant", "Charly")
+
+ # -- PARSE MISMATCH:
+ self.assert_mismatch(parser, "Variant2: __Alice__")
+ self.assert_mismatch(parser, "Variant2: Alice ")
+ self.assert_mismatch(parser, "Variant2: Alice2")
+ self.assert_mismatch(parser, "Variant2: red2")
+
+ # -- PERFORM TESTS:
+ self.ensure_can_parse_all_enum_values(parser,
+ parse_color, "Variant2: %s", "variant")
+
+ self.ensure_can_parse_all_choices(parser,
+ parse_person_choice, "Variant2: %s", "variant")
+
+
+class TestParserWithManyTypedFields(ParseTypeTestCase):
+
+ parse_variant1 = TypeBuilder.make_variant([parse_number, parse_yesno])
+ parse_variant1.name = "Number_or_YesNo"
+ parse_variant2 = TypeBuilder.make_variant([parse_color, parse_person_choice])
+ parse_variant2.name = "Color_or_PersonChoice"
+ TYPE_CONVERTERS = [
+ parse_number,
+ parse_yesno,
+ parse_color,
+ parse_person_choice,
+ parse_variant1,
+ parse_variant2,
+ ]
+
+ def test_parse_with_many_named_fields(self):
+ type_dict = build_type_dict(self.TYPE_CONVERTERS)
+ schema = """\
+Number: {number:Number}
+YesNo: {answer:YesNo}
+Color: {color:Color}
+Person: {person:PersonChoice}
+Variant1: {variant1:Number_or_YesNo}
+Variant2: {variant2:Color_or_PersonChoice}
+"""
+ parser = parse.Parser(schema, type_dict)
+
+ text = """\
+Number: 12
+YesNo: yes
+Color: red
+Person: Alice
+Variant1: 42
+Variant2: Bob
+"""
+ expected = dict(
+ number=12,
+ answer=True,
+ color=Color.red,
+ person="Alice",
+ variant1=42,
+ variant2="Bob"
+ )
+
+ result = parser.parse(text)
+ self.assertIsNotNone(result)
+ self.assertEqual(result.named, expected)
+
+ def test_parse_with_many_unnamed_fields(self):
+ type_dict = build_type_dict(self.TYPE_CONVERTERS)
+ schema = """\
+Number: {:Number}
+YesNo: {:YesNo}
+Color: {:Color}
+Person: {:PersonChoice}
+"""
+ # -- OMIT: XFAIL, due to group_index delta counting => Parser problem.
+ # Variant2: {:Color_or_PersonChoice}
+ # Variant1: {:Number_or_YesNo}
+ parser = parse.Parser(schema, type_dict)
+
+ text = """\
+Number: 12
+YesNo: yes
+Color: red
+Person: Alice
+"""
+ # SKIP: Variant2: Bob
+ # SKIP: Variant1: 42
+ expected = [ 12, True, Color.red, "Alice", ] # -- SKIP: "Bob", 42 ]
+
+ result = parser.parse(text)
+ self.assertIsNotNone(result)
+ self.assertEqual(result.fixed, tuple(expected))
+
+ def test_parse_with_many_unnamed_fields_with_variants(self):
+ type_dict = build_type_dict(self.TYPE_CONVERTERS)
+ schema = """\
+Number: {:Number}
+YesNo: {:YesNo}
+Color: {:Color}
+Person: {:PersonChoice}
+Variant2: {:Color_or_PersonChoice}
+Variant1: {:Number_or_YesNo}
+"""
+ # -- OMIT: XFAIL, due to group_index delta counting => Parser problem.
+ parser = parse.Parser(schema, type_dict)
+
+ text = """\
+Number: 12
+YesNo: yes
+Color: red
+Person: Alice
+Variant2: Bob
+Variant1: 42
+"""
+ expected = [ 12, True, Color.red, "Alice", "Bob", 42 ]
+
+ result = parser.parse(text)
+ self.assertIsNotNone(result)
+ self.assertEqual(result.fixed, tuple(expected))
+
+
+# -----------------------------------------------------------------------------
+# MAIN:
+# -----------------------------------------------------------------------------
+if __name__ == '__main__':
+ unittest.main()
+
+
+# Copyright (c) 2012-2013 by Jens Engel (https://github/jenisys/parse_type)
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.