1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170
|
from __future__ import annotations
import os
import subprocess
import sys
from pathlib import Path
import execnet
import pytest
# We use the execnet folder in order to avoid triggering a missing apipkg.
pyimportdir = os.fspath(Path(execnet.__file__).parent)
class PythonWrapper:
def __init__(self, executable: str, tmp_path: Path) -> None:
self.executable = executable
self.tmp_path = tmp_path
def dump(self, obj_rep: str) -> bytes:
script_file = self.tmp_path.joinpath("dump.py")
script_file.write_text(
f"""
import sys
sys.path.insert(0, {pyimportdir!r})
import gateway_base as serializer
sys.stdout = sys.stdout.detach()
sys.stdout.write(serializer.dumps_internal({obj_rep}))
"""
)
res = subprocess.run(
[str(self.executable), str(script_file)], capture_output=True, check=True
)
return res.stdout
def load(self, data: bytes) -> list[str]:
script_file = self.tmp_path.joinpath("load.py")
script_file.write_text(
rf"""
import sys
sys.path.insert(0, {pyimportdir!r})
import gateway_base as serializer
from io import BytesIO
data = {data!r}
io = BytesIO(data)
loader = serializer.Unserializer(io)
obj = loader.load()
sys.stdout.write(type(obj).__name__ + "\n")
sys.stdout.write(repr(obj))
"""
)
res = subprocess.run(
[str(self.executable), str(script_file)],
capture_output=True,
check=True,
)
return res.stdout.decode("ascii").splitlines()
def __repr__(self) -> str:
return f"<PythonWrapper for {self.executable}>"
@pytest.fixture
def py3(tmp_path: Path) -> PythonWrapper:
return PythonWrapper(sys.executable, tmp_path)
@pytest.fixture
def dump(py3: PythonWrapper):
return py3.dump
@pytest.fixture
def load(py3: PythonWrapper):
return py3.load
simple_tests = [
# expected before/after repr
("int", "4"),
("float", "3.25"),
("complex", "(1.78+3.25j)"),
("list", "[1, 2, 3]"),
("tuple", "(1, 2, 3)"),
("dict", "{(1, 2, 3): 32}"),
]
@pytest.mark.parametrize(["tp_name", "repr"], simple_tests)
def test_simple(tp_name, repr, dump, load) -> None:
p = dump(repr)
tp, v = load(p)
assert tp == tp_name
assert v == repr
def test_set(load, dump) -> None:
p = dump("set((1, 2, 3))")
tp, v = load(p)
assert tp == "set"
# assert v == "{1, 2, 3}" # ordering prevents this assertion
assert v.startswith("{") and v.endswith("}")
assert "1" in v and "2" in v and "3" in v
p = dump("set()")
tp, v = load(p)
assert tp == "set"
assert v == "set()"
def test_frozenset(load, dump):
p = dump("frozenset((1, 2, 3))")
tp, v = load(p)
assert tp == "frozenset"
assert v == "frozenset({1, 2, 3})"
def test_long(load, dump) -> None:
really_big = "9223372036854775807324234"
p = dump(really_big)
tp, v = load(p)
assert tp == "int"
assert v == really_big
def test_bytes(dump, load) -> None:
p = dump("b'hi'")
tp, v = load(p)
assert tp == "bytes"
assert v == "b'hi'"
def test_str(dump, load) -> None:
p = dump("'xyz'")
tp, s = load(p)
assert tp == "str"
assert s == "'xyz'"
def test_unicode(load, dump) -> None:
p = dump("u'hi'")
tp, s = load(p)
assert tp == "str"
assert s == "'hi'"
def test_bool(dump, load) -> None:
p = dump("True")
tp, s = load(p)
assert s == "True"
assert tp == "bool"
def test_none(dump, load) -> None:
p = dump("None")
tp, s = load(p)
assert s == "None"
def test_tuple_nested_with_empty_in_between(dump, load) -> None:
p = dump("(1, (), 3)")
tp, s = load(p)
assert tp == "tuple"
assert s == "(1, (), 3)"
def test_py2_string_loads() -> None:
"""Regression test for #267."""
assert execnet.loads(b"\x02M\x00\x00\x00\x01aQ") == b"a"
|