Skip to content

Commit fe19790

Browse files
Merge branch 'main' into jit-devcontainer
2 parents ff255f5 + 2629ee4 commit fe19790

File tree

12 files changed

+290
-205
lines changed

12 files changed

+290
-205
lines changed

Doc/library/html.rst

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,12 @@ This module defines utilities to manipulate HTML.
1414

1515
Convert the characters ``&``, ``<`` and ``>`` in string *s* to HTML-safe
1616
sequences. Use this if you need to display text that might contain such
17-
characters in HTML. If the optional flag *quote* is true, the characters
18-
(``"``) and (``'``) are also translated; this helps for inclusion in an HTML
19-
attribute value delimited by quotes, as in ``<a href="...">``.
17+
characters in HTML. If the optional flag *quote* is true (the default), the
18+
characters (``"``) and (``'``) are also translated; this helps for inclusion
19+
in an HTML attribute value delimited by quotes, as in ``<a href="...">``.
20+
If *quote* is set to false, the characters (``"``) and (``'``) are not
21+
translated.
22+
2023

2124
.. versionadded:: 3.2
2225

Include/internal/pycore_runtime_structs.h

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -276,12 +276,6 @@ struct pyruntimestate {
276276
struct _types_runtime_state types;
277277
struct _Py_time_runtime_state time;
278278

279-
#if defined(__EMSCRIPTEN__) && defined(PY_CALL_TRAMPOLINE)
280-
// Used in "Python/emscripten_trampoline.c" to choose between type
281-
// reflection trampoline and EM_JS trampoline.
282-
int (*emscripten_count_args_function)(PyCFunctionWithKeywords func);
283-
#endif
284-
285279
/* All the objects that are shared by the runtime's interpreters. */
286280
struct _Py_cached_objects cached_objects;
287281
struct _Py_static_objects static_objects;

Lib/test/support/_hypothesis_stubs/__init__.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,13 @@ def decorator(f):
2424
@functools.wraps(f)
2525
def test_function(self):
2626
for example_args, example_kwargs in examples:
27-
with self.subTest(*example_args, **example_kwargs):
27+
if len(example_args) < 2:
28+
subtest_args = example_args
29+
else:
30+
# subTest takes up to one positional argument.
31+
# When there are more, display them as a tuple
32+
subtest_args = [example_args]
33+
with self.subTest(*subtest_args, **example_kwargs):
2834
f(self, *example_args, **example_kwargs)
2935

3036
else:

Lib/test/test_base64.py

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import unittest
22
import base64
33
import binascii
4+
import string
45
import os
56
from array import array
67
from test.support import cpython_only
@@ -14,6 +15,8 @@ class LazyImportTest(unittest.TestCase):
1415
def test_lazy_import(self):
1516
ensure_lazy_imports("base64", {"re", "getopt"})
1617

18+
from test.support.hypothesis_helper import hypothesis
19+
1720

1821
class LegacyBase64TestCase(unittest.TestCase):
1922

@@ -68,6 +71,13 @@ def test_decodebytes(self):
6871
eq(base64.decodebytes(array('B', b'YWJj\n')), b'abc')
6972
self.check_type_errors(base64.decodebytes)
7073

74+
@hypothesis.given(payload=hypothesis.strategies.binary())
75+
@hypothesis.example(b'abcdefghijklmnopqrstuvwxyz')
76+
def test_bytes_encode_decode_round_trip(self, payload):
77+
encoded = base64.encodebytes(payload)
78+
decoded = base64.decodebytes(encoded)
79+
self.assertEqual(payload, decoded)
80+
7181
def test_encode(self):
7282
eq = self.assertEqual
7383
from io import BytesIO, StringIO
@@ -96,6 +106,19 @@ def test_decode(self):
96106
self.assertRaises(TypeError, base64.encode, BytesIO(b'YWJj\n'), StringIO())
97107
self.assertRaises(TypeError, base64.encode, StringIO('YWJj\n'), StringIO())
98108

109+
@hypothesis.given(payload=hypothesis.strategies.binary())
110+
@hypothesis.example(b'abcdefghijklmnopqrstuvwxyz')
111+
def test_legacy_encode_decode_round_trip(self, payload):
112+
from io import BytesIO
113+
payload_file_r = BytesIO(payload)
114+
encoded_file_w = BytesIO()
115+
base64.encode(payload_file_r, encoded_file_w)
116+
encoded_file_r = BytesIO(encoded_file_w.getvalue())
117+
decoded_file_w = BytesIO()
118+
base64.decode(encoded_file_r, decoded_file_w)
119+
decoded = decoded_file_w.getvalue()
120+
self.assertEqual(payload, decoded)
121+
99122

100123
class BaseXYTestCase(unittest.TestCase):
101124

@@ -276,6 +299,44 @@ def test_b64decode_invalid_chars(self):
276299
self.assertEqual(base64.b64decode(b'++[[//]]', b'[]'), res)
277300
self.assertEqual(base64.urlsafe_b64decode(b'++--//__'), res)
278301

302+
303+
def _altchars_strategy():
304+
"""Generate 'altchars' for base64 encoding."""
305+
reserved_chars = (string.digits + string.ascii_letters + "=").encode()
306+
allowed_chars = hypothesis.strategies.sampled_from(
307+
[n for n in range(256) if n not in reserved_chars])
308+
two_bytes_strategy = hypothesis.strategies.lists(
309+
allowed_chars, min_size=2, max_size=2, unique=True).map(bytes)
310+
return (hypothesis.strategies.none()
311+
| hypothesis.strategies.just(b"_-")
312+
| two_bytes_strategy)
313+
314+
@hypothesis.given(
315+
payload=hypothesis.strategies.binary(),
316+
altchars=_altchars_strategy(),
317+
validate=hypothesis.strategies.booleans())
318+
@hypothesis.example(b'abcdefghijklmnopqrstuvwxyz', b"_-", True)
319+
@hypothesis.example(b'abcdefghijklmnopqrstuvwxyz', b"_-", False)
320+
def test_b64_encode_decode_round_trip(self, payload, altchars, validate):
321+
encoded = base64.b64encode(payload, altchars=altchars)
322+
decoded = base64.b64decode(encoded, altchars=altchars,
323+
validate=validate)
324+
self.assertEqual(payload, decoded)
325+
326+
@hypothesis.given(payload=hypothesis.strategies.binary())
327+
@hypothesis.example(b'abcdefghijklmnopqrstuvwxyz')
328+
def test_standard_b64_encode_decode_round_trip(self, payload):
329+
encoded = base64.standard_b64encode(payload)
330+
decoded = base64.standard_b64decode(encoded)
331+
self.assertEqual(payload, decoded)
332+
333+
@hypothesis.given(payload=hypothesis.strategies.binary())
334+
@hypothesis.example(b'abcdefghijklmnopqrstuvwxyz')
335+
def test_urlsafe_b64_encode_decode_round_trip(self, payload):
336+
encoded = base64.urlsafe_b64encode(payload)
337+
decoded = base64.urlsafe_b64decode(encoded)
338+
self.assertEqual(payload, decoded)
339+
279340
def test_b32encode(self):
280341
eq = self.assertEqual
281342
eq(base64.b32encode(b''), b'')
@@ -363,6 +424,19 @@ def test_b32decode_error(self):
363424
with self.assertRaises(binascii.Error):
364425
base64.b32decode(data.decode('ascii'))
365426

427+
@hypothesis.given(
428+
payload=hypothesis.strategies.binary(),
429+
casefold=hypothesis.strategies.booleans(),
430+
map01=(
431+
hypothesis.strategies.none()
432+
| hypothesis.strategies.binary(min_size=1, max_size=1)))
433+
@hypothesis.example(b'abcdefghijklmnopqrstuvwxyz', True, None)
434+
@hypothesis.example(b'abcdefghijklmnopqrstuvwxyz', False, None)
435+
def test_b32_encode_decode_round_trip(self, payload, casefold, map01):
436+
encoded = base64.b32encode(payload)
437+
decoded = base64.b32decode(encoded, casefold=casefold, map01=map01)
438+
self.assertEqual(payload, decoded)
439+
366440
def test_b32hexencode(self):
367441
test_cases = [
368442
# to_encode, expected
@@ -432,6 +506,15 @@ def test_b32hexdecode_error(self):
432506
with self.assertRaises(binascii.Error):
433507
base64.b32hexdecode(data.decode('ascii'))
434508

509+
@hypothesis.given(
510+
payload=hypothesis.strategies.binary(),
511+
casefold=hypothesis.strategies.booleans())
512+
@hypothesis.example(b'abcdefghijklmnopqrstuvwxyz', True)
513+
@hypothesis.example(b'abcdefghijklmnopqrstuvwxyz', False)
514+
def test_b32_hexencode_decode_round_trip(self, payload, casefold):
515+
encoded = base64.b32hexencode(payload)
516+
decoded = base64.b32hexdecode(encoded, casefold=casefold)
517+
self.assertEqual(payload, decoded)
435518

436519
def test_b16encode(self):
437520
eq = self.assertEqual
@@ -469,6 +552,16 @@ def test_b16decode(self):
469552
# Incorrect "padding"
470553
self.assertRaises(binascii.Error, base64.b16decode, '010')
471554

555+
@hypothesis.given(
556+
payload=hypothesis.strategies.binary(),
557+
casefold=hypothesis.strategies.booleans())
558+
@hypothesis.example(b'abcdefghijklmnopqrstuvwxyz', True)
559+
@hypothesis.example(b'abcdefghijklmnopqrstuvwxyz', False)
560+
def test_b16_encode_decode_round_trip(self, payload, casefold):
561+
endoded = base64.b16encode(payload)
562+
decoded = base64.b16decode(endoded, casefold=casefold)
563+
self.assertEqual(payload, decoded)
564+
472565
def test_a85encode(self):
473566
eq = self.assertEqual
474567

@@ -799,6 +892,61 @@ def test_z85decode_errors(self):
799892
self.assertRaises(ValueError, base64.z85decode, b'%nSc')
800893
self.assertRaises(ValueError, base64.z85decode, b'%nSc1')
801894

895+
def add_padding(self, payload):
896+
"""Add the expected padding for test_?85_encode_decode_round_trip."""
897+
if len(payload) % 4 != 0:
898+
padding = b"\0" * ((-len(payload)) % 4)
899+
payload = payload + padding
900+
return payload
901+
902+
@hypothesis.given(
903+
payload=hypothesis.strategies.binary(),
904+
foldspaces=hypothesis.strategies.booleans(),
905+
wrapcol=(
906+
hypothesis.strategies.just(0)
907+
| hypothesis.strategies.integers(1, 1000)),
908+
pad=hypothesis.strategies.booleans(),
909+
adobe=hypothesis.strategies.booleans(),
910+
)
911+
@hypothesis.example(b'abcdefghijklmnopqrstuvwxyz', False, 0, False, False)
912+
@hypothesis.example(b'abcdefghijklmnopqrstuvwxyz', False, 20, True, True)
913+
@hypothesis.example(b'abcdefghijklmnopqrstuvwxyz', True, 0, False, True)
914+
@hypothesis.example(b'abcdefghijklmnopqrstuvwxyz', True, 20, True, False)
915+
def test_a85_encode_decode_round_trip(
916+
self, payload, foldspaces, wrapcol, pad, adobe
917+
):
918+
encoded = base64.a85encode(
919+
payload, foldspaces=foldspaces, wrapcol=wrapcol,
920+
pad=pad, adobe=adobe,
921+
)
922+
if wrapcol:
923+
if adobe and wrapcol == 1:
924+
# "adobe" needs wrapcol to be at least 2.
925+
# a85decode quietly uses 2 if 1 is given; it's not worth
926+
# loudly deprecating this behavior.
927+
wrapcol = 2
928+
for line in encoded.splitlines(keepends=False):
929+
self.assertLessEqual(len(line), wrapcol)
930+
if adobe:
931+
self.assertTrue(encoded.startswith(b'<~'))
932+
self.assertTrue(encoded.endswith(b'~>'))
933+
decoded = base64.a85decode(encoded, foldspaces=foldspaces, adobe=adobe)
934+
if pad:
935+
payload = self.add_padding(payload)
936+
self.assertEqual(payload, decoded)
937+
938+
@hypothesis.given(
939+
payload=hypothesis.strategies.binary(),
940+
pad=hypothesis.strategies.booleans())
941+
@hypothesis.example(b'abcdefghijklmnopqrstuvwxyz', True)
942+
@hypothesis.example(b'abcdefghijklmnopqrstuvwxyz', False)
943+
def test_b85_encode_decode_round_trip(self, payload, pad):
944+
encoded = base64.b85encode(payload, pad=pad)
945+
if pad:
946+
payload = self.add_padding(payload)
947+
decoded = base64.b85decode(encoded)
948+
self.assertEqual(payload, decoded)
949+
802950
def test_decode_nonascii_str(self):
803951
decode_funcs = (base64.b64decode,
804952
base64.standard_b64decode,

Makefile.pre.in

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3113,6 +3113,12 @@ config.status: $(srcdir)/configure
31133113
Python/asm_trampoline.o: $(srcdir)/Python/asm_trampoline.S
31143114
$(CC) -c $(PY_CORE_CFLAGS) -o $@ $<
31153115

3116+
Python/emscripten_trampoline_inner.wasm: $(srcdir)/Python/emscripten_trampoline_inner.c
3117+
# emcc has a path that ends with emsdk/upstream/emscripten/emcc, we're looking for emsdk/upstream/bin/clang.
3118+
$$(dirname $$(dirname $(CC)))/bin/clang -o $@ $< -mgc -O2 -Wl,--no-entry -Wl,--import-table -Wl,--import-memory -target wasm32-unknown-unknown -nostdlib
3119+
3120+
Python/emscripten_trampoline_wasm.c: Python/emscripten_trampoline_inner.wasm
3121+
$(PYTHON_FOR_REGEN) $(srcdir)/Tools/wasm/emscripten/prepare_external_wasm.py $< $@ getWasmTrampolineModule
31163122

31173123
JIT_DEPS = \
31183124
$(srcdir)/Tools/jit/*.c \

0 commit comments

Comments
 (0)