Skip to content
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

Build Python 3.13 wheels #461

Merged
merged 9 commits into from
Oct 7, 2024
Merged

Build Python 3.13 wheels #461

merged 9 commits into from
Oct 7, 2024

Conversation

edgarrmondragon
Copy link
Contributor

@edgarrmondragon edgarrmondragon commented Aug 18, 2024

Python 3.13 RC1 was released recently1:

We strongly encourage maintainers of third-party Python projects to prepare their projects for 3.13 compatibilities during this phase, and where necessary publish Python 3.13 wheels on PyPI to be ready for the final release of 3.13.0. Any binary wheels built against Python 3.13.0rc1 will work with future versions of Python 3.13. As always, report any issues to the Python bug tracker .

It'd be really nice to have wheels to start testing applications that use MarkupSafe before the eventual final release.

Thanks!

PS: This PR is only for GIL-enabled 3.13 wheels and not free-threaded ones2, which will certainly involve a higher level of effort.

Related: #460

Footnotes

  1. https://discuss.python.org/t/python-3-13-0-release-candidate-1-released/59703

  2. https://docs.python.org/3.13/whatsnew/3.13.html#free-threaded-cpython

@edgarrmondragon edgarrmondragon marked this pull request as ready for review August 18, 2024 17:39
@edgarrmondragon edgarrmondragon changed the title Build Python 3.13 wheels (non free-threaded) only for testing Build Python 3.13 wheels (non free-threaded) Aug 18, 2024
@davidism
Copy link
Member

davidism commented Aug 18, 2024

Thanks. However, I don't plan to merge this without free threading handled as well, as that would just make more work for me later on to try to figure out how to upload a new build for the same MarkupSafe and Python version, something my publish automation is not set up for.

From the linked documentation in #460, it doesn't seem like much additional work, but as I said there I won't have time to work on it soon. So if you can get it in here, that's the way to move this forward.

@edgarrmondragon
Copy link
Contributor Author

From the linked documentation in #460, it doesn't seem like much additional work, but as I said there I won't have time to work on it soon. So if you can get it in here, that's the way to move this forward.

Gotcha, thanks for replying! I'll try to get the free-threaded stuff in this PR and ping you back when it's ready.

@edgarrmondragon edgarrmondragon changed the title Build Python 3.13 wheels (non free-threaded) Build Python 3.13 wheels Sep 27, 2024
@edgarrmondragon
Copy link
Contributor Author

@davidism I've added free-threaded Python 3.13 to the test matrix, and set CIBW_FREE_THREADED_SUPPORT=1 to build the cp313t-* wheels (see passing workflow).

@dairiki
Copy link
Contributor

dairiki commented Sep 27, 2024

@davidism I've added free-threaded Python 3.13 to the test matrix, and set CIBW_FREE_THREADED_SUPPORT=1 to build the cp313t-* wheels (see passing workflow).

There's more to it than that: Any extension modules should declare whether they support running with the GIL disabled. Our extension module is markupsafe._speedups. [edit: typo cruft deleted] @AA-Turner has provided good pointers about how to do this in #460 (In particular, see this comment).

I have attempted that in #462. That PR also enables CI tests under 3.13t both on Linux and Windows. (It is still unclear — to me at least — how to test under 3.13t on the macOS runner.)
Unfortunately, the tests under Windows fail to run for reasons I can not claim to understand.

@edgarrmondragon
Copy link
Contributor Author

Thanks @dairiki, I've brought in the initialization change. Let's indeed hope someone gets to actions/setup-python#771 🤞.

@@ -14,6 +15,11 @@
_speedups = None # type: ignore


def pytest_report_header() -> list[str]:
"""Return a list of strings to be displayed in the header of the report."""
return [f"Free-threaded: {bool(sysconfig.get_config_var('Py_GIL_DISABLED'))}"]
Copy link
Contributor

@dairiki dairiki Sep 28, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could sys._is_gil_disabled() be of more interest here?

As I understand it Py_GIL_DISABLED tells whether --disable-gil was set at python build time.
Even for --disable-gil builds, the PYTHONGIL environment variable or loading of extension modules without a valid Py_mod_gil slot can cause the GIL to be enabled. _is_gil_disabled() tells whether the GIL is actually in use or not. (This seems more of interest when interpreting test results.)

@davidism
Copy link
Member

davidism commented Oct 6, 2024

I can't get this to do the right thing on my local Mac. I have 3.13.0rc3 installed with the official installer, including the free-threaded build. python3.13t is available separately from python3.13, and does not require setting PYTHON_GIL=0 to enable free threading.

I needed to add the following to tox to get it to recognize a py313t env:

