Repository: mozman/svgwrite

Issue:
build_animation_timing_parser uses wrong separator
The regex generated for `timing-value-list` uses a `,` as separator, while this list is separated by `;`. It thus does not validate lists of multiple values correctly (but in exchang eallows invalid values).

`0s;foo.end` is rejected while being valid; `0s,foo.end` is accepted while being invalid.

Comments:

Patch:
diff --git a/svgwrite/data/svgparser.py b/svgwrite/data/svgparser.py
index 6a79dfa..adeaa0a 100644
--- a/svgwrite/data/svgparser.py
+++ b/svgwrite/data/svgparser.py
@@ -19,6 +19,7 @@ event_names = [
 ]
 
 c = r"\s*[, ]\s*"
+s = r"\s*[; ]\s*"
 integer_constant = r"\d+"
 exponent = r"([eE][+-]?\d+)"
 nonnegative_number = fr"(\d+\.?\d*|\.\d+){exponent}?"
@@ -125,7 +126,7 @@ def build_animation_timing_parser():
     begin_value = "(" + "|".join((f"({reg})" for reg in (
         offset_value, syncbase_value, event_value, repeat_value,
         accesskey_value, wallclock_sync_value, "indefinite"))) + ")"
-    return fr"{begin_value}({c}{begin_value})*"
+    return fr"{begin_value}({s}{begin_value})*"
 
 
 is_valid_animation_timing = is_valid(build_animation_timing_parser())


Test patch:
diff --git a/.github/workflows/testrunner.yml b/.github/workflows/testrunner.yml
index 6ea7fac..12fedb6 100644
--- a/.github/workflows/testrunner.yml
+++ b/.github/workflows/testrunner.yml
@@ -10,7 +10,7 @@ jobs:
     strategy:
       matrix:
         os: [ubuntu-latest, macos-latest, windows-latest]
-        python-version: [3.6, 3.7, 3.8, 3.9, pypy-3.6]
+        python-version: [3.7, 3.8, 3.9, pypy-3.7]
     steps:
     - uses: actions/checkout@v2
     - name: Set up Python ${{ matrix.python-version }}
diff --git a/tests/test_animation_timing_parser.py b/tests/test_animation_timing_parser.py
index 2be1ff5..32e24d6 100644
--- a/tests/test_animation_timing_parser.py
+++ b/tests/test_animation_timing_parser.py
@@ -51,6 +51,12 @@ class TestAnimationTimingParser(unittest.TestCase):
         self.assertTrue(is_valid_animation_timing("wallclock(1997-07-16T19:20:30)"))
         self.assertTrue(is_valid_animation_timing("wallclock(1997-07-16T19:20)"))
 
+    def test_list(self):
+        self.assertTrue(is_valid_animation_timing("0s;foo.end"))
+        self.assertTrue(is_valid_animation_timing("foo.end;0s"))
+        self.assertTrue(is_valid_animation_timing("0s;foo.end;bar.end"))
+        self.assertTrue(is_valid_animation_timing("foo.end;bar.end;0s"))
+
     def test_invalid_value(self):
         self.assertFalse(is_valid_animation_timing("xyz"))
         self.assertFalse(is_valid_animation_timing("repeat(0"))
@@ -61,6 +67,10 @@ class TestAnimationTimingParser(unittest.TestCase):
         self.assertFalse(is_valid_animation_timing("wallclock(1997-07-16T19:2)"))
         self.assertFalse(is_valid_animation_timing("wallclock(1997-07-16T19:)"))
         self.assertFalse(is_valid_animation_timing("wallclock(1997-07-16T19)"))
+        self.assertFalse(is_valid_animation_timing("0s,foo.end"))
+        self.assertFalse(is_valid_animation_timing("foo.end,0s"))
+        self.assertFalse(is_valid_animation_timing("0s,foo.end;bar.end"))
+        self.assertFalse(is_valid_animation_timing("foo.end,bar.end;0s"))
 
 if __name__ == '__main__':
     unittest.main()