|
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,36 @@ def __reduce__(self): |
4552 | 4554 | expected = "changed size during iteration" |
4553 | 4555 | self.assertIn(expected, str(e)) |
4554 | 4556 |
|
| 4557 | + def test_fast_save_enter_leave(self): |
| 4558 | + # gh-146059: Check that fast_save_leave() is called when |
| 4559 | + # fast_save_enter() is called. |
| 4560 | + if not hasattr(self, "pickler"): |
| 4561 | + self.skipTest("need Pickler class") |
| 4562 | + |
| 4563 | + limit = FAST_NESTING_LIMIT * 2 |
| 4564 | + for proto in protocols: |
| 4565 | + for tested_type in (frozenset, list, dict): |
| 4566 | + with self.subTest(proto=proto, tested_type=tested_type): |
| 4567 | + buf = io.BytesIO() |
| 4568 | + pickler = self.pickler(buf, protocol=proto) |
| 4569 | + # Enable fast mode (disables memo, enables cycle detection) |
| 4570 | + pickler.fast = 1 |
| 4571 | + |
| 4572 | + if tested_type == frozenset: |
| 4573 | + data = [frozenset([i]) for i in range(limit)] |
| 4574 | + elif tested_type == list: |
| 4575 | + data = [[i] for i in range(limit)] |
| 4576 | + elif tested_type == dict: |
| 4577 | + data = [{"key": 123} for i in range(limit)] |
| 4578 | + else: |
| 4579 | + self.fail("unknown tested_type") |
| 4580 | + data = {"key": data} |
| 4581 | + pickler.dump(data) |
| 4582 | + |
| 4583 | + buf.seek(0) |
| 4584 | + data2 = self.unpickler(buf).load() |
| 4585 | + self.assertEqual(data2, data) |
| 4586 | + |
4555 | 4587 |
|
4556 | 4588 | class BigmemPickleTests: |
4557 | 4589 |
|
|
0 commit comments