[testenv:py313t]
base_python = python3.13t
$ tox r -e py313t
output
PYTHON_GIL=0 tox r -e py313t
py313t: install_deps> python -I -m pip install -r requirements/tests.txt
py313t: freeze> python -m pip freeze --all
.pkg-cpython313: install_requires> python -I -m pip install setuptools
.pkg-cpython313: _optional_hooks> python /Users/david/Projects/markupsafe/.venv/lib/python3.12/site-packages/pyproject_api/_backend.py True setuptools.build_meta
.pkg-cpython313: get_requires_for_build_wheel> python /Users/david/Projects/markupsafe/.venv/lib/python3.12/site-packages/pyproject_api/_backend.py True setuptools.build_meta
.pkg-cpython313: build_wheel> python /Users/david/Projects/markupsafe/.venv/lib/python3.12/site-packages/pyproject_api/_backend.py True setuptools.build_meta
py313t: install_package> python -I -m pip install --force-reinstall --no-deps /Users/david/Projects/markupsafe/.tox/.tmp/package/1/MarkupSafe-3.0.0.dev0-cp313-cp313-macosx_10_13_universal2.whl
py313t: commands[0]> pytest -v --tb=short --basetemp=/Users/david/Projects/markupsafe/.tox/py313t/tmp
======================================================================================================= test session starts =======================================================================================================
platform darwin -- Python 3.13.0rc3, pytest-8.3.2, pluggy-1.5.0 -- /Users/david/Projects/markupsafe/.tox/py313t/bin/python
cachedir: .tox/py313t/.pytest_cache
Free-threaded: True
rootdir: /Users/david/Projects/markupsafe
configfile: pyproject.toml
testpaths: tests
collected 74 items                                                                                                                                                                                                                

