markupsafe icon indicating copy to clipboard operation
markupsafe copied to clipboard

Build Python 3.13 wheels (non free-threaded)

Open edgarrmondragon opened this issue 1 year ago • 2 comments
trafficstars

Python 3.13 RC1 was released recently^1:

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 ones^2, which will certainly involve a higher level of effort.

Related: https://github.com/pallets/markupsafe/issues/460

edgarrmondragon avatar Aug 18 '24 17:08 edgarrmondragon

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.

davidism avatar Aug 18 '24 23:08 davidism

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 avatar Aug 18 '24 23:08 edgarrmondragon

@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).

edgarrmondragon avatar Sep 27 '24 06:09 edgarrmondragon

@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.

dairiki avatar Sep 27 '24 08:09 dairiki

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

edgarrmondragon avatar Sep 28 '24 00:09 edgarrmondragon

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 avatar Oct 06 '24 16:10 davidism

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?

davidism avatar Oct 06 '24 16:10 davidism

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

AA-Turner avatar Oct 06 '24 17:10 AA-Turner

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.dev0

❯ python3.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: preinitialized

❯ tox 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).

hugovk avatar Oct 06 '24 17:10 hugovk

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.

davidism avatar Oct 06 '24 18:10 davidism

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

  • https://github.com/tox-dev/tox/issues/3314
  • https://github.com/tox-dev/tox/issues/3391 - which also suggests "--discover in the meantime to force it"

hugovk avatar Oct 06 '24 18:10 hugovk

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 avatar Oct 06 '24 18:10 davidism

https://github.com/pallets/markupsafe/pull/462#issuecomment-2395535509 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 avatar Oct 06 '24 18:10 davidism

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

davidism avatar Oct 06 '24 18:10 davidism

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 avatar Oct 06 '24 18:10 davidism

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.

davidism avatar Oct 07 '24 20:10 davidism

also credit @dairiki

Thank you. Don't sweat it!

dairiki avatar Oct 07 '24 20:10 dairiki

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.

davidism avatar Oct 07 '24 21:10 davidism

Thank you David.

A

AA-Turner avatar Oct 07 '24 21:10 AA-Turner