diff --git a/.travis.yml b/.travis.yml index 86d3188e983..8e639e3e2e1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -139,7 +139,8 @@ script: deactivate source ~/virtualenv/python2.7/bin/activate pip install pip --upgrade - pip install linkchecker + # linkchecker is currently broken with requests 2.10.0 so force an earlier version + pip install $PRE requests==2.9.2 linkchecker linkchecker build/html/index.html fi - rm -rf $HOME/.cache/matplotlib/tex.cache diff --git a/lib/matplotlib/animation.py b/lib/matplotlib/animation.py index f1e2420499b..b53d25a9249 100644 --- a/lib/matplotlib/animation.py +++ b/lib/matplotlib/animation.py @@ -1217,8 +1217,8 @@ class FuncAnimation(TimedAnimation): results of drawing from the first item in the frames sequence will be used. This function will be called once before the first frame. - If blit=True, *func* and *init_func* should return an iterable of - drawables to clear. + If blit=True, *func* and *init_func* must return an iterable of + artists to be re-drawn. *kwargs* include *repeat*, *repeat_delay*, and *interval*: *interval* draws a new frame every *interval* milliseconds. @@ -1299,6 +1299,9 @@ def _init_draw(self): else: self._drawn_artists = self._init_func() if self._blit: + if self._drawn_artists is None: + raise RuntimeError('The init_func must return a ' + 'sequence of Artist objects.') for a in self._drawn_artists: a.set_animated(self._blit) self._save_seq = [] @@ -1315,5 +1318,8 @@ def _draw_frame(self, framedata): # func needs to return a sequence of any artists that were modified. self._drawn_artists = self._func(framedata, *self._args) if self._blit: + if self._drawn_artists is None: + raise RuntimeError('The animation function must return a ' + 'sequence of Artist objects.') for a in self._drawn_artists: a.set_animated(self._blit) diff --git a/lib/matplotlib/backends/backend_ps.py b/lib/matplotlib/backends/backend_ps.py index 2f8ffaeaf65..256c9f8c125 100644 --- a/lib/matplotlib/backends/backend_ps.py +++ b/lib/matplotlib/backends/backend_ps.py @@ -165,15 +165,16 @@ def _num_to_str(val): def _nums_to_str(*args): return ' '.join(map(_num_to_str,args)) + def quote_ps_string(s): "Quote dangerous characters of S for use in a PostScript string constant." - s=s.replace("\\", "\\\\") - s=s.replace("(", "\\(") - s=s.replace(")", "\\)") - s=s.replace("'", "\\251") - s=s.replace("`", "\\301") - s=re.sub(r"[^ -~\n]", lambda x: r"\%03o"%ord(x.group()), s) - return s + s = s.replace(b"\\", b"\\\\") + s = s.replace(b"(", b"\\(") + s = s.replace(b")", b"\\)") + s = s.replace(b"'", b"\\251") + s = s.replace(b"`", b"\\301") + s = re.sub(br"[^ -~\n]", lambda x: br"\%03o" % ord(x.group()), s) + return s.decode('ascii') def seq_allequal(seq1, seq2): diff --git a/lib/matplotlib/rcsetup.py b/lib/matplotlib/rcsetup.py index 38b9dafec89..578a5a2a5ab 100644 --- a/lib/matplotlib/rcsetup.py +++ b/lib/matplotlib/rcsetup.py @@ -760,17 +760,16 @@ def validate_cycler(s): # might come from the internet (future plans), this # could be downright dangerous. # I locked it down by only having the 'cycler()' function - # available. Imports and defs should not - # be possible. However, it is entirely possible that - # a security hole could open up via attributes to the - # function (this is why I decided against allowing the - # Cycler class object just to reduce the number of - # degrees of freedom (but maybe it is safer to use?). - # One possible hole I can think of (in theory) is if - # someone managed to hack the cycler module. But, if - # someone does that, this wouldn't make anything - # worse because we have to import the module anyway. - s = eval(s, {'cycler': cycler}) + # available. + # UPDATE: Partly plugging a security hole. + # I really should have read this: + # http://nedbatchelder.com/blog/201206/eval_really_is_dangerous.html + # We should replace this eval with a combo of PyParsing and + # ast.literal_eval() + if '.__' in s.replace(' ', ''): + raise ValueError("'%s' seems to have dunder methods. Raising" + " an exception for your safety") + s = eval(s, {'cycler': cycler, '__builtins__': {}}) except BaseException as e: raise ValueError("'%s' is not a valid cycler construction: %s" % (s, e)) diff --git a/lib/matplotlib/ticker.py b/lib/matplotlib/ticker.py index c6a55471f95..aec2fee307f 100644 --- a/lib/matplotlib/ticker.py +++ b/lib/matplotlib/ticker.py @@ -135,6 +135,9 @@ :class:`EngFormatter` Format labels in engineering notation +:class:`EngFormatter` + Format labels in engineering notation + :class:`PercentFormatter` Format labels as a percentage