tests/test_escape.py::test_escape[markupsafe._native--] PASSED                                                                                                                                                              [  1%]
tests/test_escape.py::test_escape[markupsafe._native-abcd&><'"efgh-abcd&amp;&gt;&lt;&#39;&#34;efgh] PASSED                                                                                                                  [  2%]
tests/test_escape.py::test_escape[markupsafe._native-&><'"efgh-&amp;&gt;&lt;&#39;&#34;efgh] PASSED                                                                                                                          [  4%]
tests/test_escape.py::test_escape[markupsafe._native-abcd&><'"-abcd&amp;&gt;&lt;&#39;&#34;] PASSED                                                                                                                          [  5%]
tests/test_escape.py::test_escape[markupsafe._native-\u3053\u3093\u306b\u3061\u306f&><'"\u3053\u3093\u3070\u3093\u306f-\u3053\u3093\u306b\u3061\u306f&amp;&gt;&lt;&#39;&#34;\u3053\u3093\u3070\u3093\u306f] PASSED          [  6%]
tests/test_escape.py::test_escape[markupsafe._native-&><'"\u3053\u3093\u3070\u3093\u306f-&amp;&gt;&lt;&#39;&#34;\u3053\u3093\u3070\u3093\u306f] PASSED                                                                      [  8%]
tests/test_escape.py::test_escape[markupsafe._native-\u3053\u3093\u306b\u3061\u306f&><'"-\u3053\u3093\u306b\u3061\u306f&amp;&gt;&lt;&#39;&#34;] PASSED                                                                      [  9%]
tests/test_escape.py::test_escape[markupsafe._native-\U0001f363\U0001f362&><'"\U0001f37a xyz-\U0001f363\U0001f362&amp;&gt;&lt;&#39;&#34;\U0001f37a xyz] PASSED                                                              [ 10%]
tests/test_escape.py::test_escape[markupsafe._native-&><'"\U0001f37a xyz-&amp;&gt;&lt;&#39;&#34;\U0001f37a xyz] PASSED                                                                                                      [ 12%]
tests/test_escape.py::test_escape[markupsafe._native-\U0001f363\U0001f362&><'"-\U0001f363\U0001f362&amp;&gt;&lt;&#39;&#34;] PASSED                                                                                          [ 13%]
tests/test_exception_custom_html.py::test_exception_custom_html[markupsafe._native] PASSED                                                                                                                                  [ 14%]
tests/test_leak.py::test_markup_leaks[markupsafe._native] PASSED                                                                                                                                                            [ 16%]
tests/test_markupsafe.py::test_adding[markupsafe._native] PASSED                                                                                                                                                            [ 17%]
tests/test_markupsafe.py::test_string_interpolation[markupsafe._native-<em>%s</em>-<bad user>-<em>&lt;bad user&gt;</em>] PASSED                                                                                             [ 18%]
tests/test_markupsafe.py::test_string_interpolation[markupsafe._native-<em>%(username)s</em>-data1-<em>&lt;bad user&gt;</em>] PASSED                                                                                        [ 20%]
tests/test_markupsafe.py::test_string_interpolation[markupsafe._native-%i-3.14-3] PASSED                                                                                                                                    [ 21%]
tests/test_markupsafe.py::test_string_interpolation[markupsafe._native-%.2f-3.14-3.14] PASSED                                                                                                                               [ 22%]
tests/test_markupsafe.py::test_type_behavior[markupsafe._native] PASSED                                                                                                                                                     [ 24%]
tests/test_markupsafe.py::test_html_interop[markupsafe._native] PASSED                                                                                                                                                      [ 25%]
tests/test_markupsafe.py::test_missing_interpol[markupsafe._native-foo] PASSED                                                                                                                                              [ 27%]
tests/test_markupsafe.py::test_missing_interpol[markupsafe._native-42] PASSED                                                                                                                                               [ 28%]
tests/test_markupsafe.py::test_missing_interpol[markupsafe._native-args2] PASSED                                                                                                                                            [ 29%]
tests/test_markupsafe.py::test_tuple_interpol[markupsafe._native] PASSED                                                                                                                                                    [ 31%]
tests/test_markupsafe.py::test_dict_interpol[markupsafe._native] PASSED                                                                                                                                                     [ 32%]
tests/test_markupsafe.py::test_escaping[markupsafe._native] PASSED                                                                                                                                                          [ 33%]
tests/test_markupsafe.py::test_unescape[markupsafe._native] PASSED                                                                                                                                                          [ 35%]
tests/test_markupsafe.py::test_format[markupsafe._native] PASSED                                                                                                                                                            [ 36%]
tests/test_markupsafe.py::test_format_map[markupsafe._native] PASSED                                                                                                                                                        [ 37%]
tests/test_markupsafe.py::test_formatting_empty[markupsafe._native] PASSED                                                                                                                                                  [ 39%]
tests/test_markupsafe.py::test_custom_formatting[markupsafe._native] PASSED                                                                                                                                                 [ 40%]
tests/test_markupsafe.py::test_complex_custom_formatting[markupsafe._native] PASSED                                                                                                                                         [ 41%]
tests/test_markupsafe.py::test_formatting_with_objects[markupsafe._native] PASSED                                                                                                                                           [ 43%]
tests/test_markupsafe.py::test_escape_silent[markupsafe._native] PASSED                                                                                                                                                     [ 44%]
tests/test_markupsafe.py::test_splitting[markupsafe._native] PASSED                                                                                                                                                         [ 45%]
tests/test_markupsafe.py::test_mul[markupsafe._native] PASSED                                                                                                                                                               [ 47%]
tests/test_markupsafe.py::test_escape_return_type[markupsafe._native] PASSED                                                                                                                                                [ 48%]
tests/test_markupsafe.py::test_soft_str[markupsafe._native] PASSED                                                                                                                                                          [ 50%]
tests/test_escape.py::test_escape[None--] SKIPPED (speedups unavailable)                                                                                                                                                    [ 51%]
tests/test_escape.py::test_escape[None-abcd&><'"efgh-abcd&amp;&gt;&lt;&#39;&#34;efgh] SKIPPED (speedups unavailable)                                                                                                        [ 52%]
tests/test_escape.py::test_escape[None-&><'"efgh-&amp;&gt;&lt;&#39;&#34;efgh] SKIPPED (speedups unavailable)                                                                                                                [ 54%]
tests/test_escape.py::test_escape[None-abcd&><'"-abcd&amp;&gt;&lt;&#39;&#34;] SKIPPED (speedups unavailable)                                                                                                                [ 55%]
tests/test_escape.py::test_escape[None-\u3053\u3093\u306b\u3061\u306f&><'"\u3053\u3093\u3070\u3093\u306f-\u3053\u3093\u306b\u3061\u306f&amp;&gt;&lt;&#39;&#34;\u3053\u3093\u3070\u3093\u306f] SKIPPED (speedups unavail...) [ 56%]
tests/test_escape.py::test_escape[None-&><'"\u3053\u3093\u3070\u3093\u306f-&amp;&gt;&lt;&#39;&#34;\u3053\u3093\u3070\u3093\u306f] SKIPPED (speedups unavailable)                                                            [ 58%]
tests/test_escape.py::test_escape[None-\u3053\u3093\u306b\u3061\u306f&><'"-\u3053\u3093\u306b\u3061\u306f&amp;&gt;&lt;&#39;&#34;] SKIPPED (speedups unavailable)                                                            [ 59%]
tests/test_escape.py::test_escape[None-\U0001f363\U0001f362&><'"\U0001f37a xyz-\U0001f363\U0001f362&amp;&gt;&lt;&#39;&#34;\U0001f37a xyz] SKIPPED (speedups unavailable)                                                    [ 60%]
tests/test_escape.py::test_escape[None-&><'"\U0001f37a xyz-&amp;&gt;&lt;&#39;&#34;\U0001f37a xyz] SKIPPED (speedups unavailable)                                                                                            [ 62%]
tests/test_escape.py::test_escape[None-\U0001f363\U0001f362&><'"-\U0001f363\U0001f362&amp;&gt;&lt;&#39;&#34;] SKIPPED (speedups unavailable)                                                                                [ 63%]
tests/test_exception_custom_html.py::test_exception_custom_html[None] SKIPPED (speedups unavailable)                                                                                                                        [ 64%]
tests/test_leak.py::test_markup_leaks[None] SKIPPED (speedups unavailable)                                                                                                                                                  [ 66%]
tests/test_markupsafe.py::test_adding[None] SKIPPED (speedups unavailable)                                                                                                                                                  [ 67%]
tests/test_markupsafe.py::test_string_interpolation[None-<em>%s</em>-<bad user>-<em>&lt;bad user&gt;</em>] SKIPPED (speedups unavailable)                                                                                   [ 68%]
tests/test_markupsafe.py::test_string_interpolation[None-<em>%(username)s</em>-data1-<em>&lt;bad user&gt;</em>] SKIPPED (speedups unavailable)                                                                              [ 70%]
tests/test_markupsafe.py::test_string_interpolation[None-%i-3.14-3] SKIPPED (speedups unavailable)                                                                                                                          [ 71%]
tests/test_markupsafe.py::test_string_interpolation[None-%.2f-3.14-3.14] SKIPPED (speedups unavailable)                                                                                                                     [ 72%]
tests/test_markupsafe.py::test_type_behavior[None] SKIPPED (speedups unavailable)                                                                                                                                           [ 74%]
tests/test_markupsafe.py::test_html_interop[None] SKIPPED (speedups unavailable)                                                                                                                                            [ 75%]
tests/test_markupsafe.py::test_missing_interpol[None-foo] SKIPPED (speedups unavailable)                                                                                                                                    [ 77%]
tests/test_markupsafe.py::test_missing_interpol[None-42] SKIPPED (speedups unavailable)                                                                                                                                     [ 78%]
tests/test_markupsafe.py::test_missing_interpol[None-args2] SKIPPED (speedups unavailable)                                                                                                                                  [ 79%]
tests/test_markupsafe.py::test_tuple_interpol[None] SKIPPED (speedups unavailable)                                                                                                                                          [ 81%]
tests/test_markupsafe.py::test_dict_interpol[None] SKIPPED (speedups unavailable)                                                                                                                                           [ 82%]
tests/test_markupsafe.py::test_escaping[None] SKIPPED (speedups unavailable)                                                                                                                                                [ 83%]
tests/test_markupsafe.py::test_unescape[None] SKIPPED (speedups unavailable)                                                                                                                                                [ 85%]
tests/test_markupsafe.py::test_format[None] SKIPPED (speedups unavailable)                                                                                                                                                  [ 86%]
tests/test_markupsafe.py::test_format_map[None] SKIPPED (speedups unavailable)                                                                                                                                              [ 87%]
tests/test_markupsafe.py::test_formatting_empty[None] SKIPPED (speedups unavailable)                                                                                                                                        [ 89%]
tests/test_markupsafe.py::test_custom_formatting[None] SKIPPED (speedups unavailable)                                                                                                                                       [ 90%]
tests/test_markupsafe.py::test_complex_custom_formatting[None] SKIPPED (speedups unavailable)                                                                                                                               [ 91%]
tests/test_markupsafe.py::test_formatting_with_objects[None] SKIPPED (speedups unavailable)                                                                                                                                 [ 93%]
tests/test_markupsafe.py::test_escape_silent[None] SKIPPED (speedups unavailable)                                                                                                                                           [ 94%]
tests/test_markupsafe.py::test_splitting[None] SKIPPED (speedups unavailable)                                                                                                                                               [ 95%]
tests/test_markupsafe.py::test_mul[None] SKIPPED (speedups unavailable)                                                                                                                                                     [ 97%]
tests/test_markupsafe.py::test_escape_return_type[None] SKIPPED (speedups unavailable)                                                                                                                                      [ 98%]
tests/test_markupsafe.py::test_soft_str[None] SKIPPED (speedups unavailable)                                                                                                                                                [100%]

================================================================================================= 37 passed, 37 skipped in 0.13s ==================================================================================================
  py313t: OK (5.76=setup[5.22]+cmd[0.54] seconds)
  congratulations :) (5.89 seconds)

You can see in the output that free threading is enabled. However, this fails to build the speedups correctly, the wheel gets tagged as 313 not 313t. Therefore the speedups aren't available and those tests are skipped.

Now clearly this is working in the CI tests, but I can't figure out why it's completely different than local. First, you don't specify a separate python3.13t, PYTHON_GIL=0 python3.13 seems to be doing the equivalent of python3.13t, which is not true locally and seems incorrect. Second, it's correctly tagging the 313t wheel. If I manually create a 3.13t virtualenv, the correct wheel is built and pytest doesn't skip anything. Is this some bug with the Mac Python? Is it a difference between Mac vs Linux?

@davidism
Copy link
Member

davidism commented Oct 6, 2024

cc @hugovk since you seem to know a lot about testing the free-threaded build: https://dev.to/hugovk/help-us-test-free-threaded-python-without-the-gil-1hgf 🤔 any chance you can explain what's going on?

@AA-Turner
Copy link

What version of setuptools is the wheel build using? I think it got support for the t suffix in v70.2.

@hugovk
Copy link
Contributor

hugovk commented Oct 6, 2024

Thanks. However, I don't plan to merge this without free threading handled as well, as that would just make more work for me later on to try to figure out how to upload a new build for the same MarkupSafe and Python version, something my publish automation is not set up for.

I think it's better to release regular 3.13 wheels as normal, to unblock regular use, and only add free-threading later. Python 3.13.0 final is scheduled for tomorrow, so it would be really good if binary wheels are available. Free-threading is still experimental, so a delay for free-threading is okay.

cc @hugovk since you seem to know a lot about testing the free-threaded build: dev.to/hugovk/help-us-test-free-threaded-python-without-the-gil-1hgf 🤔 any chance you can explain what's going on?

Hmm, I think it's something to do with the tox config. On macOS, I can install and test okay without tox:

python3.13t --version --version
Python 3.13.0rc3 experimental free-threading build (v3.13.0rc3:fae84c70fbd, Oct  1 2024, 00:22:06) [Clang 15.0.0 (clang-1500.3.9.4)]python3.13t -m pip install -e .
Obtaining file:///private/tmp/markupsafe
  Installing build dependencies ... done
  Checking if build backend supports build_editable ... done
  Getting requirements to build editable ... done
  Preparing editable metadata (pyproject.toml) ... done
Building wheels for collected packages: MarkupSafe
  Building editable for MarkupSafe (pyproject.toml) ... done
  Created wheel for MarkupSafe: filename=MarkupSafe-3.0.0.dev0-0.editable-cp313-cp313t-macosx_10_13_universal2.whl size=4013 sha256=32b458f7421af07da58ea4219f0d96cff0088ffbfbc0be7fb54fc154345a4ca5
  Stored in directory: /private/var/folders/p6/lf2s1s5d4kb335g2n1td8z8c0000gn/T/pip-ephem-wheel-cache-um2nxb9l/wheels/fe/79/54/456dc68def78a5f343e828d62061f1d8f5ca9416f55591f24e
Successfully built MarkupSafe
Installing collected packages: MarkupSafe
Successfully installed MarkupSafe-3.0.0.dev0python3.13t -m pytest -v
===================================================================== test session starts =====================================================================
platform darwin -- Python 3.13.0rc3, pytest-8.3.3, pluggy-1.5.0 -- /usr/local/bin/python3.13t
cachedir: .pytest_cache
Free-threaded: True
rootdir: /private/tmp/markupsafe
configfile: pyproject.toml
testpaths: tests
collected 74 items

tests/test_escape.py::test_escape[markupsafe._native--] PASSED                                                                                          [  1%]
tests/test_escape.py::test_escape[markupsafe._native-abcd&><'"efgh-abcd&amp;&gt;&lt;&#39;&#34;efgh] PASSED                                              [  2%]
tests/test_escape.py::test_escape[markupsafe._native-&><'"efgh-&amp;&gt;&lt;&#39;&#34;efgh] PASSED                                                      [  4%]
tests/test_escape.py::test_escape[markupsafe._native-abcd&><'"-abcd&amp;&gt;&lt;&#39;&#34;] PASSED                                                      [  5%]
tests/test_escape.py::test_escape[markupsafe._native-\u3053\u3093\u306b\u3061\u306f&><'"\u3053\u3093\u3070\u3093\u306f-\u3053\u3093\u306b\u3061\u306f&amp;&gt;&lt;&#39;&#34;\u3053\u3093\u3070\u3093\u306f] PASSED [  6%]
tests/test_escape.py::test_escape[markupsafe._native-&><'"\u3053\u3093\u3070\u3093\u306f-&amp;&gt;&lt;&#39;&#34;\u3053\u3093\u3070\u3093\u306f] PASSED  [  8%]
tests/test_escape.py::test_escape[markupsafe._native-\u3053\u3093\u306b\u3061\u306f&><'"-\u3053\u3093\u306b\u3061\u306f&amp;&gt;&lt;&#39;&#34;] PASSED  [  9%]
tests/test_escape.py::test_escape[markupsafe._native-\U0001f363\U0001f362&><'"\U0001f37a xyz-\U0001f363\U0001f362&amp;&gt;&lt;&#39;&#34;\U0001f37a xyz] PASSED [ 10%]
tests/test_escape.py::test_escape[markupsafe._native-&><'"\U0001f37a xyz-&amp;&gt;&lt;&#39;&#34;\U0001f37a xyz] PASSED                                  [ 12%]
tests/test_escape.py::test_escape[markupsafe._native-\U0001f363\U0001f362&><'"-\U0001f363\U0001f362&amp;&gt;&lt;&#39;&#34;] PASSED                      [ 13%]
tests/test_exception_custom_html.py::test_exception_custom_html[markupsafe._native] PASSED                                                              [ 14%]
tests/test_leak.py::test_markup_leaks[markupsafe._native] PASSED                                                                                        [ 16%]
tests/test_markupsafe.py::test_adding[markupsafe._native] PASSED                                                                                        [ 17%]
tests/test_markupsafe.py::test_string_interpolation[markupsafe._native-<em>%s</em>-<bad user>-<em>&lt;bad user&gt;</em>] PASSED                         [ 18%]
tests/test_markupsafe.py::test_string_interpolation[markupsafe._native-<em>%(username)s</em>-data1-<em>&lt;bad user&gt;</em>] PASSED                    [ 20%]
tests/test_markupsafe.py::test_string_interpolation[markupsafe._native-%i-3.14-3] PASSED                                                                [ 21%]
tests/test_markupsafe.py::test_string_interpolation[markupsafe._native-%.2f-3.14-3.14] PASSED                                                           [ 22%]
tests/test_markupsafe.py::test_type_behavior[markupsafe._native] PASSED                                                                                 [ 24%]
tests/test_markupsafe.py::test_html_interop[markupsafe._native] PASSED                                                                                  [ 25%]
tests/test_markupsafe.py::test_missing_interpol[markupsafe._native-foo] PASSED                                                                          [ 27%]
tests/test_markupsafe.py::test_missing_interpol[markupsafe._native-42] PASSED                                                                           [ 28%]
tests/test_markupsafe.py::test_missing_interpol[markupsafe._native-args2] PASSED                                                                        [ 29%]
tests/test_markupsafe.py::test_tuple_interpol[markupsafe._native] PASSED                                                                                [ 31%]
tests/test_markupsafe.py::test_dict_interpol[markupsafe._native] PASSED                                                                                 [ 32%]
tests/test_markupsafe.py::test_escaping[markupsafe._native] PASSED                                                                                      [ 33%]
tests/test_markupsafe.py::test_unescape[markupsafe._native] PASSED                                                                                      [ 35%]
tests/test_markupsafe.py::test_format[markupsafe._native] PASSED                                                                                        [ 36%]
tests/test_markupsafe.py::test_format_map[markupsafe._native] PASSED                                                                                    [ 37%]
tests/test_markupsafe.py::test_formatting_empty[markupsafe._native] PASSED                                                                              [ 39%]
tests/test_markupsafe.py::test_custom_formatting[markupsafe._native] PASSED                                                                             [ 40%]
tests/test_markupsafe.py::test_complex_custom_formatting[markupsafe._native] PASSED                                                                     [ 41%]
tests/test_markupsafe.py::test_formatting_with_objects[markupsafe._native] PASSED                                                                       [ 43%]
tests/test_markupsafe.py::test_escape_silent[markupsafe._native] PASSED                                                                                 [ 44%]
tests/test_markupsafe.py::test_splitting[markupsafe._native] PASSED                                                                                     [ 45%]
tests/test_markupsafe.py::test_mul[markupsafe._native] PASSED                                                                                           [ 47%]
tests/test_markupsafe.py::test_escape_return_type[markupsafe._native] PASSED                                                                            [ 48%]
tests/test_markupsafe.py::test_soft_str[markupsafe._native] PASSED                                                                                      [ 50%]
tests/test_escape.py::test_escape[markupsafe._speedups--] PASSED                                                                                        [ 51%]
tests/test_escape.py::test_escape[markupsafe._speedups-abcd&><'"efgh-abcd&amp;&gt;&lt;&#39;&#34;efgh] PASSED                                            [ 52%]
tests/test_escape.py::test_escape[markupsafe._speedups-&><'"efgh-&amp;&gt;&lt;&#39;&#34;efgh] PASSED                                                    [ 54%]
tests/test_escape.py::test_escape[markupsafe._speedups-abcd&><'"-abcd&amp;&gt;&lt;&#39;&#34;] PASSED                                                    [ 55%]
tests/test_escape.py::test_escape[markupsafe._speedups-\u3053\u3093\u306b\u3061\u306f&><'"\u3053\u3093\u3070\u3093\u306f-\u3053\u3093\u306b\u3061\u306f&amp;&gt;&lt;&#39;&#34;\u3053\u3093\u3070\u3093\u306f] PASSED [ 56%]
tests/test_escape.py::test_escape[markupsafe._speedups-&><'"\u3053\u3093\u3070\u3093\u306f-&amp;&gt;&lt;&#39;&#34;\u3053\u3093\u3070\u3093\u306f] PASSED [ 58%]
tests/test_escape.py::test_escape[markupsafe._speedups-\u3053\u3093\u306b\u3061\u306f&><'"-\u3053\u3093\u306b\u3061\u306f&amp;&gt;&lt;&#39;&#34;] PASSED [ 59%]
tests/test_escape.py::test_escape[markupsafe._speedups-\U0001f363\U0001f362&><'"\U0001f37a xyz-\U0001f363\U0001f362&amp;&gt;&lt;&#39;&#34;\U0001f37a xyz] PASSED [ 60%]
tests/test_escape.py::test_escape[markupsafe._speedups-&><'"\U0001f37a xyz-&amp;&gt;&lt;&#39;&#34;\U0001f37a xyz] PASSED                                [ 62%]
tests/test_escape.py::test_escape[markupsafe._speedups-\U0001f363\U0001f362&><'"-\U0001f363\U0001f362&amp;&gt;&lt;&#39;&#34;] PASSED                    [ 63%]
tests/test_exception_custom_html.py::test_exception_custom_html[markupsafe._speedups] PASSED                                                            [ 64%]
tests/test_leak.py::test_markup_leaks[markupsafe._speedups] PASSED                                                                                      [ 66%]
tests/test_markupsafe.py::test_adding[markupsafe._speedups] PASSED                                                                                      [ 67%]
tests/test_markupsafe.py::test_string_interpolation[markupsafe._speedups-<em>%s</em>-<bad user>-<em>&lt;bad user&gt;</em>] PASSED                       [ 68%]
tests/test_markupsafe.py::test_string_interpolation[markupsafe._speedups-<em>%(username)s</em>-data1-<em>&lt;bad user&gt;</em>] PASSED                  [ 70%]
tests/test_markupsafe.py::test_string_interpolation[markupsafe._speedups-%i-3.14-3] PASSED                                                              [ 71%]
tests/test_markupsafe.py::test_string_interpolation[markupsafe._speedups-%.2f-3.14-3.14] PASSED                                                         [ 72%]
tests/test_markupsafe.py::test_type_behavior[markupsafe._speedups] PASSED                                                                               [ 74%]
tests/test_markupsafe.py::test_html_interop[markupsafe._speedups] PASSED                                                                                [ 75%]
tests/test_markupsafe.py::test_missing_interpol[markupsafe._speedups-foo] PASSED                                                                        [ 77%]
tests/test_markupsafe.py::test_missing_interpol[markupsafe._speedups-42] PASSED                                                                         [ 78%]
tests/test_markupsafe.py::test_missing_interpol[markupsafe._speedups-args2] PASSED                                                                      [ 79%]
tests/test_markupsafe.py::test_tuple_interpol[markupsafe._speedups] PASSED                                                                              [ 81%]
tests/test_markupsafe.py::test_dict_interpol[markupsafe._speedups] PASSED                                                                               [ 82%]
tests/test_markupsafe.py::test_escaping[markupsafe._speedups] PASSED                                                                                    [ 83%]
tests/test_markupsafe.py::test_unescape[markupsafe._speedups] PASSED                                                                                    [ 85%]
tests/test_markupsafe.py::test_format[markupsafe._speedups] PASSED                                                                                      [ 86%]
tests/test_markupsafe.py::test_format_map[markupsafe._speedups] PASSED                                                                                  [ 87%]
tests/test_markupsafe.py::test_formatting_empty[markupsafe._speedups] PASSED                                                                            [ 89%]
tests/test_markupsafe.py::test_custom_formatting[markupsafe._speedups] PASSED                                                                           [ 90%]
tests/test_markupsafe.py::test_complex_custom_formatting[markupsafe._speedups] PASSED                                                                   [ 91%]
tests/test_markupsafe.py::test_formatting_with_objects[markupsafe._speedups] PASSED                                                                     [ 93%]
tests/test_markupsafe.py::test_escape_silent[markupsafe._speedups] PASSED                                                                               [ 94%]
tests/test_markupsafe.py::test_splitting[markupsafe._speedups] PASSED                                                                                   [ 95%]
tests/test_markupsafe.py::test_mul[markupsafe._speedups] PASSED                                                                                         [ 97%]
tests/test_markupsafe.py::test_escape_return_type[markupsafe._speedups] PASSED                                                                          [ 98%]
tests/test_markupsafe.py::test_soft_str[markupsafe._speedups] PASSED                                                                                    [100%]

===================================================================== 74 passed in 0.15s ======================================================================

But with the above with tox:

PYTHON_GIL=0 tox r -e py313t
Fatal Python error: config_read_gil: Disabling the GIL is not supported by this build
Python runtime state: preinitializedtox r -e py313t
.pkg: _optional_hooks> python /Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/site-packages/pyproject_api/_backend.py True setuptools.build_meta
.pkg: get_requires_for_build_wheel> python /Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/site-packages/pyproject_api/_backend.py True setuptools.build_meta
.pkg: build_wheel> python /Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/site-packages/pyproject_api/_backend.py True setuptools.build_meta
py313t: install_package> python -I -m pip install --force-reinstall --no-deps /private/tmp/markupsafe/.tox/.tmp/package/8/MarkupSafe-3.0.0.dev0-cp313-cp313-macosx_10_13_universal2.whl
ERROR: MarkupSafe-3.0.0.dev0-cp313-cp313-macosx_10_13_universal2.whl is not a supported wheel on this platform.

py313t: exit 1 (0.88 seconds) /private/tmp/markupsafe> python -I -m pip install --force-reinstall --no-deps /private/tmp/markupsafe/.tox/.tmp/package/8/MarkupSafe-3.0.0.dev0-cp313-cp313-macosx_10_13_universal2.whl pid=91457
  py313t: FAIL code 1 (1.64 seconds)
  evaluation failed :( (1.80 seconds)

Without tox we get MarkupSafe-3.0.0.dev0-0.editable-cp313-cp313t-macosx_10_13_universal2.whl (with cp313t).

With tox we get MarkupSafe-3.0.0.dev0-cp313-cp313-macosx_10_13_universal2.whl (no cp313t).

@davidism
Copy link
Member

davidism commented Oct 6, 2024

Yeah, that's what I saw too, but weirdly tox does work in CI.

I do plan to release something today, I know that 3.13 releases tomorrow. I think I might go with this PR since it does seem to work. I confirmed that tests for 3.13t pass manually on Linux, Mac, and Windows.

@hugovk
Copy link
Contributor

hugovk commented Oct 6, 2024

Yep, not supported by tox yet, waiting for virtualenv support first:

@davidism
Copy link
Member

davidism commented Oct 6, 2024

Never mind, it seems to just segfault if I try pytest in a 3.13t env on Windows, not sure how to deal with that. I think I'll split out the ifdef change, and remove the 3.13t wheel building for now. That way it can build from sdist until we can sort out wheels and testing on all platforms.

@davidism
Copy link
Member

davidism commented Oct 6, 2024

#462 (comment) I tried installing the wheel that cibuildwheel created, and then pytest passed on Windows. No idea why, but I guess it's ok to release the wheels?

@davidism
Copy link
Member

davidism commented Oct 6, 2024

By the way, I've run out of time today, so I will either get to this tonight, or tomorrow morning.

@davidism
Copy link
Member

davidism commented Oct 6, 2024

I pushed a temporary tag so that the cibuildwheel job will run. You should be able to download the artifacts when they're done and install them/see the tests pass.

@davidism davidism added this to the 3.0.0 milestone Oct 7, 2024
@davidism davidism merged commit 44a54cd into pallets:main Oct 7, 2024
11 of 12 checks passed
@edgarrmondragon edgarrmondragon deleted the cp313 branch October 7, 2024 20:16
@davidism
Copy link
Member

davidism commented Oct 7, 2024

Sigh, I meant to do a squash merge so there wasn't a bunch of work commits in there, and also credit @dairiki with co-authored-by. Sorry about that, working too quickly right now.

@dairiki
Copy link
Contributor

dairiki commented Oct 7, 2024

also credit @dairiki

Thank you. Don't sweat it!

@davidism
Copy link
Member

davidism commented Oct 7, 2024

This is now available on PyPI with MarkupSafe 3.0.0.

I confirmed that the tests pass on Linux, Mac, and Windows with the cibuildwheel 313t builds, even though a local build crashes on Windows. We'll have to figure that out at some point.

@AA-Turner
Copy link

Thank you David.

A

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants