Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Test with Python 3.12 #24711

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 28, 2023
Merged

Test with Python 3.12 #24711

merged 1 commit into from
Aug 28, 2023

Conversation

oscargus
Copy link
Member

PR Summary

PR Checklist

Documentation and Tests

  • Has pytest style unit tests (and pytest passes)
  • Documentation is sphinx and numpydoc compliant (the docs should build without error).
  • New plotting related features are documented with examples.

Release Notes

  • New features are marked with a .. versionadded:: directive in the docstring and documented in doc/users/next_whats_new/
  • API changes are marked with a .. versionchanged:: directive in the docstring and documented in doc/api/next_api_changes/
  • Release notes conform with instructions in next_whats_new/README.rst or next_api_changes/README.rst

@oscargus oscargus force-pushed the py312 branch 3 times, most recently from b1b212d to 64c9805 Compare December 13, 2022 14:40
@oscargus
Copy link
Member Author

Status:

  • Some modules must be compiled, but they do work.
  • PySide2 doesn't work, so not installed.
  • Issues with webp and/or webagg that I do not really understand.
FAILED lib/matplotlib/tests/test_agg.py::test_pil_kwargs_webp - KeyError: 'WEBP'
FAILED lib/matplotlib/tests/test_agg.py::test_webp_alpha - KeyError: 'WEBP'
FAILED lib/matplotlib/tests/test_backends_interactive.py::test_webagg - assert 1 is None
  • One deprecation in 3.12 that should be fixed.
  src/_qhull_wrapper.cpp:291:50: warning: ‘Py_VerboseFlag’ is deprecated [-Wdeprecated-declarations]
    291 |              (ret = delaunay_impl(npoints, x, y, Py_VerboseFlag == 0)));
        |                                                  ^~~~~~~~~~~~~~

Should be replaced by PyConfig.verbose https://docs.python.org/3.12/c-api/init_config.html#c.PyConfig.verbose

@tacaswell
Copy link
Member

The webp maybe due to pillow being compiled without the required c-libraries available. We should either make sure we also install the webp libraries or make those tests fail garcefully.

@oscargus
Copy link
Member Author

The strange this is the following:

DEBUG    PIL.Image:Image.py:369 Importing WebPImagePlugin

which I interpret as webp being available.

I tested installing webp before building pillow, but no change.

@oscargus
Copy link
Member Author

The remaining failing test is apparently a bit tricky as it already have a few skip markers...

    @pytest.mark.skipif('TF_BUILD' in os.environ,
                        reason="this test fails an azure for unknown reasons")
    @pytest.mark.skipif(os.name == "nt", reason="Cannot send SIGINT on Windows.")

I guess the thing to do is to add yet another marker, probably for Python version.

@QuLogic
Copy link
Member

QuLogic commented Dec 22, 2022

