From a6c87f9b668a46cb9561425139e91d5615d5eb93 Mon Sep 17 00:00:00 2001 From: Poruri Sai Rahul Date: Mon, 8 Nov 2021 10:57:16 +0000 Subject: [PATCH 1/3] FIX : Fix issue with pyparsing version >= 3 fixes #887 This PR fixes an issue because of an upstream change with the pyparsing CaselessLiteral class, where the name attribute became a read-only property in version >= 3. We now use the new public set_name method instead of directly setting the attribute. --- enable/savage/svg/pathdata.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/enable/savage/svg/pathdata.py b/enable/savage/svg/pathdata.py index 6355e9322..a9cadb312 100644 --- a/enable/savage/svg/pathdata.py +++ b/enable/savage/svg/pathdata.py @@ -40,7 +40,7 @@ class CaselessPreservingLiteral(CaselessLiteral): def __init__(self, matchString): super().__init__(matchString.upper()) - self.name = "'%s'" % matchString + self.set_name("'%s'" % matchString) self.errmsg = "Expected " + self.name def parseImpl(self, instring, loc, doActions=True): From dc64828cd74092e5f535c3bd50fbd19ccda47f7e Mon Sep 17 00:00:00 2001 From: Poruri Sai Rahul Date: Mon, 8 Nov 2021 12:15:20 +0000 Subject: [PATCH 2/3] FIX : Handle pyparsing versions 2 and 3 accordingly the new set_name API is only available on pyparsing version >= 3 so we use packaging to handle the behavior according to the version this commit makes packaging a dependency of the svg backend and this commit adds a regression test modified: enable/__init__.py modified: enable/savage/svg/pathdata.py modified: enable/savage/svg/tests/test_pathdata.py --- enable/__init__.py | 2 +- enable/savage/svg/pathdata.py | 10 +++++++++- enable/savage/svg/tests/test_pathdata.py | 10 +++++++++- 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/enable/__init__.py b/enable/__init__.py index f030b9e23..1d4e6640a 100644 --- a/enable/__init__.py +++ b/enable/__init__.py @@ -29,7 +29,7 @@ # Dependencies for PDF backend "pdf": ["reportlab"], # Dependencies for SVG backend - "svg": ["pyparsing"], + "svg": ["packaging", "pyparsing"], # Dependencies purely for running tests. "test": [ "hypothesis", diff --git a/enable/savage/svg/pathdata.py b/enable/savage/svg/pathdata.py index a9cadb312..4b4902a47 100644 --- a/enable/savage/svg/pathdata.py +++ b/enable/savage/svg/pathdata.py @@ -16,7 +16,9 @@ pass """ +from packaging.version import parse from pyparsing import ( + __version__ as pyparsing_version_str, CaselessLiteral, Combine, Group, Literal, OneOrMore, Optional, ParseException, Word, ZeroOrMore, nums, oneOf ) @@ -40,7 +42,13 @@ class CaselessPreservingLiteral(CaselessLiteral): def __init__(self, matchString): super().__init__(matchString.upper()) - self.set_name("'%s'" % matchString) + + pyparsing_version = parse(pyparsing_version_str) + if pyparsing_version.major == 2: + self.name = "'%s'" % matchString + elif pyparsing_version.major == 3: + self.set_name("'%s'" % matchString) + self.errmsg = "Expected " + self.name def parseImpl(self, instring, loc, doActions=True): diff --git a/enable/savage/svg/tests/test_pathdata.py b/enable/savage/svg/tests/test_pathdata.py index 0ce0f910f..3ded3122c 100644 --- a/enable/savage/svg/tests/test_pathdata.py +++ b/enable/savage/svg/tests/test_pathdata.py @@ -14,10 +14,18 @@ from enable.savage.svg.pathdata import ( Sequence, closePath, coordinatePair, curve, ellipticalArc, horizontalLine, lineTo, moveTo, number, quadraticBezierCurveto, - smoothQuadraticBezierCurveto, svg, verticalLine + smoothQuadraticBezierCurveto, svg, verticalLine, CaselessLiteral, ) +class TestCaselessLiteral(unittest.TestCase): + def test_instantiation(self): + # regression test for https://github.com/enthought/enable/issues/887 + # observed with pyparsing v >= 3 + # we just test that instantiating the class doesnt raise exceptions + CaselessLiteral("test") + + class TestNumber(unittest.TestCase): parser = number valid = ["1.e10", "1e2", "1e+4", "1e-10", "1.", "1.0", "0.1", ".2"] From fabd1ba802711770159019d7169f9b324928d5bb Mon Sep 17 00:00:00 2001 From: Poruri Sai Rahul Date: Tue, 9 Nov 2021 10:32:13 +0000 Subject: [PATCH 3/3] REF : Go with a simpler solution of checking for the method name instead of manually parsing and checking the pyparsing version and calling the relevant method depending on the version, we simply check for the existence of the set_name method now and use it if it exists. If it doesnt, we fall back to the old setName method The dependence of packaging has now been removed because we dont need to parse the version anymore modified: enable/__init__.py modified: enable/savage/svg/pathdata.py --- enable/__init__.py | 2 +- enable/savage/svg/pathdata.py | 15 ++++++--------- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/enable/__init__.py b/enable/__init__.py index 1d4e6640a..f030b9e23 100644 --- a/enable/__init__.py +++ b/enable/__init__.py @@ -29,7 +29,7 @@ # Dependencies for PDF backend "pdf": ["reportlab"], # Dependencies for SVG backend - "svg": ["packaging", "pyparsing"], + "svg": ["pyparsing"], # Dependencies purely for running tests. "test": [ "hypothesis", diff --git a/enable/savage/svg/pathdata.py b/enable/savage/svg/pathdata.py index 4b4902a47..c93bf78b8 100644 --- a/enable/savage/svg/pathdata.py +++ b/enable/savage/svg/pathdata.py @@ -16,9 +16,7 @@ pass """ -from packaging.version import parse from pyparsing import ( - __version__ as pyparsing_version_str, CaselessLiteral, Combine, Group, Literal, OneOrMore, Optional, ParseException, Word, ZeroOrMore, nums, oneOf ) @@ -43,13 +41,12 @@ class CaselessPreservingLiteral(CaselessLiteral): def __init__(self, matchString): super().__init__(matchString.upper()) - pyparsing_version = parse(pyparsing_version_str) - if pyparsing_version.major == 2: - self.name = "'%s'" % matchString - elif pyparsing_version.major == 3: - self.set_name("'%s'" % matchString) - - self.errmsg = "Expected " + self.name + quoted_name = f"'{matchString}'" + if hasattr(self, "set_name"): + # Only available in pyparsing >= 3 + self.set_name(quoted_name) + else: + self.setName(quoted_name) def parseImpl(self, instring, loc, doActions=True): test = instring[loc:loc + self.matchLen]