|
56 | 56 | # versions, but not all
|
57 | 57 | HAS_FORWARD_MODULE = "module" in inspect.signature(typing._type_check).parameters
|
58 | 58 |
|
| 59 | +skip_if_early_py313_alpha = skipIf( |
| 60 | + sys.version_info[:4] == (3, 13, 0, 'alpha') and sys.version_info.serial < 3, |
| 61 | + "Bugfixes will be released in 3.13.0a3" |
| 62 | +) |
| 63 | + |
59 | 64 | ANN_MODULE_SOURCE = '''\
|
60 | 65 | from typing import Optional
|
61 | 66 | from functools import wraps
|
@@ -5548,6 +5553,136 @@ class GenericNamedTuple(NamedTuple, Generic[T]):
|
5548 | 5553 |
|
5549 | 5554 | self.assertEqual(CallNamedTuple.__orig_bases__, (NamedTuple,))
|
5550 | 5555 |
|
| 5556 | + @skip_if_early_py313_alpha |
| 5557 | + def test_setname_called_on_values_in_class_dictionary(self): |
| 5558 | + class Vanilla: |
| 5559 | + def __set_name__(self, owner, name): |
| 5560 | + self.name = name |
| 5561 | + |
| 5562 | + class Foo(NamedTuple): |
| 5563 | + attr = Vanilla() |
| 5564 | + |
| 5565 | + foo = Foo() |
| 5566 | + self.assertEqual(len(foo), 0) |
| 5567 | + self.assertNotIn('attr', Foo._fields) |
| 5568 | + self.assertIsInstance(foo.attr, Vanilla) |
| 5569 | + self.assertEqual(foo.attr.name, "attr") |
| 5570 | + |
| 5571 | + class Bar(NamedTuple): |
| 5572 | + attr: Vanilla = Vanilla() |
| 5573 | + |
| 5574 | + bar = Bar() |
| 5575 | + self.assertEqual(len(bar), 1) |
| 5576 | + self.assertIn('attr', Bar._fields) |
| 5577 | + self.assertIsInstance(bar.attr, Vanilla) |
| 5578 | + self.assertEqual(bar.attr.name, "attr") |
| 5579 | + |
| 5580 | + @skipIf( |
| 5581 | + TYPING_3_12_0, |
| 5582 | + "__set_name__ behaviour changed on py312+ to use BaseException.add_note()" |
| 5583 | + ) |
| 5584 | + def test_setname_raises_the_same_as_on_other_classes_py311_minus(self): |
| 5585 | + class CustomException(BaseException): pass |
| 5586 | + |
| 5587 | + class Annoying: |
| 5588 | + def __set_name__(self, owner, name): |
| 5589 | + raise CustomException |
| 5590 | + |
| 5591 | + annoying = Annoying() |
| 5592 | + |
| 5593 | + with self.assertRaises(RuntimeError) as cm: |
| 5594 | + class NormalClass: |
| 5595 | + attr = annoying |
| 5596 | + normal_exception = cm.exception |
| 5597 | + |
| 5598 | + with self.assertRaises(RuntimeError) as cm: |
| 5599 | + class NamedTupleClass(NamedTuple): |
| 5600 | + attr = annoying |
| 5601 | + namedtuple_exception = cm.exception |
| 5602 | + |
| 5603 | + expected_note = ( |
| 5604 | + "Error calling __set_name__ on 'Annoying' instance " |
| 5605 | + "'attr' in 'NamedTupleClass'" |
| 5606 | + ) |
| 5607 | + |
| 5608 | + self.assertIs(type(namedtuple_exception), RuntimeError) |
| 5609 | + self.assertIs(type(namedtuple_exception), type(normal_exception)) |
| 5610 | + self.assertEqual(len(namedtuple_exception.args), len(normal_exception.args)) |
| 5611 | + self.assertEqual( |
| 5612 | + namedtuple_exception.args[0], |
| 5613 | + normal_exception.args[0].replace("NormalClass", "NamedTupleClass") |
| 5614 | + ) |
| 5615 | + |
| 5616 | + self.assertIs(type(namedtuple_exception.__cause__), CustomException) |
| 5617 | + self.assertIs( |
| 5618 | + type(namedtuple_exception.__cause__), type(normal_exception.__cause__) |
| 5619 | + ) |
| 5620 | + self.assertEqual( |
| 5621 | + namedtuple_exception.__cause__.args, normal_exception.__cause__.args |
| 5622 | + ) |
| 5623 | + |
| 5624 | + @skipUnless( |
| 5625 | + TYPING_3_12_0, |
| 5626 | + "__set_name__ behaviour changed on py312+ to use BaseException.add_note()" |
| 5627 | + ) |
| 5628 | + @skip_if_early_py313_alpha |
| 5629 | + def test_setname_raises_the_same_as_on_other_classes_py312_plus(self): |
| 5630 | + class CustomException(BaseException): pass |
| 5631 | + |
| 5632 | + class Annoying: |
| 5633 | + def __set_name__(self, owner, name): |
| 5634 | + raise CustomException |
| 5635 | + |
| 5636 | + annoying = Annoying() |
| 5637 | + |
| 5638 | + with self.assertRaises(CustomException) as cm: |
| 5639 | + class NormalClass: |
| 5640 | + attr = annoying |
| 5641 | + normal_exception = cm.exception |
| 5642 | + |
| 5643 | + with self.assertRaises(CustomException) as cm: |
| 5644 | + class NamedTupleClass(NamedTuple): |
| 5645 | + attr = annoying |
| 5646 | + namedtuple_exception = cm.exception |
| 5647 | + |
| 5648 | + expected_note = ( |
| 5649 | + "Error calling __set_name__ on 'Annoying' instance " |
| 5650 | + "'attr' in 'NamedTupleClass'" |
| 5651 | + ) |
| 5652 | + |
| 5653 | + self.assertIs(type(namedtuple_exception), CustomException) |
| 5654 | + self.assertIs(type(namedtuple_exception), type(normal_exception)) |
| 5655 | + self.assertEqual(namedtuple_exception.args, normal_exception.args) |
| 5656 | + |
| 5657 | + self.assertEqual(len(namedtuple_exception.__notes__), 1) |
| 5658 | + self.assertEqual( |
| 5659 | + len(namedtuple_exception.__notes__), len(normal_exception.__notes__) |
| 5660 | + ) |
| 5661 | + |
| 5662 | + self.assertEqual(namedtuple_exception.__notes__[0], expected_note) |
| 5663 | + self.assertEqual( |
| 5664 | + namedtuple_exception.__notes__[0], |
| 5665 | + normal_exception.__notes__[0].replace("NormalClass", "NamedTupleClass") |
| 5666 | + ) |
| 5667 | + |
| 5668 | + @skip_if_early_py313_alpha |
| 5669 | + def test_strange_errors_when_accessing_set_name_itself(self): |
| 5670 | + class CustomException(Exception): pass |
| 5671 | + |
| 5672 | + class Meta(type): |
| 5673 | + def __getattribute__(self, attr): |
| 5674 | + if attr == "__set_name__": |
| 5675 | + raise CustomException |
| 5676 | + return object.__getattribute__(self, attr) |
| 5677 | + |
| 5678 | + class VeryAnnoying(metaclass=Meta): pass |
| 5679 | + |
| 5680 | + very_annoying = VeryAnnoying() |
| 5681 | + |
| 5682 | + with self.assertRaises(CustomException): |
| 5683 | + class Foo(NamedTuple): |
| 5684 | + attr = very_annoying |
| 5685 | + |
5551 | 5686 |
|
5552 | 5687 | class TypeVarTests(BaseTestCase):
|
5553 | 5688 | def test_basic_plain(self):
|
|
0 commit comments