We should not be skipping that; it's a real bug:

  File "/home/runner/work/matplotlib/matplotlib/lib/matplotlib/backend_bases.py", line 1130, in start
    self._timer_start()
  File "/home/runner/work/matplotlib/matplotlib/lib/matplotlib/backends/backend_webagg_core.py", line 141, in _timer_start
    self._task = asyncio.ensure_future(
                 ^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/hostedtoolcache/Python/3.12.0-alpha.3/x64/lib/python3.12/asyncio/tasks.py", line 652, in ensure_future
    return _ensure_future(coro_or_future, loop=loop)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/hostedtoolcache/Python/3.12.0-alpha.3/x64/lib/python3.12/asyncio/tasks.py", line 671, in _ensure_future
    loop = events.get_event_loop()
           ^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/hostedtoolcache/Python/3.12.0-alpha.3/x64/lib/python3.12/asyncio/events.py", line 676, in get_event_loop
    raise RuntimeError('There is no current event loop in thread %r.'
RuntimeError: There is no current event loop in thread 'MainThread'.

asyncio.get_event_loop() and many other asyncio
functions like ensure_future(), shield() or gather(), and also the
get_event_loop() method of BaseDefaultEventLoopPolicy now raise a RuntimeError
if called when there is no running event loop and the current event loop was
not set. Previously they implicitly created and set a new current event loop.
DeprecationWarning is no longer emitted if there is no running event loop but
the current event loop is set in the policy. (Contributed by Serhiy Storchaka
in gh-93453.)

python/cpython#93453

@tacaswell
Copy link
Member

Sorry, I've been seeing (and ignoring) the event loop failure locally.

@oscargus
Copy link
Member Author

I have no idea how to proceed here. Spent some time trying to read up, but cannot really say that I found a workaround (simple enough for me to get it).

@oscargus oscargus mentioned this pull request Jan 10, 2023
6 tasks
@tacaswell
Copy link
Member

I can try to put some cycles into fixing the event loop issues after we get 3.7 mostly out the door.

@tacaswell
Copy link
Member

on a bit of testing with cpython main this does not fail but it does fail with 3.12.0a3 and 3.12.0a4. I will finish bisecting this to sort out if this is intended to be fixed on cpython main or if they need a bug report that they un-broke us.

@oscargus
Copy link
Member Author

Seems like it passes with 3.12.alpha-7.

@tacaswell
Copy link
Member

I'm seeing ~54 failures locally:

=================================================================================================================================================================================== short test summary info ====================================================================================================================================================================================
FAILED lib/matplotlib/tests/test_backend_qt.py::test_enums_available[{'MPLBACKEND': 'qtagg', 'QT_API': 'PyQt6'}] - subprocess.CalledProcessError: Command '['/home/tcaswell/.virtualenvs/bleeding/bin/python3', '-c', 'def _test_enums_impl():\n    import sys\n\n    from matplotlib.backends.qt_compat import _enum, _to_int\n    from matplotlib.backend_bases import cursors, MouseButton\n\n    _enum("QtGui.QDoubleValidator.State").Acceptable\n\n    _enum("QtWidgets.QDialogButtonBox.StandardButton"...
FAILED lib/matplotlib/tests/test_backends_interactive.py::test_figure_leak_20490[time_mem0-{'MPLBACKEND': 'qtcairo', 'QT_API': 'PyQt6'}] - subprocess.CalledProcessError: Command '['/home/tcaswell/.virtualenvs/bleeding/bin/python3', '-c', 'from matplotlib.tests.test_backends_interactive import _test_figure_leak; _test_figure_leak()', '0.0']' died with <Signals.SIGSEGV: 11>.
FAILED lib/matplotlib/tests/test_backend_svg.py::test_url_tick - DeprecationWarning: datetime.utcfromtimestamp() is deprecated and scheduled for removal in a future version. Use timezone-aware objects to represent datetimes in UTC: datetime.now(datetime.UTC).
FAILED lib/matplotlib/tests/test_backend_svg.py::test_svg_default_metadata - DeprecationWarning: datetime.utcfromtimestamp() is deprecated and scheduled for removal in a future version. Use timezone-aware objects to represent datetimes in UTC: datetime.now(datetime.UTC).
FAILED lib/matplotlib/tests/test_backend_svg.py::test_svg_clear_default_metadata - DeprecationWarning: datetime.utcfromtimestamp() is deprecated and scheduled for removal in a future version. Use timezone-aware objects to represent datetimes in UTC: datetime.now(datetime.UTC).
FAILED lib/matplotlib/tests/test_lines.py::test_set_line_coll_dash_image[pdf] - matplotlib.testing.exceptions.ImageComparisonFailure: images not close (RMS 0.402):
FAILED lib/matplotlib/tests/test_lines.py::test_set_line_coll_dash_image[svg] - matplotlib.testing.exceptions.ImageComparisonFailure: images not close (RMS 0.412):
FAILED lib/matplotlib/tests/test_backends_interactive.py::test_figure_leak_20490[time_mem1-{'MPLBACKEND': 'qtagg', 'QT_API': 'PyQt6'}] - subprocess.CalledProcessError: Command '['/home/tcaswell/.virtualenvs/bleeding/bin/python3', '-c', 'from matplotlib.tests.test_backends_interactive import _test_figure_leak; _test_figure_leak()', '0.1']' died with <Signals.SIGSEGV: 11>.
FAILED lib/matplotlib/tests/test_backend_pgf.py::test_pdflatex[pdf] - matplotlib.testing.exceptions.ImageComparisonFailure: images not close (RMS 13.194):
FAILED lib/matplotlib/tests/test_backends_interactive.py::test_figure_leak_20490[time_mem1-{'MPLBACKEND': 'qtcairo', 'QT_API': 'PyQt6'}] - subprocess.CalledProcessError: Command '['/home/tcaswell/.virtualenvs/bleeding/bin/python3', '-c', 'from matplotlib.tests.test_backends_interactive import _test_figure_leak; _test_figure_leak()', '0.1']' died with <Signals.SIGSEGV: 11>.
FAILED lib/matplotlib/tests/test_mathtext.py::test_mathtext_exceptions[hspace without value] - AssertionError: Regex pattern did not match.
FAILED lib/matplotlib/tests/test_mathtext.py::test_mathtext_exceptions[hspace with invalid value] - AssertionError: Regex pattern did not match.
FAILED lib/matplotlib/tests/test_mathtext.py::test_mathtext_exceptions[function without space] - AssertionError: Regex pattern did not match.
FAILED lib/matplotlib/tests/test_mathtext.py::test_mathtext_exceptions[accent without space] - AssertionError: Regex pattern did not match.
FAILED lib/matplotlib/tests/test_mathtext.py::test_mathtext_exceptions[frac without parameters] - AssertionError: Regex pattern did not match.
FAILED lib/matplotlib/tests/test_mathtext.py::test_mathtext_exceptions[frac with empty parameters] - AssertionError: Regex pattern did not match.
FAILED lib/matplotlib/tests/test_mathtext.py::test_mathtext_exceptions[binom without parameters] - AssertionError: Regex pattern did not match.
FAILED lib/matplotlib/tests/test_mathtext.py::test_mathtext_exceptions[binom with empty parameters] - AssertionError: Regex pattern did not match.
FAILED lib/matplotlib/tests/test_mathtext.py::test_mathtext_exceptions[genfrac without parameters] - AssertionError: Regex pattern did not match.
FAILED lib/matplotlib/tests/test_mathtext.py::test_mathtext_exceptions[genfrac with empty parameters] - AssertionError: Regex pattern did not match.
FAILED lib/matplotlib/tests/test_backend_pgf.py::test_rcupdate - matplotlib.testing.exceptions.ImageComparisonFailure: Error: Image files did not match.
FAILED lib/matplotlib/tests/test_mathtext.py::test_mathtext_exceptions[sqrt without parameters] - AssertionError: Regex pattern did not match.
FAILED lib/matplotlib/tests/test_mathtext.py::test_mathtext_exceptions[sqrt with invalid value] - AssertionError: Regex pattern did not match.
FAILED lib/matplotlib/tests/test_mathtext.py::test_mathtext_exceptions[overline without parameters] - AssertionError: Regex pattern did not match.
FAILED lib/matplotlib/tests/test_mathtext.py::test_mathtext_exceptions[overline with empty parameter] - AssertionError: Regex pattern did not match.
FAILED lib/matplotlib/tests/test_mathtext.py::test_mathtext_exceptions[left with invalid delimiter] - AssertionError: Regex pattern did not match.
FAILED lib/matplotlib/tests/test_mathtext.py::test_mathtext_exceptions[right with invalid delimiter] - AssertionError: Regex pattern did not match.
FAILED lib/matplotlib/tests/test_mathtext.py::test_mathtext_exceptions[unclosed parentheses with sizing] - AssertionError: Regex pattern did not match.
FAILED lib/matplotlib/tests/test_mathtext.py::test_mathtext_exceptions[unclosed parentheses without sizing] - AssertionError: Regex pattern did not match.
FAILED lib/matplotlib/tests/test_mathtext.py::test_mathtext_exceptions[dfrac without parameters] - AssertionError: Regex pattern did not match.
FAILED lib/matplotlib/tests/test_mathtext.py::test_mathtext_exceptions[dfrac with empty parameters] - AssertionError: Regex pattern did not match.
FAILED lib/matplotlib/tests/test_mathtext.py::test_mathtext_exceptions[overset without parameters] - AssertionError: Regex pattern did not match.
FAILED lib/matplotlib/tests/test_mathtext.py::test_mathtext_exceptions[underset without parameters] - AssertionError: Regex pattern did not match.
FAILED lib/matplotlib/tests/test_mathtext.py::test_mathtext_exceptions[unknown symbol] - AssertionError: Regex pattern did not match.
FAILED lib/matplotlib/tests/test_mathtext.py::test_mathtext_exceptions[double superscript] - AssertionError: Regex pattern did not match.
FAILED lib/matplotlib/tests/test_mathtext.py::test_mathtext_exceptions[double subscript] - AssertionError: Regex pattern did not match.
FAILED lib/matplotlib/tests/test_mathtext.py::test_mathtext_exceptions[super on sub without braces] - AssertionError: Regex pattern did not match.
FAILED lib/matplotlib/tests/test_backends_interactive.py::test_interactive_backend[toolbar2-{'MPLBACKEND': 'qtagg', 'QT_API': 'PyQt6'}] - Failed: Subprocess failed to test intended behavior
FAILED lib/matplotlib/tests/test_pickle.py::test_pickle_load_from_subprocess[png] - subprocess.CalledProcessError: Command '['/home/tcaswell/.virtualenvs/bleeding/bin/python3', '-c', 'from matplotlib.tests.test_pickle import _pickle_load_subprocess; _pickle_load_subprocess()']' died with <Signals.SIGSEGV: 11>.
FAILED lib/matplotlib/tests/test_rcparams.py::test_backend_fallback_headful - subprocess.CalledProcessError: Command '['/home/tcaswell/.virtualenvs/bleeding/bin/python3', '-c', "import matplotlib as mpl; sentinel = mpl.rcsetup._auto_backend_sentinel; assert mpl.RcParams({'backend': sentinel})['backend'] == sentinel; assert mpl.rcParams._get('backend') == sentinel; import matplotlib.pyplot; print(matplotlib.get_backend())"]' died with <Signals.SIGSEGV: 11>.
FAILED lib/matplotlib/tests/test_pyplot.py::test_pylab_integration - subprocess.CalledProcessError: Command '['/home/tcaswell/.virtualenvs/bleeding/bin/python3', '-c', 'from IPython import start_ipython; start_ipython()', '--pylab', '-c', 'import matplotlib.pyplot as plt;assert plt._REPL_DISPLAYHOOK == plt._ReplDisplayHook.IPYTHON']' died with <Signals.SIGSEGV: 11>.
FAILED lib/matplotlib/tests/test_text.py::test_parse_math - AssertionError: Regex pattern did not match.
FAILED lib/matplotlib/tests/test_text.py::test_parse_math_rcparams - AssertionError: Regex pattern did not match.
FAILED lib/matplotlib/tests/test_texmanager.py::test_openin_any_paranoid - subprocess.CalledProcessError: Command '['/home/tcaswell/.virtualenvs/bleeding/bin/python3', '-c', 'import matplotlib.pyplot as plt;plt.rcParams.update({"text.usetex": True});plt.title("paranoid");plt.show(block=False);']' died with <Signals.SIGSEGV: 11>.
FAILED lib/matplotlib/tests/test_backends_interactive.py::test_interactive_backend[toolbar2-{'MPLBACKEND': 'qtcairo', 'QT_API': 'PyQt6'}] - Failed: Subprocess failed to test intended behavior
FAILED lib/matplotlib/tests/test_backends_interactive.py::test_interactive_backend[toolmanager-{'MPLBACKEND': 'qtagg', 'QT_API': 'PyQt6'}] - Failed: Subprocess failed to test intended behavior
FAILED lib/matplotlib/tests/test_backends_interactive.py::test_interactive_backend[toolmanager-{'MPLBACKEND': 'qtcairo', 'QT_API': 'PyQt6'}] - Failed: Subprocess failed to test intended behavior
FAILED lib/matplotlib/tests/test_backends_interactive.py::test_interactive_thread_safety[{'MPLBACKEND': 'qtagg', 'QT_API': 'PyQt6'}] - subprocess.CalledProcessError: Command '['/home/tcaswell/.virtualenvs/bleeding/bin/python3', '-c', 'from matplotlib.tests.test_backends_interactive import _test_thread_impl; _test_thread_impl()']' died with <Signals.SIGSEGV: 11>.
FAILED lib/matplotlib/tests/test_backends_interactive.py::test_lazy_auto_backend_selection - subprocess.CalledProcessError: Command '['/home/tcaswell/.virtualenvs/bleeding/bin/python3', '-c', 'from matplotlib.tests.test_backends_interactive import _impl_test_lazy_auto_backend_selection; _impl_test_lazy_auto_backend_selection()']' died with <Signals.SIGSEGV: 11>.
FAILED lib/matplotlib/tests/test_backends_interactive.py::test_lazy_linux_headless[{'MPLBACKEND': 'qtagg', 'QT_API': 'PyQt6'}] - subprocess.CalledProcessError: Command '['/home/tcaswell/.virtualenvs/bleeding/bin/python3', '-c', 'from matplotlib.tests.test_backends_interactive import _lazy_headless; _lazy_headless()', 'qtagg', 'PyQt6']' died with <Signals.SIGSEGV: 11>.
FAILED lib/matplotlib/tests/test_backends_interactive.py::test_lazy_linux_headless[{'MPLBACKEND': 'qtcairo', 'QT_API': 'PyQt6'}] - subprocess.CalledProcessError: Command '['/home/tcaswell/.virtualenvs/bleeding/bin/python3', '-c', 'from matplotlib.tests.test_backends_interactive import _lazy_headless; _lazy_headless()', 'qtcairo', 'PyQt6,cairocffi']' died with <Signals.SIGSEGV: 11>.
FAILED lib/matplotlib/tests/test_backends_interactive.py::test_blitting_events[{'MPLBACKEND': 'qtagg', 'QT_API': 'PyQt6'}] - subprocess.CalledProcessError: Command '['/home/tcaswell/.virtualenvs/bleeding/bin/python3', '-c', 'from matplotlib.tests.test_backends_interactive import _test_number_of_draws_script; _test_number_of_draws_script()']' died with <Signals.SIGSEGV: 11>.
FAILED lib/matplotlib/tests/test_backends_interactive.py::test_blitting_events[{'MPLBACKEND': 'qtcairo', 'QT_API': 'PyQt6'}] - subprocess.CalledProcessError: Command '['/home/tcaswell/.virtualenvs/bleeding/bin/python3', '-c', 'from matplotlib.tests.test_backends_interactive import _test_number_of_draws_script; _test_number_of_draws_script()']' died with <Signals.SIGSEGV: 11>.
FAILED lib/matplotlib/tests/test_backends_interactive.py::test_figure_leak_20490[time_mem0-{'MPLBACKEND': 'qtagg', 'QT_API': 'PyQt6'}] - subprocess.CalledProcessError: Command '['/home/tcaswell/.virtualenvs/bleeding/bin/python3', '-c', 'from matplotlib.tests.test_backends_interactive import _test_figure_leak; _test_figure_leak()', '0.0']' died with <Signals.SIGSEGV: 11>.
================================================================================================================================================= 54 failed, 9060 passed, 257 skipped, 13 xfailed, 12 warnings, 23 rerun in 202.31s (0:03:22) ==================================================================================================================================================

Some of these are the utcdatetime issue (being dealt with), some of these are Python segfaulting on exit (which I need to sort out a way to get a better reproducer of!), and some of these are things that look like:

___________________________________________________________________________________________________________________________________________________________________________________ test_parse_math_rcparams ___________________________________________________________________________________________________________________________________________________________________________________
[gw9] linux -- Python 3.12.0 /home/tcaswell/.virtualenvs/bleeding/bin/python3

    def test_parse_math_rcparams():
        # Default is True
        fig, ax = plt.subplots()
        ax.text(0, 0, r"$ \wrong{math} $")
        with pytest.raises(ValueError, match='Unknown symbol'):
>           fig.canvas.draw()

lib/matplotlib/tests/test_text.py:836:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <matplotlib.backends.backend_agg.FigureCanvasAgg object at 0x7f2318a19730>

    def draw(self):
        # docstring inherited
        self.renderer = self.get_renderer()
        self.renderer.clear()
        # Acquire a lock on the shared font cache.
        with RendererAgg.lock, \
             (self.toolbar._wait_cursor_for_draw_cm() if self.toolbar
              else nullcontext()):
>           self.figure.draw(self.renderer)

lib/matplotlib/backends/backend_agg.py:401:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

artist = <Figure size 640x480 with 1 Axes>, renderer = <matplotlib.backends.backend_agg.RendererAgg object at 0x7f231f207da0>, args = (), kwargs = {}

    @wraps(draw)
    def draw_wrapper(artist, renderer, *args, **kwargs):
>       result = draw(artist, renderer, *args, **kwargs)

lib/matplotlib/artist.py:95:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

artist = <Figure size 640x480 with 1 Axes>, renderer = <matplotlib.backends.backend_agg.RendererAgg object at 0x7f231f207da0>

    @wraps(draw)
    def draw_wrapper(artist, renderer):
        try:
            if artist.get_rasterized():
                if renderer._raster_depth == 0 and not renderer._rasterizing:
                    renderer.start_rasterizing()
                    renderer._rasterizing = True
                renderer._raster_depth += 1
            else:
                if renderer._raster_depth == 0 and renderer._rasterizing:
                    # Only stop when we are not in a rasterized parent
                    # and something has be rasterized since last stop
                    renderer.stop_rasterizing()
                    renderer._rasterizing = False

            if artist.get_agg_filter() is not None:
                renderer.start_filter()

>           return draw(artist, renderer)

lib/matplotlib/artist.py:72:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <Figure size 640x480 with 1 Axes>, renderer = <matplotlib.backends.backend_agg.RendererAgg object at 0x7f231f207da0>

    @_finalize_rasterization
    @allow_rasterization
    def draw(self, renderer):
        # docstring inherited

        # draw the figure bounding box, perhaps none for white figure
        if not self.get_visible():
            return

        artists = self._get_draw_artists(renderer)
        try:
            renderer.open_group('figure', gid=self.get_gid())
            if self.axes and self.get_layout_engine() is not None:
                try:
                    self.get_layout_engine().execute(self)
                except ValueError:
                    pass
                    # ValueError can occur when resizing a window.

            self.patch.draw(renderer)
>           mimage._draw_list_compositing_images(
                renderer, self, artists, self.suppressComposite)

lib/matplotlib/figure.py:3139:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

renderer = <matplotlib.backends.backend_agg.RendererAgg object at 0x7f231f207da0>, parent = <Figure size 640x480 with 1 Axes>, artists = [<Axes: >], suppress_composite = None

    def _draw_list_compositing_images(
            renderer, parent, artists, suppress_composite=None):
        """
        Draw a sorted list of artists, compositing images into a single
        image where possible.

        For internal Matplotlib use only: It is here to reduce duplication
        between `Figure.draw` and `Axes.draw`, but otherwise should not be
        generally useful.
        """
        has_images = any(isinstance(x, _ImageBase) for x in artists)

        # override the renderer default if suppressComposite is not None
        not_composite = (suppress_composite if suppress_composite is not None
                         else renderer.option_image_nocomposite())

        if not_composite or not has_images:
            for a in artists:
>               a.draw(renderer)

lib/matplotlib/image.py:131:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

artist = <Axes: >, renderer = <matplotlib.backends.backend_agg.RendererAgg object at 0x7f231f207da0>

    @wraps(draw)
    def draw_wrapper(artist, renderer):
        try:
            if artist.get_rasterized():
                if renderer._raster_depth == 0 and not renderer._rasterizing:
                    renderer.start_rasterizing()
                    renderer._rasterizing = True
                renderer._raster_depth += 1
            else:
                if renderer._raster_depth == 0 and renderer._rasterizing:
                    # Only stop when we are not in a rasterized parent
                    # and something has be rasterized since last stop
                    renderer.stop_rasterizing()
                    renderer._rasterizing = False

            if artist.get_agg_filter() is not None:
                renderer.start_filter()

>           return draw(artist, renderer)

lib/matplotlib/artist.py:72:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <Axes: >, renderer = <matplotlib.backends.backend_agg.RendererAgg object at 0x7f231f207da0>

    @martist.allow_rasterization
    def draw(self, renderer):
        # docstring inherited
        if renderer is None:
            raise RuntimeError('No renderer defined')
        if not self.get_visible():
            return
        self._unstale_viewLim()

        renderer.open_group('axes', gid=self.get_gid())

        # prevent triggering call backs during the draw process
        self._stale = True

        # loop over self and child Axes...
        locator = self.get_axes_locator()
        self.apply_aspect(locator(self, renderer) if locator else None)

        artists = self.get_children()
        artists.remove(self.patch)

        # the frame draws the edges around the Axes patch -- we
        # decouple these so the patch can be in the background and the
        # frame in the foreground. Do this before drawing the axis
        # objects so that the spine has the opportunity to update them.
        if not (self.axison and self._frameon):
            for spine in self.spines.values():
                artists.remove(spine)

        self._update_title_position(renderer)

        if not self.axison:
            for _axis in self._axis_map.values():
                artists.remove(_axis)

        if not self.figure.canvas.is_saving():
            artists = [
                a for a in artists
                if not a.get_animated() or isinstance(a, mimage.AxesImage)]
        artists = sorted(artists, key=attrgetter('zorder'))

        # rasterize artists with negative zorder
        # if the minimum zorder is negative, start rasterization
        rasterization_zorder = self._rasterization_zorder

        if (rasterization_zorder is not None and
                artists and artists[0].zorder < rasterization_zorder):
            split_index = np.searchsorted(
                [art.zorder for art in artists],
                rasterization_zorder, side='right'
            )
            artists_rasterized = artists[:split_index]
            artists = artists[split_index:]
        else:
            artists_rasterized = []

        if self.axison and self._frameon:
            if artists_rasterized:
                artists_rasterized = [self.patch] + artists_rasterized
            else:
                artists = [self.patch] + artists

        if artists_rasterized:
            _draw_rasterized(self.figure, artists_rasterized, renderer)

>       mimage._draw_list_compositing_images(
            renderer, self, artists, self.figure.suppressComposite)

lib/matplotlib/axes/_base.py:3061:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

renderer = <matplotlib.backends.backend_agg.RendererAgg object at 0x7f231f207da0>, parent = <Axes: >, artists = [<matplotlib.patches.Rectangle object at 0x7f2318086e40>, <matplotlib.spines.Spine object at 0x7f2318a18ad0>, <matplot...2318a1b3b0>, <matplotlib.spines.Spine object at 0x7f2318a1b110>, <matplotlib.axis.XAxis object at 0x7f2318a18560>, ...], suppress_composite = None

    def _draw_list_compositing_images(
            renderer, parent, artists, suppress_composite=None):
        """
        Draw a sorted list of artists, compositing images into a single
        image where possible.

        For internal Matplotlib use only: It is here to reduce duplication
        between `Figure.draw` and `Axes.draw`, but otherwise should not be
        generally useful.
        """
        has_images = any(isinstance(x, _ImageBase) for x in artists)

        # override the renderer default if suppressComposite is not None
        not_composite = (suppress_composite if suppress_composite is not None
                         else renderer.option_image_nocomposite())

        if not_composite or not has_images:
            for a in artists:
>               a.draw(renderer)

lib/matplotlib/image.py:131:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

artist = Text(0, 0, '$ \\wrong{math} $'), renderer = <matplotlib.backends.backend_agg.RendererAgg object at 0x7f231f207da0>

    @wraps(draw)
    def draw_wrapper(artist, renderer):
        try:
            if artist.get_rasterized():
                if renderer._raster_depth == 0 and not renderer._rasterizing:
                    renderer.start_rasterizing()
                    renderer._rasterizing = True
                renderer._raster_depth += 1
            else:
                if renderer._raster_depth == 0 and renderer._rasterizing:
                    # Only stop when we are not in a rasterized parent
                    # and something has be rasterized since last stop
                    renderer.stop_rasterizing()
                    renderer._rasterizing = False

            if artist.get_agg_filter() is not None:
                renderer.start_filter()

>           return draw(artist, renderer)

lib/matplotlib/artist.py:72:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = Text(0, 0, '$ \\wrong{math} $'), renderer = <matplotlib.backends.backend_agg.RendererAgg object at 0x7f231f207da0>

    @artist.allow_rasterization
    def draw(self, renderer):
        # docstring inherited

        if renderer is not None:
            self._renderer = renderer
        if not self.get_visible():
            return
        if self.get_text() == '':
            return

        renderer.open_group('text', self.get_gid())

        with self._cm_set(text=self._get_wrapped_text()):
>           bbox, info, descent = self._get_layout(renderer)

lib/matplotlib/text.py:717:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = Text(0, 0, '$ \\wrong{math} $'), renderer = <matplotlib.backends.backend_agg.RendererAgg object at 0x7f231f207da0>

    def _get_layout(self, renderer):
        """
        Return the extent (bbox) of the text together with
        multiple-alignment information. Note that it returns an extent
        of a rotated text when necessary.
        """
        thisx, thisy = 0.0, 0.0
        lines = self._get_wrapped_text().split("\n")  # Ensures lines is not empty.

        ws = []
        hs = []
        xs = []
        ys = []

        # Full vertical extent of font, including ascenders and descenders:
        _, lp_h, lp_d = _get_text_metrics_with_cache(
            renderer, "lp", self._fontproperties,
            ismath="TeX" if self.get_usetex() else False, dpi=self.figure.dpi)
        min_dy = (lp_h - lp_d) * self._linespacing

        for i, line in enumerate(lines):
            clean_line, ismath = self._preprocess_math(line)
            if clean_line:
>               w, h, d = _get_text_metrics_with_cache(
                    renderer, clean_line, self._fontproperties,
                    ismath=ismath, dpi=self.figure.dpi)

lib/matplotlib/text.py:350:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

renderer = <matplotlib.backends.backend_agg.RendererAgg object at 0x7f231f207da0>, text = '$ \\wrong{math} $', fontprop = <matplotlib.font_manager.FontProperties object at 0x7f2318084a70>, ismath = True, dpi = 80.0

    def _get_text_metrics_with_cache(renderer, text, fontprop, ismath, dpi):
        """Call ``renderer.get_text_width_height_descent``, caching the results."""
        # Cached based on a copy of fontprop so that later in-place mutations of
        # the passed-in argument do not mess up the cache.
>       return _get_text_metrics_with_cache_impl(
            weakref.ref(renderer), text, fontprop.copy(), ismath, dpi)

lib/matplotlib/text.py:69:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

renderer_ref = <weakref at 0x7f23183ce340; to 'RendererAgg' at 0x7f231f207da0>, text = '$ \\wrong{math} $', fontprop = <matplotlib.font_manager.FontProperties object at 0x7f231825bdd0>, ismath = True, dpi = 80.0

    @functools.lru_cache(4096)
    def _get_text_metrics_with_cache_impl(
            renderer_ref, text, fontprop, ismath, dpi):
        # dpi is unused, but participates in cache invalidation (via the renderer).
>       return renderer_ref().get_text_width_height_descent(text, fontprop, ismath)

lib/matplotlib/text.py:77:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <matplotlib.backends.backend_agg.RendererAgg object at 0x7f231f207da0>, s = '$ \\wrong{math} $', prop = <matplotlib.font_manager.FontProperties object at 0x7f231825bdd0>, ismath = True

    def get_text_width_height_descent(self, s, prop, ismath):
        # docstring inherited

        _api.check_in_list(["TeX", True, False], ismath=ismath)
        if ismath == "TeX":
            return super().get_text_width_height_descent(s, prop, ismath)

        if ismath:
            ox, oy, width, height, descent, font_image = \
>               self.mathtext_parser.parse(s, self.dpi, prop)

lib/matplotlib/backends/backend_agg.py:230:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <matplotlib.mathtext.MathTextParser object at 0x7f2318a1bc80>, s = '$ \\wrong{math} $', dpi = 80.0, prop = <matplotlib.font_manager.FontProperties object at 0x7f2318c4d9d0>

    def parse(self, s, dpi=72, prop=None):
        """
        Parse the given math expression *s* at the given *dpi*.  If *prop* is
        provided, it is a `.FontProperties` object specifying the "default"
        font to use in the math expression, used for all non-math text.

        The results are cached, so multiple calls to `parse`
        with the same expression should be fast.

        Depending on the *output* type, this returns either a `VectorParse` or
        a `RasterParse`.
        """
        # lru_cache can't decorate parse() directly because prop
        # is mutable; key the cache using an internal copy (see
        # text._get_text_metrics_with_cache for a similar case).
        prop = prop.copy() if prop is not None else None
>       return self._parse_cached(s, dpi, prop)

lib/matplotlib/mathtext.py:77:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <matplotlib.mathtext.MathTextParser object at 0x7f2318a1bc80>, s = '$ \\wrong{math} $', dpi = 80.0, prop = <matplotlib.font_manager.FontProperties object at 0x7f2318c4d9d0>

    @functools.lru_cache(50)
    def _parse_cached(self, s, dpi, prop):
        from matplotlib.backends import backend_agg

        if prop is None:
            prop = FontProperties()
        fontset_class = _api.check_getitem(
            self._font_type_mapping, fontset=prop.get_math_fontfamily())
        load_glyph_flags = {
            "vector": LOAD_NO_HINTING,
            "raster": backend_agg.get_hinting_flag(),
        }[self._output_type]
        fontset = fontset_class(prop, load_glyph_flags)

        fontsize = prop.get_size_in_points()

        if self._parser is None:  # Cache the parser globally.
            self.__class__._parser = _mathtext.Parser()

>       box = self._parser.parse(s, fontset, fontsize, dpi)

lib/matplotlib/mathtext.py:98:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <matplotlib._mathtext.Parser object at 0x7f232911e540>, s = '$ \\wrong{math} $', fonts_object = <matplotlib._mathtext.BakomaFonts object at 0x7f2318259670>, fontsize = 12.0, dpi = 80.0

    def parse(self, s, fonts_object, fontsize, dpi):
        """
        Parse expression *s* using the given *fonts_object* for
        output, at the given *fontsize* and *dpi*.

        Returns the parse tree of `Node` instances.
        """
        self._state_stack = [
            ParserState(fonts_object, 'default', 'rm', fontsize, dpi)]
        self._em_width_cache = {}
        try:
            result = self._expression.parseString(s)
        except ParseBaseException as err:
            # explain becomes a plain method on pyparsing 3 (err.explain(0)).
>           raise ValueError("\n" + ParseException.explain(err, 0)) from None
E           ValueError:
E            \wrong{math}
E            ^
E           ParseFatalException: Expected token, found '\'  (at char 1), (line:1, col:2)

lib/matplotlib/_mathtext.py:1991: ValueError

During handling of the above exception, another exception occurred:

    def test_parse_math_rcparams():
        # Default is True
        fig, ax = plt.subplots()
        ax.text(0, 0, r"$ \wrong{math} $")
>       with pytest.raises(ValueError, match='Unknown symbol'):
E       AssertionError: Regex pattern did not match.
E        Regex: 'Unknown symbol'
E        Input: "\n \\wrong{math} \n ^\nParseFatalException: Expected token, found '\\'  (at char 1), (line:1, col:2)"

lib/matplotlib/tests/test_text.py:835: AssertionError

that appear to be pyparsing or pytest doing something a bit wild and not escaping \ properly.

@QuLogic
Copy link
Member

QuLogic commented Aug 23, 2023

Also FYI, on Fedora, which has 3.12 in Rawhide, I don't have any of these failures with 3.8.0rc1. I think this just needs a rebase.

@oscargus oscargus force-pushed the py312 branch 3 times, most recently from 330ebca to db5f2d7 Compare August 24, 2023 08:55
@oscargus oscargus force-pushed the py312 branch 2 times, most recently from b95b30c to 436713a Compare August 24, 2023 09:25
@oscargus
Copy link
Member Author

I had to change to no-build-isolation to not pull in numpy 1.25 during installation. This means that the scheduled tests are not installing Matplotlib using the pre-release NumPy. I guess that is not really the purpose?

@oscargus oscargus marked this pull request as ready for review August 24, 2023 11:01
@oscargus oscargus added the CI: testing CI configuration and testing label Aug 24, 2023
@oscargus
Copy link
Member Author

Not sure if I somehow broke the Mac-test or if it is intermittent?

Apart from that, I think this is good to go.

@QuLogic
Copy link
Member

QuLogic commented Aug 26, 2023

The macOS failure is intermittent; skipped in #24597.

@timhoffm timhoffm merged commit a04f0bf into matplotlib:main Aug 28, 2023
@oscargus oscargus deleted the py312 branch August 28, 2023 09:51
@oscargus
Copy link
Member Author

Should this possibly be backported to 3.8?

@QuLogic QuLogic added this to the v3.8.0 milestone Aug 28, 2023
@QuLogic
Copy link
Member

QuLogic commented Aug 28, 2023

@meeseeksdev backport to v3.8.x

meeseeksmachine pushed a commit to meeseeksmachine/matplotlib that referenced this pull request Aug 28, 2023
QuLogic added a commit that referenced this pull request Aug 28, 2023
…711-on-v3.8.x

Backport PR #24711 on branch v3.8.x (Test with Python 3.12)
@ksunden ksunden mentioned this pull request Sep 15, 2023
5 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
CI: testing CI configuration and testing
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants