From a8d5f968ba9cecdd39ed57085cc9020c2e9cba2f Mon Sep 17 00:00:00 2001 From: Jens Hedegaard Nielsen Date: Sat, 3 Aug 2013 21:47:41 +0100 Subject: [PATCH 1/4] Bump minimum pyparsing version to 2.0.1, replace deprecated << with <<= and remove no longer relevant work around. --- lib/matplotlib/mathtext.py | 99 ++++++++++++++++++-------------------- setupext.py | 27 +++-------- 2 files changed, 52 insertions(+), 74 deletions(-) diff --git a/lib/matplotlib/mathtext.py b/lib/matplotlib/mathtext.py index e519746a3b28..af22cf6399c4 100644 --- a/lib/matplotlib/mathtext.py +++ b/lib/matplotlib/mathtext.py @@ -40,14 +40,7 @@ ParseResults, Suppress, oneOf, StringEnd, ParseFatalException, \ FollowedBy, Regex, ParserElement, QuotedString, ParseBaseException -# Enable packrat parsing -if (sys.version_info[0] >= 3 and - [int(x) for x in pyparsing.__version__.split('.')] < [2, 0, 0]): - warn("Due to a bug in pyparsing <= 2.0.0 on Python 3.x, packrat parsing " - "has been disabled. Mathtext rendering will be much slower as a " - "result. Install pyparsing 2.0.0 or later to improve performance.") -else: - ParserElement.enablePackrat() +ParserElement.enablePackrat() from matplotlib.afm import AFM from matplotlib.cbook import Bunch, get_realpath_and_stat, \ @@ -2179,69 +2172,69 @@ def __init__(self): if key != 'self': val.setName(key) - float_literal << Regex(r"[-+]?([0-9]+\.?[0-9]*|\.[0-9]+)") - int_literal << Regex("[-+]?[0-9]+") + float_literal <<= Regex(r"[-+]?([0-9]+\.?[0-9]*|\.[0-9]+)") + int_literal <<= Regex("[-+]?[0-9]+") - lbrace << Literal('{').suppress() - rbrace << Literal('}').suppress() - lbracket << Literal('[').suppress() - rbracket << Literal(']').suppress() - bslash << Literal('\\') + lbrace <<= Literal('{').suppress() + rbrace <<= Literal('}').suppress() + lbracket <<= Literal('[').suppress() + rbracket <<= Literal(']').suppress() + bslash <<= Literal('\\') - space << oneOf(self._space_widths.keys()) - customspace << (Suppress(Literal(r'\hspace')) + space <<= oneOf(self._space_widths.keys()) + customspace <<= (Suppress(Literal(r'\hspace')) - ((lbrace + float_literal + rbrace) | Error(r"Expected \hspace{n}"))) unicode_range = u"\U00000080-\U0001ffff" - single_symbol << Regex(UR"([a-zA-Z0-9 +\-*/<>=:,.;!\?&'@()\[\]|%s])|(\\[%%${}\[\]_|])" % + single_symbol <<= Regex(UR"([a-zA-Z0-9 +\-*/<>=:,.;!\?&'@()\[\]|%s])|(\\[%%${}\[\]_|])" % unicode_range) - symbol_name << (Combine(bslash + oneOf(tex2uni.keys())) + + symbol_name <<= (Combine(bslash + oneOf(tex2uni.keys())) + FollowedBy(Regex("[^A-Za-z]").leaveWhitespace() | StringEnd())) - symbol << (single_symbol | symbol_name).leaveWhitespace() + symbol <<= (single_symbol | symbol_name).leaveWhitespace() - apostrophe << Regex("'+") + apostrophe <<= Regex("'+") - c_over_c << Suppress(bslash) + oneOf(self._char_over_chars.keys()) + c_over_c <<= Suppress(bslash) + oneOf(self._char_over_chars.keys()) - accent << Group( + accent <<= Group( Suppress(bslash) + oneOf(self._accent_map.keys() + list(self._wide_accents)) - placeable ) - function << Suppress(bslash) + oneOf(list(self._function_names)) + function <<= Suppress(bslash) + oneOf(list(self._function_names)) - start_group << Optional(latexfont) + lbrace - end_group << rbrace.copy() - simple_group << Group(lbrace + ZeroOrMore(token) + rbrace) - required_group<< Group(lbrace + OneOrMore(token) + rbrace) - group << Group(start_group + ZeroOrMore(token) + end_group) + start_group <<= Optional(latexfont) + lbrace + end_group <<= rbrace.copy() + simple_group <<= Group(lbrace + ZeroOrMore(token) + rbrace) + required_group<<= Group(lbrace + OneOrMore(token) + rbrace) + group <<= Group(start_group + ZeroOrMore(token) + end_group) - font << Suppress(bslash) + oneOf(list(self._fontnames)) - latexfont << Suppress(bslash) + oneOf(['math' + x for x in self._fontnames]) + font <<= Suppress(bslash) + oneOf(list(self._fontnames)) + latexfont <<= Suppress(bslash) + oneOf(['math' + x for x in self._fontnames]) - frac << Group( + frac <<= Group( Suppress(Literal(r"\frac")) - ((required_group + required_group) | Error(r"Expected \frac{num}{den}")) ) - stackrel << Group( + stackrel <<= Group( Suppress(Literal(r"\stackrel")) - ((required_group + required_group) | Error(r"Expected \stackrel{num}{den}")) ) - binom << Group( + binom <<= Group( Suppress(Literal(r"\binom")) - ((required_group + required_group) | Error(r"Expected \binom{num}{den}")) ) - ambi_delim << oneOf(list(self._ambi_delim)) - left_delim << oneOf(list(self._left_delim)) - right_delim << oneOf(list(self._right_delim)) - right_delim_safe << oneOf(list(self._right_delim - set(['}'])) + [r'\}']) + ambi_delim <<= oneOf(list(self._ambi_delim)) + left_delim <<= oneOf(list(self._left_delim)) + right_delim <<= oneOf(list(self._right_delim)) + right_delim_safe <<= oneOf(list(self._right_delim - set(['}'])) + [r'\}']) - genfrac << Group( + genfrac <<= Group( Suppress(Literal(r"\genfrac")) - (((lbrace + Optional(ambi_delim | left_delim, default='') + rbrace) + (lbrace + Optional(ambi_delim | right_delim_safe, default='') + rbrace) @@ -2250,27 +2243,27 @@ def __init__(self): | Error(r"Expected \genfrac{ldelim}{rdelim}{rulesize}{style}{num}{den}")) ) - sqrt << Group( + sqrt <<= Group( Suppress(Literal(r"\sqrt")) - ((Optional(lbracket + int_literal + rbracket, default=None) + required_group) | Error("Expected \sqrt{value}")) ) - overline << Group( + overline <<= Group( Suppress(Literal(r"\overline")) - (required_group | Error("Expected \overline{value}")) ) - unknown_symbol<< Combine(bslash + Regex("[A-Za-z]*")) + unknown_symbol<<= Combine(bslash + Regex("[A-Za-z]*")) - operatorname << Group( + operatorname <<= Group( Suppress(Literal(r"\operatorname")) - ((lbrace + ZeroOrMore(simple | unknown_symbol) + rbrace) | Error("Expected \operatorname{value}")) ) - placeable << ( accent # Must be first + placeable <<= ( accent # Must be first | symbol # Must be second | c_over_c | function @@ -2284,39 +2277,39 @@ def __init__(self): | operatorname ) - simple << ( space + simple <<= ( space | customspace | font | subsuper ) - subsuperop << oneOf(["_", "^"]) + subsuperop <<= oneOf(["_", "^"]) - subsuper << Group( + subsuper <<= Group( (Optional(placeable) + OneOrMore(subsuperop - placeable) + Optional(apostrophe)) | (placeable + Optional(apostrophe)) | apostrophe ) - token << ( simple + token <<= ( simple | auto_delim | unknown_symbol # Must be last ) - auto_delim << (Suppress(Literal(r"\left")) + auto_delim <<= (Suppress(Literal(r"\left")) - ((left_delim | ambi_delim) | Error("Expected a delimiter")) + Group(ZeroOrMore(simple | auto_delim)) + Suppress(Literal(r"\right")) - ((right_delim | ambi_delim) | Error("Expected a delimiter")) ) - math << OneOrMore(token) + math <<= OneOrMore(token) - math_string << QuotedString('$', '\\', unquoteResults=False) + math_string <<= QuotedString('$', '\\', unquoteResults=False) - non_math << Regex(r"(?:(?:\\[$])|[^$])*").leaveWhitespace() + non_math <<= Regex(r"(?:(?:\\[$])|[^$])*").leaveWhitespace() - main << (non_math + ZeroOrMore(math_string + non_math)) + StringEnd() + main <<= (non_math + ZeroOrMore(math_string + non_math)) + StringEnd() # Set actions for key, val in locals().items(): diff --git a/setupext.py b/setupext.py index a79585da5250..e7a397598789 100644 --- a/setupext.py +++ b/setupext.py @@ -971,30 +971,15 @@ def check(self): "support. pip/easy_install may attempt to install it " "after matplotlib.") - if sys.version_info[0] >= 3: - required = [2, 0, 0] - if [int(x) for x in pyparsing.__version__.split('.')] < required: - return ( - "matplotlib requires pyparsing >= {0} on Python 3.x".format( - '.'.join(str(x) for x in required))) - else: - required = [1, 5, 6] - if [int(x) for x in pyparsing.__version__.split('.')] < required: - return ( - "matplotlib requires pyparsing >= {0} on Python 2.x".format( - '.'.join(str(x) for x in required))) - if pyparsing.__version__ == "2.0.0": - return ( - "pyparsing 2.0.0 is not compatible with Python 2.x") - + required = [2, 0, 1] + if [int(x) for x in pyparsing.__version__.split('.')] < required: + return ( + "matplotlib requires pyparsing >= {0}".format( + '.'.join(str(x) for x in required))) return "using pyparsing version %s" % pyparsing.__version__ def get_install_requires(self): - if sys.version_info[0] >= 3: - return ['pyparsing>=1.5.6'] - else: - # pyparsing >= 2.0.0 is not compatible with Python 2 - return ['pyparsing>=1.5.6,!=2.0.0'] + return ['pyparsing>=2.0.1'] class BackendAgg(OptionalBackendPackage): From 0fa8a9ae00d7b85f9cd5c7537eb8045c6adec427 Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Wed, 7 Aug 2013 12:21:11 -0400 Subject: [PATCH 2/4] Monkey patch pyparsing so that we can support pyparsing >= 1.5.6 on both Python 2 and 3 without loads of deprecation warnings. --- lib/matplotlib/__init__.py | 10 ++++++++++ lib/matplotlib/mathtext.py | 9 ++++++++- setupext.py | 14 ++++++++++++-- 3 files changed, 30 insertions(+), 3 deletions(-) diff --git a/lib/matplotlib/__init__.py b/lib/matplotlib/__init__.py index 9d8cd5eca5c5..94dbddaa3fa2 100644 --- a/lib/matplotlib/__init__.py +++ b/lib/matplotlib/__init__.py @@ -120,6 +120,16 @@ "matplotlib requires pyparsing >= {0}".format( '.'.join(str(x) for x in _required))) + # pyparsing 1.5.6 does not have <<= on the Forward class, but + # pyparsing 2.0.0 and later will spew deprecation warnings if + # using << instead. In order to support pyparsing 1.5.6 and above + # with a common code base, this small monkey patch is applied. + if not hasattr(pyparsing.Forward, '__ilshift__'): + def _forward_ilshift(self, other): + self.__lshift__(other) + return self + pyparsing.Forward.__ilshift__ = _forward_ilshift + import os, re, shutil, warnings import distutils.sysconfig import distutils.version diff --git a/lib/matplotlib/mathtext.py b/lib/matplotlib/mathtext.py index af22cf6399c4..c35a85038dcb 100644 --- a/lib/matplotlib/mathtext.py +++ b/lib/matplotlib/mathtext.py @@ -40,7 +40,14 @@ ParseResults, Suppress, oneOf, StringEnd, ParseFatalException, \ FollowedBy, Regex, ParserElement, QuotedString, ParseBaseException -ParserElement.enablePackrat() +# Enable packrat parsing +if (sys.version_info[0] >= 3 and + [int(x) for x in pyparsing.__version__.split('.')] < [2, 0, 0]): + warn("Due to a bug in pyparsing <= 2.0.0 on Python 3.x, packrat parsing " + "has been disabled. Mathtext rendering will be much slower as a " + "result. Install pyparsing 2.0.0 or later to improve performance.") +else: + ParserElement.enablePackrat() from matplotlib.afm import AFM from matplotlib.cbook import Bunch, get_realpath_and_stat, \ diff --git a/setupext.py b/setupext.py index e7a397598789..4c9ffb6b2ec3 100644 --- a/setupext.py +++ b/setupext.py @@ -971,15 +971,25 @@ def check(self): "support. pip/easy_install may attempt to install it " "after matplotlib.") - required = [2, 0, 1] + required = [1, 5, 6] if [int(x) for x in pyparsing.__version__.split('.')] < required: return ( "matplotlib requires pyparsing >= {0}".format( '.'.join(str(x) for x in required))) + + if sys.version_info[0] == 2: + if pyparsing.__version__ == "2.0.0": + return ( + "pyparsing 2.0.0 is not compatible with Python 2.x") + return "using pyparsing version %s" % pyparsing.__version__ def get_install_requires(self): - return ['pyparsing>=2.0.1'] + if sys.version_info[0] >= 3: + return ['pyparsing>=1.5.6'] + else: + # pyparsing >= 2.0.0 is not compatible with Python 2 + return ['pyparsing>=1.5.6,!=2.0.0'] class BackendAgg(OptionalBackendPackage): From f49f9fcacedf6a36401589caa7e0d198893aab34 Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Wed, 7 Aug 2013 14:11:23 -0400 Subject: [PATCH 3/4] Install latest version of pyparsing --- .travis.yml | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 8792e50a4ec6..4128772bb8e6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,11 +7,7 @@ python: - 3.3 install: - - pip install -q --use-mirrors nose python-dateutil numpy pep8 - # This is a workaround to install the latest versions of pyparsing, - # which are not yet available on PyPI - - 'if [ ${TRAVIS_PYTHON_VERSION:0:1} == "3" ]; then pip -q install http://sourceforge.net/projects/pyparsing/files/pyparsing/pyparsing-2.0.0/pyparsing-2.0.0.tar.gz; fi' - - 'if [ ${TRAVIS_PYTHON_VERSION:0:1} == "2" ]; then pip -q install http://sourceforge.net/projects/pyparsing/files/pyparsing/pyparsing-1.5.7/pyparsing-1.5.7.tar.gz; fi' + - pip install -q --use-mirrors nose python-dateutil numpy pep8 pyparsing - if [[ $TRAVIS_PYTHON_VERSION == '2.'* ]]; then pip -q install --use-mirrors PIL; fi - sudo apt-get update && sudo apt-get -qq install inkscape - python setup.py install From 0f19fec31636235bd9fda2c06a820a3d72f9b0fd Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Wed, 7 Aug 2013 14:14:34 -0400 Subject: [PATCH 4/4] Exclude use of pyparsing 2.0.0 everywhere --- lib/matplotlib/__init__.py | 5 +++++ setupext.py | 14 +++++++------- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/lib/matplotlib/__init__.py b/lib/matplotlib/__init__.py index 94dbddaa3fa2..5213c8149561 100644 --- a/lib/matplotlib/__init__.py +++ b/lib/matplotlib/__init__.py @@ -120,6 +120,11 @@ "matplotlib requires pyparsing >= {0}".format( '.'.join(str(x) for x in _required))) + if pyparsing.__version__ == '2.0.0': + raise ImportError( + "pyparsing 2.0.0 has bugs that prevent its use with " + "matplotlib") + # pyparsing 1.5.6 does not have <<= on the Forward class, but # pyparsing 2.0.0 and later will spew deprecation warnings if # using << instead. In order to support pyparsing 1.5.6 and above diff --git a/setupext.py b/setupext.py index 4c9ffb6b2ec3..a946a4d94035 100644 --- a/setupext.py +++ b/setupext.py @@ -977,19 +977,19 @@ def check(self): "matplotlib requires pyparsing >= {0}".format( '.'.join(str(x) for x in required))) - if sys.version_info[0] == 2: - if pyparsing.__version__ == "2.0.0": + if pyparsing.__version__ == "2.0.0": + if sys.version_info[0] == 2: return ( "pyparsing 2.0.0 is not compatible with Python 2.x") + else: + return ( + "pyparsing 2.0.0 has bugs that prevent its use with " + "matplotlib") return "using pyparsing version %s" % pyparsing.__version__ def get_install_requires(self): - if sys.version_info[0] >= 3: - return ['pyparsing>=1.5.6'] - else: - # pyparsing >= 2.0.0 is not compatible with Python 2 - return ['pyparsing>=1.5.6,!=2.0.0'] + return ['pyparsing>=1.5.6,!=2.0.0'] class BackendAgg(OptionalBackendPackage):