Skip to content

Commit 994af53

Browse files
committed
Typed array support
1 parent 196f0da commit 994af53

File tree

2 files changed

+75
-0
lines changed

2 files changed

+75
-0
lines changed

playwright/_impl/_js_handle.py

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,11 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15+
import base64
1516
import collections.abc
1617
import datetime
1718
import math
19+
import struct
1820
import traceback
1921
from pathlib import Path
2022
from typing import TYPE_CHECKING, Any, Dict, List, Optional, Union
@@ -260,6 +262,56 @@ def parse_value(value: Any, refs: Optional[Dict[int, Any]] = None) -> Any:
260262

261263
if "b" in value:
262264
return value["b"]
265+
266+
if "ta" in value:
267+
encoded_bytes = value["ta"]["b"]
268+
decoded_bytes = base64.b64decode(encoded_bytes)
269+
array_type = value["ta"]["k"]
270+
if array_type == "i8":
271+
word_size = 1
272+
fmt = "b"
273+
elif array_type == "ui8" or array_type == "ui8c":
274+
word_size = 1
275+
fmt = "B"
276+
elif array_type == "i16":
277+
word_size = 2
278+
fmt = "h"
279+
elif array_type == "ui16":
280+
word_size = 2
281+
fmt = "H"
282+
elif array_type == "i32":
283+
word_size = 4
284+
fmt = "i"
285+
elif array_type == "ui32":
286+
word_size = 4
287+
fmt = "I"
288+
elif array_type == "f32":
289+
word_size = 4
290+
fmt = "f"
291+
elif array_type == "f64":
292+
word_size = 8
293+
fmt = "d"
294+
elif array_type == "bi64":
295+
word_size = 8
296+
fmt = "q"
297+
elif array_type == "bui64":
298+
word_size = 8
299+
fmt = "Q"
300+
else:
301+
raise ValueError(f"Unsupported array type: {array_type}")
302+
303+
byte_len = len(decoded_bytes)
304+
if byte_len % word_size != 0:
305+
raise ValueError(
306+
f"Decoded bytes length {byte_len} is not a multiple of word size {word_size}"
307+
)
308+
309+
if byte_len == 0:
310+
return []
311+
array_len = byte_len // word_size
312+
# "<" denotes little-endian
313+
format_string = f"<{array_len}{fmt}"
314+
return list(struct.unpack(format_string, decoded_bytes))
263315
return value
264316

265317

tests/async/test_page_evaluate.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,29 @@ async def test_evaluate_transfer_arrays(page: Page) -> None:
6565
assert result == [1, 2, 3]
6666

6767

68+
async def test_evaluate_transfer_typed_arrays(page: Page) -> None:
69+
async def test_typed_array(
70+
typed_array: str, expected: list[float], value_suffix: Optional[str]
71+
) -> None:
72+
value_suffix = "" if value_suffix is None else value_suffix
73+
result = await page.evaluate(
74+
f"() => new {typed_array}([1{value_suffix}, 2{value_suffix}, 3{value_suffix}])"
75+
)
76+
assert result == expected
77+
78+
await test_typed_array("Int8Array", [1, 2, 3], None)
79+
await test_typed_array("Uint8Array", [1, 2, 3], None)
80+
await test_typed_array("Uint8ClampedArray", [1, 2, 3], None)
81+
await test_typed_array("Int16Array", [1, 2, 3], None)
82+
await test_typed_array("Uint16Array", [1, 2, 3], None)
83+
await test_typed_array("Int32Array", [1, 2, 3], None)
84+
await test_typed_array("Uint32Array", [1, 2, 3], None)
85+
await test_typed_array("Float32Array", [1.5, 2.5, 3.5], ".5")
86+
await test_typed_array("Float64Array", [1.5, 2.5, 3.5], ".5")
87+
await test_typed_array("BigInt64Array", [1, 2, 3], "n")
88+
await test_typed_array("BigUint64Array", [1, 2, 3], "n")
89+
90+
6891
async def test_evaluate_transfer_bigint(page: Page) -> None:
6992
assert await page.evaluate("() => 42n") == 42
7093
assert await page.evaluate("a => a", 17) == 17

0 commit comments

Comments
 (0)