|
57 | 57 | # kind of outer loop. |
58 | 58 | protocols = range(pickle.HIGHEST_PROTOCOL + 1) |
59 | 59 |
|
| 60 | +FAST_NESTING_LIMIT = 50 |
| 61 | + |
60 | 62 |
|
61 | 63 | # Return True if opcode code appears in the pickle, else False. |
62 | 64 | def opcode_in_pickle(code, pickle): |
@@ -4552,6 +4554,98 @@ def __reduce__(self): |
4552 | 4554 | expected = "changed size during iteration" |
4553 | 4555 | self.assertIn(expected, str(e)) |
4554 | 4556 |
|
| 4557 | + def fast_save_enter(self, create_data, minprotocol=0): |
| 4558 | + # gh-146059: Check that fast_save() is called when |
| 4559 | + # fast_save_enter() is called. |
| 4560 | + if not hasattr(self, "pickler"): |
| 4561 | + self.skipTest("need Pickler class") |
| 4562 | + |
| 4563 | + data = [create_data(i) for i in range(FAST_NESTING_LIMIT * 2)] |
| 4564 | + data = {"key": data} |
| 4565 | + protocols = range(minprotocol, pickle.HIGHEST_PROTOCOL + 1) |
| 4566 | + for proto in protocols: |
| 4567 | + with self.subTest(proto=proto): |
| 4568 | + buf = io.BytesIO() |
| 4569 | + pickler = self.pickler(buf, protocol=proto) |
| 4570 | + # Enable fast mode (disables memo, enables cycle detection) |
| 4571 | + pickler.fast = 1 |
| 4572 | + pickler.dump(data) |
| 4573 | + |
| 4574 | + buf.seek(0) |
| 4575 | + data2 = self.unpickler(buf).load() |
| 4576 | + self.assertEqual(data2, data) |
| 4577 | + |
| 4578 | + def test_fast_save_enter_tuple(self): |
| 4579 | + self.fast_save_enter(lambda i: (i,)) |
| 4580 | + |
| 4581 | + def test_fast_save_enter_list(self): |
| 4582 | + self.fast_save_enter(lambda i: [i]) |
| 4583 | + |
| 4584 | + def test_fast_save_enter_frozenset(self): |
| 4585 | + self.fast_save_enter(lambda i: frozenset([i])) |
| 4586 | + |
| 4587 | + def test_fast_save_enter_set(self): |
| 4588 | + self.fast_save_enter(lambda i: set([i])) |
| 4589 | + |
| 4590 | + def test_fast_save_enter_frozendict(self): |
| 4591 | + if self.py_version < (3, 15): |
| 4592 | + self.skipTest('need frozendict') |
| 4593 | + self.fast_save_enter(lambda i: frozendict(key=i), minprotocol=2) |
| 4594 | + |
| 4595 | + def test_fast_save_enter_dict(self): |
| 4596 | + self.fast_save_enter(lambda i: {"key": i}) |
| 4597 | + |
| 4598 | + def deep_nested_struct(self, seed, create_nested, |
| 4599 | + minprotocol=0, compare_equal=True, |
| 4600 | + depth=FAST_NESTING_LIMIT * 2): |
| 4601 | + # gh-146059: Check that fast_save() is called when |
| 4602 | + # fast_save_enter() is called. |
| 4603 | + if not hasattr(self, "pickler"): |
| 4604 | + self.skipTest("need Pickler class") |
| 4605 | + |
| 4606 | + data = seed |
| 4607 | + for i in range(depth): |
| 4608 | + data = create_nested(data) |
| 4609 | + data = {"key": data} |
| 4610 | + protocols = range(minprotocol, pickle.HIGHEST_PROTOCOL + 1) |
| 4611 | + for proto in protocols: |
| 4612 | + with self.subTest(proto=proto): |
| 4613 | + buf = io.BytesIO() |
| 4614 | + pickler = self.pickler(buf, protocol=proto) |
| 4615 | + # Enable fast mode (disables memo, enables cycle detection) |
| 4616 | + pickler.fast = 1 |
| 4617 | + pickler.dump(data) |
| 4618 | + |
| 4619 | + buf.seek(0) |
| 4620 | + data2 = self.unpickler(buf).load() |
| 4621 | + if compare_equal: |
| 4622 | + self.assertEqual(data2, data) |
| 4623 | + |
| 4624 | + def test_deep_nested_struct_tuple(self): |
| 4625 | + self.deep_nested_struct((1,), lambda data: (data,)) |
| 4626 | + |
| 4627 | + def test_deep_nested_struct_list(self): |
| 4628 | + self.deep_nested_struct([1], lambda data: [data]) |
| 4629 | + |
| 4630 | + def test_deep_nested_struct_frozenset(self): |
| 4631 | + self.deep_nested_struct(frozenset((1,)), |
| 4632 | + lambda data: frozenset((1, data))) |
| 4633 | + |
| 4634 | + def test_deep_nested_struct_set(self): |
| 4635 | + self.deep_nested_struct({1}, lambda data: {K(data)}, |
| 4636 | + depth=FAST_NESTING_LIMIT+1, |
| 4637 | + compare_equal=False) |
| 4638 | + |
| 4639 | + def test_deep_nested_struct_frozendict(self): |
| 4640 | + if self.py_version < (3, 15): |
| 4641 | + self.skipTest('need frozendict') |
| 4642 | + self.deep_nested_struct(frozendict(x=1), |
| 4643 | + lambda data: frozendict(x=data), |
| 4644 | + minprotocol=2) |
| 4645 | + |
| 4646 | + def test_deep_nested_struct_dict(self): |
| 4647 | + self.deep_nested_struct({'x': 1}, lambda data: {'x': data}) |
| 4648 | + |
4555 | 4649 |
|
4556 | 4650 | class BigmemPickleTests: |
4557 | 4651 |
|
|
0 commit comments