this repo has no description
at trunk 1034 lines 32 kB view raw
1#!/usr/bin/env python3 2# Copyright (c) Facebook, Inc. and its affiliates. (http://www.facebook.com) 3import sys 4import unittest 5from types import MethodType, ModuleType, SimpleNamespace 6from unittest.mock import Mock 7 8 9class IntepreterTest(unittest.TestCase): 10 def test_binary_mul_smallint_returns_large_int(self): 11 def mul(a, b): 12 return a * b 13 14 # Rewrite mul() to use BINARY_MUL_SMALLINT. 15 self.assertEqual(mul(5, 6), 30) 16 17 small_int = 1 << 62 18 self.assertEqual(mul(small_int, small_int), small_int * small_int) 19 20 def test_binary_mul_smallint_with_operand_zero_returns_zero(self): 21 def mul(a, b): 22 return a * b 23 24 # Rewrite mul() to use BINARY_MUL_SMALLINT. 25 self.assertEqual(mul(5, 6), 30) 26 27 small_int = 1 << 62 28 self.assertEqual(mul(small_int, 0), 0) 29 self.assertEqual(mul(0, small_int), 0) 30 31 def test_binary_subscr_calls_type_dunder_class_getitem(self): 32 class C: 33 def __class_getitem__(cls, item): 34 return f"C:{cls.__name__}[{item.__name__}]" 35 36 self.assertEqual(C[int], "C:C[int]") 37 38 def test_binary_subscr_ignores_instance_dunder_class_getitem(self): 39 class C: 40 def __class_getitem__(cls, item): 41 return f"C:{cls.__name__}[{item.__name__}]" 42 43 with self.assertRaises(TypeError) as context: 44 C()[int] 45 self.assertEqual(str(context.exception), "'C' object is not subscriptable") 46 47 def test_binary_subscr_prioritizes_metaclass_dunder_getitem(self): 48 class M(type): 49 def __getitem__(cls, item): 50 return f"M:{cls.__name__}[{item.__name__}]" 51 52 class C(metaclass=M): 53 def __class_getitem__(cls, item): 54 return f"C:{cls.__name__}[{item.__name__}]" 55 56 self.assertEqual(C[int], "M:C[int]") 57 58 def test_build_map_returns_dict(self): 59 def foo(k0, k1, k2): 60 return {k0: 0, k1: 42.4, k2: "test"} 61 62 d = foo("key0", "aaa", "zzz") 63 self.assertIs(type(d), dict) 64 self.assertEqual(list(d.keys()), ["key0", "aaa", "zzz"]) 65 self.assertEqual(list(d.values()), [0, 42.4, "test"]) 66 67 def test_compare_op_in_propagetes_exception(self): 68 class C: 69 def __contains__(self, value): 70 raise UserWarning("C.__contains__") 71 72 c = C() 73 with self.assertRaises(UserWarning) as context: 74 1 in c 75 self.assertEqual(str(context.exception), "C.__contains__") 76 77 def test_compare_op_not_in_propagetes_exception(self): 78 class C: 79 def __contains__(self, value): 80 raise UserWarning("C.__contains__") 81 82 c = C() 83 with self.assertRaises(UserWarning) as context: 84 1 not in c 85 self.assertEqual(str(context.exception), "C.__contains__") 86 87 def test_for_iter_iterates_dict_by_insertion_order(self): 88 d = {} 89 d["a"] = 1 90 d["c"] = 3 91 d["b"] = 2 92 result = [] 93 for key in d: 94 result.append(key) 95 self.assertEqual(result, ["a", "c", "b"]) 96 97 def test_store_name_calls_dunder_setitem(self): 98 class C(dict): 99 def __setitem__(self, key, value): 100 self.result = (key, value) 101 102 locals = C() 103 exec("x = 44", None, locals) 104 self.assertEqual(locals.result[0], "x") 105 self.assertEqual(locals.result[1], 44) 106 107 def test_store_name_setitem_propagates_exception(self): 108 class C: 109 def __setitem__(self, key, value): 110 raise UserWarning("bar") 111 112 def __getitem__(self, key): 113 ... # just here so this type is considered a mapping. 114 115 locals = C() 116 with self.assertRaises(UserWarning) as context: 117 exec("x = 1", None, locals) 118 self.assertEqual(str(context.exception), "bar") 119 120 def test_store_name_setitem_propagates_descriptor_exception(self): 121 class D: 122 def __get__(self, instance, owner): 123 self.result = (instance, owner) 124 raise UserWarning("baz") 125 126 d = D() 127 128 class C: 129 __setitem__ = d 130 131 def __getitem__(self, key): 132 ... # just here so this type is considered a mapping. 133 134 locals = C() 135 with self.assertRaises(UserWarning) as context: 136 exec("x = 1", None, locals) 137 self.assertEqual(str(context.exception), "baz") 138 self.assertEqual(d.result[0], locals) 139 self.assertEqual(d.result[1], C) 140 141 def test_load_attr_calls_dunder_get(self): 142 class Descriptor: 143 def __get__(self, *args): 144 self.args = args 145 return 42 146 147 descriptor = Descriptor() 148 149 class C: 150 foo = descriptor 151 152 self.assertEqual(C.foo, 42) 153 self.assertEqual(descriptor.args, (None, C)) 154 c = C() 155 self.assertEqual(c.foo, 42) 156 self.assertEqual(descriptor.args, (c, C)) 157 158 def test_load_attr_calls_callable_dunder_get(self): 159 class Callable: 160 def __call__(self, *args): 161 self.args = args 162 return 42 163 164 callable = Callable() 165 166 class Descriptor: 167 __get__ = callable 168 169 descriptor = Descriptor() 170 171 class C: 172 foo = descriptor 173 174 self.assertEqual(C.foo, 42) 175 self.assertEqual(callable.args, (descriptor, None, C)) 176 c = C() 177 self.assertEqual(c.foo, 42) 178 self.assertEqual(callable.args, (descriptor, c, C)) 179 180 def test_load_attr_does_not_recursively_call_dunder_get(self): 181 class Descriptor0: 182 def __get__(self, *args): 183 return 13 184 185 def __call__(self, *args): 186 return 42 187 188 descriptor0 = Descriptor0() 189 190 class Descriptor1: 191 __get__ = descriptor0 192 193 descriptor1 = Descriptor1() 194 195 class C: 196 foo = descriptor1 197 198 self.assertEqual(C.foo, 42) 199 self.assertEqual(C().foo, 42) 200 self.assertIs(C.__dict__["foo"].__get__, 13) 201 202 def test_load_attr_with_module_prioritizes_data_descr_than_instance_attr(self): 203 from types import ModuleType 204 205 class MyModule(ModuleType): 206 @property 207 def foo(self): 208 return "data descriptor" 209 210 m = MyModule("m") 211 m.__dict__["foo"] = "instance attribute" 212 213 self.assertEqual(m.foo, "data descriptor") 214 215 def test_load_attr_with_module_prioritizes_instance_attr_than_non_data_descr(self): 216 from types import ModuleType 217 218 class NonDataDescriptor: 219 def __get__(self, obj, obj_type): 220 return "non-data descriptor" 221 222 class MyModule(ModuleType): 223 foo = NonDataDescriptor() 224 225 m = MyModule("m") 226 m.foo = "instance attribute" 227 228 self.assertEqual(m.foo, "instance attribute") 229 230 def test_load_attr_with_module_prioritizes_non_data_descr_than_instance_getattr( 231 self, 232 ): 233 from types import ModuleType 234 235 class NonDataDescriptor: 236 def __get__(self, obj, obj_type): 237 return "non-data descriptor" 238 239 class MyModule(ModuleType): 240 foo = NonDataDescriptor() 241 242 m = MyModule("m") 243 exec('def __getattr__(name): return name + " instance.__getattr__"', m.__dict__) 244 self.assertEqual(m.foo, "non-data descriptor") 245 246 def test_load_attr_with_module_prioritizes_instance_getattr_than_type_getattr(self): 247 from types import ModuleType 248 249 class MyModule(ModuleType): 250 def __getattr__(self, name): 251 return name + " type.__getattr__" 252 253 m = MyModule("m") 254 exec('def __getattr__(name): return name + " instance.__getattr__"', m.__dict__) 255 self.assertEqual(m.foo, "foo instance.__getattr__") 256 257 def test_load_attr_with_module_returns_type_getattr(self): 258 from types import ModuleType 259 260 class MyModule(ModuleType): 261 def __getattr__(self, name): 262 return name + " type.__getattr__" 263 264 m = MyModule("m") 265 self.assertEqual(m.foo, "foo type.__getattr__") 266 267 def test_load_attr_with_module_returns_type_getattr(self): 268 from types import ModuleType 269 270 class MyModule(ModuleType): 271 pass 272 273 m = MyModule("m") 274 with self.assertRaises(AttributeError): 275 m.foo 276 277 def test_load_deref_with_assigned_cell_returns_assigned_value(self): 278 def foo(x): 279 def bar(): 280 return x 281 282 return bar 283 284 bar = foo(10) 285 self.assertEqual(bar(), 10) 286 287 def test_load_deref_with_delete_cell_raises_name_error(self): 288 def foo(x): 289 def bar(): 290 return x # noqa: F821 291 292 del x 293 return bar 294 295 bar = foo(10) 296 with self.assertRaises(NameError): 297 bar() 298 299 def test_load_name_calls_dunder_getitem(self): 300 class C: 301 def __getitem__(self, key): 302 return (key, 17) 303 304 globals = {"foo": None} 305 locals = C() 306 exec('assert(foo == ("foo", 17))', globals, locals) 307 308 def test_load_name_continues_on_keyerror(self): 309 class C: 310 def __getitem__(self, key): 311 self.result = key 312 raise KeyError() 313 314 globals = {} 315 exec("foo = 99", globals) 316 self.assertIn("foo", globals) 317 318 locals = C() 319 exec("assert(foo == 99)", globals, locals) # should not raise 320 self.assertEqual(locals.result, "foo") 321 322 def test_load_name_getitem_propagates_exception(self): 323 class C: 324 def __getitem__(self, key): 325 raise UserWarning("bar") 326 327 globals = None 328 locals = C() 329 with self.assertRaises(UserWarning) as context: 330 exec("foo", globals, locals) 331 self.assertEqual(str(context.exception), "bar") 332 333 def test_load_name_getitem_propagates_descriptor_exception(self): 334 class D: 335 def __get__(self, instance, owner): 336 self.result = (instance, owner) 337 raise UserWarning("baz") 338 339 d = D() 340 341 class C: 342 __getitem__ = d 343 344 globals = None 345 locals = C() 346 with self.assertRaises(UserWarning) as context: 347 exec("foo", globals, locals) 348 self.assertEqual(str(context.exception), "baz") 349 self.assertEqual(d.result[0], locals) 350 self.assertEqual(d.result[1], C) 351 352 def test_load_global_returns_global(self): 353 globals = { 354 "foo": 42, 355 "__builtins__": {"foo": 8}, 356 } 357 locals = {"foo": 3} 358 self.assertIs( 359 exec("def get_foo(): global foo; return foo", globals, locals), None 360 ) 361 self.assertEqual(locals["get_foo"](), 42) 362 363 def test_load_global_returns_builtin(self): 364 globals = { 365 "foo": 42, 366 "__builtins__": {"bar": 8}, 367 } 368 locals = {"bar": 3} 369 self.assertIs( 370 exec("def get_bar(): global bar; return bar", globals, locals), None 371 ) 372 self.assertEqual(locals["get_bar"](), 8) 373 374 def test_load_global_does_not_cache_builtin(self): 375 builtins = {"bar": -8} 376 globals = {"foo": 42, "__builtins__": builtins} 377 locals = {"bar": 3} 378 self.assertIs( 379 exec("def get_bar(): global bar; return bar", globals, locals), None 380 ) 381 self.assertEqual(locals["get_bar"](), -8) 382 builtins["bar"] = 9 383 self.assertEqual(locals["get_bar"](), 9) 384 385 def test_load_global_calls_builtins_getitem(self): 386 class C: 387 def __getitem__(self, key): 388 return (self, key) 389 390 builtins = C() 391 globals = {"foo": 42, "__builtins__": builtins} 392 locals = {"bar": 3} 393 self.assertIs( 394 exec("def get_bar(): global bar; return bar", globals, locals), None 395 ) 396 self.assertEqual(locals["get_bar"](), (builtins, "bar")) 397 398 def test_delete_attr_calls_dunder_delete(self): 399 class Descriptor: 400 def __delete__(self, *args): 401 self.args = args 402 return "return value ignored" 403 404 descriptor = Descriptor() 405 406 class C: 407 foo = descriptor 408 409 c = C() 410 del c.foo 411 self.assertEqual(descriptor.args, (c,)) 412 # Deletion on class should just delete descriptor 413 del C.foo 414 self.assertFalse(hasattr(C, "foo")) 415 self.assertNotIn("foo", C.__dict__) 416 417 def test_delete_attr_calls_callable_dunder_delete(self): 418 class Callable: 419 def __call__(self, *args): 420 self.args = args 421 return "return value ignored" 422 423 callable = Callable() 424 425 class Descriptor: 426 __delete__ = callable 427 428 descriptor = Descriptor() 429 430 class C: 431 foo = descriptor 432 433 c = C() 434 del c.foo 435 self.assertEqual(callable.args, (c,)) 436 # Deletion on class should just delete descriptor 437 del C.foo 438 self.assertFalse(hasattr(C, "foo")) 439 self.assertNotIn("foo", C.__dict__) 440 441 def test_delete_attr_call_dunder_delete_descriptor(self): 442 class Callable: 443 def __call__(self, *args): 444 self.args = args 445 return "return value ignored" 446 447 callable = Callable() 448 449 class Descriptor0: 450 def __get__(self, *args): 451 self.args = args 452 return callable 453 454 descriptor0 = Descriptor0() 455 456 class Descriptor1: 457 __delete__ = descriptor0 458 459 descriptor1 = Descriptor1() 460 461 class C: 462 foo = descriptor1 463 464 c = C() 465 del c.foo 466 self.assertEqual(descriptor0.args, (descriptor1, Descriptor1)) 467 self.assertEqual(callable.args, (c,)) 468 469 def test_delete_fast_with_assigned_name_succeeds(self): 470 def foo(): 471 a = 4 472 del a 473 474 foo() 475 476 def test_delete_fast_with_deleted_name_raises_unbound_local_error(self): 477 def foo(): 478 a = 4 479 del a 480 del a # noqa: F821 481 482 with self.assertRaises(UnboundLocalError) as context: 483 foo() 484 self.assertEqual( 485 str(context.exception), "local variable 'a' referenced before assignment" 486 ) 487 488 def test_delete_name_calls_dunder_delitem(self): 489 class C(dict): 490 def __delitem__(self, key): 491 self.result = key 492 return None 493 494 locals = C() 495 exec("del foo", None, locals) 496 self.assertEqual(locals.result, "foo") 497 498 def test_delete_name_raises_name_error_on_error(self): 499 class C(dict): 500 def __delitem__(self, key): 501 self.result = key 502 raise UserWarning("bar") 503 504 globals = {} 505 locals = C() 506 with self.assertRaises(NameError) as context: 507 exec("del foo", globals, locals) 508 self.assertEqual(str(context.exception), "name 'foo' is not defined") 509 self.assertEqual(locals.result, "foo") 510 511 def test_delete_name_raises_name_error_on_descriptor_error(self): 512 class D: 513 def __get__(self, instance, owner): 514 self.result = (instance, owner) 515 raise UserWarning("baz") 516 517 d = D() 518 519 class C(dict): 520 __delitem__ = d 521 522 globals = {} 523 locals = C() 524 with self.assertRaises(NameError) as context: 525 exec("del foo", globals, locals) 526 self.assertEqual(str(context.exception), "name 'foo' is not defined") 527 self.assertEqual(d.result[0], locals) 528 self.assertEqual(d.result[1], C) 529 530 def test_get_iter_with_range_with_bool(self): 531 result = None 532 for i in range(True): 533 if result is None: 534 result = i 535 else: 536 result += i 537 self.assertEqual(result, 0) 538 539 result = 0 540 for i in range(True, 4): 541 result += i 542 self.assertEqual(result, 6) 543 544 result = 0 545 for i in range(0, 4, True): 546 result += i 547 self.assertEqual(result, 6) 548 549 def test_import_performs_secondary_lookup(self): 550 import sys 551 552 class FakeModule: 553 def __getattribute__(self, name): 554 if name == "__name__": 555 return "test_import_performs_secondary_lookup_fake_too" 556 raise AttributeError(name) 557 558 sys.modules["test_import_performs_secondary_lookup_fake"] = FakeModule() 559 sys.modules["test_import_performs_secondary_lookup_fake_too.foo"] = 42 560 try: 561 from test_import_performs_secondary_lookup_fake import foo 562 finally: 563 del sys.modules["test_import_performs_secondary_lookup_fake"] 564 del sys.modules["test_import_performs_secondary_lookup_fake_too.foo"] 565 self.assertEqual(foo, 42) 566 567 def test_call_ex_kw_with_class_with_iterable_raises_type_error(self): 568 def foo(a): 569 return a 570 571 mapping = [("hello", "world")] 572 with self.assertRaisesRegex(TypeError, "must be a mapping, not list"): 573 foo(**mapping) 574 575 def test_call_ex_kw_with_class_without_keys_method_raises_type_error(self): 576 class C: 577 __getitem__ = Mock(name="__getitem__", return_value="mock") 578 579 def foo(a): 580 return a 581 582 mapping = C() 583 with self.assertRaisesRegex(TypeError, "must be a mapping, not C"): 584 foo(**mapping) 585 586 def test_call_ex_kw_with_dict_subclass_does_not_call_keys_or_dunder_getitem(self): 587 class C(dict): 588 __getitem__ = Mock(name="__getitem__", return_value="mock") 589 keys = Mock(name="keys", return_value=("a",)) 590 591 def foo(a): 592 return a 593 594 mapping = C({"a": "foo"}) 595 result = foo(**mapping) 596 self.assertEqual(result, "foo") 597 C.keys.assert_not_called() 598 C.__getitem__.assert_not_called() 599 600 def test_call_ex_kw_with_non_dict_calls_keys_and_dunder_getitem(self): 601 class C: 602 __getitem__ = Mock(name="__getitem__", return_value="mock") 603 keys = Mock(name="keys", return_value=("a",)) 604 605 def foo(a): 606 return a 607 608 mapping = C() 609 result = foo(**mapping) 610 self.assertEqual(result, "mock") 611 C.keys.assert_called_once() 612 C.__getitem__.assert_called_once() 613 614 def test_call_ex_kw_with_non_dict_passes_dict_as_kwargs(self): 615 class C: 616 __getitem__ = Mock(name="__getitem__", return_value="mock") 617 keys = Mock(name="keys", return_value=("hello", "world")) 618 619 def foo(**kwargs): 620 self.assertIs(type(kwargs), dict) 621 self.assertIn("hello", kwargs) 622 self.assertIn("world", kwargs) 623 624 mapping = C() 625 foo(**mapping) 626 C.keys.assert_called_once() 627 self.assertEqual(C.__getitem__.call_count, 2) 628 629 def test_callfunction_kw_does_not_modify_actual_names(self): 630 def foo(a, b): 631 return (a, b) 632 633 def bar(): 634 return foo(b="b", a="a") 635 636 # Call the same function twice to see the actual names are preserved. 637 self.assertEqual(bar(), ("a", "b")) 638 self.assertEqual(bar(), ("a", "b")) 639 640 def test_call_raises_recursion_error(self): 641 def foo(x): 642 return foo(x) 643 644 with self.assertRaisesRegex(RecursionError, "maximum recursion depth exceeded"): 645 foo(1) 646 647 def test_cache_misses_after_dunder_class_update(self): 648 class C: 649 def foo(self): 650 return 100 651 652 class D: 653 def foo(self): 654 return 200 655 656 def cache_attribute(c): 657 return c.foo() 658 659 c = C() 660 # Load the cache 661 result = cache_attribute(c) 662 self.assertIs(result, 100) 663 664 c.__class__ = D 665 # The loaded cache doesn't match `c` since its layout id has changed. 666 result = cache_attribute(c) 667 self.assertIs(result, 200) 668 669 def test_unpack_sequence_raises_type_error(self): 670 class Foo: 671 pass 672 673 with self.assertRaisesRegex(TypeError, "cannot unpack non-iterable Foo object"): 674 a, b = Foo() 675 676 677class InlineCacheTests(unittest.TestCase): 678 def test_load_slot_descriptor(self): 679 class C: 680 __slots__ = "x" 681 682 def read_x(c): 683 return c.x 684 685 c = C() 686 c.x = 50 687 688 # Cache C.x. 689 self.assertEqual(read_x(c), 50) 690 # Use the cached descriptor. 691 self.assertEqual(read_x(c), 50) 692 693 # The cached descriptor raises AttributeError after its corresponding 694 # attribute gets deleted. 695 del c.x 696 with self.assertRaises(AttributeError): 697 read_x(c) 698 699 def test_load_slot_descriptor_invalidated_by_updating_type_attr(self): 700 class C: 701 __slots__ = "x" 702 703 def read_x(c): 704 return c.x 705 706 c = C() 707 c.x = 50 708 709 # Cache C.x. 710 self.assertEqual(read_x(c), 50) 711 712 # Invalidate the cache. 713 C.x = property(lambda self: 100) 714 715 # Verify that the updated type attribute is used for `c.x`. 716 self.assertEqual(read_x(c), 100) 717 718 def test_store_attr_calls_dunder_set(self): 719 class Descriptor: 720 def __set__(self, *args): 721 self.args = args 722 return "return value ignored" 723 724 descriptor = Descriptor() 725 726 class C: 727 foo = descriptor 728 729 c = C() 730 c.foo = 42 731 self.assertEqual(descriptor.args, (c, 42)) 732 # Assignment on the class should replace descriptor. 733 C.foo = 13 734 self.assertEqual(C.foo, 13) 735 self.assertEqual(C.__dict__["foo"], 13) 736 737 def test_store_attr_calls_callable_dunder_set(self): 738 class Callable: 739 def __call__(self, *args): 740 self.args = args 741 return "return value ignored" 742 743 callable = Callable() 744 745 class Descriptor: 746 __set__ = callable 747 748 descriptor = Descriptor() 749 750 class C: 751 foo = descriptor 752 753 c = C() 754 c.foo = 42 755 self.assertEqual(callable.args, (c, 42)) 756 # Assignment on the class should replace descriptor. 757 C.foo = 13 758 self.assertEqual(C.foo, 13) 759 self.assertEqual(C.__dict__["foo"], 13) 760 761 def test_store_attr_call_dunder_set_descriptor(self): 762 class Callable: 763 def __call__(self, *args): 764 self.args = args 765 return "return value ignored" 766 767 callable = Callable() 768 769 class Descriptor0: 770 def __get__(self, *args): 771 self.args = args 772 return callable 773 774 descriptor0 = Descriptor0() 775 776 class Descriptor1: 777 __set__ = descriptor0 778 779 descriptor1 = Descriptor1() 780 781 class C: 782 foo = descriptor1 783 784 c = C() 785 c.foo = 42 786 self.assertEqual(descriptor0.args, (descriptor1, Descriptor1)) 787 self.assertEqual(callable.args, (c, 42)) 788 789 def test_store_slot_descriptor(self): 790 class C: 791 __slots__ = "x" 792 793 def write_x(c, v): 794 c.x = v 795 796 c = C() 797 798 # Cache C.x. 799 write_x(c, 1) 800 self.assertEqual(c.x, 1) 801 802 # Use the cached descriptor. 803 write_x(c, 2) 804 self.assertEqual(c.x, 2) 805 806 def test_store_slot_descriptor_invalidated_by_updating_type_attr(self): 807 class C: 808 __slots__ = "x" 809 810 def write_x(c, v): 811 c.x = v 812 813 c = C() 814 815 # Cache C.x. 816 write_x(c, 1) 817 self.assertEqual(c.x, 1) 818 819 # Invalidate the cache. 820 def setter(self, value): 821 value["setter_executed"] = True 822 823 C.x = property(lambda self: 100, setter) 824 825 # Verify that the updated type attribute is used for `c.x`. 826 v = {"setter_executed": False} 827 write_x(c, v) 828 self.assertTrue(v["setter_executed"], True) 829 830 def test_raise_oserror_with_errno_and_strerror(self): 831 with self.assertRaises(FileNotFoundError) as context: 832 open("/tmp/nonexisting_file") 833 exc = context.exception 834 self.assertEqual(exc.errno, 2) 835 self.assertEqual(exc.strerror, "No such file or directory") 836 # TODO(T67323177): Check filename. 837 838 def test_call_with_bound_method_storing_arbitrary_callable_resolves_callable(self): 839 class C: 840 def __call__(self, arg): 841 return self, arg 842 843 func = C() 844 instance = object() 845 method = MethodType(func, instance) 846 self.assertEqual((func, instance), method()) 847 848 849class ImportNameTests(unittest.TestCase): 850 def test_import_name_calls_dunder_builtins_dunder_import(self): 851 def my_import(name, globals, locals, fromlist, level): 852 return SimpleNamespace(baz=42, bam=(name, fromlist, level)) 853 854 builtins = ModuleType("builtins") 855 builtins.__import__ = my_import 856 my_globals = {"__builtins__": builtins} 857 858 exec("from ..foo.bar import baz, bam", my_globals) 859 self.assertEqual(my_globals["baz"], 42) 860 self.assertEqual(my_globals["bam"], ("foo.bar", ("baz", "bam"), 2)) 861 862 def test_import_name_without_dunder_import_raises_import_error(self): 863 my_builtins = ModuleType("my_builtins") 864 my_globals = {"__builtins__": my_builtins} 865 with self.assertRaisesRegex(ImportError, "__import__ not found"): 866 exec("import foo", my_globals) 867 868 def test_import_from_module_with_raising_dunder_getattr_propagates_exception(self): 869 import collections 870 871 self.assertIn("__getattr__", collections.__dict__) 872 with self.assertRaises(ImportError): 873 from collections import definitely_does_not_exist 874 875 876class ImportStarTests(unittest.TestCase): 877 def test_import_star_imports_symbols(self): 878 def my_import(name, globals, locals, fromlist, level): 879 result = ModuleType("m") 880 result.foo = 1 881 result._bar = 2 882 result.baz_ = 3 883 result.__bam__ = 4 884 return result 885 886 builtins = ModuleType("builtins") 887 builtins.__import__ = my_import 888 my_globals = {"__builtins__": builtins} 889 890 exec("from m import *", my_globals) 891 self.assertEqual(my_globals["foo"], 1) 892 self.assertEqual(my_globals["baz_"], 3) 893 self.assertNotIn("_bar", my_globals) 894 self.assertNotIn("__bam__", my_globals) 895 896 def test_import_star_with_dunder_all_tuple_imports_symbols(self): 897 def my_import(name, globals, locals, fromlist, level): 898 result = ModuleType("m") 899 result.foo = 1 900 result._bar = 2 901 result.baz = 99 902 result.__all__ = ("foo", "_bar", "__repr__") 903 return result 904 905 builtins = ModuleType("builtins") 906 builtins.__import__ = my_import 907 my_globals = {"__builtins__": builtins} 908 909 exec("from m import *", my_globals) 910 self.assertEqual(my_globals["foo"], 1) 911 self.assertEqual(my_globals["_bar"], 2) 912 self.assertEqual(my_globals["__repr__"](), "<module 'm'>") 913 self.assertNotIn("baz", my_globals) 914 self.assertNotIn("__all__", my_globals) 915 916 def test_import_star_with_dunder_all_list_imports_symbols(self): 917 def my_import(name, globals, locals, fromlist, level): 918 result = ModuleType("m") 919 result.foo = 1 920 result._bar = 2 921 result.baz = 99 922 result.__all__ = ["foo", "_bar", "__all__"] 923 return result 924 925 builtins = ModuleType("builtins") 926 builtins.__import__ = my_import 927 my_globals = {"__builtins__": builtins} 928 929 exec("from m import *", my_globals) 930 self.assertEqual(my_globals["foo"], 1) 931 self.assertEqual(my_globals["_bar"], 2) 932 self.assertEqual(my_globals["__all__"], ["foo", "_bar", "__all__"]) 933 self.assertNotIn("baz", my_globals) 934 935 def test_import_star_with_dunder_all_sequence_imports_symbols(self): 936 def my_import(name, globals, locals, fromlist, level): 937 class C: 938 def __getitem__(self, key): 939 if key == 0: 940 return "foo" 941 if key == 1: 942 return "_bar" 943 raise IndexError 944 945 result = ModuleType("m") 946 result.foo = 1 947 result._bar = 2 948 result.baz = 99 949 result.__all__ = C() 950 return result 951 952 builtins = ModuleType("builtins") 953 builtins.__import__ = my_import 954 my_globals = {"__builtins__": builtins} 955 956 exec("from m import *", my_globals) 957 self.assertEqual(my_globals["foo"], 1) 958 self.assertEqual(my_globals["_bar"], 2) 959 self.assertNotIn("baz", my_globals) 960 961 def test_import_star_calls_object_dunder_dict_keys(self): 962 def my_import(name, globals, locals, fromlist, level): 963 class C: 964 def keys(self): 965 return ["foo", "_bar", "baz_"] 966 967 class M: 968 __dict__ = C() 969 970 def __getattr__(self, key): 971 if key == "__all__": 972 raise AttributeError 973 return f"value for {key}" 974 975 return M() 976 977 builtins = ModuleType("builtins") 978 builtins.__import__ = my_import 979 my_globals = {"__builtins__": builtins} 980 981 exec("from m import *", my_globals) 982 self.assertEqual(my_globals["foo"], "value for foo") 983 self.assertEqual(my_globals["baz_"], "value for baz_") 984 self.assertNotIn("_bar", my_globals) 985 986 def test_import_star_calls_implicit_globals_dunder_setitem(self): 987 def my_import(name, globals, locals, fromlist, level): 988 result = ModuleType("m") 989 result.foo = 88 990 result.bar = 77 991 return result 992 993 class G(dict): 994 def __init__(self): 995 self.setitem_keys = [] 996 997 def __setitem__(self, key, value): 998 dict.__setitem__(self, key, value) 999 self.setitem_keys.append(key) 1000 1001 builtins = ModuleType("builtins") 1002 builtins.__import__ = my_import 1003 my_globals = {"__builtins__": builtins} 1004 my_locals = G() 1005 1006 exec("from m import *", my_globals, my_locals) 1007 self.assertEqual(my_locals["foo"], 88) 1008 self.assertEqual(my_locals["bar"], 77) 1009 self.assertEqual(sorted(my_locals.setitem_keys), ["bar", "foo"]) 1010 self.assertNotIn("foo", my_globals) 1011 self.assertNotIn("bar", my_globals) 1012 1013 def test_import_star_with_object_without_dunder_dict_raises_import_errro(self): 1014 def my_import(name, globals, locals, fromlist, level): 1015 class C: 1016 def __getattribute__(self, key): 1017 if key == "__dict__": 1018 raise AttributeError 1019 return object.__getattribute__(self, key) 1020 1021 return C() 1022 1023 builtins = ModuleType("builtins") 1024 builtins.__import__ = my_import 1025 my_globals = {"__builtins__": builtins} 1026 1027 with self.assertRaisesRegex( 1028 ImportError, r"from-import-\* object has no __dict__ and no __all__" 1029 ): 1030 exec("from m import *", my_globals) 1031 1032 1033if __name__ == "__main__": 1034 unittest.main()